This commit is contained in:
144
src/parsers/typeAliasParser.ts
Normal file
144
src/parsers/typeAliasParser.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { createASTUtils } from '../utils/astUtils';
|
||||
import { typeToString } from '../utils/typeUtils';
|
||||
import { TypeAlias, GenericParameter } from '../types';
|
||||
|
||||
export interface TypeAliasParserOptions {
|
||||
expandUnions?: boolean;
|
||||
expandIntersections?: boolean;
|
||||
inlineObjects?: boolean;
|
||||
}
|
||||
|
||||
export class TypeAliasParser {
|
||||
private astUtils: ReturnType<typeof createASTUtils>;
|
||||
private options: TypeAliasParserOptions;
|
||||
|
||||
constructor(options: TypeAliasParserOptions = {}) {
|
||||
this.astUtils = createASTUtils();
|
||||
this.options = {
|
||||
expandUnions: options.expandUnions ?? false,
|
||||
expandIntersections: options.expandIntersections ?? false,
|
||||
inlineObjects: options.inlineObjects ?? true
|
||||
};
|
||||
}
|
||||
|
||||
parse(source: string, filePath: string): TypeAlias[] {
|
||||
const ast = this.astUtils.parse(source, filePath);
|
||||
const typeAliases = this.astUtils.getTypeAliases(ast);
|
||||
|
||||
return typeAliases.map((typeAlias) => this.parseTypeAlias(typeAlias));
|
||||
}
|
||||
|
||||
parseTypeAlias(node: any): TypeAlias {
|
||||
const typeAnnotation = typeToString(node.typeAnnotation);
|
||||
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: 'type_alias',
|
||||
dependencies,
|
||||
typeAnnotation,
|
||||
extends: [],
|
||||
generics,
|
||||
rawNode: node
|
||||
};
|
||||
}
|
||||
|
||||
private parseGenericParameters(params: any | null): GenericParameter[] {
|
||||
if (!params || !params.params) {
|
||||
return [];
|
||||
}
|
||||
return params.params.map((param: any) => ({
|
||||
name: param.name.name,
|
||||
constraint: param.constraint ? typeToString(param.constraint) : undefined,
|
||||
default: param.default ? typeToString(param.default) : undefined
|
||||
}));
|
||||
}
|
||||
|
||||
private extractDependencies(node: any): string[] {
|
||||
const dependencies: string[] = [];
|
||||
|
||||
const typeRefs = this.astUtils.findNodes<any>(
|
||||
node,
|
||||
(n): n is any => 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unions = this.astUtils.findNodes<any>(
|
||||
node,
|
||||
(n): n is any => n.type === 'TSUnionType'
|
||||
);
|
||||
|
||||
for (const union of unions) {
|
||||
for (const type of union.types) {
|
||||
if (type.type === 'TSTypeReference' && type.typeName.type === 'Identifier') {
|
||||
const name = type.typeName.name;
|
||||
if (!dependencies.includes(name)) {
|
||||
dependencies.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const intersections = this.astUtils.findNodes<any>(
|
||||
node,
|
||||
(n): n is any => n.type === 'TSIntersectionType'
|
||||
);
|
||||
|
||||
for (const intersection of intersections) {
|
||||
for (const type of intersection.types) {
|
||||
if (type.type === 'TSTypeReference' && type.typeName.type === 'Identifier') {
|
||||
const name = type.typeName.name;
|
||||
if (!dependencies.includes(name)) {
|
||||
dependencies.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
getComplexityScore(typeAlias: TypeAlias): number {
|
||||
let score = 1;
|
||||
const typeStr = typeAlias.typeAnnotation;
|
||||
|
||||
score += (typeStr.match(/\|/g) || []).length * 2;
|
||||
score += (typeStr.match(/&/g) || []).length * 2;
|
||||
score += (typeStr.match(/{/g) || []).length;
|
||||
score += (typeStr.match(/</g) || []).length * 3;
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
isUnionType(typeAlias: TypeAlias): boolean {
|
||||
return typeAlias.typeAnnotation.includes('|');
|
||||
}
|
||||
|
||||
isIntersectionType(typeAlias: TypeAlias): boolean {
|
||||
return typeAlias.typeAnnotation.includes('&');
|
||||
}
|
||||
|
||||
isGenericType(typeAlias: TypeAlias): boolean {
|
||||
return typeAlias.generics.length > 0;
|
||||
}
|
||||
|
||||
getReferencedTypes(typeAlias: TypeAlias): string[] {
|
||||
return typeAlias.dependencies;
|
||||
}
|
||||
}
|
||||
|
||||
export function createTypeAliasParser(options?: TypeAliasParserOptions): TypeAliasParser {
|
||||
return new TypeAliasParser(options);
|
||||
}
|
||||
Reference in New Issue
Block a user