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
|
@@ -3,67 +3,66 @@
|
|
|
3
3
|
* 自动更新目录的 index.dart 导出文件
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
7
|
-
import { join } from 'path'
|
|
8
|
-
import { logger } from './logger.js'
|
|
6
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
7
|
+
import { join } from 'path'
|
|
8
|
+
import { logger } from './logger.js'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* 更新 index.dart 文件
|
|
12
12
|
* @param {string} dirPath - 目录路径
|
|
13
13
|
* @param {string} fileName - 要添加的文件名
|
|
14
14
|
*/
|
|
15
|
-
export function updateIndexFile
|
|
15
|
+
export function updateIndexFile(dirPath, fileName) {
|
|
16
16
|
try {
|
|
17
|
-
const indexPath = join(dirPath, 'index.dart')
|
|
17
|
+
const indexPath = join(dirPath, 'index.dart')
|
|
18
18
|
|
|
19
19
|
// 如果 index.dart 不存在,不做处理
|
|
20
20
|
if (!existsSync(indexPath)) {
|
|
21
|
-
return false
|
|
21
|
+
return false
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
// 读取现有内容
|
|
25
|
-
let content = readFileSync(indexPath, 'utf8')
|
|
25
|
+
let content = readFileSync(indexPath, 'utf8')
|
|
26
26
|
|
|
27
27
|
// 检查是否已经导出
|
|
28
|
-
const exportStatement = `export '${fileName}'
|
|
28
|
+
const exportStatement = `export '${fileName}';`
|
|
29
29
|
if (content.includes(exportStatement)) {
|
|
30
|
-
return false
|
|
30
|
+
return false // 已经存在,不需要更新
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
// 找到注释行后添加导出语句
|
|
34
|
-
const lines = content.split('\n')
|
|
35
|
-
let insertIndex = -1
|
|
34
|
+
const lines = content.split('\n')
|
|
35
|
+
let insertIndex = -1
|
|
36
36
|
|
|
37
37
|
// 找到第一个注释行之后的位置
|
|
38
38
|
for (let i = 0; i < lines.length; i++) {
|
|
39
39
|
if (lines[i].trim().startsWith('//')) {
|
|
40
|
-
insertIndex = i + 1
|
|
41
|
-
break
|
|
40
|
+
insertIndex = i + 1
|
|
41
|
+
break
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// 如果没找到注释,添加到末尾
|
|
46
46
|
if (insertIndex === -1) {
|
|
47
|
-
insertIndex = lines.length
|
|
47
|
+
insertIndex = lines.length
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
// 跳过空行
|
|
51
51
|
while (insertIndex < lines.length && lines[insertIndex].trim() === '') {
|
|
52
|
-
insertIndex
|
|
52
|
+
insertIndex++
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
// 插入导出语句
|
|
56
|
-
lines.splice(insertIndex, 0, exportStatement)
|
|
56
|
+
lines.splice(insertIndex, 0, exportStatement)
|
|
57
57
|
|
|
58
58
|
// 写回文件
|
|
59
|
-
content = lines.join('\n')
|
|
60
|
-
writeFileSync(indexPath, content, 'utf8')
|
|
61
|
-
|
|
62
|
-
logger.info(`已更新 index.dart: ${exportStatement}`);
|
|
63
|
-
return true;
|
|
59
|
+
content = lines.join('\n')
|
|
60
|
+
writeFileSync(indexPath, content, 'utf8')
|
|
64
61
|
|
|
62
|
+
logger.info(`已更新 index.dart: ${exportStatement}`)
|
|
63
|
+
return true
|
|
65
64
|
} catch (error) {
|
|
66
|
-
logger.warn(`更新 index.dart 失败: ${error.message}`)
|
|
67
|
-
return false
|
|
65
|
+
logger.warn(`更新 index.dart 失败: ${error.message}`)
|
|
66
|
+
return false
|
|
68
67
|
}
|
|
69
68
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export function isJsonMode(options) {
|
|
2
|
+
return options?.json === true
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function createNullLogger() {
|
|
6
|
+
return {
|
|
7
|
+
info() {},
|
|
8
|
+
success() {},
|
|
9
|
+
warn() {},
|
|
10
|
+
error() {},
|
|
11
|
+
title() {},
|
|
12
|
+
newLine() {},
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function buildJsonEnvelope(command, ok, diagnostics, data) {
|
|
17
|
+
return {
|
|
18
|
+
ok: ok === true,
|
|
19
|
+
command,
|
|
20
|
+
diagnostics: Array.isArray(diagnostics) ? diagnostics : [],
|
|
21
|
+
data: data ?? null,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function printJsonEnvelope(envelope) {
|
|
26
|
+
console.log(JSON.stringify(envelope, null, 2))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function runMuted(action) {
|
|
30
|
+
const prevLog = console.log
|
|
31
|
+
const prevInfo = console.info
|
|
32
|
+
const prevWarn = console.warn
|
|
33
|
+
const prevError = console.error
|
|
34
|
+
const prevStdoutWrite = process.stdout.write
|
|
35
|
+
const prevStderrWrite = process.stderr.write
|
|
36
|
+
|
|
37
|
+
const mute = () => true
|
|
38
|
+
console.log = mute
|
|
39
|
+
console.info = mute
|
|
40
|
+
console.warn = mute
|
|
41
|
+
console.error = mute
|
|
42
|
+
process.stdout.write = mute
|
|
43
|
+
process.stderr.write = mute
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const res = await action()
|
|
47
|
+
return { ok: true, result: res }
|
|
48
|
+
} catch (e) {
|
|
49
|
+
const message = e?.message ? String(e.message) : String(e)
|
|
50
|
+
return { ok: false, error: message }
|
|
51
|
+
} finally {
|
|
52
|
+
console.log = prevLog
|
|
53
|
+
console.info = prevInfo
|
|
54
|
+
console.warn = prevWarn
|
|
55
|
+
console.error = prevError
|
|
56
|
+
process.stdout.write = prevStdoutWrite
|
|
57
|
+
process.stderr.write = prevStderrWrite
|
|
58
|
+
}
|
|
59
|
+
}
|
package/lib/utils/logger.js
CHANGED
|
@@ -3,55 +3,55 @@
|
|
|
3
3
|
* 统一的日志输出格式
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import chalk from 'chalk'
|
|
6
|
+
import chalk from 'chalk'
|
|
7
7
|
|
|
8
8
|
export const logger = {
|
|
9
9
|
/**
|
|
10
10
|
* 成功信息
|
|
11
11
|
*/
|
|
12
|
-
success
|
|
13
|
-
console.log(chalk.green('✅ ' + message))
|
|
12
|
+
success(message) {
|
|
13
|
+
console.log(chalk.green('✅ ' + message))
|
|
14
14
|
},
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* 错误信息
|
|
18
18
|
*/
|
|
19
|
-
error
|
|
20
|
-
console.log(chalk.red('❌ ' + message))
|
|
19
|
+
error(message) {
|
|
20
|
+
console.log(chalk.red('❌ ' + message))
|
|
21
21
|
},
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* 警告信息
|
|
25
25
|
*/
|
|
26
|
-
warn
|
|
27
|
-
console.log(chalk.yellow('⚠️ ' + message))
|
|
26
|
+
warn(message) {
|
|
27
|
+
console.log(chalk.yellow('⚠️ ' + message))
|
|
28
28
|
},
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* 信息
|
|
32
32
|
*/
|
|
33
|
-
info
|
|
34
|
-
console.log(chalk.blue('ℹ️ ' + message))
|
|
33
|
+
info(message) {
|
|
34
|
+
console.log(chalk.blue('ℹ️ ' + message))
|
|
35
35
|
},
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* 标题
|
|
39
39
|
*/
|
|
40
|
-
title
|
|
41
|
-
console.log(chalk.bold.cyan('\n' + message + '\n'))
|
|
40
|
+
title(message) {
|
|
41
|
+
console.log(chalk.bold.cyan('\n' + message + '\n'))
|
|
42
42
|
},
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* 分隔线
|
|
46
46
|
*/
|
|
47
|
-
divider
|
|
48
|
-
console.log(chalk.gray('─'.repeat(60)))
|
|
47
|
+
divider() {
|
|
48
|
+
console.log(chalk.gray('─'.repeat(60)))
|
|
49
49
|
},
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* 空行
|
|
53
53
|
*/
|
|
54
|
-
newLine
|
|
55
|
-
console.log('')
|
|
56
|
-
}
|
|
57
|
-
}
|
|
54
|
+
newLine() {
|
|
55
|
+
console.log('')
|
|
56
|
+
},
|
|
57
|
+
}
|
|
@@ -3,59 +3,59 @@
|
|
|
3
3
|
* 职责:基于目录结构识别 lite/modular/clean 模板,并提供生成路径解析
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { existsSync } from 'fs'
|
|
7
|
-
import { join } from 'path'
|
|
6
|
+
import { existsSync } from 'fs'
|
|
7
|
+
import { join } from 'path'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* 检测项目模板类型
|
|
11
11
|
* @param {string} projectDir - 项目目录
|
|
12
12
|
* @returns {'lite'|'modular'|'clean'|null} 模板类型
|
|
13
13
|
*/
|
|
14
|
-
export function detectProjectTemplate
|
|
14
|
+
export function detectProjectTemplate(projectDir = process.cwd()) {
|
|
15
15
|
try {
|
|
16
|
-
const libDir = join(projectDir, 'lib')
|
|
16
|
+
const libDir = join(projectDir, 'lib')
|
|
17
17
|
|
|
18
18
|
if (!existsSync(libDir)) {
|
|
19
|
-
return null
|
|
19
|
+
return null
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// 检测 Clean 架构特征
|
|
23
23
|
// Clean 架构有 features/xxx/data, features/xxx/domain, features/xxx/presentation
|
|
24
|
-
const featuresDir = join(libDir, 'features')
|
|
24
|
+
const featuresDir = join(libDir, 'features')
|
|
25
25
|
if (existsSync(featuresDir)) {
|
|
26
26
|
// 检查是否有 data/domain/presentation 三层结构
|
|
27
|
-
const coreDir = join(libDir, 'core')
|
|
28
|
-
const hasUsecases = existsSync(join(coreDir, 'usecases'))
|
|
29
|
-
const hasErrors = existsSync(join(coreDir, 'errors'))
|
|
27
|
+
const coreDir = join(libDir, 'core')
|
|
28
|
+
const hasUsecases = existsSync(join(coreDir, 'usecases'))
|
|
29
|
+
const hasErrors = existsSync(join(coreDir, 'errors'))
|
|
30
30
|
|
|
31
31
|
if (hasUsecases && hasErrors) {
|
|
32
|
-
return 'clean'
|
|
32
|
+
return 'clean'
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// 检测 Modular 架构特征
|
|
36
36
|
// Modular 架构有 core/base, core/router, shared
|
|
37
|
-
const hasBase = existsSync(join(coreDir, 'base'))
|
|
38
|
-
const hasRouter = existsSync(join(coreDir, 'router'))
|
|
39
|
-
const sharedDir = existsSync(join(libDir, 'shared'))
|
|
37
|
+
const hasBase = existsSync(join(coreDir, 'base'))
|
|
38
|
+
const hasRouter = existsSync(join(coreDir, 'router'))
|
|
39
|
+
const sharedDir = existsSync(join(libDir, 'shared'))
|
|
40
40
|
|
|
41
41
|
if (hasBase && hasRouter && sharedDir) {
|
|
42
|
-
return 'modular'
|
|
42
|
+
return 'modular'
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// 检测 Lite 架构特征
|
|
47
47
|
// Lite 架构有 pages, viewmodels, widgets 等扁平目录
|
|
48
|
-
const pagesDir = join(libDir, 'pages')
|
|
49
|
-
const viewmodelsDir = join(libDir, 'viewmodels')
|
|
50
|
-
const widgetsDir = join(libDir, 'widgets')
|
|
48
|
+
const pagesDir = join(libDir, 'pages')
|
|
49
|
+
const viewmodelsDir = join(libDir, 'viewmodels')
|
|
50
|
+
const widgetsDir = join(libDir, 'widgets')
|
|
51
51
|
|
|
52
52
|
if (existsSync(pagesDir) && existsSync(viewmodelsDir) && existsSync(widgetsDir)) {
|
|
53
|
-
return 'lite'
|
|
53
|
+
return 'lite'
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
return null
|
|
56
|
+
return null
|
|
57
57
|
} catch (error) {
|
|
58
|
-
return null
|
|
58
|
+
return null
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -65,21 +65,21 @@ export function detectProjectTemplate (projectDir = process.cwd()) {
|
|
|
65
65
|
* @param {string} moduleName - 模块名称
|
|
66
66
|
* @returns {string} 页面目录路径
|
|
67
67
|
*/
|
|
68
|
-
export function getPagePath
|
|
69
|
-
const template = detectProjectTemplate(projectDir)
|
|
68
|
+
export function getPagePath(projectDir, moduleName) {
|
|
69
|
+
const template = detectProjectTemplate(projectDir)
|
|
70
70
|
|
|
71
71
|
switch (template) {
|
|
72
72
|
case 'lite':
|
|
73
|
-
return join(projectDir, 'lib', 'pages')
|
|
73
|
+
return join(projectDir, 'lib', 'pages')
|
|
74
74
|
|
|
75
75
|
case 'modular':
|
|
76
|
-
return join(projectDir, 'lib', 'features', moduleName, 'pages')
|
|
76
|
+
return join(projectDir, 'lib', 'features', moduleName, 'pages')
|
|
77
77
|
|
|
78
78
|
case 'clean':
|
|
79
|
-
return join(projectDir, 'lib', 'features', moduleName, 'presentation', 'pages')
|
|
79
|
+
return join(projectDir, 'lib', 'features', moduleName, 'presentation', 'pages')
|
|
80
80
|
|
|
81
81
|
default:
|
|
82
|
-
return join(projectDir, 'lib', 'pages')
|
|
82
|
+
return join(projectDir, 'lib', 'pages')
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -89,21 +89,21 @@ export function getPagePath (projectDir, moduleName) {
|
|
|
89
89
|
* @param {string} moduleName - 模块名称
|
|
90
90
|
* @returns {string} ViewModel 目录路径
|
|
91
91
|
*/
|
|
92
|
-
export function getViewModelPath
|
|
93
|
-
const template = detectProjectTemplate(projectDir)
|
|
92
|
+
export function getViewModelPath(projectDir, moduleName) {
|
|
93
|
+
const template = detectProjectTemplate(projectDir)
|
|
94
94
|
|
|
95
95
|
switch (template) {
|
|
96
96
|
case 'lite':
|
|
97
|
-
return join(projectDir, 'lib', 'viewmodels')
|
|
97
|
+
return join(projectDir, 'lib', 'viewmodels')
|
|
98
98
|
|
|
99
99
|
case 'modular':
|
|
100
|
-
return join(projectDir, 'lib', 'features', moduleName, 'viewmodels')
|
|
100
|
+
return join(projectDir, 'lib', 'features', moduleName, 'viewmodels')
|
|
101
101
|
|
|
102
102
|
case 'clean':
|
|
103
|
-
return join(projectDir, 'lib', 'features', moduleName, 'presentation', 'viewmodels')
|
|
103
|
+
return join(projectDir, 'lib', 'features', moduleName, 'presentation', 'viewmodels')
|
|
104
104
|
|
|
105
105
|
default:
|
|
106
|
-
return join(projectDir, 'lib', 'viewmodels')
|
|
106
|
+
return join(projectDir, 'lib', 'viewmodels')
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -113,27 +113,27 @@ export function getViewModelPath (projectDir, moduleName) {
|
|
|
113
113
|
* @param {string} moduleName - 模块名称(可选)
|
|
114
114
|
* @returns {string} Widget 目录路径
|
|
115
115
|
*/
|
|
116
|
-
export function getWidgetPath
|
|
117
|
-
const template = detectProjectTemplate(projectDir)
|
|
116
|
+
export function getWidgetPath(projectDir, moduleName = null) {
|
|
117
|
+
const template = detectProjectTemplate(projectDir)
|
|
118
118
|
|
|
119
119
|
switch (template) {
|
|
120
120
|
case 'lite':
|
|
121
|
-
return join(projectDir, 'lib', 'widgets')
|
|
121
|
+
return join(projectDir, 'lib', 'widgets')
|
|
122
122
|
|
|
123
123
|
case 'modular':
|
|
124
124
|
if (moduleName) {
|
|
125
|
-
return join(projectDir, 'lib', 'features', moduleName, 'widgets')
|
|
125
|
+
return join(projectDir, 'lib', 'features', moduleName, 'widgets')
|
|
126
126
|
}
|
|
127
|
-
return join(projectDir, 'lib', 'shared', 'widgets')
|
|
127
|
+
return join(projectDir, 'lib', 'shared', 'widgets')
|
|
128
128
|
|
|
129
129
|
case 'clean':
|
|
130
130
|
if (moduleName) {
|
|
131
|
-
return join(projectDir, 'lib', 'features', moduleName, 'presentation', 'widgets')
|
|
131
|
+
return join(projectDir, 'lib', 'features', moduleName, 'presentation', 'widgets')
|
|
132
132
|
}
|
|
133
|
-
return join(projectDir, 'lib', 'shared', 'widgets')
|
|
133
|
+
return join(projectDir, 'lib', 'shared', 'widgets')
|
|
134
134
|
|
|
135
135
|
default:
|
|
136
|
-
return join(projectDir, 'lib', 'widgets')
|
|
136
|
+
return join(projectDir, 'lib', 'widgets')
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -143,27 +143,27 @@ export function getWidgetPath (projectDir, moduleName = null) {
|
|
|
143
143
|
* @param {string} moduleName - 模块名称(可选)
|
|
144
144
|
* @returns {string} Service 目录路径
|
|
145
145
|
*/
|
|
146
|
-
export function getServicePath
|
|
147
|
-
const template = detectProjectTemplate(projectDir)
|
|
146
|
+
export function getServicePath(projectDir, moduleName = null) {
|
|
147
|
+
const template = detectProjectTemplate(projectDir)
|
|
148
148
|
|
|
149
149
|
switch (template) {
|
|
150
150
|
case 'lite':
|
|
151
|
-
return join(projectDir, 'lib', 'services')
|
|
151
|
+
return join(projectDir, 'lib', 'services')
|
|
152
152
|
|
|
153
153
|
case 'modular':
|
|
154
154
|
if (moduleName) {
|
|
155
|
-
return join(projectDir, 'lib', 'features', moduleName, 'services')
|
|
155
|
+
return join(projectDir, 'lib', 'features', moduleName, 'services')
|
|
156
156
|
}
|
|
157
|
-
return join(projectDir, 'lib', 'shared', 'services')
|
|
157
|
+
return join(projectDir, 'lib', 'shared', 'services')
|
|
158
158
|
|
|
159
159
|
case 'clean':
|
|
160
160
|
if (moduleName) {
|
|
161
|
-
return join(projectDir, 'lib', 'features', moduleName, 'data', 'datasources')
|
|
161
|
+
return join(projectDir, 'lib', 'features', moduleName, 'data', 'datasources')
|
|
162
162
|
}
|
|
163
|
-
return join(projectDir, 'lib', 'core', 'network')
|
|
163
|
+
return join(projectDir, 'lib', 'core', 'network')
|
|
164
164
|
|
|
165
165
|
default:
|
|
166
|
-
return join(projectDir, 'lib', 'services')
|
|
166
|
+
return join(projectDir, 'lib', 'services')
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
|
|
@@ -173,27 +173,27 @@ export function getServicePath (projectDir, moduleName = null) {
|
|
|
173
173
|
* @param {string} moduleName - 模块名称(可选)
|
|
174
174
|
* @returns {string} Model 目录路径
|
|
175
175
|
*/
|
|
176
|
-
export function getModelPath
|
|
177
|
-
const template = detectProjectTemplate(projectDir)
|
|
176
|
+
export function getModelPath(projectDir, moduleName = null) {
|
|
177
|
+
const template = detectProjectTemplate(projectDir)
|
|
178
178
|
|
|
179
179
|
switch (template) {
|
|
180
180
|
case 'lite':
|
|
181
|
-
return join(projectDir, 'lib', 'models')
|
|
181
|
+
return join(projectDir, 'lib', 'models')
|
|
182
182
|
|
|
183
183
|
case 'modular':
|
|
184
184
|
if (moduleName) {
|
|
185
|
-
return join(projectDir, 'lib', 'features', moduleName, 'models')
|
|
185
|
+
return join(projectDir, 'lib', 'features', moduleName, 'models')
|
|
186
186
|
}
|
|
187
|
-
return join(projectDir, 'lib', 'shared', 'models')
|
|
187
|
+
return join(projectDir, 'lib', 'shared', 'models')
|
|
188
188
|
|
|
189
189
|
case 'clean':
|
|
190
190
|
if (moduleName) {
|
|
191
|
-
return join(projectDir, 'lib', 'features', moduleName, 'data', 'models')
|
|
191
|
+
return join(projectDir, 'lib', 'features', moduleName, 'data', 'models')
|
|
192
192
|
}
|
|
193
|
-
return join(projectDir, 'lib', 'shared', 'models')
|
|
193
|
+
return join(projectDir, 'lib', 'shared', 'models')
|
|
194
194
|
|
|
195
195
|
default:
|
|
196
|
-
return join(projectDir, 'lib', 'models')
|
|
196
|
+
return join(projectDir, 'lib', 'models')
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
|
|
@@ -203,25 +203,25 @@ export function getModelPath (projectDir, moduleName = null) {
|
|
|
203
203
|
* @param {string} toPath - 目标文件路径
|
|
204
204
|
* @returns {string} 相对路径
|
|
205
205
|
*/
|
|
206
|
-
export function getRelativeImportPath
|
|
207
|
-
const fromParts = fromPath.split('/')
|
|
208
|
-
const toParts = toPath.split('/')
|
|
206
|
+
export function getRelativeImportPath(fromPath, toPath) {
|
|
207
|
+
const fromParts = fromPath.split('/')
|
|
208
|
+
const toParts = toPath.split('/')
|
|
209
209
|
|
|
210
210
|
// 找到共同的父目录
|
|
211
|
-
let commonIndex = 0
|
|
211
|
+
let commonIndex = 0
|
|
212
212
|
while (commonIndex < fromParts.length && commonIndex < toParts.length) {
|
|
213
213
|
if (fromParts[commonIndex] !== toParts[commonIndex]) {
|
|
214
|
-
break
|
|
214
|
+
break
|
|
215
215
|
}
|
|
216
|
-
commonIndex
|
|
216
|
+
commonIndex++
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
// 计算需要返回的层级
|
|
220
|
-
const upLevels = fromParts.length - commonIndex - 1
|
|
221
|
-
const upPath = '../'.repeat(upLevels)
|
|
220
|
+
const upLevels = fromParts.length - commonIndex - 1
|
|
221
|
+
const upPath = '../'.repeat(upLevels)
|
|
222
222
|
|
|
223
223
|
// 计算目标路径
|
|
224
|
-
const targetPath = toParts.slice(commonIndex).join('/')
|
|
224
|
+
const targetPath = toParts.slice(commonIndex).join('/')
|
|
225
225
|
|
|
226
|
-
return upPath + targetPath
|
|
226
|
+
return upPath + targetPath
|
|
227
227
|
}
|
|
@@ -1,32 +1,34 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'fs'
|
|
2
|
-
import { join } from 'path'
|
|
3
|
-
import JSON5 from 'json5'
|
|
1
|
+
import { existsSync, readFileSync } from 'fs'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import JSON5 from 'json5'
|
|
4
4
|
|
|
5
5
|
// 读取项目片段文件
|
|
6
|
-
export function loadProjectSnippets
|
|
6
|
+
export function loadProjectSnippets(projectDir) {
|
|
7
7
|
try {
|
|
8
|
-
const snippetsPath = join(projectDir, '.vscode', 'dart.code-snippets')
|
|
9
|
-
if (!existsSync(snippetsPath)) return {}
|
|
10
|
-
const raw = readFileSync(snippetsPath, 'utf8')
|
|
11
|
-
const json = JSON5.parse(raw)
|
|
12
|
-
return json || {}
|
|
8
|
+
const snippetsPath = join(projectDir, '.vscode', 'dart.code-snippets')
|
|
9
|
+
if (!existsSync(snippetsPath)) return {}
|
|
10
|
+
const raw = readFileSync(snippetsPath, 'utf8')
|
|
11
|
+
const json = JSON5.parse(raw)
|
|
12
|
+
return json || {}
|
|
13
13
|
} catch (_) {
|
|
14
|
-
return {}
|
|
14
|
+
return {}
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// 渲染片段内容
|
|
19
|
-
export function renderSnippet
|
|
20
|
-
const body = Array.isArray(bodyLines) ? bodyLines.join('\n') : String(bodyLines || '')
|
|
19
|
+
export function renderSnippet(bodyLines, variables) {
|
|
20
|
+
const body = Array.isArray(bodyLines) ? bodyLines.join('\n') : String(bodyLines || '')
|
|
21
21
|
return body.replace(/\{\{(\w+)\}\}/g, (_, key) => {
|
|
22
|
-
return Object.prototype.hasOwnProperty.call(variables, key)
|
|
23
|
-
|
|
22
|
+
return Object.prototype.hasOwnProperty.call(variables, key)
|
|
23
|
+
? String(variables[key])
|
|
24
|
+
: `{{${key}}}`
|
|
25
|
+
})
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
// 简便方法:按 key 获取片段并渲染
|
|
27
|
-
export function getSnippetContent
|
|
28
|
-
const map = loadProjectSnippets(projectDir)
|
|
29
|
-
const item = map[key]
|
|
30
|
-
if (!item || !item.body) return null
|
|
31
|
-
return renderSnippet(item.body, variables)
|
|
29
|
+
export function getSnippetContent(projectDir, key, variables) {
|
|
30
|
+
const map = loadProjectSnippets(projectDir)
|
|
31
|
+
const item = map[key]
|
|
32
|
+
if (!item || !item.body) return null
|
|
33
|
+
return renderSnippet(item.body, variables)
|
|
32
34
|
}
|
|
@@ -6,51 +6,51 @@
|
|
|
6
6
|
* 转换为 PascalCase
|
|
7
7
|
* home_page -> HomePage
|
|
8
8
|
*/
|
|
9
|
-
export function toPascalCase
|
|
9
|
+
export function toPascalCase(str) {
|
|
10
10
|
return str
|
|
11
11
|
.split(/[-_\s]+/)
|
|
12
|
-
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
13
|
-
.join('')
|
|
12
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
13
|
+
.join('')
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* 转换为 snake_case
|
|
18
18
|
* HomePage -> home_page
|
|
19
19
|
*/
|
|
20
|
-
export function toSnakeCase
|
|
20
|
+
export function toSnakeCase(str) {
|
|
21
21
|
return str
|
|
22
22
|
.replace(/([A-Z])/g, '_$1')
|
|
23
23
|
.toLowerCase()
|
|
24
|
-
.replace(/^_/, '')
|
|
24
|
+
.replace(/^_/, '')
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* 转换为 camelCase
|
|
29
29
|
* home_page -> homePage
|
|
30
30
|
*/
|
|
31
|
-
export function toCamelCase
|
|
32
|
-
const pascal = toPascalCase(str)
|
|
33
|
-
return pascal.charAt(0).toLowerCase() + pascal.slice(1)
|
|
31
|
+
export function toCamelCase(str) {
|
|
32
|
+
const pascal = toPascalCase(str)
|
|
33
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1)
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* 转换为 Title Case
|
|
38
38
|
* home_page -> Home Page
|
|
39
39
|
*/
|
|
40
|
-
export function toTitleCase
|
|
40
|
+
export function toTitleCase(str) {
|
|
41
41
|
return str
|
|
42
42
|
.split(/[-_\s]+/)
|
|
43
|
-
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
44
|
-
.join(' ')
|
|
43
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
44
|
+
.join(' ')
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* 转换为 kebab-case
|
|
49
49
|
* HomePage -> home-page
|
|
50
50
|
*/
|
|
51
|
-
export function toKebabCase
|
|
51
|
+
export function toKebabCase(str) {
|
|
52
52
|
return str
|
|
53
53
|
.replace(/([A-Z])/g, '-$1')
|
|
54
54
|
.toLowerCase()
|
|
55
|
-
.replace(/^-/, '')
|
|
55
|
+
.replace(/^-/, '')
|
|
56
56
|
}
|