Skip to content

Commit 4aea496

Browse files
committed
Squash port of PR microsoft#19542
1 parent df57cdc commit 4aea496

File tree

6 files changed

+91
-19
lines changed

6 files changed

+91
-19
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

+36
Original file line numberDiff line numberDiff line change
@@ -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

+3-2
Original file line numberDiff line numberDiff line change
@@ -1057,11 +1057,12 @@ namespace ts.projectSystem {
10571057
const host = createServerHost([app, jquery, chroma]);
10581058
const logger = trackingLogger();
10591059
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(), [
1060+
const finish = logger.finish();
1061+
assert.deepEqual(finish, [
10611062
'Inferred typings from file names: ["jquery","chroma-js"]',
10621063
"Inferred typings from unresolved imports: []",
10631064
'Result: {"cachedTypingPaths":[],"newTypingNames":["jquery","chroma-js"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}',
1064-
]);
1065+
], finish.join("\r\n"));
10651066
assert.deepEqual(result.newTypingNames, ["jquery", "chroma-js"]);
10661067
});
10671068

src/server/editorServices.ts

+28-7
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ namespace ts.server {
110110

111111
export interface TypesMapFile {
112112
typesMap: SafeList;
113-
simpleMap: string[];
113+
simpleMap: { [libName: string]: string };
114114
}
115115

116116
/**
@@ -378,6 +378,7 @@ namespace ts.server {
378378

379379
private readonly hostConfiguration: HostConfiguration;
380380
private safelist: SafeList = defaultTypeSafeList;
381+
private legacySafelist: { [key: string]: string } = {};
381382

382383
private changedFiles: ScriptInfo[];
383384
private pendingProjectUpdates = createMap<Project>();
@@ -430,9 +431,12 @@ namespace ts.server {
430431
this.toCanonicalFileName = createGetCanonicalFileName(this.host.useCaseSensitiveFileNames);
431432
this.throttledOperations = new ThrottledOperations(this.host, this.logger);
432433

433-
if (opts.typesMapLocation) {
434+
if (this.typesMapLocation) {
434435
this.loadTypesMap();
435436
}
437+
else {
438+
this.logger.info("No types map provided; using the default");
439+
}
436440

437441
this.typingsInstaller.attach(this);
438442

@@ -522,10 +526,12 @@ namespace ts.server {
522526
}
523527
// raw is now fixed and ready
524528
this.safelist = raw.typesMap;
529+
this.legacySafelist = raw.simpleMap;
525530
}
526531
catch (e) {
527532
this.logger.info(`Error loading types map: ${e}`);
528533
this.safelist = defaultTypeSafeList;
534+
this.legacySafelist = {};
529535
}
530536
}
531537

@@ -1396,7 +1402,7 @@ namespace ts.server {
13961402
return false;
13971403
}
13981404

1399-
private createExternalProject(projectFileName: string, files: protocol.ExternalFile[], options: protocol.ExternalProjectCompilerOptions, typeAcquisition: TypeAcquisition) {
1405+
private createExternalProject(projectFileName: string, files: protocol.ExternalFile[], options: protocol.ExternalProjectCompilerOptions, typeAcquisition: TypeAcquisition, excludedFiles: NormalizedPath[]) {
14001406
const compilerOptions = convertCompilerOptions(options);
14011407
const project = new ExternalProject(
14021408
projectFileName,
@@ -1405,6 +1411,7 @@ namespace ts.server {
14051411
compilerOptions,
14061412
/*languageServiceEnabled*/ !this.exceededTotalSizeLimitForNonTsFiles(projectFileName, compilerOptions, files, externalFilePropertyReader),
14071413
options.compileOnSave === undefined ? true : options.compileOnSave);
1414+
project.excludedFiles = excludedFiles;
14081415

