* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import path from 'path';
import { EventEmitter } from 'events';
import * as ts from 'typescript';
import {
projectConfig,
globalProgram
} from '../../../main';
import {
serviceChecker,
languageService,
printDiagnostic,
fastBuildLogger,
emitBuildInfo,
runArkTSLinter,
targetESVersionChanged,
collectFileToIgnoreDiagnostics,
TSC_SYSTEM_CODE,
traverseProgramSourceFiles
} from '../../ets_checker';
import { TS_WATCH_END_MSG } from '../../pre_define';
import {
setChecker
} from '../../utils';
import {
configureSyscapInfo,
configurePermission
} from '../system_api/api_check_utils';
import { MemoryMonitor } from '../meomry_monitor/rollup-plugin-memory-monitor';
import { MemoryDefine } from '../meomry_monitor/memory_define';
import {
CompileEvent,
createAndStartEvent,
stopEvent,
getHookEventFactory,
processExternalEvents,
ExternalEventType
} from '../../performance';
import { LINTER_SUBSYSTEM_CODE } from '../../hvigor_error_code/hvigor_error_info';
import { ErrorCodeModule } from '../../hvigor_error_code/const/error_code_module';
import { fileInfoCache } from '../../file_info_cache';
export let tsWatchEmitter: EventEmitter | undefined = undefined;
export let tsWatchEndPromise: Promise<void>;
export function etsChecker() {
let executedOnce: boolean = false;
return {
name: 'etsChecker',
buildStart() {
const recordInfo = MemoryMonitor.recordStage(MemoryDefine.ROLLUP_PLUGIN_BUILD_START);
const hookEventFactory: CompileEvent = getHookEventFactory(this.share, 'etsChecker', 'buildStart');
const eventServiceChecker = createAndStartEvent(hookEventFactory, 'serviceChecker');
fileInfoCache.setShare(this.share);
if (process.env.watchMode === 'true' && process.env.triggerTsWatch === 'true') {
tsWatchEmitter = new EventEmitter();
tsWatchEndPromise = new Promise<void>(resolve => {
tsWatchEmitter.on(TS_WATCH_END_MSG, () => {
resolve();
});
});
}
if (this.share.projectConfig.deviceTypes) {
configureSyscapInfo(this.share.projectConfig);
}
if (this.share.projectConfig.permission) {
configurePermission(this.share.projectConfig);
}
if (this.share.projectConfig.integratedHsp) {
projectConfig.integratedHsp = this.share.projectConfig.integratedHsp;
projectConfig.resetBundleName = this.share.projectConfig.integratedHsp;
}
Object.assign(projectConfig, this.share.projectConfig);
Object.assign(this.share.projectConfig, {
compileHar: projectConfig.compileHar,
compileShared: projectConfig.compileShared,
moduleRootPath: projectConfig.moduleRootPath,
buildPath: projectConfig.buildPath,
isCrossplatform: projectConfig.isCrossplatform,
requestPermissions: projectConfig.requestPermissions,
definePermissions: projectConfig.definePermissions,
syscapIntersectionSet: projectConfig.syscapIntersectionSet,
syscapUnionSet: projectConfig.syscapUnionSet,
deviceTypesMessage: projectConfig.deviceTypesMessage,
compileSdkVersion: projectConfig.compileSdkVersion,
compatibleSdkVersion: projectConfig.compatibleSdkVersion,
runtimeOS: projectConfig.runtimeOS,
ignoreCrossplatformCheck: projectConfig.ignoreCrossplatformCheck,
strictCheckerOnly: projectConfig.strictCheckerOnly
});
const logger = this.share.getLogger('etsChecker');
const rootFileNames: string[] = [];
const resolveModulePaths: string[] = [];
rootFileNamesCollect(rootFileNames);
const rootFileNamesEventName: string = `rootFileNamesCollectFinished${rootFileNames?.length ?? 0}`;
const rootFileNamesEvent = createAndStartEvent(eventServiceChecker, rootFileNamesEventName);
stopEvent(rootFileNamesEvent);
if (this.share && this.share.projectConfig && this.share.projectConfig.resolveModulePaths &&
Array.isArray(this.share.projectConfig.resolveModulePaths)) {
resolveModulePaths.push(...this.share.projectConfig.resolveModulePaths);
}
if (process.env.watchMode === 'true') {
!executedOnce && serviceChecker(rootFileNames, logger, resolveModulePaths, eventServiceChecker, this.share);
ts.PerformanceDotting?.startAdvanced('diagnostic');
if (executedOnce) {
const timePrinterInstance = ts.ArkTSLinterTimePrinter.getInstance();
timePrinterInstance.setArkTSTimePrintSwitch(false);
const buildProgramRecordInfo = MemoryMonitor.recordStage(MemoryDefine.BUILDER_PROGRAM);
timePrinterInstance.appendTime(ts.TimePhase.START);
globalProgram.builderProgram = languageService.getBuilderProgram( true);
globalProgram.program = globalProgram.builderProgram.getProgram();
traverseProgramSourceFiles(languageService.getProps());
timePrinterInstance.appendTime(ts.TimePhase.GET_PROGRAM);
MemoryMonitor.stopRecordStage(buildProgramRecordInfo);
const collectFileToIgnore = MemoryMonitor.recordStage(MemoryDefine.COLLECT_FILE_TOIGNORE_RUN_TSLINTER);
collectFileToIgnoreDiagnostics(rootFileNames);
runArkTSLinter(getErrorCodeLogger(LINTER_SUBSYSTEM_CODE, this.share));
MemoryMonitor.stopRecordStage(collectFileToIgnore);
}
executedOnce = true;
const allDiagnostics: ts.Diagnostic[] = globalProgram.builderProgram
.getSyntacticDiagnostics()
.concat(globalProgram.builderProgram.getSemanticDiagnostics());
ts.PerformanceDotting?.stopAdvanced('diagnostic');
emitBuildInfo();
let errorCodeLogger: Object | undefined = this.share?.getHvigorConsoleLogger ?
this.share?.getHvigorConsoleLogger(TSC_SYSTEM_CODE) : undefined;
allDiagnostics.forEach((diagnostic: ts.Diagnostic) => {
printDiagnostic(diagnostic, ErrorCodeModule.TSC, errorCodeLogger);
});
fastBuildLogger.debug(TS_WATCH_END_MSG);
tsWatchEmitter.emit(TS_WATCH_END_MSG);
} else {
serviceChecker(rootFileNames, logger, resolveModulePaths, eventServiceChecker, this.share);
}
setChecker();
MemoryMonitor.stopRecordStage(recordInfo);
processExternalEvents(projectConfig, ExternalEventType.TSC, {parentEvent: eventServiceChecker, filePath: ''});
stopEvent(eventServiceChecker);
},
shouldInvalidCache(): boolean {
return targetESVersionChanged;
}
};
}
function getErrorCodeLogger(code: string, share: Object): Object | undefined {
return !!share?.getHvigorConsoleLogger ? share?.getHvigorConsoleLogger(code) : undefined;
}
function rootFileNamesCollect(rootFileNames: string[]): void {
let entryFiles: string[] = projectConfig.widgetCompile ? Object.values(projectConfig.cardEntryObj) : Object.values(projectConfig.entryObj);
entryFiles = Array.from(new Set([...entryFiles, ...projectConfig.ohExports]));
entryFiles.forEach((fileName: string) => {
rootFileNames.push(path.resolve(fileName));
});
}