css2class 2.0.0 → 2.0.1

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.
Files changed (40) hide show
  1. package/.github/workflows/deploy-docs.yml +53 -0
  2. package/.head_config.mjs +68 -0
  3. package/CONFIG.md +38 -1
  4. package/README.md +595 -633
  5. package/bin/class2css.js +32 -4
  6. package/common.css +1 -1
  7. package/configs/typography.config.js +1 -0
  8. package/docs/.vitepress/config.mjs +68 -65
  9. package/docs/guide/cli.md +97 -97
  10. package/docs/guide/config-template.md +16 -1
  11. package/docs/guide/config.md +129 -64
  12. package/docs/guide/faq.md +202 -202
  13. package/docs/guide/getting-started.md +86 -83
  14. package/docs/guide/incremental.md +164 -162
  15. package/docs/guide/rules-reference.md +73 -1
  16. package/docs/index.md +71 -68
  17. package/examples/weapp/README.md +15 -0
  18. package/examples/weapp/class2css.config.js +70 -0
  19. package/examples/weapp/src/placeholder.wxml +0 -0
  20. package/examples/weapp/styles.config.js +201 -0
  21. package/examples/web/README.md +25 -0
  22. package/examples/web/class2css.config.js +70 -0
  23. package/examples/web/demo.html +105 -0
  24. package/examples/web/src/placeholder.html +5 -0
  25. package/examples/web/styles.config.js +201 -0
  26. package/package.json +7 -2
  27. package/src/README.md +99 -0
  28. package/src/core/ConfigManager.js +440 -431
  29. package/src/core/FullScanManager.js +438 -430
  30. package/src/generators/DynamicClassGenerator.js +270 -72
  31. package/src/index.js +1091 -1046
  32. package/src/parsers/ClassParser.js +8 -2
  33. package/src/utils/CssFormatter.js +400 -47
  34. package/src/utils/UnitProcessor.js +4 -3
  35. package/src/watchers/ConfigWatcher.js +413 -413
  36. package/src/watchers/FileWatcher.js +148 -133
  37. package/src/writers/FileWriter.js +444 -302
  38. package/src/writers/UnifiedWriter.js +413 -370
  39. package/class2css.config.js +0 -124
  40. package/styles.config.js +0 -250
@@ -17,6 +17,40 @@ class DynamicClassGenerator {
17
17
  // CSS生成缓存
18
18
  this.cssCache = new Map();
19
19
  this.cacheEnabled = true;
20
+
21
+ // 缓存:已知前缀列表(按长度降序),避免每个 class 解析都重新排序
22
+ this._sortedPrefixes = [];
23
+ this._sortedPrefixesCacheKey = null;
24
+ this.refreshPrefixCache();
25
+ }
26
+
27
+ // 刷新前缀缓存(配置变更时调用)
28
+ refreshPrefixCache() {
29
+ try {
30
+ const cssNameMap = this.configManager?.getCssNameMap?.();
31
+ if (!cssNameMap) {
32
+ this._sortedPrefixes = [];
33
+ this._sortedPrefixesCacheKey = null;
34
+ return;
35
+ }
36
+
37
+ // 以 key 的拼接作为轻量 cache key(避免在热路径里做深比较)
38
+ const keys = Array.from(cssNameMap.keys());
39
+ const nextKey = keys.join('|');
40
+ if (this._sortedPrefixesCacheKey === nextKey && this._sortedPrefixes.length > 0) {
41
+ return;
42
+ }
43
+
44
+ this._sortedPrefixes = keys.sort((a, b) => b.length - a.length);
45
+ this._sortedPrefixesCacheKey = nextKey;
46
+ this.eventBus.emit('generator:dynamic:prefix_cache:refreshed', {
47
+ prefixCount: this._sortedPrefixes.length,
48
+ });
49
+ } catch (_) {
50
+ // ignore: cache refresh failure should not break generation
51
+ this._sortedPrefixes = [];
52
+ this._sortedPrefixesCacheKey = null;
53
+ }
20
54
  }
21
55
 
22
56
  // 生成动态CSS类列表
@@ -33,6 +67,11 @@ class DynamicClassGenerator {
33
67
 
34
68
  this.eventBus.emit('generator:dynamic:started', { classCount: classArr.length });
35
69
 
70
+ // 确保前缀缓存存在(热更新/首次运行兜底)
71
+ if (!this._sortedPrefixes || this._sortedPrefixes.length === 0) {
72
+ this.refreshPrefixCache();
73
+ }
74
+
36
75
  classArr.forEach((className, index) => {
37
76
  try {
38
77
  const isImportant = this.importantParser.hasImportantFlag(className);
@@ -47,25 +86,34 @@ class DynamicClassGenerator {
47
86
  return;
48
87
  }
49
88
 
50
- // name 现在可能是 [prefix, value] 或 [prefix, value, variant]
51
- const variant = name.length >= 3 ? name[2] : null;
89
+ // name 现在是 [prefix, value, responsiveVariant, stateVariants]
90
+ const responsiveVariant = name.length >= 3 ? name[2] : null;
91
+ const stateVariants = name.length >= 4 ? name[3] : [];
52
92
 
53
93
  if (cssNameMap.has(name[0])) {
54
- const classCss = this.getClassListStr([name[0], name[1]], className, isImportant, variant);
94
+ const classCss = this.getClassListStr(
95
+ [name[0], name[1]],
96
+ className,
97
+ isImportant,
98
+ responsiveVariant,
99
+ stateVariants
100
+ );
55
101
  cssStr += classCss;
56
102
  this.eventBus.emit('generator:dynamic:generated', {
57
103
  className,
58
104
  cleanName: cleanClassName,
59
105
  isImportant,
60
- variant,
106
+ responsiveVariant,
107
+ stateVariants,
61
108
  });
62
109
  } else {
63
- userBaseClassArr.push([name[0], name[1], className, isImportant, variant]);
110
+ userBaseClassArr.push([name[0], name[1], className, isImportant, responsiveVariant, stateVariants]);
64
111
  this.eventBus.emit('generator:dynamic:userBase', {
65
112
  className,
66
113
  cleanName: cleanClassName,
67
114
  isImportant,
68
- variant,
115
+ responsiveVariant,
116
+ stateVariants,
69
117
  });
70
118
  }
71
119
  } catch (error) {
@@ -86,37 +134,74 @@ class DynamicClassGenerator {
86
134
  }
87
135
 
88
136
  // 解析响应式变体前缀(如 sm:, md: 等)
137
+ // 保留向后兼容,内部调用 parseVariants
89
138
  parseResponsiveVariant(className) {
139
+ const result = this.parseVariants(className);
140
+ return { variant: result.responsiveVariant, baseClass: result.baseClass };
141
+ }
142
+
143
+ // 解析所有变体(响应式 + 状态变体如 hover/focus/active)
144
+ // 返回 { responsiveVariant, stateVariants, baseClass }
145
+ parseVariants(className) {
90
146
  if (!className || typeof className !== 'string') {
91
- return { variant: null, baseClass: className };
147
+ return { responsiveVariant: null, stateVariants: [], baseClass: className };
92
148
  }
93
149
 
94
150
  const variants = this.configManager.getVariants();
95
151
  const responsiveVariants = variants.responsive || [];
152
+ const stateVariants = variants.states || [];
96
153
 
97
- // 按 : 拆分,检查第一部分是否是响应式变体
154
+ // 按 : 拆分前缀链
98
155
  const parts = className.split(':');
99
- if (parts.length >= 2) {
100
- const potentialVariant = parts[0];
101
- if (responsiveVariants.includes(potentialVariant)) {
102
- const baseClass = parts.slice(1).join(':'); // 支持嵌套的 :(虽然当前不支持,但保留兼容性)
103
- return { variant: potentialVariant, baseClass };
156
+ if (parts.length < 2) {
157
+ return { responsiveVariant: null, stateVariants: [], baseClass: className };
158
+ }
159
+
160
+ let responsiveVariant = null;
161
+ const foundStateVariants = [];
162
+ let baseClass = className;
163
+
164
+ // 从前往后解析:最多一个响应式变体(通常在链的最前面),可以有多个状态变体
165
+ // 例如:lg:hover:focus:w-20 -> responsive: lg, states: [hover, focus], base: w-20
166
+ let i = 0;
167
+ while (i < parts.length - 1) {
168
+ const potentialVariant = parts[i];
169
+
170
+ // 检查是否是响应式变体(只取第一个)
171
+ if (!responsiveVariant && responsiveVariants.includes(potentialVariant)) {
172
+ responsiveVariant = potentialVariant;
173
+ i++;
174
+ continue;
175
+ }
176
+
177
+ // 检查是否是状态变体
178
+ if (stateVariants.includes(potentialVariant)) {
179
+ foundStateVariants.push(potentialVariant);
180
+ i++;
181
+ continue;
104
182
  }
183
+
184
+ // 遇到未知变体,停止解析,剩余部分作为 baseClass
185
+ break;
105
186
  }
106
187
 
107
- return { variant: null, baseClass: className };
188
+ // baseClass 是最后一部分(或剩余部分)
189
+ baseClass = parts.slice(i).join(':');
190
+
191
+ return {
192
+ responsiveVariant,
193
+ stateVariants: foundStateVariants,
194
+ baseClass,
195
+ };
108
196
  }
109
197
 
110
- // 智能前缀解析方法 - 支持复合前缀如 max-w, min-h 等,同时支持响应式前缀
198
+ // 智能前缀解析方法 - 支持复合前缀如 max-w, min-h 等,同时支持响应式和状态变体
111
199
  parseClassNameIntelligent(className) {
112
- // 先解析响应式变体
113
- const { variant, baseClass } = this.parseResponsiveVariant(className);
200
+ // 解析所有变体(响应式 + 状态)
201
+ const { responsiveVariant, stateVariants, baseClass } = this.parseVariants(className);
114
202
 
115
- // 使用 base class 进行解析
116
- const cssNameMap = this.configManager.getCssNameMap();
117
-
118
- // 获取所有已知前缀,按长度降序排列
119
- const prefixes = Array.from(cssNameMap.keys()).sort((a, b) => b.length - a.length);
203
+ // 使用缓存的前缀列表进行解析(避免每次都重新排序)
204
+ const prefixes = this._sortedPrefixes || [];
120
205
 
121
206
  // 尝试匹配每个前缀
122
207
  for (const prefix of prefixes) {
@@ -128,25 +213,31 @@ class DynamicClassGenerator {
128
213
  className,
129
214
  prefix,
130
215
  value,
131
- variant,
216
+ responsiveVariant,
217
+ stateVariants,
132
218
  method: 'intelligent_parsing',
133
219
  });
134
- return [prefix, value, variant]; // 返回包含 variant 的三元组
220
+ // 返回包含所有变体信息的数组:[prefix, value, responsiveVariant, stateVariants]
221
+ return [prefix, value, responsiveVariant, stateVariants];
135
222
  }
136
223
  }
137
224
  }
138
225
 
139
- // 降级到原有逻辑
140
- const parts = baseClass.split('-');
141
- if (parts.length === 2) {
226
+ // 降级到原有逻辑:支持首个 - 分割,允许 value 包含 -
227
+ // 例如:bg-hex-fff -> ['bg', 'hex-fff']
228
+ const firstDashIndex = baseClass.indexOf('-');
229
+ if (firstDashIndex > 0 && firstDashIndex < baseClass.length - 1) {
230
+ const prefix = baseClass.substring(0, firstDashIndex);
231
+ const value = baseClass.substring(firstDashIndex + 1);
142
232
  this.eventBus.emit('generator:dynamic:prefix_matched', {
143
233
  className,
144
- prefix: parts[0],
145
- value: parts[1],
146
- variant,
147
- method: 'fallback_split',
234
+ prefix,
235
+ value,
236
+ responsiveVariant,
237
+ stateVariants,
238
+ method: 'fallback_first_dash_split',
148
239
  });
149
- return [parts[0], parts[1], variant]; // 返回包含 variant 的三元组
240
+ return [prefix, value, responsiveVariant, stateVariants];
150
241
  }
151
242
 
152
243
  this.eventBus.emit('generator:dynamic:parse_failed', {
@@ -157,15 +248,17 @@ class DynamicClassGenerator {
157
248
  }
158
249
 
159
250
  // 生成单个类的CSS字符串(优化版)
160
- getClassListStr(name, originalClassName, isImportant = false, variant = null) {
161
- // 检查缓存(包含 variant 信息)
162
- const cacheKey = `${name[0]}-${name[1]}-${isImportant}-${variant || ''}`;
251
+ getClassListStr(name, originalClassName, isImportant = false, responsiveVariant = null, stateVariants = []) {
252
+ // 检查缓存(包含所有变体信息)
253
+ const stateKey = stateVariants.length > 0 ? stateVariants.join(',') : '';
254
+ const cacheKey = `${name[0]}-${name[1]}-${isImportant}-${responsiveVariant || ''}-${stateKey}`;
163
255
  if (this.cacheEnabled && this.cssCache.has(cacheKey)) {
164
256
  const cached = this.cssCache.get(cacheKey);
165
- // 替换选择器时需要考虑转义
257
+ // 替换选择器时需要考虑转义和状态伪类
166
258
  const escapedSelector = this.cssFormatter.escapeSelector(originalClassName);
259
+ const pseudoSelectors = this.cssFormatter.buildStatePseudoSelectors(stateVariants);
167
260
  // 修复:将 - 放在字符类末尾,避免被解释为范围操作符
168
- return cached.replace(/\.[\w\\:-]+\s*{/, `.${escapedSelector} {`);
261
+ return cached.replace(/\.[\w\\:-]+\s*{/, `.${escapedSelector}${pseudoSelectors} {`);
169
262
  }
170
263
 
171
264
  const classNameDefinition = this.configManager.getCssNameMap().get(name[0]);
@@ -186,7 +279,8 @@ class DynamicClassGenerator {
186
279
  originalClassName,
187
280
  classNameDefinition,
188
281
  isImportant,
189
- variant
282
+ responsiveVariant,
283
+ stateVariants
190
284
  );
191
285
  } else {
192
286
  // 处理字符串类型的CSS定义
@@ -195,7 +289,8 @@ class DynamicClassGenerator {
195
289
  originalClassName,
196
290
  classNameDefinition,
197
291
  isImportant,
198
- variant
292
+ responsiveVariant,
293
+ stateVariants
199
294
  );
200
295
  }
201
296
 
@@ -208,7 +303,7 @@ class DynamicClassGenerator {
208
303
  }
209
304
 
210
305
  // 生成基于对象定义的CSS
211
- generateObjectBasedCSS(name, originalClassName, classNameDefinition, isImportant, variant = null) {
306
+ generateObjectBasedCSS(name, originalClassName, classNameDefinition, isImportant, responsiveVariant = null, stateVariants = []) {
212
307
  if (!classNameDefinition.classArr) {
213
308
  this.eventBus.emit('generator:warning', {
214
309
  warning: `classArr not found in definition for: ${name[0]}`,
@@ -228,7 +323,8 @@ class DynamicClassGenerator {
228
323
  processedValue = this.unitProcessor.parseValue(
229
324
  rawValue,
230
325
  cssProperty,
231
- classNameDefinition.unit
326
+ classNameDefinition.unit,
327
+ { skipSpecialProcessing: !!classNameDefinition.skipSpecialProcessing }
232
328
  );
233
329
  } else {
234
330
  // 使用传统逻辑(支持skipConversion)
@@ -247,19 +343,19 @@ class DynamicClassGenerator {
247
343
  value: isImportant ? `${value} !important` : value,
248
344
  }));
249
345
 
250
- // 使用格式化器格式化CSS
251
- const cssRule = this.cssFormatter.formatRule(originalClassName, processedValuesArray);
346
+ // 使用格式化器格式化CSS(传入状态变体用于生成伪类选择器)
347
+ const cssRule = this.cssFormatter.formatRule(originalClassName, processedValuesArray, null, stateVariants);
252
348
 
253
349
  // 如果有响应式变体,用 @media 包裹
254
- if (variant) {
255
- return this.wrapWithMediaQuery(cssRule, variant);
350
+ if (responsiveVariant) {
351
+ return this.wrapWithMediaQuery(cssRule, responsiveVariant);
256
352
  }
257
353
 
258
354
  return cssRule;
259
355
  }
260
356
 
261
357
  // 生成基于字符串定义的CSS
262
- generateStringBasedCSS(name, originalClassName, classNameDefinition, isImportant, variant = null) {
358
+ generateStringBasedCSS(name, originalClassName, classNameDefinition, isImportant, responsiveVariant = null, stateVariants = []) {
263
359
  const rawValue = name[1];
264
360
  let processedValue;
265
361
 
@@ -273,25 +369,25 @@ class DynamicClassGenerator {
273
369
 
274
370
  const finalValue = isImportant ? `${processedValue} !important` : processedValue;
275
371
 
276
- // 使用格式化器格式化CSS
277
- const cssRule = this.cssFormatter.formatRule(originalClassName, `${classNameDefinition}: ${finalValue}`);
372
+ // 使用格式化器格式化CSS(传入状态变体用于生成伪类选择器)
373
+ const cssRule = this.cssFormatter.formatRule(originalClassName, `${classNameDefinition}: ${finalValue}`, null, stateVariants);
278
374
 
279
375
  // 如果有响应式变体,用 @media 包裹
280
- if (variant) {
281
- return this.wrapWithMediaQuery(cssRule, variant);
376
+ if (responsiveVariant) {
377
+ return this.wrapWithMediaQuery(cssRule, responsiveVariant);
282
378
  }
283
379
 
284
380
  return cssRule;
285
381
  }
286
382
 
287
383
  // 用 @media 查询包裹 CSS 规则
288
- wrapWithMediaQuery(cssRule, variant) {
384
+ wrapWithMediaQuery(cssRule, responsiveVariant) {
289
385
  const breakpoints = this.configManager.getBreakpoints();
290
- const breakpoint = breakpoints[variant];
386
+ const breakpoint = breakpoints[responsiveVariant];
291
387
 
292
388
  if (!breakpoint) {
293
389
  this.eventBus.emit('generator:warning', {
294
- warning: `Breakpoint not found for variant: ${variant}`,
390
+ warning: `Breakpoint not found for variant: ${responsiveVariant}`,
295
391
  });
296
392
  return cssRule; // 如果没有找到断点,返回原始规则
297
393
  }
@@ -355,15 +451,15 @@ class DynamicClassGenerator {
355
451
  }
356
452
 
357
453
  let str = '';
358
- const userBaseClass = this.configManager.getUserBaseClass();
454
+ const baseClassNameMap = this.configManager.getBaseClassNameMap();
359
455
  const cssWrite = new Set(); // 临时防重复集合
360
456
 
361
457
  this.eventBus.emit('generator:userBase:started', { classCount: arr.length });
362
458
 
363
459
  arr.forEach((item, index) => {
364
460
  try {
365
- // item 现在可能是 [className, value, originalClassName, isImportant] 或 [className, value, originalClassName, isImportant, variant]
366
- const [className, value, originalClassName, isImportant, variant] = item;
461
+ // item 现在是 [className, value, originalClassName, isImportant, responsiveVariant, stateVariants]
462
+ const [className, value, originalClassName, isImportant, responsiveVariant, stateVariants = []] = item;
367
463
  const classKey = originalClassName;
368
464
 
369
465
  if (cssWrite.has(classKey)) {
@@ -374,9 +470,9 @@ class DynamicClassGenerator {
374
470
  return;
375
471
  }
376
472
 
377
- const baseClassItem = userBaseClass.find(([k, v]) => k === className);
378
-
379
- if (baseClassItem === undefined) {
473
+ const baseDef = baseClassNameMap ? baseClassNameMap.get(className) : undefined;
474
+ // userBaseClass 应该是 object 类型(如颜色族:{ ABBR: 'color', red: '#f00', ... })
475
+ if (!baseDef || typeof baseDef !== 'object' || Array.isArray(baseDef)) {
380
476
  this.eventBus.emit('generator:userBase:skipped', {
381
477
  className: originalClassName,
382
478
  reason: 'not_found_in_config',
@@ -388,22 +484,36 @@ class DynamicClassGenerator {
388
484
  const cssClassName = className.replaceAll('_', '-');
389
485
 
390
486
  let cssRule = '';
391
- if (this.isArray(baseClassItem[1])) {
487
+ if (this.isArray(baseDef)) {
392
488
  const cssValue = isImportant ? `${value} !important` : value;
393
- // 使用格式化器格式化CSS
394
- cssRule = this.cssFormatter.formatRule(originalClassName, `${cssClassName}: ${cssValue}`);
395
- } else if (this.isObject(baseClassItem[1]) && baseClassItem[1][value] !== undefined) {
396
- const cssValue = isImportant
397
- ? `${baseClassItem[1][value]} !important`
398
- : baseClassItem[1][value];
399
- const propertyName = baseClassItem[1]['ABBR'] || cssClassName;
400
- // 使用格式化器格式化CSS
401
- cssRule = this.cssFormatter.formatRule(originalClassName, `${propertyName}: ${cssValue}`);
489
+ // 使用格式化器格式化CSS(传入状态变体)
490
+ cssRule = this.cssFormatter.formatRule(originalClassName, `${cssClassName}: ${cssValue}`, null, stateVariants);
491
+ } else if (this.isObject(baseDef)) {
492
+ // 优先使用映射值(如果存在)
493
+ if (baseDef[value] !== undefined) {
494
+ const cssValue = isImportant
495
+ ? `${baseDef[value]} !important`
496
+ : baseDef[value];
497
+ const propertyName = baseDef['ABBR'] || cssClassName;
498
+ // 使用格式化器格式化CSS(传入状态变体)
499
+ cssRule = this.cssFormatter.formatRule(originalClassName, `${propertyName}: ${cssValue}`, null, stateVariants);
500
+ } else if (baseDef['ABBR']) {
501
+ // 映射不存在,但有 ABBR,尝试解析为直接颜色值
502
+ const parsedColor = this.parseColorValue(value);
503
+ if (parsedColor) {
504
+ const cssValue = isImportant
505
+ ? `${parsedColor} !important`
506
+ : parsedColor;
507
+ const propertyName = baseDef['ABBR'];
508
+ // 使用格式化器格式化CSS(传入状态变体)
509
+ cssRule = this.cssFormatter.formatRule(originalClassName, `${propertyName}: ${cssValue}`, null, stateVariants);
510
+ }
511
+ }
402
512
  }
403
513
 
404
514
  // 如果有响应式变体,用 @media 包裹
405
- if (variant && cssRule) {
406
- cssRule = this.wrapWithMediaQuery(cssRule, variant);
515
+ if (responsiveVariant && cssRule) {
516
+ cssRule = this.wrapWithMediaQuery(cssRule, responsiveVariant);
407
517
  }
408
518
 
409
519
  str += cssRule;
@@ -411,7 +521,8 @@ class DynamicClassGenerator {
411
521
  this.eventBus.emit('generator:userBase:generated', {
412
522
  className: originalClassName,
413
523
  isImportant,
414
- variant,
524
+ responsiveVariant,
525
+ stateVariants,
415
526
  });
416
527
  } catch (error) {
417
528
  this.eventBus.emit('generator:userBase:error', {
@@ -438,6 +549,90 @@ class DynamicClassGenerator {
438
549
  return Object.prototype.toString.call(obj) === '[object Array]';
439
550
  }
440
551
 
552
+ // 解析颜色值(支持 hex、rgb、rgba)
553
+ // 返回解析后的 CSS 颜色值字符串,失败返回 null
554
+ parseColorValue(value) {
555
+ if (!value || typeof value !== 'string') {
556
+ return null;
557
+ }
558
+
559
+ // Hex 格式:hex-fff, hex-112233, hex-ffffffff
560
+ if (value.startsWith('hex-')) {
561
+ const hexValue = value.substring(4);
562
+ // 验证 hex 值:3、4、6、8 位十六进制数字
563
+ if (/^[0-9a-fA-F]{3}$/.test(hexValue)) {
564
+ return `#${hexValue}`;
565
+ }
566
+ if (/^[0-9a-fA-F]{4}$/.test(hexValue)) {
567
+ return `#${hexValue}`;
568
+ }
569
+ if (/^[0-9a-fA-F]{6}$/.test(hexValue)) {
570
+ return `#${hexValue}`;
571
+ }
572
+ if (/^[0-9a-fA-F]{8}$/.test(hexValue)) {
573
+ return `#${hexValue}`;
574
+ }
575
+ return null;
576
+ }
577
+
578
+ // RGB 格式:rgb-255-0-0
579
+ if (value.startsWith('rgb-')) {
580
+ const parts = value.substring(4).split('-');
581
+ if (parts.length === 3) {
582
+ const r = parseInt(parts[0], 10);
583
+ const g = parseInt(parts[1], 10);
584
+ const b = parseInt(parts[2], 10);
585
+ if (
586
+ !isNaN(r) && r >= 0 && r <= 255 &&
587
+ !isNaN(g) && g >= 0 && g <= 255 &&
588
+ !isNaN(b) && b >= 0 && b <= 255
589
+ ) {
590
+ return `rgb(${r}, ${g}, ${b})`;
591
+ }
592
+ }
593
+ return null;
594
+ }
595
+
596
+ // RGBA 格式:rgba-255-0-0-05 或 rgba-255-0-0-0_5
597
+ if (value.startsWith('rgba-')) {
598
+ const parts = value.substring(5).split('-');
599
+ if (parts.length === 4) {
600
+ const r = parseInt(parts[0], 10);
601
+ const g = parseInt(parts[1], 10);
602
+ const b = parseInt(parts[2], 10);
603
+ // 解析 alpha:支持 05 (0.5) 或 0_5 (0.5) 格式
604
+ let alpha = parts[3];
605
+ let alphaNum;
606
+
607
+ // 如果包含下划线,替换为点
608
+ if (alpha.includes('_')) {
609
+ alpha = alpha.replace('_', '.');
610
+ alphaNum = parseFloat(alpha);
611
+ } else if (/^\d{2}$/.test(alpha) && alpha.length === 2) {
612
+ // 两位数字格式:
613
+ // - 如果 < 10(如 05, 08),除以 10 得到 0.5, 0.8
614
+ // - 如果 >= 10(如 50, 99),除以 100 得到 0.5, 0.99(作为百分比)
615
+ const num = parseInt(alpha, 10);
616
+ alphaNum = num < 10 ? num / 10 : num / 100;
617
+ } else {
618
+ // 其他格式(如 0.5, 1 等)直接解析
619
+ alphaNum = parseFloat(alpha);
620
+ }
621
+ if (
622
+ !isNaN(r) && r >= 0 && r <= 255 &&
623
+ !isNaN(g) && g >= 0 && g <= 255 &&
624
+ !isNaN(b) && b >= 0 && b <= 255 &&
625
+ !isNaN(alphaNum) && alphaNum >= 0 && alphaNum <= 1
626
+ ) {
627
+ return `rgba(${r}, ${g}, ${b}, ${alphaNum})`;
628
+ }
629
+ }
630
+ return null;
631
+ }
632
+
633
+ return null;
634
+ }
635
+
441
636
  // 验证CSS生成结果
442
637
  validateGeneratedCSS(cssStr) {
443
638
  const errors = [];
@@ -542,6 +737,9 @@ class DynamicClassGenerator {
542
737
  // 清空缓存,因为配置可能已更改
543
738
  this.clearCache();
544
739
 
740
+ // 配置更新后刷新前缀缓存
741
+ this.refreshPrefixCache();
742
+
545
743
  this.eventBus.emit('generator:config:updated', {
546
744
  timestamp: Date.now(),
547
745
  hasUnitProcessor: !!this.unitProcessor,