14091416
this.addFilesToNonInferredProjectAndUpdateGraph(project, files, externalFilePropertyReader, typeAcquisition);
14101417
this.externalProjects.push(project);
@@ -2170,7 +2177,7 @@ namespace ts.server {
21702177
const rule = this.safelist[name];
21712178
for (const root of normalizedNames) {
21722179
if (rule.match.test(root)) {
2173-
this.logger.info(`Excluding files based on rule ${name}`);
2180+
this.logger.info(`Excluding files based on rule ${name} matching file '${root}'`);
21742181

21752182
// If the file matches, collect its types packages and exclude rules
21762183
if (rule.types) {
@@ -2229,7 +2236,22 @@ namespace ts.server {
22292236
excludedFiles.push(normalizedNames[i]);
22302237
}
22312238
else {
2232-
filesToKeep.push(proj.rootFiles[i]);
2239+
let exclude = false;
2240+
if (typeAcquisition && (typeAcquisition.enable || typeAcquisition.enableAutoDiscovery)) {
2241+
const baseName = getBaseFileName(normalizedNames[i].toLowerCase());
2242+
if (fileExtensionIs(baseName, "js")) {
2243+
const inferredTypingName = removeFileExtension(baseName);
2244+
const cleanedTypingName = removeMinAndVersionNumbers(inferredTypingName);
2245+
if (this.legacySafelist[cleanedTypingName]) {
2246+
this.logger.info(`Excluded '${normalizedNames[i]}' because it matched ${cleanedTypingName} from the legacy safelist`);
2247+
excludedFiles.push(normalizedNames[i]);
2248+
exclude = true;
2249+
}
2250+
}
2251+
}
2252+
if (!exclude) {
2253+
filesToKeep.push(proj.rootFiles[i]);
2254+
}
22332255
}
22342256
}
22352257
proj.rootFiles = filesToKeep;
@@ -2337,8 +2359,7 @@ namespace ts.server {
23372359
else {
23382360
// no config files - remove the item from the collection
23392361
this.externalProjectToConfiguredProjectMap.delete(proj.projectFileName);
2340-
const newProj = this.createExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typeAcquisition);
2341-
newProj.excludedFiles = excludedFiles;
2362+
this.createExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typeAcquisition, excludedFiles);
23422363
}
23432364
if (!suppressRefreshOfInferredProjects) {
23442365
this.ensureProjectStructuresUptoDate(/*refreshInferredProjects*/ true);

src/services/jsTyping.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ namespace ts.JsTyping {
180180
if (!hasJavaScriptFileExtension(j)) return undefined;
181181

182182
const inferredTypingName = removeFileExtension(getBaseFileName(j.toLowerCase()));
183-
const cleanedTypingName = inferredTypingName.replace(/((?:\.|-)min(?=\.|$))|((?:-|\.)\d+)/g, "");
183+
const cleanedTypingName = removeMinAndVersionNumbers(inferredTypingName);
184184
return safeList.get(cleanedTypingName);
185185
});
186186
if (fromFileNames.length) {

tests/baselines/reference/api/tsserverlibrary.d.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -7424,7 +7424,9 @@ declare namespace ts.server {
74247424
}
74257425
interface TypesMapFile {
74267426
typesMap: SafeList;
7427-
simpleMap: string[];
7427+
simpleMap: {
7428+
[libName: string]: string;
7429+
};
74287430
}
74297431
function convertFormatOptions(protocolOptions: protocol.FormatCodeSettings): FormatCodeSettings;
74307432
function convertCompilerOptions(protocolOptions: protocol.ExternalProjectCompilerOptions): CompilerOptions & protocol.CompileOnSaveMixin;
@@ -7505,6 +7507,7 @@ declare namespace ts.server {
75057507
private readonly throttledOperations;
75067508
private readonly hostConfiguration;
75077509
private safelist;
7510+
private legacySafelist;
75087511
private changedFiles;
75097512
private pendingProjectUpdates;
75107513
private pendingInferredProjectUpdate;
@@ -7613,7 +7616,7 @@ declare namespace ts.server {
76137616
private findExternalProjectByProjectName(projectFileName);
76147617
private convertConfigFileContentToProjectOptions(configFilename, cachedDirectoryStructureHost);
76157618
private exceededTotalSizeLimitForNonTsFiles<T>(name, options, fileNames, propertyReader);
7616-
private createExternalProject(projectFileName, files, options, typeAcquisition);
7619+
private createExternalProject(projectFileName, files, options, typeAcquisition, excludedFiles);
76177620
private sendProjectTelemetry(projectKey, project, projectOptions?);
76187621
private addFilesToNonInferredProjectAndUpdateGraph<T>(project, files, propertyReader, typeAcquisition);
76197622
private createConfiguredProject(configFileName);

0 commit comments

Comments
 (0)