@icebreakers/monorepo 2.2.0 → 3.0.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/assets/.github/ISSUE_TEMPLATE/bug_report.yml +1 -1
- package/assets/package.json +4 -4
- package/bin/monorepo.js +2 -0
- package/dist/cli.cjs +55 -1551
- package/dist/cli.d.cts +1 -2
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +62 -0
- package/dist/index.cjs +43 -1583
- package/dist/index.d.cts +320 -301
- package/dist/index.d.mts +509 -0
- package/dist/index.mjs +3 -0
- package/dist/upgrade-BpSxJA9Y.cjs +1519 -0
- package/dist/upgrade-DKyLL_5k.mjs +1311 -0
- package/package.json +36 -15
- package/templates/apps/client/package.json +5 -5
- package/templates/apps/server/package.json +1 -1
- package/templates/packages/vue-lib-template/package.json +2 -2
- package/bin/copy.js +0 -2
- package/dist/chunk-Y4HUH2J5.js +0 -1534
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -76
- package/dist/index.d.ts +0 -490
- package/dist/index.js +0 -70
|
@@ -0,0 +1,1519 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp$1 = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
13
|
+
key = keys[i];
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp$1(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp$1(target, "default", {
|
|
22
|
+
value: mod,
|
|
23
|
+
enumerable: true
|
|
24
|
+
}) : target, mod));
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
let git_url_parse = require("git-url-parse");
|
|
28
|
+
git_url_parse = __toESM(git_url_parse);
|
|
29
|
+
let simple_git = require("simple-git");
|
|
30
|
+
let __pnpm_find_workspace_dir = require("@pnpm/find-workspace-dir");
|
|
31
|
+
let __pnpm_workspace_find_packages = require("@pnpm/workspace.find-packages");
|
|
32
|
+
let __pnpm_workspace_read_manifest = require("@pnpm/workspace.read-manifest");
|
|
33
|
+
let pathe = require("pathe");
|
|
34
|
+
pathe = __toESM(pathe);
|
|
35
|
+
let __inquirer_checkbox = require("@inquirer/checkbox");
|
|
36
|
+
__inquirer_checkbox = __toESM(__inquirer_checkbox);
|
|
37
|
+
let fs_extra = require("fs-extra");
|
|
38
|
+
fs_extra = __toESM(fs_extra);
|
|
39
|
+
let c12 = require("c12");
|
|
40
|
+
let node_process = require("node:process");
|
|
41
|
+
node_process = __toESM(node_process);
|
|
42
|
+
let picocolors = require("picocolors");
|
|
43
|
+
picocolors = __toESM(picocolors);
|
|
44
|
+
let node_path = require("node:path");
|
|
45
|
+
node_path = __toESM(node_path);
|
|
46
|
+
let node_url = require("node:url");
|
|
47
|
+
let consola = require("consola");
|
|
48
|
+
let node_crypto = require("node:crypto");
|
|
49
|
+
node_crypto = __toESM(node_crypto);
|
|
50
|
+
require("@pnpm/types");
|
|
51
|
+
let comment_json = require("comment-json");
|
|
52
|
+
let node_os = require("node:os");
|
|
53
|
+
node_os = __toESM(node_os);
|
|
54
|
+
let execa = require("execa");
|
|
55
|
+
let p_queue = require("p-queue");
|
|
56
|
+
p_queue = __toESM(p_queue);
|
|
57
|
+
let klaw = require("klaw");
|
|
58
|
+
klaw = __toESM(klaw);
|
|
59
|
+
let node_buffer = require("node:buffer");
|
|
60
|
+
let semver = require("semver");
|
|
61
|
+
|
|
62
|
+
//#region ../../node_modules/.pnpm/get-value@4.0.1/node_modules/get-value/dist/index.mjs
|
|
63
|
+
var __defProp = Object.defineProperty;
|
|
64
|
+
var __name = (target, value) => __defProp(target, "name", {
|
|
65
|
+
value,
|
|
66
|
+
configurable: true
|
|
67
|
+
});
|
|
68
|
+
var isObject$2 = /* @__PURE__ */ __name((v) => v !== null && typeof v === "object", "isObject");
|
|
69
|
+
var join = /* @__PURE__ */ __name((segs, joinChar, options) => {
|
|
70
|
+
if (typeof options.join === "function") return options.join(segs);
|
|
71
|
+
return segs[0] + joinChar + segs[1];
|
|
72
|
+
}, "join");
|
|
73
|
+
var split$1 = /* @__PURE__ */ __name((path$12, splitChar, options) => {
|
|
74
|
+
if (typeof options.split === "function") return options.split(path$12);
|
|
75
|
+
return path$12.split(splitChar);
|
|
76
|
+
}, "split");
|
|
77
|
+
var isValid = /* @__PURE__ */ __name((key, target = {}, options) => {
|
|
78
|
+
if (typeof options?.isValid === "function") return options.isValid(key, target);
|
|
79
|
+
return true;
|
|
80
|
+
}, "isValid");
|
|
81
|
+
var isValidObject = /* @__PURE__ */ __name((v) => {
|
|
82
|
+
return isObject$2(v) || typeof v === "function";
|
|
83
|
+
}, "isValidObject");
|
|
84
|
+
var index_default = /* @__PURE__ */ __name((target, path$12, options = {}) => {
|
|
85
|
+
if (!isObject$2(options)) options = { default: options };
|
|
86
|
+
if (!isValidObject(target)) return typeof options.default !== "undefined" ? options.default : target;
|
|
87
|
+
if (typeof path$12 === "number") path$12 = String(path$12);
|
|
88
|
+
const pathIsArray = Array.isArray(path$12);
|
|
89
|
+
const pathIsString = typeof path$12 === "string";
|
|
90
|
+
const splitChar = options.separator || ".";
|
|
91
|
+
const joinChar = options.joinChar || (typeof splitChar === "string" ? splitChar : ".");
|
|
92
|
+
if (!pathIsString && !pathIsArray) return target;
|
|
93
|
+
if (target[path$12] !== void 0) return isValid(path$12, target, options) ? target[path$12] : options.default;
|
|
94
|
+
const segs = pathIsArray ? path$12 : split$1(path$12, splitChar, options);
|
|
95
|
+
const len = segs.length;
|
|
96
|
+
let idx = 0;
|
|
97
|
+
do {
|
|
98
|
+
let prop = segs[idx];
|
|
99
|
+
if (typeof prop !== "string") prop = String(prop);
|
|
100
|
+
while (prop && prop.slice(-1) === "\\") prop = join([prop.slice(0, -1), segs[++idx] || ""], joinChar, options);
|
|
101
|
+
if (target[prop] !== void 0) {
|
|
102
|
+
if (!isValid(prop, target, options)) return options.default;
|
|
103
|
+
target = target[prop];
|
|
104
|
+
} else {
|
|
105
|
+
let hasProp = false;
|
|
106
|
+
let n = idx + 1;
|
|
107
|
+
while (n < len) {
|
|
108
|
+
prop = join([prop, segs[n++]], joinChar, options);
|
|
109
|
+
if (hasProp = target[prop] !== void 0) {
|
|
110
|
+
if (!isValid(prop, target, options)) return options.default;
|
|
111
|
+
target = target[prop];
|
|
112
|
+
idx = n - 1;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (!hasProp) return options.default;
|
|
117
|
+
}
|
|
118
|
+
} while (++idx < len && isValidObject(target));
|
|
119
|
+
if (idx === len) return target;
|
|
120
|
+
return options.default;
|
|
121
|
+
}, "getValue");
|
|
122
|
+
/*!
|
|
123
|
+
* get-value <https://github.com/jonschlinkert/get-value>
|
|
124
|
+
*
|
|
125
|
+
* Copyright (c) 2014-present, Jon Schlinkert.
|
|
126
|
+
* Released under the MIT License.
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region src/core/git.ts
|
|
131
|
+
/**
|
|
132
|
+
* 对 simple-git 的轻量封装,集中处理配置缓存与常用查询。
|
|
133
|
+
*/
|
|
134
|
+
var GitClient = class {
|
|
135
|
+
client;
|
|
136
|
+
#config;
|
|
137
|
+
constructor(options = {}) {
|
|
138
|
+
this.client = (0, simple_git.simpleGit)(options);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 读取 Git 的 config 列表,原样返回 simple-git 的结果。
|
|
142
|
+
*/
|
|
143
|
+
listConfig() {
|
|
144
|
+
return this.client.listConfig();
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* 初始化配置缓存,避免多次访问 Git 产生的性能损耗。
|
|
148
|
+
*/
|
|
149
|
+
async init() {
|
|
150
|
+
this.#config = (await this.listConfig()).all;
|
|
151
|
+
return this.#config;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 获取缓存的配置,若未初始化则自动触发 init。
|
|
155
|
+
*/
|
|
156
|
+
async getConfig() {
|
|
157
|
+
if (this.#config) return this.#config;
|
|
158
|
+
else return await this.init();
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* 解析 remote.origin.url,返回 git-url-parse 的结构,便于获取仓库元信息。
|
|
162
|
+
*/
|
|
163
|
+
async getGitUrl() {
|
|
164
|
+
const x = index_default(await this.getConfig(), "remote.origin.url");
|
|
165
|
+
if (x) return (0, git_url_parse.default)(x);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* 组合 owner/name,生成常用的仓库名表达。
|
|
169
|
+
*/
|
|
170
|
+
async getRepoName() {
|
|
171
|
+
const url = await this.getGitUrl();
|
|
172
|
+
if (url) return `${url.owner}/${url.name}`;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 从 Git 配置中提取用户信息,用于填充 package.json author 字段。
|
|
176
|
+
*/
|
|
177
|
+
async getUser() {
|
|
178
|
+
const config = await this.getConfig();
|
|
179
|
+
return {
|
|
180
|
+
name: index_default(config, "user.name"),
|
|
181
|
+
email: index_default(config, "user.email")
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* 获取当前仓库的顶层目录路径。
|
|
186
|
+
*/
|
|
187
|
+
async getRepoRoot() {
|
|
188
|
+
try {
|
|
189
|
+
const root = await this.client.revparse(["--show-toplevel"]);
|
|
190
|
+
return typeof root === "string" ? root.trim() : void 0;
|
|
191
|
+
} catch {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region ../../node_modules/.pnpm/defu@6.1.4/node_modules/defu/dist/defu.mjs
|
|
199
|
+
function isPlainObject$1(value) {
|
|
200
|
+
if (value === null || typeof value !== "object") return false;
|
|
201
|
+
const prototype = Object.getPrototypeOf(value);
|
|
202
|
+
if (prototype !== null && prototype !== Object.prototype && Object.getPrototypeOf(prototype) !== null) return false;
|
|
203
|
+
if (Symbol.iterator in value) return false;
|
|
204
|
+
if (Symbol.toStringTag in value) return Object.prototype.toString.call(value) === "[object Module]";
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
function _defu(baseObject, defaults, namespace = ".", merger) {
|
|
208
|
+
if (!isPlainObject$1(defaults)) return _defu(baseObject, {}, namespace, merger);
|
|
209
|
+
const object = Object.assign({}, defaults);
|
|
210
|
+
for (const key in baseObject) {
|
|
211
|
+
if (key === "__proto__" || key === "constructor") continue;
|
|
212
|
+
const value = baseObject[key];
|
|
213
|
+
if (value === null || value === void 0) continue;
|
|
214
|
+
if (merger && merger(object, key, value, namespace)) continue;
|
|
215
|
+
if (Array.isArray(value) && Array.isArray(object[key])) object[key] = [...value, ...object[key]];
|
|
216
|
+
else if (isPlainObject$1(value) && isPlainObject$1(object[key])) object[key] = _defu(value, object[key], (namespace ? `${namespace}.` : "") + key.toString(), merger);
|
|
217
|
+
else object[key] = value;
|
|
218
|
+
}
|
|
219
|
+
return object;
|
|
220
|
+
}
|
|
221
|
+
function createDefu(merger) {
|
|
222
|
+
return (...arguments_) => arguments_.reduce((p, c) => _defu(p, c, "", merger), {});
|
|
223
|
+
}
|
|
224
|
+
const defu = createDefu();
|
|
225
|
+
const defuFn = createDefu((object, key, currentValue) => {
|
|
226
|
+
if (object[key] !== void 0 && typeof currentValue === "function") {
|
|
227
|
+
object[key] = currentValue(object[key]);
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
const defuArrayFn = createDefu((object, key, currentValue) => {
|
|
232
|
+
if (Array.isArray(object[key]) && typeof currentValue === "function") {
|
|
233
|
+
object[key] = currentValue(object[key]);
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
//#endregion
|
|
239
|
+
//#region src/core/workspace.ts
|
|
240
|
+
/**
|
|
241
|
+
* 读取 pnpm workspace 下的所有包,并根据配置过滤与补充字段。
|
|
242
|
+
*/
|
|
243
|
+
async function getWorkspacePackages(workspaceDir, options) {
|
|
244
|
+
const { ignoreRootPackage, ignorePrivatePackage, patterns } = defu(options, {
|
|
245
|
+
ignoreRootPackage: true,
|
|
246
|
+
ignorePrivatePackage: true
|
|
247
|
+
});
|
|
248
|
+
const manifest = await (0, __pnpm_workspace_read_manifest.readWorkspaceManifest)(workspaceDir);
|
|
249
|
+
let pkgs = (await (0, __pnpm_workspace_find_packages.findWorkspacePackages)(workspaceDir, { patterns: patterns ?? manifest?.packages })).filter((x) => {
|
|
250
|
+
if (ignorePrivatePackage && x.manifest.private) return false;
|
|
251
|
+
return true;
|
|
252
|
+
}).map((project) => {
|
|
253
|
+
const pkgJsonPath = pathe.default.resolve(project.rootDir, "package.json");
|
|
254
|
+
return {
|
|
255
|
+
...project,
|
|
256
|
+
pkgJsonPath
|
|
257
|
+
};
|
|
258
|
+
});
|
|
259
|
+
if (ignoreRootPackage) pkgs = pkgs.filter((x) => {
|
|
260
|
+
return x.rootDir !== workspaceDir;
|
|
261
|
+
});
|
|
262
|
+
return pkgs;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* 将工作区绝对路径、包列表与当前 cwd 打包返回,方便调用方一次获取所有信息。
|
|
266
|
+
*/
|
|
267
|
+
async function getWorkspaceData(cwd, options) {
|
|
268
|
+
const workspaceDir = await (0, __pnpm_find_workspace_dir.findWorkspaceDir)(cwd) ?? cwd;
|
|
269
|
+
return {
|
|
270
|
+
cwd,
|
|
271
|
+
workspaceDir,
|
|
272
|
+
packages: await getWorkspacePackages(workspaceDir, options)
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
//#endregion
|
|
277
|
+
//#region ../../node_modules/.pnpm/is-primitive@3.0.1/node_modules/is-primitive/index.js
|
|
278
|
+
/*!
|
|
279
|
+
* is-primitive <https://github.com/jonschlinkert/is-primitive>
|
|
280
|
+
*
|
|
281
|
+
* Copyright (c) 2014-present, Jon Schlinkert.
|
|
282
|
+
* Released under the MIT License.
|
|
283
|
+
*/
|
|
284
|
+
var require_is_primitive = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/is-primitive@3.0.1/node_modules/is-primitive/index.js": ((exports, module) => {
|
|
285
|
+
module.exports = function isPrimitive$1(val) {
|
|
286
|
+
if (typeof val === "object") return val === null;
|
|
287
|
+
return typeof val !== "function";
|
|
288
|
+
};
|
|
289
|
+
}) });
|
|
290
|
+
|
|
291
|
+
//#endregion
|
|
292
|
+
//#region ../../node_modules/.pnpm/isobject@3.0.1/node_modules/isobject/index.js
|
|
293
|
+
/*!
|
|
294
|
+
* isobject <https://github.com/jonschlinkert/isobject>
|
|
295
|
+
*
|
|
296
|
+
* Copyright (c) 2014-2017, Jon Schlinkert.
|
|
297
|
+
* Released under the MIT License.
|
|
298
|
+
*/
|
|
299
|
+
var require_isobject = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/isobject@3.0.1/node_modules/isobject/index.js": ((exports, module) => {
|
|
300
|
+
module.exports = function isObject$3(val) {
|
|
301
|
+
return val != null && typeof val === "object" && Array.isArray(val) === false;
|
|
302
|
+
};
|
|
303
|
+
}) });
|
|
304
|
+
|
|
305
|
+
//#endregion
|
|
306
|
+
//#region ../../node_modules/.pnpm/is-plain-object@2.0.4/node_modules/is-plain-object/index.js
|
|
307
|
+
/*!
|
|
308
|
+
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
|
309
|
+
*
|
|
310
|
+
* Copyright (c) 2014-2017, Jon Schlinkert.
|
|
311
|
+
* Released under the MIT License.
|
|
312
|
+
*/
|
|
313
|
+
var require_is_plain_object = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/is-plain-object@2.0.4/node_modules/is-plain-object/index.js": ((exports, module) => {
|
|
314
|
+
var isObject$1 = require_isobject();
|
|
315
|
+
function isObjectObject(o) {
|
|
316
|
+
return isObject$1(o) === true && Object.prototype.toString.call(o) === "[object Object]";
|
|
317
|
+
}
|
|
318
|
+
module.exports = function isPlainObject$2(o) {
|
|
319
|
+
var ctor, prot;
|
|
320
|
+
if (isObjectObject(o) === false) return false;
|
|
321
|
+
ctor = o.constructor;
|
|
322
|
+
if (typeof ctor !== "function") return false;
|
|
323
|
+
prot = ctor.prototype;
|
|
324
|
+
if (isObjectObject(prot) === false) return false;
|
|
325
|
+
if (prot.hasOwnProperty("isPrototypeOf") === false) return false;
|
|
326
|
+
return true;
|
|
327
|
+
};
|
|
328
|
+
}) });
|
|
329
|
+
|
|
330
|
+
//#endregion
|
|
331
|
+
//#region ../../node_modules/.pnpm/set-value@4.1.0/node_modules/set-value/index.js
|
|
332
|
+
/*!
|
|
333
|
+
* set-value <https://github.com/jonschlinkert/set-value>
|
|
334
|
+
*
|
|
335
|
+
* Copyright (c) Jon Schlinkert (https://github.com/jonschlinkert).
|
|
336
|
+
* Released under the MIT License.
|
|
337
|
+
*/
|
|
338
|
+
var require_set_value = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/set-value@4.1.0/node_modules/set-value/index.js": ((exports, module) => {
|
|
339
|
+
const { deleteProperty } = Reflect;
|
|
340
|
+
const isPrimitive = require_is_primitive();
|
|
341
|
+
const isPlainObject = require_is_plain_object();
|
|
342
|
+
const isObject = (value) => {
|
|
343
|
+
return typeof value === "object" && value !== null || typeof value === "function";
|
|
344
|
+
};
|
|
345
|
+
const isUnsafeKey = (key) => {
|
|
346
|
+
return key === "__proto__" || key === "constructor" || key === "prototype";
|
|
347
|
+
};
|
|
348
|
+
const validateKey = (key) => {
|
|
349
|
+
if (!isPrimitive(key)) throw new TypeError("Object keys must be strings or symbols");
|
|
350
|
+
if (isUnsafeKey(key)) throw new Error(`Cannot set unsafe key: "${key}"`);
|
|
351
|
+
};
|
|
352
|
+
const toStringKey = (input) => {
|
|
353
|
+
return Array.isArray(input) ? input.flat().map(String).join(",") : input;
|
|
354
|
+
};
|
|
355
|
+
const createMemoKey = (input, options) => {
|
|
356
|
+
if (typeof input !== "string" || !options) return input;
|
|
357
|
+
let key = input + ";";
|
|
358
|
+
if (options.arrays !== void 0) key += `arrays=${options.arrays};`;
|
|
359
|
+
if (options.separator !== void 0) key += `separator=${options.separator};`;
|
|
360
|
+
if (options.split !== void 0) key += `split=${options.split};`;
|
|
361
|
+
if (options.merge !== void 0) key += `merge=${options.merge};`;
|
|
362
|
+
if (options.preservePaths !== void 0) key += `preservePaths=${options.preservePaths};`;
|
|
363
|
+
return key;
|
|
364
|
+
};
|
|
365
|
+
const memoize = (input, options, fn) => {
|
|
366
|
+
const key = toStringKey(options ? createMemoKey(input, options) : input);
|
|
367
|
+
validateKey(key);
|
|
368
|
+
const value = setValue.cache.get(key) || fn();
|
|
369
|
+
setValue.cache.set(key, value);
|
|
370
|
+
return value;
|
|
371
|
+
};
|
|
372
|
+
const splitString = (input, options = {}) => {
|
|
373
|
+
const sep = options.separator || ".";
|
|
374
|
+
const preserve = sep === "/" ? false : options.preservePaths;
|
|
375
|
+
if (typeof input === "string" && preserve !== false && /\//.test(input)) return [input];
|
|
376
|
+
const parts = [];
|
|
377
|
+
let part = "";
|
|
378
|
+
const push = (part$1) => {
|
|
379
|
+
let number;
|
|
380
|
+
if (part$1.trim() !== "" && Number.isInteger(number = Number(part$1))) parts.push(number);
|
|
381
|
+
else parts.push(part$1);
|
|
382
|
+
};
|
|
383
|
+
for (let i = 0; i < input.length; i++) {
|
|
384
|
+
const value = input[i];
|
|
385
|
+
if (value === "\\") {
|
|
386
|
+
part += input[++i];
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
if (value === sep) {
|
|
390
|
+
push(part);
|
|
391
|
+
part = "";
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
part += value;
|
|
395
|
+
}
|
|
396
|
+
if (part) push(part);
|
|
397
|
+
return parts;
|
|
398
|
+
};
|
|
399
|
+
const split = (input, options) => {
|
|
400
|
+
if (options && typeof options.split === "function") return options.split(input);
|
|
401
|
+
if (typeof input === "symbol") return [input];
|
|
402
|
+
if (Array.isArray(input)) return input;
|
|
403
|
+
return memoize(input, options, () => splitString(input, options));
|
|
404
|
+
};
|
|
405
|
+
const assignProp = (obj, prop, value, options) => {
|
|
406
|
+
validateKey(prop);
|
|
407
|
+
if (value === void 0) deleteProperty(obj, prop);
|
|
408
|
+
else if (options && options.merge) {
|
|
409
|
+
const merge = options.merge === "function" ? options.merge : Object.assign;
|
|
410
|
+
if (merge && isPlainObject(obj[prop]) && isPlainObject(value)) obj[prop] = merge(obj[prop], value);
|
|
411
|
+
else obj[prop] = value;
|
|
412
|
+
} else obj[prop] = value;
|
|
413
|
+
return obj;
|
|
414
|
+
};
|
|
415
|
+
const setValue = (target, path$12, value, options) => {
|
|
416
|
+
if (!path$12 || !isObject(target)) return target;
|
|
417
|
+
const keys = split(path$12, options);
|
|
418
|
+
let obj = target;
|
|
419
|
+
for (let i = 0; i < keys.length; i++) {
|
|
420
|
+
const key = keys[i];
|
|
421
|
+
const next = keys[i + 1];
|
|
422
|
+
validateKey(key);
|
|
423
|
+
if (next === void 0) {
|
|
424
|
+
assignProp(obj, key, value, options);
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
if (typeof next === "number" && !Array.isArray(obj[key])) {
|
|
428
|
+
obj = obj[key] = [];
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
if (!isObject(obj[key])) obj[key] = {};
|
|
432
|
+
obj = obj[key];
|
|
433
|
+
}
|
|
434
|
+
return target;
|
|
435
|
+
};
|
|
436
|
+
setValue.split = split;
|
|
437
|
+
setValue.cache = /* @__PURE__ */ new Map();
|
|
438
|
+
setValue.clear = () => {
|
|
439
|
+
setValue.cache = /* @__PURE__ */ new Map();
|
|
440
|
+
};
|
|
441
|
+
module.exports = setValue;
|
|
442
|
+
}) });
|
|
443
|
+
|
|
444
|
+
//#endregion
|
|
445
|
+
//#region src/core/config.ts
|
|
446
|
+
/**
|
|
447
|
+
* 简单的内存缓存,避免同一次命令中重复走磁盘加载配置。
|
|
448
|
+
*/
|
|
449
|
+
const cache = /* @__PURE__ */ new Map();
|
|
450
|
+
/**
|
|
451
|
+
* 基于 c12 的通用配置加载逻辑,支持多种配置文件格式。
|
|
452
|
+
*/
|
|
453
|
+
async function loadConfigInternal(cwd) {
|
|
454
|
+
const { config, configFile } = await (0, c12.loadConfig)({
|
|
455
|
+
name: "monorepo",
|
|
456
|
+
cwd,
|
|
457
|
+
rcFile: false,
|
|
458
|
+
defaults: {},
|
|
459
|
+
globalRc: false,
|
|
460
|
+
packageJson: false
|
|
461
|
+
});
|
|
462
|
+
return {
|
|
463
|
+
file: configFile ? pathe.default.resolve(configFile) : null,
|
|
464
|
+
config: config ?? {}
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* 提供类型提示的辅助函数,供外部定义配置时使用。
|
|
469
|
+
*/
|
|
470
|
+
function defineMonorepoConfig(config) {
|
|
471
|
+
return config;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* 加载指定目录的 monorepo 配置,并利用缓存提升性能。
|
|
475
|
+
*/
|
|
476
|
+
async function loadMonorepoConfig(cwd) {
|
|
477
|
+
const key = pathe.default.resolve(cwd);
|
|
478
|
+
if (!cache.has(key)) cache.set(key, loadConfigInternal(key));
|
|
479
|
+
const { config } = await cache.get(key);
|
|
480
|
+
return config;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* 获取命令对应的合并配置,若未配置则返回空对象,保证调用端逻辑简单。
|
|
484
|
+
*/
|
|
485
|
+
async function resolveCommandConfig(name$1, cwd) {
|
|
486
|
+
return ((await loadMonorepoConfig(cwd)).commands ?? {})[name$1] ?? {};
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
//#endregion
|
|
490
|
+
//#region src/commands/clean.ts
|
|
491
|
+
var import_set_value$5 = /* @__PURE__ */ __toESM(require_set_value(), 1);
|
|
492
|
+
/**
|
|
493
|
+
* 交互式清理被选中的包目录,同时重写根 package.json 中的 @icebreakers/monorepo 版本。
|
|
494
|
+
*/
|
|
495
|
+
async function cleanProjects(cwd) {
|
|
496
|
+
const cleanConfig = await resolveCommandConfig("clean", cwd);
|
|
497
|
+
const { packages, workspaceDir } = await getWorkspaceData(cwd, cleanConfig?.includePrivate ? { ignorePrivatePackage: false } : void 0);
|
|
498
|
+
const filteredPackages = packages.filter((pkg) => {
|
|
499
|
+
const name$2 = pkg.manifest.name ?? "";
|
|
500
|
+
if (!name$2) return true;
|
|
501
|
+
if (!cleanConfig?.ignorePackages?.length) return true;
|
|
502
|
+
return !cleanConfig.ignorePackages.includes(name$2);
|
|
503
|
+
});
|
|
504
|
+
let cleanDirs = [];
|
|
505
|
+
if (cleanConfig?.autoConfirm) cleanDirs = filteredPackages.map((pkg) => pkg.rootDir);
|
|
506
|
+
else cleanDirs = await (0, __inquirer_checkbox.default)({
|
|
507
|
+
message: "请选择需要清理的目录",
|
|
508
|
+
choices: filteredPackages.map((x) => {
|
|
509
|
+
return {
|
|
510
|
+
name: pathe.default.relative(workspaceDir, x.rootDir),
|
|
511
|
+
value: x.rootDir,
|
|
512
|
+
checked: true,
|
|
513
|
+
description: x.manifest.name
|
|
514
|
+
};
|
|
515
|
+
})
|
|
516
|
+
});
|
|
517
|
+
const candidates = Array.from(new Set(cleanDirs.filter(Boolean)));
|
|
518
|
+
await Promise.all(candidates.map(async (dir) => {
|
|
519
|
+
if (await fs_extra.default.pathExists(dir)) await fs_extra.default.remove(dir);
|
|
520
|
+
}));
|
|
521
|
+
const name$1 = pathe.default.resolve(workspaceDir, "package.json");
|
|
522
|
+
const pkgJson = await fs_extra.default.readJson(name$1);
|
|
523
|
+
(0, import_set_value$5.default)(pkgJson, "devDependencies.@icebreakers/monorepo", cleanConfig?.pinnedVersion ?? "latest", { preservePaths: false });
|
|
524
|
+
await fs_extra.default.outputJson(name$1, pkgJson, { spaces: 2 });
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
//#endregion
|
|
528
|
+
//#region package.json
|
|
529
|
+
var name = "@icebreakers/monorepo";
|
|
530
|
+
var version = "3.0.0";
|
|
531
|
+
|
|
532
|
+
//#endregion
|
|
533
|
+
//#region src/constants.ts
|
|
534
|
+
/**
|
|
535
|
+
* 还原出 package.json 所在的绝对路径,方便后续按目录组织资源文件。
|
|
536
|
+
*/
|
|
537
|
+
const packageJsonPath = (0, node_url.fileURLToPath)(new URL("../package.json", require("url").pathToFileURL(__filename).href));
|
|
538
|
+
/**
|
|
539
|
+
* @icebreakers/monorepo 包的根目录,所有模板与资产目录都以此为基准。
|
|
540
|
+
*/
|
|
541
|
+
const packageDir = node_path.default.dirname(packageJsonPath);
|
|
542
|
+
/**
|
|
543
|
+
* CLI 提供的模板目录,`monorepo new` 会从这里复制目标工程骨架。
|
|
544
|
+
*/
|
|
545
|
+
const templatesDir = node_path.default.join(packageDir, "templates");
|
|
546
|
+
/**
|
|
547
|
+
* 升级命令需要写入的静态文件集合,位于 assets 目录中。
|
|
548
|
+
*/
|
|
549
|
+
const assetsDir = node_path.default.join(packageDir, "assets");
|
|
550
|
+
/**
|
|
551
|
+
* monorepo 根目录,方便需要跳出当前包的逻辑(例如定位工作区文件)。
|
|
552
|
+
*/
|
|
553
|
+
const rootDir = node_path.default.resolve(packageDir, "..", "..");
|
|
554
|
+
|
|
555
|
+
//#endregion
|
|
556
|
+
//#region src/core/logger.ts
|
|
557
|
+
/**
|
|
558
|
+
* 统一的日志实例,便于在命令行中输出带有前缀和颜色的消息。
|
|
559
|
+
*/
|
|
560
|
+
const logger = (0, consola.createConsola)();
|
|
561
|
+
|
|
562
|
+
//#endregion
|
|
563
|
+
//#region src/utils/fs.ts
|
|
564
|
+
/**
|
|
565
|
+
* 判断是否为可忽略的文件系统错误。
|
|
566
|
+
* - ENOENT: 文件已被删除
|
|
567
|
+
* - EBUSY: Windows 中资源被系统占用
|
|
568
|
+
*/
|
|
569
|
+
function isIgnorableFsError(error) {
|
|
570
|
+
if (!error) return false;
|
|
571
|
+
const code = error.code;
|
|
572
|
+
return code === "ENOENT" || code === "EBUSY" || code === "EEXIST";
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
//#endregion
|
|
576
|
+
//#region src/utils/gitignore.ts
|
|
577
|
+
/**
|
|
578
|
+
* Utilities to handle renaming `.gitignore` files when packaging templates.
|
|
579
|
+
* pnpm publish strips `.gitignore`, so we temporarily rename them to `gitignore`
|
|
580
|
+
* and convert them back when writing into workspaces.
|
|
581
|
+
*/
|
|
582
|
+
const publishBasename = "gitignore";
|
|
583
|
+
const workspaceBasename = ".gitignore";
|
|
584
|
+
function detectSeparator(input) {
|
|
585
|
+
if (input.includes("\\") && !input.includes("/")) return "\\";
|
|
586
|
+
return "/";
|
|
587
|
+
}
|
|
588
|
+
function replaceBasename(input, from, to) {
|
|
589
|
+
if (!input) return input;
|
|
590
|
+
const separator = detectSeparator(input);
|
|
591
|
+
const normalized = input.replace(/[\\/]/g, separator);
|
|
592
|
+
const hasTrailingSeparator = normalized.endsWith(separator);
|
|
593
|
+
const segments = normalized.split(separator);
|
|
594
|
+
if (hasTrailingSeparator && segments[segments.length - 1] === "") segments.pop();
|
|
595
|
+
const lastIndex = segments.length - 1;
|
|
596
|
+
if (lastIndex >= 0 && segments[lastIndex] === from) {
|
|
597
|
+
segments[lastIndex] = to;
|
|
598
|
+
const rebuilt = segments.join(separator);
|
|
599
|
+
return hasTrailingSeparator ? `${rebuilt}${separator}` : rebuilt;
|
|
600
|
+
}
|
|
601
|
+
return input;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Map a workspace path (containing `.gitignore`) to its packaged variant.
|
|
605
|
+
*/
|
|
606
|
+
function toPublishGitignorePath(input) {
|
|
607
|
+
return replaceBasename(input, workspaceBasename, publishBasename);
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Map a packaged path (containing `gitignore`) back to the workspace form.
|
|
611
|
+
*/
|
|
612
|
+
function toWorkspaceGitignorePath(input) {
|
|
613
|
+
return replaceBasename(input, publishBasename, workspaceBasename);
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Convenient helper to check whether a filename (with or without dot prefix)
|
|
617
|
+
* should be treated as a gitignore file.
|
|
618
|
+
*/
|
|
619
|
+
function isGitignoreFile(name$1) {
|
|
620
|
+
return toPublishGitignorePath(name$1) !== name$1 || toWorkspaceGitignorePath(name$1) !== name$1;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
//#endregion
|
|
624
|
+
//#region src/utils/hash.ts
|
|
625
|
+
/**
|
|
626
|
+
* 生成给定二进制内容的 md5 摘要,用于快速比较文件内容。
|
|
627
|
+
*/
|
|
628
|
+
function getFileHash(data) {
|
|
629
|
+
const hashSum = node_crypto.default.createHash("md5");
|
|
630
|
+
hashSum.update(data);
|
|
631
|
+
return hashSum.digest("hex");
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* 对比两个文件的 md5,如果不一致则认为内容有变化。
|
|
635
|
+
*/
|
|
636
|
+
function isFileChanged(src, dest) {
|
|
637
|
+
try {
|
|
638
|
+
return getFileHash(src) !== getFileHash(dest);
|
|
639
|
+
} catch (err) {
|
|
640
|
+
logger.error("Error calculating file hash:", err);
|
|
641
|
+
return false;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
//#endregion
|
|
646
|
+
//#region src/utils/regexp.ts
|
|
647
|
+
/**
|
|
648
|
+
* 逃逸正则表达式中所有特殊字符,避免被当做模式解析。
|
|
649
|
+
*/
|
|
650
|
+
function escapeStringRegexp(str) {
|
|
651
|
+
return str.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* 判断字符串是否命中任意一个正则,用于过滤要同步的资产文件。
|
|
655
|
+
*/
|
|
656
|
+
function isMatch(str, arr) {
|
|
657
|
+
for (const reg of arr) if (reg.test(str)) return true;
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
//#endregion
|
|
662
|
+
//#region src/commands/create.ts
|
|
663
|
+
var import_set_value$4 = /* @__PURE__ */ __toESM(require_set_value(), 1);
|
|
664
|
+
/**
|
|
665
|
+
* 内置模板映射表,value 指向仓库中对应模板所在路径。
|
|
666
|
+
*/
|
|
667
|
+
const templateMap = {
|
|
668
|
+
"tsup": "packages/tsup-template",
|
|
669
|
+
"tsdown": "packages/tsdown-template",
|
|
670
|
+
"unbuild": "packages/unbuild-template",
|
|
671
|
+
"vue-lib": "packages/vue-lib-template",
|
|
672
|
+
"hono-server": "apps/server",
|
|
673
|
+
"vue-hono": "apps/client",
|
|
674
|
+
"vitepress": "apps/website",
|
|
675
|
+
"cli": "apps/cli"
|
|
676
|
+
};
|
|
677
|
+
const defaultTemplate = "unbuild";
|
|
678
|
+
/**
|
|
679
|
+
* 交互式选择模板时的默认选项列表。
|
|
680
|
+
*/
|
|
681
|
+
const baseChoices = [
|
|
682
|
+
{
|
|
683
|
+
name: "unbuild 打包",
|
|
684
|
+
value: "unbuild"
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
name: "tsup 打包",
|
|
688
|
+
value: "tsup"
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
name: "tsdown 打包",
|
|
692
|
+
value: "tsdown"
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
name: "vue 组件",
|
|
696
|
+
value: "vue-lib"
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
name: "vue hono 全栈",
|
|
700
|
+
value: "vue-hono"
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
name: "hono 模板",
|
|
704
|
+
value: "hono-server"
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
name: "vitepress 文档",
|
|
708
|
+
value: "vitepress"
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
name: "cli 模板",
|
|
712
|
+
value: "cli"
|
|
713
|
+
}
|
|
714
|
+
];
|
|
715
|
+
/**
|
|
716
|
+
* 若配置中提供 choices 则优先使用,否则退回默认预设。
|
|
717
|
+
*/
|
|
718
|
+
function getCreateChoices(choices) {
|
|
719
|
+
if (choices?.length) return choices;
|
|
720
|
+
return [...baseChoices];
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* 合并内置与自定义模板映射,允许扩展新的模板类型。
|
|
724
|
+
*/
|
|
725
|
+
function getTemplateMap(extra) {
|
|
726
|
+
const base = { ...templateMap };
|
|
727
|
+
if (extra && Object.keys(extra).length) Object.assign(base, extra);
|
|
728
|
+
return base;
|
|
729
|
+
}
|
|
730
|
+
async function applyGitMetadata(pkgJson, repoDir, targetDir) {
|
|
731
|
+
try {
|
|
732
|
+
const git = new GitClient({ baseDir: repoDir });
|
|
733
|
+
const repoName = await git.getRepoName();
|
|
734
|
+
if (!repoName) return;
|
|
735
|
+
(0, import_set_value$4.default)(pkgJson, ["bugs", "url"], `https://github.com/${repoName}/issues`);
|
|
736
|
+
const repository = {
|
|
737
|
+
type: "git",
|
|
738
|
+
url: `git+https://github.com/${repoName}.git`
|
|
739
|
+
};
|
|
740
|
+
const directoryBase = await git.getRepoRoot() ?? repoDir;
|
|
741
|
+
const relative = pathe.default.relative(directoryBase, targetDir);
|
|
742
|
+
if (relative && relative !== ".") repository.directory = relative.split(pathe.default.sep).join("/");
|
|
743
|
+
(0, import_set_value$4.default)(pkgJson, "repository", repository);
|
|
744
|
+
const gitUser = await git.getUser();
|
|
745
|
+
if (gitUser?.name && gitUser?.email) (0, import_set_value$4.default)(pkgJson, "author", `${gitUser.name} <${gitUser.email}>`);
|
|
746
|
+
} catch {}
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* 根据提供的参数或配置生成新工程目录,并可自动改写 package.json。
|
|
750
|
+
*/
|
|
751
|
+
async function createNewProject(options) {
|
|
752
|
+
const cwd = options?.cwd ?? node_process.default.cwd();
|
|
753
|
+
const createConfig = await resolveCommandConfig("create", cwd);
|
|
754
|
+
const renameJson = options?.renameJson ?? createConfig?.renameJson ?? false;
|
|
755
|
+
const rawName = options?.name ?? createConfig?.name;
|
|
756
|
+
const name$1 = typeof rawName === "string" ? rawName.trim() : void 0;
|
|
757
|
+
const requestedTemplate = options?.type ?? createConfig?.type ?? createConfig?.defaultTemplate ?? defaultTemplate;
|
|
758
|
+
const templateDefinitions = getTemplateMap(createConfig?.templateMap);
|
|
759
|
+
const templatesRoot = createConfig?.templatesDir ? pathe.default.resolve(cwd, createConfig.templatesDir) : templatesDir;
|
|
760
|
+
const fallbackTemplate = createConfig?.defaultTemplate ?? defaultTemplate;
|
|
761
|
+
const bundlerName = typeof requestedTemplate === "string" && templateDefinitions[requestedTemplate] ? requestedTemplate : fallbackTemplate;
|
|
762
|
+
const sourceRelative = templateDefinitions[bundlerName];
|
|
763
|
+
if (!sourceRelative) throw new Error(`未找到名为 ${bundlerName} 的模板,请检查 monorepo.config.ts`);
|
|
764
|
+
const from = pathe.default.join(templatesRoot, sourceRelative);
|
|
765
|
+
const targetName = name$1 && name$1.length > 0 ? name$1 : sourceRelative;
|
|
766
|
+
const to = pathe.default.join(cwd, targetName);
|
|
767
|
+
if (await fs_extra.default.pathExists(to)) throw new Error(`${picocolors.default.red("目标目录已存在")}: ${pathe.default.relative(cwd, to)}`);
|
|
768
|
+
await fs_extra.default.ensureDir(to);
|
|
769
|
+
const filelist = await fs_extra.default.readdir(from);
|
|
770
|
+
const shouldSkip = (src) => pathe.default.basename(src) === ".DS_Store";
|
|
771
|
+
const copyTasks = filelist.filter((filename) => filename !== "package.json").map(async (filename) => {
|
|
772
|
+
const sourcePath = pathe.default.resolve(from, filename);
|
|
773
|
+
const targetPath = pathe.default.resolve(to, toWorkspaceGitignorePath(filename));
|
|
774
|
+
await fs_extra.default.copy(sourcePath, targetPath, { filter(src) {
|
|
775
|
+
if (shouldSkip(src)) return false;
|
|
776
|
+
return true;
|
|
777
|
+
} });
|
|
778
|
+
});
|
|
779
|
+
await Promise.all(copyTasks);
|
|
780
|
+
if (filelist.includes("package.json")) {
|
|
781
|
+
const sourceJsonPath = pathe.default.resolve(from, "package.json");
|
|
782
|
+
const sourceJson = await fs_extra.default.readJson(sourceJsonPath);
|
|
783
|
+
(0, import_set_value$4.default)(sourceJson, "version", "0.0.0");
|
|
784
|
+
(0, import_set_value$4.default)(sourceJson, "name", name$1?.startsWith("@") ? name$1 : pathe.default.basename(targetName));
|
|
785
|
+
await applyGitMetadata(sourceJson, cwd, to);
|
|
786
|
+
await fs_extra.default.outputJson(pathe.default.resolve(to, renameJson ? "package.mock.json" : "package.json"), sourceJson, { spaces: 2 });
|
|
787
|
+
}
|
|
788
|
+
logger.success(`${picocolors.default.bgGreenBright(picocolors.default.white(`[${bundlerName}]`))} ${targetName} 项目创建成功!`);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
//#endregion
|
|
792
|
+
//#region src/core/context.ts
|
|
793
|
+
/**
|
|
794
|
+
* 构建命令执行上下文,封装常用的工作区、Git、配置等信息。
|
|
795
|
+
*/
|
|
796
|
+
async function createContext(cwd) {
|
|
797
|
+
const { packages, workspaceDir } = await getWorkspaceData(cwd);
|
|
798
|
+
const git = new GitClient({ baseDir: workspaceDir });
|
|
799
|
+
const workspaceFilepath = pathe.default.resolve(workspaceDir, "pnpm-workspace.yaml");
|
|
800
|
+
return {
|
|
801
|
+
cwd,
|
|
802
|
+
git,
|
|
803
|
+
gitUrl: await git.getGitUrl(),
|
|
804
|
+
gitUser: await git.getUser(),
|
|
805
|
+
workspaceDir,
|
|
806
|
+
workspaceFilepath,
|
|
807
|
+
packages,
|
|
808
|
+
config: await loadMonorepoConfig(workspaceDir)
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
//#endregion
|
|
813
|
+
//#region src/commands/init/setChangeset.ts
|
|
814
|
+
var import_set_value$3 = /* @__PURE__ */ __toESM(require_set_value(), 1);
|
|
815
|
+
/**
|
|
816
|
+
* 将 changeset 配置中的仓库地址指向当前项目,方便自动生成变更日志链接。
|
|
817
|
+
*/
|
|
818
|
+
async function setChangeset_default(ctx) {
|
|
819
|
+
const { gitUrl, workspaceFilepath } = ctx;
|
|
820
|
+
if (gitUrl && await fs_extra.default.exists(workspaceFilepath)) {
|
|
821
|
+
const changesetConfigPath = pathe.default.resolve(pathe.default.dirname(workspaceFilepath), ".changeset/config.json");
|
|
822
|
+
if (await fs_extra.default.exists(changesetConfigPath)) {
|
|
823
|
+
const changesetConfig = await fs_extra.default.readJson(changesetConfigPath);
|
|
824
|
+
if (gitUrl.full_name) {
|
|
825
|
+
(0, import_set_value$3.default)(changesetConfig, "changelog.1.repo", gitUrl.full_name);
|
|
826
|
+
await fs_extra.default.outputJson(changesetConfigPath, changesetConfig, { spaces: 2 });
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
//#endregion
|
|
833
|
+
//#region src/commands/init/setPkgJson.ts
|
|
834
|
+
var import_set_value$2 = /* @__PURE__ */ __toESM(require_set_value(), 1);
|
|
835
|
+
/**
|
|
836
|
+
* 根据当前仓库信息同步 package.json 的仓库、作者等字段。
|
|
837
|
+
*/
|
|
838
|
+
async function setPkgJson_default(ctx) {
|
|
839
|
+
const { gitUrl, gitUser, packages, cwd, workspaceFilepath } = ctx;
|
|
840
|
+
const workspaceExists = await fs_extra.default.pathExists(workspaceFilepath);
|
|
841
|
+
if (gitUrl && workspaceExists) await Promise.all(packages.map(async (pkg) => {
|
|
842
|
+
if (!await fs_extra.default.pathExists(pkg.pkgJsonPath)) return;
|
|
843
|
+
const pkgJson = JSON.parse(JSON.stringify(pkg.manifest));
|
|
844
|
+
const directory = pathe.default.relative(cwd, pkg.rootDir);
|
|
845
|
+
(0, import_set_value$2.default)(pkgJson, ["bugs", "url"], `https://github.com/${gitUrl.full_name}/issues`);
|
|
846
|
+
const repository = {
|
|
847
|
+
type: "git",
|
|
848
|
+
url: `git+https://github.com/${gitUrl.full_name}.git`
|
|
849
|
+
};
|
|
850
|
+
if (directory) repository.directory = directory;
|
|
851
|
+
(0, import_set_value$2.default)(pkgJson, "repository", repository);
|
|
852
|
+
if (gitUser?.name && gitUser?.email) (0, import_set_value$2.default)(pkgJson, "author", `${gitUser.name} <${gitUser.email}>`);
|
|
853
|
+
const nextContent = `${JSON.stringify(pkgJson, void 0, 2)}\n`;
|
|
854
|
+
if (await fs_extra.default.readFile(pkg.pkgJsonPath, "utf8") !== nextContent) await fs_extra.default.writeFile(pkg.pkgJsonPath, nextContent, "utf8");
|
|
855
|
+
}));
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
//#endregion
|
|
859
|
+
//#region src/commands/init/setReadme.ts
|
|
860
|
+
async function getRows(ctx) {
|
|
861
|
+
const { packages, gitUrl, gitUser, cwd } = ctx;
|
|
862
|
+
const rows = [];
|
|
863
|
+
if (gitUrl) rows.push(`# ${gitUrl.name}\n`);
|
|
864
|
+
rows.push("## Packages\n");
|
|
865
|
+
const sortedPackages = [...packages].sort((a, b) => {
|
|
866
|
+
const left = a.manifest.name ?? "";
|
|
867
|
+
const right = b.manifest.name ?? "";
|
|
868
|
+
return left.localeCompare(right);
|
|
869
|
+
});
|
|
870
|
+
for (const pkg of sortedPackages) {
|
|
871
|
+
const p = pathe.default.relative(cwd, pkg.rootDirRealPath);
|
|
872
|
+
if (p) {
|
|
873
|
+
const description = pkg.manifest.description ? `- ${pkg.manifest.description}` : "";
|
|
874
|
+
rows.push(`- [${pkg.manifest.name}](${p}) ${description}`);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
if (gitUrl) {
|
|
878
|
+
rows.push("\n## Contributing\n");
|
|
879
|
+
rows.push("Contributions Welcome! You can contribute in the following ways.");
|
|
880
|
+
rows.push("");
|
|
881
|
+
rows.push("- Create an Issue - Propose a new feature. Report a bug.");
|
|
882
|
+
rows.push("- Pull Request - Fix a bug and typo. Refactor the code.");
|
|
883
|
+
rows.push("- Create third-party middleware - Instruct below.");
|
|
884
|
+
rows.push("- Share - Share your thoughts on the Blog, X, and others.");
|
|
885
|
+
rows.push(`- Make your application - Please try to use ${gitUrl.name}.`);
|
|
886
|
+
rows.push("");
|
|
887
|
+
rows.push("For more details, see [CONTRIBUTING.md](CONTRIBUTING.md).");
|
|
888
|
+
rows.push("\n## Contributors\n");
|
|
889
|
+
rows.push(`Thanks to [all contributors](https://github.com/${gitUrl.full_name}/graphs/contributors)!`);
|
|
890
|
+
}
|
|
891
|
+
rows.push("\n## Authors\n");
|
|
892
|
+
if (gitUser?.name && gitUser?.email) rows.push(`${gitUser.name} <${gitUser.email}>`);
|
|
893
|
+
rows.push("\n## License\n");
|
|
894
|
+
rows.push("Distributed under the MIT License. See [LICENSE](LICENSE) for more information.");
|
|
895
|
+
return rows;
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* 生成标准化的 README 草稿,列出所有子包并补充贡献者、作者信息。
|
|
899
|
+
*/
|
|
900
|
+
async function setReadme_default(ctx) {
|
|
901
|
+
const rows = await getRows(ctx);
|
|
902
|
+
await fs_extra.default.writeFile(pathe.default.resolve(ctx.cwd, "README.md"), `${rows.join("\n")}\n`);
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
//#endregion
|
|
906
|
+
//#region src/commands/init/index.ts
|
|
907
|
+
/**
|
|
908
|
+
* 初始化命令入口,根据配置逐步生成基础文件。
|
|
909
|
+
*/
|
|
910
|
+
async function init(cwd) {
|
|
911
|
+
const ctx = await createContext(cwd);
|
|
912
|
+
const initConfig = ctx.config.commands?.init ?? {};
|
|
913
|
+
if (!initConfig.skipChangeset) await setChangeset_default(ctx);
|
|
914
|
+
if (!initConfig.skipPkgJson) await setPkgJson_default(ctx);
|
|
915
|
+
if (!initConfig.skipReadme) await setReadme_default(ctx);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
//#endregion
|
|
919
|
+
//#region src/commands/mirror/sources.ts
|
|
920
|
+
const chinaMirrorsEnvs = {
|
|
921
|
+
COREPACK_NPM_REGISTRY: "https://registry.npmmirror.com",
|
|
922
|
+
EDGEDRIVER_CDNURL: "https://npmmirror.com/mirrors/edgedriver",
|
|
923
|
+
NODEJS_ORG_MIRROR: "https://cdn.npmmirror.com/binaries/node",
|
|
924
|
+
NVM_NODEJS_ORG_MIRROR: "https://cdn.npmmirror.com/binaries/node",
|
|
925
|
+
PHANTOMJS_CDNURL: "https://cdn.npmmirror.com/binaries/phantomjs",
|
|
926
|
+
CHROMEDRIVER_CDNURL: "https://cdn.npmmirror.com/binaries/chromedriver",
|
|
927
|
+
OPERADRIVER_CDNURL: "https://cdn.npmmirror.com/binaries/operadriver",
|
|
928
|
+
CYPRESS_DOWNLOAD_PATH_TEMPLATE: "https://cdn.npmmirror.com/binaries/cypress/${version}/${platform}-${arch}/cypress.zip",
|
|
929
|
+
ELECTRON_MIRROR: "https://cdn.npmmirror.com/binaries/electron/",
|
|
930
|
+
ELECTRON_BUILDER_BINARIES_MIRROR: "https://cdn.npmmirror.com/binaries/electron-builder-binaries/",
|
|
931
|
+
SASS_BINARY_SITE: "https://cdn.npmmirror.com/binaries/node-sass",
|
|
932
|
+
SWC_BINARY_SITE: "https://cdn.npmmirror.com/binaries/node-swc",
|
|
933
|
+
NWJS_URLBASE: "https://cdn.npmmirror.com/binaries/nwjs/v",
|
|
934
|
+
PUPPETEER_DOWNLOAD_HOST: "https://cdn.npmmirror.com/binaries/chrome-for-testing",
|
|
935
|
+
PUPPETEER_DOWNLOAD_BASE_URL: "https://cdn.npmmirror.com/binaries/chrome-for-testing",
|
|
936
|
+
PLAYWRIGHT_DOWNLOAD_HOST: "https://cdn.npmmirror.com/binaries/playwright",
|
|
937
|
+
SENTRYCLI_CDNURL: "https://cdn.npmmirror.com/binaries/sentry-cli",
|
|
938
|
+
SAUCECTL_INSTALL_BINARY_MIRROR: "https://cdn.npmmirror.com/binaries/saucectl",
|
|
939
|
+
RE2_DOWNLOAD_MIRROR: "https://cdn.npmmirror.com/binaries/node-re2",
|
|
940
|
+
RE2_DOWNLOAD_SKIP_PATH: "true",
|
|
941
|
+
PRISMA_ENGINES_MIRROR: "https://cdn.npmmirror.com/binaries/prisma",
|
|
942
|
+
npm_config_better_sqlite3_binary_host: "https://cdn.npmmirror.com/binaries/better-sqlite3",
|
|
943
|
+
npm_config_keytar_binary_host: "https://cdn.npmmirror.com/binaries/keytar",
|
|
944
|
+
npm_config_sharp_binary_host: "https://cdn.npmmirror.com/binaries/sharp",
|
|
945
|
+
npm_config_sharp_libvips_binary_host: "https://cdn.npmmirror.com/binaries/sharp-libvips",
|
|
946
|
+
npm_config_robotjs_binary_host: "https://cdn.npmmirror.com/binaries/robotjs"
|
|
947
|
+
};
|
|
948
|
+
|
|
949
|
+
//#endregion
|
|
950
|
+
//#region src/commands/mirror/utils.ts
|
|
951
|
+
var import_set_value$1 = /* @__PURE__ */ __toESM(require_set_value(), 1);
|
|
952
|
+
/**
|
|
953
|
+
* 在 vscode 里面设置镜像下载地址的环境变量,避免下载缓慢
|
|
954
|
+
*/
|
|
955
|
+
function setMirror(obj, envs = chinaMirrorsEnvs) {
|
|
956
|
+
const platforms = [
|
|
957
|
+
"linux",
|
|
958
|
+
"windows",
|
|
959
|
+
"osx"
|
|
960
|
+
];
|
|
961
|
+
const prefix = "terminal.integrated.env";
|
|
962
|
+
if (typeof obj === "object" && obj) for (const platform of platforms) (0, import_set_value$1.default)(obj, [prefix, platform].join(".").replaceAll(".", "\\."), envs);
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
//#endregion
|
|
966
|
+
//#region src/commands/mirror/binaryMirror.ts
|
|
967
|
+
/**
|
|
968
|
+
* 根据中国大陆镜像源,自动向 VSCode settings.json 注入终端环境变量。
|
|
969
|
+
*/
|
|
970
|
+
async function setVscodeBinaryMirror(cwd) {
|
|
971
|
+
const mirrorConfig = await resolveCommandConfig("mirror", cwd);
|
|
972
|
+
const targetJsonPath = pathe.default.resolve(cwd, ".vscode/settings.json");
|
|
973
|
+
await fs_extra.default.ensureFile(targetJsonPath);
|
|
974
|
+
const json = (0, comment_json.parse)(await fs_extra.default.readFile(targetJsonPath, "utf8"), void 0, false);
|
|
975
|
+
const env = mirrorConfig?.env ? {
|
|
976
|
+
...chinaMirrorsEnvs,
|
|
977
|
+
...mirrorConfig.env
|
|
978
|
+
} : chinaMirrorsEnvs;
|
|
979
|
+
json && typeof json === "object" && setMirror(json, env);
|
|
980
|
+
await fs_extra.default.writeFile(targetJsonPath, `${(0, comment_json.stringify)(json, void 0, 2)}\n`, "utf8");
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
//#endregion
|
|
984
|
+
//#region src/commands/sync.ts
|
|
985
|
+
function renderCommand(template, pkgName) {
|
|
986
|
+
return template.replaceAll("{name}", pkgName);
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* 批量执行 `cnpm sync`(或自定义命令),将所有包同步到 npmmirror。
|
|
990
|
+
*/
|
|
991
|
+
async function syncNpmMirror(cwd, options) {
|
|
992
|
+
const { concurrency: configConcurrency, command: configCommand, packages: packageFilter, ...workspaceOverrides } = await resolveCommandConfig("sync", cwd) ?? {};
|
|
993
|
+
const { packages, workspaceDir } = await getWorkspaceData(cwd, {
|
|
994
|
+
...workspaceOverrides,
|
|
995
|
+
...options ?? {}
|
|
996
|
+
});
|
|
997
|
+
logger.info(`[当前工作区Repo]:\n${packages.map((x) => `- ${picocolors.default.green(x.manifest.name)} : ${pathe.default.relative(workspaceDir, x.rootDir)}`).join("\n")}\n`);
|
|
998
|
+
const set$6 = new Set(packages.map((x) => x.manifest.name));
|
|
999
|
+
if (packageFilter?.length) {
|
|
1000
|
+
for (const name$1 of Array.from(set$6)) if (!name$1 || !packageFilter.includes(name$1)) set$6.delete(name$1);
|
|
1001
|
+
}
|
|
1002
|
+
logger.info(`[即将同步的包]:\n${Array.from(set$6).map((x) => `- ${picocolors.default.green(x ?? "")}`).join("\n")}\n`);
|
|
1003
|
+
const queue = new p_queue.default({ concurrency: configConcurrency ?? Math.max(node_os.default.cpus().length, 1) });
|
|
1004
|
+
const template = configCommand ?? "cnpm sync {name}";
|
|
1005
|
+
const tasks = [];
|
|
1006
|
+
for (const pkgName of set$6) {
|
|
1007
|
+
if (!pkgName) continue;
|
|
1008
|
+
tasks.push(queue.add(async () => {
|
|
1009
|
+
return (0, execa.execaCommand)(renderCommand(template, pkgName), { stdio: "inherit" });
|
|
1010
|
+
}));
|
|
1011
|
+
}
|
|
1012
|
+
await Promise.all(tasks);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
//#endregion
|
|
1016
|
+
//#region src/commands/upgrade/overwrite.ts
|
|
1017
|
+
function asBuffer(data) {
|
|
1018
|
+
return typeof data === "string" ? node_buffer.Buffer.from(data) : data;
|
|
1019
|
+
}
|
|
1020
|
+
async function evaluateWriteIntent(targetPath, options) {
|
|
1021
|
+
const { skipOverwrite, source } = options;
|
|
1022
|
+
if (!await fs_extra.default.pathExists(targetPath)) return {
|
|
1023
|
+
type: "write",
|
|
1024
|
+
reason: "missing"
|
|
1025
|
+
};
|
|
1026
|
+
if (skipOverwrite) return {
|
|
1027
|
+
type: "skip",
|
|
1028
|
+
reason: "skipOverwrite"
|
|
1029
|
+
};
|
|
1030
|
+
const src = asBuffer(source);
|
|
1031
|
+
let destSize = 0;
|
|
1032
|
+
try {
|
|
1033
|
+
destSize = (await fs_extra.default.stat(targetPath)).size;
|
|
1034
|
+
} catch {
|
|
1035
|
+
return {
|
|
1036
|
+
type: "write",
|
|
1037
|
+
reason: "missing"
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
if (destSize !== src.length) return {
|
|
1041
|
+
type: "prompt",
|
|
1042
|
+
reason: "changed"
|
|
1043
|
+
};
|
|
1044
|
+
if (!isFileChanged(src, await fs_extra.default.readFile(targetPath))) return {
|
|
1045
|
+
type: "skip",
|
|
1046
|
+
reason: "identical"
|
|
1047
|
+
};
|
|
1048
|
+
return {
|
|
1049
|
+
type: "prompt",
|
|
1050
|
+
reason: "changed"
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
async function scheduleOverwrite(intent, options) {
|
|
1054
|
+
const { relPath, targetPath, action, pending } = options;
|
|
1055
|
+
if (intent.type === "write") {
|
|
1056
|
+
await action();
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
if (intent.type === "prompt") pending.push({
|
|
1060
|
+
relPath,
|
|
1061
|
+
targetPath,
|
|
1062
|
+
action
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
async function flushPendingOverwrites(pending) {
|
|
1066
|
+
if (!pending.length) return;
|
|
1067
|
+
const selected = await (0, __inquirer_checkbox.default)({
|
|
1068
|
+
message: "检测到以下文件内容与当前仓库不同,选择需要覆盖的文件",
|
|
1069
|
+
choices: pending.map((item) => ({
|
|
1070
|
+
name: picocolors.default.greenBright(item.relPath),
|
|
1071
|
+
value: item.targetPath,
|
|
1072
|
+
checked: false
|
|
1073
|
+
})),
|
|
1074
|
+
loop: false
|
|
1075
|
+
});
|
|
1076
|
+
const selectedSet = new Set(selected);
|
|
1077
|
+
for (const item of pending) if (selectedSet.has(item.targetPath)) await item.action();
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
//#endregion
|
|
1081
|
+
//#region src/commands/upgrade/scripts.ts
|
|
1082
|
+
/**
|
|
1083
|
+
* 升级时注入到 package.json 的脚本命令集合,保证常用脚本齐全。
|
|
1084
|
+
*/
|
|
1085
|
+
const scripts = {
|
|
1086
|
+
"script:init": "monorepo init",
|
|
1087
|
+
"script:sync": "monorepo sync",
|
|
1088
|
+
"script:clean": "monorepo clean",
|
|
1089
|
+
"script:mirror": "monorepo mirror",
|
|
1090
|
+
"commitlint": "commitlint --edit"
|
|
1091
|
+
};
|
|
1092
|
+
const scriptsEntries = Object.entries(scripts);
|
|
1093
|
+
|
|
1094
|
+
//#endregion
|
|
1095
|
+
//#region src/commands/upgrade/pkg-json.ts
|
|
1096
|
+
const NON_OVERRIDABLE_PREFIXES = ["workspace:", "catalog:"];
|
|
1097
|
+
function parseVersion(input) {
|
|
1098
|
+
if (typeof input !== "string" || input.trim().length === 0) return null;
|
|
1099
|
+
try {
|
|
1100
|
+
return (0, semver.minVersion)(input) ?? (0, semver.coerce)(input);
|
|
1101
|
+
} catch {
|
|
1102
|
+
return null;
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
function hasNonOverridablePrefix(version$1) {
|
|
1106
|
+
if (typeof version$1 !== "string") return false;
|
|
1107
|
+
return NON_OVERRIDABLE_PREFIXES.some((prefix) => version$1.startsWith(prefix));
|
|
1108
|
+
}
|
|
1109
|
+
function shouldAssignVersion(currentVersion, nextVersion) {
|
|
1110
|
+
if (typeof currentVersion !== "string" || currentVersion.trim().length === 0) return true;
|
|
1111
|
+
if (currentVersion === nextVersion) return false;
|
|
1112
|
+
const current = parseVersion(currentVersion);
|
|
1113
|
+
const next = parseVersion(nextVersion);
|
|
1114
|
+
if (!current || !next) return true;
|
|
1115
|
+
return !(0, semver.gte)(current, next);
|
|
1116
|
+
}
|
|
1117
|
+
/**
|
|
1118
|
+
* 将内置 package.json 内容合并进目标工程:
|
|
1119
|
+
* - 同步依赖(保留 workspace: 前缀的版本)
|
|
1120
|
+
* - 确保 @icebreakers/monorepo 使用最新版本
|
|
1121
|
+
* - 写入预置脚本
|
|
1122
|
+
*/
|
|
1123
|
+
function setPkgJson(sourcePkgJson, targetPkgJson, options) {
|
|
1124
|
+
const packageManager = sourcePkgJson.packageManager ?? "";
|
|
1125
|
+
const sourceDeps = sourcePkgJson.dependencies ?? {};
|
|
1126
|
+
const sourceDevDeps = sourcePkgJson.devDependencies ?? {};
|
|
1127
|
+
const targetDeps = { ...targetPkgJson.dependencies ?? {} };
|
|
1128
|
+
const targetDevDeps = { ...targetPkgJson.devDependencies ?? {} };
|
|
1129
|
+
if (packageManager) targetPkgJson.packageManager = packageManager;
|
|
1130
|
+
for (const [depName, depVersion] of Object.entries(sourceDeps)) {
|
|
1131
|
+
if (typeof depVersion !== "string") continue;
|
|
1132
|
+
const targetVersion = targetDeps[depName];
|
|
1133
|
+
if (hasNonOverridablePrefix(targetVersion)) continue;
|
|
1134
|
+
if (shouldAssignVersion(targetVersion, depVersion)) targetDeps[depName] = depVersion;
|
|
1135
|
+
}
|
|
1136
|
+
if (Object.keys(targetDeps).length) targetPkgJson.dependencies = targetDeps;
|
|
1137
|
+
for (const [depName, depVersion] of Object.entries(sourceDevDeps)) {
|
|
1138
|
+
if (typeof depVersion !== "string") continue;
|
|
1139
|
+
if (depName === name) {
|
|
1140
|
+
const nextVersion = `^${version}`;
|
|
1141
|
+
const targetVersion = targetDevDeps[depName];
|
|
1142
|
+
if (!hasNonOverridablePrefix(targetVersion) && shouldAssignVersion(targetVersion, nextVersion)) targetDevDeps[depName] = nextVersion;
|
|
1143
|
+
} else {
|
|
1144
|
+
const targetVersion = targetDevDeps[depName];
|
|
1145
|
+
if (hasNonOverridablePrefix(targetVersion)) continue;
|
|
1146
|
+
if (shouldAssignVersion(targetVersion, depVersion)) targetDevDeps[depName] = depVersion;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (Object.keys(targetDevDeps).length) targetPkgJson.devDependencies = targetDevDeps;
|
|
1150
|
+
const scriptPairs = options?.scripts ? Object.entries(options.scripts) : scriptsEntries;
|
|
1151
|
+
if (scriptPairs.length) {
|
|
1152
|
+
const scripts$1 = { ...targetPkgJson.scripts ?? {} };
|
|
1153
|
+
for (const [scriptName, scriptCmd] of scriptPairs) scripts$1[scriptName] = scriptCmd;
|
|
1154
|
+
targetPkgJson.scripts = scripts$1;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
//#endregion
|
|
1159
|
+
//#region src/commands/upgrade/targets.ts
|
|
1160
|
+
/**
|
|
1161
|
+
* 根据 core 模式返回需要同步的资产目录。
|
|
1162
|
+
* core=true 时仅包含最小集,便于内联到其他项目。
|
|
1163
|
+
*/
|
|
1164
|
+
function getAssetTargets(core) {
|
|
1165
|
+
const list = [
|
|
1166
|
+
".changeset",
|
|
1167
|
+
".husky",
|
|
1168
|
+
".vscode",
|
|
1169
|
+
".editorconfig",
|
|
1170
|
+
".gitattributes",
|
|
1171
|
+
".gitignore",
|
|
1172
|
+
".npmrc",
|
|
1173
|
+
"commitlint.config.ts",
|
|
1174
|
+
"eslint.config.js",
|
|
1175
|
+
"lint-staged.config.js",
|
|
1176
|
+
"stylelint.config.js",
|
|
1177
|
+
"monorepo.config.ts",
|
|
1178
|
+
"package.json",
|
|
1179
|
+
"pnpm-workspace.yaml",
|
|
1180
|
+
"tsconfig.json",
|
|
1181
|
+
"turbo.json",
|
|
1182
|
+
"vitest.config.ts",
|
|
1183
|
+
"Dockerfile",
|
|
1184
|
+
".dockerignore"
|
|
1185
|
+
];
|
|
1186
|
+
if (!core) list.push(".github", "LICENSE", "renovate.json", "SECURITY.md", "CODE_OF_CONDUCT.md", "CONTRIBUTING.md", "netlify.toml");
|
|
1187
|
+
return list;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
//#endregion
|
|
1191
|
+
//#region src/commands/upgrade/index.ts
|
|
1192
|
+
var import_set_value = /* @__PURE__ */ __toESM(require_set_value(), 1);
|
|
1193
|
+
/**
|
|
1194
|
+
* 将 assets 目录的模版文件同步到工程中,实现一键升级脚手架能力。
|
|
1195
|
+
*/
|
|
1196
|
+
async function upgradeMonorepo(opts) {
|
|
1197
|
+
const cwd = opts.cwd ?? node_process.default.cwd();
|
|
1198
|
+
const upgradeConfig = await resolveCommandConfig("upgrade", cwd);
|
|
1199
|
+
const merged = {
|
|
1200
|
+
cwd,
|
|
1201
|
+
outDir: "",
|
|
1202
|
+
...upgradeConfig ?? {},
|
|
1203
|
+
...opts
|
|
1204
|
+
};
|
|
1205
|
+
const outDir = merged.outDir ?? "";
|
|
1206
|
+
const absOutDir = pathe.default.isAbsolute(outDir) ? outDir : pathe.default.join(cwd, outDir);
|
|
1207
|
+
const repoName = await new GitClient({ baseDir: cwd }).getRepoName();
|
|
1208
|
+
const useCoreAssets = merged.core ?? false;
|
|
1209
|
+
merged.core = useCoreAssets;
|
|
1210
|
+
const baseTargets = getAssetTargets(useCoreAssets);
|
|
1211
|
+
const configTargets = upgradeConfig?.targets ?? [];
|
|
1212
|
+
const mergeTargets = upgradeConfig?.mergeTargets;
|
|
1213
|
+
let targets = configTargets.length ? mergeTargets === false ? [...configTargets] : Array.from(new Set([...baseTargets, ...configTargets])) : baseTargets;
|
|
1214
|
+
if (merged.interactive) targets = await (0, __inquirer_checkbox.default)({
|
|
1215
|
+
message: "选择你需要的文件",
|
|
1216
|
+
choices: targets.map((x) => {
|
|
1217
|
+
return {
|
|
1218
|
+
value: x,
|
|
1219
|
+
checked: true
|
|
1220
|
+
};
|
|
1221
|
+
})
|
|
1222
|
+
});
|
|
1223
|
+
const regexpArr = targets.map((x) => {
|
|
1224
|
+
return /* @__PURE__ */ new RegExp(`^${escapeStringRegexp(x)}`);
|
|
1225
|
+
});
|
|
1226
|
+
const skipChangesetMarkdown = upgradeConfig?.skipChangesetMarkdown ?? true;
|
|
1227
|
+
const scriptOverrides = upgradeConfig?.scripts;
|
|
1228
|
+
const skipOverwrite = merged.skipOverwrite;
|
|
1229
|
+
const pendingOverwrites = [];
|
|
1230
|
+
for await (const file of (0, klaw.default)(assetsDir, { filter(p) {
|
|
1231
|
+
return isMatch(toWorkspaceGitignorePath(pathe.default.relative(assetsDir, p)), regexpArr);
|
|
1232
|
+
} })) {
|
|
1233
|
+
if (!file.stats.isFile()) continue;
|
|
1234
|
+
const relPath = toWorkspaceGitignorePath(pathe.default.relative(assetsDir, file.path));
|
|
1235
|
+
if (skipChangesetMarkdown && relPath.startsWith(".changeset/") && relPath.endsWith(".md")) continue;
|
|
1236
|
+
const targetPath = pathe.default.resolve(absOutDir, relPath);
|
|
1237
|
+
try {
|
|
1238
|
+
if (relPath === "package.json") {
|
|
1239
|
+
if (!await fs_extra.default.pathExists(targetPath)) continue;
|
|
1240
|
+
const sourcePkgJson = await fs_extra.default.readJson(file.path);
|
|
1241
|
+
const targetPkgJson = await fs_extra.default.readJson(targetPath);
|
|
1242
|
+
setPkgJson(sourcePkgJson, targetPkgJson, { scripts: scriptOverrides });
|
|
1243
|
+
const data = `${JSON.stringify(targetPkgJson, void 0, 2)}\n`;
|
|
1244
|
+
const intent$1 = await evaluateWriteIntent(targetPath, {
|
|
1245
|
+
skipOverwrite,
|
|
1246
|
+
source: data
|
|
1247
|
+
});
|
|
1248
|
+
const action$1 = async () => {
|
|
1249
|
+
await fs_extra.default.outputFile(targetPath, data, "utf8");
|
|
1250
|
+
logger.success(targetPath);
|
|
1251
|
+
};
|
|
1252
|
+
await scheduleOverwrite(intent$1, {
|
|
1253
|
+
relPath,
|
|
1254
|
+
targetPath,
|
|
1255
|
+
action: action$1,
|
|
1256
|
+
pending: pendingOverwrites
|
|
1257
|
+
});
|
|
1258
|
+
continue;
|
|
1259
|
+
}
|
|
1260
|
+
if (relPath === ".changeset/config.json" && repoName) {
|
|
1261
|
+
const changesetJson = await fs_extra.default.readJson(file.path);
|
|
1262
|
+
(0, import_set_value.default)(changesetJson, "changelog.1.repo", repoName);
|
|
1263
|
+
const data = `${JSON.stringify(changesetJson, void 0, 2)}\n`;
|
|
1264
|
+
const intent$1 = await evaluateWriteIntent(targetPath, {
|
|
1265
|
+
skipOverwrite,
|
|
1266
|
+
source: data
|
|
1267
|
+
});
|
|
1268
|
+
const action$1 = async () => {
|
|
1269
|
+
await fs_extra.default.outputFile(targetPath, data, "utf8");
|
|
1270
|
+
logger.success(targetPath);
|
|
1271
|
+
};
|
|
1272
|
+
await scheduleOverwrite(intent$1, {
|
|
1273
|
+
relPath,
|
|
1274
|
+
targetPath,
|
|
1275
|
+
action: action$1,
|
|
1276
|
+
pending: pendingOverwrites
|
|
1277
|
+
});
|
|
1278
|
+
continue;
|
|
1279
|
+
}
|
|
1280
|
+
if (relPath === "LICENSE") {
|
|
1281
|
+
const source$1 = await fs_extra.default.readFile(file.path);
|
|
1282
|
+
const intent$1 = await evaluateWriteIntent(targetPath, {
|
|
1283
|
+
skipOverwrite: true,
|
|
1284
|
+
source: source$1
|
|
1285
|
+
});
|
|
1286
|
+
const action$1 = async () => {
|
|
1287
|
+
await fs_extra.default.outputFile(targetPath, source$1);
|
|
1288
|
+
logger.success(targetPath);
|
|
1289
|
+
};
|
|
1290
|
+
await scheduleOverwrite(intent$1, {
|
|
1291
|
+
relPath,
|
|
1292
|
+
targetPath,
|
|
1293
|
+
action: action$1,
|
|
1294
|
+
pending: pendingOverwrites
|
|
1295
|
+
});
|
|
1296
|
+
continue;
|
|
1297
|
+
}
|
|
1298
|
+
const source = await fs_extra.default.readFile(file.path);
|
|
1299
|
+
const intent = await evaluateWriteIntent(targetPath, {
|
|
1300
|
+
skipOverwrite,
|
|
1301
|
+
source
|
|
1302
|
+
});
|
|
1303
|
+
const action = async () => {
|
|
1304
|
+
await fs_extra.default.outputFile(targetPath, source);
|
|
1305
|
+
logger.success(targetPath);
|
|
1306
|
+
};
|
|
1307
|
+
await scheduleOverwrite(intent, {
|
|
1308
|
+
relPath,
|
|
1309
|
+
targetPath,
|
|
1310
|
+
action,
|
|
1311
|
+
pending: pendingOverwrites
|
|
1312
|
+
});
|
|
1313
|
+
} catch (error) {
|
|
1314
|
+
if (isIgnorableFsError(error)) continue;
|
|
1315
|
+
throw error;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
await flushPendingOverwrites(pendingOverwrites);
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
//#endregion
|
|
1322
|
+
Object.defineProperty(exports, 'GitClient', {
|
|
1323
|
+
enumerable: true,
|
|
1324
|
+
get: function () {
|
|
1325
|
+
return GitClient;
|
|
1326
|
+
}
|
|
1327
|
+
});
|
|
1328
|
+
Object.defineProperty(exports, '__toESM', {
|
|
1329
|
+
enumerable: true,
|
|
1330
|
+
get: function () {
|
|
1331
|
+
return __toESM;
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
Object.defineProperty(exports, 'assetsDir', {
|
|
1335
|
+
enumerable: true,
|
|
1336
|
+
get: function () {
|
|
1337
|
+
return assetsDir;
|
|
1338
|
+
}
|
|
1339
|
+
});
|
|
1340
|
+
Object.defineProperty(exports, 'cleanProjects', {
|
|
1341
|
+
enumerable: true,
|
|
1342
|
+
get: function () {
|
|
1343
|
+
return cleanProjects;
|
|
1344
|
+
}
|
|
1345
|
+
});
|
|
1346
|
+
Object.defineProperty(exports, 'createContext', {
|
|
1347
|
+
enumerable: true,
|
|
1348
|
+
get: function () {
|
|
1349
|
+
return createContext;
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
Object.defineProperty(exports, 'createNewProject', {
|
|
1353
|
+
enumerable: true,
|
|
1354
|
+
get: function () {
|
|
1355
|
+
return createNewProject;
|
|
1356
|
+
}
|
|
1357
|
+
});
|
|
1358
|
+
Object.defineProperty(exports, 'defaultTemplate', {
|
|
1359
|
+
enumerable: true,
|
|
1360
|
+
get: function () {
|
|
1361
|
+
return defaultTemplate;
|
|
1362
|
+
}
|
|
1363
|
+
});
|
|
1364
|
+
Object.defineProperty(exports, 'defineMonorepoConfig', {
|
|
1365
|
+
enumerable: true,
|
|
1366
|
+
get: function () {
|
|
1367
|
+
return defineMonorepoConfig;
|
|
1368
|
+
}
|
|
1369
|
+
});
|
|
1370
|
+
Object.defineProperty(exports, 'escapeStringRegexp', {
|
|
1371
|
+
enumerable: true,
|
|
1372
|
+
get: function () {
|
|
1373
|
+
return escapeStringRegexp;
|
|
1374
|
+
}
|
|
1375
|
+
});
|
|
1376
|
+
Object.defineProperty(exports, 'getCreateChoices', {
|
|
1377
|
+
enumerable: true,
|
|
1378
|
+
get: function () {
|
|
1379
|
+
return getCreateChoices;
|
|
1380
|
+
}
|
|
1381
|
+
});
|
|
1382
|
+
Object.defineProperty(exports, 'getFileHash', {
|
|
1383
|
+
enumerable: true,
|
|
1384
|
+
get: function () {
|
|
1385
|
+
return getFileHash;
|
|
1386
|
+
}
|
|
1387
|
+
});
|
|
1388
|
+
Object.defineProperty(exports, 'getTemplateMap', {
|
|
1389
|
+
enumerable: true,
|
|
1390
|
+
get: function () {
|
|
1391
|
+
return getTemplateMap;
|
|
1392
|
+
}
|
|
1393
|
+
});
|
|
1394
|
+
Object.defineProperty(exports, 'getWorkspaceData', {
|
|
1395
|
+
enumerable: true,
|
|
1396
|
+
get: function () {
|
|
1397
|
+
return getWorkspaceData;
|
|
1398
|
+
}
|
|
1399
|
+
});
|
|
1400
|
+
Object.defineProperty(exports, 'getWorkspacePackages', {
|
|
1401
|
+
enumerable: true,
|
|
1402
|
+
get: function () {
|
|
1403
|
+
return getWorkspacePackages;
|
|
1404
|
+
}
|
|
1405
|
+
});
|
|
1406
|
+
Object.defineProperty(exports, 'init', {
|
|
1407
|
+
enumerable: true,
|
|
1408
|
+
get: function () {
|
|
1409
|
+
return init;
|
|
1410
|
+
}
|
|
1411
|
+
});
|
|
1412
|
+
Object.defineProperty(exports, 'isFileChanged', {
|
|
1413
|
+
enumerable: true,
|
|
1414
|
+
get: function () {
|
|
1415
|
+
return isFileChanged;
|
|
1416
|
+
}
|
|
1417
|
+
});
|
|
1418
|
+
Object.defineProperty(exports, 'isGitignoreFile', {
|
|
1419
|
+
enumerable: true,
|
|
1420
|
+
get: function () {
|
|
1421
|
+
return isGitignoreFile;
|
|
1422
|
+
}
|
|
1423
|
+
});
|
|
1424
|
+
Object.defineProperty(exports, 'isIgnorableFsError', {
|
|
1425
|
+
enumerable: true,
|
|
1426
|
+
get: function () {
|
|
1427
|
+
return isIgnorableFsError;
|
|
1428
|
+
}
|
|
1429
|
+
});
|
|
1430
|
+
Object.defineProperty(exports, 'isMatch', {
|
|
1431
|
+
enumerable: true,
|
|
1432
|
+
get: function () {
|
|
1433
|
+
return isMatch;
|
|
1434
|
+
}
|
|
1435
|
+
});
|
|
1436
|
+
Object.defineProperty(exports, 'loadMonorepoConfig', {
|
|
1437
|
+
enumerable: true,
|
|
1438
|
+
get: function () {
|
|
1439
|
+
return loadMonorepoConfig;
|
|
1440
|
+
}
|
|
1441
|
+
});
|
|
1442
|
+
Object.defineProperty(exports, 'logger', {
|
|
1443
|
+
enumerable: true,
|
|
1444
|
+
get: function () {
|
|
1445
|
+
return logger;
|
|
1446
|
+
}
|
|
1447
|
+
});
|
|
1448
|
+
Object.defineProperty(exports, 'name', {
|
|
1449
|
+
enumerable: true,
|
|
1450
|
+
get: function () {
|
|
1451
|
+
return name;
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
Object.defineProperty(exports, 'packageDir', {
|
|
1455
|
+
enumerable: true,
|
|
1456
|
+
get: function () {
|
|
1457
|
+
return packageDir;
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
Object.defineProperty(exports, 'resolveCommandConfig', {
|
|
1461
|
+
enumerable: true,
|
|
1462
|
+
get: function () {
|
|
1463
|
+
return resolveCommandConfig;
|
|
1464
|
+
}
|
|
1465
|
+
});
|
|
1466
|
+
Object.defineProperty(exports, 'rootDir', {
|
|
1467
|
+
enumerable: true,
|
|
1468
|
+
get: function () {
|
|
1469
|
+
return rootDir;
|
|
1470
|
+
}
|
|
1471
|
+
});
|
|
1472
|
+
Object.defineProperty(exports, 'setVscodeBinaryMirror', {
|
|
1473
|
+
enumerable: true,
|
|
1474
|
+
get: function () {
|
|
1475
|
+
return setVscodeBinaryMirror;
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
Object.defineProperty(exports, 'syncNpmMirror', {
|
|
1479
|
+
enumerable: true,
|
|
1480
|
+
get: function () {
|
|
1481
|
+
return syncNpmMirror;
|
|
1482
|
+
}
|
|
1483
|
+
});
|
|
1484
|
+
Object.defineProperty(exports, 'templateMap', {
|
|
1485
|
+
enumerable: true,
|
|
1486
|
+
get: function () {
|
|
1487
|
+
return templateMap;
|
|
1488
|
+
}
|
|
1489
|
+
});
|
|
1490
|
+
Object.defineProperty(exports, 'templatesDir', {
|
|
1491
|
+
enumerable: true,
|
|
1492
|
+
get: function () {
|
|
1493
|
+
return templatesDir;
|
|
1494
|
+
}
|
|
1495
|
+
});
|
|
1496
|
+
Object.defineProperty(exports, 'toPublishGitignorePath', {
|
|
1497
|
+
enumerable: true,
|
|
1498
|
+
get: function () {
|
|
1499
|
+
return toPublishGitignorePath;
|
|
1500
|
+
}
|
|
1501
|
+
});
|
|
1502
|
+
Object.defineProperty(exports, 'toWorkspaceGitignorePath', {
|
|
1503
|
+
enumerable: true,
|
|
1504
|
+
get: function () {
|
|
1505
|
+
return toWorkspaceGitignorePath;
|
|
1506
|
+
}
|
|
1507
|
+
});
|
|
1508
|
+
Object.defineProperty(exports, 'upgradeMonorepo', {
|
|
1509
|
+
enumerable: true,
|
|
1510
|
+
get: function () {
|
|
1511
|
+
return upgradeMonorepo;
|
|
1512
|
+
}
|
|
1513
|
+
});
|
|
1514
|
+
Object.defineProperty(exports, 'version', {
|
|
1515
|
+
enumerable: true,
|
|
1516
|
+
get: function () {
|
|
1517
|
+
return version;
|
|
1518
|
+
}
|
|
1519
|
+
});
|