flu-cli 2.0.6 → 2.1.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +17 -4
  3. package/config/dev.config.js +11 -11
  4. package/config/templates.js +10 -10
  5. package/index.js +554 -102
  6. package/lib/commands/add.js +365 -266
  7. package/lib/commands/assets.js +77 -78
  8. package/lib/commands/cache.js +29 -52
  9. package/lib/commands/completion.js +13 -11
  10. package/lib/commands/config.js +150 -44
  11. package/lib/commands/init-ai-base.js +89 -0
  12. package/lib/commands/newClack.js +269 -178
  13. package/lib/commands/snippets.js +58 -43
  14. package/lib/commands/template.js +98 -58
  15. package/lib/commands/templates.js +101 -57
  16. package/lib/commands/upload.js +313 -0
  17. package/lib/commands/vnext-options.js +206 -0
  18. package/lib/generators/model_generator.js +91 -88
  19. package/lib/generators/page_generator.js +100 -93
  20. package/lib/generators/service_generator.js +44 -39
  21. package/lib/generators/viewmodel_generator.js +25 -29
  22. package/lib/generators/widget_generator.js +30 -35
  23. package/lib/templates/templateCopier.js +14 -15
  24. package/lib/templates/templateManager.js +22 -21
  25. package/lib/utils/config.js +37 -20
  26. package/lib/utils/flutterHelper.js +2 -2
  27. package/lib/utils/i18n.js +3 -3
  28. package/lib/utils/index_updater.js +22 -23
  29. package/lib/utils/json-output.js +59 -0
  30. package/lib/utils/logger.js +17 -17
  31. package/lib/utils/project_detector.js +66 -66
  32. package/lib/utils/snippet_loader.js +21 -19
  33. package/lib/utils/string_helper.js +13 -13
  34. package/lib/utils/templateSelectorEnquirer.js +94 -108
  35. package/locales/en-US.json +1 -1
  36. package/locales/zh-CN.json +2 -2
  37. package/package.json +60 -57
  38. package/scripts/smoke-vnext-generate.mjs +1934 -0
  39. package/scripts/smoke-vnext-params.mjs +92 -0
  40. package/CLI.md +0 -513
  41. package/release.sh +0 -529
  42. package/scripts/e2e-state-tests.js +0 -116
  43. package/scripts/sync-base-to-templates.js +0 -108
  44. package/scripts/workspace-clone-all.sh +0 -101
  45. package/scripts/workspace-status-all.sh +0 -112
@@ -1,80 +1,95 @@
1
- import fs from 'fs-extra';
2
- import path from 'path';
3
- import chalk from 'chalk';
4
- import { fileURLToPath } from 'url';
5
- import { ProjectConfigManager, getTemplatesRootDir } from 'flu-cli-core';
6
- import { t } from '../utils/i18n.js';
1
+ import fs from 'fs-extra'
2
+ import path from 'path'
3
+ import chalk from 'chalk'
4
+ import { fileURLToPath } from 'url'
5
+ import { ProjectConfigManager, getTemplatesRootDir } from 'flu-cli-core'
6
+ import { t } from '../utils/i18n.js'
7
7
 
8
8
  /**
9
9
  * 同步代码片段到当前项目
10
10
  */
