Skip to content

Commit 17d3051

Browse files
committed
chore(deps): make node_modules strict, declare what each package imports
Drops `nodeLinker: hoisted` and `shamefullyHoist: true`, both inherited verbatim from the pre-pnpm-11 .npmrc (#3700). nodeLinker was annotated there as pnpm's default, which it is not -- the default is `isolated` -- and pairing it with shamefullyHoist is pnpm/pnpm#6620. shamefullyHoist is `publicHoistPattern: '*'`, which let nine packages import modules they never declared; all nine are now declared, at the versions the workspace already resolved. The Babel toolchain and Testing Library move into the catalog, each having been duplicated across 4-6 packages. Also fixes a latent `astryx doctor` bug the linker change exposed: checkPeerDeps resolved peers with `require.resolve(name, {paths: [cwd]})`, but Node folds NODE_PATH in regardless, so a peer merely reachable from the ambient environment read as installed and doctor stayed silent about a missing one. It now walks the project's own node_modules and reads package.json off disk, so every peer gets range-checked. The existing test caught this unmodified. Verified on a recreated node_modules: build, test, storybook:build, docsite and sandbox builds, check:repo, verify-exports, eslint, and every typecheck CI gates all pass. The local test failures that remain reproduce on main from a clean worktree -- case-insensitive filesystem, date-dependent suites -- and CI reported none of them.
1 parent e891c0d commit 17d3051

14 files changed

Lines changed: 230 additions & 52 deletions

File tree

apps/docsite/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@
4040
"zod": "^4.4.3"
4141
},
4242
"devDependencies": {
43-
"@babel/preset-react": "^8.0.1",
44-
"@babel/preset-typescript": "^7.29.7",
43+
"@babel/parser": "^7.29.7",
44+
"@babel/preset-react": "catalog:",
45+
"@babel/preset-typescript": "catalog:",
4546
"@stylexjs/babel-plugin": "catalog:",
4647
"@stylexjs/postcss-plugin": "catalog:",
4748
"@types/lz-string": "^1.5.0",

apps/sandbox/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
"@astryxdesign/theme-butter": "*"
3535
},
3636
"devDependencies": {
37-
"@babel/preset-react": "^8.0.1",
38-
"@babel/preset-typescript": "^7.29.7",
37+
"@babel/preset-react": "catalog:",
38+
"@babel/preset-typescript": "catalog:",
3939
"@stylexjs/babel-plugin": "catalog:",
4040
"@stylexjs/postcss-plugin": "catalog:",
4141
"@types/node": "^25.9.3",

apps/storybook/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,18 @@
2525
"vega-lite": "^6.4.3"
2626
},
2727
"devDependencies": {
28+
"@astryxdesign/build": "*",
29+
"@heroicons/react": "^2.2.0",
2830
"@lexical/headless": "^0.46.0",
2931
"@lexical/markdown": "^0.46.0",
32+
"@lexical/react": "^0.46.0",
3033
"@storybook/addon-docs": "^10.4.6",
3134
"@storybook/addon-links": "^10.4.6",
3235
"@storybook/react": "^10.4.6",
3336
"@storybook/react-vite": "^10.4.6",
37+
"@stylexjs/stylex": "catalog:",
3438
"@stylexjs/unplugin": "^0.19.0",
35-
"@astryxdesign/build": "*",
39+
"lexical": "^0.46.0",
3640
"storybook": "^10.4.6"
3741
}
3842
}

apps/template-viewer/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"@astryxdesign/core": "*",
1313
"@astryxdesign/theme-neutral": "*",
1414
"@heroicons/react": "^2.2.0",
15-
"@stylexjs/stylex": "^0.19.0",
15+
"@stylexjs/stylex": "catalog:",
1616
"react": "^19.2.7",
1717
"react-dom": "^19.2.7"
1818
},

