@bobfrankston/npmglobalize 1.0.204 → 1.0.205

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.
Files changed (2) hide show
  1. package/lib.js +47 -14
  2. package/package.json +1 -1
package/lib.js CHANGED
@@ -2383,23 +2383,43 @@ function migrateTsconfigDeprecations(cwd, snapshot) {
2383
2383
  };
2384
2384
  const note = (msg) => console.log(colors.cyan(` ${msg}`));
2385
2385
  let changed = false;
2386
- // moduleResolution: node/node10/classic → nodenext (+ align module).
2386
+ // moduleResolution: node/node10/classic → NodeNext (+ align module).
2387
2387
  const mr = effectiveCompilerOption(chain, 'moduleResolution');
2388
2388
  if (mr && typeof mr.value === 'string' && DEPRECATED_MODULE_RESOLUTION.has(mr.value.toLowerCase())) {
2389
2389
  const tgt = targetFor(mr.definedIn);
2390
- if (tgt && edit(tgt.path, t => upsertCompilerOption(t, 'moduleResolution', '"nodenext"'))) {
2390
+ if (tgt && edit(tgt.path, t => upsertCompilerOption(t, 'moduleResolution', `"${CANONICAL_NODENEXT}"`))) {
2391
2391
  changed = true;
2392
- note(`Migrated moduleResolution "${mr.value}" → "nodenext" in ${path.relative(cwd, tgt.path) || 'tsconfig.json'}`);
2392
+ note(`Migrated moduleResolution "${mr.value}" → "${CANONICAL_NODENEXT}" in ${path.relative(cwd, tgt.path) || 'tsconfig.json'}`);
2393
2393
  // nodenext resolution requires a matching module setting.
2394
2394
  const mod = effectiveCompilerOption(chain, 'module');
2395
2395
  const modOk = mod && typeof mod.value === 'string' && /^(node16|nodenext|preserve)$/i.test(mod.value);
2396
2396
  if (!modOk) {
2397
2397
  const modTgt = mod ? targetFor(mod.definedIn) : mostLeafWritable;
2398
- if (modTgt && edit(modTgt.path, t => upsertCompilerOption(t, 'module', '"nodenext"'))) {
2399
- note(`Aligned module → "nodenext" (required by moduleResolution "nodenext")`);
2398
+ if (modTgt && edit(modTgt.path, t => upsertCompilerOption(t, 'module', `"${CANONICAL_NODENEXT}"`))) {
2399
+ note(`Aligned module → "${CANONICAL_NODENEXT}" (required by moduleResolution "${CANONICAL_NODENEXT}")`);
2400
2400
  }
2401
2401
  }
2402
- recordBuildIssue(name, 'warning', `Migrated moduleResolution "${mr.value}" → "nodenext". Verify relative imports resolve (NodeNext requires explicit file extensions on relative specifiers).`);
2402
+ recordBuildIssue(name, 'warning', `Migrated moduleResolution "${mr.value}" → "${CANONICAL_NODENEXT}". Verify relative imports resolve (NodeNext requires explicit file extensions on relative specifiers).`);
2403
+ }
2404
+ }
2405
+ // Canonical casing for values we write ourselves. TypeScript reads these
2406
+ // case-insensitively, but the JSON schema behind editor linting (webhint,
2407
+ // "Microsoft Edge Tools") only accepts the documented spelling, so an
2408
+ // all-lowercase "nodenext" we wrote earlier shows up as an error in the
2409
+ // editor even though the build is fine.
2410
+ for (const key of ['module', 'moduleResolution']) {
2411
+ const opt = effectiveCompilerOption(chain, key);
2412
+ if (!opt || typeof opt.value !== 'string')
2413
+ continue;
2414
+ const canonical = CANONICAL_CASING[opt.value.toLowerCase()];
2415
+ if (!canonical || canonical === opt.value)
2416
+ continue;
2417
+ const def = chain.find(c => c.path === opt.definedIn);
2418
+ if (!def?.writable)
2419
+ continue; // an override would be noise, not a fix
2420
+ if (edit(def.path, t => upsertCompilerOption(t, key, `"${canonical}"`))) {
2421
+ changed = true;
2422
+ note(`Normalized ${key} "${opt.value}" → "${canonical}" in ${path.relative(cwd, def.path) || 'tsconfig.json'}`);
2403
2423
  }
2404
2424
  }
2405
2425
  // target: es3 → es2022 (es3 is removed in TS7).
@@ -2440,9 +2460,10 @@ const esLevelRank = (value) => ES_LEVEL_RANK[value.toLowerCase().replace(/\.full
2440
2460
  /** tsc says "Try changing the 'lib' compiler option to 'es2023' or later"
2441
2461
  * (TS2550/TS2583/TS2584) when the code uses a standard-library API newer than
2442
2462
  * the configured level. That isn't a deprecation — it's a tsconfig the language
2443
- * moved past — so raise the level to whatever the build asked for and let it
2444
- * try again, rather than leaving the user to decode `replaceAll` and `toSorted`
2445
- * errors by hand.
2463
+ * moved past — so raise the level and let the build try again, rather than
2464
+ * leaving the user to decode `replaceAll` and `toSorted` errors by hand. The
2465
+ * level asked for only decides *whether* to raise; what we write is
2466
+ * `RAISED_ES_LEVEL`, so the next new method used doesn't start this over.
2446
2467
  *
2447
2468
  * We raise `target`: its implied `lib` keeps the DOM declarations a bare
2448
2469
  * `lib: ["es2023"]` would silently drop. An explicit `lib` overrides `target`
@@ -2506,12 +2527,12 @@ function raiseTsconfigLibLevel(cwd, buildOutput, snapshot) {
2506
2527
  const entries = lib.value.filter((e) => typeof e === 'string');
2507
2528
  if (entries.some(e => esLevelRank(e) >= esLevelRank(required)))
2508
2529
  return false;
2509
- const raised = [required, ...entries.filter(e => esLevelRank(e) === 0)];
2530
+ const raised = [RAISED_ES_LEVEL, ...entries.filter(e => esLevelRank(e) === 0)];
2510
2531
  const tgt = targetFor(lib.definedIn);
2511
2532
  if (!edit(tgt.path, t => upsertCompilerOption(t, 'lib', JSON.stringify(raised).replace(/","/g, '", "'))))
2512
2533
  return false;
2513
2534
  console.log(colors.cyan(` Raised lib [${entries.join(', ')}] → [${raised.join(', ')}] in ${path.relative(cwd, tgt.path) || 'tsconfig.json'} (build needs ${required})`));
2514
- recordBuildIssue(name, 'warning', `Raised "lib" to ${required} — the code uses standard-library APIs newer than the tsconfig allowed.`);
2535
+ recordBuildIssue(name, 'warning', `Raised "lib" to ${RAISED_ES_LEVEL} — the code uses standard-library APIs newer than the tsconfig allowed (needs ${required}).`);
2515
2536
  return true;
2516
2537
  }
2517
2538
  const tg = effectiveCompilerOption(chain, 'target');
@@ -2519,10 +2540,10 @@ function raiseTsconfigLibLevel(cwd, buildOutput, snapshot) {
2519
2540
  if (esLevelRank(current) >= esLevelRank(required))
2520
2541
  return false;
2521
2542
  const tgt = targetFor(tg?.definedIn);
2522
- if (!edit(tgt.path, t => upsertCompilerOption(t, 'target', `"${required}"`)))
2543
+ if (!edit(tgt.path, t => upsertCompilerOption(t, 'target', `"${RAISED_ES_LEVEL}"`)))
2523
2544
  return false;
2524
- console.log(colors.cyan(` Raised target "${current}" → "${required}" in ${path.relative(cwd, tgt.path) || 'tsconfig.json'} (build needs it)`));
2525
- recordBuildIssue(name, 'warning', `Raised "target" ${current} → ${required} — the code uses standard-library APIs newer than the tsconfig allowed.`);
2545
+ console.log(colors.cyan(` Raised target "${current}" → "${RAISED_ES_LEVEL}" in ${path.relative(cwd, tgt.path) || 'tsconfig.json'} (build needs ${required})`));
2546
+ recordBuildIssue(name, 'warning', `Raised "target" ${current} → ${RAISED_ES_LEVEL} — the code uses standard-library APIs newer than the tsconfig allowed (needs ${required}).`);
2526
2547
  return true;
2527
2548
  }
2528
2549
  /** Write back the texts captured in a `migrateTsconfigDeprecations` snapshot
@@ -3249,6 +3270,18 @@ export async function buildFileDepsTopologically(cwd, opts = {}, visited = new S
3249
3270
  }
3250
3271
  /** `moduleResolution` values TypeScript 6 deprecated and TypeScript 7 removes. */
3251
3272
  const DEPRECATED_MODULE_RESOLUTION = new Set(['node', 'node10', 'classic']);
3273
+ /** Spelling the tsconfig JSON schema — and so the editor linting built on it,
3274
+ * e.g. webhint via "Microsoft Edge Tools" — expects for the values we write.
3275
+ * TypeScript reads them case-insensitively; the schema does not. Deliberately
3276
+ * limited to the values npmglobalize writes itself: re-casing whatever the user
3277
+ * hand-typed would be churn, not a fix. */
3278
+ const CANONICAL_NODENEXT = 'NodeNext';
3279
+ const CANONICAL_CASING = { nodenext: CANONICAL_NODENEXT, node16: 'Node16' };
3280
+ /** Level we raise a too-old `target`/`lib` to. These are Node packages built and
3281
+ * run on the current Node, so tracking the newest language level costs nothing
3282
+ * and saves a re-raise every time the code picks up a newer standard-library
3283
+ * method. */
3284
+ const RAISED_ES_LEVEL = 'ESNext';
3252
3285
  /** Compiler flags TypeScript deprecated (TS5101) and will remove in TS7. Their
3253
3286
  * mere presence — at any value — is a migration item. */
3254
3287
  const DEPRECATED_TS7_FLAGS = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/npmglobalize",
3
- "version": "1.0.204",
3
+ "version": "1.0.205",
4
4
  "description": "Transform file: dependencies to npm versions for publishing",
5
5
  "main": "index.js",
6
6
  "type": "module",