@bobfrankston/npmglobalize 1.0.189 → 1.0.191
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/cli.js +14 -4
- package/lib.js +81 -8
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -8,6 +8,18 @@ import path from 'path';
|
|
|
8
8
|
import { styleText } from 'util';
|
|
9
9
|
// npmglobalize install directory (for --version)
|
|
10
10
|
const __dirname = import.meta.dirname;
|
|
11
|
+
/** Own version, read once. Stamped into the startup banner AND the Issues Summary
|
|
12
|
+
* so a failure log always reveals which installed npmglobalize produced it — a
|
|
13
|
+
* build that fails on something the source already fixes usually just means the
|
|
14
|
+
* installed copy predates the fix. */
|
|
15
|
+
const NPMGLOBALIZE_VERSION = (() => {
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8')).version;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return 'unknown';
|
|
21
|
+
}
|
|
22
|
+
})();
|
|
11
23
|
function printHelp() {
|
|
12
24
|
console.log(`
|
|
13
25
|
npmglobalize - Transform file: dependencies to npm versions for publishing
|
|
@@ -417,7 +429,7 @@ function printBuildSummary() {
|
|
|
417
429
|
if (issues.length === 0)
|
|
418
430
|
return;
|
|
419
431
|
console.log('');
|
|
420
|
-
console.log(styleText('yellow',
|
|
432
|
+
console.log(styleText('yellow', `━━━ Issues Summary (npmglobalize v${NPMGLOBALIZE_VERSION}) ━━━`));
|
|
421
433
|
for (const issue of issues) {
|
|
422
434
|
const icon = issue.severity === 'error' ? '✗' : '⚠';
|
|
423
435
|
console.log(styleText('yellow', ` ${icon} ${issue.module}: ${issue.message}`));
|
|
@@ -428,9 +440,7 @@ function printBuildSummary() {
|
|
|
428
440
|
export async function main() {
|
|
429
441
|
installCleanupHandlers();
|
|
430
442
|
// Show version at the very start
|
|
431
|
-
|
|
432
|
-
const ownPkg = JSON.parse(fs.readFileSync(ownPkgPath, 'utf-8'));
|
|
433
|
-
console.log(styleText('cyan', `npmglobalize v${ownPkg.version}`));
|
|
443
|
+
console.log(styleText('cyan', `npmglobalize v${NPMGLOBALIZE_VERSION}`));
|
|
434
444
|
const args = process.argv.slice(2);
|
|
435
445
|
const cliOptions = parseArgs(args);
|
|
436
446
|
if (cliOptions.help) {
|
package/lib.js
CHANGED
|
@@ -1947,12 +1947,12 @@ function getTscMajor() {
|
|
|
1947
1947
|
catch { /* leave at 0 — can't probe, assume pre-6 (no patch) */ }
|
|
1948
1948
|
return _tscMajor;
|
|
1949
1949
|
}
|
|
1950
|
-
/** Insert
|
|
1950
|
+
/** Insert `"<key>": <valueLiteral>` as the first property of `compilerOptions`,
|
|
1951
1951
|
* preserving the file's existing formatting/comments. Returns the patched text,
|
|
1952
1952
|
* or null if the object couldn't be located safely (caller leaves file alone).
|
|
1953
|
-
* Only ever called when
|
|
1954
|
-
function
|
|
1955
|
-
const
|
|
1953
|
+
* Only ever called when the key is known to be absent. */
|
|
1954
|
+
function insertCompilerOption(text, key, valueLiteral) {
|
|
1955
|
+
const prop = `"${key}": ${valueLiteral}`;
|
|
1956
1956
|
const m = text.match(/"compilerOptions"\s*:\s*\{/);
|
|
1957
1957
|
if (!m)
|
|
1958
1958
|
return null;
|
|
@@ -1965,15 +1965,20 @@ function insertTypesIntoTsconfig(text, typesArr) {
|
|
|
1965
1965
|
const lineStart = text.lastIndexOf('\n', m.index) + 1;
|
|
1966
1966
|
const baseIndent = text.slice(lineStart, m.index).match(/^\s*/)[0];
|
|
1967
1967
|
const propIndent = baseIndent + ' ';
|
|
1968
|
-
return text.slice(0, braceEnd) + '\n' + propIndent +
|
|
1968
|
+
return text.slice(0, braceEnd) + '\n' + propIndent + prop + '\n' + baseIndent + text.slice(braceEnd + ws.length);
|
|
1969
1969
|
}
|
|
1970
1970
|
// Multiline object: derive property indent from the existing first property.
|
|
1971
1971
|
if (ws.includes('\n')) {
|
|
1972
1972
|
const propIndent = ws.slice(ws.lastIndexOf('\n') + 1);
|
|
1973
|
-
return text.slice(0, braceEnd) + '\n' + propIndent +
|
|
1973
|
+
return text.slice(0, braceEnd) + '\n' + propIndent + prop + ',' + text.slice(braceEnd);
|
|
1974
1974
|
}
|
|
1975
1975
|
// Inline single-line object: `{ "target": ... }`
|
|
1976
|
-
return text.slice(0, braceEnd) + `
|
|
1976
|
+
return text.slice(0, braceEnd) + ` ${prop},` + text.slice(braceEnd);
|
|
1977
|
+
}
|
|
1978
|
+
/** Insert a `"types": [...]` line as the first property of `compilerOptions`.
|
|
1979
|
+
* Only ever called when `compilerOptions.types` is absent. */
|
|
1980
|
+
function insertTypesIntoTsconfig(text, typesArr) {
|
|
1981
|
+
return insertCompilerOption(text, 'types', '[' + typesArr.map(t => JSON.stringify(t)).join(', ') + ']');
|
|
1977
1982
|
}
|
|
1978
1983
|
/** `@types/*` packages that inject *global* declarations (usable with no
|
|
1979
1984
|
* `import`). TS6 stopped auto-including these, so under TS6+ they must be named
|
|
@@ -2102,6 +2107,55 @@ function ensureTsconfigNodeTypes(cwd) {
|
|
|
2102
2107
|
}
|
|
2103
2108
|
recordBuildIssue(chain[0].parsed?.name || path.basename(cwd), 'warning', `TS6+ build may fail: no writable compilerOptions block in the tsconfig chain of ${cwd} to add "types"`);
|
|
2104
2109
|
}
|
|
2110
|
+
/** TS6 turned several long-deprecated compiler options (e.g.
|
|
2111
|
+
* `moduleResolution: "node10"`/`"node"`/`"classic"`, old `target`s) into hard
|
|
2112
|
+
* errors (`TS5107`/`TS5101`) that will be *removed* in TS7. TypeScript's own
|
|
2113
|
+
* sanctioned bridge for the 6→7 window is `"ignoreDeprecations": "<version>"`
|
|
2114
|
+
* (the error text names the version, e.g. `"6.0"`). We apply exactly that so the
|
|
2115
|
+
* build proceeds, and record a warning so the real migration (to `node16` /
|
|
2116
|
+
* `nodenext` / `bundler`) still happens before TS7. We do NOT auto-rewrite
|
|
2117
|
+
* `moduleResolution` itself — that changes resolution semantics and must be a
|
|
2118
|
+
* human, per-package decision. Returns true if it patched a file. Mirrors
|
|
2119
|
+
* `ensureTsconfigNodeTypes`: resolves the `extends` chain, respects an existing
|
|
2120
|
+
* `ignoreDeprecations`, and patches the base-most writable config. */
|
|
2121
|
+
function ensureTsconfigIgnoreDeprecations(cwd, version) {
|
|
2122
|
+
const tsconfigPath = path.join(cwd, 'tsconfig.json');
|
|
2123
|
+
if (!fs.existsSync(tsconfigPath))
|
|
2124
|
+
return false;
|
|
2125
|
+
const { chain, truncated } = resolveTsconfigChain(tsconfigPath);
|
|
2126
|
+
if (!chain.length)
|
|
2127
|
+
return false;
|
|
2128
|
+
// Already set somewhere in the chain (possibly with a different version) — leave it.
|
|
2129
|
+
if (chain.some(c => c.parsed?.compilerOptions?.ignoreDeprecations !== undefined))
|
|
2130
|
+
return false;
|
|
2131
|
+
if (truncated)
|
|
2132
|
+
return false;
|
|
2133
|
+
const valueLiteral = JSON.stringify(version);
|
|
2134
|
+
const candidates = chain.filter(c => c.writable).reverse();
|
|
2135
|
+
for (const cand of candidates) {
|
|
2136
|
+
let text;
|
|
2137
|
+
try {
|
|
2138
|
+
text = fs.readFileSync(cand.path, 'utf-8');
|
|
2139
|
+
}
|
|
2140
|
+
catch {
|
|
2141
|
+
continue;
|
|
2142
|
+
}
|
|
2143
|
+
const patched = insertCompilerOption(text, 'ignoreDeprecations', valueLiteral);
|
|
2144
|
+
if (!patched)
|
|
2145
|
+
continue;
|
|
2146
|
+
try {
|
|
2147
|
+
fs.writeFileSync(cand.path, patched);
|
|
2148
|
+
const where = path.relative(cwd, cand.path) || 'tsconfig.json';
|
|
2149
|
+
console.log(colors.cyan(` Patched ${where}: added "ignoreDeprecations": ${valueLiteral} (silences TS6 removed-in-TS7 deprecation errors)`));
|
|
2150
|
+
recordBuildIssue(chain[0].parsed?.name || path.basename(cwd), 'warning', `Deprecated compilerOptions silenced via ignoreDeprecations=${version}. Migrate moduleResolution to "node16"/"nodenext"/"bundler" before TypeScript 7.`);
|
|
2151
|
+
return true;
|
|
2152
|
+
}
|
|
2153
|
+
catch (error) {
|
|
2154
|
+
console.error(colors.yellow(` Could not write tsconfig patch (${cand.path}): ${error.message}`));
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
return false;
|
|
2158
|
+
}
|
|
2105
2159
|
/** Build a single project: detect tsconfig, prompt to add `build: tsc` if a
|
|
2106
2160
|
* TypeScript project lacks a build script, run `npm run build`, record
|
|
2107
2161
|
* failures. Returns true if build succeeded (or was skipped because no
|
|
@@ -2136,7 +2190,17 @@ export async function buildProject(cwd, opts = {}) {
|
|
|
2136
2190
|
}
|
|
2137
2191
|
ensureTsconfigNodeTypes(cwd);
|
|
2138
2192
|
console.log(`Building ${pkg.name || cwd}...`);
|
|
2139
|
-
|
|
2193
|
+
let buildResult = await runCommandAsync('npm', ['run', 'build'], { cwd, silent: true });
|
|
2194
|
+
if (!buildResult.success) {
|
|
2195
|
+
// TS6 deprecation error (removed-in-TS7): apply the version TS itself names
|
|
2196
|
+
// in `"ignoreDeprecations": "<v>"` and retry once.
|
|
2197
|
+
const out = (buildResult.stderr || '') + (buildResult.output || '');
|
|
2198
|
+
const dep = out.match(/error TS510[17]\b/) &&
|
|
2199
|
+
out.match(/['"]ignoreDeprecations['"]\s*:\s*['"]([\d.]+)['"]/);
|
|
2200
|
+
if (dep && ensureTsconfigIgnoreDeprecations(cwd, dep[1])) {
|
|
2201
|
+
buildResult = await runCommandAsync('npm', ['run', 'build'], { cwd, silent: true });
|
|
2202
|
+
}
|
|
2203
|
+
}
|
|
2140
2204
|
if (buildResult.success) {
|
|
2141
2205
|
console.log(colors.green(`✓ Build succeeded (${pkg.name || path.basename(cwd)})`));
|
|
2142
2206
|
return true;
|
|
@@ -2497,6 +2561,15 @@ function diagnoseBuildFailure(errorText, cwd) {
|
|
|
2497
2561
|
console.error(colors.yellow(' In a workspace this belongs in the shared base tsconfig the package extends (only global @types like node/jest need listing; imported types resolve on their own).'));
|
|
2498
2562
|
diagnosed = true;
|
|
2499
2563
|
}
|
|
2564
|
+
// Pattern: TS6 made deprecated options (moduleResolution=node10, ...) hard errors,
|
|
2565
|
+
// removed in TS7. (Safety net for when the auto ignoreDeprecations patch+retry didn't fire.)
|
|
2566
|
+
if (!diagnosed && /error TS510[17]\b/.test(errorText)) {
|
|
2567
|
+
const v = errorText.match(/['"]ignoreDeprecations['"]\s*:\s*['"]([\d.]+)['"]/);
|
|
2568
|
+
console.error(colors.yellow('\n Hint: TypeScript 6 flags long-deprecated options that TS7 will remove.'));
|
|
2569
|
+
console.error(colors.yellow(` Bridge: add "ignoreDeprecations": "${v ? v[1] : '6.0'}" to compilerOptions (shared base in a workspace).`));
|
|
2570
|
+
console.error(colors.yellow(' Real fix before TS7: migrate moduleResolution to "node16"/"nodenext"/"bundler".'));
|
|
2571
|
+
diagnosed = true;
|
|
2572
|
+
}
|
|
2500
2573
|
// Pattern: TypeScript compilation error
|
|
2501
2574
|
if (!diagnosed && /error TS\d+/.test(errorText)) {
|
|
2502
2575
|
console.error(colors.yellow('\n Hint: TypeScript compilation errors. Fix the type errors above before publishing.'));
|