@meadmin/cli 1.3.7 → 1.3.8
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/commanders/index.js +4 -2
- package/dist/commanders/update.d.ts +3 -0
- package/dist/commanders/update.js +132 -0
- package/dist/update/backup.d.ts +21 -0
- package/dist/update/backup.js +120 -0
- package/dist/update/merge.d.ts +7 -0
- package/dist/update/merge.js +432 -0
- package/dist/update/planner.d.ts +17 -0
- package/dist/update/planner.js +116 -0
- package/dist/update/rules.d.ts +12 -0
- package/dist/update/rules.js +55 -0
- package/dist/update/source.d.ts +10 -0
- package/dist/update/source.js +750 -0
- package/dist/update/sql.d.ts +12 -0
- package/dist/update/sql.js +589 -0
- package/dist/update/template.d.ts +20 -0
- package/dist/update/template.js +147 -0
- package/package.json +4 -4
- package/template/update.defaults.json +29 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, lstatSync, readFileSync, readdirSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { mergeConfig, mergeEntity, mergePackage } from './merge.js';
|
|
5
|
+
import { excluded, skipExisting, sourceMode } from './rules.js';
|
|
6
|
+
import { isIntegrationSource, mergeSource } from './source.js';
|
|
7
|
+
import { generateUpdateSql } from './sql.js';
|
|
8
|
+
export const hash = (content) => createHash('sha256').update(content).digest('hex');
|
|
9
|
+
export function readLocal(root, path) {
|
|
10
|
+
let current = root;
|
|
11
|
+
for (const part of path.split('/')) {
|
|
12
|
+
current = join(current, part);
|
|
13
|
+
if (existsSync(current) && lstatSync(current).isSymbolicLink())
|
|
14
|
+
throw new Error(`拒绝操作符号链接:${path}`);
|
|
15
|
+
}
|
|
16
|
+
if (!existsSync(current))
|
|
17
|
+
return undefined;
|
|
18
|
+
if (!lstatSync(current).isFile())
|
|
19
|
+
throw new Error(`文件路径被目录占用:${path}`);
|
|
20
|
+
return readFileSync(current);
|
|
21
|
+
}
|
|
22
|
+
function templateFiles(root) {
|
|
23
|
+
const files = new Map(), names = new Set();
|
|
24
|
+
const visit = (directory, prefix = '') => {
|
|
25
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
26
|
+
const sourcePath = prefix + entry.name;
|
|
27
|
+
if (excluded(sourcePath))
|
|
28
|
+
continue;
|
|
29
|
+
if (entry.isSymbolicLink())
|
|
30
|
+
throw new Error(`模板含符号链接:${sourcePath}`);
|
|
31
|
+
if (entry.isDirectory())
|
|
32
|
+
visit(join(directory, entry.name), sourcePath + '/');
|
|
33
|
+
else if (entry.isFile()) {
|
|
34
|
+
const path = prefix + (entry.name === 'packageTemplate.json' ? 'package.json' : entry.name);
|
|
35
|
+
if (names.has(path.toLowerCase()))
|
|
36
|
+
throw new Error(`模板映射路径冲突:${path}`);
|
|
37
|
+
names.add(path.toLowerCase());
|
|
38
|
+
files.set(path, readFileSync(join(directory, entry.name)));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
visit(root);
|
|
43
|
+
return files;
|
|
44
|
+
}
|
|
45
|
+
export function makePlan(root, oldTemplate, targetTemplate, targetVersion, rules, sourceRules = {}) {
|
|
46
|
+
const base = templateFiles(oldTemplate), target = templateFiles(targetTemplate);
|
|
47
|
+
const plan = { changes: [], skipped: [], manual: [], sqlTables: [] };
|
|
48
|
+
const add = (path, content, action, previous, conflict = false) => {
|
|
49
|
+
if (previous?.equals(content))
|
|
50
|
+
return;
|
|
51
|
+
plan.changes.push({ path, action: previous ? action : 'create', previous: previous ? hash(previous) : null, content, conflict });
|
|
52
|
+
};
|
|
53
|
+
for (const [path, content] of target) {
|
|
54
|
+
if (path.toLowerCase() === 'meadmin.sql')
|
|
55
|
+
continue;
|
|
56
|
+
if (path.toLowerCase() === 'update.sql' || /^meadmin-.*\.sql$/i.test(path)) {
|
|
57
|
+
plan.manual.push(`${path}: 模板含升级产物保留名称,未复制`);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const local = readLocal(root, path), old = base.get(path);
|
|
61
|
+
if (local && skipExisting(path, rules)) {
|
|
62
|
+
plan.skipped.push(`${path}: 存在时跳过`);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (local?.equals(content) || (old?.equals(content) && local))
|
|
66
|
+
continue;
|
|
67
|
+
if (!local) {
|
|
68
|
+
add(path, content, 'create');
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const conflict = !old || !old.equals(local);
|
|
72
|
+
const explicitMode = sourceMode(path, sourceRules);
|
|
73
|
+
const sourceFile = /\.[cm]?[jt]s$/.test(path);
|
|
74
|
+
const builtinMerge = path === 'package.json' || path.endsWith('/package.json') || /(^|\/)entities\//.test(path) || /(^|\/)src\/config\//.test(path);
|
|
75
|
+
// 显式 false 关闭自动识别;默认不扩大到有运行时初始化逻辑的入口。
|
|
76
|
+
const mode = sourceFile && !builtinMerge ? (explicitMode === undefined && isIntegrationSource(content.toString('utf8')) ? 'exports' : explicitMode) : undefined;
|
|
77
|
+
if (mode) {
|
|
78
|
+
const result = mergeSource(local.toString('utf8'), content.toString('utf8'), old?.toString('utf8'), mode, path);
|
|
79
|
+
plan.manual.push(...result.manual.map((message) => `${path}: ${message}`));
|
|
80
|
+
add(path, Buffer.from(result.content), 'merge', local, conflict);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const merge = path.endsWith('/package.json') || path === 'package.json' ? mergePackage : /(^|\/)entities\/.*\.ts$/.test(path) ? mergeEntity : /(^|\/)src\/config\//.test(path) && path.endsWith('.ts') ? mergeConfig : undefined;
|
|
84
|
+
if (merge) {
|
|
85
|
+
try {
|
|
86
|
+
const result = merge(local.toString('utf8'), content.toString('utf8'), old?.toString('utf8'));
|
|
87
|
+
plan.manual.push(...result.manual.map((message) => `${path}: ${message}`));
|
|
88
|
+
add(path, Buffer.from(result.content), 'merge', local, conflict);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
plan.manual.push(`${path}: 合并失败,需人工处理:${String(error)}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else if (/(^|\/)(vite\.config\.[^/]+|eslint\.config\.[^/]+|tsconfig[^/]*\.json|pnpm-workspace\.yaml)$/.test(path)) {
|
|
95
|
+
plan.manual.push(`${path}: 工程配置变化,保留本地,需人工对照目标模板`);
|
|
96
|
+
}
|
|
97
|
+
else
|
|
98
|
+
add(path, content, 'overwrite', local, conflict);
|
|
99
|
+
}
|
|
100
|
+
for (const path of base.keys())
|
|
101
|
+
if (!target.has(path) && !excluded(path))
|
|
102
|
+
plan.manual.push(`${path}: 目标模板已移除,本地不会删除`);
|
|
103
|
+
const sql = [...target].find(([path]) => path.toLowerCase() === 'meadmin.sql')?.[1];
|
|
104
|
+
if (sql) {
|
|
105
|
+
const generated = generateUpdateSql(sql.toString('utf8'), targetVersion);
|
|
106
|
+
const originalName = `meadmin-${targetVersion}.sql`;
|
|
107
|
+
add(originalName, sql, 'overwrite', readLocal(root, originalName));
|
|
108
|
+
add('update.sql', Buffer.from(generated.content), 'overwrite', readLocal(root, 'update.sql'));
|
|
109
|
+
plan.manual.push(...generated.manual.map((item) => 'SQL: ' + item));
|
|
110
|
+
plan.sqlTables = generated.tables;
|
|
111
|
+
}
|
|
112
|
+
else
|
|
113
|
+
plan.manual.push('目标模板缺少 meadmin.sql,未生成数据升级脚本');
|
|
114
|
+
return plan;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxhbm5lci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91cGRhdGUvcGxhbm5lci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDM0UsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNqQyxPQUFPLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDcEUsT0FBTyxFQUFFLFFBQVEsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxXQUFXLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDL0QsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sVUFBVSxDQUFDO0FBSTdDLE1BQU0sQ0FBQyxNQUFNLElBQUksR0FBRyxDQUFDLE9BQWUsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDNUYsTUFBTSxVQUFVLFNBQVMsQ0FBQyxJQUFZLEVBQUUsSUFBWTtJQUNsRCxJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUM7SUFDbkIsS0FBSyxNQUFNLElBQUksSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDbkMsT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDOUIsSUFBSSxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUksU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLGNBQWMsRUFBRTtZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMs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
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type SourcePolicy = 'functions' | 'exports' | false;
|
|
2
|
+
export type UpdateRules = {
|
|
3
|
+
skipExisting: Record<string, boolean>;
|
|
4
|
+
mergeSource: Record<string, SourcePolicy>;
|
|
5
|
+
};
|
|
6
|
+
export declare const defaults: Record<string, boolean>;
|
|
7
|
+
export declare const sourceDefaults: Record<string, SourcePolicy>;
|
|
8
|
+
export declare function excluded(path: string): boolean;
|
|
9
|
+
export declare function skipExisting(path: string, user?: Record<string, boolean>): boolean;
|
|
10
|
+
export declare function sourceMode(path: string, user?: Record<string, SourcePolicy>): SourcePolicy | undefined;
|
|
11
|
+
export declare function validateConfig(value: unknown): UpdateRules;
|
|
12
|
+
export declare const validateRules: (value: unknown) => Record<string, boolean>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { matchesGlob } from 'node:path';
|
|
3
|
+
const builtin = JSON.parse(readFileSync(new URL('../../template/update.defaults.json', import.meta.url), 'utf8'));
|
|
4
|
+
export const defaults = builtin.skipExisting;
|
|
5
|
+
export const sourceDefaults = builtin.mergeSource;
|
|
6
|
+
export function excluded(path) {
|
|
7
|
+
const normalized = path.toLowerCase();
|
|
8
|
+
return normalized.split('/').some((p) => ['.git', '.workbuddy', '.meadmin', 'node_modules', 'dist', 'logs', 'uploadfile'].includes(p)) || /(^|\/)(pnpm-lock\.yaml|package-lock\.json|yarn\.lock|.*\.tsbuildinfo)$/.test(normalized);
|
|
9
|
+
}
|
|
10
|
+
/** 精确路径优先;可证明的目录子集优先;无法区分的冲突规则拒绝猜测。 */
|
|
11
|
+
function resolveRule(path, rules) {
|
|
12
|
+
const entries = Object.entries(rules).filter(([pattern]) => matchesGlob(path, pattern));
|
|
13
|
+
const exact = entries.find(([pattern]) => !/[?*[{]/.test(pattern));
|
|
14
|
+
if (exact)
|
|
15
|
+
return exact[1];
|
|
16
|
+
const prefix = (pattern) => pattern.slice(0, pattern.search(/[?*[{]/));
|
|
17
|
+
const within = (specific, broad) => {
|
|
18
|
+
if (!broad.endsWith('/**') && !broad.endsWith('/**/*.ts'))
|
|
19
|
+
return false;
|
|
20
|
+
const broadPrefix = prefix(broad);
|
|
21
|
+
return !/[?*[{]/.test(broadPrefix) && prefix(specific).startsWith(broadPrefix) && prefix(specific).length > broadPrefix.length;
|
|
22
|
+
};
|
|
23
|
+
const candidates = entries.filter(([pattern]) => !entries.some(([other]) => other !== pattern && within(other, pattern)));
|
|
24
|
+
if (!candidates.length)
|
|
25
|
+
return undefined;
|
|
26
|
+
if (candidates.some(([, value]) => value !== candidates[0][1]))
|
|
27
|
+
throw new Error(`规则冲突:${path},请使用精确路径消除歧义`);
|
|
28
|
+
return candidates[0][1];
|
|
29
|
+
}
|
|
30
|
+
export function skipExisting(path, user = {}) {
|
|
31
|
+
return resolveRule(path, { ...defaults, ...user }) ?? false;
|
|
32
|
+
}
|
|
33
|
+
export function sourceMode(path, user = {}) {
|
|
34
|
+
return resolveRule(path, { ...sourceDefaults, ...user });
|
|
35
|
+
}
|
|
36
|
+
export function validateConfig(value) {
|
|
37
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
38
|
+
throw new Error('规则文件必须为JSON对象');
|
|
39
|
+
const config = value;
|
|
40
|
+
if (Object.keys(config).some((k) => !['skipExisting', 'mergeSource'].includes(k)))
|
|
41
|
+
throw new Error('规则仅支持 skipExisting、mergeSource');
|
|
42
|
+
const check = (name, allowed) => {
|
|
43
|
+
const rules = config[name] ?? {};
|
|
44
|
+
if (typeof rules !== 'object' || rules === null || Array.isArray(rules))
|
|
45
|
+
throw new Error(`${name} 必须为对象`);
|
|
46
|
+
for (const [path, mode] of Object.entries(rules)) {
|
|
47
|
+
if (!path || path.startsWith('/') || path.includes('\\') || path.includes(':') || path.split('/').some((part) => part === '..' || part === '.') || !allowed.includes(mode))
|
|
48
|
+
throw new Error(`${name}规则无效:${path}`);
|
|
49
|
+
}
|
|
50
|
+
return rules;
|
|
51
|
+
};
|
|
52
|
+
return { skipExisting: check('skipExisting', [true, false]), mergeSource: check('mergeSource', ['functions', 'exports', false]) };
|
|
53
|
+
}
|
|
54
|
+
export const validateRules = (value) => validateConfig(value).skipExisting;
|
|
55
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXBkYXRlL3J1bGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDdkMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUl4QyxNQUFNLE9BQU8sR0FBZ0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsSUFBSSxHQUFHLENBQUMscUNBQXFDLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDO0FBQy9ILE1BQU0sQ0FBQyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsWUFBWSxDQUFDO0FBQzdDLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsV0FBVyxDQUFDO0FBRWxELE1BQU0sVUFBVSxRQUFRLENBQUMsSUFBWTtJQUNuQyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDdEMsT0FBTyxVQUFVLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxjQUFjLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxZQUFZLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSx3RUFBd0UsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7QUFDdE8sQ0FBQztBQUVELHVDQUF1QztBQUN2QyxTQUFTLFdBQVcsQ0FBSSxJQUFZLEVBQUUsS0FBd0I7SUFDNUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxXQUFXLENB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
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type SourceMergeMode = 'functions' | 'exports';
|
|
2
|
+
export type SourceMergeResult = {
|
|
3
|
+
content: string;
|
|
4
|
+
manual: string[];
|
|
5
|
+
changed: boolean;
|
|
6
|
+
};
|
|
7
|
+
/** 只识别静态集成入口;包含类、函数或执行语句的入口仍交由其他规则处理。 */
|
|
8
|
+
export declare function isIntegrationSource(text: string): boolean;
|
|
9
|
+
/** 按函数和静态注册项增量合并,所有坐标和文本均属于节点自身的 SourceFile。 */
|
|
10
|
+
export declare function mergeSource(localText: string, targetText: string, baseText: string | undefined, mode: SourceMergeMode, path?: string): SourceMergeResult;
|