1/* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { 17 isClassDeclaration, isEnumDeclaration, isExportAssignment, isExportDeclaration, isFunctionDeclaration, 18 isImportDeclaration, isInterfaceDeclaration, isModuleDeclaration, isTypeAliasDeclaration, isVariableStatement, 19 SyntaxKind 20} from 'typescript'; 21import type { Node, SourceFile, ClassDeclaration, FunctionDeclaration } from 'typescript'; 22import { getClassDeclaration } from './classDeclaration'; 23import type { ClassEntity } from './classDeclaration'; 24import { getEnumDeclaration } from './enumDeclaration'; 25import type { EnumEntity } from './enumDeclaration'; 26import { getFunctionDeclaration } from './functionDeclaration'; 27import type { FunctionEntity } from './functionDeclaration'; 28import { getExportAssignment, getImportDeclaration } from './importAndExportDeclaration'; 29import type { ImportElementEntity } from './importAndExportDeclaration'; 30import { getInterfaceDeclaration } from './interfaceDeclaration'; 31import type { InterfaceEntity } from './interfaceDeclaration'; 32import type { StaticMethodEntity } from './methodDeclaration'; 33import { getModuleDeclaration } from './moduleDeclaration'; 34import type { ModuleBlockEntity } from './moduleDeclaration'; 35import { getTypeAliasDeclaration } from './typeAliasDeclaration'; 36import type { TypeAliasEntity } from './typeAliasDeclaration'; 37import { getVariableStatementDeclaration } from './variableStatementResolve'; 38import type { StatementEntity } from './variableStatementResolve'; 39 40interface SubstepClassParams { 41 node: ClassDeclaration, 42 sourceFile: SourceFile, 43 classDeclarations: Array<ClassEntity>, 44 staticMethods: Array<Array<StaticMethodEntity>>, 45} 46 47interface SubstepFuntionParams { 48 node: FunctionDeclaration, 49 sourceFile: SourceFile, 50 functionDeclarations: Map<string, Array<FunctionEntity>> 51} 52 53export interface SourceFileEntity { 54 importDeclarations: Array<ImportElementEntity>, 55 moduleDeclarations: Array<ModuleBlockEntity>, 56 typeAliasDeclarations: Array<TypeAliasEntity>, 57 classDeclarations: Array<ClassEntity>, 58 interfaceDeclarations: Array<InterfaceEntity>, 59 enumDeclarations: Array<EnumEntity>, 60 exportAssignment: Array<string>, 61 staticMethods: Array<Array<StaticMethodEntity>>, 62 exportDeclarations: Array<string>, 63 functionDeclarations: Map<string, Array<FunctionEntity>> 64} 65 66/** 67 * assembly all sourceFile node info 68 * @param sourceFile 69 * @param fileName 70 * @returns 71 */ 72export function getSourceFileAssembly(sourceFile: SourceFile, fileName: string): SourceFileEntity { 73 const importDeclarations: Array<ImportElementEntity> = []; 74 const moduleDeclarations: Array<ModuleBlockEntity> = []; 75 const typeAliasDeclarations: Array<TypeAliasEntity> = []; 76 let classDeclarations: Array<ClassEntity> = []; 77 const interfaceDeclarations: Array<InterfaceEntity> = []; 78 const enumDeclarations: Array<EnumEntity> = []; 79 let exportAssignment: Array<string> = []; 80 let staticMethods: Array<Array<StaticMethodEntity>> = []; 81 const exportDeclarations: Array<string> = []; 82 let functionDeclarations: Map<string, Array<FunctionEntity>> = new Map<string, Array<FunctionEntity>>(); 83 sourceFile.forEachChild(node => { 84 if (isImportDeclaration(node)) { 85 importDeclarations.push(getImportDeclaration(node, sourceFile)); 86 } else if (isModuleDeclaration(node)) { 87 moduleDeclarations.push(getModuleDeclaration(node, sourceFile, fileName)); 88 } else if (isTypeAliasDeclaration(node)) { 89 typeAliasDeclarations.push(getTypeAliasDeclaration(node, sourceFile)); 90 } else if (isClassDeclaration(node)) { 91 const substepClassBack = substepClass({ node, sourceFile, classDeclarations, staticMethods }); 92 classDeclarations = substepClassBack.classDeclarations; 93 staticMethods = substepClassBack.staticMethods; 94 } else if (isInterfaceDeclaration(node)) { 95 interfaceDeclarations.push(getInterfaceDeclaration(node, sourceFile)); 96 } else if (isExportAssignment(node)) { 97 exportAssignment = getExportAssignment(node, sourceFile); 98 } else if (isEnumDeclaration(node)) { 99 enumDeclarations.push(getEnumDeclaration(node, sourceFile)); 100 } else if (isExportDeclaration(node)) { 101 exportDeclarations.push(sourceFile.text.substring(node.pos, node.end).trimStart().trimEnd()); 102 } else if (isFunctionDeclaration(node)) { 103 const classParams = substepFunction({ node, sourceFile, functionDeclarations }); 104 functionDeclarations = classParams.functionDeclarations; 105 } else { 106 substepConsole(node, fileName); 107 } 108 }); 109 return { 110 importDeclarations, 111 moduleDeclarations, 112 typeAliasDeclarations, 113 classDeclarations, 114 interfaceDeclarations, 115 enumDeclarations, 116 exportAssignment, 117 staticMethods, 118 exportDeclarations, 119 functionDeclarations 120 }; 121} 122 123/** 124 * get default export class 125 * @param sourceFile 126 * @returns 127 */ 128export function getDefaultExportClassDeclaration(sourceFile: SourceFile): Array<ClassEntity> { 129 const defaultExportClass: Array<ClassEntity> = []; 130 sourceFile.forEachChild(node => { 131 if (isClassDeclaration(node)) { 132 defaultExportClass.push(getClassDeclaration(node, sourceFile)); 133 } 134 }); 135 return defaultExportClass; 136} 137 138/** 139 * get sourceFile const variable statement 140 * @param sourceFile 141 * @returns 142 */ 143export function getSourceFileVariableStatements(sourceFile: SourceFile): Array<Array<StatementEntity>> { 144 const variableStatements: Array<Array<StatementEntity>> = []; 145 sourceFile.forEachChild(node => { 146 if (isVariableStatement(node)) { 147 variableStatements.push(getVariableStatementDeclaration(node, sourceFile)); 148 } 149 }); 150 return variableStatements; 151} 152 153/** 154 * get sourcefile functions 155 * @param sourceFile 156 * @returns 157 */ 158export function getSourceFileFunctions(sourceFile: SourceFile): Map<string, Array<FunctionEntity>> { 159 const functionDeclarations: Map<string, Array<FunctionEntity>> = new Map<string, Array<FunctionEntity>>(); 160 sourceFile.forEachChild(node => { 161 if (isFunctionDeclaration(node)) { 162 const functionEntity = getFunctionDeclaration(node, sourceFile); 163 if (functionDeclarations.get(functionEntity.functionName) !== undefined) { 164 functionDeclarations.get(functionEntity.functionName)?.push(functionEntity); 165 } else { 166 const functionArray: Array<FunctionEntity> = []; 167 functionArray.push(functionEntity); 168 functionDeclarations.set(functionEntity.functionName, functionArray); 169 } 170 } 171 }); 172 return functionDeclarations; 173} 174 175/** 176 * assembly some sourceFile node info 177 * @param substepClassParams 178 * @returns 179 */ 180function substepClass(substepClassParams: SubstepClassParams): SubstepClassParams { 181 let isDefaultExportClass = false; 182 if (substepClassParams.node.modifiers !== undefined) { 183 substepClassParams.node.modifiers.forEach(value => { 184 if (value.kind === SyntaxKind.DefaultKeyword) { 185 isDefaultExportClass = true; 186 } 187 }); 188 } 189 if (isDefaultExportClass) { 190 const classDeclarationEntity = getClassDeclaration(substepClassParams.node, substepClassParams.sourceFile); 191 substepClassParams.classDeclarations.push(classDeclarationEntity); 192 if (classDeclarationEntity.staticMethods.length > 0) { 193 substepClassParams.staticMethods.push(classDeclarationEntity.staticMethods); 194 } 195 } 196 return substepClassParams; 197} 198 199/** 200 * assembly some sourceFile node info 201 * @param substepClassParams 202 * @returns 203 */ 204function substepFunction(substepClassParams: SubstepFuntionParams): SubstepFuntionParams { 205 const functionEntity = getFunctionDeclaration(substepClassParams.node, substepClassParams.sourceFile); 206 if (substepClassParams.functionDeclarations.get(functionEntity.functionName) !== undefined) { 207 substepClassParams.functionDeclarations.get(functionEntity.functionName)?.push(functionEntity); 208 } else { 209 const functionArray: Array<FunctionEntity> = []; 210 functionArray.push(functionEntity); 211 substepClassParams.functionDeclarations.set(functionEntity.functionName, functionArray); 212 } 213 return substepClassParams; 214} 215 216/** 217 * assembly some sourceFile node info 218 * @param substepClassParams 219 * @returns 220 */ 221function substepConsole(node: Node, fileName: string):void { 222 if (node.kind !== SyntaxKind.EndOfFileToken && !isFunctionDeclaration(node) && !isVariableStatement(node)) { 223 console.log('--------------------------- uncaught sourceFile type start -----------------------'); 224 console.log('fileName: ' + fileName); 225 console.log(node); 226 console.log('--------------------------- uncaught sourceFile type end -----------------------'); 227 } 228 return; 229} 230