Add parser modules
Some checks failed
CI / test (push) Has been cancelled

This commit is contained in:
2026-01-30 00:57:43 +00:00
parent 657442c9a7
commit 2cc244c408

144
src/parsers/importParser.ts Normal file
View File

@@ -0,0 +1,144 @@
import * as path from 'path';
import * as fs from 'fs';
import type * as TSESTree from '@typescript-eslint/typescript-estree';
import { createASTUtils } from '../utils/astUtils';
import { TypeReference } from '../types';
export interface ImportParserOptions {
resolvePaths?: boolean;
basePath?: string;
}
export interface ParsedImport {
moduleName: string;
filePath: string;
defaultImport?: string;
namespaceImport?: string;
namedImports: NamedImport[];
reExports: string[];
isExternal: boolean;
}
export interface NamedImport {
localName: string;
importedName: string;
}
export class ImportParser {
private astUtils: ReturnType<typeof createASTUtils>;
private options: ImportParserOptions;
constructor(options: ImportParserOptions = {}) {
this.astUtils = createASTUtils();
this.options = {
resolvePaths: options.resolvePaths ?? true,
basePath: options.basePath ?? process.cwd()
};
}
parse(source: string, filePath: string): ParsedImport[] {
const ast = this.astUtils.parse(source, filePath);
const imports = this.astUtils.getImports(ast);
return imports.map((imp) => this.parseImportDeclaration(imp, filePath));
}
private parseImportDeclaration(node: TSESTree.ImportDeclaration, filePath: string): ParsedImport {
const moduleName = typeof node.source.value === 'string' ? node.source.value : '';
const isExternal = this.isExternalModule(moduleName);
const namedImports: NamedImport[] = [];
let defaultImport: string | undefined;
let namespaceImport: string | undefined;
if (node.specifiers && node.specifiers.length > 0) {
for (const specifier of node.specifiers) {
if (specifier.type === 'ImportSpecifier') {
namedImports.push({
localName: specifier.local.name,
importedName: specifier.imported.type === 'Identifier' ? specifier.imported.name : specifier.imported.value
});
} else if (specifier.type === 'ImportDefaultSpecifier') {
defaultImport = specifier.local.name;
} else if (specifier.type === 'ImportNamespaceSpecifier') {
namespaceImport = specifier.local.name;
}
}
}
return {
moduleName,
filePath,
defaultImport,
namespaceImport,
namedImports,
reExports: [],
isExternal
};
}
private isExternalModule(moduleName: string): boolean {
return (
moduleName.startsWith('@') ||
!moduleName.startsWith('.') &&
!moduleName.startsWith('/') &&
!moduleName.startsWith('http://') &&
!moduleName.startsWith('https://')
);
}
extractImportedTypes(source: string, filePath: string): TypeReference[] {
const ast = this.astUtils.parse(source, filePath);
const typeRefs = this.astUtils.findNodes<TSESTree.TSTypeReference>(
ast,
(n): n is TSESTree.TSTypeReference => n.type === 'TSTypeReference'
);
return typeRefs.map((ref) => ({
name: ref.typeName.type === 'Identifier' ? ref.typeName.name : '',
module: undefined,
isExternal: false,
location: {
filePath,
startLine: ref.loc?.start?.line ?? 0,
startColumn: ref.loc?.start?.column ?? 0,
endLine: ref.loc?.end?.line ?? 0,
endColumn: ref.loc?.end?.column ?? 0
}
}));
}
resolveImportPath(moduleName: string, fromFile: string): string {
if (this.isExternalModule(moduleName)) {
return moduleName;
}
const baseDir = path.dirname(fromFile);
let resolvedPath = moduleName;
if (!path.extname(resolvedPath)) {
const tsPath = path.join(baseDir, `${resolvedPath}.ts`);
const tsxPath = path.join(baseDir, `${resolvedPath}.tsx`);
const dtsPath = path.join(baseDir, `${resolvedPath}.d.ts`);
const indexPath = path.join(baseDir, resolvedPath, 'index.ts');
if (fs.existsSync(tsPath)) {
resolvedPath = tsPath;
} else if (fs.existsSync(tsxPath)) {
resolvedPath = tsxPath;
} else if (fs.existsSync(dtsPath)) {
resolvedPath = dtsPath;
} else if (fs.existsSync(indexPath)) {
resolvedPath = indexPath;
} else {
resolvedPath = path.join(baseDir, resolvedPath);
}
}
return path.resolve(baseDir, resolvedPath);
}
}
export function createImportParser(options?: ImportParserOptions): ImportParser {
return new ImportParser(options);
}