import * as ts from "typescript"; import * as fs from "fs"; import {BuilderProgram, Declaration, Program, Signature, Symbol, Type, TypeChecker} from "typescript"; import {__approot} from "../config/ApplicationEnvironment"; import {AST_INFO, AST_TYPE, DocEntry} from "../@types/types"; import {logger} from "../logger/Logger"; export default class TSDocumentSimpleParser{ private fileName:string = ""; private sourceFile?:ts.SourceFile; public clazz?:DocEntry[] = []; public static with(file: string) { const p:TSDocumentSimpleParser = new TSDocumentSimpleParser(); p.fileName = file; return p; } public parse():DocEntry[]{ this.sourceFile = this.getSourceAst(this.fileName); this.clazz = this.getClass(); return this.clazz; } public getSourceAst(fileName:string):ts.SourceFile{ const code = fs.readFileSync(fileName).toString(); const sourceFile = ts.createSourceFile('temp.ts', code, ts.ScriptTarget.Latest); return sourceFile; } public getClassEntry(name:string):DocEntry|null { if (this.clazz) { this.clazz.forEach((entry)=>{ if (entry.name == name) { return entry; } }); } return null; } public getClass():DocEntry[] { let entrys: DocEntry[] = []; this.sourceFile?.forEachChild((child) => { if (child.kind === ts.SyntaxKind.ClassDeclaration) { let entry:DocEntry = { name: this.getSafe(child, 'name.escapedText'), type: "class",fileName:this.fileName, "decorators":this.getDecorator(child), "fields":this.getField(child) }; entry.scope = this.getScope(entry); entrys.push(entry); } }); return entrys; } public getScope(entry:DocEntry):string { let scope:string = ""; if (entry && entry.decorators) { entry.decorators.forEach((dec)=>{ if (dec.parameters) { dec.parameters.forEach((param)=>{ if (param.parameterValues) { param.parameterValues.forEach((pval) => { if (pval.type == 'property' && pval.name == "SCOPE" && pval.value != null && scope != "") { scope = pval.value; } }); } }) } }) } if (scope == "") { scope = "singleton"; } return scope; } public getDecorator(child:ts.Node):DocEntry[] { let entrys: DocEntry[] = []; if(child && child.decorators){ (child.decorators as any).forEach((node:any)=>{ let entry = { name: this.getSafe(node, 'expression.expression.escapedText'), type: "decorator", parameters:this.getParameter(node) }; entrys.push(entry); }) } return entrys; } public getField(child:ts.Node):DocEntry[] { let entrys: DocEntry[] = []; let members:ts.Node[] = this.getSafe(child, 'members'); if(child && members){ members.forEach((node)=>{ let entry = { name: this.getSafe(child, 'name.escapedText'), type: "field", "decorators":this.getDecorator(node) }; entrys.push(entry); }) } return entrys; } public getParameter(child:ts.Node):DocEntry[] { let entrys: DocEntry[] = []; let parameters:ts.Node[] = this.getSafe(child, 'expression.arguments'); if(child && parameters){ parameters.forEach((node)=>{ const entry:DocEntry = { name: this.getSafe(node, 'name.escapedText'), type: "parameter", parameterValues:[] }; if (node.kind === ts.SyntaxKind.ObjectLiteralExpression) { const prop:ts.Node[] = this.getSafe(node, 'properties'); if (prop) { entry.parameterValues = this.propertyToEntity(node); } }else if (node.kind === ts.SyntaxKind.ArrayLiteralExpression) { const elements:ts.Node[] = this.getSafe(node, 'elements'); if (elements) { elements.forEach((el)=>{ let entry2:DocEntry = { type: "array", parameterValues: this.propertyToEntity(el) }; entry.parameterValues?.push(entry2); }) } }else{ entry.parameterValues = [{ type: "property", name: "primitive", value: this.getSafe(node, 'text') }]; } entrys.push(entry); }) } return entrys; } private propertyToEntity(child: ts.Node) { let entrys: DocEntry[] = []; const prop:ts.Node[] = this.getSafe(child, 'properties'); if (prop) { entrys = prop.map((node)=>{ let entry2:DocEntry = { type: "property", name: this.getSafe(node, 'name.escapedText'), value: this.getSafe(node, 'initializer.text') }; return entry2; }); } return entrys; } public isDecorator(target:DocEntry, name:string[]):boolean{ if (target && target.decorators) { target.decorators.forEach((entry2)=>{ name.forEach((value)=>{ if (entry2.name == value) { return true; } }) }); } return false; } public getSafe(obj: any, key: string) { try{ return eval(`obj.${key}`); }catch(e){ // logger.debug(`객체로부터 ${key} 를 얻어올 수 없습니다.`); } return null; } }