css2class 2.0.0
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/API.md +1143 -0
- package/CHANGELOG.md +291 -0
- package/CONFIG.md +1096 -0
- package/CONTRIBUTING.md +571 -0
- package/MIGRATION.md +402 -0
- package/README.md +634 -0
- package/bin/class2css.js +380 -0
- package/class2css.config.js +124 -0
- package/common.css +3 -0
- package/configs/colors.config.js +62 -0
- package/configs/layout.config.js +110 -0
- package/configs/spacing.config.js +37 -0
- package/configs/typography.config.js +41 -0
- package/docs/.vitepress/config.mjs +65 -0
- package/docs/.vitepress/theme/custom.css +74 -0
- package/docs/.vitepress/theme/index.js +7 -0
- package/docs/guide/cli.md +97 -0
- package/docs/guide/concepts.md +63 -0
- package/docs/guide/config-template.md +365 -0
- package/docs/guide/config.md +275 -0
- package/docs/guide/faq.md +202 -0
- package/docs/guide/getting-started.md +83 -0
- package/docs/guide/important-and-static.md +67 -0
- package/docs/guide/incremental.md +162 -0
- package/docs/guide/rules-reference.md +354 -0
- package/docs/guide/units.md +57 -0
- package/docs/index.md +68 -0
- package/package.json +49 -0
- package/run.js +90 -0
- package/src/README.md +571 -0
- package/src/core/CacheManager.js +650 -0
- package/src/core/CompatibilityAdapter.js +264 -0
- package/src/core/ConfigManager.js +431 -0
- package/src/core/ConfigValidator.js +350 -0
- package/src/core/EventBus.js +77 -0
- package/src/core/FullScanManager.js +430 -0
- package/src/core/StateManager.js +631 -0
- package/src/docs/DocsServer.js +179 -0
- package/src/example.js +106 -0
- package/src/generators/DynamicClassGenerator.js +674 -0
- package/src/index.js +1046 -0
- package/src/parsers/ClassParser.js +572 -0
- package/src/parsers/ImportantParser.js +279 -0
- package/src/parsers/RegexCompiler.js +200 -0
- package/src/utils/ClassChangeTracker.js +366 -0
- package/src/utils/ConfigDiagnostics.js +673 -0
- package/src/utils/CssFormatter.js +261 -0
- package/src/utils/FileUtils.js +230 -0
- package/src/utils/Logger.js +150 -0
- package/src/utils/Throttle.js +172 -0
- package/src/utils/UnitProcessor.js +334 -0
- package/src/utils/WxssClassExtractor.js +137 -0
- package/src/watchers/ConfigWatcher.js +413 -0
- package/src/watchers/FileWatcher.js +133 -0
- package/src/writers/FileWriter.js +302 -0
- package/src/writers/UnifiedWriter.js +370 -0
- package/styles.config.js +250 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
const { spawn } = require('child_process');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const net = require('net');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* VitePress 文档服务器管理器
|
|
8
|
+
*/
|
|
9
|
+
class DocsServer {
|
|
10
|
+
constructor(eventBus) {
|
|
11
|
+
this.eventBus = eventBus;
|
|
12
|
+
this.process = null;
|
|
13
|
+
this.port = null;
|
|
14
|
+
this.host = null;
|
|
15
|
+
this.docsDir = path.join(__dirname, '../../docs');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 获取可用端口
|
|
20
|
+
* @param {number} startPort - 起始端口
|
|
21
|
+
* @returns {Promise<number>}
|
|
22
|
+
*/
|
|
23
|
+
async getAvailablePort(startPort = 5173) {
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
const server = net.createServer();
|
|
26
|
+
|
|
27
|
+
server.listen(startPort, () => {
|
|
28
|
+
const port = server.address().port;
|
|
29
|
+
server.close(() => {
|
|
30
|
+
resolve(port);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
server.on('error', (err) => {
|
|
35
|
+
if (err.code === 'EADDRINUSE') {
|
|
36
|
+
// 端口被占用,尝试下一个端口
|
|
37
|
+
try {
|
|
38
|
+
server.close(() => {});
|
|
39
|
+
} catch (_) {}
|
|
40
|
+
this.getAvailablePort(startPort + 1)
|
|
41
|
+
.then(resolve)
|
|
42
|
+
.catch(reject);
|
|
43
|
+
} else {
|
|
44
|
+
try {
|
|
45
|
+
server.close(() => {});
|
|
46
|
+
} catch (_) {}
|
|
47
|
+
reject(err);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 启动 VitePress 开发服务器
|
|
55
|
+
* @param {Object} options - 启动选项
|
|
56
|
+
* @param {number} options.port - 端口号(默认自动寻找)
|
|
57
|
+
* @param {string} options.host - 主机地址(默认 127.0.0.1)
|
|
58
|
+
* @returns {Promise<{port: number, url: string}>}
|
|
59
|
+
*/
|
|
60
|
+
async start(options = {}) {
|
|
61
|
+
if (this.process) {
|
|
62
|
+
throw new Error('Docs server is already running');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const { port: requestedPort = 5173, host = '127.0.0.1' } = options;
|
|
66
|
+
|
|
67
|
+
// 获取可用端口
|
|
68
|
+
this.port = await this.getAvailablePort(requestedPort);
|
|
69
|
+
this.host = host;
|
|
70
|
+
|
|
71
|
+
// 查找 VitePress CLI 脚本
|
|
72
|
+
const vitepressPath = path.join(__dirname, '../../node_modules/vitepress/bin/vitepress.js');
|
|
73
|
+
|
|
74
|
+
// 检查 VitePress 是否已安装
|
|
75
|
+
if (!fs.existsSync(vitepressPath)) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
'VitePress is not installed. Please run: npm install --save-dev vitepress'
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 启动 VitePress dev server
|
|
82
|
+
const args = [
|
|
83
|
+
vitepressPath,
|
|
84
|
+
'dev',
|
|
85
|
+
this.docsDir,
|
|
86
|
+
'--port',
|
|
87
|
+
String(this.port),
|
|
88
|
+
'--host',
|
|
89
|
+
host
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
const cwd = path.join(__dirname, '../..');
|
|
93
|
+
|
|
94
|
+
this.process = spawn(process.execPath, args, {
|
|
95
|
+
stdio: 'inherit',
|
|
96
|
+
cwd,
|
|
97
|
+
env: { ...process.env },
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
this.process.on('error', (error) => {
|
|
101
|
+
this.eventBus?.emit('docs:server:error', { error: error.message });
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
this.process.on('exit', (code) => {
|
|
105
|
+
this.process = null;
|
|
106
|
+
this.eventBus?.emit('docs:server:exited', { code });
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const url = `http://${host}:${this.port}`;
|
|
110
|
+
|
|
111
|
+
// VitePress dev server 启动需要一点时间;这里做一个轻量延迟,避免立刻打开浏览器时失败
|
|
112
|
+
await new Promise((resolve) => setTimeout(resolve, 1200));
|
|
113
|
+
|
|
114
|
+
this.eventBus?.emit('docs:server:started', { port: this.port, host: this.host, url });
|
|
115
|
+
|
|
116
|
+
return { port: this.port, url };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 停止文档服务器
|
|
121
|
+
*/
|
|
122
|
+
async stop() {
|
|
123
|
+
if (!this.process) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return new Promise((resolve) => {
|
|
128
|
+
const timeout = setTimeout(() => {
|
|
129
|
+
if (this.process) {
|
|
130
|
+
try {
|
|
131
|
+
this.process.kill('SIGKILL');
|
|
132
|
+
} catch (_) {}
|
|
133
|
+
}
|
|
134
|
+
resolve();
|
|
135
|
+
}, 5000);
|
|
136
|
+
|
|
137
|
+
this.process.on('exit', () => {
|
|
138
|
+
this.process = null;
|
|
139
|
+
this.eventBus?.emit('docs:server:stopped');
|
|
140
|
+
clearTimeout(timeout);
|
|
141
|
+
resolve();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// 发送终止信号
|
|
145
|
+
if (process.platform === 'win32') {
|
|
146
|
+
// Windows 使用 taskkill
|
|
147
|
+
spawn('taskkill', ['/pid', this.process.pid, '/F', '/T'], {
|
|
148
|
+
stdio: 'ignore',
|
|
149
|
+
});
|
|
150
|
+
} else {
|
|
151
|
+
// Unix-like 系统使用 kill
|
|
152
|
+
try {
|
|
153
|
+
this.process.kill('SIGTERM');
|
|
154
|
+
} catch (_) {}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 检查服务器是否运行中
|
|
161
|
+
* @returns {boolean}
|
|
162
|
+
*/
|
|
163
|
+
isRunning() {
|
|
164
|
+
return this.process !== null && this.process.exitCode === null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 获取服务器 URL
|
|
169
|
+
* @returns {string|null}
|
|
170
|
+
*/
|
|
171
|
+
getUrl() {
|
|
172
|
+
if (!this.port || !this.host) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
return `http://${this.host}:${this.port}`;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
module.exports = DocsServer;
|
package/src/example.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Class2CSS 模块化版本使用示例
|
|
2
|
+
const Class2CSS = require('./index');
|
|
3
|
+
|
|
4
|
+
async function example() {
|
|
5
|
+
try {
|
|
6
|
+
// 创建 Class2CSS 实例
|
|
7
|
+
const class2css = new Class2CSS({
|
|
8
|
+
configPath: './class2css.config.js',
|
|
9
|
+
cacheSize: 1000,
|
|
10
|
+
logger: {
|
|
11
|
+
level: 'info',
|
|
12
|
+
enableDebug: true,
|
|
13
|
+
enableTimestamp: true,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// 获取事件总线进行监听
|
|
18
|
+
const eventBus = class2css.getEventBus();
|
|
19
|
+
|
|
20
|
+
// 监听重要事件
|
|
21
|
+
eventBus.on('class2css:started', () => {
|
|
22
|
+
console.log('Class2CSS started successfully!');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
eventBus.on('parser:completed', (stats) => {
|
|
26
|
+
// console.log(`Parsing completed: ${stats.totalCount} classes found`);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
eventBus.on('generator:dynamic:completed', (stats) => {
|
|
30
|
+
console.log(`Dynamic CSS generated: ${stats.generatedCount} classes`);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// 启动 Class2CSS
|
|
34
|
+
await class2css.start();
|
|
35
|
+
|
|
36
|
+
// 获取状态信息
|
|
37
|
+
const status = class2css.getStatus();
|
|
38
|
+
console.log('Class2CSS Status:', JSON.stringify(status, null, 2));
|
|
39
|
+
|
|
40
|
+
// 模拟文件变更处理
|
|
41
|
+
await class2css.handleFileChange('./example.html');
|
|
42
|
+
|
|
43
|
+
// 获取模块进行高级操作
|
|
44
|
+
const modules = class2css.getModules();
|
|
45
|
+
|
|
46
|
+
// 示例:直接使用解析器
|
|
47
|
+
const htmlContent = '<div class="w-100 h-50 bg-red text-white">Hello World</div>';
|
|
48
|
+
const parseResult = modules.classParser.parseClassOptimized(htmlContent);
|
|
49
|
+
console.log('Parse result:', parseResult);
|
|
50
|
+
|
|
51
|
+
// 示例:直接使用生成器
|
|
52
|
+
const generateResult = modules.dynamicClassGenerator.getClassList(parseResult.classArr);
|
|
53
|
+
console.log('Generated CSS length:', generateResult.cssStr.length);
|
|
54
|
+
|
|
55
|
+
// 停止 Class2CSS
|
|
56
|
+
class2css.stop();
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error('Example failed:', error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 高级用法示例
|
|
63
|
+
function advancedExample() {
|
|
64
|
+
const class2css = new Class2CSS();
|
|
65
|
+
const modules = class2css.getModules();
|
|
66
|
+
|
|
67
|
+
// 直接使用各个模块
|
|
68
|
+
const { logger, importantParser, regexCompiler } = modules;
|
|
69
|
+
|
|
70
|
+
// 测试 Important 标识
|
|
71
|
+
const testClasses = ['w-100', '!w-100', 'w-100_i', 'w-100-important'];
|
|
72
|
+
const importantResults = importantParser.batchProcessImportant(testClasses);
|
|
73
|
+
console.log('Important test results:', importantResults);
|
|
74
|
+
|
|
75
|
+
// 测试正则表达式
|
|
76
|
+
const regexStats = regexCompiler.getRegexStats();
|
|
77
|
+
console.log('Regex stats:', regexStats);
|
|
78
|
+
|
|
79
|
+
// 设置日志级别
|
|
80
|
+
logger.setLevel('debug');
|
|
81
|
+
logger.setDebugMode(true);
|
|
82
|
+
|
|
83
|
+
// 监听特定事件
|
|
84
|
+
const eventBus = class2css.getEventBus();
|
|
85
|
+
eventBus.on('important:detected', (data) => {
|
|
86
|
+
console.log('Important flag detected:', data);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
eventBus.on('parser:static:found', (data) => {
|
|
90
|
+
console.log('Static class found:', data);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 运行示例
|
|
95
|
+
if (require.main === module) {
|
|
96
|
+
console.log('Running Class2CSS module example...');
|
|
97
|
+
example()
|
|
98
|
+
.then(() => {
|
|
99
|
+
console.log('Example completed');
|
|
100
|
+
})
|
|
101
|
+
.catch((error) => {
|
|
102
|
+
console.error('Example error:', error);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = { example, advancedExample };
|