Skip to content

Fix map_kind for generated rules so renamed kinds keep deps/data#67

Open
firestreaker wants to merge 2 commits into
benchsci:mainfrom
firestreaker:fix-map-kind-generated-rules
Open

Fix map_kind for generated rules so renamed kinds keep deps/data#67
firestreaker wants to merge 2 commits into
benchsci:mainfrom
firestreaker:fix-map-kind-generated-rules

Conversation

@firestreaker

Copy link
Copy Markdown

I'm adding Vitest into my Bazel project, but gazelle hardcodes the generated test target to jest_test which is kinda misleading since we don't use Jest. Tried map_kind

# gazelle:map_kind jest_test vitest_test //build:vitest_test.bzl

but the renamed rule comes out with no deps, no data, and no load(). Getting by with a self-map (# gazelle:map_kind jest_test jest_test //build:vitest_test.bzl and jest_test = vitest_test in build/vitest_test.bzl) for now, but would like a cleaner fix that doesn't leave the BUILD files reading jest_test.

This change has the plugin emit builtin kinds and lets gazelle do the renaming, and adds an unmapKind helper for the few spots that read existing on-disk rules so a rule already renamed on a previous run is still recognized and not churned

Using `# gazelle:map_kind` to rename a kind this extension generates (e.g.
`map_kind jest_test vitest_test //build:vitest_test.bzl`) produced a rule with
no deps, no data, and no load() statement, breaking dependency management.
Self-maps (X X //file) worked, which is why this went unnoticed.

Root cause: the extension pre-applied map_kind itself at generation time via a
getKind() helper, writing the mapped kind to disk directly. That bypassed
gazelle core's rename handling:
  - Core never saw a builtin rule to record/remember, so it never injected the
    load() for the mapped kind.
  - Core's inverseMapKindResolver resets a renamed rule back to its builtin kind
    before calling Imports/Resolve, but resolve.go compared r.Kind() against the
    mapped name (getKind), so the comparison failed and the dep/data block was
    skipped.

Let gazelle core own map_kind instead:
  - generate.go: emit builtin kinds at rule creation; add unmapKind() (the
    inverse of KindMap) and use it only where the code inspects on-disk kinds
    (readExistingRules, pruneManagedRules, the collect-all collision check) so a
    rule already renamed on disk is still recognized, merged, and pruned across
    re-runs.
  - resolve.go: compare r.Kind() against builtin literals (consistent with the
    existing ts_project checks).

Add a golden fixture (tests/map_kind_test) covering both a fresh rename and a
re-run over an existing renamed rule. Document map_kind on the test rule in the
README.

Backward-compatible: with no map_kind (or a self-map), KindMap is empty/identity
and output is byte-identical, so the existing golden suite is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@firestreaker
firestreaker force-pushed the fix-map-kind-generated-rules branch from deb3840 to 70257fa Compare June 24, 2026 02:39
@firestreaker

Copy link
Copy Markdown
Author

Hi @ewianda, would you mind taking a look at this?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts the JS Gazelle extension so that # gazelle:map_kind can rename generated rule kinds (notably jest_testvitest_test) without losing automatic deps/data population or required load() statements, and adds regression coverage to prevent churn on reruns.

Changes:

  • Generate builtin rule kinds (e.g. jest_test, js_library) and rely on Gazelle’s map_kind machinery to rename them consistently.
  • Add unmapKind and use it when interpreting on-disk rules so previously-renamed kinds are still recognized as managed.
  • Add a new tests/map_kind_test fixture to validate correct outputs and rerun behavior; document the recommended map_kind usage in README.md.

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
gazelle/generate.go Adds unmapKind and uses it while pruning/reading managed rules so mapped kinds remain managed.
gazelle/resolve.go Updates kind comparisons after shifting generation to builtin kinds (needs follow-up fixes to preserve map_kind behavior).
README.md Documents using map_kind to emit vitest_test while retaining automatic dependency management.
tests/BUILD Registers the new map_kind_test test case.
tests/map_kind_test/** Adds fixtures to validate correct map_kind outputs and stability on reruns.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread gazelle/generate.go
Comment thread gazelle/resolve.go
Comment on lines 114 to 118
// modules can be resolved via the directory containing them
if (isBarrel || jsConfig.CollectAll) && r.Kind() != getKind(c, "jest_test") {
if (isBarrel || jsConfig.CollectAll) && r.Kind() != "jest_test" {
importSpecs = append(importSpecs, resolve.ImportSpec{
Lang: lang.Name(),
Imp: f.Pkg,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Gazelle sets the mapped kind on the rule in the file, but for resolution it wraps the language resolver in an inverseMapKindResolver that resets the rule's kind back to the builtin before calling Imports/Resolve. So in these methods r.Kind() is jest_test, not vitest_test, which is why the literal matches (and why the existing r.Kind() == "ts_project" checks work the same way).

Comment thread gazelle/resolve.go
Comment on lines 258 to 262
// Add in additional jest dependencies
if r.Kind() == getKind(c, "jest_test") {
if r.Kind() == "jest_test" {
// All deps are also data for jest_test rules.
for name := range depSet {
dataSet[name] = true

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

See comment on the above for resolve.go

unmapKind reversed only a single map_kind step, so a chained mapping
(A->B->C) left an on-disk kind resolving to the intermediate kind rather
than the builtin, which would break managed-rule detection for chained
maps. Follow the chain back to the builtin, mirroring gazelle's forward
resolution, with a visited-set guard against cycles and self-maps. Add a
unit test covering single/chained/self-map/unmapped/cyclic cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants