@bobfrankston/npmglobalize 1.0.186 → 1.0.187
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 +12 -0
- package/lib.js +123 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -585,6 +585,18 @@ Cycle-safe via a shared visited set; each project is built at most once per run.
|
|
|
585
585
|
|
|
586
586
|
This complements the existing publish cascade (which ensures version refs are correct) by closing the build-freshness gap that `npm install` alone left open.
|
|
587
587
|
|
|
588
|
+
#### TypeScript 6 `types` auto-fix
|
|
589
|
+
|
|
590
|
+
TypeScript 6 dropped the legacy behavior of auto-including every installed `@types/*` package. A `tsconfig.json` with no explicit `compilerOptions.types` then loses the Node globals (`process`, `Buffer`, …) and the build fails with `TS2591`.
|
|
591
|
+
|
|
592
|
+
Before each build, when the global `tsc` is version 6 or newer, `npmglobalize` patches the project's `tsconfig.json` to add an explicit `types` list — enumerating the installed `@types/*` packages (e.g. `"types": ["node", …]`) — restoring the old behavior. The edit is:
|
|
593
|
+
|
|
594
|
+
- **Conservative** — only applied when `compilerOptions.types` is **absent**, `node_modules/@types/node` is actually installed, and there is no `extends` (whose merged `types` can't be seen). An explicit `types` you already set is never overridden.
|
|
595
|
+
- **Format-preserving** — the single `types` key is inserted into the existing `compilerOptions` block; comments, ordering, and indentation are left intact.
|
|
596
|
+
- **Idempotent** — once the list is present, subsequent runs skip it.
|
|
597
|
+
|
|
598
|
+
If the patch can't be applied for some reason and the build still fails with `TS2591`, the failure summary prints a hint to add `"types": ["node"]` manually.
|
|
599
|
+
|
|
588
600
|
### The `.dependencies` Backup (Internal/Transient)
|
|
589
601
|
|
|
590
602
|
**You should never see `.dependencies` in your `package.json` under normal operation.** It is a temporary internal backup that exists only during the brief publish cycle and is removed automatically when the cycle completes.
|
package/lib.js
CHANGED
|
@@ -1927,6 +1927,120 @@ export async function ensureFileDepModules(cwd, verbose = false, visited = new S
|
|
|
1927
1927
|
}
|
|
1928
1928
|
}
|
|
1929
1929
|
}
|
|
1930
|
+
/** Cached major version of the global `tsc`. null = not yet probed,
|
|
1931
|
+
* 0 = probe failed / tsc not found. TypeScript 6 stopped auto-including
|
|
1932
|
+
* every `@types/*` package, so a tsconfig that relied on that needs an
|
|
1933
|
+
* explicit `types` list under TS6+. */
|
|
1934
|
+
let _tscMajor = null;
|
|
1935
|
+
/** Major version of the globally-installed `tsc`, or 0 if undeterminable.
|
|
1936
|
+
* Cached for the run. Needs shell:true on Windows to resolve `tsc.cmd`. */
|
|
1937
|
+
function getTscMajor() {
|
|
1938
|
+
if (_tscMajor !== null)
|
|
1939
|
+
return _tscMajor;
|
|
1940
|
+
_tscMajor = 0;
|
|
1941
|
+
try {
|
|
1942
|
+
const result = spawnSafe('tsc', ['--version'], { stdio: 'pipe', shell: true, env: process.env });
|
|
1943
|
+
const m = (result.stdout || '').match(/Version\s+(\d+)\./);
|
|
1944
|
+
if (m)
|
|
1945
|
+
_tscMajor = parseInt(m[1], 10);
|
|
1946
|
+
}
|
|
1947
|
+
catch { /* leave at 0 — can't probe, assume pre-6 (no patch) */ }
|
|
1948
|
+
return _tscMajor;
|
|
1949
|
+
}
|
|
1950
|
+
/** Insert a `"types": [...]` line as the first property of `compilerOptions`,
|
|
1951
|
+
* preserving the file's existing formatting/comments. Returns the patched text,
|
|
1952
|
+
* or null if the object couldn't be located safely (caller leaves file alone).
|
|
1953
|
+
* Only ever called when `compilerOptions.types` is absent. */
|
|
1954
|
+
function insertTypesIntoTsconfig(text, typesArr) {
|
|
1955
|
+
const arrLiteral = '[' + typesArr.map(t => JSON.stringify(t)).join(', ') + ']';
|
|
1956
|
+
const m = text.match(/"compilerOptions"\s*:\s*\{/);
|
|
1957
|
+
if (!m)
|
|
1958
|
+
return null;
|
|
1959
|
+
const braceEnd = m.index + m[0].length;
|
|
1960
|
+
const rest = text.slice(braceEnd);
|
|
1961
|
+
const ws = rest.match(/^\s*/)[0];
|
|
1962
|
+
// Empty object: `compilerOptions: {}` (or whitespace only before `}`)
|
|
1963
|
+
if (rest.slice(ws.length).startsWith('}')) {
|
|
1964
|
+
// Indent one level deeper than the `compilerOptions` line itself.
|
|
1965
|
+
const lineStart = text.lastIndexOf('\n', m.index) + 1;
|
|
1966
|
+
const baseIndent = text.slice(lineStart, m.index).match(/^\s*/)[0];
|
|
1967
|
+
const propIndent = baseIndent + ' ';
|
|
1968
|
+
return text.slice(0, braceEnd) + '\n' + propIndent + `"types": ${arrLiteral}\n` + baseIndent + text.slice(braceEnd + ws.length);
|
|
1969
|
+
}
|
|
1970
|
+
// Multiline object: derive property indent from the existing first property.
|
|
1971
|
+
if (ws.includes('\n')) {
|
|
1972
|
+
const propIndent = ws.slice(ws.lastIndexOf('\n') + 1);
|
|
1973
|
+
return text.slice(0, braceEnd) + '\n' + propIndent + `"types": ${arrLiteral},` + text.slice(braceEnd);
|
|
1974
|
+
}
|
|
1975
|
+
// Inline single-line object: `{ "target": ... }`
|
|
1976
|
+
return text.slice(0, braceEnd) + ` "types": ${arrLiteral},` + text.slice(braceEnd);
|
|
1977
|
+
}
|
|
1978
|
+
/** TypeScript 6 dropped the legacy behavior of auto-including every installed
|
|
1979
|
+
* `@types/*` package. A tsconfig with no explicit `compilerOptions.types` then
|
|
1980
|
+
* loses the Node globals (`process`, `Buffer`, ...), breaking the build with
|
|
1981
|
+
* `TS2591`. When building under TS6+, add an explicit `types` list enumerating
|
|
1982
|
+
* the installed `@types/*` (restoring the old behavior). Idempotent and
|
|
1983
|
+
* conservative — only patches when `types` is absent, `@types/node` is actually
|
|
1984
|
+
* installed, and there is no `extends` (whose merged `types` we can't see). */
|
|
1985
|
+
function ensureTsconfigNodeTypes(cwd) {
|
|
1986
|
+
if (getTscMajor() < 6)
|
|
1987
|
+
return;
|
|
1988
|
+
const tsconfigPath = path.join(cwd, 'tsconfig.json');
|
|
1989
|
+
let text;
|
|
1990
|
+
try {
|
|
1991
|
+
text = fs.readFileSync(tsconfigPath, 'utf-8');
|
|
1992
|
+
}
|
|
1993
|
+
catch {
|
|
1994
|
+
return;
|
|
1995
|
+
}
|
|
1996
|
+
let parsed;
|
|
1997
|
+
try {
|
|
1998
|
+
parsed = JSON5.parse(text);
|
|
1999
|
+
}
|
|
2000
|
+
catch {
|
|
2001
|
+
return;
|
|
2002
|
+
}
|
|
2003
|
+
const co = parsed?.compilerOptions;
|
|
2004
|
+
if (!co || typeof co !== 'object')
|
|
2005
|
+
return;
|
|
2006
|
+
// Respect any explicit choice; never override a user-set `types`.
|
|
2007
|
+
if (co.types !== undefined)
|
|
2008
|
+
return;
|
|
2009
|
+
// `extends` may already supply `types`; a local array would override it, so leave it.
|
|
2010
|
+
if (parsed.extends !== undefined)
|
|
2011
|
+
return;
|
|
2012
|
+
// Gate on @types/node actually being installed so the list resolves and we
|
|
2013
|
+
// only touch genuine Node projects.
|
|
2014
|
+
const typesDir = path.join(cwd, 'node_modules', '@types');
|
|
2015
|
+
if (!fs.existsSync(path.join(typesDir, 'node')))
|
|
2016
|
+
return;
|
|
2017
|
+
let installed;
|
|
2018
|
+
try {
|
|
2019
|
+
installed = fs.readdirSync(typesDir, { withFileTypes: true })
|
|
2020
|
+
.filter(e => e.isDirectory() && !e.name.startsWith('.'))
|
|
2021
|
+
.map(e => e.name);
|
|
2022
|
+
}
|
|
2023
|
+
catch {
|
|
2024
|
+
return;
|
|
2025
|
+
}
|
|
2026
|
+
if (!installed.length)
|
|
2027
|
+
return;
|
|
2028
|
+
// node first, rest sorted, for a stable readable list.
|
|
2029
|
+
installed.sort();
|
|
2030
|
+
const typesArr = ['node', ...installed.filter(n => n !== 'node')];
|
|
2031
|
+
const patched = insertTypesIntoTsconfig(text, typesArr);
|
|
2032
|
+
if (!patched) {
|
|
2033
|
+
recordBuildIssue(parsed.name || path.basename(cwd), 'warning', `TS6+ build may fail: couldn't locate compilerOptions in ${tsconfigPath} to add explicit "types"`);
|
|
2034
|
+
return;
|
|
2035
|
+
}
|
|
2036
|
+
try {
|
|
2037
|
+
fs.writeFileSync(tsconfigPath, patched);
|
|
2038
|
+
console.log(colors.cyan(` Patched tsconfig.json: added "types": [${typesArr.join(', ')}] (TypeScript ${_tscMajor}+ no longer auto-includes @types/*)`));
|
|
2039
|
+
}
|
|
2040
|
+
catch (error) {
|
|
2041
|
+
console.error(colors.yellow(` Could not write tsconfig.json patch: ${error.message}`));
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
1930
2044
|
/** Build a single project: detect tsconfig, prompt to add `build: tsc` if a
|
|
1931
2045
|
* TypeScript project lacks a build script, run `npm run build`, record
|
|
1932
2046
|
* failures. Returns true if build succeeded (or was skipped because no
|
|
@@ -1959,6 +2073,7 @@ export async function buildProject(cwd, opts = {}) {
|
|
|
1959
2073
|
return true;
|
|
1960
2074
|
}
|
|
1961
2075
|
}
|
|
2076
|
+
ensureTsconfigNodeTypes(cwd);
|
|
1962
2077
|
console.log(`Building ${pkg.name || cwd}...`);
|
|
1963
2078
|
const buildResult = await runCommandAsync('npm', ['run', 'build'], { cwd, silent: true });
|
|
1964
2079
|
if (buildResult.success) {
|
|
@@ -2313,6 +2428,13 @@ function diagnoseBuildFailure(errorText, cwd) {
|
|
|
2313
2428
|
console.error(colors.yellow(' Check file ownership and that no other process has files locked.'));
|
|
2314
2429
|
diagnosed = true;
|
|
2315
2430
|
}
|
|
2431
|
+
// Pattern: TS6 dropped @types/* auto-inclusion → Node globals missing.
|
|
2432
|
+
// (Safety net for when the proactive ensureTsconfigNodeTypes patch didn't fire.)
|
|
2433
|
+
if (!diagnosed && /error TS2591|Do you need to install type definitions for node/.test(errorText)) {
|
|
2434
|
+
console.error(colors.yellow('\n Hint: TypeScript 6 no longer auto-includes @types/*, so Node globals (process, Buffer) are unresolved.'));
|
|
2435
|
+
console.error(colors.yellow(` Fix: add "types": ["node"] to compilerOptions in ${path.join(cwd, 'tsconfig.json')}`));
|
|
2436
|
+
diagnosed = true;
|
|
2437
|
+
}
|
|
2316
2438
|
// Pattern: TypeScript compilation error
|
|
2317
2439
|
if (!diagnosed && /error TS\d+/.test(errorText)) {
|
|
2318
2440
|
console.error(colors.yellow('\n Hint: TypeScript compilation errors. Fix the type errors above before publishing.'));
|
|
@@ -4168,6 +4290,7 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
4168
4290
|
// workspaces[] array order; rewrite to topological order so deps build
|
|
4169
4291
|
// before consumers (avoids stale-.d.ts errors in cross-package imports).
|
|
4170
4292
|
const restoreWorkspaces = reorderWorkspacesForBuild(cwd, pkg, verbose);
|
|
4293
|
+
ensureTsconfigNodeTypes(cwd);
|
|
4171
4294
|
try {
|
|
4172
4295
|
// Always capture output so we can extract tsc errors for the summary
|
|
4173
4296
|
const buildResult = await runCommandAsync('npm', ['run', 'build'], { cwd, silent: true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/npmglobalize",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.187",
|
|
4
4
|
"description": "Transform file: dependencies to npm versions for publishing",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@bobfrankston/freezepak": "^0.1.8",
|
|
35
|
-
"@bobfrankston/importgen": "^0.1.
|
|
36
|
-
"@bobfrankston/themecolors": "^0.1.
|
|
35
|
+
"@bobfrankston/importgen": "^0.1.37",
|
|
36
|
+
"@bobfrankston/themecolors": "^0.1.7",
|
|
37
37
|
"@bobfrankston/userconfig": "^1.0.9",
|
|
38
38
|
"@npmcli/package-json": "^7.0.4",
|
|
39
39
|
"json5": "^2.2.3",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
".transformedSnapshot": {
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@bobfrankston/freezepak": "^0.1.8",
|
|
63
|
-
"@bobfrankston/importgen": "^0.1.
|
|
64
|
-
"@bobfrankston/themecolors": "^0.1.
|
|
63
|
+
"@bobfrankston/importgen": "^0.1.37",
|
|
64
|
+
"@bobfrankston/themecolors": "^0.1.7",
|
|
65
65
|
"@bobfrankston/userconfig": "^1.0.9",
|
|
66
66
|
"@npmcli/package-json": "^7.0.4",
|
|
67
67
|
"json5": "^2.2.3",
|