• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  storedFileInfo
26} = require('./lib/utils');
27
28const {
29  WORKERS_DIR,
30  TEST_RUNNER_DIR_SET,
31  TS2ABC,
32  ES2ABC,
33  FAIL
34} = require('./lib/pre_define');
35
36const {
37  checkAotConfig
38} = require('./lib/gen_aot');
39
40const {
41  configure,
42  getLogger
43} = require('log4js');
44
45configure({
46  appenders: { 'ETS': {type: 'stderr', layout: {type: 'messagePassThrough'}}},
47  categories: {'default': {appenders: ['ETS'], level: 'info'}}
48});
49const logger = getLogger('ETS');
50
51const staticPreviewPage = process.env.aceStaticPreview;
52const aceCompileMode = process.env.aceCompileMode || 'page';
53const abilityConfig = {
54  abilityType: process.env.abilityType || 'page',
55  abilityEntryFile: null,
56  projectAbilityPath: [],
57  testRunnerFile: []
58};
59const projectConfig = {};
60const resources = {
61  app: {},
62  sys: {}
63};
64const systemModules = [];
65const abilityPagesFullPath = [];
66const globalModulePaths = [];
67let sdkConfigs = [];
68let defaultSdkConfigs = [];
69const extendSdkConfigs = [];
70let sdkConfigPrefix = 'ohos|system';
71let ohosSystemModulePaths = [];
72
73function initProjectConfig(projectConfig) {
74  projectConfig.entryObj = {};
75  projectConfig.cardObj = {};
76  projectConfig.projectPath = projectConfig.projectPath || process.env.aceModuleRoot ||
77    path.join(process.cwd(), 'sample');
78  projectConfig.buildPath = projectConfig.buildPath || process.env.aceModuleBuild ||
79    path.resolve(projectConfig.projectPath, 'build');
80  projectConfig.aceModuleBuild = projectConfig.buildPath; // To be compatible with both webpack and rollup
81  projectConfig.manifestFilePath = projectConfig.manifestFilePath || process.env.aceManifestPath ||
82    path.join(projectConfig.projectPath, 'manifest.json');
83  projectConfig.aceProfilePath = projectConfig.aceProfilePath || process.env.aceProfilePath;
84  projectConfig.aceModuleJsonPath = projectConfig.aceModuleJsonPath || process.env.aceModuleJsonPath;
85  projectConfig.aceSuperVisualPath = projectConfig.aceSuperVisualPath ||
86    process.env.aceSuperVisualPath;
87  projectConfig.hashProjectPath = projectConfig.hashProjectPath ||
88    hashProjectPath(projectConfig.projectPath);
89  projectConfig.aceBuildJson = projectConfig.aceBuildJson || process.env.aceBuildJson;
90  projectConfig.cachePath = projectConfig.cachePath || process.env.cachePath ||
91    path.resolve(__dirname, 'node_modules/.cache');
92  projectConfig.aceSoPath = projectConfig.aceSoPath || process.env.aceSoPath;
93  projectConfig.xtsMode = /ets_loader_ark$/.test(__dirname);
94  projectConfig.localPropertiesPath = projectConfig.localPropertiesPath || process.env.localPropertiesPath;
95  projectConfig.projectProfilePath = projectConfig.projectProfilePath || process.env.projectProfilePath;
96  projectConfig.isPreview = projectConfig.isPreview || process.env.isPreview === 'true';
97  projectConfig.compileMode = projectConfig.compileMode || 'jsbundle';
98  projectConfig.runtimeOS = projectConfig.runtimeOS || process.env.runtimeOS || 'default';
99  projectConfig.sdkInfo = projectConfig.sdkInfo || process.env.sdkInfo || 'default';
100  projectConfig.compileHar = false;
101  projectConfig.compileShared = false;
102  projectConfig.splitCommon = false;
103  projectConfig.checkEntry = projectConfig.checkEntry || process.env.checkEntry;
104  projectConfig.obfuscateHarType = projectConfig.obfuscateHarType || process.env.obfuscate;
105  projectConfig.packageDir = 'node_modules';
106  projectConfig.packageJson = 'package.json';
107  projectConfig.packageManagerType = 'npm';
108  projectConfig.cardEntryObj = {};
109  projectConfig.compilerTypes = [];
110  projectConfig.isCrossplatform = projectConfig.isCrossplatform || false;
111}
112
113function loadEntryObj(projectConfig) {
114  let manifest = {};
115  initProjectConfig(projectConfig);
116  loadBuildJson();
117  if (process.env.aceManifestPath && aceCompileMode === 'page') {
118    setEntryFile(projectConfig);
119    setFaTestRunnerFile(projectConfig);
120  }
121  if (process.env.aceModuleJsonPath) {
122    setAbilityPages(projectConfig);
123    setStageTestRunnerFile(projectConfig);
124  }
125
126  if (staticPreviewPage) {
127    projectConfig.entryObj['./' + staticPreviewPage] = projectConfig.projectPath + path.sep +
128      staticPreviewPage + '.ets?entry';
129  } else if (abilityConfig.abilityType === 'page') {
130    if (fs.existsSync(projectConfig.manifestFilePath)) {
131      const jsonString = fs.readFileSync(projectConfig.manifestFilePath).toString();
132      manifest = JSON.parse(jsonString);
133      if (manifest && manifest.minPlatformVersion) {
134        process.env.minPlatformVersion = manifest.minPlatformVersion;
135        partialUpdateController(manifest.minPlatformVersion);
136      }
137      projectConfig.pagesJsonFileName = 'config.json';
138    } else if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) {
139      process.env.compileMode = 'moduleJson';
140      buildManifest(manifest, projectConfig.aceModuleJsonPath);
141    } else {
142      throw Error('\u001b[31m ERROR: the manifest file ' + projectConfig.manifestFilePath.replace(/\\/g, '/') +
143        ' or module.json is lost or format is invalid. \u001b[39m').message;
144    }
145    if (!projectConfig.compileHar) {
146      if (manifest.pages) {
147        const pages = manifest.pages;
148        pages.forEach((element) => {
149          const sourcePath = element.replace(/^\.\/ets\//, '');
150          const fileName = path.resolve(projectConfig.projectPath, sourcePath + '.ets');
151          if (fs.existsSync(fileName)) {
152            projectConfig.entryObj['./' + sourcePath] = fileName + '?entry';
153          } else {
154            throw Error(`\u001b[31m ERROR: page '${fileName.replace(/\\/g, '/')}' does not exist. \u001b[39m`)
155              .message;
156          }
157        });
158      } else {
159        throw Error('\u001b[31m ERROR: missing pages attribute in ' +
160          projectConfig.manifestFilePath.replace(/\\/g, '/') +
161          '. \u001b[39m').message;
162      }
163    }
164  }
165}
166
167function buildManifest(manifest, aceConfigPath) {
168  try {
169    const moduleConfigJson = JSON.parse(fs.readFileSync(aceConfigPath).toString());
170    manifest.type = process.env.abilityType;
171    if (moduleConfigJson && moduleConfigJson.app && moduleConfigJson.app.minAPIVersion) {
172      if (moduleConfigJson.module && moduleConfigJson.module.metadata) {
173        partialUpdateController(moduleConfigJson.app.minAPIVersion, moduleConfigJson.module.metadata);
174        stageOptimization(moduleConfigJson.module.metadata);
175      } else {
176        partialUpdateController(moduleConfigJson.app.minAPIVersion);
177      }
178    }
179    if (moduleConfigJson.module) {
180      switch (moduleConfigJson.module.type) {
181        case 'har':
182          projectConfig.compileHar = true;
183          getPackageJsonEntryPath();
184          break;
185        case 'shared':
186          projectConfig.compileShared = true;
187          getPackageJsonEntryPath();
188          manifest.pages = getPages(moduleConfigJson);
189          break;
190        default:
191          manifest.pages = getPages(moduleConfigJson);
192          break;
193      }
194    } else {
195      throw Error('\u001b[31m' +
196        'BUIDERROR: the config.json file miss key word module || module[abilities].' +
197        '\u001b[39m').message;
198    }
199  } catch (e) {
200    if (/BUIDERROR/.test(e)) {
201      throw Error(e.replace('BUIDERROR', 'ERROR')).message;
202    } else {
203      throw Error('\x1B[31m' + 'ERROR: the module.json file is lost or format is invalid.' +
204        '\x1B[39m').message;
205    }
206  }
207}
208
209function getPackageJsonEntryPath() {
210  const rootPackageJsonPath = path.resolve(projectConfig.projectPath, '../../../' + projectConfig.packageJson);
211  if (fs.existsSync(rootPackageJsonPath)) {
212    let rootPackageJsonContent;
213    try {
214      rootPackageJsonContent = (projectConfig.packageManagerType === 'npm' ?
215        JSON : JSON5).parse(fs.readFileSync(rootPackageJsonPath, 'utf-8'));
216    } catch (e) {
217      throw Error('\u001b[31m' + 'BUIDERROR: ' + rootPackageJsonPath + ' format is invalid.' + '\u001b[39m').message;
218    }
219    if (rootPackageJsonContent) {
220      if (rootPackageJsonContent.module) {
221        getEntryPath(rootPackageJsonContent.module, rootPackageJsonPath);
222      } else if (rootPackageJsonContent.main) {
223        getEntryPath(rootPackageJsonContent.main, rootPackageJsonPath);
224      } else {
225        getEntryPath('', rootPackageJsonPath);
226      }
227    } else if (projectConfig.compileHar) {
228      throw Error('\u001b[31m' + 'BUIDERROR: lack message in ' + projectConfig.packageJson + '.' +
229        '\u001b[39m').message;
230    }
231  }
232}
233
234function supportSuffix(mainEntryPath) {
235  if (fs.existsSync(path.join(mainEntryPath, 'index.ets'))) {
236    mainEntryPath = path.join(mainEntryPath, 'index.ets');
237  } else if (fs.existsSync(path.join(mainEntryPath, 'index.ts'))) {
238    mainEntryPath = path.join(mainEntryPath, 'index.ts');
239  } else if (fs.existsSync(path.join(mainEntryPath, 'index.js'))) {
240    mainEntryPath = path.join(mainEntryPath, 'index.js');
241  } else if (projectConfig.compileHar) {
242    throw Error('\u001b[31m' + 'BUIDERROR: not find entry file in ' + projectConfig.packageJson +
243      '.' + '\u001b[39m').message;
244  }
245  return mainEntryPath;
246}
247
248function supportExtName(mainEntryPath) {
249  if (path.extname(mainEntryPath) === '') {
250    if (fs.existsSync(mainEntryPath + '.ets')) {
251      mainEntryPath = mainEntryPath + '.ets';
252    } else if (fs.existsSync(mainEntryPath + '.ts')) {
253      mainEntryPath = mainEntryPath + '.ts';
254    } else if (fs.existsSync(mainEntryPath + '.js')) {
255      mainEntryPath = mainEntryPath + '.js';
256    }
257  }
258  return mainEntryPath;
259}
260
261function getEntryPath(entryPath, rootPackageJsonPath) {
262  let mainEntryPath = path.resolve(rootPackageJsonPath, '../', entryPath);
263  if (fs.existsSync(mainEntryPath) && fs.statSync(mainEntryPath).isDirectory()) {
264    mainEntryPath = supportSuffix(mainEntryPath);
265  } else {
266    mainEntryPath = supportExtName(mainEntryPath);
267  }
268  if (fs.existsSync(mainEntryPath) && fs.statSync(mainEntryPath).isFile()) {
269    const entryKey = path.relative(projectConfig.projectPath, mainEntryPath);
270    projectConfig.entryObj[entryKey] = mainEntryPath;
271    abilityPagesFullPath.push(path.resolve(mainEntryPath).toLowerCase());
272  } else if (projectConfig.compileHar) {
273    throw Error('\u001b[31m' + `BUIDERROR: not find entry file in ${rootPackageJsonPath}.` + '\u001b[39m').message;
274  }
275}
276
277function stageOptimization(metadata) {
278  if (Array.isArray(metadata) && metadata.length) {
279    metadata.some(item => {
280      if (item.name && item.name === 'USE_COMMON_CHUNK' &&
281        item.value && item.value === 'true') {
282        projectConfig.splitCommon = true;
283        return true;
284      }
285    });
286  }
287}
288
289function getPages(configJson) {
290  const pages = [];
291  let pagesJsonFileName = '';
292  // pages is not necessary in stage
293  if (process.env.compileMode === 'moduleJson' && configJson.module && configJson.module.pages) {
294    pagesJsonFileName = `${configJson.module.pages.replace(/\$profile\:/, '')}.json`;
295  } else {
296    return pages;
297  }
298  const modulePagePath = path.resolve(projectConfig.aceProfilePath, pagesJsonFileName);
299  if (fs.existsSync(modulePagePath)) {
300    try {
301      const pagesConfig = JSON.parse(fs.readFileSync(modulePagePath, 'utf-8'));
302      if (pagesConfig && pagesConfig.src) {
303        projectConfig.pagesJsonFileName = pagesJsonFileName;
304        return pagesConfig.src;
305      }
306    } catch (e) {
307      throw Error("\x1B[31m" + `BUIDERROR: the ${modulePagePath} file format is invalid.` +
308        "\x1B[39m").message;
309    }
310  }
311  return pages;
312}
313
314function setEntryFile(projectConfig) {
315  const entryFileName = abilityConfig.abilityType === 'page' ? 'app' : abilityConfig.abilityType;
316  const extendFile = entryFileName === 'app' ? '.ets' : '.ts';
317  const entryFileRealPath = entryFileName + extendFile;
318  const entryFilePath = path.resolve(projectConfig.projectPath, entryFileRealPath);
319  abilityConfig.abilityEntryFile = entryFilePath;
320  if (!fs.existsSync(entryFilePath) && aceCompileMode === 'page') {
321    throw Error(`\u001b[31m ERROR: missing ${entryFilePath.replace(/\\/g, '/')}. \u001b[39m`).message;
322  }
323  projectConfig.entryObj[`./${entryFileName}`] = entryFilePath + '?entry';
324}
325
326function setAbilityPages(projectConfig) {
327  let abilityPages = [];
328  if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) {
329    const moduleJson = JSON.parse(fs.readFileSync(projectConfig.aceModuleJsonPath).toString());
330    abilityPages = readAbilityEntrance(moduleJson);
331    setAbilityFile(projectConfig, abilityPages);
332    setBundleModuleInfo(projectConfig, moduleJson);
333  }
334}
335
336function setTestRunnerFile(projectConfig, isStageBased) {
337  const index = projectConfig.projectPath.split(path.sep).join('/').lastIndexOf('\/');
338  TEST_RUNNER_DIR_SET.forEach((dir) => {
339    const projectPath = isStageBased ? projectConfig.projectPath : projectConfig.projectPath.substring(0, index + 1);
340    const testRunnerPath = path.resolve(projectPath, dir);
341    if (fs.existsSync(testRunnerPath)) {
342      const testRunnerFiles = [];
343      readFile(testRunnerPath, testRunnerFiles);
344      testRunnerFiles.forEach((item) => {
345        if (/\.(ts|js|ets)$/.test(item)) {
346          if (/\.ets$/.test(item)) {
347            abilityPagesFullPath.push(path.resolve(item).toLowerCase());
348          }
349          const relativePath = path.relative(testRunnerPath, item).replace(/\.(ts|js|ets)$/, '');
350          if (isStageBased) {
351            projectConfig.entryObj[`./${dir}/${relativePath}`] = item;
352          } else {
353            projectConfig.entryObj[`../${dir}/${relativePath}`] = item;
354          }
355          abilityConfig.testRunnerFile.push(item);
356        }
357      });
358    }
359  });
360}
361
362function setFaTestRunnerFile(projectConfig) {
363  setTestRunnerFile(projectConfig, false);
364}
365
366function setStageTestRunnerFile(projectConfig) {
367  setTestRunnerFile(projectConfig, true);
368}
369
370function setBundleModuleInfo(projectConfig, moduleJson) {
371  if (moduleJson.module) {
372    projectConfig.moduleName = moduleJson.module.name;
373  }
374  if (moduleJson.app) {
375    projectConfig.bundleName = moduleJson.app.bundleName;
376  }
377}
378
379function setAbilityFile(projectConfig, abilityPages) {
380  abilityPages.forEach(abilityPath => {
381    const projectAbilityPath = path.resolve(projectConfig.projectPath, '../', abilityPath);
382    if (path.isAbsolute(abilityPath)) {
383      abilityPath = '.' + abilityPath.slice(projectConfig.projectPath.length);
384    }
385    const entryPageKey = abilityPath.replace(/^\.\/ets\//, './').replace(/\.ts$/, '').replace(/\.ets$/, '');
386    if (fs.existsSync(projectAbilityPath)) {
387      abilityConfig.projectAbilityPath.push(projectAbilityPath);
388      projectConfig.entryObj[entryPageKey] = projectAbilityPath + '?entry';
389    } else {
390      throw Error(
391        `\u001b[31m ERROR: srcEntry file '${projectAbilityPath.replace(/\\/g, '/')}' does not exist. \u001b[39m`
392      ).message;
393    }
394  });
395}
396
397function readAbilityEntrance(moduleJson) {
398  const abilityPages = [];
399  if (moduleJson.module) {
400    const moduleSrcEntrance = moduleJson.module.srcEntrance;
401    const moduleSrcEntry = moduleJson.module.srcEntry;
402    if (moduleSrcEntry) {
403      abilityPages.push(moduleSrcEntry);
404      abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, moduleSrcEntry));
405    } else if (moduleSrcEntrance) {
406      abilityPages.push(moduleSrcEntrance);
407      abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, moduleSrcEntrance));
408    }
409    if (moduleJson.module.abilities && moduleJson.module.abilities.length > 0) {
410      setEntrance(moduleJson.module.abilities, abilityPages);
411    }
412    if (moduleJson.module.extensionAbilities && moduleJson.module.extensionAbilities.length > 0) {
413      setEntrance(moduleJson.module.extensionAbilities, abilityPages);
414      setCardPages(moduleJson.module.extensionAbilities);
415    }
416  }
417  return abilityPages;
418}
419
420function setEntrance(abilityConfig, abilityPages) {
421  if (abilityConfig && abilityConfig.length > 0) {
422    abilityConfig.forEach(ability => {
423      if (ability.srcEntry) {
424        abilityPages.push(ability.srcEntry)
425        abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, ability.srcEntry))
426      } else if (ability.srcEntrance) {
427        abilityPages.push(ability.srcEntrance);
428        abilityPagesFullPath.push(getAbilityFullPath(projectConfig.projectPath, ability.srcEntrance));
429      }
430    });
431  }
432}
433
434function setCardPages(extensionAbilities) {
435  if (extensionAbilities && extensionAbilities.length > 0) {
436    extensionAbilities.forEach(extensionAbility => {
437      if (extensionAbility.metadata) {
438        extensionAbility.metadata.forEach(metadata => {
439          if (metadata.resource) {
440            readCardResource(metadata.resource);
441          }
442        });
443      }
444    });
445  }
446}
447
448function readCardResource(resource) {
449  const cardJsonFileName = `${resource.replace(/\$profile\:/, '')}.json`;
450  const modulePagePath = path.resolve(projectConfig.aceProfilePath, cardJsonFileName);
451  if (fs.existsSync(modulePagePath)) {
452    const cardConfig = JSON.parse(fs.readFileSync(modulePagePath, 'utf-8'));
453    if (cardConfig.forms) {
454      cardConfig.forms.forEach(form => {
455        readCardForm(form);
456      });
457    }
458  }
459}
460
461function readCardForm(form) {
462  if ((form.type && form.type === 'eTS') ||
463    (form.uiSyntax && form.uiSyntax === 'arkts')) {
464    const sourcePath = form.src.replace(/\.ets$/, '');
465    const cardPath = path.resolve(projectConfig.projectPath, '..', sourcePath + '.ets');
466    if (cardPath && fs.existsSync(cardPath)) {
467      projectConfig.entryObj['../' + sourcePath] = cardPath + '?entry';
468      projectConfig.cardEntryObj['../' + sourcePath] = cardPath;
469      projectConfig.cardObj[cardPath] = sourcePath.replace(/^\.\//, '');
470    }
471  }
472}
473
474function getAbilityFullPath(projectPath, abilityPath) {
475  const finalPath = path.resolve(path.resolve(projectPath, '../'), abilityPath);
476  if (fs.existsSync(finalPath)) {
477    return finalPath.toLowerCase();
478  } else {
479    return path.resolve(abilityPath).toLowerCase();
480  }
481}
482
483function loadWorker(projectConfig, workerFileEntry) {
484  if (workerFileEntry) {
485    projectConfig.entryObj = Object.assign(projectConfig.entryObj, workerFileEntry);
486  } else {
487    const workerPath = path.resolve(projectConfig.projectPath, WORKERS_DIR);
488    if (fs.existsSync(workerPath)) {
489      const workerFiles = [];
490      readFile(workerPath, workerFiles);
491      workerFiles.forEach((item) => {
492        if (/\.(ts|js|ets)$/.test(item)) {
493          const relativePath = path.relative(workerPath, item)
494            .replace(/\.(ts|js|ets)$/, '').replace(/\\/g, '/');
495          projectConfig.entryObj[`./${WORKERS_DIR}/` + relativePath] = item;
496          abilityPagesFullPath.push(path.resolve(item).toLowerCase());
497        }
498      });
499    }
500  }
501}
502
503let aceBuildJson = {};
504function loadBuildJson() {
505  if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) {
506    aceBuildJson = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString());
507  }
508  if (aceBuildJson.packageManagerType === 'ohpm') {
509    projectConfig.packageManagerType = 'ohpm';
510    projectConfig.packageDir = 'oh_modules';
511    projectConfig.packageJson = 'oh-package.json5';
512  }
513}
514
515function initBuildInfo() {
516  projectConfig.projectRootPath = aceBuildJson.projectRootPath;
517  if (projectConfig.compileHar && aceBuildJson.moduleName &&
518    aceBuildJson.modulePathMap[aceBuildJson.moduleName]) {
519    projectConfig.moduleRootPath = aceBuildJson.modulePathMap[aceBuildJson.moduleName];
520  }
521}
522
523function readWorkerFile() {
524  const workerFileEntry = {};
525  if (aceBuildJson.workers) {
526    aceBuildJson.workers.forEach(worker => {
527      if (!/\.(ts|js|ets)$/.test(worker)) {
528        throw Error(
529          '\u001b[31mArkTS:ERROR: File: ' + worker + '.' + '\n' +
530          "  The worker file can only be an '.ets', '.ts', or '.js' file.\u001b[39m"
531        ).message;
532      }
533      const relativePath = path.relative(projectConfig.projectPath, worker);
534      if (filterWorker(relativePath)) {
535        const workerKey = relativePath.replace(/\.(ts|js)$/, '').replace(/\\/g, '/');
536        if (workerFileEntry[workerKey]) {
537          throw Error(
538            '\u001b[31m ERROR: The worker file cannot use the same file name: \n' +
539            workerFileEntry[workerKey] + '\n' + worker + '\u001b[39m'
540          ).message;
541        } else {
542          workerFileEntry[workerKey] = worker;
543          abilityPagesFullPath.push(path.resolve(workerFileEntry[workerKey]).toLowerCase());
544        }
545      }
546    });
547    return workerFileEntry;
548  }
549  return null;
550}
551
552function readPatchConfig() {
553  if (aceBuildJson.patchConfig) {
554    projectConfig.hotReload = process.env.watchMode === 'true' && !projectConfig.isPreview;
555    projectConfig.patchAbcPath = aceBuildJson.patchConfig.patchAbcPath;
556    projectConfig.changedFileList = aceBuildJson.patchConfig.changedFileList ?
557      aceBuildJson.patchConfig.changedFileList : path.join(projectConfig.cachePath, 'changedFileList.json');
558    if (projectConfig.hotReload) {
559      writeFileSync(projectConfig.changedFileList, JSON.stringify({
560        modifiedFiles: [],
561        removedFiles: []
562      }));
563    }
564  }
565}
566
567function filterWorker(workerPath) {
568  return /\.(ts|js|ets)$/.test(workerPath);
569}
570
571;(function initSystemResource() {
572  const sysResourcePath = path.resolve(__dirname, './sysResource.js');
573  if (fs.existsSync(sysResourcePath)) {
574    resources.sys = require(sysResourcePath).sys;
575  }
576})();
577
578;(function readSystemModules() {
579  const systemModulesPath = path.resolve(__dirname, '../../api');
580  if (fs.existsSync(systemModulesPath)) {
581    globalModulePaths.push(systemModulesPath);
582    const modulePaths = [];
583    readFile(systemModulesPath, modulePaths);
584    systemModules.push(...fs.readdirSync(systemModulesPath));
585    ohosSystemModulePaths.push(...modulePaths);
586    defaultSdkConfigs = [
587      {
588        'apiPath': systemModulesPath,
589        'prefix': '@ohos'
590      }, {
591        'apiPath': systemModulesPath,
592        'prefix': '@system'
593      }
594    ];
595  }
596  const externalApiPathStr = process.env.externalApiPaths || '';
597  const externalApiPaths = externalApiPathStr.split(path.delimiter);
598  externalApiPaths.forEach(sdkPath => {
599    const sdkConfigPath = path.resolve(sdkPath, 'sdkConfig.json');
600    if (fs.existsSync(sdkConfigPath)) {
601      const sdkConfig = JSON.parse(fs.readFileSync(sdkConfigPath, "utf-8"));
602      sdkConfig.apiPath = path.resolve(sdkPath, sdkConfig.apiPath);
603      if (fs.existsSync(sdkConfig.apiPath)) {
604        globalModulePaths.push(sdkConfig.apiPath);
605        systemModules.push(...fs.readdirSync(sdkConfig.apiPath));
606        sdkConfigPrefix += `|${sdkConfig.prefix.replace(/^@/, '')}`;
607        extendSdkConfigs.push(sdkConfig);
608      }
609    }
610  });
611  sdkConfigs = [...defaultSdkConfigs, ...extendSdkConfigs];
612})()
613
614function readAppResource(filePath) {
615  if (fs.existsSync(filePath)) {
616    const appResource = fs.readFileSync(filePath, 'utf-8');
617    const resourceArr = appResource.split(/\n/);
618    const resourceMap = new Map();
619    processResourceArr(resourceArr, resourceMap, filePath);
620    for (let [key, value] of resourceMap) {
621      resources.app[key] = value;
622    }
623  }
624  if (process.env.rawFileResource && process.env.compileMode === 'moduleJson') {
625    resourcesRawfile(process.env.rawFileResource, storedFileInfo.resourcesArr);
626  }
627}
628
629function processResourceArr(resourceArr, resourceMap, filePath) {
630  for (let i = 0; i < resourceArr.length; i++) {
631    if (!resourceArr[i].length) {
632      continue;
633    }
634    const resourceData = resourceArr[i].split(/\s/);
635    if (resourceData.length === 3 && !isNaN(Number(resourceData[2]))) {
636      if (resourceMap.get(resourceData[0])) {
637        const resourceKeys = resourceMap.get(resourceData[0]);
638        if (!resourceKeys[resourceData[1]] || resourceKeys[resourceData[1]] !== Number(resourceData[2])) {
639          resourceKeys[resourceData[1]] = Number(resourceData[2]);
640        }
641      } else {
642        let obj = {};
643        obj[resourceData[1]] = Number(resourceData[2]);
644        resourceMap.set(resourceData[0], obj);
645      }
646      if (process.env.compileTool === 'rollup' && process.env.compileMode === 'moduleJson') {
647        storedFileInfo.updateResourceList(resourceData[0] + '_' + resourceData[1]);
648      }
649    } else {
650      logger.warn(`\u001b[31m ArkTS:WARN The format of file '${filePath}' is incorrect. \u001b[39m`);
651      break;
652    }
653  }
654}
655
656function hashProjectPath(projectPath) {
657  const hash = crypto.createHash('sha256');
658  hash.update(projectPath.toString());
659  process.env.hashProjectPath = "_" + hash.digest('hex');
660  return process.env.hashProjectPath;
661}
662
663function loadModuleInfo(projectConfig, envArgs) {
664  if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) {
665    const buildJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString());
666    if (buildJsonInfo.compileMode) {
667      projectConfig.compileMode = buildJsonInfo.compileMode;
668    }
669    projectConfig.projectRootPath = buildJsonInfo.projectRootPath;
670    projectConfig.modulePathMap = buildJsonInfo.modulePathMap;
671    projectConfig.isOhosTest = buildJsonInfo.isOhosTest;
672    let faultHandler = function (error) {
673      // rollup's error will be handled in fast build
674      if (process.env.compileTool === 'rollup') {
675        return;
676      }
677      logger.error(error);
678      process.exit(FAIL);
679    }
680    projectConfig.es2abcCompileTsInAotMode = true;
681    projectConfig.es2abcCompileTsInNonAotMode = false;
682    const compileMode = process.env.compileTool === 'rollup' ? projectConfig.compileMode : buildJsonInfo.compileMode;
683    if (checkAotConfig(compileMode, buildJsonInfo, faultHandler)) {
684      projectConfig.processTs = true;
685      projectConfig.pandaMode = TS2ABC;
686      projectConfig.anBuildOutPut = buildJsonInfo.anBuildOutPut;
687      projectConfig.anBuildMode = buildJsonInfo.anBuildMode;
688      projectConfig.apPath = buildJsonInfo.apPath;
689      if (projectConfig.es2abcCompileTsInAotMode) {
690        projectConfig.pandaMode = ES2ABC;
691      }
692    } else {
693      projectConfig.processTs = false;
694      projectConfig.pandaMode = buildJsonInfo.pandaMode;
695      if (projectConfig.es2abcCompileTsInNonAotMode) {
696        projectConfig.pandaMode = ES2ABC;
697        projectConfig.processTs = true;
698      }
699    }
700    if (envArgs !== undefined) {
701      projectConfig.buildArkMode = envArgs.buildMode;
702    }
703    if (compileMode === 'esmodule') {
704      projectConfig.nodeModulesPath = buildJsonInfo.nodeModulesPath;
705      projectConfig.harNameOhmMap = buildJsonInfo.harNameOhmMap;
706    }
707    if (projectConfig.compileHar && buildJsonInfo.moduleName &&
708      buildJsonInfo.modulePathMap[buildJsonInfo.moduleName]) {
709      projectConfig.moduleRootPath = buildJsonInfo.modulePathMap[buildJsonInfo.moduleName];
710    }
711  }
712}
713
714function checkAppResourcePath(appResourcePath, config) {
715  if (appResourcePath) {
716    readAppResource(appResourcePath);
717    if (fs.existsSync(appResourcePath) && config.cache) {
718      config.cache.buildDependencies.config.push(appResourcePath);
719    }
720    if (!projectConfig.xtsMode) {
721      const appResourcePathSavePath = path.resolve(projectConfig.cachePath, 'resource_path.txt');
722      saveAppResourcePath(appResourcePath, appResourcePathSavePath);
723      if (fs.existsSync(appResourcePathSavePath) && config.cache) {
724        config.cache.buildDependencies.config.push(appResourcePathSavePath);
725      }
726    }
727  }
728}
729
730function saveAppResourcePath(appResourcePath, appResourcePathSavePath) {
731  let isSave = false;
732  if (fs.existsSync(appResourcePathSavePath)) {
733    const saveContent = fs.readFileSync(appResourcePathSavePath);
734    if (appResourcePath !== saveContent) {
735      isSave = true;
736    }
737  } else {
738    isSave = true;
739  }
740  if (isSave) {
741    fs.writeFileSync(appResourcePathSavePath, appResourcePath);
742  }
743}
744
745function addSDKBuildDependencies(config) {
746  if (projectConfig.localPropertiesPath &&
747    fs.existsSync(projectConfig.localPropertiesPath) && config.cache) {
748    config.cache.buildDependencies.config.push(projectConfig.localPropertiesPath)
749  }
750  if (projectConfig.projectProfilePath &&
751    fs.existsSync(projectConfig.projectProfilePath) && config.cache) {
752    config.cache.buildDependencies.config.push(projectConfig.projectProfilePath)
753  }
754}
755
756function getCleanConfig(workerFile) {
757  const cleanPath = [];
758  if (projectConfig.compileMode === 'esmodule') {
759    return cleanPath;
760  }
761  cleanPath.push(projectConfig.buildPath);
762  if (workerFile) {
763    const workerFilesPath = Object.keys(workerFile);
764    for (const workerFilePath of workerFilesPath) {
765      cleanPath.push(path.join(projectConfig.buildPath, workerFilePath, '..'));
766    }
767  }
768  return cleanPath;
769}
770
771function isPartialUpdate(metadata) {
772  if (!Array.isArray(metadata) || !metadata.length) {
773    return;
774  }
775  metadata.some(item => {
776    if (item.name && item.value) {
777      if (item.name === 'ArkTSPartialUpdate' && item.value === 'false') {
778        partialUpdateConfig.partialUpdateMode = false;
779        if (projectConfig.aceModuleJsonPath) {
780          logger.warn('\u001b[33m ArkTS:WARN File: ' + projectConfig.aceModuleJsonPath + '.' + '\n' +
781          " The 'ArkTSPartialUpdate' field will no longer be supported in the future. \u001b[39m");
782        }
783      }
784      if (item.name === 'ArkTSBuilderCheck' && item.value === 'false') {
785        partialUpdateConfig.builderCheck = false;
786      }
787      if (item.name === 'ArkTSCheck' && item.value === 'SkipArkTSCheck') {
788        partialUpdateConfig.executeArkTSLinter = false;
789      }
790      if (item.name === 'ArkTSCheckMode' && item.value === 'DoArkTSCheckInCompatibleMode') {
791        partialUpdateConfig.standardArkTSLinter = false;
792      }
793      if (item.name === 'SkipTscOhModuleCheck' && item.value === 'true') {
794        partialUpdateConfig.skipTscOhModuleCheck = true;
795      }
796    }
797    return !partialUpdateConfig.partialUpdateMode && !partialUpdateConfig.builderCheck &&
798      !partialUpdateConfig.executeArkTSLinter && !partialUpdateConfig.standardArkTSLinter &&
799      partialUpdateConfig.skipTscOhModuleCheck;
800  });
801}
802
803function applicationConfig() {
804  const localProperties = path.resolve(aceBuildJson.projectRootPath, 'local.properties');
805  if (fs.existsSync(localProperties)) {
806    try {
807      const localPropertiesFile = fs.readFileSync(localProperties, {encoding: 'utf-8'}).split(/\r?\n/);
808      localPropertiesFile.some((item) => {
809        const builderCheckValue = item.replace(/\s+|;/g, '');
810        if (builderCheckValue === 'ArkTSConfig.ArkTSBuilderCheck=false') {
811          partialUpdateConfig.builderCheck = false;
812          return true;
813        }
814      });
815    } catch (err) {
816    }
817  }
818}
819
820function partialUpdateController(minAPIVersion, metadata = null) {
821  projectConfig.minAPIVersion = minAPIVersion;
822  if (minAPIVersion >= 9) {
823    partialUpdateConfig.partialUpdateMode = true;
824  }
825  if (minAPIVersion < 10) {
826    partialUpdateConfig.optimizeComponent = false;
827  }
828  if (metadata) {
829    isPartialUpdate(metadata);
830  }
831  if (aceBuildJson.projectRootPath) {
832    applicationConfig();
833  }
834}
835
836const globalProgram = {
837  program: null,
838  watchProgram: null,
839  checker: null,
840};
841
842const partialUpdateConfig = {
843  partialUpdateMode: false,
844  builderCheck: true,
845  executeArkTSLinter: true,
846  standardArkTSLinter: true,
847  optimizeComponent: true,
848  skipTscOhModuleCheck: false,
849};
850
851exports.globalProgram = globalProgram;
852exports.projectConfig = projectConfig;
853exports.loadEntryObj = loadEntryObj;
854exports.readAppResource = readAppResource;
855exports.resources = resources;
856exports.loadWorker = loadWorker;
857exports.abilityConfig = abilityConfig;
858exports.readWorkerFile = readWorkerFile;
859exports.abilityPagesFullPath = abilityPagesFullPath;
860exports.loadModuleInfo = loadModuleInfo;
861exports.systemModules = systemModules;
862exports.checkAppResourcePath = checkAppResourcePath;
863exports.addSDKBuildDependencies = addSDKBuildDependencies;
864exports.partialUpdateConfig = partialUpdateConfig;
865exports.readPatchConfig = readPatchConfig;
866exports.initBuildInfo = initBuildInfo;
867exports.getCleanConfig = getCleanConfig;
868exports.globalModulePaths = globalModulePaths;
869exports.defaultSdkConfigs = defaultSdkConfigs;
870exports.extendSdkConfigs = extendSdkConfigs;
871exports.sdkConfigs = sdkConfigs;
872exports.sdkConfigPrefix = sdkConfigPrefix;
873exports.ohosSystemModulePaths = ohosSystemModulePaths;
874