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.
- package/.github/workflows/deploy-docs.yml +53 -0
- package/.head_config.mjs +68 -0
- package/CONFIG.md +38 -1
- package/README.md +595 -633
- package/bin/class2css.js +32 -4
- package/common.css +1 -1
- package/configs/typography.config.js +1 -0
- package/docs/.vitepress/config.mjs +68 -65
- package/docs/guide/cli.md +97 -97
- package/docs/guide/config-template.md +16 -1
- package/docs/guide/config.md +129 -64
- package/docs/guide/faq.md +202 -202
- package/docs/guide/getting-started.md +86 -83
- package/docs/guide/incremental.md +164 -162
- package/docs/guide/rules-reference.md +73 -1
- package/docs/index.md +71 -68
- package/examples/weapp/README.md +15 -0
- package/examples/weapp/class2css.config.js +70 -0
- package/examples/weapp/src/placeholder.wxml +0 -0
- package/examples/weapp/styles.config.js +201 -0
- package/examples/web/README.md +25 -0
- package/examples/web/class2css.config.js +70 -0
- package/examples/web/demo.html +105 -0
- package/examples/web/src/placeholder.html +5 -0
- package/examples/web/styles.config.js +201 -0
- package/package.json +7 -2
- package/src/README.md +99 -0
- package/src/core/ConfigManager.js +440 -431
- package/src/core/FullScanManager.js +438 -430
- package/src/generators/DynamicClassGenerator.js +270 -72
- package/src/index.js +1091 -1046
- package/src/parsers/ClassParser.js +8 -2
- package/src/utils/CssFormatter.js +400 -47
- package/src/utils/UnitProcessor.js +4 -3
- package/src/watchers/ConfigWatcher.js +413 -413
- package/src/watchers/FileWatcher.js +148 -133
- package/src/writers/FileWriter.js +444 -302
- package/src/writers/UnifiedWriter.js +413 -370
- package/class2css.config.js +0 -124
- package/styles.config.js +0 -250
|
@@ -1,431 +1,440 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
|
|
3
|
-
class ConfigManager {
|
|
4
|
-
constructor(eventBus, configPath = './class2css.config.js') {
|
|
5
|
-
this.eventBus = eventBus;
|
|
6
|
-
this.configPath = configPath;
|
|
7
|
-
this.config = null;
|
|
8
|
-
this.importantFlags = null;
|
|
9
|
-
this.cssNameMap = null;
|
|
10
|
-
this.baseClassNameMap = null;
|
|
11
|
-
this.userStaticClassSet = null;
|
|
12
|
-
this.userBaseClass = null;
|
|
13
|
-
this.userStaticClass = null;
|
|
14
|
-
this._fileUtils = null;
|
|
15
|
-
this._logger = null;
|
|
16
|
-
this._commonCssCache = null;
|
|
17
|
-
this.breakpoints = null;
|
|
18
|
-
|
|
19
|
-
this.loadConfig();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
loadConfig() {
|
|
23
|
-
try {
|
|
24
|
-
// 解析绝对路径
|
|
25
|
-
const path = require('path');
|
|
26
|
-
const absoluteConfigPath = path.resolve(this.configPath);
|
|
27
|
-
this.configPath = absoluteConfigPath; // 保存绝对路径
|
|
28
|
-
|
|
29
|
-
// 清除require缓存以确保重新加载
|
|
30
|
-
delete require.cache[require.resolve(absoluteConfigPath)];
|
|
31
|
-
|
|
32
|
-
// 清除样式配置文件的缓存(如果存在)
|
|
33
|
-
try {
|
|
34
|
-
const stylesConfigPath = path.resolve(path.dirname(absoluteConfigPath), 'styles.config.js');
|
|
35
|
-
if (require.cache[stylesConfigPath]) {
|
|
36
|
-
delete require.cache[stylesConfigPath];
|
|
37
|
-
}
|
|
38
|
-
} catch (e) {
|
|
39
|
-
// 样式配置文件不存在或无法解析,忽略
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
this.config = require(absoluteConfigPath);
|
|
43
|
-
|
|
44
|
-
this.updateConfigReferences();
|
|
45
|
-
this.eventBus.emit('config:loaded', this.config);
|
|
46
|
-
|
|
47
|
-
return this.config;
|
|
48
|
-
} catch (error) {
|
|
49
|
-
this.eventBus.emit('config:error', error);
|
|
50
|
-
throw error;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
updateConfigReferences() {
|
|
55
|
-
// 更新基础配置 - 支持新的system配置结构
|
|
56
|
-
this.baseUnit = this.config.system?.baseUnit || this.config.baseUnit || 'px';
|
|
57
|
-
this.multiFile = this.config.multiFile;
|
|
58
|
-
|
|
59
|
-
// 更新自定义 important 标识
|
|
60
|
-
this.importantFlags = {
|
|
61
|
-
prefix: this.config.importantFlags?.prefix || ['!'],
|
|
62
|
-
suffix: this.config.importantFlags?.suffix || ['_i', '-i'],
|
|
63
|
-
custom: this.config.importantFlags?.custom || [],
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
// 从atomicRules构建类名映射
|
|
67
|
-
const cssNameMap = this.buildCssNameMapFromAtomicRules();
|
|
68
|
-
|
|
69
|
-
// 获取baseClassName配置
|
|
70
|
-
const baseClassName = this.config.baseClassName || {};
|
|
71
|
-
|
|
72
|
-
// 更新类名配置
|
|
73
|
-
this.userBaseClass = Object.entries(baseClassName).filter(([k, v]) => typeof v === 'object');
|
|
74
|
-
this.userStaticClass = Object.entries(baseClassName).filter(([k, v]) => typeof v === 'string');
|
|
75
|
-
|
|
76
|
-
// 重建索引和缓存
|
|
77
|
-
this.cssNameMap = cssNameMap;
|
|
78
|
-
this.baseClassNameMap = new Map(Object.entries(baseClassName));
|
|
79
|
-
this.userStaticClassSet = new Set(this.userStaticClass.map(([k]) => k));
|
|
80
|
-
|
|
81
|
-
// 清空共用CSS缓存,确保配置变更时重新读取
|
|
82
|
-
this._commonCssCache = null;
|
|
83
|
-
|
|
84
|
-
// 更新 breakpoints 配置(响应式断点)
|
|
85
|
-
this.updateBreakpoints();
|
|
86
|
-
|
|
87
|
-
this.eventBus.emit('config:references:updated');
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// 更新 breakpoints 配置
|
|
91
|
-
updateBreakpoints() {
|
|
92
|
-
// 默认 Tailwind 断点值
|
|
93
|
-
const defaultBreakpoints = {
|
|
94
|
-
sm: '640px',
|
|
95
|
-
md: '768px',
|
|
96
|
-
lg: '1024px',
|
|
97
|
-
xl: '1280px',
|
|
98
|
-
'2xl': '1536px',
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
// 如果配置中有 breakpoints,则合并(用户配置优先)
|
|
102
|
-
const configBreakpoints = this.config.breakpoints || {};
|
|
103
|
-
this.breakpoints = { ...defaultBreakpoints, ...configBreakpoints };
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// 从atomicRules构建cssName格式的映射
|
|
107
|
-
buildCssNameMapFromAtomicRules() {
|
|
108
|
-
const cssNameMap = new Map();
|
|
109
|
-
const atomicRules = this.config.atomicRules || {};
|
|
110
|
-
|
|
111
|
-
// 遍历所有规则类别
|
|
112
|
-
Object.values(atomicRules).forEach((category) => {
|
|
113
|
-
Object.entries(category).forEach(([className, rule]) => {
|
|
114
|
-
// 转换新格式到旧格式以保持兼容
|
|
115
|
-
const legacyFormat = {
|
|
116
|
-
classArr: rule.properties || [],
|
|
117
|
-
unit: rule.defaultUnit || '',
|
|
118
|
-
skipConversion: rule.skipConversion || false,
|
|
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
|
-
return this.config.system?.
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return this.
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
this.
|
|
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
|
-
this.
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
this.
|
|
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
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
if (!this.config.multiFile) {
|
|
392
|
-
this.config.multiFile = {};
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
if (!this.config.multiFile) {
|
|
404
|
-
this.config.multiFile = {};
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
if (!this.config.multiFile) {
|
|
416
|
-
this.config.multiFile = {};
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
class ConfigManager {
|
|
4
|
+
constructor(eventBus, configPath = './class2css.config.js') {
|
|
5
|
+
this.eventBus = eventBus;
|
|
6
|
+
this.configPath = configPath;
|
|
7
|
+
this.config = null;
|
|
8
|
+
this.importantFlags = null;
|
|
9
|
+
this.cssNameMap = null;
|
|
10
|
+
this.baseClassNameMap = null;
|
|
11
|
+
this.userStaticClassSet = null;
|
|
12
|
+
this.userBaseClass = null;
|
|
13
|
+
this.userStaticClass = null;
|
|
14
|
+
this._fileUtils = null;
|
|
15
|
+
this._logger = null;
|
|
16
|
+
this._commonCssCache = null;
|
|
17
|
+
this.breakpoints = null;
|
|
18
|
+
|
|
19
|
+
this.loadConfig();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
loadConfig() {
|
|
23
|
+
try {
|
|
24
|
+
// 解析绝对路径
|
|
25
|
+
const path = require('path');
|
|
26
|
+
const absoluteConfigPath = path.resolve(this.configPath);
|
|
27
|
+
this.configPath = absoluteConfigPath; // 保存绝对路径
|
|
28
|
+
|
|
29
|
+
// 清除require缓存以确保重新加载
|
|
30
|
+
delete require.cache[require.resolve(absoluteConfigPath)];
|
|
31
|
+
|
|
32
|
+
// 清除样式配置文件的缓存(如果存在)
|
|
33
|
+
try {
|
|
34
|
+
const stylesConfigPath = path.resolve(path.dirname(absoluteConfigPath), 'styles.config.js');
|
|
35
|
+
if (require.cache[stylesConfigPath]) {
|
|
36
|
+
delete require.cache[stylesConfigPath];
|
|
37
|
+
}
|
|
38
|
+
} catch (e) {
|
|
39
|
+
// 样式配置文件不存在或无法解析,忽略
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
this.config = require(absoluteConfigPath);
|
|
43
|
+
|
|
44
|
+
this.updateConfigReferences();
|
|
45
|
+
this.eventBus.emit('config:loaded', this.config);
|
|
46
|
+
|
|
47
|
+
return this.config;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
this.eventBus.emit('config:error', error);
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
updateConfigReferences() {
|
|
55
|
+
// 更新基础配置 - 支持新的system配置结构
|
|
56
|
+
this.baseUnit = this.config.system?.baseUnit || this.config.baseUnit || 'px';
|
|
57
|
+
this.multiFile = this.config.multiFile;
|
|
58
|
+
|
|
59
|
+
// 更新自定义 important 标识
|
|
60
|
+
this.importantFlags = {
|
|
61
|
+
prefix: this.config.importantFlags?.prefix || ['!'],
|
|
62
|
+
suffix: this.config.importantFlags?.suffix || ['_i', '-i'],
|
|
63
|
+
custom: this.config.importantFlags?.custom || [],
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// 从atomicRules构建类名映射
|
|
67
|
+
const cssNameMap = this.buildCssNameMapFromAtomicRules();
|
|
68
|
+
|
|
69
|
+
// 获取baseClassName配置
|
|
70
|
+
const baseClassName = this.config.baseClassName || {};
|
|
71
|
+
|
|
72
|
+
// 更新类名配置
|
|
73
|
+
this.userBaseClass = Object.entries(baseClassName).filter(([k, v]) => typeof v === 'object');
|
|
74
|
+
this.userStaticClass = Object.entries(baseClassName).filter(([k, v]) => typeof v === 'string');
|
|
75
|
+
|
|
76
|
+
// 重建索引和缓存
|
|
77
|
+
this.cssNameMap = cssNameMap;
|
|
78
|
+
this.baseClassNameMap = new Map(Object.entries(baseClassName));
|
|
79
|
+
this.userStaticClassSet = new Set(this.userStaticClass.map(([k]) => k));
|
|
80
|
+
|
|
81
|
+
// 清空共用CSS缓存,确保配置变更时重新读取
|
|
82
|
+
this._commonCssCache = null;
|
|
83
|
+
|
|
84
|
+
// 更新 breakpoints 配置(响应式断点)
|
|
85
|
+
this.updateBreakpoints();
|
|
86
|
+
|
|
87
|
+
this.eventBus.emit('config:references:updated');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 更新 breakpoints 配置
|
|
91
|
+
updateBreakpoints() {
|
|
92
|
+
// 默认 Tailwind 断点值
|
|
93
|
+
const defaultBreakpoints = {
|
|
94
|
+
sm: '640px',
|
|
95
|
+
md: '768px',
|
|
96
|
+
lg: '1024px',
|
|
97
|
+
xl: '1280px',
|
|
98
|
+
'2xl': '1536px',
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// 如果配置中有 breakpoints,则合并(用户配置优先)
|
|
102
|
+
const configBreakpoints = this.config.breakpoints || {};
|
|
103
|
+
this.breakpoints = { ...defaultBreakpoints, ...configBreakpoints };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 从atomicRules构建cssName格式的映射
|
|
107
|
+
buildCssNameMapFromAtomicRules() {
|
|
108
|
+
const cssNameMap = new Map();
|
|
109
|
+
const atomicRules = this.config.atomicRules || {};
|
|
110
|
+
|
|
111
|
+
// 遍历所有规则类别
|
|
112
|
+
Object.values(atomicRules).forEach((category) => {
|
|
113
|
+
Object.entries(category).forEach(([className, rule]) => {
|
|
114
|
+
// 转换新格式到旧格式以保持兼容
|
|
115
|
+
const legacyFormat = {
|
|
116
|
+
classArr: rule.properties || [],
|
|
117
|
+
unit: rule.defaultUnit || '',
|
|
118
|
+
skipConversion: rule.skipConversion || false,
|
|
119
|
+
skipSpecialProcessing: rule.skipSpecialProcessing || false,
|
|
120
|
+
};
|
|
121
|
+
cssNameMap.set(className, legacyFormat);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return cssNameMap;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 配置获取方法
|
|
129
|
+
getConfig() {
|
|
130
|
+
return this.config;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
getImportantFlags() {
|
|
134
|
+
return this.importantFlags;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
getCssNameMap() {
|
|
138
|
+
return this.cssNameMap;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
getBaseClassNameMap() {
|
|
142
|
+
return this.baseClassNameMap;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
getUserStaticClassSet() {
|
|
146
|
+
return this.userStaticClassSet;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
getUserBaseClass() {
|
|
150
|
+
return this.userBaseClass;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
getUserStaticClass() {
|
|
154
|
+
return this.userStaticClass;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
getBaseUnit() {
|
|
158
|
+
return this.baseUnit;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
getMultiFile() {
|
|
162
|
+
return this.multiFile;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* 获取 multiFile.entry 下的所有监听/扫描入口路径(支持多目录/多文件)
|
|
167
|
+
* - 兼容:entry.path 可以是 string 或 string[]
|
|
168
|
+
* - 推荐:entry.paths: string[]
|
|
169
|
+
* - 相对路径以配置文件所在目录为基准解析(而非 process.cwd())
|
|
170
|
+
* @returns {string[]}
|
|
171
|
+
*/
|
|
172
|
+
getMultiFileEntryPaths() {
|
|
173
|
+
const entry = this.multiFile?.entry;
|
|
174
|
+
const pathsValue = entry?.paths ?? entry?.path;
|
|
175
|
+
|
|
176
|
+
// 以配置文件所在目录为基准解析相对路径,确保跨机器/跨工作目录时路径一致
|
|
177
|
+
const configDir = path.dirname(this.configPath);
|
|
178
|
+
const resolvePath = (p) => {
|
|
179
|
+
const trimmed = p.trim();
|
|
180
|
+
return path.isAbsolute(trimmed) ? trimmed : path.resolve(configDir, trimmed);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
if (Array.isArray(pathsValue)) {
|
|
184
|
+
return pathsValue.filter((p) => typeof p === 'string' && p.trim()).map(resolvePath);
|
|
185
|
+
}
|
|
186
|
+
if (typeof pathsValue === 'string' && pathsValue.trim()) {
|
|
187
|
+
return [resolvePath(pathsValue)];
|
|
188
|
+
}
|
|
189
|
+
return [];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
getUnitConversion() {
|
|
193
|
+
return Number(this.config.system?.unitConversion || this.config.unitConversion) || 1;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
getCompression() {
|
|
197
|
+
return this.config.system?.compression || this.config.compression || false;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
getCssFormat() {
|
|
201
|
+
// 获取CSS格式配置,默认返回 'multiLine'
|
|
202
|
+
return this.config.system?.cssFormat || 'multiLine';
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
getSortClasses() {
|
|
206
|
+
// 获取排序配置,默认返回 false
|
|
207
|
+
return this.config.system?.sortClasses || false;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
getBreakpoints() {
|
|
211
|
+
// 获取响应式断点配置
|
|
212
|
+
return this.breakpoints || {};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
getVariants() {
|
|
216
|
+
// 获取变体配置(responsive, states, darkMode 等)
|
|
217
|
+
return this.config.variants || {};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
getOutput() {
|
|
221
|
+
return this.config.output;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// 设置依赖(FileUtils和Logger)
|
|
225
|
+
setDependencies(fileUtils, logger) {
|
|
226
|
+
this._fileUtils = fileUtils;
|
|
227
|
+
this._logger = logger;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// 获取共用CSS文件路径
|
|
231
|
+
getCommonCssPath() {
|
|
232
|
+
// 优先从 multiFile.output.commonCssPath 读取
|
|
233
|
+
let commonCssPath = this.multiFile?.output?.commonCssPath;
|
|
234
|
+
|
|
235
|
+
// 如果没有,尝试从 output.commonCssPath 读取(向后兼容)
|
|
236
|
+
if (!commonCssPath && this.config?.output?.commonCssPath) {
|
|
237
|
+
commonCssPath = this.config.output.commonCssPath;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return commonCssPath || null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 读取共用CSS文件内容
|
|
244
|
+
async getCommonCssContent() {
|
|
245
|
+
// 检查依赖是否已设置
|
|
246
|
+
if (!this._fileUtils || !this._logger) {
|
|
247
|
+
return '';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// 获取共用CSS文件路径
|
|
251
|
+
const commonCssPath = this.getCommonCssPath();
|
|
252
|
+
if (!commonCssPath) {
|
|
253
|
+
return '';
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// 如果缓存存在,直接返回
|
|
257
|
+
if (this._commonCssCache !== null) {
|
|
258
|
+
return this._commonCssCache;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
// 解析路径:支持绝对路径和相对路径
|
|
263
|
+
// 如果是绝对路径,直接使用;如果是相对路径,基于配置文件所在目录解析
|
|
264
|
+
let absolutePath;
|
|
265
|
+
if (path.isAbsolute(commonCssPath)) {
|
|
266
|
+
// 绝对路径:直接使用并规范化
|
|
267
|
+
absolutePath = path.normalize(commonCssPath);
|
|
268
|
+
} else {
|
|
269
|
+
// 相对路径:基于配置文件所在目录解析
|
|
270
|
+
const configDir = path.dirname(this.configPath);
|
|
271
|
+
absolutePath = path.resolve(configDir, commonCssPath);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// 检查文件是否存在
|
|
275
|
+
const exists = await this._fileUtils.fileExists(absolutePath);
|
|
276
|
+
if (!exists) {
|
|
277
|
+
this._logger.warn(`共用CSS文件不存在: ${absolutePath}`);
|
|
278
|
+
this._commonCssCache = '';
|
|
279
|
+
return '';
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// 读取文件内容
|
|
283
|
+
const content = await this._fileUtils.readFile(absolutePath, 'utf-8');
|
|
284
|
+
if (content === null) {
|
|
285
|
+
this._logger.warn(`读取共用CSS文件失败: ${absolutePath}`);
|
|
286
|
+
this._commonCssCache = '';
|
|
287
|
+
return '';
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// 缓存内容
|
|
291
|
+
this._commonCssCache = content;
|
|
292
|
+
this._logger.info(`成功读取共用CSS文件: ${absolutePath} (${content.length} 字符)`);
|
|
293
|
+
return content;
|
|
294
|
+
} catch (error) {
|
|
295
|
+
this._logger.warn(`读取共用CSS文件时出错: ${commonCssPath}`, error.message);
|
|
296
|
+
this._commonCssCache = '';
|
|
297
|
+
return '';
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// 配置验证
|
|
302
|
+
validateConfig() {
|
|
303
|
+
const errors = [];
|
|
304
|
+
|
|
305
|
+
if (!this.config) {
|
|
306
|
+
errors.push('Configuration is null or undefined');
|
|
307
|
+
return errors;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// 检查系统配置
|
|
311
|
+
if (!this.config.system?.baseUnit && !this.config.baseUnit) {
|
|
312
|
+
errors.push('baseUnit configuration is required (either in system.baseUnit or baseUnit)');
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// 检查原子规则配置
|
|
316
|
+
const atomicRules = this.config.atomicRules;
|
|
317
|
+
const baseClassName = this.config.baseClassName;
|
|
318
|
+
|
|
319
|
+
if (!atomicRules || typeof atomicRules !== 'object') {
|
|
320
|
+
errors.push('atomicRules configuration is required and must be an object');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (!baseClassName || typeof baseClassName !== 'object') {
|
|
324
|
+
errors.push('baseClassName configuration is required and must be an object');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (this.config.multiFile) {
|
|
328
|
+
const entry = this.config.multiFile.entry;
|
|
329
|
+
const pathsValue = entry?.paths ?? entry?.path;
|
|
330
|
+
const hasValidString = typeof pathsValue === 'string' && pathsValue.trim().length > 0;
|
|
331
|
+
const hasValidArray =
|
|
332
|
+
Array.isArray(pathsValue) &&
|
|
333
|
+
pathsValue.some((p) => typeof p === 'string' && p.trim().length > 0);
|
|
334
|
+
|
|
335
|
+
if (!hasValidString && !hasValidArray) {
|
|
336
|
+
errors.push('multiFile.entry.path (string|string[]) or multiFile.entry.paths (string[]) is required when multiFile is enabled');
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (this.config.output) {
|
|
341
|
+
if (!this.config.output.path || !this.config.output.fileName) {
|
|
342
|
+
errors.push('output.path and output.fileName are required');
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return errors;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// 配置重载
|
|
350
|
+
async reloadConfig() {
|
|
351
|
+
try {
|
|
352
|
+
this.eventBus.emit('config:reloading');
|
|
353
|
+
this.loadConfig();
|
|
354
|
+
this.eventBus.emit('config:reloaded', this.config);
|
|
355
|
+
return true;
|
|
356
|
+
} catch (error) {
|
|
357
|
+
this.eventBus.emit('config:reload:error', error);
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// 配置信息输出
|
|
363
|
+
getConfigInfo() {
|
|
364
|
+
return {
|
|
365
|
+
userBaseClassCount: this.userBaseClass.length,
|
|
366
|
+
userStaticClassCount: this.userStaticClass.length,
|
|
367
|
+
importantFlags: this.importantFlags,
|
|
368
|
+
baseUnit: this.baseUnit,
|
|
369
|
+
multiFile: !!this.multiFile,
|
|
370
|
+
compression: this.getCompression(),
|
|
371
|
+
unitConversion: this.getUnitConversion(),
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// 运行时覆盖配置
|
|
376
|
+
overrideConfig(overrides) {
|
|
377
|
+
if (!overrides || typeof overrides !== 'object') {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// 确保 config 对象存在
|
|
382
|
+
if (!this.config) {
|
|
383
|
+
this.config = {};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// 覆盖输入目录(multiFile.entry.path)
|
|
387
|
+
if (overrides.inputPath) {
|
|
388
|
+
if (!this.config.multiFile) {
|
|
389
|
+
this.config.multiFile = {};
|
|
390
|
+
}
|
|
391
|
+
if (!this.config.multiFile.entry) {
|
|
392
|
+
this.config.multiFile.entry = {};
|
|
393
|
+
}
|
|
394
|
+
this.config.multiFile.entry.path = overrides.inputPath;
|
|
395
|
+
this.eventBus.emit('config:override:inputPath', overrides.inputPath);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// 覆盖输出目录(multiFile.output.path)
|
|
399
|
+
if (overrides.outputPath) {
|
|
400
|
+
if (!this.config.multiFile) {
|
|
401
|
+
this.config.multiFile = {};
|
|
402
|
+
}
|
|
403
|
+
if (!this.config.multiFile.output) {
|
|
404
|
+
this.config.multiFile.output = {};
|
|
405
|
+
}
|
|
406
|
+
this.config.multiFile.output.path = overrides.outputPath;
|
|
407
|
+
this.eventBus.emit('config:override:outputPath', overrides.outputPath);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// 覆盖输出文件名(multiFile.output.fileName)
|
|
411
|
+
if (overrides.outputFileName) {
|
|
412
|
+
if (!this.config.multiFile) {
|
|
413
|
+
this.config.multiFile = {};
|
|
414
|
+
}
|
|
415
|
+
if (!this.config.multiFile.output) {
|
|
416
|
+
this.config.multiFile.output = {};
|
|
417
|
+
}
|
|
418
|
+
this.config.multiFile.output.fileName = overrides.outputFileName;
|
|
419
|
+
this.eventBus.emit('config:override:outputFileName', overrides.outputFileName);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// 覆盖输出类型(multiFile.output.cssOutType)
|
|
423
|
+
if (overrides.outputType) {
|
|
424
|
+
if (!this.config.multiFile) {
|
|
425
|
+
this.config.multiFile = {};
|
|
426
|
+
}
|
|
427
|
+
if (!this.config.multiFile.output) {
|
|
428
|
+
this.config.multiFile.output = {};
|
|
429
|
+
}
|
|
430
|
+
this.config.multiFile.output.cssOutType = overrides.outputType;
|
|
431
|
+
this.eventBus.emit('config:override:outputType', overrides.outputType);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// 重新更新配置引用
|
|
435
|
+
this.updateConfigReferences();
|
|
436
|
+
this.eventBus.emit('config:overridden', overrides);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
module.exports = ConfigManager;
|