mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-27 04:46:25 -05:00
Do not write files directly from builder when noEmitOnError is true (#34832)
* Add tests for noEmitOnError * Do not write files directly from builder when noEmitOnError is true Fixes #34823 * make linter happy * Instead of generating output in memory, check errors before doing the emit in case of noEmitOnError
This commit is contained in:
@@ -882,36 +882,36 @@ namespace ts {
|
||||
oldProgram = undefined;
|
||||
oldState = undefined;
|
||||
|
||||
const result = createRedirectedBuilderProgram(state, configFileParsingDiagnostics);
|
||||
result.getState = () => state;
|
||||
result.backupState = () => {
|
||||
const builderProgram = createRedirectedBuilderProgram(state, configFileParsingDiagnostics);
|
||||
builderProgram.getState = () => state;
|
||||
builderProgram.backupState = () => {
|
||||
Debug.assert(backupState === undefined);
|
||||
backupState = cloneBuilderProgramState(state);
|
||||
};
|
||||
result.restoreState = () => {
|
||||
builderProgram.restoreState = () => {
|
||||
state = Debug.assertDefined(backupState);
|
||||
backupState = undefined;
|
||||
};
|
||||
result.getAllDependencies = sourceFile => BuilderState.getAllDependencies(state, Debug.assertDefined(state.program), sourceFile);
|
||||
result.getSemanticDiagnostics = getSemanticDiagnostics;
|
||||
result.emit = emit;
|
||||
result.releaseProgram = () => {
|
||||
builderProgram.getAllDependencies = sourceFile => BuilderState.getAllDependencies(state, Debug.assertDefined(state.program), sourceFile);
|
||||
builderProgram.getSemanticDiagnostics = getSemanticDiagnostics;
|
||||
builderProgram.emit = emit;
|
||||
builderProgram.releaseProgram = () => {
|
||||
releaseCache(state);
|
||||
backupState = undefined;
|
||||
};
|
||||
|
||||
if (kind === BuilderProgramKind.SemanticDiagnosticsBuilderProgram) {
|
||||
(result as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile;
|
||||
(builderProgram as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile;
|
||||
}
|
||||
else if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
|
||||
(result as EmitAndSemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile;
|
||||
(result as EmitAndSemanticDiagnosticsBuilderProgram).emitNextAffectedFile = emitNextAffectedFile;
|
||||
(builderProgram as EmitAndSemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile;
|
||||
(builderProgram as EmitAndSemanticDiagnosticsBuilderProgram).emitNextAffectedFile = emitNextAffectedFile;
|
||||
}
|
||||
else {
|
||||
notImplemented();
|
||||
}
|
||||
|
||||
return result;
|
||||
return builderProgram;
|
||||
|
||||
/**
|
||||
* Emits the next affected file's emit result (EmitResult and sourceFiles emitted) or returns undefined if iteration is complete
|
||||
@@ -987,6 +987,8 @@ namespace ts {
|
||||
function emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult {
|
||||
if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
|
||||
assertSourceFileOkWithoutNextAffectedCall(state, targetSourceFile);
|
||||
const result = handleNoEmitOptions(builderProgram, targetSourceFile, cancellationToken);
|
||||
if (result) return result;
|
||||
if (!targetSourceFile) {
|
||||
// Emit and report any errors we ran into.
|
||||
let sourceMaps: SourceMapEmitResult[] = [];
|
||||
|
||||
@@ -1570,37 +1570,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function emitWorker(program: Program, sourceFile: SourceFile | undefined, writeFileCallback: WriteFileCallback | undefined, cancellationToken: CancellationToken | undefined, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers, forceDtsEmit?: boolean): EmitResult {
|
||||
let declarationDiagnostics: readonly Diagnostic[] = [];
|
||||
|
||||
if (!forceDtsEmit) {
|
||||
if (options.noEmit) {
|
||||
return { diagnostics: declarationDiagnostics, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true };
|
||||
}
|
||||
|
||||
// If the noEmitOnError flag is set, then check if we have any errors so far. If so,
|
||||
// immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we
|
||||
// get any preEmit diagnostics, not just the ones
|
||||
if (options.noEmitOnError) {
|
||||
const diagnostics = [
|
||||
...program.getOptionsDiagnostics(cancellationToken),
|
||||
...program.getSyntacticDiagnostics(sourceFile, cancellationToken),
|
||||
...program.getGlobalDiagnostics(cancellationToken),
|
||||
...program.getSemanticDiagnostics(sourceFile, cancellationToken)
|
||||
];
|
||||
|
||||
if (diagnostics.length === 0 && getEmitDeclarations(program.getCompilerOptions())) {
|
||||
declarationDiagnostics = program.getDeclarationDiagnostics(/*sourceFile*/ undefined, cancellationToken);
|
||||
}
|
||||
|
||||
if (diagnostics.length > 0 || declarationDiagnostics.length > 0) {
|
||||
return {
|
||||
diagnostics: concatenate(diagnostics, declarationDiagnostics),
|
||||
sourceMaps: undefined,
|
||||
emittedFiles: undefined,
|
||||
emitSkipped: true
|
||||
};
|
||||
}
|
||||
}
|
||||
const result = handleNoEmitOptions(program, sourceFile, cancellationToken);
|
||||
if (result) return result;
|
||||
}
|
||||
|
||||
// Create the emit resolver outside of the "emitTime" tracking code below. That way
|
||||
@@ -3442,6 +3414,33 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function handleNoEmitOptions(program: ProgramToEmitFilesAndReportErrors, sourceFile: SourceFile | undefined, cancellationToken: CancellationToken | undefined): EmitResult | undefined {
|
||||
const options = program.getCompilerOptions();
|
||||
if (options.noEmit) {
|
||||
return { diagnostics: emptyArray, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true };
|
||||
}
|
||||
|
||||
// If the noEmitOnError flag is set, then check if we have any errors so far. If so,
|
||||
// immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we
|
||||
// get any preEmit diagnostics, not just the ones
|
||||
if (!options.noEmitOnError) return undefined;
|
||||
let diagnostics: readonly Diagnostic[] = [
|
||||
...program.getOptionsDiagnostics(cancellationToken),
|
||||
...program.getSyntacticDiagnostics(sourceFile, cancellationToken),
|
||||
...program.getGlobalDiagnostics(cancellationToken),
|
||||
...program.getSemanticDiagnostics(sourceFile, cancellationToken)
|
||||
];
|
||||
|
||||
if (diagnostics.length === 0 && getEmitDeclarations(program.getCompilerOptions())) {
|
||||
diagnostics = program.getDeclarationDiagnostics(/*sourceFile*/ undefined, cancellationToken);
|
||||
}
|
||||
|
||||
return diagnostics.length > 0 ?
|
||||
{ diagnostics, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true } :
|
||||
undefined;
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
interface CompilerHostLike {
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
|
||||
@@ -124,6 +124,7 @@ namespace ts {
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[];
|
||||
getConfigFileParsingDiagnostics(): readonly Diagnostic[];
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
|
||||
}
|
||||
@@ -152,20 +153,20 @@ namespace ts {
|
||||
const isListFilesOnly = !!program.getCompilerOptions().listFilesOnly;
|
||||
|
||||
// First get and report any syntactic errors.
|
||||
const diagnostics = program.getConfigFileParsingDiagnostics().slice();
|
||||
const configFileParsingDiagnosticsLength = diagnostics.length;
|
||||
addRange(diagnostics, program.getSyntacticDiagnostics(/*sourceFile*/ undefined, cancellationToken));
|
||||
const allDiagnostics = program.getConfigFileParsingDiagnostics().slice();
|
||||
const configFileParsingDiagnosticsLength = allDiagnostics.length;
|
||||
addRange(allDiagnostics, program.getSyntacticDiagnostics(/*sourceFile*/ undefined, cancellationToken));
|
||||
|
||||
// If we didn't have any syntactic errors, then also try getting the global and
|
||||
// semantic errors.
|
||||
if (diagnostics.length === configFileParsingDiagnosticsLength) {
|
||||
addRange(diagnostics, program.getOptionsDiagnostics(cancellationToken));
|
||||
if (allDiagnostics.length === configFileParsingDiagnosticsLength) {
|
||||
addRange(allDiagnostics, program.getOptionsDiagnostics(cancellationToken));
|
||||
|
||||
if (!isListFilesOnly) {
|
||||
addRange(diagnostics, program.getGlobalDiagnostics(cancellationToken));
|
||||
addRange(allDiagnostics, program.getGlobalDiagnostics(cancellationToken));
|
||||
|
||||
if (diagnostics.length === configFileParsingDiagnosticsLength) {
|
||||
addRange(diagnostics, program.getSemanticDiagnostics(/*sourceFile*/ undefined, cancellationToken));
|
||||
if (allDiagnostics.length === configFileParsingDiagnosticsLength) {
|
||||
addRange(allDiagnostics, program.getSemanticDiagnostics(/*sourceFile*/ undefined, cancellationToken));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,9 +176,10 @@ namespace ts {
|
||||
? { emitSkipped: true, diagnostics: emptyArray }
|
||||
: program.emit(/*targetSourceFile*/ undefined, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
|
||||
const { emittedFiles, diagnostics: emitDiagnostics } = emitResult;
|
||||
addRange(diagnostics, emitDiagnostics);
|
||||
addRange(allDiagnostics, emitDiagnostics);
|
||||
|
||||
sortAndDeduplicateDiagnostics(diagnostics).forEach(reportDiagnostic);
|
||||
const diagnostics = sortAndDeduplicateDiagnostics(allDiagnostics);
|
||||
diagnostics.forEach(reportDiagnostic);
|
||||
if (writeFileName) {
|
||||
const currentDir = program.getCurrentDirectory();
|
||||
forEach(emittedFiles, file => {
|
||||
|
||||
Reference in New Issue
Block a user