@bobfrankston/npmglobalize 1.0.219 → 1.0.220
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 +1 -1
- package/lib.d.ts +0 -10
- package/lib.js +67 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -756,7 +756,7 @@ As with import maps, these have historically been built only by a second `.vscod
|
|
|
756
756
|
Before building, `npmglobalize` looks for sub-projects, in this order:
|
|
757
757
|
|
|
758
758
|
1. `.vscode/tasks.json` has a task that runs `tsc` or `importgen` with `"options": { "cwd": "${workspaceFolder}/client" }`, or runs `tsc` with `-p`/`--project` naming a sub-directory (authoritative — it's how the project is actually built today; the task's `label` is quoted back in the prompt).
|
|
759
|
-
2. An immediate sub-directory
|
|
759
|
+
2. An immediate sub-directory that is a build of its own: a `package.json` with a `build` script or an import map to regenerate (a sub-package gets its build script set up the same way the root does — importgen, `tsc`, its own sub-projects — before the root delegates to it), or a `tsconfig.json` the root `tsconfig.json` does not already compile. A `package.json` that only holds dependencies for files the root `tsc` compiles (`whts/pdfToImg`) is not a sub-project. Build output and vendored trees (`node_modules`, `prev`, `dist`, `built`, `out`, `wwwroot`, `coverage`, `temp`, `preflight`, dot-directories) are never scanned.
|
|
760
760
|
|
|
761
761
|
Nothing is detected when the root `tsconfig.json` uses project `references` — that build graph belongs to `tsc -b` and isn't second-guessed.
|
|
762
762
|
|
package/lib.d.ts
CHANGED
|
@@ -397,16 +397,6 @@ export declare function missingDeps(pkgDir: string, pkg: any): string[];
|
|
|
397
397
|
* re-run" (partial-sync) cases. Also covers `cwd` itself on the first call.
|
|
398
398
|
* Cycle-safe via the shared `visited` set. */
|
|
399
399
|
export declare function ensureFileDepModules(cwd: string, verbose?: boolean, visited?: Set<string>): Promise<boolean>;
|
|
400
|
-
/** Cheap freshness check so the build cascade can skip packages whose output is
|
|
401
|
-
* already current. Returns true only when provably up to date:
|
|
402
|
-
* - outDir projects: newest source (.ts/.tsx/.mts/.cts + tsconfig*.json) must
|
|
403
|
-
* not be newer than the newest file under outDir.
|
|
404
|
-
* - side-by-side projects: every source must have an emitted sibling
|
|
405
|
-
* (.js/.jsx/.mjs/.cjs or declaration) at least as new.
|
|
406
|
-
* Conservative: project references, allowJs, missing outputs, or unreadable
|
|
407
|
-
* tsconfig all report stale (→ build). package.json mtime is deliberately
|
|
408
|
-
* ignored — npmglobalize itself rewrites it around every publish, which would
|
|
409
|
-
* otherwise force a rebuild on every run. */
|
|
410
400
|
export declare function isBuildUpToDate(cwd: string): boolean;
|
|
411
401
|
/** Detect whether a package is an importgen project — a browser app whose HTML
|
|
412
402
|
* carries a generated `<script type="importmap">`. Signals, in order:
|
package/lib.js
CHANGED
|
@@ -2888,6 +2888,35 @@ function newestMtimeUnder(dir) {
|
|
|
2888
2888
|
* tsconfig all report stale (→ build). package.json mtime is deliberately
|
|
2889
2889
|
* ignored — npmglobalize itself rewrites it around every publish, which would
|
|
2890
2890
|
* otherwise force a rebuild on every run. */
|
|
2891
|
+
/** The directories a parsed tsconfig's `exclude` keeps out of the compile, as
|
|
2892
|
+
* lower-cased relative paths. Matches on the literal path prefix (glob tails
|
|
2893
|
+
* like "tests/**" reduce to "tests"). */
|
|
2894
|
+
function tsconfigExcludedDirs(tsconfig) {
|
|
2895
|
+
return (Array.isArray(tsconfig?.exclude) ? tsconfig.exclude : [])
|
|
2896
|
+
.filter((x) => typeof x === 'string')
|
|
2897
|
+
.map((x) => x.replace(/^\.\//, '').replace(/[\\/]?\*.*$/, '').replace(/[\\/]+$/, '').toLowerCase())
|
|
2898
|
+
.filter((x) => x.length > 0 && !x.includes('*'));
|
|
2899
|
+
}
|
|
2900
|
+
/** True when the root tsconfig in `cwd` already compiles the sources under
|
|
2901
|
+
* `rel`: it exists, doesn't narrow the compile with `files`/`include`, and
|
|
2902
|
+
* doesn't `exclude` the directory. Conservative — a root that uses `include`
|
|
2903
|
+
* is treated as not covering the sub-directory. */
|
|
2904
|
+
function rootTsconfigCompiles(cwd, rel) {
|
|
2905
|
+
let tsconfig;
|
|
2906
|
+
try {
|
|
2907
|
+
tsconfig = JSON5.parse(fs.readFileSync(path.join(cwd, 'tsconfig.json'), 'utf-8'));
|
|
2908
|
+
}
|
|
2909
|
+
catch {
|
|
2910
|
+
return false;
|
|
2911
|
+
}
|
|
2912
|
+
if (Array.isArray(tsconfig.files) || Array.isArray(tsconfig.include))
|
|
2913
|
+
return false;
|
|
2914
|
+
const target = normalizeProjectPath(rel).toLowerCase();
|
|
2915
|
+
const parts = target.split('/');
|
|
2916
|
+
const excludes = tsconfigExcludedDirs(tsconfig);
|
|
2917
|
+
// Excluding a parent excludes everything under it.
|
|
2918
|
+
return !parts.some((_, i) => excludes.includes(parts.slice(0, i + 1).join('/')));
|
|
2919
|
+
}
|
|
2891
2920
|
export function isBuildUpToDate(cwd) {
|
|
2892
2921
|
let tsconfig;
|
|
2893
2922
|
try {
|
|
@@ -2901,12 +2930,8 @@ export function isBuildUpToDate(cwd) {
|
|
|
2901
2930
|
return false;
|
|
2902
2931
|
const outDir = typeof co.outDir === 'string' ? path.resolve(cwd, co.outDir) : null;
|
|
2903
2932
|
// tsconfig "exclude" dirs aren't compiled, so their .ts files never get
|
|
2904
|
-
// outputs — don't count them as sources.
|
|
2905
|
-
|
|
2906
|
-
const excludes = (Array.isArray(tsconfig.exclude) ? tsconfig.exclude : [])
|
|
2907
|
-
.filter((x) => typeof x === 'string')
|
|
2908
|
-
.map((x) => x.replace(/^\.\//, '').replace(/[\\/]?\*.*$/, '').replace(/[\\/]+$/, '').toLowerCase())
|
|
2909
|
-
.filter((x) => x.length > 0 && !x.includes('*'));
|
|
2933
|
+
// outputs — don't count them as sources.
|
|
2934
|
+
const excludes = tsconfigExcludedDirs(tsconfig);
|
|
2910
2935
|
const sources = [];
|
|
2911
2936
|
const collect = (dir, rel) => {
|
|
2912
2937
|
let entries;
|
|
@@ -3198,13 +3223,31 @@ function resolveOnDiskCase(base, rel) {
|
|
|
3198
3223
|
}
|
|
3199
3224
|
return out.length ? out.join('/') : null;
|
|
3200
3225
|
}
|
|
3201
|
-
/** Classify `rel` under `cwd`: a package (its own package.json
|
|
3202
|
-
* script
|
|
3203
|
-
* sub-project, or null when it
|
|
3226
|
+
/** Classify `rel` under `cwd`: a package (its own package.json with a build
|
|
3227
|
+
* script, or an importgen project — `ensureBuildScript` sets its script up),
|
|
3228
|
+
* a plain tsconfig sub-project the root tsc doesn't compile, or null when it
|
|
3229
|
+
* is neither.
|
|
3230
|
+
* 2026-09-06 — Claude Code (Fable 5.1), at Bob's direction. whts/pdfToImg has
|
|
3231
|
+
* a package.json that only holds puppeteer/sharp for a file the root tsc
|
|
3232
|
+
* already compiles; treating every package.json as a sub-package gave it a
|
|
3233
|
+
* `build: tsc` it never needed and a second compile under its stale tsconfig.
|
|
3234
|
+
* A package.json is a build of its own only when it has something the root
|
|
3235
|
+
* can't do — its own build script, or an import map to regenerate. */
|
|
3204
3236
|
function subProjectKind(cwd, rel) {
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3237
|
+
const dir = path.join(cwd, rel);
|
|
3238
|
+
if (fs.existsSync(path.join(dir, 'package.json'))) {
|
|
3239
|
+
let pkg = {};
|
|
3240
|
+
try {
|
|
3241
|
+
pkg = readPackageJson(dir);
|
|
3242
|
+
}
|
|
3243
|
+
catch { /* unreadable — treat as having no build script */ }
|
|
3244
|
+
const hasBuild = typeof pkg?.scripts?.build === 'string' && pkg.scripts.build.trim();
|
|
3245
|
+
if (hasBuild || detectImportgen(dir))
|
|
3246
|
+
return 'package';
|
|
3247
|
+
}
|
|
3248
|
+
if (!fs.existsSync(path.join(dir, 'tsconfig.json')))
|
|
3249
|
+
return null;
|
|
3250
|
+
return rootTsconfigCompiles(cwd, rel) ? null : 'tsconfig';
|
|
3208
3251
|
}
|
|
3209
3252
|
/** The command the root build script runs for a sub-project. */
|
|
3210
3253
|
function subProjectBuildCommand(s) {
|
|
@@ -3505,7 +3548,7 @@ export async function buildProject(cwd, opts = {}) {
|
|
|
3505
3548
|
// tsconfig.json, which makes the freshness check correctly read as stale.
|
|
3506
3549
|
const tsconfigSnapshot = new Map();
|
|
3507
3550
|
const issueMark = markBuildIssues();
|
|
3508
|
-
|
|
3551
|
+
let migratedUpFront = fs.existsSync(path.join(cwd, 'tsconfig.json')) && migrateTsconfigDeprecations(cwd, tsconfigSnapshot);
|
|
3509
3552
|
const setup = await ensureBuildScript(cwd);
|
|
3510
3553
|
if (!setup)
|
|
3511
3554
|
return true;
|
|
@@ -3514,6 +3557,16 @@ export async function buildProject(cwd, opts = {}) {
|
|
|
3514
3557
|
// freshness — one the user declined to wire in isn't this build's business.
|
|
3515
3558
|
const finalBuild = typeof pkg.scripts?.build === 'string' ? pkg.scripts.build : '';
|
|
3516
3559
|
const wiredSubs = detectSubProjects(cwd).filter(s => scriptBuildsSubProject(finalBuild, s.dir));
|
|
3560
|
+
// 2026-09-06 — Claude Code (Fable 5.1), at Bob's direction.
|
|
3561
|
+
// The sub-projects this build runs get the same TS7 migration as the root.
|
|
3562
|
+
// whts: `tsc -p pdfToImg` failed on pdfToImg/tsconfig.json's
|
|
3563
|
+
// `moduleResolution: node10` (TS5107) and the retry below re-migrated only
|
|
3564
|
+
// the root chain, which had nothing left to fix — so no retry ever happened.
|
|
3565
|
+
const migrateSubProjects = () => wiredSubs
|
|
3566
|
+
.map(s => migrateTsconfigDeprecations(path.join(cwd, s.dir), tsconfigSnapshot))
|
|
3567
|
+
.some(Boolean);
|
|
3568
|
+
if (migrateSubProjects())
|
|
3569
|
+
migratedUpFront = true;
|
|
3517
3570
|
// A migration just changed how modules resolve — never report that as fresh;
|
|
3518
3571
|
// the rebuild is what validates it (and what the revert path above needs).
|
|
3519
3572
|
if (!opts.forceBuild && !migratedUpFront && isBuildUpToDate(cwd) && areSubProjectsUpToDate(cwd, wiredSubs)
|
|
@@ -3529,7 +3582,7 @@ export async function buildProject(cwd, opts = {}) {
|
|
|
3529
3582
|
// We don't silence with ignoreDeprecations — the retry may now surface real
|
|
3530
3583
|
// resolution errors, which are genuine bugs to fix, not deprecations.
|
|
3531
3584
|
const out = (buildResult.stderr || '') + (buildResult.output || '');
|
|
3532
|
-
if (/error TS510[17]\b/.test(out) && migrateTsconfigDeprecations(cwd, tsconfigSnapshot)) {
|
|
3585
|
+
if (/error TS510[17]\b/.test(out) && [migrateTsconfigDeprecations(cwd, tsconfigSnapshot), migrateSubProjects()].some(Boolean)) {
|
|
3533
3586
|
buildResult = await runCommandAsync('npm', ['run', 'build'], { cwd, silent: true });
|
|
3534
3587
|
}
|
|
3535
3588
|
}
|