diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts
index 1a0aabd97fd..49434e80aba 100644
--- a/src/compiler/binder.ts
+++ b/src/compiler/binder.ts
@@ -1,5 +1,4 @@
///
-///
///
/* @internal */
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 72d2ca92af0..d0781097f39 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -1,3 +1,4 @@
+///
///
/* @internal */
diff --git a/src/compiler/core.ts b/src/compiler/core.ts
index 3967a867014..9de92cce3a5 100644
--- a/src/compiler/core.ts
+++ b/src/compiler/core.ts
@@ -1889,6 +1889,78 @@ namespace ts {
: ((fileName) => fileName.toLowerCase());
}
+ /**
+ * patternStrings contains both pattern strings (containing "*") and regular strings.
+ * Return an exact match if possible, or a pattern match, or undefined.
+ * (These are verified by verifyCompilerOptions to have 0 or 1 "*" characters.)
+ */
+ /* @internal */
+ export function matchPatternOrExact(patternStrings: string[], candidate: string): string | Pattern | undefined {
+ const patterns: Pattern[] = [];
+ for (const patternString of patternStrings) {
+ const pattern = tryParsePattern(patternString);
+ if (pattern) {
+ patterns.push(pattern);
+ }
+ else if (patternString === candidate) {
+ // pattern was matched as is - no need to search further
+ return patternString;
+ }
+ }
+
+ return findBestPatternMatch(patterns, _ => _, candidate);
+ }
+
+ /* @internal */
+ export function patternText({prefix, suffix}: Pattern): string {
+ return `${prefix}*${suffix}`;
+ }
+
+ /**
+ * Given that candidate matches pattern, returns the text matching the '*'.
+ * E.g.: matchedText(tryParsePattern("foo*baz"), "foobarbaz") === "bar"
+ */
+ /* @internal */
+ export function matchedText(pattern: Pattern, candidate: string): string {
+ Debug.assert(isPatternMatch(pattern, candidate));
+ return candidate.substr(pattern.prefix.length, candidate.length - pattern.suffix.length);
+ }
+
+ /** Return the object corresponding to the best pattern to match `candidate`. */
+ /* @internal */
+ export function findBestPatternMatch(values: T[], getPattern: (value: T) => Pattern, candidate: string): T | undefined {
+ let matchedValue: T | undefined = undefined;
+ // use length of prefix as betterness criteria
+ let longestMatchPrefixLength = -1;
+
+ for (const v of values) {
+ const pattern = getPattern(v);
+ if (isPatternMatch(pattern, candidate) && pattern.prefix.length > longestMatchPrefixLength) {
+ longestMatchPrefixLength = pattern.prefix.length;
+ matchedValue = v;
+ }
+ }
+
+ return matchedValue;
+ }
+
+ function isPatternMatch({prefix, suffix}: Pattern, candidate: string) {
+ return candidate.length >= prefix.length + suffix.length &&
+ startsWith(candidate, prefix) &&
+ endsWith(candidate, suffix);
+ }
+
+ /* @internal */
+ export function tryParsePattern(pattern: string): Pattern | undefined {
+ // This should be verified outside of here and a proper error thrown.
+ Debug.assert(hasZeroOrOneAsteriskCharacter(pattern));
+ const indexOfStar = pattern.indexOf("*");
+ return indexOfStar === -1 ? undefined : {
+ prefix: pattern.substr(0, indexOfStar),
+ suffix: pattern.substr(indexOfStar + 1)
+ };
+ }
+
export function positionIsSynthesized(pos: number): boolean {
// This is a fast way of testing the following conditions:
// pos === undefined || pos === null || isNaN(pos) || pos < 0;
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index 03de307f2f3..90742f30c16 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -13,6 +13,9 @@ namespace ts {
_i = 0x10000000, // Use/preference flag for '_i'
}
+ const id = (s: SourceFile) => s;
+ const nullTransformers: Transformer[] = [ctx => id];
+
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile, emitOnlyDtsFiles?: boolean): EmitResult {
const delimiters = createDelimiterMap();
@@ -192,7 +195,7 @@ const _super = (function (geti, seti) {
const emittedFilesList: string[] = compilerOptions.listEmittedFiles ? [] : undefined;
const emitterDiagnostics = createDiagnosticCollection();
const newLine = host.getNewLine();
- const transformers = getTransformers(compilerOptions);
+ const transformers: Transformer[] = emitOnlyDtsFiles ? nullTransformers : getTransformers(compilerOptions);
const writer = createTextWriter(newLine);
const {
write,
@@ -271,7 +274,9 @@ const _super = (function (geti, seti) {
function emitFile(jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
// Make sure not to write js file and source map file if any of them cannot be written
if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) {
- printFile(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
+ if (!emitOnlyDtsFiles) {
+ printFile(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
+ }
}
else {
emitSkipped = true;
@@ -282,7 +287,9 @@ const _super = (function (geti, seti) {
}
if (!emitSkipped && emittedFilesList) {
- emittedFilesList.push(jsFilePath);
+ if (!emitOnlyDtsFiles) {
+ emittedFilesList.push(jsFilePath);
+ }
if (sourceMapFilePath) {
emittedFilesList.push(sourceMapFilePath);
}
diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts
index 6068cf55a7a..ca702173e79 100644
--- a/src/compiler/moduleNameResolver.ts
+++ b/src/compiler/moduleNameResolver.ts
@@ -512,75 +512,6 @@ namespace ts {
}
}
- /**
- * patternStrings contains both pattern strings (containing "*") and regular strings.
- * Return an exact match if possible, or a pattern match, or undefined.
- * (These are verified by verifyCompilerOptions to have 0 or 1 "*" characters.)
- */
- function matchPatternOrExact(patternStrings: string[], candidate: string): string | Pattern | undefined {
- const patterns: Pattern[] = [];
- for (const patternString of patternStrings) {
- const pattern = tryParsePattern(patternString);
- if (pattern) {
- patterns.push(pattern);
- }
- else if (patternString === candidate) {
- // pattern was matched as is - no need to search further
- return patternString;
- }
- }
-
- return findBestPatternMatch(patterns, _ => _, candidate);
- }
-
- function patternText({prefix, suffix}: Pattern): string {
- return `${prefix}*${suffix}`;
- }
-
- /**
- * Given that candidate matches pattern, returns the text matching the '*'.
- * E.g.: matchedText(tryParsePattern("foo*baz"), "foobarbaz") === "bar"
- */
- function matchedText(pattern: Pattern, candidate: string): string {
- Debug.assert(isPatternMatch(pattern, candidate));
- return candidate.substr(pattern.prefix.length, candidate.length - pattern.suffix.length);
- }
-
- /** Return the object corresponding to the best pattern to match `candidate`. */
- /* @internal */
- export function findBestPatternMatch(values: T[], getPattern: (value: T) => Pattern, candidate: string): T | undefined {
- let matchedValue: T | undefined = undefined;
- // use length of prefix as betterness criteria
- let longestMatchPrefixLength = -1;
-
- for (const v of values) {
- const pattern = getPattern(v);
- if (isPatternMatch(pattern, candidate) && pattern.prefix.length > longestMatchPrefixLength) {
- longestMatchPrefixLength = pattern.prefix.length;
- matchedValue = v;
- }
- }
-
- return matchedValue;
- }
-
- function isPatternMatch({prefix, suffix}: Pattern, candidate: string) {
- return candidate.length >= prefix.length + suffix.length &&
- startsWith(candidate, prefix) &&
- endsWith(candidate, suffix);
- }
-
- /* @internal */
- export function tryParsePattern(pattern: string): Pattern | undefined {
- // This should be verified outside of here and a proper error thrown.
- Debug.assert(hasZeroOrOneAsteriskCharacter(pattern));
- const indexOfStar = pattern.indexOf("*");
- return indexOfStar === -1 ? undefined : {
- prefix: pattern.substr(0, indexOfStar),
- suffix: pattern.substr(indexOfStar + 1)
- };
- }
-
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
const containingDirectory = getDirectoryPath(containingFile);
const supportedExtensions = getSupportedExtensions(compilerOptions);
diff --git a/src/services/services.ts b/src/services/services.ts
index da8cb5e9c30..eb103cebb11 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -945,6 +945,8 @@ namespace ts {
let program: Program;
let lastProjectVersion: string;
+ let lastTypesRootVersion = 0;
+
const useCaseSensitivefileNames = false;
const cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken());
@@ -993,6 +995,13 @@ namespace ts {
}
}
+ const typeRootsVersion = host.getTypeRootsVersion ? host.getTypeRootsVersion() : 0;
+ if (lastTypesRootVersion !== typeRootsVersion) {
+ log("TypeRoots version has changed; provide new program");
+ program = undefined;
+ lastTypesRootVersion = typeRootsVersion;
+ }
+
// Get a fresh cache of the host information
let hostCache = new HostCache(host, getCanonicalFileName);
diff --git a/src/services/types.ts b/src/services/types.ts
index a6fc92d5460..79bee8d1818 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -148,6 +148,11 @@ namespace ts {
readFile?(path: string, encoding?: string): string;
fileExists?(path: string): boolean;
+ /*
+ * LS host can optionally implement these methods to support automatic updating when new type libraries are installed
+ */
+ getTypeRootsVersion?(): number;
+
/*
* LS host can optionally implement this method if it wants to be completely in charge of module name resolution.
* if implementation is omitted then language service will use built-in module resolution logic and get answers to
diff --git a/tests/baselines/reference/assignmentTypeNarrowing_BACKUP_22380.types b/tests/baselines/reference/assignmentTypeNarrowing_BACKUP_22380.types
deleted file mode 100644
index bb9805ca5ba..00000000000
--- a/tests/baselines/reference/assignmentTypeNarrowing_BACKUP_22380.types
+++ /dev/null
@@ -1,106 +0,0 @@
-=== tests/cases/conformance/expressions/assignmentOperator/assignmentTypeNarrowing.ts ===
-let x: string | number | boolean | RegExp;
->x : string | number | boolean | RegExp
->RegExp : RegExp
-
-x = "";
->x = "" : ""
->x : string | number | boolean | RegExp
->"" : ""
-
-x; // string
->x : string
-
-[x] = [true];
->[x] = [true] : [true]
->[x] : [string | number | boolean | RegExp]
->x : string | number | boolean | RegExp
->[true] : [true]
->true : true
-
-x; // boolean
->x : true
-
-[x = ""] = [1];
->[x = ""] = [1] : [number]
->[x = ""] : [string]
->x = "" : ""
->x : string | number | boolean | RegExp
->"" : ""
->[1] : [number]
->1 : 1
-
-x; // string | number
->x : string | number
-
-({x} = {x: true});
->({x} = {x: true}) : { x: true; }
->{x} = {x: true} : { x: true; }
->{x} : { x: string | number | boolean | RegExp; }
->x : string | number | boolean | RegExp
->{x: true} : { x: true; }
-<<<<<<< HEAD
->x : true
-=======
->x : boolean
->>>>>>> origin/master
->true : true
-
-x; // boolean
->x : true
-
-({y: x} = {y: 1});
->({y: x} = {y: 1}) : { y: 1; }
->{y: x} = {y: 1} : { y: 1; }
->{y: x} : { y: string | number | boolean | RegExp; }
->y : string | number | boolean | RegExp
->x : string | number | boolean | RegExp
->{y: 1} : { y: 1; }
->y : number
->1 : 1
-
-x; // number
->x : number
-
-({x = ""} = {x: true});
->({x = ""} = {x: true}) : { x?: true; }
->{x = ""} = {x: true} : { x?: true; }
->{x = ""} : { x?: string | number | boolean | RegExp; }
->x : string | number | boolean | RegExp
->{x: true} : { x?: true; }
-<<<<<<< HEAD
->x : true
-=======
->x : boolean
->>>>>>> origin/master
->true : true
-
-x; // string | boolean
->x : string | true
-
-({y: x = /a/} = {y: 1});
->({y: x = /a/} = {y: 1}) : { y?: number; }
->{y: x = /a/} = {y: 1} : { y?: number; }
->{y: x = /a/} : { y?: RegExp; }
->y : RegExp
->x = /a/ : RegExp
->x : string | number | boolean | RegExp
->/a/ : RegExp
->{y: 1} : { y?: number; }
->y : number
->1 : 1
-
-x; // number | RegExp
->x : number | RegExp
-
-let a: string[];
->a : string[]
-
-for (x of a) {
->x : string | number | boolean | RegExp
->a : string[]
-
- x; // string
->x : string
-}
-
diff --git a/tests/baselines/reference/assignmentTypeNarrowing_BASE_22380.types b/tests/baselines/reference/assignmentTypeNarrowing_BASE_22380.types
deleted file mode 100644
index be99a31501d..00000000000
--- a/tests/baselines/reference/assignmentTypeNarrowing_BASE_22380.types
+++ /dev/null
@@ -1,98 +0,0 @@
-=== tests/cases/conformance/expressions/assignmentOperator/assignmentTypeNarrowing.ts ===
-let x: string | number | boolean | RegExp;
->x : string | number | boolean | RegExp
->RegExp : RegExp
-
-x = "";
->x = "" : string
->x : string | number | boolean | RegExp
->"" : string
-
-x; // string
->x : string
-
-[x] = [true];
->[x] = [true] : [boolean]
->[x] : [string | number | boolean | RegExp]
->x : string | number | boolean | RegExp
->[true] : [boolean]
->true : boolean
-
-x; // boolean
->x : boolean
-
-[x = ""] = [1];
->[x = ""] = [1] : [number]
->[x = ""] : [string]
->x = "" : string
->x : string | number | boolean | RegExp
->"" : string
->[1] : [number]
->1 : number
-
-x; // string | number
->x : string | number
-
-({x} = {x: true});
->({x} = {x: true}) : { x: boolean; }
->{x} = {x: true} : { x: boolean; }
->{x} : { x: string | number | boolean | RegExp; }
->x : string | number | boolean | RegExp
->{x: true} : { x: boolean; }
->x : boolean
->true : boolean
-
-x; // boolean
->x : boolean
-
-({y: x} = {y: 1});
->({y: x} = {y: 1}) : { y: number; }
->{y: x} = {y: 1} : { y: number; }
->{y: x} : { y: string | number | boolean | RegExp; }
->y : string | number | boolean | RegExp
->x : string | number | boolean | RegExp
->{y: 1} : { y: number; }
->y : number
->1 : number
-
-x; // number
->x : number
-
-({x = ""} = {x: true});
->({x = ""} = {x: true}) : { x?: boolean; }
->{x = ""} = {x: true} : { x?: boolean; }
->{x = ""} : { x?: string | number | boolean | RegExp; }
->x : string | number | boolean | RegExp
->{x: true} : { x?: boolean; }
->x : boolean
->true : boolean
-
-x; // string | boolean
->x : string | boolean
-
-({y: x = /a/} = {y: 1});
->({y: x = /a/} = {y: 1}) : { y?: number; }
->{y: x = /a/} = {y: 1} : { y?: number; }
->{y: x = /a/} : { y?: RegExp; }
->y : RegExp
->x = /a/ : RegExp
->x : string | number | boolean | RegExp
->/a/ : RegExp
->{y: 1} : { y?: number; }
->y : number
->1 : number
-
-x; // number | RegExp
->x : number | RegExp
-
-let a: string[];
->a : string[]
-
-for (x of a) {
->x : string | number | boolean | RegExp
->a : string[]
-
- x; // string
->x : string
-}
-
diff --git a/tests/baselines/reference/assignmentTypeNarrowing_LOCAL_22380.types b/tests/baselines/reference/assignmentTypeNarrowing_LOCAL_22380.types
deleted file mode 100644
index f46b2a16c3b..00000000000
--- a/tests/baselines/reference/assignmentTypeNarrowing_LOCAL_22380.types
+++ /dev/null
@@ -1,98 +0,0 @@
-=== tests/cases/conformance/expressions/assignmentOperator/assignmentTypeNarrowing.ts ===
-let x: string | number | boolean | RegExp;
->x : string | number | boolean | RegExp
->RegExp : RegExp
-
-x = "";
->x = "" : string
->x : string | number | boolean | RegExp
->"" : string
-
-x; // string
->x : string
-
-[x] = [true];
->[x] = [true] : [true]
->[x] : [string | number | boolean | RegExp]
->x : string | number | boolean | RegExp
->[true] : [true]
->true : true
-
-x; // boolean
->x : true
-
-[x = ""] = [1];
->[x = ""] = [1] : [number]
->[x = ""] : [string]
->x = "" : string
->x : string | number | boolean | RegExp
->"" : string
->[1] : [number]
->1 : number
-
-x; // string | number
->x : string | number
-
-({x} = {x: true});
->({x} = {x: true}) : { x: true; }
->{x} = {x: true} : { x: true; }
->{x} : { x: string | number | boolean | RegExp; }
->x : string | number | boolean | RegExp
->{x: true} : { x: true; }
->x : true
->true : true
-
-x; // boolean
->x : true
-
-({y: x} = {y: 1});
->({y: x} = {y: 1}) : { y: number; }
->{y: x} = {y: 1} : { y: number; }
->{y: x} : { y: string | number | boolean | RegExp; }
->y : string | number | boolean | RegExp
->x : string | number | boolean | RegExp
->{y: 1} : { y: number; }
->y : number
->1 : number
-
-x; // number
->x : number
-
-({x = ""} = {x: true});
->({x = ""} = {x: true}) : { x?: true; }
->{x = ""} = {x: true} : { x?: true; }
->{x = ""} : { x?: string | number | boolean | RegExp; }
->x : string | number | boolean | RegExp
->{x: true} : { x?: true; }
->x : true
->true : true
-
-x; // string | boolean
->x : string | true
-
-({y: x = /a/} = {y: 1});
->({y: x = /a/} = {y: 1}) : { y?: number; }
->{y: x = /a/} = {y: 1} : { y?: number; }
->{y: x = /a/} : { y?: RegExp; }
->y : RegExp
->x = /a/ : RegExp
->x : string | number | boolean | RegExp
->/a/ : RegExp
->{y: 1} : { y?: number; }
->y : number
->1 : number
-
-x; // number | RegExp
->x : number | RegExp
-
-let a: string[];
->a : string[]
-
-for (x of a) {
->x : string | number | boolean | RegExp
->a : string[]
-
- x; // string
->x : string
-}
-
diff --git a/tests/baselines/reference/assignmentTypeNarrowing_REMOTE_22380.types b/tests/baselines/reference/assignmentTypeNarrowing_REMOTE_22380.types
deleted file mode 100644
index 8c5fea315ce..00000000000
--- a/tests/baselines/reference/assignmentTypeNarrowing_REMOTE_22380.types
+++ /dev/null
@@ -1,98 +0,0 @@
-=== tests/cases/conformance/expressions/assignmentOperator/assignmentTypeNarrowing.ts ===
-let x: string | number | boolean | RegExp;
->x : string | number | boolean | RegExp
->RegExp : RegExp
-
-x = "";
->x = "" : ""
->x : string | number | boolean | RegExp
->"" : ""
-
-x; // string
->x : string
-
-[x] = [true];
->[x] = [true] : [true]
->[x] : [string | number | boolean | RegExp]
->x : string | number | boolean | RegExp
->[true] : [true]
->true : true
-
-x; // boolean
->x : true
-
-[x = ""] = [1];
->[x = ""] = [1] : [number]
->[x = ""] : [string]
->x = "" : ""
->x : string | number | boolean | RegExp
->"" : ""
->[1] : [number]
->1 : 1
-
-x; // string | number
->x : string | number
-
-({x} = {x: true});
->({x} = {x: true}) : { x: true; }
->{x} = {x: true} : { x: true; }
->{x} : { x: string | number | boolean | RegExp; }
->x : string | number | boolean | RegExp
->{x: true} : { x: true; }
->x : boolean
->true : true
-
-x; // boolean
->x : true
-
-({y: x} = {y: 1});
->({y: x} = {y: 1}) : { y: 1; }
->{y: x} = {y: 1} : { y: 1; }
->{y: x} : { y: string | number | boolean | RegExp; }
->y : string | number | boolean | RegExp
->x : string | number | boolean | RegExp
->{y: 1} : { y: 1; }
->y : number
->1 : 1
-
-x; // number
->x : number
-
-({x = ""} = {x: true});
->({x = ""} = {x: true}) : { x?: true; }
->{x = ""} = {x: true} : { x?: true; }
->{x = ""} : { x?: string | number | boolean | RegExp; }
->x : string | number | boolean | RegExp
->{x: true} : { x?: true; }
->x : boolean
->true : true
-
-x; // string | boolean
->x : string | true
-
-({y: x = /a/} = {y: 1});
->({y: x = /a/} = {y: 1}) : { y?: number; }
->{y: x = /a/} = {y: 1} : { y?: number; }
->{y: x = /a/} : { y?: RegExp; }
->y : RegExp
->x = /a/ : RegExp
->x : string | number | boolean | RegExp
->/a/ : RegExp
->{y: 1} : { y?: number; }
->y : number
->1 : 1
-
-x; // number | RegExp
->x : number | RegExp
-
-let a: string[];
->a : string[]
-
-for (x of a) {
->x : string | number | boolean | RegExp
->a : string[]
-
- x; // string
->x : string
-}
-