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 { createSourceFile, ScriptTarget } from 'typescript'; 19import { 20 collectAllFileName, 21 getAllClassDeclaration, 22 dtsFileList, 23 getOhosInterfacesDir, 24 specialFiles, 25 generateKitMap, 26 generateDependJsonFile, 27 generateMyComponent 28} from './common/commonUtils'; 29import { getSourceFileAssembly } from './declaration-node/sourceFileElementsAssemply'; 30import { generateEntry } from './generate/generateEntry'; 31import { generateIndex } from './generate/generateIndex'; 32import { generateSourceFileElements } from './generate/generateMockJsFile'; 33import { generateSystemIndex } from './generate/generateSystemIndex'; 34 35/** 36 * get all api .d.ts file path 37 * @param dir 38 * @returns 39 */ 40function getAllDtsFile(dir: string): Array<string> { 41 const arr = fs.readdirSync(dir); 42 if (!dir.toString().includes('node_modules') && !dir.toString().includes(path.join('@internal', 'component'))) { 43 arr.forEach(value => { 44 const fullPath = path.join(dir, value); 45 const stats = fs.statSync(fullPath); 46 if (stats.isDirectory()) { 47 getAllDtsFile(fullPath); 48 } else { 49 dtsFileList.push(fullPath); 50 } 51 }); 52 } 53 return dtsFileList; 54} 55 56/** 57 * get all component .d.ts file path 58 * @param dir 59 * @returns 60 */ 61function getAllComponentsFilePath(dir: string): Array<string> { 62 const componentPath = path.join(dir, '@internal', 'component', 'ets'); 63 if (!fs.existsSync(componentPath)) { 64 return; 65 } 66 const componentPathArr = fs.readdirSync(componentPath); 67 componentPathArr.forEach(value => { 68 const fullPath = path.join(componentPath, value); 69 if (fs.existsSync(fullPath) && !fs.statSync(fullPath).isDirectory()) { 70 const componentName = `@internal/component/ets/${value}`; 71 if (!specialFiles.includes(componentName)) { 72 specialFiles.push(componentName); 73 } 74 } 75 }); 76} 77/** 78 * delete the old mock file befor generate new mock file 79 * @param outDir 80 */ 81function deleteOldMockJsFile(outDir: string): void { 82 const arr = fs.readdirSync(outDir); 83 arr.forEach(value => { 84 const currPath = path.join(outDir, value); 85 const stas = fs.statSync(currPath); 86 if (stas.isDirectory()) { 87 deleteOldMockJsFile(currPath); 88 } else { 89 fs.unlink(currPath, function (err) { 90 if (err) { 91 console.log(err); 92 } 93 }); 94 } 95 }); 96} 97 98/** 99 * mkdir 100 * @param dirname 101 * @returns 102 */ 103function mkdirsSync(dirname): boolean { 104 if (fs.existsSync(dirname)) { 105 return true; 106 } else { 107 if (mkdirsSync(path.dirname(dirname))) { 108 fs.mkdirSync(dirname); 109 return true; 110 } 111 } 112 return false; 113} 114 115/** 116 * hgandle all ets file mock logic 117 * @param outMockJsFileDir automated mock file output path 118 * @returns 119 */ 120function etsFileToMock(outMockJsFileDir: string): void { 121 let index = 0; 122 while (index < dtsFileList.length) { 123 const value = dtsFileList[index]; 124 index++; 125 126 if (!value.endsWith('.d.ts') && !value.endsWith('.d.ets')) { 127 continue; 128 } 129 130 const code = fs.readFileSync(value); 131 const sourceFile = createSourceFile(value, code.toString(), ScriptTarget.Latest); 132 let fileName: string; 133 if (value.endsWith('.d.ts')) { 134 fileName = path.basename(value, '.d.ts'); 135 } else if (value.endsWith('.d.ets')) { 136 fileName = path.basename(value, '.d.ets'); 137 } else { 138 continue; 139 } 140 let outputFileName = ''; 141 if (fileName.includes('@')) { 142 outputFileName = fileName.split('@')[1].replace(/\./g, '_'); 143 } else { 144 outputFileName = fileName; 145 } 146 147 let tmpOutputMockJsFileDir = outMockJsFileDir; 148 if (!outputFileName.startsWith('system_')) { 149 tmpOutputMockJsFileDir = path.join(outMockJsFileDir, 'napi'); 150 } 151 152 if (value.startsWith(getOhosInterfacesDir()) && !apiInputPath.startsWith(getOhosInterfacesDir())) { 153 tmpOutputMockJsFileDir = path.join(tmpOutputMockJsFileDir, '@ohos'); 154 } 155 156 let dirName = ''; 157 dirName = path.join(tmpOutputMockJsFileDir, path.dirname(value).split(`${path.sep}api`)[1]); 158 if (!fs.existsSync(dirName)) { 159 mkdirsSync(dirName); 160 } 161 const sourceFileEntity = getSourceFileAssembly(sourceFile, fileName); 162 const filePath = path.join(dirName, outputFileName + '.js'); 163 fs.writeFileSync(filePath, ''); 164 fs.appendFileSync(path.join(filePath), generateSourceFileElements('', sourceFileEntity, sourceFile, outputFileName)); 165 } 166} 167 168/** 169 * Project Entry Function 170 * @param apiInputPath interface_sdk-js\api absolute file path 171 * @returns 172 */ 173function main(apiInputPath): void { 174 const dtsDir = apiInputPath; 175 const outMockJsFileDir = path.join(__dirname, '../../runtime/main/extend/systemplugin'); 176 generateKitMap(apiInputPath); 177 getAllDtsFile(dtsDir); 178 getAllComponentsFilePath(dtsDir); 179 dtsFileList.forEach(value => { 180 collectAllFileName(value); 181 if (value.endsWith('.d.ts') || value.endsWith('.d.ets')) { 182 const code = fs.readFileSync(value); 183 const sourceFile = createSourceFile(value, code.toString(), ScriptTarget.Latest); 184 getAllClassDeclaration(sourceFile); 185 } 186 }); 187 188 etsFileToMock(outMockJsFileDir); 189 190 if (!fs.existsSync(path.join(outMockJsFileDir, 'napi'))) { 191 mkdirsSync(path.join(outMockJsFileDir, 'napi')); 192 } 193 generateDependJsonFile(); 194 generateMyComponent(outMockJsFileDir); 195 fs.writeFileSync(path.join(outMockJsFileDir, 'napi', 'index.js'), generateIndex()); 196 fs.writeFileSync(path.join(outMockJsFileDir, 'index.js'), generateSystemIndex()); 197 fs.writeFileSync(path.join(outMockJsFileDir, 'entry.js'), generateEntry()); 198} 199 200const paramIndex = 2; 201const apiInputPath = process.argv[paramIndex]; 202main(apiInputPath); 203