11
- export async function syncSnippets (targetDir) {
12
- const projectRoot = targetDir || process.cwd();
13
- const vscodeDir = path.join(projectRoot, '.vscode');
14
- const targetFile = path.join(vscodeDir, 'dart.code-snippets');
11
+ export async function syncSnippets(targetDir) {
12
+ const projectRoot = targetDir || process.cwd()
13
+ const vscodeDir = path.join(projectRoot, '.vscode')
14
+ const targetFile = path.join(vscodeDir, 'dart.code-snippets')
15
15
 
16
16
  // 获取 centralized snippets 路径 (从 Core 的模板根目录获取)
17
- const templatesDir = getTemplatesRootDir();
18
- const snippetsSource = path.join(templatesDir, 'snippets/dart.code-snippets');
17
+ const templatesDir = getTemplatesRootDir()
18
+ const snippetsSource = path.join(templatesDir, 'snippets/flu-cli.code-snippets')
19
19
 
20
20
  if (!fs.existsSync(snippetsSource)) {
21
- console.log(chalk.red(`❌ 错误: 找不到标准代码片段源文件: ${snippetsSource}`));
22
- return;
21
+ console.log(chalk.red(`❌ 错误: 找不到标准代码片段源文件: ${snippetsSource}`))
22
+ return
23
23
  }
24
24
 
25
25
  try {
26
- // 读取原始 Snippets
27
- const originalSnippets = await fs.readJson(snippetsSource);
28
- let finalSnippets = { ...originalSnippets };
26
+ // 读取原始 Snippets(源文件可能含尾随逗号等非严格 JSON,readJson 失败时原样复制)
27
+ let originalSnippets
28
+ try {
29
+ originalSnippets = await fs.readJson(snippetsSource)
30
+ } catch {
31
+ await fs.ensureDir(vscodeDir)
32
+ await fs.copy(snippetsSource, targetFile)
33
+ console.log(chalk.green(t('snippets.sync_success')))
34
+ console.log(
35
+ chalk.gray(`已复制: ${targetFile}(源片段非严格 JSON,未按 .flu-cli.json 过滤键)`),
36
+ )
37
+ return
38
+ }
39
+ let finalSnippets = { ...originalSnippets }
29
40
 
30
41
  // 读取项目配置
31
- const config = ProjectConfigManager.loadConfig(projectRoot);
42
+ const resolvedConfig = ProjectConfigManager.resolveEffectiveConfig(projectRoot)
43
+ const config = resolvedConfig?.config
32
44
 
33
45
  if (config) {
34
- console.log(chalk.cyan(t('snippets.detect_config')));
35
- const pageConfig = config.generators?.page;
36
- const vmConfig = config.generators?.viewModel;
46
+ console.log(chalk.cyan(t('snippets.detect_config')))
47
+ const pageConfig = config.generators?.page
48
+ const vmConfig = config.generators?.viewModel
37
49
 
38
- const withBasePage = pageConfig?.withBasePage ?? true;
39
- const withViewModel = pageConfig?.withViewModel ?? true;
40
- const withBaseViewModel = vmConfig?.withBaseViewModel ?? true;
50
+ const withBasePage = pageConfig?.withBasePage ?? true
51
+ const withViewModel = pageConfig?.withViewModel ?? true
52
+ const withBaseViewModel = vmConfig?.withBaseViewModel ?? true
41
53
 
42
54
  // 过滤规则
43
55
  if (!withBasePage) {
44
- delete finalSnippets['flu.stPage'];
45
- delete finalSnippets['flu.listPage'];
56
+ delete finalSnippets['flu.stPage']
57
+ delete finalSnippets['flu.listPage']
46
58
  }
47
59
 
48
60
  if (!withViewModel) {
49
- delete finalSnippets['flu.stPage'];
50
- delete finalSnippets['flu.viewmodel'];
51
- delete finalSnippets['flu.listPage'];
52
- delete finalSnippets['flu.listViewModel'];
61
+ delete finalSnippets['flu.stPage']
62
+ delete finalSnippets['flu.viewmodel']
63
+ delete finalSnippets['flu.listPage']
64
+ delete finalSnippets['flu.listViewModel']
53
65
  }
54
66
 
55
67
  if (!withBaseViewModel) {
56
- delete finalSnippets['flu.viewmodel'];
57
- delete finalSnippets['flu.listViewModel'];
68
+ delete finalSnippets['flu.viewmodel']
69
+ delete finalSnippets['flu.listViewModel']
58
70
  }
59
71
  }
60
72
 
61
73
  // 确保 .vscode 目录存在
62
- await fs.ensureDir(vscodeDir);
74
+ await fs.ensureDir(vscodeDir)
63
75
 
64
76
  // 写入文件
65
- await fs.writeJson(targetFile, finalSnippets, { spaces: 2 });
77
+ await fs.writeJson(targetFile, finalSnippets, { spaces: 2 })
66
78
 
67
- console.log(chalk.green(t('snippets.sync_success')));
79
+ console.log(chalk.green(t('snippets.sync_success')))
68
80
  if (config) {
69
- console.log(chalk.gray(t('snippets.applied_filter', {
70
- basePage: config.generators?.page?.withBasePage ? 'ON' : 'OFF',
71
- viewModel: config.generators?.page?.withViewModel ? 'ON' : 'OFF'
72
- })));
81
+ console.log(
82
+ chalk.gray(
83
+ t('snippets.applied_filter', {
84
+ basePage: config.generators?.page?.withBasePage ? 'ON' : 'OFF',
85
+ viewModel: config.generators?.page?.withViewModel ? 'ON' : 'OFF',
86
+ }),
87
+ ),
88
+ )
73
89
  }
74
- console.log(chalk.gray(`已更新: ${targetFile}`));
75
- console.log(chalk.cyan('提示: 重启 VS Code 或运行 "Developer: Reload Window" 以应用更改'));
76
-
90
+ console.log(chalk.gray(`已更新: ${targetFile}`))
91
+ console.log(chalk.cyan('提示: 重启 VS Code 或运行 "Developer: Reload Window" 以应用更改'))
77
92
  } catch (error) {
78
- console.log(chalk.red(`❌ 同步失败: ${error.message}`));
93
+ console.log(chalk.red(`❌ 同步失败: ${error.message}`))
79
94
  }
80
95
  }
@@ -1,113 +1,153 @@
1
- import chalk from 'chalk';
2
- import { ConfigManager } from 'flu-cli-core';
3
- import { getAllTemplates } from '../../config/templates.js';
4
- import { logger } from '../utils/logger.js';
5
- import { existsSync } from 'fs';
6
- import { getTemplateCachePath } from '../templates/templateManager.js';
7
- import { format } from 'date-fns'; // 需要检查是否已安装 date-fns,如果没有可以用原生 Date
1
+ import chalk from 'chalk'
2
+ import { ConfigManager } from 'flu-cli-core'
3
+ import { getAllTemplates } from '../../config/templates.js'
4
+ import { logger } from '../utils/logger.js'
5
+ import { existsSync } from 'fs'
6
+ import { getTemplateCachePath } from '../templates/templateManager.js'
7
+ import { format } from 'date-fns' // 需要检查是否已安装 date-fns,如果没有可以用原生 Date
8
8
 
9
9
  /**
10
10
  * 格式化日期
11
11
  */
12
- function formatDate (timestamp) {
13
- if (!timestamp) return '从未';
14
- return new Date(timestamp).toLocaleString('zh-CN');
12
+ function formatDate(timestamp) {
13
+ if (!timestamp) return '从未'
14
+ return new Date(timestamp).toLocaleString('zh-CN')
15
15
  }
16
16
 
17
17
  /**
18
18
  * 列出所有模板(内置 + 自定义)
19
19
  */
20
- export function listAllTemplates () {
21
- logger.title('📦 可用的项目模板');
20
+ export function listAllTemplates() {
21
+ logger.title('📦 可用的项目模板')
22
22
 
23
23
  // 1. 内置模板
24
- console.log(chalk.bold.cyan('📌 内置模板'));
25
- const builtinTemplates = getAllTemplates();
24
+ console.log(chalk.bold.cyan('📌 内置模板'))
25
+ const builtinTemplates = getAllTemplates()
26
26
  builtinTemplates.forEach((template) => {
27
- const cachePath = getTemplateCachePath(template.name);
28
- const isCached = existsSync(cachePath);
29
- const status = isCached ? chalk.green('已缓存') : chalk.gray('未缓存');
27
+ const cachePath = getTemplateCachePath(template.name)
28
+ const isCached = existsSync(cachePath)
29
+ const status = isCached ? chalk.green('已缓存') : chalk.gray('未缓存')
30
30
 
31
- console.log(chalk.bold(` • ${template.name} (${template.displayName})`) + ` [${status}]`);
32
- console.log(chalk.gray(` ${template.description}`));
33
- });
31
+ console.log(chalk.bold(` • ${template.name} (${template.displayName})`) + ` [${status}]`)
32
+ console.log(chalk.gray(` ${template.description}`))
33
+ })
34
34
 
35
35
  // 2. 自定义模板
36
- const configManager = ConfigManager.getInstance();
37
- const customTemplates = configManager.getTemplates();
36
+ const configManager = ConfigManager.getInstance()
37
+ const customTemplates = configManager.getTemplates()
38
38
 
39
39
  if (customTemplates.length > 0) {
40
- logger.newLine();
41
- console.log(chalk.bold.cyan('🔧 自定义模板'));
40
+ logger.newLine()
41
+ console.log(chalk.bold.cyan('🔧 自定义模板'))
42
42
  customTemplates.forEach((template) => {
43
- const source = template.type === 'git' ? template.url : template.path;
44
- let status = '';
45
- let updateInfo = '';
43
+ const source = template.type === 'git' ? template.url : template.path
44
+ let status = ''
45
+ let updateInfo = ''
46
46
 
47
47
  if (template.type === 'git') {
48
- const cachePath = getTemplateCachePath(template.id);
49
- const isCached = existsSync(cachePath);
50
- status = isCached ? chalk.green('已缓存') : chalk.gray('未缓存');
48
+ const cachePath = getTemplateCachePath(template.id)
49
+ const isCached = existsSync(cachePath)
50
+ status = isCached ? chalk.green('已缓存') : chalk.gray('未缓存')
51
51
  if (template.lastUsedAt) {
52
- updateInfo = chalk.gray(` (上次使用: ${formatDate(template.lastUsedAt)})`);
52
+ updateInfo = chalk.gray(` (上次使用: ${formatDate(template.lastUsedAt)})`)
53
53
  }
54
54
  } else {
55
- status = chalk.blue('本地链接');
55
+ status = chalk.blue('本地链接')
56
56
  }
57
57
 
58
- console.log(chalk.bold(` • ${template.id} (${template.name})`) + ` [${status}]` + updateInfo);
59
- console.log(chalk.gray(` ${template.description || '无描述'}`));
60
- console.log(chalk.gray(` 来源: [${template.type}] ${source}`));
58
+ console.log(chalk.bold(` • ${template.id} (${template.name})`) + ` [${status}]` + updateInfo)
59
+ console.log(chalk.gray(` ${template.description || '无描述'}`))
60
+ console.log(chalk.gray(` 来源: [${template.type}] ${source}`))
61
61
  if (template.branch) {
62
- console.log(chalk.gray(` 分支: ${template.branch}`));
62
+ console.log(chalk.gray(` 分支: ${template.branch}`))
63
63
  }
64
- });
64
+ })
65
65
  } else {
66
- logger.newLine();
67
- console.log(chalk.gray(' (暂无自定义模板)'));
66
+ logger.newLine()
67
+ console.log(chalk.gray(' (暂无自定义模板)'))
68
68
  }
69
69
 
70
- logger.newLine();
71
- logger.info('使用 "flu template add" 添加自定义模板');
72
- logger.info('使用 "flu new <name> -t <template>" 创建项目');
70
+ logger.newLine()
71
+ logger.info('使用 "flu template add" 添加自定义模板')
72
+ logger.info('使用 "flu new <name> -t <template>" 创建项目')
73
+ }
74
+
75
+ export function collectAllTemplates() {
76
+ const builtinTemplates = getAllTemplates().map((t) => {
77
+ const cachePath = getTemplateCachePath(t.name)
78
+ const isCached = existsSync(cachePath)
79
+ return {
80
+ kind: 'builtin',
81
+ id: t.name,
82
+ name: t.name,
83
+ displayName: t.displayName,
84
+ description: t.description,
85
+ cached: isCached,
86
+ cachePath: isCached ? cachePath : null,
87
+ }
88
+ })
89
+
90
+ const configManager = ConfigManager.getInstance()
91
+ const customTemplates = configManager.getTemplates().map((t) => {
92
+ const source = t.type === 'git' ? t.url : t.path
93
+ const cachePath = t.type === 'git' ? getTemplateCachePath(t.id) : null
94
+ const cached = cachePath ? existsSync(cachePath) : null
95
+ return {
96
+ kind: 'custom',
97
+ id: t.id,
98
+ name: t.name,
99
+ type: t.type,
100
+ description: t.description || '',
101
+ source,
102
+ branch: t.branch || null,
103
+ cached,
104
+ cachePath,
105
+ lastUsedAt: t.lastUsedAt || null,
106
+ }
107
+ })
108
+
109
+ return {
110
+ builtin: builtinTemplates,
111
+ custom: customTemplates,
112
+ }
73
113
  }
74
114
 
75
115
  /**
76
116
  * 添加自定义模板
77
117
  */
78
- export function addTemplate (name, source, options) {
79
- const configManager = ConfigManager.getInstance();
80
- const existing = configManager.getTemplate(name);
118
+ export function addTemplate(name, source, options) {
119
+ const configManager = ConfigManager.getInstance()
120
+ const existing = configManager.getTemplate(name)
81
121
 
82
122
  if (existing && !options.force) {
83
- logger.error(`模板 "${name}" 已存在`);
84
- logger.info('使用 --force 覆盖,或使用 "flu template remove" 删除');
85
- return;
123
+ logger.error(`模板 "${name}" 已存在`)
124
+ logger.info('使用 --force 覆盖,或使用 "flu template remove" 删除')
125
+ return
86
126
  }
87
127
 
88
- const isLocal = options.local;
128
+ const isLocal = options.local
89
129
  const template = {
90
130
  id: name,
91
131
  name: options.name || name,
92
132
  type: isLocal ? 'local' : 'git',
93
133
  description: options.description || '自定义模板',
94
- ...(isLocal ? { path: source } : { url: source, branch: options.branch || 'main' })
95
- };
134
+ ...(isLocal ? { path: source } : { url: source, branch: options.branch || 'main' }),
135
+ }
96
136
 
97
- configManager.addTemplate(template);
98
- logger.success(`✅ 模板 "${name}" 添加成功`);
137
+ configManager.addTemplate(template)
138
+ logger.success(`✅ 模板 "${name}" 添加成功`)
99
139
  }
100
140
 
101
141
  /**
102
142
  * 删除自定义模板
103
143
  */
104
- export function removeTemplate (name) {
105
- const configManager = ConfigManager.getInstance();
106
- const success = configManager.removeTemplate(name);
144
+ export function removeTemplate(name) {
145
+ const configManager = ConfigManager.getInstance()
146
+ const success = configManager.removeTemplate(name)
107
147
 
108
148
  if (success) {
109
- logger.success(`🗑️ 模板 "${name}" 已删除`);
149
+ logger.success(`🗑️ 模板 "${name}" 已删除`)
110
150
  } else {
111
- logger.error(`模板 "${name}" 不存在`);
151
+ logger.error(`模板 "${name}" 不存在`)
112
152
  }
113
153
  }
@@ -3,82 +3,126 @@
3
3
  * 显示所有模板或指定模板的详细信息
4
4
  */
5
5
 
6
- import chalk from 'chalk';
7
- import { getAllTemplates, getTemplate, isValidTemplate } from '../../config/templates.js';
8
- import { logger } from '../utils/logger.js';
6
+ import chalk from 'chalk'
7
+ import { getAllTemplates, getTemplate, isValidTemplate } from '../../config/templates.js'
8
+ import { logger } from '../utils/logger.js'
9
+
10
+ export function collectTemplates() {
11
+ const templates = getAllTemplates()
12
+ return templates.map((t) => ({
13
+ name: t.name,
14
+ displayName: t.displayName,
15
+ description: t.description,
16
+ complexity: t.complexity,
17
+ teamSize: t.teamSize,
18
+ codeSize: t.codeSize,
19
+ features: t.features,
20
+ structure: t.structure,
21
+ }))
22
+ }
23
+
24
+ export function collectTemplateDetail(templateName) {
25
+ if (!isValidTemplate(templateName)) return null
26
+ const t = getTemplate(templateName)
27
+ return {
28
+ name: t.name,
29
+ displayName: t.displayName,
30
+ description: t.description,
31
+ complexity: t.complexity,
32
+ teamSize: t.teamSize,
33
+ codeSize: t.codeSize,
34
+ features: t.features,
35
+ structure: t.structure,
36
+ }
37
+ }
9
38
 
10
39
  /**
11
40
  * 列出所有模板
12
41
  */
13
- export function listTemplates () {
14
- logger.title('📦 可用的项目模板');
42
+ export function listTemplates() {
43
+ logger.title('📦 可用的项目模板')
15
44
 
16
- const templates = getAllTemplates();
45
+ const templates = getAllTemplates()
17
46
 
18
47
  templates.forEach((template, index) => {
19
- console.log(chalk.bold(`${index + 1}. ${template.displayName}`));
20
- console.log(chalk.gray(` ${template.description}`));
21
- console.log(chalk.gray(` 复杂度: ${'⭐'.repeat(template.complexity)}${'☆'.repeat(5 - template.complexity)}`));
22
- console.log(chalk.gray(` 团队规模: ${template.teamSize}`));
23
- console.log(chalk.gray(` 代码量: ${template.codeSize}`));
24
- logger.newLine();
25
- });
26
-
27
- logger.info('使用 "flu-cli templates <name>" 查看详细信息');
28
- logger.info('使用 "flu-cli new <project-name> -t <template>" 创建项目');
29
-
30
- logger.newLine();
31
- console.log(chalk.gray('示例:'));
32
- console.log(chalk.yellow(' flu-cli templates lite'));
33
- console.log(chalk.yellow(' flu-cli new my_app -t modular'));
48
+ console.log(chalk.bold(`${index + 1}. ${template.displayName}`))
49
+ console.log(chalk.gray(` ${template.description}`))
50
+ console.log(
51
+ chalk.gray(
52
+ ` 复杂度: ${'⭐'.repeat(template.complexity)}${'☆'.repeat(5 - template.complexity)}`,
53
+ ),
54
+ )
55
+ console.log(chalk.gray(` 团队规模: ${template.teamSize}`))
56
+ console.log(chalk.gray(` 代码量: ${template.codeSize}`))
57
+ logger.newLine()
58
+ })
59
+
60
+ logger.info('使用 "flu-cli templates <name>" 查看详细信息')
61
+ logger.info('使用 "flu-cli new <project-name> -t <template>" 创建项目')
62
+
63
+ logger.newLine()
64
+ console.log(chalk.gray('示例:'))
65
+ console.log(chalk.yellow(' flu-cli templates lite'))
66
+ console.log(chalk.yellow(' flu-cli new my_app -t modular'))
34
67
  }
