Merge branch 'master' into printDiagnosticCodes

This commit is contained in:
Daniel Rosenwasser 2014-08-22 15:52:04 -07:00
commit 48c6bdb2aa
41 changed files with 1239 additions and 1029 deletions

View file

@ -188,14 +188,11 @@ module ts {
export var localizedDiagnosticMessages: Map<string> = undefined;
function getLocaleSpecificMessage(message: string) {
export function getLocaleSpecificMessage(message: string) {
if (ts.localizedDiagnosticMessages) {
message = localizedDiagnosticMessages[message];
}
/* Check to see that we got an actual value back. */
Debug.assert(message, "Diagnostic message does not exist in locale map.");
return message;
}

View file

@ -111,7 +111,7 @@ module ts {
Import_declarations_in_an_internal_module_cannot_reference_an_external_module: { code: 1147, category: DiagnosticCategory.Error, key: "Import declarations in an internal module cannot reference an external module." },
Cannot_compile_external_modules_unless_the_module_flag_is_provided: { code: 1148, category: DiagnosticCategory.Error, key: "Cannot compile external modules unless the '--module' flag is provided." },
Filename_0_differs_from_already_included_filename_1_only_in_casing: { code: 1149, category: DiagnosticCategory.Error, key: "Filename '{0}' differs from already included filename '{1}' only in casing" },
new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 2068, category: DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array<T>()' instead." },
new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: { code: 1150, category: DiagnosticCategory.Error, key: "'new T[]' cannot be used to create an array. Use 'new Array<T>()' instead." },
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
@ -389,5 +389,6 @@ module ts {
Object_literal_s_property_0_implicitly_has_an_1_type: { code: 7018, category: DiagnosticCategory.Error, key: "Object literal's property '{0}' implicitly has an '{1}' type." },
Rest_parameter_0_implicitly_has_an_any_type: { code: 7019, category: DiagnosticCategory.Error, key: "Rest parameter '{0}' implicitly has an 'any[]' type." },
Call_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: { code: 7020, category: DiagnosticCategory.Error, key: "Call signature, which lacks return-type annotation, implicitly has an 'any' return type." },
You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." },
};
}

View file

@ -1355,7 +1355,6 @@
"category": "Error",
"code": 5039
},
"Concatenate and emit output to single file.": {
"category": "Message",
"code": 6001
@ -1552,5 +1551,9 @@
"Call signature, which lacks return-type annotation, implicitly has an 'any' return type.": {
"category": "Error",
"code": 7020
},
"You cannot rename this element.": {
"category": "Error",
"code": 8000
}
}

View file

@ -9,7 +9,7 @@ module ts {
export function getNodeConstructor(kind: SyntaxKind): new () => Node {
return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind));
}
function createRootNode(kind: SyntaxKind, pos: number, end: number, flags: NodeFlags): Node {
var node = new (getNodeConstructor(kind))();
node.pos = pos;
@ -443,7 +443,7 @@ module ts {
nodeIsNestedInLabel(label: Identifier, requireIterationStatement: boolean, stopAtFunctionBoundary: boolean): ControlBlockContext;
}
export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, version: number = 0, isOpen: boolean = false): SourceFile {
export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, version: string, isOpen: boolean = false): SourceFile {
var file: SourceFile;
var scanner: Scanner;
var token: SyntaxKind;

View file

@ -147,7 +147,7 @@ module ts {
}
text = "";
}
return text !== undefined ? createSourceFile(filename, text, languageVersion) : undefined;
return text !== undefined ? createSourceFile(filename, text, languageVersion, /*version:*/ "0") : undefined;
}
function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) {

View file

@ -535,7 +535,7 @@ module ts {
identifierCount: number;
symbolCount: number;
isOpen: boolean;
version: number;
version: string;
languageVersion: ScriptTarget;
}

View file

@ -183,19 +183,40 @@ class CompilerBaselineRunner extends RunnerBase {
// if the .d.ts is non-empty, confirm it compiles correctly as well
if (options.declaration && result.errors.length === 0 && result.declFilesCode.length > 0) {
function getDtsFile(file: { unitName: string; content: string }) {
function addDtsFile(file: { unitName: string; content: string }, dtsFiles: { unitName: string; content: string }[]) {
if (Harness.Compiler.isDTS(file.unitName)) {
return file;
} else {
var declFile = ts.forEach(result.declFilesCode,
declFile => declFile.fileName === (file.unitName.substr(0, file.unitName.length - ".ts".length) + ".d.ts")
dtsFiles.push(file);
}
else {
var declFile = findResultCodeFile(file.unitName);
// Look if there is --out file corresponding to this ts file
if (!declFile && options.out) {
declFile = findResultCodeFile(options.out);
if (!declFile || findUnit(declFile.fileName, declToBeCompiled) ||
findUnit(declFile.fileName, declOtherFiles)) {
return;
}
}
if (declFile) {
dtsFiles.push({ unitName: declFile.fileName, content: declFile.code });
return;
}
}
function findResultCodeFile(fileName: string) {
return ts.forEach(result.declFilesCode,
declFile => declFile.fileName === (fileName.substr(0, fileName.length - ".ts".length) + ".d.ts")
? declFile : undefined);
return { unitName: declFile.fileName, content: declFile.code };
}
function findUnit(fileName: string, units: { unitName: string; content: string }[]) {
return ts.forEach(units, unit => unit.unitName === fileName ? unit : undefined);
}
}
ts.forEach(toBeCompiled, file => { declToBeCompiled.push(getDtsFile(file)); });
ts.forEach(otherFiles, file => { declOtherFiles.push(getDtsFile(file)); });
ts.forEach(toBeCompiled, file => addDtsFile(file, declToBeCompiled));
ts.forEach(otherFiles, file => addDtsFile(file, declOtherFiles));
harnessCompiler.compileFiles(declToBeCompiled, declOtherFiles, function (compileResult) {
declResult = compileResult;
}, function (settings) {

View file

@ -732,22 +732,22 @@ module FourSlash {
this.taoInvalidReason = 'verifyCurrentSignatureHelpIs NYI';
var help = this.getActiveSignatureHelp();
assert.equal(help.signatureInfo, expected);
assert.equal(help.prefix + help.parameters.map(p => p.display).join(help.separator) + help.suffix, expected);
}
public verifyCurrentParameterIsVariable(isVariable: boolean) {
this.taoInvalidReason = 'verifyCurrentParameterIsVariable NYI';
var activeParameter = this.getActiveParameter();
assert.isNotNull(activeParameter.parameter);
assert.equal(isVariable, activeParameter.parameter.isVariable);
var signature = this.getActiveSignatureHelp();
assert.isNotNull(signature);
assert.equal(isVariable, signature.isVariadic);
}
public verifyCurrentParameterHelpName(name: string) {
this.taoInvalidReason = 'verifyCurrentParameterHelpName NYI';
var activeParameter = this.getActiveParameter();
var activeParameterName = activeParameter.parameter ? activeParameter.parameter.name : activeParameter.typeParameter.name;
var activeParameterName = activeParameter.name;
assert.equal(activeParameterName, name);
}
@ -756,16 +756,14 @@ module FourSlash {
var activeSignature = this.getActiveSignatureHelp();
var activeParameter = this.getActiveParameter();
var activeParameterMinChar = activeParameter.parameter ? activeParameter.parameter.minChar : activeParameter.typeParameter.minChar;
var activeParameterLimChar = activeParameter.parameter ? activeParameter.parameter.limChar : activeParameter.typeParameter.limChar;
assert.equal(activeSignature.signatureInfo.substring(activeParameterMinChar, activeParameterLimChar), parameter);
assert.equal(activeParameter.display, parameter);
}
public verifyCurrentParameterHelpDocComment(docComment: string) {
this.taoInvalidReason = 'verifyCurrentParameterHelpDocComment NYI';
var activeParameter = this.getActiveParameter();
var activeParameterDocComment = activeParameter.parameter ? activeParameter.parameter.docComment : activeParameter.typeParameter.docComment;
var activeParameterDocComment = activeParameter.documentation;
assert.equal(activeParameterDocComment, docComment);
}
@ -778,13 +776,13 @@ module FourSlash {
public verifyCurrentSignatureHelpTypeParameterCount(expectedCount: number) {
this.taoInvalidReason = 'verifyCurrentSignatureHelpTypeParameterCount NYI';
assert.equal(this.getActiveSignatureHelp().typeParameters.length, expectedCount);
// assert.equal(this.getActiveSignatureHelp().typeParameters.length, expectedCount);
}
public verifyCurrentSignatureHelpDocComment(docComment: string) {
this.taoInvalidReason = 'verifyCurrentSignatureHelpDocComment NYI';
var actualDocComment = this.getActiveSignatureHelp().docComment;
var actualDocComment = this.getActiveSignatureHelp().documentation;
assert.equal(actualDocComment, docComment);
}
@ -792,15 +790,15 @@ module FourSlash {
this.scenarioActions.push('<InvokeSignatureHelp />');
this.scenarioActions.push('<VerifySignatureHelpOverloadCountEquals Count="' + expected + '" />');
var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition);
var actual = help && help.formal ? help.formal.length : 0;
var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
var actual = help && help.items ? help.items.length : 0;
assert.equal(actual, expected);
}
public verifySignatureHelpPresent(shouldBePresent = true) {
this.taoInvalidReason = 'verifySignatureHelpPresent NYI';
var actual = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition);
var actual = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
if (shouldBePresent) {
if (!actual) {
throw new Error("Expected signature help to be present, but it wasn't");
@ -812,45 +810,32 @@ module FourSlash {
}
}
private getFormalParameter() {
var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition);
return help.formal;
}
//private getFormalParameter() {
// var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
// return help.formal;
//}
private getActiveSignatureHelp() {
var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition);
var activeFormal = help.activeFormal;
var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
// If the signature hasn't been narrowed down yet (e.g. no parameters have yet been entered),
// 'activeFormal' will be -1 (even if there is only 1 signature). Signature help will show the
// first signature in the signature group, so go with that
if (activeFormal === -1) {
activeFormal = 0;
}
var index = help.selectedItemIndex < 0 ? 0 : help.selectedItemIndex;
return help.formal[activeFormal];
return help.items[index];
}
private getActiveParameter(): { parameter: ts.FormalParameterInfo; typeParameter: ts.FormalTypeParameterInfo; } {
private getActiveParameter(): ts.SignatureHelpParameter {
var currentSig = this.getActiveSignatureHelp();
var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition);
var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
var item = help.items[help.selectedItemIndex];
var state = this.languageService.getSignatureHelpCurrentArgumentState(this.activeFile.fileName, this.currentCaretPosition, help.applicableSpan.start());
// Same logic as in getActiveSignatureHelp - this value might be -1 until a parameter value actually gets typed
var currentParam = help.actual.currentParameter;
if (currentParam === -1) currentParam = 0;
if (help.actual.currentParameterIsTypeParameter) {
return {
parameter: null,
typeParameter: currentSig.typeParameters[currentParam]
};
}
else {
return {
parameter: currentSig.parameters[currentParam],
typeParameter: null
};
}
var currentParam = state === null ? 0 : state.argumentIndex;
return item.parameters[currentParam];
}
public getBreakpointStatementLocation(pos: number) {
@ -859,7 +844,7 @@ module FourSlash {
var spanInfo = this.languageService.getBreakpointStatementAtPosition(this.activeFile.fileName, pos);
var resultString = "\n**Pos: " + pos + " SpanInfo: " + JSON.stringify(spanInfo) + "\n** Statement: ";
if (spanInfo !== null) {
resultString = resultString + this.activeFile.content.substr(spanInfo.minChar, spanInfo.limChar - spanInfo.minChar);
resultString = resultString + this.activeFile.content.substr(spanInfo.start(), spanInfo.length());
}
return resultString;
}
@ -890,7 +875,7 @@ module FourSlash {
}
public printCurrentParameterHelp() {
var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition);
var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
Harness.IO.log(JSON.stringify(help));
}
@ -1071,7 +1056,7 @@ module FourSlash {
if (ch === '(' || ch === ',') {
/* Signature help*/
this.languageService.getSignatureAtPosition(this.activeFile.fileName, offset);
this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset);
} else if (prevChar === ' ' && /A-Za-z_/.test(ch)) {
/* Completions */
this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset, false);
@ -1111,7 +1096,7 @@ module FourSlash {
// Handle formatting
if (this.enableFormatting) {
var edits = this.languageService.getFormattingEditsOnPaste(this.activeFile.fileName, start, offset, this.formatCodeOptions);
var edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeOptions);
offset += this.applyEdits(this.activeFile.fileName, edits, true);
this.editCheckpoint(this.activeFile.fileName);
}
@ -1175,18 +1160,18 @@ module FourSlash {
};
}
private applyEdits(fileName: string, edits: ts.TextEdit[], isFormattingEdit = false): number {
private applyEdits(fileName: string, edits: ts.TextChange[], isFormattingEdit = false): number {
// We get back a set of edits, but langSvc.editScript only accepts one at a time. Use this to keep track
// of the incremental offest from each edit to the next. Assumption is that these edit ranges don't overlap
var runningOffset = 0;
edits = edits.sort((a, b) => a.minChar - b.minChar);
edits = edits.sort((a, b) => a.span.start() - b.span.start());
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
var snapshot = this.languageServiceShimHost.getScriptSnapshot(fileName);
var oldContent = snapshot.getText(0, snapshot.getLength());
for (var j = 0; j < edits.length; j++) {
this.languageServiceShimHost.editScript(fileName, edits[j].minChar + runningOffset, edits[j].limChar + runningOffset, edits[j].text);
this.updateMarkersForEdit(fileName, edits[j].minChar + runningOffset, edits[j].limChar + runningOffset, edits[j].text);
var change = (edits[j].minChar - edits[j].limChar) + edits[j].text.length;
this.languageServiceShimHost.editScript(fileName, edits[j].span.start() + runningOffset, edits[j].span.end() + runningOffset, edits[j].newText);
this.updateMarkersForEdit(fileName, edits[j].span.start() + runningOffset, edits[j].span.end() + runningOffset, edits[j].newText);
var change = (edits[j].span.start() - edits[j].span.end()) + edits[j].newText.length;
runningOffset += change;
// TODO: Consider doing this at least some of the time for higher fidelity. Currently causes a failure (bug 707150)
// this.languageService.getScriptLexicalStructure(fileName);
@ -1206,7 +1191,7 @@ module FourSlash {
public formatDocument() {
this.scenarioActions.push('<FormatDocument />');
var edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, 0, this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getLength(), this.formatCodeOptions);
var edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, this.formatCodeOptions);
this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, true);
this.fixCaretPosition();
}
@ -1263,7 +1248,7 @@ module FourSlash {
var definition = definitions[definitionIndex];
this.openFile(definition.fileName);
this.currentCaretPosition = definition.minChar;
this.currentCaretPosition = definition.textSpan.start();
}
public verifyDefinitionLocationExists(negative: boolean) {
@ -1369,7 +1354,7 @@ module FourSlash {
'\t Actual: null');
}
var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(span.minChar, span.limChar);
var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(span.start(), span.end());
if (actual !== text) {
throw new Error('verifyCurrentNameOrDottedNameSpanText\n' +
'\tExpected: "' + text + '"\n' +
@ -1381,7 +1366,7 @@ module FourSlash {
var spanInfo = this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, pos, pos);
var resultString = "\n**Pos: " + pos + " SpanInfo: " + JSON.stringify(spanInfo) + "\n** Statement: ";
if (spanInfo !== null) {
resultString = resultString + this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(spanInfo.minChar, spanInfo.limChar);
resultString = resultString + this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(spanInfo.start(), spanInfo.end());
}
return resultString;
}
@ -1410,7 +1395,7 @@ module FourSlash {
public verifyOutliningSpans(spans: TextSpan[]) {
this.taoInvalidReason = 'verifyOutliningSpans NYI';
var actual = this.languageService.getOutliningRegions(this.activeFile.fileName);
var actual = this.languageService.getOutliningSpans(this.activeFile.fileName);
if (actual.length !== spans.length) {
throw new Error('verifyOutliningSpans failed - expected total spans to be ' + spans.length + ', but was ' + actual.length);
@ -1425,6 +1410,25 @@ module FourSlash {
}
}
public verifyTodoComments(descriptors: string[], spans: TextSpan[]) {
var actual = this.languageService.getTodoComments(this.activeFile.fileName,
descriptors.map(d => new ts.TodoCommentDescriptor(d, 0)));
if (actual.length !== spans.length) {
throw new Error('verifyTodoComments failed - expected total spans to be ' + spans.length + ', but was ' + actual.length);
}
for (var i = 0; i < spans.length; i++) {
var expectedSpan = spans[i];
var actualComment = actual[i];
var actualCommentSpan = new TypeScript.TextSpan(actualComment.position, actualComment.message.length);
if (expectedSpan.start !== actualCommentSpan.start() || expectedSpan.end !== actualCommentSpan.end()) {
throw new Error('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start() + ',' + actualCommentSpan.end() + ')');
}
}
}
public verifyMatchingBracePosition(bracePosition: number, expectedMatchPosition: number) {
this.taoInvalidReason = 'verifyMatchingBracePosition NYI';
@ -1584,70 +1588,61 @@ module FourSlash {
public verifyGetScriptLexicalStructureListCount(expected: number) {
this.taoInvalidReason = 'verifyNavigationItemsListContains impossible';
var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName);
var actual = (items && items.length) || 0;
var items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
var actual = this.getNavigationBarItemsCount(items);
if (expected != actual) {
throw new Error('verifyGetScriptLexicalStructureListCount failed - found: ' + actual + ' navigation items, expected: ' + expected + '.');
}
}
private getNavigationBarItemsCount(items: ts.NavigationBarItem[]) {
var result = 0;
if (items) {
for (var i = 0, n = items.length; i < n; i++) {
result++;
result += this.getNavigationBarItemsCount(items[i].childItems);
}
}
return result;
}
public verifGetScriptLexicalStructureListContains(
name: string,
kind: string,
fileName?: string,
parentName?: string,
isAdditionalSpan?: boolean,
markerPosition?: number) {
this.taoInvalidReason = 'verifGetScriptLexicalStructureListContains impossible';
var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName);
var items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
if (!items || items.length === 0) {
throw new Error('verifyGetScriptLexicalStructureListContains failed - found 0 navigation items, expected at least one.');
}
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item && item.name === name && item.kind === kind &&
(fileName === undefined || item.fileName === fileName) &&
(parentName === undefined || item.containerName === parentName)) {
if (markerPosition !== undefined || isAdditionalSpan !== undefined) {
if (isAdditionalSpan) {
if (item.additionalSpans &&
item.additionalSpans.some(span => span.minChar <= markerPosition && markerPosition <= span.limChar)) {
// marker is in an additional span for this item.
return;
}
else {
throw new Error(
'verifGetScriptLexicalStructureListContains failed - ' +
'no additional span was found that contained the position: ' + JSON.stringify(markerPosition) +
' in the item: ' + JSON.stringify(item));
}
}
else if (!isAdditionalSpan) {
if (item.minChar <= markerPosition &&
markerPosition <= item.minChar) {
// marker is in span normal item's span
return;
}
else {
throw new Error(
'verifGetScriptLexicalStructureListContains failed - ' +
'marker was positioned: ' + JSON.stringify(markerPosition) +
' which is not in the item: ' + JSON.stringify(item));
}
}
if (this.navigationBarItemsContains(items, name, kind)) {
return;
}
var missingItem = { name: name, kind: kind };
throw new Error('verifyGetScriptLexicalStructureListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')');
}
private navigationBarItemsContains(items: ts.NavigationBarItem[], name: string, kind: string) {
if (items) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item && item.text === name && item.kind === kind) {
return true;
}
else {
return;
if (this.navigationBarItemsContains(item.childItems, name, kind)) {
return true;
}
}
}
var missingItem = { name: name, kind: kind, fileName: fileName, parentName: parentName };
throw new Error('verifyGetScriptLexicalStructureListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')');
return false;
}
public printNavigationItems(searchValue: string) {
@ -1663,14 +1658,14 @@ module FourSlash {
}
public printScriptLexicalStructureItems() {
var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName);
var items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
var length = items && items.length;
Harness.IO.log('NavigationItems list (' + length + ' items)');
for (var i = 0; i < length; i++) {
var item = items[i];
Harness.IO.log('name: ' + item.name + ', kind: ' + item.kind + ', parentName: ' + item.containerName + ', fileName: ' + item.fileName);
Harness.IO.log('name: ' + item.text + ', kind: ' + item.kind);
}
}
@ -1689,7 +1684,7 @@ module FourSlash {
for (var i = 0; i < occurances.length; i++) {
var occurance = occurances[i];
if (occurance && occurance.fileName === fileName && occurance.minChar === start && occurance.limChar === end) {
if (occurance && occurance.fileName === fileName && occurance.textSpan.start() === start && occurance.textSpan.end() === end) {
if (typeof isWriteAccess !== "undefined" && occurance.isWriteAccess !== isWriteAccess) {
throw new Error('verifyOccurancesAtPositionListContains failed - item isWriteAccess value doe not match, actual: ' + occurance.isWriteAccess + ', expected: ' + isWriteAccess + '.');
}
@ -1895,11 +1890,11 @@ module FourSlash {
var result = '';
var fourslashFilename = 'fourslash.ts';
var tsFn = 'tests/cases/fourslash/' + fourslashFilename;
fourslashSourceFile = fourslashSourceFile || ts.createSourceFile(tsFn, Harness.IO.readFile(tsFn), ts.ScriptTarget.ES5, /*version*/ 0, /*isOpen*/ false);
fourslashSourceFile = fourslashSourceFile || ts.createSourceFile(tsFn, Harness.IO.readFile(tsFn), ts.ScriptTarget.ES5, /*version*/ "0", /*isOpen*/ false);
var files: { [filename: string]: ts.SourceFile; } = {};
files[ts.getCanonicalFileName(fourslashFilename)] = fourslashSourceFile;
files[ts.getCanonicalFileName(fileName)] = ts.createSourceFile(fileName, content, ts.ScriptTarget.ES5, /*version*/ 0, /*isOpen*/ false);
files[ts.getCanonicalFileName(fileName)] = ts.createSourceFile(fileName, content, ts.ScriptTarget.ES5, /*version*/ "0", /*isOpen*/ false);
files[ts.getCanonicalFileName(Harness.Compiler.defaultLibFileName)] = Harness.Compiler.defaultLibSourceFile;
var host = Harness.Compiler.createCompilerHost(files, (fn, contents) => result = contents);

View file

@ -532,7 +532,7 @@ module Harness {
}
export var defaultLibFileName = 'lib.d.ts';
export var defaultLibSourceFile = ts.createSourceFile(defaultLibFileName, IO.readFile(libFolder + 'lib.core.d.ts'), /*languageVersion*/ ts.ScriptTarget.ES5);
export var defaultLibSourceFile = ts.createSourceFile(defaultLibFileName, IO.readFile(libFolder + 'lib.core.d.ts'), /*languageVersion*/ ts.ScriptTarget.ES5, /*version:*/ "0");
export function createCompilerHost(filemap: { [filename: string]: ts.SourceFile; }, writeFile: (fn: string, contents: string, writeByteOrderMark:boolean) => void): ts.CompilerHost {
return {
@ -729,7 +729,7 @@ module Harness {
var filemap: { [name: string]: ts.SourceFile; } = {};
var register = (file: { unitName: string; content: string; }) => {
var filename = Path.switchToForwardSlashes(file.unitName);
filemap[ts.getCanonicalFileName(filename)] = ts.createSourceFile(filename, file.content, options.target);
filemap[ts.getCanonicalFileName(filename)] = ts.createSourceFile(filename, file.content, options.target, /*version:*/ "0");
};
inputFiles.forEach(register);
otherFiles.forEach(register);

View file

@ -80,8 +80,9 @@ module Harness.LanguageService {
return JSON.stringify(this.lineMap.lineStarts());
}
public getTextChangeRangeSinceVersion(scriptVersion: number): string {
var range = this.scriptInfo.getTextChangeRangeBetweenVersions(scriptVersion, this.version);
public getChangeRange(oldScript: ts.ScriptSnapshotShim): string {
var oldShim = <ScriptSnapshotShim>oldScript;
var range = this.scriptInfo.getTextChangeRangeBetweenVersions(oldShim.version, this.version);
if (range === null) {
return null;
}
@ -101,50 +102,14 @@ module Harness.LanguageService {
}
}
class ScriptSnapshotShimAdapter implements TypeScript.IScriptSnapshot {
private lineStartPositions: number[] = null;
constructor(private scriptSnapshotShim: ts.ScriptSnapshotShim) {}
getText(start: number, end: number): string {return this.scriptSnapshotShim.getText(start, end);}
getLength(): number {return this.scriptSnapshotShim.getLength();}
getLineStartPositions(): number[] { return JSON.parse(this.scriptSnapshotShim.getLineStartPositions()); }
getTextChangeRangeSinceVersion(scriptVersion: number): TypeScript.TextChangeRange {
var encoded = this.scriptSnapshotShim.getTextChangeRangeSinceVersion(scriptVersion);
if (encoded == null) {
return null;
}
var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded);
return new TypeScript.TextChangeRange(
new TypeScript.TextSpan(decoded.span.start, decoded.span.length), decoded.newLength);
}
}
class LanguageServiceShimHostAdapter implements ts.LanguageServiceHost {
constructor(private shimHost: ts.LanguageServiceShimHost) { }
information(): boolean { return this.shimHost.information(); }
debug(): boolean { return this.shimHost.debug(); }
warning(): boolean { return this.shimHost.warning();}
error(): boolean { return this.shimHost.error(); }
fatal(): boolean { return this.shimHost.fatal(); }
log(s: string): void { this.shimHost.log(s); }
getCompilationSettings(): ts.CompilerOptions { return JSON.parse(this.shimHost.getCompilationSettings()); }
getScriptFileNames(): string[] { return JSON.parse(this.shimHost.getScriptFileNames());}
getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot { return new ScriptSnapshotShimAdapter(this.shimHost.getScriptSnapshot(fileName));}
getScriptVersion(fileName: string): number { return this.shimHost.getScriptVersion(fileName);}
getScriptIsOpen(fileName: string): boolean { return this.shimHost.getScriptIsOpen(fileName); }
getLocalizedDiagnosticMessages(): any { JSON.parse(this.shimHost.getLocalizedDiagnosticMessages());}
getCancellationToken(): ts.CancellationToken { return this.shimHost.getCancellationToken(); }
}
export class NonCachingDocumentRegistry implements ts.DocumentRegistry {
public static Instance: ts.DocumentRegistry = new NonCachingDocumentRegistry();
public acquireDocument(
fileName: string,
compilationSettings: ts.CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
version: number,
version: string,
isOpen: boolean): ts.SourceFile {
return ts.createSourceFile(fileName, scriptSnapshot.getText(0, scriptSnapshot.getLength()), compilationSettings.target, version, isOpen);
}
@ -154,7 +119,7 @@ module Harness.LanguageService {
fileName: string,
compilationSettings: ts.CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
version: number,
version: string,
isOpen: boolean,
textChangeRange: TypeScript.TextChangeRange
): ts.SourceFile {
@ -251,8 +216,8 @@ module Harness.LanguageService {
return new ScriptSnapshotShim(this.getScriptInfo(fileName));
}
public getScriptVersion(fileName: string): number {
return this.getScriptInfo(fileName).version;
public getScriptVersion(fileName: string): string {
return this.getScriptInfo(fileName).version.toString();
}
public getScriptIsOpen(fileName: string): boolean {
@ -316,7 +281,7 @@ module Harness.LanguageService {
}
/** Verify that applying edits to sourceFileName result in the content of the file baselineFileName */
public checkEdits(sourceFileName: string, baselineFileName: string, edits: ts.TextEdit[]) {
public checkEdits(sourceFileName: string, baselineFileName: string, edits: ts.TextChange[]) {
var script = Harness.IO.readFile(sourceFileName);
var formattedScript = this.applyEdits(script, edits);
var baseline = Harness.IO.readFile(baselineFileName);
@ -345,26 +310,26 @@ module Harness.LanguageService {
/** Apply an array of text edits to a string, and return the resulting string. */
public applyEdits(content: string, edits: ts.TextEdit[]): string {
public applyEdits(content: string, edits: ts.TextChange[]): string {
var result = content;
edits = this.normalizeEdits(edits);
for (var i = edits.length - 1; i >= 0; i--) {
var edit = edits[i];
var prefix = result.substring(0, edit.minChar);
var middle = edit.text;
var suffix = result.substring(edit.limChar);
var prefix = result.substring(0, edit.span.start());
var middle = edit.newText;
var suffix = result.substring(edit.span.end());
result = prefix + middle + suffix;
}
return result;
}
/** Normalize an array of edits by removing overlapping entries and sorting entries on the minChar position. */
private normalizeEdits(edits: ts.TextEdit[]): ts.TextEdit[] {
var result: ts.TextEdit[] = [];
private normalizeEdits(edits: ts.TextChange[]): ts.TextChange[] {
var result: ts.TextChange[] = [];
function mapEdits(edits: ts.TextEdit[]): { edit: ts.TextEdit; index: number; }[] {
var result: { edit: ts.TextEdit; index: number; }[] = [];
function mapEdits(edits: ts.TextChange[]): { edit: ts.TextChange; index: number; }[] {
var result: { edit: ts.TextChange; index: number; }[] = [];
for (var i = 0; i < edits.length; i++) {
result.push({ edit: edits[i], index: i });
}
@ -372,7 +337,7 @@ module Harness.LanguageService {
}
var temp = mapEdits(edits).sort(function (a, b) {
var result = a.edit.minChar - b.edit.limChar;
var result = a.edit.span.start() - b.edit.span.start();
if (result === 0)
result = a.index - b.index;
return result;
@ -391,7 +356,7 @@ module Harness.LanguageService {
}
var nextEdit = temp[next].edit;
var gap = nextEdit.minChar - currentEdit.limChar;
var gap = nextEdit.span.start() - currentEdit.span.end();
// non-overlapping edits
if (gap >= 0) {
@ -400,10 +365,10 @@ module Harness.LanguageService {
next++;
continue;
}
// overlapping edits: for now, we only support ignoring an next edit
// entirely contained in the current edit.
if (currentEdit.minChar >= nextEdit.limChar) {
if (currentEdit.span.end() >= nextEdit.span.end()) {
next++;
continue;
}

View file

@ -174,7 +174,7 @@ class ProjectRunner extends RunnerBase {
else {
var text = getSourceFileText(filename);
if (text !== undefined) {
sourceFile = ts.createSourceFile(filename, text, languageVersion);
sourceFile = ts.createSourceFile(filename, text, languageVersion, /*version:*/ "0");
}
}

View file

@ -24,93 +24,50 @@ module TypeScript.Services {
public static getMatchSpans(syntaxTree: TypeScript.SyntaxTree, position: number): TypeScript.TextSpan[] {
var result: TypeScript.TextSpan[] = [];
var currentToken = findToken(syntaxTree.sourceUnit(), position);
var token = findToken(syntaxTree.sourceUnit(), position);
BraceMatcher.getMatchingCloseBrace(currentToken, position, result);
BraceMatcher.getMatchingOpenBrace(currentToken, position, result);
if (start(token) === position) {
var matchKind = BraceMatcher.getMatchingTokenKind(token);
if (matchKind !== null) {
var parentElement = token.parent;
for (var i = 0, n = childCount(parentElement); i < n; i++) {
var current = childAt(parentElement, i);
if (current !== null && fullWidth(current) > 0) {
if (current.kind() === matchKind) {
var range1 = new TypeScript.TextSpan(start(token), width(token));
var range2 = new TypeScript.TextSpan(start(current), width(current));
if (range1.start() < range2.start()) {
result.push(range1, range2);
}
else {
result.push(range2, range1);
}
break;
}
}
}
}
}
return result;
}
private static getMatchingCloseBrace(currentToken: TypeScript.ISyntaxToken, position: number, result: TypeScript.TextSpan[]) {
if (start(currentToken) === position) {
var closingBraceKind = BraceMatcher.getMatchingCloseBraceTokenKind(currentToken);
if (closingBraceKind !== null) {
var parentElement = currentToken.parent;
var currentPosition = fullStart(currentToken.parent);
for (var i = 0, n = childCount(parentElement); i < n; i++) {
var element = childAt(parentElement, i);
if (element !== null && fullWidth(element) > 0) {
if (element.kind() === closingBraceKind) {
var range1 = new TypeScript.TextSpan(position, width(currentToken));
var range2 = new TypeScript.TextSpan(currentPosition + leadingTriviaWidth(element), width(element));
result.push(range1, range2);
break;
}
currentPosition += fullWidth(element);
}
}
}
}
}
private static getMatchingOpenBrace(currentToken: TypeScript.ISyntaxToken, position: number, result: TypeScript.TextSpan[]) {
// Check if the current token to the left is a close brace
if (currentToken.fullStart() === position) {
currentToken = previousToken(currentToken);
private static getMatchingTokenKind(token: TypeScript.ISyntaxToken): TypeScript.SyntaxKind {
switch (token.kind()) {
case TypeScript.SyntaxKind.OpenBraceToken: return TypeScript.SyntaxKind.CloseBraceToken
case TypeScript.SyntaxKind.OpenParenToken: return TypeScript.SyntaxKind.CloseParenToken;
case TypeScript.SyntaxKind.OpenBracketToken: return TypeScript.SyntaxKind.CloseBracketToken;
case TypeScript.SyntaxKind.LessThanToken: return TypeScript.SyntaxKind.GreaterThanToken;
case TypeScript.SyntaxKind.CloseBraceToken: return TypeScript.SyntaxKind.OpenBraceToken
case TypeScript.SyntaxKind.CloseParenToken: return TypeScript.SyntaxKind.OpenParenToken;
case TypeScript.SyntaxKind.CloseBracketToken: return TypeScript.SyntaxKind.OpenBracketToken;
case TypeScript.SyntaxKind.GreaterThanToken: return TypeScript.SyntaxKind.LessThanToken;
}
if (currentToken !== null && start(currentToken) === (position - 1)) {
var openBraceKind = BraceMatcher.getMatchingOpenBraceTokenKind(currentToken);
if (openBraceKind !== null) {
var parentElement = currentToken.parent;
var currentPosition = fullStart(currentToken.parent) + fullWidth(parentElement);
for (var i = childCount(parentElement) - 1 ; i >= 0; i--) {
var element = childAt(parentElement, i);
if (element !== null && fullWidth(element) > 0) {
if (element.kind() === openBraceKind) {
var range1 = new TypeScript.TextSpan(position - 1, width(currentToken));
var range2 = new TypeScript.TextSpan(currentPosition - lastToken(element).trailingTriviaWidth() - width(element), width(element));
result.push(range1, range2);
break;
}
currentPosition -= fullWidth(element);
}
}
}
}
}
private static getMatchingCloseBraceTokenKind(positionedElement: TypeScript.ISyntaxElement): TypeScript.SyntaxKind {
var element = positionedElement !== null && positionedElement;
switch (element.kind()) {
case TypeScript.SyntaxKind.OpenBraceToken:
return TypeScript.SyntaxKind.CloseBraceToken;
case TypeScript.SyntaxKind.OpenParenToken:
return TypeScript.SyntaxKind.CloseParenToken;
case TypeScript.SyntaxKind.OpenBracketToken:
return TypeScript.SyntaxKind.CloseBracketToken;
case TypeScript.SyntaxKind.LessThanToken:
return TypeScript.SyntaxUtilities.isAngleBracket(positionedElement) ? TypeScript.SyntaxKind.GreaterThanToken : null;
}
return null;
}
private static getMatchingOpenBraceTokenKind(positionedElement: TypeScript.ISyntaxElement): TypeScript.SyntaxKind {
var element = positionedElement !== null && positionedElement;
switch (element.kind()) {
case TypeScript.SyntaxKind.CloseBraceToken:
return TypeScript.SyntaxKind.OpenBraceToken
case TypeScript.SyntaxKind.CloseParenToken:
return TypeScript.SyntaxKind.OpenParenToken;
case TypeScript.SyntaxKind.CloseBracketToken:
return TypeScript.SyntaxKind.OpenBracketToken;
case TypeScript.SyntaxKind.GreaterThanToken:
return TypeScript.SyntaxUtilities.isAngleBracket(positionedElement) ? TypeScript.SyntaxKind.LessThanToken : null;
}
return null;
}
}
}
}

View file

@ -4,16 +4,13 @@
///<reference path='references.ts' />
module TypeScript.Services.Breakpoints {
function createBreakpointSpanInfo(parentElement: TypeScript.ISyntaxElement, ...childElements: TypeScript.ISyntaxElement[]): ts.SpanInfo {
function createBreakpointSpanInfo(parentElement: TypeScript.ISyntaxElement, ...childElements: TypeScript.ISyntaxElement[]): TextSpan {
if (!parentElement) {
return null;
}
if (childElements.length == 0) {
return {
minChar: TypeScript.start(parentElement),
limChar: TypeScript.end(parentElement)
};
return TextSpan.fromBounds(TypeScript.start(parentElement), TypeScript.end(parentElement));
}
var start: number;
@ -28,24 +25,18 @@ module TypeScript.Services.Breakpoints {
}
}
return {
minChar: start,
limChar: end
};
return TextSpan.fromBounds(start, end);
}
function createBreakpointSpanInfoWithLimChar(startElement: TypeScript.ISyntaxElement, limChar: number): ts.SpanInfo {
return {
minChar: start(startElement),
limChar: limChar
};
function createBreakpointSpanInfoWithLimChar(startElement: TypeScript.ISyntaxElement, limChar: number): TextSpan {
return TextSpan.fromBounds(start(startElement), limChar);
}
class BreakpointResolver {
constructor(private posLine: number, private lineMap: TypeScript.LineMap) {
}
private breakpointSpanOfToken(positionedToken: TypeScript.ISyntaxToken): ts.SpanInfo {
private breakpointSpanOfToken(positionedToken: TypeScript.ISyntaxToken): TextSpan {
switch (positionedToken.kind()) {
case TypeScript.SyntaxKind.OpenBraceToken:
return this.breakpointSpanOfOpenBrace(positionedToken);
@ -74,7 +65,7 @@ module TypeScript.Services.Breakpoints {
return this.breakpointSpanOfContainingNode(positionedToken);
}
private breakpointSpanOfOpenBrace(openBraceToken: TypeScript.ISyntaxToken): ts.SpanInfo {
private breakpointSpanOfOpenBrace(openBraceToken: TypeScript.ISyntaxToken): TextSpan {
var container = Syntax.containingNode(openBraceToken);
if (container) {
var originalContainer = container;
@ -168,7 +159,7 @@ module TypeScript.Services.Breakpoints {
return null;
}
private breakpointSpanOfCloseBrace(closeBraceToken: TypeScript.ISyntaxToken): ts.SpanInfo {
private breakpointSpanOfCloseBrace(closeBraceToken: TypeScript.ISyntaxToken): TextSpan {
var container = Syntax.containingNode(closeBraceToken);
if (container) {
var originalContainer = container;
@ -243,7 +234,7 @@ module TypeScript.Services.Breakpoints {
}
private breakpointSpanOfComma(commaToken: TypeScript.ISyntaxToken): ts.SpanInfo {
private breakpointSpanOfComma(commaToken: TypeScript.ISyntaxToken): TextSpan {
var commaParent = commaToken.parent;
if (isSeparatedList(commaParent)) {
var grandParent = commaParent.parent;
@ -271,7 +262,7 @@ module TypeScript.Services.Breakpoints {
return this.breakpointSpanOfContainingNode(commaToken);
}
private breakpointSpanOfCloseParen(closeParenToken: TypeScript.ISyntaxToken): ts.SpanInfo {
private breakpointSpanOfCloseParen(closeParenToken: TypeScript.ISyntaxToken): TextSpan {
var closeParenParent = closeParenToken.parent;
if (closeParenParent) {
switch (closeParenParent.kind()) {
@ -293,7 +284,7 @@ module TypeScript.Services.Breakpoints {
return blockSyntax.statements && blockSyntax.statements.length != 0;
}
private breakpointSpanOfFirstStatementInBlock(blockNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfFirstStatementInBlock(blockNode: TypeScript.ISyntaxNode): TextSpan {
if (!blockNode) {
return null;
}
@ -316,7 +307,7 @@ module TypeScript.Services.Breakpoints {
}
}
private breakpointSpanOfLastStatementInBlock(blockNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfLastStatementInBlock(blockNode: TypeScript.ISyntaxNode): TextSpan {
if (!blockNode) {
return null;
}
@ -339,7 +330,7 @@ module TypeScript.Services.Breakpoints {
}
}
private breakpointSpanOfFirstChildOfSyntaxList(positionedList: TypeScript.ISyntaxNodeOrToken[]): ts.SpanInfo {
private breakpointSpanOfFirstChildOfSyntaxList(positionedList: TypeScript.ISyntaxNodeOrToken[]): TextSpan {
if (!positionedList) {
return null;
}
@ -363,7 +354,7 @@ module TypeScript.Services.Breakpoints {
}
}
private breakpointSpanOfLastChildOfSyntaxList(positionedList: TypeScript.ISyntaxNodeOrToken[]): ts.SpanInfo {
private breakpointSpanOfLastChildOfSyntaxList(positionedList: TypeScript.ISyntaxNodeOrToken[]): TextSpan {
if (!positionedList) {
return null;
}
@ -385,7 +376,7 @@ module TypeScript.Services.Breakpoints {
}
}
private breakpointSpanOfNode(positionedNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfNode(positionedNode: ISyntaxNode): TextSpan {
var node = positionedNode;
switch (node.kind()) {
// Declarations with elements
@ -493,7 +484,7 @@ module TypeScript.Services.Breakpoints {
}
return false;
}
private isInitializerOfForStatement(expressionNode: TypeScript.ISyntaxNode): boolean {
if (!expressionNode) {
return false;
@ -552,12 +543,12 @@ module TypeScript.Services.Breakpoints {
return false;
}
private breakpointOfLeftOfCommaExpression(commaExpressionNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointOfLeftOfCommaExpression(commaExpressionNode: TypeScript.ISyntaxNode): TextSpan {
var commaExpression = <TypeScript.BinaryExpressionSyntax>commaExpressionNode;
return this.breakpointSpanOf(commaExpression.left);
}
private breakpointOfExpression(expressionNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointOfExpression(expressionNode: TypeScript.ISyntaxNode): TextSpan {
if (this.isInitializerOfForStatement(expressionNode) ||
this.isConditionOfForStatement(expressionNode) ||
this.isIncrememtorOfForStatement(expressionNode)) {
@ -582,7 +573,7 @@ module TypeScript.Services.Breakpoints {
return this.breakpointSpanOfContainingNode(expressionNode);
}
private breakpointSpanOfStatement(statementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfStatement(statementNode: TypeScript.ISyntaxNode): TextSpan {
var statement = statementNode;
if (statement.kind() == TypeScript.SyntaxKind.EmptyStatement) {
return null;
@ -722,7 +713,7 @@ module TypeScript.Services.Breakpoints {
return positionedNode && !TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(positionedNode);
}
private breakpointSpanOfDeclarationWithElements(positionedNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfDeclarationWithElements(positionedNode: TypeScript.ISyntaxNode): TextSpan {
if (!this.canHaveBreakpointInDeclaration(positionedNode)) {
return null;
}
@ -751,7 +742,7 @@ module TypeScript.Services.Breakpoints {
return !!varDeclaratorSyntax.equalsValueClause;
}
private breakpointSpanOfVariableDeclarator(varDeclaratorNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfVariableDeclarator(varDeclaratorNode: TypeScript.ISyntaxNode): TextSpan {
if (!this.canHaveBreakpointInVariableDeclarator(varDeclaratorNode)) {
return null;
}
@ -799,7 +790,7 @@ module TypeScript.Services.Breakpoints {
return false;
}
private breakpointSpanOfVariableDeclaration(varDeclarationNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfVariableDeclaration(varDeclarationNode: TypeScript.ISyntaxNode): TextSpan {
if (!this.canHaveBreakpointInDeclaration(varDeclarationNode)) {
return null;
}
@ -830,7 +821,7 @@ module TypeScript.Services.Breakpoints {
return this.canHaveBreakpointInVariableDeclaration(<TypeScript.ISyntaxNode>variableStatement.variableDeclaration);
}
private breakpointSpanOfVariableStatement(varStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfVariableStatement(varStatementNode: TypeScript.ISyntaxNode): TextSpan {
if (!this.canHaveBreakpointInVariableStatement(varStatementNode)) {
return null;
}
@ -842,7 +833,7 @@ module TypeScript.Services.Breakpoints {
return createBreakpointSpanInfoWithLimChar(varStatementNode, end(childAt(varDeclarators, 0)));
}
private breakpointSpanOfParameter(parameterNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfParameter(parameterNode: TypeScript.ISyntaxNode): TextSpan {
if (parameterNode.parent.kind() === SyntaxKind.SimpleArrowFunctionExpression) {
return this.breakpointSpanOfNode(<ISyntaxNode>parameterNode.parent);
}
@ -860,7 +851,7 @@ module TypeScript.Services.Breakpoints {
}
}
private breakpointSpanOfMemberVariableDeclaration(memberVarDeclarationNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfMemberVariableDeclaration(memberVarDeclarationNode: TypeScript.ISyntaxNode): TextSpan {
if (TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(memberVarDeclarationNode)) {
return null;
}
@ -874,7 +865,7 @@ module TypeScript.Services.Breakpoints {
}
}
private breakpointSpanOfImportDeclaration(importDeclarationNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfImportDeclaration(importDeclarationNode: TypeScript.ISyntaxNode): TextSpan {
if (TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(importDeclarationNode)) {
return null;
}
@ -883,7 +874,7 @@ module TypeScript.Services.Breakpoints {
return createBreakpointSpanInfo(importDeclarationNode, importSyntax.modifiers, importSyntax.importKeyword, importSyntax.identifier, importSyntax.equalsToken, importSyntax.moduleReference);
}
private breakpointSpanOfEnumDeclaration(enumDeclarationNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfEnumDeclaration(enumDeclarationNode: TypeScript.ISyntaxNode): TextSpan {
if (!this.canHaveBreakpointInDeclaration(enumDeclarationNode)) {
return null;
}
@ -891,7 +882,7 @@ module TypeScript.Services.Breakpoints {
return createBreakpointSpanInfo(enumDeclarationNode);
}
private breakpointSpanOfFirstEnumElement(enumDeclarationNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfFirstEnumElement(enumDeclarationNode: TypeScript.ISyntaxNode): TextSpan {
var enumDeclarationSyntax = <TypeScript.EnumDeclarationSyntax>enumDeclarationNode;
var enumElements = enumDeclarationSyntax.enumElements;
if (enumElements && childCount(enumElements)) {
@ -901,7 +892,7 @@ module TypeScript.Services.Breakpoints {
return null;
}
private breakpointSpanOfEnumElement(enumElementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfEnumElement(enumElementNode: TypeScript.ISyntaxNode): TextSpan {
if (TypeScript.SyntaxUtilities.isAmbientDeclarationSyntax(enumElementNode)) {
return null;
}
@ -909,45 +900,45 @@ module TypeScript.Services.Breakpoints {
return createBreakpointSpanInfo(enumElementNode);
}
private breakpointSpanOfIfStatement(ifStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfIfStatement(ifStatementNode: TypeScript.ISyntaxNode): TextSpan {
var ifStatement = <TypeScript.IfStatementSyntax>ifStatementNode;
return createBreakpointSpanInfo(ifStatementNode, ifStatement.ifKeyword, ifStatement.openParenToken, ifStatement.condition, ifStatement.closeParenToken);
}
private breakpointSpanOfElseClause(elseClauseNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfElseClause(elseClauseNode: TypeScript.ISyntaxNode): TextSpan {
var elseClause = <TypeScript.ElseClauseSyntax>elseClauseNode;
return this.breakpointSpanOf(elseClause.statement);
}
private breakpointSpanOfForInStatement(forInStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfForInStatement(forInStatementNode: TypeScript.ISyntaxNode): TextSpan {
var forInStatement = <TypeScript.ForInStatementSyntax>forInStatementNode;
return createBreakpointSpanInfo(forInStatementNode, forInStatement.forKeyword, forInStatement.openParenToken, forInStatement.variableDeclaration,
forInStatement.left, forInStatement.inKeyword, forInStatement.expression, forInStatement.closeParenToken);
}
private breakpointSpanOfForStatement(forStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfForStatement(forStatementNode: TypeScript.ISyntaxNode): TextSpan {
var forStatement = <TypeScript.ForStatementSyntax>forStatementNode;
return this.breakpointSpanOf(forStatement.variableDeclaration
? <TypeScript.ISyntaxElement>forStatement.variableDeclaration
: forStatement.initializer);
}
private breakpointSpanOfWhileStatement(whileStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfWhileStatement(whileStatementNode: TypeScript.ISyntaxNode): TextSpan {
var whileStatement = <TypeScript.WhileStatementSyntax>whileStatementNode;
return createBreakpointSpanInfo(whileStatementNode, whileStatement.whileKeyword, whileStatement.openParenToken, whileStatement.condition, whileStatement.closeParenToken);
}
private breakpointSpanOfDoStatement(doStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfDoStatement(doStatementNode: TypeScript.ISyntaxNode): TextSpan {
var doStatement = <TypeScript.DoStatementSyntax>doStatementNode;
return createBreakpointSpanInfo(doStatementNode, doStatement.whileKeyword, doStatement.openParenToken, doStatement.condition, doStatement.closeParenToken);
}
private breakpointSpanOfSwitchStatement(switchStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfSwitchStatement(switchStatementNode: TypeScript.ISyntaxNode): TextSpan {
var switchStatement = <TypeScript.SwitchStatementSyntax>switchStatementNode;
return createBreakpointSpanInfo(switchStatementNode, switchStatement.switchKeyword, switchStatement.openParenToken, switchStatement.expression, switchStatement.closeParenToken);
}
private breakpointSpanOfFirstStatementOfFirstCaseClause(switchStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfFirstStatementOfFirstCaseClause(switchStatementNode: TypeScript.ISyntaxNode): TextSpan {
var switchStatement = <TypeScript.SwitchStatementSyntax>switchStatementNode;
if (switchStatement.switchClauses && switchStatement.switchClauses.length == 0) {
return null;
@ -964,7 +955,7 @@ module TypeScript.Services.Breakpoints {
return this.breakpointSpanOfFirstChildOfSyntaxList(statements);
}
private breakpointSpanOfLastStatementOfLastCaseClause(switchStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfLastStatementOfLastCaseClause(switchStatementNode: TypeScript.ISyntaxNode): TextSpan {
var switchStatement = <TypeScript.SwitchStatementSyntax>switchStatementNode;
if (switchStatement.switchClauses && switchStatement.switchClauses.length == 0) {
return null;
@ -981,37 +972,37 @@ module TypeScript.Services.Breakpoints {
return this.breakpointSpanOfLastChildOfSyntaxList(statements);
}
private breakpointSpanOfCaseSwitchClause(caseClauseNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfCaseSwitchClause(caseClauseNode: TypeScript.ISyntaxNode): TextSpan {
var caseSwitchClause = <TypeScript.CaseSwitchClauseSyntax>caseClauseNode;
return this.breakpointSpanOfFirstChildOfSyntaxList(caseSwitchClause.statements);
}
private breakpointSpanOfDefaultSwitchClause(defaultSwithClauseNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfDefaultSwitchClause(defaultSwithClauseNode: TypeScript.ISyntaxNode): TextSpan {
var defaultSwitchClause = <TypeScript.DefaultSwitchClauseSyntax>defaultSwithClauseNode;
return this.breakpointSpanOfFirstChildOfSyntaxList(defaultSwitchClause.statements);
}
private breakpointSpanOfWithStatement(withStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfWithStatement(withStatementNode: TypeScript.ISyntaxNode): TextSpan {
var withStatement = <TypeScript.WithStatementSyntax>withStatementNode;
return this.breakpointSpanOf(withStatement.statement);
}
private breakpointSpanOfTryStatement(tryStatementNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfTryStatement(tryStatementNode: TypeScript.ISyntaxNode): TextSpan {
var tryStatement = <TypeScript.TryStatementSyntax>tryStatementNode;
return this.breakpointSpanOfFirstStatementInBlock(<TypeScript.ISyntaxNode>tryStatement.block);
}
private breakpointSpanOfCatchClause(catchClauseNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfCatchClause(catchClauseNode: TypeScript.ISyntaxNode): TextSpan {
var catchClause = <TypeScript.CatchClauseSyntax>catchClauseNode;
return createBreakpointSpanInfo(catchClauseNode, catchClause.catchKeyword, catchClause.openParenToken, catchClause.identifier, catchClause.typeAnnotation, catchClause.closeParenToken);
}
private breakpointSpanOfFinallyClause(finallyClauseNode: TypeScript.ISyntaxNode): ts.SpanInfo {
private breakpointSpanOfFinallyClause(finallyClauseNode: TypeScript.ISyntaxNode): TextSpan {
var finallyClause = <TypeScript.FinallyClauseSyntax>finallyClauseNode;
return this.breakpointSpanOfFirstStatementInBlock(<TypeScript.ISyntaxNode>finallyClause.block);
}
private breakpointSpanOfParenthesizedArrowFunctionExpression(arrowFunctionExpression: ParenthesizedArrowFunctionExpressionSyntax): ts.SpanInfo {
private breakpointSpanOfParenthesizedArrowFunctionExpression(arrowFunctionExpression: ParenthesizedArrowFunctionExpressionSyntax): TextSpan {
if (arrowFunctionExpression.block) {
return this.breakpointSpanOfFirstStatementInBlock(arrowFunctionExpression.block);
}
@ -1020,7 +1011,7 @@ module TypeScript.Services.Breakpoints {
}
}
private breakpointSpanOfSimpleArrowFunctionExpression(arrowFunctionExpression: SimpleArrowFunctionExpressionSyntax): ts.SpanInfo {
private breakpointSpanOfSimpleArrowFunctionExpression(arrowFunctionExpression: SimpleArrowFunctionExpressionSyntax): TextSpan {
if (arrowFunctionExpression.block) {
return this.breakpointSpanOfFirstStatementInBlock(arrowFunctionExpression.block);
}
@ -1029,7 +1020,7 @@ module TypeScript.Services.Breakpoints {
}
}
private breakpointSpanOfContainingNode(positionedElement: ISyntaxElement): ts.SpanInfo {
private breakpointSpanOfContainingNode(positionedElement: ISyntaxElement): TextSpan {
var current = positionedElement.parent;
while (!isNode(current)) {
current = current.parent;
@ -1038,7 +1029,7 @@ module TypeScript.Services.Breakpoints {
return this.breakpointSpanOf(current);
}
private breakpointSpanIfStartsOnSameLine(positionedElement: TypeScript.ISyntaxElement): ts.SpanInfo {
private breakpointSpanIfStartsOnSameLine(positionedElement: TypeScript.ISyntaxElement): TextSpan {
if (positionedElement && this.posLine == this.lineMap.getLineNumberFromPosition(start(positionedElement))) {
return this.breakpointSpanOf(positionedElement);
}
@ -1046,7 +1037,7 @@ module TypeScript.Services.Breakpoints {
return null;
}
public breakpointSpanOf(positionedElement: TypeScript.ISyntaxElement): ts.SpanInfo {
public breakpointSpanOf(positionedElement: TypeScript.ISyntaxElement): TextSpan {
if (!positionedElement) {
return null;
}
@ -1075,7 +1066,7 @@ module TypeScript.Services.Breakpoints {
}
}
export function getBreakpointLocation(syntaxTree: TypeScript.SyntaxTree, askedPos: number): ts.SpanInfo {
export function getBreakpointLocation(syntaxTree: TypeScript.SyntaxTree, askedPos: number): TextSpan {
// Cannot set breakpoint in dts file
if (TypeScript.isDTSFile(syntaxTree.fileName())) {
return null;

View file

@ -17,31 +17,11 @@
module TypeScript {
export interface Logger {
information(): boolean;
debug(): boolean;
warning(): boolean;
error(): boolean;
fatal(): boolean;
log(s: string): void;
}
export class NullLogger implements Logger {
public information(): boolean { return false; }
public debug(): boolean { return false; }
public warning(): boolean { return false; }
public error(): boolean { return false; }
public fatal(): boolean { return false; }
public log(s: string): void {
}
}
export function timeFunction(logger: Logger, funcDescription: string, func: () => any): any {
var start = (new Date()).getTime();
var result = func();
var end = (new Date()).getTime();
if (logger.information()) {
logger.log(funcDescription + " completed in " + (end - start) + " msec");
}
return result;
}
}

View file

@ -19,28 +19,26 @@ module TypeScript.Services.Formatting {
export class FormattingManager {
private options: FormattingOptions;
constructor(private syntaxTree: SyntaxTree, private snapshot: ITextSnapshot, private rulesProvider: RulesProvider, editorOptions: ts.EditorOptions) {
constructor(private syntaxTree: SyntaxTree,
private snapshot: ITextSnapshot,
private rulesProvider: RulesProvider,
editorOptions: ts.EditorOptions) {
//
// TODO: convert to use FormattingOptions instead of EditorOptions
this.options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter);
this.options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter)
}
public formatSelection(minChar: number, limChar: number): ts.TextEdit[] {
public formatSelection(minChar: number, limChar: number): ts.TextChange[] {
var span = TextSpan.fromBounds(minChar, limChar);
return this.formatSpan(span, FormattingRequestKind.FormatSelection);
}
public formatDocument(minChar: number, limChar: number): ts.TextEdit[] {
var span = TextSpan.fromBounds(minChar, limChar);
public formatDocument(): ts.TextChange[] {
var span = TextSpan.fromBounds(0, this.snapshot.getLength());
return this.formatSpan(span, FormattingRequestKind.FormatDocument);
}
public formatOnPaste(minChar: number, limChar: number): ts.TextEdit[] {
var span = TextSpan.fromBounds(minChar, limChar);
return this.formatSpan(span, FormattingRequestKind.FormatOnPaste);
}
public formatOnSemicolon(caretPosition: number): ts.TextEdit[] {
public formatOnSemicolon(caretPosition: number): ts.TextChange[] {
var sourceUnit = this.syntaxTree.sourceUnit();
var semicolonPositionedToken = findToken(sourceUnit, caretPosition - 1);
@ -48,7 +46,7 @@ module TypeScript.Services.Formatting {
// Find the outer most parent that this semicolon terminates
var current: ISyntaxElement = semicolonPositionedToken;
while (current.parent !== null &&
end(current.parent) === end(semicolonPositionedToken) &&
end(current.parent) === end(semicolonPositionedToken) &&
current.parent.kind() !== SyntaxKind.List) {
current = current.parent;
}
@ -63,7 +61,7 @@ module TypeScript.Services.Formatting {
return [];
}
public formatOnClosingCurlyBrace(caretPosition: number): ts.TextEdit[] {
public formatOnClosingCurlyBrace(caretPosition: number): ts.TextChange[] {
var sourceUnit = this.syntaxTree.sourceUnit();
var closeBracePositionedToken = findToken(sourceUnit, caretPosition - 1);
@ -71,8 +69,8 @@ module TypeScript.Services.Formatting {
// Find the outer most parent that this closing brace terminates
var current: ISyntaxElement = closeBracePositionedToken;
while (current.parent !== null &&
end(current.parent) === end(closeBracePositionedToken) &&
current.parent.kind() !== SyntaxKind.List) {
end(current.parent) === end(closeBracePositionedToken) &&
current.parent.kind() !== SyntaxKind.List) {
current = current.parent;
}
@ -86,7 +84,7 @@ module TypeScript.Services.Formatting {
return [];
}
public formatOnEnter(caretPosition: number): ts.TextEdit[] {
public formatOnEnter(caretPosition: number): ts.TextChange[] {
var lineNumber = this.snapshot.getLineNumberFromPosition(caretPosition);
if (lineNumber > 0) {
@ -103,23 +101,20 @@ module TypeScript.Services.Formatting {
return [];
}
private formatSpan(span: TextSpan, formattingRequestKind: FormattingRequestKind): ts.TextEdit[] {
private formatSpan(span: TextSpan, formattingRequestKind: FormattingRequestKind): ts.TextChange[] {
// Always format from the beginning of the line
var startLine = this.snapshot.getLineFromPosition(span.start());
span = TextSpan.fromBounds(startLine.startPosition(), span.end());
var result: ts.TextEdit[] = [];
var result: ts.TextChange[] = [];
var formattingEdits = Formatter.getEdits(span, this.syntaxTree.sourceUnit(), this.options, true, this.snapshot, this.rulesProvider, formattingRequestKind);
//
// TODO: Change the ILanguageService interface to return TextEditInfo (with start, and length) instead of TextEdit (with minChar and limChar)
formattingEdits.forEach((item) => {
result.push({
minChar: item.position,
limChar: item.position + item.length,
text: item.replaceWith
});
var edit = new ts.TextChange(new TextSpan(item.position, item.length), item.replaceWith);
result.push(edit);
});
return result;

View file

@ -40,8 +40,8 @@ module TypeScript.Services.Formatting {
public ensureUpToDate(options: ts.FormatCodeOptions) {
if (this.options == null || !ts.compareDataObjects(this.options, options)) {
var activeRules: Rule[] = TypeScript.timeFunction(this.logger, "RulesProvider: createActiveRules()", () => { return this.createActiveRules(options); });
var rulesMap: RulesMap = TypeScript.timeFunction(this.logger, "RulesProvider: RulesMap.create()", () => { return RulesMap.create(activeRules); });
var activeRules = this.createActiveRules(options);
var rulesMap = RulesMap.create(activeRules);
this.activeRules = activeRules;
this.rulesMap = rulesMap;

View file

@ -17,6 +17,7 @@
module TypeScript.Services.Formatting {
export interface ITextSnapshot {
getLength(): number;
getText(span: TextSpan): string;
getLineNumberFromPosition(position: number): number;
getLineFromPosition(position: number): ITextSnapshotLine;
@ -30,6 +31,10 @@ module TypeScript.Services.Formatting {
this.lines = [];
}
public getLength(): number {
return this.snapshot.length();
}
public getText(span: TextSpan): string {
return this.snapshot.substr(span.start(), span.length());
}

View file

@ -1,121 +1,22 @@
///<reference path='references.ts' />
module TypeScript.Services {
interface LexicalScope {
items: ts.Map<ts.NavigateToItem>;
itemNames: string[];
childScopes: ts.Map<LexicalScope>;
childScopeNames: string[];
}
export class NavigationBarItemGetter {
private hasGlobalNode = false;
export class GetScriptLexicalStructureWalker extends TypeScript.SyntaxWalker {
private nameStack: string[] = [];
private kindStack: string[] = [];
private getIndent(node: ISyntaxNode): number {
var indent = this.hasGlobalNode ? 1 : 0;
private parentScopes: LexicalScope[] = [];
private currentScope: LexicalScope;
var current = node.parent;
while (current != null) {
if (current.kind() == SyntaxKind.ModuleDeclaration || current.kind() === SyntaxKind.FunctionDeclaration) {
indent++;
}
private createScope(): LexicalScope {
return {
items: TypeScript.createIntrinsicsObject<ts.NavigateToItem>(),
childScopes: TypeScript.createIntrinsicsObject<LexicalScope>(),
childScopeNames: [],
itemNames: []
};
}
private pushNewContainerScope(containerName: string, kind: string): LexicalScope {
Debug.assert(containerName, "No scope name provided");
var key = kind + "+" + containerName;
this.nameStack.push(containerName);
this.kindStack.push(kind);
var parentScope = this.currentScope;
this.parentScopes.push(parentScope);
var scope = ts.lookUp(parentScope.childScopes, key);
if (!scope) {
scope = this.createScope()
parentScope.childScopes[key] = scope;
parentScope.childScopeNames.push(key);
current = current.parent;
}
this.currentScope = scope;
return parentScope;
}
private popScope() {
Debug.assert(this.parentScopes.length > 0, "No parent scopes to return to")
this.currentScope = this.parentScopes.pop();
this.kindStack.pop();
this.nameStack.pop();
}
constructor(private fileName: string) {
super();
this.currentScope = this.createScope();
}
private collectItems(items: ts.NavigateToItem[], scope = this.currentScope) {
scope.itemNames.forEach(item => {
items.push(scope.items[item]);
});
scope.childScopeNames.forEach(childScope => {
this.collectItems(items, scope.childScopes[childScope]);
});
}
static getListsOfAllScriptLexicalStructure(items: ts.NavigateToItem[], fileName: string, unit: TypeScript.SourceUnitSyntax) {
var visitor = new GetScriptLexicalStructureWalker(fileName);
visitNodeOrToken(visitor, unit);
visitor.collectItems(items);
}
private createItem(node: TypeScript.ISyntaxNode, modifiers: ISyntaxToken[], kind: string, name: string): void {
var key = kind + "+" + name;
if (ts.lookUp(this.currentScope.items, key) !== undefined) {
this.addAdditionalSpan(node, key);
return;
}
var item: ts.NavigateToItem = {
name: name,
kind: kind,
matchKind: ts.MatchKind.exact,
fileName: this.fileName,
kindModifiers: this.getKindModifiers(modifiers),
minChar: start(node),
limChar: end(node),
containerName: this.nameStack.join("."),
containerKind: this.kindStack.length === 0 ? "" : TypeScript.ArrayUtilities.last(this.kindStack),
};
this.currentScope.items[key] = item;
this.currentScope.itemNames.push(key);
}
private addAdditionalSpan(
node: TypeScript.ISyntaxNode,
key: string) {
var item = ts.lookUp(this.currentScope.items, key);
Debug.assert(item !== undefined);
var start = TypeScript.start(node);
var span: ts.SpanInfo = {
minChar: start,
limChar: start + width(node)
};
if (item.additionalSpans) {
item.additionalSpans.push(span);
}
else {
item.additionalSpans = [span];
}
return indent;
}
private getKindModifiers(modifiers: TypeScript.ISyntaxToken[]): string {
@ -128,30 +29,221 @@ module TypeScript.Services {
return result.length > 0 ? result.join(',') : ts.ScriptElementKindModifier.none;
}
public visitModuleDeclaration(node: TypeScript.ModuleDeclarationSyntax): void {
var names = this.getModuleNames(node);
this.visitModuleDeclarationWorker(node, names, 0);
public getItems(node: TypeScript.SourceUnitSyntax): ts.NavigationBarItem[] {
return this.getItemsWorker(() => this.getTopLevelNodes(node), n => this.createTopLevelItem(n));
}
private visitModuleDeclarationWorker(node: TypeScript.ModuleDeclarationSyntax, names: string[], nameIndex: number): void {
if (nameIndex === names.length) {
// We're after all the module names, descend and process all children.
super.visitModuleDeclaration(node);
private getChildNodes(nodes: IModuleElementSyntax[]): ISyntaxNode[] {
var childNodes: ISyntaxNode[] = [];
for (var i = 0, n = nodes.length; i < n; i++) {
var node = <ISyntaxNode>nodes[i];
if (node.kind() === SyntaxKind.FunctionDeclaration) {
childNodes.push(node);
}
else if (node.kind() === SyntaxKind.VariableStatement) {
var variableDeclaration = (<VariableStatementSyntax>node).variableDeclaration;
childNodes.push.apply(childNodes, variableDeclaration.variableDeclarators);
}
}
else {
var name = names[nameIndex];
var kind = ts.ScriptElementKind.moduleElement;
this.createItem(node, node.modifiers, kind, name);
return childNodes;
}
this.pushNewContainerScope(name, kind);
private getTopLevelNodes(node: SourceUnitSyntax): ISyntaxNode[] {
var topLevelNodes: ISyntaxNode[] = [];
topLevelNodes.push(node);
this.visitModuleDeclarationWorker(node, names, nameIndex + 1);
this.addTopLevelNodes(node.moduleElements, topLevelNodes);
this.popScope();
return topLevelNodes;
}
private addTopLevelNodes(nodes: IModuleElementSyntax[], topLevelNodes: ISyntaxNode[]): void {
for (var i = 0, n = nodes.length; i < n; i++) {
var node = nodes[i];
switch (node.kind()) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.InterfaceDeclaration:
topLevelNodes.push(node);
break;
case SyntaxKind.ModuleDeclaration:
var moduleDeclaration = <ModuleDeclarationSyntax>node;
topLevelNodes.push(node);
this.addTopLevelNodes(moduleDeclaration.moduleElements, topLevelNodes);
break;
case SyntaxKind.FunctionDeclaration:
var functionDeclaration = <FunctionDeclarationSyntax>node;
if (this.isTopLevelFunctionDeclaration(functionDeclaration)) {
topLevelNodes.push(node);
this.addTopLevelNodes(functionDeclaration.block.statements, topLevelNodes);
}
break;
}
}
}
public isTopLevelFunctionDeclaration(functionDeclaration: FunctionDeclarationSyntax) {
// A function declaration is 'top level' if it contains any function declarations
// within it.
return functionDeclaration.block && ArrayUtilities.any(functionDeclaration.block.statements, s => s.kind() === SyntaxKind.FunctionDeclaration);
}
private getItemsWorker(getNodes: () => ISyntaxNode[], createItem: (n: ISyntaxNode) => ts.NavigationBarItem): ts.NavigationBarItem[] {
var items: ts.NavigationBarItem[] = [];
var keyToItem = createIntrinsicsObject<ts.NavigationBarItem>();
var nodes = getNodes();
for (var i = 0, n = nodes.length; i < n; i++) {
var child = nodes[i];
var item = createItem(child);
if (item != null) {
if (item.text.length > 0) {
var key = item.text + "-" + item.kind;
var itemWithSameName = keyToItem[key];
if (itemWithSameName) {
// We had an item with the same name. Merge these items together.
this.merge(itemWithSameName, item);
}
else {
keyToItem[key] = item;
items.push(item);
}
}
}
}
return items;
}
private merge(target: ts.NavigationBarItem, source: ts.NavigationBarItem) {
// First, add any spans in the source to the target.
target.spans.push.apply(target.spans, source.spans);
if (source.childItems) {
if (!target.childItems) {
target.childItems = [];
}
// Next, recursively merge or add any children in the source as appropriate.
outer:
for (var i = 0, n = source.childItems.length; i < n; i++) {
var sourceChild = source.childItems[i];
for (var j = 0, m = target.childItems.length; j < m; j++) {
var targetChild = target.childItems[j];
if (targetChild.text === sourceChild.text && targetChild.kind === sourceChild.kind) {
// Found a match. merge them.
this.merge(targetChild, sourceChild);
continue outer;
}
}
// Didn't find a match, just add this child to the list.
target.childItems.push(sourceChild);
}
}
}
private createChildItem(node: ISyntaxNode): ts.NavigationBarItem {
switch (node.kind()) {
case SyntaxKind.Parameter:
var parameter = <ParameterSyntax>node;
if (parameter.modifiers.length === 0) {
return null;
}
return new ts.NavigationBarItem(parameter.identifier.text(), ts.ScriptElementKind.memberVariableElement, this.getKindModifiers(parameter.modifiers), [TextSpan.fromBounds(start(node), end(node))]);
case SyntaxKind.MemberFunctionDeclaration:
var memberFunction = <MemberFunctionDeclarationSyntax>node;
return new ts.NavigationBarItem(memberFunction.propertyName.text(), ts.ScriptElementKind.memberFunctionElement, this.getKindModifiers(memberFunction.modifiers), [TextSpan.fromBounds(start(node), end(node))]);
case SyntaxKind.GetAccessor:
var getAccessor = <GetAccessorSyntax>node;
return new ts.NavigationBarItem(getAccessor.propertyName.text(), ts.ScriptElementKind.memberGetAccessorElement, this.getKindModifiers(getAccessor.modifiers), [TextSpan.fromBounds(start(node), end(node))]);
case SyntaxKind.SetAccessor:
var setAccessor = <SetAccessorSyntax>node;
return new ts.NavigationBarItem(setAccessor.propertyName.text(), ts.ScriptElementKind.memberSetAccessorElement, this.getKindModifiers(setAccessor.modifiers), [TextSpan.fromBounds(start(node), end(node))]);
case SyntaxKind.IndexSignature:
var indexSignature = <IndexSignatureSyntax>node;
return new ts.NavigationBarItem("[]", ts.ScriptElementKind.indexSignatureElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]);
case SyntaxKind.EnumElement:
var enumElement = <EnumElementSyntax>node;
return new ts.NavigationBarItem(enumElement.propertyName.text(), ts.ScriptElementKind.memberVariableElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]);
case SyntaxKind.CallSignature:
var callSignature = <CallSignatureSyntax>node;
return new ts.NavigationBarItem("()", ts.ScriptElementKind.callSignatureElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]);
case SyntaxKind.ConstructSignature:
var constructSignature = <ConstructSignatureSyntax>node;
return new ts.NavigationBarItem("new()", ts.ScriptElementKind.constructSignatureElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]);
case SyntaxKind.MethodSignature:
var methodSignature = <MethodSignatureSyntax>node;
return new ts.NavigationBarItem(methodSignature.propertyName.text(), ts.ScriptElementKind.memberFunctionElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]);
case SyntaxKind.PropertySignature:
var propertySignature = <PropertySignatureSyntax>node;
return new ts.NavigationBarItem(propertySignature.propertyName.text(), ts.ScriptElementKind.memberVariableElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]);
case SyntaxKind.FunctionDeclaration:
var functionDeclaration = <FunctionDeclarationSyntax>node;
if (!this.isTopLevelFunctionDeclaration(functionDeclaration)) {
return new ts.NavigationBarItem(functionDeclaration.identifier.text(), ts.ScriptElementKind.functionElement, this.getKindModifiers(functionDeclaration.modifiers), [TextSpan.fromBounds(start(node), end(node))]);
}
break;
case SyntaxKind.MemberVariableDeclaration:
var memberVariableDeclaration = <MemberVariableDeclarationSyntax>node;
return new ts.NavigationBarItem(memberVariableDeclaration.variableDeclarator.propertyName.text(), ts.ScriptElementKind.memberVariableElement, this.getKindModifiers(memberVariableDeclaration.modifiers), [TextSpan.fromBounds(start(memberVariableDeclaration.variableDeclarator), end(memberVariableDeclaration.variableDeclarator))]);
case SyntaxKind.VariableDeclarator:
var variableDeclarator = <VariableDeclaratorSyntax>node;
return new ts.NavigationBarItem(variableDeclarator.propertyName.text(), ts.ScriptElementKind.variableElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(variableDeclarator), end(variableDeclarator))]);
case SyntaxKind.ConstructorDeclaration:
var constructorDeclaration = <ConstructorDeclarationSyntax>node;
return new ts.NavigationBarItem("constructor", ts.ScriptElementKind.constructorImplementationElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]);
}
return null;
}
private createTopLevelItem(node: ISyntaxNode): ts.NavigationBarItem {
switch (node.kind()) {
case SyntaxKind.SourceUnit:
return this.createSourceUnitItem(<SourceUnitSyntax>node);
case SyntaxKind.ClassDeclaration:
return this.createClassItem(<ClassDeclarationSyntax>node);
case SyntaxKind.EnumDeclaration:
return this.createEnumItem(<EnumDeclarationSyntax>node);
case SyntaxKind.InterfaceDeclaration:
return this.createIterfaceItem(<InterfaceDeclarationSyntax>node);
case SyntaxKind.ModuleDeclaration:
return this.createModuleItem(<ModuleDeclarationSyntax>node);
case SyntaxKind.FunctionDeclaration:
return this.createFunctionItem(<FunctionDeclarationSyntax>node);
}
return null;
}
private getModuleNames(node: TypeScript.ModuleDeclarationSyntax): string[] {
var result: string[] = [];
@ -176,180 +268,84 @@ module TypeScript.Services {
}
}
public visitClassDeclaration(node: TypeScript.ClassDeclarationSyntax): void {
var name = node.identifier.text();
var kind = ts.ScriptElementKind.classElement;
private createModuleItem(node: ModuleDeclarationSyntax): ts.NavigationBarItem {
var moduleNames = this.getModuleNames(node);
this.createItem(node, node.modifiers, kind, name);
var childItems = this.getItemsWorker(() => this.getChildNodes(node.moduleElements), n => this.createChildItem(n));
this.pushNewContainerScope(name, kind);
super.visitClassDeclaration(node);
this.popScope();
return new ts.NavigationBarItem(moduleNames.join("."),
ts.ScriptElementKind.moduleElement,
this.getKindModifiers(node.modifiers),
[TextSpan.fromBounds(start(node), end(node))],
childItems,
this.getIndent(node));
}
public visitInterfaceDeclaration(node: TypeScript.InterfaceDeclarationSyntax): void {
var name = node.identifier.text();
var kind = ts.ScriptElementKind.interfaceElement;
private createFunctionItem(node: FunctionDeclarationSyntax) {
var childItems = this.getItemsWorker(() => node.block.statements, n => this.createChildItem(n));
this.createItem(node, node.modifiers, kind, name);
this.pushNewContainerScope(name, kind);
super.visitInterfaceDeclaration(node);
this.popScope();
return new ts.NavigationBarItem(node.identifier.text(),
ts.ScriptElementKind.functionElement,
this.getKindModifiers(node.modifiers),
[TextSpan.fromBounds(start(node), end(node))],
childItems,
this.getIndent(node));
}
public visitObjectType(node: TypeScript.ObjectTypeSyntax): void {
// Ignore an object type if we aren't inside an interface declaration. We don't want
// to add some random object type's members to the nav bar.
if (node.parent.kind() === SyntaxKind.InterfaceDeclaration) {
super.visitObjectType(node);
}
}
private createSourceUnitItem(node: SourceUnitSyntax): ts.NavigationBarItem {
var childItems = this.getItemsWorker(() => this.getChildNodes(node.moduleElements), n => this.createChildItem(n));
public visitEnumDeclaration(node: TypeScript.EnumDeclarationSyntax): void {
var name = node.identifier.text();
var kind = ts.ScriptElementKind.enumElement;
this.createItem(node, node.modifiers, kind, name);
this.pushNewContainerScope(name, kind);
super.visitEnumDeclaration(node);
this.popScope();
}
public visitConstructorDeclaration(node: TypeScript.ConstructorDeclarationSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.constructorImplementationElement, "constructor");
// Search the parameter list of class properties
var parameters = node.callSignature.parameterList.parameters;
if (parameters) {
for (var i = 0, n = parameters.length; i < n; i++) {
var parameter = <ParameterSyntax>parameters[i];
Debug.assert(parameter.kind() === SyntaxKind.Parameter);
if (SyntaxUtilities.containsToken(parameter.modifiers, SyntaxKind.PublicKeyword) ||
SyntaxUtilities.containsToken(parameter.modifiers, SyntaxKind.PrivateKeyword)) {
this.createItem(node, parameter.modifiers, ts.ScriptElementKind.memberVariableElement, parameter.identifier.text());
}
}
if (childItems === null || childItems.length === 0) {
return null;
}
// No need to descend into a constructor;
this.hasGlobalNode = true;
return new ts.NavigationBarItem("<global>",
ts.ScriptElementKind.moduleElement,
ts.ScriptElementKindModifier.none,
[TextSpan.fromBounds(start(node), end(node))],
childItems);
}
public visitMemberFunctionDeclaration(node: TypeScript.MemberFunctionDeclarationSyntax): void {
this.createItem(node, node.modifiers, ts.ScriptElementKind.memberFunctionElement, node.propertyName.text());
private createClassItem(node: ClassDeclarationSyntax): ts.NavigationBarItem {
var constructor = <ConstructorDeclarationSyntax>ArrayUtilities.firstOrDefault(
node.classElements, n => n.kind() === SyntaxKind.ConstructorDeclaration);
// No need to descend into a member function;
// Add the constructor parameters in as children of hte class (for property parameters).
var nodes: ISyntaxNode[] = constructor
? (<ISyntaxNode[]>constructor.callSignature.parameterList.parameters).concat(node.classElements)
: node.classElements;
var childItems = this.getItemsWorker(() => nodes, n => this.createChildItem(n));
return new ts.NavigationBarItem(
node.identifier.text(),
ts.ScriptElementKind.classElement,
this.getKindModifiers(node.modifiers),
[TextSpan.fromBounds(start(node), end(node))],
childItems,
this.getIndent(node));
}
public visitGetAccessor(node: TypeScript.GetAccessorSyntax): void {
this.createItem(node, node.modifiers, ts.ScriptElementKind.memberGetAccessorElement, node.propertyName.text());
// No need to descend into a member accessor;
private createEnumItem(node: TypeScript.EnumDeclarationSyntax): ts.NavigationBarItem {
var childItems = this.getItemsWorker(() => node.enumElements, n => this.createChildItem(n));
return new ts.NavigationBarItem(
node.identifier.text(),
ts.ScriptElementKind.enumElement,
this.getKindModifiers(node.modifiers),
[TextSpan.fromBounds(start(node), end(node))],
childItems,
this.getIndent(node));
}
public visitSetAccessor(node: TypeScript.SetAccessorSyntax): void {
this.createItem(node, node.modifiers, ts.ScriptElementKind.memberSetAccessorElement, node.propertyName.text());
// No need to descend into a member accessor;
}
public visitVariableDeclarator(node: TypeScript.VariableDeclaratorSyntax): void {
var modifiers = node.parent.kind() === SyntaxKind.MemberVariableDeclaration
? (<MemberVariableDeclarationSyntax>node.parent).modifiers
: TypeScript.Syntax.emptyList<ISyntaxToken>();
var kind = node.parent.kind() === SyntaxKind.MemberVariableDeclaration
? ts.ScriptElementKind.memberVariableElement
: ts.ScriptElementKind.variableElement;
this.createItem(node, modifiers, kind, node.propertyName.text());
// No need to descend into a variable declarator;
}
public visitIndexSignature(node: TypeScript.IndexSignatureSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.indexSignatureElement, "[]");
// No need to descend into an index signature;
}
public visitEnumElement(node: TypeScript.EnumElementSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.memberVariableElement, node.propertyName.text());
// No need to descend into an enum element;
}
public visitCallSignature(node: TypeScript.CallSignatureSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.callSignatureElement, "()");
// No need to descend into a call signature;
}
public visitConstructSignature(node: TypeScript.ConstructSignatureSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.constructSignatureElement, "new()");
// No need to descend into a construct signature;
}
public visitMethodSignature(node: TypeScript.MethodSignatureSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.memberFunctionElement, node.propertyName.text());
// No need to descend into a method signature;
}
public visitPropertySignature(node: TypeScript.PropertySignatureSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.memberVariableElement, node.propertyName.text());
// No need to descend into a property signature;
}
public visitFunctionDeclaration(node: TypeScript.FunctionDeclarationSyntax): void {
// in the case of:
// declare function
// the parser will synthesize an identifier.
// we shouldn't add an unnamed function declaration
if (width(node.identifier) > 0) {
this.createItem(node, node.modifiers, ts.ScriptElementKind.functionElement, node.identifier.text());
}
// No need to descend into a function declaration;
}
// Common statement types. Don't even bother walking into them as we'll never find anything
// inside that we'd put in the navbar.
public visitBlock(node: TypeScript.BlockSyntax): void {
}
public visitIfStatement(node: TypeScript.IfStatementSyntax): void {
}
public visitExpressionStatement(node: TypeScript.ExpressionStatementSyntax): void {
}
public visitThrowStatement(node: TypeScript.ThrowStatementSyntax): void {
}
public visitReturnStatement(node: TypeScript.ReturnStatementSyntax): void {
}
public visitSwitchStatement(node: TypeScript.SwitchStatementSyntax): void {
}
public visitWithStatement(node: TypeScript.WithStatementSyntax): void {
}
public visitTryStatement(node: TypeScript.TryStatementSyntax): void {
}
public visitLabeledStatement(node: TypeScript.LabeledStatementSyntax): void {
private createIterfaceItem(node: TypeScript.InterfaceDeclarationSyntax): ts.NavigationBarItem {
var childItems = this.getItemsWorker(() => node.body.typeMembers, n => this.createChildItem(n));
return new ts.NavigationBarItem(
node.identifier.text(),
ts.ScriptElementKind.interfaceElement,
this.getKindModifiers(node.modifiers),
[TextSpan.fromBounds(start(node), end(node))],
childItems,
this.getIndent(node));
}
}
}

View file

@ -26,7 +26,6 @@
/// <reference path='compiler\pathUtils.ts' />
module ts {
export interface Node {
getSourceFile(): SourceFile;
getChildCount(): number;
@ -72,7 +71,8 @@ module ts {
getSourceUnit(): TypeScript.SourceUnitSyntax;
getSyntaxTree(): TypeScript.SyntaxTree;
getBloomFilter(): TypeScript.BloomFilter;
update(scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): SourceFile;
getScriptSnapshot(): TypeScript.IScriptSnapshot;
update(scriptSnapshot: TypeScript.IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): SourceFile;
}
var scanner: Scanner = createScanner(ScriptTarget.ES5);
@ -321,7 +321,7 @@ module ts {
public identifierCount: number;
public symbolCount: number;
public statements: NodeArray<Statement>;
public version: number;
public version: string;
public isOpen: boolean;
public languageVersion: ScriptTarget;
@ -334,6 +334,10 @@ module ts {
return this.getSyntaxTree().sourceUnit();
}
public getScriptSnapshot(): TypeScript.IScriptSnapshot {
return this.scriptSnapshot;
}
public getLineMap(): TypeScript.LineMap {
return this.getSyntaxTree().lineMap();
}
@ -385,7 +389,7 @@ module ts {
return this.bloomFilter;
}
public update(scriptSnapshot: TypeScript.IScriptSnapshot, version: number, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): SourceFile {
public update(scriptSnapshot: TypeScript.IScriptSnapshot, version: string, isOpen: boolean, textChangeRange: TypeScript.TextChangeRange): SourceFile {
// See if we are currently holding onto a syntax tree. We may not be because we're
// either a closed file, or we've just been lazy and haven't had to create the syntax
// tree yet. Access the field instead of the method so we don't accidently realize
@ -420,7 +424,7 @@ module ts {
return SourceFileObject.createSourceFileObject(this.filename, scriptSnapshot, this.languageVersion, version, isOpen, newSyntaxTree);
}
public static createSourceFileObject(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot, languageVersion: ScriptTarget, version: number, isOpen: boolean, syntaxTree?: TypeScript.SyntaxTree) {
public static createSourceFileObject(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot, languageVersion: ScriptTarget, version: string, isOpen: boolean, syntaxTree?: TypeScript.SyntaxTree) {
var newSourceFile = <SourceFileObject><any>createSourceFile(filename, scriptSnapshot.getText(0, scriptSnapshot.getLength()), languageVersion, version, isOpen);
newSourceFile.scriptSnapshot = scriptSnapshot;
newSourceFile.syntaxTree = syntaxTree;
@ -429,11 +433,6 @@ module ts {
}
export interface Logger {
information(): boolean;
debug(): boolean;
warning(): boolean;
error(): boolean;
fatal(): boolean;
log(s: string): void;
}
@ -443,7 +442,7 @@ module ts {
export interface LanguageServiceHost extends Logger {
getCompilationSettings(): CompilerOptions;
getScriptFileNames(): string[];
getScriptVersion(fileName: string): number;
getScriptVersion(fileName: string): string;
getScriptIsOpen(fileName: string): boolean;
getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot;
getLocalizedDiagnosticMessages(): any;
@ -455,9 +454,6 @@ module ts {
// with a language service host instance
//
export interface LanguageService {
// Note: refresh is a no-op now. It is only around for back compat purposes.
refresh(): void;
cleanupSemanticCache(): void;
getSyntacticDiagnostics(fileName: string): Diagnostic[];
@ -469,28 +465,30 @@ module ts {
getTypeAtPosition(fileName: string, position: number): TypeInfo;
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): SpanInfo;
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TypeScript.TextSpan;
getBreakpointStatementAtPosition(fileName: string, position: number): SpanInfo;
getBreakpointStatementAtPosition(fileName: string, position: number): TypeScript.TextSpan;
getSignatureAtPosition(fileName: string, position: number): SignatureInfo;
getSignatureHelpItems(fileName: string, position: number): SignatureHelpItems;
getSignatureHelpCurrentArgumentState(fileName: string, position: number, applicableSpanStart: number): SignatureHelpState;
getRenameInfo(fileName: string, position: number): RenameInfo;
getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[];
getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[];
getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[];
getImplementorsAtPosition(fileName: string, position: number): ReferenceEntry[];
getNavigateToItems(searchValue: string): NavigateToItem[];
getScriptLexicalStructure(fileName: string): NavigateToItem[];
getNavigationBarItems(fileName: string): NavigationBarItem[];
getOutliningRegions(fileName: string): OutliningSpan[];
getOutliningSpans(fileName: string): OutliningSpan[];
getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[];
getBraceMatchingAtPosition(fileName: string, position: number): TypeScript.TextSpan[];
getIndentationAtPosition(fileName: string, position: number, options: EditorOptions): number;
getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[];
getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[];
getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[];
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextEdit[];
getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions): TextChange[];
getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions): TextChange[];
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextChange[];
getEmitOutput(fileName: string): EmitOutput;
@ -499,30 +497,68 @@ module ts {
dispose(): void;
}
export interface ReferenceEntry {
fileName: string;
minChar: number;
limChar: number;
isWriteAccess: boolean;
export class NavigationBarItem {
constructor(public text: string,
public kind: string,
public kindModifiers: string,
public spans: TypeScript.TextSpan[],
public childItems: NavigationBarItem[] = null,
public indent = 0,
public bolded = false,
public grayed = false) {
}
}
export interface NavigateToItem {
name: string;
kind: string; // see ScriptElementKind
kindModifiers: string; // see ScriptElementKindModifier, comma separated
matchKind: string;
fileName: string;
minChar: number;
limChar: number;
additionalSpans?: SpanInfo[];
containerName: string;
containerKind: string; // see ScriptElementKind
export class TodoCommentDescriptor {
constructor(public text: string,
public priority: number) {
}
}
export interface TextEdit {
minChar: number;
limChar: number;
text: string;
export class TodoComment {
constructor(public descriptor: TodoCommentDescriptor,
public message: string,
public position: number) {
}
}
export class TextChange {
constructor(public span: TypeScript.TextSpan, public newText: string) {
}
static createInsert(pos: number, newText: string): TextChange {
return new TextChange(new TypeScript.TextSpan(pos, 0), newText);
}
static createDelete(start: number, end: number): TextChange {
return new TextChange(TypeScript.TextSpan.fromBounds(start, end), "");
}
static createReplace(start: number, end: number, newText: string): TextChange {
return new TextChange(TypeScript.TextSpan.fromBounds(start, end), newText);
}
}
export class ReferenceEntry {
public fileName: string = "";
public textSpan: TypeScript.TextSpan;
public isWriteAccess: boolean = false;
constructor(fileName: string, textSpan: TypeScript.TextSpan, isWriteAccess: boolean) {
this.fileName = fileName;
this.textSpan = textSpan;
this.isWriteAccess = isWriteAccess;
}
}
export class NavigateToItem {
constructor(public name: string,
public kind: string,
public kindModifiers: string,
public matchKind: string,
public fileName: string,
public textSpan: TypeScript.TextSpan,
public containerName: string,
public containerKind: string) {
}
}
export interface EditorOptions {
@ -543,14 +579,14 @@ module ts {
PlaceOpenBraceOnNewLineForControlBlocks: boolean;
}
export interface DefinitionInfo {
fileName: string;
minChar: number;
limChar: number;
kind: string;
name: string;
containerKind: string;
containerName: string;
export class DefinitionInfo {
constructor(public fileName: string,
public textSpan: TypeScript.TextSpan,
public kind: string,
public name: string,
public containerKind: string,
public containerName: string) {
}
}
export interface MemberName {
@ -559,54 +595,80 @@ module ts {
text: string;
}
export interface TypeInfo {
memberName: MemberName;
docComment: string;
fullSymbolName: string;
kind: string;
minChar: number;
limChar: number;
export class TypeInfo {
constructor(
public memberName: TypeScript.MemberName,
public docComment: string,
public fullSymbolName: string,
public kind: string,
public textSpan: TypeScript.TextSpan) {
}
}
export interface SpanInfo {
minChar: number;
limChar: number;
// text?: string;
export class RenameInfo {
constructor(public canRename: boolean,
public localizedErrorMessage: string,
public displayName: string,
public fullDisplayName: string,
public kind: string,
public kindModifiers: string,
public triggerSpan: TypeScript.TextSpan) {
}
public static CreateError(localizedErrorMessage: string) {
return new RenameInfo(/*canRename:*/ false, localizedErrorMessage,
/*displayName:*/ null, /*fullDisplayName:*/ null,
/*kind:*/ null, /*kindModifiers:*/ null, /*triggerSpan:*/ null);
}
public static Create(displayName: string,
fullDisplayName: string,
kind: string,
kindModifiers: string,
triggerSpan: TypeScript.TextSpan) {
return new RenameInfo(/*canRename:*/ true, /*localizedErrorMessage:*/ null, displayName, fullDisplayName, kind, kindModifiers, triggerSpan);
}
}
export interface SignatureInfo {
actual: ActualSignatureInfo;
formal: FormalSignatureItemInfo[]; // Formal signatures
activeFormal: number; // Index of the "best match" formal signature
export class SignatureHelpParameter {
constructor(public name: string,
public documentation: string,
public display: string,
public isOptional: boolean) {
}
}
export interface FormalSignatureItemInfo {
signatureInfo: string;
typeParameters: FormalTypeParameterInfo[];
parameters: FormalParameterInfo[]; // Array of parameters
docComment: string; // Help for the signature
/**
* Represents a single signature to show in signature help.
* The id is used for subsequent calls into the language service to ask questions about the
* signature help item in the context of any documents that have been updated. i.e. after
* an edit has happened, while signature help is still active, the host can ask important
* questions like 'what parameter is the user currently contained within?'.
*/
export class SignatureHelpItem {
constructor(public isVariadic: boolean,
public prefix: string,
public suffix: string,
public separator: string,
public parameters: SignatureHelpParameter[],
public documentation: string) {
}
}
export interface FormalTypeParameterInfo {
name: string; // Type parameter name
docComment: string; // Comments that contain help for the parameter
minChar: number; // minChar for parameter info in the formal signature info string
limChar: number; // lim char for parameter info in the formal signature info string
/**
* Represents a set of signature help items, and the preferred item that should be selected.
*/
export class SignatureHelpItems {
constructor(public items: SignatureHelpItem[],
public applicableSpan: TypeScript.TextSpan,
public selectedItemIndex: number) {
}
}
export interface FormalParameterInfo {
name: string; // Parameter name
isVariable: boolean; // true if parameter is var args
docComment: string; // Comments that contain help for the parameter
minChar: number; // minChar for parameter info in the formal signature info string
limChar: number; // lim char for parameter info in the formal signature info string
}
export interface ActualSignatureInfo {
parameterMinChar: number;
parameterLimChar: number;
currentParameterIsTypeParameter: boolean; // current parameter is a type argument or a normal argument
currentParameter: number; // Index of active parameter in "parameters" or "typeParamters" array
export class SignatureHelpState {
constructor(public argumentIndex: number,
public argumentCount: number) {
}
}
export interface CompletionInfo {
@ -694,7 +756,7 @@ module ts {
filename: string,
compilationSettings: CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
version: number,
version: string,
isOpen: boolean): SourceFile;
updateDocument(
@ -702,7 +764,7 @@ module ts {
filename: string,
compilationSettings: CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
version: number,
version: string,
isOpen: boolean,
textChangeRange: TypeScript.TextChangeRange
): SourceFile;
@ -820,7 +882,7 @@ module ts {
// Information about a specific host file.
interface HostFileInformation {
filename: string;
version: number;
version: string;
isOpen: boolean;
sourceText?: TypeScript.IScriptSnapshot;
}
@ -929,7 +991,7 @@ module ts {
return fileNames;
}
public getVersion(filename: string): number {
public getVersion(filename: string): string {
return this.getEntry(filename).version;
}
@ -945,14 +1007,14 @@ module ts {
return file.sourceText;
}
public getScriptTextChangeRangeSinceVersion(filename: string, lastKnownVersion: number): TypeScript.TextChangeRange {
public getChangeRange(filename: string, lastKnownVersion: string, oldScriptSnapshot: TypeScript.IScriptSnapshot): TypeScript.TextChangeRange {
var currentVersion = this.getVersion(filename);
if (lastKnownVersion === currentVersion) {
return TypeScript.TextChangeRange.unchanged; // "No changes"
}
var scriptSnapshot = this.getScriptSnapshot(filename);
return scriptSnapshot.getTextChangeRangeSinceVersion(lastKnownVersion);
return scriptSnapshot.getChangeRange(oldScriptSnapshot);
}
}
@ -961,11 +1023,10 @@ module ts {
// For our syntactic only features, we also keep a cache of the syntax tree for the
// currently edited file.
private currentfilename: string = "";
private currentFileVersion: number = -1;
private currentFilename: string = "";
private currentFileVersion: string = null;
private currentSourceFile: SourceFile = null;
private currentFileSyntaxTree: TypeScript.SyntaxTree = null;
private currentFileScriptSnapshot: TypeScript.IScriptSnapshot = null;
constructor(private host: LanguageServiceHost) {
this.hostCache = new HostCache(host);
@ -980,7 +1041,7 @@ module ts {
var syntaxTree: TypeScript.SyntaxTree = null;
var sourceFile: SourceFile;
if (this.currentFileSyntaxTree === null || this.currentfilename !== filename) {
if (this.currentFileSyntaxTree === null || this.currentFilename !== filename) {
var scriptSnapshot = this.hostCache.getScriptSnapshot(filename);
syntaxTree = this.createSyntaxTree(filename, scriptSnapshot);
sourceFile = createSourceFileFromScriptSnapshot(filename, scriptSnapshot, getDefaultCompilerOptions(), version, /*isOpen*/ true);
@ -989,9 +1050,10 @@ module ts {
}
else if (this.currentFileVersion !== version) {
var scriptSnapshot = this.hostCache.getScriptSnapshot(filename);
syntaxTree = this.updateSyntaxTree(filename, scriptSnapshot, this.currentFileSyntaxTree, this.currentFileVersion);
syntaxTree = this.updateSyntaxTree(filename, scriptSnapshot,
this.currentSourceFile.getScriptSnapshot(), this.currentFileSyntaxTree, this.currentFileVersion);
var editRange = this.hostCache.getScriptTextChangeRangeSinceVersion(filename, this.currentFileVersion);
var editRange = this.hostCache.getChangeRange(filename, this.currentFileVersion, this.currentSourceFile.getScriptSnapshot());
sourceFile = !editRange
? createSourceFileFromScriptSnapshot(filename, scriptSnapshot, getDefaultCompilerOptions(), version, /*isOpen*/ true)
: this.currentSourceFile.update(scriptSnapshot, version, /*isOpen*/ true, editRange);
@ -1002,9 +1064,8 @@ module ts {
if (syntaxTree !== null) {
Debug.assert(sourceFile);
// All done, ensure state is up to date
this.currentFileScriptSnapshot = scriptSnapshot;
this.currentFileVersion = version;
this.currentfilename = filename;
this.currentFilename = filename;
this.currentFileSyntaxTree = syntaxTree;
this.currentSourceFile = sourceFile;
}
@ -1039,7 +1100,7 @@ module ts {
public getCurrentScriptSnapshot(filename: string): TypeScript.IScriptSnapshot {
// update currentFileScriptSnapshot as a part of 'getCurrentFileSyntaxTree' call
this.getCurrentFileSyntaxTree(filename);
return this.currentFileScriptSnapshot;
return this.getCurrentSourceFile(filename).getScriptSnapshot();
}
private createSyntaxTree(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot): TypeScript.SyntaxTree {
@ -1053,8 +1114,8 @@ module ts {
return syntaxTree;
}
private updateSyntaxTree(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot, previousSyntaxTree: TypeScript.SyntaxTree, previousFileVersion: number): TypeScript.SyntaxTree {
var editRange = this.hostCache.getScriptTextChangeRangeSinceVersion(filename, previousFileVersion);
private updateSyntaxTree(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot, previousScriptSnapshot: TypeScript.IScriptSnapshot, previousSyntaxTree: TypeScript.SyntaxTree, previousFileVersion: string): TypeScript.SyntaxTree {
var editRange = this.hostCache.getChangeRange(filename, previousFileVersion, previousScriptSnapshot);
// Debug.assert(newLength >= 0);
@ -1066,7 +1127,7 @@ module ts {
var nextSyntaxTree = TypeScript.IncrementalParser.parse(
previousSyntaxTree, editRange, TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot));
this.ensureInvariants(filename, editRange, nextSyntaxTree, this.currentFileScriptSnapshot, scriptSnapshot);
this.ensureInvariants(filename, editRange, nextSyntaxTree, previousScriptSnapshot, scriptSnapshot);
return nextSyntaxTree;
}
@ -1134,7 +1195,7 @@ module ts {
}
}
function createSourceFileFromScriptSnapshot(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot, settings: CompilerOptions, version: number, isOpen: boolean) {
function createSourceFileFromScriptSnapshot(filename: string, scriptSnapshot: TypeScript.IScriptSnapshot, settings: CompilerOptions, version: string, isOpen: boolean) {
return SourceFileObject.createSourceFileObject(filename, scriptSnapshot, settings.target, version, isOpen);
}
@ -1179,7 +1240,7 @@ module ts {
filename: string,
compilationSettings: CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
version: number,
version: string,
isOpen: boolean): SourceFile {
var bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true);
@ -1203,7 +1264,7 @@ module ts {
filename: string,
compilationSettings: CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
version: number,
version: string,
isOpen: boolean,
textChangeRange: TypeScript.TextChangeRange
): SourceFile {
@ -1397,7 +1458,7 @@ module ts {
// new text buffer).
var textChangeRange: TypeScript.TextChangeRange = null;
if (sourceFile.isOpen && isOpen) {
textChangeRange = hostCache.getScriptTextChangeRangeSinceVersion(filename, sourceFile.version);
textChangeRange = hostCache.getChangeRange(filename, sourceFile.version, sourceFile.getScriptSnapshot());
}
sourceFile = documentRegistry.updateDocument(sourceFile, filename, compilationSettings, scriptSnapshot, version, isOpen, textChangeRange);
@ -1885,25 +1946,21 @@ module ts {
}
/// QuickInfo
function getTypeAtPosition(filename: string, position: number): TypeInfo {
function getTypeAtPosition(fileName: string, position: number): TypeInfo {
synchronizeHostData();
filename = TypeScript.switchToForwardSlashes(filename);
var sourceFile = getSourceFile(filename);
fileName = TypeScript.switchToForwardSlashes(fileName);
var sourceFile = getSourceFile(fileName);
var node = getNodeAtPosition(sourceFile.getSourceFile(), position);
if (!node) return undefined;
var symbol = typeInfoResolver.getSymbolInfo(node);
var type = symbol && typeInfoResolver.getTypeOfSymbol(symbol);
if (type) {
return {
memberName: new TypeScript.MemberNameString(typeInfoResolver.typeToString(type)),
docComment: "",
fullSymbolName: typeInfoResolver.symbolToString(symbol, getContainerNode(node)),
kind: getSymbolKind(symbol),
minChar: node.pos,
limChar: node.end
};
return new TypeInfo(
new TypeScript.MemberNameString(typeInfoResolver.typeToString(type)),
"", typeInfoResolver.symbolToString(symbol, getContainerNode(node)),
getSymbolKind(symbol), TypeScript.TextSpan.fromBounds(node.pos, node.end));
}
return undefined;
@ -1958,15 +2015,13 @@ module ts {
}
function getDefinitionInfo(node: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo {
return {
fileName: node.getSourceFile().filename,
minChar: node.getStart(),
limChar: node.getEnd(),
kind: symbolKind,
name: symbolName,
containerName: containerName,
containerKind: undefined
};
return new DefinitionInfo(
node.getSourceFile().filename,
TypeScript.TextSpan.fromBounds(node.getStart(), node.getEnd()),
symbolKind,
symbolName,
undefined,
containerName);
}
function tryAddSignature(signatureDeclarations: Declaration[], selectConstructors: boolean, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) {
@ -2036,11 +2091,10 @@ module ts {
if (comment) {
var targetFilename = normalizePath(combinePaths(getDirectoryPath(filename), comment.filename));
if (program.getSourceFile(targetFilename)) {
return [{
fileName: targetFilename, minChar: 0, limChar: 0,
kind: ScriptElementKind.scriptElement,
name: comment.filename, containerName: undefined, containerKind: undefined
}];
return [new DefinitionInfo(
targetFilename, TypeScript.TextSpan.fromBounds(0, 0),
ScriptElementKind.scriptElement,
comment.filename, undefined, undefined)];
}
return undefined;
}
@ -2085,7 +2139,7 @@ module ts {
return currentSourceFile;
}
function getNameOrDottedNameSpan(filename: string, startPos: number, endPos: number): SpanInfo {
function getNameOrDottedNameSpan(filename: string, startPos: number, endPos: number): TypeScript.TextSpan {
function getTypeInfoEligiblePath(filename: string, position: number, isConstructorValidPosition: boolean) {
var sourceUnit = syntaxTreeCache.getCurrentFileSyntaxTree(filename).sourceUnit();
@ -2136,10 +2190,9 @@ module ts {
}
}
return {
minChar: TypeScript.start(node),
limChar: TypeScript.end(node)
};
return TypeScript.TextSpan.fromBounds(
TypeScript.start(node),
TypeScript.end(node));
}
function getBreakpointStatementAtPosition(filename: string, position: number) {
@ -2150,15 +2203,13 @@ module ts {
return TypeScript.Services.Breakpoints.getBreakpointLocation(syntaxtree, position);
}
function getScriptLexicalStructure(filename: string) {
function getNavigationBarItems(filename: string) {
filename = TypeScript.switchToForwardSlashes(filename);
var syntaxTree = getSyntaxTree(filename);
var items: NavigateToItem[] = [];
TypeScript.Services.GetScriptLexicalStructureWalker.getListsOfAllScriptLexicalStructure(items, filename, syntaxTree.sourceUnit());
return items;
return new TypeScript.Services.NavigationBarItemGetter().getItems(syntaxTree.sourceUnit());
}
function getOutliningRegions(filename: string): OutliningSpan[] {
function getOutliningSpans(filename: string): OutliningSpan[] {
// doesn't use compiler - no need to synchronize with host
filename = TypeScript.switchToForwardSlashes(filename);
var sourceFile = getCurrentSourceFile(filename);
@ -2205,41 +2256,202 @@ module ts {
return manager;
}
function getFormattingEditsForRange(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] {
filename = TypeScript.switchToForwardSlashes(filename);
function getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions): TextChange[] {
fileName = TypeScript.switchToForwardSlashes(fileName);
var manager = getFormattingManager(filename, options);
return manager.formatSelection(minChar, limChar);
var manager = getFormattingManager(fileName, options);
return manager.formatSelection(start, end);
}
function getFormattingEditsForDocument(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] {
filename = TypeScript.switchToForwardSlashes(filename);
function getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions): TextChange[] {
fileName = TypeScript.switchToForwardSlashes(fileName);
var manager = getFormattingManager(filename, options);
return manager.formatDocument(minChar, limChar);
var manager = getFormattingManager(fileName, options);
return manager.formatDocument();
}
function getFormattingEditsOnPaste(filename: string, minChar: number, limChar: number, options: FormatCodeOptions): TextEdit[] {
filename = TypeScript.switchToForwardSlashes(filename);
function getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextChange[] {
fileName = TypeScript.switchToForwardSlashes(fileName);
var manager = getFormattingManager(filename, options);
return manager.formatOnPaste(minChar, limChar);
var manager = getFormattingManager(fileName, options);
if (key === "}") {
return manager.formatOnClosingCurlyBrace(position);
}
else if (key === ";") {
return manager.formatOnSemicolon(position);
}
else if (key === "\n") {
return manager.formatOnEnter(position);
}
return [];
}
function getFormattingEditsAfterKeystroke(filename: string, position: number, key: string, options: FormatCodeOptions): TextEdit[] {
filename = TypeScript.switchToForwardSlashes(filename);
var manager = getFormattingManager(filename, options);
if (key === "}") return manager.formatOnClosingCurlyBrace(position);
else if (key === ";") return manager.formatOnSemicolon(position);
else if (key === "\n") return manager.formatOnEnter(position);
else return [];
function escapeRegExp(str: string): string {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
function getTodoCommentsRegExp(descriptors: TodoCommentDescriptor[]): RegExp {
// NOTE: ?: means 'non-capture group'. It allows us to have groups without having to
// filter them out later in the final result array.
// TODO comments can appear in one of the following forms:
//
// 1) // TODO or /////////// TODO
//
// 2) /* TODO or /********** TODO
//
// 3) /*
// * TODO
// */
//
// The following three regexps are used to match the start of the text up to the TODO
// comment portion.
var singleLineCommentStart = /(?:\/\/+\s*)/.source;
var multiLineCommentStart = /(?:\/\*+\s*)/.source;
var anyNumberOfSpacesAndAsterixesAtStartOfLine = /(?:^(?:\s|\*)*)/.source;
// Match any of the above three TODO comment start regexps.
// Note that the outermost group *is* a capture group. We want to capture the preamble
// so that we can determine the starting position of the TODO comment match.
var preamble = "(" + anyNumberOfSpacesAndAsterixesAtStartOfLine + "|" + singleLineCommentStart + "|" + multiLineCommentStart + ")";
// Takes the descriptors and forms a regexp that matches them as if they were literals.
// For example, if the descriptors are "TODO(jason)" and "HACK", then this will be:
//
// (?:(TODO\(jason\))|(HACK))
//
// Note that the outermost group is *not* a capture group, but the innermost groups
// *are* capture groups. By capturing the inner literals we can determine after
// matching which descriptor we are dealing with.
var literals = "(?:" + descriptors.map(d => "(" + escapeRegExp(d.text) + ")").join("|") + ")";
// After matching a descriptor literal, the following regexp matches the rest of the
// text up to the end of the line (or */).
var endOfLineOrEndOfComment = /(?:$|\*\/)/.source
var messageRemainder = /(?:.*?)/.source
// This is the portion of the match we'll return as part of the TODO comment result. We
// match the literal portion up to the end of the line or end of comment.
var messagePortion = "(" + literals + messageRemainder + ")";
var regExpString = preamble + messagePortion + endOfLineOrEndOfComment;
// The final regexp will look like this:
// /((?:\/\/+\s*)|(?:\/\*+\s*)|(?:^(?:\s|\*)*))((?:(TODO\(jason\))|(HACK))(?:.*?))(?:$|\*\/)/gim
// The flags of the regexp are important here.
// 'g' is so that we are doing a global search and can find matches several times
// in the input.
//
// 'i' is for case insensitivity (We do this to match C# TODO comment code).
//
// 'm' is so we can find matches in a multiline input.
return new RegExp(regExpString, "gim");
}
function getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] {
fileName = TypeScript.switchToForwardSlashes(fileName);
var sourceFile = getCurrentSourceFile(fileName);
var syntaxTree = sourceFile.getSyntaxTree();
cancellationToken.throwIfCancellationRequested();
var text = syntaxTree.text;
var fileContents = text.substr(0, text.length());
cancellationToken.throwIfCancellationRequested();
var result: TodoComment[] = [];
if (descriptors.length > 0) {
var regExp = getTodoCommentsRegExp(descriptors);
var matchArray: RegExpExecArray;
while (matchArray = regExp.exec(fileContents)) {
cancellationToken.throwIfCancellationRequested();
// If we got a match, here is what the match array will look like. Say the source text is:
//
// " // hack 1"
//
// The result array with the regexp: will be:
//
// ["// hack 1", "// ", "hack 1", undefined, "hack"]
//
// Here are the relevant capture groups:
// 0) The full match for hte entire regex.
// 1) The preamble to the message portion.
// 2) The message portion.
// 3...N) The descriptor that was matched - by index. 'undefined' for each
// descriptor that didn't match. an actual value if it did match.
//
// i.e. 'undefined' in position 3 above means TODO(jason) didn't match.
// "hack" in position 4 means HACK did match.
var firstDescriptorCaptureIndex = 3;
Debug.assert(matchArray.length === descriptors.length + firstDescriptorCaptureIndex);
var preamble = matchArray[1];
var matchPosition = matchArray.index + preamble.length;
// Ok, we have found a match in the file. This is ony an acceptable match if
// it is contained within a comment.
var token = TypeScript.findToken(syntaxTree.sourceUnit(), matchPosition);
if (matchPosition >= TypeScript.start(token) && matchPosition < TypeScript.end(token)) {
// match was within the token itself. Not in the comment. Keep searching
// descriptor.
continue;
}
// Looks to be within the trivia. See if we can find hte comment containing it.
var triviaList = matchPosition < TypeScript.start(token) ? token.leadingTrivia(syntaxTree.text) : token.trailingTrivia(syntaxTree.text);
var trivia = findContainingComment(triviaList, matchPosition);
if (trivia === null) {
continue;
}
var descriptor: TodoCommentDescriptor = undefined;
for (var i = 0, n = descriptors.length; i < n; i++) {
if (matchArray[i + firstDescriptorCaptureIndex]) {
descriptor = descriptors[i];
}
}
Debug.assert(descriptor);
// We don't want to match something like 'TODOBY', so we make sure a non
// letter/digit follows the match.
if (isLetterOrDigit(fileContents.charCodeAt(matchPosition + descriptor.text.length))) {
continue;
}
var message = matchArray[2];
result.push(new TodoComment(descriptor, message, matchPosition));
}
}
return result;
}
function isLetterOrDigit(char: number): boolean {
return (char >= TypeScript.CharacterCodes.a && char <= TypeScript.CharacterCodes.z) ||
(char >= TypeScript.CharacterCodes.A && char <= TypeScript.CharacterCodes.Z) ||
(char >= TypeScript.CharacterCodes._0 && char <= TypeScript.CharacterCodes._9);
}
function findContainingComment(triviaList: TypeScript.ISyntaxTriviaList, position: number): TypeScript.ISyntaxTrivia {
for (var i = 0, n = triviaList.count(); i < n; i++) {
var trivia = triviaList.syntaxTriviaAt(i);
var fullEnd = trivia.fullStart() + trivia.fullWidth();
if (trivia.isComment() && trivia.fullStart() <= position && position < fullEnd) {
return trivia;
}
}
return null;
}
return {
dispose: dispose,
refresh: () => { },
cleanupSemanticCache: cleanupSemanticCache,
getSyntacticDiagnostics: getSyntacticDiagnostics,
getSemanticDiagnostics: getSemanticDiagnostics,
@ -2247,7 +2459,8 @@ module ts {
getCompletionsAtPosition: getCompletionsAtPosition,
getCompletionEntryDetails: getCompletionEntryDetails,
getTypeAtPosition: getTypeAtPosition,
getSignatureAtPosition: (filename, position): SignatureInfo => undefined,
getSignatureHelpItems: (filename, position): SignatureHelpItems => null,
getSignatureHelpCurrentArgumentState: (fileName, position, applicableSpanStart): SignatureHelpState => null,
getDefinitionAtPosition: getDefinitionAtPosition,
getReferencesAtPosition: (filename, position) => [],
getOccurrencesAtPosition: (filename, position) => [],
@ -2255,27 +2468,44 @@ module ts {
getNameOrDottedNameSpan: getNameOrDottedNameSpan,
getBreakpointStatementAtPosition: getBreakpointStatementAtPosition,
getNavigateToItems: (searchValue) => [],
getScriptLexicalStructure: getScriptLexicalStructure,
getOutliningRegions: getOutliningRegions,
getRenameInfo: (fileName, position): RenameInfo => RenameInfo.CreateError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_this_element.key)),
getNavigationBarItems: getNavigationBarItems,
getOutliningSpans: getOutliningSpans,
getTodoComments: getTodoComments,
getBraceMatchingAtPosition: getBraceMatchingAtPosition,
getIndentationAtPosition: getIndentationAtPosition,
getFormattingEditsForRange: getFormattingEditsForRange,
getFormattingEditsForDocument: getFormattingEditsForDocument,
getFormattingEditsOnPaste: getFormattingEditsOnPaste,
getFormattingEditsAfterKeystroke: getFormattingEditsAfterKeystroke,
getEmitOutput: (filename): EmitOutput => undefined,
getEmitOutput: (filename): EmitOutput => null,
};
}
/// Classifier
export function createClassifier(host: Logger): Classifier {
var scanner: Scanner;
var noRegexTable: boolean[];
var noRegexTable: boolean[];
/// We do not have a full parser support to know when we should parse a regex or not
/// If we consider every slash token to be a regex, we could be missing cases like "1/2/3", where
/// we have a series of divide operator. this list allows us to be more accurate by ruling out
/// locations where a regexp cannot exist.
if (!noRegexTable) { noRegexTable = []; noRegexTable[SyntaxKind.Identifier] = true; noRegexTable[SyntaxKind.StringLiteral] = true; noRegexTable[SyntaxKind.NumericLiteral] = true; noRegexTable[SyntaxKind.RegularExpressionLiteral] = true; noRegexTable[SyntaxKind.ThisKeyword] = true; noRegexTable[SyntaxKind.PlusPlusToken] = true; noRegexTable[SyntaxKind.MinusMinusToken] = true; noRegexTable[SyntaxKind.CloseParenToken] = true; noRegexTable[SyntaxKind.CloseBracketToken] = true; noRegexTable[SyntaxKind.CloseBraceToken] = true; noRegexTable[SyntaxKind.TrueKeyword] = true; noRegexTable[SyntaxKind.FalseKeyword] = true; }
if (!noRegexTable) {
noRegexTable = [];
noRegexTable[SyntaxKind.Identifier] = true;
noRegexTable[SyntaxKind.StringLiteral] = true;
noRegexTable[SyntaxKind.NumericLiteral] = true;
noRegexTable[SyntaxKind.RegularExpressionLiteral] = true;
noRegexTable[SyntaxKind.ThisKeyword] = true;
noRegexTable[SyntaxKind.PlusPlusToken] = true;
noRegexTable[SyntaxKind.MinusMinusToken] = true;
noRegexTable[SyntaxKind.CloseParenToken] = true;
noRegexTable[SyntaxKind.CloseBracketToken] = true;
noRegexTable[SyntaxKind.CloseBraceToken] = true;
noRegexTable[SyntaxKind.TrueKeyword] = true;
noRegexTable[SyntaxKind.FalseKeyword] = true;
}
function getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult {
var offset = 0;
var lastTokenOrCommentEnd = 0;

View file

@ -36,7 +36,7 @@ module ts {
// { span: { start: number; length: number }; newLength: number }
//
// Or null value if there was no change.
getTextChangeRangeSinceVersion(scriptVersion: number): string;
getChangeRange(oldSnapshot: ScriptSnapshotShim): string;
}
//
@ -48,7 +48,7 @@ module ts {
// Returns a JSON encoded value of the type:
// string[]
getScriptFileNames(): string;
getScriptVersion(fileName: string): number;
getScriptVersion(fileName: string): string;
getScriptIsOpen(fileName: string): boolean;
getScriptSnapshot(fileName: string): ScriptSnapshotShim;
getLocalizedDiagnosticMessages(): string;
@ -86,44 +86,51 @@ module ts {
getTypeAtPosition(fileName: string, position: number): string;
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string;
getBreakpointStatementAtPosition(fileName: string, position: number): string;
getSignatureAtPosition(fileName: string, position: number): string;
getSignatureHelpItems(fileName: string, position: number): string;
getSignatureHelpCurrentArgumentState(fileName: string, position: number, applicableSpanStart: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; kind: string; name: string; containerKind: string; containerName: string }
// { canRename: boolean, localizedErrorMessage: string, displayName: string, fullDisplayName: string, kind: string, kindModifiers: string, triggerSpan: { start; length } }
getRenameInfo(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; textSpan: { start: number; length: number}; kind: string; name: string; containerKind: string; containerName: string }
//
// Or null value if no definition can be found.
getDefinitionAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[]
// { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean }[]
getReferencesAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[]
// { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean }[]
getOccurrencesAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[]
// { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean }[]
getImplementorsAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = [];
// { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; textSpan: { start: number; length: number}; } [] = [];
getNavigateToItems(searchValue: string): string;
// Returns a JSON encoded value of the type:
// { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = [];
getScriptLexicalStructure(fileName: string): string;
// { text: string; kind: string; kindModifiers: string; bolded: boolean; grayed: boolean; indent: number; spans: { start: number; length: number; }[]; childItems: <recursive use of this type>[] } [] = [];
getNavigationBarItems(fileName: string): string;
// Returns a JSON encoded value of the type:
// { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = [];
getOutliningRegions(fileName: string): string;
// { textSpan: { start: number, length: number }; hintSpan: { start: number, length: number }; bannerText: string; autoCollapse: boolean } [] = [];
getOutliningSpans(fileName: string): string;
getTodoComments(fileName: string, todoCommentDescriptors: string): string;
getBraceMatchingAtPosition(fileName: string, position: number): string;
getIndentationAtPosition(fileName: string, position: number, options: string/*Services.EditorOptions*/): string;
getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string;
getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string;
getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string;
getFormattingEditsForRange(fileName: string, start: number, end: number, options: string/*Services.FormatCodeOptions*/): string;
getFormattingEditsForDocument(fileName: string, options: string/*Services.FormatCodeOptions*/): string;
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string;
getEmitOutput(fileName: string): string;
@ -283,8 +290,9 @@ module ts {
return this.lineStartPositions;
}
public getTextChangeRangeSinceVersion(scriptVersion: number): TypeScript.TextChangeRange {
var encoded = this.scriptSnapshotShim.getTextChangeRangeSinceVersion(scriptVersion);
public getChangeRange(oldSnapshot: TypeScript.IScriptSnapshot): TypeScript.TextChangeRange {
var oldSnapshotShim = <ScriptSnapshotShimAdapter>oldSnapshot;
var encoded = this.scriptSnapshotShim.getChangeRange(oldSnapshotShim.scriptSnapshotShim);
if (encoded == null) {
return null;
}
@ -295,30 +303,10 @@ module ts {
}
}
class LanguageServiceShimHostAdapter implements LanguageServiceHost {
export class LanguageServiceShimHostAdapter implements LanguageServiceHost {
constructor(private shimHost: LanguageServiceShimHost) {
}
public information(): boolean {
return this.shimHost.information();
}
public debug(): boolean {
return this.shimHost.debug();
}
public warning(): boolean {
return this.shimHost.warning();
}
public error(): boolean {
return this.shimHost.error();
}
public fatal(): boolean {
return this.shimHost.fatal();
}
public log(s: string): void {
this.shimHost.log(s);
}
@ -349,7 +337,7 @@ module ts {
return new ScriptSnapshotShimAdapter(this.shimHost.getScriptSnapshot(fileName));
}
public getScriptVersion(fileName: string): number {
public getScriptVersion(fileName: string): string {
return this.shimHost.getScriptVersion(fileName);
}
@ -455,7 +443,6 @@ module ts {
this.forwardJSONCall(
"refresh(" + throwOnError + ")",
() => {
this.languageService.refresh();
return <any>null;
});
}
@ -468,8 +455,6 @@ module ts {
return <any>null;
});
}
/// SQUIGGLES
///
private static realizeDiagnostic(diagnostic: Diagnostic): { message: string; start: number; length: number; category: string; } {
return {
@ -494,7 +479,7 @@ module ts {
public getSyntacticDiagnostics(fileName: string): string {
return this.forwardJSONCall(
"getSyntacticDiagnostics(\"" + fileName + "\")",
"getSyntacticDiagnostics('" + fileName + "')",
() => {
var errors = this.languageService.getSyntacticDiagnostics(fileName);
return errors.map(LanguageServiceShimObject.realizeDiagnostic);
@ -503,7 +488,7 @@ module ts {
public getSemanticDiagnostics(fileName: string): string {
return this.forwardJSONCall(
"getSemanticDiagnostics(\"" + fileName + "\")",
"getSemanticDiagnostics('" + fileName + "')",
() => {
var errors = this.languageService.getSemanticDiagnostics(fileName);
return errors.map(LanguageServiceShimObject.realizeDiagnostic);
@ -524,7 +509,7 @@ module ts {
/// in the active file.
public getTypeAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getTypeAtPosition(\"" + fileName + "\", " + position + ")",
"getTypeAtPosition('" + fileName + "', " + position + ")",
() => {
var typeInfo = this.languageService.getTypeAtPosition(fileName, position);
return typeInfo;
@ -536,7 +521,7 @@ module ts {
// in the active file.
public getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string {
return this.forwardJSONCall(
"getNameOrDottedNameSpan(\"" + fileName + "\", " + startPos + ", " + endPos + ")",
"getNameOrDottedNameSpan('" + fileName + "', " + startPos + ", " + endPos + ")",
() => {
var spanInfo = this.languageService.getNameOrDottedNameSpan(fileName, startPos, endPos);
return spanInfo;
@ -547,7 +532,7 @@ module ts {
/// Computes span information of statement at the requested position in the active file.
public getBreakpointStatementAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getBreakpointStatementAtPosition(\"" + fileName + "\", " + position + ")",
"getBreakpointStatementAtPosition('" + fileName + "', " + position + ")",
() => {
var spanInfo = this.languageService.getBreakpointStatementAtPosition(fileName, position);
return spanInfo;
@ -555,32 +540,49 @@ module ts {
}
/// SIGNATUREHELP
/// Computes a string representation of the signatures at the requested position
/// in the active file.
public getSignatureAtPosition(fileName: string, position: number): string {
public getSignatureHelpItems(fileName: string, position: number): string {
return this.forwardJSONCall(
"getSignatureAtPosition(\"" + fileName + "\", " + position + ")",
"getSignatureHelpItems('" + fileName + "', " + position + ")",
() => {
var signatureInfo = this.languageService.getSignatureAtPosition(fileName, position);
var signatureInfo = this.languageService.getSignatureHelpItems(fileName, position);
return signatureInfo;
});
}
public getSignatureHelpCurrentArgumentState(fileName: string, position: number, applicableSpanStart: number): string {
return this.forwardJSONCall(
"getSignatureHelpCurrentArgumentState('" + fileName + "', " + position + ", " + applicableSpanStart + ")",
() => {
var signatureInfo = this.languageService.getSignatureHelpItems(fileName, position);
return signatureInfo;
});
}
/// GOTO DEFINITION
/// Computes the definition location and file for the symbol
/// at the requested position.
public getDefinitionAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getDefinitionAtPosition(\"" + fileName + "\", " + position + ")",
"getDefinitionAtPosition('" + fileName + "', " + position + ")",
() => {
return this.languageService.getDefinitionAtPosition(fileName, position);
});
}
public getRenameInfo(fileName: string, position: number): string {
return this.forwardJSONCall(
"getRenameInfo('" + fileName + "', " + position + ")",
() => {
return this.languageService.getRenameInfo(fileName, position);
});
}
/// GET BRACE MATCHING
public getBraceMatchingAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getBraceMatchingAtPosition(\"" + fileName + "\", " + position + ")",
"getBraceMatchingAtPosition('" + fileName + "', " + position + ")",
() => {
var textRanges = this.languageService.getBraceMatchingAtPosition(fileName, position);
return textRanges;
@ -590,11 +592,10 @@ module ts {
/// GET SMART INDENT
public getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string {
return this.forwardJSONCall(
"getIndentationAtPosition(\"" + fileName + "\", " + position + ")",
"getIndentationAtPosition('" + fileName + "', " + position + ")",
() => {
var localOptions: EditorOptions = JSON.parse(options);
var columnOffset = this.languageService.getIndentationAtPosition(fileName, position, localOptions);
return { value: columnOffset };
return this.languageService.getIndentationAtPosition(fileName, position, localOptions);
});
}
@ -604,7 +605,7 @@ module ts {
/// Each reference is a "fileindex min lim" sub-string.
public getReferencesAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getReferencesAtPosition(\"" + fileName + "\", " + position + ")",
"getReferencesAtPosition('" + fileName + "', " + position + ")",
() => {
return this.languageService.getReferencesAtPosition(fileName, position);
});
@ -612,7 +613,7 @@ module ts {
public getOccurrencesAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getOccurrencesAtPosition(\"" + fileName + "\", " + position + ")",
"getOccurrencesAtPosition('" + fileName + "', " + position + ")",
() => {
return this.languageService.getOccurrencesAtPosition(fileName, position);
});
@ -621,7 +622,7 @@ module ts {
/// GET IMPLEMENTORS
public getImplementorsAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getImplementorsAtPosition(\"" + fileName + "\", " + position + ")",
"getImplementorsAtPosition('" + fileName + "', " + position + ")",
() => {
return this.languageService.getImplementorsAtPosition(fileName, position);
});
@ -634,7 +635,7 @@ module ts {
/// list if requested.
public getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean) {
return this.forwardJSONCall(
"getCompletionsAtPosition(\"" + fileName + "\", " + position + ", " + isMemberCompletion + ")",
"getCompletionsAtPosition('" + fileName + "', " + position + ", " + isMemberCompletion + ")",
() => {
var completion = this.languageService.getCompletionsAtPosition(fileName, position, isMemberCompletion);
return completion;
@ -644,52 +645,38 @@ module ts {
/// Get a string based representation of a completion list entry details
public getCompletionEntryDetails(fileName: string, position: number, entryName: string) {
return this.forwardJSONCall(
"getCompletionEntryDetails(\"" + fileName + "\", " + position + ", " + entryName + ")",
"getCompletionEntryDetails('" + fileName + "', " + position + ", " + entryName + ")",
() => {
var details = this.languageService.getCompletionEntryDetails(fileName, position, entryName);
return details;
});
}
/// FORMAT SELECTION
public getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string {
public getFormattingEditsForRange(fileName: string, start: number, end: number, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsForRange(\"" + fileName + "\", " + minChar + ", " + limChar + ")",
"getFormattingEditsForRange('" + fileName + "', " + start + ", " + end + ")",
() => {
var localOptions: FormatCodeOptions = JSON.parse(options);
var edits = this.languageService.getFormattingEditsForRange(fileName, minChar, limChar, localOptions);
var localOptions: ts.FormatCodeOptions = JSON.parse(options);
var edits = this.languageService.getFormattingEditsForRange(fileName, start, end, localOptions);
return edits;
});
}
/// FORMAT DOCUMENT
public getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string {
public getFormattingEditsForDocument(fileName: string, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsForDocument(\"" + fileName + "\", " + minChar + ", " + limChar + ")",
"getFormattingEditsForDocument('" + fileName + "')",
() => {
var localOptions: FormatCodeOptions = JSON.parse(options);
var edits = this.languageService.getFormattingEditsForDocument(fileName, minChar, limChar, localOptions);
var localOptions: ts.FormatCodeOptions = JSON.parse(options);
var edits = this.languageService.getFormattingEditsForDocument(fileName, localOptions);
return edits;
});
}
/// FORMAT ON PASTE
public getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsOnPaste(\"" + fileName + "\", " + minChar + ", " + limChar + ")",
() => {
var localOptions: FormatCodeOptions = JSON.parse(options);
var edits = this.languageService.getFormattingEditsOnPaste(fileName, minChar, limChar, localOptions);
return edits;
});
}
/// FORMAT
public getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsAfterKeystroke(\"" + fileName + "\", " + position + ", \"" + key + "\")",
"getFormattingEditsAfterKeystroke('" + fileName + "', " + position + ", '" + key + "')",
() => {
var localOptions: FormatCodeOptions = JSON.parse(options);
var localOptions: ts.FormatCodeOptions = JSON.parse(options);
var edits = this.languageService.getFormattingEditsAfterKeystroke(fileName, position, key, localOptions);
return edits;
});
@ -699,91 +686,57 @@ module ts {
/// Return a list of symbols that are interesting to navigate to
public getNavigateToItems(searchValue: string): string {
return this.forwardJSONCall(
"getNavigateToItems(\"" + searchValue + "\")",
"getNavigateToItems('" + searchValue + "')",
() => {
var items = this.languageService.getNavigateToItems(searchValue);
var result = this._navigateToItemsToString(items);
return result;
return items;
});
}
// GET SCRIPT LEXICAL STRUCTURE
//
public getScriptLexicalStructure(fileName: string): string {
public getNavigationBarItems(fileName: string): string {
return this.forwardJSONCall(
"getScriptLexicalStructure(\"" + fileName + "\")",
"getNavigationBarItems('" + fileName + "')",
() => {
var items = this.languageService.getScriptLexicalStructure(fileName);
var result = this._navigateToItemsToString(items);
return result;
var items = this.languageService.getNavigationBarItems(fileName);
return items;
});
}
// GET OUTLINING REGIONS
//
public getOutliningRegions(fileName: string): string {
public getOutliningSpans(fileName: string): string {
return this.forwardJSONCall(
"getOutliningRegions(\"" + fileName + "\")",
"getOutliningSpans('" + fileName + "')",
() => {
var items = this.languageService.getOutliningRegions(fileName);
// return just the part of data that language service v2 can understand
// language service v2 will use the entire OutliningSpan
var spans = map(items, i => i.textSpan);
return spans;
var items = this.languageService.getOutliningSpans(fileName);
return items;
});
}
public getTodoComments(fileName: string, descriptors: string): string {
return this.forwardJSONCall(
"getTodoComments('" + fileName + "')",
() => {
var items = this.languageService.getTodoComments(fileName, JSON.parse(descriptors));
return items;
});
}
/// Emit
public getEmitOutput(fileName: string): string {
return this.forwardJSONCall(
"getEmitOutput(\"" + fileName + "\")",
"getEmitOutput('" + fileName + "')",
() => {
var output = this.languageService.getEmitOutput(fileName);
return output;
});
}
private _navigateToItemsToString(items: NavigateToItem[]): any {
var result: {
name: string;
kind: string;
kindModifiers: string;
containerName: string;
containerKind: string;
matchKind: string;
fileName: string;
minChar: number;
limChar: number;
additionalSpans?: { start: number; end: number; }[];
}[] = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
result.push({
name: item.name,
kind: item.kind,
kindModifiers: item.kindModifiers,
containerName: item.containerName,
containerKind: item.containerKind,
matchKind: item.matchKind,
fileName: item.fileName,
minChar: item.minChar,
limChar: item.limChar,
additionalSpans: item.additionalSpans ? item.additionalSpans.map(i => { return { start: i.minChar, end: i.limChar }; }) : undefined
});
}
return result;
}
}
class ClassifierShimObject extends ShimBase implements ClassifierShim {
public classifier: Classifier;
constructor(factory: ShimFactory, public host: Logger) {
constructor(factory: ShimFactory, public logger: Logger) {
super(factory);
this.classifier = createClassifier(this.host);
this.classifier = createClassifier(this.logger);
}
/// COLORIZATION
@ -801,12 +754,12 @@ module ts {
}
class CoreServicesShimObject extends ShimBase implements CoreServicesShim {
constructor(factory: ShimFactory, public host: Logger) {
constructor(factory: ShimFactory, public logger: Logger) {
super(factory);
}
private forwardJSONCall(actionDescription: string, action: () => any): any {
return forwardJSONCall(this.host, actionDescription, action);
return forwardJSONCall(this.logger, actionDescription, action);
}
///
@ -814,7 +767,7 @@ module ts {
///
public getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): string {
return this.forwardJSONCall(
"getPreProcessedFileInfo(\"" + fileName + "\")",
"getPreProcessedFileInfo('" + fileName + "')",
() => {
var result = TypeScript.preProcessFile(fileName, sourceText);
return result;
@ -849,22 +802,22 @@ module ts {
}
}
public createClassifierShim(host: Logger): ClassifierShim {
public createClassifierShim(logger: Logger): ClassifierShim {
try {
return new ClassifierShimObject(this, host);
return new ClassifierShimObject(this, logger);
}
catch (err) {
logInternalError(host, err);
logInternalError(logger, err);
throw err;
}
}
public createCoreServicesShim(host: Logger): CoreServicesShim {
public createCoreServicesShim(logger: Logger): CoreServicesShim {
try {
return new CoreServicesShimObject(this, host);
return new CoreServicesShimObject(this, logger);
}
catch (err) {
logInternalError(host, err);
logInternalError(logger, err);
throw err;
}
}

View file

@ -38,13 +38,15 @@ module TypeScript.Scanner {
// _packedFullStartAndInfo:
//
// 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 000x <-- has leading trivia
// 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 00x0 <-- has trailing trivia
// 0000 0000 0000 0000 0000 0000 0000 0000 00xx xxxx xxxx xxxx xxxx xxxx xxxx xx00 <-- full start
// 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 00x0 <-- has leading comment (implies has leading trivia)
// 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0x00 <-- has trailing trivia
// 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 x000 <-- has trailing comment (implies has trailing trivia)
// 0000 0000 0000 0000 0000 0000 0000 0000 00xx xxxx xxxx xxxx xxxx xxxx xxxx 0000 <-- full start
// ^ ^ ^
// | | |
// Bit 64 Bit 30 Bit 1
//
// This gives us 28 bits for the start of the token. At 256MB That's more than enough for
// This gives us 26 bits for the start of the token. At 64MB That's more than enough for
// any codebase.
//
// _packedFullWidthAndKind:
@ -58,31 +60,31 @@ module TypeScript.Scanner {
// This gives us 23bit for width (or 8MB of width which should be enough for any codebase).
enum ScannerConstants {
LargeTokenFullStartShift = 2,
LargeTokenFullStartShift = 4,
LargeTokenFullWidthShift = 7,
LargeTokenLeadingTriviaBitMask = 0x01, // 00000001
LargeTokenLeadingCommentBitMask = 0x02, // 00000010
LargeTokenTrailingTriviaBitMask = 0x04, // 00000100
LargeTokenTrailingCommentBitMask = 0x08, // 00001000
LargeTokenTriviaBitMask = 0x0F, // 00001111
FixedWidthTokenFullStartShift = 7,
FixedWidthTokenMaxFullStart = 0x7FFFFF, // 23 ones.
SmallTokenFullWidthShift = 7,
SmallTokenFullStartShift = 12,
SmallTokenMaxFullStart = 0x3FFFF, // 18 ones.
SmallTokenMaxFullWidth = 0x1F, // 5 ones
SmallTokenFullWidthMask = 0x1F, // 00011111
KindMask = 0x7F, // 01111111
IsVariableWidthMask = 0x80, // 10000000
LargeTokenLeadingTriviaBitMask = 0x01, // 00000001
LargeTokenTrailingTriviaBitMask = 0x02, // 00000010
SmallTokenFullWidthMask = 0x1F, // 00011111
FixedWidthTokenMaxFullStart = 0x7FFFFF, // 23 ones.
SmallTokenMaxFullStart = 0x3FFFF, // 18 ones.
SmallTokenMaxFullWidth = 0x1F, // 5 ones
}
// Make sure our math works for packing/unpacking large fullStarts.
Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(1 << 28, 1, 1)) === (1 << 28));
Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(3 << 27, 0, 1)) === (3 << 27));
Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(10 << 25, 1, 0)) === (10 << 25));
Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(1 << 26, 3)) === (1 << 26));
Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(3 << 25, 1)) === (3 << 25));
Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(10 << 23, 2)) === (10 << 23));
function fixedWidthTokenPackData(fullStart: number, kind: SyntaxKind) {
return (fullStart << ScannerConstants.FixedWidthTokenFullStartShift) | kind;
@ -94,8 +96,8 @@ module TypeScript.Scanner {
function smallTokenPackData(fullStart: number, fullWidth: number, kind: SyntaxKind) {
return (fullStart << ScannerConstants.SmallTokenFullStartShift) |
(fullWidth << ScannerConstants.SmallTokenFullWidthShift) |
kind;
(fullWidth << ScannerConstants.SmallTokenFullWidthShift) |
kind;
}
function smallTokenUnpackFullWidth(packedData: number): SyntaxKind {
@ -106,8 +108,8 @@ module TypeScript.Scanner {
return packedData >> ScannerConstants.SmallTokenFullStartShift;
}
function largeTokenPackFullStartAndInfo(fullStart: number, hasLeadingTriviaInfo: number, hasTrailingTriviaInfo: number): number {
return (fullStart << ScannerConstants.LargeTokenFullStartShift) | hasLeadingTriviaInfo | hasTrailingTriviaInfo;
function largeTokenPackFullStartAndInfo(fullStart: number, triviaInfo: number): number {
return (fullStart << ScannerConstants.LargeTokenFullStartShift) | triviaInfo;
}
function largeTokenUnpackFullWidth(packedFullWidthAndKind: number) {
@ -118,12 +120,24 @@ module TypeScript.Scanner {
return packedFullStartAndInfo >> ScannerConstants.LargeTokenFullStartShift;
}
function largeTokenUnpackHasLeadingTriviaInfo(packed: number): number {
return packed & ScannerConstants.LargeTokenLeadingTriviaBitMask;
function largeTokenUnpackHasLeadingTrivia(packed: number): boolean {
return (packed & ScannerConstants.LargeTokenLeadingTriviaBitMask) !== 0;
}
function largeTokenUnpackHasTrailingTriviaInfo(packed: number): number {
return packed & ScannerConstants.LargeTokenTrailingTriviaBitMask;
function largeTokenUnpackHasTrailingTrivia(packed: number): boolean {
return (packed & ScannerConstants.LargeTokenTrailingTriviaBitMask) !== 0;
}
function largeTokenUnpackHasLeadingComment(packed: number): boolean {
return (packed & ScannerConstants.LargeTokenLeadingCommentBitMask) !== 0;
}
function largeTokenUnpackHasTrailingComment(packed: number): boolean {
return (packed & ScannerConstants.LargeTokenTrailingCommentBitMask) !== 0;
}
function largeTokenUnpackTriviaInfo(packed: number): number {
return packed & ScannerConstants.LargeTokenTriviaBitMask;
}
var isKeywordStartCharacter: number[] = ArrayUtilities.createArray<number>(CharacterCodes.maxAsciiCharacter, 0);
@ -174,7 +188,7 @@ module TypeScript.Scanner {
var triviaScanner = createScannerInternal(ts.ScriptTarget.ES5, SimpleText.fromString(""), () => { });
interface IScannerToken extends ISyntaxToken {
interface IScannerToken extends ISyntaxToken {
}
function fillSizeInfo(token: IScannerToken, text: ISimpleText): void {
@ -256,6 +270,8 @@ module TypeScript.Scanner {
public fullStart(): number { return fixedWidthTokenUnpackFullStart(this._packedData); }
public hasLeadingTrivia(): boolean { return false; }
public hasTrailingTrivia(): boolean { return false; }
public hasLeadingComment(): boolean { return false; }
public hasTrailingComment(): boolean { return false; }
public clone(): ISyntaxToken { return new FixedWidthTokenWithNoTrivia(this._packedData); }
}
@ -271,19 +287,18 @@ module TypeScript.Scanner {
public setFullStart(fullStart: number): void {
this._packedFullStartAndInfo = largeTokenPackFullStartAndInfo(fullStart,
largeTokenUnpackHasLeadingTriviaInfo(this._packedFullStartAndInfo),
largeTokenUnpackHasTrailingTriviaInfo(this._packedFullStartAndInfo));
largeTokenUnpackTriviaInfo(this._packedFullStartAndInfo));
}
private syntaxTreeText(text: ISimpleText) {
private syntaxTreeText(text: ISimpleText) {
var result = text || syntaxTree(this).text;
Debug.assert(result);
return result;
}
public isIncrementallyUnusable(): boolean { return tokenIsIncrementallyUnusable(this); }
public isKeywordConvertedToIdentifier(): boolean { return false; }
public hasSkippedToken(): boolean { return false; }
public isIncrementallyUnusable(): boolean { return tokenIsIncrementallyUnusable(this); }
public isKeywordConvertedToIdentifier(): boolean { return false; }
public hasSkippedToken(): boolean { return false; }
public fullText(text?: ISimpleText): string {
return fullText(this, this.syntaxTreeText(text));
@ -294,8 +309,8 @@ module TypeScript.Scanner {
return cachedText !== undefined ? cachedText : SyntaxFacts.getText(this.kind());
}
public leadingTrivia(text?: ISimpleText): ISyntaxTriviaList { return leadingTrivia(this, this.syntaxTreeText(text)); }
public trailingTrivia(text?: ISimpleText): ISyntaxTriviaList { return trailingTrivia(this, this.syntaxTreeText(text)); }
public leadingTrivia(text?: ISimpleText): ISyntaxTriviaList { return leadingTrivia(this, this.syntaxTreeText(text)); }
public trailingTrivia(text?: ISimpleText): ISyntaxTriviaList { return trailingTrivia(this, this.syntaxTreeText(text)); }
public leadingTriviaWidth(text?: ISimpleText): number {
return leadingTriviaWidth(this, this.syntaxTreeText(text));
@ -308,8 +323,10 @@ module TypeScript.Scanner {
public kind(): SyntaxKind { return this._packedFullWidthAndKind & ScannerConstants.KindMask; }
public fullWidth(): number { return largeTokenUnpackFullWidth(this._packedFullWidthAndKind); }
public fullStart(): number { return largeTokenUnpackFullStart(this._packedFullStartAndInfo); }
public hasLeadingTrivia(): boolean { return largeTokenUnpackHasLeadingTriviaInfo(this._packedFullStartAndInfo) !== 0; }
public hasTrailingTrivia(): boolean { return largeTokenUnpackHasTrailingTriviaInfo(this._packedFullStartAndInfo) !== 0; }
public hasLeadingTrivia(): boolean { return largeTokenUnpackHasLeadingTrivia(this._packedFullStartAndInfo); }
public hasTrailingTrivia(): boolean { return largeTokenUnpackHasTrailingTrivia(this._packedFullStartAndInfo); }
public hasLeadingComment(): boolean { return largeTokenUnpackHasLeadingComment(this._packedFullStartAndInfo); }
public hasTrailingComment(): boolean { return largeTokenUnpackHasTrailingComment(this._packedFullStartAndInfo); }
public clone(): ISyntaxToken { return new LargeScannerToken(this._packedFullStartAndInfo, this._packedFullWidthAndKind, this.cachedText); }
}
@ -351,8 +368,8 @@ module TypeScript.Scanner {
}
function reset(_text: ISimpleText, _start: number, _end: number) {
Debug.assert(_start <= _text.length());
Debug.assert(_end <= _text.length());
Debug.assert(_start <= _text.length(), "Token's start was not within the bounds of text: " + _start + " - [0, " + _text.length() + ")");
Debug.assert(_end <= _text.length(), "Token's end was not within the bounds of text: " + _end + " - [0, " + _text.length() + ")");
if (!str || text !== _text) {
text = _text;
@ -392,7 +409,7 @@ module TypeScript.Scanner {
else {
// inline the packing logic for perf.
var packedFullStartAndTriviaInfo = (fullStart << ScannerConstants.LargeTokenFullStartShift) |
leadingTriviaInfo | (trailingTriviaInfo << 1);
leadingTriviaInfo | (trailingTriviaInfo << 2);
var packedFullWidthAndKind = (fullWidth << ScannerConstants.LargeTokenFullWidthShift) | kind;
var cachedText = isFixedWidth ? undefined : text.substr(start, end - start);
@ -505,7 +522,8 @@ module TypeScript.Scanner {
case CharacterCodes.verticalTab:
case CharacterCodes.formFeed:
index++;
result = 1;
// we have trivia
result |= 1;
continue;
case CharacterCodes.carriageReturn:
@ -516,27 +534,31 @@ module TypeScript.Scanner {
case CharacterCodes.lineFeed:
index++;
// we have trivia
result |= 1;
// If we're consuming leading trivia, then we will continue consuming more
// trivia (including newlines) up to the first token we see. If we're
// consuming trailing trivia, then we break after the first newline we see.
if (isTrailing) {
return 1;
return result;
}
result = 1;
continue;
case CharacterCodes.slash:
if ((index + 1) < _end) {
var ch2 = str.charCodeAt(index + 1);
if (ch2 === CharacterCodes.slash) {
result = 1;
// we have a comment, and we have trivia
result |= 3;
skipSingleLineCommentTrivia();
continue;
}
if (ch2 === CharacterCodes.asterisk) {
result = 1;
// we have a comment, and we have trivia
result |= 3;
skipMultiLineCommentTrivia();
continue;
}
@ -547,7 +569,7 @@ module TypeScript.Scanner {
default:
if (ch > CharacterCodes.maxAsciiCharacter && slowScanTriviaInfo(ch)) {
result = 1;
result |= 1;
continue;
}
@ -1427,7 +1449,7 @@ module TypeScript.Scanner {
var fullEnd = fullStart + token.fullWidth();
reset(text, fullStart, fullEnd);
var leadingTriviaInfo = scanTriviaInfo(/*isTrailing: */ false);
scanTriviaInfo(/*isTrailing: */ false);
var start = index;
scanSyntaxKind(isContextualToken(token));
@ -1616,6 +1638,8 @@ module TypeScript.Scanner {
}
function resetToPosition(absolutePosition: number): void {
Debug.assert(absolutePosition <= text.length(), "Trying to set the position outside the bounds of the text!");
_absolutePosition = absolutePosition;
// First, remove any diagnostics that came after this position.

View file

@ -17,6 +17,8 @@ module TypeScript {
hasLeadingTrivia(): boolean;
hasTrailingTrivia(): boolean;
hasLeadingComment(): boolean;
hasTrailingComment(): boolean;
hasSkippedToken(): boolean;
@ -264,7 +266,7 @@ module TypeScript.Syntax {
export function realizeToken(token: ISyntaxToken, text: ISimpleText): ISyntaxToken {
return new RealizedToken(token.fullStart(), token.kind(), token.isKeywordConvertedToIdentifier(), token.leadingTrivia(text), token.text(), token.trailingTrivia(text));
}
export function convertKeywordToIdentifier(token: ISyntaxToken): ISyntaxToken {
return new ConvertedKeywordToken(token);
}
@ -381,11 +383,14 @@ module TypeScript.Syntax {
public fullText(): string { return ""; }
public hasLeadingTrivia() { return false; }
public leadingTriviaWidth() { return 0; }
public hasTrailingTrivia() { return false; }
public hasLeadingComment() { return false; }
public hasTrailingComment() { return false; }
public hasSkippedToken() { return false; }
public leadingTriviaWidth() { return 0; }
public trailingTriviaWidth() { return 0; }
public leadingTrivia(): ISyntaxTriviaList { return Syntax.emptyTriviaList; }
public trailingTrivia(): ISyntaxTriviaList { return Syntax.emptyTriviaList; }
}
@ -401,11 +406,11 @@ module TypeScript.Syntax {
public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any;
constructor(fullStart: number,
kind: SyntaxKind,
isKeywordConvertedToIdentifier: boolean,
leadingTrivia: ISyntaxTriviaList,
text: string,
trailingTrivia: ISyntaxTriviaList) {
kind: SyntaxKind,
isKeywordConvertedToIdentifier: boolean,
leadingTrivia: ISyntaxTriviaList,
text: string,
trailingTrivia: ISyntaxTriviaList) {
this._fullStart = fullStart;
this._kind = kind;
this._isKeywordConvertedToIdentifier = isKeywordConvertedToIdentifier;
@ -438,8 +443,8 @@ module TypeScript.Syntax {
// Realized tokens are created from the parser. They are *never* incrementally reusable.
public isIncrementallyUnusable() { return true; }
public isKeywordConvertedToIdentifier() {
return this._isKeywordConvertedToIdentifier;
public isKeywordConvertedToIdentifier() {
return this._isKeywordConvertedToIdentifier;
}
public fullStart(): number { return this._fullStart; }
@ -450,6 +455,8 @@ module TypeScript.Syntax {
public hasLeadingTrivia(): boolean { return this._leadingTrivia.count() > 0; }
public hasTrailingTrivia(): boolean { return this._trailingTrivia.count() > 0; }
public hasLeadingComment(): boolean { return this._leadingTrivia.hasComment(); }
public hasTrailingComment(): boolean { return this._trailingTrivia.hasComment(); }
public leadingTriviaWidth(): number { return this._leadingTrivia.fullWidth(); }
public trailingTriviaWidth(): number { return this._trailingTrivia.fullWidth(); }
@ -504,6 +511,14 @@ module TypeScript.Syntax {
return this.underlyingToken.hasTrailingTrivia();
}
public hasLeadingComment(): boolean {
return this.underlyingToken.hasLeadingComment();
}
public hasTrailingComment(): boolean {
return this.underlyingToken.hasTrailingComment();
}
public hasSkippedToken(): boolean {
return this.underlyingToken.hasSkippedToken();
}

View file

@ -16,10 +16,12 @@ module TypeScript {
// always determine this (albeit in a more expensive manner).
getLineStartPositions(): number[];
// Returns a text change range representing what text has changed since the specified version.
// If the change cannot be determined (say, because a file was opened/closed), then 'null'
// should be returned.
getTextChangeRangeSinceVersion(scriptVersion: number): TextChangeRange;
// Gets the TextChangeRange that describe how the text changed between this text and
// an older version. This informatoin is used by the incremental parser to determine
// what sections of the script need to be reparsed. 'null' can be returned if the
// change range cannot be determined. However, in that case, incremental parsing will
// not happen and the entire document will be reparsed.
getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange;
}
export module ScriptSnapshot {
@ -45,7 +47,7 @@ module TypeScript {
return this._lineStartPositions;
}
public getTextChangeRangeSinceVersion(scriptVersion: number): TypeScript.TextChangeRange {
public getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange {
throw Errors.notYetImplemented();
}
}

View file

@ -27,6 +27,10 @@ module TypeScript {
this._length = length;
}
public toJSON(key: any): any {
return { start: this._start, length: this._length };
}
public start(): number {
return this._start;
}

View file

@ -0,0 +1,3 @@
//// // [|TODO|]
debugger;
verify.todoCommentsInCurrentFile(["TODO"]);

View file

@ -0,0 +1,6 @@
//// /*
//// [|todo 1|]
//// [|hack 2|]
//// */
debugger;
verify.todoCommentsInCurrentFile(["TODO", "HACK"]);

View file

@ -0,0 +1,6 @@
//// /*
//// [|TODO(jason) 1|]
//// [|HACK 2|]
//// */
debugger;
verify.todoCommentsInCurrentFile(["TODO(jason)", "HACK"]);

View file

@ -0,0 +1,6 @@
//// /*
//// [|TODO(jason) 1|]
//// [|HACK 2|]
//// */
debugger;
verify.todoCommentsInCurrentFile(["HACK", "TODO(jason)"]);

View file

@ -0,0 +1,4 @@
//// TODO
debugger;
verify.todoCommentsInCurrentFile(["TODO"]);

View file

@ -0,0 +1,3 @@
//// BAR // [|TODO|]
debugger;
verify.todoCommentsInCurrentFile(["TODO"]);

View file

@ -0,0 +1,3 @@
//// "// HACK 1";
debugger;
verify.todoCommentsInCurrentFile(["TODO(jason)", "HACK"]);

View file

@ -0,0 +1,3 @@
//// //// [|HACK 1|]
debugger;
verify.todoCommentsInCurrentFile(["TODO(jason)", "HACK"]);

View file

@ -0,0 +1,3 @@
//// /**** [|HACK 1 |]*/ a
debugger;
verify.todoCommentsInCurrentFile(["TODO(jason)", "HACK"]);

View file

@ -0,0 +1,3 @@
//// // not TODO
debugger;
verify.todoCommentsInCurrentFile(["TODO"]);

View file

@ -0,0 +1,3 @@
//// // [|TODO with stuff|]
debugger;
verify.todoCommentsInCurrentFile(["TODO"]);

View file

@ -0,0 +1,3 @@
//// // TODOnomatch
debugger;
verify.todoCommentsInCurrentFile(["TODO"]);

View file

@ -0,0 +1,6 @@
//// /*
//// [|TODO 1|]
//// [|TODO 2|]
//// */
debugger;
verify.todoCommentsInCurrentFile(["TODO"]);

View file

@ -0,0 +1,6 @@
//// /*
//// * [|TODO 1|]
//// * [|TODO 2|]
//// */
debugger;
verify.todoCommentsInCurrentFile(["TODO"]);

View file

@ -0,0 +1,6 @@
//// /*
//// [|TODO 1|]
//// [|HACK 2|]
//// */
debugger;
verify.todoCommentsInCurrentFile(["TODO", "HACK"]);

View file

@ -0,0 +1,6 @@
//// /*
//// [|HACK 1|]
//// [|TODO 2|]
//// */
debugger;
verify.todoCommentsInCurrentFile(["TODO", "HACK"]);

View file

@ -0,0 +1,6 @@
//// /*
//// [|TODO HACK|]
//// [|HACK TODO|]
//// */
debugger;
verify.todoCommentsInCurrentFile(["TODO", "HACK"]);