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,133 +1,148 @@
|
|
|
1
|
-
const chokidar = require('chokidar');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
class FileWatcher {
|
|
5
|
-
constructor(eventBus, configManager) {
|
|
6
|
-
this.eventBus = eventBus;
|
|
7
|
-
this.configManager = configManager;
|
|
8
|
-
this.watcher = null;
|
|
9
|
-
this.isWatching = false;
|
|
10
|
-
this.watchedPaths = new Set();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// 启动文件监听
|
|
14
|
-
async startWatching() {
|
|
15
|
-
if (this.isWatching) {
|
|
16
|
-
this.eventBus.emit('watcher:already-running');
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
const multiFile = this.configManager.getMultiFile();
|
|
22
|
-
const entryPaths = this.configManager.getMultiFileEntryPaths();
|
|
23
|
-
if (!multiFile || !multiFile.entry || entryPaths.length === 0) {
|
|
24
|
-
throw new Error('MultiFile configuration is required for file watching');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const fileTypes = multiFile.entry.fileType || ['html', 'wxml'];
|
|
28
|
-
|
|
29
|
-
// 构建监听目标(支持多目录 + 多文件)
|
|
30
|
-
const targets = [];
|
|
31
|
-
for (const p of entryPaths) {
|
|
32
|
-
const normalized = p.replace(/\\/g, '/');
|
|
33
|
-
const ext = path.extname(normalized).slice(1).toLowerCase();
|
|
34
|
-
// 如果看起来是具体文件且扩展名在监听范围内,则直接监听该文件
|
|
35
|
-
if (ext && fileTypes.includes(ext)) {
|
|
36
|
-
targets.push(normalized);
|
|
37
|
-
} else {
|
|
38
|
-
// 当作目录(或未知),监听其下指定类型文件
|
|
39
|
-
for (const type of fileTypes) {
|
|
40
|
-
targets.push(`${normalized}/**/*.${type}`);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// console.log('[FileWatcher] 监听目标:', targets);
|
|
46
|
-
|
|
47
|
-
this.eventBus.emit('watcher:starting', { paths: entryPaths, targets });
|
|
48
|
-
|
|
49
|
-
//
|
|
50
|
-
this.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
usePolling: true
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
this.
|
|
104
|
-
|
|
105
|
-
this.
|
|
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
|
-
|
|
1
|
+
const chokidar = require('chokidar');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
class FileWatcher {
|
|
5
|
+
constructor(eventBus, configManager) {
|
|
6
|
+
this.eventBus = eventBus;
|
|
7
|
+
this.configManager = configManager;
|
|
8
|
+
this.watcher = null;
|
|
9
|
+
this.isWatching = false;
|
|
10
|
+
this.watchedPaths = new Set();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// 启动文件监听
|
|
14
|
+
async startWatching() {
|
|
15
|
+
if (this.isWatching) {
|
|
16
|
+
this.eventBus.emit('watcher:already-running');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const multiFile = this.configManager.getMultiFile();
|
|
22
|
+
const entryPaths = this.configManager.getMultiFileEntryPaths();
|
|
23
|
+
if (!multiFile || !multiFile.entry || entryPaths.length === 0) {
|
|
24
|
+
throw new Error('MultiFile configuration is required for file watching');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const fileTypes = multiFile.entry.fileType || ['html', 'wxml'];
|
|
28
|
+
|
|
29
|
+
// 构建监听目标(支持多目录 + 多文件)
|
|
30
|
+
const targets = [];
|
|
31
|
+
for (const p of entryPaths) {
|
|
32
|
+
const normalized = p.replace(/\\/g, '/');
|
|
33
|
+
const ext = path.extname(normalized).slice(1).toLowerCase();
|
|
34
|
+
// 如果看起来是具体文件且扩展名在监听范围内,则直接监听该文件
|
|
35
|
+
if (ext && fileTypes.includes(ext)) {
|
|
36
|
+
targets.push(normalized);
|
|
37
|
+
} else {
|
|
38
|
+
// 当作目录(或未知),监听其下指定类型文件
|
|
39
|
+
for (const type of fileTypes) {
|
|
40
|
+
targets.push(`${normalized}/**/*.${type}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// console.log('[FileWatcher] 监听目标:', targets);
|
|
46
|
+
|
|
47
|
+
this.eventBus.emit('watcher:starting', { paths: entryPaths, targets });
|
|
48
|
+
|
|
49
|
+
// 监听策略:允许通过 config.system.watch 覆盖,默认保持现有行为(usePolling=true)
|
|
50
|
+
const config = this.configManager.getConfig ? this.configManager.getConfig() : {};
|
|
51
|
+
const watchConfig = (config && config.system && config.system.watch) || {};
|
|
52
|
+
const usePolling =
|
|
53
|
+
typeof watchConfig.usePolling === 'boolean' ? watchConfig.usePolling : true;
|
|
54
|
+
const interval = typeof watchConfig.interval === 'number' ? watchConfig.interval : 150;
|
|
55
|
+
const binaryInterval =
|
|
56
|
+
typeof watchConfig.binaryInterval === 'number' ? watchConfig.binaryInterval : 300;
|
|
57
|
+
const stabilityThreshold =
|
|
58
|
+
typeof watchConfig.stabilityThreshold === 'number'
|
|
59
|
+
? watchConfig.stabilityThreshold
|
|
60
|
+
: 400;
|
|
61
|
+
const pollInterval =
|
|
62
|
+
typeof watchConfig.pollInterval === 'number' ? watchConfig.pollInterval : 100;
|
|
63
|
+
|
|
64
|
+
// 创建文件监听器
|
|
65
|
+
this.watcher = chokidar.watch(targets, {
|
|
66
|
+
ignoreInitial: false,
|
|
67
|
+
persistent: true,
|
|
68
|
+
usePolling,
|
|
69
|
+
interval,
|
|
70
|
+
binaryInterval,
|
|
71
|
+
awaitWriteFinish: {
|
|
72
|
+
// Windows/编辑器保存时可能经历“清空/重写/替换”的瞬时状态,适当加大稳定窗口降低误触发
|
|
73
|
+
stabilityThreshold,
|
|
74
|
+
pollInterval,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// 监听文件变化事件
|
|
79
|
+
this.watcher
|
|
80
|
+
.on('all', (event, filePath) => {
|
|
81
|
+
// console.log(`[FileWatcher] 文件事件: ${event} -> ${filePath}`);
|
|
82
|
+
if (event === 'add') {
|
|
83
|
+
this.eventBus.emit('file:added', filePath);
|
|
84
|
+
this.eventBus.emit('file:changed', filePath);
|
|
85
|
+
} else if (event === 'change') {
|
|
86
|
+
this.eventBus.emit('file:changed', filePath);
|
|
87
|
+
} else if (event === 'unlink') {
|
|
88
|
+
this.eventBus.emit('file:removed', filePath);
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
.on('error', (error) => {
|
|
92
|
+
this.eventBus.emit('watcher:error', error);
|
|
93
|
+
})
|
|
94
|
+
.on('ready', () => {
|
|
95
|
+
this.isWatching = true;
|
|
96
|
+
this.eventBus.emit('watcher:ready', {
|
|
97
|
+
paths: entryPaths,
|
|
98
|
+
targets,
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// 记录监听的路径
|
|
103
|
+
for (const p of entryPaths) this.watchedPaths.add(p);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
this.eventBus.emit('watcher:error', error);
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 停止文件监听
|
|
111
|
+
stopWatching() {
|
|
112
|
+
if (!this.isWatching || !this.watcher) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
this.watcher.close();
|
|
118
|
+
this.watcher = null;
|
|
119
|
+
this.isWatching = false;
|
|
120
|
+
this.watchedPaths.clear();
|
|
121
|
+
|
|
122
|
+
this.eventBus.emit('watcher:stopped');
|
|
123
|
+
} catch (error) {
|
|
124
|
+
this.eventBus.emit('watcher:error', error);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 获取监听状态
|
|
129
|
+
getWatchStats() {
|
|
130
|
+
return {
|
|
131
|
+
isWatching: this.isWatching,
|
|
132
|
+
watchedPaths: Array.from(this.watchedPaths),
|
|
133
|
+
watcherActive: !!this.watcher,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 检查是否正在监听
|
|
138
|
+
isCurrentlyWatching() {
|
|
139
|
+
return this.isWatching && !!this.watcher;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 获取监听的路径列表
|
|
143
|
+
getWatchedPaths() {
|
|
144
|
+
return Array.from(this.watchedPaths);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
module.exports = FileWatcher;
|