fix(lua): close latest review gaps

This commit is contained in:
taoxin 2026-08-24 21:26:15 +08:00
parent a5611a3f86
commit 9d11a33f8e
4 changed files with 61 additions and 2 deletions

View file

@ -362,7 +362,9 @@ export const extractReceiverNode = (nameNode: SyntaxNode): SyntaxNode | undefine
// Lua: the receiver is the `table` field of the call's `function` variable.
if (!receiver && callNode.type === 'call') {
const callee = callNode.childForFieldName('function');
if (callee?.type === 'variable') receiver = callNode.childForFieldName('table');
if (callee?.type === 'variable') {
receiver = callNode.childForFieldName('table') ?? callee.childForFieldName('table');
}
}
if (

View file

@ -2,6 +2,7 @@ import { describe, it, expect } from 'vitest';
import {
inferCallForm,
extractReceiverName,
extractReceiverNode,
} from '../../src/core/ingestion/utils/call-analysis.js';
import type { SyntaxNode } from '../../src/core/ingestion/utils/ast-helpers.js';
import { createSymbolTable } from '../../src/core/ingestion/model/symbol-table.js';
@ -116,6 +117,33 @@ describe('inferCallForm', () => {
expect(inferCallForm(match!.callNode, match!.nameNode)).toBe('member');
expect(extractReceiverName(match!.nameNode)).toBe('util');
});
it('captures a complex receiver node for deferred chain resolution', () => {
parser.setLanguage(Lua);
const captures = extractCallCaptures(parser, 'getService().run()', SupportedLanguages.Lua);
const match = captures.find((c) => c.calledName === 'run');
expect(match).toBeDefined();
expect(inferCallForm(match!.callNode, match!.nameNode)).toBe('member');
expect(extractReceiverName(match!.nameNode)).toBeUndefined();
expect(extractReceiverNode(match!.nameNode)?.text).toBe('getService()');
});
it('captures a bare middleclass class binding', () => {
parser.setLanguage(Lua);
const provider = getProvider(SupportedLanguages.Lua);
const tree = parser.parse('local Foo = class("Foo")');
const query = new Parser.Query(parser.getLanguage(), provider.treeSitterQueries);
const matches = query.matches(tree.rootNode);
expect(
matches.some(
(match) =>
match.captures.some((capture) => capture.name === 'definition.class') &&
match.captures.some(
(capture) => capture.name === 'name' && capture.node.text === 'Foo',
),
),
).toBe(true);
});
});
describe('Java', () => {

View file

@ -203,8 +203,11 @@ describe('parser-loader ABI load-smoke (#1922)', () => {
return;
}
const lf = String.fromCharCode(10);
const crlf = String.fromCharCode(13, 10);
const snippets = [
`local value = "line\\${lf}continued"${lf}`,
`local value = 'line\\${lf}continued'${lf}`,
`local value = "line\\${crlf}continued"${crlf}`,
`local value = 'line\\${crlf}continued'${crlf}`,
];

View file

@ -1,5 +1,31 @@
// Type stub mirroring gitnexus/vendor/tree-sitter-c/bindings/node/index.d.ts.
// The runtime binding is a native .node loaded by node-gyp-build; this stub
// gives TypeScript a Language-shaped module to import.
declare const language: unknown;
type BaseNode = {
type: string;
named: boolean;
};
type ChildNode = {
multiple: boolean;
required: boolean;
types: BaseNode[];
};
type NodeInfo =
| (BaseNode & {
subtypes: BaseNode[];
})
| (BaseNode & {
fields: { [name: string]: ChildNode };
children: ChildNode[];
});
type Language = {
name: string;
language: unknown;
nodeTypeInfo: NodeInfo[];
};
declare const language: Language;
export = language;