internal/test-utils/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
"main": "./src/index.ts",
77
"scripts": {},
88
"dependencies": {
9-
"@testing-library/jest-dom": "^6.6.0",
10-
"@testing-library/react": "^16.3.2",
9+
"@testing-library/jest-dom": "catalog:",
10+
"@testing-library/react": "catalog:",
1111
"@testing-library/user-event": "^14.5.0"
1212
}
1313
}

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,26 +53,32 @@
5353
},
5454
"devDependencies": {
5555
"@axe-core/playwright": "^4.12.1",
56+
"@babel/core": "catalog:",
5657
"@changesets/cli": "^2.31.0",
5758
"@eslint-react/eslint-plugin": "^5.10.4",
5859
"@eslint/compat": "^2.1.0",
5960
"@eslint/js": "^10.0.1",
6061
"@playwright/test": "^1.61.1",
62+
"@stylexjs/babel-plugin": "catalog:",
63+
"@testing-library/jest-dom": "catalog:",
6164
"@testing-library/user-event": "^14.5.0",
6265
"@types/node": "^25.9.3",
6366
"@types/react": "^19.2.17",
6467
"@types/react-dom": "^19.2.3",
6568
"@vitejs/plugin-react": "^5.2.0",
6669
"@vitest/coverage-v8": "^4.1.9",
70+
"chokidar": "^4.0.3",
6771
"cldr-core": "^48.2.0",
6872
"cldr-dates-full": "^48.2.0",
6973
"dom-accessibility-api": "^0.6.3",
7074
"esbuild": "catalog:",
7175
"eslint": "^10.6.0",
7276
"eslint-plugin-react-compiler": "19.1.0-rc.2",
77+
"glob": "^13.0.6",
7378
"husky": "^9.1.7",
7479
"jsdom": "^27.4.0",
7580
"lint-staged": "^17.0.8",
81+
"playwright": "^1.61.1",
7682
"prettier": "catalog:",
7783
"react": "^19.2.7",
7884
"react-dom": "^19.2.7",

packages/charts/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@
6969
},
7070
"devDependencies": {
7171
"@astryxdesign/cli": "workspace:*",
72+
"@babel/cli": "catalog:",
73+
"@babel/core": "catalog:",
74+
"@babel/preset-react": "catalog:",
75+
"@babel/preset-typescript": "catalog:",
76+
"@stylexjs/babel-plugin": "catalog:",
77+
"@testing-library/react": "catalog:",
7278
"@types/d3-scale": "^4.0.9",
7379
"@types/d3-shape": "^3.1.8",
7480
"rimraf": "^6.0.1"

packages/cli/api/doctor/doctor.mjs

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,13 @@
2222

2323
import * as fs from 'node:fs';
2424
import * as path from 'node:path';
25-
import {createRequire} from 'node:module';
2625

2726
import {MIN_NODE_VERSION, isNodeVersionSupported} from '../../foundation/env/node-version.mjs';
2827
import {CLI_ROOT, findCoreDir} from '../../foundation/fs/paths.mjs';
2928
import {detectPackageManager, getCliInvocation} from '../../foundation/env/package-manager.mjs';
3029
import {findConfigPath, Project} from '../../foundation/config/project.mjs';
3130
import {semverCompare, isValidSemver, satisfiesRange} from '../../foundation/env/semver.mjs';
3231

33-
const _require = createRequire(import.meta.url);
34-
3532
/**
3633
* @typedef {'pass'|'warn'|'fail'|'info'} DoctorStatus
3734
*
@@ -99,6 +96,31 @@ function findNodeModules(startDir) {
9996
return null;
10097
}
10198

99+
/**
100+
* Locate a package inside the project's own node_modules chain.
101+
*
102+
* Deliberately not `require.resolve`: Node folds NODE_PATH and the global
103+
* folders into resolution even when `paths` is given, so a package merely
104+
* reachable from the ambient environment would read as installed in the
105+
* user's project. Reading package.json off disk also sidesteps packages that
106+
* don't export it, so the version is always available to range-check.
107+
*
108+
* @param {string} startDir
109+
* @param {string} name
110+
* @returns {string|null} the package directory, or null when not installed
111+
*/
112+
function findInstalledPackage(startDir, name) {
113+
let dir = startDir;
114+
for (let i = 0; i < 6; i++) {
115+
const candidate = path.join(dir, 'node_modules', ...name.split('/'));
116+
if (fs.existsSync(path.join(candidate, 'package.json'))) return candidate;
117+
const parent = path.dirname(dir);
118+
if (parent === dir) break;
119+
dir = parent;
120+
}
121+
return null;
122+
}
123+
102124
/**
103125
* Find every installed @astryxdesign/theme-* package under node_modules.
104126
* @param {string} cwd
@@ -440,23 +462,15 @@ export function checkPeerDeps(ctx) {
440462
const mismatched = [];
441463
for (const name of peerNames) {
442464
const want = peers[name];
443-
let pkgJsonPath;
444-
try {
445-
pkgJsonPath = _require.resolve(`${name}/package.json`, {paths: [ctx.cwd]});
446-
} catch {
447-
// package.json isn't exported — fall back to entry resolution for
448-
// presence only (we then can't read the version to range-check it).
449-
try {
450-
_require.resolve(name, {paths: [ctx.cwd]});
451-
} catch {
452-
missing.push(`${name}@${want}`);
453-
}
465+
const installedDir = findInstalledPackage(ctx.cwd, name);
466+
if (!installedDir) {
467+
missing.push(`${name}@${want}`);
454468
continue;
455469
}
456470
// Present and version-readable: verify it actually satisfies the range,
457471
// not just that the package exists (a bare `npm install` can resolve an
458472
// out-of-range version from a stale consumer range and still "look" fine).
459-
const have = pkgVersion(path.dirname(pkgJsonPath));
473+
const have = pkgVersion(installedDir);
460474
if (have && !satisfiesRange(have, want)) {
461475
mismatched.push({name, want, have});
462476
}

packages/cli/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@
126126
"@astryxdesign/core": "*",
127127
"@astryxdesign/lab": "*",
128128
"@astryxdesign/theme-neutral": "*",
129-
"gpt-tokenizer": "^3.4.0"
129+
"@heroicons/react": "^2.2.0",
130+
"@stylexjs/stylex": "catalog:",
131+
"gpt-tokenizer": "^3.4.0",
132+
"lucide-react": "^1.18.0",
133+
"recharts": "^3.9.2"
130134
}
131135
}

packages/core/package.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -671,14 +671,15 @@
671671
},
672672
"devDependencies": {
673673
"@astryxdesign/cli": "workspace:*",
674-
"@babel/cli": "^8.0.4",
675-
"@babel/core": "^7.29.7",
676-
"@babel/preset-react": "^8.0.1",
677-
"@babel/preset-typescript": "^7.29.7",
674+
"@babel/cli": "catalog:",
675+
"@babel/core": "catalog:",
676+
"@babel/preset-react": "catalog:",
677+
"@babel/preset-typescript": "catalog:",
678678
"@stylexjs/babel-plugin": "catalog:",
679679
"@testing-library/dom": "^10.0.0",
680-
"@testing-library/jest-dom": "^6.6.0",
681-
"@testing-library/react": "^16.3.2",
680+
"@testing-library/jest-dom": "catalog:",
681+
"@testing-library/react": "catalog:",
682+
"@types/babel__core": "^7.20.5",
682683
"rimraf": "^6.0.1"
683684
},
684685
"dependencies": {

0 commit comments

Comments
 (0)