@mnci/cli 4.0.6 → 4.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1136,9 +1136,39 @@ ${githubReleases ? "" : `
1136
1136
  if: \${{ ${onMain} }}
1137
1137
  `}`;
1138
1138
  }
1139
- var DEPENDABOT_CONFIG = `# Generated by MoNecromanCI. Weekly dependency-update PRs so vulnerable or
1139
+ var PIP_PROJECT_GLOBS = ["apps", "python-packages", "libs"];
1140
+ var PUB_PROJECT_GLOBS = ["apps", "packages", "libs"];
1141
+ var ECOSYSTEM_MANIFESTS = {
1142
+ pip: ["pyproject.toml", "requirements.txt"],
1143
+ pub: ["pubspec.yaml"]
1144
+ };
1145
+ function hasEcosystemProject(workspaceRoot, roots, manifests) {
1146
+ return roots.some((root) => {
1147
+ const base = (0, import_node_path2.join)(workspaceRoot, root);
1148
+ if (!(0, import_node_fs2.existsSync)(base)) {
1149
+ return false;
1150
+ }
1151
+ return (0, import_node_fs2.readdirSync)(base, { withFileTypes: true }).some(
1152
+ (entry) => entry.isDirectory() && manifests.some((manifest) => (0, import_node_fs2.existsSync)((0, import_node_path2.join)(base, entry.name, manifest)))
1153
+ );
1154
+ });
1155
+ }
1156
+ function dependabotBlock(ecosystem, roots) {
1157
+ return `
1158
+ - package-ecosystem: ${ecosystem}
1159
+ directories:
1160
+ ` + roots.map((root) => ` - "/${root}/*"
1161
+ `).join("") + " schedule:\n interval: weekly\n";
1162
+ }
1163
+ function dependabotConfig(workspaceRoot) {
1164
+ let config = `# Generated by MoNecromanCI. Weekly dependency-update PRs so vulnerable or
1140
1165
  # stale dependencies surface as a reviewable PR instead of only a push-time
1141
1166
  # warning.
1167
+ #
1168
+ # pip and pub appear here only once the workspace HAS a Python or Dart project.
1169
+ # An ecosystem entry whose directories match no manifest is a hard Dependabot
1170
+ # failure, not a no-op, so emitting them unconditionally cost every workspace
1171
+ # two red runs a week over projects it does not have.
1142
1172
  version: 2
1143
1173
  updates:
1144
1174
  - package-ecosystem: npm
@@ -1150,30 +1180,15 @@ updates:
1150
1180
  directory: "/"
1151
1181
  schedule:
1152
1182
  interval: weekly
1153
-
1154
- # Globs, not one entry per project: Python projects are added later via
1155
- # 'mnci add python-*', so this starts covering them automatically the
1156
- # moment the first one exists \u2014 a glob matching nothing yet is not an error.
1157
- - package-ecosystem: pip
1158
- directories:
1159
- - "/apps/*"
1160
- - "/python-packages/*"
1161
- - "/libs/*"
1162
- schedule:
1163
- interval: weekly
1164
-
1165
- # Same glob reasoning as pip above. Dart projects are pub workspace members,
1166
- # so each one declares its own dependencies even though they all resolve
1167
- # through the single root pubspec.lock \u2014 hence the per-project directories
1168
- # rather than just "/".
1169
- - package-ecosystem: pub
1170
- directories:
1171
- - "/apps/*"
1172
- - "/packages/*"
1173
- - "/libs/*"
1174
- schedule:
1175
- interval: weekly
1176
1183
  `;
1184
+ if (hasEcosystemProject(workspaceRoot, PIP_PROJECT_GLOBS, ECOSYSTEM_MANIFESTS.pip)) {
1185
+ config += dependabotBlock("pip", PIP_PROJECT_GLOBS);
1186
+ }
1187
+ if (hasEcosystemProject(workspaceRoot, PUB_PROJECT_GLOBS, ECOSYSTEM_MANIFESTS.pub)) {
1188
+ config += dependabotBlock("pub", PUB_PROJECT_GLOBS);
1189
+ }
1190
+ return config;
1191
+ }
1177
1192
  var NX_SCAFFOLDING_TO_REMOVE = [".prettierrc", ".prettierrc.json", ".vscode"];
1178
1193
  function removeNxScaffolding(workspaceRoot) {
1179
1194
  for (const entry of NX_SCAFFOLDING_TO_REMOVE) {
@@ -1300,7 +1315,7 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
1300
1315
  (0, import_node_path2.join)(workspaceRoot, ".github/workflows/ci.yml"),
1301
1316
  githubActionsYaml(options.agent, publishUrl, options.registry.kind, options.ci)
1302
1317
  );
1303
- writeFileEnsured((0, import_node_path2.join)(workspaceRoot, ".github/dependabot.yml"), DEPENDABOT_CONFIG);
1318
+ writeFileEnsured((0, import_node_path2.join)(workspaceRoot, ".github/dependabot.yml"), dependabotConfig(workspaceRoot));
1304
1319
  }
