Skip to content

Commit f77cbf2

Browse files
feat(pipeline): resolve npm workspaces package imports (#271 Phase 1)
A Yarn/Lerna/npm monorepo references a sibling package by its declared `name` (e.g. `@org/a`), but package.json `main`/`exports` often points at a build artifact (dist/index.js) that is not indexed. pkgmap maps the name to that dead entry QN, so the import resolves to no node and no cross-package IMPORTS edge (and therefore no downstream CALLS edge) is produced. Phase 1 (npm `workspaces` only, per the maintainer's scoping in #271): - Detect workspace roots and member manifests during the existing pkgmap manifest walk (cbm_workspace_try_detect) — no extra file IO. Roots declare `workspaces` as an array or {"packages":[...]}; member globs are compiled with the reused gitignore engine ('*', '**', '!' negation, charclasses). Brace {a,b} expansion is out of scope (debug-logged). - Collect-then-finalize (cbm_workspaces_finalize) so a member can be parsed before its declaring root; maps each member NAME -> source DIR, first-wins on name collision. - Resolver Strategy 1c (resolve_workspace_member) probes conventional source entry files (src/index, index, src/main, ...) and subpath targets (`@org/a/utils/helper` -> <dir>/src/utils/helper). Runs only after the existing pkgmap/sibling strategies miss, so healthy repos (entry points at a real indexed file) are byte-for-byte unchanged. The import-targetable label filter preserves the #767 Folder-phantom guard; self-imports are rejected. Because the CALLS import-map is built from IMPORTS edges, fixing IMPORTS here also improves cross-package call resolution without touching the generic module resolver. Tests: new tests/test_workspaces.c (11 unit cases — array/object detection, single-star/doublestar/negation glob matching, first-wins, NULL-safety, scan_repo end-to-end) plus two previously-RED contract tests in test_lang_contract.c (unbuilt dist `main`, and subpath import) that now pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Hitoshi Okazaki <okazaki.hitoshi@tecnos.co.jp>
1 parent 90f59c5 commit f77cbf2

9 files changed

Lines changed: 733 additions & 15 deletions

File tree

Makefile.cbm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ TEST_DISCOVER_SRCS = \
355355

356356
TEST_GRAPH_BUFFER_SRCS = tests/test_graph_buffer.c
357357

358-
TEST_PIPELINE_SRCS = tests/test_registry.c tests/test_pipeline.c tests/test_fqn.c tests/test_route_canon.c tests/test_path_alias.c tests/test_configlink.c tests/test_infrascan.c tests/test_worker_pool.c tests/test_parallel.c tests/test_index_resilience.c
358+
TEST_PIPELINE_SRCS = tests/test_registry.c tests/test_pipeline.c tests/test_fqn.c tests/test_route_canon.c tests/test_path_alias.c tests/test_workspaces.c tests/test_configlink.c tests/test_infrascan.c tests/test_worker_pool.c tests/test_parallel.c tests/test_index_resilience.c
359359

360360
TEST_WATCHER_SRCS = tests/test_watcher.c
361361

src/pipeline/pass_parallel.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -817,9 +817,15 @@ static void merge_pkg_entries(cbm_pipeline_ctx_t *ctx, cbm_pkg_entries_t *pkg_en
817817
/* Supplement with a repo-wide filesystem walk so manifests filtered
818818
* by the main discoverer (package.json, composer.json — in
819819
* IGNORED_JSON_FILES) still feed pkgmap. Append into worker 0's
820-
* array so the existing merge below sees them. */
821-
cbm_pkgmap_scan_repo(ctx->repo_path, &pkg_entries[0], ctx->excluded_dirs, ctx->excluded_count);
820+
* array so the existing merge below sees them. The same walk populates
821+
* npm-workspace roots/candidates (#271); this runs in the sequential
822+
* post-join region, so no worker races on `ws`. */
823+
cbm_workspaces_t *ws = cbm_workspaces_new();
824+
cbm_pkgmap_scan_repo(ctx->repo_path, &pkg_entries[0], ctx->excluded_dirs, ctx->excluded_count,
825+
ws);
822826
cbm_pipeline_set_pkgmap(cbm_pkgmap_build(pkg_entries, worker_count, ctx->project_name));
827+
cbm_workspaces_finalize(ws);
828+
cbm_pipeline_set_workspaces(ws);
823829
for (int i = 0; i < worker_count; i++) {
824830
cbm_pkg_entries_free(&pkg_entries[i]);
825831
}

0 commit comments

Comments
 (0)