@lark-apaas/miaoda-cli 0.1.46 → 0.1.47

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.
@@ -0,0 +1,146 @@
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.writePathSymlinkConflicts = writePathSymlinkConflicts;
7
+ exports.migrationWritePaths = migrationWritePaths;
8
+ exports.migrationSymlinkConflicts = migrationSymlinkConflicts;
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const project_snapshot_1 = require("../../../utils/project-snapshot");
12
+ function rulePaths(rule) {
13
+ switch (rule.type) {
14
+ case 'set-stack':
15
+ return ['.spark/meta.json'];
16
+ case 'add-script':
17
+ case 'patch-script':
18
+ case 'ensure-dependency':
19
+ return ['package.json'];
20
+ case 'codemod-client-toolkit-lite':
21
+ return [rule.root ?? 'client/src'];
22
+ case 'codemod-vite-config-fullstack':
23
+ return [rule.to ?? 'vite.config.ts'];
24
+ case 'add-deps-from-template':
25
+ case 'ensure-scripts':
26
+ return [rule.to ?? 'package.json'];
27
+ case 'adapt-nest-app-module':
28
+ return [rule.to ?? 'server/app.module.ts', rule.checkMain ?? 'server/main.ts'];
29
+ case 'move-directory':
30
+ case 'move-file':
31
+ case 'move-capabilities':
32
+ case 'adapt-html-entry':
33
+ return [rule.from, rule.to];
34
+ default:
35
+ return [rule.to];
36
+ }
37
+ }
38
+ function overlaps(first, second) {
39
+ return (first === '.' ||
40
+ second === '.' ||
41
+ first === second ||
42
+ first.startsWith(`${second}/`) ||
43
+ second.startsWith(`${first}/`));
44
+ }
45
+ function writePathSymlinkConflicts(root, writePaths) {
46
+ const links = new Set();
47
+ for (const rel of writePaths) {
48
+ const parts = rel.split('/');
49
+ for (let count = 1; count <= parts.length; count++) {
50
+ const parent = parts.slice(0, count).join('/');
51
+ try {
52
+ if (node_fs_1.default.lstatSync(node_path_1.default.join(root, parent)).isSymbolicLink()) {
53
+ links.add(parent);
54
+ break;
55
+ }
56
+ }
57
+ catch (err) {
58
+ if (err.code !== 'ENOENT')
59
+ throw err;
60
+ break;
61
+ }
62
+ }
63
+ }
64
+ return [...links].sort().map((rel) => ({
65
+ path: rel,
66
+ reason: 'symlink intersects a migration write path; replace it with a project-owned file or directory',
67
+ }));
68
+ }
69
+ function migrationWritePaths(rules, mode) {
70
+ return [
71
+ '.spark/meta.json',
72
+ '.spark/local',
73
+ 'package.json',
74
+ 'package-lock.json',
75
+ 'node_modules',
76
+ ...rules.filter((rule) => mode !== 'repair' || rule.migrateOnly !== true).flatMap(rulePaths),
77
+ ];
78
+ }
79
+ function migrationSymlinkConflicts(root, writePaths, installed = false) {
80
+ const writeConflicts = writePathSymlinkConflicts(root, writePaths);
81
+ if (writeConflicts.length > 0)
82
+ return writeConflicts;
83
+ const links = new Set();
84
+ const pending = [''];
85
+ while (pending.length > 0) {
86
+ const directory = pending.pop() ?? '';
87
+ for (const name of node_fs_1.default.readdirSync(node_path_1.default.join(root, directory))) {
88
+ const rel = directory === '' ? name : `${directory}/${name}`;
89
+ if ((0, project_snapshot_1.isExcludedPath)(rel) &&
90
+ !(installed && (rel === 'node_modules' || rel.startsWith('node_modules/')))) {
91
+ continue;
92
+ }
93
+ const stat = node_fs_1.default.lstatSync(node_path_1.default.join(root, rel));
94
+ if (stat.isSymbolicLink()) {
95
+ links.add(rel);
96
+ }
97
+ else if (stat.isDirectory()) {
98
+ pending.push(rel);
99
+ }
100
+ }
101
+ }
102
+ return [...links].sort().flatMap((rel) => {
103
+ const link = node_fs_1.default.readlinkSync(node_path_1.default.join(root, rel));
104
+ if (writePaths.some((writePath) => overlaps(rel, writePath)) &&
105
+ !(installed && rel.startsWith('node_modules/'))) {
106
+ return [
107
+ {
108
+ path: rel,
109
+ reason: 'symlink intersects a migration write path; replace it with a project-owned file or directory',
110
+ },
111
+ ];
112
+ }
113
+ if (node_path_1.default.isAbsolute(link)) {
114
+ return [
115
+ {
116
+ path: rel,
117
+ reason: 'absolute symlink would let in-place install/build reach outside the project',
118
+ },
119
+ ];
120
+ }
121
+ try {
122
+ const resolved = node_fs_1.default.realpathSync(node_path_1.default.join(root, rel));
123
+ const target = node_path_1.default.relative(node_fs_1.default.realpathSync(root), resolved).split(node_path_1.default.sep).join('/');
124
+ const parts = target.split('/');
125
+ const excluded = !(installed && target.startsWith('node_modules/')) &&
126
+ parts.some((_, index) => (0, project_snapshot_1.isExcludedPath)(parts.slice(0, index + 1).join('/')));
127
+ if (target === '..' || target.startsWith('../') || node_path_1.default.isAbsolute(target) || excluded) {
128
+ return [
129
+ {
130
+ path: rel,
131
+ reason: 'symlink target is outside the project or in an excluded directory; in-place install/build could escape',
132
+ },
133
+ ];
134
+ }
135
+ }
136
+ catch {
137
+ return [
138
+ {
139
+ path: rel,
140
+ reason: 'symlink target cannot be resolved safely for in-place install/build',
141
+ },
142
+ ];
143
+ }
144
+ return [];
145
+ });
146
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /**
3
+ * 工程操作的本地执行记录(.spark/local/engineering-state.json)。
4
+ *
5
+ * 为什么不写进 .spark/meta.json:meta.json 随 Git 提交,而依赖是否装好、上次迁移停在哪个阶段
6
+ * 是本机/本沙箱的事实,不能跟着代码传播到别的副本。.spark/local/ 目录自带 `.gitignore`(`*`),
7
+ * 整个目录不进 Git。
8
+ *
9
+ * 用途:
10
+ * - init --strict 判断工程是否真正就绪(上次安装失败 / 迁移未完成不能凭 meta 存在放行)
11
+ * - migrate 重试时核对上一次执行(源/目标、停在哪个阶段)
12
+ * 这是执行记录,不是平台状态源;平台权威结果仍由调用方读回。
13
+ */
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.LOCAL_STATE_DIR = void 0;
19
+ exports.readEngineeringState = readEngineeringState;
20
+ exports.writeEngineeringState = writeEngineeringState;
21
+ const node_fs_1 = __importDefault(require("node:fs"));
22
+ const node_path_1 = __importDefault(require("node:path"));
23
+ exports.LOCAL_STATE_DIR = node_path_1.default.join('.spark', 'local');
24
+ const STATE_FILE = 'engineering-state.json';
25
+ function ensureLocalDir(appDir) {
26
+ const dir = node_path_1.default.join(appDir, exports.LOCAL_STATE_DIR);
27
+ node_fs_1.default.mkdirSync(dir, { recursive: true });
28
+ const ignore = node_path_1.default.join(dir, '.gitignore');
29
+ if (!node_fs_1.default.existsSync(ignore))
30
+ node_fs_1.default.writeFileSync(ignore, '*\n', 'utf-8');
31
+ return dir;
32
+ }
33
+ function readEngineeringState(appDir) {
34
+ const file = node_path_1.default.join(appDir, exports.LOCAL_STATE_DIR, STATE_FILE);
35
+ if (!node_fs_1.default.existsSync(file))
36
+ return undefined;
37
+ try {
38
+ return JSON.parse(node_fs_1.default.readFileSync(file, 'utf-8'));
39
+ }
40
+ catch {
41
+ // 本地执行记录损坏只影响诊断,不影响工程本身;按"无记录"处理并由调用方重新校验
42
+ return undefined;
43
+ }
44
+ }
45
+ function writeEngineeringState(appDir, state) {
46
+ const dir = ensureLocalDir(appDir);
47
+ const file = node_path_1.default.join(dir, STATE_FILE);
48
+ const tmp = `${file}.${process.pid.toString()}.tmp`;
49
+ const payload = { ...state, updatedAt: new Date().toISOString() };
50
+ node_fs_1.default.writeFileSync(tmp, JSON.stringify(payload, null, 2) + '\n', 'utf-8');
51
+ node_fs_1.default.renameSync(tmp, file);
52
+ }