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 2cc244c408
commit b088216147

View File

@@ -0,0 +1,156 @@
import { createASTUtils } from '../utils/astUtils';
import { typeToString } from '../utils/typeUtils';
import { InterfaceType, InterfaceMember, GenericParameter } from '../types';
import type * as TSESTree from '@typescript-eslint/typescript-estree';
export interface InterfaceParserOptions {
includeInheritedMembers?: boolean;
skipMethods?: boolean;
skipIndexSignatures?: boolean;
}
export class InterfaceParser {
private astUtils: ReturnType<typeof createASTUtils>;
private options: InterfaceParserOptions;
constructor(options: InterfaceParserOptions = {}) {
this.astUtils = createASTUtils();
this.options = {
includeInheritedMembers: options.includeInheritedMembers ?? false,
skipMethods: options.skipMethods ?? false,
skipIndexSignatures: options.skipIndexSignatures ?? false
};
}
parse(source: string, filePath: string): InterfaceType[] {
const ast = this.astUtils.parse(source, filePath);
const interfaces = this.astUtils.getInterfaces(ast);
return interfaces.map((iface) => this.parseInterface(iface));
}
parseInterface(node: any): InterfaceType {
const members = this.parseMembers(node.body.body);
const extendsNames = this.parseExtends(node.extends);
const generics = this.parseGenericParameters(node.typeParameters);
const dependencies = this.extractDependencies(node);
return {
name: node.id.name,
filePath: '',
startLine: node.loc?.start?.line ?? 0,
endLine: node.loc?.end?.line ?? 0,
kind: 'interface',
members,
extends: extendsNames,
generics,
dependencies,
rawNode: node
};
}
private parseMembers(members: any[]): InterfaceMember[] {
return members
.filter((m) => {
if (this.options.skipMethods && (m.type === 'TSMethodSignature')) {
return false;
}
if (this.options.skipIndexSignatures && (m.type === 'TSIndexedAccessType')) {
return false;
}
return m.type === 'TSPropertySignature' || m.type === 'TSMethodSignature';
})
.map((m) => this.parseMember(m));
}
private parseMember(node: any): InterfaceMember {
const key = node.key;
const name = key.type === 'Identifier' ? key.name : typeToString(key);
let type = 'unknown';
if (node.typeAnnotation) {
type = typeToString(node.typeAnnotation.typeAnnotation);
} else if (node.type === 'TSMethodSignature') {
const params = (node as any).params
.map((p: any) => typeToString(p))
.join(', ');
type = `(${params}) => void`;
}
return {
name,
type,
isOptional: node.optional ?? false,
isReadonly: (node as any).readonly ?? false,
modifiers: []
};
}
private parseExtends(extendsClause: any[] | null): string[] {
if (!extendsClause) {
return [];
}
return extendsClause.map((ext) => {
if (ext.expression.type === 'Identifier') {
return ext.expression.name;
}
return typeToString(ext.expression);
});
}
private parseGenericParameters(params: any | null): GenericParameter[] {
if (!params || !params.params) {
return [];
}
return params.params.map((param: TSESTree.TSTypeParameter) => ({
name: param.name.name,
constraint: param.constraint ? typeToString(param.constraint) : undefined,
default: param.default ? typeToString(param.default) : undefined
}));
}
private extractDependencies(node: TSESTree.TSInterfaceDeclaration): string[] {
const dependencies: string[] = [];
if (node.extends) {
for (const ext of node.extends) {
if (ext.expression.type === 'Identifier') {
dependencies.push(ext.expression.name);
}
}
}
const typeRefs = this.astUtils.findNodes<TSESTree.TSTypeReference>(
node,
(n): n is TSESTree.TSTypeReference => n.type === 'TSTypeReference'
);
for (const ref of typeRefs) {
if (ref.typeName.type === 'Identifier') {
const name = ref.typeName.name;
if (!dependencies.includes(name)) {
dependencies.push(name);
}
}
}
return dependencies;
}
getMemberCount(interfaceType: InterfaceType): number {
return interfaceType.members.length;
}
getPropertyCount(interfaceType: InterfaceType): number {
return interfaceType.members.filter((_m) => true).length;
}
hasMethod(interfaceType: InterfaceType, methodName: string): boolean {
return interfaceType.members.some((m) => m.name === methodName);
}
}
export function createInterfaceParser(options?: InterfaceParserOptions): InterfaceParser {
return new InterfaceParser(options);
}