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.
- package/CHANGELOG.md +23 -0
- package/README.md +17 -4
- package/config/dev.config.js +11 -11
- package/config/templates.js +10 -10
- package/index.js +554 -102
- package/lib/commands/add.js +365 -266
- package/lib/commands/assets.js +77 -78
- package/lib/commands/cache.js +29 -52
- package/lib/commands/completion.js +13 -11
- package/lib/commands/config.js +150 -44
- package/lib/commands/init-ai-base.js +89 -0
- package/lib/commands/newClack.js +269 -178
- package/lib/commands/snippets.js +58 -43
- package/lib/commands/template.js +98 -58
- package/lib/commands/templates.js +101 -57
- package/lib/commands/upload.js +313 -0
- package/lib/commands/vnext-options.js +206 -0
- package/lib/generators/model_generator.js +91 -88
- package/lib/generators/page_generator.js +100 -93
- package/lib/generators/service_generator.js +44 -39
- package/lib/generators/viewmodel_generator.js +25 -29
- package/lib/generators/widget_generator.js +30 -35
- package/lib/templates/templateCopier.js +14 -15
- package/lib/templates/templateManager.js +22 -21
- package/lib/utils/config.js +37 -20
- package/lib/utils/flutterHelper.js +2 -2
- package/lib/utils/i18n.js +3 -3
- package/lib/utils/index_updater.js +22 -23
- package/lib/utils/json-output.js +59 -0
- package/lib/utils/logger.js +17 -17
- package/lib/utils/project_detector.js +66 -66
- package/lib/utils/snippet_loader.js +21 -19
- package/lib/utils/string_helper.js +13 -13
- package/lib/utils/templateSelectorEnquirer.js +94 -108
- package/locales/en-US.json +1 -1
- package/locales/zh-CN.json +2 -2
- package/package.json +60 -57
- package/scripts/smoke-vnext-generate.mjs +1934 -0
- package/scripts/smoke-vnext-params.mjs +92 -0
- package/CLI.md +0 -513
- package/release.sh +0 -529
- package/scripts/e2e-state-tests.js +0 -116
- package/scripts/sync-base-to-templates.js +0 -108
- package/scripts/workspace-clone-all.sh +0 -101
- package/scripts/workspace-status-all.sh +0 -112
package/lib/commands/snippets.js
CHANGED
|
@@ -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
|
|
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/
|
|
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
|
-
|
|
28
|
-
|
|
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
|
|
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(
|
|
70
|
-
|
|
71
|
-
|
|
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
|
}
|
package/lib/commands/template.js
CHANGED
|
@@ -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'
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
|
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(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
console.log(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
}
|