@lark-apaas/miaoda-cli 0.1.19 → 0.1.20-beta.4eeca5a
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/db/index.js +0 -3
- package/dist/cli/commands/file/index.js +4 -3
- package/dist/cli/handlers/app/migrate.js +26 -0
- package/dist/config/migrate-configs/vite-react-to-nestjs-react-fullstack.js +21 -0
- package/dist/main.js +3 -0
- package/dist/utils/sync-rule.js +50 -0
- package/package.json +1 -1
|
@@ -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:
|
|
@@ -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,
|
|
@@ -67,9 +67,26 @@ exports.MIGRATE_CONFIG = {
|
|
|
67
67
|
{ type: 'file', from: 'tsconfig.json', to: 'tsconfig.json', overwrite: true },
|
|
68
68
|
{ type: 'file', from: 'tsconfig.app.json', to: 'tsconfig.app.json', overwrite: true },
|
|
69
69
|
{ type: 'file', from: 'tsconfig.node.json', to: 'tsconfig.node.json', overwrite: true },
|
|
70
|
+
// vite-react template 的 tsconfig 里有 exclude: ["src/components/ui"],把 shadcn 组件目录
|
|
71
|
+
// 整个从 typecheck 排除 —— 因为 template 里 shadcn 组件是老写法(recharts 2.x / RP v3 API),
|
|
72
|
+
// 但 dep 已经装到 recharts 3.x / RP v4 新版,两侧错配靠 exclude 藏起来。
|
|
73
|
+
// fullstack template 的 tsconfig 没这条 exclude,migrate 覆盖后 user 老 shadcn 组件
|
|
74
|
+
// (client/src/components/ui/*.tsx) 立刻被 tsc 扫到,chart.tsx / resizable.tsx 类型 / 命名报错。
|
|
75
|
+
// 这里在覆盖 tsconfig.app.json 之后补一行 exclude,跟 vite-react 行为对齐。
|
|
76
|
+
{
|
|
77
|
+
type: 'add-json-array-items',
|
|
78
|
+
to: 'tsconfig.app.json',
|
|
79
|
+
path: ['exclude'],
|
|
80
|
+
items: ['client/src/components/ui'],
|
|
81
|
+
},
|
|
70
82
|
// ESLint 9 flat config —— vite-react 用 eslint.config.mjs 已删,fullstack 用
|
|
71
83
|
// eslint.config.js (commonjs) + extends @lark-apaas/fullstack-presets;user 通常不改
|
|
72
84
|
{ type: 'file', from: 'eslint.config.js', to: 'eslint.config.js', overwrite: true },
|
|
85
|
+
// stylelint 配置 —— package.json 加了 `stylelint` script(下面 add-script 那条)
|
|
86
|
+
// + npm run precommit 会调它,缺配置文件时报 `No configuration provided for
|
|
87
|
+
// client/src/index.css`。fullstack template 的 .stylelintrc.js extends
|
|
88
|
+
// @lark-apaas/fullstack-presets 的 stylelintPresetsOfSimple。
|
|
89
|
+
{ type: 'file', from: '.stylelintrc.js', to: '.stylelintrc.js', overwrite: true },
|
|
73
90
|
// client/index.html:HBS 模板(fullstack 用,vite-react 用根 index.html 已删)
|
|
74
91
|
{ type: 'file', from: 'client/index.html', to: 'client/index.html', overwrite: true },
|
|
75
92
|
// scripts/ 整目录:fullstack 形态启动 / 构建 / lint 所需的 8 个平台脚本(dev.sh /
|
|
@@ -274,6 +291,10 @@ exports.MIGRATE_CONFIG = {
|
|
|
274
291
|
// (@lark-apaas/fullstack-presets/lib/simple/tsconfig/tsconfig.node.json);
|
|
275
292
|
// 不装会导致 nest build / type:check:server / vite dev 解析 tsconfig 时 ENOENT
|
|
276
293
|
'@lark-apaas/fullstack-presets',
|
|
294
|
+
// stylelint —— scripts.stylelint + npm run precommit 会调它,
|
|
295
|
+
// 缺依赖时 CI / 本地 precommit 报 "stylelint: command not found"。
|
|
296
|
+
// 配套的 .stylelintrc.js 由上面 file rule 从 template 搬过来。
|
|
297
|
+
'stylelint',
|
|
277
298
|
],
|
|
278
299
|
},
|
|
279
300
|
// ===== 7. 业务代码 codemod:lite → client-toolkit 包名替换 =====
|
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)();
|
package/dist/utils/sync-rule.js
CHANGED
|
@@ -109,6 +109,9 @@ function applyOne(rule, opts) {
|
|
|
109
109
|
case 'merge-json': {
|
|
110
110
|
return applyMergeJson(rule, sourceRoot, targetDir, logPrefix);
|
|
111
111
|
}
|
|
112
|
+
case 'add-json-array-items': {
|
|
113
|
+
return applyAddJsonArrayItems(rule, targetDir, logPrefix);
|
|
114
|
+
}
|
|
112
115
|
case 'directory': {
|
|
113
116
|
const src = node_path_1.default.join(sourceRoot, rule.from);
|
|
114
117
|
const dest = node_path_1.default.join(targetDir, rule.to);
|
|
@@ -257,6 +260,53 @@ function applyMergeJson(rule, sourceRoot, targetDir, logPrefix) {
|
|
|
257
260
|
(0, logger_1.log)(logPrefix, ` ✓ ${rule.to} (merged: ${keys})`);
|
|
258
261
|
return { rule, action: 'merged', path: rule.to, detail: keys };
|
|
259
262
|
}
|
|
263
|
+
function applyAddJsonArrayItems(rule, targetDir, logPrefix) {
|
|
264
|
+
const dest = node_path_1.default.join(targetDir, rule.to);
|
|
265
|
+
if (!node_fs_1.default.existsSync(dest)) {
|
|
266
|
+
(0, logger_1.log)(logPrefix, ` ○ ${rule.to} (not found, skip add-json-array-items)`);
|
|
267
|
+
return { rule, action: 'skipped', path: rule.to };
|
|
268
|
+
}
|
|
269
|
+
const originalText = node_fs_1.default.readFileSync(dest, 'utf-8');
|
|
270
|
+
// 读一次拿数组当前值来判断幂等;jsonc 兼容 trailing comma / 注释。
|
|
271
|
+
const errors = [];
|
|
272
|
+
const root = jsonc.parse(originalText, errors, { allowTrailingComma: true });
|
|
273
|
+
if (errors.length > 0) {
|
|
274
|
+
const first = errors[0];
|
|
275
|
+
throw new Error(`${rule.to}: jsonc parse error ${jsonc.printParseErrorCode(first.error)} at offset ${String(first.offset)}`);
|
|
276
|
+
}
|
|
277
|
+
// 沿 rule.path 走到目标节点
|
|
278
|
+
let node = root;
|
|
279
|
+
for (const seg of rule.path) {
|
|
280
|
+
if (node && typeof node === 'object' && seg in node) {
|
|
281
|
+
node = node[seg];
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
node = undefined;
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (!Array.isArray(node)) {
|
|
289
|
+
(0, logger_1.log)(logPrefix, ` ○ ${rule.to} (path ${rule.path.join('.')} is not an array, skip)`);
|
|
290
|
+
return { rule, action: 'skipped', path: rule.to };
|
|
291
|
+
}
|
|
292
|
+
const existing = new Set(node.filter((v) => typeof v === 'string'));
|
|
293
|
+
const toAdd = rule.items.filter((it) => !existing.has(it));
|
|
294
|
+
if (toAdd.length === 0) {
|
|
295
|
+
(0, logger_1.log)(logPrefix, ` ○ ${rule.to} (${rule.path.join('.')} already has all items)`);
|
|
296
|
+
return { rule, action: 'noop', path: rule.to };
|
|
297
|
+
}
|
|
298
|
+
// jsonc.modify 逐项 append,保留缩进 / 注释 / trailing comma。
|
|
299
|
+
let text = originalText;
|
|
300
|
+
for (const item of toAdd) {
|
|
301
|
+
const edits = jsonc.modify(text, [...rule.path, -1], item, {
|
|
302
|
+
formattingOptions: { insertSpaces: true, tabSize: 2 },
|
|
303
|
+
});
|
|
304
|
+
text = jsonc.applyEdits(text, edits);
|
|
305
|
+
}
|
|
306
|
+
node_fs_1.default.writeFileSync(dest, text);
|
|
307
|
+
(0, logger_1.log)(logPrefix, ` ✓ ${rule.to} (${rule.path.join('.')} += ${toAdd.map((s) => JSON.stringify(s)).join(', ')})`);
|
|
308
|
+
return { rule, action: 'patched', path: rule.to, detail: toAdd.join(',') };
|
|
309
|
+
}
|
|
260
310
|
/**
|
|
261
311
|
* 用 jsonc-parser 读 user 端 JSON 文件,兼容 tsconfig/nest-cli.json 等带 trailing comma 或
|
|
262
312
|
* 注释的配置。模板侧严格 JSON 走 JSON.parse 也能通,统一走 jsonc 简化代码。
|