@mnci/cli 4.2.2 → 4.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -135,6 +135,32 @@ chain breaks, and the map comes out valid-looking and **empty** — `sources: []
135
135
  Measured on a real package: swc gave 0 sources, babel gave 9. Revert the swap
136
136
  once Nx passes `sourceMaps` through; ROADMAP 7d has the one-line upstream fix.
137
137
 
138
+ Re-measured against the exact toolchain `mnci new` pins today (Nx 23.2.0,
139
+ `@swc/core` 1.15.8): `@nx/rollup`'s swc plugin still does **not** pass
140
+ `sourceMaps` to `transform()` — read straight from the installed package, not
141
+ assumed — yet a real build with `compiler: 'swc'` left unmodified now emits a
142
+ map with real `sources`/`sourcesContent`, and tracing a generated position
143
+ through it with `@jridgewell/trace-mapping` resolves to the correct original
144
+ line and column. So the empty-map failure this section exists to route around
145
+ did not reproduce on the current pinned versions, even though the documented
146
+ root cause (the plugin's own missing `sourceMaps` option) is still there
147
+ verbatim. That is not the revert condition stated above — nothing upstream
148
+ changed the call this section is about — so the swap stays in place as a
149
+ safety net rather than being removed on an unexplained, unpinned-by-upstream
150
+ behavior change that a future `@swc/core` patch could revert without notice.
151
+ **A real, separate bug in the swap itself was found and fixed**, independent
152
+ of the above: it matched `compiler: 'swc'` with a plain string, one space
153
+ after the colon. `@stylistic/key-spacing` (aligned on value) — which
154
+ `eslint --fix` applies to every mnci-generated file — pads that column out to
155
+ whatever the object's longest key is, so on any config reached after even one
156
+ lint pass (most concretely: `mnci upgrade` repairing a project whose `add`
157
+ partially failed) the literal silently stopped matching and the swap
158
+ silently no-op'd, while `sourceMap: true` and `sourcemapPathTransform` — added
159
+ by separate, whitespace-tolerant repairs — went in regardless. `mnci doctor`'s
160
+ check did not catch it either, since it only verifies the flag, not the
161
+ compiler. Confirmed end to end and fixed with the same whitespace-tolerant
162
+ approach `sourceMap: true`'s own guard already used.
163
+
138
164
  **The paths are wrong twice over.** rollup hands `sourcemapPathTransform` a
139
165
  path like `..\..\src\index.ts` for a map in `dist/` — one parent segment too
140
166
  many, so it resolves above the project to a file that does not exist, and
package/dist/cli.js CHANGED
@@ -1392,6 +1392,24 @@ function removeNxScaffolding(workspaceRoot) {
1392
1392
  function removeIfPresent(path) {
1393
1393
  (0, import_node_fs2.rmSync)(path, { recursive: true, force: true });
1394
1394
  }
1395
+ function ensureEslintCacheIgnored(workspaceRoot) {
1396
+ const gitignorePath = (0, import_node_path2.join)(workspaceRoot, ".gitignore");
1397
+ if (!fileExists(gitignorePath)) {
1398
+ return;
1399
+ }
1400
+ const current = (0, import_node_fs2.readFileSync)(gitignorePath, "utf8");
1401
+ if (current.split("\n").some((line) => line.trim() === ".eslintcache")) {
1402
+ return;
1403
+ }
1404
+ const withoutTrailingBlankLines = current.replace(/\n+$/, "");
1405
+ const separator = withoutTrailingBlankLines.length > 0 ? "\n\n" : "";
1406
+ writeFileEnsured(
1407
+ gitignorePath,
1408
+ `${withoutTrailingBlankLines}${separator}# Added by MoNecromanCI: \`npm run format\`/\`lint\` run \`eslint --cache\`.
1409
+ .eslintcache
1410
+ `
1411
+ );
1412
+ }
1395
1413
  function removeProjectEslintConfigs(workspaceRoot) {
1396
1414
  const matches = (0, import_node_fs2.globSync)("{apps,libs,packages}/*/eslint.config.{js,mjs,cjs,ts,mts,cts}", {
1397
1415
  cwd: workspaceRoot
@@ -1468,6 +1486,7 @@ function applyOverlay(workspaceRoot, options, onProgress = () => {
1468
1486
  markExecutable(hookPath);
1469
1487
  onProgress("eslint.config.mjs \u2014 the shared lint AND formatting opinion");
1470
1488
  writeFileEnsured((0, import_node_path2.join)(workspaceRoot, "eslint.config.mjs"), ESLINT_CONFIG);
1489
+ ensureEslintCacheIgnored(workspaceRoot);
1471
1490
  for (const retired of RETIRED_FORMATTER_FILES) {
1472
1491
  removeIfPresent((0, import_node_path2.join)(workspaceRoot, retired));
1473
1492
  }
@@ -1528,6 +1547,23 @@ function ensurePlugin(workspaceRoot, packageName) {
1528
1547
  logger.step(`Installing Nx plugin ${packageName}`);
1529
1548
  runNx(["add", packageName], workspaceRoot);
1530
1549
  }
1550
+ function runGeneratorAndRepair(workspaceRoot, nxArguments, markerPath, repair) {
1551
+ let installFailure;
1552
+ try {
1553
+ runNx(nxArguments, workspaceRoot);
1554
+ } catch (error) {
1555
+ installFailure = error instanceof Error ? error : new Error(String(error));
1556
+ }
1557
+ if (!fileExists(markerPath)) {
1558
+ throw installFailure ?? new Error(`unreachable: runNx did not throw and ${markerPath} is missing`);
1559
+ }
1560
+ repair();
1561
+ if (installFailure) {
1562
+ throw new Error(
1563
+ `The project was generated and mnci's own repairs were applied, but the underlying Nx generator's install step still failed (${installFailure.message}). Fix the install error above (commonly resolved by 'npm install' with a newer npm major), then verify with 'mnci doctor'.`
1564
+ );
1565
+ }
1566
+ }
1531
1567
  function markPrivate(manifestPath) {
1532
1568
  const manifest = readJson(manifestPath);
1533
1569
  writeFileEnsured(manifestPath, toJson({ ...manifest, private: true }));
@@ -1547,13 +1583,15 @@ var ROLLUP_CONFIG_PLACEHOLDER = [
1547
1583
  " // output: { sourcemap: true },",
1548
1584
  " }"
1549
1585
  ].join("\n");
1550
- var GENERATED_COMPILER = " compiler: 'swc',";
1551
- var SOURCE_MAP_CAPABLE_COMPILER = [
1552
- " // Swapped from swc by MoNecromanCI. @nx/rollup runs swc without",
1553
- " // sourceMaps, so it returns no map and the bundle's map comes out empty -",
1554
- " // valid-looking, and useless for debugging. See ROADMAP.",
1555
- " compiler: 'babel',"
1556
- ].join("\n");
1586
+ var GENERATED_COMPILER_PATTERN = /^( {4})compiler\s*:\s*'swc',$/m;
1587
+ function sourceMapCapableCompiler(indent) {
1588
+ return [
1589
+ `${indent}// Swapped from swc by MoNecromanCI. @nx/rollup runs swc without`,
1590
+ `${indent}// sourceMaps, so it returns no map and the bundle's map comes out empty -`,
1591
+ `${indent}// valid-looking, and useless for debugging. See ROADMAP.`,
1592
+ `${indent}compiler: 'babel',`
1593
+ ].join("\n");
1594
+ }
1557
1595
  var ROLLUP_ARG_ONE_BOUNDARY = [" },", " {", ""].join("\n");
