mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-16 20:53:57 +08:00
7ac8eefb85
A Lua `local` (variable or function) belongs to the file that declares it, but cross-file name matching treated it like a global. kong's spec helpers re-bind busted's globals (`local it = it`, `local assert = require "luassert"`), and every other spec file's `it(…)` / `assert(…)` / `describe(…)` linked to them — 15,776 edges; koreader's `local ipairs = ipairs` in one module took the project's `ipairs` / `pairs` / `type` / `tonumber` (2,329). isVisibleAcrossFiles now reads a Lua/Luau variable or function's declaration line and rejects a `local` one from another file (the reference stays unresolved rather than taking a runner-up). Globals stay visible. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
56 lines
1.8 KiB
TypeScript
56 lines
1.8 KiB
TypeScript
/**
|
|
* A Lua `local` belongs to its chunk: another file can never name it.
|
|
*
|
|
* kong's spec helpers re-bind busted's globals (`local it = it`,
|
|
* `local assert = require "luassert"`); every other spec file's `it(…)` and
|
|
* `assert(…)` linked to them — 4,166 and 1,234 times. koreader's
|
|
* `local ipairs = ipairs` in one module took the whole project's `ipairs`.
|
|
* A global function stays reachable.
|
|
*/
|
|
import { describe, it, expect, afterAll } from 'vitest';
|
|
import * as fs from 'fs';
|
|
import * as os from 'os';
|
|
import * as path from 'path';
|
|
import { CodeGraph } from '../src';
|
|
|
|
const roots: string[] = [];
|
|
afterAll(() => {
|
|
for (const r of roots.splice(0)) fs.rmSync(r, { recursive: true, force: true });
|
|
});
|
|
|
|
describe('Lua locals', () => {
|
|
it('are invisible outside their file; globals are not', async () => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-lua-local-'));
|
|
roots.push(root);
|
|
const files: Record<string, string> = {
|
|
'spec/helpers.lua': `local it = it
|
|
local ipairs = ipairs
|
|
local function helper() return 1 end
|
|
function global_helper() return 2 end
|
|
return {}
|
|
`,
|
|
'spec/plugin_spec.lua': `describe("plugin", function()
|
|
it("works", function()
|
|
for _, v in ipairs({ 1 }) do helper(v) end
|
|
global_helper()
|
|
end)
|
|
end)
|
|
`,
|
|
};
|
|
for (const [rel, content] of Object.entries(files)) {
|
|
fs.mkdirSync(path.dirname(path.join(root, rel)), { recursive: true });
|
|
fs.writeFileSync(path.join(root, rel), content);
|
|
}
|
|
const cg = await CodeGraph.init(root, { index: true });
|
|
try {
|
|
const targets = cg
|
|
.getOutgoingEdgesFrom(cg.getNodesInFile('spec/plugin_spec.lua').map((n) => n.id), ['calls'])
|
|
.map((e) => cg.getNode(e.target)!.name)
|
|
.sort();
|
|
expect(targets).toEqual(['global_helper']);
|
|
} finally {
|
|
cg.close();
|
|
}
|
|
});
|
|
});
|