diff --git a/scripts/processDiagnosticMessages.ts b/scripts/processDiagnosticMessages.ts
index 431cf460180..e5eaa46c8e5 100644
--- a/scripts/processDiagnosticMessages.ts
+++ b/scripts/processDiagnosticMessages.ts
@@ -86,7 +86,7 @@ function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, nameMap:
'/// \r\n' +
'/* @internal */\r\n' +
'namespace ts {\r\n' +
- ' export var Diagnostics = {\r\n';
+ ' export const Diagnostics = {\r\n';
var names = Utilities.getObjectKeys(messageTable);
for (var i = 0; i < names.length; i++) {
var name = names[i];
diff --git a/src/compiler/core.ts b/src/compiler/core.ts
index 7d705acc5de..bc98d411b82 100644
--- a/src/compiler/core.ts
+++ b/src/compiler/core.ts
@@ -212,7 +212,7 @@ namespace ts {
* true for all elements, otherwise returns a new array instance containing the filtered subset.
*/
export function filter(array: T[], f: (x: T) => x is U): U[];
- export function filter(array: T[], f: (x: T) => boolean): T[]
+ export function filter(array: T[], f: (x: T) => boolean): T[];
export function filter(array: T[], f: (x: T) => boolean): T[] {
if (array) {
const len = array.length;
@@ -1879,10 +1879,10 @@ namespace ts {
declare var process: any;
declare var require: any;
- let currentAssertionLevel: AssertionLevel;
+ export let currentAssertionLevel = AssertionLevel.None;
export function shouldAssert(level: AssertionLevel): boolean {
- return getCurrentAssertionLevel() >= level;
+ return currentAssertionLevel >= level;
}
export function assert(expression: boolean, message?: string, verboseDebugInfo?: () => string): void {
@@ -1899,35 +1899,6 @@ namespace ts {
export function fail(message?: string): void {
Debug.assert(/*expression*/ false, message);
}
-
- function getCurrentAssertionLevel() {
- if (currentAssertionLevel !== undefined) {
- return currentAssertionLevel;
- }
-
- if (sys === undefined) {
- return AssertionLevel.None;
- }
-
- const developmentMode = /^development$/i.test(getEnvironmentVariable("NODE_ENV"));
- currentAssertionLevel = developmentMode
- ? AssertionLevel.Normal
- : AssertionLevel.None;
-
- return currentAssertionLevel;
- }
- }
-
- export function getEnvironmentVariable(name: string, host?: CompilerHost) {
- if (host && host.getEnvironmentVariable) {
- return host.getEnvironmentVariable(name);
- }
-
- if (sys && sys.getEnvironmentVariable) {
- return sys.getEnvironmentVariable(name);
- }
-
- return "";
}
/** Remove an item from an array, moving everything to its right one space left. */
diff --git a/src/compiler/program.ts b/src/compiler/program.ts
index 91adb09c402..5d46038b2b1 100644
--- a/src/compiler/program.ts
+++ b/src/compiler/program.ts
@@ -206,7 +206,7 @@ namespace ts {
readFile: fileName => sys.readFile(fileName),
trace: (s: string) => sys.write(s + newLine),
directoryExists: directoryName => sys.directoryExists(directoryName),
- getEnvironmentVariable: name => getEnvironmentVariable(name, /*host*/ undefined),
+ getEnvironmentVariable: name => sys.getEnvironmentVariable ? sys.getEnvironmentVariable(name) : "",
getDirectories: (path: string) => sys.getDirectories(path),
realpath
};
diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts
index 2d4fcd241aa..7cf7d75bc02 100644
--- a/src/compiler/sys.ts
+++ b/src/compiler/sys.ts
@@ -83,7 +83,7 @@ namespace ts {
getEnvironmentVariable?(name: string): string;
};
- export var sys: System = (function() {
+ export let sys: System = (function() {
function getWScriptSystem(): System {
@@ -637,4 +637,10 @@ namespace ts {
}
return sys;
})();
+
+ if (sys && sys.getEnvironmentVariable) {
+ Debug.currentAssertionLevel = /^development$/i.test(sys.getEnvironmentVariable("NODE_ENV"))
+ ? AssertionLevel.Normal
+ : AssertionLevel.None;
+ }
}
diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index 0b4418b1236..49f834963ee 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -754,6 +754,13 @@ namespace FourSlash {
}
}
+ public verifyCompletionListIsGlobal(expected: boolean) {
+ const completions = this.getCompletionListAtCaret();
+ if (completions && completions.isGlobalCompletion !== expected) {
+ this.raiseError(`verifyCompletionListIsGlobal failed - expected result to be ${completions.isGlobalCompletion}`);
+ }
+ }
+
public verifyCompletionListContains(symbol: string, text?: string, documentation?: string, kind?: string, spanIndex?: number) {
const completions = this.getCompletionListAtCaret();
if (completions) {
@@ -3046,6 +3053,10 @@ namespace FourSlashInterface {
this.state.verifyCompletionListIsEmpty(this.negative);
}
+ public completionListIsGlobal(expected: boolean) {
+ this.state.verifyCompletionListIsGlobal(expected);
+ }
+
public completionListAllowsNewIdentifier() {
this.state.verifyCompletionListAllowsNewIdentifier(this.negative);
}
diff --git a/src/harness/harness.ts b/src/harness/harness.ts
index c6b6b460fca..7c82aeece78 100644
--- a/src/harness/harness.ts
+++ b/src/harness/harness.ts
@@ -509,7 +509,7 @@ namespace Harness {
tryEnableSourceMapsForHost?(): void;
getEnvironmentVariable?(name: string): string;
}
- export var IO: IO;
+ export let IO: IO;
// harness always uses one kind of new line
const harnessNewLine = "\r\n";
diff --git a/src/server/client.ts b/src/server/client.ts
index 5032056c2f3..688408dfb88 100644
--- a/src/server/client.ts
+++ b/src/server/client.ts
@@ -214,6 +214,7 @@ namespace ts.server {
const response = this.processResponse(request);
return {
+ isGlobalCompletion: false,
isMemberCompletion: false,
isNewIdentifierLocation: false,
entries: response.body.map(entry => {
diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts
index 2b28e66bf88..51310c90a6b 100644
--- a/src/server/editorServices.ts
+++ b/src/server/editorServices.ts
@@ -12,7 +12,7 @@ namespace ts.server {
export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024;
export type ProjectServiceEvent =
- { eventName: "context", data: { project: Project, fileName: NormalizedPath } } | { eventName: "configFileDiag", data: { triggerFile?: string, configFileName: string, diagnostics: Diagnostic[] } }
+ { eventName: "context", data: { project: Project, fileName: NormalizedPath } } | { eventName: "configFileDiag", data: { triggerFile?: string, configFileName: string, diagnostics: Diagnostic[] } };
export interface ProjectServiceEventHandler {
(event: ProjectServiceEvent): void;
diff --git a/src/services/completions.ts b/src/services/completions.ts
index a9395bd665b..071cac27bc6 100644
--- a/src/services/completions.ts
+++ b/src/services/completions.ts
@@ -14,11 +14,11 @@ namespace ts.Completions {
return undefined;
}
- const { symbols, isMemberCompletion, isNewIdentifierLocation, location, isJsDocTagName } = completionData;
+ const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isJsDocTagName } = completionData;
if (isJsDocTagName) {
// If the current position is a jsDoc tag name, only tag names should be provided for completion
- return { isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getAllJsDocCompletionEntries() };
+ return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getAllJsDocCompletionEntries() };
}
const entries: CompletionEntry[] = [];
@@ -56,7 +56,7 @@ namespace ts.Completions {
addRange(entries, keywordCompletions);
}
- return { isMemberCompletion, isNewIdentifierLocation: isNewIdentifierLocation, entries };
+ return { isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation: isNewIdentifierLocation, entries };
function getJavaScriptCompletionEntries(sourceFile: SourceFile, position: number, uniqueNames: Map): CompletionEntry[] {
const entries: CompletionEntry[] = [];
@@ -190,7 +190,7 @@ namespace ts.Completions {
if (type) {
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, element, /*performCharacterChecks*/false);
if (entries.length) {
- return { isMemberCompletion: true, isNewIdentifierLocation: true, entries };
+ return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: true, entries };
}
}
}
@@ -209,7 +209,7 @@ namespace ts.Completions {
}
if (entries.length) {
- return { isMemberCompletion: false, isNewIdentifierLocation: true, entries };
+ return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: true, entries };
}
return undefined;
@@ -221,7 +221,7 @@ namespace ts.Completions {
if (type) {
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, node, /*performCharacterChecks*/false);
if (entries.length) {
- return { isMemberCompletion: true, isNewIdentifierLocation: true, entries };
+ return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: true, entries };
}
}
return undefined;
@@ -233,7 +233,7 @@ namespace ts.Completions {
const entries: CompletionEntry[] = [];
addStringLiteralCompletionsFromType(type, entries);
if (entries.length) {
- return { isMemberCompletion: false, isNewIdentifierLocation: false, entries };
+ return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries };
}
}
return undefined;
@@ -281,6 +281,7 @@ namespace ts.Completions {
entries = getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, span);
}
return {
+ isGlobalCompletion: false,
isMemberCompletion: false,
isNewIdentifierLocation: true,
entries
@@ -549,13 +550,18 @@ namespace ts.Completions {
}
const completionInfo: CompletionInfo = {
- isMemberCompletion: false,
- /**
- * The user may type in a path that doesn't yet exist, creating a "new identifier"
- * with respect to the collection of identifiers the server is aware of.
- */
- isNewIdentifierLocation: true,
- entries: []
+ /**
+ * We don't want the editor to offer any other completions, such as snippets, inside a comment.
+ */
+ isGlobalCompletion: false,
+ isMemberCompletion: false,
+ /**
+ * The user may type in a path that doesn't yet exist, creating a "new identifier"
+ * with respect to the collection of identifiers the server is aware of.
+ */
+ isNewIdentifierLocation: true,
+
+ entries: []
};
const text = sourceFile.text.substr(range.pos, position - range.pos);
@@ -828,7 +834,7 @@ namespace ts.Completions {
}
if (isJsDocTagName) {
- return { symbols: undefined, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, isJsDocTagName };
+ return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, isJsDocTagName };
}
if (!insideJsDocTagExpression) {
@@ -900,6 +906,7 @@ namespace ts.Completions {
}
const semanticStart = timestamp();
+ let isGlobalCompletion = false;
let isMemberCompletion: boolean;
let isNewIdentifierLocation: boolean;
let symbols: Symbol[] = [];
@@ -935,14 +942,16 @@ namespace ts.Completions {
if (!tryGetGlobalSymbols()) {
return undefined;
}
+ isGlobalCompletion = true;
}
log("getCompletionData: Semantic work: " + (timestamp() - semanticStart));
- return { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), isJsDocTagName };
+ return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), isJsDocTagName };
function getTypeScriptMemberSymbols(): void {
// Right of dot member completion list
+ isGlobalCompletion = false;
isMemberCompletion = true;
isNewIdentifierLocation = false;
diff --git a/src/services/types.ts b/src/services/types.ts
index fc9a3da5331..ac81a87daf5 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -503,6 +503,7 @@ namespace ts {
}
export interface CompletionInfo {
+ isGlobalCompletion: boolean;
isMemberCompletion: boolean;
/**
diff --git a/tests/cases/fourslash/completionListIsGlobalCompletion.ts b/tests/cases/fourslash/completionListIsGlobalCompletion.ts
new file mode 100644
index 00000000000..3a7adb465a1
--- /dev/null
+++ b/tests/cases/fourslash/completionListIsGlobalCompletion.ts
@@ -0,0 +1,42 @@
+///
+
+/////// // no globals in reference paths
+////import { /*2*/ } from "./file.ts"; // no globals in imports
+////var test = "/*3*/"; // no globals in strings
+/////*4*/class A { // insert globals
+//// foo(): string { return ''; }
+////}
+////
+////class /*5*/B extends A { // no globals after class keyword
+//// bar(): string {
+//// /*6*/ // insert globals
+//// return '';
+//// }
+////}
+////
+////class C*7*/ U extends A, T extends A> { // no globals at beginning of generics
+//// x: U;
+//// y = this./*8*/x; // no globals inserted for member completions
+//// /*9*/ // insert globals
+////}
+/////*10*/ // insert globals
+goTo.marker("1");
+verify.completionListIsGlobal(false);
+goTo.marker("2");
+verify.completionListIsGlobal(false);
+goTo.marker("3");
+verify.completionListIsGlobal(false);
+goTo.marker("4");
+verify.completionListIsGlobal(true);
+goTo.marker("5");
+verify.completionListIsGlobal(false);
+goTo.marker("6");
+verify.completionListIsGlobal(true);
+goTo.marker("7");
+verify.completionListIsGlobal(false);
+goTo.marker("8");
+verify.completionListIsGlobal(false);
+goTo.marker("9");
+verify.completionListIsGlobal(true);
+goTo.marker("10");
+verify.completionListIsGlobal(true);