Read log file or requests file if supplied as input
This commit is contained in:
Родитель
9f18c3fd9c
Коммит
3e5466ec51
|
@ -81,6 +81,7 @@ import {
|
|||
WriteFileCallback,
|
||||
WriteFileCallbackData,
|
||||
} from "./_namespaces/ts";
|
||||
import * as performance from "./_namespaces/ts.performance";
|
||||
|
||||
/** @internal */
|
||||
export interface ReusableDiagnostic extends ReusableDiagnosticRelatedInformation {
|
||||
|
@ -966,10 +967,18 @@ export function isProgramBundleEmitBuildInfo(info: ProgramBuildInfo): info is Pr
|
|||
return !!outFile(info.options || {});
|
||||
}
|
||||
|
||||
function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | undefined) {
|
||||
performance.mark("beforeGetProgramBuildInfo");
|
||||
const result = getBuildInfoWorker(state, bundle);
|
||||
performance.mark("afterGetProgramBuildInfo");
|
||||
performance.measure("BuildInfo generation", "beforeGetProgramBuildInfo", "afterGetProgramBuildInfo");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the program information to be emitted in buildInfo so that we can use it to create new program
|
||||
*/
|
||||
function getBuildInfo(state: BuilderProgramState, bundle: BundleBuildInfo | undefined): BuildInfo {
|
||||
function getBuildInfoWorker(state: BuilderProgramState, bundle: BundleBuildInfo | undefined): BuildInfo {
|
||||
const currentDirectory = Debug.checkDefined(state.program).getCurrentDirectory();
|
||||
const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getTsBuildInfoEmitOutputFilePath(state.compilerOptions)!, currentDirectory));
|
||||
// Convert the file name to Path here if we set the fileName instead to optimize multiple d.ts file emits and having to compute Canonical path
|
||||
|
|
|
@ -829,8 +829,13 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
|
|||
return;
|
||||
}
|
||||
const buildInfo = host.getBuildInfo(bundle) || createBuildInfo(/*program*/ undefined, bundle);
|
||||
performance.mark("beforeBuildInfoStringify");
|
||||
const buildInfoText = getBuildInfoText(buildInfo);
|
||||
performance.mark("afterBuildInfoStringify");
|
||||
performance.measure("BuildInfo stringify", "beforeBuildInfoStringify", "afterBuildInfoStringify");
|
||||
host.buildInfoCallbacks?.onWrite(buildInfoText.length);
|
||||
// Pass buildinfo as additional data to avoid having to reparse
|
||||
writeFile(host, emitterDiagnostics, buildInfoPath, getBuildInfoText(buildInfo), /*writeByteOrderMark*/ false, /*sourceFiles*/ undefined, { buildInfo });
|
||||
writeFile(host, emitterDiagnostics, buildInfoPath, buildInfoText, /*writeByteOrderMark*/ false, /*sourceFiles*/ undefined, { buildInfo });
|
||||
}
|
||||
|
||||
function emitJsFileOrBundle(
|
||||
|
@ -1229,7 +1234,7 @@ function emitUsingBuildInfoWorker(
|
|||
): EmitUsingBuildInfoResult {
|
||||
const { buildInfoPath, jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath } = getOutputPathsForBundle(config.options, /*forceDtsPaths*/ false);
|
||||
// If host directly provides buildinfo we can get it directly. This allows host to cache the buildinfo
|
||||
const buildInfo = host.getBuildInfo!(buildInfoPath!, config.options.configFilePath);
|
||||
const buildInfo = host.getBuildInfo!(buildInfoPath!, config.options);
|
||||
if (!buildInfo) return buildInfoPath!;
|
||||
if (!buildInfo.bundle || !buildInfo.bundle.js || (declarationFilePath && !buildInfo.bundle.dts)) return buildInfoPath!;
|
||||
|
||||
|
@ -1330,6 +1335,7 @@ function emitUsingBuildInfoWorker(
|
|||
redirectTargetsMap: createMultiMap(),
|
||||
getFileIncludeReasons: notImplemented,
|
||||
createHash: maybeBind(host, host.createHash),
|
||||
buildInfoCallbacks: host.buildInfoCallbacks,
|
||||
};
|
||||
emitFiles(
|
||||
notImplementedResolver,
|
||||
|
|
|
@ -7514,11 +7514,14 @@ export function createInputFilesWithFilePaths(
|
|||
const getAndCacheBuildInfo = () => {
|
||||
if (buildInfo === undefined && buildInfoPath) {
|
||||
if (host?.getBuildInfo) {
|
||||
buildInfo = host.getBuildInfo(buildInfoPath, options!.configFilePath) ?? false;
|
||||
buildInfo = host.getBuildInfo(buildInfoPath, options!) ?? false;
|
||||
}
|
||||
else {
|
||||
host?.buildInfoCallbacks?.onReadStart(options);
|
||||
const result = textGetter(buildInfoPath);
|
||||
host?.buildInfoCallbacks?.onReadText(result);
|
||||
buildInfo = result !== undefined ? getBuildInfo(buildInfoPath, result) ?? false : false;
|
||||
host?.buildInfoCallbacks?.onReadEnd();
|
||||
}
|
||||
}
|
||||
return buildInfo || undefined;
|
||||
|
|
|
@ -2518,6 +2518,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
|
|||
redirectTargetsMap,
|
||||
getFileIncludeReasons: program.getFileIncludeReasons,
|
||||
createHash: maybeBind(host, host.createHash),
|
||||
buildInfoCallbacks: host.buildInfoCallbacks,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -239,9 +239,9 @@ export interface SolutionBuilderHostBase<T extends BuilderProgram> extends Progr
|
|||
|
||||
// TODO: To do better with watch mode and normal build mode api that creates program and emits files
|
||||
// This currently helps enable --diagnostics and --extendedDiagnostics
|
||||
afterProgramEmitAndDiagnostics?(program: T): void;
|
||||
/** @deprecated @internal */ beforeEmitBundle?(config: ParsedCommandLine): void;
|
||||
/** @deprecated @internal */ afterEmitBundle?(config: ParsedCommandLine): void;
|
||||
afterProgramEmitAndDiagnostics?(program: T, host?: CompilerHost): void;
|
||||
/** @deprecated @internal */ beforeEmitBundle?(config: ParsedCommandLine, host: CompilerHost): void;
|
||||
/** @deprecated @internal */ afterEmitBundle?(config: ParsedCommandLine, host: CompilerHost): void;
|
||||
|
||||
// For testing
|
||||
/** @internal */ now?(): Date;
|
||||
|
@ -465,7 +465,7 @@ function createSolutionBuilderState<T extends BuilderProgram>(watch: boolean, ho
|
|||
createTypeReferenceResolutionLoader,
|
||||
);
|
||||
}
|
||||
compilerHost.getBuildInfo = (fileName, configFilePath) => getBuildInfo(state, fileName, toResolvedConfigFilePath(state, configFilePath as ResolvedConfigFileName), /*modifiedTime*/ undefined);
|
||||
compilerHost.getBuildInfo = (fileName, options) => getBuildInfo(state, fileName, options, toResolvedConfigFilePath(state, options.configFilePath as ResolvedConfigFileName), /*modifiedTime*/ undefined);
|
||||
|
||||
const { watchFile, watchDirectory, writeLog } = createWatchFactory<ResolvedConfigFileName>(hostWithWatch, options);
|
||||
|
||||
|
@ -1125,6 +1125,8 @@ function createBuildOrUpdateInvalidedProject<T extends BuilderProgram>(
|
|||
// Don't emit .d.ts if there are decl file errors
|
||||
if (declDiagnostics) {
|
||||
program.restoreEmitState(saved);
|
||||
// Revert buildInfo write size
|
||||
state.compilerHost.buildInfoCallbacks?.revertLastWrite();
|
||||
({ buildResult, step } = buildErrors(
|
||||
state,
|
||||
projectPath,
|
||||
|
@ -1142,6 +1144,7 @@ function createBuildOrUpdateInvalidedProject<T extends BuilderProgram>(
|
|||
|
||||
// Actual Emit
|
||||
const { host, compilerHost } = state;
|
||||
compilerHost.buildInfoCallbacks?.clearLastWrite();
|
||||
const resultFlags = program.hasChangedEmitSignature?.() ? BuildResultFlags.None : BuildResultFlags.DeclarationOutputUnchanged;
|
||||
const emitterDiagnostics = createDiagnosticCollection();
|
||||
const emittedOutputs = new Map<Path, string>();
|
||||
|
@ -1244,7 +1247,7 @@ function createBuildOrUpdateInvalidedProject<T extends BuilderProgram>(
|
|||
// Update js, and source map
|
||||
const { compilerHost } = state;
|
||||
state.projectCompilerOptions = config.options;
|
||||
state.host.beforeEmitBundle?.(config);
|
||||
state.host.beforeEmitBundle?.(config, compilerHost);
|
||||
const outputFiles = emitUsingBuildInfo(
|
||||
config,
|
||||
compilerHost,
|
||||
|
@ -1525,12 +1528,12 @@ function afterProgramDone<T extends BuilderProgram>(
|
|||
if (program) {
|
||||
if (state.write) listFiles(program, state.write);
|
||||
if (state.host.afterProgramEmitAndDiagnostics) {
|
||||
state.host.afterProgramEmitAndDiagnostics(program);
|
||||
state.host.afterProgramEmitAndDiagnostics(program, state.compilerHost);
|
||||
}
|
||||
program.releaseProgram();
|
||||
}
|
||||
else if (state.host.afterEmitBundle) {
|
||||
state.host.afterEmitBundle(config);
|
||||
state.host.afterEmitBundle(config, state.compilerHost);
|
||||
}
|
||||
state.projectCompilerOptions = state.baseCompilerOptions;
|
||||
}
|
||||
|
@ -1653,14 +1656,24 @@ function getBuildInfoCacheEntry<T extends BuilderProgram>(state: SolutionBuilder
|
|||
return existing?.path === path ? existing : undefined;
|
||||
}
|
||||
|
||||
function getBuildInfo<T extends BuilderProgram>(state: SolutionBuilderState<T>, buildInfoPath: string, resolvedConfigPath: ResolvedConfigFilePath, modifiedTime: Date | undefined): BuildInfo | undefined {
|
||||
function getBuildInfo<T extends BuilderProgram>(
|
||||
state: SolutionBuilderState<T>,
|
||||
buildInfoPath: string,
|
||||
options: CompilerOptions,
|
||||
resolvedConfigPath: ResolvedConfigFilePath,
|
||||
modifiedTime: Date | undefined,
|
||||
): BuildInfo | undefined {
|
||||
const path = toPath(state, buildInfoPath);
|
||||
const existing = state.buildInfoCache.get(resolvedConfigPath);
|
||||
if (existing !== undefined && existing.path === path) {
|
||||
return existing.buildInfo || undefined;
|
||||
}
|
||||
const host = (modifiedTime ? state.host : state.compilerHost);
|
||||
host.buildInfoCallbacks?.onReadStart(options);
|
||||
const value = state.readFileWithCache(buildInfoPath);
|
||||
host.buildInfoCallbacks?.onReadText(value);
|
||||
const buildInfo = value ? ts_getBuildInfo(buildInfoPath, value) : undefined;
|
||||
host.buildInfoCallbacks?.onReadEnd();
|
||||
state.buildInfoCache.set(resolvedConfigPath, { path, buildInfo: buildInfo || false, modifiedTime: modifiedTime || missingFileModifiedTime });
|
||||
return buildInfo;
|
||||
}
|
||||
|
@ -1750,7 +1763,7 @@ function getUpToDateStatusWorker<T extends BuilderProgram>(state: SolutionBuilde
|
|||
};
|
||||
}
|
||||
|
||||
const buildInfo = getBuildInfo(state, buildInfoPath, resolvedPath, buildInfoTime);
|
||||
const buildInfo = getBuildInfo(state, buildInfoPath, project.options, resolvedPath, buildInfoTime);
|
||||
if (!buildInfo) {
|
||||
// Error reading buildInfo
|
||||
return {
|
||||
|
|
|
@ -7706,6 +7706,16 @@ export type HasInvalidatedResolutions = (sourceFile: Path) => boolean;
|
|||
/** @internal */
|
||||
export type HasChangedAutomaticTypeDirectiveNames = () => boolean;
|
||||
|
||||
/** @internal */
|
||||
export interface BuildInfoCallbacks {
|
||||
onReadStart(compilerOptions: CompilerOptions | undefined): void;
|
||||
onReadText(text: string | undefined): void;
|
||||
onReadEnd(): void;
|
||||
onWrite(size: number): void;
|
||||
revertLastWrite(): void;
|
||||
clearLastWrite(): void;
|
||||
}
|
||||
|
||||
export interface CompilerHost extends ModuleResolutionHost {
|
||||
getSourceFile(fileName: string, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined;
|
||||
getSourceFileByPath?(fileName: string, path: Path, languageVersionOrOptions: ScriptTarget | CreateSourceFileOptions, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): SourceFile | undefined;
|
||||
|
@ -7770,7 +7780,8 @@ export interface CompilerHost extends ModuleResolutionHost {
|
|||
|
||||
// For testing:
|
||||
/** @internal */ storeFilesChangingSignatureDuringEmit?: boolean;
|
||||
/** @internal */ getBuildInfo?(fileName: string, configFilePath: string | undefined): BuildInfo | undefined;
|
||||
/** @internal */ getBuildInfo?(fileName: string, options: CompilerOptions): BuildInfo | undefined;
|
||||
/** @internal */ buildInfoCallbacks?: BuildInfoCallbacks;
|
||||
}
|
||||
|
||||
/** true if --out otherwise source file name *
|
||||
|
@ -8091,6 +8102,7 @@ export interface EmitHost extends ScriptReferenceHost, ModuleSpecifierResolution
|
|||
getSourceFileFromReference: Program["getSourceFileFromReference"];
|
||||
readonly redirectTargetsMap: RedirectTargetsMap;
|
||||
createHash?(data: string): string;
|
||||
buildInfoCallbacks: BuildInfoCallbacks | undefined;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
|
|
@ -763,6 +763,7 @@ export function createCompilerHostFromProgramHost(host: ProgramHost<any>, getCom
|
|||
createHash: maybeBind(host, host.createHash),
|
||||
readDirectory: maybeBind(host, host.readDirectory),
|
||||
storeFilesChangingSignatureDuringEmit: host.storeFilesChangingSignatureDuringEmit,
|
||||
buildInfoCallbacks: host.buildInfoCallbacks,
|
||||
};
|
||||
return compilerHost;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
BuilderProgram,
|
||||
BuildInfo,
|
||||
BuildInfoCallbacks,
|
||||
canJsonReportNoInputFiles,
|
||||
changeCompilerHostLikeToUseCache,
|
||||
changesAffectModuleResolution,
|
||||
|
@ -98,7 +99,8 @@ export interface ReadBuildProgramHost {
|
|||
getCurrentDirectory(): string;
|
||||
readFile(fileName: string): string | undefined;
|
||||
/** @internal */
|
||||
getBuildInfo?(fileName: string, configFilePath: string | undefined): BuildInfo | undefined;
|
||||
getBuildInfo?(fileName: string, options: CompilerOptions): BuildInfo | undefined;
|
||||
/** @internal */ buildInfoCallbacks?: BuildInfoCallbacks;
|
||||
}
|
||||
export function readBuilderProgram(compilerOptions: CompilerOptions, host: ReadBuildProgramHost) {
|
||||
const buildInfoPath = getTsBuildInfoEmitOutputFilePath(compilerOptions);
|
||||
|
@ -106,12 +108,14 @@ export function readBuilderProgram(compilerOptions: CompilerOptions, host: ReadB
|
|||
let buildInfo;
|
||||
if (host.getBuildInfo) {
|
||||
// host provides buildinfo, get it from there. This allows host to cache it
|
||||
buildInfo = host.getBuildInfo(buildInfoPath, compilerOptions.configFilePath);
|
||||
buildInfo = host.getBuildInfo(buildInfoPath, compilerOptions);
|
||||
}
|
||||
else {
|
||||
host.buildInfoCallbacks?.onReadStart(compilerOptions);
|
||||
const content = host.readFile(buildInfoPath);
|
||||
if (!content) return undefined;
|
||||
buildInfo = getBuildInfo(buildInfoPath, content);
|
||||
host.buildInfoCallbacks?.onReadText(content);
|
||||
buildInfo = content ? getBuildInfo(buildInfoPath, content) : undefined;
|
||||
host.buildInfoCallbacks?.onReadEnd();
|
||||
}
|
||||
if (!buildInfo || buildInfo.version !== version || !buildInfo.program) return undefined;
|
||||
return createBuilderProgramUsingProgramBuildInfo(buildInfo, buildInfoPath, host);
|
||||
|
@ -245,6 +249,7 @@ export interface ProgramHost<T extends BuilderProgram> {
|
|||
// TODO: GH#18217 Optional methods are frequently asserted
|
||||
createDirectory?(path: string): void;
|
||||
writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void;
|
||||
buildInfoCallbacks?: BuildInfoCallbacks;
|
||||
// For testing
|
||||
storeFilesChangingSignatureDuringEmit?: boolean;
|
||||
now?(): Date;
|
||||
|
@ -258,7 +263,7 @@ export interface WatchCompilerHost<T extends BuilderProgram> extends ProgramHost
|
|||
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
|
||||
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
afterProgramCreate?(program: T, host?: CompilerHost): void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -611,7 +616,7 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
|
|||
|
||||
reportFileChangeDetectedOnCreateProgram = false;
|
||||
if (host.afterProgramCreate && program !== builderProgram) {
|
||||
host.afterProgramCreate(builderProgram);
|
||||
host.afterProgramCreate(builderProgram, compilerHost);
|
||||
}
|
||||
|
||||
compilerHost.readFile = originalReadFile;
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as performance from "../compiler/performance";
|
|||
import {
|
||||
arrayFrom,
|
||||
BuilderProgram,
|
||||
BuildInfoCallbacks as ts_BuildInfoCallbacks,
|
||||
BuildOptions,
|
||||
buildOpts,
|
||||
changeCompilerHostLikeToUseCache,
|
||||
|
@ -9,6 +10,7 @@ import {
|
|||
combinePaths,
|
||||
CommandLineOption,
|
||||
compareStringsCaseInsensitive,
|
||||
CompilerHost as ts_CompilerHost,
|
||||
CompilerOptions,
|
||||
contains,
|
||||
convertToOptionsWithAbsolutePaths,
|
||||
|
@ -57,6 +59,7 @@ import {
|
|||
getNormalizedAbsolutePath,
|
||||
isIncrementalCompilation,
|
||||
isWatchSet,
|
||||
noop,
|
||||
normalizePath,
|
||||
optionDeclarations,
|
||||
optionsForBuild,
|
||||
|
@ -71,6 +74,7 @@ import {
|
|||
Program,
|
||||
reduceLeftIterator,
|
||||
ReportEmitErrorSummary,
|
||||
returnUndefined,
|
||||
SolutionBuilder,
|
||||
SolutionBuilderHostBase,
|
||||
sort,
|
||||
|
@ -82,6 +86,7 @@ import {
|
|||
supportedTSExtensionsFlat,
|
||||
sys,
|
||||
System,
|
||||
timestamp,
|
||||
toPath,
|
||||
tracing,
|
||||
validateLocaleAndSetLanguage,
|
||||
|
@ -100,6 +105,7 @@ export enum StatisticType {
|
|||
time,
|
||||
count,
|
||||
memory,
|
||||
size,
|
||||
}
|
||||
|
||||
function countLines(program: Program): Map<string, number> {
|
||||
|
@ -841,7 +847,7 @@ function performBuild(
|
|||
createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)),
|
||||
createWatchStatusReporter(sys, buildOptions)
|
||||
);
|
||||
const solutionPerformance = enableSolutionPerformance(sys, buildOptions);
|
||||
const solutionPerformance = enableSolutionPerformance(sys, buildOptions, buildHost);
|
||||
updateSolutionBuilderHost(sys, cb, buildHost, solutionPerformance);
|
||||
const onWatchStatusChange = buildHost.onWatchStatusChange;
|
||||
let reportBuildStatistics = false;
|
||||
|
@ -868,7 +874,7 @@ function performBuild(
|
|||
createBuilderStatusReporter(sys, shouldBePretty(sys, buildOptions)),
|
||||
createReportErrorSummary(sys, buildOptions)
|
||||
);
|
||||
const solutionPerformance = enableSolutionPerformance(sys, buildOptions);
|
||||
const solutionPerformance = enableSolutionPerformance(sys, buildOptions, buildHost);
|
||||
updateSolutionBuilderHost(sys, cb, buildHost, solutionPerformance);
|
||||
const builder = createSolutionBuilder(buildHost, projects, buildOptions);
|
||||
const exitStatus = buildOptions.clean ? builder.clean() : builder.build();
|
||||
|
@ -894,7 +900,7 @@ function performCompilation(
|
|||
const currentDirectory = host.getCurrentDirectory();
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
|
||||
changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, currentDirectory, getCanonicalFileName));
|
||||
enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false);
|
||||
enableStatisticsAndTracing(sys, options, host as CompilerHost, /*isBuildMode*/ false);
|
||||
|
||||
const programOptions: CreateProgramOptions = {
|
||||
rootNames: fileNames,
|
||||
|
@ -910,7 +916,7 @@ function performCompilation(
|
|||
s => sys.write(s + sys.newLine),
|
||||
createReportErrorSummary(sys, options)
|
||||
);
|
||||
reportStatistics(sys, program, /*builder*/ undefined);
|
||||
reportStatistics(sys, program, host as CompilerHost, /*builder*/ undefined);
|
||||
cb(program);
|
||||
return sys.exit(exitStatus);
|
||||
}
|
||||
|
@ -922,8 +928,8 @@ function performIncrementalCompilation(
|
|||
config: ParsedCommandLine
|
||||
) {
|
||||
const { options, fileNames, projectReferences } = config;
|
||||
enableStatisticsAndTracing(sys, options, /*isBuildMode*/ false);
|
||||
const host = createIncrementalCompilerHost(options, sys);
|
||||
enableStatisticsAndTracing(sys, options, host as CompilerHost, /*isBuildMode*/ false);
|
||||
const exitStatus = ts_performIncrementalCompilation({
|
||||
host,
|
||||
system: sys,
|
||||
|
@ -934,7 +940,7 @@ function performIncrementalCompilation(
|
|||
reportDiagnostic,
|
||||
reportErrorSummary: createReportErrorSummary(sys, options),
|
||||
afterProgramEmitAndDiagnostics: builderProgram => {
|
||||
reportStatistics(sys, builderProgram.getProgram(), /*builder*/ undefined);
|
||||
reportStatistics(sys, builderProgram.getProgram(), host as CompilerHost, /*builder*/ undefined);
|
||||
cb(builderProgram);
|
||||
}
|
||||
});
|
||||
|
@ -948,13 +954,13 @@ function updateSolutionBuilderHost(
|
|||
solutionPerformance: SolutionPerformance | undefined,
|
||||
) {
|
||||
updateCreateProgram(sys, buildHost, /*isBuildMode*/ true);
|
||||
buildHost.afterProgramEmitAndDiagnostics = program => {
|
||||
reportStatistics(sys, program.getProgram(), solutionPerformance);
|
||||
buildHost.afterProgramEmitAndDiagnostics = (program, host) => {
|
||||
reportStatistics(sys, program.getProgram(), host as CompilerHost, solutionPerformance);
|
||||
cb(program);
|
||||
};
|
||||
buildHost.beforeEmitBundle = config => enableStatisticsAndTracing(sys, config.options, /*isBuildMode*/ true);
|
||||
buildHost.afterEmitBundle = config => {
|
||||
reportStatistics(sys, config, solutionPerformance);
|
||||
buildHost.beforeEmitBundle = (config, host) => enableStatisticsAndTracing(sys, config.options, host as CompilerHost, /*isBuildMode*/ true);
|
||||
buildHost.afterEmitBundle = (config, host) => {
|
||||
reportStatistics(sys, config, host as CompilerHost, solutionPerformance);
|
||||
cb(config);
|
||||
};
|
||||
}
|
||||
|
@ -964,22 +970,26 @@ function updateCreateProgram<T extends BuilderProgram>(sys: System, host: { crea
|
|||
host.createProgram = (rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences) => {
|
||||
Debug.assert(rootNames !== undefined || (options === undefined && !!oldProgram));
|
||||
if (options !== undefined) {
|
||||
enableStatisticsAndTracing(sys, options, isBuildMode);
|
||||
enableStatisticsAndTracing(sys, options, host as CompilerHost, isBuildMode);
|
||||
}
|
||||
return compileUsingBuilder(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences);
|
||||
};
|
||||
}
|
||||
|
||||
function updateWatchCompilationHost(
|
||||
sys: System,
|
||||
system: System,
|
||||
cb: ExecuteCommandLineCallbacks,
|
||||
watchCompilerHost: WatchCompilerHost<EmitAndSemanticDiagnosticsBuilderProgram>,
|
||||
options: CompilerOptions,
|
||||
) {
|
||||
updateCreateProgram(sys, watchCompilerHost, /*isBuildMode*/ false);
|
||||
updateCreateProgram(system, watchCompilerHost, /*isBuildMode*/ false);
|
||||
if (system === sys && options.extendedDiagnostics) {
|
||||
createBuildInfoCallbacks(watchCompilerHost, options);
|
||||
}
|
||||
const emitFilesUsingBuilder = watchCompilerHost.afterProgramCreate!; // TODO: GH#18217
|
||||
watchCompilerHost.afterProgramCreate = builderProgram => {
|
||||
emitFilesUsingBuilder(builderProgram);
|
||||
reportStatistics(sys, builderProgram.getProgram(), /*builder*/ undefined);
|
||||
watchCompilerHost.afterProgramCreate = (builderProgram, host) => {
|
||||
emitFilesUsingBuilder(builderProgram, host);
|
||||
reportStatistics(system, builderProgram.getProgram(), host as CompilerHost, /*builder*/ undefined);
|
||||
cb(builderProgram);
|
||||
};
|
||||
}
|
||||
|
@ -1005,7 +1015,7 @@ function createWatchOfConfigFile(
|
|||
reportDiagnostic,
|
||||
reportWatchStatus: createWatchStatusReporter(system, configParseResult.options)
|
||||
});
|
||||
updateWatchCompilationHost(system, cb, watchCompilerHost);
|
||||
updateWatchCompilationHost(system, cb, watchCompilerHost, configParseResult.options);
|
||||
watchCompilerHost.configFileParsingResult = configParseResult;
|
||||
watchCompilerHost.extendedConfigCache = extendedConfigCache;
|
||||
return createWatchProgram(watchCompilerHost);
|
||||
|
@ -1027,29 +1037,34 @@ function createWatchOfFilesAndCompilerOptions(
|
|||
reportDiagnostic,
|
||||
reportWatchStatus: createWatchStatusReporter(system, options)
|
||||
});
|
||||
updateWatchCompilationHost(system, cb, watchCompilerHost);
|
||||
updateWatchCompilationHost(system, cb, watchCompilerHost, options);
|
||||
return createWatchProgram(watchCompilerHost);
|
||||
}
|
||||
|
||||
interface SolutionPerformance {
|
||||
addAggregateStatistic(s: Statistic): void;
|
||||
hasStatistics(name: string): boolean;
|
||||
forEachAggregateStatistics(cb: (s: Statistic) => void): void;
|
||||
buildInfoCallbacks: BuildInfoCallbacks;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
function enableSolutionPerformance(system: System, options: BuildOptions) {
|
||||
function enableSolutionPerformance(system: System, options: BuildOptions, buildHost: SolutionBuilderHostBase<EmitAndSemanticDiagnosticsBuilderProgram>) {
|
||||
if (system === sys && options.extendedDiagnostics) {
|
||||
performance.enable();
|
||||
return createSolutionPerfomrance();
|
||||
return createSolutionPerfomrance(buildHost);
|
||||
}
|
||||
}
|
||||
|
||||
function createSolutionPerfomrance(): SolutionPerformance {
|
||||
function createSolutionPerfomrance(buildHost: SolutionBuilderHostBase<EmitAndSemanticDiagnosticsBuilderProgram>): SolutionPerformance {
|
||||
let statistics: Map<string, Statistic> | undefined;
|
||||
const buildInfoCallbacks = createBuildInfoCallbacks(buildHost, /*options*/ undefined);
|
||||
return {
|
||||
addAggregateStatistic,
|
||||
forEachAggregateStatistics: forEachAggreateStatistics,
|
||||
hasStatistics,
|
||||
forEachAggregateStatistics,
|
||||
clear,
|
||||
buildInfoCallbacks,
|
||||
};
|
||||
|
||||
function addAggregateStatistic(s: Statistic) {
|
||||
|
@ -1063,12 +1078,17 @@ function createSolutionPerfomrance(): SolutionPerformance {
|
|||
}
|
||||
}
|
||||
|
||||
function forEachAggreateStatistics(cb: (s: Statistic) => void) {
|
||||
function hasStatistics(name: string) {
|
||||
return !!statistics?.has(name);
|
||||
}
|
||||
|
||||
function forEachAggregateStatistics(cb: (s: Statistic) => void) {
|
||||
statistics?.forEach(cb);
|
||||
}
|
||||
|
||||
function clear() {
|
||||
statistics = undefined;
|
||||
buildInfoCallbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1089,6 +1109,8 @@ function reportSolutionBuilderTimes(
|
|||
reportSolutionBuilderCountStatistic("SolutionBuilder::Projects built");
|
||||
reportSolutionBuilderCountStatistic("SolutionBuilder::Timestamps only updates");
|
||||
reportSolutionBuilderCountStatistic("SolutionBuilder::Bundles updated");
|
||||
reportBuildInfoReadOrWriteStatistic(solutionPerformance.buildInfoCallbacks.getRead(), "read");
|
||||
reportBuildInfoReadOrWriteStatistic(solutionPerformance.buildInfoCallbacks.getWrite(), "write");
|
||||
solutionPerformance.forEachAggregateStatistics(s => {
|
||||
s.name = `Aggregate ${s.name}`;
|
||||
statistics.push(s);
|
||||
|
@ -1112,6 +1134,22 @@ function reportSolutionBuilderTimes(
|
|||
function getNameFromSolutionBuilderMarkOrMeasure(name: string) {
|
||||
return name.replace("SolutionBuilder::", "");
|
||||
}
|
||||
|
||||
function reportBuildInfoReadOrWriteStatistic(s: CountAndSize | undefined, type: "read" | "write") {
|
||||
if (s?.count) {
|
||||
const countStatisticName = `BuildInfo ${type}`;
|
||||
if (s.count !== 1) statistics.push({ name: countStatisticName, value: s.count, type: StatisticType.count });
|
||||
if (s.size) statistics.push({ name: `BuildInfo ${type} size`, value: s.size, type: StatisticType.size });
|
||||
if (s.textTime) statistics.push({ name: `BuildInfo ${type} time`, value: s.textTime, type: StatisticType.time });
|
||||
if (s.parseTime) statistics.push({ name: `BuildInfo ${type} parsing time`, value: s.parseTime, type: StatisticType.time });
|
||||
if (solutionPerformance!.hasStatistics(countStatisticName)) {
|
||||
solutionPerformance!.addAggregateStatistic({ name: countStatisticName, value: s.count, type: StatisticType.count });
|
||||
if (s.size) solutionPerformance!.addAggregateStatistic({ name: `BuildInfo ${type} size`, value: s.size, type: StatisticType.size });
|
||||
if (s.textTime) solutionPerformance!.addAggregateStatistic({ name: `BuildInfo ${type} time`, value: s.textTime, type: StatisticType.time });
|
||||
if (s.parseTime) solutionPerformance!.addAggregateStatistic({ name: `BuildInfo ${type} parsing time`, value: s.parseTime, type: StatisticType.time });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function canReportDiagnostics(system: System, compilerOptions: CompilerOptions) {
|
||||
|
@ -1122,15 +1160,177 @@ function canTrace(system: System, compilerOptions: CompilerOptions) {
|
|||
return system === sys && compilerOptions.generateTrace;
|
||||
}
|
||||
|
||||
function enableStatisticsAndTracing(system: System, compilerOptions: CompilerOptions, isBuildMode: boolean) {
|
||||
function enableStatisticsAndTracing(system: System, compilerOptions: CompilerOptions, host: CompilerHost | undefined, isBuildMode: boolean) {
|
||||
if (canReportDiagnostics(system, compilerOptions)) {
|
||||
performance.enable(system);
|
||||
}
|
||||
|
||||
if (canTrace(system, compilerOptions)) {
|
||||
startTracing(isBuildMode ? "build" : "project",
|
||||
compilerOptions.generateTrace!, compilerOptions.configFilePath);
|
||||
}
|
||||
if (system === sys && host) {
|
||||
if (compilerOptions.extendedDiagnostics && isIncrementalCompilation(compilerOptions)) {
|
||||
createBuildInfoCallbacks(host, compilerOptions);
|
||||
}
|
||||
else {
|
||||
createNoOpBuildInfoCallbacks(host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface CountAndSize {
|
||||
count: number;
|
||||
size: number;
|
||||
textTime: number;
|
||||
parseTime: number;
|
||||
}
|
||||
interface LastRead {
|
||||
size: number;
|
||||
compilerOptions: CompilerOptions | undefined;
|
||||
start: number;
|
||||
textTime: number;
|
||||
end: number;
|
||||
}
|
||||
interface BuildInfoCallbacks extends ts_BuildInfoCallbacks {
|
||||
getRead(): CountAndSize | undefined;
|
||||
getWrite(): CountAndSize | undefined;
|
||||
getLastRead(): LastRead | undefined;
|
||||
onTransferLastRead(): void;
|
||||
clearLastRead(): void;
|
||||
close(host: CompilerHost): void;
|
||||
clear(): void;
|
||||
}
|
||||
interface CompilerHost extends ts_CompilerHost {
|
||||
buildInfoCallbacks?: BuildInfoCallbacks;
|
||||
}
|
||||
|
||||
function createNoOpBuildInfoCallbacks(host: CompilerHost) {
|
||||
const oldCallbacks = host.buildInfoCallbacks;
|
||||
oldCallbacks?.clearLastRead();
|
||||
return host.buildInfoCallbacks = {
|
||||
onReadStart: noop,
|
||||
onReadText: noop,
|
||||
onReadEnd: noop,
|
||||
onWrite: noop,
|
||||
getRead: returnUndefined,
|
||||
getWrite: returnUndefined,
|
||||
getLastRead: returnUndefined,
|
||||
onTransferLastRead: noop,
|
||||
clearLastRead: noop,
|
||||
revertLastWrite: noop,
|
||||
clearLastWrite: noop,
|
||||
close: host => host.buildInfoCallbacks = oldCallbacks,
|
||||
clear: noop,
|
||||
};
|
||||
}
|
||||
|
||||
function createBuildInfoCallbacks(
|
||||
host: CompilerHost | SolutionBuilderHostBase<EmitAndSemanticDiagnosticsBuilderProgram> | WatchCompilerHost<EmitAndSemanticDiagnosticsBuilderProgram>,
|
||||
options: CompilerOptions | undefined
|
||||
) {
|
||||
const read = initializedCountAndSize();
|
||||
const write = initializedCountAndSize();
|
||||
let lastRead: LastRead | undefined;
|
||||
let lastWrite: number | undefined;
|
||||
const oldCallbacks = host.buildInfoCallbacks as BuildInfoCallbacks | undefined;
|
||||
if (oldCallbacks) {
|
||||
// Transfer read of build info to new callbacks
|
||||
// This is needed to ensure that we report buildinfo read of program since its done before program is created
|
||||
const oldLastRead = oldCallbacks.getLastRead();
|
||||
if (oldLastRead && oldLastRead.compilerOptions === options) {
|
||||
recordRead(oldLastRead);
|
||||
oldCallbacks.onTransferLastRead();
|
||||
}
|
||||
else {
|
||||
oldCallbacks.clearLastRead();
|
||||
}
|
||||
}
|
||||
return host.buildInfoCallbacks = {
|
||||
onReadStart,
|
||||
onReadText,
|
||||
onReadEnd,
|
||||
onWrite,
|
||||
getRead: () => read,
|
||||
getWrite: () => write,
|
||||
getLastRead: () => lastRead,
|
||||
onTransferLastRead,
|
||||
clearLastRead: () => lastRead = undefined,
|
||||
revertLastWrite,
|
||||
clearLastWrite: () => lastWrite = undefined,
|
||||
close: host => host.buildInfoCallbacks = oldCallbacks,
|
||||
clear,
|
||||
};
|
||||
|
||||
function clear() {
|
||||
Debug.assert(!oldCallbacks);
|
||||
read.count = read.size = read.textTime = read.parseTime = 0;
|
||||
write.count = write.size = 0;
|
||||
lastRead = undefined;
|
||||
lastWrite = undefined;
|
||||
}
|
||||
|
||||
function onTransferLastRead() {
|
||||
read.count--;
|
||||
read.size -= lastRead!.size;
|
||||
read.textTime -= lastReadTextTime(lastRead!);
|
||||
read.parseTime -= lastReadParseTime(lastRead!);
|
||||
lastRead = undefined;
|
||||
}
|
||||
|
||||
function revertLastWrite() {
|
||||
if (lastWrite) {
|
||||
revertReadOrWrite(write, lastWrite);
|
||||
lastWrite = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function revertReadOrWrite(countAndSize: CountAndSize, size: number) {
|
||||
countAndSize.count--;
|
||||
countAndSize.size -= size;
|
||||
}
|
||||
|
||||
function onReadStart(compilerOptions: CompilerOptions | undefined) {
|
||||
lastRead = { start: timestamp(), compilerOptions, textTime: 0, end: 0, size: 0 };
|
||||
}
|
||||
|
||||
function onReadText(content: string | undefined) {
|
||||
lastRead!.textTime = timestamp();
|
||||
lastRead!.size = content?.length ?? 0;
|
||||
}
|
||||
|
||||
function onReadEnd() {
|
||||
lastRead!.end = timestamp();
|
||||
recordRead(lastRead!);
|
||||
if (!lastRead!.compilerOptions) lastRead = undefined;
|
||||
}
|
||||
|
||||
function recordRead(lastRead: LastRead) {
|
||||
onReadOrWrite(read, lastRead.size);
|
||||
read.textTime += lastReadTextTime(lastRead);
|
||||
read.parseTime += lastReadParseTime(lastRead);
|
||||
}
|
||||
|
||||
function lastReadTextTime(lastRead: LastRead) {
|
||||
return lastRead.textTime - lastRead.start;
|
||||
}
|
||||
|
||||
function lastReadParseTime(lastRead: LastRead) {
|
||||
return lastRead.end - lastRead.textTime;
|
||||
}
|
||||
|
||||
function onWrite(size: number) {
|
||||
onReadOrWrite(write, size);
|
||||
lastWrite = size;
|
||||
}
|
||||
|
||||
function onReadOrWrite(countAndSize: CountAndSize, size: number) {
|
||||
countAndSize.count++;
|
||||
countAndSize.size += size;
|
||||
}
|
||||
}
|
||||
|
||||
function initializedCountAndSize(): CountAndSize {
|
||||
return { count: 0, size: 0, textTime: 0, parseTime: 0 };
|
||||
}
|
||||
|
||||
function isSolutionMarkOrMeasure(name: string) {
|
||||
|
@ -1141,7 +1341,7 @@ function isProgram(programOrConfig: Program | ParsedCommandLine): programOrConfi
|
|||
return !(programOrConfig as ParsedCommandLine).options;
|
||||
}
|
||||
|
||||
function reportStatistics(sys: System, programOrConfig: Program | ParsedCommandLine, solutionPerformance: SolutionPerformance | undefined) {
|
||||
function reportStatistics(sys: System, programOrConfig: Program | ParsedCommandLine, host: CompilerHost | undefined, solutionPerformance: SolutionPerformance | undefined) {
|
||||
const program = isProgram(programOrConfig) ? programOrConfig : undefined;
|
||||
const config = isProgram(programOrConfig) ? undefined : programOrConfig;
|
||||
const compilerOptions = program ? program.getCompilerOptions() : config!.options;
|
||||
|
@ -1189,6 +1389,11 @@ function reportStatistics(sys: System, programOrConfig: Program | ParsedCommandL
|
|||
reportCountStatistic("Subtype cache size", caches.subtype);
|
||||
reportCountStatistic("Strict subtype cache size", caches.strictSubtype);
|
||||
}
|
||||
if (host?.buildInfoCallbacks) {
|
||||
reportBuildInfoReadOrWriteStatistic(host.buildInfoCallbacks.getRead(), "read");
|
||||
reportBuildInfoReadOrWriteStatistic(host.buildInfoCallbacks.getWrite(), "write");
|
||||
host.buildInfoCallbacks.close(host);
|
||||
}
|
||||
if (isPerformanceEnabled) {
|
||||
performance.forEachMeasure((name, duration) => {
|
||||
if (!isSolutionMarkOrMeasure(name)) reportTimeStatistic(`${name} time`, duration, /*aggregate*/ true);
|
||||
|
@ -1242,6 +1447,20 @@ function reportStatistics(sys: System, programOrConfig: Program | ParsedCommandL
|
|||
function reportTimeStatistic(name: string, time: number, aggregate: boolean) {
|
||||
reportStatisticalValue({ name, value: time, type: StatisticType.time }, aggregate);
|
||||
}
|
||||
|
||||
function reportBuildInfoReadOrWriteStatistic(s: CountAndSize | undefined, type: "read" | "write") {
|
||||
if (s?.count) {
|
||||
if (s.count === 1) {
|
||||
solutionPerformance?.addAggregateStatistic({ name: `BuildInfo ${type}`, value: s.count, type: StatisticType.count });
|
||||
}
|
||||
else {
|
||||
reportCountStatistic(`BuildInfo ${type}`, s.count);
|
||||
}
|
||||
if (s.size) reportStatisticalValue({ name: `BuildInfo ${type} size`, value: s.size, type: StatisticType.size }, /*aggregate*/ true);
|
||||
if (s.textTime) reportTimeStatistic(`BuildInfo ${type} time`, s.textTime, /*aggregate*/ true);
|
||||
if (s.parseTime) reportTimeStatistic(`BuildInfo ${type} parsing time`, s.parseTime, /*aggregate*/ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function reportAllStatistics(sys: System, statistics: Statistic[]) {
|
||||
|
@ -1270,6 +1489,7 @@ function statisticValue(s: Statistic) {
|
|||
case StatisticType.time:
|
||||
return (s.value / 1000).toFixed(2) + "s";
|
||||
case StatisticType.memory:
|
||||
case StatisticType.size:
|
||||
return Math.round(s.value / 1000) + "K";
|
||||
default:
|
||||
Debug.assertNever(s.type);
|
||||
|
@ -1289,7 +1509,7 @@ function writeConfigFile(
|
|||
}
|
||||
else {
|
||||
sys.writeFile(file, generateTSConfig(options, fileNames, sys.newLine));
|
||||
const output: string[] = [sys.newLine, ...getHeader(sys,"Created a new tsconfig.json with:")];
|
||||
const output: string[] = [sys.newLine, ...getHeader(sys, "Created a new tsconfig.json with:")];
|
||||
output.push(getCompilerOptionsDiffValue(options, sys.newLine) + sys.newLine + sys.newLine);
|
||||
output.push(`You can learn more at https://aka.ms/tsconfig` + sys.newLine);
|
||||
for (const line of output) {
|
||||
|
|
|
@ -9646,7 +9646,7 @@ declare namespace ts {
|
|||
/** If provided, use this method to get parsed command lines for referenced projects */
|
||||
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
afterProgramCreate?(program: T, host?: CompilerHost): void;
|
||||
}
|
||||
/**
|
||||
* Host to create watch with root files and options
|
||||
|
@ -9735,7 +9735,7 @@ declare namespace ts {
|
|||
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
|
||||
reportDiagnostic: DiagnosticReporter;
|
||||
reportSolutionBuilderStatus: DiagnosticReporter;
|
||||
afterProgramEmitAndDiagnostics?(program: T): void;
|
||||
afterProgramEmitAndDiagnostics?(program: T, host?: CompilerHost): void;
|
||||
}
|
||||
interface SolutionBuilderHost<T extends BuilderProgram> extends SolutionBuilderHostBase<T> {
|
||||
reportErrorSummary?: ReportEmitErrorSummary;
|
||||
|
|
|
@ -5703,7 +5703,7 @@ declare namespace ts {
|
|||
/** If provided, use this method to get parsed command lines for referenced projects */
|
||||
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
|
||||
/** If provided, callback to invoke after every new program creation */
|
||||
afterProgramCreate?(program: T): void;
|
||||
afterProgramCreate?(program: T, host?: CompilerHost): void;
|
||||
}
|
||||
/**
|
||||
* Host to create watch with root files and options
|
||||
|
@ -5792,7 +5792,7 @@ declare namespace ts {
|
|||
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
|
||||
reportDiagnostic: DiagnosticReporter;
|
||||
reportSolutionBuilderStatus: DiagnosticReporter;
|
||||
afterProgramEmitAndDiagnostics?(program: T): void;
|
||||
afterProgramEmitAndDiagnostics?(program: T, host?: CompilerHost): void;
|
||||
}
|
||||
interface SolutionBuilderHost<T extends BuilderProgram> extends SolutionBuilderHostBase<T> {
|
||||
reportErrorSummary?: ReportEmitErrorSummary;
|
||||
|
|
Загрузка…
Ссылка в новой задаче