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>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c5eebe6beb
commit
9ad5cd7ba2
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 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;
|
||||
},
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user