scss-variable-extractor 1.6.4 → 1.6.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +7 -0
- package/.prettierrc.json +18 -0
- package/.scssextractrc.example.json +31 -35
- package/MULTI-APP-GUIDE.md +262 -0
- package/README.md +1283 -778
- package/THEME-GUIDE.md +289 -0
- package/bin/cli.js +1002 -652
- package/jest.config.js +7 -12
- package/multi-app.example.json +44 -0
- package/package.json +50 -45
- package/src/analyzer.js +285 -285
- package/src/angular-parser.js +383 -381
- package/src/bootstrap-migrator.js +694 -661
- package/src/config.js +87 -91
- package/src/generator.js +220 -219
- package/src/index.js +37 -29
- package/src/multi-app-analyzer.js +612 -0
- package/src/ng-refactorer.js +654 -578
- package/src/parser.js +424 -421
- package/src/refactorer.js +329 -322
- package/src/scanner.js +63 -55
- package/src/style-organizer.js +500 -504
- package/src/theme-utils.js +432 -0
- package/test/analyzer.test.js +107 -107
- package/test/angular-parser.test.js +230 -230
- package/test/bootstrap-migrator.test.js +230 -213
- package/test/generator.test.js +139 -149
- package/test/multi-app-analyzer.test.js +216 -0
- package/test/ng-refactorer-global.test.js +140 -0
- package/test/ng-refactorer.test.js +191 -184
- package/test/parser.test.js +131 -131
- package/test/refactorer-edge-cases.test.js +385 -353
- package/test/refactorer.test.js +277 -257
- package/test/scanner.test.js +34 -32
- package/test/style-organizer.test.js +106 -106
- package/test/theme-utils.test.js +140 -0
package/src/parser.js
CHANGED
|
@@ -1,421 +1,424 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Regular expressions for matching various CSS/SCSS value types
|
|
5
|
-
*/
|
|
6
|
-
const PATTERNS = {
|
|
7
|
-
// Hex colors: #RGB, #RRGGBB, #RRGGBBAA
|
|
8
|
-
hexColor: /#([0-9a-fA-F]{3,8})\b/g,
|
|
9
|
-
|
|
10
|
-
// RGB/RGBA colors
|
|
11
|
-
rgbColor: /rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\s*\)/g,
|
|
12
|
-
|
|
13
|
-
// Named colors (common ones)
|
|
14
|
-
namedColor:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
*
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
PATTERNS.
|
|
98
|
-
PATTERNS.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Regular expressions for matching various CSS/SCSS value types
|
|
5
|
+
*/
|
|
6
|
+
const PATTERNS = {
|
|
7
|
+
// Hex colors: #RGB, #RRGGBB, #RRGGBBAA
|
|
8
|
+
hexColor: /#([0-9a-fA-F]{3,8})\b/g,
|
|
9
|
+
|
|
10
|
+
// RGB/RGBA colors
|
|
11
|
+
rgbColor: /rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)(?:\s*,\s*([\d.]+))?\s*\)/g,
|
|
12
|
+
|
|
13
|
+
// Named colors (common ones)
|
|
14
|
+
namedColor:
|
|
15
|
+
/\b(red|blue|green|white|black|gray|grey|yellow|orange|purple|pink|brown|cyan|magenta|transparent)\b/g,
|
|
16
|
+
|
|
17
|
+
// Pixel values
|
|
18
|
+
pixelValue: /\b(\d+)px\b/g,
|
|
19
|
+
|
|
20
|
+
// Percentage values
|
|
21
|
+
percentValue: /\b(\d+)%\b/g,
|
|
22
|
+
|
|
23
|
+
// Font weight values
|
|
24
|
+
fontWeight: /\b(bold|normal|lighter|bolder|[1-9]00)\b/g,
|
|
25
|
+
|
|
26
|
+
// Decimal values (for opacity, line-height)
|
|
27
|
+
decimalValue: /\b(0?\.\d+|1\.\d+|[2-9]\.\d+)\b/g,
|
|
28
|
+
|
|
29
|
+
// Box shadow
|
|
30
|
+
boxShadow: /(-?\d+px\s+){2,4}(rgba?\([^)]+\)|#[0-9a-fA-F]{3,8}|\w+)/g,
|
|
31
|
+
|
|
32
|
+
// Font family
|
|
33
|
+
fontFamily: /(['"][^'"]+['"](?:\s*,\s*(?:sans-serif|serif|monospace|cursive|fantasy))?)/g,
|
|
34
|
+
|
|
35
|
+
// Transition
|
|
36
|
+
transition:
|
|
37
|
+
/\b(all|none|[\w-]+)\s+[\d.]+m?s\s+(?:ease|linear|ease-in|ease-out|ease-in-out|cubic-bezier\([^)]+\))/g,
|
|
38
|
+
|
|
39
|
+
// Variable declaration (to skip)
|
|
40
|
+
variableDeclaration: /\$[\w-]+\s*:/g,
|
|
41
|
+
|
|
42
|
+
// URL function (to skip)
|
|
43
|
+
urlFunction: /url\([^)]+\)/g,
|
|
44
|
+
|
|
45
|
+
// Content property (to skip string literals)
|
|
46
|
+
contentProperty: /content\s*:\s*[^;]+;/g,
|
|
47
|
+
|
|
48
|
+
// String interpolation (to skip)
|
|
49
|
+
interpolation: /#\{[^}]+\}/g,
|
|
50
|
+
|
|
51
|
+
// @use and @forward statements (to skip)
|
|
52
|
+
useForward: /@(?:use|forward)\s+[^;]+;/g,
|
|
53
|
+
|
|
54
|
+
// Material palette functions (to skip)
|
|
55
|
+
materialFunctions:
|
|
56
|
+
/mat\.(?:define-palette|get-color-from-palette|define-(?:light|dark)-theme|all-component-themes)\([^)]*\)/g,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Extracts hardcoded values from SCSS content
|
|
61
|
+
* @param {string} content - SCSS file content
|
|
62
|
+
* @param {string} filePath - Path to the file (for context)
|
|
63
|
+
* @returns {Object} - Extracted values categorized by type
|
|
64
|
+
*/
|
|
65
|
+
function parseScss(content, filePath) {
|
|
66
|
+
const extracted = {
|
|
67
|
+
colors: [],
|
|
68
|
+
spacing: [],
|
|
69
|
+
fontSizes: [],
|
|
70
|
+
fontWeights: [],
|
|
71
|
+
fontFamilies: [],
|
|
72
|
+
borderRadius: [],
|
|
73
|
+
shadows: [],
|
|
74
|
+
zIndex: [],
|
|
75
|
+
sizing: [],
|
|
76
|
+
lineHeight: [],
|
|
77
|
+
opacity: [],
|
|
78
|
+
transitions: [],
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Remove comments
|
|
82
|
+
let cleanContent = content.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
83
|
+
cleanContent = cleanContent.replace(/\/\/.*/g, '');
|
|
84
|
+
|
|
85
|
+
// Remove safe zones (values we should not extract)
|
|
86
|
+
const safeZones = [];
|
|
87
|
+
|
|
88
|
+
// Mark variable declarations - entire lines with $variable:
|
|
89
|
+
let match;
|
|
90
|
+
const varDeclPattern = /\$[\w-]+\s*:[^;]+;/g;
|
|
91
|
+
while ((match = varDeclPattern.exec(cleanContent)) !== null) {
|
|
92
|
+
safeZones.push({ start: match.index, end: match.index + match[0].length });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Mark other safe zones
|
|
96
|
+
const markers = [
|
|
97
|
+
PATTERNS.urlFunction,
|
|
98
|
+
PATTERNS.contentProperty,
|
|
99
|
+
PATTERNS.interpolation,
|
|
100
|
+
PATTERNS.useForward,
|
|
101
|
+
PATTERNS.materialFunctions,
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
markers.forEach(pattern => {
|
|
105
|
+
pattern.lastIndex = 0;
|
|
106
|
+
while ((match = pattern.exec(cleanContent)) !== null) {
|
|
107
|
+
safeZones.push({ start: match.index, end: match.index + match[0].length });
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Helper to check if position is in safe zone
|
|
112
|
+
const isInSafeZone = pos => {
|
|
113
|
+
return safeZones.some(zone => pos >= zone.start && pos < zone.end);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Extract colors (hex)
|
|
117
|
+
PATTERNS.hexColor.lastIndex = 0;
|
|
118
|
+
while ((match = PATTERNS.hexColor.exec(cleanContent)) !== null) {
|
|
119
|
+
if (!isInSafeZone(match.index)) {
|
|
120
|
+
extracted.colors.push({
|
|
121
|
+
value: match[0],
|
|
122
|
+
line: getLineNumber(cleanContent, match.index),
|
|
123
|
+
file: filePath,
|
|
124
|
+
context: getContext(cleanContent, match.index),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Extract colors (rgb/rgba)
|
|
130
|
+
PATTERNS.rgbColor.lastIndex = 0;
|
|
131
|
+
while ((match = PATTERNS.rgbColor.exec(cleanContent)) !== null) {
|
|
132
|
+
if (!isInSafeZone(match.index)) {
|
|
133
|
+
extracted.colors.push({
|
|
134
|
+
value: match[0],
|
|
135
|
+
line: getLineNumber(cleanContent, match.index),
|
|
136
|
+
file: filePath,
|
|
137
|
+
context: getContext(cleanContent, match.index),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Extract named colors
|
|
143
|
+
PATTERNS.namedColor.lastIndex = 0;
|
|
144
|
+
while ((match = PATTERNS.namedColor.exec(cleanContent)) !== null) {
|
|
145
|
+
if (!isInSafeZone(match.index)) {
|
|
146
|
+
const ctx = getContext(cleanContent, match.index);
|
|
147
|
+
// Only extract if it looks like a color value (not in selectors)
|
|
148
|
+
if (ctx.includes(':')) {
|
|
149
|
+
extracted.colors.push({
|
|
150
|
+
value: match[0],
|
|
151
|
+
line: getLineNumber(cleanContent, match.index),
|
|
152
|
+
file: filePath,
|
|
153
|
+
context: ctx,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Extract pixel values (categorize by property)
|
|
160
|
+
PATTERNS.pixelValue.lastIndex = 0;
|
|
161
|
+
while ((match = PATTERNS.pixelValue.exec(cleanContent)) !== null) {
|
|
162
|
+
if (!isInSafeZone(match.index)) {
|
|
163
|
+
const ctx = getContext(cleanContent, match.index);
|
|
164
|
+
const property = extractPropertyAtPosition(cleanContent, match.index);
|
|
165
|
+
|
|
166
|
+
if (isFontSizeProperty(property)) {
|
|
167
|
+
extracted.fontSizes.push({
|
|
168
|
+
value: match[0],
|
|
169
|
+
line: getLineNumber(cleanContent, match.index),
|
|
170
|
+
file: filePath,
|
|
171
|
+
context: ctx,
|
|
172
|
+
property,
|
|
173
|
+
});
|
|
174
|
+
} else if (isSpacingProperty(property)) {
|
|
175
|
+
extracted.spacing.push({
|
|
176
|
+
value: match[0],
|
|
177
|
+
line: getLineNumber(cleanContent, match.index),
|
|
178
|
+
file: filePath,
|
|
179
|
+
context: ctx,
|
|
180
|
+
property,
|
|
181
|
+
});
|
|
182
|
+
} else if (isSizingProperty(property)) {
|
|
183
|
+
extracted.sizing.push({
|
|
184
|
+
value: match[0],
|
|
185
|
+
line: getLineNumber(cleanContent, match.index),
|
|
186
|
+
file: filePath,
|
|
187
|
+
context: ctx,
|
|
188
|
+
property,
|
|
189
|
+
});
|
|
190
|
+
} else if (isBorderRadiusProperty(property)) {
|
|
191
|
+
extracted.borderRadius.push({
|
|
192
|
+
value: match[0],
|
|
193
|
+
line: getLineNumber(cleanContent, match.index),
|
|
194
|
+
file: filePath,
|
|
195
|
+
context: ctx,
|
|
196
|
+
property,
|
|
197
|
+
});
|
|
198
|
+
} else if (isLineHeightProperty(property)) {
|
|
199
|
+
extracted.lineHeight.push({
|
|
200
|
+
value: match[0],
|
|
201
|
+
line: getLineNumber(cleanContent, match.index),
|
|
202
|
+
file: filePath,
|
|
203
|
+
context: ctx,
|
|
204
|
+
property,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Extract percentage values (for border-radius)
|
|
211
|
+
PATTERNS.percentValue.lastIndex = 0;
|
|
212
|
+
while ((match = PATTERNS.percentValue.exec(cleanContent)) !== null) {
|
|
213
|
+
if (!isInSafeZone(match.index)) {
|
|
214
|
+
const ctx = getContext(cleanContent, match.index);
|
|
215
|
+
const property = extractPropertyAtPosition(cleanContent, match.index);
|
|
216
|
+
|
|
217
|
+
if (isBorderRadiusProperty(property)) {
|
|
218
|
+
extracted.borderRadius.push({
|
|
219
|
+
value: match[0],
|
|
220
|
+
line: getLineNumber(cleanContent, match.index),
|
|
221
|
+
file: filePath,
|
|
222
|
+
context: ctx,
|
|
223
|
+
property,
|
|
224
|
+
});
|
|
225
|
+
} else if (isOpacityProperty(property)) {
|
|
226
|
+
extracted.opacity.push({
|
|
227
|
+
value: match[0],
|
|
228
|
+
line: getLineNumber(cleanContent, match.index),
|
|
229
|
+
file: filePath,
|
|
230
|
+
context: ctx,
|
|
231
|
+
property,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Extract font weights
|
|
238
|
+
PATTERNS.fontWeight.lastIndex = 0;
|
|
239
|
+
while ((match = PATTERNS.fontWeight.exec(cleanContent)) !== null) {
|
|
240
|
+
if (!isInSafeZone(match.index)) {
|
|
241
|
+
const ctx = getContext(cleanContent, match.index);
|
|
242
|
+
const property = extractPropertyAtPosition(cleanContent, match.index);
|
|
243
|
+
|
|
244
|
+
if (property && property.includes('font-weight')) {
|
|
245
|
+
extracted.fontWeights.push({
|
|
246
|
+
value: match[0],
|
|
247
|
+
line: getLineNumber(cleanContent, match.index),
|
|
248
|
+
file: filePath,
|
|
249
|
+
context: ctx,
|
|
250
|
+
property,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Extract font families
|
|
257
|
+
PATTERNS.fontFamily.lastIndex = 0;
|
|
258
|
+
while ((match = PATTERNS.fontFamily.exec(cleanContent)) !== null) {
|
|
259
|
+
if (!isInSafeZone(match.index)) {
|
|
260
|
+
const ctx = getContext(cleanContent, match.index);
|
|
261
|
+
const property = extractPropertyAtPosition(cleanContent, match.index);
|
|
262
|
+
|
|
263
|
+
if (property && property.includes('font-family')) {
|
|
264
|
+
extracted.fontFamilies.push({
|
|
265
|
+
value: match[0],
|
|
266
|
+
line: getLineNumber(cleanContent, match.index),
|
|
267
|
+
file: filePath,
|
|
268
|
+
context: ctx,
|
|
269
|
+
property,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Extract box shadows
|
|
276
|
+
PATTERNS.boxShadow.lastIndex = 0;
|
|
277
|
+
while ((match = PATTERNS.boxShadow.exec(cleanContent)) !== null) {
|
|
278
|
+
if (!isInSafeZone(match.index)) {
|
|
279
|
+
const ctx = getContext(cleanContent, match.index);
|
|
280
|
+
const property = extractPropertyAtPosition(cleanContent, match.index);
|
|
281
|
+
|
|
282
|
+
if (property && property.includes('box-shadow')) {
|
|
283
|
+
extracted.shadows.push({
|
|
284
|
+
value: match[0],
|
|
285
|
+
line: getLineNumber(cleanContent, match.index),
|
|
286
|
+
file: filePath,
|
|
287
|
+
context: ctx,
|
|
288
|
+
property,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Extract decimal values (opacity, line-height)
|
|
295
|
+
PATTERNS.decimalValue.lastIndex = 0;
|
|
296
|
+
while ((match = PATTERNS.decimalValue.exec(cleanContent)) !== null) {
|
|
297
|
+
if (!isInSafeZone(match.index)) {
|
|
298
|
+
const ctx = getContext(cleanContent, match.index);
|
|
299
|
+
const property = extractPropertyAtPosition(cleanContent, match.index);
|
|
300
|
+
|
|
301
|
+
if (isOpacityProperty(property)) {
|
|
302
|
+
extracted.opacity.push({
|
|
303
|
+
value: match[0],
|
|
304
|
+
line: getLineNumber(cleanContent, match.index),
|
|
305
|
+
file: filePath,
|
|
306
|
+
context: ctx,
|
|
307
|
+
property,
|
|
308
|
+
});
|
|
309
|
+
} else if (isLineHeightProperty(property)) {
|
|
310
|
+
extracted.lineHeight.push({
|
|
311
|
+
value: match[0],
|
|
312
|
+
line: getLineNumber(cleanContent, match.index),
|
|
313
|
+
file: filePath,
|
|
314
|
+
context: ctx,
|
|
315
|
+
property,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Extract transitions
|
|
322
|
+
PATTERNS.transition.lastIndex = 0;
|
|
323
|
+
while ((match = PATTERNS.transition.exec(cleanContent)) !== null) {
|
|
324
|
+
if (!isInSafeZone(match.index)) {
|
|
325
|
+
extracted.transitions.push({
|
|
326
|
+
value: match[0],
|
|
327
|
+
line: getLineNumber(cleanContent, match.index),
|
|
328
|
+
file: filePath,
|
|
329
|
+
context: getContext(cleanContent, match.index),
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Extract z-index values (pure integers in z-index context)
|
|
335
|
+
const zIndexRegex = /z-index\s*:\s*(\d+)/g;
|
|
336
|
+
while ((match = zIndexRegex.exec(cleanContent)) !== null) {
|
|
337
|
+
if (!isInSafeZone(match.index)) {
|
|
338
|
+
extracted.zIndex.push({
|
|
339
|
+
value: match[1],
|
|
340
|
+
line: getLineNumber(cleanContent, match.index),
|
|
341
|
+
file: filePath,
|
|
342
|
+
context: getContext(cleanContent, match.index),
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return extracted;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Gets line number for a position in text
|
|
352
|
+
*/
|
|
353
|
+
function getLineNumber(text, position) {
|
|
354
|
+
return text.substring(0, position).split('\n').length;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Gets surrounding context for a position
|
|
359
|
+
*/
|
|
360
|
+
function getContext(text, position, contextSize = 50) {
|
|
361
|
+
const start = Math.max(0, position - contextSize);
|
|
362
|
+
const end = Math.min(text.length, position + contextSize);
|
|
363
|
+
return text.substring(start, end).trim();
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Extracts property name at a specific position in the content
|
|
368
|
+
* Looks backward from position to find the property name
|
|
369
|
+
*/
|
|
370
|
+
function extractPropertyAtPosition(content, position) {
|
|
371
|
+
// Find the start of the current line
|
|
372
|
+
const lineStart = content.lastIndexOf('\n', position) + 1;
|
|
373
|
+
const lineSegment = content.substring(lineStart, position);
|
|
374
|
+
|
|
375
|
+
// Look for property: pattern before the position
|
|
376
|
+
const match = lineSegment.match(/([\w-]+)\s*:\s*[^:;]*$/);
|
|
377
|
+
return match ? match[1] : null;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Extracts property name from context (legacy, for other uses)
|
|
382
|
+
*/
|
|
383
|
+
function extractProperty(context) {
|
|
384
|
+
const match = context.match(/([\w-]+)\s*:/);
|
|
385
|
+
return match ? match[1] : null;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Property type checkers
|
|
390
|
+
*/
|
|
391
|
+
function isSpacingProperty(prop) {
|
|
392
|
+
if (!prop) return false;
|
|
393
|
+
return /^(padding|margin|gap|top|right|bottom|left)/.test(prop);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function isFontSizeProperty(prop) {
|
|
397
|
+
if (!prop) return false;
|
|
398
|
+
return prop === 'font-size';
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function isSizingProperty(prop) {
|
|
402
|
+
if (!prop) return false;
|
|
403
|
+
return /^(width|height|min-width|max-width|min-height|max-height)/.test(prop);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function isBorderRadiusProperty(prop) {
|
|
407
|
+
if (!prop) return false;
|
|
408
|
+
return /border-radius/.test(prop);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function isLineHeightProperty(prop) {
|
|
412
|
+
if (!prop) return false;
|
|
413
|
+
return prop === 'line-height';
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function isOpacityProperty(prop) {
|
|
417
|
+
if (!prop) return false;
|
|
418
|
+
return prop === 'opacity';
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
module.exports = {
|
|
422
|
+
parseScss,
|
|
423
|
+
PATTERNS,
|
|
424
|
+
};
|