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, 18 isEnumDeclaration, 19 isExportAssignment, 20 isExportDeclaration, 21 isFunctionDeclaration, 22 isImportDeclaration, 23 isInterfaceDeclaration, 24 isModuleDeclaration, 25 isTypeAliasDeclaration, 26 isVariableStatement, 27 SyntaxKind 28} from 'typescript'; 29import type { Node, SourceFile, ClassDeclaration, FunctionDeclaration } from 'typescript'; 30import { getClassDeclaration } from './classDeclaration'; 31import type { ClassEntity } from './classDeclaration'; 32import { getEnumDeclaration } from './enumDeclaration'; 33import type { EnumEntity } from './enumDeclaration'; 34import { getFunctionDeclaration } from './functionDeclaration'; 35import type { FunctionEntity } from './functionDeclaration'; 36import { getExportAssignment, getImportDeclaration } from './importAndExportDeclaration'; 37import type { ImportElementEntity } from './importAndExportDeclaration'; 38import { getInterfaceDeclaration } from './interfaceDeclaration'; 39import type { InterfaceEntity } from './interfaceDeclaration'; 40import type { StaticMethodEntity } from './methodDeclaration'; 41import { getModuleDeclaration } from './moduleDeclaration'; 42import type { ModuleBlockEntity } from './moduleDeclaration'; 43import { getTypeAliasDeclaration } from './typeAliasDeclaration'; 44import type { TypeAliasEntity } from './typeAliasDeclaration'; 45import { getVariableStatementDeclaration } from './variableStatementResolve'; 46import type { StatementEntity } from './variableStatementResolve'; 47 48interface SubstepClassParams { 49 node: ClassDeclaration; 50 sourceFile: SourceFile; 51 classDeclarations: Array<ClassEntity>; 52 staticMethods: Array<Array<StaticMethodEntity>>; 53} 54 55interface SubstepFuntionParams { 56 node: FunctionDeclaration; 57 sourceFile: SourceFile; 58 functionDeclarations: Map<string, Array<FunctionEntity>>; 59} 60 61export interface SourceFileEntity { 62 importDeclarations: Array<ImportElementEntity>; 63 moduleDeclarations: Array<ModuleBlockEntity>; 64 typeAliasDeclarations: Array<TypeAliasEntity>; 65 classDeclarations: Array<ClassEntity>; 66 interfaceDeclarations: Array<InterfaceEntity>; 67 enumDeclarations: Array<EnumEntity>; 68 exportAssignment: Array<string>; 69 staticMethods: Array<Array<StaticMethodEntity>>; 70 exportDeclarations: Array<string>; 71 functionDeclarations: Map<string, Array<FunctionEntity>>; 72} 73 74/** 75 * assembly all sourceFile node info 76 * @param sourceFile 77 * @param fileName 78 * @returns 79 */ 80export function getSourceFileAssembly(sourceFile: SourceFile, fileName: string): SourceFileEntity { 81 const importDeclarations: Array<ImportElementEntity> = []; 82 const moduleDeclarations: Array<ModuleBlockEntity> = []; 83 const typeAliasDeclarations: Array<TypeAliasEntity> = []; 84 let classDeclarations: Array<ClassEntity> = []; 85 const interfaceDeclarations: Array<InterfaceEntity> = []; 86 const enumDeclarations: Array<EnumEntity> = []; 87 let exportAssignment: Array<string> = []; 88 let staticMethods: Array<Array<StaticMethodEntity>> = []; 89 const exportDeclarations: Array<string> = []; 90 let functionDeclarations: Map<string, Array<FunctionEntity>> = new Map<string, Array<FunctionEntity>>(); 91 sourceFile.forEachChild(node => { 92 if (isImportDeclaration(node)) { 93 importDeclarations.push(getImportDeclaration(node, sourceFile)); 94 } else if (isModuleDeclaration(node)) { 95 moduleDeclarations.push(getModuleDeclaration(node, sourceFile, fileName)); 96 } else if (isTypeAliasDeclaration(node)) { 97 typeAliasDeclarations.push(getTypeAliasDeclaration(node, sourceFile)); 98 } else if (isClassDeclaration(node)) { 99 const substepClassBack = substepClass({ node, sourceFile, classDeclarations, staticMethods }); 100 classDeclarations = substepClassBack.classDeclarations; 101 staticMethods = substepClassBack.staticMethods; 102 } else if (isInterfaceDeclaration(node)) { 103 interfaceDeclarations.push(getInterfaceDeclaration(node, sourceFile)); 104 } else if (isExportAssignment(node)) { 105 exportAssignment = getExportAssignment(node, sourceFile); 106 } else if (isEnumDeclaration(node)) { 107 enumDeclarations.push(getEnumDeclaration(node, sourceFile)); 108 } else if (isExportDeclaration(node)) { 109 exportDeclarations.push(sourceFile.text.substring(node.pos, node.end).trim()); 110 } else if (isFunctionDeclaration(node)) { 111 const classParams = substepFunction({ node, sourceFile, functionDeclarations }); 112 functionDeclarations = classParams.functionDeclarations; 113 } else { 114 substepConsole(node, fileName); 115 } 116 }); 117 return { 118 importDeclarations, 119 moduleDeclarations, 120 typeAliasDeclarations, 121 classDeclarations, 122 interfaceDeclarations, 123 enumDeclarations, 124 exportAssignment, 125 staticMethods, 126 exportDeclarations, 127 functionDeclarations 128 }; 129} 130 131/** 132 * get default export class 133 * @param sourceFile 134 * @returns 135 */ 136export function getDefaultExportClassDeclaration(sourceFile: SourceFile): Array<ClassEntity> { 137 const defaultExportClass: Array<ClassEntity> = []; 138 sourceFile.forEachChild(node => { 139 if (isClassDeclaration(node)) { 140 defaultExportClass.push(getClassDeclaration(node, sourceFile)); 141 } 142 }); 143 return defaultExportClass; 144} 145 146/** 147 * get sourceFile const variable statement 148 * @param sourceFile 149 * @returns 150 */ 151export function getSourceFileVariableStatements(sourceFile: SourceFile): Array<Array<StatementEntity>> { 152 const variableStatements: Array<Array<StatementEntity>> = []; 153 sourceFile.forEachChild(node => { 154 if (isVariableStatement(node)) { 155 variableStatements.push(getVariableStatementDeclaration(node, sourceFile)); 156 } 157 }); 158 return variableStatements; 159} 160 161/** 162 * get sourcefile functions 163 * @param sourceFile 164 * @returns 165 */ 166export function getSourceFileFunctions(sourceFile: SourceFile): Map<string, Array<FunctionEntity>> { 167 const functionDeclarations: Map<string, Array<FunctionEntity>> = new Map<string, Array<FunctionEntity>>(); 168 sourceFile.forEachChild(node => { 169 if (isFunctionDeclaration(node)) { 170 const functionEntity = getFunctionDeclaration(node, sourceFile); 171 if (functionDeclarations.get(functionEntity.functionName) !== undefined) { 172 functionDeclarations.get(functionEntity.functionName)?.push(functionEntity); 173 } else { 174 const functionArray: Array<FunctionEntity> = []; 175 functionArray.push(functionEntity); 176 functionDeclarations.set(functionEntity.functionName, functionArray); 177 } 178 } 179 }); 180 return functionDeclarations; 181} 182 183/** 184 * assembly some sourceFile node info 185 * @param substepClassParams 186 * @returns 187 */ 188function substepClass(substepClassParams: SubstepClassParams): SubstepClassParams { 189 let isDefaultExportClass = false; 190 if (substepClassParams.node.modifiers !== undefined) { 191 substepClassParams.node.modifiers.forEach(value => { 192 if (value.kind === SyntaxKind.DefaultKeyword) { 193 isDefaultExportClass = true; 194 } 195 }); 196 } 197 if (isDefaultExportClass) { 198 const classDeclarationEntity = getClassDeclaration(substepClassParams.node, substepClassParams.sourceFile); 199 substepClassParams.classDeclarations.push(classDeclarationEntity); 200 if (classDeclarationEntity.staticMethods.length > 0) { 201 substepClassParams.staticMethods.push(classDeclarationEntity.staticMethods); 202 } 203 } 204 return substepClassParams; 205} 206 207/** 208 * assembly some sourceFile node info 209 * @param substepClassParams 210 * @returns 211 */ 212function substepFunction(substepClassParams: SubstepFuntionParams): SubstepFuntionParams { 213 const functionEntity = getFunctionDeclaration(substepClassParams.node, substepClassParams.sourceFile); 214 if (substepClassParams.functionDeclarations.get(functionEntity.functionName) !== undefined) { 215 substepClassParams.functionDeclarations.get(functionEntity.functionName)?.push(functionEntity); 216 } else { 217 const functionArray: Array<FunctionEntity> = []; 218 functionArray.push(functionEntity); 219 substepClassParams.functionDeclarations.set(functionEntity.functionName, functionArray); 220 } 221 return substepClassParams; 222} 223 224/** 225 * assembly some sourceFile node info 226 * @param substepClassParams 227 * @returns 228 */ 229function substepConsole(node: Node, fileName: string): void { 230 if (node.kind !== SyntaxKind.EndOfFileToken && !isFunctionDeclaration(node) && !isVariableStatement(node)) { 231 console.log('--------------------------- uncaught sourceFile type start -----------------------'); 232 console.log('fileName: ' + fileName); 233 console.log(node); 234 console.log('--------------------------- uncaught sourceFile type end -----------------------'); 235 } 236} 237