1
- import { OverType } from '../../overtype/mock-overtype'
1
+ import hljs from 'highlight.js'
2
+ import { logger } from '../../lib/logger'
3
+ import OverType , { type OverTypeInstance } from '../../overtype/overtype'
2
4
import type { CommentEnhancer , CommentSpot } from '../enhancer'
3
5
4
6
const GITHUB_SPOT_TYPES = [
7
+ 'GH_PR_ADD_COMMENT' ,
8
+ /* TODO
5
9
'GH_ISSUE_NEW',
6
10
'GH_PR_NEW',
7
11
'GH_ISSUE_ADD_COMMENT',
8
- 'GH_PR_ADD_COMMENT' ,
9
- /* TODO
10
12
'GH_ISSUE_EDIT_COMMENT',
11
13
'GH_PR_EDIT_COMMENT',
12
14
'GH_PR_CODE_COMMENT',
@@ -15,95 +17,95 @@ const GITHUB_SPOT_TYPES = [
15
17
16
18
export type GitHubSpotType = ( typeof GITHUB_SPOT_TYPES ) [ number ]
17
19
18
- export interface GitHubSpot extends CommentSpot {
20
+ export interface GitHubAddCommentSpot extends CommentSpot {
19
21
type : GitHubSpotType // Override to narrow from string to specific union
20
22
domain : string
21
23
slug : string // owner/repo
22
- number ? : number | undefined // issue/PR number, undefined for new issues and PRs
24
+ number : number // issue/PR number, undefined for new issues and PRs
23
25
}
24
26
25
- export class GitHubEnhancer implements CommentEnhancer < GitHubSpot > {
27
+ export class GitHubAddCommentEnhancer implements CommentEnhancer < GitHubAddCommentSpot > {
26
28
forSpotTypes ( ) : string [ ] {
27
29
return [ ...GITHUB_SPOT_TYPES ]
28
30
}
29
31
30
- tryToEnhance ( textarea : HTMLTextAreaElement ) : [ OverType , GitHubSpot ] | null {
31
- // Only handle GitHub domains
32
- if ( ! window . location . hostname . includes ( 'github' ) ) {
32
+ tryToEnhance ( textarea : HTMLTextAreaElement ) : [ OverTypeInstance , GitHubAddCommentSpot ] | null {
33
+ // Only handle github.com domains TODO: identify GitHub Enterprise somehow
34
+ if ( window . location . hostname !== 'github.com' ) {
33
35
return null
34
36
}
35
37
36
- const pathname = window . location . pathname
37
-
38
38
// Parse GitHub URL structure: /owner/repo/issues/123 or /owner/repo/pull/456
39
- const match = pathname . match ( / ^ \/ ( [ ^ / ] + ) \/ ( [ ^ / ] + ) (?: \/ ( i s s u e s | p u l l ) \/ ( \d + ) ) ? / )
40
- if ( ! match ) return null
39
+ logger . debug ( `${ this . constructor . name } examing url` , window . location . pathname )
41
40
42
- const [ , owner , repo , urlType , numberStr ] = match
41
+ const match = window . location . pathname . match ( / ^ \/ ( [ ^ / ] + ) \/ ( [ ^ / ] + ) (?: \/ p u l l \/ ( \d + ) ) / )
42
+ logger . debug ( `${ this . constructor . name } found match` , window . location . pathname )
43
+ if ( ! match ) return null
44
+ const [ , owner , repo , numberStr ] = match
43
45
const slug = `${ owner } /${ repo } `
44
- const number = numberStr ? parseInt ( numberStr , 10 ) : undefined
45
-
46
- // Determine comment type
47
- let type : GitHubSpotType
48
-
49
- if ( pathname . includes ( '/issues/new' ) ) {
50
- type = 'GH_ISSUE_NEW'
51
- } else if ( pathname . includes ( '/compare/' ) || pathname . endsWith ( '/compare' ) ) {
52
- type = 'GH_PR_NEW'
53
- } else if ( urlType && number ) {
54
- if ( urlType === 'issues' ) {
55
- type = 'GH_ISSUE_ADD_COMMENT'
56
- } else {
57
- type = 'GH_PR_ADD_COMMENT'
58
- }
59
- } else {
60
- return null
61
- }
46
+ const number = parseInt ( numberStr ! , 10 )
62
47
63
- // Generate unique key based on context
64
- let unique_key = `github:${ slug } `
65
- if ( number ) {
66
- unique_key += `:${ urlType } :${ number } `
67
- } else {
68
- unique_key += ':new'
69
- }
48
+ const unique_key = `github.com:${ slug } :${ number } `
70
49
71
- const spot : GitHubSpot = {
72
- domain : window . location . hostname ,
50
+ const spot : GitHubAddCommentSpot = {
51
+ domain : 'github.com' ,
73
52
number,
74
53
slug,
75
- type,
54
+ type : 'GH_PR_ADD_COMMENT' ,
76
55
unique_key,
77
56
}
78
- const overtype = new OverType ( textarea )
79
- return [ overtype , spot ]
57
+ return [ this . createOvertypeFor ( textarea ) , spot ]
58
+ }
59
+
60
+ private createOvertypeFor ( ghCommentBox : HTMLTextAreaElement ) : OverTypeInstance {
61
+ OverType . setCodeHighlighter ( hljsHighlighter )
62
+ const overtypeContainer = this . modifyDOM ( ghCommentBox )
63
+ return new OverType ( overtypeContainer , {
64
+ autoResize : true ,
65
+ minHeight : '102px' ,
66
+ padding : 'var(--base-size-8)' ,
67
+ placeholder : 'Add your comment here...' ,
68
+ } ) [ 0 ] !
69
+ }
70
+
71
+ private modifyDOM ( overtypeInput : HTMLTextAreaElement ) : HTMLElement {
72
+ overtypeInput . classList . add ( 'overtype-input' )
73
+ const overtypePreview = document . createElement ( 'div' )
74
+ overtypePreview . classList . add ( 'overtype-preview' )
75
+ overtypeInput . insertAdjacentElement ( 'afterend' , overtypePreview )
76
+ const overtypeWrapper = overtypeInput . parentElement ! . closest ( 'div' ) !
77
+ overtypeWrapper . classList . add ( 'overtype-wrapper' )
78
+ overtypeInput . placeholder = 'Add your comment here...'
79
+ const overtypeContainer = overtypeWrapper . parentElement ! . closest ( 'div' ) !
80
+ overtypeContainer . classList . add ( 'overtype-container' )
81
+ return overtypeContainer . parentElement ! . closest ( 'div' ) !
80
82
}
81
83
82
- tableTitle ( spot : GitHubSpot ) : string {
84
+ tableTitle ( spot : GitHubAddCommentSpot ) : string {
83
85
const { slug, number } = spot
84
- if ( number ) {
85
- return `Comment on ${ slug } #${ number } `
86
- }
87
- return `New ${ window . location . pathname . includes ( '/issues/' ) ? 'issue' : 'PR' } in ${ slug } `
86
+ return `${ slug } PR #${ number } `
88
87
}
89
88
90
- tableIcon ( spot : GitHubSpot ) : string {
91
- switch ( spot . type ) {
92
- case 'GH_ISSUE_NEW' :
93
- case 'GH_ISSUE_ADD_COMMENT' :
94
- return '🐛' // Issue icon
95
- case 'GH_PR_NEW' :
96
- case 'GH_PR_ADD_COMMENT' :
97
- return '🔄' // PR icon
98
- }
89
+ tableIcon ( _ : GitHubAddCommentSpot ) : string {
90
+ return '🔄' // PR icon TODO: icon urls in /public
91
+ }
92
+
93
+ buildUrl ( spot : GitHubAddCommentSpot ) : string {
94
+ return `https://${ spot . domain } /${ spot . slug } /pull/${ spot . number } `
99
95
}
96
+ }
100
97
101
- buildUrl ( spot : GitHubSpot ) : string {
102
- const baseUrl = `https://${ spot . domain } /${ spot . slug } `
103
- if ( spot . number ) {
104
- const type = spot . type . indexOf ( 'ISSUE' ) ? 'issues' : 'pull'
105
- return `${ baseUrl } /${ type } /${ spot . number } `
98
+ function hljsHighlighter ( code : string , language : string ) {
99
+ try {
100
+ if ( language && hljs . getLanguage ( language ) ) {
101
+ const result = hljs . highlight ( code , { language } )
102
+ return result . value
103
+ } else {
104
+ const result = hljs . highlightAuto ( code )
105
+ return result . value
106
106
}
107
- return baseUrl
107
+ } catch ( error ) {
108
+ console . warn ( 'highlight.js highlighting failed:' , error )
109
+ return code
108
110
}
109
111
}
0 commit comments