1/*
2 * Copyright (c) 2020 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
16const fs = require('fs');
17const path = require('path');
18const crypto = require('crypto');
19const JSON5 = require('json5');
20
21const {
22  readFile,
23  writeFileSync,
24  resourcesRawfile,
25  getStoredFileInfo
26} = require('./lib/utils');
27
28const {
29  COLD_RELOAD_MODE,
30  ES2ABC,
31  FAIL,
32  TEST_RUNNER_DIR_SET,
33  TS2ABC,
34  WORKERS_DIR
35} = require('./lib/pre_define');
36
37const {
38  checkAotConfig
39} = require('./lib/gen_aot');
40
41const {
42  configure,
43  getLogger
44} = require('log4js');
45
46configure({
47  appenders: { 'ETS': {type: 'stderr', layout: {type: 'messagePassThrough'}}},
48  categories: {'default': {appenders: ['ETS'], level: 'info'}}
49});
50const logger = getLogger('ETS');
51
52let staticPreviewPage = process.env.aceStaticPreview;
53let aceCompileMode = process.env.aceCompileMode || 'page';
54const abilityConfig = {
55  abilityType: process.env.abilityType || 'page',
56  abilityEntryFile: null,
57  projectAbilityPath: [],
58  testRunnerFile: []
59};
60const projectConfig = {};
61const resources = {
62  app: {},
63  sys: {}
64};
65const systemModules = [];
66const abilityPagesFullPath = new Set();
67let globalModulePaths = [];
68let sdkConfigs = [];
69let defaultSdkConfigs = [];
70let extendSdkConfigs = [];
71let sdkConfigPrefix = 'ohos|system|kit|arkts';
72let ohosSystemModulePaths = [];
73let ohosSystemModuleSubDirPaths = [];
74let allModulesPaths = [];
75
76function initProjectConfig(projectConfig) {
77  projectConfig.entryObj = {};
78  projectConfig.entryArrayForObf = []; // Only used for arkguard
79  projectConfig.cardObj = {};
80  projectConfig.projectPath = projectConfig.projectPath || process.env.aceModuleRoot ||
81    path.join(process.cwd(), 'sample');
82  projectConfig.buildPath = projectConfig.buildPath || process.env.aceModuleBuild ||
83    path.resolve(projectConfig.projectPath, 'build');
84  projectConfig.aceModuleBuild = projectConfig.buildPath; // To be compatible with both webpack and rollup
85  projectConfig.manifestFilePath = projectConfig.manifestFilePath || process.env.aceManifestPath ||
86    path.join(projectConfig.projectPath, 'manifest.json');
87  projectConfig.aceProfilePath = projectConfig.aceProfilePath || process.env.aceProfilePath;
88  projectConfig.aceModuleJsonPath = projectConfig.aceModuleJsonPath || process.env.aceModuleJsonPath;
89  projectConfig.aceSuperVisualPath = projectConfig.aceSuperVisualPath ||
90    process.env.aceSuperVisualPath;
91  projectConfig.hashProjectPath = projectConfig.hashProjectPath ||
92    hashProjectPath(projectConfig.projectPath);
93  projectConfig.aceBuildJson = projectConfig.aceBuildJson || process.env.aceBuildJson;
94  projectConfig.cachePath = projectConfig.cachePath || process.env.cachePath ||
95    path.resolve(__dirname, 'node_modules/.cache');
96  projectConfig.aceSoPath = projectConfig.aceSoPath || process.env.aceSoPath;
97  projectConfig.xtsMode = /ets_loader_ark$/.test(__dirname);
98  projectConfig.localPropertiesPath = projectConfig.localPropertiesPath || process.env.localPropertiesPath;
99  projectConfig.projectProfilePath = projectConfig.projectProfilePath || process.env.projectProfilePath;
100  projectConfig.isPreview = projectConfig.isPreview || process.env.isPreview === 'true';
101  projectConfig.compileMode = projectConfig.compileMode || process.env.compileMode || 'jsbundle';
102  projectConfig.runtimeOS = projectConfig.runtimeOS || process.env.runtimeOS || 'default';
103  projectConfig.sdkInfo = projectConfig.sdkInfo || process.env.sdkInfo || 'default';
104  projectConfig.compileHar = false;
105  projectConfig.compileShared = false;
106  projectConfig.splitCommon = false;
107  projectConfig.checkEntry = projectConfig.checkEntry || process.env.checkEntry;
108  projectConfig.obfuscateHarType = projectConfig.obfuscateHarType || process.env.obfuscate;
109  projectConfig.packageDir = 'node_modules';
110  projectConfig.packageJson = 'package.json';
111  projectConfig.packageManagerType = 'npm';
112  projectConfig.cardEntryObj = {};
113  projectConfig.compilerTypes = [];
114  projectConfig.isCrossplatform = projectConfig.isCrossplatform || false;
115  projectConfig.enableDebugLine = projectConfig.enableDebugLine || process.env.enableDebugLine || false;
116  projectConfig.bundleType = projectConfig.bundleType || process.env.bundleType || '';
117  projectConfig.optLazyForEach = false;
118  projectConfig.hspResourcesMap = false;
119  projectConfig.useArkoala = false;
120  projectConfig.resetBundleName = false;
121  projectConfig.integratedHsp = false;
122  projectConfig.useTsHar = false;
123  projectConfig.optTryCatchFunc = true;
124  // All files which dependent on bytecode har, and should be added to compilation entries.
125  projectConfig.otherCompileFiles = {};
126  // Packages which need to update version in bytecode har
127  projectConfig.updateVersionInfo = undefined;
128}
129
130function loadEntryObj(projectConfig) {
131  let manifest = {};
132  initMain();
133  initProjectConfig(projectConfig);
134  loadBuildJson();
135  if (process.env.aceManifestPath && aceCompileMode === 'page') {
136    setEntryFile(projectConfig);
137    setFaTestRunnerFile(projectConfig);
138  }
139  if (process.env.aceModuleJsonPath) {
140    setIntentEntryPages(projectConfig);
141    setAbilityPages(projectConfig);
142    setStageTestRunnerFile(projectConfig);
143    loadNavigationConfig(aceBuildJson);
144  }
145
146  if (staticPreviewPage) {
147    projectConfig.entryObj['./' + staticPreviewPage] = projectConfig.projectPath + path.sep +
148      staticPreviewPage + '.ets?entry';
149    setEntryArrayForObf(staticPreviewPage);
150  } else if (abilityConfig.abilityType === 'page') {
151    if (fs.existsSync(projectConfig.manifestFilePath)) {
152      const jsonString = fs.readFileSync(projectConfig.manifestFilePath).toString();
153      manifest = JSON.parse(jsonString);
154      if (manifest && manifest.minPlatformVersion) {
155        process.env.minPlatformVersion = manifest.minPlatformVersion;
156        partialUpdateController(manifest.minPlatformVersion);
157      }
158      projectConfig.pagesJsonFileName = 'config.json';
159    } else if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) {
160      process.env.compileMode = 'moduleJson';
161      buildManifest(manifest, projectConfig.aceModuleJsonPath);
162    } else {
163      throw Error('\u001b[31m ERROR: the manifest file ' + projectConfig.manifestFilePath.replace(/\\/g, '/') +
164        ' or module.json is lost or format is invalid. \u001b[39m').message;
165    }
166    if (!projectConfig.compileHar) {
167      if (manifest.pages) {
168        const pages = manifest.pages;
169        pages.forEach((element) => {
170          const sourcePath = element.replace(/^\.\/ets\//, '');
171          const fileName = path.resolve(projectConfig.projectPath, sourcePath + '.ets');
172          if (fs.existsSync(fileName)) {
173            projectConfig.entryObj['./' + sourcePath] = fileName + '?entry';
174            // Collect the file paths in main_pages.json
175            setEntryArrayForObf(sourcePath);
176          } else {
177            throw Error(`\u001b[31m ERROR: page '${fileName.replace(/\\/g, '/')}' does not exist. \u001b[39m`)
178              .message;
179          }
180        });
181      } else {
182        throw Error('\u001b[31m ERROR: missing pages attribute in ' +
183          projectConfig.manifestFilePath.replace(/\\/g, '/') +
184          '. \u001b[39m').message;
185      }
186    }
187  }
188}
189
190function loadNavigationConfig(aceBuildJson) {
191  if (aceBuildJson && aceBuildJson.routerMap && Array.isArray(aceBuildJson.routerMap)) {
192    aceBuildJson.routerMap.forEach((item) => {
193      if (item.pageSourceFile && item.name && item.buildFunction) {
194        const filePath = path.resolve(item.pageSourceFile);
195        const storedFileInfo = getStoredFileInfo();
196        if (storedFileInfo.routerInfo.has(filePath)) {
197          storedFileInfo.routerInfo.get(filePath).push({name: item.name, buildFunction: item.buildFunction});
198        } else {
199          storedFileInfo.routerInfo.set(filePath, [{name: item.name, buildFunction: item.buildFunction}]);
200        }
201      }
202    });
203  }
204}
205
206function buildManifest(manifest, aceConfigPath) {
207  try {
208    const moduleConfigJson = JSON.parse(fs.readFileSync(aceConfigPath).toString());
209    manifest.type = process.env.abilityType;
210    if (moduleConfigJson && moduleConfigJson.app && moduleConfigJson.app.minAPIVersion) {
211      if (moduleConfigJson.module && moduleConfigJson.module.metadata) {
212        partialUpdateController(moduleConfigJson.app.minAPIVersion, moduleConfigJson.module.metadata,
213          moduleConfigJson.module.type);
214        stageOptimization(moduleConfigJson.module.metadata);
215      } else {
216        partialUpdateController(moduleConfigJson.app.minAPIVersion);
217      }
218    }
219    if (moduleConfigJson.module) {
220      switch (moduleConfigJson.module.type) {
221        case 'har':
222          projectConfig.compileHar = true;
223          getPackageJsonEntryPath();
224          break;
225        case 'shared':
226          projectConfig.compileShared = true;
227          getPackageJsonEntryPath();
228          manifest.pages = getPages(moduleConfigJson);
229          break;
230        default:
231          manifest.pages = getPages(moduleConfigJson);
232          break;
233      }
234    } else {
235      throw Error('\u001b[31m' +
236        'BUIDERROR: the config.json file miss key word module || module[abilities].' +
237        '\u001b[39m').message;
238    }
239  } catch (e) {
240    if (/BUIDERROR/.test(e)) {
241      throw Error(e.replace('BUIDERROR', 'ERROR')).message;
242    } else {
243      throw Error('\x1B[31m' + 'ERROR: the module.json file is lost or format is invalid.' +
244        '\x1B[39m').message;
245    }
246  }
247}
248
249function getPackageJsonEntryPath() {
250  const rootPackageJsonPath = path.resolve(projectConfig.projectPath, '../../../' + projectConfig.packageJson);
251  if (fs.existsSync(rootPackageJsonPath)) {
252    let rootPackageJsonContent;
253    try {
254      rootPackageJsonContent = (projectConfig.packageManagerType === 'npm' ?
255        JSON : JSON5).parse(fs.readFileSync(rootPackageJsonPath, 'utf-8'));
256    } catch (e) {
257      throw Error('\u001b[31m' + 'BUIDERROR: ' + rootPackageJsonPath + ' format is invalid.' + '\u001b[39m').message;
258    }
259    if (rootPackageJsonContent) {
260      if (rootPackageJsonContent.module) {
261        getEntryPath(rootPackageJsonContent.module, rootPackageJsonPath);
262      } else if (rootPackageJsonContent.main) {
263        getEntryPath(rootPackageJsonContent.main, rootPackageJsonPath);
264      } else {
265        getEntryPath('', rootPackageJsonPath);
266      }
267    } else if (projectConfig.compileHar) {
268      throw Error('\u001b[31m' + 'BUIDERROR: lack message in ' + projectConfig.packageJson + '.' +
269        '\u001b[39m').message;
270    }
271  }
272}
273
274function supportSuffix(mainEntryPath) {
275  if (fs.existsSync(path.join(mainEntryPath, 'index.ets'))) {
276    mainEntryPath = path.join(mainEntryPath, 'index.ets');
277  } else if (fs.existsSync(path.join(mainEntryPath, 'index.ts'))) {
278    mainEntryPath = path.join(mainEntryPath, 'index.ts');
279  } else if (fs.existsSync(path.join(mainEntryPath, 'index.js'))) {
280    mainEntryPath = path.join(mainEntryPath, 'index.js');
281  } else if (projectConfig.compileHar) {
282    throw Error('\u001b[31m' + 'BUIDERROR: not find entry file in ' + projectConfig.packageJson +
283      '.' + '\u001b[39m').message;
284  }
285  return mainEntryPath;
286}
287
288function supportExtName(mainEntryPath) {
289  if (path.extname(mainEntryPath) === '') {
290    if (fs.existsSync(mainEntryPath + '.ets')) {
291      mainEntryPath = mainEntryPath + '.ets';
292    } else if (fs.existsSync(mainEntryPath + '.ts')) {
293      mainEntryPath = mainEntryPath + '.ts';
294    } else if (fs.existsSync(mainEntryPath + '.js')) {
295      mainEntryPath = mainEntryPath + '.js';
296    }
297  }
298  return mainEntryPath;
299}
300
301function getEntryPath(entryPath, rootPackageJsonPath) {
302  let mainEntryPath = path.resolve(rootPackageJsonPath, '../', entryPath);
303  if (fs.existsSync(mainEntryPath) && fs.statSync(mainEntryPath).isDirectory()) {
304    mainEntryPath = supportSuffix(mainEntryPath);
305  } else {
306    mainEntryPath = supportExtName(mainEntryPath);
307  }
308  if (fs.existsSync(mainEntryPath) && fs.statSync(mainEntryPath).isFile()) {
309    const entryKey = path.relative(projectConfig.projectPath, mainEntryPath);
310    projectConfig.entryObj[entryKey] = mainEntryPath;
311    setEntryArrayForObf(entryKey);
312    abilityPagesFullPath.add(path.resolve(mainEntryPath).toLowerCase());
313  } else if (projectConfig.compileHar) {
314    throw Error('\u001b[31m' + `BUIDERROR: not find entry file in ${rootPackageJsonPath}.` + '\u001b[39m').message;
315  }
316}
317
318function stageOptimization(metadata) {
319  if (Array.isArray(metadata) && metadata.length) {
320    metadata.some(item => {
321      if (item.name && item.name === 'USE_COMMON_CHUNK' &&
322        item.value && item.value === 'true') {
323        projectConfig.splitCommon = true;
324        return true;
325      }
326    });
327  }
328}
329
330function getPages(configJson) {
331  const pages = [];
332  let pagesJsonFileName = '';
333  // pages is not necessary in stage
334  if (process.env.compileMode === 'moduleJson' && configJson.module && configJson.module.pages) {
335    pagesJsonFileName = `${configJson.module.pages.replace(/\$profile\:/, '')}.json`;
336  } else {
337    return pages;
338  }
339  const modulePagePath = path.resolve(projectConfig.aceProfilePath, pagesJsonFileName);
340  if (fs.existsSync(modulePagePath)) {
341    try {
342      const pagesConfig = JSON.parse(fs.readFileSync(modulePagePath, 'utf-8'));
343      if (pagesConfig && pagesConfig.src) {
344        projectConfig.pagesJsonFileName = pagesJsonFileName;
345        return pagesConfig.src;
346      }
347    } catch (e) {
348      throw Error('\x1B[31m' + `BUIDERROR: the ${modulePagePath} file format is invalid.` +
349        '\x1B[39m').message;
350    }
351  }
352  return pages;
353}
354
355function setEntryFile(projectConfig) {
356  const entryFileName = abilityConfig.abilityType === 'page' ? 'app' : abilityConfig.abilityType;
357  const extendFile = entryFileName === 'app' ? '.ets' : '.ts';
358  const entryFileRealPath = entryFileName + extendFile;
359  const entryFilePath = path.resolve(projectConfig.projectPath, entryFileRealPath);
360  abilityConfig.abilityEntryFile = entryFilePath;
361  if (!fs.existsSync(entryFilePath) && aceCompileMode === 'page') {
362    throw Error(`\u001b[31m ERROR: missing ${entryFilePath.replace(/\\/g, '/')}. \u001b[39m`).message;
363  }
364  projectConfig.entryObj[`./${entryFileName}`] = entryFilePath + '?entry';
365  setEntryArrayForObf(entryFileName);
366}
367
368function setIntentEntryPages(projectConfig) {
369  projectConfig.intentEntry.forEach(pages => {
370    const entryKey = path.relative(projectConfig.projectPath, pages).replace(/\.(ets|ts|js)$/, '');
371    projectConfig.entryObj[entryKey] = pages;
372    if (/\.ets$/.test(pages)) {
373      abilityPagesFullPath.add(path.resolve(pages).toLowerCase());
374    }
375  });
376}
377
378function setAbilityPages(projectConfig) {
379  let abilityPages = [];
380  if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) {
381    const moduleJson = JSON.parse(fs.readFileSync(projectConfig.aceModuleJsonPath).toString());
382    abilityPages = readAbilityEntrance(moduleJson);
383    setAbilityFile(projectConfig, abilityPages);
384    setBundleModuleInfo(projectConfig, moduleJson);
385  }
386}
387
388function setTestRunnerFile(projectConfig, isStageBased) {
389  const index = projectConfig.projectPath.split(path.sep).join('/').lastIndexOf('\/');
390  TEST_RUNNER_DIR_SET.forEach((dir) => {
391    const projectPath = isStageBased ? projectConfig.projectPath : projectConfig.projectPath.substring(0, index + 1);
392    const testRunnerPath = path.resolve(projectPath, dir);
393    if (fs.existsSync(testRunnerPath) && folderExistsCaseSensitive(testRunnerPath)) {
394      const testRunnerFiles = [];
395      readFile(testRunnerPath, testRunnerFiles);
396      testRunnerFiles.forEach((item) => {
397        if (/\.(ts|js|ets)$/.test(item)) {
398          if (/\.ets$/.test(item)) {
399            abilityPagesFullPath.add(path.resolve(item).toLowerCase());
400          }
401          const relativePath = path.relative(testRunnerPath, item).replace(/\.(ts|js|ets)$/, '');
402          if (isStageBased) {
403            projectConfig.entryObj[`./${dir}/${relativePath}`] = item;
404          } else {
405            projectConfig.entryObj[`../${dir}/${relativePath}`] = item;
406          }
407          setEntryArrayForObf(dir, relativePath);
408          abilityConfig.testRunnerFile.push(item);
409        }
410      });
411    }
412  });
413}
414
415// entryPath: the filename of the entry file and the name of the outer directory.
416// The directory should be placed before the filename, and the filename must be the last argument.
417function setEntryArrayForObf(...entryPath) {
418  projectConfig.entryArrayForObf?.push(entryPath.join('/'));
419}
420
421function folderExistsCaseSensitive(folderPath) {
422  try {
423    const folders = fs.readdirSync(path.dirname(folderPath), { withFileTypes: true })
424      .filter(entry => entry.isDirectory())
425      .map(entry => entry.name);
426    const targetFolderName = path.basename(folderPath);
427    return folders.includes(targetFolderName);
428  } catch (error) {
429    return false;
430  }
431}
432
433function setFaTestRunnerFile(projectConfig) {
434  setTestRunnerFile(projectConfig, false);
435}
436
437function setStageTestRunnerFile(projectConfig) {
438  setTestRunnerFile(projectConfig, true);
439}
440
441function setBundleModuleInfo(projectConfig, moduleJson) {
442  if (moduleJson.module) {
443    projectConfig.moduleName = moduleJson.module.name;
444  }
445  if (moduleJson.app) {
446    projectConfig.bundleName = moduleJson.app.bundleName;
447  }
448}
449
450function setAbilityFile(projectConfig, abilityPages) {
451  abilityPages.forEach(abilityPath => {
452    const projectAbilityPath = path.resolve(projectConfig.projectPath, '../', abilityPath);
453    if (path.isAbsolute(abilityPath)) {
454      abilityPath = '.' + abilityPath.slice(projectConfig.projectPath.length);
455    }
456    const entryPageKey = abilityPath.replace(/^\.\/ets\//, './').replace(/\.ts$/, '').replace(/\.ets$/, '');
457    if (fs.existsSync(projectAbilityPath)) {
458      abilityConfig.projectAbilityPath.push(projectAbilityPath);
459      projectConfig.entryObj[entryPageKey] = projectAbilityPath + '?entry';
460      setEntryArrayForObf(entryPageKey);
461    } else {
462      throw Error(
463        `\u001b[31m ERROR: srcEntry file '${projectAbilityPath.replace(/\\/g, '/')}' does not exist. \u001b[39m`
464      ).message;
465    }
466  });
467}
468
469function readAbilityEntrance(moduleJson) {
470  const abilityPages = [];
471  if (moduleJson.module) {
472    const moduleSrcEntrance = moduleJson.module.srcEntrance;
473    const moduleSrcEntry = moduleJson.module.srcEntry;
474    if (moduleSrcEntry) {
475      abilityPages.push(moduleSrcEntry);
476      abilityPagesFullPath.add(getAbilityFullPath(projectConfig.projectPath, moduleSrcEntry));
477    } else if (moduleSrcEntrance) {
478      abilityPages.push(moduleSrcEntrance);
479      abilityPagesFullPath.add(getAbilityFullPath(projectConfig.projectPath, moduleSrcEntrance));
480    }
481    if (moduleJson.module.abilities && moduleJson.module.abilities.length > 0) {
482      setEntrance(moduleJson.module.abilities, abilityPages);
483    }
484    if (moduleJson.module.extensionAbilities && moduleJson.module.extensionAbilities.length > 0) {
485      setEntrance(moduleJson.module.extensionAbilities, abilityPages);
486      setCardPages(moduleJson.module.extensionAbilities);
487    }
488  }
489  return abilityPages;
490}
491
492function setEntrance(abilityConfig, abilityPages) {
493  if (abilityConfig && abilityConfig.length > 0) {
494    abilityConfig.forEach(ability => {
495      if (ability.srcEntry) {
496        abilityPages.push(ability.srcEntry);
497        abilityPagesFullPath.add(getAbilityFullPath(projectConfig.projectPath, ability.srcEntry));
498      } else if (ability.srcEntrance) {
499        abilityPages.push(ability.srcEntrance);
500        abilityPagesFullPath.add(getAbilityFullPath(projectConfig.projectPath, ability.srcEntrance));
501      }
502    });
503  }
504}
505
506function setCardPages(extensionAbilities) {
507  if (extensionAbilities && extensionAbilities.length > 0) {
508    extensionAbilities.forEach(extensionAbility => {
509      if (extensionAbility.metadata) {
510        extensionAbility.metadata.forEach(metadata => {
511          if (metadata.resource) {
512            readCardResource(metadata.resource);
513          }
514        });
515      }
516    });
517  }
518}
519
520function readCardResource(resource) {
521  const cardJsonFileName = `${resource.replace(/\$profile\:/, '')}.json`;
522  const modulePagePath = path.resolve(projectConfig.aceProfilePath, cardJsonFileName);
523  if (fs.existsSync(modulePagePath)) {
524    const cardConfig = JSON.parse(fs.readFileSync(modulePagePath, 'utf-8'));
525    if (cardConfig.forms) {
526      cardConfig.forms.forEach(form => {
527        readCardForm(form);
528      });
529    }
530  }
531}
532
533function readCardForm(form) {
534  if ((form.type && form.type === 'eTS') ||
535    (form.uiSyntax && form.uiSyntax === 'arkts')) {
536    const sourcePath = form.src.replace(/\.ets$/, '');
537    const cardPath = path.resolve(projectConfig.projectPath, '..', sourcePath + '.ets');
538    if (cardPath && fs.existsSync(cardPath)) {
539      projectConfig.entryObj['../' + sourcePath] = cardPath + '?entry';
540      setEntryArrayForObf(sourcePath);
541      projectConfig.cardEntryObj['../' + sourcePath] = cardPath;
542      projectConfig.cardObj[cardPath] = sourcePath.replace(/^\.\//, '');
543    }
544  }
545}
546
547function getAbilityFullPath(projectPath, abilityPath) {
548  const finalPath = path.resolve(path.resolve(projectPath, '../'), abilityPath);
549  if (fs.existsSync(finalPath)) {
550    return finalPath.toLowerCase();
551  } else {
552    return path.resolve(abilityPath).toLowerCase();
553  }
554}
555
556function loadWorker(projectConfig, workerFileEntry) {
557  if (workerFileEntry) {
558    projectConfig.entryObj = Object.assign(projectConfig.entryObj, workerFileEntry);
559    const keys = Object.keys(workerFileEntry);
560    for (const key of keys) {
561      setEntryArrayForObf(key);
562    }
563  } else {
564    const workerPath = path.resolve(projectConfig.projectPath, WORKERS_DIR);
565    if (fs.existsSync(workerPath)) {
566      const workerFiles = [];
567      readFile(workerPath, workerFiles);
568      workerFiles.forEach((item) => {
569        if (/\.(ts|js|ets)$/.test(item)) {
570          const relativePath = path.relative(workerPath, item)
571            .replace(/\.(ts|js|ets)$/, '').replace(/\\/g, '/');
572          projectConfig.entryObj[`./${WORKERS_DIR}/` + relativePath] = item;
573          setEntryArrayForObf(WORKERS_DIR, relativePath);
574          abilityPagesFullPath.add(path.resolve(item).toLowerCase());
575        }
576      });
577    }
578  }
579}
580
581let aceBuildJson = {};
582function loadBuildJson() {
583  if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) {
584    aceBuildJson = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString());
585  }
586  if (aceBuildJson.packageManagerType === 'ohpm') {
587    projectConfig.packageManagerType = 'ohpm';
588    projectConfig.packageDir = 'oh_modules';
589    projectConfig.packageJson = 'oh-package.json5';
590  }
591  // add intent framework entry file
592  projectConfig.intentEntry = aceBuildJson.compileEntry || [];
593  if (!!aceBuildJson.otherCompileFiles) {
594    aceBuildJson.otherCompileFiles.forEach(pages => {
595      const entryKey = path.relative(projectConfig.projectPath, pages).replace(/\.(ets|ts|js|mjs|cjs)$/, '');
596      projectConfig.otherCompileFiles[entryKey] = pages;
597      if (/\.ets$/.test(pages)) {
598        abilityPagesFullPath.add(path.resolve(pages).toLowerCase());
599      }
600    });
601  }
602  if (!!aceBuildJson.byteCodeHar) {
603    projectConfig.useTsHar = true;
604  }
605  if (aceBuildJson.updateVersionInfo) {
606    projectConfig.updateVersionInfo = aceBuildJson.updateVersionInfo;
607  }
608}
609
610function initBuildInfo() {
611  projectConfig.projectRootPath = aceBuildJson.projectRootPath;
612  if (projectConfig.compileHar && aceBuildJson.moduleName &&
613    aceBuildJson.modulePathMap[aceBuildJson.moduleName]) {
614    projectConfig.moduleRootPath = aceBuildJson.modulePathMap[aceBuildJson.moduleName];
615  }
616}
617
618function readWorkerFile() {
619  const workerFileEntry = {};
620  if (aceBuildJson.workers) {
621    aceBuildJson.workers.forEach(worker => {
622      if (!/\.(ts|js|ets)$/.test(worker)) {
623        throw Error(
624          '\u001b[31mArkTS:ERROR: File: ' + worker + '.' + '\n' +
625          "  The worker file can only be an '.ets', '.ts', or '.js' file.\u001b[39m"
626        ).message;
627      }
628      const relativePath = path.relative(projectConfig.projectPath, worker);
629      if (filterWorker(relativePath)) {
630        const workerKey = relativePath.replace(/\.(ts|js)$/, '').replace(/\\/g, '/');
631        if (workerFileEntry[workerKey]) {
632          throw Error(
633            '\u001b[31m ERROR: The worker file cannot use the same file name: \n' +
634            workerFileEntry[workerKey] + '\n' + worker + '\u001b[39m'
635          ).message;
636        } else {
637          workerFileEntry[workerKey] = worker;
638          abilityPagesFullPath.add(path.resolve(workerFileEntry[workerKey]).toLowerCase());
639        }
640      }
641    });
642    return workerFileEntry;
643  }
644  return null;
645}
646
647function readPatchConfig() {
648  if (aceBuildJson.patchConfig) {
649    projectConfig.hotReload = (process.env.watchMode === 'true' && !projectConfig.isPreview) ||
650      aceBuildJson.patchConfig.mode === 'hotReload';
651    projectConfig.coldReload = aceBuildJson.patchConfig.mode === COLD_RELOAD_MODE ? true : false;
652    // The "isFirstBuild" field indicates whether it is the first compilation of cold reload mode
653    // It is determined by hvigor and passed via env
654    projectConfig.isFirstBuild = process.env.isFirstBuild === 'false' ? false : true;
655    projectConfig.patchAbcPath = aceBuildJson.patchConfig.patchAbcPath;
656    projectConfig.changedFileList = aceBuildJson.patchConfig.changedFileList ?
657      aceBuildJson.patchConfig.changedFileList : path.join(projectConfig.cachePath, 'changedFileList.json');
658    projectConfig.removeChangedFileListInSdk = aceBuildJson.patchConfig.removeChangedFileListInSdk === 'true' || false;
659    if (!projectConfig.removeChangedFileListInSdk && projectConfig.hotReload) {
660      writeFileSync(projectConfig.changedFileList, JSON.stringify({
661        modifiedFiles: [],
662        removedFiles: []
663      }));
664    }
665  }
666}
667
668function filterWorker(workerPath) {
669  return /\.(ts|js|ets)$/.test(workerPath);
670}
671
672;(function initSystemResource() {
673  const sysResourcePath = path.resolve(__dirname, './sysResource.js');
674  if (fs.existsSync(sysResourcePath)) {
675    resources.sys = require(sysResourcePath).sys;
676  }
677  if (process.env.externalApiPaths) {
678    const sysResourceExtPath = path.resolve(__dirname, process.env.externalApiPaths, 'sysResource.js');
679    if (fs.existsSync(sysResourceExtPath)) {
680      Object.entries(require(sysResourceExtPath).sys).forEach(([key, value]) => {
681        if (key in resources.sys) {
682          Object.assign(resources.sys[key], value);
683        }
684      });
685    }
686  }
687})();
688
689;(function readSystemModules() {
690  const apiDirPath = path.resolve(__dirname, '../../api');
691  const arktsDirPath = path.resolve(__dirname, '../../arkts');
692  const kitsDirPath = path.resolve(__dirname, '../../kits');
693  const systemModulePathArray = [apiDirPath];
694  if (!process.env.isFaMode) {
695    systemModulePathArray.push(arktsDirPath, kitsDirPath);
696  }
697  systemModulePathArray.forEach(systemModulesPath => {
698    if (fs.existsSync(systemModulesPath)) {
699      globalModulePaths.push(systemModulesPath);
700      const modulePaths = [];
701      readFile(systemModulesPath, modulePaths);
702      systemModules.push(...fs.readdirSync(systemModulesPath));
703      ohosSystemModulePaths.push(...modulePaths);
704      const moduleSubdir = modulePaths.filter(filePath => {
705        const dirName = path.dirname(filePath);
706        return !(dirName === apiDirPath || dirName === arktsDirPath || dirName === kitsDirPath);
707      }).map(filePath => {
708        return filePath
709          .replace(apiDirPath, '')
710          .replace(arktsDirPath, '')
711          .replace(kitsDirPath, '')
712          .replace(/(^\\)|(.d.e?ts$)/g, '')
713          .replace(/\\/g, '/');
714      });
715      ohosSystemModuleSubDirPaths.push(...moduleSubdir);
716      allModulesPaths.push(...modulePaths);
717    }
718  });
719  defaultSdkConfigs = [
720    {
721      'apiPath': systemModulePathArray,
722      'prefix': '@ohos'
723    }, {
724      'apiPath': systemModulePathArray,
725      'prefix': '@system'
726    }, {
727      'apiPath': systemModulePathArray,
728      'prefix': '@arkts'
729    }
730  ];
731  const externalApiPathStr = process.env.externalApiPaths || '';
732  const externalApiPaths = externalApiPathStr.split(path.delimiter);
733  collectExternalModules(externalApiPaths);
734  sdkConfigs = [...defaultSdkConfigs, ...extendSdkConfigs];
735})();
736
737function collectExternalModules(sdkPaths) {
738  for (let i = 0; i < sdkPaths.length; i++) {
739    const sdkPath = sdkPaths[i];
740    const sdkConfigPath = path.resolve(sdkPath, 'sdkConfig.json');
741    if (!fs.existsSync(sdkConfigPath)) {
742      continue;
743    }
744    const sdkConfig = JSON.parse(fs.readFileSync(sdkConfigPath, 'utf-8'));
745    if (!sdkConfig.apiPath) {
746      continue;
747    }
748    let externalApiPathArray = [];
749    if (Array.isArray(sdkConfig.apiPath)) {
750      externalApiPathArray = sdkConfig.apiPath;
751    } else {
752      externalApiPathArray.push(sdkConfig.apiPath);
753    }
754    const resolveApiPathArray = [];
755    externalApiPathArray.forEach(element => {
756      const resolvePath = path.resolve(sdkPath, element);
757      resolveApiPathArray.push(resolvePath);
758      if (fs.existsSync(resolvePath)) {
759        const extrenalModulePaths = [];
760        globalModulePaths.push(resolvePath);
761        systemModules.push(...fs.readdirSync(resolvePath));
762        readFile(resolvePath, extrenalModulePaths);
763        allModulesPaths.push(...extrenalModulePaths);
764      }
765    });
766    sdkConfigPrefix += `|${sdkConfig.prefix.replace(/^@/, '')}`;
767    sdkConfig.apiPath = resolveApiPathArray;
768    extendSdkConfigs.push(sdkConfig);
769  }
770}
771
772function readHspResource() {
773  if (aceBuildJson.hspResourcesMap) {
774    projectConfig.hspResourcesMap = true;
775    for (const hspName in aceBuildJson.hspResourcesMap) {
776      if (fs.existsSync(aceBuildJson.hspResourcesMap[hspName])) {
777        const resourceMap = new Map();
778        const hspResourceCollect = resources[hspName] = {};
779        const hspResource = fs.readFileSync(aceBuildJson.hspResourcesMap[hspName], 'utf-8');
780        const resourceArr = hspResource.split(/\n/);
781        processResourceArr(resourceArr, resourceMap, aceBuildJson.hspResourcesMap[hspName]);
782        for (const [key, value] of resourceMap) {
783          hspResourceCollect[key] = value;
784        }
785      }
786    }
787  }
788}
789
790function readAppResource(filePath) {
791  readHspResource();
792  if (fs.existsSync(filePath)) {
793    const appResource = fs.readFileSync(filePath, 'utf-8');
794    const resourceArr = appResource.split(/\n/);
795    const resourceMap = new Map();
796    processResourceArr(resourceArr, resourceMap, filePath);
797    for (let [key, value] of resourceMap) {
798      resources.app[key] = value;
799    }
800  }
801  if (process.env.rawFileResource && process.env.compileMode === 'moduleJson') {
802    resourcesRawfile(process.env.rawFileResource, getStoredFileInfo().resourcesArr);
803  }
804}
805
806function processResourceArr(resourceArr, resourceMap, filePath) {
807  for (let i = 0; i < resourceArr.length; i++) {
808    if (!resourceArr[i].length) {
809      continue;
810    }
811    const resourceData = resourceArr[i].split(/\s/);
812    if (resourceData.length === 3 && !isNaN(Number(resourceData[2]))) {
813      if (resourceMap.get(resourceData[0])) {
814        const resourceKeys = resourceMap.get(resourceData[0]);
815        if (!resourceKeys[resourceData[1]] || resourceKeys[resourceData[1]] !== Number(resourceData[2])) {
816          resourceKeys[resourceData[1]] = Number(resourceData[2]);
817        }
818      } else {
819        let obj = {};
820        obj[resourceData[1]] = Number(resourceData[2]);
821        resourceMap.set(resourceData[0], obj);
822      }
823      if (process.env.compileTool === 'rollup' && process.env.compileMode === 'moduleJson') {
824        getStoredFileInfo().updateResourceList(resourceData[0] + '_' + resourceData[1]);
825      }
826    } else {
827      logger.warn(`\u001b[31m ArkTS:WARN The format of file '${filePath}' is incorrect. \u001b[39m`);
828      break;
829    }
830  }
831}
832
833function hashProjectPath(projectPath) {
834  const hash = crypto.createHash('sha256');
835  hash.update(projectPath.toString());
836  process.env.hashProjectPath = '_' + hash.digest('hex');
837  return process.env.hashProjectPath;
838}
839
840function loadModuleInfo(projectConfig, envArgs) {
841  if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) {
842    const buildJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString());
843    if (buildJsonInfo.compileMode) {
844      projectConfig.compileMode = buildJsonInfo.compileMode;
845    }
846    projectConfig.projectRootPath = buildJsonInfo.projectRootPath;
847    projectConfig.modulePathMap = buildJsonInfo.modulePathMap;
848    projectConfig.isOhosTest = buildJsonInfo.isOhosTest;
849    let faultHandler = function (error) {
850      // rollup's error will be handled in fast build
851      if (process.env.compileTool === 'rollup') {
852        return;
853      }
854      logger.error(error);
855      process.exit(FAIL);
856    };
857    projectConfig.es2abcCompileTsInAotMode = true;
858    projectConfig.es2abcCompileTsInNonAotMode = false;
859    const compileMode = process.env.compileTool === 'rollup' ? projectConfig.compileMode : buildJsonInfo.compileMode;
860    if (checkAotConfig(compileMode, buildJsonInfo, faultHandler)) {
861      projectConfig.processTs = true;
862      projectConfig.pandaMode = TS2ABC;
863      projectConfig.anBuildOutPut = buildJsonInfo.anBuildOutPut;
864      projectConfig.anBuildMode = buildJsonInfo.anBuildMode;
865      projectConfig.apPath = buildJsonInfo.apPath;
866      if (projectConfig.es2abcCompileTsInAotMode) {
867        projectConfig.pandaMode = ES2ABC;
868      }
869    } else {
870      projectConfig.processTs = false;
871      projectConfig.pandaMode = buildJsonInfo.pandaMode;
872      if (projectConfig.es2abcCompileTsInNonAotMode) {
873        projectConfig.pandaMode = ES2ABC;
874        projectConfig.processTs = true;
875      }
876    }
877    if (envArgs !== undefined) {
878      projectConfig.buildArkMode = envArgs.buildMode;
879    }
880    if (compileMode === 'esmodule') {
881      projectConfig.nodeModulesPath = buildJsonInfo.nodeModulesPath;
882      projectConfig.harNameOhmMap = buildJsonInfo.harNameOhmMap;
883    }
884    if (projectConfig.compileHar && buildJsonInfo.moduleName &&
885      buildJsonInfo.modulePathMap[buildJsonInfo.moduleName]) {
886      if (projectConfig.useTsHar) {
887        projectConfig.processTs = true;
888      }
889      projectConfig.moduleRootPath = buildJsonInfo.modulePathMap[buildJsonInfo.moduleName];
890    }
891  }
892}
893
894function checkAppResourcePath(appResourcePath, config) {
895  if (appResourcePath) {
896    readAppResource(appResourcePath);
897    if (fs.existsSync(appResourcePath) && config.cache) {
898      config.cache.buildDependencies.config.push(appResourcePath);
899    }
900    if (!projectConfig.xtsMode) {
901      const appResourcePathSavePath = path.resolve(projectConfig.cachePath, 'resource_path.txt');
902      saveAppResourcePath(appResourcePath, appResourcePathSavePath);
903      if (fs.existsSync(appResourcePathSavePath) && config.cache) {
904        config.cache.buildDependencies.config.push(appResourcePathSavePath);
905      }
906    }
907  }
908}
909
910function saveAppResourcePath(appResourcePath, appResourcePathSavePath) {
911  let isSave = false;
912  if (fs.existsSync(appResourcePathSavePath)) {
913    const saveContent = fs.readFileSync(appResourcePathSavePath);
914    if (appResourcePath !== saveContent) {
915      isSave = true;
916    }
917  } else {
918    isSave = true;
919  }
920  if (isSave) {
921    fs.writeFileSync(appResourcePathSavePath, appResourcePath);
922  }
923}
924
925function addSDKBuildDependencies(config) {
926  if (projectConfig.localPropertiesPath &&
927    fs.existsSync(projectConfig.localPropertiesPath) && config.cache) {
928    config.cache.buildDependencies.config.push(projectConfig.localPropertiesPath);
929  }
930  if (projectConfig.projectProfilePath &&
931    fs.existsSync(projectConfig.projectProfilePath) && config.cache) {
932    config.cache.buildDependencies.config.push(projectConfig.projectProfilePath);
933  }
934}
935
936function getCleanConfig(workerFile) {
937  const cleanPath = [];
938  if (projectConfig.compileMode === 'esmodule') {
939    return cleanPath;
940  }
941  cleanPath.push(projectConfig.buildPath);
942  if (workerFile) {
943    const workerFilesPath = Object.keys(workerFile);
944    for (const workerFilePath of workerFilesPath) {
945      cleanPath.push(path.join(projectConfig.buildPath, workerFilePath, '..'));
946    }
947  }
948  return cleanPath;
949}
950
951function isPartialUpdate(metadata, moduleType) {
952  if (!Array.isArray(metadata) || !metadata.length) {
953    return;
954  }
955  metadata.some(item => {
956    if (item.name && item.value) {
957      if (item.name === 'ArkTSPartialUpdate' && item.value === 'false') {
958        partialUpdateConfig.partialUpdateMode = false;
959        if (projectConfig.aceModuleJsonPath) {
960          logger.warn('\u001b[33m ArkTS:WARN File: ' + projectConfig.aceModuleJsonPath + '.' + '\n' +
961          " The 'ArkTSPartialUpdate' field will no longer be supported in the future. \u001b[39m");
962        }
963      }
964      if (item.name === 'ArkTSBuilderCheck' && item.value === 'false') {
965        partialUpdateConfig.builderCheck = false;
966      }
967      if (item.name === 'Api11ArkTSCheck' && item.value === 'SkipArkTSCheckInApi11') {
968        partialUpdateConfig.executeArkTSLinter = false;
969      }
970      if (item.name === 'Api11ArkTSCheckMode' && item.value === 'DoArkTSCheckInCompatibleModeInApi11') {
971        partialUpdateConfig.standardArkTSLinter = false;
972      }
973      if (item.name === 'ArkTSVersion') {
974        partialUpdateConfig.arkTSVersion = item.value;
975      }
976      if (item.name === 'OPTLazyForEach' && item.value === 'true') {
977        projectConfig.optLazyForEach = true;
978      }
979      if (item.name === 'SkipTscOhModuleCheck' && item.value === 'true') {
980        partialUpdateConfig.skipTscOhModuleCheck = true;
981      }
982      if (item.name === 'SkipArkTSStaticBlocksCheck' && item.value === 'true') {
983        partialUpdateConfig.skipArkTSStaticBlocksCheck = true;
984      }
985      if (item.name === 'ArkoalaPlugin' && item.value === 'true') {
986        projectConfig.useArkoala = true;
987      }
988      if (item.name === 'UseTsHar' && item.value === 'true' && moduleType === 'har') {
989        projectConfig.useTsHar = true;
990      }
991      if (item.name === 'OptTryCatchFunc' && item.value === 'false') {
992        projectConfig.optTryCatchFunc = false;
993      }
994    }
995    return !partialUpdateConfig.partialUpdateMode && !partialUpdateConfig.builderCheck &&
996      !partialUpdateConfig.executeArkTSLinter && !partialUpdateConfig.standardArkTSLinter &&
997      partialUpdateConfig.arkTSVersion !== undefined && projectConfig.optLazyForEach &&
998      partialUpdateConfig.skipTscOhModuleCheck && partialUpdateConfig.skipArkTSStaticBlocksCheck;
999  });
1000}
1001
1002function applicationConfig() {
1003  const localProperties = path.resolve(aceBuildJson.projectRootPath, 'local.properties');
1004  if (fs.existsSync(localProperties)) {
1005    try {
1006      const localPropertiesFile = fs.readFileSync(localProperties, {encoding: 'utf-8'}).split(/\r?\n/);
1007      localPropertiesFile.some((item) => {
1008        const builderCheckValue = item.replace(/\s+|;/g, '');
1009        if (builderCheckValue === 'ArkTSConfig.ArkTSBuilderCheck=false') {
1010          partialUpdateConfig.builderCheck = false;
1011          return true;
1012        }
1013      });
1014    } catch (err) {
1015    }
1016  }
1017}
1018
1019function partialUpdateController(minAPIVersion, metadata = null, moduleType = '') {
1020  projectConfig.minAPIVersion = minAPIVersion;
1021  if (minAPIVersion >= 9) {
1022    partialUpdateConfig.partialUpdateMode = true;
1023  }
1024  const MIN_VERSION_OPTIMIZE_COMPONENT = 10;
1025  if (minAPIVersion < MIN_VERSION_OPTIMIZE_COMPONENT) {
1026    partialUpdateConfig.optimizeComponent = false;
1027  }
1028  if (metadata) {
1029    isPartialUpdate(metadata, moduleType);
1030  }
1031  if (aceBuildJson.projectRootPath) {
1032    applicationConfig();
1033  }
1034}
1035
1036const globalProgram = {
1037  builderProgram: null,
1038  program: null,
1039  watchProgram: null,
1040  checker: null,
1041  strictChecker: null,
1042  strictLanguageService: null,
1043};
1044
1045const partialUpdateConfig = {
1046  partialUpdateMode: false,
1047  builderCheck: true,
1048  executeArkTSLinter: true,
1049  standardArkTSLinter: true,
1050  optimizeComponent: true,
1051  arkTSVersion: undefined,
1052  skipTscOhModuleCheck: false,
1053  skipArkTSStaticBlocksCheck: false,
1054};
1055
1056function resetMain() {
1057  staticPreviewPage = undefined;
1058  aceCompileMode = 'page';
1059  resetAbilityConfig();
1060  resetProjectConfig();
1061  resources.app = {};
1062  abilityPagesFullPath.clear();
1063  aceBuildJson = {};
1064  partialUpdateConfig.builderCheck = true;
1065  globalModulePaths = [];
1066  sdkConfigs = [];
1067  defaultSdkConfigs = [];
1068  extendSdkConfigs = [];
1069  sdkConfigPrefix = 'ohos|system|kit';
1070  ohosSystemModulePaths = [];
1071  ohosSystemModuleSubDirPaths = [];
1072  allModulesPaths = [];
1073}
1074
1075function resetAbilityConfig() {
1076  abilityConfig.abilityType = 'page';
1077  abilityConfig.abilityEntryFile = null;
1078  abilityConfig.projectAbilityPath = [];
1079  abilityConfig.testRunnerFile = [];
1080}
1081
1082function resetProjectConfig() {
1083  projectConfig.entryObj = {};
1084  projectConfig.entryArrayForObf = [];
1085  projectConfig.cardObj = {};
1086  projectConfig.compileHar = false;
1087  projectConfig.compileShared = false;
1088  projectConfig.packageDir = 'node_modules';
1089  projectConfig.packageJson = 'package.json';
1090  projectConfig.packageManagerType = 'npm';
1091  projectConfig.cardEntryObj = {};
1092  projectConfig.compilerTypes = [];
1093  projectConfig.optLazyForEach = false;
1094  projectConfig.hspResourcesMap = false;
1095  projectConfig.coldReload = undefined;
1096  projectConfig.hotReload = undefined;
1097  projectConfig.isFirstBuild = undefined;
1098  projectConfig.changedFileList = undefined;
1099  projectConfig.patchAbcPath = undefined;
1100  projectConfig.removeChangedFileListInSdk = false;
1101  const props = ['projectPath', 'buildPath', 'aceModuleBuild', 'manifestFilePath', 'aceProfilePath',
1102    'aceModuleJsonPath', 'aceSuperVisualPath', 'hashProjectPath', 'aceBuildJson', 'cachePath',
1103    'aceSoPath', 'localPropertiesPath', 'projectProfilePath', 'isPreview', 'compileMode', 'runtimeOS',
1104    'sdkInfo', 'checkEntry', 'obfuscateHarType', 'isCrossplatform', 'enableDebugLine', 'bundleType'
1105  ];
1106  for (let key in projectConfig) {
1107    if (props.includes(key)) {
1108      projectConfig[key] = undefined;
1109    }
1110  }
1111  projectConfig.otherCompileFiles = {};
1112  projectConfig.updateVersionInfo = undefined;
1113}
1114
1115function resetGlobalProgram() {
1116  globalProgram.builderProgram = null;
1117  globalProgram.program = null;
1118  globalProgram.checker = null;
1119  globalProgram.strictChecker = null;
1120  globalProgram.strictLanguageService = null;
1121}
1122
1123function initMain() {
1124  staticPreviewPage = process.env.aceStaticPreview;
1125  aceCompileMode = process.env.aceCompileMode || 'page';
1126  abilityConfig.abilityType = process.env.abilityType || 'page';
1127}
1128
1129exports.globalProgram = globalProgram;
1130exports.projectConfig = projectConfig;
1131exports.loadEntryObj = loadEntryObj;
1132exports.readAppResource = readAppResource;
1133exports.resources = resources;
1134exports.loadWorker = loadWorker;
1135exports.abilityConfig = abilityConfig;
1136exports.readWorkerFile = readWorkerFile;
1137exports.abilityPagesFullPath = abilityPagesFullPath;
1138exports.loadModuleInfo = loadModuleInfo;
1139exports.systemModules = systemModules;
1140exports.checkAppResourcePath = checkAppResourcePath;
1141exports.addSDKBuildDependencies = addSDKBuildDependencies;
1142exports.partialUpdateConfig = partialUpdateConfig;
1143exports.readPatchConfig = readPatchConfig;
1144exports.initBuildInfo = initBuildInfo;
1145exports.getCleanConfig = getCleanConfig;
1146exports.globalModulePaths = globalModulePaths;
1147exports.defaultSdkConfigs = defaultSdkConfigs;
1148exports.extendSdkConfigs = extendSdkConfigs;
1149exports.sdkConfigs = sdkConfigs;
1150exports.sdkConfigPrefix = sdkConfigPrefix;
1151exports.ohosSystemModulePaths = ohosSystemModulePaths;
1152exports.resetMain = resetMain;
1153exports.ohosSystemModuleSubDirPaths = ohosSystemModuleSubDirPaths;
1154exports.allModulesPaths = allModulesPaths;
1155exports.resetProjectConfig = resetProjectConfig;
1156exports.resetGlobalProgram = resetGlobalProgram;
1157exports.setEntryArrayForObf = setEntryArrayForObf;
1158