• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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