35
68
 
36
69
  /**
37
70
  * 显示模板详情
38
71
  */
39
- export function showTemplateDetail (templateName) {
72
+ export function showTemplateDetail(templateName) {
40
73
  if (!isValidTemplate(templateName)) {
41
- logger.error(`模板 "${templateName}" 不存在`);
42
- logger.info('使用 "flu-cli templates" 查看所有可用模板');
43
- return;
74
+ logger.error(`模板 "${templateName}" 不存在`)
75
+ logger.info('使用 "flu-cli templates" 查看所有可用模板')
76
+ return
44
77
  }
45
78
 
46
- const template = getTemplate(templateName);
79
+ const template = getTemplate(templateName)
47
80
 
48
81
  // 显示模板信息框
49
- console.log(chalk.bold.cyan('\n┌─────────────────────────────────────────────────────────────┐'));
50
- console.log(chalk.bold.cyan(`│ 📦 ${template.displayName.padEnd(56)} │`));
51
- console.log(chalk.bold.cyan('├─────────────────────────────────────────────────────────────┤'));
82
+ console.log(chalk.bold.cyan('\n┌─────────────────────────────────────────────────────────────┐'))
83
+ console.log(chalk.bold.cyan(`│ 📦 ${template.displayName.padEnd(56)} │`))
84
+ console.log(chalk.bold.cyan('├─────────────────────────────────────────────────────────────┤'))
52
85
 
53
86
  // 基本信息
54
- console.log(chalk.cyan('│ ') + chalk.gray('描述: ') + template.description.padEnd(50) + chalk.cyan(' │'));
55
- console.log(chalk.cyan('│ ') + chalk.gray('复杂度: ') + ('⭐'.repeat(template.complexity) + '☆'.repeat(5 - template.complexity)).padEnd(50) + chalk.cyan(' │'));
56
- console.log(chalk.cyan('│ ') + chalk.gray('团队规模: ') + template.teamSize.padEnd(48) + chalk.cyan(' │'));
57
- console.log(chalk.cyan('│ ') + chalk.gray('代码量: ') + template.codeSize.padEnd(50) + chalk.cyan(' │'));
58
-
59
- console.log(chalk.bold.cyan('├─────────────────────────────────────────────────────────────┤'));
60
- console.log(chalk.bold.cyan('│ 特性: │'));
61
- console.log(chalk.cyan('│'));
62
-
63
- template.features.forEach(feature => {
64
- console.log(chalk.cyan('│ ') + feature.padEnd(60) + chalk.cyan(' │'));
65
- });
66
-
67
- console.log(chalk.bold.cyan('├─────────────────────────────────────────────────────────────┤'));
68
- console.log(chalk.bold.cyan('│ 项目结构: │'));
69
- console.log(chalk.cyan('│ │'));
87
+ console.log(
88
+ chalk.cyan('│ ') + chalk.gray('描述: ') + template.description.padEnd(50) + chalk.cyan(' │'),
89
+ )
90
+ console.log(
91
+ chalk.cyan('│ ') +
92
+ chalk.gray('复杂度: ') +
93
+ ('⭐'.repeat(template.complexity) + '☆'.repeat(5 - template.complexity)).padEnd(50) +
94
+ chalk.cyan(' │'),
95
+ )
96
+ console.log(
97
+ chalk.cyan('│ ') + chalk.gray('团队规模: ') + template.teamSize.padEnd(48) + chalk.cyan(' │'),
98
+ )
99
+ console.log(
100
+ chalk.cyan('│ ') + chalk.gray('代码量: ') + template.codeSize.padEnd(50) + chalk.cyan(''),
101
+ )
102
+
103
+ console.log(chalk.bold.cyan('├─────────────────────────────────────────────────────────────┤'))
104
+ console.log(chalk.bold.cyan('│ 特性: │'))
105
+ console.log(chalk.cyan('│ │'))
106
+
107
+ template.features.forEach((feature) => {
108
+ console.log(chalk.cyan('│ ') + feature.padEnd(60) + chalk.cyan(' │'))
109
+ })
110
+
111
+ console.log(chalk.bold.cyan('├─────────────────────────────────────────────────────────────┤'))
112
+ console.log(chalk.bold.cyan('│ 项目结构: │'))
113
+ console.log(chalk.cyan('│ │'))
70
114
 
71
115
  // 显示项目结构
72
- const structureLines = template.structure.trim().split('\n');
73
- structureLines.forEach(line => {
74
- const paddedLine = line.padEnd(60);
75
- console.log(chalk.cyan('│ ') + paddedLine + chalk.cyan(' │'));
76
- });
77
-
78
- console.log(chalk.bold.cyan('└─────────────────────────────────────────────────────────────┘'));
79
-
80
- logger.newLine();
81
- logger.info('创建项目:');
82
- console.log(chalk.yellow(` flu-cli new my_app -t ${templateName}`));
83
- logger.newLine();
116
+ const structureLines = template.structure.trim().split('\n')
117
+ structureLines.forEach((line) => {
118
+ const paddedLine = line.padEnd(60)
119
+ console.log(chalk.cyan('│ ') + paddedLine + chalk.cyan(' │'))
120
+ })
121
+
122
+ console.log(chalk.bold.cyan('└─────────────────────────────────────────────────────────────┘'))
123
+
124
+ logger.newLine()
125
+ logger.info('创建项目:')
126
+ console.log(chalk.yellow(` flu-cli new my_app -t ${templateName}`))
127
+ logger.newLine()
84
128
  }