template-syncer 1.1.3 → 1.2.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/README.md +39 -123
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -1
- package/lib/package.json +3 -61
- package/lib/syncer.d.ts +0 -10
- package/lib/syncer.d.ts.map +1 -1
- package/lib/syncer.js +11 -41
- package/lib/syncer.js.map +1 -1
- package/lib/types.d.ts +0 -1
- package/lib/types.js +0 -1
- package/lib/ui/index.d.ts +0 -1
- package/lib/ui/index.js +0 -1
- package/lib/ui/logger.d.ts +6 -22
- package/lib/ui/logger.js +21 -49
- package/lib/ui/prompts.d.ts +0 -32
- package/lib/ui/prompts.js +61 -87
- package/lib/ui/tree.d.ts +0 -1
- package/lib/ui/tree.js +0 -1
- package/lib/utils/categorizer.d.ts +0 -1
- package/lib/utils/categorizer.js +0 -1
- package/lib/utils/git.d.ts +0 -1
- package/lib/utils/git.js +0 -1
- package/lib/utils/index.d.ts +0 -1
- package/lib/utils/index.js +0 -1
- package/lib/utils/merger.d.ts +2 -27
- package/lib/utils/merger.d.ts.map +1 -1
- package/lib/utils/merger.js +56 -114
- package/lib/utils/merger.js.map +1 -1
- package/lib/utils/platform.d.ts +5 -2
- package/lib/utils/platform.d.ts.map +1 -1
- package/lib/utils/platform.js +13 -2
- package/lib/utils/platform.js.map +1 -1
- package/lib/utils/scanner.d.ts +5 -29
- package/lib/utils/scanner.d.ts.map +1 -1
- package/lib/utils/scanner.js +98 -108
- package/lib/utils/scanner.js.map +1 -1
- package/native/index.d.ts +0 -0
- package/native/index.js +25 -0
- package/native/index.win32-x64-msvc.node +0 -0
- package/package.json +65 -61
package/lib/ui/prompts.d.ts
CHANGED
|
@@ -1,48 +1,16 @@
|
|
|
1
1
|
import type { FileChange, Recommendation } from '../types';
|
|
2
|
-
/**
|
|
3
|
-
* 交互式提示工具
|
|
4
|
-
*/
|
|
5
2
|
export declare const prompts: {
|
|
6
|
-
/**
|
|
7
|
-
* 输入模板仓库 URL
|
|
8
|
-
*/
|
|
9
3
|
inputRepo(): Promise<string>;
|
|
10
|
-
/**
|
|
11
|
-
* 选择分支
|
|
12
|
-
*/
|
|
13
4
|
selectBranch(branches: string[]): Promise<string>;
|
|
14
|
-
/**
|
|
15
|
-
* 选择处理方式
|
|
16
|
-
*/
|
|
17
5
|
selectAction(): Promise<"category" | "individual" | "all" | "cancel">;
|
|
18
|
-
/**
|
|
19
|
-
* 按分类选择文件
|
|
20
|
-
*/
|
|
21
6
|
selectByCategory(changes: FileChange[]): Promise<FileChange[]>;
|
|
22
|
-
/**
|
|
23
|
-
* 逐一选择文件
|
|
24
|
-
*/
|
|
25
7
|
selectIndividually(changes: FileChange[]): Promise<FileChange[]>;
|
|
26
|
-
/**
|
|
27
|
-
* 确认操作
|
|
28
|
-
*/
|
|
29
8
|
confirm(message: string, defaultValue?: boolean): Promise<boolean>;
|
|
30
|
-
/**
|
|
31
|
-
* 选择推荐操作
|
|
32
|
-
*/
|
|
33
9
|
selectRecommendations(recommendations: Recommendation[]): Promise<Recommendation[]>;
|
|
34
|
-
/**
|
|
35
|
-
* 初始化配置向导
|
|
36
|
-
*/
|
|
37
10
|
initConfig(): Promise<{
|
|
38
11
|
repo: string;
|
|
39
12
|
branch: string;
|
|
40
13
|
ignore: string[];
|
|
41
|
-
verbose: boolean;
|
|
42
14
|
}>;
|
|
43
|
-
/**
|
|
44
|
-
* 显示变更统计
|
|
45
|
-
*/
|
|
46
15
|
showChangeSummary(changes: FileChange[]): void;
|
|
47
16
|
};
|
|
48
|
-
//# sourceMappingURL=prompts.d.ts.map
|
package/lib/ui/prompts.js
CHANGED
|
@@ -7,13 +7,12 @@ exports.prompts = void 0;
|
|
|
7
7
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
8
|
const tree_1 = require("./tree");
|
|
9
9
|
const chalk = require('chalk');
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const STATUS_TEXT = {
|
|
11
|
+
new: '新增',
|
|
12
|
+
modified: '修改',
|
|
13
|
+
deleted: '删除'
|
|
14
|
+
};
|
|
13
15
|
exports.prompts = {
|
|
14
|
-
/**
|
|
15
|
-
* 输入模板仓库 URL
|
|
16
|
-
*/
|
|
17
16
|
async inputRepo() {
|
|
18
17
|
const { repo } = await inquirer_1.default.prompt([{
|
|
19
18
|
type: 'input',
|
|
@@ -23,9 +22,6 @@ exports.prompts = {
|
|
|
23
22
|
}]);
|
|
24
23
|
return repo;
|
|
25
24
|
},
|
|
26
|
-
/**
|
|
27
|
-
* 选择分支
|
|
28
|
-
*/
|
|
29
25
|
async selectBranch(branches) {
|
|
30
26
|
if (branches.length === 0)
|
|
31
27
|
return 'main';
|
|
@@ -39,13 +35,10 @@ exports.prompts = {
|
|
|
39
35
|
name: b === 'main' || b === 'master' ? `${b} (默认)` : b,
|
|
40
36
|
value: b
|
|
41
37
|
})),
|
|
42
|
-
default: branches.find(b => b === 'main')
|
|
38
|
+
default: branches.find(b => b === 'main') ?? branches.find(b => b === 'master') ?? branches[0]
|
|
43
39
|
}]);
|
|
44
40
|
return branch;
|
|
45
41
|
},
|
|
46
|
-
/**
|
|
47
|
-
* 选择处理方式
|
|
48
|
-
*/
|
|
49
42
|
async selectAction() {
|
|
50
43
|
const { action } = await inquirer_1.default.prompt([{
|
|
51
44
|
type: 'list',
|
|
@@ -60,73 +53,61 @@ exports.prompts = {
|
|
|
60
53
|
}]);
|
|
61
54
|
return action;
|
|
62
55
|
},
|
|
63
|
-
|
|
64
|
-
* 按分类选择文件
|
|
65
|
-
*/
|
|
56
|
+
// 一次 checkbox 选择所有分类,而不是逐个 confirm
|
|
66
57
|
async selectByCategory(changes) {
|
|
67
|
-
// 按分类分组
|
|
68
58
|
const categories = new Map();
|
|
69
59
|
for (const file of changes) {
|
|
70
|
-
const list = categories.get(file.category)
|
|
60
|
+
const list = categories.get(file.category) ?? [];
|
|
71
61
|
list.push(file);
|
|
72
62
|
categories.set(file.category, list);
|
|
73
63
|
}
|
|
74
|
-
const
|
|
75
|
-
for (const [category, files] of categories) {
|
|
64
|
+
const choices = Array.from(categories.entries()).map(([category, files]) => {
|
|
76
65
|
const icon = files[0].icon;
|
|
66
|
+
const parts = [];
|
|
77
67
|
const newCount = files.filter(f => f.status === 'new').length;
|
|
78
68
|
const modCount = files.filter(f => f.status === 'modified').length;
|
|
79
69
|
const delCount = files.filter(f => f.status === 'deleted').length;
|
|
80
|
-
let stats = `${files.length} 个文件`;
|
|
81
|
-
const parts = [];
|
|
82
70
|
if (newCount > 0)
|
|
83
|
-
parts.push(
|
|
71
|
+
parts.push(chalk.green(`新增 ${newCount}`));
|
|
84
72
|
if (modCount > 0)
|
|
85
|
-
parts.push(
|
|
73
|
+
parts.push(chalk.yellow(`修改 ${modCount}`));
|
|
86
74
|
if (delCount > 0)
|
|
87
|
-
parts.push(
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
75
|
+
parts.push(chalk.red(`删除 ${delCount}`));
|
|
76
|
+
return {
|
|
77
|
+
name: `${icon} ${category} ${parts.join(' ')}`,
|
|
78
|
+
value: category,
|
|
79
|
+
checked: delCount === 0
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
const { selected } = await inquirer_1.default.prompt([{
|
|
83
|
+
type: 'checkbox',
|
|
84
|
+
name: 'selected',
|
|
85
|
+
message: '选择要处理的分类:',
|
|
86
|
+
choices,
|
|
87
|
+
pageSize: 15
|
|
88
|
+
}]);
|
|
89
|
+
return changes.filter(f => selected.includes(f.category));
|
|
101
90
|
},
|
|
102
|
-
/**
|
|
103
|
-
* 逐一选择文件
|
|
104
|
-
*/
|
|
105
91
|
async selectIndividually(changes) {
|
|
106
|
-
const statusText = (status) => {
|
|
107
|
-
switch (status) {
|
|
108
|
-
case 'new': return '新增';
|
|
109
|
-
case 'modified': return '修改';
|
|
110
|
-
case 'deleted': return '删除';
|
|
111
|
-
default: return status;
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
92
|
const { selected } = await inquirer_1.default.prompt([{
|
|
115
93
|
type: 'checkbox',
|
|
116
94
|
name: 'selected',
|
|
117
95
|
message: '选择要处理的文件:',
|
|
118
|
-
choices: changes.map(file =>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
96
|
+
choices: changes.map(file => {
|
|
97
|
+
const statusLabel = STATUS_TEXT[file.status] ?? file.status;
|
|
98
|
+
const colorFn = file.status === 'new' ? chalk.green
|
|
99
|
+
: file.status === 'deleted' ? chalk.red
|
|
100
|
+
: chalk.yellow;
|
|
101
|
+
return {
|
|
102
|
+
name: `${file.icon} ${file.path} ${colorFn(statusLabel)}`,
|
|
103
|
+
value: file,
|
|
104
|
+
checked: file.status !== 'deleted'
|
|
105
|
+
};
|
|
106
|
+
}),
|
|
107
|
+
pageSize: 20
|
|
124
108
|
}]);
|
|
125
109
|
return selected;
|
|
126
110
|
},
|
|
127
|
-
/**
|
|
128
|
-
* 确认操作
|
|
129
|
-
*/
|
|
130
111
|
async confirm(message, defaultValue = true) {
|
|
131
112
|
const { confirmed } = await inquirer_1.default.prompt([{
|
|
132
113
|
type: 'confirm',
|
|
@@ -136,28 +117,21 @@ exports.prompts = {
|
|
|
136
117
|
}]);
|
|
137
118
|
return confirmed;
|
|
138
119
|
},
|
|
139
|
-
|
|
140
|
-
* 选择推荐操作
|
|
141
|
-
*/
|
|
120
|
+
// batch/smart 模式:一次选择推荐组
|
|
142
121
|
async selectRecommendations(recommendations) {
|
|
122
|
+
const PRIORITY_ICON = { high: '🔴', medium: '🟡', low: '🟢' };
|
|
143
123
|
const { selected } = await inquirer_1.default.prompt([{
|
|
144
124
|
type: 'checkbox',
|
|
145
125
|
name: 'selected',
|
|
146
|
-
message: '
|
|
147
|
-
choices: recommendations.map(rec => {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
checked: rec.priority === 'high'
|
|
153
|
-
};
|
|
154
|
-
})
|
|
126
|
+
message: '选择要执行的更新:',
|
|
127
|
+
choices: recommendations.map(rec => ({
|
|
128
|
+
name: `${PRIORITY_ICON[rec.priority]} ${rec.title} ${chalk.gray(rec.description)} (${rec.files.length} 个文件)`,
|
|
129
|
+
value: rec,
|
|
130
|
+
checked: rec.priority === 'high'
|
|
131
|
+
}))
|
|
155
132
|
}]);
|
|
156
133
|
return selected;
|
|
157
134
|
},
|
|
158
|
-
/**
|
|
159
|
-
* 初始化配置向导
|
|
160
|
-
*/
|
|
161
135
|
async initConfig() {
|
|
162
136
|
return inquirer_1.default.prompt([
|
|
163
137
|
{
|
|
@@ -177,26 +151,26 @@ exports.prompts = {
|
|
|
177
151
|
name: 'ignore',
|
|
178
152
|
message: '额外忽略的文件:',
|
|
179
153
|
choices: [
|
|
180
|
-
{ name: '.env.local', value: '.env.local'
|
|
181
|
-
{ name: 'README.md', value: 'README.md'
|
|
182
|
-
{ name: '.vscode/', value: '.vscode/**'
|
|
154
|
+
{ name: '.env.local', value: '.env.local' },
|
|
155
|
+
{ name: 'README.md', value: 'README.md' },
|
|
156
|
+
{ name: '.vscode/', value: '.vscode/**' }
|
|
183
157
|
]
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
type: 'confirm',
|
|
187
|
-
name: 'verbose',
|
|
188
|
-
message: '默认启用详细输出?',
|
|
189
|
-
default: false
|
|
190
158
|
}
|
|
191
159
|
]);
|
|
192
160
|
},
|
|
193
|
-
/**
|
|
194
|
-
* 显示变更统计
|
|
195
|
-
*/
|
|
196
161
|
showChangeSummary(changes) {
|
|
197
|
-
|
|
162
|
+
const newCount = changes.filter(f => f.status === 'new').length;
|
|
163
|
+
const modCount = changes.filter(f => f.status === 'modified').length;
|
|
164
|
+
const delCount = changes.filter(f => f.status === 'deleted').length;
|
|
165
|
+
const parts = [];
|
|
166
|
+
if (newCount > 0)
|
|
167
|
+
parts.push(chalk.green(`新增 ${newCount}`));
|
|
168
|
+
if (modCount > 0)
|
|
169
|
+
parts.push(chalk.yellow(`修改 ${modCount}`));
|
|
170
|
+
if (delCount > 0)
|
|
171
|
+
parts.push(chalk.red(`删除 ${delCount}`));
|
|
172
|
+
console.log(`\n发现 ${chalk.bold(changes.length)} 个变更 ${parts.join(' ')}\n`);
|
|
198
173
|
console.log((0, tree_1.formatGroupedTree)(changes));
|
|
199
174
|
console.log('');
|
|
200
175
|
}
|
|
201
176
|
};
|
|
202
|
-
//# sourceMappingURL=prompts.js.map
|
package/lib/ui/tree.d.ts
CHANGED
package/lib/ui/tree.js
CHANGED
package/lib/utils/categorizer.js
CHANGED
package/lib/utils/git.d.ts
CHANGED
package/lib/utils/git.js
CHANGED
package/lib/utils/index.d.ts
CHANGED
package/lib/utils/index.js
CHANGED
|
@@ -11,4 +11,3 @@ var git_1 = require("./git");
|
|
|
11
11
|
Object.defineProperty(exports, "Git", { enumerable: true, get: function () { return git_1.Git; } });
|
|
12
12
|
var scanner_1 = require("./scanner");
|
|
13
13
|
Object.defineProperty(exports, "Scanner", { enumerable: true, get: function () { return scanner_1.Scanner; } });
|
|
14
|
-
//# sourceMappingURL=index.js.map
|
package/lib/utils/merger.d.ts
CHANGED
|
@@ -1,40 +1,15 @@
|
|
|
1
1
|
import type { MergeStrategy } from '../types';
|
|
2
|
-
/**
|
|
3
|
-
* 文件合并器
|
|
4
|
-
*/
|
|
5
2
|
export declare class Merger {
|
|
6
3
|
private strategies;
|
|
7
4
|
constructor(customStrategies?: Record<string, MergeStrategy>);
|
|
8
|
-
/**
|
|
9
|
-
* 获取文件的合并策略
|
|
10
|
-
*/
|
|
11
5
|
getStrategy(filePath: string): MergeStrategy;
|
|
12
|
-
|
|
13
|
-
* 合并文件
|
|
14
|
-
*/
|
|
15
|
-
merge(templatePath: string, currentPath: string, targetPath: string): {
|
|
6
|
+
merge(templatePath: string, currentPath: string, targetPath: string): Promise<{
|
|
16
7
|
success: boolean;
|
|
17
8
|
message: string;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* 智能合并
|
|
21
|
-
*/
|
|
9
|
+
}>;
|
|
22
10
|
private smartMerge;
|
|
23
|
-
/**
|
|
24
|
-
* 合并 package.json
|
|
25
|
-
*/
|
|
26
11
|
private mergePackageJson;
|
|
27
|
-
/**
|
|
28
|
-
* 合并普通 JSON 文件
|
|
29
|
-
*/
|
|
30
12
|
private mergeJson;
|
|
31
|
-
/**
|
|
32
|
-
* 深度合并对象
|
|
33
|
-
*/
|
|
34
13
|
private deepMerge;
|
|
35
|
-
/**
|
|
36
|
-
* 设置合并策略
|
|
37
|
-
*/
|
|
38
14
|
setStrategy(pattern: string, strategy: MergeStrategy): void;
|
|
39
15
|
}
|
|
40
|
-
//# sourceMappingURL=merger.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merger.d.ts","sourceRoot":"","sources":["../../src/utils/merger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"merger.d.ts","sourceRoot":"","sources":["../../src/utils/merger.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,qBAAa,MAAM;IACjB,OAAO,CAAC,UAAU,CAAgC;gBAEtC,gBAAgB,GAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAM;IAShE,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa;IAKtC,KAAK,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;YAY5G,UAAU;YAcV,gBAAgB;YAyDhB,SAAS;IAoBvB,OAAO,CAAC,SAAS;IAajB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;CAG5D"}
|
package/lib/utils/merger.js
CHANGED
|
@@ -34,155 +34,110 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.Merger = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
37
38
|
const path = __importStar(require("path"));
|
|
38
39
|
const platform_1 = require("./platform");
|
|
39
|
-
/**
|
|
40
|
-
* 文件合并器
|
|
41
|
-
*/
|
|
42
40
|
class Merger {
|
|
43
41
|
constructor(customStrategies = {}) {
|
|
44
42
|
this.strategies = {
|
|
45
|
-
// 默认智能合并的文件
|
|
46
43
|
'package.json': 'smart',
|
|
47
44
|
'tsconfig.json': 'smart',
|
|
48
45
|
'jsconfig.json': 'smart',
|
|
49
46
|
...customStrategies
|
|
50
47
|
};
|
|
51
48
|
}
|
|
52
|
-
/**
|
|
53
|
-
* 获取文件的合并策略
|
|
54
|
-
*/
|
|
55
49
|
getStrategy(filePath) {
|
|
56
50
|
const fileName = path.basename(filePath);
|
|
57
|
-
return this.strategies[fileName]
|
|
51
|
+
return this.strategies[fileName] ?? this.strategies[filePath] ?? 'overwrite';
|
|
58
52
|
}
|
|
59
|
-
|
|
60
|
-
* 合并文件
|
|
61
|
-
*/
|
|
62
|
-
merge(templatePath, currentPath, targetPath) {
|
|
53
|
+
async merge(templatePath, currentPath, targetPath) {
|
|
63
54
|
const strategy = this.getStrategy(targetPath);
|
|
64
55
|
const fileName = path.basename(targetPath);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
platform_1.platform.copyFile(templatePath, targetPath);
|
|
73
|
-
return { success: true, message: '已覆盖' };
|
|
74
|
-
}
|
|
56
|
+
if (strategy === 'skip')
|
|
57
|
+
return { success: false, message: '已跳过' };
|
|
58
|
+
if (strategy === 'smart')
|
|
59
|
+
return this.smartMerge(templatePath, currentPath, targetPath, fileName);
|
|
60
|
+
// overwrite
|
|
61
|
+
platform_1.platform.copyFile(templatePath, targetPath);
|
|
62
|
+
return { success: true, message: '已覆盖' };
|
|
75
63
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
smartMerge(templatePath, currentPath, targetPath, fileName) {
|
|
80
|
-
// 如果当前文件不存在,直接复制
|
|
81
|
-
if (!require('fs').existsSync(currentPath)) {
|
|
64
|
+
async smartMerge(templatePath, currentPath, targetPath, fileName) {
|
|
65
|
+
const exists = await fs.promises.access(currentPath).then(() => true).catch(() => false);
|
|
66
|
+
if (!exists) {
|
|
82
67
|
platform_1.platform.copyFile(templatePath, targetPath);
|
|
83
68
|
return { success: true, message: '已创建' };
|
|
84
69
|
}
|
|
85
|
-
|
|
86
|
-
if (fileName === 'package.json') {
|
|
70
|
+
if (fileName === 'package.json')
|
|
87
71
|
return this.mergePackageJson(templatePath, currentPath, targetPath);
|
|
88
|
-
|
|
89
|
-
if (fileName.endsWith('.json')) {
|
|
72
|
+
if (fileName.endsWith('.json'))
|
|
90
73
|
return this.mergeJson(templatePath, currentPath, targetPath);
|
|
91
|
-
}
|
|
92
|
-
// 默认覆盖
|
|
93
74
|
platform_1.platform.copyFile(templatePath, targetPath);
|
|
94
75
|
return { success: true, message: '已覆盖' };
|
|
95
76
|
}
|
|
96
|
-
|
|
97
|
-
* 合并 package.json
|
|
98
|
-
*/
|
|
99
|
-
mergePackageJson(templatePath, currentPath, targetPath) {
|
|
77
|
+
async mergePackageJson(templatePath, currentPath, targetPath) {
|
|
100
78
|
try {
|
|
101
|
-
const template =
|
|
102
|
-
|
|
79
|
+
const [template, current] = await Promise.all([
|
|
80
|
+
platform_1.platform.readJsonAsync(templatePath),
|
|
81
|
+
platform_1.platform.readJsonAsync(currentPath)
|
|
82
|
+
]);
|
|
103
83
|
if (!template || !current) {
|
|
104
84
|
platform_1.platform.copyFile(templatePath, targetPath);
|
|
105
85
|
return { success: true, message: '已覆盖 (无法解析)' };
|
|
106
86
|
}
|
|
107
|
-
// 智能合并
|
|
108
87
|
const merged = {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
...(template.scripts || {})
|
|
132
|
-
},
|
|
133
|
-
// 合并依赖 (模板版本优先)
|
|
134
|
-
dependencies: {
|
|
135
|
-
...(current.dependencies || {}),
|
|
136
|
-
...(template.dependencies || {})
|
|
137
|
-
},
|
|
138
|
-
devDependencies: {
|
|
139
|
-
...(current.devDependencies || {}),
|
|
140
|
-
...(template.devDependencies || {})
|
|
141
|
-
},
|
|
142
|
-
peerDependencies: {
|
|
143
|
-
...(current.peerDependencies || {}),
|
|
144
|
-
...(template.peerDependencies || {})
|
|
145
|
-
},
|
|
146
|
-
optionalDependencies: {
|
|
147
|
-
...(current.optionalDependencies || {}),
|
|
148
|
-
...(template.optionalDependencies || {})
|
|
149
|
-
}
|
|
88
|
+
name: current.name ?? template.name,
|
|
89
|
+
version: current.version ?? template.version,
|
|
90
|
+
description: current.description ?? template.description,
|
|
91
|
+
author: current.author ?? template.author,
|
|
92
|
+
license: current.license ?? template.license,
|
|
93
|
+
repository: current.repository ?? template.repository,
|
|
94
|
+
homepage: current.homepage ?? template.homepage,
|
|
95
|
+
bugs: current.bugs ?? template.bugs,
|
|
96
|
+
keywords: current.keywords ?? template.keywords,
|
|
97
|
+
type: template.type ?? current.type,
|
|
98
|
+
main: template.main ?? current.main,
|
|
99
|
+
module: template.module ?? current.module,
|
|
100
|
+
types: template.types ?? current.types,
|
|
101
|
+
exports: template.exports ?? current.exports,
|
|
102
|
+
bin: template.bin ?? current.bin,
|
|
103
|
+
files: template.files ?? current.files,
|
|
104
|
+
engines: template.engines ?? current.engines,
|
|
105
|
+
scripts: { ...(current.scripts ?? {}), ...(template.scripts ?? {}) },
|
|
106
|
+
dependencies: { ...(current.dependencies ?? {}), ...(template.dependencies ?? {}) },
|
|
107
|
+
devDependencies: { ...(current.devDependencies ?? {}), ...(template.devDependencies ?? {}) },
|
|
108
|
+
peerDependencies: { ...(current.peerDependencies ?? {}), ...(template.peerDependencies ?? {}) },
|
|
109
|
+
optionalDependencies: { ...(current.optionalDependencies ?? {}), ...(template.optionalDependencies ?? {}) }
|
|
150
110
|
};
|
|
151
|
-
// 复制其他字段
|
|
152
111
|
for (const key of Object.keys(template)) {
|
|
153
|
-
if (!(key in merged))
|
|
112
|
+
if (!(key in merged))
|
|
154
113
|
merged[key] = template[key];
|
|
155
|
-
}
|
|
156
114
|
}
|
|
157
115
|
// 清理空对象
|
|
158
116
|
for (const key of Object.keys(merged)) {
|
|
159
|
-
const
|
|
160
|
-
if (
|
|
117
|
+
const v = merged[key];
|
|
118
|
+
if (v && typeof v === 'object' && !Array.isArray(v) && Object.keys(v).length === 0) {
|
|
161
119
|
delete merged[key];
|
|
162
120
|
}
|
|
163
121
|
}
|
|
164
122
|
platform_1.platform.writeJson(targetPath, merged);
|
|
165
123
|
return { success: true, message: '已智能合并' };
|
|
166
124
|
}
|
|
167
|
-
catch
|
|
125
|
+
catch {
|
|
168
126
|
platform_1.platform.copyFile(templatePath, targetPath);
|
|
169
127
|
return { success: true, message: '已覆盖 (合并失败)' };
|
|
170
128
|
}
|
|
171
129
|
}
|
|
172
|
-
|
|
173
|
-
* 合并普通 JSON 文件
|
|
174
|
-
*/
|
|
175
|
-
mergeJson(templatePath, currentPath, targetPath) {
|
|
130
|
+
async mergeJson(templatePath, currentPath, targetPath) {
|
|
176
131
|
try {
|
|
177
|
-
const template =
|
|
178
|
-
|
|
132
|
+
const [template, current] = await Promise.all([
|
|
133
|
+
platform_1.platform.readJsonAsync(templatePath),
|
|
134
|
+
platform_1.platform.readJsonAsync(currentPath)
|
|
135
|
+
]);
|
|
179
136
|
if (!template || !current) {
|
|
180
137
|
platform_1.platform.copyFile(templatePath, targetPath);
|
|
181
138
|
return { success: true, message: '已覆盖' };
|
|
182
139
|
}
|
|
183
|
-
|
|
184
|
-
const merged = this.deepMerge(current, template);
|
|
185
|
-
platform_1.platform.writeJson(targetPath, merged);
|
|
140
|
+
platform_1.platform.writeJson(targetPath, this.deepMerge(current, template));
|
|
186
141
|
return { success: true, message: '已合并' };
|
|
187
142
|
}
|
|
188
143
|
catch {
|
|
@@ -190,34 +145,21 @@ class Merger {
|
|
|
190
145
|
return { success: true, message: '已覆盖' };
|
|
191
146
|
}
|
|
192
147
|
}
|
|
193
|
-
/**
|
|
194
|
-
* 深度合并对象
|
|
195
|
-
*/
|
|
196
148
|
deepMerge(target, source) {
|
|
197
149
|
const result = { ...target };
|
|
198
150
|
for (const key of Object.keys(source)) {
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
typeof sourceValue === 'object' &&
|
|
203
|
-
!Array.isArray(sourceValue) &&
|
|
204
|
-
targetValue &&
|
|
205
|
-
typeof targetValue === 'object' &&
|
|
206
|
-
!Array.isArray(targetValue)) {
|
|
207
|
-
result[key] = this.deepMerge(targetValue, sourceValue);
|
|
151
|
+
const s = source[key], t = target[key];
|
|
152
|
+
if (s && typeof s === 'object' && !Array.isArray(s) && t && typeof t === 'object' && !Array.isArray(t)) {
|
|
153
|
+
result[key] = this.deepMerge(t, s);
|
|
208
154
|
}
|
|
209
155
|
else {
|
|
210
|
-
result[key] =
|
|
156
|
+
result[key] = s;
|
|
211
157
|
}
|
|
212
158
|
}
|
|
213
159
|
return result;
|
|
214
160
|
}
|
|
215
|
-
/**
|
|
216
|
-
* 设置合并策略
|
|
217
|
-
*/
|
|
218
161
|
setStrategy(pattern, strategy) {
|
|
219
162
|
this.strategies[pattern] = strategy;
|
|
220
163
|
}
|
|
221
164
|
}
|
|
222
165
|
exports.Merger = Merger;
|
|
223
|
-
//# sourceMappingURL=merger.js.map
|