jacky-proxy 1.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.
@@ -0,0 +1,337 @@
1
+ /**
2
+ * 配置生成工具
3
+ * 自动扫描目录,发现包含 .mock.ts 文件的文件夹,生成 proxy.config.json 配置文件
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ /**
10
+ * 扫描目录,查找包含 .mock.ts 文件的文件夹
11
+ * @param {string} rootDir - 根目录路径
12
+ * @param {string} basePath - 基础路径(用于生成相对路径)
13
+ * @returns {Array} 包含 Mock 文件的文件夹列表
14
+ */
15
+ function scanForMockFolders(rootDir, basePath = '') {
16
+ const mockFolders = [];
17
+ const visited = new Set();
18
+
19
+ function scanDirectory(dir, relativePath) {
20
+ // 避免重复扫描
21
+ const normalizedPath = path.normalize(dir);
22
+ if (visited.has(normalizedPath)) {
23
+ return;
24
+ }
25
+ visited.add(normalizedPath);
26
+
27
+ if (!fs.existsSync(dir)) {
28
+ return;
29
+ }
30
+
31
+ try {
32
+ const items = fs.readdirSync(dir);
33
+
34
+ let hasMockFiles = false;
35
+ const mockFiles = [];
36
+
37
+ for (const item of items) {
38
+ const itemPath = path.join(dir, item);
39
+ const stat = fs.statSync(itemPath);
40
+
41
+ if (stat.isDirectory()) {
42
+ // 递归扫描子目录
43
+ const subRelativePath = path.join(relativePath, item).replace(/\\/g, '/');
44
+ scanDirectory(itemPath, subRelativePath);
45
+ } else if (item.endsWith('.mock.ts') || item.endsWith('.mock.js')) {
46
+ hasMockFiles = true;
47
+ mockFiles.push(item);
48
+ }
49
+ }
50
+
51
+ // 如果当前目录包含 Mock 文件,添加到列表
52
+ if (hasMockFiles) {
53
+ const folderPath = relativePath || '.';
54
+ const folderName = path.basename(dir) || 'Root';
55
+
56
+ // 检查是否已存在(避免重复)
57
+ const existingIndex = mockFolders.findIndex(f => f.path === folderPath);
58
+ if (existingIndex === -1) {
59
+ mockFolders.push({
60
+ path: folderPath,
61
+ name: folderName,
62
+ mockFiles: mockFiles,
63
+ fullPath: dir
64
+ });
65
+ }
66
+ }
67
+ } catch (error) {
68
+ console.warn(`扫描目录失败: ${dir}`, error.message);
69
+ }
70
+ }
71
+
72
+ scanDirectory(rootDir, basePath);
73
+ return mockFolders;
74
+ }
75
+
76
+ /**
77
+ * 生成配置文件
78
+ * @param {Object} options - 配置选项
79
+ * @param {string} options.rootDir - 扫描的根目录(默认:当前目录)
80
+ * @param {string} options.outputPath - 输出文件路径(默认:proxy.config.json)
81
+ * @param {number} options.libraryId - 库 ID(默认:2773)
82
+ * @param {number} options.startId - 起始 ID(默认:1)
83
+ * @param {Array} options.excludePaths - 要排除的路径(默认:['node_modules', '.git', 'dist'])
84
+ * @returns {Object} 生成的配置对象
85
+ */
86
+ function generateConfig(options = {}) {
87
+ const {
88
+ rootDir = process.cwd(),
89
+ outputPath = path.join(process.cwd(), 'proxy.config.json'),
90
+ libraryId = 2773,
91
+ startId = 1,
92
+ excludePaths = ['node_modules', '.git', 'dist', 'base-data', 'utils', 'config', 'scripts']
93
+ } = options;
94
+
95
+ console.log('\n🔍 开始扫描目录...');
96
+ console.log(`📂 根目录: ${rootDir}`);
97
+
98
+ // 扫描包含 Mock 文件的文件夹
99
+ const mockFolders = scanForMockFolders(rootDir);
100
+
101
+ // 过滤排除的路径
102
+ const filteredFolders = mockFolders.filter(folder => {
103
+ const folderPath = folder.path.toLowerCase();
104
+ return !excludePaths.some(exclude =>
105
+ folderPath.includes(exclude.toLowerCase()) ||
106
+ folder.fullPath.includes(exclude)
107
+ );
108
+ });
109
+
110
+ console.log(`\n✅ 找到 ${filteredFolders.length} 个包含 Mock 文件的文件夹`);
111
+
112
+ // 生成配置对象
113
+ const config = {
114
+ libraryId: libraryId,
115
+ folders: {
116
+ list: filteredFolders.map((folder, index) => ({
117
+ id: startId + index,
118
+ path: folder.path,
119
+ name: folder.name || path.basename(folder.path) || `Mock Folder ${startId + index}`
120
+ }))
121
+ }
122
+ };
123
+
124
+ // 输出信息
125
+ console.log('\n📋 生成的配置:');
126
+ config.folders.list.forEach(folder => {
127
+ console.log(` - ID: ${folder.id}, 路径: ${folder.path}, 名称: ${folder.name}`);
128
+ });
129
+
130
+ // 保存配置文件
131
+ try {
132
+ fs.writeFileSync(outputPath, JSON.stringify(config, null, 2), 'utf-8');
133
+ console.log(`\n✅ 配置文件已保存: ${outputPath}`);
134
+ } catch (error) {
135
+ console.error(`\n❌ 保存配置文件失败:`, error.message);
136
+ throw error;
137
+ }
138
+
139
+ return config;
140
+ }
141
+
142
+ /**
143
+ * 合并现有配置(保留已有的 ID 和配置)
144
+ * @param {Object} existingConfig - 现有配置
145
+ * @param {Object} newConfig - 新扫描的配置
146
+ * @returns {Object} 合并后的配置
147
+ */
148
+ function mergeConfig(existingConfig, newConfig) {
149
+ const existingPaths = new Set(
150
+ existingConfig.folders.list.map(f => f.path)
151
+ );
152
+
153
+ // 保留现有配置
154
+ const mergedList = [...existingConfig.folders.list];
155
+
156
+ // 添加新发现的文件夹
157
+ let nextId = Math.max(...existingConfig.folders.list.map(f => f.id), 0) + 1;
158
+ newConfig.folders.list.forEach(folder => {
159
+ if (!existingPaths.has(folder.path)) {
160
+ mergedList.push({
161
+ ...folder,
162
+ id: nextId++
163
+ });
164
+ }
165
+ });
166
+
167
+ return {
168
+ libraryId: existingConfig.libraryId,
169
+ folders: {
170
+ list: mergedList
171
+ }
172
+ };
173
+ }
174
+
175
+ /**
176
+ * 验证配置文件
177
+ * @param {string} configPath - 配置文件路径
178
+ * @returns {Object} 验证结果
179
+ */
180
+ function validateConfig(configPath) {
181
+ const result = {
182
+ valid: true,
183
+ errors: [],
184
+ warnings: []
185
+ };
186
+
187
+ try {
188
+ if (!fs.existsSync(configPath)) {
189
+ result.valid = false;
190
+ result.errors.push('配置文件不存在');
191
+ return result;
192
+ }
193
+
194
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
195
+
196
+ // 验证结构
197
+ if (!config.folders || !config.folders.list) {
198
+ result.valid = false;
199
+ result.errors.push('配置文件格式错误:缺少 folders.list');
200
+ return result;
201
+ }
202
+
203
+ // 验证每个配置项
204
+ config.folders.list.forEach((folder, index) => {
205
+ if (!folder.id) {
206
+ result.errors.push(`配置项 ${index + 1}: 缺少 id`);
207
+ }
208
+ if (!folder.path) {
209
+ result.errors.push(`配置项 ${index + 1}: 缺少 path`);
210
+ }
211
+
212
+ // 检查路径是否存在
213
+ const fullPath = path.join(path.dirname(configPath), folder.path);
214
+ if (!fs.existsSync(fullPath)) {
215
+ result.warnings.push(`配置项 ${index + 1}: 路径不存在 - ${folder.path}`);
216
+ } else {
217
+ // 检查是否包含 Mock 文件
218
+ const files = fs.readdirSync(fullPath);
219
+ const hasMockFiles = files.some(f =>
220
+ f.endsWith('.mock.ts') || f.endsWith('.mock.js')
221
+ );
222
+ if (!hasMockFiles) {
223
+ result.warnings.push(`配置项 ${index + 1}: 路径下没有 Mock 文件 - ${folder.path}`);
224
+ }
225
+ }
226
+ });
227
+
228
+ result.valid = result.errors.length === 0;
229
+ } catch (error) {
230
+ result.valid = false;
231
+ result.errors.push(`解析配置文件失败: ${error.message}`);
232
+ }
233
+
234
+ return result;
235
+ }
236
+
237
+ // 命令行接口
238
+ if (require.main === module) {
239
+ const args = process.argv.slice(2);
240
+ const command = args[0];
241
+
242
+ if (command === 'generate' || !command) {
243
+ // 生成配置
244
+ const options = {
245
+ rootDir: process.cwd(),
246
+ outputPath: path.join(process.cwd(), 'proxy.config.json'),
247
+ libraryId: 2773,
248
+ startId: 1
249
+ };
250
+
251
+ // 解析命令行参数
252
+ for (let i = 1; i < args.length; i++) {
253
+ const arg = args[i];
254
+ if (arg === '--root' && args[i + 1]) {
255
+ options.rootDir = args[++i];
256
+ } else if (arg === '--output' && args[i + 1]) {
257
+ options.outputPath = args[++i];
258
+ } else if (arg === '--library-id' && args[i + 1]) {
259
+ options.libraryId = parseInt(args[++i]);
260
+ } else if (arg === '--start-id' && args[i + 1]) {
261
+ options.startId = parseInt(args[++i]);
262
+ }
263
+ }
264
+
265
+ try {
266
+ generateConfig(options);
267
+ console.log('\n✨ 配置生成完成!');
268
+ } catch (error) {
269
+ console.error('\n❌ 配置生成失败:', error.message);
270
+ process.exit(1);
271
+ }
272
+ } else if (command === 'validate') {
273
+ // 验证配置
274
+ const configPath = args[1] || path.join(process.cwd(), 'proxy.config.json');
275
+ const result = validateConfig(configPath);
276
+
277
+ if (result.valid) {
278
+ console.log('\n✅ 配置文件验证通过');
279
+ if (result.warnings.length > 0) {
280
+ console.log('\n⚠️ 警告:');
281
+ result.warnings.forEach(w => console.log(` - ${w}`));
282
+ }
283
+ } else {
284
+ console.error('\n❌ 配置文件验证失败:');
285
+ result.errors.forEach(e => console.error(` - ${e}`));
286
+ if (result.warnings.length > 0) {
287
+ console.log('\n⚠️ 警告:');
288
+ result.warnings.forEach(w => console.log(` - ${w}`));
289
+ }
290
+ process.exit(1);
291
+ }
292
+ } else if (command === 'merge') {
293
+ // 合并配置
294
+ const existingPath = path.join(process.cwd(), 'proxy.config.json');
295
+ if (!fs.existsSync(existingPath)) {
296
+ console.error('❌ 现有配置文件不存在');
297
+ process.exit(1);
298
+ }
299
+
300
+ const existingConfig = JSON.parse(fs.readFileSync(existingPath, 'utf-8'));
301
+ const newConfig = generateConfig({ rootDir: process.cwd() });
302
+ const mergedConfig = mergeConfig(existingConfig, newConfig);
303
+
304
+ fs.writeFileSync(existingPath, JSON.stringify(mergedConfig, null, 2), 'utf-8');
305
+ console.log('\n✅ 配置合并完成');
306
+ } else {
307
+ console.log(`
308
+ 用法:
309
+ node scripts/generate-config.js [command] [options]
310
+
311
+ 命令:
312
+ generate 生成配置文件(默认)
313
+ validate 验证配置文件
314
+ merge 合并新发现的配置到现有配置
315
+
316
+ 选项:
317
+ --root <dir> 扫描的根目录(默认:当前目录)
318
+ --output <path> 输出文件路径(默认:proxy.config.json)
319
+ --library-id <id> 库 ID(默认:2773)
320
+ --start-id <id> 起始 ID(默认:1)
321
+
322
+ 示例:
323
+ node scripts/generate-config.js generate
324
+ node scripts/generate-config.js generate --root ./mocks
325
+ node scripts/generate-config.js validate
326
+ node scripts/generate-config.js merge
327
+ `);
328
+ }
329
+ }
330
+
331
+ module.exports = {
332
+ generateConfig,
333
+ validateConfig,
334
+ mergeConfig,
335
+ scanForMockFolders
336
+ };
337
+