1305
1320
  }
1306
1321
 
@@ -1328,6 +1343,100 @@ function markPublic(manifestPath) {
1328
1343
  var WRONG_TYPES_PATH = "./dist/index.esm.d.ts";
1329
1344
  var ACTUAL_TYPES_PATH = "./dist/src/index.d.ts";
1330
1345
  var DECLARATION_MAP_EXCLUSION = "!**/*.d.ts.map";
1346
+ var ROLLUP_CONFIG_PLACEHOLDER = [
1347
+ " {",
1348
+ " // Provide additional rollup configuration here. See: https://rollupjs.org/configuration-options",
1349
+ " // e.g.",
1350
+ " // output: { sourcemap: true },",
1351
+ " }"
1352
+ ].join("\n");
1353
+ var ROLLUP_CONFIG_WITH_DTS_FIX = [
1354
+ " {",
1355
+ " // Added by MoNecromanCI. @nx/rollup's dts-bundle plugin writes dist/index.d.ts",
1356
+ " // as a stub re-exporting the real declarations, and builds that specifier with",
1357
+ " // path.relative() - an OS-NATIVE path. On Windows it emits",
1358
+ String.raw` // export * from "./src\\index";`,
1359
+ " // which is not a valid module specifier on ANY platform: a specifier is",
1360
+ " // URL-style, so / is correct everywhere and a backslash nowhere. It resolves on",
1361
+ " // Windows only because the resolver normalises separators there, leaving the",
1362
+ " // package untyped on Linux and macOS.",
1363
+ " //",
1364
+ " // mnci also points `types` past this stub, so nothing depends on it being",
1365
+ " // correct; this makes the emitted file correct too. Remove once Nx fixes the",
1366
+ " // plugin - its own devkit already exports normalizePath for exactly this.",
1367
+ " plugins: [",
1368
+ " {",
1369
+ " name: 'mnci-normalise-declaration-specifiers',",
1370
+ " writeBundle (outputOptions) {",
1371
+ " const { readFileSync, writeFileSync } = require('node:fs')",
1372
+ " const { join } = require('node:path')",
1373
+ " const stub = join(outputOptions.dir ?? './dist', 'index.d.ts')",
1374
+ " let source",
1375
+ " try {",
1376
+ " source = readFileSync(stub, 'utf8')",
1377
+ " } catch {",
1378
+ " return",
1379
+ " }",
1380
+ " // The stub carries a TWO-character escape (JSON.stringify escaped one",
1381
+ " // backslash), so this must not match a single one - that would turn",
1382
+ String.raw` // "./src\index" into "./src//index". Built from char codes so there is`,
1383
+ " // no escaping in this file to get wrong.",
1384
+ " const separator = String.fromCodePoint(92, 92)",
1385
+ " const normalised = source.replaceAll(separator, '/')",
1386
+ " if (normalised !== source) writeFileSync(stub, normalised)",
1387
+ " }",
1388
+ " }",
1389
+ " ]",
1390
+ " }"
1391
+ ].join("\n");
1392
+ function repairDeclarationSpecifiers(projectRoot) {
1393
+ const configPath = (0, import_node_path3.join)(projectRoot, "rollup.config.cjs");
1394
+ if (!fileExists(configPath)) {
1395
+ return;
1396
+ }
1397
+ const config = (0, import_node_fs3.readFileSync)(configPath, "utf8");
1398
+ if (!config.includes(ROLLUP_CONFIG_PLACEHOLDER)) {
1399
+ return;
1400
+ }
1401
+ writeFileEnsured(
1402
+ configPath,
1403
+ config.split(ROLLUP_CONFIG_PLACEHOLDER).join(ROLLUP_CONFIG_WITH_DTS_FIX)
1404
+ );
1405
+ }
1406
+ function writeProjectReadme(projectRoot, projectName, testRunner) {
1407
+ const runner = testRunner === "vitest" ? "[Vitest](https://vitest.dev)" : "[Jest](https://jestjs.io)";
1408
+ writeFileEnsured(
1409
+ (0, import_node_path3.join)(projectRoot, "README.md"),
1410
+ [
1411
+ `# ${projectName}`,
1412
+ "",
1413
+ "Generated by [MoNecromanCI](https://github.com/russoedu/MoNecromanCi).",
1414
+ "",
1415
+ "## Building",
1416
+ "",
1417
+ `Run \`nx build ${projectName}\` to build this project.`,
1418
+ "",
1419
+ "## Running unit tests",
1420
+ "",
1421
+ `Run \`nx test ${projectName}\` to execute the unit tests via ${runner}.`,
1422
+ ""
1423
+ ].join("\n")
1424
+ );
1425
+ }
1426
+ function removeStaleGitkeeps(workspaceRoot) {
1427
+ for (const scaffold of ["apps", "libs", "packages"]) {
1428
+ const directory = (0, import_node_path3.join)(workspaceRoot, scaffold);
1429
+ try {
1430
+ const holdsAProject = (0, import_node_fs3.readdirSync)(directory, { withFileTypes: true }).some(
1431
+ (entry) => entry.isDirectory()
1432
+ );
1433
+ if (holdsAProject) {
1434
+ (0, import_node_fs3.rmSync)((0, import_node_path3.join)(directory, ".gitkeep"), { force: true });
1435
+ }
1436
+ } catch {
1437
+ }
1438
+ }
1439
+ }
1331
1440
  function repairPublishableManifest(manifestPath) {
1332
1441
  const manifest = readJson(manifestPath);
1333
1442
  if (manifest.types === WRONG_TYPES_PATH) {
@@ -1397,6 +1506,7 @@ function projectTask(name, kind) {
1397
1506
  return kind === "start" ? { ...base, isBackground: true } : { ...base, group: kind };
1398
1507
  }
1399
1508
  function registerProjectCommands(workspaceRoot, name, commands) {
1509
+ removeStaleGitkeeps(workspaceRoot);
1400
1510
  const scripts = {
1401
1511
  [`${name}:qa`]: `nx run ${name}:lint && nx run ${name}:test`
1402
1512
  };
@@ -1406,6 +1516,10 @@ function registerProjectCommands(workspaceRoot, name, commands) {
1406
1516
  if (commands.start) {
1407
1517
  scripts[`${name}:start`] = commands.start;
1408
1518
  }
1519
+ const dependabotPath = (0, import_node_path3.join)(workspaceRoot, ".github/dependabot.yml");
1520
+ if ((0, import_node_fs3.existsSync)(dependabotPath)) {
1521
+ writeFileEnsured(dependabotPath, dependabotConfig(workspaceRoot));
1522
+ }
1409
1523
  const manifestPath = (0, import_node_path3.join)(workspaceRoot, "package.json");
1410
1524
  const manifest = readJson(manifestPath);
1411
1525
  const existingScripts = manifest.scripts ?? {};
@@ -1860,6 +1974,8 @@ async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
1860
1974
  const manifestPath = (0, import_node_path7.join)(workspaceRoot, "packages", name, "package.json");
1861
1975
  markPublic(manifestPath);
1862
1976
  repairPublishableManifest(manifestPath);
1977
+ repairDeclarationSpecifiers((0, import_node_path7.join)(workspaceRoot, `packages/${name}`));
1978
+ writeProjectReadme((0, import_node_path7.join)(workspaceRoot, `packages/${name}`), `${scope}/${name}`, stack.testRunner);
1863
1979
  removeGeneratedEslintConfig(workspaceRoot, `packages/${name}`);
1864
1980
  registerProjectCommands(workspaceRoot, name, { build: true });
1865
1981
  }
@@ -2188,6 +2304,8 @@ async function addReactLib(workspaceRoot, name, options, kindProvided, stack) {
2188
2304
  const publishableManifest = (0, import_node_path10.join)(workspaceRoot, "packages", name, "package.json");
2189
2305
  markPublic(publishableManifest);
2190
2306
  repairPublishableManifest(publishableManifest);
2307
+ repairDeclarationSpecifiers((0, import_node_path10.join)(workspaceRoot, "packages", name));
2308
+ writeProjectReadme((0, import_node_path10.join)(workspaceRoot, "packages", name), `${scope}/${name}`, stack.testRunner);
2191
2309
  removeGeneratedEslintConfig(workspaceRoot, `packages/${name}`);
2192
2310
  registerProjectCommands(workspaceRoot, name, { build: true });
2193
2311
  }
@@ -2209,6 +2327,8 @@ function addReactInternalLib(workspaceRoot, name, stack) {
2209
2327
  const privateManifest = (0, import_node_path10.join)(workspaceRoot, "libs", name, "package.json");
2210
2328
  markPrivate(privateManifest);
2211
2329
  repairPublishableManifest(privateManifest);
2330
+ repairDeclarationSpecifiers((0, import_node_path10.join)(workspaceRoot, "libs", name));
2331
+ writeProjectReadme((0, import_node_path10.join)(workspaceRoot, "libs", name), name, stack.testRunner);
2212
2332
  removeGeneratedEslintConfig(workspaceRoot, `libs/${name}`);
2213
2333
  registerProjectCommands(workspaceRoot, name, { build: true });
2214
2334
  }