fix(ingestion): index generator function declarations (#2305)

This commit is contained in:
Parafee41 2026-06-26 20:37:02 +08:00 • committed by GitHub
parent 70767b2918
commit 49fb596271
3 changed files with 95 additions and 0 deletions

View file

@ -27,6 +27,9 @@ export const TYPESCRIPT_QUERIES = `
(function_declaration
name: (identifier) @name) @definition.function
(generator_function_declaration
name: (identifier) @name) @definition.function
; TypeScript overload signatures (function_signature is a separate node type from function_declaration)
(function_signature
name: (identifier) @name) @definition.function
@ -374,6 +377,9 @@ export const JAVASCRIPT_QUERIES = `
(function_declaration
name: (identifier) @name) @definition.function
(generator_function_declaration
name: (identifier) @name) @definition.function
(method_definition
name: (property_identifier) @name) @definition.method

View file

@ -0,0 +1,28 @@
import { describe, expect, it } from 'vitest';
import { parseFilesWithWorkers } from '../helpers/worker-parse.js';
describe('TypeScript async generator functions', () => {
it('indexes exported async function* declarations as Function nodes', async () => {
const { graph } = await parseFilesWithWorkers([
{
path: 'src/coach.ts',
content: `
export function userText(input: string): string {
return input.trim();
}
export async function* runCoachLoop(input: string): AsyncGenerator<string> {
yield userText(input);
}
`,
},
]);
const functionNames = new Set(
graph.nodes.filter((node) => node.label === 'Function').map((node) => node.properties.name),
);
expect(functionNames).toContain('userText');
expect(functionNames).toContain('runCoachLoop');
});
});

View file

@ -1,4 +1,7 @@
import { describe, it, expect } from 'vitest';
import Parser from 'tree-sitter';
import JavaScript from 'tree-sitter-javascript';
import TypeScript from 'tree-sitter-typescript';
import {
TYPESCRIPT_QUERIES,
JAVASCRIPT_QUERIES,
@ -15,6 +18,28 @@ import {
DART_QUERIES,
} from '../../src/core/ingestion/tree-sitter-queries.js';
function capturedDefinitionFunctionNames(
language: Parameters<Parser['setLanguage']>[0],
querySource: string,
src: string,
): string[] {
const parser = new Parser();
parser.setLanguage(language);
const query = new Parser.Query(language, querySource);
const tree = parser.parse(src);
const names: string[] = [];
for (const match of query.matches(tree.rootNode)) {
let isFunction = false;
let name: string | undefined;
for (const capture of match.captures) {
if (capture.name === 'definition.function') isFunction = true;
if (capture.name === 'name') name = capture.node.text;
}
if (isFunction && name !== undefined) names.push(name);
}
return names;
}
describe('tree-sitter queries', () => {
describe('TypeScript queries', () => {
it('captures class declarations', () => {
@ -32,6 +57,22 @@ describe('tree-sitter queries', () => {
expect(TYPESCRIPT_QUERIES).toContain('@definition.function');
});
it('captures async generator function declarations as function definitions', () => {
const names = capturedDefinitionFunctionNames(
TypeScript.typescript as Parameters<Parser['setLanguage']>[0],
TYPESCRIPT_QUERIES,
`
export function userText() { return ''; }
export async function* runCoachLoop(): AsyncGenerator<string> {
yield 'ready';
}
`,
);
expect(names).toContain('userText');
expect(names).toContain('runCoachLoop');
});
it('captures method definitions', () => {
expect(TYPESCRIPT_QUERIES).toContain('method_definition');
expect(TYPESCRIPT_QUERIES).toContain('@definition.method');
@ -62,6 +103,26 @@ describe('tree-sitter queries', () => {
it('does not have interface declarations', () => {
expect(JAVASCRIPT_QUERIES).not.toContain('interface_declaration');
});
it('captures generator function declarations as function definitions', () => {
const names = capturedDefinitionFunctionNames(
JavaScript as Parameters<Parser['setLanguage']>[0],
JAVASCRIPT_QUERIES,
`
export function userText() { return ''; }
export async function* runCoachLoop() {
yield 'ready';
}
export function* plainGen() {
yield 1;
}
`,
);
expect(names).toContain('userText');
expect(names).toContain('runCoachLoop');
expect(names).toContain('plainGen');
});
});
describe('Python queries', () => {