fix(lockfile): hoist npm workspace links to root importer deps#374
Conversation
npm symlinks every workspace member into the root `node_modules/`
regardless of whether the root `package.json` declares it as a dep.
The lockfile records each as `node_modules/<name>: { link: true,
resolved: "<rel>" }` independent of the root manifest. Aube was
seeding the root importer's direct deps from `dependencies` /
`devDependencies` / `optionalDependencies` only, so workspace
projects that weren't explicitly listed in the root manifest never
got a top-level `node_modules/<ws-pkg>` symlink — Angular CLI / Nx
/ many monorepo build tools that resolve workspace libraries from
the repo root silently broke after migrating from npm to aube.
Surface every top-level link entry in `node_modules/` (plain or
scoped, no nested `/node_modules/` segment) as a direct dep of the
root importer when the npm parser builds the graph. The existing
`already_added` dedupe keeps explicit `dependencies: { "@scope/x":
"file:packages/x" }` declarations from doubling up. Sorted by name
for stable output.
Reported in #345 (comment).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR fixes a silent breakage for npm monorepos where workspace members are not listed in the root Confidence Score: 5/5Safe to merge — the change is narrow, correct, and backed by two well-targeted tests. No logical, security, or correctness issues found. The scoped-package segment check handles all edge cases, No files require special attention. Important Files Changed
Reviews (1): Last reviewed commit: "fix(lockfile): hoist npm workspace links..." | Re-trigger Greptile |
Summary
node_modules/regardless of whether the rootpackage.jsondeclares it as a dep — recorded inpackage-lock.jsonasnode_modules/<name>: { link: true, resolved: "<rel>" }. Aube was seeding the root importer only fromdependencies/devDependencies/optionalDependencies, so undeclared workspace projects never got a top-levelnode_modules/<ws-pkg>symlink and Angular CLI / Nx / similar tooling that resolves workspace libraries from the repo root broke when migrating npm-managed monorepos to aube./node_modules/segment) as a direct dep of the root importer in the npm-lockfile parser. Existingalready_addeddedupe preserves explicitdependencies: { "@scope/x": "file:packages/x" }declarations; entries are appended sorted by name for deterministic output.Reported in #345 (comment) (siemens/element).
Test plan
cargo test -p aube-lockfile(new testtest_parse_workspace_links_undeclared_in_root_deps+ existingtest_parse_workspace_linksto confirm no double-add when the workspace IS in root deps)cargo testworkspace-wideworkspaces: ["projects/foo", "projects/bar"], neither declared in rootdependencies, package-lock.json withnode_modules/@scope/foo+node_modules/@scope/barlink entries →aube installproducesnode_modules/@scope/fooandnode_modules/@scope/barsymlinks pointing at../../projects/<name>🤖 Generated with Claude Code
Note
Medium Risk
Medium risk because it changes how npm lockfiles are interpreted to seed root direct dependencies, which can affect install layout and hoisting behavior for workspace/linked packages.
Overview
Ensures npm-managed workspaces that are not declared in the root
package.jsondeps still get their top-levelnode_modules/<workspace>symlinks recreated byaube install.The npm lockfile parser now scans
package-lock.jsonpackagesfor top-levelnode_modules/*entries withlink: true, de-dupes against already-declared direct deps, sorts them deterministically, and appends them to the root importer’s direct deps. Adds a regression test covering undeclared workspace members being surfaced as root direct deps and round-tripping asLocalSource::Link.Reviewed by Cursor Bugbot for commit c98805f. Bugbot is set up for automated code reviews on this repo. Configure here.