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 Logger, { LOG_MODULE_TYPE } from './logger'; 19import { transfer2UnixPath } from './pathTransfer'; 20import { OH_PACKAGE_JSON5 } from '../core/common/EtsConst'; 21import { Language } from '../core/model/ArkFile'; 22 23const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'FileUtils'); 24 25export class FileUtils { 26 public static readonly FILE_FILTER = { 27 ignores: ['.git', '.preview', '.hvigor', '.idea', 'test', 'ohosTest'], 28 include: /(?<!\.d)\.(ets|ts|json5)$/, 29 }; 30 31 public static getIndexFileName(srcPath: string): string { 32 for (const fileInDir of fs.readdirSync(srcPath, { withFileTypes: true })) { 33 if (fileInDir.isFile() && /^index(\.d)?\.e?ts$/i.test(fileInDir.name)) { 34 return fileInDir.name; 35 } 36 } 37 return ''; 38 } 39 40 public static isDirectory(srcPath: string): boolean { 41 try { 42 return fs.statSync(srcPath).isDirectory(); 43 } catch (e) {} 44 return false; 45 } 46 47 public static isAbsolutePath(path: string): boolean { 48 return /^(\/|\\|[A-Z]:\\)/.test(path); 49 } 50 51 public static generateModuleMap(ohPkgContentMap: Map<string, { [k: string]: unknown }>): Map<string, ModulePath> { 52 const moduleMap: Map<string, ModulePath> = new Map(); 53 ohPkgContentMap.forEach((content, filePath) => { 54 const moduleName = content.name as string; 55 if (moduleName && moduleName.startsWith('@')) { 56 const modulePath = path.dirname(filePath); 57 moduleMap.set(moduleName, new ModulePath(modulePath, content.main ? path.resolve(modulePath, content.main as string) : '')); 58 } 59 }); 60 ohPkgContentMap.forEach((content, filePath) => { 61 if (!content.dependencies) { 62 return; 63 } 64 Object.entries(content.dependencies).forEach(([name, value]) => { 65 if (moduleMap.get(name)) { 66 return; 67 } 68 const modulePath = path.resolve(path.dirname(filePath), value.replace('file:', '')); 69 const key = path.resolve(modulePath, OH_PACKAGE_JSON5); 70 const target = ohPkgContentMap.get(key); 71 if (target) { 72 moduleMap.set(name, new ModulePath(modulePath, target.main ? path.resolve(modulePath, target.main as string) : '')); 73 } 74 }); 75 }); 76 return moduleMap; 77 } 78 79 public static getFileLanguage(file: string, fileTags?: Map<string, Language>): Language { 80 if (fileTags && fileTags.has(file)) { 81 return fileTags.get(file) as Language; 82 } 83 const extension = path.extname(file).toLowerCase(); 84 switch (extension) { 85 case '.ts': 86 return Language.TYPESCRIPT; 87 case '.ets': 88 return Language.ARKTS1_1; 89 case '.js': 90 return Language.JAVASCRIPT; 91 default: 92 return Language.UNKNOWN; 93 } 94 } 95} 96 97export class ModulePath { 98 path: string; 99 main: string; 100 101 constructor(path: string, main: string) { 102 this.path = transfer2UnixPath(path); 103 this.main = transfer2UnixPath(main); 104 } 105} 106 107export function getFileRecursively(srcDir: string, fileName: string, visited: Set<string> = new Set<string>()): string { 108 let res = ''; 109 if (!fs.existsSync(srcDir) || !fs.statSync(srcDir).isDirectory()) { 110 logger.warn(`Input directory ${srcDir} is not exist`); 111 return res; 112 } 113 114 const filesUnderThisDir = fs.readdirSync(srcDir, { withFileTypes: true }); 115 const realSrc = fs.realpathSync(srcDir); 116 if (visited.has(realSrc)) { 117 return res; 118 } 119 visited.add(realSrc); 120 121 filesUnderThisDir.forEach(file => { 122 if (res !== '') { 123 return res; 124 } 125 if (file.name === fileName) { 126 res = path.resolve(srcDir, file.name); 127 return res; 128 } 129 const tmpDir = path.resolve(srcDir, '../'); 130 res = getFileRecursively(tmpDir, fileName, visited); 131 return res; 132 }); 133 return res; 134} 135