Files
codegraph/__tests__/fixtures/kernel-parity/torture.js
T
Colby McHenryandClaude Fable 5 9ad5cd7ba2 feat(kernel): R2 — full TypeScript/JavaScript extraction port, byte-parity with the wasm path
Replaces the R1 seed .scm emitter with a bespoke Rust walker
(codegraph-kernel/src/tsjs/) that mirrors TreeSitterExtractor's TS/JS
paths function-for-function: declarations (incl. #808 field/property
classification), qualified names, docstrings (#780 wrapper climbs),
signatures, imports/re-exports + per-binding refs, calls with
receiver-qualified callees (#1230 literal-receiver skip), instantiations,
decorators, inheritance, type annotations (#381), type-alias members +
tuple contracts (#359/#634), React component recognition (#841
forwardRef/memo/styled), object-of-functions / zustand-through-middleware
/ RTK Query endpoints + generated hooks / vuex + pinia store shapes,
function-as-value capture with the flush gate (#756), and value-reference
edges with the shadow prune (#895/#897). The generic query emitter is
deleted — extraction parity needs logic .scm can't express; future
languages get walkers too (migration plan §4a).

Positions and JS string-slice semantics are emitted in UTF-16 code units
natively, so kernel output is byte-identical to web-tree-sitter's — no
column diff class exists.

Parity evidence (macOS): scripts/kernel-parity.mjs (full-object multiset
diff per file) — this repo 353/353 files, excalidraw 643/643 (10,650
nodes / 10,726 edges / 68,307 refs), plus torture fixtures checked into
__tests__/fixtures/kernel-parity/ and enforced in npm test by
kernel-tsjs-parity.test.ts. The strict compare caught one real decoder
bug the loose harness missed: refs must NOT carry denormalized
filePath/language at the extractFromSource seam (the store fills them).

Perf: extraction 2.6× single-thread on excalidraw (487ms vs 1,255ms,
identical outputs). Routing stays opt-in (CODEGRAPH_KERNEL_LANGS) until
the R3 equivalence gate (large repo, DB dump-diff, retrieval invariants,
agent A/B, Linux/Windows) passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 22:14:40 -05:00

76 lines
1.4 KiB
JavaScript

/**
* JS-grammar torture fixture (javascript variant: no type machinery, JS class
* fields use `field_definition` with a `property` field).
*/
import { EventEmitter } from 'node:events';
const { promisify } = require('node:util');
/** Legacy prototype-style helper. */
function legacyHelper(a, b) {
return a + b;
}
const arrow = (x) => legacyHelper(x, 1);
class Widget extends EventEmitter {
static registry = new Map();
#privateField = 1;
label = 'w';
onTick = () => {
this.render();
};
wrapped = debounce(function () {
expensive();
}, 50);
constructor(opts) {
super();
this.opts = opts;
register(this.onTick);
}
render() {
paint(this.label);
}
static create(opts) {
return new Widget(opts);
}
}
// AMD-style wrapper — anonymous, but inner functions must still surface.
(function () {
function hiddenInner() {
return 7;
}
hiddenInner();
})();
module.exports.makeWidget = function makeWidget(opts) {
return Widget.create(opts);
};
// Vuex module shape (store-file signals: mutations + actions + getters).
const mutations = {
SET_USER(state, user) {
state.user = user;
},
};
const actions = {
async loadUser({ commit }, id) {
const user = await fetchUser(id);
commit('SET_USER', user);
},
};
export default {
namespaced: true,
state: () => ({ user: null }),
mutations,
actions,
getters: {
userName(state) {
return state.user?.name;
},
},
};