Skip to content

Commit cd40d26

Browse files
authored
Skip typechecking file when generating declaraiton to get d.ts signature for incremental build (#58592)
1 parent 0684152 commit cd40d26

File tree

7 files changed

+131
-104
lines changed

7 files changed

+131
-104
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2428,10 +2428,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
24282428
return visitEachChild(node, markAsSynthetic, /*context*/ undefined);
24292429
}
24302430

2431-
function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) {
2431+
function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken, skipDiagnostics?: boolean) {
24322432
// Ensure we have all the type information in place for this file so that all the
24332433
// emitter questions of this resolver will return the right information.
2434-
getDiagnostics(sourceFile, cancellationToken);
2434+
if (!skipDiagnostics) getDiagnostics(sourceFile, cancellationToken);
24352435
return emitResolver;
24362436
}
24372437

src/compiler/emitter.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,11 @@ export function getFirstProjectOutput(configFile: ParsedCommandLine, ignoreCase:
717717
return Debug.fail(`project ${configFile.options.configFilePath} expected to have at least one output`);
718718
}
719719

720+
/** @internal */
721+
export function emitResolverSkipsTypeChecking(emitOnly: boolean | EmitOnly | undefined, forceDtsEmit: boolean | undefined) {
722+
return !!forceDtsEmit && !!emitOnly;
723+
}
724+
720725
/** @internal */
721726
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
722727
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile | undefined, { scriptTransformers, declarationTransformers }: EmitTransformers, emitOnly?: boolean | EmitOnly, onlyBuildInfo?: boolean, forceDtsEmit?: boolean): EmitResult {
@@ -848,7 +853,11 @@ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFi
848853
const filesForEmit = forceDtsEmit ? sourceFiles : filter(sourceFiles, isSourceFileNotJson);
849854
// Setup and perform the transformation to retrieve declarations from the input files
850855
const inputListOrBundle = compilerOptions.outFile ? [factory.createBundle(filesForEmit)] : filesForEmit;
851-
if ((emitOnly && !getEmitDeclarations(compilerOptions)) || compilerOptions.noCheck) {
856+
if (
857+
(emitOnly && !getEmitDeclarations(compilerOptions)) ||
858+
compilerOptions.noCheck ||
859+
emitResolverSkipsTypeChecking(emitOnly, forceDtsEmit)
860+
) {
852861
// Checker wont collect the linked aliases since thats only done when declaration is enabled and checking is performed.
853862
// Do that here when emitting only dts files
854863
filesForEmit.forEach(collectLinkedAliases);

src/compiler/program.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import {
6868
EmitHost,
6969
emitModuleKindIsNonNodeESM,
7070
EmitOnly,
71+
emitResolverSkipsTypeChecking,
7172
EmitResult,
7273
emptyArray,
7374
ensureTrailingDirectorySeparator,
@@ -2870,18 +2871,27 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg
28702871
// This is because in the -out scenario all files need to be emitted, and therefore all
28712872
// files need to be type checked. And the way to specify that all files need to be type
28722873
// checked is to not pass the file to getEmitResolver.
2873-
const emitResolver = getTypeChecker().getEmitResolver(options.outFile ? undefined : sourceFile, cancellationToken);
2874+
const typeChecker = getTypeChecker();
2875+
const emitResolver = typeChecker.getEmitResolver(
2876+
options.outFile ? undefined : sourceFile,
2877+
cancellationToken,
2878+
emitResolverSkipsTypeChecking(emitOnly, forceDtsEmit),
2879+
);
28742880

28752881
performance.mark("beforeEmit");
28762882

2877-
const emitResult = emitFiles(
2878-
emitResolver,
2879-
getEmitHost(writeFileCallback),
2880-
sourceFile,
2881-
getTransformers(options, customTransformers, emitOnly),
2882-
emitOnly,
2883-
/*onlyBuildInfo*/ false,
2884-
forceDtsEmit,
2883+
const emitResult = typeChecker.runWithCancellationToken(
2884+
cancellationToken,
2885+
() =>
2886+
emitFiles(
2887+
emitResolver,
2888+
getEmitHost(writeFileCallback),
2889+
sourceFile,
2890+
getTransformers(options, customTransformers, emitOnly),
2891+
emitOnly,
2892+
/*onlyBuildInfo*/ false,
2893+
forceDtsEmit,
2894+
),
28852895
);
28862896

28872897
performance.mark("afterEmit");

src/compiler/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5264,7 +5264,7 @@ export interface TypeChecker {
52645264
// Should not be called directly. Should only be accessed through the Program instance.
52655265
/** @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
52665266
/** @internal */ getGlobalDiagnostics(): Diagnostic[];
5267-
/** @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken): EmitResolver;
5267+
/** @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken, forceDts?: boolean): EmitResolver;
52685268

52695269
/** @internal */ getNodeCount(): number;
52705270
/** @internal */ getIdentifierCount(): number;
@@ -5354,6 +5354,8 @@ export interface TypeChecker {
53545354
* and the operation is cancelled, then it should be discarded, otherwise it is safe to keep.
53555355
*/
53565356
runWithCancellationToken<T>(token: CancellationToken, cb: (checker: TypeChecker) => T): T;
5357+
/**@internal */
5358+
runWithCancellationToken<T>(token: CancellationToken | undefined, cb: (checker: TypeChecker) => T): T; // eslint-disable-line @typescript-eslint/unified-signatures
53575359

53585360
/** @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): readonly TypeParameter[] | undefined;
53595361
/** @internal */ isDeclarationVisible(node: Declaration | AnyImportSyntax): boolean;

src/testRunner/unittests/tsc/cancellationToken.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
libFile,
1818
} from "../helpers/virtualFileSystemWithWatch.js";
1919

20-
describe("unittests:: tsc:: builder cancellationToken", () => {
20+
describe("unittests:: tsc:: builder cancellationToken::", () => {
2121
verifyCancellation(/*useBuildInfo*/ true, "when emitting buildInfo");
2222
verifyCancellation(/*useBuildInfo*/ false, "when using state");
2323
function verifyCancellation(useBuildInfo: boolean, scenario: string) {
@@ -41,9 +41,9 @@ describe("unittests:: tsc:: builder cancellationToken", () => {
4141
const cFile: File = {
4242
path: `/user/username/projects/myproject/c.ts`,
4343
content: Utils.dedent`
44-
export class C {
44+
export var C = class CReal {
4545
d = 1;
46-
}`,
46+
};`,
4747
};
4848
const dFile: File = {
4949
path: `/user/username/projects/myproject/d.ts`,

0 commit comments

Comments
 (0)