1/*
2 * Copyright (c) 2022 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 fs from 'fs';
17import path from 'path';
18import * as ts from 'typescript';
19import * as crypto from 'crypto';
20const fse = require('fs-extra');
21
22import {
23  projectConfig,
24  systemModules,
25  globalProgram,
26  sdkConfigs,
27  sdkConfigPrefix,
28  partialUpdateConfig,
29  resetProjectConfig,
30  resetGlobalProgram
31} from '../main';
32import {
33  preprocessExtend,
34  preprocessNewExtend
35} from './validate_ui_syntax';
36import {
37  INNER_COMPONENT_MEMBER_DECORATORS,
38  COMPONENT_DECORATORS_PARAMS,
39  COMPONENT_BUILD_FUNCTION,
40  STYLE_ADD_DOUBLE_DOLLAR,
41  $$,
42  PROPERTIES_ADD_DOUBLE_DOLLAR,
43  DOLLAR_BLOCK_INTERFACE,
44  COMPONENT_EXTEND_DECORATOR,
45  COMPONENT_BUILDER_DECORATOR,
46  ESMODULE,
47  EXTNAME_D_ETS,
48  EXTNAME_JS,
49  FOREACH_LAZYFOREACH,
50  COMPONENT_IF,
51  TS_WATCH_END_MSG,
52  TS_BUILD_INFO_SUFFIX,
53  HOT_RELOAD_BUILD_INFO_SUFFIX,
54  WATCH_COMPILER_BUILD_INFO_SUFFIX,
55  COMPONENT_STYLES_DECORATOR
56} from './pre_define';
57import {
58  INNER_COMPONENT_NAMES,
59  JS_BIND_COMPONENTS,
60  BUILDIN_STYLE_NAMES
61} from './component_map';
62import { logger } from './compile_info';
63import {
64  hasDecorator,
65  isString,
66  generateSourceFilesInHar,
67  startTimeStatisticsLocation,
68  stopTimeStatisticsLocation,
69  resolveModuleNamesTime,
70  CompilationTimeStatistics,
71  storedFileInfo,
72  toUnixPath,
73  isWindows,
74  isMac,
75  tryToLowerCasePath,
76  getRollupCache,
77  setRollupCache
78} from './utils';
79import {
80  isExtendFunction,
81  isOriginalExtend
82} from './process_ui_syntax';
83import { visualTransform } from './process_visual';
84import { tsWatchEmitter } from './fast_build/ets_ui/rollup-plugin-ets-checker';
85import {
86  doArkTSLinter,
87  ArkTSLinterMode,
88  ArkTSVersion,
89} from './do_arkTS_linter';
90import {
91  getJsDocNodeCheckConfig,
92  isCardFile,
93  getRealModulePath,
94  getJsDocNodeConditionCheckResult
95} from './fast_build/system_api/api_check_utils';
96import { sourceFileDependencies } from './fast_build/ark_compiler/common/ob_config_resolver';
97
98export interface LanguageServiceCache {
99  service?: ts.LanguageService;
100  pkgJsonFileHash?: string;
101  targetESVersion?: ts.ScriptTarget;
102  preTsImportSendable?: boolean;
103}
104
105export const SOURCE_FILES: Map<string, ts.SourceFile> = new Map();
106export let localPackageSet: Set<string> = new Set();
107
108export function readDeaclareFiles(): string[] {
109  const declarationsFileNames: string[] = [];
110  fs.readdirSync(path.resolve(__dirname, '../declarations'))
111    .forEach((fileName: string) => {
112      if (/\.d\.ts$/.test(fileName)) {
113        declarationsFileNames.push(path.resolve(__dirname, '../declarations', fileName));
114      }
115    });
116  return declarationsFileNames;
117}
118
119const buildInfoWriteFile: ts.WriteFileCallback = (fileName: string, data: string) => {
120  if (fileName.includes(TS_BUILD_INFO_SUFFIX)) {
121    const fd: number = fs.openSync(fileName, 'w');
122    fs.writeSync(fd, data, undefined, 'utf8');
123    fs.closeSync(fd);
124  }
125};
126// The collection records the file name and the corresponding version, where the version is the hash value of the text in last compilation.
127const filesBuildInfo: Map<string, string> = new Map();
128
129export const compilerOptions: ts.CompilerOptions = ts.readConfigFile(
130  path.resolve(__dirname, '../tsconfig.json'), ts.sys.readFile).config.compilerOptions;
131function setCompilerOptions(resolveModulePaths: string[]): void {
132  const allPath: Array<string> = ['*'];
133  const basePath: string = path.resolve(projectConfig.projectPath);
134  if (process.env.compileTool === 'rollup' && resolveModulePaths && resolveModulePaths.length) {
135    resolveModulePaths.forEach((item: string) => {
136      if (!(/oh_modules$/.test(item) || /node_modules$/.test(item))) {
137        allPath.push(path.join(path.relative(basePath, item), '*'));
138      }
139    });
140  } else {
141    if (!projectConfig.aceModuleJsonPath) {
142      allPath.push('../../../../../*');
143      allPath.push('../../*');
144    } else {
145      allPath.push('../../../../*');
146      allPath.push('../*');
147    }
148  }
149  const suffix: string = projectConfig.hotReload ? HOT_RELOAD_BUILD_INFO_SUFFIX : TS_BUILD_INFO_SUFFIX;
150  const buildInfoPath: string = path.resolve(projectConfig.cachePath, '..', suffix);
151  checkArkTSVersion();
152  Object.assign(compilerOptions, {
153    'allowJs': getArkTSLinterMode() !== ArkTSLinterMode.NOT_USE ? true : false,
154    'checkJs': getArkTSLinterMode() !== ArkTSLinterMode.NOT_USE ? false : undefined,
155    'emitNodeModulesFiles': true,
156    'importsNotUsedAsValues': ts.ImportsNotUsedAsValues.Preserve,
157    'module': ts.ModuleKind.CommonJS,
158    'moduleResolution': ts.ModuleResolutionKind.NodeJs,
159    'noEmit': true,
160    'target': convertConfigTarget(getTargetESVersion()),
161    'baseUrl': basePath,
162    'paths': {
163      '*': allPath
164    },
165    'lib': convertConfigLib(getTargetESVersionLib()),
166    'types': projectConfig.compilerTypes,
167    'etsLoaderPath': projectConfig.etsLoaderPath,
168    'needDoArkTsLinter': getArkTSLinterMode() !== ArkTSLinterMode.NOT_USE,
169    'isCompatibleVersion': getArkTSLinterMode() === ArkTSLinterMode.COMPATIBLE_MODE,
170    'skipTscOhModuleCheck': partialUpdateConfig.skipTscOhModuleCheck,
171    'skipArkTSStaticBlocksCheck': partialUpdateConfig.skipArkTSStaticBlocksCheck,
172    // options incremental && tsBuildInfoFile are required for applying incremental ability of typescript
173    'incremental': true,
174    'tsBuildInfoFile': buildInfoPath,
175    'tsImportSendableEnable': tsImportSendable,
176    'skipPathsInKeyForCompilationSettings': reuseLanguageServiceForDepChange,
177    'compatibleSdkVersionStage': projectConfig.compatibleSdkVersionStage,
178    'compatibleSdkVersion': projectConfig.compatibleSdkVersion
179  });
180  if (projectConfig.compileMode === ESMODULE) {
181    Object.assign(compilerOptions, {
182      'importsNotUsedAsValues': ts.ImportsNotUsedAsValues.Remove,
183      'module': ts.ModuleKind.ES2020
184    });
185  }
186  if (projectConfig.packageDir === 'oh_modules') {
187    Object.assign(compilerOptions, {'packageManagerType': 'ohpm'});
188  }
189  readTsBuildInfoFileInCrementalMode(buildInfoPath, projectConfig);
190}
191
192function checkArkTSVersion(): void {
193  const etsCheckerLogger = fastBuildLogger || logger;
194  if (getArkTSVersion() === ArkTSVersion.ArkTS_1_0 && tsImportSendable) {
195    const logMessage: string = 'ArkTS: ArkTSVersion1.0 does not support tsImportSendable in any condition';
196    etsCheckerLogger.error('\u001b[31m' + logMessage);
197    tsImportSendable = false;
198  }
199}
200
201// Change target to enum's value,e.g: "es2021" => ts.ScriptTarget.ES2021
202function convertConfigTarget(target: number | string): number | string {
203  if ((typeof target === 'number') && (target in ts.ScriptTarget)) {
204    return target;
205  }
206  return ts.convertCompilerOptionsFromJson({ 'target': target }, '').options.target;
207}
208
209// Change lib to libMap's value,e.g: "es2021" => "lib.es2021.d.ts"
210function convertConfigLib(libs: string[]): string[] {
211  let converted: boolean = true;
212  let libMapValues: string[] = Array.from(ts.libMap.values());
213  for (let i = 0; i < libs.length; i++) {
214    if (!libMapValues.includes(libs[i])) {
215      converted = false;
216      break;
217    }
218  }
219  if (converted) {
220    return libs;
221  }
222  return ts.convertCompilerOptionsFromJson({ 'lib': libs }, '').options.lib;
223}
224
225/**
226 * Read the source code information in the project of the last compilation process, and then use it
227 * to determine whether the file has been modified during this compilation process.
228 */
229function readTsBuildInfoFileInCrementalMode(buildInfoPath: string, projectConfig: Object): void {
230  if (!fs.existsSync(buildInfoPath) || !(projectConfig.compileHar || projectConfig.compileShared)) {
231    return;
232  }
233
234  type FileInfoType = {
235    version: string;
236    affectsGlobalScope: boolean;
237  };
238  type ProgramType = {
239    fileNames: string[];
240    fileInfos: (FileInfoType | string)[];
241  };
242  let buildInfoProgram: ProgramType;
243  try {
244    const content: {program: ProgramType} = JSON.parse(fs.readFileSync(buildInfoPath, 'utf-8'));
245    buildInfoProgram = content.program;
246    if (!buildInfoProgram || !buildInfoProgram.fileNames || !buildInfoProgram.fileInfos) {
247      throw new Error('.tsbuildinfo content is invalid');
248    }
249  } catch (err) {
250    fastBuildLogger.warn('\u001b[33m' + 'ArkTS: Failed to parse .tsbuildinfo file. Error message: ' + err.message.toString());
251    return;
252  }
253  const buildInfoDirectory: string = path.dirname(buildInfoPath);
254  /**
255   * For the windos and mac platform, the file path in tsbuildinfo is in lowercase, while buildInfoDirectory is the original path (including uppercase).
256   * Therefore, the path needs to be converted to lowercase, and then perform path comparison.
257   */
258  const isMacOrWin = isWindows() || isMac();
259  const fileNames: string[] = buildInfoProgram.fileNames;
260  const fileInfos: (FileInfoType | string)[] = buildInfoProgram.fileInfos;
261  fileInfos.forEach((fileInfo, index) => {
262    const version: string = typeof fileInfo === 'string' ? fileInfo : fileInfo.version;
263    const absPath: string = path.resolve(buildInfoDirectory, fileNames[index]);
264    filesBuildInfo.set(isMacOrWin ? tryToLowerCasePath(absPath) : absPath, version);
265  });
266}
267
268interface extendInfo {
269  start: number,
270  end: number,
271  compName: string
272}
273
274function createHash(str: string): string {
275  const hash = crypto.createHash('sha256');
276  hash.update(str);
277  return hash.digest('hex');
278}
279
280export const fileHashScriptVersion: (fileName: string) => string = (fileName: string) => {
281  if (!fs.existsSync(fileName)) {
282    return '0';
283  }
284
285  let fileContent: string = fs.readFileSync(fileName).toString();
286  let cacheInfo: CacheFileName = cache[path.resolve(fileName)];
287
288  // Error code corresponding to message `Cannot find module xx or its corresponding type declarations`
289  const errorCodeRequireRecheck: number = 2307;
290
291  if (cacheInfo && cacheInfo.error === true && cacheInfo.errorCodes && cacheInfo.errorCodes.includes(errorCodeRequireRecheck)) {
292    // If this file had errors that require recheck in the last compilation,
293    // mark the file as modified by modifying its hash value, thereby triggering tsc to recheck.
294    fileContent += Date.now().toString();
295  }
296  return createHash(fileContent);
297};
298
299// Reuse the last language service when dependency in oh-package.json5 changes to enhance performance in incremental building.
300// Setting this to false will create a new language service on dependency changes, like a full rebuild.
301const reuseLanguageServiceForDepChange: boolean = true;
302// When dependency changes and reusing the last language service, enable this flag to recheck code dependent on those dependencies.
303export let needReCheckForChangedDepUsers: boolean = false;
304
305export function createLanguageService(rootFileNames: string[], resolveModulePaths: string[],
306  compilationTime: CompilationTimeStatistics = null, rollupShareObject?: any): ts.LanguageService {
307  setCompilerOptions(resolveModulePaths);
308  const servicesHost: ts.LanguageServiceHost = {
309    getScriptFileNames: () => [...rootFileNames, ...readDeaclareFiles()],
310    getScriptVersion: fileHashScriptVersion,
311    getScriptSnapshot: function(fileName) {
312      if (!fs.existsSync(fileName)) {
313        return undefined;
314      }
315      if (/(?<!\.d)\.(ets|ts)$/.test(fileName)) {
316        startTimeStatisticsLocation(compilationTime ? compilationTime.scriptSnapshotTime : undefined);
317        appComponentCollection.set(path.join(fileName), new Set());
318        let content: string = processContent(fs.readFileSync(fileName).toString(), fileName);
319        const extendFunctionInfo: extendInfo[] = [];
320        content = instanceInsteadThis(content, fileName, extendFunctionInfo, this.uiProps);
321        stopTimeStatisticsLocation(compilationTime ? compilationTime.scriptSnapshotTime : undefined);
322        return ts.ScriptSnapshot.fromString(content);
323      }
324      return ts.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString());
325    },
326    getCurrentDirectory: () => process.cwd(),
327    getCompilationSettings: () => compilerOptions,
328    getDefaultLibFileName: options => ts.getDefaultLibFilePath(options),
329    fileExists: ts.sys.fileExists,
330    readFile: ts.sys.readFile,
331    readDirectory: ts.sys.readDirectory,
332    resolveModuleNames: resolveModuleNames,
333    resolveTypeReferenceDirectives: resolveTypeReferenceDirectives,
334    directoryExists: ts.sys.directoryExists,
335    getDirectories: ts.sys.getDirectories,
336    getJsDocNodeCheckedConfig: (fileCheckedInfo: ts.FileCheckModuleInfo, sourceFileName: string) => {
337      return getJsDocNodeCheckConfig(fileCheckedInfo.currentFileName, sourceFileName);
338    },
339    getFileCheckedModuleInfo: (containFilePath: string) => {
340      return {
341        fileNeedCheck: true,
342        checkPayload: undefined,
343        currentFileName: containFilePath
344      };
345    },
346    getJsDocNodeConditionCheckedResult: (jsDocFileCheckedInfo: ts.FileCheckModuleInfo, jsDocs: ts.JsDocTagInfo[]) => {
347      return getJsDocNodeConditionCheckResult(jsDocFileCheckedInfo, jsDocs);
348    },
349    uiProps: [],
350    clearProps: function() {
351      dollarCollection.clear();
352      extendCollection.clear();
353      this.uiProps.length = 0;
354    },
355    // TSC will re-do resolution if this callback return true.
356    hasInvalidatedResolutions: (filePath: string): boolean => {
357      return reuseLanguageServiceForDepChange && needReCheckForChangedDepUsers;
358    }
359  };
360
361  if (process.env.watchMode === 'true') {
362    return ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
363  }
364
365  return getOrCreateLanguageService(servicesHost, rootFileNames, rollupShareObject);
366}
367
368export let targetESVersionChanged: boolean = false;
369
370function getOrCreateLanguageService(servicesHost: ts.LanguageServiceHost, rootFileNames: string[],
371  rollupShareObject?: any): ts.LanguageService {
372  let cacheKey: string = 'service';
373  let cache: LanguageServiceCache | undefined = getRollupCache(rollupShareObject, projectConfig, cacheKey);
374
375  let service: ts.LanguageService | undefined = cache?.service;
376  const currentHash: string | undefined = rollupShareObject?.projectConfig?.pkgJsonFileHash;
377  const currentTargetESVersion: ts.ScriptTarget = compilerOptions.target;
378  const lastHash: string | undefined = cache?.pkgJsonFileHash;
379  const lastTargetESVersion: ts.ScriptTarget | undefined = cache?.targetESVersion;
380  const hashDiffers: boolean | undefined = currentHash && lastHash && currentHash !== lastHash;
381  const shouldRebuildForDepDiffers: boolean | undefined = reuseLanguageServiceForDepChange ?
382    (hashDiffers && !rollupShareObject?.depInfo?.enableIncre) : hashDiffers;
383  const targetESVersionDiffers: boolean | undefined = lastTargetESVersion && currentTargetESVersion && lastTargetESVersion !== currentTargetESVersion;
384  const tsImportSendableDiff: boolean = (cache?.preTsImportSendable === undefined && !tsImportSendable) ?
385    false :
386    cache?.preTsImportSendable !== tsImportSendable;
387  const shouldRebuild: boolean | undefined = shouldRebuildForDepDiffers || targetESVersionDiffers || tsImportSendableDiff;
388  if (reuseLanguageServiceForDepChange && hashDiffers && rollupShareObject?.depInfo?.enableIncre) {
389    needReCheckForChangedDepUsers = true;
390  }
391
392  if (!service || shouldRebuild) {
393    rebuiuldProgram(targetESVersionDiffers, tsImportSendableDiff);
394    service = ts.createLanguageService(servicesHost, ts.createDocumentRegistry());
395  } else {
396    // Found language service from cache, update root files
397    const updateRootFileNames = [...rootFileNames, ...readDeaclareFiles()];
398    service.updateRootFiles(updateRootFileNames);
399  }
400
401  const newCache: LanguageServiceCache = {
402    service: service,
403    pkgJsonFileHash: currentHash,
404    targetESVersion: currentTargetESVersion,
405    preTsImportSendable: tsImportSendable
406  };
407  setRollupCache(rollupShareObject, projectConfig, cacheKey, newCache);
408  return service;
409}
410
411function rebuiuldProgram(targetESVersionDiffers: boolean | undefined, tsImportSendableDiff: boolean): void {
412  if (targetESVersionDiffers) {
413    // If the targetESVersion is changed, we need to delete the build info cahce files
414    deleteBuildInfoCache(compilerOptions.tsBuildInfoFile);
415    targetESVersionChanged = true;
416  } else if (tsImportSendableDiff) {
417    // When tsImportSendable is changed, we need to delete the build info cahce files
418    deleteBuildInfoCache(compilerOptions.tsBuildInfoFile);
419  }
420}
421
422function deleteBuildInfoCache(tsBuildInfoFilePath: string): void {
423  // The file name of tsBuildInfoLinterFile is '.tsbuildinfo.linter', so we need to add '.linter' after tsBuildInfoFilePath
424  const tsBuildInfoLinterFilePath: string = tsBuildInfoFilePath + '.linter';
425  deleteFile(tsBuildInfoFilePath);
426  deleteFile(tsBuildInfoLinterFilePath);
427}
428
429function deleteFile(filePath: string): void {
430  if (fs.existsSync(filePath)) {
431      fs.unlinkSync(filePath);
432  }
433}
434
435interface CacheFileName {
436  mtimeMs: number,
437  children: string[],
438  parent: string[],
439  error: boolean,
440  errorCodes?: number[]
441}
442interface NeedUpdateFlag {
443  flag: boolean;
444}
445interface CheckerResult {
446  count: number
447}
448
449interface WarnCheckerResult {
450  count: number
451}
452
453interface WholeCache {
454  runtimeOS: string,
455  sdkInfo: string,
456  fileList: Cache
457}
458type Cache = Record<string, CacheFileName>;
459export let cache: Cache = {};
460export const hotReloadSupportFiles: Set<string> = new Set();
461export const shouldResolvedFiles: Set<string> = new Set();
462export const appComponentCollection: Map<string, Set<string>> = new Map();
463const allResolvedModules: Set<string> = new Set();
464// all files of tsc and rollup for obfuscation scanning.
465export const allSourceFilePaths: Set<string> = new Set();
466// Used to collect file paths that have not been converted toUnixPath.
467export const allModuleIds: Set<string> = new Set();
468export let props: string[] = [];
469
470export let fastBuildLogger = null;
471
472export const checkerResult: CheckerResult = { count: 0 };
473export const warnCheckerResult: WarnCheckerResult = { count: 0 };
474export let languageService: ts.LanguageService = null;
475let tsImportSendable: boolean = false;
476export function serviceChecker(rootFileNames: string[], newLogger: Object = null, resolveModulePaths: string[] = null,
477  compilationTime: CompilationTimeStatistics = null, rollupShareObject?: Object): void {
478  fastBuildLogger = newLogger;
479  let cacheFile: string = null;
480  tsImportSendable = rollupShareObject?.projectConfig.tsImportSendable;
481  if (projectConfig.xtsMode || process.env.watchMode === 'true') {
482    if (projectConfig.hotReload) {
483      rootFileNames.forEach(fileName => {
484        hotReloadSupportFiles.add(fileName);
485      });
486    }
487    languageService = createLanguageService(rootFileNames, resolveModulePaths, compilationTime);
488    props = languageService.getProps();
489  } else {
490    cacheFile = path.resolve(projectConfig.cachePath, '../.ts_checker_cache');
491    const [isJsonObject, cacheJsonObject]: [boolean, WholeCache | undefined] = isJsonString(cacheFile);
492    const wholeCache: WholeCache = isJsonObject ? cacheJsonObject : { 'runtimeOS': projectConfig.runtimeOS, 'sdkInfo': projectConfig.sdkInfo, 'fileList': {} };
493    if (wholeCache.runtimeOS === projectConfig.runtimeOS && wholeCache.sdkInfo === projectConfig.sdkInfo) {
494      cache = wholeCache.fileList;
495    } else {
496      cache = {};
497    }
498    languageService = createLanguageService(rootFileNames, resolveModulePaths, compilationTime, rollupShareObject);
499  }
500
501  const timePrinterInstance = ts.ArkTSLinterTimePrinter.getInstance();
502  timePrinterInstance.setArkTSTimePrintSwitch(false);
503  timePrinterInstance.appendTime(ts.TimePhase.START);
504  startTimeStatisticsLocation(compilationTime ? compilationTime.createProgramTime : undefined);
505
506  globalProgram.builderProgram = languageService.getBuilderProgram(/*withLinterProgram*/ true);
507  globalProgram.program = globalProgram.builderProgram.getProgram();
508  props = languageService.getProps();
509  timePrinterInstance.appendTime(ts.TimePhase.GET_PROGRAM);
510  stopTimeStatisticsLocation(compilationTime ? compilationTime.createProgramTime : undefined);
511
512  collectAllFiles(globalProgram.program, undefined, undefined, rollupShareObject);
513  collectFileToIgnoreDiagnostics(rootFileNames);
514  startTimeStatisticsLocation(compilationTime ? compilationTime.runArkTSLinterTime : undefined);
515  runArkTSLinter();
516  stopTimeStatisticsLocation(compilationTime ? compilationTime.runArkTSLinterTime : undefined);
517
518  if (process.env.watchMode !== 'true') {
519    processBuildHap(cacheFile, rootFileNames, compilationTime, rollupShareObject);
520  }
521}
522
523function isJsonString(cacheFile: string): [boolean, WholeCache | undefined] {
524  if (fs.existsSync(cacheFile)) {
525    try {
526      return [true, JSON.parse(fs.readFileSync(cacheFile).toString())];
527    } catch (e) {
528      return [false, undefined];
529    }
530  } else {
531    return [false, undefined];
532  }
533}
534
535// collect the compiled files of tsc and rollup for obfuscation scanning.
536export function collectAllFiles(program?: ts.Program, rollupFileList?: IterableIterator<string>,
537  rollupObject?: Object, rollupShareObject: Object = null): void {
538  if (program) {
539    collectTscFiles(program, rollupShareObject);
540    return;
541  }
542  mergeRollUpFiles(rollupFileList, rollupObject);
543}
544
545export function collectTscFiles(program: ts.Program, rollupShareObject: Object = null): void {
546  const programAllFiles: readonly ts.SourceFile[] = program.getSourceFiles();
547  let projectRootPath: string = projectConfig.projectRootPath;
548  if (!projectRootPath) {
549    return;
550  }
551  projectRootPath = toUnixPath(projectRootPath);
552  const isMacOrWin = isWindows() || isMac();
553  programAllFiles.forEach(sourceFile => {
554    const fileName = toUnixPath(sourceFile.fileName);
555    // @ts-ignore
556    sourceFileDependencies.set(fileName, sourceFile.resolvedModules);
557    if (!(fileName.startsWith(projectRootPath + '/') || isOtherProjectResolvedModulesFilePaths(rollupShareObject, fileName))) {
558      return;
559    }
560    allSourceFilePaths.add(fileName);
561    allModuleIds.add(sourceFile.fileName);
562    // For the windos and mac platform, the file path in filesBuildInfo is in lowercase,
563    // while fileName of sourceFile is the original path (including uppercase).
564    if (filesBuildInfo.size > 0 &&
565      Reflect.get(sourceFile, 'version') !== filesBuildInfo.get(isMacOrWin ? tryToLowerCasePath(fileName) : fileName)) {
566      allResolvedModules.add(fileName);
567    }
568  });
569}
570
571function isOtherProjectResolvedModulesFilePaths(rollupShareObject: Object, fileName: string): boolean {
572  if (!!rollupShareObject && rollupShareObject.projectConfig && !!rollupShareObject.projectConfig.rootPathSet) {
573    const rootPathSet: string[] | Set<string> = rollupShareObject.projectConfig.rootPathSet;
574    if (Array.isArray(rootPathSet)) {
575      for (let i = 0; i < rootPathSet.length; i++) {
576        const pathNormalization: string = toUnixPath(rootPathSet[i]) + '/';
577        if (fileName.startsWith(pathNormalization)) {
578          return true;
579        }
580      }
581    } else {
582      return false;
583    }
584  }
585  return false;
586}
587
588export function mergeRollUpFiles(rollupFileList: IterableIterator<string>, rollupObject: Object) {
589  for (const moduleId of rollupFileList) {
590    if (fs.existsSync(moduleId)) {
591      allSourceFilePaths.add(toUnixPath(moduleId));
592      allModuleIds.add(moduleId);
593      addLocalPackageSet(moduleId, rollupObject);
594    }
595  }
596}
597
598// collect the modulename or pkgname of all local modules.
599export function addLocalPackageSet(moduleId: string, rollupObject: Object): void {
600  const moduleInfo: Object = rollupObject.getModuleInfo(moduleId);
601  const metaInfo: Object = moduleInfo.meta;
602  if (metaInfo.isLocalDependency) {
603    if (projectConfig.useNormalizedOHMUrl && metaInfo.pkgName) {
604      localPackageSet.add(metaInfo.pkgName);
605    }
606    if (!projectConfig.useNormalizedOHMUrl && metaInfo.moduleName) {
607      localPackageSet.add(metaInfo.moduleName);
608    }
609  }
610}
611
612export function emitBuildInfo(): void {
613  globalProgram.builderProgram.emitBuildInfo(buildInfoWriteFile);
614}
615
616function processBuildHap(cacheFile: string, rootFileNames: string[], compilationTime: CompilationTimeStatistics,
617  rollupShareObject: Object): void {
618  startTimeStatisticsLocation(compilationTime ? compilationTime.diagnosticTime : undefined);
619  const allDiagnostics: ts.Diagnostic[] = globalProgram.builderProgram
620    .getSyntacticDiagnostics()
621    .concat(globalProgram.builderProgram.getSemanticDiagnostics());
622  stopTimeStatisticsLocation(compilationTime ? compilationTime.diagnosticTime : undefined);
623  emitBuildInfo();
624  allDiagnostics.forEach((diagnostic: ts.Diagnostic) => {
625    printDiagnostic(diagnostic);
626  });
627  if (!projectConfig.xtsMode) {
628    fse.ensureDirSync(projectConfig.cachePath);
629    fs.writeFileSync(cacheFile, JSON.stringify({
630      'runtimeOS': projectConfig.runtimeOS,
631      'sdkInfo': projectConfig.sdkInfo,
632      'fileList': cache
633    }, null, 2));
634  }
635  if (projectConfig.compileHar || projectConfig.compileShared) {
636    let emit: string | undefined = undefined;
637    let writeFile = (fileName: string, text: string, writeByteOrderMark: boolean): void => {
638      emit = text;
639    };
640    [...allResolvedModules, ...rootFileNames].forEach(moduleFile => {
641      if (!(moduleFile.match(new RegExp(projectConfig.packageDir)) && projectConfig.compileHar)) {
642        try {
643          if ((/\.d\.e?ts$/).test(moduleFile)) {
644            generateSourceFilesInHar(moduleFile, fs.readFileSync(moduleFile, 'utf-8'), path.extname(moduleFile),
645              projectConfig, projectConfig.modulePathMap);
646          } else if ((/\.e?ts$/).test(moduleFile)) {
647            emit = undefined;
648            let sourcefile = globalProgram.program.getSourceFile(moduleFile);
649            if (sourcefile) {
650              globalProgram.program.emit(sourcefile, writeFile, undefined, true, undefined, true);
651            }
652            if (emit) {
653              generateSourceFilesInHar(moduleFile, emit, '.d' + path.extname(moduleFile), projectConfig, projectConfig.modulePathMap);
654            }
655          }
656        } catch (err) { }
657      }
658    });
659    printDeclarationDiagnostics();
660  }
661}
662
663function printDeclarationDiagnostics(): void {
664  globalProgram.builderProgram.getDeclarationDiagnostics().forEach((diagnostic: ts.Diagnostic) => {
665    printDiagnostic(diagnostic);
666  });
667}
668
669function containFormError(message: string): boolean {
670  if (/can't support form application./.test(message)) {
671    return true;
672  }
673  return false;
674}
675
676let fileToIgnoreDiagnostics: Set<string> | undefined = undefined;
677
678function collectFileToThrowDiagnostics(file: string, fileToThrowDiagnostics: Set<string>): void {
679  const normalizedFilePath: string = path.resolve(file);
680  const unixFilePath: string = toUnixPath(file);
681  if (fileToThrowDiagnostics.has(unixFilePath)) {
682    return;
683  }
684
685  fileToThrowDiagnostics.add(unixFilePath);
686  // Although the cache object filters JavaScript files when collecting dependency relationships, we still include the
687  // filtering of JavaScript files here to avoid potential omissions.
688  if ((/\.(c|m)?js$/).test(file) ||
689    !cache[normalizedFilePath] || cache[normalizedFilePath].children.length === 0) {
690    return;
691  }
692  cache[normalizedFilePath].children.forEach(file => {
693    collectFileToThrowDiagnostics(file, fileToThrowDiagnostics);
694  });
695}
696
697export function collectFileToIgnoreDiagnostics(rootFileNames: string[]): void {
698  if (getArkTSLinterMode() === ArkTSLinterMode.NOT_USE) {
699    return;
700  }
701
702  // In watch mode, the `beforeBuild` phase will clear the parent and children fields in the cache. For files that have
703  // not been modified, the information needs to be restored using the `resolvedModuleNames` variable.
704  if (process.env.watchMode === 'true') {
705    for (let [file, resolvedModules] of resolvedModulesCache) {
706      createOrUpdateCache(resolvedModules, file);
707    }
708  }
709
710  // With arkts linter enabled, `allowJs` option is set to true, resulting JavaScript files themselves and
711  // JavaScript-referenced files are included in the tsc program and checking process,
712  // potentially introducing new errors. For instance, in scenarios where an ets file imports js file imports ts file,
713  // it’s necessary to filter out errors from ts files.
714  let fileToThrowDiagnostics: Set<string> = new Set<string>();
715  rootFileNames.forEach(file => {
716    if (!(/\.(c|m)?js$/).test(file)) {
717      collectFileToThrowDiagnostics(file, fileToThrowDiagnostics);
718    }
719  });
720
721  let resolvedTypeReferenceDirectivesFiles: Set<string> = new Set<string>();
722  globalProgram.program.getResolvedTypeReferenceDirectives().forEach(
723    (elem: ts.ResolvedTypeReferenceDirective | undefined) => {
724      elem && elem.resolvedFileName && resolvedTypeReferenceDirectivesFiles.add(elem.resolvedFileName);
725  });
726
727  fileToIgnoreDiagnostics = new Set<string>();
728  globalProgram.program.getSourceFiles().forEach(sourceFile => {
729    // Previous projects had js libraries that were available through SDK, so need to filter js-file in SDK,
730    // like: hypium library
731    sourceFile.fileName &&
732    (!isInSDK(sourceFile.fileName) || (/\.(c|m)?js$/).test(sourceFile.fileName)) &&
733    !resolvedTypeReferenceDirectivesFiles.has(sourceFile.fileName) &&
734    fileToIgnoreDiagnostics.add(toUnixPath(sourceFile.fileName));
735  });
736
737  fileToThrowDiagnostics.forEach(file => {
738    fileToIgnoreDiagnostics.delete(file);
739  });
740}
741
742export function printDiagnostic(diagnostic: ts.Diagnostic): void {
743  if (projectConfig.ignoreWarning) {
744    return;
745  }
746
747  if (fileToIgnoreDiagnostics && diagnostic.file && diagnostic.file.fileName &&
748    fileToIgnoreDiagnostics.has(toUnixPath(diagnostic.file.fileName))) {
749    return;
750  }
751
752  const message: string = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
753  if (validateError(message)) {
754    if (process.env.watchMode !== 'true' && !projectConfig.xtsMode) {
755      updateErrorFileCache(diagnostic);
756    }
757
758    if (containFormError(message) && !isCardFile(diagnostic.file.fileName)) {
759      return;
760    }
761
762    const logPrefix: string = diagnostic.category === ts.DiagnosticCategory.Error ? 'ERROR' : 'WARN';
763    const etsCheckerLogger = fastBuildLogger || logger;
764    let logMessage: string;
765    if (logPrefix === 'ERROR') {
766      checkerResult.count += 1;
767    } else {
768      warnCheckerResult.count += 1;
769    }
770    if (diagnostic.file) {
771      const { line, character }: ts.LineAndCharacter =
772        diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!);
773      logMessage = `ArkTS:${logPrefix} File: ${diagnostic.file.fileName}:${line + 1}:${character + 1}\n ${message}\n`;
774    } else {
775      logMessage = `ArkTS:${logPrefix}: ${message}`;
776    }
777
778    if (diagnostic.category === ts.DiagnosticCategory.Error) {
779      etsCheckerLogger.error('\u001b[31m' + logMessage);
780    } else {
781      etsCheckerLogger.warn('\u001b[33m' + logMessage);
782    }
783  }
784}
785
786function validateError(message: string): boolean {
787  const propInfoReg: RegExp = /Cannot find name\s*'(\$?\$?[_a-zA-Z0-9]+)'/;
788  const stateInfoReg: RegExp = /Property\s*'(\$?[_a-zA-Z0-9]+)' does not exist on type/;
789  if (matchMessage(message, props, propInfoReg) ||
790    matchMessage(message, props, stateInfoReg)) {
791    return false;
792  }
793  return true;
794}
795function matchMessage(message: string, nameArr: any, reg: RegExp): boolean {
796  if (reg.test(message)) {
797    const match: string[] = message.match(reg);
798    if (match[1] && nameArr.includes(match[1])) {
799      return true;
800    }
801  }
802  return false;
803}
804
805function updateErrorFileCache(diagnostic: ts.Diagnostic): void {
806  if (!diagnostic.file) {
807    return;
808  }
809
810  let cacheInfo: CacheFileName = cache[path.resolve(diagnostic.file.fileName)];
811  if (cacheInfo) {
812    cacheInfo.error = true;
813    if (!cacheInfo.errorCodes) {
814      cacheInfo.errorCodes = [];
815    }
816    cacheInfo.errorCodes.includes(diagnostic.code) || cacheInfo.errorCodes.push(diagnostic.code);
817  }
818}
819
820function filterInput(rootFileNames: string[]): string[] {
821  return rootFileNames.filter((file: string) => {
822    const needUpdate: NeedUpdateFlag = { flag: false };
823    const alreadyCheckedFiles: Set<string> = new Set();
824    checkNeedUpdateFiles(path.resolve(file), needUpdate, alreadyCheckedFiles);
825    if (!needUpdate.flag) {
826      storedFileInfo.changeFiles.push(path.resolve(file));
827    }
828    return needUpdate.flag;
829  });
830}
831
832function checkNeedUpdateFiles(file: string, needUpdate: NeedUpdateFlag, alreadyCheckedFiles: Set<string>): void {
833  if (alreadyCheckedFiles.has(file)) {
834    return;
835  } else {
836    alreadyCheckedFiles.add(file);
837  }
838
839  if (needUpdate.flag) {
840    return;
841  }
842
843  const value: CacheFileName = cache[file];
844  const mtimeMs: number = fs.statSync(file).mtimeMs;
845  if (value) {
846    if (value.error || value.mtimeMs !== mtimeMs) {
847      needUpdate.flag = true;
848      return;
849    }
850    for (let i = 0; i < value.children.length; ++i) {
851      if (fs.existsSync(value.children[i])) {
852        checkNeedUpdateFiles(value.children[i], needUpdate, alreadyCheckedFiles);
853      } else {
854        needUpdate.flag = true;
855      }
856    }
857  } else {
858    cache[file] = { mtimeMs, children: [], parent: [], error: false };
859    needUpdate.flag = true;
860  }
861}
862
863const fileExistsCache: Map<string, boolean> = new Map<string, boolean>();
864const dirExistsCache: Map<string, boolean> = new Map<string, boolean>();
865const moduleResolutionHost: ts.ModuleResolutionHost = {
866  fileExists: (fileName: string): boolean => {
867    let exists = fileExistsCache.get(fileName);
868    if (exists === undefined) {
869      exists = ts.sys.fileExists(fileName);
870      fileExistsCache.set(fileName, exists);
871    }
872    return exists;
873  },
874  directoryExists: (directoryName: string): boolean => {
875    let exists = dirExistsCache.get(directoryName);
876    if (exists === undefined) {
877      exists = ts.sys.directoryExists(directoryName);
878      dirExistsCache.set(directoryName, exists);
879    }
880    return exists;
881  },
882  readFile(fileName: string): string | undefined {
883    return ts.sys.readFile(fileName);
884  },
885  realpath(path: string): string {
886    return ts.sys.realpath(path);
887  },
888  trace(s: string): void {
889    console.info(s);
890  }
891};
892
893//This is only for test
894export const moduleResolutionHostTest = moduleResolutionHost;
895
896export function resolveTypeReferenceDirectives(typeDirectiveNames: string[] | ts.FileReference[]): ts.ResolvedTypeReferenceDirective[] {
897  if (typeDirectiveNames.length === 0) {
898    return [];
899  }
900
901  const resolvedTypeReferenceCache: ts.ResolvedTypeReferenceDirective[] = [];
902  const cache: Map<string, ts.ResolvedTypeReferenceDirective> = new Map<string, ts.ResolvedTypeReferenceDirective>();
903  const containingFile: string = path.join(projectConfig.modulePath, 'build-profile.json5');
904
905  for (const entry of typeDirectiveNames) {
906    const typeName = isString(entry) ? entry : entry.fileName.toLowerCase();
907    if (!cache.has(typeName)) {
908      const resolvedFile = ts.resolveTypeReferenceDirective(typeName, containingFile, compilerOptions, moduleResolutionHost);
909      if (!resolvedFile || !resolvedFile.resolvedTypeReferenceDirective) {
910        logger.error('\u001b[31m', `ArkTS:Cannot find type definition file for: ${typeName}\n`);
911      }
912      const result: ts.ResolvedTypeReferenceDirective = resolvedFile.resolvedTypeReferenceDirective;
913      cache.set(typeName, result);
914      resolvedTypeReferenceCache.push(result);
915    }
916  }
917  return resolvedTypeReferenceCache;
918}
919
920// resolvedModulesCache records the files and their dependencies of program.
921export const resolvedModulesCache: Map<string, ts.ResolvedModuleFull[]> = new Map();
922
923export function resolveModuleNames(moduleNames: string[], containingFile: string): ts.ResolvedModuleFull[] {
924  startTimeStatisticsLocation(resolveModuleNamesTime);
925  const resolvedModules: ts.ResolvedModuleFull[] = [];
926  const cacheFileContent: ts.ResolvedModuleFull[] = resolvedModulesCache.get(path.resolve(containingFile));
927  if (![...shouldResolvedFiles].length || shouldResolvedFiles.has(path.resolve(containingFile)) ||
928    !(cacheFileContent && cacheFileContent.length === moduleNames.length)) {
929    for (const moduleName of moduleNames) {
930      const result = ts.resolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionHost);
931      if (result.resolvedModule) {
932        if (result.resolvedModule.resolvedFileName &&
933          path.extname(result.resolvedModule.resolvedFileName) === EXTNAME_JS) {
934          const resultDETSPath: string =
935            result.resolvedModule.resolvedFileName.replace(EXTNAME_JS, EXTNAME_D_ETS);
936          if (ts.sys.fileExists(resultDETSPath)) {
937            resolvedModules.push(getResolveModule(resultDETSPath, EXTNAME_D_ETS));
938          } else {
939            resolvedModules.push(result.resolvedModule);
940          }
941        } else {
942          resolvedModules.push(result.resolvedModule);
943        }
944      } else if (new RegExp(`^@(${sdkConfigPrefix})\\.`, 'i').test(moduleName.trim())) {
945        let apiFileExist: boolean = false;
946        for (let i = 0; i < sdkConfigs.length; i++) {
947          const sdkConfig = sdkConfigs[i];
948          const resolveModuleInfo: ResolveModuleInfo = getRealModulePath(sdkConfig.apiPath, moduleName, ['.d.ts', '.d.ets']);
949          const modulePath: string = resolveModuleInfo.modulePath;
950          const isDETS: boolean = resolveModuleInfo.isEts;
951          if (systemModules.includes(moduleName + (isDETS ? '.d.ets' : '.d.ts')) && ts.sys.fileExists(modulePath)) {
952            resolvedModules.push(getResolveModule(modulePath, isDETS ? '.d.ets' : '.d.ts'));
953            apiFileExist = true;
954            break;
955          }
956        }
957        if (!apiFileExist) {
958          resolvedModules.push(null);
959        }
960      } else if (/\.ets$/.test(moduleName) && !/\.d\.ets$/.test(moduleName)) {
961        const modulePath: string = path.resolve(path.dirname(containingFile), moduleName);
962        if (ts.sys.fileExists(modulePath)) {
963          resolvedModules.push(getResolveModule(modulePath, '.ets'));
964        } else {
965          resolvedModules.push(null);
966        }
967      } else if (/\.ts$/.test(moduleName)) {
968        const modulePath: string = path.resolve(path.dirname(containingFile), moduleName);
969        if (ts.sys.fileExists(modulePath)) {
970          resolvedModules.push(getResolveModule(modulePath, '.ts'));
971        } else {
972          resolvedModules.push(null);
973        }
974      } else {
975        const modulePath: string = path.resolve(__dirname, '../../../api', moduleName + '.d.ts');
976        const systemDETSModulePath: string = path.resolve(__dirname, '../../../api', moduleName + '.d.ets');
977        const kitModulePath: string = path.resolve(__dirname, '../../../kits', moduleName + '.d.ts');
978        const kitSystemDETSModulePath: string = path.resolve(__dirname, '../../../kits', moduleName + '.d.ets');
979        const suffix: string = /\.js$/.test(moduleName) ? '' : '.js';
980        const jsModulePath: string = path.resolve(__dirname, '../node_modules', moduleName + suffix);
981        const fileModulePath: string =
982          path.resolve(__dirname, '../node_modules', moduleName + '/index.js');
983        const DETSModulePath: string = path.resolve(path.dirname(containingFile),
984          /\.d\.ets$/.test(moduleName) ? moduleName : moduleName + EXTNAME_D_ETS);
985        if (ts.sys.fileExists(modulePath)) {
986          resolvedModules.push(getResolveModule(modulePath, '.d.ts'));
987        } else if (ts.sys.fileExists(systemDETSModulePath)) {
988          resolvedModules.push(getResolveModule(systemDETSModulePath, '.d.ets'));
989        } else if (ts.sys.fileExists(kitModulePath)) {
990          resolvedModules.push(getResolveModule(kitModulePath, '.d.ts'));
991        } else if (ts.sys.fileExists(kitSystemDETSModulePath)) {
992          resolvedModules.push(getResolveModule(kitSystemDETSModulePath, '.d.ets'));
993        } else if (ts.sys.fileExists(jsModulePath)) {
994          resolvedModules.push(getResolveModule(jsModulePath, '.js'));
995        } else if (ts.sys.fileExists(fileModulePath)) {
996          resolvedModules.push(getResolveModule(fileModulePath, '.js'));
997        } else if (ts.sys.fileExists(DETSModulePath)) {
998          resolvedModules.push(getResolveModule(DETSModulePath, '.d.ets'));
999        } else {
1000          const srcIndex: number = projectConfig.projectPath.indexOf('src' + path.sep + 'main');
1001          let DETSModulePathFromModule: string;
1002          if (srcIndex > 0) {
1003            DETSModulePathFromModule = path.resolve(
1004              projectConfig.projectPath.substring(0, srcIndex), moduleName + path.sep + 'index' + EXTNAME_D_ETS);
1005            if (DETSModulePathFromModule && ts.sys.fileExists(DETSModulePathFromModule)) {
1006              resolvedModules.push(getResolveModule(DETSModulePathFromModule, '.d.ets'));
1007            } else {
1008              resolvedModules.push(null);
1009            }
1010          } else {
1011            resolvedModules.push(null);
1012          }
1013        }
1014      }
1015      if (projectConfig.hotReload && resolvedModules.length &&
1016        resolvedModules[resolvedModules.length - 1]) {
1017        hotReloadSupportFiles.add(path.resolve(resolvedModules[resolvedModules.length - 1].resolvedFileName));
1018      }
1019      if (collectShouldPackedFiles(resolvedModules)) {
1020        allResolvedModules.add(resolvedModules[resolvedModules.length - 1].resolvedFileName);
1021      }
1022    }
1023    if (!projectConfig.xtsMode) {
1024      createOrUpdateCache(resolvedModules, path.resolve(containingFile));
1025    }
1026    resolvedModulesCache.set(path.resolve(containingFile), resolvedModules);
1027    stopTimeStatisticsLocation(resolveModuleNamesTime);
1028    return resolvedModules;
1029  }
1030  stopTimeStatisticsLocation(resolveModuleNamesTime);
1031  return resolvedModulesCache.get(path.resolve(containingFile));
1032}
1033
1034export interface ResolveModuleInfo {
1035  modulePath: string;
1036  isEts: boolean;
1037}
1038
1039function collectShouldPackedFiles(resolvedModules: ts.ResolvedModuleFull[]): boolean | RegExpMatchArray {
1040  return (projectConfig.compileHar || projectConfig.compileShared) && resolvedModules[resolvedModules.length - 1] &&
1041    resolvedModules[resolvedModules.length - 1].resolvedFileName &&
1042    (path.resolve(resolvedModules[resolvedModules.length - 1].resolvedFileName).match(/(\.[^d]|[^\.]d|[^\.][^d])\.e?ts$/) ||
1043      path.resolve(resolvedModules[resolvedModules.length - 1].resolvedFileName).match(/\.d\.e?ts$/) &&
1044      path.resolve(resolvedModules[resolvedModules.length - 1].resolvedFileName).match(
1045        new RegExp('\\' + path.sep + 'src' + '\\' + path.sep + 'main' + '\\' + path.sep)));
1046}
1047
1048function createOrUpdateCache(resolvedModules: ts.ResolvedModuleFull[], containingFile: string): void {
1049  const children: string[] = [];
1050  const error: boolean = false;
1051  resolvedModules.forEach(moduleObj => {
1052    if (moduleObj && moduleObj.resolvedFileName && /\.(ets|ts)$/.test(moduleObj.resolvedFileName)) {
1053      const file: string = path.resolve(moduleObj.resolvedFileName);
1054      const mtimeMs: number = fs.statSync(file).mtimeMs;
1055      children.push(file);
1056      const value: CacheFileName = cache[file];
1057      if (value) {
1058        value.mtimeMs = mtimeMs;
1059        value.error = error;
1060        value.parent = value.parent || [];
1061        value.parent.push(path.resolve(containingFile));
1062        value.parent = [...new Set(value.parent)];
1063      } else {
1064        cache[file] = { mtimeMs, children: [], parent: [containingFile], error };
1065      }
1066    }
1067  });
1068  cache[path.resolve(containingFile)] = {
1069    mtimeMs: fs.statSync(containingFile).mtimeMs, children,
1070    parent: cache[path.resolve(containingFile)] && cache[path.resolve(containingFile)].parent ?
1071      cache[path.resolve(containingFile)].parent : [], error
1072  };
1073}
1074
1075export function createWatchCompilerHost(rootFileNames: string[],
1076  reportDiagnostic: ts.DiagnosticReporter, delayPrintLogCount: Function, resetErrorCount: Function,
1077  isPipe: boolean = false, resolveModulePaths: string[] = null): ts.WatchCompilerHostOfFilesAndCompilerOptions<ts.BuilderProgram> {
1078  if (projectConfig.hotReload) {
1079    rootFileNames.forEach(fileName => {
1080      hotReloadSupportFiles.add(fileName);
1081    });
1082  }
1083  if (!(isPipe && process.env.compileTool === 'rollup')) {
1084    setCompilerOptions(resolveModulePaths);
1085  }
1086  // Change the buildInfo file path, or it will cover the buildInfo file created before.
1087  const buildInfoPath: string = path.resolve(projectConfig.cachePath, '..', WATCH_COMPILER_BUILD_INFO_SUFFIX);
1088  const watchCompilerOptions = {...compilerOptions, tsBuildInfoFile: buildInfoPath};
1089  const createProgram = ts.createSemanticDiagnosticsBuilderProgram;
1090  const host = ts.createWatchCompilerHost(
1091    [...rootFileNames, ...readDeaclareFiles()], watchCompilerOptions,
1092    ts.sys, createProgram, reportDiagnostic,
1093    (diagnostic: ts.Diagnostic) => {
1094      if ([6031, 6032].includes(diagnostic.code)) {
1095        if (!isPipe) {
1096          process.env.watchTs = 'start';
1097          resetErrorCount();
1098        }
1099      }
1100      // End of compilation in watch mode flag.
1101      if ([6193, 6194].includes(diagnostic.code)) {
1102        if (!isPipe) {
1103          process.env.watchTs = 'end';
1104          if (fastBuildLogger) {
1105            fastBuildLogger.debug(TS_WATCH_END_MSG);
1106            tsWatchEmitter.emit(TS_WATCH_END_MSG);
1107          }
1108        }
1109        delayPrintLogCount();
1110      }
1111    });
1112  host.readFile = (fileName: string) => {
1113    if (!fs.existsSync(fileName)) {
1114      return undefined;
1115    }
1116    if (/(?<!\.d)\.(ets|ts)$/.test(fileName)) {
1117      let content: string = processContent(fs.readFileSync(fileName).toString(), fileName);
1118      const extendFunctionInfo: extendInfo[] = [];
1119      content = instanceInsteadThis(content, fileName, extendFunctionInfo, props);
1120      return content;
1121    }
1122    return fs.readFileSync(fileName).toString();
1123  };
1124  host.resolveModuleNames = resolveModuleNames;
1125  host.resolveTypeReferenceDirectives = resolveTypeReferenceDirectives;
1126  return host;
1127}
1128
1129export function watchChecker(rootFileNames: string[], newLogger: any = null, resolveModulePaths: string[] = null): void {
1130  fastBuildLogger = newLogger;
1131  globalProgram.watchProgram = ts.createWatchProgram(
1132    createWatchCompilerHost(rootFileNames, printDiagnostic, () => { }, () => { }, false, resolveModulePaths));
1133}
1134
1135export function instanceInsteadThis(content: string, fileName: string, extendFunctionInfo: extendInfo[],
1136  props: string[]): string {
1137  checkUISyntax(content, fileName, extendFunctionInfo, props);
1138  extendFunctionInfo.reverse().forEach((item) => {
1139    const subStr: string = content.substring(item.start, item.end);
1140    const insert: string = subStr.replace(/(\s)\$(\.)/g, (origin, item1, item2) => {
1141      return item1 + item.compName + 'Instance' + item2;
1142    });
1143    content = content.slice(0, item.start) + insert + content.slice(item.end);
1144  });
1145  return content;
1146}
1147
1148function getResolveModule(modulePath: string, type): ts.ResolvedModuleFull {
1149  return {
1150    resolvedFileName: modulePath,
1151    isExternalLibraryImport: false,
1152    extension: type
1153  };
1154}
1155
1156export const dollarCollection: Set<string> = new Set();
1157export const extendCollection: Set<string> = new Set();
1158export const importModuleCollection: Set<string> = new Set();
1159
1160function checkUISyntax(source: string, fileName: string, extendFunctionInfo: extendInfo[], props: string[]): void {
1161  if (/\.ets$/.test(fileName)) {
1162    if (process.env.compileMode === 'moduleJson' ||
1163      path.resolve(fileName) !== path.resolve(projectConfig.projectPath, 'app.ets')) {
1164      const sourceFile: ts.SourceFile = ts.createSourceFile(fileName, source,
1165        ts.ScriptTarget.Latest, true, ts.ScriptKind.ETS, compilerOptions);
1166      collectComponents(sourceFile);
1167      collectionCustomizeStyles(sourceFile);
1168      parseAllNode(sourceFile, sourceFile, extendFunctionInfo);
1169      props.push(...dollarCollection, ...extendCollection);
1170    }
1171  }
1172}
1173
1174function collectionCustomizeStyles(node: ts.Node): void {
1175  if ((ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) &&
1176    (isUIDecorator(node, COMPONENT_STYLES_DECORATOR) || isUIDecorator(node, COMPONENT_EXTEND_DECORATOR)) &&
1177    node.name && ts.isIdentifier(node.name)) {
1178    BUILDIN_STYLE_NAMES.add(node.name.escapedText.toString());
1179  }
1180  if (ts.isSourceFile(node)) {
1181    node.statements.forEach((item: ts.Node) => {
1182      return collectionCustomizeStyles(item);
1183    });
1184  } else if (ts.isStructDeclaration(node)) {
1185    node.members.forEach((item: ts.Node) => {
1186      return collectionCustomizeStyles(item);
1187    });
1188  }
1189}
1190
1191function isUIDecorator(node: ts.MethodDeclaration | ts.FunctionDeclaration |
1192  ts.StructDeclaration | ts.ClassDeclaration, decortorName: string): boolean {
1193  const decorators: readonly ts.Decorator[] = ts.getAllDecorators(node);
1194  if (decorators && decorators.length) {
1195    for (let i = 0; i < decorators.length; i++) {
1196      const originalDecortor: string = decorators[i].getText().replace(/\(.*\)$/, '').trim();
1197      if (originalDecortor === decortorName) {
1198        return true;
1199      } else {
1200        return false;
1201      }
1202    }
1203  }
1204  return false;
1205}
1206function collectComponents(node: ts.SourceFile): void {
1207  // @ts-ignore
1208  if (process.env.watchMode !== 'true' && node.identifiers && node.identifiers.size) {
1209    // @ts-ignore
1210    for (const key of node.identifiers.keys()) {
1211      if (JS_BIND_COMPONENTS.has(key)) {
1212        appComponentCollection.get(path.join(node.fileName)).add(key);
1213      }
1214    }
1215  }
1216}
1217
1218function parseAllNode(node: ts.Node, sourceFileNode: ts.SourceFile, extendFunctionInfo: extendInfo[]): void {
1219  if (ts.isStructDeclaration(node)) {
1220    if (node.members) {
1221      node.members.forEach(item => {
1222        if (ts.isPropertyDeclaration(item) && ts.isIdentifier(item.name)) {
1223          const propertyName: string = item.name.getText();
1224          const decorators: readonly ts.Decorator[] = ts.getAllDecorators(item);
1225          if (decorators && decorators.length) {
1226            for (let i = 0; i < decorators.length; i++) {
1227              const decoratorName: string = decorators[i].getText().replace(/\(.*\)$/, '').trim();
1228              if (INNER_COMPONENT_MEMBER_DECORATORS.has(decoratorName)) {
1229                dollarCollection.add('$' + propertyName);
1230              }
1231            }
1232          }
1233        }
1234      });
1235    }
1236  }
1237  if (process.env.watchMode !== 'true' && ts.isIfStatement(node)) {
1238    appComponentCollection.get(path.join(sourceFileNode.fileName)).add(COMPONENT_IF);
1239  }
1240  if (ts.isMethodDeclaration(node) && node.name.getText() === COMPONENT_BUILD_FUNCTION ||
1241    (ts.isMethodDeclaration(node) || ts.isFunctionDeclaration(node)) &&
1242    hasDecorator(node, COMPONENT_BUILDER_DECORATOR)) {
1243    if (node.body && node.body.statements && node.body.statements.length) {
1244      const checkProp: ts.NodeArray<ts.Statement> = node.body.statements;
1245      checkProp.forEach((item, index) => {
1246        traverseBuild(item, index);
1247      });
1248    }
1249  }
1250  if (ts.isFunctionDeclaration(node) && hasDecorator(node, COMPONENT_EXTEND_DECORATOR)) {
1251    if (node.body && node.body.statements && node.body.statements.length &&
1252      !isOriginalExtend(node.body)) {
1253      extendFunctionInfo.push({
1254        start: node.pos,
1255        end: node.end,
1256        compName: isExtendFunction(node, { decoratorName: '', componentName: '' })
1257      });
1258    }
1259  }
1260  node.getChildren().forEach((item: ts.Node) => parseAllNode(item, sourceFileNode, extendFunctionInfo));
1261}
1262
1263function isForeachAndLzayForEach(node: ts.Node): boolean {
1264  return ts.isCallExpression(node) && node.expression && ts.isIdentifier(node.expression) &&
1265    FOREACH_LAZYFOREACH.has(node.expression.escapedText.toString()) && node.arguments && node.arguments[1] &&
1266    ts.isArrowFunction(node.arguments[1]) && node.arguments[1].body && ts.isBlock(node.arguments[1].body);
1267}
1268
1269function getComponentName(node: ts.Node): string {
1270  let temp = node.expression;
1271  let name: string;
1272  while (temp) {
1273    if (ts.isIdentifier(temp) && temp.parent && (ts.isCallExpression(temp.parent) ||
1274      ts.isEtsComponentExpression(temp.parent))) {
1275      name = temp.escapedText.toString();
1276      break;
1277    }
1278    temp = temp.expression;
1279  }
1280  return name;
1281}
1282
1283function traverseBuild(node: ts.Node, index: number): void {
1284  if (ts.isExpressionStatement(node)) {
1285    const parentComponentName: string = getComponentName(node);
1286    node = node.expression;
1287    while (node) {
1288      if (ts.isEtsComponentExpression(node) && node.body && ts.isBlock(node.body) &&
1289        ts.isIdentifier(node.expression) && !DOLLAR_BLOCK_INTERFACE.has(node.expression.escapedText.toString())) {
1290        node.body.statements.forEach((item: ts.Statement, indexBlock: number) => {
1291          traverseBuild(item, indexBlock);
1292        });
1293        break;
1294      } else if (isForeachAndLzayForEach(node)) {
1295        node.arguments[1].body.statements.forEach((item: ts.Statement, indexBlock: number) => {
1296          traverseBuild(item, indexBlock);
1297        });
1298        break;
1299      } else {
1300        loopNodeFindDoubleDollar(node, parentComponentName);
1301        if (ts.isEtsComponentExpression(node) && node.body && ts.isBlock(node.body) &&
1302          ts.isIdentifier(node.expression)) {
1303          node.body.statements.forEach((item: ts.Statement, indexBlock: number) => {
1304            traverseBuild(item, indexBlock);
1305          });
1306          break;
1307        }
1308      }
1309      node = node.expression;
1310    }
1311  } else if (ts.isIfStatement(node)) {
1312    ifInnerDollarAttribute(node);
1313  }
1314}
1315
1316function ifInnerDollarAttribute(node: ts.IfStatement): void {
1317  if (node.thenStatement && ts.isBlock(node.thenStatement) && node.thenStatement.statements) {
1318    node.thenStatement.statements.forEach((item, indexIfBlock) => {
1319      traverseBuild(item, indexIfBlock);
1320    });
1321  }
1322  if (node.elseStatement) {
1323    elseInnerDollarAttribute(node);
1324  }
1325}
1326
1327function elseInnerDollarAttribute(node: ts.IfStatement): void {
1328  if (ts.isIfStatement(node.elseStatement) && node.elseStatement.thenStatement && ts.isBlock(node.elseStatement.thenStatement)) {
1329    traverseBuild(node.elseStatement, 0);
1330  } else if (ts.isBlock(node.elseStatement) && node.elseStatement.statements) {
1331    node.elseStatement.statements.forEach((item, indexElseBlock) => {
1332      traverseBuild(item, indexElseBlock);
1333    });
1334  }
1335}
1336
1337function isPropertiesAddDoubleDollar(node: ts.Node): boolean {
1338  if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.arguments && node.arguments.length) {
1339    return true;
1340  } else if (ts.isEtsComponentExpression(node) && ts.isIdentifier(node.expression) &&
1341    DOLLAR_BLOCK_INTERFACE.has(node.expression.escapedText.toString())) {
1342    return true;
1343  } else {
1344    return false;
1345  }
1346}
1347function loopNodeFindDoubleDollar(node: ts.Node, parentComponentName: string): void {
1348  if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
1349    const argument: ts.NodeArray<ts.Node> = node.arguments;
1350    const propertyName: ts.Identifier | ts.PrivateIdentifier = node.expression.name;
1351    if (isCanAddDoubleDollar(propertyName.getText(), parentComponentName)) {
1352      argument.forEach((item: ts.Node) => {
1353        doubleDollarCollection(item);
1354      });
1355    }
1356  } else if (isPropertiesAddDoubleDollar(node)) {
1357    node.arguments.forEach((item: ts.Node) => {
1358      if (ts.isObjectLiteralExpression(item) && item.properties && item.properties.length) {
1359        item.properties.forEach((param: ts.Node) => {
1360          if (isObjectPram(param, parentComponentName)) {
1361            doubleDollarCollection(param.initializer);
1362          }
1363        });
1364      } else if (ts.isPropertyAccessExpression(item) && (handleComponentDollarBlock(node as ts.CallExpression, parentComponentName) ||
1365        STYLE_ADD_DOUBLE_DOLLAR.has(node.expression.getText()))) {
1366        doubleDollarCollection(item);
1367      }
1368    });
1369  }
1370}
1371
1372function handleComponentDollarBlock(node: ts.CallExpression, parentComponentName: string): boolean {
1373  return ts.isCallExpression(node) && ts.isIdentifier(node.expression) &&
1374    DOLLAR_BLOCK_INTERFACE.has(parentComponentName) && PROPERTIES_ADD_DOUBLE_DOLLAR.has(parentComponentName) &&
1375    PROPERTIES_ADD_DOUBLE_DOLLAR.get(parentComponentName).has(node.expression.escapedText.toString());
1376}
1377
1378function doubleDollarCollection(item: ts.Node): void {
1379  if (item.getText().startsWith($$)) {
1380    while (item.expression) {
1381      item = item.expression;
1382    }
1383    dollarCollection.add(item.getText());
1384  }
1385}
1386
1387function isObjectPram(param: ts.Node, parentComponentName: string): boolean {
1388  return ts.isPropertyAssignment(param) && param.name && ts.isIdentifier(param.name) &&
1389    param.initializer && PROPERTIES_ADD_DOUBLE_DOLLAR.has(parentComponentName) &&
1390    PROPERTIES_ADD_DOUBLE_DOLLAR.get(parentComponentName).has(param.name.getText());
1391}
1392
1393function isCanAddDoubleDollar(propertyName: string, parentComponentName: string): boolean {
1394  return PROPERTIES_ADD_DOUBLE_DOLLAR.has(parentComponentName) &&
1395    PROPERTIES_ADD_DOUBLE_DOLLAR.get(parentComponentName).has(propertyName) ||
1396    STYLE_ADD_DOUBLE_DOLLAR.has(propertyName);
1397}
1398
1399function processContent(source: string, id: string): string {
1400  if (fastBuildLogger) {
1401    source = visualTransform(source, id, fastBuildLogger);
1402  }
1403  source = preprocessExtend(source, extendCollection);
1404  source = preprocessNewExtend(source, extendCollection);
1405  return source;
1406}
1407
1408function judgeFileShouldResolved(file: string, shouldResolvedFiles: Set<string>): void {
1409  if (shouldResolvedFiles.has(file)) {
1410    return;
1411  }
1412  shouldResolvedFiles.add(file);
1413  if (cache && cache[file] && cache[file].parent) {
1414    cache[file].parent.forEach((item) => {
1415      judgeFileShouldResolved(item, shouldResolvedFiles);
1416    });
1417    cache[file].parent = [];
1418  }
1419  if (cache && cache[file] && cache[file].children) {
1420    cache[file].children.forEach((item) => {
1421      judgeFileShouldResolved(item, shouldResolvedFiles);
1422    });
1423    cache[file].children = [];
1424  }
1425}
1426
1427export function incrementWatchFile(watchModifiedFiles: string[],
1428  watchRemovedFiles: string[]): void {
1429  const changedFiles: string[] = [...watchModifiedFiles, ...watchRemovedFiles];
1430  if (changedFiles.length) {
1431    shouldResolvedFiles.clear();
1432  }
1433  changedFiles.forEach((file) => {
1434    judgeFileShouldResolved(file, shouldResolvedFiles);
1435  });
1436}
1437
1438export function runArkTSLinter(): void {
1439  const originProgram: ts.BuilderProgram = globalProgram.builderProgram;
1440
1441  const timePrinterInstance = ts.ArkTSLinterTimePrinter.getInstance();
1442
1443  const arkTSLinterDiagnostics = doArkTSLinter(getArkTSVersion(),
1444    getArkTSLinterMode(),
1445    originProgram,
1446    printArkTSLinterDiagnostic,
1447    !projectConfig.xtsMode,
1448    buildInfoWriteFile);
1449
1450  if (process.env.watchMode !== 'true' && !projectConfig.xtsMode) {
1451    arkTSLinterDiagnostics.forEach((diagnostic: ts.Diagnostic) => {
1452      updateErrorFileCache(diagnostic);
1453    });
1454    timePrinterInstance.appendTime(ts.TimePhase.UPDATE_ERROR_FILE);
1455  }
1456  timePrinterInstance.printTimes();
1457  ts.ArkTSLinterTimePrinter.destroyInstance();
1458}
1459
1460function printArkTSLinterDiagnostic(diagnostic: ts.Diagnostic): void {
1461  if (diagnostic.category === ts.DiagnosticCategory.Error && (isInOhModuleFile(diagnostic) || isEtsDeclFileInSdk(diagnostic))) {
1462    const originalCategory = diagnostic.category;
1463    diagnostic.category = ts.DiagnosticCategory.Warning;
1464    printDiagnostic(diagnostic);
1465    diagnostic.category = originalCategory;
1466    return;
1467  }
1468  printDiagnostic(diagnostic);
1469}
1470
1471function isEtsDeclFileInSdk(diagnostics: ts.Diagnostic): boolean {
1472  if (diagnostics.file?.fileName === undefined) {
1473    return false;
1474  }
1475  return isInSDK(diagnostics.file.fileName) && diagnostics.file.fileName.endsWith('.ets');
1476}
1477
1478function isInOhModuleFile(diagnostics: ts.Diagnostic): boolean {
1479  return (diagnostics.file !== undefined) &&
1480    ((diagnostics.file.fileName.indexOf('/oh_modules/') !== -1) || diagnostics.file.fileName.indexOf('\\oh_modules\\') !== -1);
1481}
1482
1483function isInSDK(fileName: string | undefined): boolean {
1484  if (projectConfig.etsLoaderPath === undefined || fileName === undefined) {
1485    return false;
1486  }
1487  const sdkPath = path.resolve(projectConfig.etsLoaderPath, '../../../');
1488  return path.resolve(fileName).startsWith(sdkPath);
1489}
1490
1491export function getArkTSLinterMode(): ArkTSLinterMode {
1492  if (!partialUpdateConfig.executeArkTSLinter) {
1493    return ArkTSLinterMode.NOT_USE;
1494  }
1495
1496  if (!partialUpdateConfig.standardArkTSLinter) {
1497    return ArkTSLinterMode.COMPATIBLE_MODE;
1498  }
1499
1500  if (isStandardMode()) {
1501    return ArkTSLinterMode.STANDARD_MODE;
1502  }
1503  return ArkTSLinterMode.COMPATIBLE_MODE;
1504}
1505
1506export function isStandardMode(): boolean {
1507  const STANDARD_MODE_COMPATIBLE_SDK_VERSION = 10;
1508  if (projectConfig &&
1509    projectConfig.compatibleSdkVersion &&
1510    projectConfig.compatibleSdkVersion >= STANDARD_MODE_COMPATIBLE_SDK_VERSION) {
1511    return true;
1512  }
1513  return false;
1514}
1515
1516function getArkTSVersion(): ArkTSVersion {
1517  if (projectConfig.arkTSVersion === '1.0') {
1518    return ArkTSVersion.ArkTS_1_0;
1519  } else if (projectConfig.arkTSVersion === '1.1') {
1520    return ArkTSVersion.ArkTS_1_1;
1521  } else if (projectConfig.arkTSVersion !== undefined) {
1522    const arkTSVersionLogger = fastBuildLogger || logger;
1523    arkTSVersionLogger.warn('\u001b[33m' + 'ArkTS: Invalid ArkTS version\n');
1524  }
1525
1526  if (partialUpdateConfig.arkTSVersion === '1.0') {
1527    return ArkTSVersion.ArkTS_1_0;
1528  } else if (partialUpdateConfig.arkTSVersion === '1.1') {
1529    return ArkTSVersion.ArkTS_1_1;
1530  } else if (partialUpdateConfig.arkTSVersion !== undefined) {
1531    const arkTSVersionLogger = fastBuildLogger || logger;
1532    arkTSVersionLogger.warn('\u001b[33m' + 'ArkTS: Invalid ArkTS version in metadata\n');
1533  }
1534
1535  return ArkTSVersion.ArkTS_1_1;
1536}
1537
1538enum TargetESVersion {
1539  ES2017 = 'ES2017',
1540  ES2021 = 'ES2021',
1541}
1542
1543function getTargetESVersion(): TargetESVersion {
1544  const targetESVersion = projectConfig?.projectArkOption?.tscConfig?.targetESVersion;
1545  if (targetESVersion === 'ES2017') {
1546    return TargetESVersion.ES2017;
1547  } else if (targetESVersion === 'ES2021') {
1548    return TargetESVersion.ES2021;
1549  } else if (targetESVersion !== undefined) {
1550    const targetESVersionLogger = fastBuildLogger || logger;
1551    targetESVersionLogger.warn('\u001b[33m' + 'ArkTS: Invalid Target ES version\n');
1552  }
1553  return TargetESVersion.ES2021;
1554}
1555
1556interface TargetESVersionLib {
1557  ES2017: string[],
1558  ES2021: string[],
1559}
1560
1561const targetESVersionLib: TargetESVersionLib = {
1562  // When target is es2017, the lib is es2020.
1563  ES2017: ['ES2020'],
1564  ES2021: ['ES2021'],
1565};
1566
1567function getTargetESVersionLib(): string[] {
1568  const targetESVersion = projectConfig?.projectArkOption?.tscConfig?.targetESVersion;
1569  if (targetESVersion === 'ES2017') {
1570    return targetESVersionLib.ES2017;
1571  } else if (targetESVersion === 'ES2021') {
1572    return targetESVersionLib.ES2021;
1573  } else if (targetESVersion !== undefined) {
1574    const targetESVersionLogger = fastBuildLogger || logger;
1575    targetESVersionLogger.warn('\u001b[33m' + 'ArkTS: Invalid Target ES version\n');
1576  }
1577  return targetESVersionLib.ES2021;
1578}
1579
1580function initEtsStandaloneCheckerConfig(logger, config): void {
1581  fastBuildLogger = logger;
1582  if (config.packageManagerType === 'ohpm') {
1583    config.packageDir = 'oh_modules';
1584    config.packageJson = 'oh-package.json5';
1585  } else {
1586    config.packageDir = 'node_modules';
1587    config.packageJson = 'package.json';
1588  }
1589  if (config.aceModuleJsonPath && fs.existsSync(config.aceModuleJsonPath)) {
1590    process.env.compileMode = 'moduleJson';
1591  }
1592  Object.assign(projectConfig, config);
1593}
1594
1595function resetEtsStandaloneCheckerConfig(beforeInitFastBuildLogger, beforeInitCompileMode: string): void {
1596  resetProjectConfig();
1597  resetEtsCheck();
1598  fastBuildLogger = beforeInitFastBuildLogger;
1599  process.env.compileMode = beforeInitCompileMode;
1600}
1601
1602export function etsStandaloneChecker(entryObj, logger, projectConfig): void {
1603  const beforeInitFastBuildLogger = fastBuildLogger;
1604  const beforeInitCompileMode = process.env.compileMode;
1605  initEtsStandaloneCheckerConfig(logger, projectConfig);
1606  const rootFileNames: string[] = [];
1607  const resolveModulePaths: string[] = [];
1608  Object.values(entryObj).forEach((fileName: string) => {
1609    rootFileNames.push(path.resolve(fileName));
1610  });
1611  if (projectConfig.resolveModulePaths && Array.isArray(projectConfig.resolveModulePaths)) {
1612    resolveModulePaths.push(...projectConfig.resolveModulePaths);
1613  }
1614  const filterFiles: string[] = filterInput(rootFileNames);
1615  languageService = createLanguageService(filterFiles, resolveModulePaths);
1616  const timePrinterInstance = ts.ArkTSLinterTimePrinter.getInstance();
1617  timePrinterInstance.setArkTSTimePrintSwitch(false);
1618  timePrinterInstance.appendTime(ts.TimePhase.START);
1619  globalProgram.builderProgram = languageService.getBuilderProgram(/*withLinterProgram*/ true);
1620  globalProgram.program = globalProgram.builderProgram.getProgram();
1621  props = languageService.getProps();
1622  timePrinterInstance.appendTime(ts.TimePhase.GET_PROGRAM);
1623  collectFileToIgnoreDiagnostics(filterFiles);
1624  runArkTSLinter();
1625  const allDiagnostics: ts.Diagnostic[] = globalProgram.builderProgram
1626    .getSyntacticDiagnostics()
1627    .concat(globalProgram.builderProgram.getSemanticDiagnostics());
1628  globalProgram.builderProgram.emitBuildInfo(buildInfoWriteFile);
1629
1630  allDiagnostics.forEach((diagnostic: ts.Diagnostic) => {
1631    printDiagnostic(diagnostic);
1632  });
1633  resetEtsStandaloneCheckerConfig(beforeInitFastBuildLogger, beforeInitCompileMode);
1634}
1635
1636export function resetEtsCheckTypeScript(): void {
1637  if (globalProgram.program) {
1638    globalProgram.program.releaseTypeChecker();
1639  } else if (languageService) {
1640    languageService.getProgram().releaseTypeChecker();
1641  }
1642  resetGlobalProgram();
1643  languageService = null;
1644}
1645
1646export function resetEtsCheck(): void {
1647  cache = {};
1648  props = [];
1649  needReCheckForChangedDepUsers = false;
1650  resetEtsCheckTypeScript();
1651  allResolvedModules.clear();
1652  checkerResult.count = 0;
1653  warnCheckerResult.count = 0;
1654  resolvedModulesCache.clear();
1655  dollarCollection.clear();
1656  extendCollection.clear();
1657  allSourceFilePaths.clear();
1658  allModuleIds.clear();
1659  filesBuildInfo.clear();
1660  fileExistsCache.clear();
1661  dirExistsCache.clear();
1662  targetESVersionChanged = false;
1663  fileToIgnoreDiagnostics = undefined;
1664}
1665