@icebreakers/monorepo 2.0.9 → 2.0.11

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.
@@ -48,7 +48,7 @@
48
48
  "@icebreakers/monorepo": "workspace:*",
49
49
  "@icebreakers/stylelint-config": "^1.2.1",
50
50
  "@types/fs-extra": "^11.0.4",
51
- "@types/node": "^24.7.2",
51
+ "@types/node": "^24.8.0",
52
52
  "@types/semver": "^7.7.1",
53
53
  "@vitest/coverage-v8": "~3.2.4",
54
54
  "ci-info": "^4.3.1",
@@ -27,11 +27,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  mod
28
28
  ));
29
29
 
30
- // ../../node_modules/.pnpm/tsup@8.5.0_@microsoft+api-extractor@7.52.12_@types+node@24.7.2__jiti@2.6.1_postcss@8.5._3d4ae7d8e5b6f496c0110ecf5a7e8328/node_modules/tsup/assets/esm_shims.js
30
+ // ../../node_modules/.pnpm/tsup@8.5.0_@microsoft+api-extractor@7.52.12_@types+node@24.8.0__jiti@2.6.1_postcss@8.5._ab94ebbbd28243190e5d9689f774411e/node_modules/tsup/assets/esm_shims.js
31
31
  import path from "path";
32
32
  import { fileURLToPath } from "url";