1558
1596
  var ROLLUP_ARG_ONE_WITH_SOURCE_MAPS = [
1559
1597
  " // Added by MoNecromanCI: without this rollup emits no .js.map at all, so",
@@ -1573,7 +1611,10 @@ function withRollupSourceMaps(config) {
1573
1611
  if (hasRollupSourceMaps(config) || !canRepairRollupConfig(config)) {
1574
1612
  return config;
1575
1613
  }
1576
- const withCompiler = config.replace(GENERATED_COMPILER, () => SOURCE_MAP_CAPABLE_COMPILER);
1614
+ const withCompiler = config.replace(
1615
+ GENERATED_COMPILER_PATTERN,
1616
+ (_match, indent) => sourceMapCapableCompiler(indent)
1617
+ );
1577
1618
  const withFlag = withCompiler.replace(
1578
1619
  ROLLUP_ARG_ONE_BOUNDARY,
1579
1620
  () => ROLLUP_ARG_ONE_WITH_SOURCE_MAPS
@@ -1648,13 +1689,24 @@ var ROLLUP_CONFIG_WITH_DTS_FIX = [
1648
1689
  " // mnci also points `types` past this stub, so nothing depends on it being",
1649
1690
  " // correct; this makes the emitted file correct too. Remove once Nx fixes the",
1650
1691
  " // plugin - its own devkit already exports normalizePath for exactly this.",
1692
+ " //",
1693
+ " // The second half fixes a separate defect in the REAL declarations `types`",
1694
+ ' // points at: tsconfig.lib.json declares under moduleResolution "bundler",',
1695
+ ' // where a bare relative specifier ("./lib/align") is valid, so every emitted',
1696
+ " // .d.ts keeps the source's own extensionless imports verbatim. A consumer on",
1697
+ ' // "moduleResolution": "nodenext" - the workspace root default - requires an',
1698
+ " // explicit extension on every relative specifier and gets TS2834 (or,",
1699
+ " // combined with skipLibCheck, a silent zero-export module) instead. Declared",
1700
+ " // extensions are left untouched; only a bare relative specifier gets .js",
1701
+ " // appended, matching what tsc itself emits under node16/nodenext.",
1651
1702
  " plugins: [",
1652
1703
  " {",
1653
1704
  " name: 'mnci-normalise-declaration-specifiers',",
1654
1705
  " writeBundle (outputOptions) {",
1655
- " const { readFileSync, writeFileSync } = require('node:fs')",
1706
+ " const { readdirSync, readFileSync, writeFileSync } = require('node:fs')",
1656
1707
  " const { join } = require('node:path')",
1657
- " const stub = join(outputOptions.dir ?? './dist', 'index.d.ts')",
1708
+ " const dir = outputOptions.dir ?? './dist'",
1709
+ " const stub = join(dir, 'index.d.ts')",
1658
1710
  " let source",
1659
1711
  " try {",
1660
1712
  " source = readFileSync(stub, 'utf8')",
@@ -1668,6 +1720,31 @@ var ROLLUP_CONFIG_WITH_DTS_FIX = [
1668
1720
  " const separator = String.fromCodePoint(92, 92)",
1669
1721
  " const normalised = source.replaceAll(separator, '/')",
1670
1722
  " if (normalised !== source) writeFileSync(stub, normalised)",
1723
+ "",
1724
+ String.raw` const bareRelativeSpecifier = /from(\s+)(['"])(\.[^'"]+?)\2/g`,
1725
+ String.raw` const hasExtension = /\.(?:mjs|cjs|jsx?|json)$/`,
1726
+ " let entries",
1727
+ " try {",
1728
+ " entries = readdirSync(dir, { recursive: true, withFileTypes: true })",
1729
+ " } catch {",
1730
+ " return",
1731
+ " }",
1732
+ " for (const entry of entries) {",
1733
+ " if (!entry.name.endsWith('.d.ts')) continue",
1734
+ " const filePath = join(entry.parentPath ?? entry.path, entry.name)",
1735
+ " let declaration",
1736
+ " try {",
1737
+ " declaration = readFileSync(filePath, 'utf8')",
1738
+ " } catch {",
1739
+ " continue",
1740
+ " }",
1741
+ " const withExtensions = declaration.replace(",
1742
+ " bareRelativeSpecifier,",
1743
+ " (match, space, quote, specifier) =>",
1744
+ " hasExtension.test(specifier) ? match : `from${space}${quote}${specifier}.js${quote}`,",
1745
+ " )",
1746
+ " if (withExtensions !== declaration) writeFileSync(filePath, withExtensions)",
1747
+ " }",
1671
1748
  " }",
1672
1749
  " }",
1673
1750
  " ]",
@@ -2538,7 +2615,10 @@ function addNodeFunctionApp(workspaceRoot, name, stack) {
2538
2615
  var import_node_path8 = require("path");
2539
2616
  async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
2540
2617
  const scope = options.scope ?? (kindProvided ? defaultScope(workspaceRoot) : await promptText("npm scope for the published package", defaultScope(workspaceRoot)));
2541
- runNx(
2618
+ const projectRoot = (0, import_node_path8.join)(workspaceRoot, "packages", name);
2619
+ const manifestPath = (0, import_node_path8.join)(projectRoot, "package.json");
2620
+ runGeneratorAndRepair(
2621
+ workspaceRoot,
2542
2622
  [
2543
2623
  "g",
2544
2624
  "@nx/js:lib",
@@ -2550,15 +2630,16 @@ async function addNpmLib(workspaceRoot, name, options, kindProvided, stack) {
2550
2630
  "--linter=none",
2551
2631
  "--no-interactive"
2552
2632
  ],
2553
- workspaceRoot
2633
+ manifestPath,
2634
+ () => {
2635
+ markPublic(manifestPath);
2636
+ repairPublishableManifest(manifestPath);
2637
+ repairDeclarationSpecifiers(projectRoot);
2638
+ writeProjectReadme(projectRoot, `${scope}/${name}`, stack.testRunner);
2639
+ removeGeneratedEslintConfig(workspaceRoot, `packages/${name}`);
2640
+ registerProjectCommands(workspaceRoot, name, { build: true });
2641
+ }
2554
2642
  );
2555
- const manifestPath = (0, import_node_path8.join)(workspaceRoot, "packages", name, "package.json");
2556
- markPublic(manifestPath);
2557
- repairPublishableManifest(manifestPath);
2558
- repairDeclarationSpecifiers((0, import_node_path8.join)(workspaceRoot, `packages/${name}`));
2559
- writeProjectReadme((0, import_node_path8.join)(workspaceRoot, `packages/${name}`), `${scope}/${name}`, stack.testRunner);
2560
- removeGeneratedEslintConfig(workspaceRoot, `packages/${name}`);
2561
- registerProjectCommands(workspaceRoot, name, { build: true });
2562
2643
  }
2563
2644
 
2564
2645
  // src/commands/add/python.ts
@@ -2862,7 +2943,10 @@ var REACT_LIB_BUNDLER = "rollup";
2862
2943
  async function addReactLib(workspaceRoot, name, options, kindProvided, stack) {
2863
2944
  ensurePlugin(workspaceRoot, "@nx/react");
2864
2945
  const scope = options.scope ?? (kindProvided ? defaultScope(workspaceRoot) : await promptText("npm scope for the published package", defaultScope(workspaceRoot)));
2865
- runNx(
2946
+ const projectRoot = (0, import_node_path11.join)(workspaceRoot, "packages", name);
2947
+ const publishableManifest = (0, import_node_path11.join)(projectRoot, "package.json");
2948
+ runGeneratorAndRepair(
2949
+ workspaceRoot,
2866
2950
  [
2867
2951
  "g",
2868
2952
  "@nx/react:library",
@@ -2875,19 +2959,23 @@ async function addReactLib(workspaceRoot, name, options, kindProvided, stack) {
2875
2959
  "--linter=none",
2876
2960
  "--no-interactive"
2877
2961
  ],
2878
- workspaceRoot
2962
+ publishableManifest,
2963
+ () => {
2964
+ markPublic(publishableManifest);
2965
+ repairPublishableManifest(publishableManifest);
2966
+ repairDeclarationSpecifiers(projectRoot);
2967
+ writeProjectReadme(projectRoot, `${scope}/${name}`, stack.testRunner);
2968
+ removeGeneratedEslintConfig(workspaceRoot, `packages/${name}`);
2969
+ registerProjectCommands(workspaceRoot, name, { build: true });
2970
+ }
2879
2971
  );
2880
- const publishableManifest = (0, import_node_path11.join)(workspaceRoot, "packages", name, "package.json");
2881
- markPublic(publishableManifest);
2882
- repairPublishableManifest(publishableManifest);
2883
- repairDeclarationSpecifiers((0, import_node_path11.join)(workspaceRoot, "packages", name));
2884
- writeProjectReadme((0, import_node_path11.join)(workspaceRoot, "packages", name), `${scope}/${name}`, stack.testRunner);
2885
- removeGeneratedEslintConfig(workspaceRoot, `packages/${name}`);
2886
- registerProjectCommands(workspaceRoot, name, { build: true });
2887
2972
  }
2888
2973
  function addReactInternalLib(workspaceRoot, name, stack) {
2889
2974
  ensurePlugin(workspaceRoot, "@nx/react");
2890
- runNx(
2975
+ const projectRoot = (0, import_node_path11.join)(workspaceRoot, "libs", name);
2976
+ const privateManifest = (0, import_node_path11.join)(projectRoot, "package.json");
2977
+ runGeneratorAndRepair(
2978
+ workspaceRoot,
2891
2979
  [
2892
2980
  "g",
2893
2981
  "@nx/react:library",
@@ -2898,15 +2986,16 @@ function addReactInternalLib(workspaceRoot, name, stack) {
2898
2986
  "--linter=none",
2899
2987
  "--no-interactive"
2900
2988
  ],
2901
- workspaceRoot
2989
+ privateManifest,
2990
+ () => {
2991
+ markPrivate(privateManifest);
2992
+ repairPublishableManifest(privateManifest);
2993
+ repairDeclarationSpecifiers(projectRoot);
2994
+ writeProjectReadme(projectRoot, name, stack.testRunner);
2995
+ removeGeneratedEslintConfig(workspaceRoot, `libs/${name}`);
2996
+ registerProjectCommands(workspaceRoot, name, { build: true });
2997
+ }
2902
2998
  );
2903
- const privateManifest = (0, import_node_path11.join)(workspaceRoot, "libs", name, "package.json");
2904
- markPrivate(privateManifest);
2905
- repairPublishableManifest(privateManifest);
2906
- repairDeclarationSpecifiers((0, import_node_path11.join)(workspaceRoot, "libs", name));
2907
- writeProjectReadme((0, import_node_path11.join)(workspaceRoot, "libs", name), name, stack.testRunner);
2908
- removeGeneratedEslintConfig(workspaceRoot, `libs/${name}`);
2909
- registerProjectCommands(workspaceRoot, name, { build: true });
2910
2999
  }
2911
3000
 
2912
3001
  // src/commands/sync.ts