Skip to content

Commit 9971e8b

Browse files
Merge pull request #32688 from uniqueiniquity/skipCOSForDTS
Avoid compile on save when there is no emit impact
2 parents b239c2a + 3646809 commit 9971e8b

File tree

2 files changed

+126
-8
lines changed

2 files changed

+126
-8
lines changed

src/server/session.ts

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ namespace ts.server {
4242
return false;
4343
}
4444

45+
46+
function dtsChangeCanAffectEmit(compilationSettings: CompilerOptions) {
47+
return getEmitDeclarations(compilationSettings) || !!compilationSettings.emitDecoratorMetadata;
48+
}
49+
4550
function formatDiag(fileName: NormalizedPath, project: Project, diag: Diagnostic): protocol.Diagnostic {
4651
const scriptInfo = project.getScriptInfoForNormalizedPath(fileName)!; // TODO: GH#18217
4752
return {
@@ -1606,15 +1611,22 @@ namespace ts.server {
16061611
path => this.projectService.getScriptInfoForPath(path)!,
16071612
projects,
16081613
(project, info) => {
1609-
let result: protocol.CompileOnSaveAffectedFileListSingleProject | undefined;
1610-
if (project.compileOnSaveEnabled && project.languageServiceEnabled && !project.isOrphan() && !project.getCompilationSettings().noEmit) {
1611-
result = {
1612-
projectFileName: project.getProjectName(),
1613-
fileNames: project.getCompileOnSaveAffectedFileList(info),
1614-
projectUsesOutFile: !!project.getCompilationSettings().outFile || !!project.getCompilationSettings().out
1615-
};
1614+
if (!project.compileOnSaveEnabled || !project.languageServiceEnabled || project.isOrphan()) {
1615+
return undefined;
1616+
}
1617+
1618+
const compilationSettings = project.getCompilationSettings();
1619+
1620+
if (!!compilationSettings.noEmit || fileExtensionIs(info.fileName, Extension.Dts) && !dtsChangeCanAffectEmit(compilationSettings)) {
1621+
// avoid triggering emit when a change is made in a .d.ts when declaration emit and decorator metadata emit are disabled
1622+
return undefined;
16161623
}
1617-
return result;
1624+
1625+
return {
1626+
projectFileName: project.getProjectName(),
1627+
fileNames: project.getCompileOnSaveAffectedFileList(info),
1628+
projectUsesOutFile: !!compilationSettings.outFile || !!compilationSettings.out
1629+
};
16181630
}
16191631
);
16201632
}

src/testRunner/unittests/tsserver/compileOnSave.ts

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,112 @@ namespace ts.projectSystem {
503503
});
504504
});
505505

506+
describe("for changes in declaration files", () => {
507+
function testDTS(dtsFileContents: string, tsFileContents: string, opts: CompilerOptions, expectDTSEmit: boolean) {
508+
const dtsFile = {
509+
path: "/a/runtime/a.d.ts",
510+
content: dtsFileContents
511+
};
512+
const f2 = {
513+
path: "/a/b.ts",
514+
content: tsFileContents
515+
};
516+
const config = {
517+
path: "/a/tsconfig.json",
518+
content: JSON.stringify({
519+
compilerOptions: opts,
520+
compileOnSave: true
521+
})
522+
};
523+
const host = createServerHost([dtsFile, f2, config]);
524+
const session = projectSystem.createSession(host);
525+
session.executeCommand(<protocol.OpenRequest>{
526+
seq: 1,
527+
type: "request",
528+
command: "open",
529+
arguments: { file: dtsFile.path }
530+
});
531+
const projectService = session.getProjectService();
532+
checkNumberOfProjects(projectService, { configuredProjects: 1 });
533+
const project = projectService.configuredProjects.get(config.path)!;
534+
checkProjectRootFiles(project, [dtsFile.path, f2.path]);
535+
session.executeCommand(<protocol.OpenRequest>{
536+
seq: 2,
537+
type: "request",
538+
command: "open",
539+
arguments: { file: f2.path }
540+
});
541+
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 });
542+
const { response } = session.executeCommand(<protocol.CompileOnSaveAffectedFileListRequest>{
543+
seq: 3,
544+
type: "request",
545+
command: "compileOnSaveAffectedFileList",
546+
arguments: { file: dtsFile.path }
547+
});
548+
if (expectDTSEmit) {
549+
assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 1, "expected output from 1 project");
550+
assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[])[0].fileNames.length, 2, "expected to affect 2 files");
551+
}
552+
else {
553+
assert.equal((response as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 0, "expected no output");
554+
}
555+
556+
557+
const { response: response2 } = session.executeCommand(<protocol.CompileOnSaveAffectedFileListRequest>{
558+
seq: 4,
559+
type: "request",
560+
command: "compileOnSaveAffectedFileList",
561+
arguments: { file: f2.path }
562+
});
563+
assert.equal((response2 as protocol.CompileOnSaveAffectedFileListSingleProject[]).length, 1, "expected output from 1 project");
564+
}
565+
566+
it("should return empty array if change is made in a global declaration file", () => {
567+
testDTS(
568+
/*dtsFileContents*/ "declare const x: string;",
569+
/*tsFileContents*/ "var y = 1;",
570+
/*opts*/ {},
571+
/*expectDTSEmit*/ false
572+
);
573+
});
574+
575+
it("should return empty array if change is made in a module declaration file", () => {
576+
testDTS(
577+
/*dtsFileContents*/ "export const x: string;",
578+
/*tsFileContents*/ "import { x } from './runtime/a;",
579+
/*opts*/ {},
580+
/*expectDTSEmit*/ false
581+
);
582+
});
583+
584+
it("should return results if change is made in a global declaration file with declaration emit", () => {
585+
testDTS(
586+
/*dtsFileContents*/ "declare const x: string;",
587+
/*tsFileContents*/ "var y = 1;",
588+
/*opts*/ { declaration: true },
589+
/*expectDTSEmit*/ true
590+
);
591+
});
592+
593+
it("should return results if change is made in a global declaration file with composite enabled", () => {
594+
testDTS(
595+
/*dtsFileContents*/ "declare const x: string;",
596+
/*tsFileContents*/ "var y = 1;",
597+
/*opts*/ { composite: true },
598+
/*expectDTSEmit*/ true
599+
);
600+
});
601+
602+
it("should return results if change is made in a global declaration file with decorator emit enabled", () => {
603+
testDTS(
604+
/*dtsFileContents*/ "declare const x: string;",
605+
/*tsFileContents*/ "var y = 1;",
606+
/*opts*/ { experimentalDecorators: true, emitDecoratorMetadata: true },
607+
/*expectDTSEmit*/ true
608+
);
609+
});
610+
});
611+
506612
describe("tsserverProjectSystem emit with outFile or out setting", () => {
507613
function test(opts: CompilerOptions, expectedUsesOutFile: boolean) {
508614
const f1 = {

0 commit comments

Comments
 (0)