|
|
@@ -45,7 +45,7 @@ agent read-reduction (see §4.3).
|
|
|
|
|
|
| Symbol | Role |
|
|
|
|---|---|
|
|
|
-| `VALUE_REF_LANGS` (static Set) | languages the feature runs for. Currently `typescript`, `javascript`, `tsx`, `go`, `python`, `rust`, `ruby`, `c`, `java`, `csharp`, `php`, `scala`, `kotlin`, `swift`. **Add the new language here.** |
|
|
|
+| `VALUE_REF_LANGS` (static Set) | languages the feature runs for. Currently `typescript`, `javascript`, `tsx`, `go`, `python`, `rust`, `ruby`, `c`, `java`, `csharp`, `php`, `scala`, `kotlin`, `swift`, `dart`. **Add the new language here.** |
|
|
|
| `valueRefsEnabled` | `process.env.CODEGRAPH_VALUE_REFS !== '0'` — default ON, env opts out. |
|
|
|
| `MAX_VALUE_REF_NODES` (20_000) | per-scope traversal cap (and the shadow-scan cap). |
|
|
|
| `captureValueRefScope(kind, name, id, node)` | called from `createNode` on every node. Records **targets** (file-scope `const`/`var`) and **reader scopes** (`function`/`method`/`const`/`var`). |
|
|
|
@@ -128,6 +128,21 @@ targets** (see §3).
|
|
|
`var x:Int{ … }` getter has no stored value — detect the `computed_property` child). Node creation
|
|
|
slots into the *existing* Swift `property_declaration` handler (property-wrapper/type deps), leaving
|
|
|
that untouched. Clean parse, no tail. Validated S/M/L (Alamofire/swift-argument-parser/swift-nio).
|
|
|
+- **Dart — clean grammar separation, but a sibling-body reader-scan fix.** Dart's grammar already
|
|
|
+ splits the cases: **`static_final_declaration`** is *exactly* a top-level/`static` `const`/`final`
|
|
|
+ (the shared-constant idiom), while instance fields/`var` use `initialized_identifier` and locals use
|
|
|
+ `initialized_variable_definition` — so extracting `static_final_declaration` → `constant` (in a
|
|
|
+ `visitNode` hook) has **no instance/local leaks to guard**. Reader-scan free (Dart refs are
|
|
|
+ `identifier`). The catch was the **reader-scan**: Dart attaches a method/function `body` as a *next
|
|
|
+ sibling* of the signature node (the stored scope), not a child, so the scan saw only the signature
|
|
|
+ and **found nothing** until it was taught to pull in a `function_body` next-sibling (Dart-only among
|
|
|
+ the value-ref set). Shadow prune needed `static_final_declaration` + `initialized_identifier` +
|
|
|
+ `initialized_variable_definition` (a local `const X` shadowing a file `const X`). Validated S/M/L
|
|
|
+ (http/flame/flutter-packages). **Caveat:** generated Dart files inflate the sibling-class ambiguity
|
|
|
+ (a JNIGEN `_bindings.dart` with hundreds of `static final _class` collapses to the file-wide target).
|
|
|
+ The common codegen suffixes (`.g.dart`/`.freezed.dart`/`.pb.dart`) are already filtered by
|
|
|
+ `isGeneratedFile`; header-only-marked generators (JNIGEN) are not, so real source is clean but
|
|
|
+ generated FFI/JNI bindings are noisy.
|
|
|
- **Tests:** `__tests__/value-reference-edges.test.ts` — same-file readers edged; surfaced in
|
|
|
impact radius; shadowed const NOT edged (verified to fail without the guard); JSX-only read
|
|
|
edged (tsx); `CODEGRAPH_VALUE_REFS=0` emits nothing.
|
|
|
@@ -157,6 +172,7 @@ the bottom of this section).
|
|
|
| Scala | top-level `val` (already `constant`) + **`object` val** (the singleton-constant idiom; re-kinded from `field` by walking to the enclosing `object_definition`). `class`/`trait`/`enum` vals stay `field`. `val_definition`/`var_definition` added to the shadow prune. Minor val/def name-collision limit |
|
|
|
| Kotlin | top-level / `object` / `companion object` `val` (re-kinded from nothing — properties weren't extracted at all). Handled in `visitNode`: nested name (`variable_declaration → simple_identifier`, the C move) + scope-walk for kind (Scala move) + `simple_identifier` in the reader-scan (PHP move) + prune. `class` instance vals stay `field`. Clean — one of the best yields (companion bit-masks) |
|
|
|
| Swift | top-level `let` + `static let` in `struct`/`enum`/`class`. Reused Kotlin (nested name + `simple_identifier` reader-scan). Two Swift touches: **gate widened to `struct:`/`enum:` parents** (Swift namespaces consts there), and **computed properties skipped**. `class`/instance stored props stay `field`. Slots into the existing Swift property-wrapper handler |
|
|
|
+| Dart | top-level `const`/`final` + class `static const`/`static final` — all the **`static_final_declaration`** node, cleanly separated by the grammar from instance/`var`/local (so no leak guard). `visitNode` → `constant`. Needed a reader-scan fix: Dart's method **body is a next sibling** of the signature, so the scan pulls in a `function_body` sibling. Generated-FFI noise (JNIGEN `_bindings.dart`) is the one caveat |
|
|
|
| **Svelte, Vue, Astro** | **inherited for free** — their extractors re-parse the `<script>`/frontmatter block as `typescript`/`javascript`, which are in `VALUE_REF_LANGS` (verified: a `.svelte` `const` edges its readers). No separate work; no separate matrix row needed. |
|
|
|
|
|
|
**🔜 Remaining — likely the easy path** (constants are file/module-scope, or top-level; do §5: add
|
|
|
@@ -170,7 +186,6 @@ column.**
|
|
|
|
|
|
| Language | Constant forms | Note |
|
|
|
|---|---|---|
|
|
|
-| Dart | top-level `const`/`final` (file) + `static const` (class) | mixed; AST is a flat `static_final_declaration_list`, not a clean property node — messier than Swift |
|
|
|
| Lua / Luau | file/chunk `local X =` + globals; no `const` keyword | distinctive-name gate (needs `[A-Z_]`) catches fewer — Lua casing varies |
|
|
|
| R | file-scope `X <- …` / `X = …` | |
|
|
|
|
|
|
@@ -377,6 +392,7 @@ silently does nothing for the new language and intra-file shadowing produces fal
|
|
|
| Scala | `val_definition`, `var_definition` | `pattern` field (identifier) — catches an object/top-level val shadowed by a method-local `val` | **done** |
|
|
|
| Kotlin | `property_declaration` | `variable_declaration → simple_identifier` (and `bump` accepts `simple_identifier`) — catches an object/companion const shadowed by a method-local `val` | **done** |
|
|
|
| Swift | `property_declaration` | `<name> pattern → simple_identifier` (`firstSimpleIdentifier`) — the prune case resolves both Kotlin and Swift shapes; catches a static const shadowed by a method-local `let` | **done** |
|
|
|
+| Dart | `static_final_declaration` (target) + `initialized_identifier` (field/`var`) + `initialized_variable_definition` (local) | each has a direct `identifier` child — catches a top-level/static const shadowed by a method-local `const` | **done** |
|
|
|
|
|
|
**The prune rule is `declarators > file-scope-node-count`, NOT `> 1`.** A name can be bound
|
|
|
twice *at file scope* legitimately — a **conditional module def** (`try: X = a; except: X = b`,
|
|
|
@@ -488,6 +504,13 @@ fixed); impact delta shows the blind→real radius win; full test suite green.
|
|
|
(2,956 files) gave only 86 edges vs Ruby rails's 2,255. Don't chase it: cross-file value consumers
|
|
|
are out of scope for *every* language (would need import/scope resolution). Report the lower yield
|
|
|
honestly in the matrix rather than treating it as a bug to fix.
|
|
|
+- **A zero-edge sweep with targets present can be the READER side, not just the reader-scan node type
|
|
|
+ (the Dart trap).** Targets extracted fine, reader scopes registered, reader-scan node type correct —
|
|
|
+ and still zero edges, because Dart attaches a method **body as a next *sibling*** of the signature
|
|
|
+ node (which is what gets stored as the reader scope), so the scan walked only the signature subtree.
|
|
|
+ If a language's function/method body isn't a descendant of the node you register as the reader scope,
|
|
|
+ the scan won't see the reads — pull in the sibling/linked body. Check this when edges are zero but
|
|
|
+ both the targets and the reader nodes look right.
|
|
|
|
|
|
---
|
|
|
|