1/* 2 * Copyright (c) 2024-2025 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 fs from 'fs'; 17import path from 'path'; 18import ts from 'ohos-typescript'; 19import { ArkFile, Language } from '../ArkFile'; 20import { ArkNamespace } from '../ArkNamespace'; 21import Logger, { LOG_MODULE_TYPE } from '../../../utils/logger'; 22import { buildDefaultArkClassFromArkFile, buildNormalArkClassFromArkFile } from './ArkClassBuilder'; 23import { buildArkMethodFromArkClass } from './ArkMethodBuilder'; 24import { buildImportInfo } from './ArkImportBuilder'; 25import { 26 buildExportAssignment, 27 buildExportDeclaration, 28 buildExportInfo, 29 buildExportTypeAliasDeclaration, 30 buildExportVariableStatement, 31 isExported, 32} from './ArkExportBuilder'; 33import { buildArkNamespace, mergeNameSpaces } from './ArkNamespaceBuilder'; 34import { ArkClass } from '../ArkClass'; 35import { ArkMethod } from '../ArkMethod'; 36import { LineColPosition } from '../../base/Position'; 37import { ETS_COMPILER_OPTIONS } from '../../common/EtsConst'; 38import { FileSignature } from '../ArkSignature'; 39import { ARKTS_STATIC_MARK } from '../../common/Const'; 40 41const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'ArkFileBuilder'); 42 43export const notStmtOrExprKind = [ 44 'ModuleDeclaration', 45 'ClassDeclaration', 46 'InterfaceDeclaration', 47 'EnumDeclaration', 48 'ExportDeclaration', 49 'ExportAssignment', 50 'MethodDeclaration', 51 'Constructor', 52 'FunctionDeclaration', 53 'GetAccessor', 54 'SetAccessor', 55 'ArrowFunction', 56 'FunctionExpression', 57 'MethodSignature', 58 'ConstructSignature', 59 'CallSignature', 60]; 61 62/** 63 * Entry of building ArkFile instance 64 * 65 * @param arkFile 66 * @returns 67 */ 68export function buildArkFileFromFile(absoluteFilePath: string, projectDir: string, arkFile: ArkFile, projectName: string): void { 69 arkFile.setFilePath(absoluteFilePath); 70 arkFile.setProjectDir(projectDir); 71 72 const fileSignature = new FileSignature(projectName, path.relative(projectDir, absoluteFilePath)); 73 arkFile.setFileSignature(fileSignature); 74 75 arkFile.setCode(fs.readFileSync(arkFile.getFilePath(), 'utf8')); 76 const sourceFile = ts.createSourceFile(arkFile.getName(), arkFile.getCode(), ts.ScriptTarget.Latest, true, undefined, ETS_COMPILER_OPTIONS); 77 genDefaultArkClass(arkFile, sourceFile); 78 buildArkFile(arkFile, sourceFile); 79} 80 81/** 82 * Building ArkFile instance 83 * 84 * @param arkFile 85 * @param astRoot 86 * @returns 87 */ 88function buildArkFile(arkFile: ArkFile, astRoot: ts.SourceFile): void { 89 const statements = astRoot.statements; 90 const namespaces: ArkNamespace[] = []; 91 statements.forEach(child => { 92 if (ts.isModuleDeclaration(child)) { 93 let ns: ArkNamespace = new ArkNamespace(); 94 ns.setDeclaringArkFile(arkFile); 95 96 buildArkNamespace(child, arkFile, ns, astRoot); 97 namespaces.push(ns); 98 if (ns.isExported()) { 99 arkFile.addExportInfo(buildExportInfo(ns, arkFile, LineColPosition.buildFromNode(child, astRoot))); 100 } 101 } else if (ts.isClassDeclaration(child) || ts.isInterfaceDeclaration(child) || ts.isEnumDeclaration(child) || ts.isStructDeclaration(child)) { 102 let cls: ArkClass = new ArkClass(); 103 104 buildNormalArkClassFromArkFile(child, arkFile, cls, astRoot); 105 arkFile.addArkClass(cls); 106 107 if (cls.isExported()) { 108 arkFile.addExportInfo(buildExportInfo(cls, arkFile, LineColPosition.buildFromNode(child, astRoot))); 109 } 110 } 111 // TODO: Check 112 else if (ts.isMethodDeclaration(child)) { 113 logger.trace('This is a MethodDeclaration in ArkFile.'); 114 let mthd: ArkMethod = new ArkMethod(); 115 116 buildArkMethodFromArkClass(child, arkFile.getDefaultClass(), mthd, astRoot); 117 118 if (mthd.isExported()) { 119 arkFile.addExportInfo(buildExportInfo(mthd, arkFile, LineColPosition.buildFromNode(child, astRoot))); 120 } 121 } else if (ts.isFunctionDeclaration(child)) { 122 let mthd: ArkMethod = new ArkMethod(); 123 124 buildArkMethodFromArkClass(child, arkFile.getDefaultClass(), mthd, astRoot); 125 126 if (mthd.isExported()) { 127 arkFile.addExportInfo(buildExportInfo(mthd, arkFile, LineColPosition.buildFromNode(child, astRoot))); 128 } 129 } else if (ts.isImportEqualsDeclaration(child) || ts.isImportDeclaration(child)) { 130 let importInfos = buildImportInfo(child, astRoot, arkFile); 131 importInfos?.forEach(element => { 132 element.setDeclaringArkFile(arkFile); 133 arkFile.addImportInfo(element); 134 }); 135 } else if (ts.isExportDeclaration(child)) { 136 buildExportDeclaration(child, astRoot, arkFile).forEach(item => arkFile.addExportInfo(item)); 137 } else if (ts.isExportAssignment(child)) { 138 buildExportAssignment(child, astRoot, arkFile).forEach(item => arkFile.addExportInfo(item)); 139 } else if (ts.isVariableStatement(child) && isExported(child.modifiers)) { 140 buildExportVariableStatement(child, astRoot, arkFile).forEach(item => arkFile.addExportInfo(item)); 141 } else if (ts.isTypeAliasDeclaration(child) && isExported(child.modifiers)) { 142 buildExportTypeAliasDeclaration(child, astRoot, arkFile).forEach(item => arkFile.addExportInfo(item)); 143 } else if (ts.isExpressionStatement(child) && ts.isStringLiteral(child.expression)) { 144 child.expression.text.trim() === ARKTS_STATIC_MARK && arkFile.setLanguage(Language.ARKTS1_2); 145 } else { 146 logger.trace('Child joined default method of arkFile: ', ts.SyntaxKind[child.kind]); 147 } 148 }); 149 150 const mergedNameSpaces = mergeNameSpaces(namespaces); 151 mergedNameSpaces.forEach(mergedNameSpace => { 152 arkFile.addNamespace(mergedNameSpace); 153 if (mergedNameSpace.isExport()) { 154 const linCol = new LineColPosition(mergedNameSpace.getLine(), mergedNameSpace.getColumn()); 155 arkFile.addExportInfo(buildExportInfo(mergedNameSpace, arkFile, linCol)); 156 } 157 }); 158} 159 160function genDefaultArkClass(arkFile: ArkFile, astRoot: ts.SourceFile): void { 161 let defaultClass = new ArkClass(); 162 163 buildDefaultArkClassFromArkFile(arkFile, defaultClass, astRoot); 164 arkFile.setDefaultClass(defaultClass); 165 arkFile.addArkClass(defaultClass); 166} 167