mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
Replace the 120-line if-chain in resolveLanguageImport() and the 7-branch dispatch in extractNamedBindings() with per-language dispatch tables using `satisfies Record<SupportedLanguages, T>` for compile-time exhaustiveness. Key changes: - New import-resolution.ts: buildImportResolvers factory + namedBindingExtractors table + preprocessImportPath with control character rejection - Extracted loadImportConfigs(), createImportEdgeHelpers(), getLabelFromCaptures() to eliminate duplication across import-processor.ts and parse-worker.ts - Added isCppDuplicateClassFunction and getLabelFromCaptures shared helpers - Migrated ENTRY_POINT_PATTERNS and AST_FRAMEWORK_PATTERNS_BY_LANGUAGE to satisfies Record<SupportedLanguages, T> with compile-time exhaustiveness - Added Kotlin entry-point patterns (Android lifecycle, Ktor, MVVM) - Expanded framework detection: Go (Gin/Echo/Fiber/gRPC), Rust (Actix/Axum/ Rocket/Tokio), C++ (Qt), Swift (UIKit/SwiftUI/Vapor), Ruby (Rails/Sinatra) - Fixed Go cmd/ entry-point detection operator precedence bug - Added EMPTY_INDEX frozen sentinel for type-safe memory cleanup - Unified ImportResolutionContext (suffixIndex->index, removed unused dispose()) - Extracted NamedBinding interface (replaced 16 inline occurrences) - Replaced any with SyntaxNode on all tree-sitter node parameters - Added contributor checklist to SupportedLanguages enum 14 files changed, +318/-550 (net -232 lines). All 3550+ tests pass.
87 lines
2.8 KiB
TypeScript
87 lines
2.8 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { buildImportResolutionContext, type ImportResolutionContext } from '../../src/core/ingestion/import-processor.js';
|
|
import { createResolutionContext } from '../../src/core/ingestion/resolution-context.js';
|
|
|
|
describe('ResolutionContext.importMap', () => {
|
|
it('creates an empty Map', () => {
|
|
const map = createResolutionContext().importMap;
|
|
expect(map).toBeInstanceOf(Map);
|
|
expect(map.size).toBe(0);
|
|
});
|
|
|
|
it('can be used to store import relationships', () => {
|
|
const map = createResolutionContext().importMap;
|
|
map.set('src/index.ts', new Set(['src/utils.ts', 'src/types.ts']));
|
|
expect(map.get('src/index.ts')!.size).toBe(2);
|
|
expect(map.get('src/index.ts')!.has('src/utils.ts')).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('buildImportResolutionContext', () => {
|
|
let ctx: ImportResolutionContext;
|
|
const testPaths = [
|
|
'src/index.ts',
|
|
'src/utils.ts',
|
|
'src/components/Button.tsx',
|
|
'src/lib/helpers.ts',
|
|
];
|
|
|
|
beforeEach(() => {
|
|
ctx = buildImportResolutionContext(testPaths);
|
|
});
|
|
|
|
it('creates a Set of all file paths', () => {
|
|
expect(ctx.allFilePaths).toBeInstanceOf(Set);
|
|
expect(ctx.allFilePaths.size).toBe(4);
|
|
expect(ctx.allFilePaths.has('src/index.ts')).toBe(true);
|
|
});
|
|
|
|
it('stores the original file list', () => {
|
|
expect(ctx.allFileList).toBe(testPaths);
|
|
});
|
|
|
|
it('creates normalized file list with forward slashes', () => {
|
|
const winPaths = ['src\\index.ts', 'src\\utils.ts'];
|
|
const winCtx = buildImportResolutionContext(winPaths);
|
|
expect(winCtx.normalizedFileList[0]).toBe('src/index.ts');
|
|
expect(winCtx.normalizedFileList[1]).toBe('src/utils.ts');
|
|
});
|
|
|
|
it('creates a suffix index for O(1) lookups', () => {
|
|
expect(ctx.index).toBeDefined();
|
|
expect(typeof ctx.index.get).toBe('function');
|
|
});
|
|
|
|
it('initializes empty resolve cache', () => {
|
|
expect(ctx.resolveCache).toBeInstanceOf(Map);
|
|
expect(ctx.resolveCache.size).toBe(0);
|
|
});
|
|
|
|
it('handles empty paths array', () => {
|
|
const emptyCtx = buildImportResolutionContext([]);
|
|
expect(emptyCtx.allFilePaths.size).toBe(0);
|
|
expect(emptyCtx.allFileList).toHaveLength(0);
|
|
});
|
|
|
|
describe('suffix index', () => {
|
|
it('resolves file by suffix', () => {
|
|
const result = ctx.index.get('utils.ts');
|
|
expect(result).toBeDefined();
|
|
});
|
|
|
|
it('resolves file by full path', () => {
|
|
const result = ctx.index.get('src/index.ts');
|
|
expect(result).toBeDefined();
|
|
});
|
|
|
|
it('resolves nested component path', () => {
|
|
const result = ctx.index.get('components/Button.tsx');
|
|
expect(result).toBeDefined();
|
|
});
|
|
|
|
it('returns undefined for non-existent suffix', () => {
|
|
const result = ctx.index.get('nonexistent.ts');
|
|
expect(result).toBeUndefined();
|
|
});
|
|
});
|
|
});
|