Skip to content

Commit c2a3837

Browse files
Merge pull request #20079 from RyanCavanaugh/port20048
Port #20048 to release-2.6
2 parents df57cdc + b9a548c commit c2a3837

File tree

9 files changed

+203
-85
lines changed

9 files changed

+203
-85
lines changed

src/compiler/core.ts

+18-7
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,13 @@ namespace ts {
7474
}
7575

7676
// The global Map object. This may not be available, so we must test for it.
77-
declare const Map: { new<T>(): Map<T> } | undefined;
77+
declare const Map: { new <T>(): Map<T> } | undefined;
7878
// Internet Explorer's Map doesn't support iteration, so don't use it.
7979
// tslint:disable-next-line:no-in-operator
8080
const MapCtr = typeof Map !== "undefined" && "entries" in Map.prototype ? Map : shimMap();
8181

8282
// Keep the class inside a function so it doesn't get compiled if it's not used.
83-
function shimMap(): { new<T>(): Map<T> } {
83+
function shimMap(): { new <T>(): Map<T> } {
8484

8585
class MapIterator<T, U extends (string | T | [string, T])> {
8686
private data: MapLike<T>;
@@ -103,7 +103,7 @@ namespace ts {
103103
}
104104
}
105105

106-
return class<T> implements Map<T> {
106+
return class <T> implements Map<T> {
107107
private data = createDictionaryObject<T>();
108108
public size = 0;
109109

@@ -166,8 +166,8 @@ namespace ts {
166166
}
167167

168168
export const enum Comparison {
169-
LessThan = -1,
170-
EqualTo = 0,
169+
LessThan = -1,
170+
EqualTo = 0,
171171
GreaterThan = 1
172172
}
173173

@@ -2413,6 +2413,17 @@ namespace ts {
24132413
return <T>(removeFileExtension(path) + newExtension);
24142414
}
24152415

2416+
/**
2417+
* Takes a string like "jquery-min.4.2.3" and returns "jquery"
2418+
*/
2419+
export function removeMinAndVersionNumbers(fileName: string) {
2420+
// Match a "." or "-" followed by a version number or 'min' at the end of the name
2421+
const trailingMinOrVersion = /[.-]((min)|(\d+(\.\d+)*))$/;
2422+
2423+
// The "min" or version may both be present, in either order, so try applying the above twice.
2424+
return fileName.replace(trailingMinOrVersion, "").replace(trailingMinOrVersion, "");
2425+
}
2426+
24162427
export interface ObjectAllocator {
24172428
getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node;
24182429
getTokenConstructor(): new <TKind extends SyntaxKind>(kind: TKind, pos?: number, end?: number) => Token<TKind>;
@@ -2615,7 +2626,7 @@ namespace ts {
26152626
return findBestPatternMatch(patterns, _ => _, candidate);
26162627
}
26172628

2618-
export function patternText({prefix, suffix}: Pattern): string {
2629+
export function patternText({ prefix, suffix }: Pattern): string {
26192630
return `${prefix}*${suffix}`;
26202631
}
26212632

@@ -2645,7 +2656,7 @@ namespace ts {
26452656
return matchedValue;
26462657
}
26472658

2648-
function isPatternMatch({prefix, suffix}: Pattern, candidate: string) {
2659+
function isPatternMatch({ prefix, suffix }: Pattern, candidate: string) {
26492660
return candidate.length >= prefix.length + suffix.length &&
26502661
startsWith(candidate, prefix) &&
26512662
endsWith(candidate, suffix);

src/harness/unittests/tsserverProjectSystem.ts

+38-2
Original file line numberDiff line numberDiff line change
@@ -1483,7 +1483,7 @@ namespace ts.projectSystem {
14831483

14841484
it("ignores files excluded by a custom safe type list", () => {
14851485
const file1 = {
1486-
path: "/a/b/f1.ts",
1486+
path: "/a/b/f1.js",
14871487
content: "export let x = 5"
14881488
};
14891489
const office = {
@@ -1504,7 +1504,7 @@ namespace ts.projectSystem {
15041504

15051505
it("ignores files excluded by the default type list", () => {
15061506
const file1 = {
1507-
path: "/a/b/f1.ts",
1507+
path: "/a/b/f1.js",
15081508
content: "export let x = 5"
15091509
};
15101510
const minFile = {
@@ -1540,6 +1540,42 @@ namespace ts.projectSystem {
15401540
}
15411541
});
15421542

1543+
it("removes version numbers correctly", () => {
1544+
const testData: [string, string][] = [
1545+
["jquery-max", "jquery-max"],
1546+
["jquery.min", "jquery"],
1547+
["jquery-min.4.2.3", "jquery"],
1548+
["jquery.min.4.2.1", "jquery"],
1549+
["minimum", "minimum"],
1550+
["min", "min"],
1551+
["min.3.2", "min"],
1552+
["jquery", "jquery"]
1553+
];
1554+
for (const t of testData) {
1555+
assert.equal(removeMinAndVersionNumbers(t[0]), t[1], t[0]);
1556+
}
1557+
});
1558+
1559+
it("ignores files excluded by a legacy safe type list", () => {
1560+
const file1 = {
1561+
path: "/a/b/bliss.js",
1562+
content: "let x = 5"
1563+
};
1564+
const file2 = {
1565+
path: "/a/b/foo.js",
1566+
content: ""
1567+
};
1568+
const host = createServerHost([file1, file2, customTypesMap]);
1569+
const projectService = createProjectService(host);
1570+
try {
1571+
projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, file2.path]), typeAcquisition: { enable: true } });
1572+
const proj = projectService.externalProjects[0];
1573+
assert.deepEqual(proj.getFileNames(), [file2.path]);
1574+
} finally {
1575+
projectService.resetSafeList();
1576+
}
1577+
});
1578+
15431579
it("open file become a part of configured project if it is referenced from root file", () => {
15441580
const file1 = {
15451581
path: "/a/b/f1.ts",

src/harness/unittests/typingsInstaller.ts

+78-32
Original file line numberDiff line numberDiff line change
@@ -304,35 +304,35 @@ namespace ts.projectSystem {
304304
// 1. react typings are installed for .jsx
305305
// 2. loose files names are matched against safe list for typings if
306306
// this is a JS project (only js, jsx, d.ts files are present)
307-
const file1 = {
307+
const lodashJs = {
308308
path: "/a/b/lodash.js",
309309
content: ""
310310
};
311-
const file2 = {
311+
const file2Jsx = {
312312
path: "/a/b/file2.jsx",
313313
content: ""
314314
};
315-
const file3 = {
315+
const file3dts = {
316316
path: "/a/b/file3.d.ts",
317317
content: ""
318318
};
319-
const react = {
319+
const reactDts = {
320320
path: "/a/data/node_modules/@types/react/index.d.ts",
321321
content: "declare const react: { x: number }"
322322
};
323-
const lodash = {
323+
const lodashDts = {
324324
path: "/a/data/node_modules/@types/lodash/index.d.ts",
325325
content: "declare const lodash: { x: number }"
326326
};
327327

328-
const host = createServerHost([file1, file2, file3, customTypesMap]);
328+
const host = createServerHost([lodashJs, file2Jsx, file3dts, customTypesMap]);
329329
const installer = new (class extends Installer {
330330
constructor() {
331331
super(host, { typesRegistry: createTypesRegistry("lodash", "react") });
332332
}
333333
installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction): void {
334334
const installedTypings = ["@types/lodash", "@types/react"];
335-
const typingFiles = [lodash, react];
335+
const typingFiles = [lodashDts, reactDts];
336336
executeCommand(this, host, installedTypings, typingFiles, cb);
337337
}
338338
})();
@@ -342,35 +342,74 @@ namespace ts.projectSystem {
342342
projectService.openExternalProject({
343343
projectFileName,
344344
options: { allowJS: true, moduleResolution: ModuleResolutionKind.NodeJs },
345-
rootFiles: [toExternalFile(file1.path), toExternalFile(file2.path), toExternalFile(file3.path)],
346-
typeAcquisition: {}
345+
rootFiles: [toExternalFile(lodashJs.path), toExternalFile(file2Jsx.path), toExternalFile(file3dts.path)],
346+
typeAcquisition: { }
347347
});
348348

349349
const p = projectService.externalProjects[0];
350350
projectService.checkNumberOfProjects({ externalProjects: 1 });
351-
checkProjectActualFiles(p, [file1.path, file2.path, file3.path]);
351+
checkProjectActualFiles(p, [file2Jsx.path, file3dts.path]);
352352

353353
installer.installAll(/*expectedCount*/ 1);
354354

355355
checkNumberOfProjects(projectService, { externalProjects: 1 });
356356
host.checkTimeoutQueueLengthAndRun(2);
357357
checkNumberOfProjects(projectService, { externalProjects: 1 });
358-
checkProjectActualFiles(p, [file1.path, file2.path, file3.path, lodash.path, react.path]);
358+
checkProjectActualFiles(p, [file2Jsx.path, file3dts.path, lodashDts.path, reactDts.path]);
359359
});
360360

361+
it("external project - type acquisition with enable: false", () => {
362+
// Tests:
363+
// Exclude
364+
const jqueryJs = {
365+
path: "/a/b/jquery.js",
366+
content: ""
367+
};
368+
369+
const host = createServerHost([jqueryJs]);
370+
const installer = new (class extends Installer {
371+
constructor() {
372+
super(host, { typesRegistry: createTypesRegistry("jquery") });
373+
}
374+
enqueueInstallTypingsRequest(project: server.Project, typeAcquisition: TypeAcquisition, unresolvedImports: server.SortedReadonlyArray<string>) {
375+
super.enqueueInstallTypingsRequest(project, typeAcquisition, unresolvedImports);
376+
}
377+
installWorker(_requestId: number, _args: string[], _cwd: string, cb: TI.RequestCompletedAction): void {
378+
const installedTypings: string[] = [];
379+
const typingFiles: FileOrFolder[] = [];
380+
executeCommand(this, host, installedTypings, typingFiles, cb);
381+
}
382+
})();
383+
384+
const projectFileName = "/a/app/test.csproj";
385+
const projectService = createProjectService(host, { typingsInstaller: installer });
386+
projectService.openExternalProject({
387+
projectFileName,
388+
options: { allowJS: true, moduleResolution: ModuleResolutionKind.NodeJs },
389+
rootFiles: [toExternalFile(jqueryJs.path)],
390+
typeAcquisition: { enable: false }
391+
});
392+
393+
const p = projectService.externalProjects[0];
394+
projectService.checkNumberOfProjects({ externalProjects: 1 });
395+
396+
checkProjectActualFiles(p, [jqueryJs.path]);
397+
398+
installer.checkPendingCommands(/*expectedCount*/ 0);
399+
});
361400
it("external project - no type acquisition, with js & ts files", () => {
362401
// Tests:
363402
// 1. No typings are included for JS projects when the project contains ts files
364-
const file1 = {
403+
const jqueryJs = {
365404
path: "/a/b/jquery.js",
366405
content: ""
367406
};
368-
const file2 = {
407+
const file2Ts = {
369408
path: "/a/b/file2.ts",
370409
content: ""
371410
};
372411

373-
const host = createServerHost([file1, file2]);
412+
const host = createServerHost([jqueryJs, file2Ts]);
374413
const installer = new (class extends Installer {
375414
constructor() {
376415
super(host, { typesRegistry: createTypesRegistry("jquery") });
@@ -390,34 +429,35 @@ namespace ts.projectSystem {
390429
projectService.openExternalProject({
391430
projectFileName,
392431
options: { allowJS: true, moduleResolution: ModuleResolutionKind.NodeJs },
393-
rootFiles: [toExternalFile(file1.path), toExternalFile(file2.path)],
432+
rootFiles: [toExternalFile(jqueryJs.path), toExternalFile(file2Ts.path)],
394433
typeAcquisition: {}
395434
});
396435

397436
const p = projectService.externalProjects[0];
398437
projectService.checkNumberOfProjects({ externalProjects: 1 });
399-
checkProjectActualFiles(p, [file2.path]);
438+
439+
checkProjectActualFiles(p, [jqueryJs.path, file2Ts.path]);
400440

401441
installer.checkPendingCommands(/*expectedCount*/ 0);
402442

403443
checkNumberOfProjects(projectService, { externalProjects: 1 });
404-
checkProjectActualFiles(p, [file2.path]);
444+
checkProjectActualFiles(p, [jqueryJs.path, file2Ts.path]);
405445
});
406446

407447
it("external project - with type acquisition, with only js, d.ts files", () => {
408448
// Tests:
409449
// 1. Safelist matching, type acquisition includes/excludes and package.json typings are all acquired
410450
// 2. Types for safelist matches are not included when they also appear in the type acquisition exclude list
411451
// 3. Multiple includes and excludes are respected in type acquisition
412-
const file1 = {
452+
const lodashJs = {
413453
path: "/a/b/lodash.js",
414454
content: ""
415455
};
416-
const file2 = {
456+
const commanderJs = {
417457
path: "/a/b/commander.js",
418458
content: ""
419459
};
420-
const file3 = {
460+
const file3dts = {
421461
path: "/a/b/file3.d.ts",
422462
content: ""
423463
};
@@ -448,7 +488,7 @@ namespace ts.projectSystem {
448488
content: "declare const moment: { x: number }"
449489
};
450490

451-
const host = createServerHost([file1, file2, file3, packageJson, customTypesMap]);
491+
const host = createServerHost([lodashJs, commanderJs, file3dts, packageJson, customTypesMap]);
452492
const installer = new (class extends Installer {
453493
constructor() {
454494
super(host, { typesRegistry: createTypesRegistry("jquery", "commander", "moment", "express") });
@@ -465,20 +505,25 @@ namespace ts.projectSystem {
465505
projectService.openExternalProject({
466506
projectFileName,
467507
options: { allowJS: true, moduleResolution: ModuleResolutionKind.NodeJs },
468-
rootFiles: [toExternalFile(file1.path), toExternalFile(file2.path), toExternalFile(file3.path)],
469-
typeAcquisition: { include: ["jquery", "moment"], exclude: ["lodash"] }
508+
rootFiles: [toExternalFile(lodashJs.path), toExternalFile(commanderJs.path), toExternalFile(file3dts.path)],
509+
typeAcquisition: { enable: true, include: ["jquery", "moment"], exclude: ["lodash"] }
470510
});
471511

472512
const p = projectService.externalProjects[0];
473513
projectService.checkNumberOfProjects({ externalProjects: 1 });
474-
checkProjectActualFiles(p, [file1.path, file2.path, file3.path]);
514+
checkProjectActualFiles(p, [file3dts.path]);
475515

476516
installer.installAll(/*expectedCount*/ 1);
477517

478518
checkNumberOfProjects(projectService, { externalProjects: 1 });
479519
host.checkTimeoutQueueLengthAndRun(2);
480520
checkNumberOfProjects(projectService, { externalProjects: 1 });
481-
checkProjectActualFiles(p, [file1.path, file2.path, file3.path, commander.path, express.path, jquery.path, moment.path]);
521+
// Commander: Existed as a JS file
522+
// JQuery: Specified in 'include'
523+
// Moment: Specified in 'include'
524+
// Express: Specified in package.json
525+
// lodash: Excluded (not present)
526+
checkProjectActualFiles(p, [file3dts.path, commander.path, express.path, jquery.path, moment.path]);
482527
});
483528

484529
it("Throttle - delayed typings to install", () => {
@@ -548,7 +593,7 @@ namespace ts.projectSystem {
548593

549594
const p = projectService.externalProjects[0];
550595
projectService.checkNumberOfProjects({ externalProjects: 1 });
551-
checkProjectActualFiles(p, [lodashJs.path, commanderJs.path, file3.path]);
596+
checkProjectActualFiles(p, [file3.path]);
552597
installer.checkPendingCommands(/*expectedCount*/ 1);
553598
installer.executePendingCommands();
554599
// expected all typings file to exist
@@ -557,7 +602,7 @@ namespace ts.projectSystem {
557602
}
558603
host.checkTimeoutQueueLengthAndRun(2);
559604
checkNumberOfProjects(projectService, { externalProjects: 1 });
560-
checkProjectActualFiles(p, [lodashJs.path, commanderJs.path, file3.path, commander.path, express.path, jquery.path, moment.path, lodash.path]);
605+
checkProjectActualFiles(p, [file3.path, commander.path, express.path, jquery.path, moment.path, lodash.path]);
561606
});
562607

563608
it("Throttle - delayed run install requests", () => {
@@ -648,7 +693,7 @@ namespace ts.projectSystem {
648693
const p1 = projectService.externalProjects[0];
649694
const p2 = projectService.externalProjects[1];
650695
projectService.checkNumberOfProjects({ externalProjects: 2 });
651-
checkProjectActualFiles(p1, [lodashJs.path, commanderJs.path, file3.path]);
696+
checkProjectActualFiles(p1, [file3.path]);
652697
checkProjectActualFiles(p2, [file3.path]);
653698

654699
installer.executePendingCommands();
@@ -659,7 +704,7 @@ namespace ts.projectSystem {
659704

660705
installer.executePendingCommands();
661706
host.checkTimeoutQueueLengthAndRun(3); // for 2 projects and 1 refreshing inferred project
662-
checkProjectActualFiles(p1, [lodashJs.path, commanderJs.path, file3.path, commander.path, jquery.path, lodash.path, cordova.path]);
707+
checkProjectActualFiles(p1, [file3.path, commander.path, jquery.path, lodash.path, cordova.path]);
663708
checkProjectActualFiles(p2, [file3.path, grunt.path, gulp.path]);
664709
});
665710

@@ -973,7 +1018,7 @@ namespace ts.projectSystem {
9731018
}
9741019
};
9751020
session.executeCommand(changeRequest);
976-
host.checkTimeoutQueueLengthAndRun(2); // This enqueues the updategraph and refresh inferred projects
1021+
host.checkTimeoutQueueLengthAndRun(0); // This enqueues the updategraph and refresh inferred projects
9771022
const version2 = proj.getCachedUnresolvedImportsPerFile_TestOnly().getVersion();
9781023
assert.equal(version1, version2, "set of unresolved imports should not change");
9791024
});
@@ -1057,11 +1102,12 @@ namespace ts.projectSystem {
10571102
const host = createServerHost([app, jquery, chroma]);
10581103
const logger = trackingLogger();
10591104
const result = JsTyping.discoverTypings(host, logger.log, [app.path, jquery.path, chroma.path], getDirectoryPath(<Path>app.path), safeList, emptyMap, { enable: true }, emptyArray);
1060-
assert.deepEqual(logger.finish(), [
1105+
const finish = logger.finish();
1106+
assert.deepEqual(finish, [
10611107
'Inferred typings from file names: ["jquery","chroma-js"]',
10621108
"Inferred typings from unresolved imports: []",
10631109
'Result: {"cachedTypingPaths":[],"newTypingNames":["jquery","chroma-js"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}',
1064-
]);
1110+
], finish.join("\r\n"));
10651111
assert.deepEqual(result.newTypingNames, ["jquery", "chroma-js"]);
10661112
});
10671113

0 commit comments

Comments
 (0)