Skip to content

fix(workspace): discover packages nested under a bare glob-matched intermediate dir - #854

Closed
BartWaardenburg wants to merge 1 commit into
mainfrom
fix/issue-842-phantom-intermediate-workspace
Closed

fix(workspace): discover packages nested under a bare glob-matched intermediate dir#854
BartWaardenburg wants to merge 1 commit into
mainfrom
fix/issue-842-phantom-intermediate-workspace

Conversation

@BartWaardenburg

@BartWaardenburg BartWaardenburg commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes the false unlisted-dependencies (e.g. react) reported for packages nested under a bare workspace-glob intermediate directory.

When a root package.json declares a single-level glob such as "workspaces": ["packages/*"] but a real package lives two levels deep (packages/themes/my-theme/package.json, where packages/themes itself has no package.json), the glob only matched the bare packages/themes directory. The deep package was never discovered, so its files fell back to the root manifest and every dependency it correctly declared surfaced as unlisted.

Approach (re-scoped to workspace discovery)

The fix lives in workspace discovery (crates/config/src/workspace/parsers.rs), not analysis-time dependency attribution. When a workspace glob matches a directory that has no package.json of its own, expand_workspace_glob_with_diagnostics now descends exactly one level via recover_nested_packages and registers any immediate child that is a real, named package, in the same shape the discovery loop already consumes. So the deep package becomes a normal discovered workspace and feeds ws_dep_map, and unused-files / unused-exports / boundary checks all see one consistent owning package.

Recovery is conservative: node_modules and conventional skip-list directories (build output, caches, hidden dirs) are excluded, and a manifest without a name (fixtures, build artifacts, __mocks__) is rejected. When at least one child is recovered the glob-matched-no-package-json diagnostic is suppressed; when none is, it still fires.

Tests

  • expand_workspace_glob_recovers_nested_package_under_bare_intermediate (config): proves the named deep package is recovered while a nameless manifest and a non-package dir under the same grouping dir are not.
  • discover_workspaces_recovers_package_under_bare_glob_intermediate (config): end-to-end discovery reconstructing the reporter's exact workspaces: ["./packages/*", "./themes/*"] array, asserting metrists-theme-next becomes a discovered workspace (it is not on main).

Full fallow-config workspace suite + full fallow-core suite pass; clippy -D warnings, fmt, and the agent-file manifest gate are clean.

Note

This replaces the earlier analysis-time attribution approach, which a panel review found did not change the reporter's output (its helper only ran when the intermediate dir was itself a tracked workspace, which it is not in the reporter's layout). The fix now reproduces and resolves the reporter's actual case.

Closes #842

@BartWaardenburg
BartWaardenburg force-pushed the fix/issue-842-phantom-intermediate-workspace branch 2 times, most recently from c7ad12f to 0b19da2 Compare June 2, 2026 07:39
@BartWaardenburg
BartWaardenburg marked this pull request as ready for review June 2, 2026 07:42
@BartWaardenburg
BartWaardenburg force-pushed the fix/issue-842-phantom-intermediate-workspace branch 2 times, most recently from 3213cea to f33f9c2 Compare June 2, 2026 10:18
@BartWaardenburg BartWaardenburg changed the title fix(workspace): attribute files to nearest package.json, not glob-matched intermediate dirs fix(workspace): discover packages nested under a bare glob-matched intermediate dir Jun 2, 2026
…termediate dir

A single-level workspace glob (packages/*) matches a bare grouping directory
(packages/themes) that has no package.json, while the real package lives one
level deeper (packages/themes/my-theme). The deep package was never discovered,
so its files fell back to the root manifest and its declared deps (e.g. react)
were reported as unlisted. Workspace discovery now descends one level into a
no-package.json glob match and recovers any immediate child that is a real,
named package, gated against node_modules / skip-list dirs / nameless manifests.

Re-scopes the fix from analysis-time dependency attribution to workspace
discovery so unused-files / unused-exports / boundary checks share one owning
package. Replaces the prior nearest-ancestor attribution approach.

Fixes #842
@BartWaardenburg
BartWaardenburg force-pushed the fix/issue-842-phantom-intermediate-workspace branch from f33f9c2 to d56eb86 Compare June 2, 2026 10:19

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Fallow Benchmarks'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: d56eb86 Previous: 2df7aae Ratio
dupe_detect_2x500_identical 236921 ns/iter (± 4784) 156496 ns/iter (± 2359) 1.51
dupe_detect_2x2000_identical 1079788 ns/iter (± 11967) 714903 ns/iter (± 6355) 1.51
dupe_detect_100x200_mixed 4382385 ns/iter (± 29091) 2919083 ns/iter (± 30803) 1.50
dupe_detect_2x5000_identical 3005720 ns/iter (± 6078) 1966738 ns/iter (± 21340) 1.53

This comment was automatically generated by workflow using github-action-benchmark.

@BartWaardenburg

Copy link
Copy Markdown
Collaborator Author

Landed on main via maintainer direct-to-main flow, squashed into ae240a0. #842 is fixed on main; closing as redundant.

@BartWaardenburg
BartWaardenburg deleted the fix/issue-842-phantom-intermediate-workspace branch June 2, 2026 12:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

npm packages/* workspace glob matching an intermediate dir misattributes nested-package files

1 participant