From d186c8311903dec4e88e0e3d8d09688a9c72d9da Mon Sep 17 00:00:00 2001 From: Jason Ramsay Date: Mon, 3 Oct 2016 16:29:06 -0700 Subject: [PATCH 1/3] Add isGlobalCompletion to CompletionInfo for snippet injection --- src/harness/fourslash.ts | 14 +++++++ src/server/client.ts | 1 + src/services/completions.ts | 25 +++++++---- src/services/types.ts | 1 + .../completionListIsGlobalCompletion.ts | 42 +++++++++++++++++++ 5 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 tests/cases/fourslash/completionListIsGlobalCompletion.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 0b4418b1236..9e20e8a36da 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -754,6 +754,16 @@ namespace FourSlash { } } + public verifyCompletionListIsGlobal(expected: boolean) { + const completions = this.getCompletionListAtCaret(); + if (!completions && expected !== undefined) { + this.raiseError(`verifyCompletionListIsGlobal failed - expected result to be ${completions}`); + } + else 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 +3056,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/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/services/completions.ts b/src/services/completions.ts index a43717921c4..78756c1ac45 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 @@ -558,6 +559,7 @@ namespace ts.Completions { } return { + isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: true, entries @@ -812,7 +814,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) { @@ -884,6 +886,7 @@ namespace ts.Completions { } const semanticStart = timestamp(); + let isGlobalCompletion: boolean; let isMemberCompletion: boolean; let isNewIdentifierLocation: boolean; let symbols: Symbol[] = []; @@ -899,6 +902,7 @@ namespace ts.Completions { else { symbols = tagSymbols; } + isGlobalCompletion = false; isMemberCompletion = true; isNewIdentifierLocation = false; } @@ -909,6 +913,7 @@ namespace ts.Completions { if (!typeChecker.isUnknownSymbol(tagSymbol)) { symbols = [tagSymbol]; } + isGlobalCompletion = false; isMemberCompletion = true; isNewIdentifierLocation = false; } @@ -919,14 +924,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 874d96fccc3..f84986bb534 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -503,6 +503,7 @@ namespace ts { } export interface CompletionInfo { + isGlobalCompletion: boolean; isMemberCompletion: boolean; isNewIdentifierLocation: boolean; // true when the current location also allows for a new identifier entries: CompletionEntry[]; diff --git a/tests/cases/fourslash/completionListIsGlobalCompletion.ts b/tests/cases/fourslash/completionListIsGlobalCompletion.ts new file mode 100644 index 00000000000..58107cbcb7f --- /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 { // 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(undefined); +goTo.marker("3"); +verify.completionListIsGlobal(undefined); +goTo.marker("4"); +verify.completionListIsGlobal(true); +goTo.marker("5"); +verify.completionListIsGlobal(undefined); +goTo.marker("6"); +verify.completionListIsGlobal(true); +goTo.marker("7"); +verify.completionListIsGlobal(undefined); +goTo.marker("8"); +verify.completionListIsGlobal(false); +goTo.marker("9"); +verify.completionListIsGlobal(true); +goTo.marker("10"); +verify.completionListIsGlobal(true); From 62fddba88eebf2517c6041159b8408fba166f5cc Mon Sep 17 00:00:00 2001 From: Jason Ramsay Date: Tue, 4 Oct 2016 12:48:44 -0700 Subject: [PATCH 2/3] Changes from CR feedback --- src/harness/fourslash.ts | 5 +---- src/services/completions.ts | 4 +--- tests/cases/fourslash/completionListIsGlobalCompletion.ts | 8 ++++---- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 9e20e8a36da..49f834963ee 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -756,10 +756,7 @@ namespace FourSlash { public verifyCompletionListIsGlobal(expected: boolean) { const completions = this.getCompletionListAtCaret(); - if (!completions && expected !== undefined) { - this.raiseError(`verifyCompletionListIsGlobal failed - expected result to be ${completions}`); - } - else if (completions && completions.isGlobalCompletion !== expected) { + if (completions && completions.isGlobalCompletion !== expected) { this.raiseError(`verifyCompletionListIsGlobal failed - expected result to be ${completions.isGlobalCompletion}`); } } diff --git a/src/services/completions.ts b/src/services/completions.ts index 78756c1ac45..64ea05e4f2b 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -886,7 +886,7 @@ namespace ts.Completions { } const semanticStart = timestamp(); - let isGlobalCompletion: boolean; + let isGlobalCompletion = false; let isMemberCompletion: boolean; let isNewIdentifierLocation: boolean; let symbols: Symbol[] = []; @@ -902,7 +902,6 @@ namespace ts.Completions { else { symbols = tagSymbols; } - isGlobalCompletion = false; isMemberCompletion = true; isNewIdentifierLocation = false; } @@ -913,7 +912,6 @@ namespace ts.Completions { if (!typeChecker.isUnknownSymbol(tagSymbol)) { symbols = [tagSymbol]; } - isGlobalCompletion = false; isMemberCompletion = true; isNewIdentifierLocation = false; } diff --git a/tests/cases/fourslash/completionListIsGlobalCompletion.ts b/tests/cases/fourslash/completionListIsGlobalCompletion.ts index 58107cbcb7f..3a7adb465a1 100644 --- a/tests/cases/fourslash/completionListIsGlobalCompletion.ts +++ b/tests/cases/fourslash/completionListIsGlobalCompletion.ts @@ -23,17 +23,17 @@ goTo.marker("1"); verify.completionListIsGlobal(false); goTo.marker("2"); -verify.completionListIsGlobal(undefined); +verify.completionListIsGlobal(false); goTo.marker("3"); -verify.completionListIsGlobal(undefined); +verify.completionListIsGlobal(false); goTo.marker("4"); verify.completionListIsGlobal(true); goTo.marker("5"); -verify.completionListIsGlobal(undefined); +verify.completionListIsGlobal(false); goTo.marker("6"); verify.completionListIsGlobal(true); goTo.marker("7"); -verify.completionListIsGlobal(undefined); +verify.completionListIsGlobal(false); goTo.marker("8"); verify.completionListIsGlobal(false); goTo.marker("9"); From 8dabe33b32fac70f3b751a6ac145840d6fbc0164 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 4 Oct 2016 14:00:45 -0700 Subject: [PATCH 3/3] fix linter (#11366) --- scripts/processDiagnosticMessages.ts | 2 +- src/compiler/core.ts | 35 +++------------------------- src/compiler/program.ts | 2 +- src/compiler/sys.ts | 8 ++++++- src/harness/harness.ts | 2 +- src/server/editorServices.ts | 2 +- 6 files changed, 14 insertions(+), 37 deletions(-) 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 4e1f4553642..e63bcbf8474 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; @@ -1867,10 +1867,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 { @@ -1887,35 +1887,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/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/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;