Read log file or requests file if supplied as input

This commit is contained in:
Sheetal Nandi 2023-03-22 12:20:29 -07:00
Родитель 9f18c3fd9c
Коммит 3e5466ec51
11 изменённых файлов: 322 добавлений и 52 удалений

Просмотреть файл

@ -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;