@@ -16,182 +16,182 @@ const LEADING_TRAILING_SLASH_REGEXP = /^\/?([^/]+(?:\/[^/]+)*)\/?$/;
1616const TRAILING_SLASH_REGEXP = / \/ ? $ / ;
1717
1818function inverse ( string ) {
19- return string
20- . split ( '' )
21- . reverse ( )
22- . join ( '' ) ;
19+ return string
20+ . split ( '' )
21+ . reverse ( )
22+ . join ( '' ) ;
2323}
2424
2525function join ( keywords ) {
26- return keywords
27- . filter ( Boolean )
28- . map ( escapeRegExp )
29- . join ( '|' ) ;
26+ return keywords
27+ . filter ( Boolean )
28+ . map ( escapeRegExp )
29+ . join ( '|' ) ;
3030}
3131
3232function addLeadingAndTrailingSlash ( value ) {
33- return value . replace ( LEADING_TRAILING_SLASH_REGEXP , '/$1/' ) ;
33+ return value . replace ( LEADING_TRAILING_SLASH_REGEXP , '/$1/' ) ;
3434}
3535
3636function addTrailingSlash ( value ) {
37- return value . replace ( TRAILING_SLASH_REGEXP , '/' ) ;
37+ return value . replace ( TRAILING_SLASH_REGEXP , '/' ) ;
3838}
3939
4040function includesIgnoreCase ( array , value ) {
41- return array . findIndex ( arrayValue => arrayValue . toUpperCase ( ) === value . toUpperCase ( ) ) > - 1 ;
41+ return array . findIndex ( arrayValue => arrayValue . toUpperCase ( ) === value . toUpperCase ( ) ) > - 1 ;
4242}
4343
4444function buildMentionsRegexp ( { mentionsPrefixes} ) {
45- return `((?:(?:[^\\w\\n\\v\\r]|^)+(?:${ join ( mentionsPrefixes ) } )[\\w-\\.]+[^\\W])+)` ;
45+ return `((?:(?:[^\\w\\n\\v\\r]|^)+(?:${ join ( mentionsPrefixes ) } )[\\w-\\.]+[^\\W])+)` ;
4646}
4747
4848function buildRefRegexp ( { actions, delimiters, issuePrefixes, issueURLSegments, hosts} ) {
49- return `(?:(?:[^\\w\\n\\v\\r]|^)+(${ join (
50- [ ] . concat ( ...Object . keys ( actions ) . map ( key => actions [ key ] ) )
51- ) } ))?(?:[^\\w\\n\\v\\r]|^|(?: |\\t)*(?:${ join ( [ ' ' , '\t' , ...delimiters ] ) } )(?: |\\t)*)${
52- hosts . length > 0 ? `(?:${ join ( hosts ) } )?` : ''
53- } ((?:(?:[\\w-\\.]+)\\/)+(?:[\\w-\\.]+))?(${ join ( [ ...issuePrefixes , ...issueURLSegments ] ) } )(\\d+)(?!\\w)`;
49+ return `(?:(?:[^\\w\\n\\v\\r]|^)+(${ join (
50+ [ ] . concat ( ...Object . keys ( actions ) . map ( key => actions [ key ] ) )
51+ ) } ))?(?:[^\\w\\n\\v\\r]|^|(?: |\\t)*(?:${ join ( [ ' ' , '\t' , ...delimiters ] ) } )(?: |\\t)*)${
52+ hosts . length > 0 ? `(?:${ join ( hosts ) } )?` : ''
53+ } ((?:(?:[\\w-\\.]+)\\/)+(?:[\\w-\\.]+))?(${ join ( [ ...issuePrefixes , ...issueURLSegments ] ) } )(\\d+)(?!\\w)`;
5454}
5555
5656function buildRegexp ( options ) {
57- return new RegExp (
58- options . mentionsPrefixes . length > 0
59- ? `(?:${ buildRefRegexp ( options ) } |${ buildMentionsRegexp ( options ) } )`
60- : buildMentionsRegexp ( options ) ,
61- 'gim'
62- ) ;
57+ return new RegExp (
58+ options . mentionsPrefixes . length > 0
59+ ? `(?:${ buildRefRegexp ( options ) } |${ buildMentionsRegexp ( options ) } )`
60+ : buildMentionsRegexp ( options ) ,
61+ 'gim'
62+ ) ;
6363}
6464
6565function buildMentionRegexp ( { mentionsPrefixes} ) {
66- return new RegExp ( `(${ join ( mentionsPrefixes ) } )([\\w-\\.]+)` , 'gim' ) ;
66+ return new RegExp ( `(${ join ( mentionsPrefixes ) } )([\\w-\\.]+)` , 'gim' ) ;
6767}
6868
6969function parse ( text , regexp , mentionRegexp , { actions, issuePrefixes, hosts} ) {
70- let parsed ;
71- const results = {
72- actions : Object . keys ( actions ) . reduce (
73- ( result , key ) => ( actions [ key ] . length > 0 ? Object . assign ( result , { [ key ] : [ ] } ) : result ) ,
74- { }
75- ) ,
76- refs : [ ] ,
77- mentions : [ ] ,
78- } ;
79- let noCodeBlock = inverse ( inverse ( text . replace ( FENCE_BLOCK_REGEXP , '' ) ) . replace ( CODE_BLOCK_REGEXP , '' ) ) ;
80-
81- while ( regexp . test ( noCodeBlock ) ) {
82- noCodeBlock = noCodeBlock . replace ( HTML_CODE_BLOCK_REGEXP , '' ) ;
83- }
84-
85- while ( ( parsed = regexp . exec ( noCodeBlock ) ) !== null ) {
86- let [ raw , action , slug , prefix , issue , mentions ] = parsed ;
87- prefix =
88- prefix && issuePrefixes . some ( issuePrefix => issuePrefix . toUpperCase ( ) === prefix . toUpperCase ( ) )
89- ? prefix
90- : undefined ;
91- raw = parsed [ 0 ] . slice (
92- parsed [ 0 ] . indexOf (
93- parsed [ 1 ] || hosts . find ( host => parsed [ 0 ] . toUpperCase ( ) . includes ( host . toUpperCase ( ) ) ) || parsed [ 2 ] || parsed [ 3 ]
94- )
95- ) ;
96- action = capitalize ( parsed [ 1 ] ) ;
97-
98- const actionTypes = Object . keys ( actions ) . filter ( key => includesIgnoreCase ( actions [ key ] , action ) ) ;
99-
100- if ( actionTypes . length > 0 ) {
101- for ( const actionType of actionTypes ) {
102- results . actions [ actionType ] . push ( { raw, action, slug, prefix, issue} ) ;
103- }
104- } else if ( issue ) {
105- results . refs . push ( { raw, slug, prefix, issue} ) ;
106- } else if ( mentions ) {
107- let parsedMention ;
108- while ( ( parsedMention = mentionRegexp . exec ( mentions ) ) !== null ) {
109- const [ rawMention , prefixMention , user ] = parsedMention ;
110-
111- results . mentions . push ( { raw : rawMention . trim ( ) , prefix : prefixMention , user} ) ;
112- }
113- }
114- }
115-
116- return results ;
70+ let parsed ;
71+ const results = {
72+ actions : Object . keys ( actions ) . reduce (
73+ ( result , key ) => ( actions [ key ] . length > 0 ? Object . assign ( result , { [ key ] : [ ] } ) : result ) ,
74+ { }
75+ ) ,
76+ refs : [ ] ,
77+ mentions : [ ] ,
78+ } ;
79+ let noCodeBlock = inverse ( inverse ( text . replace ( FENCE_BLOCK_REGEXP , '' ) ) . replace ( CODE_BLOCK_REGEXP , '' ) ) ;
80+
81+ while ( regexp . test ( noCodeBlock ) ) {
82+ noCodeBlock = noCodeBlock . replace ( HTML_CODE_BLOCK_REGEXP , '' ) ;
83+ }
84+
85+ while ( ( parsed = regexp . exec ( noCodeBlock ) ) !== null ) {
86+ let [ raw , action , slug , prefix , issue , mentions ] = parsed ;
87+ prefix =
88+ prefix && issuePrefixes . some ( issuePrefix => issuePrefix . toUpperCase ( ) === prefix . toUpperCase ( ) )
89+ ? prefix
90+ : undefined ;
91+ raw = parsed [ 0 ] . slice (
92+ parsed [ 0 ] . indexOf (
93+ parsed [ 1 ] || hosts . find ( host => parsed [ 0 ] . toUpperCase ( ) . includes ( host . toUpperCase ( ) ) ) || parsed [ 2 ] || parsed [ 3 ]
94+ )
95+ ) ;
96+ action = capitalize ( parsed [ 1 ] ) ;
97+
98+ const actionTypes = Object . keys ( actions ) . filter ( key => includesIgnoreCase ( actions [ key ] , action ) ) ;
99+
100+ if ( actionTypes . length > 0 ) {
101+ for ( const actionType of actionTypes ) {
102+ results . actions [ actionType ] . push ( { raw, action, slug, prefix, issue} ) ;
103+ }
104+ } else if ( issue ) {
105+ results . refs . push ( { raw, slug, prefix, issue} ) ;
106+ } else if ( mentions ) {
107+ let parsedMention ;
108+ while ( ( parsedMention = mentionRegexp . exec ( mentions ) ) !== null ) {
109+ const [ rawMention , prefixMention , user ] = parsedMention ;
110+
111+ results . mentions . push ( { raw : rawMention . trim ( ) , prefix : prefixMention , user} ) ;
112+ }
113+ }
114+ }
115+
116+ return results ;
117117}
118118
119119function typeError ( parentOpt , opt ) {
120- return new TypeError (
121- `The ${ [ parentOpt , opt ] . filter ( Boolean ) . join ( '.' ) } property must be a String or an array of Strings`
122- ) ;
120+ return new TypeError (
121+ `The ${ [ parentOpt , opt ] . filter ( Boolean ) . join ( '.' ) } property must be a String or an array of Strings`
122+ ) ;
123123}
124124
125125function normalize ( options , parentOpt ) {
126- for ( const opt of Object . keys ( options ) ) {
127- if ( ! parentOpt && opt === 'actions' ) {
128- normalize ( options [ opt ] , opt ) ;
129- } else {
130- if ( ! options [ opt ] ) {
131- options [ opt ] = [ ] ;
132- } else if ( isString ( options [ opt ] ) ) {
133- options [ opt ] = [ options [ opt ] ] ;
134- } else if ( ! Array . isArray ( options [ opt ] ) ) {
135- throw typeError ( parentOpt , opt ) ;
136- }
137-
138- if ( options [ opt ] . length !== 0 && ! options [ opt ] . every ( opt => isString ( opt ) ) ) {
139- throw typeError ( parentOpt , opt ) ;
140- }
141-
142- options [ opt ] = options [ opt ] . filter ( Boolean ) ;
143- }
144- }
126+ for ( const opt of Object . keys ( options ) ) {
127+ if ( ! parentOpt && opt === 'actions' ) {
128+ normalize ( options [ opt ] , opt ) ;
129+ } else {
130+ if ( ! options [ opt ] ) {
131+ options [ opt ] = [ ] ;
132+ } else if ( isString ( options [ opt ] ) ) {
133+ options [ opt ] = [ options [ opt ] ] ;
134+ } else if ( ! Array . isArray ( options [ opt ] ) ) {
135+ throw typeError ( parentOpt , opt ) ;
136+ }
137+
138+ if ( options [ opt ] . length !== 0 && ! options [ opt ] . every ( opt => isString ( opt ) ) ) {
139+ throw typeError ( parentOpt , opt ) ;
140+ }
141+
142+ options [ opt ] = options [ opt ] . filter ( Boolean ) ;
143+ }
144+ }
145145}
146146
147147module . exports = ( options = 'default' , overrides = { } ) => {
148- if ( ! isString ( options ) && ! isPlainObject ( options ) ) {
149- throw new TypeError ( 'The options argument must be a String or an Object' ) ;
150- }
151-
152- if ( isPlainObject ( options ) && hasOwnProperty . call ( options , 'actions' ) && ! isPlainObject ( options . actions ) ) {
153- throw new TypeError ( 'The options.actions property must be an Object' ) ;
154- }
155-
156- if ( isString ( options ) && ! includesIgnoreCase ( Object . keys ( hostConfig ) , options ) ) {
157- throw new TypeError ( `The supported configuration are [${ Object . keys ( hostConfig ) . join ( ', ' ) } ], got '${ options } '` ) ;
158- }
159-
160- if ( ! isPlainObject ( overrides ) ) {
161- throw new TypeError ( 'The overrides argument must be an Object' ) ;
162- } else if ( hasOwnProperty . call ( overrides , 'actions' ) && ! isPlainObject ( overrides . actions ) ) {
163- throw new TypeError ( 'The overrides.actions property must be an Object' ) ;
164- }
165-
166- options = isString ( options ) ? hostConfig [ options . toLowerCase ( ) ] : options ;
167-
168- const mergedOptions = {
169- ...hostConfig . default ,
170- ...options ,
171- ...overrides ,
172- actions : { ...hostConfig . default . actions , ...options . actions , ...overrides . actions } ,
173- } ;
174-
175- normalize ( mergedOptions ) ;
176-
177- mergedOptions . hosts = mergedOptions . hosts . map ( addTrailingSlash ) ;
178- mergedOptions . issueURLSegments = mergedOptions . issueURLSegments . map ( addLeadingAndTrailingSlash ) ;
179-
180- const regexp = buildRegexp ( mergedOptions ) ;
181- const mentionRegexp = buildMentionRegexp ( mergedOptions ) ;
182-
183- return text => {
184- if ( ! isString ( text ) ) {
185- throw new TypeError ( 'The issue text must be a String' ) ;
186- }
187-
188- const results = parse ( text , regexp , mentionRegexp , mergedOptions ) ;
189-
190- Reflect . defineProperty ( results , 'allRefs' , {
191- get ( ) {
192- return uniqBy ( this . refs . concat ( ...Object . keys ( this . actions ) . map ( key => this . actions [ key ] ) ) , 'raw' ) ;
193- } ,
194- } ) ;
195- return results ;
196- } ;
148+ if ( ! isString ( options ) && ! isPlainObject ( options ) ) {
149+ throw new TypeError ( 'The options argument must be a String or an Object' ) ;
150+ }
151+
152+ if ( isPlainObject ( options ) && hasOwnProperty . call ( options , 'actions' ) && ! isPlainObject ( options . actions ) ) {
153+ throw new TypeError ( 'The options.actions property must be an Object' ) ;
154+ }
155+
156+ if ( isString ( options ) && ! includesIgnoreCase ( Object . keys ( hostConfig ) , options ) ) {
157+ throw new TypeError ( `The supported configuration are [${ Object . keys ( hostConfig ) . join ( ', ' ) } ], got '${ options } '` ) ;
158+ }
159+
160+ if ( ! isPlainObject ( overrides ) ) {
161+ throw new TypeError ( 'The overrides argument must be an Object' ) ;
162+ } else if ( hasOwnProperty . call ( overrides , 'actions' ) && ! isPlainObject ( overrides . actions ) ) {
163+ throw new TypeError ( 'The overrides.actions property must be an Object' ) ;
164+ }
165+
166+ options = isString ( options ) ? hostConfig [ options . toLowerCase ( ) ] : options ;
167+
168+ const mergedOptions = {
169+ ...hostConfig . default ,
170+ ...options ,
171+ ...overrides ,
172+ actions : { ...hostConfig . default . actions , ...options . actions , ...overrides . actions } ,
173+ } ;
174+
175+ normalize ( mergedOptions ) ;
176+
177+ mergedOptions . hosts = mergedOptions . hosts . map ( addTrailingSlash ) ;
178+ mergedOptions . issueURLSegments = mergedOptions . issueURLSegments . map ( addLeadingAndTrailingSlash ) ;
179+
180+ const regexp = buildRegexp ( mergedOptions ) ;
181+ const mentionRegexp = buildMentionRegexp ( mergedOptions ) ;
182+
183+ return text => {
184+ if ( ! isString ( text ) ) {
185+ throw new TypeError ( 'The issue text must be a String' ) ;
186+ }
187+
188+ const results = parse ( text , regexp , mentionRegexp , mergedOptions ) ;
189+
190+ Reflect . defineProperty ( results , 'allRefs' , {
191+ get ( ) {
192+ return uniqBy ( this . refs . concat ( ...Object . keys ( this . actions ) . map ( key => this . actions [ key ] ) ) , 'raw' ) ;
193+ } ,
194+ } ) ;
195+ return results ;
196+ } ;
197197} ;
0 commit comments