• 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 {
19  ArkObfuscator,
20  readProjectProperties
21} from "arkguard"
22
23import {
24  TS2ABC,
25  ESMODULE,
26  AOT_FULL,
27  AOT_PARTIAL,
28  AOT_TYPE,
29  AOT_PROFILE_SUFFIX,
30  NODE_MODULES,
31  OH_MODULES,
32  FAIL,
33  OBFUSCATION_TOOL
34} from './ark_define';
35import { isAotMode, isDebug } from '../utils';
36import {
37  isLinux,
38  isMac,
39  isWindows
40} from '../../../utils';
41import { getArkBuildDir } from '../../../ark_utils';
42import { checkAotConfig } from '../../../gen_aot';
43import { projectConfig as mainProjectConfig } from '../../../../main';
44import { MergedConfig, ObConfigResolver, readNameCache} from './ob_config_resolver'
45
46type ArkConfig = {
47  arkRootPath: string;
48  ts2abcPath: string;
49  js2abcPath: string;
50  mergeAbcPath: string;
51  es2abcPath: string;
52  aotCompilerPath: string;
53  nodePath: string;
54  isDebug: boolean;
55};
56
57let arkConfig: ArkConfig = {};
58export function initArkConfig(projectConfig: any) {
59  let arkRootPath: string = path.join(__dirname, '..', '..', '..', '..', 'bin', 'ark');
60  if (projectConfig.arkFrontendDir) {
61    arkRootPath = projectConfig.arkFrontendDir;
62  }
63  arkConfig.nodePath = 'node';
64  if (projectConfig.nodeJs) {
65    arkConfig.nodePath = projectConfig.nodePath;
66  }
67  processPlatformInfo(arkRootPath);
68  processCompatibleVersion(projectConfig, arkRootPath);
69  arkConfig.isDebug = isDebug(projectConfig);
70  arkConfig.arkRootPath = arkRootPath;
71
72  return arkConfig;
73}
74
75export function initArkProjectConfig(share: any) {
76  let projectConfig: any = share.projectConfig;
77  let arkProjectConfig: any = {};
78  if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) {
79    const buildJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString());
80    arkProjectConfig.projectRootPath = buildJsonInfo.projectRootPath;
81    arkProjectConfig.modulePathMap = buildJsonInfo.modulePathMap;
82    arkProjectConfig.isOhosTest = buildJsonInfo.isOhosTest;
83    if (buildJsonInfo.patchConfig) {
84      arkProjectConfig.oldMapFilePath = buildJsonInfo.patchConfig.oldMapFilePath;
85    }
86    if (checkAotConfig(projectConfig.compileMode, buildJsonInfo,
87      (error: string) => { share.throwArkTsCompilerError(error) })) {
88      arkProjectConfig.processTs = true;
89      arkProjectConfig.pandaMode = TS2ABC;
90      arkProjectConfig.anBuildOutPut = buildJsonInfo.anBuildOutPut;
91      arkProjectConfig.anBuildMode = buildJsonInfo.anBuildMode;
92      arkProjectConfig.apPath = buildJsonInfo.apPath;
93    } else {
94      arkProjectConfig.processTs = false;
95      arkProjectConfig.pandaMode = buildJsonInfo.pandaMode;
96    }
97
98    if (projectConfig.compileMode === ESMODULE) {
99      arkProjectConfig.nodeModulesPath = buildJsonInfo.nodeModulesPath;
100      arkProjectConfig.harNameOhmMap = buildJsonInfo.harNameOhmMap;
101      projectConfig.packageDir = buildJsonInfo.packageManagerType === 'ohpm' ? OH_MODULES : NODE_MODULES;
102    }
103  }
104  if (projectConfig.aceManifestPath && fs.existsSync(projectConfig.aceManifestPath)) {
105    const manifestJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceManifestPath).toString());
106    if (manifestJsonInfo.minPlatformVersion) {
107      arkProjectConfig.minPlatformVersion = manifestJsonInfo.minPlatformVersion;
108    }
109  }
110  if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) {
111    const moduleJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceModuleJsonPath).toString());
112    if (moduleJsonInfo.app.minAPIVersion) {
113      arkProjectConfig.minPlatformVersion = moduleJsonInfo.app.minAPIVersion;
114    }
115    if (moduleJsonInfo.module) {
116      arkProjectConfig.moduleName = moduleJsonInfo.module.name;
117    }
118    if (moduleJsonInfo.app) {
119      arkProjectConfig.bundleName = moduleJsonInfo.app.bundleName;
120    }
121  }
122
123  // Hotreload attributes are initialized by arkui in main.js, just copy them.
124  arkProjectConfig.hotReload = mainProjectConfig.hotReload;
125  arkProjectConfig.patchAbcPath = mainProjectConfig.patchAbcPath;
126  arkProjectConfig.changedFileList = mainProjectConfig.changedFileList;
127
128  if(mainProjectConfig.es2abcCompileTsInAotMode || mainProjectConfig.es2abcCompileTsInNonAotMode) {
129    arkProjectConfig.pandaMode = mainProjectConfig.pandaMode;
130    arkProjectConfig.processTs = mainProjectConfig.processTs;
131  }
132  arkProjectConfig.compileMode = projectConfig.compileMode;
133
134  if (projectConfig.compileHar || !isDebug(projectConfig))  {
135    const logger: any = share.getLogger(OBFUSCATION_TOOL);
136    initObfuscationConfig(projectConfig, arkProjectConfig, logger);
137  }
138  return arkProjectConfig;
139}
140
141function initObfuscationConfig(projectConfig: any, arkProjectConfig: any, logger: any): void {
142  const obConfig: ObConfigResolver =  new ObConfigResolver(projectConfig, logger, true);
143  const mergedObConfig: MergedConfig = obConfig.resolveObfuscationConfigs();
144  const isHarCompiled: boolean = projectConfig.compileHar;
145  if (mergedObConfig.options.disableObfuscation) {
146    return;
147  }
148
149  let projectAndLibsReservedProperties: string[];
150  if (mergedObConfig.options.enablePropertyObfuscation) {
151    projectAndLibsReservedProperties = readProjectProperties([projectConfig.modulePath],
152      { mNameObfuscation: {mReservedProperties: [], mKeepStringProperty: !mergedObConfig.options.enableStringPropertyObfuscation } }, true);
153    mergedObConfig.reservedPropertyNames.push(...projectAndLibsReservedProperties);
154  }
155  arkProjectConfig.obfuscationMergedObConfig = mergedObConfig;
156
157  if (isAotMode(arkProjectConfig)) {
158    arkProjectConfig.arkObfuscator = initArkGuardConfig(projectConfig.obfuscationOptions?.obfuscationCacheDir, logger, mergedObConfig);
159    return;
160  }
161  arkProjectConfig.terserConfig = initTerserConfig(projectConfig, logger, mergedObConfig, isHarCompiled);
162}
163
164function initTerserConfig(projectConfig: any, logger: any, mergedObConfig: MergedConfig, isHarCompiled: boolean): any {
165  const isCompact = projectConfig.obfuscationOptions ? mergedObConfig.options.compact : isHarCompiled;
166  const minifyOptions = {
167    format: {
168      beautify: !isCompact,
169      indent_level: 2
170    },
171    compress: {
172      join_vars: false,
173      sequences: 0,
174      directives: false,
175      drop_console: mergedObConfig.options.removeLog
176    },
177    mangle: {
178      reserved: mergedObConfig.reservedNames,
179      toplevel: mergedObConfig.options.enableToplevelObfuscation
180    }
181  }
182  const applyNameCache: string | undefined = mergedObConfig.options.applyNameCache;
183  if (applyNameCache &&  applyNameCache.length > 0) {
184    if (fs.existsSync(applyNameCache)) {
185      minifyOptions.nameCache = JSON.parse(fs.readFileSync(applyNameCache, 'utf-8'));
186    } else {
187      logger.error(`ArkTS:ERROR Namecache file ${applyNameCache} does not exist`);
188    }
189  } else {
190    if (projectConfig.obfuscationOptions && projectConfig.obfuscationOptions.obfuscationCacheDir) {
191      const defaultNameCachePath: string = path.join(projectConfig.obfuscationOptions.obfuscationCacheDir,"nameCache.json");
192      if (fs.existsSync(defaultNameCachePath)) {
193        minifyOptions.nameCache = JSON.parse(fs.readFileSync(defaultNameCachePath, 'utf-8'));
194      } else {
195        minifyOptions.nameCache = {};
196      }
197    }
198  }
199
200  if (mergedObConfig.options.enablePropertyObfuscation) {
201    minifyOptions.mangle.properties = {
202      reserved: mergedObConfig.reservedPropertyNames,
203      keep_quoted: !mergedObConfig.options.enableStringPropertyObfuscation
204    };
205  }
206  return minifyOptions;
207}
208
209function initArkGuardConfig(obfuscationCacheDir: string | undefined, logger: any, mergedObConfig: any) {
210  const arkguardConfig = {
211    mCompact: mergedObConfig.options.compact,
212    mDisableHilog: false,
213    mDisableConsole: mergedObConfig.options.removeLog,
214    mSimplify: false,
215    mTopLevel: mergedObConfig.options.enableToplevelObfuscation,
216    mNameObfuscation: {
217      mEnable: true,
218      mNameGeneratorType: 1,
219      mReservedNames: mergedObConfig.reservedNames,
220      mRenameProperties: mergedObConfig.options.enablePropertyObfuscation,
221      mReservedProperties: mergedObConfig.reservedPropertyNames,
222      mKeepStringProperty: !mergedObConfig.options.enableStringPropertyObfuscation
223    },
224    mEnableSourceMap: true,
225    mEnableNameCache: true
226  }
227
228  const arkObfuscator: ArkObfuscator = new ArkObfuscator();
229  arkObfuscator.init(arkguardConfig);
230  if (mergedObConfig.options.applyNameCache && mergedObConfig.options.applyNameCache.length > 0) {
231    readNameCache(mergedObConfig.options.applyNameCache, logger);
232  } else {
233    if (obfuscationCacheDir) {
234      const defaultNameCachePath: string = path.join(obfuscationCacheDir,"nameCache.json");
235      if (fs.existsSync(defaultNameCachePath)) {
236        readNameCache(defaultNameCachePath, logger);
237      }
238    }
239  }
240  return arkObfuscator;
241}
242
243function processPlatformInfo(arkRootPath: string): void {
244  const arkPlatformPath: string = getArkBuildDir(arkRootPath);
245  if (isWindows()) {
246    arkConfig.es2abcPath = path.join(arkPlatformPath, 'bin', 'es2abc.exe');
247    arkConfig.ts2abcPath = path.join(arkPlatformPath, 'src', 'index.js');
248    arkConfig.mergeAbcPath = path.join(arkPlatformPath, 'bin', 'merge_abc.exe');
249    arkConfig.js2abcPath = path.join(arkPlatformPath, 'bin', 'js2abc.exe');
250    arkConfig.aotCompilerPath = path.join(arkPlatformPath, 'bin', 'ark_aot_compiler.exe');
251    return;
252  }
253  if (isLinux() || isMac()) {
254    arkConfig.es2abcPath = path.join(arkPlatformPath, 'bin', 'es2abc');
255    arkConfig.ts2abcPath = path.join(arkPlatformPath, 'src', 'index.js');
256    arkConfig.mergeAbcPath = path.join(arkPlatformPath, 'bin', 'merge_abc');
257    arkConfig.js2abcPath = path.join(arkPlatformPath, 'bin', 'js2abc');
258    arkConfig.aotCompilerPath = path.join(arkPlatformPath, 'bin', 'ark_aot_compiler');
259    return;
260  }
261}
262
263function processCompatibleVersion(projectConfig: any, arkRootPath: string) {
264  const platformPath: string = getArkBuildDir(arkRootPath);
265  if (projectConfig.minPlatformVersion && projectConfig.minPlatformVersion.toString() === '8') {
266    // use ts2abc to compile apps with 'CompatibleSdkVersion' set to 8
267    arkConfig.ts2abcPath = path.join(platformPath, 'legacy_api8', 'src', 'index.js');
268    projectConfig.pandaMode = TS2ABC;
269  }
270}
271