mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-06 02:49:56 +00:00
feat(type-env): add flush() method to TypeEnvironment
Adds flush(filePath, accumulator) to the TypeEnvironment interface and buildTypeEnv return object, draining all scoped bindings into a BindingAccumulator. Adds 4 unit tests covering file-scope, function-scope, empty env, and multi-file accumulation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3111f4dcd3
commit
56e2e7f520
2 changed files with 78 additions and 0 deletions
|
|
@ -8,6 +8,7 @@ import { CALL_EXPRESSION_TYPES } from './utils/call-analysis.js';
|
|||
import { SupportedLanguages } from 'gitnexus-shared';
|
||||
import { TYPED_PARAMETER_TYPES } from './type-extractors/shared.js';
|
||||
import { getProvider } from './languages/index.js';
|
||||
import type { BindingAccumulator, BindingEntry } from './binding-accumulator.js';
|
||||
import type {
|
||||
ClassNameLookup,
|
||||
ReturnTypeLookup,
|
||||
|
|
@ -73,6 +74,9 @@ export interface TypeEnvironment {
|
|||
* Populated when a variable has BOTH a declared base type AND a more specific
|
||||
* constructor type (e.g., `Animal a = new Dog()` → key maps to 'Dog'). */
|
||||
readonly constructorTypeMap: ReadonlyMap<string, string>;
|
||||
/** Drain all scoped bindings into a BindingAccumulator.
|
||||
* Called once per file at end of processing. Skips empty scopes. */
|
||||
flush(filePath: string, accumulator: BindingAccumulator): void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1245,6 +1249,17 @@ export const buildTypeEnv = (
|
|||
fileScope: () => env.get(FILE_SCOPE) ?? EMPTY_FILE_SCOPE,
|
||||
allScopes: () => env as ReadonlyMap<string, ReadonlyMap<string, string>>,
|
||||
constructorTypeMap,
|
||||
flush(filePath: string, accumulator: BindingAccumulator): void {
|
||||
const entries: BindingEntry[] = [];
|
||||
for (const [scope, scopeMap] of env) {
|
||||
for (const [varName, typeName] of scopeMap) {
|
||||
entries.push({ scope, varName, typeName });
|
||||
}
|
||||
}
|
||||
if (entries.length > 0) {
|
||||
accumulator.appendFile(filePath, entries);
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { buildTypeEnv, type TypeEnvironment } from '../../src/core/ingestion/type-env.js';
|
||||
import { BindingAccumulator } from '../../src/core/ingestion/binding-accumulator.js';
|
||||
import {
|
||||
createSymbolTable,
|
||||
type SymbolDefinition,
|
||||
|
|
@ -5859,4 +5860,66 @@ function process() {
|
|||
expect(typeEnv.lookup('c', validateCall)).toBe('Config');
|
||||
});
|
||||
});
|
||||
|
||||
describe('flush', () => {
|
||||
it('flushes file-scope bindings into accumulator', () => {
|
||||
const code = `const user: User = getUser();\nconst count: number = 0;`;
|
||||
const tree = parse(code, TypeScript.typescript);
|
||||
const typeEnv = buildTypeEnv(tree, 'typescript');
|
||||
const acc = new BindingAccumulator();
|
||||
|
||||
typeEnv.flush('/src/test.ts', acc);
|
||||
|
||||
const entries = acc.getFile('/src/test.ts');
|
||||
expect(entries).toBeDefined();
|
||||
const userEntry = entries!.find(e => e.varName === 'user');
|
||||
expect(userEntry).toBeDefined();
|
||||
expect(userEntry!.typeName).toBe('User');
|
||||
expect(userEntry!.scope).toBe('');
|
||||
});
|
||||
|
||||
it('flushes function-scoped bindings into accumulator', () => {
|
||||
const code = `function process() {\n const result: Response = fetch();\n}`;
|
||||
const tree = parse(code, TypeScript.typescript);
|
||||
const typeEnv = buildTypeEnv(tree, 'typescript');
|
||||
const acc = new BindingAccumulator();
|
||||
|
||||
typeEnv.flush('/src/test.ts', acc);
|
||||
|
||||
const entries = acc.getFile('/src/test.ts');
|
||||
expect(entries).toBeDefined();
|
||||
const resultEntry = entries!.find(e => e.varName === 'result');
|
||||
expect(resultEntry).toBeDefined();
|
||||
expect(resultEntry!.typeName).toBe('Response');
|
||||
expect(resultEntry!.scope).not.toBe('');
|
||||
});
|
||||
|
||||
it('flushes nothing for an empty TypeEnv', () => {
|
||||
const code = `// empty file`;
|
||||
const tree = parse(code, TypeScript.typescript);
|
||||
const typeEnv = buildTypeEnv(tree, 'typescript');
|
||||
const acc = new BindingAccumulator();
|
||||
|
||||
typeEnv.flush('/src/empty.ts', acc);
|
||||
|
||||
expect(acc.getFile('/src/empty.ts')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('multiple files flush into same accumulator', () => {
|
||||
const code1 = `const a: A = makeA();`;
|
||||
const code2 = `const b: B = makeB();`;
|
||||
const tree1 = parse(code1, TypeScript.typescript);
|
||||
const tree2 = parse(code2, TypeScript.typescript);
|
||||
const typeEnv1 = buildTypeEnv(tree1, 'typescript');
|
||||
const typeEnv2 = buildTypeEnv(tree2, 'typescript');
|
||||
const acc = new BindingAccumulator();
|
||||
|
||||
typeEnv1.flush('/src/a.ts', acc);
|
||||
typeEnv2.flush('/src/b.ts', acc);
|
||||
|
||||
expect(acc.fileCount).toBe(2);
|
||||
expect(acc.getFile('/src/a.ts')).toBeDefined();
|
||||
expect(acc.getFile('/src/b.ts')).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue