@@ -60,6 +60,8 @@ function replaceJsonKeysInFiles(
60
60
allowExtensions,
61
61
classConversionJsonFolderPath,
62
62
63
+ contentIgnoreRegexes,
64
+
63
65
whiteListedFolderPaths,
64
66
blackListedFolderPaths,
65
67
includeAnyMatchRegexes,
@@ -72,6 +74,8 @@ function replaceJsonKeysInFiles(
72
74
allowExtensions : string [ ] ,
73
75
classConversionJsonFolderPath : string ,
74
76
77
+ contentIgnoreRegexes : RegExp [ ] ,
78
+
75
79
whiteListedFolderPaths : string [ ] ,
76
80
blackListedFolderPaths : string [ ] ,
77
81
includeAnyMatchRegexes : RegExp [ ] ,
@@ -111,19 +115,25 @@ function replaceJsonKeysInFiles(
111
115
} ) ;
112
116
}
113
117
if ( blackListedFolderPaths . length > 0 ) {
114
- isTargetFile = ! blackListedFolderPaths . some ( ( incloudPath ) => {
118
+ const res = ! blackListedFolderPaths . some ( ( incloudPath ) => {
115
119
return normalizePath ( filePath ) . includes ( normalizePath ( incloudPath ) ) ;
116
120
} ) ;
121
+ if ( ! res ) {
122
+ isTargetFile = false ;
123
+ }
117
124
}
118
125
if ( includeAnyMatchRegexes . length > 0 ) {
119
126
isTargetFile = includeAnyMatchRegexes . some ( ( regex ) => {
120
127
return normalizePath ( filePath ) . match ( regex ) ;
121
128
} ) ;
122
129
}
123
130
if ( excludeAnyMatchRegexes . length > 0 ) {
124
- isTargetFile = ! excludeAnyMatchRegexes . some ( ( regex ) => {
131
+ const res = ! excludeAnyMatchRegexes . some ( ( regex ) => {
125
132
return normalizePath ( filePath ) . match ( regex ) ;
126
133
} ) ;
134
+ if ( ! res ) {
135
+ isTargetFile = false ;
136
+ }
127
137
}
128
138
if ( ! isTargetFile ) {
129
139
return ;
@@ -146,7 +156,7 @@ function replaceJsonKeysInFiles(
146
156
const htmlOriginal = html ;
147
157
const tagContents = findHtmlTagContentsByClass ( html , obfuscateMarkerClass ) ;
148
158
tagContents . forEach ( tagContent => {
149
- const { obfuscatedContent, usedKeys } = obfuscateKeys ( classConversion , tagContent ) ;
159
+ const { obfuscatedContent, usedKeys } = obfuscateKeys ( classConversion , tagContent , contentIgnoreRegexes ) ;
150
160
addKeysToRegistery ( usedKeys ) ;
151
161
if ( tagContent !== obfuscatedContent ) {
152
162
html = html . replace ( tagContent , obfuscatedContent ) ;
@@ -156,7 +166,7 @@ function replaceJsonKeysInFiles(
156
166
157
167
const scriptTagContents = findHtmlTagContents ( html , "script" ) ;
158
168
scriptTagContents . forEach ( scriptTagContent => {
159
- const obfuscateScriptContent = obfuscateJs ( scriptTagContent , obfuscateMarkerClass , classConversion , filePath ) ;
169
+ const obfuscateScriptContent = obfuscateJs ( scriptTagContent , obfuscateMarkerClass , classConversion , filePath , contentIgnoreRegexes ) ;
160
170
if ( scriptTagContent !== obfuscateScriptContent ) {
161
171
html = html . replace ( scriptTagContent , obfuscateScriptContent ) ;
162
172
log ( "debug" , `Obscured keys under HTML script tag in file:` , normalizePath ( filePath ) ) ;
@@ -168,7 +178,7 @@ function replaceJsonKeysInFiles(
168
178
}
169
179
}
170
180
} else {
171
- const obfuscateScriptContent = obfuscateJs ( fileContent , obfuscateMarkerClass , classConversion , filePath ) ;
181
+ const obfuscateScriptContent = obfuscateJs ( fileContent , obfuscateMarkerClass , classConversion , filePath , contentIgnoreRegexes ) ;
172
182
if ( fileContent !== obfuscateScriptContent ) {
173
183
fileContent = obfuscateScriptContent ;
174
184
log ( "debug" , `Obscured keys in JS like content file:` , normalizePath ( filePath ) ) ;
@@ -177,9 +187,17 @@ function replaceJsonKeysInFiles(
177
187
178
188
} ) ;
179
189
} else {
180
- const { obfuscatedContent, usedKeys } = obfuscateKeys ( classConversion , fileContent ) ;
181
- fileContent = obfuscatedContent ;
182
- addKeysToRegistery ( usedKeys ) ;
190
+ if ( [ ".js" ] . includes ( fileExt ) ) {
191
+ const obfuscateScriptContent = obfuscateJs ( fileContent , "jsx" , classConversion , filePath , contentIgnoreRegexes ) ;
192
+ if ( fileContent !== obfuscateScriptContent ) {
193
+ fileContent = obfuscateScriptContent ;
194
+ log ( "debug" , `Obscured keys in JSX related file:` , normalizePath ( filePath ) ) ;
195
+ }
196
+ } else {
197
+ const { obfuscatedContent, usedKeys } = obfuscateKeys ( classConversion , fileContent , contentIgnoreRegexes ) ;
198
+ fileContent = obfuscatedContent ;
199
+ addKeysToRegistery ( usedKeys ) ;
200
+ }
183
201
}
184
202
185
203
if ( fileContentOriginal !== fileContent ) {
@@ -202,20 +220,40 @@ function replaceJsonKeysInFiles(
202
220
203
221
}
204
222
205
- function obfuscateKeys ( jsonData : ClassConversion , fileContent : string ) {
223
+ function obfuscateKeys ( jsonData : ClassConversion , fileContent : string , contentIgnoreRegexes : RegExp [ ] = [ ] ) {
206
224
//ref: https://github.com/n4j1Br4ch1D/postcss-obfuscator/blob/main/utils.js
207
225
208
226
const usedKeys = new Set < string > ( ) ;
209
227
Object . keys ( jsonData ) . forEach ( ( key ) => {
210
228
const fileContentOriginal = fileContent ;
211
229
let keyUse = escapeRegExp ( key . slice ( 1 ) . replace ( / \\ / g, "" ) ) ;
212
- let regex ;
213
-
214
230
//? sample: "text-sm w-full\n text-right\n p-2 flex gap-2 hover:bg-gray-100 dark:hover:bg-red-700 text-right"
215
- regex = new RegExp ( `([\\s"'\\\`]|^)(${ keyUse } )(?=$|[\\s"'\\\`]|\\\\n)` , 'g' ) ; // match exact wording & avoid ` ' ""
216
- // regex = new RegExp(`([\\s"'\\\`]|^)(${keyUse})(?=$|[\\s"'\\\`])`, 'g'); // match exact wording & avoid ` ' ""
231
+ let exactMatchRegex = new RegExp ( `([\\s"'\\\`]|^)(${ keyUse } )(?=$|[\\s"'\\\`]|\\\\n)` , 'g' ) ; // match exact wording & avoid ` ' ""
232
+ // exactMatchRegex = new RegExp(`([\\s"'\\\`]|^)(${keyUse})(?=$|[\\s"'\\\`])`, 'g'); // match exact wording & avoid ` ' ""
233
+
234
+ const replacement = `$1` + jsonData [ key ] . slice ( 1 ) . replace ( / \\ / g, "" ) ;
235
+
236
+ const matches = fileContent . match ( exactMatchRegex ) ;
237
+ const originalObscuredContentPairs = matches ?. map ( ( match ) => {
238
+ return { originalContent : match , obscuredContent : match . replace ( exactMatchRegex , replacement ) } ;
239
+ } ) ;
240
+ fileContent = fileContent . replace ( exactMatchRegex , replacement ) ; // capture preceding space
241
+
242
+ if ( contentIgnoreRegexes . length > 0 ) {
243
+ contentIgnoreRegexes . forEach ( ( regex ) => {
244
+ const originalContentFragments = fileContentOriginal . match ( regex ) ;
245
+
246
+ originalContentFragments ?. map ( ( originalContentFragment ) => {
247
+ originalObscuredContentPairs ?. map ( ( pair ) => {
248
+ if ( originalContentFragments ?. some ( ( fragment ) => fragment . includes ( pair . originalContent ) ) ) {
249
+ log ( "debug" , "Obscured keys:" , `Ignored ${ pair . originalContent } at ${ originalContentFragment } ` ) ;
250
+ fileContent = fileContent . replace ( originalContentFragment . replace ( pair . originalContent , pair . obscuredContent ) , originalContentFragment ) ;
251
+ }
252
+ } ) ;
253
+ } ) ;
254
+ } ) ;
255
+ }
217
256
218
- fileContent = fileContent . replace ( regex , `$1` + jsonData [ key ] . slice ( 1 ) . replace ( / \\ / g, "" ) ) ; // capture preceding space
219
257
220
258
if ( fileContentOriginal !== fileContent && ! usedKeys . has ( key ) ) {
221
259
usedKeys . add ( key ) ;
@@ -375,60 +413,57 @@ function findContentBetweenMarker(content: string, targetStr: string, openMarker
375
413
if ( openMarker === closeMarker ) {
376
414
throw new Error ( "openMarker and closeMarker can not be the same" ) ;
377
415
}
416
+ // not support multi char marker
417
+ if ( openMarker . length > 1 || closeMarker . length > 1 ) {
418
+ throw new Error ( "openMarker and closeMarker can only be one character" ) ;
419
+ }
378
420
379
- const foundContents : string [ ] = [ ] ;
380
-
381
- let targetStrPosition = content . indexOf ( targetStr ) ;
382
- while ( targetStrPosition !== - 1 && targetStrPosition < content . length ) {
383
- let openMarkerPosition = - 1 ;
421
+ let lastEndIndex = 0 ;
422
+ let results : string [ ] = [ ] ;
384
423
385
- // search the closer openMarker before the targetStr
386
- let currentPosition = targetStrPosition ;
387
- while ( openMarkerPosition === - 1 && currentPosition > 0 ) {
388
- const reading = content . slice ( currentPosition , currentPosition + openMarker . length ) ;
389
- if ( reading === openMarker ) {
390
- openMarkerPosition = currentPosition ;
391
- } else if ( reading === closeMarker ) {
392
- break ;
393
- } else {
394
- currentPosition -- ;
395
- }
424
+ while ( true ) {
425
+ const targetIndex = content . indexOf ( targetStr , lastEndIndex ) ;
426
+ if ( targetIndex === - 1 ) {
427
+ break ;
396
428
}
397
- if ( openMarkerPosition !== - 1 ) {
398
- let closeMarkerPosition = openMarkerPosition ;
399
- if ( closeMarkerPosition < content . length ) {
400
- let count = 1 ;
401
- let closeMarkerReadingFramePos = closeMarkerPosition + closeMarker . length ;
402
- while ( count > 0 && closeMarkerReadingFramePos < content . length ) {
403
- if ( content . slice ( closeMarkerReadingFramePos , closeMarkerReadingFramePos + openMarker . length ) === openMarker ) {
404
- count ++ ;
405
- closeMarkerReadingFramePos += openMarker . length ;
406
- } else if ( content . slice ( closeMarkerReadingFramePos , closeMarkerReadingFramePos + closeMarker . length ) === closeMarker ) {
407
- count -- ;
408
- closeMarkerReadingFramePos += closeMarker . length ;
409
- } else {
410
- closeMarkerReadingFramePos ++ ;
411
- }
429
+
430
+ let level = 0 ;
431
+ let openMarkerIndex = - 1 ;
432
+ let closeMarkerIndex = - 1 ;
433
+
434
+ for ( let i = 0 ; i < content . length ; i ++ ) {
435
+ if ( content . substring ( i , i + openMarker . length ) === openMarker ) {
436
+ if ( i < targetIndex && ( openMarkerIndex === - 1 || level === 0 ) ) {
437
+ openMarkerIndex = i ;
412
438
}
413
- if ( count === 0 ) {
414
- const block = content . slice ( openMarkerPosition + openMarker . length , closeMarkerReadingFramePos - closeMarker . length ) ;
415
- if ( block . includes ( targetStr ) ) {
416
- foundContents . push ( block ) ;
417
- }
439
+ level ++ ;
440
+ i += openMarker . length - 1 ; // Skip the characters we've just checked
441
+ } else if ( content . substring ( i , i + closeMarker . length ) === closeMarker ) {
442
+ level -- ;
443
+ if ( level === 0 && i > targetIndex ) {
444
+ closeMarkerIndex = i ;
445
+ break ;
418
446
}
447
+ i += closeMarker . length - 1 ; // Skip the characters we've just checked
419
448
}
420
449
}
421
- targetStrPosition = content . indexOf ( targetStr , targetStrPosition + 1 ) ;
450
+
451
+ if ( openMarkerIndex === - 1 || closeMarkerIndex === - 1 ) {
452
+ break ;
453
+ }
454
+
455
+ results . push ( content . substring ( openMarkerIndex + openMarker . length , closeMarkerIndex ) ) ;
456
+ lastEndIndex = closeMarkerIndex + closeMarker . length ;
422
457
}
423
458
424
- return foundContents ;
459
+ return results ;
425
460
}
426
461
427
462
function obfuscateJs ( content : string , key : string , jsonData : ClassConversion
428
- , filePath : string ) {
463
+ , filePath : string , contentIgnoreRegexes : RegExp [ ] = [ ] ) {
429
464
const truncatedContents = findContentBetweenMarker ( content , key , "{" , "}" ) ;
430
465
truncatedContents . forEach ( ( truncatedContent ) => {
431
- const { obfuscatedContent, usedKeys } = obfuscateKeys ( jsonData , truncatedContent ) ;
466
+ const { obfuscatedContent, usedKeys } = obfuscateKeys ( jsonData , truncatedContent , contentIgnoreRegexes ) ;
432
467
addKeysToRegistery ( usedKeys ) ;
433
468
if ( truncatedContent !== obfuscatedContent ) {
434
469
content = content . replace ( truncatedContent , obfuscatedContent ) ;
@@ -784,4 +819,5 @@ export {
784
819
, replaceJsonKeysInFiles , setLogLevel
785
820
, copyCssData , findContentBetweenMarker , findHtmlTagContentsByClass
786
821
, findAllFilesWithExt , createClassConversionJson , extractClassFromSelector
822
+ , obfuscateKeys
787
823
} ;
0 commit comments