`exports.getItems = async (req, res) => {…}` and `module.exports.x =
function () {…}` — the Express controller style — produced no symbol: the
arrow's parent is an assignment, not a declarator, so it stayed anonymous,
its calls attributed to the file, and `node`/`callers` answered "Symbol
not found" for a route-wired handler. Resolve the name from the export
property, mark it exported, in both the wasm walker and the kernel.
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
This commit is contained in:
co-authored by
danusha2345
Colby McHenry
parent
3adf06772b
commit
43271f3cd3
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* CommonJS export assignments name the function they hold (#1675).
|
||||
*
|
||||
* `exports.getItems = async (req, res) => {…}` and `module.exports.x =
|
||||
* function () {…}` are how Express controllers are commonly written. The
|
||||
* arrow is anonymous only syntactically — the export property is the name
|
||||
* every `router.get('/items', getItems)` resolves — so it gets the same
|
||||
* treatment `const getItems = () => {}` already has: a function node, exported,
|
||||
* with its calls attributed to it rather than to the file.
|
||||
*/
|
||||
import { describe, it, expect, beforeAll } from 'vitest';
|
||||
import { extractFromSource } from '../src/extraction';
|
||||
import { initGrammars, loadAllGrammars } from '../src/extraction/grammars';
|
||||
|
||||
beforeAll(async () => {
|
||||
await initGrammars();
|
||||
await loadAllGrammars();
|
||||
});
|
||||
|
||||
const refsFrom = (result: ReturnType<typeof extractFromSource>, id: string) =>
|
||||
result.unresolvedReferences.filter((r) => r.fromNodeId === id).map((r) => r.referenceName);
|
||||
|
||||
describe('CommonJS export assignments', () => {
|
||||
it('indexes exports.X / module.exports.X functions as exported function nodes', () => {
|
||||
const code = `
|
||||
const { findItems, removeItem } = require('./db');
|
||||
|
||||
exports.getItems = async (req, res) => {
|
||||
res.json(await findItems());
|
||||
};
|
||||
|
||||
module.exports.deleteItem = function (req, res) {
|
||||
removeItem(req.params.id);
|
||||
res.end();
|
||||
};
|
||||
|
||||
exports.plain = 42;
|
||||
module.exports = { legacy: 1 };
|
||||
`;
|
||||
const result = extractFromSource('src/controller.js', code);
|
||||
const fns = result.nodes.filter((n) => n.kind === 'function');
|
||||
expect(fns.map((n) => n.name).sort()).toEqual(['deleteItem', 'getItems']);
|
||||
|
||||
const getItems = fns.find((n) => n.name === 'getItems')!;
|
||||
const deleteItem = fns.find((n) => n.name === 'deleteItem')!;
|
||||
expect(getItems.startLine).toBe(4);
|
||||
expect(getItems.isExported).toBe(true);
|
||||
expect(deleteItem.isExported).toBe(true);
|
||||
expect(getItems.isAsync).toBe(true);
|
||||
|
||||
// The handlers' calls are their own, not the file's.
|
||||
expect(refsFrom(result, getItems.id)).toContain('findItems');
|
||||
expect(refsFrom(result, deleteItem.id)).toContain('removeItem');
|
||||
const file = result.nodes.find((n) => n.kind === 'file')!;
|
||||
expect(refsFrom(result, file.id)).not.toContain('findItems');
|
||||
expect(refsFrom(result, file.id)).not.toContain('removeItem');
|
||||
|
||||
// A non-function export is not a function, and nothing is left anonymous.
|
||||
expect(result.nodes.map((n) => n.name)).not.toContain('<anonymous>');
|
||||
});
|
||||
|
||||
it('leaves other member assignments alone', () => {
|
||||
const code = `
|
||||
const handlers = {};
|
||||
handlers.onSave = () => { persist(); };
|
||||
app.locals.format = function () { return 1; };
|
||||
`;
|
||||
const result = extractFromSource('src/other.js', code);
|
||||
expect(result.nodes.filter((n) => n.kind === 'function')).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -74,6 +74,11 @@ export default {
|
||||
},
|
||||
};
|
||||
|
||||
// --- 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);
|
||||
|
||||
Reference in New Issue
Block a user