@lark-apaas/miaoda-cli 0.1.19 → 0.1.20-alpha.dd573f8
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/dist/cli/commands/app/index.js +19 -1
- package/dist/cli/commands/db/index.js +0 -3
- package/dist/cli/commands/file/index.js +4 -3
- package/dist/cli/handlers/app/init.js +30 -11
- package/dist/cli/handlers/app/migrate.js +26 -0
- package/dist/main.js +3 -0
- package/dist/services/app/init/import-source.js +67 -0
- package/dist/services/app/init/index.js +8 -1
- package/dist/services/app/init/template.js +47 -1
- package/package.json +1 -1
|
@@ -164,6 +164,8 @@ function registerAppInit(parent) {
|
|
|
164
164
|
.command('init')
|
|
165
165
|
.description('初始化应用代码:抓 template 渲染、同步 upgrade/templates、装 .agent/steering/ skills、写 .spark/meta.json。.spark/meta.json 已存在则直接退出')
|
|
166
166
|
.option('--template <stack>', `技术栈短名(${index_1.SUPPORTED_STACKS.join(' / ')})`)
|
|
167
|
+
.option('--app-type <type>', 'aPaaS 业务类型(html / modern_html / jspage / full_stack);未传 --template 时用于解析技术栈')
|
|
168
|
+
.option('--source-path <path>', '导入源目录:把该目录内容聚合进脚手架 src/(当前仅 --app-type modern_html 生效)')
|
|
167
169
|
.option('--conf <json>', 'init 配置 JSON。支持 {"version": "<template 版本>"},默认 latest')
|
|
168
170
|
.option('--skip-install', '跳过依赖安装', false)
|
|
169
171
|
.option('--async-install', '派发后台进程装依赖并立即返回(与 --skip-install 互斥)', false)
|
|
@@ -180,6 +182,17 @@ function registerAppInit(parent) {
|
|
|
180
182
|
未提供则不写。运行端命令(deploy / file / plugin 等)仍优先读 MIAODA_APP_ID env,
|
|
181
183
|
env 未设置时回退到 meta.json.app_id。
|
|
182
184
|
|
|
185
|
+
技术栈解析(--template / --app-type)
|
|
186
|
+
--template 传了 → 直接用(vite-react / html / nestjs-react-fullstack)
|
|
187
|
+
否则 --app-type 传了 → 查表:html→html, modern_html→html, jspage→vite-react, full_stack→nestjs-react-fullstack
|
|
188
|
+
两者都没传 → 报错 ARGS_INVALID
|
|
189
|
+
|
|
190
|
+
源码导入(--source-path)
|
|
191
|
+
仅 --app-type modern_html 生效:把 <source-path> 整个目录递归聚合进 src/(同名覆盖,叠加保留)。
|
|
192
|
+
过滤:跳过 node_modules/.git/dist/build 目录,跳过 .env/.env.*/.DS_Store/.npmrc/package.json/lockfiles。
|
|
193
|
+
source-path 不存在 → 报错;非 modern_html 传了 source-path → 警告并忽略,继续正常 init。
|
|
194
|
+
app_type 不写入 .spark/meta.json。
|
|
195
|
+
|
|
183
196
|
平台同步(upgrade/templates)
|
|
184
197
|
init 内嵌一次 upgrade/templates 同步(跟 app upgrade 共用同一份 util):
|
|
185
198
|
从 miaoda-cli 自带的 upgrade/templates/<stack>/ 同步 files/(覆盖)+ patches/
|
|
@@ -208,7 +221,8 @@ function registerAppInit(parent) {
|
|
|
208
221
|
JSON 输出
|
|
209
222
|
已初始化:{"data": {"initialized": false, "reason": "already_initialized", "targetDir": "..."}}
|
|
210
223
|
新初始化:{"data": {"initialized": true, "template": "...", "templateVersion": "...", "steeringVersion": "...",
|
|
211
|
-
"appId": "...", "
|
|
224
|
+
"appId": "...", "appType": "modern_html", "sourceImported": true, "importedFileCount": 7,
|
|
225
|
+
"platformStackFound": true, "platformSyncedFiles": [...],
|
|
212
226
|
"installed": true, "installSource": "cache|npm|skipped", "installHash": "...", ...}}
|
|
213
227
|
async 模式:{"data": {"initialized": true, "asyncInstall": true, "installed": false,
|
|
214
228
|
"installSource": "async", "installPid": 123, "installLogPath": "...",
|
|
@@ -220,12 +234,16 @@ JSON 输出
|
|
|
220
234
|
$ miaoda app init --template vite-react --conf '{"version": "0.1.0"}'
|
|
221
235
|
$ miaoda app init --template vite-react --skip-install
|
|
222
236
|
$ miaoda app init --template vite-react --async-install
|
|
237
|
+
$ miaoda app init --app-type full_stack --app-id app_demo_xxx
|
|
238
|
+
$ miaoda app init --app-type modern_html --source-path ./my-assets
|
|
223
239
|
$ MIAODA_DEP_CACHE_DIR=/tmp/dep-cache miaoda app init --template vite-react
|
|
224
240
|
`);
|
|
225
241
|
cmd.action((0, shared_1.withHelp)(cmd, async (rawOpts) => {
|
|
226
242
|
const conf = parseInitConf(rawOpts.conf);
|
|
227
243
|
await (0, index_1.handleAppInit)({
|
|
228
244
|
template: rawOpts.template,
|
|
245
|
+
appType: rawOpts.appType,
|
|
246
|
+
sourcePath: rawOpts.sourcePath,
|
|
229
247
|
conf,
|
|
230
248
|
skipInstall: rawOpts.skipInstall,
|
|
231
249
|
appId: rawOpts.appId,
|
|
@@ -481,7 +481,6 @@ Examples:
|
|
|
481
481
|
'应用到 online;online 将无法直接更改数据库结构(仍可进行数据 DML 操作)。')
|
|
482
482
|
.usage('[flags]')
|
|
483
483
|
.option('--sync-data', '启用时将现有数据同步一份到 dev 环境')
|
|
484
|
-
.option('-y, --yes', '跳过确认提示直接执行')
|
|
485
484
|
.action(async function () {
|
|
486
485
|
await (0, index_1.handleDbMigrationInit)(this.optsWithGlobals());
|
|
487
486
|
})
|
|
@@ -562,7 +561,6 @@ Examples:
|
|
|
562
561
|
.summary('将 dev 的变更发布到 online(单事务原子)')
|
|
563
562
|
.description('将 dev 的变更发布到 online。')
|
|
564
563
|
.usage('[flags]')
|
|
565
|
-
.option('-y, --yes', '跳过确认提示直接执行')
|
|
566
564
|
.action(async function () {
|
|
567
565
|
await (0, index_1.handleDbMigrationApply)(this.optsWithGlobals());
|
|
568
566
|
})
|
|
@@ -681,7 +679,6 @@ Examples:
|
|
|
681
679
|
.description('将数据库恢复到指定时间点的状态。')
|
|
682
680
|
.usage('<timestamp> [flags]')
|
|
683
681
|
.argument('<timestamp>', '目标时间')
|
|
684
|
-
.option('-y, --yes', '跳过确认提示直接执行')
|
|
685
682
|
.action(async function (target) {
|
|
686
683
|
await (0, index_1.handleDbRecoveryApply)(target, this.optsWithGlobals());
|
|
687
684
|
})
|
|
@@ -146,9 +146,10 @@ Examples:
|
|
|
146
146
|
.usage('[paths...] [flags]')
|
|
147
147
|
.argument('[paths...]', '要删除的文件,每项可填路径或文件名(自动识别)')
|
|
148
148
|
.option('-n, --name <name>', '按文件名删除(可重复指定)', (value, prev) => [...(prev ?? []), value])
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
149
|
+
// --yes 是 root 全局 option(见 main.ts),不在此重复声明;必须经 optsWithGlobals
|
|
150
|
+
// 读取(值挂在 root 上,本地 this.opts().yes 为 undefined),否则非交互场景确认门会误拦。
|
|
151
|
+
.action(async function (paths) {
|
|
152
|
+
await (0, index_1.handleFileRm)(paths, { ...this.optsWithGlobals(), appId: (0, shared_1.resolveAppId)({}) });
|
|
152
153
|
})
|
|
153
154
|
.addHelpText('after', `
|
|
154
155
|
Notes:
|
|
@@ -51,23 +51,15 @@ async function handleAppInit(opts) {
|
|
|
51
51
|
});
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
|
-
const stack = opts.template;
|
|
55
|
-
if (!stack) {
|
|
56
|
-
throw new error_1.AppError('ARGS_INVALID', '缺少 --template <stack>', {
|
|
57
|
-
next_actions: [`可用 stack:${index_1.SUPPORTED_STACKS.join(', ')}`],
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
if (!index_1.SUPPORTED_STACKS.includes(stack)) {
|
|
61
|
-
throw new error_1.AppError('ARGS_INVALID', `不支持的 template: ${stack}`, {
|
|
62
|
-
next_actions: [`可用 stack:${index_1.SUPPORTED_STACKS.join(', ')}`],
|
|
63
|
-
});
|
|
64
|
-
}
|
|
54
|
+
const stack = (0, index_1.resolveStack)({ template: opts.template, appType: opts.appType });
|
|
65
55
|
if (opts.asyncInstall && opts.skipInstall) {
|
|
66
56
|
throw new error_1.AppError('ARGS_INVALID', '--async-install 与 --skip-install 互斥');
|
|
67
57
|
}
|
|
68
58
|
const version = opts.conf?.version;
|
|
69
59
|
const projectName = node_path_1.default.basename(targetDir);
|
|
70
60
|
const tplResult = (0, index_1.renderTemplate)({ stack, version, targetDir, projectName });
|
|
61
|
+
// source_path 导入:当前仅 app_type=modern_html 生效。渲染完模板后、装依赖前叠加进 src/。
|
|
62
|
+
const sourceImport = applySourcePathImport(opts, targetDir);
|
|
71
63
|
// 先建 logs/,防止 user 跑 dev 之前 AI/工具 redirect 到 logs/*.log 因为父目录不存在直接挂
|
|
72
64
|
// (dev.js / dev-local.js 自己也建 logs/,但只在它启动后;启动前的 shell redirect 会先于此)
|
|
73
65
|
(0, logs_dir_1.ensureLogsDir)(targetDir);
|
|
@@ -135,6 +127,11 @@ async function handleAppInit(opts) {
|
|
|
135
127
|
steeringVersion: steeringResult.version,
|
|
136
128
|
archType: tplResult.archType,
|
|
137
129
|
appId: opts.appId,
|
|
130
|
+
appType: opts.appType,
|
|
131
|
+
sourcePath: opts.sourcePath,
|
|
132
|
+
sourceImported: sourceImport.sourceImported,
|
|
133
|
+
importedFileCount: sourceImport.importedFileCount,
|
|
134
|
+
sourceIgnoredReason: sourceImport.sourceIgnoredReason,
|
|
138
135
|
syncedSkills: steeringResult.syncedSkills,
|
|
139
136
|
techSynced: steeringResult.techSynced,
|
|
140
137
|
steeringError,
|
|
@@ -159,3 +156,25 @@ async function handleAppInit(opts) {
|
|
|
159
156
|
},
|
|
160
157
|
});
|
|
161
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* 处理 --source-path 导入:当前仅 app_type=modern_html 生效。
|
|
161
|
+
* - 未传 source_path → 什么都不做
|
|
162
|
+
* - modern_html → 调 importSourceSrc 把源目录聚合进 targetDir/src/
|
|
163
|
+
* - 传了 source_path 但非 modern_html → 警告并忽略,继续正常 init(退出码 0)
|
|
164
|
+
* 终端提示留在 handler 层(service 不做终端输出)。
|
|
165
|
+
*/
|
|
166
|
+
function applySourcePathImport(opts, targetDir) {
|
|
167
|
+
// 真值判断:未传或空串都视为"无 source_path"。
|
|
168
|
+
if (!opts.sourcePath) {
|
|
169
|
+
return { sourceImported: false };
|
|
170
|
+
}
|
|
171
|
+
if (opts.appType === 'modern_html') {
|
|
172
|
+
const { importedFileCount } = (0, index_1.importSourceSrc)({ sourcePath: opts.sourcePath, targetDir });
|
|
173
|
+
return { sourceImported: true, importedFileCount };
|
|
174
|
+
}
|
|
175
|
+
(0, logger_1.log)('init', '⚠ source-path ignored: 仅 app_type=modern_html 支持 source_path 导入');
|
|
176
|
+
if (!(0, output_1.isJsonMode)()) {
|
|
177
|
+
process.stdout.write('⚠ 不支持 source_path(仅 app_type=modern_html 生效),已忽略\n');
|
|
178
|
+
}
|
|
179
|
+
return { sourceImported: false, sourceIgnoredReason: 'not_modern_html' };
|
|
180
|
+
}
|
|
@@ -135,6 +135,32 @@ async function handleAppMigrate(opts) {
|
|
|
135
135
|
installError = err instanceof Error ? err.message : String(err);
|
|
136
136
|
(0, logger_1.log)('migrate', `⚠ npm install failed (continuing): ${installError}`);
|
|
137
137
|
}
|
|
138
|
+
// 重启 dev process 前清 vite cache —— migrate 改了 package.json + lockfile,
|
|
139
|
+
// 老 vite 进程的 .vite/deps cache 的 lockfileHash 跟新 lockfile 不一致。
|
|
140
|
+
// 不清的话 supervisor 拉起的新 vite cold start 会立即 "Re-optimizing because
|
|
141
|
+
// lockfile has changed", re-optimize 期间 ModuleGraph transform cache 跟
|
|
142
|
+
// deps middleware metadata 短暂不同步, 浏览器请求老 hash 触发
|
|
143
|
+
// ERR_OUTDATED_OPTIMIZED_DEP → 504 死锁(详见 fullstack-plugin#1143 的 504
|
|
144
|
+
// ignoreOutdatedRequests fix 注释)。直接 rm -rf 让新 vite 从干净状态 cold
|
|
145
|
+
// optimize, 一次写到位 lockfile 一致的 metadata, 不再触发中途 re-optimize。
|
|
146
|
+
//
|
|
147
|
+
// - 只在 SANDBOX_ID 非空时做(本地一般不会撞这条链路)
|
|
148
|
+
// - 只在 install 成功时做(install 挂了 node_modules 状态不对, 清 cache 也救不回来)
|
|
149
|
+
// - 软失败:.vite 不存在 / 删失败都不阻断
|
|
150
|
+
if (installError === undefined &&
|
|
151
|
+
process.env.SANDBOX_ID !== undefined &&
|
|
152
|
+
process.env.SANDBOX_ID !== '') {
|
|
153
|
+
const viteCacheDir = node_path_1.default.join(targetDir, 'node_modules', '.vite');
|
|
154
|
+
if (node_fs_1.default.existsSync(viteCacheDir)) {
|
|
155
|
+
(0, logger_1.log)('migrate', '清理 node_modules/.vite (vite cache 跟新 lockfile 错位会 504)...');
|
|
156
|
+
try {
|
|
157
|
+
node_fs_1.default.rmSync(viteCacheDir, { recursive: true, force: true });
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
(0, logger_1.log)('migrate', `⚠ 清 .vite 失败 (continuing): ${err instanceof Error ? err.message : String(err)}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
138
164
|
// 沙箱环境下重启 dev process —— scripts/dev.js 被 fullstack 版本覆盖了,但当前正在
|
|
139
165
|
// 跑的 node 进程仍按老逻辑工作(只起 vite,没起 nest),整体没切到 fullstack 模式。
|
|
140
166
|
// 通过 pkill 杀掉 dev.js 主进程,依赖沙箱平台 supervisor 自动重新 exec dev.sh → dev.js,
|
package/dist/main.js
CHANGED
|
@@ -30,6 +30,9 @@ program
|
|
|
30
30
|
.argParser((0, shared_1.caseInsensitiveChoice)(['pretty', 'json']))
|
|
31
31
|
.default('pretty'))
|
|
32
32
|
.option('--verbose', 'debug 日志到 stderr')
|
|
33
|
+
// 全局接受 -y/--yes:作为 root 全局 option 下发到所有子命令解析(同 --json/--verbose),
|
|
34
|
+
// 让任意命令带 --yes 都不报 unknown option。对有确认门的破坏性命令生效,其余命令忽略。
|
|
35
|
+
.option('-y, --yes', '跳过确认提示(对有确认门的命令生效,其余命令忽略)')
|
|
33
36
|
.helpOption('-h, --help', '显示帮助信息')
|
|
34
37
|
.hook('preAction', (_thisCmd, actionCmd) => {
|
|
35
38
|
(0, log_id_1.generateLogId)();
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.IMPORT_SKIP_FILES = exports.IMPORT_SKIP_DIRS = void 0;
|
|
7
|
+
exports.importSourceSrc = importSourceSrc;
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const error_1 = require("../../../utils/error");
|
|
11
|
+
const logger_1 = require("../../../utils/logger");
|
|
12
|
+
/** 导入时跳过的目录名(任意层级命中即整目录跳过)。 */
|
|
13
|
+
exports.IMPORT_SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build']);
|
|
14
|
+
/** 导入时跳过的精确文件名。`.env.*`(如 .env.local)另由前缀规则处理。 */
|
|
15
|
+
exports.IMPORT_SKIP_FILES = new Set([
|
|
16
|
+
'.env',
|
|
17
|
+
'.DS_Store',
|
|
18
|
+
'.npmrc',
|
|
19
|
+
'package.json',
|
|
20
|
+
'package-lock.json',
|
|
21
|
+
'yarn.lock',
|
|
22
|
+
'pnpm-lock.yaml',
|
|
23
|
+
]);
|
|
24
|
+
function isSkippedFile(name) {
|
|
25
|
+
if (exports.IMPORT_SKIP_FILES.has(name))
|
|
26
|
+
return true;
|
|
27
|
+
// .env.local / .env.production 等一律跳过
|
|
28
|
+
if (name.startsWith('.env.'))
|
|
29
|
+
return true;
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 把整个 sourcePath 递归拷进 targetDir/src/(叠加,同名覆盖,不删目标已有文件),
|
|
34
|
+
* 按 IMPORT_SKIP_DIRS / IMPORT_SKIP_FILES 过滤。
|
|
35
|
+
* sourcePath 不存在或非目录 → 抛 ARGS_INVALID。
|
|
36
|
+
*/
|
|
37
|
+
function importSourceSrc(opts) {
|
|
38
|
+
const sourcePath = node_path_1.default.resolve(opts.sourcePath);
|
|
39
|
+
if (!node_fs_1.default.existsSync(sourcePath) || !node_fs_1.default.statSync(sourcePath).isDirectory()) {
|
|
40
|
+
throw new error_1.AppError('ARGS_INVALID', `--source-path 不存在或不是目录: ${opts.sourcePath}`);
|
|
41
|
+
}
|
|
42
|
+
const destSrc = node_path_1.default.join(opts.targetDir, 'src');
|
|
43
|
+
node_fs_1.default.mkdirSync(destSrc, { recursive: true });
|
|
44
|
+
let count = 0;
|
|
45
|
+
const walk = (relDir) => {
|
|
46
|
+
const absDir = node_path_1.default.join(sourcePath, relDir);
|
|
47
|
+
for (const entry of node_fs_1.default.readdirSync(absDir, { withFileTypes: true })) {
|
|
48
|
+
if (entry.isDirectory()) {
|
|
49
|
+
if (exports.IMPORT_SKIP_DIRS.has(entry.name))
|
|
50
|
+
continue;
|
|
51
|
+
walk(node_path_1.default.join(relDir, entry.name));
|
|
52
|
+
}
|
|
53
|
+
else if (entry.isFile()) {
|
|
54
|
+
if (isSkippedFile(entry.name))
|
|
55
|
+
continue;
|
|
56
|
+
const rel = node_path_1.default.join(relDir, entry.name);
|
|
57
|
+
const dest = node_path_1.default.join(destSrc, rel);
|
|
58
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(dest), { recursive: true });
|
|
59
|
+
node_fs_1.default.copyFileSync(node_path_1.default.join(sourcePath, rel), dest);
|
|
60
|
+
count += 1;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
walk('.');
|
|
65
|
+
(0, logger_1.log)('init', `Imported ${String(count)} file(s) from ${sourcePath} → src/`);
|
|
66
|
+
return { importedFileCount: count };
|
|
67
|
+
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ASYNC_INSTALL_LOG = exports.runAsyncInstallWorker = exports.dispatchAsyncInstall = exports.resolveNpmInstallRegistry = exports.installDependencies = exports.writeSparkMeta = exports.readSparkMeta = exports.TEMPLATE_PACKAGE_BY_STACK = exports.SUPPORTED_STACKS = exports.renderTemplate = void 0;
|
|
3
|
+
exports.ASYNC_INSTALL_LOG = exports.runAsyncInstallWorker = exports.dispatchAsyncInstall = exports.resolveNpmInstallRegistry = exports.installDependencies = exports.writeSparkMeta = exports.readSparkMeta = exports.IMPORT_SKIP_FILES = exports.IMPORT_SKIP_DIRS = exports.importSourceSrc = exports.TEMPLATE_PACKAGE_BY_STACK = exports.STACK_BY_APP_TYPE = exports.APP_TYPES = exports.SUPPORTED_STACKS = exports.resolveStack = exports.renderTemplate = void 0;
|
|
4
4
|
var template_1 = require("./template");
|
|
5
5
|
Object.defineProperty(exports, "renderTemplate", { enumerable: true, get: function () { return template_1.renderTemplate; } });
|
|
6
|
+
Object.defineProperty(exports, "resolveStack", { enumerable: true, get: function () { return template_1.resolveStack; } });
|
|
6
7
|
Object.defineProperty(exports, "SUPPORTED_STACKS", { enumerable: true, get: function () { return template_1.SUPPORTED_STACKS; } });
|
|
8
|
+
Object.defineProperty(exports, "APP_TYPES", { enumerable: true, get: function () { return template_1.APP_TYPES; } });
|
|
9
|
+
Object.defineProperty(exports, "STACK_BY_APP_TYPE", { enumerable: true, get: function () { return template_1.STACK_BY_APP_TYPE; } });
|
|
7
10
|
Object.defineProperty(exports, "TEMPLATE_PACKAGE_BY_STACK", { enumerable: true, get: function () { return template_1.TEMPLATE_PACKAGE_BY_STACK; } });
|
|
11
|
+
var import_source_1 = require("./import-source");
|
|
12
|
+
Object.defineProperty(exports, "importSourceSrc", { enumerable: true, get: function () { return import_source_1.importSourceSrc; } });
|
|
13
|
+
Object.defineProperty(exports, "IMPORT_SKIP_DIRS", { enumerable: true, get: function () { return import_source_1.IMPORT_SKIP_DIRS; } });
|
|
14
|
+
Object.defineProperty(exports, "IMPORT_SKIP_FILES", { enumerable: true, get: function () { return import_source_1.IMPORT_SKIP_FILES; } });
|
|
8
15
|
var spark_meta_1 = require("../../../utils/spark-meta");
|
|
9
16
|
Object.defineProperty(exports, "readSparkMeta", { enumerable: true, get: function () { return spark_meta_1.readSparkMeta; } });
|
|
10
17
|
Object.defineProperty(exports, "writeSparkMeta", { enumerable: true, get: function () { return spark_meta_1.writeSparkMeta; } });
|
|
@@ -3,7 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.SUPPORTED_STACKS = exports.TEMPLATE_PINNED_VERSION_BY_STACK = exports.TEMPLATE_PACKAGE_BY_STACK = void 0;
|
|
6
|
+
exports.APP_TYPES = exports.STACK_BY_APP_TYPE = exports.SUPPORTED_STACKS = exports.TEMPLATE_PINNED_VERSION_BY_STACK = exports.TEMPLATE_PACKAGE_BY_STACK = void 0;
|
|
7
|
+
exports.resolveStack = resolveStack;
|
|
7
8
|
exports.renderTemplate = renderTemplate;
|
|
8
9
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
@@ -25,6 +26,51 @@ exports.TEMPLATE_PACKAGE_BY_STACK = {
|
|
|
25
26
|
*/
|
|
26
27
|
exports.TEMPLATE_PINNED_VERSION_BY_STACK = {};
|
|
27
28
|
exports.SUPPORTED_STACKS = Object.keys(exports.TEMPLATE_PACKAGE_BY_STACK);
|
|
29
|
+
/**
|
|
30
|
+
* app_type(业务类型)→ stack 短名映射。仅在调用方未显式传 --template 时用于解析 stack。
|
|
31
|
+
* 与 src/api/app/types.ts 的 AppType 枚举无关,是独立的业务类型概念。
|
|
32
|
+
*/
|
|
33
|
+
exports.STACK_BY_APP_TYPE = {
|
|
34
|
+
html: 'html',
|
|
35
|
+
modern_html: 'html',
|
|
36
|
+
jspage: 'vite-react',
|
|
37
|
+
full_stack: 'nestjs-react-fullstack',
|
|
38
|
+
};
|
|
39
|
+
exports.APP_TYPES = Object.keys(exports.STACK_BY_APP_TYPE);
|
|
40
|
+
/**
|
|
41
|
+
* 解析要用的 stack(template-first):
|
|
42
|
+
* 1. template 传了 → 直接用(SUPPORTED_STACKS 校验)
|
|
43
|
+
* 2. 否则 appType 传了 → 按 STACK_BY_APP_TYPE 查表
|
|
44
|
+
* 3. 都没传 → ARGS_INVALID
|
|
45
|
+
* 非法 template / 非法 appType 均抛 ARGS_INVALID。
|
|
46
|
+
*/
|
|
47
|
+
function resolveStack(opts) {
|
|
48
|
+
const { template, appType } = opts;
|
|
49
|
+
// 用真值判断(非 undefined/null/空串):空串视为未传,回落到 appType。
|
|
50
|
+
if (template) {
|
|
51
|
+
if (!exports.SUPPORTED_STACKS.includes(template)) {
|
|
52
|
+
throw new error_1.AppError('ARGS_INVALID', `不支持的 template: ${template}`, {
|
|
53
|
+
next_actions: [`可用 stack:${exports.SUPPORTED_STACKS.join(', ')}`],
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return template;
|
|
57
|
+
}
|
|
58
|
+
if (appType) {
|
|
59
|
+
const stack = exports.STACK_BY_APP_TYPE[appType];
|
|
60
|
+
if (!stack) {
|
|
61
|
+
throw new error_1.AppError('ARGS_INVALID', `不支持的 app_type: ${appType}`, {
|
|
62
|
+
next_actions: [`可用 app_type:${exports.APP_TYPES.join(', ')}`],
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return stack;
|
|
66
|
+
}
|
|
67
|
+
throw new error_1.AppError('ARGS_INVALID', '缺少 --template 或 --app-type', {
|
|
68
|
+
next_actions: [
|
|
69
|
+
`可用 stack:${exports.SUPPORTED_STACKS.join(', ')}`,
|
|
70
|
+
`可用 app_type:${exports.APP_TYPES.join(', ')}`,
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
}
|
|
28
74
|
// template/ 内以下划线开头的占位文件名在渲染时改名。
|
|
29
75
|
// 原因:
|
|
30
76
|
// 1. npm pack 强制剥的:.npmrc(防 auth token 泄露)
|