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 rollupObject 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 { 19 COMMONJS, 20 ESM, 21 EXTNAME_PROTO_BIN, 22 EXTNAME_JS, 23 EXTNAME_TS, 24 EXTNAME_ETS, 25 EXTNAME_MJS, 26 EXTNAME_CJS 27} from '../../../../lib/fast_build/ark_compiler/common/ark_define'; 28import { 29 ModuleMode, 30 PackageEntryInfo 31} from '../../../../lib/fast_build/ark_compiler/module/module_mode'; 32import { getNormalizedOhmUrlByFilepath } from '../../../../lib/ark_utils'; 33import { 34 changeFileExtension, 35 compilingEtsOrTsFiles, 36 shouldETSOrTSFileTransformToJS 37} from '../../../../lib/fast_build/ark_compiler/utils'; 38import { toUnixPath } from '../../../../lib/utils'; 39import { META } from '../rollup_mock/common'; 40import { sharedModuleSet } from '../../../../lib/fast_build/ark_compiler/check_shared_module'; 41import { SourceMapGenerator } from '../../../../lib/fast_build/ark_compiler/generate_sourcemap'; 42import { CompileEvent } from '../../../../lib/performance'; 43class ModuleModeMock extends ModuleMode { 44 collectModuleFileListMock(rollupObject: object) { 45 const fileList = Array.from(rollupObject.getModuleIds()); 46 this.collectModuleFileList(rollupObject, fileList); 47 } 48 49 addModuleInfoItemMock(rollupObject: object) { 50 const mockFileList = rollupObject.getModuleIds(); 51 for (const filePath of mockFileList) { 52 if (filePath.endsWith(EXTNAME_TS) || filePath.endsWith(EXTNAME_ETS) || filePath.endsWith(EXTNAME_JS)) { 53 const moduleInfo: object = rollupObject.getModuleInfo(filePath); 54 const metaInfo: object = moduleInfo[META]; 55 compilingEtsOrTsFiles.push(filePath); 56 this.processModuleInfos(filePath, this.moduleInfos, metaInfo); 57 } 58 } 59 } 60 61 addSourceMapMock(rollupObject: object, sourceMapGenerator: SourceMapGenerator) { 62 for (const filePath of rollupObject.getModuleIds()) { 63 64 const isValidSuffix: boolean = 65 filePath.endsWith(EXTNAME_TS) || filePath.endsWith(EXTNAME_ETS) || filePath.endsWith(EXTNAME_JS); 66 if (!isValidSuffix) 67 continue; 68 const moduleInfo: object = rollupObject.getModuleInfo(filePath); 69 const metaInfo: object = moduleInfo[META]; 70 compilingEtsOrTsFiles.push(filePath); 71 if (sourceMapGenerator.isNewSourceMaps()) { 72 sourceMapGenerator.updateSourceMap(filePath, {}); 73 } else { 74 let filePathCache: string = this.genFileCachePath( 75 filePath, this.projectConfig.projectRootPath, this.projectConfig.cachePath); 76 const extName: string = this.getExtName(filePath, metaInfo); 77 if (extName) { 78 filePathCache = changeFileExtension(filePathCache, this.getExtName(filePath, metaInfo)); 79 } 80 sourceMapGenerator.updateSourceMap( 81 filePathCache.replace(this.projectConfig.projectRootPath + path.sep, ''), {}); 82 } 83 } 84 } 85 86 static getModuleInfosAndSourceMapMock(rollupObject: object, sourceMapGenerator: SourceMapGenerator) { 87 const moduleMode = new ModuleModeMock(rollupObject); 88 moduleMode.addSourceMapMock(rollupObject, sourceMapGenerator); 89 moduleMode.addModuleInfoItemMock(rollupObject); 90 return { moduleInfos: moduleMode.moduleInfos, sourceMap: sourceMapGenerator.getSourceMaps() }; 91 } 92 93 getExtName(moduleId: string, metaInfo: object): string { 94 switch (path.extname(moduleId)) { 95 case EXTNAME_ETS: { 96 return shouldETSOrTSFileTransformToJS(moduleId, this.projectConfig, metaInfo) ? EXTNAME_JS : EXTNAME_TS; 97 } 98 case EXTNAME_TS: { 99 return shouldETSOrTSFileTransformToJS(moduleId, this.projectConfig, metaInfo) ? EXTNAME_JS : ''; 100 } 101 case EXTNAME_JS: 102 case EXTNAME_MJS: 103 case EXTNAME_CJS: { 104 return (moduleId.endsWith(EXTNAME_MJS) || moduleId.endsWith(EXTNAME_CJS)) ? EXTNAME_JS : ''; 105 } 106 default: 107 return '' 108 } 109 } 110 111 generateCompileFilesInfoMock(includeByteCodeHarInfo: boolean) { 112 this.generateCompileFilesInfo(includeByteCodeHarInfo); 113 } 114 115 generateNpmEntriesInfoMock() { 116 this.generateNpmEntriesInfo(); 117 } 118 119 generateAbcCacheFilesInfoMock() { 120 this.generateAbcCacheFilesInfo(); 121 } 122 123 generateCompileContextInfoMock(rollupObject: object): void { 124 this.compileContextInfoPath = this.generateCompileContextInfo(rollupObject); 125 } 126 127 checkGenerateCompileContextInfo(rollupObject: object): boolean { 128 const cacheCompileContextInfo = fs.readFileSync(this.compileContextInfoPath, 'utf-8'); 129 130 let compileContextInfo: Object = {}; 131 let hspPkgNames: Array<string> = []; 132 for (const hspName in rollupObject.share.projectConfig.hspNameOhmMap) { 133 let hspPkgName: string = hspName; 134 if (rollupObject.share.projectConfig.dependencyAliasMap.has(hspName)) { 135 hspPkgName = rollupObject.share.projectConfig.dependencyAliasMap.get(hspName); 136 } 137 hspPkgNames.push(toUnixPath(hspPkgName)); 138 } 139 compileContextInfo.hspPkgNames = hspPkgNames; 140 let compileEntries: Set<string> = new Set(); 141 let entryObj: Object = this.projectConfig.entryObj; 142 if (this.projectConfig.widgetCompile) { 143 entryObj = this.projectConfig.cardEntryObj; 144 } 145 for (const key in entryObj) { 146 let moduleId: string = entryObj[key]; 147 let moduleInfo: Object = rollupObject.getModuleInfo(moduleId); 148 if (!moduleInfo) { 149 this.throwArkTsCompilerError(red, `ArkTS:INTERNAL ERROR: Failed to find module info.\n` + 150 `Error Message: Failed to find module info with '${moduleId}' from the context information.`, reset); 151 } 152 let metaInfo: Object = moduleInfo.meta; 153 if (!metaInfo) { 154 this.throwArkTsCompilerError(red, `ArkTS:INTERNAL ERROR: Failed to find meta info.\n` + 155 `Error Message: Failed to find meta info with '${moduleId}' from the module info.`, reset); 156 } 157 const pkgParams = { 158 pkgName: metaInfo.pkgName, 159 pkgPath: metaInfo.pkgPath, 160 isRecordName: true 161 }; 162 let recordName: string = getNormalizedOhmUrlByFilepath(moduleId, rollupObject.share.projectConfig, 163 rollupObject.share.logger, pkgParams, undefined); 164 compileEntries.add(recordName); 165 } 166 this.collectDeclarationFilesEntry(compileEntries, hspPkgNames); 167 compileContextInfo.compileEntries = Array.from(compileEntries); 168 if (rollupObject.share.projectConfig.updateVersionInfo) { 169 compileContextInfo.updateVersionInfo = this.projectConfig.updateVersionInfo; 170 } else if (rollupObject.share.projectConfig.pkgContextInfo) { 171 compileContextInfo.pkgContextInfo = this.projectConfig.pkgContextInfo; 172 } 173 if (this.projectConfig.bundleType === 'shared') { 174 compileContextInfo.needModifyRecord = true; 175 compileContextInfo.bundleName = this.projectConfig.bundleName; 176 } 177 if (JSON.stringify(compileContextInfo) === cacheCompileContextInfo) { 178 return true; 179 } 180 return false; 181 } 182 183 checkGenerateCompileFilesInfo(includeByteCodeHarInfo: boolean): boolean { 184 let mockfilesInfo: string = ''; 185 const filesInfo = fs.readFileSync(this.filesInfoPath, 'utf-8'); 186 this.moduleInfos.forEach((info) => { 187 const moduleType: string = info.isCommonJs ? COMMONJS : ESM; 188 const isSharedModule: boolean = sharedModuleSet.has(info.filePath); 189 mockfilesInfo += 190 `${info.cacheFilePath};${info.recordName};${moduleType};${info.sourceFile};${info.packageName};` + 191 `${isSharedModule};${info.originSourceLang}\n`; 192 }); 193 if (includeByteCodeHarInfo) { 194 Object.entries(this.projectConfig.byteCodeHarInfo).forEach(([pkgName, abcInfo]) => { 195 const abcPath: string = toUnixPath(abcInfo.abcPath); 196 mockfilesInfo += `${abcPath};;;;${pkgName};\n`; 197 }); 198 } 199 if (filesInfo === mockfilesInfo) { 200 return true; 201 } 202 return false; 203 } 204 205 checkGenerateNpmEntriesInfo(): boolean { 206 let mockentriesInfo: string = ''; 207 const filesInfo = fs.readFileSync(this.npmEntriesInfoPath, 'utf-8'); 208 for (const value of this.pkgEntryInfos.values()) { 209 mockentriesInfo += `${value.pkgEntryPath}:${value.pkgBuildPath}\n`; 210 } 211 if (filesInfo === mockentriesInfo) { 212 return true; 213 } 214 return false; 215 } 216 217 checkGenerateAbcCacheFilesInfo(): boolean { 218 let mockabcCacheFilesInfo: string = ''; 219 const filesInfo = fs.readFileSync(this.cacheFilePath, 'utf-8'); 220 this.moduleInfos.forEach((info) => { 221 const abcCacheFilePath: string = changeFileExtension(info.cacheFilePath, EXTNAME_PROTO_BIN); 222 mockabcCacheFilesInfo += `${info.cacheFilePath};${abcCacheFilePath}\n`; 223 }); 224 225 const npmEntriesCacheFilePath: string = changeFileExtension(this.npmEntriesInfoPath, EXTNAME_PROTO_BIN); 226 mockabcCacheFilesInfo += `${this.npmEntriesInfoPath};${npmEntriesCacheFilePath}\n`; 227 this.abcPaths.forEach((abcPath) => { 228 let abcCacheFilePath: string = changeFileExtension(abcPath, EXTNAME_PROTO_BIN); 229 mockabcCacheFilesInfo += `${abcPath};${abcCacheFilePath}\n`; 230 }); 231 if (filesInfo === mockabcCacheFilesInfo) { 232 return true; 233 } 234 return false; 235 } 236 237 checkGetPackageEntryInfo(rollup: object, isTestErrorLog: boolean = false) { 238 this.pkgEntryInfos = new Map<String, PackageEntryInfo>(); 239 const mockFileList = rollup.getModuleIds(); 240 for (const filePath of mockFileList) { 241 if (filePath.endsWith(EXTNAME_TS) || filePath.endsWith(EXTNAME_ETS) || filePath.endsWith(EXTNAME_JS)) { 242 const moduleInfos = rollup.getModuleInfo(filePath); 243 moduleInfos.setIsLocalDependency(false); 244 moduleInfos.setIsNodeEntryFile(true); 245 const metaInfo: object = moduleInfos[META]; 246 if (isTestErrorLog) { 247 metaInfo['pkgPath'] = ''; 248 } 249 this.getPackageEntryInfo(filePath, metaInfo, this.pkgEntryInfos); 250 } 251 } 252 } 253 254 updateCachedSourceMapsMock(sourceMapGenerator: Object) { 255 sourceMapGenerator.updateCachedSourceMaps(); 256 } 257 258 buildModuleSourceMapInfoMock(sourceMapGenerator: Object) { 259 sourceMapGenerator.buildModuleSourceMapInfo(); 260 } 261 262 checkModuleSourceMapInfoMock(): boolean { 263 let readSourceMap: string = ''; 264 if (fs.existsSync(this.sourceMapPath)) { 265 readSourceMap = fs.readFileSync(this.sourceMapPath, 'utf-8'); 266 } 267 let readCacheSourceMap: string = ''; 268 if (fs.existsSync(this.cacheSourceMapPath)) { 269 readCacheSourceMap = fs.readFileSync(this.cacheSourceMapPath, 'utf-8'); 270 } 271 272 if (readSourceMap.length == 0 && readCacheSourceMap.length == 0) { 273 return true; 274 } else { 275 const sourcemapObj: Object = JSON.parse(readSourceMap); 276 const cacheArrayStr: string = '[' + readCacheSourceMap.replace(/\n/g, ',') + ']'; 277 const cacheArray: Array<Object> = JSON.parse(cacheArrayStr); 278 for (const item of cacheArray) { 279 if (!sourcemapObj.hasOwnProperty(item.key)) { 280 return false; 281 } 282 if (JSON.stringify(sourcemapObj[item.key]) != JSON.stringify(item.val)) { 283 return false; 284 } 285 } 286 return true; 287 } 288 } 289 290 generateMergedAbcOfEs2AbcMock(parentEvent: CompileEvent) { 291 this.generateMergedAbcOfEs2Abc(parentEvent) 292 } 293 294 filterModulesByHashJsonMock() { 295 this.filterModulesByHashJson(); 296 } 297 298 invokeTs2AbcWorkersToGenProtoMock(splittedModules: Object) { 299 this.invokeTs2AbcWorkersToGenProto(splittedModules) 300 } 301 302 303} 304 305export default ModuleModeMock;