mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-28 22:52:00 +08:00
A TypeScript or JavaScript call on a constructed object, new C(args).m(),
reached the resolver as the bare method name in both engines, so exact
matching bound it to any project method called m: new RegExp(p).exec(s)
to a database wrapper's exec, new Array(n).fill(0) to a text class's
fill, new TextEncoder().encode(s) to a project encode function.
Both engines now emit new C().m (new ns.C().m for a namespaced class, and
nothing for a constructor that is not a plain name or member chain). The
resolver looks m up on C with resolveMethodOnType, inherited methods on
the conformance pass once extends edges exist, an aliased named import
mapped back to its class, and a JS built-in (RegExp, Map, Date...) never
a project class unless the file imports or declares one. An ES5
constructor function keeps its prototype method.
Our changes: the lookup passes the file the call's file imports the class
from (tsImportedTypeFile), so of two classes sharing a name the imported
one is the one constructed (the PR as written took the first indexed copy,
at 0.9); new this.constructor() and a static new this() keep the bare
method name, as a call on this does (the PR dropped three.js's clone
idiom, 29 links to a class's own copy); rebased onto PR #2852, which
edits the same keepsBareTsJsReceiver and test lists; resolved the import
list conflict with rustChainedCallByName from PR #2846; CHANGELOG bullet
moved next to the JS/TS receiver bullets.
Validation: the new tests fail 4 of 6 on main 449eefa7 with both engines
and pass here. A/B against main, kernel per arm: flask, gin and vite
byte-identical. codegraph 48 links added (new ToolHandler(cg).execute), 2
retargeted and 14 typed, all right, 58 removed, 57 wrong (RegExp exec and
test, Array fill, Set add) and 1 right one lost to the grammar's parse of
new nodeSqlite!.DatabaseSync(). excalidraw 22 wrong removed (TextEncoder,
TextDecoder, URLSearchParams, Array fill), 3 typed. pixijs 14 retargeted
and 278 typed, all right, 7 wrong removed. pdf.js 5 added, 47 retargeted
and 68 typed, all right, 76 wrong removed (Array keys and fill, typed
arrays, Response). three.js 33 added, 404 retargeted (Capsule::set to
Matrix4::set and Matrix3::set, NURBSCurve::copy to the class's own copy)
and 429 typed, all right; 135 removed, 133 wrong (UINumber onChange, which
three.js attaches at run time, TextDecoder, typed arrays, URL) and 2 right
only by name (Loader methods inherited through a base imported from the
three package). No default-imported class under another name lost an edge.
Kernel parity holds on all six TS/JS repos and this repository, 0 diffs.
Index CPU time unchanged or lower: codegraph 81.5 s to 79.5 s, three.js
72.0 s to 71.2 s (medians of 3, interleaved).
Original PR #1945 by @danusha2345.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
143 lines
4.0 KiB
JavaScript
143 lines
4.0 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();
|
|
static hooks = { tick: legacyHelper };
|
|
#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;
|
|
},
|
|
},
|
|
};
|
|
|
|
// Initializer walks attributed to the declared symbol (#693). A plain call
|
|
// leaked to the FILE node; a non-exported object literal was skipped outright.
|
|
const eagerConfig = loadConfig();
|
|
const handlerMap = { onSave: () => persist(eagerConfig), onLoad: loadConfig() };
|
|
const registry = { legacyHelper, run: arrow, nested: [legacyHelper] };
|
|
const lazyList = [() => persist(eagerConfig)];
|
|
// --- CommonJS export assignments (#1675) -----------------------------------
|
|
exports.getItems = async (req, res) => { res.json(await findItems()); };
|
|
module.exports.deleteItem = function (req, res) { removeItem(req.params.id); res.end(); };
|
|
exports.plain = 42;
|
|
handlers.onSave = () => { persist(); };
|
|
// --- call-expression receivers (#1683) ----------------------------------------
|
|
function bucketChains(d, k, v) {
|
|
d.setdefault(k, []).append(v);
|
|
make().run();
|
|
(0, make)().run();
|
|
arr[0]().go();
|
|
obj.make().run().again();
|
|
}
|
|
// --- expression receivers ----------------------------------------------------
|
|
async function exprReceivers(x) {
|
|
(await list()).map(g);
|
|
(x).run();
|
|
(a ?? b).map(g);
|
|
f().list.map(g);
|
|
(() => 1).call(null);
|
|
this.a.b.run();
|
|
new Runner().go();
|
|
new RegExp(p).exec(s);
|
|
(new ns.Widget(1)).draw();
|
|
new (pick())().go();
|
|
new this.constructor().copy(x);
|
|
}
|
|
// --- component wrappers walked under the component ------------------------------
|
|
const PANEL_GAP = 8;
|
|
const Panel = styled(Widget)`
|
|
gap: ${PANEL_GAP}px;
|
|
color: ${(props) => colorOf(props.theme)};
|
|
`;
|
|
const Row = styled.div.attrs((props) => ({ role: roleOf(props) }))`
|
|
${Panel} { margin: 0; }
|
|
`;
|
|
const MemoPanel = React.memo(Panel, legacyHelper);
|
|
// --- callees that name nothing, and wrappers that keep one -----------------------
|
|
function calleeShapes(handlers, type, fn, ns) {
|
|
(() => { legacyHelper(1, 2); })();
|
|
(function () { arrow(3); })();
|
|
connect(mapState)(Widget);
|
|
breakpoint('tablet')`padding: 0;`;
|
|
handlers[type](1);
|
|
(0, fn)();
|
|
(fn)();
|
|
(ns.fn)();
|
|
}
|
|
// --- parameter defaults are the function's code (#2588) -----------------------
|
|
function defaultsOf(note = legacyHelper(1), { a = arrow(2), b: { c = new Widget() } = {} } = {}, [x = legacyHelper(3), , y = arrow(4)] = [], { [legacyHelper(5)]: keyed } = {}) {
|
|
return [note, a, c, x, y, keyed];
|
|
}
|
|
class DefaultsHolder {
|
|
constructor(o = new Widget()) { this.o = o; }
|
|
pick(item = legacyHelper(6)) { return item; }
|
|
onPick = (item = arrow(7)) => item;
|
|
}
|
|
const defaultsApi = { load(note = legacyHelper(8)) { return note; } };
|
|
export default function (note = arrow(9)) { return note; }
|