11import { type TransformResult , createUnplugin } from 'unplugin'
22import { createFilter } from '@rollup/pluginutils'
33import MagicString from 'magic-string'
4- import { type Options , resolveOption } from './core/options'
4+ import { type Options , type ReplaceItem , resolveOptions } from './core/options'
55
66export default createUnplugin < Options | undefined , false > ( ( rawOptions = { } ) => {
77 let {
@@ -13,16 +13,25 @@ export default createUnplugin<Options | undefined, false>((rawOptions = {}) => {
1313 delimiters,
1414 values,
1515 enforce,
16- } = resolveOption ( rawOptions )
16+ } = resolveOptions ( rawOptions )
1717 const filter = createFilter ( include , exclude )
1818
19- if ( objectGuards ) expandTypeofReplacements ( values )
20- const functionValues = mapToFunctions ( values )
21- // eslint-disable-next-line unicorn/no-array-callback-reference
22- const keys = Object . keys ( functionValues ) . sort ( longest ) . map ( escape )
19+ const stringValues = values . filter (
20+ ( value ) : value is ReplaceItem < string > => typeof value . find === 'string' ,
21+ )
22+ const regexpValues = values . filter (
23+ ( value ) : value is ReplaceItem < RegExp > => value . find instanceof RegExp ,
24+ )
25+
26+ if ( objectGuards ) expandTypeofReplacements ( stringValues )
27+ const escapedKeys = stringValues
28+ . map ( ( { find } ) => find )
29+ . sort ( longest )
30+ // eslint-disable-next-line unicorn/no-array-callback-reference
31+ . map ( escape )
2332 const lookahead = preventAssignment ? '(?!\\s*(=[^=]|:[^:]))' : ''
2433 const pattern = new RegExp (
25- `${ delimiters [ 0 ] } (${ keys . join ( '|' ) } )${ delimiters [ 1 ] } ${ lookahead } ` ,
34+ `${ delimiters [ 0 ] } (${ escapedKeys . join ( '|' ) } )${ delimiters [ 1 ] } ${ lookahead } ` ,
2635 'g' ,
2736 )
2837
@@ -40,7 +49,7 @@ export default createUnplugin<Options | undefined, false>((rawOptions = {}) => {
4049 } ,
4150
4251 transformInclude ( id ) {
43- if ( keys . length === 0 ) return false
52+ if ( escapedKeys . length === 0 && regexpValues . length === 0 ) return false
4453 return filter ( id )
4554 } ,
4655
@@ -73,18 +82,32 @@ export default createUnplugin<Options | undefined, false>((rawOptions = {}) => {
7382 id : string ,
7483 magicString : MagicString ,
7584 ) {
76- let result = false
77- let match
85+ let has = false
86+ let match : RegExpExecArray | null
87+
88+ const values : ReplaceItem < RegExp > [ ] = [ ...regexpValues ]
89+ if ( escapedKeys . length > 0 )
90+ values . push ( { find : pattern , replacement : null ! } )
91+
92+ for ( const { find, replacement } of values ) {
93+ while ( ( match = find . exec ( code ) ) ) {
94+ has = true
95+
96+ const start = match . index
97+ const end = start + match [ 0 ] . length
7898
79- while ( ( match = pattern . exec ( code ) ) ) {
80- result = true
99+ const finalReplacement =
100+ find === pattern
101+ ? stringValues . find ( ( { find } ) => find === match ! [ 1 ] ) ! . replacement
102+ : replacement
103+ const result = String ( ensureFunction ( finalReplacement ) ( id , match ) )
104+ magicString . overwrite ( start , end , result )
81105
82- const start = match . index
83- const end = start + match [ 0 ] . length
84- const replacement = String ( functionValues [ match [ 1 ] ] ( id ) )
85- magicString . overwrite ( start , end , replacement )
106+ if ( ! find . global ) break
107+ }
86108 }
87- return result
109+
110+ return has
88111 }
89112} )
90113
@@ -93,7 +116,9 @@ function escape(str: string) {
93116 return str . replace ( / [ $ ( ) * + . / ? [ \\ \] ^ { | } - ] / g, '\\$&' )
94117}
95118
96- function ensureFunction ( functionOrValue : any ) : ( ) => any {
119+ function ensureFunction (
120+ functionOrValue : any ,
121+ ) : ( id : string , match : RegExpExecArray ) => any {
97122 if ( typeof functionOrValue === 'function' ) return functionOrValue
98123 return ( ) => functionOrValue
99124}
@@ -102,47 +127,51 @@ function longest(a: string, b: string) {
102127 return b . length - a . length
103128}
104129
105- function mapToFunctions ( object : Record < string , any > ) : Record < string , Function > {
106- return Object . keys ( object ) . reduce ( ( fns , key ) => {
107- const functions : Record < string , Function > = Object . assign ( { } , fns )
108- functions [ key ] = ensureFunction ( object [ key ] )
109- return functions
110- } , { } )
111- }
112-
113130const objKeyRegEx =
114131 / ^ ( [ $ A - Z _ a - z \u00A0 - \uFFFF ] [ \w $ \u00A0 - \uFFFF ] * ) ( \. ( [ $ A - Z _ a - z \u00A0 - \uFFFF ] [ \w $ \u00A0 - \uFFFF ] * ) ) + $ /
115- function expandTypeofReplacements ( replacements : Record < string , any > ) {
116- Object . keys ( replacements ) . forEach ( ( key ) => {
117- const objMatch = key . match ( objKeyRegEx )
132+ function expandTypeofReplacements ( values : ReplaceItem < string > [ ] ) {
133+ values . forEach ( ( { find } ) => {
134+ const objMatch = find . match ( objKeyRegEx )
118135 if ( ! objMatch ) return
119136 let dotIndex = objMatch [ 1 ] . length
120137 let lastIndex = 0
121138 do {
122- // eslint-disable-next-line no-param-reassign
123- replacements [ `typeof ${ key . slice ( lastIndex , dotIndex ) } ===` ] =
124- '"object" ==='
125- // eslint-disable-next-line no-param-reassign
126- replacements [ `typeof ${ key . slice ( lastIndex , dotIndex ) } !==` ] =
127- '"object" !=='
128- // eslint-disable-next-line no-param-reassign
129- replacements [ `typeof ${ key . slice ( lastIndex , dotIndex ) } ===` ] =
130- '"object"==='
131- // eslint-disable-next-line no-param-reassign
132- replacements [ `typeof ${ key . slice ( lastIndex , dotIndex ) } !==` ] =
133- '"object"!=='
134- // eslint-disable-next-line no-param-reassign
135- replacements [ `typeof ${ key . slice ( lastIndex , dotIndex ) } ==` ] =
136- '"object" ==='
137- // eslint-disable-next-line no-param-reassign
138- replacements [ `typeof ${ key . slice ( lastIndex , dotIndex ) } !=` ] =
139- '"object" !=='
140- // eslint-disable-next-line no-param-reassign
141- replacements [ `typeof ${ key . slice ( lastIndex , dotIndex ) } ==` ] = '"object"==='
142- // eslint-disable-next-line no-param-reassign
143- replacements [ `typeof ${ key . slice ( lastIndex , dotIndex ) } !=` ] = '"object"!=='
139+ values . push (
140+ {
141+ find : `typeof ${ find . slice ( lastIndex , dotIndex ) } ===` ,
142+ replacement : '"object" ===' ,
143+ } ,
144+ {
145+ find : `typeof ${ find . slice ( lastIndex , dotIndex ) } !==` ,
146+ replacement : '"object" !==' ,
147+ } ,
148+ {
149+ find : `typeof ${ find . slice ( lastIndex , dotIndex ) } ===` ,
150+ replacement : '"object"===' ,
151+ } ,
152+ {
153+ find : `typeof ${ find . slice ( lastIndex , dotIndex ) } !==` ,
154+ replacement : '"object"!==' ,
155+ } ,
156+ {
157+ find : `typeof ${ find . slice ( lastIndex , dotIndex ) } ==` ,
158+ replacement : '"object" ===' ,
159+ } ,
160+ {
161+ find : `typeof ${ find . slice ( lastIndex , dotIndex ) } !=` ,
162+ replacement : '"object" !==' ,
163+ } ,
164+ {
165+ find : `typeof ${ find . slice ( lastIndex , dotIndex ) } ==` ,
166+ replacement : '"object"===' ,
167+ } ,
168+ {
169+ find : `typeof ${ find . slice ( lastIndex , dotIndex ) } !=` ,
170+ replacement : '"object"!==' ,
171+ } ,
172+ )
144173 lastIndex = dotIndex + 1
145- dotIndex = key . indexOf ( '.' , lastIndex )
174+ dotIndex = find . indexOf ( '.' , lastIndex )
146175 } while ( dotIndex !== - 1 )
147176 } )
148177}
0 commit comments