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 fs from 'fs'; 17import path from 'path'; 18import ts from 'typescript'; 19import { ImportElementEntity } from '../declaration-node/importAndExportDeclaration'; 20 21export interface KitImportInfo { 22 fromPath: string, 23 isExport: string[], 24 isDefaultExport: string 25} 26 27// kit file map 28export const KIT_MAP = new Map<string, KitImportInfo[]>(); 29 30/** 31 * get all kit files 32 * @param kitDir root path 33 */ 34export function collectAllKitFiles(kitDir: string): void { 35 const arr = fs.readdirSync(kitDir); 36 arr.forEach(value => { 37 const fullPath = path.join(kitDir, value); 38 const stats = fs.statSync(fullPath); 39 if (stats.isDirectory()) { 40 collectAllKitFiles(fullPath); 41 } else { 42 let fileBaseName: string; 43 if (value.endsWith('.d.ts')) { 44 fileBaseName = path.basename(value, '.d.ts'); 45 } 46 if (fileBaseName) { 47 handleKitFile(fullPath, fileBaseName); 48 } 49 } 50 }); 51} 52 53/** 54 * kit file convert to ast 55 * @param kitPath kit file path 56 * @param fileName kit file name 57 */ 58function handleKitFile(kitPath: string, fileName: string): void { 59 KIT_MAP.set(fileName, []); 60 61 const code = fs.readFileSync(kitPath); 62 const sourceFile = ts.createSourceFile(kitPath, code.toString(), ts.ScriptTarget.Latest); 63 sourceFile.forEachChild(node => { 64 if (ts.isImportDeclaration(node)) { 65 KIT_MAP.get(fileName).push(getKitImportDeclaration(node)); 66 } 67 }); 68} 69 70/** 71 * get kit file import declaration 72 * @param importNode kit file import node 73 * @returns KitImportInfo 74 */ 75export function getKitImportDeclaration(importNode: ts.ImportDeclaration): KitImportInfo { 76 let isDefaultExport = ''; 77 const isExport = []; 78 const moduleSpecifier = importNode.moduleSpecifier as ts.StringLiteral; 79 const fromPath = moduleSpecifier.text.trim(); 80 const importClause = importNode.importClause; 81 if (importClause !== undefined) { 82 if (importClause.name) { 83 isDefaultExport = importClause.name.text.trim(); 84 } 85 importClause.namedBindings?.forEachChild((node: ts.ImportSpecifier) => { 86 if (node.name) { 87 isExport.push(node.name.text.trim()); 88 } 89 }); 90 } 91 92 return { 93 fromPath, 94 isDefaultExport, 95 isExport 96 }; 97} 98 99/** 100 * handle kit file import map info 101 * @param importEntity import entity data 102 * @returns ImportElementEntity[] 103 */ 104export function handleImportKit(importEntity: ImportElementEntity): ImportElementEntity[] { 105 const importPath = importEntity.importPath.replace(/(\'|\")/g, ''); 106 if (!importPath.startsWith('@kit.')) { 107 return []; 108 } 109 const importEntities: ImportElementEntity[] = []; 110 let importElements: string[]; 111 if (importEntity.importElements.startsWith('{') && importEntity.importElements.endsWith('}')) { 112 importElements = importEntity.importElements 113 .substring(1, importEntity.importElements.length - 1) 114 .split(',') 115 .map(element => element.trim()); 116 } 117 118 const kitImportInfos: KitImportInfo[] = KIT_MAP.get(importPath); 119 if (!kitImportInfos) { 120 throw new Error(`Can't find kitFileInfos from ${importPath}`); 121 } 122 123 importElements.forEach(element => { 124 importEntities.push(getKitImportInfo(kitImportInfos, element, importPath)); 125 }); 126 return importEntities; 127} 128 129/** 130 * get Kit file import map info 131 * @param kitImportInfos map infos 132 * @param element import entity info 133 * @param importPath import file path 134 * @returns ImportElementEntity 135 */ 136function getKitImportInfo(kitImportInfos: KitImportInfo[], element: string, importPath: string): ImportElementEntity { 137 let defaultImport: string; 138 let commonImport: string; 139 const kitImportInfo = kitImportInfos.find(kitInfo => { 140 if (element === kitInfo.isDefaultExport) { 141 defaultImport = kitInfo.isDefaultExport; 142 return true; 143 } else if (kitInfo.isExport.includes(element)) { 144 commonImport = element; 145 return true; 146 } else { 147 return false; 148 } 149 }); 150 151 if (!kitImportInfo) { 152 throw new Error(`Can't find ${element} from ${importPath}`); 153 } 154 155 const defaultImportStr = defaultImport ? `${defaultImport}${commonImport ? ',' : ''}` : ''; 156 const commonImportsStr = commonImport ? `{ ${commonImport} }` : ''; 157 return { 158 importElements: `${defaultImportStr} ${commonImportsStr}`, 159 importPath: kitImportInfo.fromPath 160 }; 161} 162