diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index 6a4e13b22e3..9dad3dddf60 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -146,7 +146,7 @@ module FourSlash {
function convertGlobalOptionsToCompilationSettings(globalOptions: { [idx: string]: string }): ts.CompilationSettings {
var settings: ts.CompilationSettings = {};
- // Convert all property in globalOptions into ts.CompilationSettings
+ // Convert all property in globalOptions into ts.CompilationSettings
for (var prop in globalOptions) {
if (globalOptions.hasOwnProperty(prop)) {
switch (prop) {
@@ -1610,7 +1610,7 @@ module FourSlash {
Harness.IO.log(this.getNameOrDottedNameSpan(pos));
}
- private verifyClassifications(expected: { classificationType: string; text: string }[], actual: ts.ClassifiedSpan[]) {
+ private verifyClassifications(expected: { classificationType: string; text: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[]) {
if (actual.length !== expected.length) {
this.raiseError('verifyClassifications failed - expected total classifications to be ' + expected.length + ', but was ' + actual.length);
}
@@ -1626,7 +1626,19 @@ module FourSlash {
actualClassification.classificationType);
}
+ var expectedSpan = expectedClassification.textSpan;
var actualSpan = actualClassification.textSpan;
+
+ if (expectedSpan) {
+ var expectedLength = expectedSpan.end - expectedSpan.start;
+
+ if (expectedSpan.start !== actualSpan.start() || expectedLength !== actualSpan.length()) {
+ this.raiseError("verifyClassifications failed - expected span of text to be " +
+ "{start=" + expectedSpan.start + ", length=" + expectedLength + "}, but was " +
+ "{start=" + actualSpan.start() + ", length=" + actualSpan.length() + "}");
+ }
+ }
+
var actualText = this.activeFile.content.substr(actualSpan.start(), actualSpan.length());
if (expectedClassification.text !== actualText) {
this.raiseError('verifyClassifications failed - expected classificatied text to be ' +
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index 7be7dd63c92..d184be57712 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -80,6 +80,10 @@ module FourSlashInterface {
return FourSlash.currentTestState.getMarkers();
}
+ public marker(name?: string): Marker {
+ return FourSlash.currentTestState.getMarkerByName(name);
+ }
+
public ranges(): Range[] {
return FourSlash.currentTestState.getRanges();
}
@@ -401,11 +405,17 @@ module FourSlashInterface {
FourSlash.currentTestState.verifyCompletionEntryDetails(entryName, text, documentation, kind);
}
+ /**
+ * This method *requires* a contiguous, complete, and ordered stream of classifications for a file.
+ */
public syntacticClassificationsAre(...classifications: { classificationType: string; text: string }[]) {
FourSlash.currentTestState.verifySyntacticClassifications(classifications);
}
- public semanticClassificationsAre(...classifications: { classificationType: string; text: string }[]) {
+ /**
+ * This method *requires* an ordered stream of classifications for a file, and spans are highly recommended.
+ */
+ public semanticClassificationsAre(...classifications: { classificationType: string; text: string; textSpan?: TextSpan }[]) {
FourSlash.currentTestState.verifySemanticClassifications(classifications);
}
@@ -563,61 +573,69 @@ module FourSlashInterface {
}
}
- export class classification {
- public static comment(text: string): { classificationType: string; text: string } {
- return { classificationType: "comment", text: text };
+ export module classification {
+ export function comment(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("comment", text, position);
}
- public static identifier(text: string): { classificationType: string; text: string } {
- return { classificationType: "identifier", text: text };
+ export function identifier(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("identifier", text, position);
}
- public static keyword(text: string): { classificationType: string; text: string } {
- return { classificationType: "keyword", text: text };
+ export function keyword(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("keyword", text, position);
}
- public static numericLiteral(text: string): { classificationType: string; text: string } {
- return { classificationType: "numericLiteral", text: text };
+ export function numericLiteral(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("numericLiteral", text, position);
}
- public static operator(text: string): { classificationType: string; text: string } {
- return { classificationType: "operator", text: text };
+ export function operator(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("operator", text, position);
}
- public static stringLiteral(text: string): { classificationType: string; text: string } {
- return { classificationType: "stringLiteral", text: text };
+ export function stringLiteral(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("stringLiteral", text, position);
}
- public static whiteSpace(text: string): { classificationType: string; text: string } {
- return { classificationType: "whiteSpace", text: text };
+ export function whiteSpace(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("whiteSpace", text, position);
}
- public static text(text: string): { classificationType: string; text: string } {
- return { classificationType: "text", text: text };
+ export function text(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("text", text, position);
}
- public static punctuation(text: string): { classificationType: string; text: string } {
- return { classificationType: "punctuation", text: text };
+ export function punctuation(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("punctuation", text, position);
}
- public static className(text: string): { classificationType: string; text: string } {
- return { classificationType: "className", text: text };
+ export function className(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("className", text, position);
}
- public static enumName(text: string): { classificationType: string; text: string } {
- return { classificationType: "enumName", text: text };
+ export function enumName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("enumName", text, position);
}
- public static interfaceName(text: string): { classificationType: string; text: string } {
- return { classificationType: "interfaceName", text: text };
+ export function interfaceName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("interfaceName", text, position);
}
- public static moduleName(text: string): { classificationType: string; text: string } {
- return { classificationType: "moduleName", text: text };
+ export function moduleName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("moduleName", text, position);
}
- public static typeParameterName(text: string): { classificationType: string; text: string } {
- return { classificationType: "typeParameterName", text: text };
+ export function typeParameterName(text: string, position?: number): { classificationType: string; text: string; textSpan?: TextSpan } {
+ return getClassification("typeParameterName", text, position);
+ }
+
+ function getClassification(type: string, text: string, position?: number) {
+ return {
+ classificationType: type,
+ text: text,
+ textSpan: position === undefined ? undefined : { start: position, end: position + text.length }
+ };
}
}
}
@@ -635,6 +653,7 @@ module fs {
function verifyOperationIsCancelled(f) {
FourSlash.verifyOperationIsCancelled(f);
}
+
var test = new FourSlashInterface.test_();
var goTo = new FourSlashInterface.goTo();
var verify = new FourSlashInterface.verify();
diff --git a/tests/cases/fourslash/semanticClassification1.ts b/tests/cases/fourslash/semanticClassification1.ts
index ad9e88ea842..4eb7f2a32ed 100644
--- a/tests/cases/fourslash/semanticClassification1.ts
+++ b/tests/cases/fourslash/semanticClassification1.ts
@@ -1,11 +1,15 @@
///
-//// module M {
-//// export interface I {
+//// module /*0*/M {
+//// export interface /*1*/I {
//// }
//// }
-//// interface X extends M.I { }
+//// interface /*2*/X extends /*3*/M./*4*/I { }
var c = classification;
verify.semanticClassificationsAre(
- c.moduleName("M"), c.interfaceName("I"), c.interfaceName("X"), c.moduleName("M"), c.interfaceName("I"));
+ c.moduleName("M", test.marker("0").position),
+ c.interfaceName("I", test.marker("1").position),
+ c.interfaceName("X", test.marker("2").position),
+ c.moduleName("M", test.marker("3").position),
+ c.interfaceName("I", test.marker("4").position));
diff --git a/tests/cases/fourslash/semanticClassification2.ts b/tests/cases/fourslash/semanticClassification2.ts
index 810636dba3e..f7f6340e5bd 100644
--- a/tests/cases/fourslash/semanticClassification2.ts
+++ b/tests/cases/fourslash/semanticClassification2.ts
@@ -1,6 +1,6 @@
///
-//// interface Thing {
+//// interface /*0*/Thing {
//// toExponential(): number;
//// }
////
@@ -8,4 +8,4 @@
//// Thing.toExponential();
var c = classification;
-verify.semanticClassificationsAre(c.interfaceName("Thing"));
\ No newline at end of file
+verify.semanticClassificationsAre(c.interfaceName("Thing", test.marker("0").position));
\ No newline at end of file
diff --git a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts
index 96cce6f4255..2b8b6824558 100644
--- a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts
+++ b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName1.ts
@@ -1,20 +1,24 @@
///
-////module M {
-//// export interface I {
+////module /*0*/M {
+//// export interface /*1*/I {
//// }
//// var x = 10;
////}
////
-////var M = {
+////var /*2*/M = {
//// foo: 10,
//// bar: 20
////}
////
-////var v: M.I;
+////var v: /*3*/M./*4*/I;
////
-////var x = M;
+////var x = /*5*/M;
var c = classification;
verify.semanticClassificationsAre(
- c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"));
+ c.moduleName("M", test.marker("0").position),
+ c.interfaceName("I", test.marker("1").position),
+ c.moduleName("M", test.marker("3").position),
+ c.interfaceName("I", test.marker("4").position),
+ c.moduleName("M", test.marker("5").position));
diff --git a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts
index bcbd5f514f4..5d2ed9844cc 100644
--- a/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts
+++ b/tests/cases/fourslash/semanticClassificationInstantiatedModuleWithVariableOfSameName2.ts
@@ -1,23 +1,28 @@
///
-////module M {
-//// export interface I {
+////module /*0*/M {
+//// export interface /*1*/I {
//// }
////}
////
-////module M {
+////module /*2*/M {
//// var x = 10;
////}
////
-////var M = {
+////var /*3*/M = {
//// foo: 10,
//// bar: 20
////}
////
-////var v: M.I;
+////var v: /*4*/M./*5*/I;
////
-////var x = M;
+////var x = /*6*/M;
var c = classification;
verify.semanticClassificationsAre(
- c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"), c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"));
+ c.moduleName("M", test.marker("0").position),
+ c.interfaceName("I", test.marker("1").position),
+ c.moduleName("M", test.marker("2").position),
+ c.moduleName("M", test.marker("4").position),
+ c.interfaceName("I", test.marker("5").position),
+ c.moduleName("M", test.marker("6").position));
diff --git a/tests/cases/fourslash/semanticClassificationModules.ts b/tests/cases/fourslash/semanticClassificationModules.ts
index fc75b3bba98..86c2819983a 100644
--- a/tests/cases/fourslash/semanticClassificationModules.ts
+++ b/tests/cases/fourslash/semanticClassificationModules.ts
@@ -1,13 +1,19 @@
///
-////module M {
+////module /*0*/M {
//// export var v;
-//// export interface I {
+//// export interface /*1*/I {
//// }
////}
////
-////var x: M.I = M.v;
-////var y = M;
+////var x: /*2*/M./*3*/I = /*4*/M.v;
+////var y = /*5*/M;
var c = classification;
-verify.semanticClassificationsAre(c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"), c.moduleName("M"));
\ No newline at end of file
+verify.semanticClassificationsAre(
+ c.moduleName("M", test.marker("0").position),
+ c.interfaceName("I", test.marker("1").position),
+ c.moduleName("M", test.marker("2").position),
+ c.interfaceName("I", test.marker("3").position),
+ c.moduleName("M", test.marker("4").position),
+ c.moduleName("M", test.marker("5").position));
\ No newline at end of file
diff --git a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts
index fb3717006fe..e7486c2c0cb 100644
--- a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts
+++ b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName1.ts
@@ -1,7 +1,7 @@
///
-////declare module M {
-//// interface I {
+////declare module /*0*/M {
+//// interface /*1*/I {
////
//// }
////}
@@ -9,4 +9,6 @@
////var M = { I: 10 };
var c = classification;
-verify.semanticClassificationsAre(c.moduleName("M"), c.interfaceName("I"));
\ No newline at end of file
+verify.semanticClassificationsAre(
+ c.moduleName("M", test.marker("0").position),
+ c.interfaceName("I", test.marker("1").position));
\ No newline at end of file
diff --git a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts
index 295af091e75..f90efd7518d 100644
--- a/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts
+++ b/tests/cases/fourslash/semanticClassificationUninstantiatedModuleWithVariableOfSameName2.ts
@@ -1,19 +1,22 @@
///
-////module M {
-//// export interface I {
+////module /*0*/M {
+//// export interface /*1*/I {
//// }
////}
////
-////var M = {
+////var /*2*/M = {
//// foo: 10,
//// bar: 20
////}
////
-////var v: M.I;
+////var v: /*3*/M./*4*/I;
////
-////var x = M;
+////var x = /*5*/M;
var c = classification;
verify.semanticClassificationsAre(
- c.moduleName("M"), c.interfaceName("I"), c.moduleName("M"), c.interfaceName("I"));
+ c.moduleName("M", test.marker("0").position),
+ c.interfaceName("I", test.marker("1").position),
+ c.moduleName("M", test.marker("3").position),
+ c.interfaceName("I", test.marker("4").position));
diff --git a/tests/cases/fourslash/syntacticClassifications1.ts b/tests/cases/fourslash/syntacticClassifications1.ts
index e70a4b672ff..88f655683a3 100644
--- a/tests/cases/fourslash/syntacticClassifications1.ts
+++ b/tests/cases/fourslash/syntacticClassifications1.ts
@@ -18,7 +18,6 @@
//// }
//// }
-debugger;
var c = classification;
verify.syntacticClassificationsAre(
c.comment("// comment"),