33
33
  var init_esm_shims = __esm({
34
- "../../node_modules/.pnpm/tsup@8.5.0_@microsoft+api-extractor@7.52.12_@types+node@24.7.2__jiti@2.6.1_postcss@8.5._3d4ae7d8e5b6f496c0110ecf5a7e8328/node_modules/tsup/assets/esm_shims.js"() {
34
+ "../../node_modules/.pnpm/tsup@8.5.0_@microsoft+api-extractor@7.52.12_@types+node@24.8.0__jiti@2.6.1_postcss@8.5._ab94ebbbd28243190e5d9689f774411e/node_modules/tsup/assets/esm_shims.js"() {
35
35
  "use strict";
36
36
  }
37
37
  });
@@ -578,7 +578,7 @@ async function cleanProjects(cwd) {
578
578
 
579
579
  // package.json
580
580
  var name = "@icebreakers/monorepo";
581
- var version = "2.0.9";
581
+ var version = "2.0.11";
582
582
 
583
583
  // src/constants.ts
584
584
  init_esm_shims();
@@ -595,6 +595,88 @@ init_esm_shims();
595
595
  import { createConsola } from "consola";
596
596
  var logger = createConsola();
597
597
 
598
+ // src/utils/fs.ts
599
+ init_esm_shims();
600
+ function isIgnorableFsError(error) {
601
+ if (!error) {
602
+ return false;
603
+ }
604
+ const code = error.code;
605
+ return code === "ENOENT" || code === "EBUSY" || code === "EEXIST";
606
+ }
607
+
608
+ // src/utils/gitignore.ts
609
+ init_esm_shims();
610
+ var publishBasename = "gitignore";
611
+ var workspaceBasename = ".gitignore";
612
+ function detectSeparator(input) {
613
+ if (input.includes("\\") && !input.includes("/")) {
614
+ return "\\";
615
+ }
616
+ return "/";
617
+ }
618
+ function replaceBasename(input, from, to) {
619
+ if (!input) {
620
+ return input;
621
+ }
622
+ const separator = detectSeparator(input);
623
+ const normalized = input.replace(/[\\/]/g, separator);
624
+ const hasTrailingSeparator = normalized.endsWith(separator);
625
+ const segments = normalized.split(separator);
626
+ if (hasTrailingSeparator && segments[segments.length - 1] === "") {
627
+ segments.pop();
628
+ }
629
+ const lastIndex = segments.length - 1;
630
+ if (lastIndex >= 0 && segments[lastIndex] === from) {
631
+ segments[lastIndex] = to;
632
+ const rebuilt = segments.join(separator);
633
+ return hasTrailingSeparator ? `${rebuilt}${separator}` : rebuilt;
634
+ }
635
+ return input;
636
+ }
637
+ function toPublishGitignorePath(input) {
638
+ return replaceBasename(input, workspaceBasename, publishBasename);
639
+ }
640
+ function toWorkspaceGitignorePath(input) {
641
+ return replaceBasename(input, publishBasename, workspaceBasename);
642
+ }
643
+ function isGitignoreFile(name2) {
644
+ return toPublishGitignorePath(name2) !== name2 || toWorkspaceGitignorePath(name2) !== name2;
645
+ }
646
+
647
+ // src/utils/hash.ts
648
+ init_esm_shims();
649
+ import crypto from "crypto";
650
+ function getFileHash(data) {
651
+ const hashSum = crypto.createHash("md5");
652
+ hashSum.update(data);
653
+ return hashSum.digest("hex");
654
+ }
655
+ function isFileChanged(src, dest) {
656
+ try {
657
+ const currentHash = getFileHash(src);
658
+ const previousHash = getFileHash(dest);
659
+ return currentHash !== previousHash;
660
+ } catch (err) {
661
+ logger.error("Error calculating file hash:", err);
662
+ return false;
663
+ }
664
+ }
665
+
666
+ // src/utils/regexp.ts
667
+ init_esm_shims();
668
+ function escapeStringRegexp(str) {
669
+ return str.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
670
+ }
671
+ function isMatch(str, arr) {
672
+ for (const reg of arr) {
673
+ if (reg.test(str)) {
674
+ return true;
675
+ }
676
+ }
677
+ return false;
678
+ }
679
+
598
680
  // src/commands/create.ts
599
681
  init_esm_shims();
600
682
  var import_set_value2 = __toESM(require_set_value(), 1);
@@ -660,7 +742,7 @@ async function createNewProject(options) {
660
742
  const shouldSkip = (src) => path6.basename(src) === ".DS_Store";
661
743
  const copyTasks = filelist.filter((filename) => filename !== "package.json").map(async (filename) => {
662
744
  const sourcePath = path6.resolve(from, filename);
663
- const targetPath = path6.resolve(to, filename === "gitignore" ? ".gitignore" : filename);
745
+ const targetPath = path6.resolve(to, toWorkspaceGitignorePath(filename));
664
746
  await fs2.copy(sourcePath, targetPath, {
665
747
  filter(src) {
666
748
  if (shouldSkip(src)) {
@@ -960,60 +1042,105 @@ ${Array.from(set7).map((x) => `- ${pc2.green(x ?? "")}`).join("\n")}
960
1042
  await Promise.all(tasks);
961
1043
  }
962
1044
 
963
- // src/utils/fs.ts
1045
+ // src/commands/upgrade/index.ts
964
1046
  init_esm_shims();
965
- function isIgnorableFsError(error) {
966
- if (!error) {
967
- return false;
968
- }
969
- const code = error.code;
970
- return code === "ENOENT" || code === "EBUSY" || code === "EEXIST";
971
- }
1047
+ var import_set_value6 = __toESM(require_set_value(), 1);
1048
+ import process2 from "process";
1049
+ import checkbox3 from "@inquirer/checkbox";
1050
+ import fs8 from "fs-extra";
1051
+ import klaw from "klaw";
1052
+ import path13 from "pathe";
972
1053
 
973
- // src/utils/hash.ts
1054
+ // src/commands/upgrade/overwrite.ts
974
1055
  init_esm_shims();
975
- import crypto from "crypto";
976
- function getFileHash(data) {
977
- const hashSum = crypto.createHash("md5");
978
- hashSum.update(data);
979
- return hashSum.digest("hex");
1056
+ import { Buffer as Buffer2 } from "buffer";
1057
+ import checkbox2 from "@inquirer/checkbox";
1058
+ import fs7 from "fs-extra";
1059
+ import pc3 from "picocolors";
1060
+ function asBuffer(data) {
1061
+ return typeof data === "string" ? Buffer2.from(data) : data;
980
1062
  }
981
- function isFileChanged(src, dest) {
1063
+ async function evaluateWriteIntent(targetPath, options) {
1064
+ const { skipOverwrite, source } = options;
1065
+ const exists = await fs7.pathExists(targetPath);
1066
+ if (!exists) {
1067
+ return {
1068
+ type: "write",
1069
+ reason: "missing"
1070
+ };
1071
+ }
1072
+ if (skipOverwrite) {
1073
+ return {
1074
+ type: "skip",
1075
+ reason: "skipOverwrite"
1076
+ };
1077
+ }
1078
+ const src = asBuffer(source);
1079
+ let destSize = 0;
982
1080
  try {
983
- const currentHash = getFileHash(src);
984
- const previousHash = getFileHash(dest);
985
- return currentHash !== previousHash;
986
- } catch (err) {
987
- logger.error("Error calculating file hash:", err);
988
- return false;
1081
+ const stat = await fs7.stat(targetPath);
1082
+ destSize = stat.size;
1083
+ } catch {
1084
+ return {
1085
+ type: "write",
1086
+ reason: "missing"
1087
+ };
1088
+ }
1089
+ if (destSize !== src.length) {
1090
+ return {
1091
+ type: "prompt",
1092
+ reason: "changed"
1093
+ };
989
1094
  }
1095
+ const dest = await fs7.readFile(targetPath);
1096
+ if (!isFileChanged(src, dest)) {
1097
+ return {
1098
+ type: "skip",
1099
+ reason: "identical"
1100
+ };
1101
+ }
1102
+ return {
1103
+ type: "prompt",
1104
+ reason: "changed"
1105
+ };
990
1106
  }
991
-
992
- // src/utils/regexp.ts
993
- init_esm_shims();
994
- function escapeStringRegexp(str) {
995
- return str.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
1107
+ async function scheduleOverwrite(intent, options) {
1108
+ const { relPath, targetPath, action, pending } = options;
1109
+ if (intent.type === "write") {
1110
+ await action();
1111
+ return;
1112
+ }
1113
+ if (intent.type === "prompt") {
1114
+ pending.push({
1115
+ relPath,
1116
+ targetPath,
1117
+ action
1118
+ });
1119
+ }
996
1120
  }
997
- function isMatch(str, arr) {
998
- for (const reg of arr) {
999
- if (reg.test(str)) {
1000
- return true;
1121
+ async function flushPendingOverwrites(pending) {
1122
+ if (!pending.length) {
1123
+ return;
1124
+ }
1125
+ const selected = await checkbox2({
1126
+ message: "\u68C0\u6D4B\u5230\u4EE5\u4E0B\u6587\u4EF6\u5185\u5BB9\u4E0E\u5F53\u524D\u4ED3\u5E93\u4E0D\u540C\uFF0C\u9009\u62E9\u9700\u8981\u8986\u76D6\u7684\u6587\u4EF6",
1127
+ choices: pending.map((item) => ({
1128
+ name: pc3.greenBright(item.relPath),
1129
+ value: item.targetPath,
1130
+ checked: false
1131
+ })),
1132
+ loop: false
1133
+ });
1134
+ const selectedSet = new Set(selected);
1135
+ for (const item of pending) {
1136
+ if (selectedSet.has(item.targetPath)) {
1137
+ await item.action();
1001
1138
  }
1002
1139
  }
1003
- return false;
1004
1140
  }
1005
1141
 
1006
- // src/commands/upgrade/index.ts
1142
+ // src/commands/upgrade/pkg-json.ts
1007
1143
  init_esm_shims();
1008
- var import_set_value6 = __toESM(require_set_value(), 1);
1009
- import { Buffer as Buffer2 } from "buffer";
1010
- import process2 from "process";
1011
- import checkbox2 from "@inquirer/checkbox";
1012
- import confirm from "@inquirer/confirm";
1013
- import fs7 from "fs-extra";
1014
- import klaw from "klaw";
1015
- import path13 from "pathe";
1016
- import pc3 from "picocolors";
1017
1144
  import { coerce, gte, minVersion } from "semver";
1018
1145
 
1019
1146
  // src/commands/upgrade/scripts.ts
@@ -1027,44 +1154,7 @@ var scripts = {
1027
1154
  };
1028
1155
  var scriptsEntries = Object.entries(scripts);
1029
1156
 
1030
- // src/commands/upgrade/targets.ts
1031
- init_esm_shims();
1032
- function getAssetTargets(raw) {
1033
- const list = [
1034
- ".changeset",
1035
- ".husky",
1036
- ".vscode",
1037
- ".editorconfig",
1038
- ".gitattributes",
1039
- ".gitignore",
1040
- ".npmrc",
1041
- "commitlint.config.ts",
1042
- "eslint.config.js",
1043
- "lint-staged.config.js",
1044
- "stylelint.config.js",
1045
- "monorepo.config.ts",
1046
- "package.json",
1047
- // pnpm
1048
- "pnpm-workspace.yaml",
1049
- // base tsconfig
1050
- "tsconfig.json",
1051
- // turbo
1052
- "turbo.json",
1053
- // vitest
1054
- "vitest.config.ts",
1055
- // 'vitest.workspace.ts',
1056
- // #region docker
1057
- "Dockerfile",
1058
- ".dockerignore"
1059
- // #endregion
1060
- ];
1061
- if (!raw) {
1062
- list.push(".github", "LICENSE", "renovate.json", "SECURITY.md", "CODE_OF_CONDUCT.md", "CONTRIBUTING.md", "netlify.toml");
1063
- }
1064
- return list;
1065
- }
1066
-
1067
- // src/commands/upgrade/index.ts
1157
+ // src/commands/upgrade/pkg-json.ts
1068
1158
  function isWorkspace(version2) {
1069
1159
  if (typeof version2 === "string") {
1070
1160
  return version2.startsWith("workspace:");
@@ -1147,38 +1237,45 @@ function setPkgJson(sourcePkgJson, targetPkgJson, options) {
1147
1237
  targetPkgJson.scripts = scripts2;
1148
1238
  }
1149
1239
  }
1150
- function confirmOverwrite(filename) {
1151
- return confirm({ message: `${pc3.greenBright(filename)} \u6587\u4EF6\u5185\u5BB9\u53D1\u751F\u6539\u53D8,\u662F\u5426\u8986\u76D6?`, default: true });
1152
- }
1153
- function asBuffer(data) {
1154
- return typeof data === "string" ? Buffer2.from(data) : data;
1155
- }
1156
- async function shouldWriteFile(targetPath, options) {
1157
- const { skipOverwrite, source, promptLabel } = options;
1158
- const exists = await fs7.pathExists(targetPath);
1159
- if (!exists) {
1160
- return true;
1161
- }
1162
- if (skipOverwrite) {
1163
- return false;
1164
- }
1165
- const src = asBuffer(source);
1166
- let destSize = 0;
1167
- try {
1168
- const stat = await fs7.stat(targetPath);
1169
- destSize = stat.size;
1170
- } catch {
1171
- return true;
1172
- }
1173
- if (destSize !== src.length) {
1174
- return confirmOverwrite(promptLabel);
1175
- }
1176
- const dest = await fs7.readFile(targetPath);
1177
- if (!isFileChanged(src, dest)) {
1178
- return false;
1240
+
1241
+ // src/commands/upgrade/targets.ts
1242
+ init_esm_shims();
1243
+ function getAssetTargets(raw) {
1244
+ const list = [
1245
+ ".changeset",
1246
+ ".husky",
1247
+ ".vscode",
1248
+ ".editorconfig",
1249
+ ".gitattributes",
1250
+ ".gitignore",
1251
+ ".npmrc",
1252
+ "commitlint.config.ts",
1253
+ "eslint.config.js",
1254
+ "lint-staged.config.js",
1255
+ "stylelint.config.js",
1256
+ "monorepo.config.ts",
1257
+ "package.json",
1258
+ // pnpm
1259
+ "pnpm-workspace.yaml",
1260
+ // base tsconfig
1261
+ "tsconfig.json",
1262
+ // turbo
1263
+ "turbo.json",
1264
+ // vitest
1265
+ "vitest.config.ts",
1266
+ // 'vitest.workspace.ts',
1267
+ // #region docker
1268
+ "Dockerfile",
1269
+ ".dockerignore"
1270
+ // #endregion
1271
+ ];
1272
+ if (!raw) {
1273
+ list.push(".github", "LICENSE", "renovate.json", "SECURITY.md", "CODE_OF_CONDUCT.md", "CONTRIBUTING.md", "netlify.toml");
1179
1274
  }
1180
- return confirmOverwrite(promptLabel);
1275
+ return list;
1181
1276
  }
1277
+
1278
+ // src/commands/upgrade/index.ts
1182
1279
  async function upgradeMonorepo(opts) {
1183
1280
  const cwd = opts.cwd ?? process2.cwd();
1184
1281
  const upgradeConfig = await resolveCommandConfig("upgrade", cwd);
@@ -1199,7 +1296,7 @@ async function upgradeMonorepo(opts) {
1199
1296
  const mergeTargets = upgradeConfig == null ? void 0 : upgradeConfig.mergeTargets;
1200
1297
  let targets = configTargets.length ? mergeTargets === false ? [...configTargets] : Array.from(/* @__PURE__ */ new Set([...baseTargets, ...configTargets])) : baseTargets;
1201
1298
  if (merged.interactive) {
1202
- targets = await checkbox2({
1299
+ targets = await checkbox3({
1203
1300
  message: "\u9009\u62E9\u4F60\u9700\u8981\u7684\u6587\u4EF6",
1204
1301
  choices: targets.map((x) => {
1205
1302
  return {
@@ -1215,62 +1312,89 @@ async function upgradeMonorepo(opts) {
1215
1312
  const skipChangesetMarkdown = (upgradeConfig == null ? void 0 : upgradeConfig.skipChangesetMarkdown) ?? true;
1216
1313
  const scriptOverrides = upgradeConfig == null ? void 0 : upgradeConfig.scripts;
1217
1314
  const skipOverwrite = merged.skipOverwrite;
1315
+ const pendingOverwrites = [];
1218
1316
  for await (const file of klaw(assetsDir, {
1219
1317
  filter(p) {
1220
- const str = path13.relative(assetsDir, p);
1221
- return isMatch(str, regexpArr);
1318
+ const rel = toWorkspaceGitignorePath(path13.relative(assetsDir, p));
1319
+ return isMatch(rel, regexpArr);
1222
1320
  }
1223
1321
  })) {
1224
1322
  if (!file.stats.isFile()) {
1225
1323
  continue;
1226
1324
  }
1227
- let relPath = path13.relative(assetsDir, file.path);
1228
- if (relPath === "gitignore") {
1229
- relPath = ".gitignore";
1230
- }
1325
+ const relPath = toWorkspaceGitignorePath(path13.relative(assetsDir, file.path));
1231
1326
  if (skipChangesetMarkdown && relPath.startsWith(".changeset/") && relPath.endsWith(".md")) {
1232
1327
  continue;
1233
1328
  }
1234
1329
  const targetPath = path13.resolve(absOutDir, relPath);
1235
1330
  try {
1236
1331
  if (relPath === "package.json") {
1237
- if (!await fs7.pathExists(targetPath)) {
1332
+ if (!await fs8.pathExists(targetPath)) {
1238
1333
  continue;
1239
1334
  }
1240
- const sourcePkgJson = await fs7.readJson(file.path);
1241
- const targetPkgJson = await fs7.readJson(targetPath);
1335
+ const sourcePkgJson = await fs8.readJson(file.path);
1336
+ const targetPkgJson = await fs8.readJson(targetPath);
1242
1337
  setPkgJson(sourcePkgJson, targetPkgJson, { scripts: scriptOverrides });
1243
1338
  const data = `${JSON.stringify(targetPkgJson, void 0, 2)}
1244
1339
  `;
1245
- if (await shouldWriteFile(targetPath, { skipOverwrite, source: data, promptLabel: relPath })) {
1246
- await fs7.outputFile(targetPath, data, "utf8");
1340
+ const intent2 = await evaluateWriteIntent(targetPath, { skipOverwrite, source: data });
1341
+ const action2 = async () => {
1342
+ await fs8.outputFile(targetPath, data, "utf8");
1247
1343
  logger.success(targetPath);
1248
- }
1344
+ };
1345
+ await scheduleOverwrite(intent2, {
1346
+ relPath,
1347
+ targetPath,
1348
+ action: action2,
1349
+ pending: pendingOverwrites
1350
+ });
1249
1351
  continue;
1250
1352
  }
1251
1353
  if (relPath === ".changeset/config.json" && repoName) {
1252
- const changesetJson = await fs7.readJson(file.path);
1354
+ const changesetJson = await fs8.readJson(file.path);
1253
1355
  (0, import_set_value6.default)(changesetJson, "changelog.1.repo", repoName);
1254
1356
  const data = `${JSON.stringify(changesetJson, void 0, 2)}
1255
1357
  `;
1256
- if (await shouldWriteFile(targetPath, { skipOverwrite, source: data, promptLabel: relPath })) {
1257
- await fs7.outputFile(targetPath, data, "utf8");
1358
+ const intent2 = await evaluateWriteIntent(targetPath, { skipOverwrite, source: data });
1359
+ const action2 = async () => {
1360
+ await fs8.outputFile(targetPath, data, "utf8");
1258
1361
  logger.success(targetPath);
1259
- }
1362
+ };
1363
+ await scheduleOverwrite(intent2, {
1364
+ relPath,
1365
+ targetPath,
1366
+ action: action2,
1367
+ pending: pendingOverwrites
1368
+ });
1260
1369
  continue;
1261
1370
  }
1262
1371
  if (relPath === "LICENSE") {
1263
- const source = await fs7.readFile(file.path);
1264
- if (await shouldWriteFile(targetPath, { skipOverwrite: true, source, promptLabel: relPath })) {
1265
- await fs7.copy(file.path, targetPath);
1372
+ const source2 = await fs8.readFile(file.path);
1373
+ const intent2 = await evaluateWriteIntent(targetPath, { skipOverwrite: true, source: source2 });
1374
+ const action2 = async () => {
1375
+ await fs8.outputFile(targetPath, source2);
1266
1376
  logger.success(targetPath);
1267
- }
1377
+ };
1378
+ await scheduleOverwrite(intent2, {
1379
+ relPath,
1380
+ targetPath,
1381
+ action: action2,
1382
+ pending: pendingOverwrites
1383
+ });
1268
1384
  continue;
1269
1385
  }
1270
- if (await shouldWriteFile(targetPath, { skipOverwrite, source: await fs7.readFile(file.path), promptLabel: relPath })) {
1271
- await fs7.copy(file.path, targetPath);
1386
+ const source = await fs8.readFile(file.path);
1387
+ const intent = await evaluateWriteIntent(targetPath, { skipOverwrite, source });
1388
+ const action = async () => {
1389
+ await fs8.outputFile(targetPath, source);
1272
1390
  logger.success(targetPath);
1273
- }
1391
+ };
1392
+ await scheduleOverwrite(intent, {
1393
+ relPath,
1394
+ targetPath,
1395
+ action,
1396
+ pending: pendingOverwrites
1397
+ });
1274
1398
  } catch (error) {
1275
1399
  if (isIgnorableFsError(error)) {
1276
1400
  continue;
@@ -1278,6 +1402,7 @@ async function upgradeMonorepo(opts) {
1278
1402
  throw error;
1279
1403
  }
1280
1404
  }
1405
+ await flushPendingOverwrites(pendingOverwrites);
1281
1406
  }
1282
1407
 
1283
1408
  // src/commands/index.ts
@@ -1299,6 +1424,14 @@ export {
1299
1424
  assetsDir,
1300
1425
  rootDir,
1301
1426
  logger,
1427
+ isIgnorableFsError,
1428
+ toPublishGitignorePath,
1429
+ toWorkspaceGitignorePath,
1430
+ isGitignoreFile,
1431
+ getFileHash,
1432
+ isFileChanged,
1433
+ escapeStringRegexp,
1434
+ isMatch,
1302
1435
  templateMap,
1303
1436
  defaultTemplate,
1304
1437
  getCreateChoices,
@@ -1308,11 +1441,6 @@ export {
1308
1441
  init,
1309
1442
  setVscodeBinaryMirror,
1310
1443
  syncNpmMirror,
1311
- isIgnorableFsError,
1312
- getFileHash,
1313
- isFileChanged,
1314
- escapeStringRegexp,
1315
- isMatch,
1316
1444
  upgradeMonorepo
1317
1445
  };
1318
1446
  /*! Bundled license information: