Skip to content

Commit 460de66

Browse files
authored
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 2671668 commit 460de66

File tree

5 files changed

+151
-23
lines changed

5 files changed

+151
-23
lines changed

src/compiler/commandLineParser.ts

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

977977
const options: CompilerOptions = getBaseFileName(configFileName) === "jsconfig.json"
978-
? { allowJs: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true }
978+
? { allowJs: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true, skipLibCheck: true }
979979
: {};
980980
convertOptionsFromJson(optionDeclarations, jsonOptions, basePath, options, Diagnostics.Unknown_compiler_option_0, errors);
981981
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: 86 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

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

79
const safeList = {
810
path: <Path>"/safeList.json",
@@ -128,7 +130,7 @@ namespace ts.projectSystem {
128130
return combinePaths(getDirectoryPath(libFile.path), "tsc.js");
129131
}
130132

131-
export function toExternalFile(fileName: string): server.protocol.ExternalFile {
133+
export function toExternalFile(fileName: string): protocol.ExternalFile {
132134
return { fileName };
133135
}
134136

@@ -527,7 +529,7 @@ namespace ts.projectSystem {
527529
}
528530

529531
export function makeSessionRequest<T>(command: string, args: T) {
530-
const newRequest: server.protocol.Request = {
532+
const newRequest: protocol.Request = {
531533
seq: 0,
532534
type: "request",
533535
command,
@@ -538,7 +540,7 @@ namespace ts.projectSystem {
538540

539541
export function openFilesForSession(files: FileOrFolder[], session: server.Session) {
540542
for (const file of files) {
541-
const request = makeSessionRequest<server.protocol.OpenRequestArgs>(server.CommandNames.Open, { file: file.path });
543+
const request = makeSessionRequest<protocol.OpenRequestArgs>(CommandNames.Open, { file: file.path });
542544
session.executeCommand(request);
543545
}
544546
}
@@ -1751,7 +1753,7 @@ namespace ts.projectSystem {
17511753
});
17521754

17531755
describe("navigate-to for javascript project", () => {
1754-
function containsNavToItem(items: server.protocol.NavtoItem[], itemName: string, itemKind: string) {
1756+
function containsNavToItem(items: protocol.NavtoItem[], itemName: string, itemKind: string) {
17551757
return find(items, item => item.name === itemName && item.kind === itemKind) !== undefined;
17561758
}
17571759

@@ -1769,12 +1771,12 @@ namespace ts.projectSystem {
17691771
openFilesForSession([file1], session);
17701772

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

1776-
const localFunctionNavToRequst = makeSessionRequest<server.protocol.NavtoRequestArgs>(server.CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path });
1777-
const items2: server.protocol.NavtoItem[] = session.executeCommand(localFunctionNavToRequst).response;
1778+
const localFunctionNavToRequst = makeSessionRequest<protocol.NavtoRequestArgs>(CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path });
1779+
const items2: protocol.NavtoItem[] = session.executeCommand(localFunctionNavToRequst).response;
17781780
assert.isTrue(containsNavToItem(items2, "foo", "function"), `Cannot find function symbol "foo".`);
17791781
});
17801782
});
@@ -2309,4 +2311,80 @@ namespace ts.projectSystem {
23092311
serverEventManager.checkEventCountOfType("configFileDiag", 1);
23102312
});
23112313
});
2314+
2315+
describe("skipLibCheck", () => {
2316+
it("should be turned on for js-only inferred projects", () => {
2317+
const file1 = {
2318+
path: "/a/b/file1.js",
2319+
content: `
2320+
/// <reference path="file2.d.ts" />
2321+
var x = 1;`
2322+
};
2323+
const file2 = {
2324+
path: "/a/b/file2.d.ts",
2325+
content: `
2326+
interface T {
2327+
name: string;
2328+
};
2329+
interface T {
2330+
name: number;
2331+
};`
2332+
};
2333+
const host = createServerHost([file1, file2]);
2334+
const session = createSession(host);
2335+
openFilesForSession([file1, file2], session);
2336+
2337+
const file2GetErrRequest = makeSessionRequest<protocol.SemanticDiagnosticsSyncRequestArgs>(
2338+
CommandNames.SemanticDiagnosticsSync,
2339+
{ file: file2.path }
2340+
);
2341+
let errorResult = <protocol.Diagnostic[]>session.executeCommand(file2GetErrRequest).response;
2342+
assert.isTrue(errorResult.length === 0);
2343+
2344+
const closeFileRequest = makeSessionRequest<protocol.FileRequestArgs>(CommandNames.Close, { file: file1.path });
2345+
session.executeCommand(closeFileRequest);
2346+
errorResult = <protocol.Diagnostic[]>session.executeCommand(file2GetErrRequest).response;
2347+
assert.isTrue(errorResult.length !== 0);
2348+
2349+
openFilesForSession([file1], session);
2350+
errorResult = <protocol.Diagnostic[]>session.executeCommand(file2GetErrRequest).response;
2351+
assert.isTrue(errorResult.length === 0);
2352+
});
2353+
2354+
it("should be turned on for js-only external projects", () => {
2355+
const jsFile = {
2356+
path: "/a/b/file1.js",
2357+
content: "let x =1;"
2358+
};
2359+
const dTsFile = {
2360+
path: "/a/b/file2.d.ts",
2361+
content: `
2362+
interface T {
2363+
name: string;
2364+
};
2365+
interface T {
2366+
name: number;
2367+
};`
2368+
};
2369+
const host = createServerHost([jsFile, dTsFile]);
2370+
const session = createSession(host);
2371+
2372+
const openExternalProjectRequest = makeSessionRequest<protocol.OpenExternalProjectArgs>(
2373+
CommandNames.OpenExternalProject,
2374+
{
2375+
projectFileName: "project1",
2376+
rootFiles: toExternalFiles([jsFile.path, dTsFile.path]),
2377+
options: {}
2378+
}
2379+
);
2380+
session.executeCommand(openExternalProjectRequest);
2381+
2382+
const dTsFileGetErrRequest = makeSessionRequest<protocol.SemanticDiagnosticsSyncRequestArgs>(
2383+
CommandNames.SemanticDiagnosticsSync,
2384+
{ file: dTsFile.path }
2385+
);
2386+
const errorResult = <protocol.Diagnostic[]>session.executeCommand(dTsFileGetErrRequest).response;
2387+
assert.isTrue(errorResult.length === 0);
2388+
});
2389+
});
23122390
}

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
@@ -1133,7 +1148,7 @@ namespace ts.server {
11331148
return combineProjectOutput(
11341149
projects,
11351150
project => {
1136-
const navItems = project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isJsOnlyProject());
1151+
const navItems = project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isNonTsProject());
11371152
if (!navItems) {
11381153
return [];
11391154
}
@@ -1171,7 +1186,7 @@ namespace ts.server {
11711186
else {
11721187
return combineProjectOutput(
11731188
projects,
1174-
project => project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isJsOnlyProject()),
1189+
project => project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isNonTsProject()),
11751190
/*comparer*/ undefined,
11761191
navigateToItemIsEqualTo);
11771192
}

0 commit comments

Comments
 (0)