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 path from 'path'; 17import fs from 'fs'; 18import type sourceMap from 'source-map'; 19 20import { minify, MinifyOutput } from 'terser'; 21import { ArkObfuscator, getMapFromJson } from "arkguard" 22 23import { OH_MODULES } from './fast_build/ark_compiler/common/ark_define'; 24import { 25 PACKAGES, 26 TEMPORARY, 27 ZERO, 28 ONE, 29 EXTNAME_JS, 30 EXTNAME_TS, 31 EXTNAME_MJS, 32 EXTNAME_CJS, 33 EXTNAME_ABC, 34 EXTNAME_ETS, 35 EXTNAME_TS_MAP, 36 EXTNAME_JS_MAP, 37 ESMODULE, 38 FAIL, 39 TS2ABC, 40 ES2ABC, 41 EXTNAME_PROTO_BIN, 42 NATIVE_MODULE 43} from './pre_define'; 44import { 45 isMac, 46 isWindows, 47 isPackageModulesFile, 48 genTemporaryPath, 49 getExtensionIfUnfullySpecifiedFilepath, 50 mkdirsSync, 51 toUnixPath, 52 validateFilePathLength 53} from './utils'; 54import { 55 extendSdkConfigs, 56 projectConfig, 57 sdkConfigPrefix 58} from '../main'; 59import config from '../rollup.config'; 60import { MergedConfig } from './fast_build/ark_compiler/common/ob_config_resolver'; 61const red: string = '\u001b[31m'; 62const reset: string = '\u001b[39m'; 63 64export const SRC_MAIN: string = 'src/main'; 65 66export var newSourceMaps: Object = {}; 67export var identifierCaches: Object = {}; 68export const packageCollection: Map<string, Array<string>> = new Map(); 69 70export function getOhmUrlByFilepath(filePath: string, projectConfig: any, logger: any, namespace?: string): string { 71 // remove '\x00' from the rollup virtual commonjs file's filePath 72 if (filePath.startsWith('\x00')) { 73 filePath = filePath.replace('\x00', ''); 74 } 75 let unixFilePath: string = toUnixPath(filePath); 76 unixFilePath = unixFilePath.substring(0, filePath.lastIndexOf('.')); // remove extension 77 const REG_PROJECT_SRC: RegExp = /(\S+)\/src\/(?:main|ohosTest)\/(ets|js)\/(\S+)/; 78 79 const packageInfo: string[] = getPackageInfo(projectConfig.aceModuleJsonPath); 80 const bundleName: string = packageInfo[0]; 81 const moduleName: string = packageInfo[1]; 82 const moduleRootPath: string = toUnixPath(projectConfig.modulePathMap[moduleName]); 83 const projectRootPath: string = toUnixPath(projectConfig.projectRootPath); 84 // case1: /entry/src/main/ets/xxx/yyy ---> @bundle:<bundleName>/entry/ets/xxx/yyy 85 // case2: /entry/src/ohosTest/ets/xxx/yyy ---> @bundle:<bundleName>/entry_test@entry/ets/xxx/yyy 86 // case3: /node_modules/xxx/yyy ---> @package:pkg_modules/xxx/yyy 87 // case4: /entry/node_modules/xxx/yyy ---> @package:pkg_modules@entry/xxx/yyy 88 // case5: /library/node_modules/xxx/yyy ---> @package:pkg_modules@library/xxx/yyy 89 // case6: /library/index.ts ---> @bundle:<bundleName>/library/index 90 const projectFilePath: string = unixFilePath.replace(projectRootPath, ''); 91 const packageDir: string = projectConfig.packageDir; 92 const result: RegExpMatchArray | null = projectFilePath.match(REG_PROJECT_SRC); 93 if (result && result[1].indexOf(packageDir) === -1) { 94 let langType: string = result[2]; 95 let relativePath: string = result[3]; 96 // case7: /entry/src/main/ets/xxx/src/main/js/yyy ---> @bundle:<bundleName>/entry/ets/xxx/src/main/js/yyy 97 const REG_SRC_MAIN: RegExp = /src\/(?:main|ohosTest)\/(ets|js)\//; 98 const srcMainIndex: number = result[1].search(REG_SRC_MAIN); 99 if (srcMainIndex !== -1) { 100 relativePath = projectFilePath.substring(srcMainIndex).replace(REG_SRC_MAIN, ''); 101 langType = projectFilePath.replace(relativePath, '').match(REG_SRC_MAIN)[1]; 102 } 103 if (namespace && moduleName !== namespace) { 104 return `${bundleName}/${moduleName}@${namespace}/${langType}/${relativePath}`; 105 } 106 return `${bundleName}/${moduleName}/${langType}/${relativePath}`; 107 } 108 109 if (projectFilePath.indexOf(packageDir) !== -1) { 110 if (process.env.compileTool === 'rollup') { 111 const tryProjectPkg: string = toUnixPath(path.join(projectRootPath, packageDir)); 112 if (unixFilePath.indexOf(tryProjectPkg) !== -1) { 113 return unixFilePath.replace(tryProjectPkg, `${packageDir}`).replace(new RegExp(packageDir, 'g'), PACKAGES); 114 } 115 // iterate the modulePathMap to find the moudleName which contains the pkg_module's file 116 for (const moduleName in projectConfig.modulePathMap) { 117 const modulePath: string = projectConfig.modulePathMap[moduleName]; 118 const tryModulePkg: string = toUnixPath(path.resolve(modulePath, packageDir)); 119 if (unixFilePath.indexOf(tryModulePkg) !== -1) { 120 return unixFilePath.replace(tryModulePkg, `${packageDir}@${moduleName}`).replace( 121 new RegExp(packageDir, 'g'), PACKAGES); 122 } 123 } 124 125 logger.error(red, `ArkTS:ERROR Failed to get an resolved OhmUrl by filepath "${filePath}"`, reset); 126 return filePath; 127 } 128 129 // webpack with old implematation 130 const tryProjectPkg: string = toUnixPath(path.join(projectRootPath, packageDir)); 131 if (unixFilePath.indexOf(tryProjectPkg) !== -1) { 132 return unixFilePath.replace(tryProjectPkg, `${packageDir}/${ONE}`).replace(new RegExp(packageDir, 'g'), PACKAGES); 133 } 134 135 const tryModulePkg: string = toUnixPath(path.join(moduleRootPath, packageDir)); 136 if (unixFilePath.indexOf(tryModulePkg) !== -1) { 137 return unixFilePath.replace(tryModulePkg, `${packageDir}/${ZERO}`).replace(new RegExp(packageDir, 'g'), PACKAGES); 138 } 139 } 140 141 for (const key in projectConfig.modulePathMap) { 142 const moduleRootPath: string = toUnixPath(projectConfig.modulePathMap[key]); 143 if (unixFilePath.indexOf(moduleRootPath + '/') !== -1) { 144 const relativeModulePath: string = unixFilePath.replace(moduleRootPath + '/', ''); 145 if (namespace && moduleName !== namespace) { 146 return `${bundleName}/${moduleName}@${namespace}/${relativeModulePath}`; 147 } 148 return `${bundleName}/${moduleName}/${relativeModulePath}`; 149 } 150 } 151 152 logger.error(red, `ArkTS:ERROR Failed to get an resolved OhmUrl by filepath "${filePath}"`, reset); 153 return filePath; 154} 155 156export function getOhmUrlBySystemApiOrLibRequest(moduleRequest: string) : string 157{ 158 // 'arkui-x' represents cross platform related APIs, processed as 'ohos' 159 const REG_SYSTEM_MODULE: RegExp = new RegExp(`@(${sdkConfigPrefix})\\.(\\S+)`); 160 const REG_LIB_SO: RegExp = /lib(\S+)\.so/; 161 162 if (REG_SYSTEM_MODULE.test(moduleRequest.trim())) { 163 return moduleRequest.replace(REG_SYSTEM_MODULE, (_, moduleType, systemKey) => { 164 const systemModule: string = `${moduleType}.${systemKey}`; 165 if (extendSdkConfigs) { 166 for (let config of extendSdkConfigs.values()) { 167 if (config.prefix == '@arkui-x') { 168 continue; 169 } 170 if (moduleRequest.startsWith(config.prefix + '.')) { 171 return `${config.prefix}:${systemKey}`; 172 } 173 } 174 } 175 if (NATIVE_MODULE.has(systemModule)) { 176 return `@native:${systemModule}`; 177 } else { 178 return `@ohos:${systemKey}`; 179 }; 180 }); 181 } 182 if (REG_LIB_SO.test(moduleRequest.trim())) { 183 return moduleRequest.replace(REG_LIB_SO, (_, libsoKey) => { 184 return `@app:${projectConfig.bundleName}/${projectConfig.moduleName}/${libsoKey}`; 185 }); 186 } 187 188 return undefined; 189} 190 191export function genSourceMapFileName(temporaryFile: string): string { 192 let abcFile: string = temporaryFile; 193 if (temporaryFile.endsWith(EXTNAME_TS)) { 194 abcFile = temporaryFile.replace(/\.ts$/, EXTNAME_TS_MAP); 195 } else { 196 abcFile = temporaryFile.replace(/\.js$/, EXTNAME_JS_MAP); 197 } 198 return abcFile; 199} 200 201export function getBuildModeInLowerCase(projectConfig: any): string { 202 return (process.env.compileTool === 'rollup' ? projectConfig.buildMode : projectConfig.buildArkMode).toLowerCase(); 203} 204 205export function writeFileSyncByString(sourcePath: string, sourceCode: string, projectConfig: any, logger: any): void { 206 const filePath: string = genTemporaryPath(sourcePath, projectConfig.projectPath, process.env.cachePath, projectConfig); 207 if (filePath.length === 0) { 208 return; 209 } 210 mkdirsSync(path.dirname(filePath)); 211 if (/\.js$/.test(sourcePath)) { 212 sourceCode = transformModuleSpecifier(sourcePath, sourceCode, projectConfig); 213 if (projectConfig.buildArkMode === 'debug') { 214 fs.writeFileSync(filePath, sourceCode); 215 return; 216 } 217 writeObfuscatedSourceCode(sourceCode, filePath, logger, projectConfig); 218 } 219 if (/\.json$/.test(sourcePath)) { 220 fs.writeFileSync(filePath, sourceCode); 221 } 222} 223 224export function transformModuleSpecifier(sourcePath: string, sourceCode: string, projectConfig: any): string { 225 // replace relative moduleSpecifier with ohmURl 226 const REG_RELATIVE_DEPENDENCY: RegExp = /(?:import|from)(?:\s*)['"]((?:\.\/|\.\.\/)[^'"]+|(?:\.\/?|\.\.\/?))['"]/g; 227 const REG_HAR_DEPENDENCY: RegExp = /(?:import|from)(?:\s*)['"]([^\.\/][^'"]+)['"]/g; 228 // replace requireNapi and requireNativeModule with import 229 const REG_REQUIRE_NATIVE_MODULE: RegExp = /var (\S+) = globalThis.requireNativeModule\(['"](\S+)['"]\);/g; 230 const REG_REQUIRE_NAPI_APP: RegExp = /var (\S+) = globalThis.requireNapi\(['"](\S+)['"], true, ['"](\S+)['"]\);/g; 231 const REG_REQUIRE_NAPI_OHOS: RegExp = /var (\S+) = globalThis.requireNapi\(['"](\S+)['"]\);/g; 232 233 return sourceCode.replace(REG_HAR_DEPENDENCY, (item, moduleRequest) => { 234 return replaceHarDependency(item, moduleRequest, projectConfig); 235 }).replace(REG_RELATIVE_DEPENDENCY, (item, moduleRequest) => { 236 return replaceRelativeDependency(item, moduleRequest, toUnixPath(sourcePath), projectConfig); 237 }).replace(REG_REQUIRE_NATIVE_MODULE, (_, moduleRequest, moduleName) => { 238 return `import ${moduleRequest} from '@native:${moduleName}';`; 239 }).replace(REG_REQUIRE_NAPI_APP, (_, moduleRequest, soName, moudlePath) => { 240 return `import ${moduleRequest} from '@app:${moudlePath}/${soName}';`; 241 }).replace(REG_REQUIRE_NAPI_OHOS, (_, moduleRequest, moduleName) => { 242 return `import ${moduleRequest} from '@ohos:${moduleName}';`; 243 }); 244} 245 246export function getOhmUrlByHarName(moduleRequest: string, projectConfig: any): string | undefined { 247 if (projectConfig.harNameOhmMap) { 248 // case1: "@ohos/lib" ---> "@bundle:bundleName/lib/ets/index" 249 if (projectConfig.harNameOhmMap.hasOwnProperty(moduleRequest)) { 250 return projectConfig.harNameOhmMap[moduleRequest]; 251 } 252 // case2: "@ohos/lib/src/main/ets/pages/page1" ---> "@bundle:bundleName/lib/ets/pages/page1" 253 for (const harName in projectConfig.harNameOhmMap) { 254 if (moduleRequest.startsWith(harName + '/')) { 255 const idx: number = projectConfig.harNameOhmMap[harName].split('/', 2).join('/').length; 256 const harOhmName: string = projectConfig.harNameOhmMap[harName].substring(0, idx); 257 if (moduleRequest.indexOf(harName + '/' + SRC_MAIN) === 0) { 258 return moduleRequest.replace(harName + '/' + SRC_MAIN, harOhmName); 259 } else { 260 return moduleRequest.replace(harName, harOhmName); 261 } 262 } 263 } 264 } 265 return undefined; 266} 267 268function replaceHarDependency(item:string, moduleRequest: string, projectConfig: any): string { 269 const harOhmUrl: string | undefined = getOhmUrlByHarName(moduleRequest, projectConfig); 270 if (harOhmUrl !== undefined) { 271 return item.replace(/(['"])(?:\S+)['"]/, (_, quotation) => { 272 return quotation + harOhmUrl + quotation; 273 }); 274 } 275 return item; 276} 277 278function locateActualFilePathWithModuleRequest(absolutePath: string): string { 279 if (!fs.existsSync(absolutePath) || !fs.statSync(absolutePath).isDirectory()) { 280 return absolutePath 281 } 282 283 const filePath: string = absolutePath + getExtensionIfUnfullySpecifiedFilepath(absolutePath); 284 if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) { 285 return absolutePath; 286 } 287 288 return path.join(absolutePath, 'index'); 289} 290 291function replaceRelativeDependency(item:string, moduleRequest: string, sourcePath: string, projectConfig: any): string { 292 if (sourcePath && projectConfig.compileMode === ESMODULE) { 293 // remove file extension from moduleRequest 294 const SUFFIX_REG: RegExp = /\.(?:[cm]?js|[e]?ts|json)$/; 295 moduleRequest = moduleRequest.replace(SUFFIX_REG, ''); 296 297 // normalize the moduleRequest 298 item = item.replace(/(['"])(?:\S+)['"]/, (_, quotation) => { 299 let normalizedModuleRequest: string = toUnixPath(path.normalize(moduleRequest)); 300 if (moduleRequest.startsWith("./")) { 301 normalizedModuleRequest = "./" + normalizedModuleRequest; 302 } 303 return quotation + normalizedModuleRequest + quotation; 304 }); 305 306 const filePath: string = 307 locateActualFilePathWithModuleRequest(path.resolve(path.dirname(sourcePath), moduleRequest)); 308 const result: RegExpMatchArray | null = 309 filePath.match(/(\S+)(\/|\\)src(\/|\\)(?:main|ohosTest)(\/|\\)(ets|js)(\/|\\)(\S+)/); 310 if (result && projectConfig.aceModuleJsonPath) { 311 const npmModuleIdx: number = result[1].search(/(\/|\\)node_modules(\/|\\)/); 312 const projectRootPath: string = projectConfig.projectRootPath; 313 if (npmModuleIdx === -1 || npmModuleIdx === projectRootPath.search(/(\/|\\)node_modules(\/|\\)/)) { 314 const packageInfo: string[] = getPackageInfo(projectConfig.aceModuleJsonPath); 315 const bundleName: string = packageInfo[0]; 316 const moduleName: string = packageInfo[1]; 317 moduleRequest = `@bundle:${bundleName}/${moduleName}/${result[5]}/${toUnixPath(result[7])}`; 318 item = item.replace(/(['"])(?:\S+)['"]/, (_, quotation) => { 319 return quotation + moduleRequest + quotation; 320 }); 321 } 322 } 323 } 324 return item; 325} 326 327export async function writeObfuscatedSourceCode(content: string, filePath: string, logger: any, projectConfig: any, 328 relativeSourceFilePath: string = '', rollupNewSourceMaps: any = {}): Promise<void> { 329 if (projectConfig.arkObfuscator) { 330 await writeArkguardObfuscatedSourceCode(content, filePath, logger, projectConfig.arkObfuscator, relativeSourceFilePath, rollupNewSourceMaps, 331 projectConfig.obfuscationMergedObConfig); 332 return; 333 } 334 if (projectConfig.terserConfig) { 335 await writeTerserObfuscatedSourceCode(content, filePath, logger, projectConfig.terserConfig, relativeSourceFilePath, rollupNewSourceMaps); 336 return; 337 } 338 if (process.env.compileTool !== 'rollup') { 339 await writeMinimizedSourceCode(content, filePath, logger, projectConfig.compileHar); 340 return; 341 } 342 fs.writeFileSync(filePath, content); 343} 344 345export async function writeArkguardObfuscatedSourceCode(content: string, filePath: string, logger: any, arkObfuscator: ArkObfuscator, 346 relativeSourceFilePath: string = '', rollupNewSourceMaps: any = {}, obfuscationMergedObConfig: MergedConfig): Promise<void> { 347 let previousStageSourceMap: sourceMap.RawSourceMap | undefined = undefined; 348 if (relativeSourceFilePath.length > 0) { 349 previousStageSourceMap = rollupNewSourceMaps[relativeSourceFilePath]; 350 } 351 352 let historyNameCache: Map<string, string> = undefined; 353 if (identifierCaches && identifierCaches[relativeSourceFilePath]) { 354 historyNameCache = getMapFromJson(identifierCaches[relativeSourceFilePath]); 355 } 356 357 let mixedInfo: {content: string, sourceMap?: any, nameCache?: any}; 358 try { 359 mixedInfo = await arkObfuscator.obfuscate(content, filePath, previousStageSourceMap, historyNameCache); 360 } catch { 361 logger.error(red, `ArkTS:ERROR Failed to obfuscate file: ${relativeSourceFilePath}`); 362 process.exit(FAIL); 363 } 364 365 if (mixedInfo.sourceMap) { 366 mixedInfo.sourceMap.sources = [relativeSourceFilePath]; 367 rollupNewSourceMaps[relativeSourceFilePath] = mixedInfo.sourceMap; 368 } 369 370 if (mixedInfo.nameCache) { 371 identifierCaches[relativeSourceFilePath] = mixedInfo.nameCache; 372 } 373 374 fs.writeFileSync(filePath, mixedInfo.content ?? ''); 375} 376 377export async function writeTerserObfuscatedSourceCode(content: string, filePath: string, logger: any, 378 minifyOptions: any, relativeSourceFilePath: string = '', rollupNewSourceMaps: any = {}): Promise<void> { 379 let result: MinifyOutput; 380 381 if (relativeSourceFilePath.length > 0) { 382 minifyOptions['sourceMap'] = { 383 content: rollupNewSourceMaps[relativeSourceFilePath], 384 asObject: true 385 }; 386 } 387 388 try { 389 result = await minify(content, minifyOptions); 390 } catch { 391 logger.error(red, `ArkTS:ERROR Failed to obfuscate file: ${relativeSourceFilePath}`); 392 process.exit(FAIL); 393 } 394 395 if (result.map) { 396 result.map.sourcesContent && delete result.map.sourcesContent; 397 result.map.sources = [relativeSourceFilePath]; 398 rollupNewSourceMaps[relativeSourceFilePath] = result.map; 399 } 400 401 fs.writeFileSync(filePath, result.code ?? ''); 402} 403 404export async function writeMinimizedSourceCode(content: string, filePath: string, logger: any, 405 isHar: boolean = false): Promise<void> { 406 let result: MinifyOutput; 407 try { 408 const minifyOptions = { 409 compress: { 410 join_vars: false, 411 sequences: 0, 412 directives: false 413 } 414 }; 415 if (!isHar) { 416 minifyOptions['format'] = { 417 semicolons: false, 418 beautify: true, 419 indent_level: 2 420 }; 421 } 422 result = await minify(content, minifyOptions); 423 } catch { 424 logger.error(red, `ArkTS:ERROR Failed to source code obfuscation.`, reset); 425 process.exit(FAIL); 426 } 427 428 fs.writeFileSync(filePath, result.code); 429} 430 431export function genBuildPath(filePath: string, projectPath: string, buildPath: string, projectConfig: any): string { 432 filePath = toUnixPath(filePath); 433 if (filePath.endsWith(EXTNAME_MJS)) { 434 filePath = filePath.replace(/\.mjs$/, EXTNAME_JS); 435 } 436 if (filePath.endsWith(EXTNAME_CJS)) { 437 filePath = filePath.replace(/\.cjs$/, EXTNAME_JS); 438 } 439 projectPath = toUnixPath(projectPath); 440 441 if (isPackageModulesFile(filePath, projectConfig)) { 442 const packageDir: string = projectConfig.packageDir; 443 const fakePkgModulesPath: string = toUnixPath(path.join(projectConfig.projectRootPath, packageDir)); 444 let output: string = ''; 445 if (filePath.indexOf(fakePkgModulesPath) === -1) { 446 const hapPath: string = toUnixPath(projectConfig.projectRootPath); 447 const tempFilePath: string = filePath.replace(hapPath, ''); 448 const sufStr: string = tempFilePath.substring(tempFilePath.indexOf(packageDir) + packageDir.length + 1); 449 output = path.join(projectConfig.nodeModulesPath, ZERO, sufStr); 450 } else { 451 output = filePath.replace(fakePkgModulesPath, path.join(projectConfig.nodeModulesPath, ONE)); 452 } 453 return output; 454 } 455 456 if (filePath.indexOf(projectPath) !== -1) { 457 const sufStr: string = filePath.replace(projectPath, ''); 458 const output: string = path.join(buildPath, sufStr); 459 return output; 460 } 461 462 return ''; 463} 464 465export function getPackageInfo(configFile: string): Array<string> { 466 if (packageCollection.has(configFile)) { 467 return packageCollection.get(configFile); 468 } 469 const data: any = JSON.parse(fs.readFileSync(configFile).toString()); 470 const bundleName: string = data.app.bundleName; 471 const moduleName: string = data.module.name; 472 packageCollection.set(configFile, [bundleName, moduleName]); 473 return [bundleName, moduleName]; 474} 475 476export function generateSourceFilesToTemporary(sourcePath: string, sourceContent: string, sourceMap: any, 477 projectConfig: any, logger: any): void { 478 let jsFilePath: string = genTemporaryPath(sourcePath, projectConfig.projectPath, process.env.cachePath, projectConfig); 479 if (jsFilePath.length === 0) { 480 return; 481 } 482 if (jsFilePath.endsWith(EXTNAME_ETS)) { 483 jsFilePath = jsFilePath.replace(/\.ets$/, EXTNAME_JS); 484 } else { 485 jsFilePath = jsFilePath.replace(/\.ts$/, EXTNAME_JS); 486 } 487 let sourceMapFile: string = genSourceMapFileName(jsFilePath); 488 if (sourceMapFile.length > 0 && projectConfig.buildArkMode === 'debug') { 489 let source = toUnixPath(sourcePath).replace(toUnixPath(projectConfig.projectRootPath) + '/', ''); 490 // adjust sourceMap info 491 sourceMap.sources = [source]; 492 sourceMap.file = path.basename(sourceMap.file); 493 delete sourceMap.sourcesContent; 494 newSourceMaps[source] = sourceMap; 495 } 496 sourceContent = transformModuleSpecifier(sourcePath, sourceContent, projectConfig); 497 498 mkdirsSync(path.dirname(jsFilePath)); 499 if (projectConfig.buildArkMode === 'debug') { 500 fs.writeFileSync(jsFilePath, sourceContent); 501 return; 502 } 503 504 writeObfuscatedSourceCode(sourceContent, jsFilePath, logger, projectConfig); 505} 506 507export function genAbcFileName(temporaryFile: string): string { 508 let abcFile: string = temporaryFile; 509 if (temporaryFile.endsWith(EXTNAME_TS)) { 510 abcFile = temporaryFile.replace(/\.ts$/, EXTNAME_ABC); 511 } else { 512 abcFile = temporaryFile.replace(/\.js$/, EXTNAME_ABC); 513 } 514 return abcFile; 515} 516 517export function isOhModules(projectConfig: any): boolean { 518 return projectConfig.packageDir === OH_MODULES; 519} 520 521export function isEs2Abc(projectConfig: any): boolean { 522 return projectConfig.pandaMode === ES2ABC || projectConfig.pandaMode === "undefined" || 523 projectConfig.pandaMode === undefined; 524} 525 526export function isTs2Abc(projectConfig: any): boolean { 527 return projectConfig.pandaMode === TS2ABC; 528} 529 530export function genProtoFileName(temporaryFile: string): string { 531 return temporaryFile.replace(/\.(?:[tj]s|json)$/, EXTNAME_PROTO_BIN); 532} 533 534export function genMergeProtoFileName(temporaryFile: string): string { 535 let protoTempPathArr: string[] = temporaryFile.split(TEMPORARY); 536 const sufStr: string = protoTempPathArr[protoTempPathArr.length - 1]; 537 let protoBuildPath: string = path.join(process.env.cachePath, "protos", sufStr); 538 539 return protoBuildPath; 540} 541 542export function removeDuplicateInfo(moduleInfos: Array<any>): Array<any> { 543 const tempModuleInfos: any[] = Array<any>(); 544 moduleInfos.forEach((item) => { 545 let check: boolean = tempModuleInfos.every((newItem) => { 546 return item.tempFilePath !== newItem.tempFilePath; 547 }); 548 if (check) { 549 tempModuleInfos.push(item); 550 } 551 }); 552 moduleInfos = tempModuleInfos; 553 554 return moduleInfos; 555} 556 557export function buildCachePath(tailName: string, projectConfig: any, logger: any): string { 558 let pathName: string = process.env.cachePath !== undefined ? 559 path.join(projectConfig.cachePath, tailName) : path.join(projectConfig.aceModuleBuild, tailName); 560 validateFilePathLength(pathName, logger); 561 return pathName; 562} 563 564export function getArkBuildDir(arkDir: string): string { 565 if (isWindows()) { 566 return path.join(arkDir, 'build-win'); 567 } else if (isMac()) { 568 return path.join(arkDir, 'build-mac'); 569 } else { 570 return path.join(arkDir, 'build'); 571 } 572} 573 574export function getBuildBinDir(arkDir: string): string { 575 return path.join(getArkBuildDir(arkDir), 'bin'); 576} 577