flu-cli 0.0.5 → 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/CLI.md +349 -0
- package/README.md +59 -276
- package/config/dev.config.js +56 -0
- package/config/templates.js +147 -0
- package/index.js +128 -81
- package/lib/commands/add.js +472 -0
- package/lib/commands/cache.js +99 -0
- package/lib/commands/completion.js +94 -0
- package/lib/commands/generate.js +26 -0
- package/lib/commands/newClack.js +396 -0
- package/lib/commands/snippets.js +39 -0
- package/lib/commands/templates.js +84 -0
- package/lib/generators/component_generator.js +93 -0
- package/lib/generators/model_generator.js +303 -0
- package/lib/generators/module_generator.js +141 -0
- package/lib/generators/page_generator.js +322 -0
- package/lib/generators/project_generator.js +96 -0
- package/lib/generators/service_generator.js +408 -0
- package/lib/generators/state_manager_generator.js +402 -0
- package/lib/generators/viewmodel_generator.js +115 -0
- package/lib/generators/widget_generator.js +104 -0
- package/lib/templates/templateCopier.js +296 -0
- package/lib/templates/templateManager.js +191 -0
- package/lib/utils/config.js +99 -0
- package/lib/utils/flutterHelper.js +85 -0
- package/lib/utils/index_updater.js +69 -0
- package/lib/utils/logger.js +57 -0
- package/lib/utils/project_detector.js +227 -0
- package/lib/utils/snippet_loader.js +32 -0
- package/lib/utils/string_helper.js +56 -0
- package/lib/utils/templateSelectorEnquirer.js +200 -0
- package/package.json +31 -6
- package/release.sh +107 -0
- package/scripts/e2e-state-tests.js +116 -0
- package/scripts/sync-base-to-templates.js +108 -0
- package/scripts/workspace-clone-all.sh +101 -0
- package/scripts/workspace-status-all.sh +112 -0
- package/templates/README.md +138 -0
- package/templates/base_files/base_list_page.dart.template +174 -0
- package/templates/base_files/base_list_viewmodel.dart.template +134 -0
- package/templates/base_files/base_page.dart.template +251 -0
- package/templates/base_files/base_viewmodel.dart.template +77 -0
- package/templates/base_files/theme/status_views_theme.dart.template +46 -0
- package/templates/snippets/dart.code-snippets +487 -0
- package/lib/createProject.js +0 -220
- package/lib/flutterProjectCreator.js +0 -80
- package/lib/libCopier.js +0 -368
- package/lib/userInteraction.js +0 -274
- package/lib/utils.js +0 -200
- package/publish.sh +0 -29
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* add 命令 - 添加组件
|
|
3
|
+
* 生成页面、Widget、Component、ViewModel 等
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
import { generatePage } from '../generators/page_generator.js';
|
|
8
|
+
import { generateWidget } from '../generators/widget_generator.js';
|
|
9
|
+
import { generateComponent } from '../generators/component_generator.js';
|
|
10
|
+
import { generateViewModel } from '../generators/viewmodel_generator.js';
|
|
11
|
+
import { generateService } from '../generators/service_generator.js';
|
|
12
|
+
import { generateModel } from '../generators/model_generator.js';
|
|
13
|
+
import { generateModule } from '../generators/module_generator.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 添加组件
|
|
17
|
+
*/
|
|
18
|
+
export async function addComponent (type, name, options) {
|
|
19
|
+
// 处理 --list 参数
|
|
20
|
+
if (options.list || (type === '--list')) {
|
|
21
|
+
await printSupportedTypes();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!type || !name) {
|
|
26
|
+
logger.error('请指定类型和名称');
|
|
27
|
+
await printSupportedTypes();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
logger.title(`📝 添加 ${type}: ${name}`);
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
// 处理别名
|
|
35
|
+
const typeMap = {
|
|
36
|
+
'p': 'page',
|
|
37
|
+
'w': 'widget',
|
|
38
|
+
'c': 'component',
|
|
39
|
+
'v': 'viewmodel',
|
|
40
|
+
'vm': 'viewmodel',
|
|
41
|
+
's': 'service',
|
|
42
|
+
'm': 'model',
|
|
43
|
+
'mod': 'module'
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const normalizedType = typeMap[type.toLowerCase()] || type.toLowerCase();
|
|
47
|
+
|
|
48
|
+
switch (normalizedType) {
|
|
49
|
+
case 'page':
|
|
50
|
+
await addPage(name, options);
|
|
51
|
+
break;
|
|
52
|
+
|
|
53
|
+
case 'widget':
|
|
54
|
+
await addWidget(name, options);
|
|
55
|
+
break;
|
|
56
|
+
|
|
57
|
+
case 'component':
|
|
58
|
+
await addComponentItem(name, options);
|
|
59
|
+
break;
|
|
60
|
+
|
|
61
|
+
case 'viewmodel':
|
|
62
|
+
await addViewModel(name, options);
|
|
63
|
+
break;
|
|
64
|
+
|
|
65
|
+
case 'service':
|
|
66
|
+
await addService(name, options);
|
|
67
|
+
break;
|
|
68
|
+
|
|
69
|
+
case 'model':
|
|
70
|
+
await addModel(name, options);
|
|
71
|
+
break;
|
|
72
|
+
|
|
73
|
+
case 'module':
|
|
74
|
+
await addModule(name, options);
|
|
75
|
+
break;
|
|
76
|
+
|
|
77
|
+
default:
|
|
78
|
+
logger.error(`未知的类型: ${type}`);
|
|
79
|
+
logger.info('支持的类型: page (p), widget (w), component (c), vm (v), service (s), model (m), module (mod)');
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
} catch (error) {
|
|
84
|
+
logger.error(`生成失败: ${error.message}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 添加页面
|
|
90
|
+
*/
|
|
91
|
+
async function addPage (name, options) {
|
|
92
|
+
const {
|
|
93
|
+
feature = null,
|
|
94
|
+
stateful = false,
|
|
95
|
+
stateless = false,
|
|
96
|
+
noVm = false,
|
|
97
|
+
listPage = false
|
|
98
|
+
} = options;
|
|
99
|
+
|
|
100
|
+
logger.info(`生成页面: ${name}`);
|
|
101
|
+
if (feature) {
|
|
102
|
+
logger.info(`功能模块: ${feature}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (listPage) {
|
|
106
|
+
logger.info(`类型: 列表页 (BaseListPage)`);
|
|
107
|
+
} else if (stateless) {
|
|
108
|
+
logger.info(`强制类型: StatelessWidget`);
|
|
109
|
+
} else if (stateful) {
|
|
110
|
+
logger.info(`类型: StatefulWidget`);
|
|
111
|
+
}
|
|
112
|
+
if (noVm) {
|
|
113
|
+
logger.info(`不生成 ViewModel`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const success = generatePage(name, {
|
|
117
|
+
feature,
|
|
118
|
+
stateful,
|
|
119
|
+
stateless,
|
|
120
|
+
withViewModel: !noVm,
|
|
121
|
+
isListPage: listPage,
|
|
122
|
+
outputDir: process.cwd()
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (success) {
|
|
126
|
+
logger.newLine();
|
|
127
|
+
logger.success('✅ 页面生成完成!');
|
|
128
|
+
logger.newLine();
|
|
129
|
+
|
|
130
|
+
logger.info('下一步:');
|
|
131
|
+
if (feature) {
|
|
132
|
+
console.log(` 1. 在 lib/features/${feature}/pages/${name}_page.dart 中实现页面逻辑`);
|
|
133
|
+
if (!noVm) {
|
|
134
|
+
console.log(` 2. 在 lib/features/${feature}/viewmodels/${name}_viewmodel.dart 中实现业务逻辑`);
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
console.log(` 1. 在 lib/pages/${name}_page.dart 中实现页面逻辑`);
|
|
138
|
+
if (!noVm) {
|
|
139
|
+
console.log(` 2. 在 lib/viewmodels/${name}_viewmodel.dart 中实现业务逻辑`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
console.log(` ${noVm ? 2 : 3}. 在路由中注册新页面`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 添加 Widget
|
|
148
|
+
*/
|
|
149
|
+
async function addWidget (name, options) {
|
|
150
|
+
const {
|
|
151
|
+
feature = null,
|
|
152
|
+
stateful = false
|
|
153
|
+
} = options;
|
|
154
|
+
|
|
155
|
+
logger.info(`生成 Widget: ${name}`);
|
|
156
|
+
if (feature) {
|
|
157
|
+
logger.info(`功能模块: ${feature}`);
|
|
158
|
+
}
|
|
159
|
+
if (stateful) {
|
|
160
|
+
logger.info(`类型: StatefulWidget`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const success = generateWidget(name, {
|
|
164
|
+
feature,
|
|
165
|
+
stateful,
|
|
166
|
+
outputDir: process.cwd()
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
if (success) {
|
|
170
|
+
logger.newLine();
|
|
171
|
+
logger.success('✅ Widget 生成完成!');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* 添加 Component
|
|
177
|
+
*/
|
|
178
|
+
async function addComponentItem (name, options) {
|
|
179
|
+
const {
|
|
180
|
+
feature = null
|
|
181
|
+
} = options;
|
|
182
|
+
|
|
183
|
+
logger.info(`生成 Component: ${name}`);
|
|
184
|
+
if (feature) {
|
|
185
|
+
logger.info(`功能模块: ${feature}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const success = generateComponent(name, {
|
|
189
|
+
feature,
|
|
190
|
+
outputDir: process.cwd()
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
if (success) {
|
|
194
|
+
logger.newLine();
|
|
195
|
+
logger.success('✅ Component 生成完成!');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* 添加 ViewModel
|
|
201
|
+
*/
|
|
202
|
+
async function addViewModel (name, options) {
|
|
203
|
+
const {
|
|
204
|
+
feature = null
|
|
205
|
+
} = options;
|
|
206
|
+
|
|
207
|
+
logger.info(`生成 ViewModel: ${name}`);
|
|
208
|
+
if (feature) {
|
|
209
|
+
logger.info(`功能模块: ${feature}`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const success = generateViewModel(name, {
|
|
213
|
+
feature,
|
|
214
|
+
outputDir: process.cwd()
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
if (success) {
|
|
218
|
+
logger.newLine();
|
|
219
|
+
logger.success('✅ ViewModel 生成完成!');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* 添加 Service
|
|
225
|
+
*/
|
|
226
|
+
async function addService (name, options) {
|
|
227
|
+
const {
|
|
228
|
+
feature = null,
|
|
229
|
+
type = 'api'
|
|
230
|
+
} = options;
|
|
231
|
+
|
|
232
|
+
logger.info(`生成 Service: ${name}`);
|
|
233
|
+
if (feature) {
|
|
234
|
+
logger.info(`功能模块: ${feature}`);
|
|
235
|
+
}
|
|
236
|
+
logger.info(`类型: ${type}`);
|
|
237
|
+
|
|
238
|
+
const success = generateService(name, {
|
|
239
|
+
feature,
|
|
240
|
+
type,
|
|
241
|
+
outputDir: process.cwd()
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
if (success) {
|
|
245
|
+
logger.newLine();
|
|
246
|
+
logger.success('✅ Service 生成完成!');
|
|
247
|
+
logger.newLine();
|
|
248
|
+
|
|
249
|
+
if (type === 'api') {
|
|
250
|
+
logger.info('提示: 记得在 pubspec.yaml 中添加 http 依赖');
|
|
251
|
+
console.log(' dependencies:');
|
|
252
|
+
console.log(' http: ^1.1.0');
|
|
253
|
+
} else if (type === 'storage' || type === 'auth') {
|
|
254
|
+
logger.info('提示: 记得在 pubspec.yaml 中添加 shared_preferences 依赖');
|
|
255
|
+
console.log(' dependencies:');
|
|
256
|
+
console.log(' shared_preferences: ^2.2.0');
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* 添加 Model
|
|
263
|
+
*/
|
|
264
|
+
async function addModel (name, options) {
|
|
265
|
+
const {
|
|
266
|
+
feature = null,
|
|
267
|
+
json = null
|
|
268
|
+
} = options;
|
|
269
|
+
|
|
270
|
+
logger.info(`生成 Model: ${name}`);
|
|
271
|
+
if (feature) {
|
|
272
|
+
logger.info(`功能模块: ${feature}`);
|
|
273
|
+
}
|
|
274
|
+
if (json) {
|
|
275
|
+
logger.info(`从 JSON 文件生成: ${json}`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const success = generateModel(name, {
|
|
279
|
+
feature,
|
|
280
|
+
jsonFile: json,
|
|
281
|
+
outputDir: process.cwd()
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
if (success) {
|
|
285
|
+
logger.newLine();
|
|
286
|
+
logger.success('✅ Model 生成完成!');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* 添加模块
|
|
292
|
+
*/
|
|
293
|
+
async function addModule (name, options) {
|
|
294
|
+
logger.info(`生成模块: ${name}`);
|
|
295
|
+
|
|
296
|
+
const success = generateModule(name, {
|
|
297
|
+
outputDir: process.cwd()
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
if (!success) {
|
|
301
|
+
logger.error('模块创建失败');
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* 打印支持的类型列表
|
|
307
|
+
*/
|
|
308
|
+
async function printSupportedTypes () {
|
|
309
|
+
const chalk = (await import('chalk')).default;
|
|
310
|
+
|
|
311
|
+
console.log(chalk.bold.cyan('\n📦 flu-cli add - 代码生成工具\n'));
|
|
312
|
+
console.log(chalk.gray('用于快速生成 Flutter 项目中的各种代码组件\n'));
|
|
313
|
+
|
|
314
|
+
// 基本用法
|
|
315
|
+
console.log(chalk.bold.yellow('📖 基本用法:'));
|
|
316
|
+
console.log(chalk.white(' flu-cli add <type> <name> [options]\n'));
|
|
317
|
+
|
|
318
|
+
// 支持的类型
|
|
319
|
+
console.log(chalk.bold.yellow('🎯 支持的组件类型:\n'));
|
|
320
|
+
|
|
321
|
+
const types = [
|
|
322
|
+
{
|
|
323
|
+
name: 'page',
|
|
324
|
+
emoji: '📄',
|
|
325
|
+
desc: '页面组件',
|
|
326
|
+
detail: '生成完整的页面文件 (Page + ViewModel)',
|
|
327
|
+
options: [
|
|
328
|
+
'-f, --feature <name> 指定功能模块',
|
|
329
|
+
'--stateful 创建 StatefulWidget',
|
|
330
|
+
'--stateless 强制创建 StatelessWidget',
|
|
331
|
+
'--list-page 创建列表页 (BaseListPage)',
|
|
332
|
+
'--no-vm 不生成 ViewModel'
|
|
333
|
+
],
|
|
334
|
+
examples: [
|
|
335
|
+
'flu-cli add page home',
|
|
336
|
+
'flu-cli add page login --feature auth',
|
|
337
|
+
'flu-cli add page profile --stateful --no-vm'
|
|
338
|
+
]
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
name: 'widget',
|
|
342
|
+
emoji: '🧩',
|
|
343
|
+
desc: '通用组件',
|
|
344
|
+
detail: '生成可复用的 Widget 组件',
|
|
345
|
+
options: [
|
|
346
|
+
'-f, --feature <name> 指定功能模块',
|
|
347
|
+
'--stateful 创建 StatefulWidget'
|
|
348
|
+
],
|
|
349
|
+
examples: [
|
|
350
|
+
'flu-cli add widget custom_button',
|
|
351
|
+
'flu-cli add widget user_avatar --stateful'
|
|
352
|
+
]
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
name: 'component',
|
|
356
|
+
emoji: '🔧',
|
|
357
|
+
desc: '业务组件',
|
|
358
|
+
detail: '生成特定业务场景的组件',
|
|
359
|
+
options: [
|
|
360
|
+
'-f, --feature <name> 指定功能模块'
|
|
361
|
+
],
|
|
362
|
+
examples: [
|
|
363
|
+
'flu-cli add component product_card',
|
|
364
|
+
'flu-cli add component order_item --feature shop'
|
|
365
|
+
]
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
name: 'vm / viewmodel',
|
|
369
|
+
emoji: '🎮',
|
|
370
|
+
desc: '视图模型',
|
|
371
|
+
detail: '生成独立的 ViewModel 文件',
|
|
372
|
+
options: [
|
|
373
|
+
'-f, --feature <name> 指定功能模块'
|
|
374
|
+
],
|
|
375
|
+
examples: [
|
|
376
|
+
'flu-cli add vm settings',
|
|
377
|
+
'flu-cli add viewmodel user --feature auth'
|
|
378
|
+
]
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
name: 'service',
|
|
382
|
+
emoji: '⚙️',
|
|
383
|
+
desc: '服务层',
|
|
384
|
+
detail: '生成 API、存储、认证等服务',
|
|
385
|
+
options: [
|
|
386
|
+
'-f, --feature <name> 指定功能模块',
|
|
387
|
+
'--type <type> 服务类型: api, storage, auth (默认: api)'
|
|
388
|
+
],
|
|
389
|
+
examples: [
|
|
390
|
+
'flu-cli add service user --type api',
|
|
391
|
+
'flu-cli add service cache --type storage',
|
|
392
|
+
'flu-cli add service auth --type auth --feature user'
|
|
393
|
+
]
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
name: 'model',
|
|
397
|
+
emoji: '📊',
|
|
398
|
+
desc: '数据模型',
|
|
399
|
+
detail: '生成数据模型类',
|
|
400
|
+
options: [
|
|
401
|
+
'-f, --feature <name> 指定功能模块',
|
|
402
|
+
'--json <file> 从 JSON 文件生成'
|
|
403
|
+
],
|
|
404
|
+
examples: [
|
|
405
|
+
'flu-cli add model user',
|
|
406
|
+
'flu-cli add model product --json ./data/product.json'
|
|
407
|
+
]
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
name: 'module',
|
|
411
|
+
emoji: '📦',
|
|
412
|
+
desc: '完整模块',
|
|
413
|
+
detail: '生成包含多个文件的完整功能模块',
|
|
414
|
+
options: [],
|
|
415
|
+
examples: [
|
|
416
|
+
'flu-cli add module shop',
|
|
417
|
+
'flu-cli add module user_profile'
|
|
418
|
+
]
|
|
419
|
+
}
|
|
420
|
+
];
|
|
421
|
+
|
|
422
|
+
types.forEach((t, index) => {
|
|
423
|
+
// 类型名称和描述
|
|
424
|
+
console.log(chalk.bold.green(` ${t.emoji} ${t.name}`));
|
|
425
|
+
console.log(chalk.gray(` ${t.detail}`));
|
|
426
|
+
|
|
427
|
+
// 可用选项
|
|
428
|
+
if (t.options.length > 0) {
|
|
429
|
+
console.log(chalk.cyan(' 选项:'));
|
|
430
|
+
t.options.forEach(opt => {
|
|
431
|
+
console.log(chalk.gray(` ${opt}`));
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// 使用示例
|
|
436
|
+
if (t.examples.length > 0) {
|
|
437
|
+
console.log(chalk.cyan(' 示例:'));
|
|
438
|
+
t.examples.forEach(ex => {
|
|
439
|
+
console.log(chalk.white(` ${ex}`));
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// 添加分隔线(最后一项除外)
|
|
444
|
+
if (index < types.length - 1) {
|
|
445
|
+
console.log('');
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
// 通用选项
|
|
450
|
+
console.log(chalk.bold.yellow('\n⚡ 通用选项:\n'));
|
|
451
|
+
console.log(chalk.white(' --list 查看此帮助信息'));
|
|
452
|
+
console.log(chalk.white(' -f, --feature <name> 指定功能模块(modular/clean 架构)\n'));
|
|
453
|
+
|
|
454
|
+
// 快速开始
|
|
455
|
+
console.log(chalk.bold.yellow('🚀 快速开始:\n'));
|
|
456
|
+
console.log(chalk.white(' # 查看所有支持的类型'));
|
|
457
|
+
console.log(chalk.gray(' flu-cli add --list\n'));
|
|
458
|
+
console.log(chalk.white(' # 创建一个简单页面'));
|
|
459
|
+
console.log(chalk.gray(' flu-cli add page home\n'));
|
|
460
|
+
console.log(chalk.white(' # 创建带功能模块的页面'));
|
|
461
|
+
console.log(chalk.gray(' flu-cli add page login --feature auth\n'));
|
|
462
|
+
console.log(chalk.white(' # 创建一个 API 服务'));
|
|
463
|
+
console.log(chalk.gray(' flu-cli add service user --type api\n'));
|
|
464
|
+
|
|
465
|
+
// 提示信息
|
|
466
|
+
console.log(chalk.bold.cyan('💡 提示:\n'));
|
|
467
|
+
console.log(chalk.gray(' • 支持简写: p(page), w(widget), c(component), v(vm), s(service), m(model)'));
|
|
468
|
+
console.log(chalk.gray(' • 使用 -f 或 --feature 可将组件生成到指定功能模块下'));
|
|
469
|
+
console.log(chalk.gray(' • page 类型默认会同时生成 ViewModel,使用 --no-vm 可禁用'));
|
|
470
|
+
console.log(chalk.gray(' • 更多帮助请运行: flu-cli add --help\n'));
|
|
471
|
+
}
|
|
472
|
+
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 缓存管理命令
|
|
3
|
+
* 更新和清理模板缓存
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { logger } from '../utils/logger.js';
|
|
7
|
+
import { getAllTemplates } from '../../config/templates.js';
|
|
8
|
+
import { cloneOrUpdateTemplate, getTemplateCachePath, checkTemplateUpdate } from '../templates/templateManager.js';
|
|
9
|
+
import fsExtra from 'fs-extra';
|
|
10
|
+
import ora from 'ora';
|
|
11
|
+
|
|
12
|
+
const { removeSync, existsSync } = fsExtra;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 更新模板缓存
|
|
16
|
+
*/
|
|
17
|
+
export async function updateTemplates (templateName, options = {}) {
|
|
18
|
+
logger.title('🔄 更新模板缓存');
|
|
19
|
+
|
|
20
|
+
if (templateName) {
|
|
21
|
+
// 更新指定模板
|
|
22
|
+
await updateSingleTemplate(templateName, options);
|
|
23
|
+
} else {
|
|
24
|
+
// 更新所有模板
|
|
25
|
+
const templates = getAllTemplates();
|
|
26
|
+
|
|
27
|
+
for (const template of templates) {
|
|
28
|
+
await updateSingleTemplate(template.name.toLowerCase(), options);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
logger.newLine();
|
|
33
|
+
logger.success('模板更新完成');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 更新单个模板
|
|
38
|
+
*/
|
|
39
|
+
async function updateSingleTemplate (templateName, options = {}) {
|
|
40
|
+
const templates = getAllTemplates();
|
|
41
|
+
const template = templates.find(t => t.name.toLowerCase() === templateName);
|
|
42
|
+
|
|
43
|
+
if (!template) {
|
|
44
|
+
logger.error(`模板 "${templateName}" 不存在`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
logger.info(`检查模板 ${template.displayName}...`);
|
|
49
|
+
|
|
50
|
+
const updateInfo = await checkTemplateUpdate(templateName);
|
|
51
|
+
|
|
52
|
+
// 更新模板
|
|
53
|
+
const spinner = ora(`更新 ${template.displayName}...`).start();
|
|
54
|
+
|
|
55
|
+
const result = await cloneOrUpdateTemplate(
|
|
56
|
+
templateName,
|
|
57
|
+
template.repo,
|
|
58
|
+
template.branch,
|
|
59
|
+
true
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (result) {
|
|
63
|
+
spinner.succeed(`${template.displayName} 更新成功`);
|
|
64
|
+
} else {
|
|
65
|
+
spinner.fail(`${template.displayName} 更新失败`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 清理缓存
|
|
71
|
+
*/
|
|
72
|
+
export async function cleanCache () {
|
|
73
|
+
logger.title('🗑️ 清理模板缓存');
|
|
74
|
+
|
|
75
|
+
const templates = getAllTemplates();
|
|
76
|
+
let cleaned = 0;
|
|
77
|
+
|
|
78
|
+
for (const template of templates) {
|
|
79
|
+
const templateName = template.name.toLowerCase();
|
|
80
|
+
const cachePath = getTemplateCachePath(templateName);
|
|
81
|
+
|
|
82
|
+
if (existsSync(cachePath)) {
|
|
83
|
+
try {
|
|
84
|
+
removeSync(cachePath);
|
|
85
|
+
logger.success(`已清理: ${template.displayName}`);
|
|
86
|
+
cleaned++;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
logger.error(`清理失败: ${template.displayName} - ${error.message}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
logger.newLine();
|
|
94
|
+
if (cleaned > 0) {
|
|
95
|
+
logger.success(`已清理 ${cleaned} 个模板缓存`);
|
|
96
|
+
} else {
|
|
97
|
+
logger.info('没有需要清理的缓存');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 生成 Shell 自动补全脚本
|
|
5
|
+
*/
|
|
6
|
+
export function completion () {
|
|
7
|
+
const script = `
|
|
8
|
+
###-begin-flu-cli-completion-###
|
|
9
|
+
#
|
|
10
|
+
# flu-cli command completion script
|
|
11
|
+
#
|
|
12
|
+
# Installation: flu-cli completion >> ~/.zshrc (or ~/.bashrc)
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
if type compdef &>/dev/null; then
|
|
16
|
+
_flu_cli_completion() {
|
|
17
|
+
local -a commands
|
|
18
|
+
commands=(
|
|
19
|
+
'new:创建新 Flutter 项目'
|
|
20
|
+
'n:创建新 Flutter 项目 (new 别名)'
|
|
21
|
+
'add:添加组件 (page, widget, etc.)'
|
|
22
|
+
'a:添加组件 (add 别名)'
|
|
23
|
+
'templates:管理模板'
|
|
24
|
+
't:管理模板 (templates 别名)'
|
|
25
|
+
'generate-sm:生成状态管理代码'
|
|
26
|
+
'g:生成状态管理代码 (generate-sm 别名)'
|
|
27
|
+
'update-templates:更新模板缓存'
|
|
28
|
+
'u:更新模板缓存 (update-templates 别名)'
|
|
29
|
+
'cache:管理缓存'
|
|
30
|
+
'c:管理缓存 (cache 别名)'
|
|
31
|
+
'sync-snippets:同步标准代码片段'
|
|
32
|
+
'sync:同步标准代码片段 (sync-snippets 别名)'
|
|
33
|
+
'completion:生成自动补全脚本'
|
|
34
|
+
'comp:生成自动补全脚本 (completion 别名)'
|
|
35
|
+
'help:显示帮助信息'
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
local -a add_types
|
|
39
|
+
add_types=(
|
|
40
|
+
'page:页面组件'
|
|
41
|
+
'widget:通用组件'
|
|
42
|
+
'component:业务组件'
|
|
43
|
+
'viewmodel:ViewModel'
|
|
44
|
+
'service:服务层 (Service)'
|
|
45
|
+
'model:数据模型 (Model)'
|
|
46
|
+
'module:完整功能模块'
|
|
47
|
+
'p:页面 (page 别名)'
|
|
48
|
+
'w:组件 (widget 别名)'
|
|
49
|
+
'c:业务组件 (component 别名)'
|
|
50
|
+
'v:ViewModel (vm 别名)'
|
|
51
|
+
's:服务 (service 别名)'
|
|
52
|
+
'm:模型 (model 别名)'
|
|
53
|
+
'mod:模块 (module 别名)'
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
_arguments -C \\
|
|
57
|
+
'1: :->command' \\
|
|
58
|
+
'*:: :->args'
|
|
59
|
+
|
|
60
|
+
case $state in
|
|
61
|
+
(command)
|
|
62
|
+
_describe -t commands 'flu-cli commands' commands
|
|
63
|
+
;;
|
|
64
|
+
(args)
|
|
65
|
+
case $line[1] in
|
|
66
|
+
(add|a)
|
|
67
|
+
_describe -t add_types 'component types' add_types
|
|
68
|
+
;;
|
|
69
|
+
(new|n)
|
|
70
|
+
_arguments \\
|
|
71
|
+
'--template[模板类型]:template:(lite modular clean)' \\
|
|
72
|
+
'--state[状态管理器]:state:(default provider getx riverpod)' \\
|
|
73
|
+
'--dir[目标目录]:dir:_files -/' \\
|
|
74
|
+
'--no-cache[禁用缓存]' \\
|
|
75
|
+
'--remote[使用远程模板]'
|
|
76
|
+
;;
|
|
77
|
+
*)
|
|
78
|
+
;;
|
|
79
|
+
esac
|
|
80
|
+
;;
|
|
81
|
+
esac
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
compdef _flu_cli_completion flu-cli
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
###-end-flu-cli-completion-###
|
|
88
|
+
`;
|
|
89
|
+
|
|
90
|
+
console.log(script);
|
|
91
|
+
console.error(chalk.green('✅ 补全脚本已生成'));
|
|
92
|
+
console.error(chalk.gray('请将其添加到您的 shell 配置文件中 (例如 ~/.zshrc 或 ~/.bashrc)'));
|
|
93
|
+
console.error(chalk.gray('用法: flu-cli completion >> ~/.zshrc && source ~/.zshrc'));
|
|
94
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// generate-sm 命令:为现有项目生成/切换状态管理器(依赖注入、入口与路由增强、适配器/变体生成)
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import { existsSync } from 'fs'
|
|
4
|
+
import { StateManagerGenerator } from '../generators/state_manager_generator.js'
|
|
5
|
+
import { ProjectGenerator } from '../generators/project_generator.js'
|
|
6
|
+
|
|
7
|
+
const SUPPORTED = ['default', 'provider', 'getx', 'riverpod']
|
|
8
|
+
|
|
9
|
+
export async function generateStateManager (type, options) {
|
|
10
|
+
try {
|
|
11
|
+
const state = SUPPORTED.includes(type) ? type : 'default'
|
|
12
|
+
const projectPath = options.dir || process.cwd()
|
|
13
|
+
if (!existsSync(projectPath)) {
|
|
14
|
+
console.log(chalk.red(`目录不存在: ${projectPath}`))
|
|
15
|
+
process.exit(1)
|
|
16
|
+
}
|
|
17
|
+
const pg = new ProjectGenerator()
|
|
18
|
+
await pg.processTemplates(projectPath)
|
|
19
|
+
const sm = new StateManagerGenerator(projectPath, state, { module: options.module })
|
|
20
|
+
await sm.generate()
|
|
21
|
+
console.log(chalk.green('生成完成'))
|
|
22
|
+
} catch (e) {
|
|
23
|
+
console.log(chalk.red(`生成失败: ${e.message}`))
|
|
24
|
+
process.exit(1)
|
|
25
|
+
}
|
|
26
|
+
}
|