Skip to content

Commit b5441de

Browse files
committed
Turn on skipLibCheck for js-only inferred project and external project (#11399)
* Turn on skipLibCheck for js-only inferred project and external project * avoid changing compiler options * Update tests
1 parent cca3c1f commit b5441de

File tree

5 files changed

+149
-23
lines changed

5 files changed

+149
-23
lines changed

src/compiler/commandLineParser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ namespace ts {
902902
basePath: string, errors: Diagnostic[], configFileName?: string): CompilerOptions {
903903

904904
const options: CompilerOptions = getBaseFileName(configFileName) === "jsconfig.json"
905-
? { allowJs: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true }
905+
? { allowJs: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true, skipLibCheck: true }
906906
: {};
907907
convertOptionsFromJson(optionDeclarations, jsonOptions, basePath, options, Diagnostics.Unknown_compiler_option_0, errors);
908908
return options;

src/harness/unittests/convertCompilerOptionsFromJson.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ namespace ts {
405405
allowJs: true,
406406
maxNodeModuleJsDepth: 2,
407407
allowSyntheticDefaultImports: true,
408+
skipLibCheck: true,
408409
module: ModuleKind.CommonJS,
409410
target: ScriptTarget.ES5,
410411
noImplicitAny: false,
@@ -433,6 +434,7 @@ namespace ts {
433434
allowJs: false,
434435
maxNodeModuleJsDepth: 2,
435436
allowSyntheticDefaultImports: true,
437+
skipLibCheck: true,
436438
module: ModuleKind.CommonJS,
437439
target: ScriptTarget.ES5,
438440
noImplicitAny: false,
@@ -456,7 +458,8 @@ namespace ts {
456458
{
457459
allowJs: true,
458460
maxNodeModuleJsDepth: 2,
459-
allowSyntheticDefaultImports: true
461+
allowSyntheticDefaultImports: true,
462+
skipLibCheck: true
460463
},
461464
errors: [{
462465
file: undefined,
@@ -477,7 +480,8 @@ namespace ts {
477480
{
478481
allowJs: true,
479482
maxNodeModuleJsDepth: 2,
480-
allowSyntheticDefaultImports: true
483+
allowSyntheticDefaultImports: true,
484+
skipLibCheck: true
481485
},
482486
errors: <Diagnostic[]>[]
483487
}

src/harness/unittests/tsserverProjectSystem.ts

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace ts.projectSystem {
55
import TI = server.typingsInstaller;
6+
import protocol = server.protocol;
67
import CommandNames = server.CommandNames;
78

89
const safeList = {
@@ -125,7 +126,7 @@ namespace ts.projectSystem {
125126
return combinePaths(getDirectoryPath(libFile.path), "tsc.js");
126127
}
127128

128-
export function toExternalFile(fileName: string): server.protocol.ExternalFile {
129+
export function toExternalFile(fileName: string): protocol.ExternalFile {
129130
return { fileName };
130131
}
131132

@@ -551,7 +552,7 @@ namespace ts.projectSystem {
551552
}
552553

553554
export function makeSessionRequest<T>(command: string, args: T) {
554-
const newRequest: server.protocol.Request = {
555+
const newRequest: protocol.Request = {
555556
seq: 0,
556557
type: "request",
557558
command,
@@ -562,7 +563,7 @@ namespace ts.projectSystem {
562563

563564
export function openFilesForSession(files: FileOrFolder[], session: server.Session) {
564565
for (const file of files) {
565-
const request = makeSessionRequest<server.protocol.OpenRequestArgs>(CommandNames.Open, { file: file.path });
566+
const request = makeSessionRequest<protocol.OpenRequestArgs>(CommandNames.Open, { file: file.path });
566567
session.executeCommand(request);
567568
}
568569
}
@@ -1775,7 +1776,7 @@ namespace ts.projectSystem {
17751776
});
17761777

17771778
describe("navigate-to for javascript project", () => {
1778-
function containsNavToItem(items: server.protocol.NavtoItem[], itemName: string, itemKind: string) {
1779+
function containsNavToItem(items: protocol.NavtoItem[], itemName: string, itemKind: string) {
17791780
return find(items, item => item.name === itemName && item.kind === itemKind) !== undefined;
17801781
}
17811782

@@ -1793,12 +1794,12 @@ namespace ts.projectSystem {
17931794
openFilesForSession([file1], session);
17941795

17951796
// Try to find some interface type defined in lib.d.ts
1796-
const libTypeNavToRequest = makeSessionRequest<server.protocol.NavtoRequestArgs>(CommandNames.Navto, { searchValue: "Document", file: file1.path, projectFileName: configFile.path });
1797-
const items: server.protocol.NavtoItem[] = session.executeCommand(libTypeNavToRequest).response;
1797+
const libTypeNavToRequest = makeSessionRequest<protocol.NavtoRequestArgs>(CommandNames.Navto, { searchValue: "Document", file: file1.path, projectFileName: configFile.path });
1798+
const items: protocol.NavtoItem[] = session.executeCommand(libTypeNavToRequest).response;
17981799
assert.isFalse(containsNavToItem(items, "Document", "interface"), `Found lib.d.ts symbol in JavaScript project nav to request result.`);
17991800

1800-
const localFunctionNavToRequst = makeSessionRequest<server.protocol.NavtoRequestArgs>(CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path });
1801-
const items2: server.protocol.NavtoItem[] = session.executeCommand(localFunctionNavToRequst).response;
1801+
const localFunctionNavToRequst = makeSessionRequest<protocol.NavtoRequestArgs>(CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path });
1802+
const items2: protocol.NavtoItem[] = session.executeCommand(localFunctionNavToRequst).response;
18021803
assert.isTrue(containsNavToItem(items2, "foo", "function"), `Cannot find function symbol "foo".`);
18031804
});
18041805
});
@@ -2245,7 +2246,82 @@ namespace ts.projectSystem {
22452246
// verify content
22462247
const snap2 = projectServiice.getScriptInfo(f1.path).snap();
22472248
assert.equal(snap2.getText(0, snap2.getLength()), f1.content, "content should be equal to the content of original file");
2249+
});
2250+
});
2251+
2252+
describe("skipLibCheck", () => {
2253+
it("should be turned on for js-only inferred projects", () => {
2254+
const file1 = {
2255+
path: "/a/b/file1.js",
2256+
content: `
2257+
/// <reference path="file2.d.ts" />
2258+
var x = 1;`
2259+
};
2260+
const file2 = {
2261+
path: "/a/b/file2.d.ts",
2262+
content: `
2263+
interface T {
2264+
name: string;
2265+
};
2266+
interface T {
2267+
name: number;
2268+
};`
2269+
};
2270+
const host = createServerHost([file1, file2]);
2271+
const session = createSession(host);
2272+
openFilesForSession([file1, file2], session);
2273+
2274+
const file2GetErrRequest = makeSessionRequest<protocol.SemanticDiagnosticsSyncRequestArgs>(
2275+
CommandNames.SemanticDiagnosticsSync,
2276+
{ file: file2.path }
2277+
);
2278+
let errorResult = <protocol.Diagnostic[]>session.executeCommand(file2GetErrRequest).response;
2279+
assert.isTrue(errorResult.length === 0);
22482280

2281+
const closeFileRequest = makeSessionRequest<protocol.FileRequestArgs>(CommandNames.Close, { file: file1.path });
2282+
session.executeCommand(closeFileRequest);
2283+
errorResult = <protocol.Diagnostic[]>session.executeCommand(file2GetErrRequest).response;
2284+
assert.isTrue(errorResult.length !== 0);
2285+
2286+
openFilesForSession([file1], session);
2287+
errorResult = <protocol.Diagnostic[]>session.executeCommand(file2GetErrRequest).response;
2288+
assert.isTrue(errorResult.length === 0);
2289+
});
2290+
2291+
it("should be turned on for js-only external projects", () => {
2292+
const jsFile = {
2293+
path: "/a/b/file1.js",
2294+
content: "let x =1;"
2295+
};
2296+
const dTsFile = {
2297+
path: "/a/b/file2.d.ts",
2298+
content: `
2299+
interface T {
2300+
name: string;
2301+
};
2302+
interface T {
2303+
name: number;
2304+
};`
2305+
};
2306+
const host = createServerHost([jsFile, dTsFile]);
2307+
const session = createSession(host);
2308+
2309+
const openExternalProjectRequest = makeSessionRequest<protocol.OpenExternalProjectArgs>(
2310+
CommandNames.OpenExternalProject,
2311+
{
2312+
projectFileName: "project1",
2313+
rootFiles: toExternalFiles([jsFile.path, dTsFile.path]),
2314+
options: {}
2315+
}
2316+
);
2317+
session.executeCommand(openExternalProjectRequest);
2318+
2319+
const dTsFileGetErrRequest = makeSessionRequest<protocol.SemanticDiagnosticsSyncRequestArgs>(
2320+
CommandNames.SemanticDiagnosticsSync,
2321+
{ file: dTsFile.path }
2322+
);
2323+
const errorResult = <protocol.Diagnostic[]>session.executeCommand(dTsFileGetErrRequest).response;
2324+
assert.isTrue(errorResult.length === 0);
22492325
});
22502326
});
22512327
}

src/server/project.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,42 @@ namespace ts.server {
2020
}
2121
}
2222

23-
function isJsOrDtsFile(info: ScriptInfo) {
24-
return info.scriptKind === ScriptKind.JS || info.scriptKind == ScriptKind.JSX || fileExtensionIs(info.fileName, ".d.ts");
23+
function countEachFileTypes(infos: ScriptInfo[]): { js: number, jsx: number, ts: number, tsx: number, dts: number } {
24+
const result = { js: 0, jsx: 0, ts: 0, tsx: 0, dts: 0 };
25+
for (const info of infos) {
26+
switch (info.scriptKind) {
27+
case ScriptKind.JS:
28+
result.js += 1;
29+
break;
30+
case ScriptKind.JSX:
31+
result.jsx += 1;
32+
break;
33+
case ScriptKind.TS:
34+
fileExtensionIs(info.fileName, ".d.ts")
35+
? result.dts += 1
36+
: result.ts += 1;
37+
break;
38+
case ScriptKind.TSX:
39+
result.tsx += 1;
40+
break;
41+
}
42+
}
43+
return result;
44+
}
45+
46+
function hasOneOrMoreJsAndNoTsFiles(project: Project) {
47+
const counts = countEachFileTypes(project.getScriptInfos());
48+
return counts.js > 0 && counts.ts === 0 && counts.tsx === 0;
2549
}
2650

2751
export function allRootFilesAreJsOrDts(project: Project): boolean {
28-
return project.getRootScriptInfos().every(isJsOrDtsFile);
52+
const counts = countEachFileTypes(project.getRootScriptInfos());
53+
return counts.ts === 0 && counts.tsx === 0;
2954
}
3055

3156
export function allFilesAreJsOrDts(project: Project): boolean {
32-
return project.getScriptInfos().every(isJsOrDtsFile);
57+
const counts = countEachFileTypes(project.getScriptInfos());
58+
return counts.ts === 0 && counts.tsx === 0;
3359
}
3460

3561
export interface ProjectFilesWithTSDiagnostics extends protocol.ProjectFiles {
@@ -71,11 +97,16 @@ namespace ts.server {
7197

7298
public typesVersion = 0;
7399

74-
public isJsOnlyProject() {
100+
public isNonTsProject() {
75101
this.updateGraph();
76102
return allFilesAreJsOrDts(this);
77103
}
78104

105+
public isJsOnlyProject() {
106+
this.updateGraph();
107+
return hasOneOrMoreJsAndNoTsFiles(this);
108+
}
109+
79110
constructor(
80111
readonly projectKind: ProjectKind,
81112
readonly projectService: ProjectService,

src/server/session.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@ namespace ts.server {
1414
return ((1e9 * seconds) + nanoseconds) / 1000000.0;
1515
}
1616

17+
function shouldSkipSematicCheck(project: Project) {
18+
if (project.getCompilerOptions().skipLibCheck !== undefined) {
19+
return false;
20+
}
21+
22+
if ((project.projectKind === ProjectKind.Inferred || project.projectKind === ProjectKind.External) && project.isJsOnlyProject()) {
23+
return true;
24+
}
25+
return false;
26+
}
27+
1728
interface FileStart {
1829
file: string;
1930
start: ILineInfo;
@@ -255,12 +266,13 @@ namespace ts.server {
255266

256267
private semanticCheck(file: NormalizedPath, project: Project) {
257268
try {
258-
const diags = project.getLanguageService().getSemanticDiagnostics(file);
259-
260-
if (diags) {
261-
const bakedDiags = diags.map((diag) => formatDiag(file, project, diag));
262-
this.event({ file: file, diagnostics: bakedDiags }, "semanticDiag");
269+
let diags: Diagnostic[] = [];
270+
if (!shouldSkipSematicCheck(project)) {
271+
diags = project.getLanguageService().getSemanticDiagnostics(file);
263272
}
273+
274+
const bakedDiags = diags.map((diag) => formatDiag(file, project, diag));
275+
this.event({ file: file, diagnostics: bakedDiags }, "semanticDiag");
264276
}
265277
catch (err) {
266278
this.logError(err, "semantic check");
@@ -373,6 +385,9 @@ namespace ts.server {
373385

374386
private getDiagnosticsWorker(args: protocol.FileRequestArgs, selector: (project: Project, file: string) => Diagnostic[], includeLinePosition: boolean) {
375387
const { project, file } = this.getFileAndProject(args);
388+
if (shouldSkipSematicCheck(project)) {
389+
return [];
390+
}
376391
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
377392
const diagnostics = selector(project, file);
378393
return includeLinePosition
@@ -1122,7 +1137,7 @@ namespace ts.server {
11221137
return combineProjectOutput(
11231138
projects,
11241139
project => {
1125-
const navItems = project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, /*excludeDts*/ project.isJsOnlyProject());
1140+
const navItems = project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, /*excludeDts*/ project.isNonTsProject());
11261141
if (!navItems) {
11271142
return [];
11281143
}
@@ -1160,7 +1175,7 @@ namespace ts.server {
11601175
else {
11611176
return combineProjectOutput(
11621177
projects,
1163-
project => project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, /*excludeDts*/ project.isJsOnlyProject()),
1178+
project => project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, /*excludeDts*/ project.isNonTsProject()),
11641179
/*comparer*/ undefined,
11651180
navigateToItemIsEqualTo);
11661181
}

0 commit comments

Comments
 (0)