Merge branch 'master' into taggedSigHelp
This commit is contained in:
commit
4bf023982c
|
@ -9102,7 +9102,12 @@ module ts {
|
||||||
globalNumberType = getGlobalType("Number");
|
globalNumberType = getGlobalType("Number");
|
||||||
globalBooleanType = getGlobalType("Boolean");
|
globalBooleanType = getGlobalType("Boolean");
|
||||||
globalRegExpType = getGlobalType("RegExp");
|
globalRegExpType = getGlobalType("RegExp");
|
||||||
globalTemplateStringsArrayType = getGlobalType("TemplateStringsArray");
|
|
||||||
|
// If we're in ES6 mode, load the TemplateStringsArray.
|
||||||
|
// Otherwise, default to 'unknown' for the purposes of type checking in LS scenarios.
|
||||||
|
globalTemplateStringsArrayType = compilerOptions.target >= ScriptTarget.ES6
|
||||||
|
? getGlobalType("TemplateStringsArray")
|
||||||
|
: unknownType;
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeTypeChecker();
|
initializeTypeChecker();
|
||||||
|
|
|
@ -139,7 +139,7 @@ module ts {
|
||||||
function writeLiteral(s: string) {
|
function writeLiteral(s: string) {
|
||||||
if (s && s.length) {
|
if (s && s.length) {
|
||||||
write(s);
|
write(s);
|
||||||
var lineStartsOfS = getLineStarts(s);
|
var lineStartsOfS = computeLineStarts(s);
|
||||||
if (lineStartsOfS.length > 1) {
|
if (lineStartsOfS.length > 1) {
|
||||||
lineCount = lineCount + lineStartsOfS.length - 1;
|
lineCount = lineCount + lineStartsOfS.length - 1;
|
||||||
linePos = output.length - s.length + lineStartsOfS[lineStartsOfS.length - 1];
|
linePos = output.length - s.length + lineStartsOfS[lineStartsOfS.length - 1];
|
||||||
|
|
|
@ -957,18 +957,16 @@ module ts {
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function getLineAndCharacterlFromSourcePosition(position: number) {
|
function getLineStarts(): number[] {
|
||||||
if (!lineStarts) {
|
return lineStarts || (lineStarts = computeLineStarts(sourceText));
|
||||||
lineStarts = getLineStarts(sourceText);
|
|
||||||
}
|
}
|
||||||
return getLineAndCharacterOfPosition(lineStarts, position);
|
|
||||||
|
function getLineAndCharacterFromSourcePosition(position: number) {
|
||||||
|
return getLineAndCharacterOfPosition(getLineStarts(), position);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPositionFromSourceLineAndCharacter(line: number, character: number): number {
|
function getPositionFromSourceLineAndCharacter(line: number, character: number): number {
|
||||||
if (!lineStarts) {
|
return getPositionFromLineAndCharacter(getLineStarts(), line, character);
|
||||||
lineStarts = getLineStarts(sourceText);
|
|
||||||
}
|
|
||||||
return getPositionFromLineAndCharacter(lineStarts, line, character);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function error(message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void {
|
function error(message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void {
|
||||||
|
@ -1011,7 +1009,9 @@ module ts {
|
||||||
? file.syntacticErrors[file.syntacticErrors.length - 1].start
|
? file.syntacticErrors[file.syntacticErrors.length - 1].start
|
||||||
: -1;
|
: -1;
|
||||||
if (start !== lastErrorPos) {
|
if (start !== lastErrorPos) {
|
||||||
file.syntacticErrors.push(createFileDiagnostic(file, start, length, message, arg0, arg1, arg2));
|
var diagnostic = createFileDiagnostic(file, start, length, message, arg0, arg1, arg2);
|
||||||
|
diagnostic.isParseError = true;
|
||||||
|
file.syntacticErrors.push(diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lookAheadMode === LookAheadMode.NoErrorYet) {
|
if (lookAheadMode === LookAheadMode.NoErrorYet) {
|
||||||
|
@ -4282,8 +4282,9 @@ module ts {
|
||||||
file = <SourceFile>createRootNode(SyntaxKind.SourceFile, 0, sourceText.length, rootNodeFlags);
|
file = <SourceFile>createRootNode(SyntaxKind.SourceFile, 0, sourceText.length, rootNodeFlags);
|
||||||
file.filename = normalizePath(filename);
|
file.filename = normalizePath(filename);
|
||||||
file.text = sourceText;
|
file.text = sourceText;
|
||||||
file.getLineAndCharacterFromPosition = getLineAndCharacterlFromSourcePosition;
|
file.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition;
|
||||||
file.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter;
|
file.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter;
|
||||||
|
file.getLineStarts = getLineStarts;
|
||||||
file.syntacticErrors = [];
|
file.syntacticErrors = [];
|
||||||
file.semanticErrors = [];
|
file.semanticErrors = [];
|
||||||
var referenceComments = processReferenceComments();
|
var referenceComments = processReferenceComments();
|
||||||
|
|
|
@ -246,7 +246,7 @@ module ts {
|
||||||
return tokenStrings[t];
|
return tokenStrings[t];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLineStarts(text: string): number[] {
|
export function computeLineStarts(text: string): number[] {
|
||||||
var result: number[] = new Array();
|
var result: number[] = new Array();
|
||||||
var pos = 0;
|
var pos = 0;
|
||||||
var lineStart = 0;
|
var lineStart = 0;
|
||||||
|
@ -294,7 +294,7 @@ module ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function positionToLineAndCharacter(text: string, pos: number) {
|
export function positionToLineAndCharacter(text: string, pos: number) {
|
||||||
var lineStarts = getLineStarts(text);
|
var lineStarts = computeLineStarts(text);
|
||||||
return getLineAndCharacterOfPosition(lineStarts, pos);
|
return getLineAndCharacterOfPosition(lineStarts, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,11 @@ module ts {
|
||||||
FirstLiteralToken = NumericLiteral,
|
FirstLiteralToken = NumericLiteral,
|
||||||
LastLiteralToken = NoSubstitutionTemplateLiteral,
|
LastLiteralToken = NoSubstitutionTemplateLiteral,
|
||||||
FirstTemplateToken = NoSubstitutionTemplateLiteral,
|
FirstTemplateToken = NoSubstitutionTemplateLiteral,
|
||||||
LastTemplateToken = TemplateTail
|
LastTemplateToken = TemplateTail,
|
||||||
|
FirstOperator = SemicolonToken,
|
||||||
|
LastOperator = CaretEqualsToken,
|
||||||
|
FirstBinaryOperator = LessThanToken,
|
||||||
|
LastBinaryOperator = CaretEqualsToken
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum NodeFlags {
|
export const enum NodeFlags {
|
||||||
|
@ -627,8 +631,9 @@ module ts {
|
||||||
export interface SourceFile extends Block {
|
export interface SourceFile extends Block {
|
||||||
filename: string;
|
filename: string;
|
||||||
text: string;
|
text: string;
|
||||||
getLineAndCharacterFromPosition(position: number): { line: number; character: number };
|
getLineAndCharacterFromPosition(position: number): LineAndCharacter;
|
||||||
getPositionFromLineAndCharacter(line: number, character: number): number;
|
getPositionFromLineAndCharacter(line: number, character: number): number;
|
||||||
|
getLineStarts(): number[];
|
||||||
amdDependencies: string[];
|
amdDependencies: string[];
|
||||||
referencedFiles: FileReference[];
|
referencedFiles: FileReference[];
|
||||||
syntacticErrors: Diagnostic[];
|
syntacticErrors: Diagnostic[];
|
||||||
|
@ -1121,7 +1126,16 @@ module ts {
|
||||||
messageText: string;
|
messageText: string;
|
||||||
category: DiagnosticCategory;
|
category: DiagnosticCategory;
|
||||||
code: number;
|
code: number;
|
||||||
|
/**
|
||||||
|
* Early error - any error (can be produced at parsing\binding\typechecking step) that blocks emit
|
||||||
|
*/
|
||||||
isEarly?: boolean;
|
isEarly?: boolean;
|
||||||
|
/**
|
||||||
|
* Parse error - error produced by parser when it scanner returns a token
|
||||||
|
* that parser does not understand in its current state
|
||||||
|
* (as opposed to grammar error when parser can interpret the token but interpretation is not legal from the grammar perespective)
|
||||||
|
*/
|
||||||
|
isParseError?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DiagnosticCategory {
|
export enum DiagnosticCategory {
|
||||||
|
|
|
@ -1021,7 +1021,7 @@ module FourSlash {
|
||||||
var resultString = "SpanInfo: " + JSON.stringify(spanInfo);
|
var resultString = "SpanInfo: " + JSON.stringify(spanInfo);
|
||||||
if (spanInfo) {
|
if (spanInfo) {
|
||||||
var spanString = this.activeFile.content.substr(spanInfo.start(), spanInfo.length());
|
var spanString = this.activeFile.content.substr(spanInfo.start(), spanInfo.length());
|
||||||
var spanLineMap = ts.getLineStarts(spanString);
|
var spanLineMap = ts.computeLineStarts(spanString);
|
||||||
for (var i = 0; i < spanLineMap.length; i++) {
|
for (var i = 0; i < spanLineMap.length; i++) {
|
||||||
if (!i) {
|
if (!i) {
|
||||||
resultString += "\n";
|
resultString += "\n";
|
||||||
|
@ -1035,7 +1035,7 @@ module FourSlash {
|
||||||
}
|
}
|
||||||
|
|
||||||
private baselineCurrentFileLocations(getSpanAtPos: (pos: number) => TypeScript.TextSpan): string {
|
private baselineCurrentFileLocations(getSpanAtPos: (pos: number) => TypeScript.TextSpan): string {
|
||||||
var fileLineMap = ts.getLineStarts(this.activeFile.content);
|
var fileLineMap = ts.computeLineStarts(this.activeFile.content);
|
||||||
var nextLine = 0;
|
var nextLine = 0;
|
||||||
var resultString = "";
|
var resultString = "";
|
||||||
var currentLine: string;
|
var currentLine: string;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
/// <reference path='..\services\services.ts' />
|
/// <reference path='..\services\services.ts' />
|
||||||
/// <reference path='..\services\shims.ts' />
|
/// <reference path='..\services\shims.ts' />
|
||||||
|
/// <reference path='..\compiler\core.ts' />
|
||||||
/// <reference path='..\compiler\sys.ts' />
|
/// <reference path='..\compiler\sys.ts' />
|
||||||
/// <reference path='external\mocha.d.ts'/>
|
/// <reference path='external\mocha.d.ts'/>
|
||||||
/// <reference path='external\chai.d.ts'/>
|
/// <reference path='external\chai.d.ts'/>
|
||||||
|
@ -957,7 +958,7 @@ module Harness {
|
||||||
// Note: IE JS engine incorrectly handles consecutive delimiters here when using RegExp split, so
|
// Note: IE JS engine incorrectly handles consecutive delimiters here when using RegExp split, so
|
||||||
// we have to string-based splitting instead and try to figure out the delimiting chars
|
// we have to string-based splitting instead and try to figure out the delimiting chars
|
||||||
|
|
||||||
var lineStarts = ts.getLineStarts(inputFile.content);
|
var lineStarts = ts.computeLineStarts(inputFile.content);
|
||||||
var lines = inputFile.content.split('\n');
|
var lines = inputFile.content.split('\n');
|
||||||
lines.forEach((line, lineIndex) => {
|
lines.forEach((line, lineIndex) => {
|
||||||
if (line.length > 0 && line.charAt(line.length - 1) === '\r') {
|
if (line.length > 0 && line.charAt(line.length - 1) === '\r') {
|
||||||
|
@ -1002,8 +1003,12 @@ module Harness {
|
||||||
assert.equal(markedErrorCount, fileErrors.length, 'count of errors in ' + inputFile.unitName);
|
assert.equal(markedErrorCount, fileErrors.length, 'count of errors in ' + inputFile.unitName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var numLibraryDiagnostics = ts.countWhere(diagnostics, diagnostic => {
|
||||||
|
return diagnostic.filename && isLibraryFile(diagnostic.filename);
|
||||||
|
});
|
||||||
|
|
||||||
// Verify we didn't miss any errors in total
|
// Verify we didn't miss any errors in total
|
||||||
assert.equal(totalErrorsReported, diagnostics.length, 'total number of errors');
|
assert.equal(totalErrorsReported + numLibraryDiagnostics, diagnostics.length, 'total number of errors');
|
||||||
|
|
||||||
return minimalDiagnosticsToString(diagnostics) +
|
return minimalDiagnosticsToString(diagnostics) +
|
||||||
sys.newLine + sys.newLine + outputLines.join('\r\n');
|
sys.newLine + sys.newLine + outputLines.join('\r\n');
|
||||||
|
|
|
@ -223,7 +223,7 @@ module Harness.SourceMapRecoder {
|
||||||
sourceMapNames = sourceMapData.sourceMapNames;
|
sourceMapNames = sourceMapData.sourceMapNames;
|
||||||
|
|
||||||
jsFile = currentJsFile;
|
jsFile = currentJsFile;
|
||||||
jsLineMap = ts.getLineStarts(jsFile.code);
|
jsLineMap = ts.computeLineStarts(jsFile.code);
|
||||||
|
|
||||||
spansOnSingleLine = [];
|
spansOnSingleLine = [];
|
||||||
prevWrittenSourcePos = 0;
|
prevWrittenSourcePos = 0;
|
||||||
|
@ -294,7 +294,7 @@ module Harness.SourceMapRecoder {
|
||||||
sourceMapRecoder.WriteLine("sourceFile:" + sourceMapSources[spansOnSingleLine[0].sourceMapSpan.sourceIndex]);
|
sourceMapRecoder.WriteLine("sourceFile:" + sourceMapSources[spansOnSingleLine[0].sourceMapSpan.sourceIndex]);
|
||||||
sourceMapRecoder.WriteLine("-------------------------------------------------------------------");
|
sourceMapRecoder.WriteLine("-------------------------------------------------------------------");
|
||||||
|
|
||||||
tsLineMap = ts.getLineStarts(newSourceFileCode);
|
tsLineMap = ts.computeLineStarts(newSourceFileCode);
|
||||||
tsCode = newSourceFileCode;
|
tsCode = newSourceFileCode;
|
||||||
prevWrittenSourcePos = 0;
|
prevWrittenSourcePos = 0;
|
||||||
}
|
}
|
||||||
|
@ -390,7 +390,7 @@ module Harness.SourceMapRecoder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tsCodeLineMap = ts.getLineStarts(sourceText);
|
var tsCodeLineMap = ts.computeLineStarts(sourceText);
|
||||||
for (var i = 0; i < tsCodeLineMap.length; i++) {
|
for (var i = 0; i < tsCodeLineMap.length; i++) {
|
||||||
writeSourceMapIndent(prevEmittedCol, i == 0 ? markerIds[index] : " >");
|
writeSourceMapIndent(prevEmittedCol, i == 0 ? markerIds[index] : " >");
|
||||||
sourceMapRecoder.Write(getTextOfLine(i, tsCodeLineMap, sourceText));
|
sourceMapRecoder.Write(getTextOfLine(i, tsCodeLineMap, sourceText));
|
||||||
|
|
953
src/services/formatting.ts
Normal file
953
src/services/formatting.ts
Normal file
|
@ -0,0 +1,953 @@
|
||||||
|
///<reference path='services.ts' />
|
||||||
|
///<reference path='formatting\indentation.ts' />
|
||||||
|
///<reference path='formatting\formattingScanner.ts' />
|
||||||
|
///<reference path='formatting\rulesProvider.ts' />
|
||||||
|
|
||||||
|
module ts.formatting {
|
||||||
|
|
||||||
|
export interface TextRangeWithKind extends TextRange {
|
||||||
|
kind: SyntaxKind;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TokenInfo {
|
||||||
|
leadingTrivia: TextRangeWithKind[];
|
||||||
|
token: TextRangeWithKind;
|
||||||
|
trailingTrivia: TextRangeWithKind[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum Constants {
|
||||||
|
Unknown = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Indentation for the scope that can be dynamically recomputed.
|
||||||
|
* i.e
|
||||||
|
* while(true)
|
||||||
|
* { var x;
|
||||||
|
* }
|
||||||
|
* Normally indentation is applied only to the first token in line so at glance 'var' should not be touched.
|
||||||
|
* However if some format rule adds new line between '}' and 'var' 'var' will become
|
||||||
|
* the first token in line so it should be indented
|
||||||
|
*/
|
||||||
|
interface DynamicIndentation {
|
||||||
|
getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind): number;
|
||||||
|
getIndentationForComment(owningToken: SyntaxKind): number;
|
||||||
|
/**
|
||||||
|
* Indentation for open and close tokens of the node if it is block or another node that needs special indentation
|
||||||
|
* ... {
|
||||||
|
* .........<child>
|
||||||
|
* ....}
|
||||||
|
* ____ - indentation
|
||||||
|
* ____ - delta
|
||||||
|
**/
|
||||||
|
getIndentation(): number;
|
||||||
|
/**
|
||||||
|
* Prefered relative indentation for child nodes.
|
||||||
|
* Delta is used to carry the indentation info
|
||||||
|
* foo(bar({
|
||||||
|
* $
|
||||||
|
* }))
|
||||||
|
* Both 'foo', 'bar' introduce new indentation with delta = 4, but total indentation in $ is not 8.
|
||||||
|
* foo: { indentation: 0, delta: 4 }
|
||||||
|
* bar: { indentation: foo.indentation + foo.delta = 4, delta: 4} however 'foo' and 'bar' are on the same line
|
||||||
|
* so bar inherits indentation from foo and bar.delta will be 4
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
getDelta(): number;
|
||||||
|
/**
|
||||||
|
* Formatter calls this function when rule adds or deletes new lines from the text
|
||||||
|
* so indentation scope can adjust values of indentation and delta.
|
||||||
|
*/
|
||||||
|
recomputeIndentation(lineAddedByFormatting: boolean): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Indentation {
|
||||||
|
indentation: number;
|
||||||
|
delta: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatOnEnter(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||||
|
var line = sourceFile.getLineAndCharacterFromPosition(position).line;
|
||||||
|
Debug.assert(line >= 2);
|
||||||
|
// get the span for the previous\current line
|
||||||
|
var span = {
|
||||||
|
// get start position for the previous line
|
||||||
|
pos: getStartPositionOfLine(line - 1, sourceFile),
|
||||||
|
// get end position for the current line (end value is exclusive so add 1 to the result)
|
||||||
|
end: getEndLinePosition(line, sourceFile) + 1
|
||||||
|
}
|
||||||
|
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnEnter);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatOnSemicolon(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||||
|
return formatOutermostParent(position, SyntaxKind.SemicolonToken, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnSemicolon);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatOnClosingCurly(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||||
|
return formatOutermostParent(position, SyntaxKind.CloseBraceToken, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnClosingCurlyBrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatDocument(sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||||
|
var span = {
|
||||||
|
pos: 0,
|
||||||
|
end: sourceFile.text.length
|
||||||
|
};
|
||||||
|
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatSelection(start: number, end: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||||
|
// format from the beginning of the line
|
||||||
|
var span = {
|
||||||
|
pos: getStartLinePositionForPosition(start, sourceFile),
|
||||||
|
end: end
|
||||||
|
};
|
||||||
|
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatSelection);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatOutermostParent(position: number, expectedLastToken: SyntaxKind, sourceFile: SourceFile, options: FormatCodeOptions, rulesProvider: RulesProvider, requestKind: FormattingRequestKind): TextChange[] {
|
||||||
|
var parent = findOutermostParent(position, expectedLastToken, sourceFile);
|
||||||
|
if (!parent) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
var span = {
|
||||||
|
pos: getStartLinePositionForPosition(parent.getStart(sourceFile), sourceFile),
|
||||||
|
end: parent.end
|
||||||
|
};
|
||||||
|
return formatSpan(span, sourceFile, options, rulesProvider, requestKind);
|
||||||
|
}
|
||||||
|
|
||||||
|
function findOutermostParent(position: number, expectedTokenKind: SyntaxKind, sourceFile: SourceFile): Node {
|
||||||
|
var precedingToken = findPrecedingToken(position, sourceFile);
|
||||||
|
if (!precedingToken || precedingToken.kind !== expectedTokenKind) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// walk up and search for the parent node that ends at the same position with precedingToken.
|
||||||
|
// for cases like this
|
||||||
|
//
|
||||||
|
// var x = 1;
|
||||||
|
// while (true) {
|
||||||
|
// }
|
||||||
|
// after typing close curly in while statement we want to reformat just the while statement.
|
||||||
|
// However if we just walk upwards searching for the parent that has the same end value -
|
||||||
|
// we'll end up with the whole source file. isListElement allows to stop on the list element level
|
||||||
|
var current = precedingToken;
|
||||||
|
while (current &&
|
||||||
|
current.parent &&
|
||||||
|
current.parent.end === precedingToken.end &&
|
||||||
|
!isListElement(current.parent, current)) {
|
||||||
|
current = current.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if node is a element in some list in parent
|
||||||
|
// i.e. parent is class declaration with the list of members and node is one of members.
|
||||||
|
function isListElement(parent: Node, node: Node): boolean {
|
||||||
|
switch (parent.kind) {
|
||||||
|
case SyntaxKind.ClassDeclaration:
|
||||||
|
case SyntaxKind.InterfaceDeclaration:
|
||||||
|
return rangeContainsRange((<InterfaceDeclaration>parent).members, node);
|
||||||
|
case SyntaxKind.ModuleDeclaration:
|
||||||
|
var body = (<ModuleDeclaration>parent).body;
|
||||||
|
return body && body.kind === SyntaxKind.Block && rangeContainsRange((<Block>body).statements, node);
|
||||||
|
case SyntaxKind.SourceFile:
|
||||||
|
case SyntaxKind.Block:
|
||||||
|
case SyntaxKind.TryBlock:
|
||||||
|
case SyntaxKind.CatchBlock:
|
||||||
|
case SyntaxKind.FinallyBlock:
|
||||||
|
case SyntaxKind.ModuleBlock:
|
||||||
|
return rangeContainsRange((<Block>parent).statements, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** find node that fully contains given text range */
|
||||||
|
function findEnclosingNode(range: TextRange, sourceFile: SourceFile): Node {
|
||||||
|
return find(sourceFile);
|
||||||
|
|
||||||
|
function find(n: Node): Node {
|
||||||
|
var candidate = forEachChild(n, c => startEndContainsRange(c.getStart(sourceFile), c.end, range) && c);
|
||||||
|
if (candidate) {
|
||||||
|
var result = find(candidate);
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** formatting is not applied to ranges that contain parse errors.
|
||||||
|
* This function will return a predicate that for a given text range will tell
|
||||||
|
* if there are any parse errors that overlap with the range.
|
||||||
|
*/
|
||||||
|
function prepareRangeContainsErrorFunction(errors: Diagnostic[], originalRange: TextRange): (r: TextRange) => boolean {
|
||||||
|
if (!errors.length) {
|
||||||
|
return rangeHasNoErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pick only errors that fall in range
|
||||||
|
var sorted = errors
|
||||||
|
.filter(d => d.isParseError && rangeOverlapsWithStartEnd(originalRange, d.start, d.start + d.length))
|
||||||
|
.sort((e1, e2) => e1.start - e2.start);
|
||||||
|
|
||||||
|
if (!sorted.length) {
|
||||||
|
return rangeHasNoErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
|
||||||
|
return r => {
|
||||||
|
// in current implementation sequence of arguments [r1, r2...] is monotonically increasing.
|
||||||
|
// 'index' tracks the index of the most recent error that was checked.
|
||||||
|
while (true) {
|
||||||
|
if (index >= sorted.length) {
|
||||||
|
// all errors in the range were already checked -> no error in specified range
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var error = sorted[index];
|
||||||
|
if (r.end <= error.start) {
|
||||||
|
// specified range ends before the error refered by 'index' - no error in range
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startEndOverlapsWithStartEnd(r.pos, r.end, error.start, error.start + error.length)) {
|
||||||
|
// specified range overlaps with error range
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function rangeHasNoErrors(r: TextRange): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start of the original range might fall inside the comment - scanner will not yield appropriate results
|
||||||
|
* This function will look for token that is located before the start of target range
|
||||||
|
* and return its end as start position for the scanner.
|
||||||
|
*/
|
||||||
|
function getScanStartPosition(enclosingNode: Node, originalRange: TextRange, sourceFile: SourceFile): number {
|
||||||
|
var start = enclosingNode.getStart(sourceFile);
|
||||||
|
if (start === originalRange.pos && enclosingNode.end === originalRange.end) {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
var precedingToken = findPrecedingToken(enclosingNode.pos, sourceFile);
|
||||||
|
// no preceding token found - start from the beginning of enclosing node
|
||||||
|
return precedingToken ? precedingToken.end : enclosingNode.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSpan(originalRange: TextRange,
|
||||||
|
sourceFile: SourceFile,
|
||||||
|
options: FormatCodeOptions,
|
||||||
|
rulesProvider: RulesProvider,
|
||||||
|
requestKind: FormattingRequestKind): TextChange[] {
|
||||||
|
|
||||||
|
var rangeContainsError = prepareRangeContainsErrorFunction(sourceFile.syntacticErrors, originalRange);
|
||||||
|
|
||||||
|
// formatting context is used by rules provider
|
||||||
|
var formattingContext = new FormattingContext(sourceFile, requestKind);
|
||||||
|
|
||||||
|
// find the smallest node that fully wraps the range and compute the initial indentation for the node
|
||||||
|
var enclosingNode = findEnclosingNode(originalRange, sourceFile);
|
||||||
|
|
||||||
|
var formattingScanner = getFormattingScanner(sourceFile, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end);
|
||||||
|
|
||||||
|
var initialIndentation = SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options);
|
||||||
|
|
||||||
|
var previousRangeHasError: boolean;
|
||||||
|
var previousRange: TextRangeWithKind;
|
||||||
|
var previousParent: Node;
|
||||||
|
var previousRangeStartLine: number;
|
||||||
|
|
||||||
|
var edits: TextChange[] = [];
|
||||||
|
|
||||||
|
formattingScanner.advance();
|
||||||
|
|
||||||
|
if (formattingScanner.isOnToken()) {
|
||||||
|
var startLine = sourceFile.getLineAndCharacterFromPosition(enclosingNode.getStart(sourceFile)).line;
|
||||||
|
var delta = SmartIndenter.shouldIndentChildNode(enclosingNode.kind, SyntaxKind.Unknown) ? options.IndentSize : 0;
|
||||||
|
processNode(enclosingNode, enclosingNode, startLine, initialIndentation, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
formattingScanner.close();
|
||||||
|
|
||||||
|
return edits;
|
||||||
|
|
||||||
|
// local functions
|
||||||
|
|
||||||
|
/** Tries to compute the indentation for a list element.
|
||||||
|
* If list element is not in range then
|
||||||
|
* function will pick its actual indentation
|
||||||
|
* so it can be pushed downstream as inherited indentation.
|
||||||
|
* If list element is in the range - its indentation will be equal
|
||||||
|
* to inherited indentation from its predecessors.
|
||||||
|
*/
|
||||||
|
function tryComputeIndentationForListItem(startPos: number,
|
||||||
|
endPos: number,
|
||||||
|
parentStartLine: number,
|
||||||
|
range: TextRange,
|
||||||
|
inheritedIndentation: number): number {
|
||||||
|
|
||||||
|
if (rangeOverlapsWithStartEnd(range, startPos, endPos)) {
|
||||||
|
if (inheritedIndentation !== Constants.Unknown) {
|
||||||
|
return inheritedIndentation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var startLine = sourceFile.getLineAndCharacterFromPosition(startPos).line;
|
||||||
|
var startLinePosition = getStartLinePositionForPosition(startPos, sourceFile);
|
||||||
|
var column = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, startPos, sourceFile, options);
|
||||||
|
if (startLine !== parentStartLine || startPos === column) {
|
||||||
|
return column
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Constants.Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeIndentation(
|
||||||
|
node: TextRangeWithKind,
|
||||||
|
startLine: number,
|
||||||
|
inheritedIndentation: number,
|
||||||
|
parent: Node,
|
||||||
|
parentDynamicIndentation: DynamicIndentation,
|
||||||
|
effectiveParentStartLine: number): Indentation {
|
||||||
|
|
||||||
|
var indentation = inheritedIndentation;
|
||||||
|
if (indentation === Constants.Unknown) {
|
||||||
|
if (isSomeBlock(node.kind)) {
|
||||||
|
// blocks should be indented in
|
||||||
|
// - other blocks
|
||||||
|
// - source file
|
||||||
|
// - switch\default clauses
|
||||||
|
if (isSomeBlock(parent.kind) ||
|
||||||
|
parent.kind === SyntaxKind.SourceFile ||
|
||||||
|
parent.kind === SyntaxKind.CaseClause ||
|
||||||
|
parent.kind === SyntaxKind.DefaultClause) {
|
||||||
|
|
||||||
|
indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
indentation = parentDynamicIndentation.getIndentation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile)) {
|
||||||
|
indentation = parentDynamicIndentation.getIndentation();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var delta = SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown) ? options.IndentSize : 0;
|
||||||
|
|
||||||
|
if (effectiveParentStartLine === startLine) {
|
||||||
|
// if node is located on the same line with the parent
|
||||||
|
// - inherit indentation from the parent
|
||||||
|
// - push children if either parent of node itself has non-zero delta
|
||||||
|
indentation = parentDynamicIndentation.getIndentation();
|
||||||
|
delta = Math.min(options.IndentSize, parentDynamicIndentation.getDelta() + delta);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
indentation: indentation,
|
||||||
|
delta: delta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDynamicIndentation(node: Node, nodeStartLine: number, indentation: number, delta: number): DynamicIndentation {
|
||||||
|
return {
|
||||||
|
getIndentationForComment: kind => {
|
||||||
|
switch (kind) {
|
||||||
|
// preceding comment to the token that closes the indentation scope inherits the indentation from the scope
|
||||||
|
// .. {
|
||||||
|
// // comment
|
||||||
|
// }
|
||||||
|
case SyntaxKind.CloseBraceToken:
|
||||||
|
case SyntaxKind.CloseBracketToken:
|
||||||
|
return indentation + delta;
|
||||||
|
}
|
||||||
|
return indentation;
|
||||||
|
},
|
||||||
|
getIndentationForToken: (line, kind) => {
|
||||||
|
switch (kind) {
|
||||||
|
// open and close brace, 'else' and 'while' (in do statement) tokens has indentation of the parent
|
||||||
|
case SyntaxKind.OpenBraceToken:
|
||||||
|
case SyntaxKind.CloseBraceToken:
|
||||||
|
case SyntaxKind.OpenBracketToken:
|
||||||
|
case SyntaxKind.CloseBracketToken:
|
||||||
|
case SyntaxKind.ElseKeyword:
|
||||||
|
case SyntaxKind.WhileKeyword:
|
||||||
|
return indentation;
|
||||||
|
default:
|
||||||
|
// if token line equals to the line of containing node (this is a first token in the node) - use node indentation
|
||||||
|
return nodeStartLine !== line ? indentation + delta : indentation;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getIndentation: () => indentation,
|
||||||
|
getDelta: () => delta,
|
||||||
|
recomputeIndentation: lineAdded => {
|
||||||
|
if (node.parent && SmartIndenter.shouldIndentChildNode(node.parent.kind, node.kind)) {
|
||||||
|
if (lineAdded) {
|
||||||
|
indentation += options.IndentSize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
indentation -= options.IndentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown)) {
|
||||||
|
delta = options.IndentSize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delta = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processNode(node: Node, contextNode: Node, nodeStartLine: number, indentation: number, delta: number) {
|
||||||
|
if (!rangeOverlapsWithStartEnd(originalRange, node.getStart(sourceFile), node.getEnd())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodeDynamicIndentation = getDynamicIndentation(node, nodeStartLine, indentation, delta);
|
||||||
|
|
||||||
|
// a useful observations when tracking context node
|
||||||
|
// /
|
||||||
|
// [a]
|
||||||
|
// / | \
|
||||||
|
// [b] [c] [d]
|
||||||
|
// node 'a' is a context node for nodes 'b', 'c', 'd'
|
||||||
|
// except for the leftmost leaf token in [b] - in this case context node ('e') is located somewhere above 'a'
|
||||||
|
// this rule can be applied recursively to child nodes of 'a'.
|
||||||
|
//
|
||||||
|
// context node is set to parent node value after processing every child node
|
||||||
|
// context node is set to parent of the token after processing every token
|
||||||
|
|
||||||
|
var childContextNode = contextNode;
|
||||||
|
|
||||||
|
// if there are any tokens that logically belong to node and interleave child nodes
|
||||||
|
// such tokens will be consumed in processChildNode for for the child that follows them
|
||||||
|
forEachChild(
|
||||||
|
node,
|
||||||
|
child => {
|
||||||
|
processChildNode(child, /*inheritedIndentation*/ Constants.Unknown, node, nodeDynamicIndentation, nodeStartLine, /*isListElement*/ false)
|
||||||
|
},
|
||||||
|
(nodes: NodeArray<Node>) => {
|
||||||
|
processChildNodes(nodes, node, nodeStartLine, nodeDynamicIndentation);
|
||||||
|
});
|
||||||
|
|
||||||
|
// proceed any tokens in the node that are located after child nodes
|
||||||
|
while (formattingScanner.isOnToken()) {
|
||||||
|
var tokenInfo = formattingScanner.readTokenInfo(node);
|
||||||
|
if (tokenInfo.token.end > node.end) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
consumeTokenAndAdvanceScanner(tokenInfo, node, nodeDynamicIndentation);
|
||||||
|
}
|
||||||
|
|
||||||
|
function processChildNode(
|
||||||
|
child: Node,
|
||||||
|
inheritedIndentation: number,
|
||||||
|
parent: Node,
|
||||||
|
parentDynamicIndentation: DynamicIndentation,
|
||||||
|
parentStartLine: number,
|
||||||
|
isListItem: boolean): number {
|
||||||
|
|
||||||
|
var childStartPos = child.getStart(sourceFile);
|
||||||
|
|
||||||
|
var childStart = sourceFile.getLineAndCharacterFromPosition(childStartPos);
|
||||||
|
|
||||||
|
// if child is a list item - try to get its indentation
|
||||||
|
var childIndentationAmount = Constants.Unknown;
|
||||||
|
if (isListItem) {
|
||||||
|
childIndentationAmount = tryComputeIndentationForListItem(childStartPos, child.end, parentStartLine, originalRange, inheritedIndentation);
|
||||||
|
if (childIndentationAmount !== Constants.Unknown) {
|
||||||
|
inheritedIndentation = childIndentationAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// child node is outside the target range - do not dive inside
|
||||||
|
if (!rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) {
|
||||||
|
return inheritedIndentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child.kind === SyntaxKind.Missing) {
|
||||||
|
return inheritedIndentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (formattingScanner.isOnToken()) {
|
||||||
|
// proceed any parent tokens that are located prior to child.getStart()
|
||||||
|
var tokenInfo = formattingScanner.readTokenInfo(node);
|
||||||
|
if (tokenInfo.token.end > childStartPos) {
|
||||||
|
// stop when formatting scanner advances past the beginning of the child
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!formattingScanner.isOnToken()) {
|
||||||
|
return inheritedIndentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isToken(child)) {
|
||||||
|
// if child node is a token, it does not impact indentation, proceed it using parent indentation scope rules
|
||||||
|
var tokenInfo = formattingScanner.readTokenInfo(node);
|
||||||
|
Debug.assert(tokenInfo.token.end === child.end);
|
||||||
|
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation);
|
||||||
|
return inheritedIndentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
var childIndentation = computeIndentation(child, childStart.line, childIndentationAmount, node, parentDynamicIndentation, parentStartLine);
|
||||||
|
|
||||||
|
processNode(child, childContextNode, childStart.line, childIndentation.indentation, childIndentation.delta);
|
||||||
|
|
||||||
|
childContextNode = node;
|
||||||
|
|
||||||
|
return inheritedIndentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processChildNodes(nodes: NodeArray<Node>,
|
||||||
|
parent: Node,
|
||||||
|
parentStartLine: number,
|
||||||
|
parentDynamicIndentation: DynamicIndentation): void {
|
||||||
|
|
||||||
|
var listStartToken = getOpenTokenForList(parent, nodes);
|
||||||
|
var listEndToken = getCloseTokenForOpenToken(listStartToken);
|
||||||
|
|
||||||
|
var listDynamicIndentation = parentDynamicIndentation;
|
||||||
|
var startLine = parentStartLine;
|
||||||
|
|
||||||
|
if (listStartToken !== SyntaxKind.Unknown) {
|
||||||
|
// introduce a new indentation scope for lists (including list start and end tokens)
|
||||||
|
while (formattingScanner.isOnToken()) {
|
||||||
|
var tokenInfo = formattingScanner.readTokenInfo(parent);
|
||||||
|
if (tokenInfo.token.end > nodes.pos) {
|
||||||
|
// stop when formatting scanner moves past the beginning of node list
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (tokenInfo.token.kind === listStartToken) {
|
||||||
|
// consume list start token
|
||||||
|
startLine = sourceFile.getLineAndCharacterFromPosition(tokenInfo.token.pos).line;
|
||||||
|
var indentation =
|
||||||
|
computeIndentation(tokenInfo.token, startLine, Constants.Unknown, parent, parentDynamicIndentation, startLine);
|
||||||
|
|
||||||
|
listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation.indentation, indentation.delta);
|
||||||
|
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// consume any tokens that precede the list as child elements of 'node' using its indentation scope
|
||||||
|
consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var inheritedIndentation = Constants.Unknown;
|
||||||
|
for (var i = 0, len = nodes.length; i < len; ++i) {
|
||||||
|
inheritedIndentation = processChildNode(nodes[i], inheritedIndentation, node, listDynamicIndentation, startLine, /*isListElement*/ true)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listEndToken !== SyntaxKind.Unknown) {
|
||||||
|
if (formattingScanner.isOnToken()) {
|
||||||
|
var tokenInfo = formattingScanner.readTokenInfo(parent);
|
||||||
|
if (tokenInfo.token.kind === listEndToken) {
|
||||||
|
// consume list end token
|
||||||
|
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation): void {
|
||||||
|
Debug.assert(rangeContainsRange(parent, currentTokenInfo.token));
|
||||||
|
|
||||||
|
var lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine();
|
||||||
|
var indentToken = false;
|
||||||
|
|
||||||
|
if (currentTokenInfo.leadingTrivia) {
|
||||||
|
processTrivia(currentTokenInfo.leadingTrivia, parent, childContextNode, dynamicIndentation);
|
||||||
|
}
|
||||||
|
|
||||||
|
var lineAdded: boolean;
|
||||||
|
var isTokenInRange = rangeContainsRange(originalRange, currentTokenInfo.token);
|
||||||
|
|
||||||
|
var tokenStart = sourceFile.getLineAndCharacterFromPosition(currentTokenInfo.token.pos);
|
||||||
|
if (isTokenInRange) {
|
||||||
|
// save prevStartLine since processRange will overwrite this value with current ones
|
||||||
|
var prevStartLine = previousRangeStartLine;
|
||||||
|
lineAdded = processRange(currentTokenInfo.token, tokenStart, parent, childContextNode, dynamicIndentation);
|
||||||
|
if (lineAdded !== undefined) {
|
||||||
|
indentToken = lineAdded;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
indentToken = lastTriviaWasNewLine && tokenStart.line !== prevStartLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentTokenInfo.trailingTrivia) {
|
||||||
|
processTrivia(currentTokenInfo.trailingTrivia, parent, childContextNode, dynamicIndentation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indentToken) {
|
||||||
|
var indentNextTokenOrTrivia = true;
|
||||||
|
if (currentTokenInfo.leadingTrivia) {
|
||||||
|
for (var i = 0, len = currentTokenInfo.leadingTrivia.length; i < len; ++i) {
|
||||||
|
var triviaItem = currentTokenInfo.leadingTrivia[i];
|
||||||
|
if (!rangeContainsRange(originalRange, triviaItem)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var triviaStartLine = sourceFile.getLineAndCharacterFromPosition(triviaItem.pos).line;
|
||||||
|
switch (triviaItem.kind) {
|
||||||
|
case SyntaxKind.MultiLineCommentTrivia:
|
||||||
|
var commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind);
|
||||||
|
indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia);
|
||||||
|
indentNextTokenOrTrivia = false;
|
||||||
|
break;
|
||||||
|
case SyntaxKind.SingleLineCommentTrivia:
|
||||||
|
if (indentNextTokenOrTrivia) {
|
||||||
|
var commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind);
|
||||||
|
insertIndentation(triviaItem.pos, commentIndentation, /*lineAdded*/ false);
|
||||||
|
indentNextTokenOrTrivia = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SyntaxKind.NewLineTrivia:
|
||||||
|
indentNextTokenOrTrivia = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// indent token only if is it is in target range and does not overlap with any error ranges
|
||||||
|
if (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) {
|
||||||
|
var tokenIndentation = dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind);
|
||||||
|
insertIndentation(currentTokenInfo.token.pos, tokenIndentation, lineAdded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formattingScanner.advance();
|
||||||
|
|
||||||
|
childContextNode = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processTrivia(trivia: TextRangeWithKind[], parent: Node, contextNode: Node, dynamicIndentation: DynamicIndentation): void {
|
||||||
|
for (var i = 0, len = trivia.length; i < len; ++i) {
|
||||||
|
var triviaItem = trivia[i];
|
||||||
|
if (isComment(triviaItem.kind) && rangeContainsRange(originalRange, triviaItem)) {
|
||||||
|
var triviaItemStart = sourceFile.getLineAndCharacterFromPosition(triviaItem.pos);
|
||||||
|
processRange(triviaItem, triviaItemStart, parent, contextNode, dynamicIndentation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processRange(range: TextRangeWithKind,
|
||||||
|
rangeStart: LineAndCharacter,
|
||||||
|
parent: Node,
|
||||||
|
contextNode: Node,
|
||||||
|
dynamicIndentation: DynamicIndentation): boolean {
|
||||||
|
|
||||||
|
var rangeHasError = rangeContainsError(range);
|
||||||
|
var lineAdded: boolean;
|
||||||
|
if (!rangeHasError && !previousRangeHasError) {
|
||||||
|
if (!previousRange) {
|
||||||
|
// trim whitespaces starting from the beginning of the span up to the current line
|
||||||
|
var originalStart = sourceFile.getLineAndCharacterFromPosition(originalRange.pos);
|
||||||
|
trimTrailingWhitespacesForLines(originalStart.line, rangeStart.line);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lineAdded =
|
||||||
|
processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, dynamicIndentation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previousRange = range;
|
||||||
|
previousParent = parent;
|
||||||
|
previousRangeStartLine = rangeStart.line;
|
||||||
|
previousRangeHasError = rangeHasError;
|
||||||
|
|
||||||
|
return lineAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
function processPair(currentItem: TextRangeWithKind,
|
||||||
|
currentStartLine: number,
|
||||||
|
currentParent: Node,
|
||||||
|
previousItem: TextRangeWithKind,
|
||||||
|
previousStartLine: number,
|
||||||
|
previousParent: Node,
|
||||||
|
contextNode: Node,
|
||||||
|
dynamicIndentation: DynamicIndentation): boolean {
|
||||||
|
|
||||||
|
formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode);
|
||||||
|
|
||||||
|
var rule = rulesProvider.getRulesMap().GetRule(formattingContext);
|
||||||
|
|
||||||
|
var trimTrailingWhitespaces: boolean;
|
||||||
|
var lineAdded: boolean;
|
||||||
|
if (rule) {
|
||||||
|
applyRuleEdits(rule, previousItem, previousStartLine, currentItem, currentStartLine);
|
||||||
|
|
||||||
|
if (rule.Operation.Action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) {
|
||||||
|
// Handle the case where the next line is moved to be the end of this line.
|
||||||
|
// In this case we don't indent the next line in the next pass.
|
||||||
|
if (currentParent.getStart(sourceFile) === currentItem.pos) {
|
||||||
|
lineAdded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rule.Operation.Action & RuleAction.NewLine && currentStartLine === previousStartLine) {
|
||||||
|
// Handle the case where token2 is moved to the new line.
|
||||||
|
// In this case we indent token2 in the next pass but we set
|
||||||
|
// sameLineIndent flag to notify the indenter that the indentation is within the line.
|
||||||
|
if (currentParent.getStart(sourceFile) === currentItem.pos) {
|
||||||
|
lineAdded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lineAdded !== undefined) {
|
||||||
|
dynamicIndentation.recomputeIndentation(lineAdded);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
|
||||||
|
trimTrailingWhitespaces =
|
||||||
|
(rule.Operation.Action & (RuleAction.NewLine | RuleAction.Space)) &&
|
||||||
|
rule.Flag !== RuleFlags.CanDeleteNewLines;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
trimTrailingWhitespaces = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentStartLine !== previousStartLine && trimTrailingWhitespaces) {
|
||||||
|
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
|
||||||
|
trimTrailingWhitespacesForLines(previousStartLine, currentStartLine, previousItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lineAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertIndentation(pos: number, indentation: number, lineAdded: boolean): void {
|
||||||
|
var indentationString = getIndentationString(indentation, options);
|
||||||
|
if (lineAdded) {
|
||||||
|
// new line is added before the token by the formatting rules
|
||||||
|
// insert indentation string at the very beginning of the token
|
||||||
|
recordReplace(pos, 0, indentationString);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var tokenStart = sourceFile.getLineAndCharacterFromPosition(pos);
|
||||||
|
if (indentation !== tokenStart.character - 1) {
|
||||||
|
var startLinePosition = getStartPositionOfLine(tokenStart.line, sourceFile);
|
||||||
|
recordReplace(startLinePosition, tokenStart.character - 1, indentationString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function indentMultilineComment(commentRange: TextRange, indentation: number, firstLineIsIndented: boolean) {
|
||||||
|
// split comment in lines
|
||||||
|
var startLine = sourceFile.getLineAndCharacterFromPosition(commentRange.pos).line;
|
||||||
|
var endLine = sourceFile.getLineAndCharacterFromPosition(commentRange.end).line;
|
||||||
|
|
||||||
|
if (startLine === endLine) {
|
||||||
|
if (!firstLineIsIndented) {
|
||||||
|
// treat as single line comment
|
||||||
|
insertIndentation(commentRange.pos, indentation, /*lineAdded*/ false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var parts: TextRange[] = [];
|
||||||
|
var startPos = commentRange.pos;
|
||||||
|
for (var line = startLine; line < endLine; ++line) {
|
||||||
|
var endOfLine = getEndLinePosition(line, sourceFile);
|
||||||
|
parts.push({ pos: startPos, end: endOfLine });
|
||||||
|
startPos = getStartPositionOfLine(line + 1, sourceFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.push({ pos: startPos, end: commentRange.end });
|
||||||
|
}
|
||||||
|
|
||||||
|
var startLinePos = getStartPositionOfLine(startLine, sourceFile);
|
||||||
|
|
||||||
|
var nonWhitespaceColumnInFirstPart =
|
||||||
|
SmartIndenter.findFirstNonWhitespaceColumn(startLinePos, parts[0].pos, sourceFile, options);
|
||||||
|
|
||||||
|
if (indentation === nonWhitespaceColumnInFirstPart) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var startIndex = 0;
|
||||||
|
if (firstLineIsIndented) {
|
||||||
|
startIndex = 1;
|
||||||
|
startLine++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shift all parts on the delta size
|
||||||
|
var delta = indentation - nonWhitespaceColumnInFirstPart;
|
||||||
|
for (var i = startIndex, len = parts.length; i < len; ++i, ++startLine) {
|
||||||
|
var startLinePos = getStartPositionOfLine(startLine, sourceFile);
|
||||||
|
var nonWhitespaceColumn =
|
||||||
|
i === 0
|
||||||
|
? nonWhitespaceColumnInFirstPart
|
||||||
|
: SmartIndenter.findFirstNonWhitespaceColumn(parts[i].pos, parts[i].end, sourceFile, options);
|
||||||
|
|
||||||
|
var newIndentation = nonWhitespaceColumn + delta;
|
||||||
|
if (newIndentation > 0) {
|
||||||
|
var indentationString = getIndentationString(newIndentation, options);
|
||||||
|
recordReplace(startLinePos, nonWhitespaceColumn, indentationString);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
recordDelete(startLinePos, nonWhitespaceColumn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function trimTrailingWhitespacesForLines(line1: number, line2: number, range?: TextRangeWithKind) {
|
||||||
|
for (var line = line1; line < line2; ++line) {
|
||||||
|
var lineStartPosition = getStartPositionOfLine(line, sourceFile);
|
||||||
|
var lineEndPosition = getEndLinePosition(line, sourceFile);
|
||||||
|
|
||||||
|
// do not trim whitespaces in comments
|
||||||
|
if (range && isComment(range.kind) && range.pos <= lineEndPosition && range.end > lineEndPosition) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos = lineEndPosition;
|
||||||
|
while (pos >= lineStartPosition && isWhiteSpace(sourceFile.text.charCodeAt(pos))) {
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
if (pos !== lineEndPosition) {
|
||||||
|
Debug.assert(pos === lineStartPosition || !isWhiteSpace(sourceFile.text.charCodeAt(pos)));
|
||||||
|
recordDelete(pos + 1, lineEndPosition - pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function newTextChange(start: number, len: number, newText: string): TextChange {
|
||||||
|
return { span: new TypeScript.TextSpan(start, len), newText: newText }
|
||||||
|
}
|
||||||
|
|
||||||
|
function recordDelete(start: number, len: number) {
|
||||||
|
if (len) {
|
||||||
|
edits.push(newTextChange(start, len, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function recordReplace(start: number, len: number, newText: string) {
|
||||||
|
if (len || newText) {
|
||||||
|
edits.push(newTextChange(start, len, newText));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyRuleEdits(rule: Rule,
|
||||||
|
previousRange: TextRangeWithKind,
|
||||||
|
previousStartLine: number,
|
||||||
|
currentRange: TextRangeWithKind,
|
||||||
|
currentStartLine: number): void {
|
||||||
|
|
||||||
|
var between: TextRange;
|
||||||
|
switch (rule.Operation.Action) {
|
||||||
|
case RuleAction.Ignore:
|
||||||
|
// no action required
|
||||||
|
return;
|
||||||
|
case RuleAction.Delete:
|
||||||
|
if (previousRange.end !== currentRange.pos) {
|
||||||
|
// delete characters starting from t1.end up to t2.pos exclusive
|
||||||
|
recordDelete(previousRange.end, currentRange.pos - previousRange.end);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RuleAction.NewLine:
|
||||||
|
// exit early if we on different lines and rule cannot change number of newlines
|
||||||
|
// if line1 and line2 are on subsequent lines then no edits are required - ok to exit
|
||||||
|
// if line1 and line2 are separated with more than one newline - ok to exit since we cannot delete extra new lines
|
||||||
|
if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// edit should not be applied only if we have one line feed between elements
|
||||||
|
var lineDelta = currentStartLine - previousStartLine;
|
||||||
|
if (lineDelta !== 1) {
|
||||||
|
recordReplace(previousRange.end, currentRange.pos - previousRange.end, options.NewLineCharacter);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RuleAction.Space:
|
||||||
|
// exit early if we on different lines and rule cannot change number of newlines
|
||||||
|
if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var posDelta = currentRange.pos - previousRange.end;
|
||||||
|
if (posDelta !== 1 || sourceFile.text.charCodeAt(previousRange.end) !== CharacterCodes.space) {
|
||||||
|
recordReplace(previousRange.end, currentRange.pos - previousRange.end, " ");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSomeBlock(kind: SyntaxKind): boolean {
|
||||||
|
switch (kind) {
|
||||||
|
case SyntaxKind.Block:
|
||||||
|
case SyntaxKind.FunctionBlock:
|
||||||
|
case SyntaxKind.TryBlock:
|
||||||
|
case SyntaxKind.CatchBlock:
|
||||||
|
case SyntaxKind.FinallyBlock:
|
||||||
|
case SyntaxKind.ModuleBlock:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getOpenTokenForList(node: Node, list: Node[]) {
|
||||||
|
switch (node.kind) {
|
||||||
|
case SyntaxKind.Constructor:
|
||||||
|
case SyntaxKind.FunctionDeclaration:
|
||||||
|
case SyntaxKind.FunctionExpression:
|
||||||
|
case SyntaxKind.Method:
|
||||||
|
case SyntaxKind.ArrowFunction:
|
||||||
|
if ((<FunctionDeclaration>node).typeParameters === list) {
|
||||||
|
return SyntaxKind.LessThanToken;
|
||||||
|
}
|
||||||
|
else if ((<FunctionDeclaration>node).parameters === list) {
|
||||||
|
return SyntaxKind.OpenParenToken;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SyntaxKind.CallExpression:
|
||||||
|
case SyntaxKind.NewExpression:
|
||||||
|
if ((<CallExpression>node).typeArguments === list) {
|
||||||
|
return SyntaxKind.LessThanToken;
|
||||||
|
}
|
||||||
|
else if ((<CallExpression>node).arguments === list) {
|
||||||
|
return SyntaxKind.OpenParenToken;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SyntaxKind.TypeReference:
|
||||||
|
if ((<TypeReferenceNode>node).typeArguments === list) {
|
||||||
|
return SyntaxKind.LessThanToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SyntaxKind.Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCloseTokenForOpenToken(kind: SyntaxKind) {
|
||||||
|
switch (kind) {
|
||||||
|
case SyntaxKind.OpenParenToken:
|
||||||
|
return SyntaxKind.CloseParenToken;
|
||||||
|
case SyntaxKind.LessThanToken:
|
||||||
|
return SyntaxKind.GreaterThanToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SyntaxKind.Unknown;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,315 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
|
||||||
export class Formatter extends MultipleTokenIndenter {
|
|
||||||
private previousTokenSpan: TokenSpan = null;
|
|
||||||
private previousTokenParent: IndentationNodeContext = null;
|
|
||||||
|
|
||||||
// TODO: implement it with skipped tokens in Fidelity
|
|
||||||
private scriptHasErrors: boolean = false;
|
|
||||||
|
|
||||||
private rulesProvider: RulesProvider;
|
|
||||||
private formattingRequestKind: FormattingRequestKind;
|
|
||||||
private formattingContext: FormattingContext;
|
|
||||||
|
|
||||||
constructor(textSpan: TextSpan,
|
|
||||||
sourceUnit: SourceUnitSyntax,
|
|
||||||
indentFirstToken: boolean,
|
|
||||||
options: FormattingOptions,
|
|
||||||
snapshot: ITextSnapshot,
|
|
||||||
rulesProvider: RulesProvider,
|
|
||||||
formattingRequestKind: FormattingRequestKind) {
|
|
||||||
|
|
||||||
super(textSpan, sourceUnit, snapshot, indentFirstToken, options);
|
|
||||||
|
|
||||||
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
|
|
||||||
|
|
||||||
this.rulesProvider = rulesProvider;
|
|
||||||
this.formattingRequestKind = formattingRequestKind;
|
|
||||||
this.formattingContext = new FormattingContext(this.snapshot(), this.formattingRequestKind);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static getEdits(textSpan: TextSpan,
|
|
||||||
sourceUnit: SourceUnitSyntax,
|
|
||||||
options: FormattingOptions,
|
|
||||||
indentFirstToken: boolean,
|
|
||||||
snapshot: ITextSnapshot,
|
|
||||||
rulesProvider: RulesProvider,
|
|
||||||
formattingRequestKind: FormattingRequestKind): TextEditInfo[] {
|
|
||||||
var walker = new Formatter(textSpan, sourceUnit, indentFirstToken, options, snapshot, rulesProvider, formattingRequestKind);
|
|
||||||
walker.walk(sourceUnit);
|
|
||||||
return walker.edits();
|
|
||||||
}
|
|
||||||
|
|
||||||
public visitTokenInSpan(token: ISyntaxToken): void {
|
|
||||||
if (token.fullWidth() !== 0) {
|
|
||||||
var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token));
|
|
||||||
if (this.textSpan().containsTextSpan(tokenSpan)) {
|
|
||||||
this.processToken(token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call the base class to process the token and indent it if needed
|
|
||||||
super.visitTokenInSpan(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private processToken(token: ISyntaxToken): void {
|
|
||||||
var position = this.position();
|
|
||||||
|
|
||||||
// Extract any leading comments
|
|
||||||
if (token.leadingTriviaWidth() !== 0) {
|
|
||||||
this.processTrivia(token.leadingTrivia(), position);
|
|
||||||
position += token.leadingTriviaWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push the token
|
|
||||||
var currentTokenSpan = new TokenSpan(token.kind, position, width(token));
|
|
||||||
if (!this.parent().hasSkippedOrMissingTokenChild()) {
|
|
||||||
if (this.previousTokenSpan) {
|
|
||||||
// Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens
|
|
||||||
this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia
|
|
||||||
this.trimWhitespaceInLineRange(this.getLineNumber(this.textSpan()), this.getLineNumber(currentTokenSpan));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.previousTokenSpan = currentTokenSpan;
|
|
||||||
if (this.previousTokenParent) {
|
|
||||||
// Make sure to clear the previous parent before assigning a new value to it
|
|
||||||
this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true);
|
|
||||||
}
|
|
||||||
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
|
|
||||||
position += width(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private processTrivia(triviaList: ISyntaxTriviaList, fullStart: number) {
|
|
||||||
var position = fullStart;
|
|
||||||
|
|
||||||
for (var i = 0, n = triviaList.count(); i < n ; i++) {
|
|
||||||
var trivia = triviaList.syntaxTriviaAt(i);
|
|
||||||
// For a comment, format it like it is a token. For skipped text, eat it up as a token, but skip the formatting
|
|
||||||
if (trivia.isComment() || trivia.isSkippedToken()) {
|
|
||||||
var currentTokenSpan = new TokenSpan(trivia.kind, position, trivia.fullWidth());
|
|
||||||
if (this.textSpan().containsTextSpan(currentTokenSpan)) {
|
|
||||||
if (trivia.isComment() && this.previousTokenSpan) {
|
|
||||||
// Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens
|
|
||||||
this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia
|
|
||||||
var startLine = this.getLineNumber(this.previousTokenSpan || this.textSpan());
|
|
||||||
this.trimWhitespaceInLineRange(startLine, this.getLineNumber(currentTokenSpan));
|
|
||||||
}
|
|
||||||
this.previousTokenSpan = currentTokenSpan;
|
|
||||||
if (this.previousTokenParent) {
|
|
||||||
// Make sure to clear the previous parent before assigning a new value to it
|
|
||||||
this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true);
|
|
||||||
}
|
|
||||||
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
position += trivia.fullWidth();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private findCommonParents(parent1: IndentationNodeContext, parent2: IndentationNodeContext): IndentationNodeContext {
|
|
||||||
// TODO: disable debug assert message
|
|
||||||
|
|
||||||
var shallowParent: IndentationNodeContext;
|
|
||||||
var shallowParentDepth: number;
|
|
||||||
var deepParent: IndentationNodeContext;
|
|
||||||
var deepParentDepth: number;
|
|
||||||
|
|
||||||
if (parent1.depth() < parent2.depth()) {
|
|
||||||
shallowParent = parent1;
|
|
||||||
shallowParentDepth = parent1.depth();
|
|
||||||
deepParent = parent2;
|
|
||||||
deepParentDepth = parent2.depth();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
shallowParent = parent2;
|
|
||||||
shallowParentDepth = parent2.depth();
|
|
||||||
deepParent = parent1;
|
|
||||||
deepParentDepth = parent1.depth();
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug.assert(shallowParentDepth >= 0, "Expected shallowParentDepth >= 0");
|
|
||||||
Debug.assert(deepParentDepth >= 0, "Expected deepParentDepth >= 0");
|
|
||||||
Debug.assert(deepParentDepth >= shallowParentDepth, "Expected deepParentDepth >= shallowParentDepth");
|
|
||||||
|
|
||||||
while (deepParentDepth > shallowParentDepth) {
|
|
||||||
deepParent = <IndentationNodeContext>deepParent.parent();
|
|
||||||
deepParentDepth--;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug.assert(deepParentDepth === shallowParentDepth, "Expected deepParentDepth === shallowParentDepth");
|
|
||||||
|
|
||||||
while (deepParent.node() && shallowParent.node()) {
|
|
||||||
if (deepParent.node() === shallowParent.node()) {
|
|
||||||
return deepParent;
|
|
||||||
}
|
|
||||||
deepParent = <IndentationNodeContext>deepParent.parent();
|
|
||||||
shallowParent = <IndentationNodeContext>shallowParent.parent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// The root should be the first element in the parent chain, we can not be here unless something wrong
|
|
||||||
// happened along the way
|
|
||||||
throw Errors.invalidOperation();
|
|
||||||
}
|
|
||||||
|
|
||||||
private formatPair(t1: TokenSpan, t1Parent: IndentationNodeContext, t2: TokenSpan, t2Parent: IndentationNodeContext): void {
|
|
||||||
var token1Line = this.getLineNumber(t1);
|
|
||||||
var token2Line = this.getLineNumber(t2);
|
|
||||||
|
|
||||||
// Find common parent
|
|
||||||
var commonParent= this.findCommonParents(t1Parent, t2Parent);
|
|
||||||
|
|
||||||
// Update the context
|
|
||||||
this.formattingContext.updateContext(t1, t1Parent, t2, t2Parent, commonParent);
|
|
||||||
|
|
||||||
// Find rules matching the current context
|
|
||||||
var rule = this.rulesProvider.getRulesMap().GetRule(this.formattingContext);
|
|
||||||
|
|
||||||
if (rule != null) {
|
|
||||||
// Record edits from the rule
|
|
||||||
this.RecordRuleEdits(rule, t1, t2);
|
|
||||||
|
|
||||||
// Handle the case where the next line is moved to be the end of this line.
|
|
||||||
// In this case we don't indent the next line in the next pass.
|
|
||||||
if ((rule.Operation.Action == RuleAction.Space || rule.Operation.Action == RuleAction.Delete) &&
|
|
||||||
token1Line != token2Line) {
|
|
||||||
this.forceSkipIndentingNextToken(t2.start());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the case where token2 is moved to the new line.
|
|
||||||
// In this case we indent token2 in the next pass but we set
|
|
||||||
// sameLineIndent flag to notify the indenter that the indentation is within the line.
|
|
||||||
if (rule.Operation.Action == RuleAction.NewLine && token1Line == token2Line) {
|
|
||||||
this.forceIndentNextToken(t2.start());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
|
|
||||||
if (token1Line != token2Line && (!rule || (rule.Operation.Action != RuleAction.Delete && rule.Flag != RuleFlags.CanDeleteNewLines))) {
|
|
||||||
this.trimWhitespaceInLineRange(token1Line, token2Line, t1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getLineNumber(span: TextSpan): number {
|
|
||||||
return this.snapshot().getLineNumberFromPosition(span.start());
|
|
||||||
}
|
|
||||||
|
|
||||||
private trimWhitespaceInLineRange(startLine: number, endLine: number, token?: TokenSpan): void {
|
|
||||||
for (var lineNumber = startLine; lineNumber < endLine; ++lineNumber) {
|
|
||||||
var line = this.snapshot().getLineFromLineNumber(lineNumber);
|
|
||||||
|
|
||||||
this.trimWhitespace(line, token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private trimWhitespace(line: ITextSnapshotLine, token?: TokenSpan): void {
|
|
||||||
// Don't remove the trailing spaces inside comments (this includes line comments and block comments)
|
|
||||||
if (token && (token.kind == SyntaxKind.MultiLineCommentTrivia || token.kind == SyntaxKind.SingleLineCommentTrivia) && token.start() <= line.endPosition() && token.end() >= line.endPosition())
|
|
||||||
return;
|
|
||||||
|
|
||||||
var text = line.getText();
|
|
||||||
var index = 0;
|
|
||||||
|
|
||||||
for (index = text.length - 1; index >= 0; --index) {
|
|
||||||
if (!CharacterInfo.isWhitespace(text.charCodeAt(index))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
++index;
|
|
||||||
|
|
||||||
if (index < text.length) {
|
|
||||||
this.recordEdit(line.startPosition() + index, line.length() - index, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private RecordRuleEdits(rule: Rule, t1: TokenSpan, t2: TokenSpan): void {
|
|
||||||
if (rule.Operation.Action == RuleAction.Ignore) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var betweenSpan: TextSpan;
|
|
||||||
|
|
||||||
switch (rule.Operation.Action) {
|
|
||||||
case RuleAction.Delete:
|
|
||||||
{
|
|
||||||
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
|
|
||||||
|
|
||||||
if (betweenSpan.length() > 0) {
|
|
||||||
this.recordEdit(betweenSpan.start(), betweenSpan.length(), "");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RuleAction.NewLine:
|
|
||||||
{
|
|
||||||
if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
|
|
||||||
|
|
||||||
var doEdit = false;
|
|
||||||
var betweenText = this.snapshot().getText(betweenSpan);
|
|
||||||
|
|
||||||
var lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter);
|
|
||||||
if (lineFeedLoc < 0) {
|
|
||||||
// no linefeeds, do the edit
|
|
||||||
doEdit = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// We only require one line feed. If there is another one, do the edit
|
|
||||||
lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter, lineFeedLoc + 1);
|
|
||||||
if (lineFeedLoc >= 0) {
|
|
||||||
doEdit = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doEdit) {
|
|
||||||
this.recordEdit(betweenSpan.start(), betweenSpan.length(), this.options.newLineCharacter);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RuleAction.Space:
|
|
||||||
{
|
|
||||||
if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
|
|
||||||
|
|
||||||
if (betweenSpan.length() > 1 || this.snapshot().getText(betweenSpan) != " ") {
|
|
||||||
this.recordEdit(betweenSpan.start(), betweenSpan.length(), " ");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,48 +13,48 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
/// <reference path="formatting.ts"/>
|
/// <reference path="references.ts"/>
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
export class FormattingContext {
|
export class FormattingContext {
|
||||||
public currentTokenSpan: TokenSpan = null;
|
public currentTokenSpan: TextRangeWithKind;
|
||||||
public nextTokenSpan: TokenSpan = null;
|
public nextTokenSpan: TextRangeWithKind;
|
||||||
public contextNode: IndentationNodeContext = null;
|
public contextNode: Node;
|
||||||
public currentTokenParent: IndentationNodeContext = null;
|
public currentTokenParent: Node;
|
||||||
public nextTokenParent: IndentationNodeContext = null;
|
public nextTokenParent: Node;
|
||||||
|
|
||||||
private contextNodeAllOnSameLine: boolean = null;
|
private contextNodeAllOnSameLine: boolean;
|
||||||
private nextNodeAllOnSameLine: boolean = null;
|
private nextNodeAllOnSameLine: boolean;
|
||||||
private tokensAreOnSameLine: boolean = null;
|
private tokensAreOnSameLine: boolean;
|
||||||
private contextNodeBlockIsOnOneLine: boolean = null;
|
private contextNodeBlockIsOnOneLine: boolean;
|
||||||
private nextNodeBlockIsOnOneLine: boolean = null;
|
private nextNodeBlockIsOnOneLine: boolean;
|
||||||
|
|
||||||
constructor(private snapshot: ITextSnapshot, public formattingRequestKind: FormattingRequestKind) {
|
constructor(private sourceFile: SourceFile, public formattingRequestKind: FormattingRequestKind) {
|
||||||
Debug.assert(this.snapshot != null, "snapshot is null");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateContext(currentTokenSpan: TokenSpan, currentTokenParent: IndentationNodeContext, nextTokenSpan: TokenSpan, nextTokenParent: IndentationNodeContext, commonParent: IndentationNodeContext) {
|
public updateContext(currentRange: TextRangeWithKind, currentTokenParent: Node, nextRange: TextRangeWithKind, nextTokenParent: Node, commonParent: Node) {
|
||||||
Debug.assert(currentTokenSpan != null, "currentTokenSpan is null");
|
Debug.assert(currentRange !== undefined, "currentTokenSpan is null");
|
||||||
Debug.assert(currentTokenParent != null, "currentTokenParent is null");
|
Debug.assert(currentTokenParent !== undefined, "currentTokenParent is null");
|
||||||
Debug.assert(nextTokenSpan != null, "nextTokenSpan is null");
|
Debug.assert(nextRange !== undefined, "nextTokenSpan is null");
|
||||||
Debug.assert(nextTokenParent != null, "nextTokenParent is null");
|
Debug.assert(nextTokenParent !== undefined, "nextTokenParent is null");
|
||||||
Debug.assert(commonParent != null, "commonParent is null");
|
Debug.assert(commonParent !== undefined, "commonParent is null");
|
||||||
|
|
||||||
this.currentTokenSpan = currentTokenSpan;
|
this.currentTokenSpan = currentRange;
|
||||||
this.currentTokenParent = currentTokenParent;
|
this.currentTokenParent = currentTokenParent;
|
||||||
this.nextTokenSpan = nextTokenSpan;
|
this.nextTokenSpan = nextRange;
|
||||||
this.nextTokenParent = nextTokenParent;
|
this.nextTokenParent = nextTokenParent;
|
||||||
this.contextNode = commonParent;
|
this.contextNode = commonParent;
|
||||||
|
|
||||||
this.contextNodeAllOnSameLine = null;
|
// drop cached results
|
||||||
this.nextNodeAllOnSameLine = null;
|
this.contextNodeAllOnSameLine = undefined;
|
||||||
this.tokensAreOnSameLine = null;
|
this.nextNodeAllOnSameLine = undefined;
|
||||||
this.contextNodeBlockIsOnOneLine = null;
|
this.tokensAreOnSameLine = undefined;
|
||||||
this.nextNodeBlockIsOnOneLine = null;
|
this.contextNodeBlockIsOnOneLine = undefined;
|
||||||
|
this.nextNodeBlockIsOnOneLine = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContextNodeAllOnSameLine(): boolean {
|
public ContextNodeAllOnSameLine(): boolean {
|
||||||
if (this.contextNodeAllOnSameLine === null) {
|
if (this.contextNodeAllOnSameLine === undefined) {
|
||||||
this.contextNodeAllOnSameLine = this.NodeIsOnOneLine(this.contextNode);
|
this.contextNodeAllOnSameLine = this.NodeIsOnOneLine(this.contextNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ module TypeScript.Services.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
public NextNodeAllOnSameLine(): boolean {
|
public NextNodeAllOnSameLine(): boolean {
|
||||||
if (this.nextNodeAllOnSameLine === null) {
|
if (this.nextNodeAllOnSameLine === undefined) {
|
||||||
this.nextNodeAllOnSameLine = this.NodeIsOnOneLine(this.nextTokenParent);
|
this.nextNodeAllOnSameLine = this.NodeIsOnOneLine(this.nextTokenParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,10 +70,9 @@ module TypeScript.Services.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TokensAreOnSameLine(): boolean {
|
public TokensAreOnSameLine(): boolean {
|
||||||
if (this.tokensAreOnSameLine === null) {
|
if (this.tokensAreOnSameLine === undefined) {
|
||||||
var startLine = this.snapshot.getLineNumberFromPosition(this.currentTokenSpan.start());
|
var startLine = this.sourceFile.getLineAndCharacterFromPosition(this.currentTokenSpan.pos).line;
|
||||||
var endLine = this.snapshot.getLineNumberFromPosition(this.nextTokenSpan.start());
|
var endLine = this.sourceFile.getLineAndCharacterFromPosition(this.nextTokenSpan.pos).line;
|
||||||
|
|
||||||
this.tokensAreOnSameLine = (startLine == endLine);
|
this.tokensAreOnSameLine = (startLine == endLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +80,7 @@ module TypeScript.Services.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContextNodeBlockIsOnOneLine() {
|
public ContextNodeBlockIsOnOneLine() {
|
||||||
if (this.contextNodeBlockIsOnOneLine === null) {
|
if (this.contextNodeBlockIsOnOneLine === undefined) {
|
||||||
this.contextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.contextNode);
|
this.contextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.contextNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,28 +88,28 @@ module TypeScript.Services.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
public NextNodeBlockIsOnOneLine() {
|
public NextNodeBlockIsOnOneLine() {
|
||||||
if (this.nextNodeBlockIsOnOneLine === null) {
|
if (this.nextNodeBlockIsOnOneLine === undefined) {
|
||||||
this.nextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.nextTokenParent);
|
this.nextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.nextTokenParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.nextNodeBlockIsOnOneLine;
|
return this.nextNodeBlockIsOnOneLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeIsOnOneLine(node: IndentationNodeContext): boolean {
|
private NodeIsOnOneLine(node: Node): boolean {
|
||||||
var startLine = this.snapshot.getLineNumberFromPosition(node.start());
|
var startLine = this.sourceFile.getLineAndCharacterFromPosition(node.getStart(this.sourceFile)).line;
|
||||||
var endLine = this.snapshot.getLineNumberFromPosition(node.end());
|
var endLine = this.sourceFile.getLineAndCharacterFromPosition(node.getEnd()).line;
|
||||||
|
|
||||||
return startLine == endLine;
|
return startLine == endLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we know we have a block (or a fake block represented by some other kind of node with an open and close brace as children).
|
private BlockIsOnOneLine(node: Node): boolean {
|
||||||
// IMPORTANT!!! This relies on the invariant that IsBlockContext must return true ONLY for nodes with open and close braces as immediate children
|
var openBrace = findChildOfKind(node, SyntaxKind.OpenBraceToken, this.sourceFile);
|
||||||
public BlockIsOnOneLine(node: IndentationNodeContext): boolean {
|
var closeBrace = findChildOfKind(node, SyntaxKind.CloseBraceToken, this.sourceFile);
|
||||||
var block = <BlockSyntax>node.node();
|
if (openBrace && closeBrace) {
|
||||||
|
var startLine = this.sourceFile.getLineAndCharacterFromPosition(openBrace.getEnd()).line;
|
||||||
// Now check if they are on the same line
|
var endLine = this.sourceFile.getLineAndCharacterFromPosition(closeBrace.getStart(this.sourceFile)).line;
|
||||||
return this.snapshot.getLineNumberFromPosition(fullEnd(block.openBraceToken)) ===
|
return startLine === endLine;
|
||||||
this.snapshot.getLineNumberFromPosition(start(block.closeBraceToken));
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,125 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
/// <reference path="formatting.ts"/>
|
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
|
||||||
export class FormattingManager {
|
|
||||||
private options: FormattingOptions;
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
public formatSelection(minChar: number, limChar: number): ts.TextChange[] {
|
|
||||||
var span = TextSpan.fromBounds(minChar, limChar);
|
|
||||||
return this.formatSpan(span, FormattingRequestKind.FormatSelection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public formatDocument(): ts.TextChange[] {
|
|
||||||
var span = TextSpan.fromBounds(0, this.snapshot.getLength());
|
|
||||||
return this.formatSpan(span, FormattingRequestKind.FormatDocument);
|
|
||||||
}
|
|
||||||
|
|
||||||
public formatOnSemicolon(caretPosition: number): ts.TextChange[] {
|
|
||||||
var sourceUnit = this.syntaxTree.sourceUnit();
|
|
||||||
var semicolonPositionedToken = findToken(sourceUnit, caretPosition - 1);
|
|
||||||
|
|
||||||
if (semicolonPositionedToken.kind === SyntaxKind.SemicolonToken) {
|
|
||||||
// Find the outer most parent that this semicolon terminates
|
|
||||||
var current: ISyntaxElement = semicolonPositionedToken;
|
|
||||||
while (current.parent !== null &&
|
|
||||||
fullEnd(current.parent) === fullEnd(semicolonPositionedToken) &&
|
|
||||||
current.parent.kind !== SyntaxKind.List) {
|
|
||||||
current = current.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the span
|
|
||||||
var span = new TextSpan(fullStart(current), fullWidth(current));
|
|
||||||
|
|
||||||
// Format the span
|
|
||||||
return this.formatSpan(span, FormattingRequestKind.FormatOnSemicolon);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public formatOnClosingCurlyBrace(caretPosition: number): ts.TextChange[] {
|
|
||||||
var sourceUnit = this.syntaxTree.sourceUnit();
|
|
||||||
var closeBracePositionedToken = findToken(sourceUnit, caretPosition - 1);
|
|
||||||
|
|
||||||
if (closeBracePositionedToken.kind === SyntaxKind.CloseBraceToken) {
|
|
||||||
// Find the outer most parent that this closing brace terminates
|
|
||||||
var current: ISyntaxElement = closeBracePositionedToken;
|
|
||||||
while (current.parent !== null &&
|
|
||||||
fullEnd(current.parent) === fullEnd(closeBracePositionedToken) &&
|
|
||||||
current.parent.kind !== SyntaxKind.List) {
|
|
||||||
current = current.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the span
|
|
||||||
var span = new TextSpan(fullStart(current), fullWidth(current));
|
|
||||||
|
|
||||||
// Format the span
|
|
||||||
return this.formatSpan(span, FormattingRequestKind.FormatOnClosingCurlyBrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public formatOnEnter(caretPosition: number): ts.TextChange[] {
|
|
||||||
var lineNumber = this.snapshot.getLineNumberFromPosition(caretPosition);
|
|
||||||
|
|
||||||
if (lineNumber > 0) {
|
|
||||||
// Format both lines
|
|
||||||
var prevLine = this.snapshot.getLineFromLineNumber(lineNumber - 1);
|
|
||||||
var currentLine = this.snapshot.getLineFromLineNumber(lineNumber);
|
|
||||||
var span = TextSpan.fromBounds(prevLine.startPosition(), currentLine.endPosition());
|
|
||||||
|
|
||||||
// Format the span
|
|
||||||
return this.formatSpan(span, FormattingRequestKind.FormatOnEnter);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
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.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({
|
|
||||||
span: new TextSpan(item.position, item.length),
|
|
||||||
newText: item.replaceWith
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,15 +13,14 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
/// <reference path="formatting.ts"/>
|
/// <reference path="references.ts"/>
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
export enum FormattingRequestKind {
|
export const enum FormattingRequestKind {
|
||||||
FormatDocument,
|
FormatDocument,
|
||||||
FormatSelection,
|
FormatSelection,
|
||||||
FormatOnEnter,
|
FormatOnEnter,
|
||||||
FormatOnSemicolon,
|
FormatOnSemicolon,
|
||||||
FormatOnClosingCurlyBrace,
|
FormatOnClosingCurlyBrace
|
||||||
FormatOnPaste
|
|
||||||
}
|
}
|
||||||
}
|
}
|
210
src/services/formatting/formattingScanner.ts
Normal file
210
src/services/formatting/formattingScanner.ts
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/// <reference path="..\..\compiler\scanner.ts"/>
|
||||||
|
|
||||||
|
module ts.formatting {
|
||||||
|
var scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false);
|
||||||
|
|
||||||
|
export interface FormattingScanner {
|
||||||
|
advance(): void;
|
||||||
|
isOnToken(): boolean;
|
||||||
|
readTokenInfo(n: Node): TokenInfo;
|
||||||
|
lastTrailingTriviaWasNewLine(): boolean;
|
||||||
|
close(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum ScanAction{
|
||||||
|
Scan,
|
||||||
|
RescanGreaterThanToken,
|
||||||
|
RescanSlashToken
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFormattingScanner(sourceFile: SourceFile, startPos: number, endPos: number): FormattingScanner {
|
||||||
|
|
||||||
|
scanner.setText(sourceFile.text);
|
||||||
|
scanner.setTextPos(startPos);
|
||||||
|
|
||||||
|
var wasNewLine: boolean = true;
|
||||||
|
var leadingTrivia: TextRangeWithKind[];
|
||||||
|
var trailingTrivia: TextRangeWithKind[];
|
||||||
|
|
||||||
|
var savedPos: number;
|
||||||
|
var lastScanAction: ScanAction;
|
||||||
|
var lastTokenInfo: TokenInfo;
|
||||||
|
|
||||||
|
return {
|
||||||
|
advance: advance,
|
||||||
|
readTokenInfo: readTokenInfo,
|
||||||
|
isOnToken: isOnToken,
|
||||||
|
lastTrailingTriviaWasNewLine: () => wasNewLine,
|
||||||
|
close: () => {
|
||||||
|
lastTokenInfo = undefined;
|
||||||
|
scanner.setText(undefined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function advance(): void {
|
||||||
|
lastTokenInfo = undefined;
|
||||||
|
var isStarted = scanner.getStartPos() !== startPos;
|
||||||
|
|
||||||
|
if (isStarted) {
|
||||||
|
if (trailingTrivia) {
|
||||||
|
Debug.assert(trailingTrivia.length !== 0);
|
||||||
|
wasNewLine = trailingTrivia[trailingTrivia.length - 1].kind === SyntaxKind.NewLineTrivia;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wasNewLine = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
leadingTrivia = undefined;
|
||||||
|
trailingTrivia = undefined;
|
||||||
|
|
||||||
|
if (!isStarted) {
|
||||||
|
scanner.scan();
|
||||||
|
}
|
||||||
|
|
||||||
|
var t: SyntaxKind;
|
||||||
|
var pos = scanner.getStartPos();
|
||||||
|
|
||||||
|
// Read leading trivia and token
|
||||||
|
while (pos < endPos) {
|
||||||
|
var t = scanner.getToken();
|
||||||
|
if (!isTrivia(t)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume leading trivia
|
||||||
|
scanner.scan();
|
||||||
|
var item = {
|
||||||
|
pos: pos,
|
||||||
|
end: scanner.getStartPos(),
|
||||||
|
kind: t
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = scanner.getStartPos();
|
||||||
|
|
||||||
|
if (!leadingTrivia) {
|
||||||
|
leadingTrivia = [];
|
||||||
|
}
|
||||||
|
leadingTrivia.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
savedPos = scanner.getStartPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldRescanGreaterThanToken(container: Node): boolean {
|
||||||
|
if (container.kind !== SyntaxKind.BinaryExpression) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch ((<BinaryExpression>container).operator) {
|
||||||
|
case SyntaxKind.GreaterThanEqualsToken:
|
||||||
|
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
|
||||||
|
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
|
||||||
|
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
|
||||||
|
case SyntaxKind.GreaterThanGreaterThanToken:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldRescanSlashToken(container: Node): boolean {
|
||||||
|
return container.kind === SyntaxKind.RegularExpressionLiteral;
|
||||||
|
}
|
||||||
|
|
||||||
|
function startsWithSlashToken(t: SyntaxKind): boolean {
|
||||||
|
return t === SyntaxKind.SlashToken || t === SyntaxKind.SlashEqualsToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readTokenInfo(n: Node): TokenInfo {
|
||||||
|
if (!isOnToken()) {
|
||||||
|
// scanner is not on the token (either advance was not called yet or scanner is already past the end position)
|
||||||
|
return {
|
||||||
|
leadingTrivia: leadingTrivia,
|
||||||
|
trailingTrivia: undefined,
|
||||||
|
token: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// normally scanner returns the smallest available token
|
||||||
|
// check the kind of context node to determine if scanner should have more greedy behavior and consume more text.
|
||||||
|
var expectedScanAction =
|
||||||
|
shouldRescanGreaterThanToken(n)
|
||||||
|
? ScanAction.RescanGreaterThanToken
|
||||||
|
: shouldRescanSlashToken(n)
|
||||||
|
? ScanAction.RescanSlashToken
|
||||||
|
: ScanAction.Scan
|
||||||
|
|
||||||
|
if (lastTokenInfo && expectedScanAction === lastScanAction) {
|
||||||
|
// readTokenInfo was called before with the same expected scan action.
|
||||||
|
// No need to re-scan text, return existing 'lastTokenInfo'
|
||||||
|
return lastTokenInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scanner.getStartPos() !== savedPos) {
|
||||||
|
Debug.assert(lastTokenInfo !== undefined);
|
||||||
|
// readTokenInfo was called before but scan action differs - rescan text
|
||||||
|
scanner.setTextPos(savedPos);
|
||||||
|
scanner.scan();
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentToken = scanner.getToken();
|
||||||
|
|
||||||
|
if (expectedScanAction === ScanAction.RescanGreaterThanToken && currentToken === SyntaxKind.GreaterThanToken) {
|
||||||
|
currentToken = scanner.reScanGreaterToken();
|
||||||
|
Debug.assert((<BinaryExpression>n).operator === currentToken);
|
||||||
|
lastScanAction = ScanAction.RescanGreaterThanToken;
|
||||||
|
}
|
||||||
|
else if (expectedScanAction === ScanAction.RescanSlashToken && startsWithSlashToken(currentToken)) {
|
||||||
|
currentToken = scanner.reScanSlashToken();
|
||||||
|
Debug.assert(n.kind === currentToken);
|
||||||
|
lastScanAction = ScanAction.RescanSlashToken;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lastScanAction = ScanAction.Scan;
|
||||||
|
}
|
||||||
|
|
||||||
|
var token: TextRangeWithKind = {
|
||||||
|
pos: scanner.getStartPos(),
|
||||||
|
end: scanner.getTextPos(),
|
||||||
|
kind: currentToken
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume trailing trivia
|
||||||
|
while(scanner.getStartPos() < endPos) {
|
||||||
|
currentToken = scanner.scan();
|
||||||
|
if (!isTrivia(currentToken)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var trivia = {
|
||||||
|
pos: scanner.getStartPos(),
|
||||||
|
end: scanner.getTextPos(),
|
||||||
|
kind: currentToken
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!trailingTrivia) {
|
||||||
|
trailingTrivia = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
trailingTrivia.push(trivia);
|
||||||
|
|
||||||
|
if (currentToken === SyntaxKind.NewLineTrivia) {
|
||||||
|
// move past new line
|
||||||
|
scanner.scan();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastTokenInfo = {
|
||||||
|
leadingTrivia: leadingTrivia,
|
||||||
|
trailingTrivia: trailingTrivia,
|
||||||
|
token: token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOnToken(): boolean {
|
||||||
|
var current = (lastTokenInfo && lastTokenInfo.token.kind) || scanner.getToken();
|
||||||
|
var startPos = (lastTokenInfo && lastTokenInfo.token.pos) || scanner.getStartPos();
|
||||||
|
return startPos < endPos && current !== SyntaxKind.EndOfFileToken && !isTrivia(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
src/services/formatting/indentation.ts
Normal file
54
src/services/formatting/indentation.ts
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
module ts.formatting {
|
||||||
|
|
||||||
|
var internedTabsIndentation: string[];
|
||||||
|
var internedSpacesIndentation: string[];
|
||||||
|
|
||||||
|
export function getIndentationString(indentation: number, options: FormatCodeOptions): string {
|
||||||
|
if (!options.ConvertTabsToSpaces) {
|
||||||
|
var tabs = Math.floor(indentation / options.TabSize);
|
||||||
|
var spaces = indentation - tabs * options.TabSize;
|
||||||
|
|
||||||
|
var tabString: string;
|
||||||
|
if (!internedTabsIndentation) {
|
||||||
|
internedTabsIndentation = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (internedTabsIndentation[tabs] === undefined) {
|
||||||
|
internedTabsIndentation[tabs] = tabString = repeat('\t', tabs);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tabString = internedTabsIndentation[tabs];
|
||||||
|
}
|
||||||
|
|
||||||
|
return spaces ? tabString + repeat(" ", spaces) : tabString;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var spacesString: string;
|
||||||
|
var quotient = Math.floor(indentation / options.IndentSize);
|
||||||
|
var remainder = indentation % options.IndentSize;
|
||||||
|
if (!internedSpacesIndentation) {
|
||||||
|
internedSpacesIndentation = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (internedSpacesIndentation[quotient] === undefined) {
|
||||||
|
spacesString = repeat(" ", options.IndentSize * quotient);
|
||||||
|
internedSpacesIndentation[quotient] = spacesString;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
spacesString = internedSpacesIndentation[quotient];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return remainder ? spacesString + repeat(" ", remainder) : spacesString;
|
||||||
|
}
|
||||||
|
|
||||||
|
function repeat(value: string, count: number): string {
|
||||||
|
var s = "";
|
||||||
|
for (var i = 0; i < count; ++i) {
|
||||||
|
s += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,103 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
|
||||||
export class IndentationNodeContext {
|
|
||||||
private _node: ISyntaxNode;
|
|
||||||
private _parent: IndentationNodeContext;
|
|
||||||
private _fullStart: number;
|
|
||||||
private _indentationAmount: number;
|
|
||||||
private _childIndentationAmountDelta: number;
|
|
||||||
private _depth: number;
|
|
||||||
private _hasSkippedOrMissingTokenChild: boolean;
|
|
||||||
|
|
||||||
constructor(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) {
|
|
||||||
this.update(parent, node, fullStart, indentationAmount, childIndentationAmountDelta);
|
|
||||||
}
|
|
||||||
|
|
||||||
public parent(): IndentationNodeContext {
|
|
||||||
return this._parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public node(): ISyntaxNode {
|
|
||||||
return this._node;
|
|
||||||
}
|
|
||||||
|
|
||||||
public fullStart(): number {
|
|
||||||
return this._fullStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
public fullWidth(): number {
|
|
||||||
return fullWidth(this._node);
|
|
||||||
}
|
|
||||||
|
|
||||||
public start(): number {
|
|
||||||
return this._fullStart + leadingTriviaWidth(this._node);
|
|
||||||
}
|
|
||||||
|
|
||||||
public end(): number {
|
|
||||||
return this._fullStart + leadingTriviaWidth(this._node) + width(this._node);
|
|
||||||
}
|
|
||||||
|
|
||||||
public indentationAmount(): number {
|
|
||||||
return this._indentationAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public childIndentationAmountDelta(): number {
|
|
||||||
return this._childIndentationAmountDelta;
|
|
||||||
}
|
|
||||||
|
|
||||||
public depth(): number {
|
|
||||||
return this._depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
public kind(): SyntaxKind {
|
|
||||||
return this._node.kind;
|
|
||||||
}
|
|
||||||
|
|
||||||
public hasSkippedOrMissingTokenChild(): boolean {
|
|
||||||
if (this._hasSkippedOrMissingTokenChild === null) {
|
|
||||||
this._hasSkippedOrMissingTokenChild = Syntax.nodeHasSkippedOrMissingTokens(this._node);
|
|
||||||
}
|
|
||||||
return this._hasSkippedOrMissingTokenChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
public clone(pool: IndentationNodeContextPool): IndentationNodeContext {
|
|
||||||
var parent: IndentationNodeContext = null;
|
|
||||||
if (this._parent) {
|
|
||||||
parent = this._parent.clone(pool);
|
|
||||||
}
|
|
||||||
return pool.getNode(parent, this._node, this._fullStart, this._indentationAmount, this._childIndentationAmountDelta);
|
|
||||||
}
|
|
||||||
|
|
||||||
public update(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) {
|
|
||||||
this._parent = parent;
|
|
||||||
this._node = node;
|
|
||||||
this._fullStart = fullStart;
|
|
||||||
this._indentationAmount = indentationAmount;
|
|
||||||
this._childIndentationAmountDelta = childIndentationAmountDelta;
|
|
||||||
this._hasSkippedOrMissingTokenChild = null;
|
|
||||||
|
|
||||||
if (parent) {
|
|
||||||
this._depth = parent.depth() + 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this._depth = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
|
||||||
export class IndentationNodeContextPool {
|
|
||||||
private nodes: IndentationNodeContext[] = [];
|
|
||||||
|
|
||||||
public getNode(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationLevel: number, childIndentationLevelDelta: number): IndentationNodeContext {
|
|
||||||
if (this.nodes.length > 0) {
|
|
||||||
var cachedNode = this.nodes.pop();
|
|
||||||
cachedNode.update(parent, node, fullStart, indentationLevel, childIndentationLevelDelta);
|
|
||||||
return cachedNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new IndentationNodeContext(parent, node, fullStart, indentationLevel, childIndentationLevelDelta);
|
|
||||||
}
|
|
||||||
|
|
||||||
public releaseNode(node: IndentationNodeContext, recursive: boolean = false): void {
|
|
||||||
this.nodes.push(node);
|
|
||||||
|
|
||||||
if (recursive) {
|
|
||||||
var parent = node.parent();
|
|
||||||
if (parent) {
|
|
||||||
this.releaseNode(parent, recursive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,371 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
|
||||||
export class IndentationTrackingWalker {
|
|
||||||
private _position: number = 0;
|
|
||||||
private _parent: IndentationNodeContext = null;
|
|
||||||
private _textSpan: TextSpan;
|
|
||||||
private _snapshot: ITextSnapshot;
|
|
||||||
private _lastTriviaWasNewLine: boolean;
|
|
||||||
private _indentationNodeContextPool: IndentationNodeContextPool;
|
|
||||||
private _text: ISimpleText;
|
|
||||||
|
|
||||||
constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, public options: FormattingOptions) {
|
|
||||||
// Create a pool object to manage context nodes while walking the tree
|
|
||||||
this._indentationNodeContextPool = new IndentationNodeContextPool();
|
|
||||||
|
|
||||||
this._textSpan = textSpan;
|
|
||||||
this._text = sourceUnit.syntaxTree.text;
|
|
||||||
this._snapshot = snapshot;
|
|
||||||
this._parent = this._indentationNodeContextPool.getNode(null, sourceUnit, 0, 0, 0);
|
|
||||||
|
|
||||||
// Is the first token in the span at the start of a new line.
|
|
||||||
this._lastTriviaWasNewLine = indentFirstToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public position(): number {
|
|
||||||
return this._position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public parent(): IndentationNodeContext {
|
|
||||||
return this._parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public textSpan(): TextSpan {
|
|
||||||
return this._textSpan;
|
|
||||||
}
|
|
||||||
|
|
||||||
public snapshot(): ITextSnapshot {
|
|
||||||
return this._snapshot;
|
|
||||||
}
|
|
||||||
|
|
||||||
public indentationNodeContextPool(): IndentationNodeContextPool {
|
|
||||||
return this._indentationNodeContextPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public forceIndentNextToken(tokenStart: number): void {
|
|
||||||
this._lastTriviaWasNewLine = true;
|
|
||||||
this.forceRecomputeIndentationOfParent(tokenStart, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public forceSkipIndentingNextToken(tokenStart: number): void {
|
|
||||||
this._lastTriviaWasNewLine = false;
|
|
||||||
this.forceRecomputeIndentationOfParent(tokenStart, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
|
|
||||||
throw Errors.abstract();
|
|
||||||
}
|
|
||||||
|
|
||||||
public visitTokenInSpan(token: ISyntaxToken): void {
|
|
||||||
if (this._lastTriviaWasNewLine) {
|
|
||||||
// Compute the indentation level at the current token
|
|
||||||
var indentationAmount = this.getTokenIndentationAmount(token);
|
|
||||||
var commentIndentationAmount = this.getCommentIndentationAmount(token);
|
|
||||||
|
|
||||||
// Process the token
|
|
||||||
this.indentToken(token, indentationAmount, commentIndentationAmount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public visitToken(token: ISyntaxToken): void {
|
|
||||||
var tokenSpan = new TextSpan(this._position, token.fullWidth());
|
|
||||||
|
|
||||||
if (tokenSpan.intersectsWithTextSpan(this._textSpan)) {
|
|
||||||
this.visitTokenInSpan(token);
|
|
||||||
|
|
||||||
// Only track new lines on tokens within the range. Make sure to check that the last trivia is a newline, and not just one of the trivia
|
|
||||||
var _nextToken = nextToken(token);
|
|
||||||
if (_nextToken && _nextToken.hasLeadingTrivia()) {
|
|
||||||
var trivia = _nextToken.leadingTrivia();
|
|
||||||
this._lastTriviaWasNewLine = trivia.hasNewLine();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this._lastTriviaWasNewLine = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the position
|
|
||||||
this._position += token.fullWidth();
|
|
||||||
}
|
|
||||||
|
|
||||||
public walk(element: ISyntaxElement) {
|
|
||||||
if (element) {
|
|
||||||
if (isToken(element)) {
|
|
||||||
this.visitToken(<ISyntaxToken>element);
|
|
||||||
}
|
|
||||||
else if (element.kind === SyntaxKind.List) {
|
|
||||||
for (var i = 0, n = childCount(element); i < n; i++) {
|
|
||||||
this.walk(childAt(element, i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.visitNode(<ISyntaxNode>element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private visitNode(node: ISyntaxNode): void {
|
|
||||||
var nodeSpan = new TextSpan(this._position, fullWidth(node));
|
|
||||||
|
|
||||||
if (nodeSpan.intersectsWithTextSpan(this._textSpan)) {
|
|
||||||
// Update indentation level
|
|
||||||
var indentation = this.getNodeIndentation(node);
|
|
||||||
|
|
||||||
// Update the parent
|
|
||||||
var currentParent = this._parent;
|
|
||||||
this._parent = this._indentationNodeContextPool.getNode(currentParent, node, this._position, indentation.indentationAmount, indentation.indentationAmountDelta);
|
|
||||||
|
|
||||||
// Visit node
|
|
||||||
for (var i = 0, n = childCount(node); i < n; i++) {
|
|
||||||
this.walk(childAt(node, i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset state
|
|
||||||
this._indentationNodeContextPool.releaseNode(this._parent);
|
|
||||||
this._parent = currentParent;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// We're skipping the node, so update our position accordingly.
|
|
||||||
this._position += fullWidth(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getTokenIndentationAmount(token: ISyntaxToken): number {
|
|
||||||
// If this is the first token of a node, it should follow the node indentation and not the child indentation;
|
|
||||||
// (e.g.class in a class declaration or module in module declariotion).
|
|
||||||
// Open and close braces should follow the indentation of thier parent as well(e.g.
|
|
||||||
// class {
|
|
||||||
// }
|
|
||||||
// Also in a do-while statement, the while should be indented like the parent.
|
|
||||||
if (firstToken(this._parent.node()) === token ||
|
|
||||||
token.kind === SyntaxKind.OpenBraceToken || token.kind === SyntaxKind.CloseBraceToken ||
|
|
||||||
token.kind === SyntaxKind.OpenBracketToken || token.kind === SyntaxKind.CloseBracketToken ||
|
|
||||||
(token.kind === SyntaxKind.WhileKeyword && this._parent.node().kind == SyntaxKind.DoStatement)) {
|
|
||||||
return this._parent.indentationAmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta());
|
|
||||||
}
|
|
||||||
|
|
||||||
private getCommentIndentationAmount(token: ISyntaxToken): number {
|
|
||||||
// If this is token terminating an indentation scope, leading comments should be indented to follow the children
|
|
||||||
// indentation level and not the node
|
|
||||||
|
|
||||||
if (token.kind === SyntaxKind.CloseBraceToken || token.kind === SyntaxKind.CloseBracketToken) {
|
|
||||||
return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta());
|
|
||||||
}
|
|
||||||
return this._parent.indentationAmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
private getNodeIndentation(node: ISyntaxNode, newLineInsertedByFormatting?: boolean): { indentationAmount: number; indentationAmountDelta: number; } {
|
|
||||||
var parent = this._parent;
|
|
||||||
|
|
||||||
// We need to get the parent's indentation, which could be one of 2 things. If first token of the parent is in the span, use the parent's computed indentation.
|
|
||||||
// If the parent was outside the span, use the actual indentation of the parent.
|
|
||||||
var parentIndentationAmount: number;
|
|
||||||
if (this._textSpan.containsPosition(parent.start())) {
|
|
||||||
parentIndentationAmount = parent.indentationAmount();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (parent.kind() === SyntaxKind.Block && !this.shouldIndentBlockInParent(this._parent.parent())) {
|
|
||||||
// Blocks preserve the indentation of their containing node (unless they're a
|
|
||||||
// standalone block in a list). i.e. if you have:
|
|
||||||
//
|
|
||||||
// function foo(
|
|
||||||
// a: number) {
|
|
||||||
//
|
|
||||||
// Then we expect the indentation of the block to be tied to the function, not to
|
|
||||||
// the line that the block is defined on. If we were to do the latter, then the
|
|
||||||
// indentation would be here:
|
|
||||||
//
|
|
||||||
// function foo(
|
|
||||||
// a: number) {
|
|
||||||
// |
|
|
||||||
//
|
|
||||||
// Instead of:
|
|
||||||
//
|
|
||||||
// function foo(
|
|
||||||
// a: number) {
|
|
||||||
// |
|
|
||||||
parent = this._parent.parent();
|
|
||||||
}
|
|
||||||
|
|
||||||
var line = this._snapshot.getLineFromPosition(parent.start()).getText();
|
|
||||||
var firstNonWhiteSpacePosition = Indentation.firstNonWhitespacePosition(line);
|
|
||||||
parentIndentationAmount = Indentation.columnForPositionInString(line, firstNonWhiteSpacePosition, this.options);
|
|
||||||
}
|
|
||||||
var parentIndentationAmountDelta = parent.childIndentationAmountDelta();
|
|
||||||
|
|
||||||
// The indentation level of the node
|
|
||||||
var indentationAmount: number;
|
|
||||||
|
|
||||||
// The delta it adds to its children.
|
|
||||||
var indentationAmountDelta: number;
|
|
||||||
var parentNode = parent.node();
|
|
||||||
|
|
||||||
switch (node.kind) {
|
|
||||||
default:
|
|
||||||
// General case
|
|
||||||
// This node should follow the child indentation set by its parent
|
|
||||||
// This node does not introduce any new indentation scope, indent any decendants of this node (tokens or child nodes)
|
|
||||||
// using the same indentation level
|
|
||||||
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
|
|
||||||
indentationAmountDelta = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Statements introducing {}
|
|
||||||
case SyntaxKind.ClassDeclaration:
|
|
||||||
case SyntaxKind.ModuleDeclaration:
|
|
||||||
case SyntaxKind.ObjectType:
|
|
||||||
case SyntaxKind.EnumDeclaration:
|
|
||||||
case SyntaxKind.SwitchStatement:
|
|
||||||
case SyntaxKind.ObjectLiteralExpression:
|
|
||||||
case SyntaxKind.ConstructorDeclaration:
|
|
||||||
case SyntaxKind.FunctionDeclaration:
|
|
||||||
case SyntaxKind.FunctionExpression:
|
|
||||||
case SyntaxKind.MemberFunctionDeclaration:
|
|
||||||
case SyntaxKind.GetAccessor:
|
|
||||||
case SyntaxKind.SetAccessor:
|
|
||||||
case SyntaxKind.IndexMemberDeclaration:
|
|
||||||
case SyntaxKind.CatchClause:
|
|
||||||
// Statements introducing []
|
|
||||||
case SyntaxKind.ArrayLiteralExpression:
|
|
||||||
case SyntaxKind.ArrayType:
|
|
||||||
case SyntaxKind.ElementAccessExpression:
|
|
||||||
case SyntaxKind.IndexSignature:
|
|
||||||
// Other statements
|
|
||||||
case SyntaxKind.ForStatement:
|
|
||||||
case SyntaxKind.ForInStatement:
|
|
||||||
case SyntaxKind.WhileStatement:
|
|
||||||
case SyntaxKind.DoStatement:
|
|
||||||
case SyntaxKind.WithStatement:
|
|
||||||
case SyntaxKind.CaseSwitchClause:
|
|
||||||
case SyntaxKind.DefaultSwitchClause:
|
|
||||||
case SyntaxKind.ReturnStatement:
|
|
||||||
case SyntaxKind.ThrowStatement:
|
|
||||||
case SyntaxKind.SimpleArrowFunctionExpression:
|
|
||||||
case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
|
||||||
case SyntaxKind.VariableDeclaration:
|
|
||||||
case SyntaxKind.ExportAssignment:
|
|
||||||
|
|
||||||
// Expressions which have argument lists or parameter lists
|
|
||||||
case SyntaxKind.InvocationExpression:
|
|
||||||
case SyntaxKind.ObjectCreationExpression:
|
|
||||||
case SyntaxKind.CallSignature:
|
|
||||||
case SyntaxKind.ConstructSignature:
|
|
||||||
|
|
||||||
// These nodes should follow the child indentation set by its parent;
|
|
||||||
// they introduce a new indenation scope; children should be indented at one level deeper
|
|
||||||
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
|
|
||||||
indentationAmountDelta = this.options.indentSpaces;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SyntaxKind.IfStatement:
|
|
||||||
if (parent.kind() === SyntaxKind.ElseClause &&
|
|
||||||
!SyntaxUtilities.isLastTokenOnLine((<ElseClauseSyntax>parentNode).elseKeyword, this._text)) {
|
|
||||||
// This is an else if statement with the if on the same line as the else, do not indent the if statmement.
|
|
||||||
// Note: Children indentation has already been set by the parent if statement, so no need to increment
|
|
||||||
indentationAmount = parentIndentationAmount;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Otherwise introduce a new indenation scope; children should be indented at one level deeper
|
|
||||||
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
|
|
||||||
}
|
|
||||||
indentationAmountDelta = this.options.indentSpaces;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SyntaxKind.ElseClause:
|
|
||||||
// Else should always follow its parent if statement indentation.
|
|
||||||
// Note: Children indentation has already been set by the parent if statement, so no need to increment
|
|
||||||
indentationAmount = parentIndentationAmount;
|
|
||||||
indentationAmountDelta = this.options.indentSpaces;
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
case SyntaxKind.Block:
|
|
||||||
// Check if the block is a member in a list of statements (if the parent is a source unit, module, or block, or switch clause)
|
|
||||||
if (this.shouldIndentBlockInParent(parent)) {
|
|
||||||
indentationAmount = parentIndentationAmount + parentIndentationAmountDelta;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
indentationAmount = parentIndentationAmount;
|
|
||||||
}
|
|
||||||
|
|
||||||
indentationAmountDelta = this.options.indentSpaces;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the parent happens to start on the same line as this node, then override the current node indenation with that
|
|
||||||
// of the parent. This avoid having to add an extra level of indentation for the children. e.g.:
|
|
||||||
// return {
|
|
||||||
// a:1
|
|
||||||
// };
|
|
||||||
// instead of:
|
|
||||||
// return {
|
|
||||||
// a:1
|
|
||||||
// };
|
|
||||||
// We also need to pass the delta (if it is nonzero) to the children, so that subsequent lines get indented. Essentially, if any node starting on the given line
|
|
||||||
// has a nonzero delta , the resulting delta should be inherited from this node. This is to indent cases like the following:
|
|
||||||
// return a
|
|
||||||
// || b;
|
|
||||||
// Lastly, it is possible the node indentation needs to be recomputed because the formatter inserted a newline before its first token.
|
|
||||||
// If this is the case, we know the node no longer starts on the same line as its parent (or at least we shouldn't treat it as such).
|
|
||||||
if (parentNode) {
|
|
||||||
if (!newLineInsertedByFormatting /*This could be false or undefined here*/) {
|
|
||||||
var parentStartLine = this._snapshot.getLineNumberFromPosition(parent.start());
|
|
||||||
var currentNodeStartLine = this._snapshot.getLineNumberFromPosition(this._position + leadingTriviaWidth(node));
|
|
||||||
if (parentStartLine === currentNodeStartLine || newLineInsertedByFormatting === false /*meaning a new line was removed and we are force recomputing*/) {
|
|
||||||
indentationAmount = parentIndentationAmount;
|
|
||||||
indentationAmountDelta = Math.min(this.options.indentSpaces, parentIndentationAmountDelta + indentationAmountDelta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
indentationAmount: indentationAmount,
|
|
||||||
indentationAmountDelta: indentationAmountDelta
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private shouldIndentBlockInParent(parent: IndentationNodeContext): boolean {
|
|
||||||
switch (parent.kind()) {
|
|
||||||
case SyntaxKind.SourceUnit:
|
|
||||||
case SyntaxKind.ModuleDeclaration:
|
|
||||||
case SyntaxKind.Block:
|
|
||||||
case SyntaxKind.CaseSwitchClause:
|
|
||||||
case SyntaxKind.DefaultSwitchClause:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private forceRecomputeIndentationOfParent(tokenStart: number, newLineAdded: boolean /*as opposed to removed*/): void {
|
|
||||||
var parent = this._parent;
|
|
||||||
if (start(parent.node()) === tokenStart) {
|
|
||||||
// Temporarily pop the parent before recomputing
|
|
||||||
this._parent = parent.parent();
|
|
||||||
var indentation = this.getNodeIndentation(parent.node(), /* newLineInsertedByFormatting */ newLineAdded);
|
|
||||||
parent.update(parent.parent(), parent.node(), parent.fullStart(), indentation.indentationAmount, indentation.indentationAmountDelta);
|
|
||||||
this._parent = parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,221 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
|
||||||
export class MultipleTokenIndenter extends IndentationTrackingWalker {
|
|
||||||
private _edits: TextEditInfo[] = [];
|
|
||||||
|
|
||||||
constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, options: FormattingOptions) {
|
|
||||||
super(textSpan, sourceUnit, snapshot, indentFirstToken, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
|
|
||||||
// Ignore generated tokens
|
|
||||||
if (token.fullWidth() === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have any skipped tokens as children, do not process this node for indentation or formatting
|
|
||||||
if (this.parent().hasSkippedOrMissingTokenChild()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Be strict, and only consider nodes that fall inside the span. This avoids indenting a multiline string
|
|
||||||
// on enter at the end of, as the whole token was not included in the span
|
|
||||||
var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token));
|
|
||||||
if (!this.textSpan().containsTextSpan(tokenSpan)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute an indentation string for this token
|
|
||||||
var indentationString = Indentation.indentationString(indentationAmount, this.options);
|
|
||||||
|
|
||||||
var commentIndentationString = Indentation.indentationString(commentIndentationAmount, this.options);
|
|
||||||
|
|
||||||
// Record any needed indentation edits
|
|
||||||
this.recordIndentationEditsForToken(token, indentationString, commentIndentationString);
|
|
||||||
}
|
|
||||||
|
|
||||||
public edits(): TextEditInfo[]{
|
|
||||||
return this._edits;
|
|
||||||
}
|
|
||||||
|
|
||||||
public recordEdit(position: number, length: number, replaceWith: string): void {
|
|
||||||
this._edits.push(new TextEditInfo(position, length, replaceWith));
|
|
||||||
}
|
|
||||||
|
|
||||||
private recordIndentationEditsForToken(token: ISyntaxToken, indentationString: string, commentIndentationString: string) {
|
|
||||||
var position = this.position();
|
|
||||||
var indentNextTokenOrTrivia = true;
|
|
||||||
var leadingWhiteSpace = ""; // We need to track the whitespace before a multiline comment
|
|
||||||
|
|
||||||
// Process any leading trivia if any
|
|
||||||
var triviaList = token.leadingTrivia();
|
|
||||||
if (triviaList) {
|
|
||||||
var seenNewLine = position === 0;
|
|
||||||
|
|
||||||
for (var i = 0, length = triviaList.count(); i < length; i++, position += trivia.fullWidth()) {
|
|
||||||
var trivia = triviaList.syntaxTriviaAt(i);
|
|
||||||
|
|
||||||
// Skip all trivia up to the first newline we see. We consider this trivia to
|
|
||||||
// 'belong' to the previous token.
|
|
||||||
if (!seenNewLine) {
|
|
||||||
if (trivia.kind !== SyntaxKind.NewLineTrivia) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
seenNewLine = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip this trivia if it is not in the span
|
|
||||||
if (!this.textSpan().containsTextSpan(new TextSpan(position, trivia.fullWidth()))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (trivia.kind) {
|
|
||||||
case SyntaxKind.MultiLineCommentTrivia:
|
|
||||||
// We will only indent the first line of the multiline comment if we were planning to indent the next trivia. However,
|
|
||||||
// subsequent lines will always be indented
|
|
||||||
this.recordIndentationEditsForMultiLineComment(trivia, position, commentIndentationString, leadingWhiteSpace, !indentNextTokenOrTrivia /* already indented first line */);
|
|
||||||
indentNextTokenOrTrivia = false;
|
|
||||||
leadingWhiteSpace = "";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SyntaxKind.SingleLineCommentTrivia:
|
|
||||||
case SyntaxKind.SkippedTokenTrivia:
|
|
||||||
if (indentNextTokenOrTrivia) {
|
|
||||||
this.recordIndentationEditsForSingleLineOrSkippedText(trivia, position, commentIndentationString);
|
|
||||||
indentNextTokenOrTrivia = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SyntaxKind.WhitespaceTrivia:
|
|
||||||
// If the next trivia is a comment, use the comment indentation level instead of the regular indentation level
|
|
||||||
// If the next trivia is a newline, this whole line is just whitespace, so don't do anything (trimming will take care of it)
|
|
||||||
var nextTrivia = length > i + 1 && triviaList.syntaxTriviaAt(i + 1);
|
|
||||||
var whiteSpaceIndentationString = nextTrivia && nextTrivia.isComment() ? commentIndentationString : indentationString;
|
|
||||||
if (indentNextTokenOrTrivia) {
|
|
||||||
if (!(nextTrivia && nextTrivia.isNewLine())) {
|
|
||||||
this.recordIndentationEditsForWhitespace(trivia, position, whiteSpaceIndentationString);
|
|
||||||
}
|
|
||||||
indentNextTokenOrTrivia = false;
|
|
||||||
}
|
|
||||||
leadingWhiteSpace += trivia.fullText();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SyntaxKind.NewLineTrivia:
|
|
||||||
// We hit a newline processing the trivia. We need to add the indentation to the
|
|
||||||
// next line as well. Note: don't bother indenting the newline itself. This will
|
|
||||||
// just insert ugly whitespace that most users probably will not want.
|
|
||||||
indentNextTokenOrTrivia = true;
|
|
||||||
leadingWhiteSpace = "";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw Errors.invalidOperation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (token.kind !== SyntaxKind.EndOfFileToken && indentNextTokenOrTrivia) {
|
|
||||||
// If the last trivia item was a new line, or no trivia items were encounterd record the
|
|
||||||
// indentation edit at the token position
|
|
||||||
if (indentationString.length > 0) {
|
|
||||||
this.recordEdit(position, 0, indentationString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private recordIndentationEditsForSingleLineOrSkippedText(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void {
|
|
||||||
// Record the edit
|
|
||||||
if (indentationString.length > 0) {
|
|
||||||
this.recordEdit(fullStart, 0, indentationString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private recordIndentationEditsForWhitespace(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void {
|
|
||||||
var text = trivia.fullText();
|
|
||||||
|
|
||||||
// Check if the current indentation matches the desired indentation or not
|
|
||||||
if (indentationString === text) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record the edit
|
|
||||||
this.recordEdit(fullStart, text.length, indentationString);
|
|
||||||
}
|
|
||||||
|
|
||||||
private recordIndentationEditsForMultiLineComment(trivia: ISyntaxTrivia, fullStart: number, indentationString: string, leadingWhiteSpace: string, firstLineAlreadyIndented: boolean): void {
|
|
||||||
// If the multiline comment spans multiple lines, we need to add the right indent amount to
|
|
||||||
// each successive line segment as well.
|
|
||||||
var position = fullStart;
|
|
||||||
var segments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia);
|
|
||||||
|
|
||||||
if (segments.length <= 1) {
|
|
||||||
if (!firstLineAlreadyIndented) {
|
|
||||||
// Process the one-line multiline comment just like a single line comment
|
|
||||||
this.recordIndentationEditsForSingleLineOrSkippedText(trivia, fullStart, indentationString);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find number of columns in first segment
|
|
||||||
var whiteSpaceColumnsInFirstSegment = Indentation.columnForPositionInString(leadingWhiteSpace, leadingWhiteSpace.length, this.options);
|
|
||||||
|
|
||||||
var indentationColumns = Indentation.columnForPositionInString(indentationString, indentationString.length, this.options);
|
|
||||||
var startIndex = 0;
|
|
||||||
if (firstLineAlreadyIndented) {
|
|
||||||
startIndex = 1;
|
|
||||||
position += segments[0].length;
|
|
||||||
}
|
|
||||||
for (var i = startIndex; i < segments.length; i++) {
|
|
||||||
var segment = segments[i];
|
|
||||||
this.recordIndentationEditsForSegment(segment, position, indentationColumns, whiteSpaceColumnsInFirstSegment);
|
|
||||||
position += segment.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private recordIndentationEditsForSegment(segment: string, fullStart: number, indentationColumns: number, whiteSpaceColumnsInFirstSegment: number): void {
|
|
||||||
// Indent subsequent lines using a column delta of the actual indentation relative to the first line
|
|
||||||
var firstNonWhitespacePosition = Indentation.firstNonWhitespacePosition(segment);
|
|
||||||
var leadingWhiteSpaceColumns = Indentation.columnForPositionInString(segment, firstNonWhitespacePosition, this.options);
|
|
||||||
var deltaFromFirstSegment = leadingWhiteSpaceColumns - whiteSpaceColumnsInFirstSegment;
|
|
||||||
var finalColumns = indentationColumns + deltaFromFirstSegment;
|
|
||||||
if (finalColumns < 0) {
|
|
||||||
finalColumns = 0;
|
|
||||||
}
|
|
||||||
var indentationString = Indentation.indentationString(finalColumns, this.options);
|
|
||||||
|
|
||||||
if (firstNonWhitespacePosition < segment.length &&
|
|
||||||
CharacterInfo.isLineTerminator(segment.charCodeAt(firstNonWhitespacePosition))) {
|
|
||||||
// If this segment was just a newline, then don't bother indenting it. That will just
|
|
||||||
// leave the user with an ugly indent in their output that they probably do not want.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indentationString === segment.substring(0, firstNonWhitespacePosition)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Record the edit
|
|
||||||
this.recordEdit(fullStart, firstNonWhitespacePosition, indentationString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,11 +14,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
///<reference path='..\services.ts' />
|
///<reference path='..\services.ts' />
|
||||||
///<reference path='textSnapshot.ts' />
|
|
||||||
///<reference path='textSnapshotLine.ts' />
|
|
||||||
///<reference path='snapshotPoint.ts' />
|
|
||||||
///<reference path='formattingContext.ts' />
|
///<reference path='formattingContext.ts' />
|
||||||
///<reference path='formattingManager.ts' />
|
|
||||||
///<reference path='formattingRequestKind.ts' />
|
///<reference path='formattingRequestKind.ts' />
|
||||||
///<reference path='rule.ts' />
|
///<reference path='rule.ts' />
|
||||||
///<reference path='ruleAction.ts' />
|
///<reference path='ruleAction.ts' />
|
||||||
|
@ -28,12 +24,5 @@
|
||||||
///<reference path='ruleOperationContext.ts' />
|
///<reference path='ruleOperationContext.ts' />
|
||||||
///<reference path='rules.ts' />
|
///<reference path='rules.ts' />
|
||||||
///<reference path='rulesMap.ts' />
|
///<reference path='rulesMap.ts' />
|
||||||
///<reference path='rulesProvider.ts' />
|
|
||||||
///<reference path='textEditInfo.ts' />
|
|
||||||
///<reference path='tokenRange.ts' />
|
///<reference path='tokenRange.ts' />
|
||||||
///<reference path='tokenSpan.ts' />
|
///<reference path='tokenSpan.ts' />
|
||||||
///<reference path='indentationNodeContext.ts' />
|
|
||||||
///<reference path='indentationNodeContextPool.ts' />
|
|
||||||
///<reference path='indentationTrackingWalker.ts' />
|
|
||||||
///<reference path='multipleTokenIndenter.ts' />
|
|
||||||
///<reference path='formatter.ts' />
|
|
|
@ -13,9 +13,9 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
///<reference path='references.ts' />
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
export class Rule {
|
export class Rule {
|
||||||
constructor(
|
constructor(
|
||||||
public Descriptor: RuleDescriptor,
|
public Descriptor: RuleDescriptor,
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
///<reference path='references.ts' />
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
export enum RuleAction {
|
export const enum RuleAction {
|
||||||
Ignore,
|
Ignore = 0x00000001,
|
||||||
Space,
|
Space = 0x00000002,
|
||||||
NewLine,
|
NewLine = 0x00000004,
|
||||||
Delete
|
Delete = 0x00000008
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,9 +13,9 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
///<reference path='references.ts' />
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
export class RuleDescriptor {
|
export class RuleDescriptor {
|
||||||
constructor(public LeftTokenRange: Shared.TokenRange, public RightTokenRange: Shared.TokenRange) {
|
constructor(public LeftTokenRange: Shared.TokenRange, public RightTokenRange: Shared.TokenRange) {
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ module TypeScript.Services.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
static create3(left: SyntaxKind, right: Shared.TokenRange): RuleDescriptor
|
static create3(left: SyntaxKind, right: Shared.TokenRange): RuleDescriptor
|
||||||
//: this(TokenRange.FromToken(left), right)
|
|
||||||
{
|
{
|
||||||
return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), right);
|
return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), right);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
///<reference path='references.ts' />
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
export enum RuleFlags {
|
export const enum RuleFlags {
|
||||||
None,
|
None,
|
||||||
CanDeleteNewLines
|
CanDeleteNewLines
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
///<reference path='references.ts' />
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
export class RuleOperation {
|
export class RuleOperation {
|
||||||
public Context: RuleOperationContext;
|
public Context: RuleOperationContext;
|
||||||
public Action: RuleAction;
|
public Action: RuleAction;
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
///<reference path='references.ts' />
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
|
|
||||||
export class RuleOperationContext {
|
export class RuleOperationContext {
|
||||||
private customContextChecks: { (context: FormattingContext): boolean; }[];
|
private customContextChecks: { (context: FormattingContext): boolean; }[];
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
///<reference path='references.ts' />
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
export class Rules {
|
export class Rules {
|
||||||
public getRuleName(rule: Rule) {
|
public getRuleName(rule: Rule) {
|
||||||
var o: ts.Map<any> = <any>this;
|
var o: ts.Map<any> = <any>this;
|
||||||
|
@ -241,7 +241,7 @@ module TypeScript.Services.Formatting {
|
||||||
this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
|
this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
|
||||||
|
|
||||||
// Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc)
|
// Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc)
|
||||||
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.MultiLineCommentTrivia]);
|
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia]);
|
||||||
this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
|
this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
|
||||||
|
|
||||||
// Place a space before open brace in a control flow construct
|
// Place a space before open brace in a control flow construct
|
||||||
|
@ -299,7 +299,7 @@ module TypeScript.Services.Formatting {
|
||||||
|
|
||||||
// get x() {}
|
// get x() {}
|
||||||
// set x(val) {}
|
// set x(val) {}
|
||||||
this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
|
this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
|
||||||
|
|
||||||
// Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options.
|
// Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options.
|
||||||
this.SpaceBeforeBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryKeywordOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
|
this.SpaceBeforeBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryKeywordOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
|
||||||
|
@ -324,7 +324,7 @@ module TypeScript.Services.Formatting {
|
||||||
this.SpaceAfterArrow = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsGreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
|
this.SpaceAfterArrow = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsGreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
|
||||||
|
|
||||||
// Optional parameters and var args
|
// Optional parameters and var args
|
||||||
this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||||
this.NoSpaceAfterOptionalParameters = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
|
this.NoSpaceAfterOptionalParameters = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
|
||||||
|
|
||||||
// generics
|
// generics
|
||||||
|
@ -437,7 +437,7 @@ module TypeScript.Services.Formatting {
|
||||||
///
|
///
|
||||||
|
|
||||||
static IsForContext(context: FormattingContext): boolean {
|
static IsForContext(context: FormattingContext): boolean {
|
||||||
return context.contextNode.kind() === SyntaxKind.ForStatement;
|
return context.contextNode.kind === SyntaxKind.ForStatement;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsNotForContext(context: FormattingContext): boolean {
|
static IsNotForContext(context: FormattingContext): boolean {
|
||||||
|
@ -446,8 +446,7 @@ module TypeScript.Services.Formatting {
|
||||||
|
|
||||||
static IsBinaryOpContext(context: FormattingContext): boolean {
|
static IsBinaryOpContext(context: FormattingContext): boolean {
|
||||||
|
|
||||||
switch (context.contextNode.kind()) {
|
switch (context.contextNode.kind) {
|
||||||
// binary expressions
|
|
||||||
case SyntaxKind.BinaryExpression:
|
case SyntaxKind.BinaryExpression:
|
||||||
case SyntaxKind.ConditionalExpression:
|
case SyntaxKind.ConditionalExpression:
|
||||||
return true;
|
return true;
|
||||||
|
@ -455,8 +454,11 @@ module TypeScript.Services.Formatting {
|
||||||
// equal in import a = module('a');
|
// equal in import a = module('a');
|
||||||
case SyntaxKind.ImportDeclaration:
|
case SyntaxKind.ImportDeclaration:
|
||||||
// equal in var a = 0;
|
// equal in var a = 0;
|
||||||
case SyntaxKind.VariableDeclarator:
|
case SyntaxKind.VariableDeclaration:
|
||||||
case SyntaxKind.EqualsValueClause:
|
// equal in p = 0;
|
||||||
|
case SyntaxKind.Parameter:
|
||||||
|
case SyntaxKind.EnumMember:
|
||||||
|
case SyntaxKind.Property:
|
||||||
return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken;
|
return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken;
|
||||||
// "in" keyword in for (var x in []) { }
|
// "in" keyword in for (var x in []) { }
|
||||||
case SyntaxKind.ForInStatement:
|
case SyntaxKind.ForInStatement:
|
||||||
|
@ -512,16 +514,21 @@ module TypeScript.Services.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children
|
// IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children
|
||||||
static NodeIsBlockContext(node: IndentationNodeContext): boolean {
|
static NodeIsBlockContext(node: Node): boolean {
|
||||||
if (Rules.NodeIsTypeScriptDeclWithBlockContext(node)) {
|
if (Rules.NodeIsTypeScriptDeclWithBlockContext(node)) {
|
||||||
// This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc).
|
// This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc).
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (node.kind()) {
|
switch (node.kind) {
|
||||||
case SyntaxKind.Block:
|
case SyntaxKind.Block:
|
||||||
case SyntaxKind.SwitchStatement:
|
case SyntaxKind.SwitchStatement:
|
||||||
case SyntaxKind.ObjectLiteralExpression:
|
case SyntaxKind.ObjectLiteral:
|
||||||
|
case SyntaxKind.TryBlock:
|
||||||
|
case SyntaxKind.CatchBlock:
|
||||||
|
case SyntaxKind.FinallyBlock:
|
||||||
|
case SyntaxKind.FunctionBlock:
|
||||||
|
case SyntaxKind.ModuleBlock:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,17 +536,20 @@ module TypeScript.Services.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsFunctionDeclContext(context: FormattingContext): boolean {
|
static IsFunctionDeclContext(context: FormattingContext): boolean {
|
||||||
switch (context.contextNode.kind()) {
|
switch (context.contextNode.kind) {
|
||||||
case SyntaxKind.FunctionDeclaration:
|
case SyntaxKind.FunctionDeclaration:
|
||||||
case SyntaxKind.MemberFunctionDeclaration:
|
case SyntaxKind.Method:
|
||||||
|
//case SyntaxKind.MemberFunctionDeclaration:
|
||||||
case SyntaxKind.GetAccessor:
|
case SyntaxKind.GetAccessor:
|
||||||
case SyntaxKind.SetAccessor:
|
case SyntaxKind.SetAccessor:
|
||||||
case SyntaxKind.MethodSignature:
|
///case SyntaxKind.MethodSignature:
|
||||||
case SyntaxKind.CallSignature:
|
case SyntaxKind.CallSignature:
|
||||||
case SyntaxKind.FunctionExpression:
|
case SyntaxKind.FunctionExpression:
|
||||||
case SyntaxKind.ConstructorDeclaration:
|
case SyntaxKind.Constructor:
|
||||||
case SyntaxKind.SimpleArrowFunctionExpression:
|
case SyntaxKind.ArrowFunction:
|
||||||
case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
//case SyntaxKind.ConstructorDeclaration:
|
||||||
|
//case SyntaxKind.SimpleArrowFunctionExpression:
|
||||||
|
//case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
||||||
case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one
|
case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -551,11 +561,12 @@ module TypeScript.Services.Formatting {
|
||||||
return Rules.NodeIsTypeScriptDeclWithBlockContext(context.contextNode);
|
return Rules.NodeIsTypeScriptDeclWithBlockContext(context.contextNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NodeIsTypeScriptDeclWithBlockContext(node: IndentationNodeContext): boolean {
|
static NodeIsTypeScriptDeclWithBlockContext(node: Node): boolean {
|
||||||
switch (node.kind()) {
|
switch (node.kind) {
|
||||||
case SyntaxKind.ClassDeclaration:
|
case SyntaxKind.ClassDeclaration:
|
||||||
|
case SyntaxKind.InterfaceDeclaration:
|
||||||
case SyntaxKind.EnumDeclaration:
|
case SyntaxKind.EnumDeclaration:
|
||||||
case SyntaxKind.ObjectType:
|
case SyntaxKind.TypeLiteral:
|
||||||
case SyntaxKind.ModuleDeclaration:
|
case SyntaxKind.ModuleDeclaration:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -564,11 +575,16 @@ module TypeScript.Services.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsAfterCodeBlockContext(context: FormattingContext): boolean {
|
static IsAfterCodeBlockContext(context: FormattingContext): boolean {
|
||||||
switch (context.currentTokenParent.kind()) {
|
switch (context.currentTokenParent.kind) {
|
||||||
case SyntaxKind.ClassDeclaration:
|
case SyntaxKind.ClassDeclaration:
|
||||||
case SyntaxKind.ModuleDeclaration:
|
case SyntaxKind.ModuleDeclaration:
|
||||||
case SyntaxKind.EnumDeclaration:
|
case SyntaxKind.EnumDeclaration:
|
||||||
case SyntaxKind.Block:
|
case SyntaxKind.Block:
|
||||||
|
case SyntaxKind.TryBlock:
|
||||||
|
case SyntaxKind.CatchBlock:
|
||||||
|
case SyntaxKind.FinallyBlock:
|
||||||
|
case SyntaxKind.FunctionBlock:
|
||||||
|
case SyntaxKind.ModuleBlock:
|
||||||
case SyntaxKind.SwitchStatement:
|
case SyntaxKind.SwitchStatement:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -576,7 +592,7 @@ module TypeScript.Services.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsControlDeclContext(context: FormattingContext): boolean {
|
static IsControlDeclContext(context: FormattingContext): boolean {
|
||||||
switch (context.contextNode.kind()) {
|
switch (context.contextNode.kind) {
|
||||||
case SyntaxKind.IfStatement:
|
case SyntaxKind.IfStatement:
|
||||||
case SyntaxKind.SwitchStatement:
|
case SyntaxKind.SwitchStatement:
|
||||||
case SyntaxKind.ForStatement:
|
case SyntaxKind.ForStatement:
|
||||||
|
@ -585,9 +601,10 @@ module TypeScript.Services.Formatting {
|
||||||
case SyntaxKind.TryStatement:
|
case SyntaxKind.TryStatement:
|
||||||
case SyntaxKind.DoStatement:
|
case SyntaxKind.DoStatement:
|
||||||
case SyntaxKind.WithStatement:
|
case SyntaxKind.WithStatement:
|
||||||
case SyntaxKind.ElseClause:
|
// TODO
|
||||||
case SyntaxKind.CatchClause:
|
// case SyntaxKind.ElseClause:
|
||||||
case SyntaxKind.FinallyClause:
|
case SyntaxKind.CatchBlock:
|
||||||
|
case SyntaxKind.FinallyBlock:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -596,15 +613,15 @@ module TypeScript.Services.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsObjectContext(context: FormattingContext): boolean {
|
static IsObjectContext(context: FormattingContext): boolean {
|
||||||
return context.contextNode.kind() === SyntaxKind.ObjectLiteralExpression;
|
return context.contextNode.kind === SyntaxKind.ObjectLiteral;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsFunctionCallContext(context: FormattingContext): boolean {
|
static IsFunctionCallContext(context: FormattingContext): boolean {
|
||||||
return context.contextNode.kind() === SyntaxKind.InvocationExpression;
|
return context.contextNode.kind === SyntaxKind.CallExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsNewContext(context: FormattingContext): boolean {
|
static IsNewContext(context: FormattingContext): boolean {
|
||||||
return context.contextNode.kind() === SyntaxKind.ObjectCreationExpression;
|
return context.contextNode.kind === SyntaxKind.NewExpression;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsFunctionCallOrNewContext(context: FormattingContext): boolean {
|
static IsFunctionCallOrNewContext(context: FormattingContext): boolean {
|
||||||
|
@ -620,25 +637,43 @@ module TypeScript.Services.Formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsModuleDeclContext(context: FormattingContext): boolean {
|
static IsModuleDeclContext(context: FormattingContext): boolean {
|
||||||
return context.contextNode.kind() === SyntaxKind.ModuleDeclaration;
|
return context.contextNode.kind === SyntaxKind.ModuleDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsObjectTypeContext(context: FormattingContext): boolean {
|
static IsObjectTypeContext(context: FormattingContext): boolean {
|
||||||
return context.contextNode.kind() === SyntaxKind.ObjectType && context.contextNode.parent().kind() !== SyntaxKind.InterfaceDeclaration;
|
return context.contextNode.kind === SyntaxKind.TypeLiteral;// && context.contextNode.parent.kind !== SyntaxKind.InterfaceDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsTypeArgumentOrParameter(tokenKind: SyntaxKind, parentKind: SyntaxKind): boolean {
|
static IsTypeArgumentOrParameter(token: TextRangeWithKind, parent: Node): boolean {
|
||||||
return ((tokenKind === SyntaxKind.LessThanToken || tokenKind === SyntaxKind.GreaterThanToken) &&
|
if (token.kind !== SyntaxKind.LessThanToken && token.kind !== SyntaxKind.GreaterThanToken) {
|
||||||
(parentKind === SyntaxKind.TypeParameterList || parentKind === SyntaxKind.TypeArgumentList));
|
return false;
|
||||||
|
}
|
||||||
|
switch (parent.kind) {
|
||||||
|
case SyntaxKind.TypeReference:
|
||||||
|
case SyntaxKind.ClassDeclaration:
|
||||||
|
case SyntaxKind.InterfaceDeclaration:
|
||||||
|
case SyntaxKind.FunctionDeclaration:
|
||||||
|
case SyntaxKind.FunctionExpression:
|
||||||
|
case SyntaxKind.ArrowFunction:
|
||||||
|
case SyntaxKind.Method:
|
||||||
|
case SyntaxKind.CallSignature:
|
||||||
|
case SyntaxKind.ConstructSignature:
|
||||||
|
case SyntaxKind.CallExpression:
|
||||||
|
case SyntaxKind.NewExpression:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsTypeArgumentOrParameterContext(context: FormattingContext): boolean {
|
static IsTypeArgumentOrParameterContext(context: FormattingContext): boolean {
|
||||||
return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan.kind, context.currentTokenParent.kind()) ||
|
return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan, context.currentTokenParent) ||
|
||||||
Rules.IsTypeArgumentOrParameter(context.nextTokenSpan.kind, context.nextTokenParent.kind());
|
Rules.IsTypeArgumentOrParameter(context.nextTokenSpan, context.nextTokenParent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static IsVoidOpContext(context: FormattingContext): boolean {
|
static IsVoidOpContext(context: FormattingContext): boolean {
|
||||||
return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind() === SyntaxKind.VoidExpression;
|
return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.PrefixOperator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,9 +13,9 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
///<reference path='references.ts' />
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
export class RulesMap {
|
export class RulesMap {
|
||||||
public map: RulesBucket[];
|
public map: RulesBucket[];
|
||||||
public mapRowLength: number;
|
public mapRowLength: number;
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
/// <reference path="formatting.ts"/>
|
/// <reference path="references.ts"/>
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
export class RulesProvider {
|
export class RulesProvider {
|
||||||
private globalRules: Rules;
|
private globalRules: Rules;
|
||||||
private options: ts.FormatCodeOptions;
|
private options: ts.FormatCodeOptions;
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
|
||||||
|
|
||||||
export class SnapshotPoint {
|
|
||||||
constructor(public snapshot: ITextSnapshot, public position: number) {
|
|
||||||
}
|
|
||||||
public getContainingLine(): ITextSnapshotLine {
|
|
||||||
return this.snapshot.getLineFromPosition(this.position);
|
|
||||||
}
|
|
||||||
public add(offset: number): SnapshotPoint {
|
|
||||||
return new SnapshotPoint(this.snapshot, this.position + offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
|
||||||
export class TextEditInfo {
|
|
||||||
|
|
||||||
constructor(public position: number, public length: number, public replaceWith: string) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public toString() {
|
|
||||||
return "[ position: " + this.position + ", length: " + this.length + ", replaceWith: '" + this.replaceWith + "' ]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
|
||||||
export interface ITextSnapshot {
|
|
||||||
getLength(): number;
|
|
||||||
getText(span: TextSpan): string;
|
|
||||||
getLineNumberFromPosition(position: number): number;
|
|
||||||
getLineFromPosition(position: number): ITextSnapshotLine;
|
|
||||||
getLineFromLineNumber(lineNumber: number): ITextSnapshotLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TextSnapshot implements ITextSnapshot {
|
|
||||||
private lines: TextSnapshotLine[];
|
|
||||||
|
|
||||||
constructor(private snapshot: ISimpleText) {
|
|
||||||
this.lines = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public getLength(): number {
|
|
||||||
return this.snapshot.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
public getText(span: TextSpan): string {
|
|
||||||
return this.snapshot.substr(span.start(), span.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
public getLineNumberFromPosition(position: number): number {
|
|
||||||
return this.snapshot.lineMap().getLineNumberFromPosition(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getLineFromPosition(position: number): ITextSnapshotLine {
|
|
||||||
var lineNumber = this.getLineNumberFromPosition(position);
|
|
||||||
return this.getLineFromLineNumber(lineNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getLineFromLineNumber(lineNumber: number): ITextSnapshotLine {
|
|
||||||
var line = this.lines[lineNumber];
|
|
||||||
if (line === undefined) {
|
|
||||||
line = <TextSnapshotLine>this.getLineFromLineNumberWorker(lineNumber);
|
|
||||||
this.lines[lineNumber] = line;
|
|
||||||
}
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getLineFromLineNumberWorker(lineNumber: number): ITextSnapshotLine {
|
|
||||||
var lineMap = this.snapshot.lineMap().lineStarts();
|
|
||||||
var lineMapIndex = lineNumber; //Note: lineMap is 0-based
|
|
||||||
if (lineMapIndex < 0 || lineMapIndex >= lineMap.length)
|
|
||||||
throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Invalid_line_number_0, [lineMapIndex]));
|
|
||||||
var start = lineMap[lineMapIndex];
|
|
||||||
|
|
||||||
var end: number;
|
|
||||||
var endIncludingLineBreak: number;
|
|
||||||
var lineBreak = "";
|
|
||||||
if (lineMapIndex == lineMap.length) {
|
|
||||||
end = endIncludingLineBreak = this.snapshot.length();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
endIncludingLineBreak = (lineMapIndex >= lineMap.length - 1 ? this.snapshot.length() : lineMap[lineMapIndex + 1]);
|
|
||||||
for (var p = endIncludingLineBreak - 1; p >= start; p--) {
|
|
||||||
var c = this.snapshot.substr(p, 1);
|
|
||||||
//TODO: Other ones?
|
|
||||||
if (c != "\r" && c != "\n") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end = p + 1;
|
|
||||||
lineBreak = this.snapshot.substr(end, endIncludingLineBreak - end);
|
|
||||||
}
|
|
||||||
var result = new TextSnapshotLine(this, lineNumber, start, end, lineBreak);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
//
|
|
||||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
|
||||||
export interface ITextSnapshotLine {
|
|
||||||
snapshot(): ITextSnapshot;
|
|
||||||
|
|
||||||
start(): SnapshotPoint;
|
|
||||||
startPosition(): number;
|
|
||||||
|
|
||||||
end(): SnapshotPoint;
|
|
||||||
endPosition(): number;
|
|
||||||
|
|
||||||
endIncludingLineBreak(): SnapshotPoint;
|
|
||||||
endIncludingLineBreakPosition(): number;
|
|
||||||
|
|
||||||
length(): number;
|
|
||||||
lineNumber(): number;
|
|
||||||
getText(): string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TextSnapshotLine implements ITextSnapshotLine {
|
|
||||||
constructor(private _snapshot: ITextSnapshot, private _lineNumber: number, private _start: number, private _end: number, private _lineBreak: string) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public snapshot() {
|
|
||||||
return this._snapshot;
|
|
||||||
}
|
|
||||||
|
|
||||||
public start() {
|
|
||||||
return new SnapshotPoint(this._snapshot, this._start);
|
|
||||||
}
|
|
||||||
|
|
||||||
public startPosition() {
|
|
||||||
return this._start;
|
|
||||||
}
|
|
||||||
|
|
||||||
public end() {
|
|
||||||
return new SnapshotPoint(this._snapshot, this._end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public endPosition() {
|
|
||||||
return this._end;
|
|
||||||
}
|
|
||||||
|
|
||||||
public endIncludingLineBreak() {
|
|
||||||
return new SnapshotPoint(this._snapshot, this._end + this._lineBreak.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public endIncludingLineBreakPosition() {
|
|
||||||
return this._end + this._lineBreak.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public length() {
|
|
||||||
return this._end - this._start;
|
|
||||||
}
|
|
||||||
|
|
||||||
public lineNumber() {
|
|
||||||
return this._lineNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getText(): string {
|
|
||||||
return this._snapshot.getText(TextSpan.fromBounds(this._start, this._end));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,9 +13,9 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
///<reference path='references.ts' />
|
||||||
|
|
||||||
module TypeScript.Services.Formatting {
|
module ts.formatting {
|
||||||
export module Shared {
|
export module Shared {
|
||||||
export interface ITokenAccess {
|
export interface ITokenAccess {
|
||||||
GetTokens(): SyntaxKind[];
|
GetTokens(): SyntaxKind[];
|
||||||
|
@ -41,12 +41,6 @@ module TypeScript.Services.Formatting {
|
||||||
public Contains(token: SyntaxKind): boolean {
|
public Contains(token: SyntaxKind): boolean {
|
||||||
return this.tokens.indexOf(token) >= 0;
|
return this.tokens.indexOf(token) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public toString(): string {
|
|
||||||
return "[tokenRangeStart=" + SyntaxKind[this.tokens[0]] + "," +
|
|
||||||
"tokenRangeEnd=" + SyntaxKind[this.tokens[this.tokens.length - 1]] + "]";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TokenValuesAccess implements ITokenAccess {
|
export class TokenValuesAccess implements ITokenAccess {
|
||||||
|
@ -76,10 +70,6 @@ module TypeScript.Services.Formatting {
|
||||||
public Contains(tokenValue: SyntaxKind): boolean {
|
public Contains(tokenValue: SyntaxKind): boolean {
|
||||||
return tokenValue == this.token;
|
return tokenValue == this.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public toString(): string {
|
|
||||||
return "[singleTokenKind=" + SyntaxKind[this.token] + "]";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TokenAllAccess implements ITokenAccess {
|
export class TokenAllAccess implements ITokenAccess {
|
||||||
|
@ -135,18 +125,18 @@ module TypeScript.Services.Formatting {
|
||||||
static Any: TokenRange = TokenRange.AllTokens();
|
static Any: TokenRange = TokenRange.AllTokens();
|
||||||
static AnyIncludingMultilineComments = TokenRange.FromTokens(TokenRange.Any.GetTokens().concat([SyntaxKind.MultiLineCommentTrivia]));
|
static AnyIncludingMultilineComments = TokenRange.FromTokens(TokenRange.Any.GetTokens().concat([SyntaxKind.MultiLineCommentTrivia]));
|
||||||
static Keywords = TokenRange.FromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword);
|
static Keywords = TokenRange.FromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword);
|
||||||
static Operators = TokenRange.FromRange(SyntaxKind.SemicolonToken, SyntaxKind.SlashEqualsToken);
|
static Operators = TokenRange.FromRange(SyntaxKind.FirstOperator, SyntaxKind.LastOperator);
|
||||||
static BinaryOperators = TokenRange.FromRange(SyntaxKind.LessThanToken, SyntaxKind.SlashEqualsToken);
|
static BinaryOperators = TokenRange.FromRange(SyntaxKind.FirstBinaryOperator, SyntaxKind.LastBinaryOperator);
|
||||||
static BinaryKeywordOperators = TokenRange.FromTokens([SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword]);
|
static BinaryKeywordOperators = TokenRange.FromTokens([SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword]);
|
||||||
static ReservedKeywords = TokenRange.FromRange(SyntaxKind.FirstFutureReservedStrictKeyword, SyntaxKind.LastFutureReservedStrictKeyword);
|
static ReservedKeywords = TokenRange.FromRange(SyntaxKind.FirstFutureReservedWord, SyntaxKind.LastFutureReservedWord);
|
||||||
static UnaryPrefixOperators = TokenRange.FromTokens([SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]);
|
static UnaryPrefixOperators = TokenRange.FromTokens([SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]);
|
||||||
static UnaryPrefixExpressions = TokenRange.FromTokens([SyntaxKind.NumericLiteral, SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
static UnaryPrefixExpressions = TokenRange.FromTokens([SyntaxKind.NumericLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||||
static UnaryPreincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
static UnaryPreincrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||||
static UnaryPostincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
static UnaryPostincrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||||
static UnaryPredecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
static UnaryPredecrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||||
static UnaryPostdecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
static UnaryPostdecrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||||
static Comments = TokenRange.FromTokens([SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]);
|
static Comments = TokenRange.FromTokens([SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]);
|
||||||
static TypeNames = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]);
|
static TypeNames = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,11 +13,10 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
///<reference path='formatting.ts' />
|
///<reference path='references.ts' />
|
||||||
|
|
||||||
|
module ts.formatting {
|
||||||
module TypeScript.Services.Formatting {
|
export class TokenSpan extends TypeScript.TextSpan {
|
||||||
export class TokenSpan extends TextSpan {
|
|
||||||
constructor(public kind: SyntaxKind, start: number, length: number) {
|
constructor(public kind: SyntaxKind, start: number, length: number) {
|
||||||
super(start, length);
|
super(start, length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
|
|
||||||
module TypeScript.Indentation {
|
|
||||||
// Returns the column that this input string ends at (assuming it starts at column 0).
|
|
||||||
export function columnForPositionInString(input: string, position: number, options: FormattingOptions): number {
|
|
||||||
return columnForPositionInStringWorker(input, position, 0, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
function columnForPositionInStringWorker(input: string, position: number, startColumn: number, options: FormattingOptions): number {
|
|
||||||
var column = startColumn;
|
|
||||||
var spacesPerTab = options.spacesPerTab;
|
|
||||||
|
|
||||||
for (var j = 0; j < position; j++) {
|
|
||||||
var ch = input.charCodeAt(j);
|
|
||||||
|
|
||||||
if (ch === CharacterCodes.tab) {
|
|
||||||
column += spacesPerTab - column % spacesPerTab;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
column++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return column;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function indentationString(column: number, options: FormattingOptions): string {
|
|
||||||
var numberOfTabs = 0;
|
|
||||||
var numberOfSpaces = Math.max(0, column);
|
|
||||||
|
|
||||||
if (options.useTabs) {
|
|
||||||
numberOfTabs = Math.floor(column / options.spacesPerTab);
|
|
||||||
numberOfSpaces -= numberOfTabs * options.spacesPerTab;
|
|
||||||
}
|
|
||||||
|
|
||||||
return StringUtilities.repeat('\t', numberOfTabs) +
|
|
||||||
StringUtilities.repeat(' ', numberOfSpaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function firstNonWhitespacePosition(value: string): number {
|
|
||||||
for (var i = 0; i < value.length; i++) {
|
|
||||||
var ch = value.charCodeAt(i);
|
|
||||||
if (!CharacterInfo.isWhitespace(ch)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.length;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -96,6 +96,7 @@ module TypeScript {
|
||||||
Type_expected: "Type expected.",
|
Type_expected: "Type expected.",
|
||||||
Template_literal_cannot_be_used_as_an_element_name: "Template literal cannot be used as an element name.",
|
Template_literal_cannot_be_used_as_an_element_name: "Template literal cannot be used as an element name.",
|
||||||
Computed_property_names_cannot_be_used_here: "Computed property names cannot be used here.",
|
Computed_property_names_cannot_be_used_here: "Computed property names cannot be used here.",
|
||||||
|
yield_expression_must_be_contained_within_a_generator_declaration: "'yield' expression must be contained within a generator declaration.",
|
||||||
Duplicate_identifier_0: "Duplicate identifier '{0}'.",
|
Duplicate_identifier_0: "Duplicate identifier '{0}'.",
|
||||||
The_name_0_does_not_exist_in_the_current_scope: "The name '{0}' does not exist in the current scope.",
|
The_name_0_does_not_exist_in_the_current_scope: "The name '{0}' does not exist in the current scope.",
|
||||||
The_name_0_does_not_refer_to_a_value: "The name '{0}' does not refer to a value.",
|
The_name_0_does_not_refer_to_a_value: "The name '{0}' does not refer to a value.",
|
||||||
|
|
|
@ -98,6 +98,7 @@ module TypeScript {
|
||||||
"Type expected.": { "code": 1110, "category": DiagnosticCategory.Error },
|
"Type expected.": { "code": 1110, "category": DiagnosticCategory.Error },
|
||||||
"Template literal cannot be used as an element name.": { "code": 1111, "category": DiagnosticCategory.Error },
|
"Template literal cannot be used as an element name.": { "code": 1111, "category": DiagnosticCategory.Error },
|
||||||
"Computed property names cannot be used here.": { "code": 1112, "category": DiagnosticCategory.Error },
|
"Computed property names cannot be used here.": { "code": 1112, "category": DiagnosticCategory.Error },
|
||||||
|
"'yield' expression must be contained within a generator declaration.": { "code": 1113, "category": DiagnosticCategory.Error },
|
||||||
"Duplicate identifier '{0}'.": { "code": 2000, "category": DiagnosticCategory.Error },
|
"Duplicate identifier '{0}'.": { "code": 2000, "category": DiagnosticCategory.Error },
|
||||||
"The name '{0}' does not exist in the current scope.": { "code": 2001, "category": DiagnosticCategory.Error },
|
"The name '{0}' does not exist in the current scope.": { "code": 2001, "category": DiagnosticCategory.Error },
|
||||||
"The name '{0}' does not refer to a value.": { "code": 2002, "category": DiagnosticCategory.Error },
|
"The name '{0}' does not refer to a value.": { "code": 2002, "category": DiagnosticCategory.Error },
|
||||||
|
|
|
@ -379,6 +379,10 @@
|
||||||
"category": "Error",
|
"category": "Error",
|
||||||
"code": 1112
|
"code": 1112
|
||||||
},
|
},
|
||||||
|
"'yield' expression must be contained within a generator declaration.": {
|
||||||
|
"category": "Error",
|
||||||
|
"code": 1113
|
||||||
|
},
|
||||||
"Duplicate identifier '{0}'.": {
|
"Duplicate identifier '{0}'.": {
|
||||||
"category": "Error",
|
"category": "Error",
|
||||||
"code": 2000
|
"code": 2000
|
||||||
|
|
|
@ -8,11 +8,10 @@
|
||||||
/// <reference path='outliningElementsCollector.ts' />
|
/// <reference path='outliningElementsCollector.ts' />
|
||||||
/// <reference path='navigationBar.ts' />
|
/// <reference path='navigationBar.ts' />
|
||||||
/// <reference path='breakpoints.ts' />
|
/// <reference path='breakpoints.ts' />
|
||||||
/// <reference path='indentation.ts' />
|
|
||||||
/// <reference path='signatureHelp.ts' />
|
/// <reference path='signatureHelp.ts' />
|
||||||
/// <reference path='utilities.ts' />
|
/// <reference path='utilities.ts' />
|
||||||
/// <reference path='formatting\formatting.ts' />
|
/// <reference path='smartIndenter.ts' />
|
||||||
/// <reference path='formatting\smartIndenter.ts' />
|
/// <reference path='formatting.ts' />
|
||||||
|
|
||||||
/// <reference path='core\references.ts' />
|
/// <reference path='core\references.ts' />
|
||||||
/// <reference path='resources\references.ts' />
|
/// <reference path='resources\references.ts' />
|
||||||
|
@ -667,6 +666,7 @@ module ts {
|
||||||
public text: string;
|
public text: string;
|
||||||
public getLineAndCharacterFromPosition(position: number): { line: number; character: number } { return null; }
|
public getLineAndCharacterFromPosition(position: number): { line: number; character: number } { return null; }
|
||||||
public getPositionFromLineAndCharacter(line: number, character: number): number { return -1; }
|
public getPositionFromLineAndCharacter(line: number, character: number): number { return -1; }
|
||||||
|
public getLineStarts(): number[] { return undefined; }
|
||||||
public amdDependencies: string[];
|
public amdDependencies: string[];
|
||||||
public referencedFiles: FileReference[];
|
public referencedFiles: FileReference[];
|
||||||
public syntacticErrors: Diagnostic[];
|
public syntacticErrors: Diagnostic[];
|
||||||
|
@ -2137,7 +2137,7 @@ module ts {
|
||||||
|
|
||||||
export function createLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry): LanguageService {
|
export function createLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry): LanguageService {
|
||||||
var syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host);
|
var syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host);
|
||||||
var formattingRulesProvider: TypeScript.Services.Formatting.RulesProvider;
|
var ruleProvider: ts.formatting.RulesProvider;
|
||||||
var hostCache: HostCache; // A cache of all the information about the files on the host side.
|
var hostCache: HostCache; // A cache of all the information about the files on the host side.
|
||||||
var program: Program;
|
var program: Program;
|
||||||
|
|
||||||
|
@ -2168,6 +2168,16 @@ module ts {
|
||||||
return fullTypeCheckChecker_doNotAccessDirectly || (fullTypeCheckChecker_doNotAccessDirectly = program.getTypeChecker(/*fullTypeCheck*/ true));
|
return fullTypeCheckChecker_doNotAccessDirectly || (fullTypeCheckChecker_doNotAccessDirectly = program.getTypeChecker(/*fullTypeCheck*/ true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRuleProvider(options: FormatCodeOptions) {
|
||||||
|
// Ensure rules are initialized and up to date wrt to formatting options
|
||||||
|
if (!ruleProvider) {
|
||||||
|
ruleProvider = new ts.formatting.RulesProvider(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
ruleProvider.ensureUpToDate(options);
|
||||||
|
return ruleProvider;
|
||||||
|
}
|
||||||
|
|
||||||
function createCompilerHost(): CompilerHost {
|
function createCompilerHost(): CompilerHost {
|
||||||
return {
|
return {
|
||||||
getSourceFile: (filename, languageVersion) => {
|
getSourceFile: (filename, languageVersion) => {
|
||||||
|
@ -5044,7 +5054,7 @@ module ts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPunctuation(token)) {
|
if (isPunctuation(token.kind)) {
|
||||||
// the '=' in a variable declaration is special cased here.
|
// the '=' in a variable declaration is special cased here.
|
||||||
if (token.parent.kind === SyntaxKind.BinaryExpression ||
|
if (token.parent.kind === SyntaxKind.BinaryExpression ||
|
||||||
token.parent.kind === SyntaxKind.VariableDeclaration ||
|
token.parent.kind === SyntaxKind.VariableDeclaration ||
|
||||||
|
@ -5190,62 +5200,39 @@ module ts {
|
||||||
host.log("getIndentationAtPosition: getCurrentSourceFile: " + (new Date().getTime() - start));
|
host.log("getIndentationAtPosition: getCurrentSourceFile: " + (new Date().getTime() - start));
|
||||||
|
|
||||||
var start = new Date().getTime();
|
var start = new Date().getTime();
|
||||||
var options = new TypeScript.FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter)
|
|
||||||
|
|
||||||
var result = formatting.SmartIndenter.getIndentation(position, sourceFile, options);
|
var result = formatting.SmartIndenter.getIndentation(position, sourceFile, editorOptions);
|
||||||
host.log("getIndentationAtPosition: computeIndentation : " + (new Date().getTime() - start));
|
host.log("getIndentationAtPosition: computeIndentation : " + (new Date().getTime() - start));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFormattingManager(filename: string, options: FormatCodeOptions) {
|
|
||||||
// Ensure rules are initialized and up to date wrt to formatting options
|
|
||||||
if (formattingRulesProvider == null) {
|
|
||||||
formattingRulesProvider = new TypeScript.Services.Formatting.RulesProvider(host);
|
|
||||||
}
|
|
||||||
|
|
||||||
formattingRulesProvider.ensureUpToDate(options);
|
|
||||||
|
|
||||||
// Get the Syntax Tree
|
|
||||||
var syntaxTree = getSyntaxTree(filename);
|
|
||||||
|
|
||||||
// Convert IScriptSnapshot to ITextSnapshot
|
|
||||||
var scriptSnapshot = syntaxTreeCache.getCurrentScriptSnapshot(filename);
|
|
||||||
var scriptText = TypeScript.SimpleText.fromScriptSnapshot(scriptSnapshot);
|
|
||||||
var textSnapshot = new TypeScript.Services.Formatting.TextSnapshot(scriptText);
|
|
||||||
|
|
||||||
var manager = new TypeScript.Services.Formatting.FormattingManager(syntaxTree, textSnapshot, formattingRulesProvider, options);
|
|
||||||
|
|
||||||
return manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions): TextChange[] {
|
function getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions): TextChange[] {
|
||||||
fileName = normalizeSlashes(fileName);
|
fileName = normalizeSlashes(fileName);
|
||||||
|
var sourceFile = getCurrentSourceFile(fileName);
|
||||||
var manager = getFormattingManager(fileName, options);
|
return formatting.formatSelection(start, end, sourceFile, getRuleProvider(options), options);
|
||||||
return manager.formatSelection(start, end);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions): TextChange[] {
|
function getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions): TextChange[] {
|
||||||
fileName = normalizeSlashes(fileName);
|
fileName = normalizeSlashes(fileName);
|
||||||
|
|
||||||
var manager = getFormattingManager(fileName, options);
|
var sourceFile = getCurrentSourceFile(fileName);
|
||||||
return manager.formatDocument();
|
return formatting.formatDocument(sourceFile, getRuleProvider(options), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextChange[] {
|
function getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextChange[] {
|
||||||
fileName = normalizeSlashes(fileName);
|
fileName = normalizeSlashes(fileName);
|
||||||
|
|
||||||
var manager = getFormattingManager(fileName, options);
|
var sourceFile = getCurrentSourceFile(fileName);
|
||||||
|
|
||||||
if (key === "}") {
|
if (key === "}") {
|
||||||
return manager.formatOnClosingCurlyBrace(position);
|
return formatting.formatOnClosingCurly(position, sourceFile, getRuleProvider(options), options);
|
||||||
}
|
}
|
||||||
else if (key === ";") {
|
else if (key === ";") {
|
||||||
return manager.formatOnSemicolon(position);
|
return formatting.formatOnSemicolon(position, sourceFile, getRuleProvider(options), options);
|
||||||
}
|
}
|
||||||
else if (key === "\n") {
|
else if (key === "\n") {
|
||||||
return manager.formatOnEnter(position);
|
return formatting.formatOnEnter(position, sourceFile, getRuleProvider(options), options);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
///<reference path='..\services.ts' />
|
///<reference path='services.ts' />
|
||||||
|
|
||||||
module ts.formatting {
|
module ts.formatting {
|
||||||
export module SmartIndenter {
|
export module SmartIndenter {
|
||||||
export function getIndentation(position: number, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
export function getIndentation(position: number, sourceFile: SourceFile, options: EditorOptions): number {
|
||||||
if (position > sourceFile.text.length) {
|
if (position > sourceFile.text.length) {
|
||||||
return 0; // past EOF
|
return 0; // past EOF
|
||||||
}
|
}
|
||||||
|
@ -37,14 +37,14 @@ module ts.formatting {
|
||||||
var indentationDelta: number;
|
var indentationDelta: number;
|
||||||
|
|
||||||
while (current) {
|
while (current) {
|
||||||
if (positionBelongsToNode(current, position, sourceFile) && nodeContentIsIndented(current, previous)) {
|
if (positionBelongsToNode(current, position, sourceFile) && shouldIndentChildNode(current.kind, previous ? previous.kind : SyntaxKind.Unknown)) {
|
||||||
currentStart = getStartLineAndCharacterForNode(current, sourceFile);
|
currentStart = getStartLineAndCharacterForNode(current, sourceFile);
|
||||||
|
|
||||||
if (nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile)) {
|
if (nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile)) {
|
||||||
indentationDelta = 0;
|
indentationDelta = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
indentationDelta = lineAtPosition !== currentStart.line ? options.indentSpaces : 0;
|
indentationDelta = lineAtPosition !== currentStart.line ? options.IndentSize : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -65,6 +65,21 @@ module ts.formatting {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return getIndentationForNodeWorker(current, currentStart, /*ignoreActualIndentationRange*/ undefined, indentationDelta, sourceFile, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getIndentationForNode(n: Node, ignoreActualIndentationRange: TextRange, sourceFile: SourceFile, options: FormatCodeOptions): number {
|
||||||
|
var start = sourceFile.getLineAndCharacterFromPosition(n.getStart(sourceFile));
|
||||||
|
return getIndentationForNodeWorker(n, start, ignoreActualIndentationRange, /*indentationDelta*/ 0, sourceFile, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIndentationForNodeWorker(
|
||||||
|
current: Node,
|
||||||
|
currentStart: LineAndCharacter,
|
||||||
|
ignoreActualIndentationRange: TextRange,
|
||||||
|
indentationDelta: number,
|
||||||
|
sourceFile: SourceFile,
|
||||||
|
options: EditorOptions): number {
|
||||||
|
|
||||||
var parent: Node = current.parent;
|
var parent: Node = current.parent;
|
||||||
var parentStart: LineAndCharacter;
|
var parentStart: LineAndCharacter;
|
||||||
|
@ -72,26 +87,35 @@ module ts.formatting {
|
||||||
// walk upwards and collect indentations for pairs of parent-child nodes
|
// walk upwards and collect indentations for pairs of parent-child nodes
|
||||||
// indentation is not added if parent and child nodes start on the same line or if parent is IfStatement and child starts on the same line with 'else clause'
|
// indentation is not added if parent and child nodes start on the same line or if parent is IfStatement and child starts on the same line with 'else clause'
|
||||||
while (parent) {
|
while (parent) {
|
||||||
|
var useActualIndentation = true;
|
||||||
|
if (ignoreActualIndentationRange) {
|
||||||
|
var start = current.getStart(sourceFile);
|
||||||
|
useActualIndentation = start < ignoreActualIndentationRange.pos || start > ignoreActualIndentationRange.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useActualIndentation) {
|
||||||
// check if current node is a list item - if yes, take indentation from it
|
// check if current node is a list item - if yes, take indentation from it
|
||||||
var actualIndentation = getActualIndentationForListItem(current, sourceFile, options);
|
var actualIndentation = getActualIndentationForListItem(current, sourceFile, options);
|
||||||
if (actualIndentation !== -1) {
|
if (actualIndentation !== -1) {
|
||||||
return actualIndentation + indentationDelta;
|
return actualIndentation + indentationDelta;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
parentStart = sourceFile.getLineAndCharacterFromPosition(parent.getStart(sourceFile));
|
parentStart = getParentStart(parent, current, sourceFile);
|
||||||
var parentAndChildShareLine =
|
var parentAndChildShareLine =
|
||||||
parentStart.line === currentStart.line ||
|
parentStart.line === currentStart.line ||
|
||||||
childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile);
|
childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile);
|
||||||
|
|
||||||
|
if (useActualIndentation) {
|
||||||
// try to fetch actual indentation for current node from source text
|
// try to fetch actual indentation for current node from source text
|
||||||
var actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options);
|
var actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options);
|
||||||
if (actualIndentation !== -1) {
|
if (actualIndentation !== -1) {
|
||||||
return actualIndentation + indentationDelta;
|
return actualIndentation + indentationDelta;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// increase indentation if parent node wants its content to be indented and parent and child nodes don't start on the same line
|
// increase indentation if parent node wants its content to be indented and parent and child nodes don't start on the same line
|
||||||
if (nodeContentIsIndented(parent, current) && !parentAndChildShareLine) {
|
if (shouldIndentChildNode(parent.kind, current.kind) && !parentAndChildShareLine) {
|
||||||
indentationDelta += options.indentSpaces;
|
indentationDelta += options.IndentSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
current = parent;
|
current = parent;
|
||||||
|
@ -102,10 +126,20 @@ module ts.formatting {
|
||||||
return indentationDelta;
|
return indentationDelta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getParentStart(parent: Node, child: Node, sourceFile: SourceFile): LineAndCharacter {
|
||||||
|
var containingList = getContainingList(child, sourceFile);
|
||||||
|
if (containingList) {
|
||||||
|
return sourceFile.getLineAndCharacterFromPosition(containingList.pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceFile.getLineAndCharacterFromPosition(parent.getStart(sourceFile));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Function returns -1 if indentation cannot be determined
|
* Function returns -1 if indentation cannot be determined
|
||||||
*/
|
*/
|
||||||
function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: EditorOptions): number {
|
||||||
// previous token is comma that separates items in list - find the previous item and try to derive indentation from it
|
// previous token is comma that separates items in list - find the previous item and try to derive indentation from it
|
||||||
var commaItemInfo = findListItemInfo(commaToken);
|
var commaItemInfo = findListItemInfo(commaToken);
|
||||||
Debug.assert(commaItemInfo && commaItemInfo.listItemIndex > 0);
|
Debug.assert(commaItemInfo && commaItemInfo.listItemIndex > 0);
|
||||||
|
@ -121,7 +155,7 @@ module ts.formatting {
|
||||||
currentLineAndChar: LineAndCharacter,
|
currentLineAndChar: LineAndCharacter,
|
||||||
parentAndChildShareLine: boolean,
|
parentAndChildShareLine: boolean,
|
||||||
sourceFile: SourceFile,
|
sourceFile: SourceFile,
|
||||||
options: TypeScript.FormattingOptions): number {
|
options: EditorOptions): number {
|
||||||
|
|
||||||
// actual indentation is used for statements\declarations if one of cases below is true:
|
// actual indentation is used for statements\declarations if one of cases below is true:
|
||||||
// - parent is SourceFile - by default immediate children of SourceFile are not indented except when user indents them manually
|
// - parent is SourceFile - by default immediate children of SourceFile are not indented except when user indents them manually
|
||||||
|
@ -172,7 +206,7 @@ module ts.formatting {
|
||||||
return candidate.end > position || !isCompletedNode(candidate, sourceFile);
|
return candidate.end > position || !isCompletedNode(candidate, sourceFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: Node, childStartLine: number, sourceFile: SourceFile): boolean {
|
export function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFile): boolean {
|
||||||
if (parent.kind === SyntaxKind.IfStatement && (<IfStatement>parent).elseStatement === child) {
|
if (parent.kind === SyntaxKind.IfStatement && (<IfStatement>parent).elseStatement === child) {
|
||||||
var elseKeyword = findChildOfKind(parent, SyntaxKind.ElseKeyword, sourceFile);
|
var elseKeyword = findChildOfKind(parent, SyntaxKind.ElseKeyword, sourceFile);
|
||||||
Debug.assert(elseKeyword !== undefined);
|
Debug.assert(elseKeyword !== undefined);
|
||||||
|
@ -180,22 +214,22 @@ module ts.formatting {
|
||||||
var elseKeywordStartLine = getStartLineAndCharacterForNode(elseKeyword, sourceFile).line;
|
var elseKeywordStartLine = getStartLineAndCharacterForNode(elseKeyword, sourceFile).line;
|
||||||
return elseKeywordStartLine === childStartLine;
|
return elseKeywordStartLine === childStartLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
function getContainingList(node: Node, sourceFile: SourceFile): NodeArray<Node> {
|
||||||
if (node.parent) {
|
if (node.parent) {
|
||||||
switch (node.parent.kind) {
|
switch (node.parent.kind) {
|
||||||
case SyntaxKind.TypeReference:
|
case SyntaxKind.TypeReference:
|
||||||
if ((<TypeReferenceNode>node.parent).typeArguments) {
|
if ((<TypeReferenceNode>node.parent).typeArguments) {
|
||||||
return getActualIndentationFromList((<TypeReferenceNode>node.parent).typeArguments);
|
return (<TypeReferenceNode>node.parent).typeArguments;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SyntaxKind.ObjectLiteral:
|
case SyntaxKind.ObjectLiteral:
|
||||||
return getActualIndentationFromList((<ObjectLiteral>node.parent).properties);
|
return (<ObjectLiteral>node.parent).properties;
|
||||||
case SyntaxKind.TypeLiteral:
|
|
||||||
return getActualIndentationFromList((<TypeLiteralNode>node.parent).members);
|
|
||||||
case SyntaxKind.ArrayLiteral:
|
case SyntaxKind.ArrayLiteral:
|
||||||
return getActualIndentationFromList((<ArrayLiteral>node.parent).elements);
|
return (<ArrayLiteral>node.parent).elements;
|
||||||
case SyntaxKind.FunctionDeclaration:
|
case SyntaxKind.FunctionDeclaration:
|
||||||
case SyntaxKind.FunctionExpression:
|
case SyntaxKind.FunctionExpression:
|
||||||
case SyntaxKind.ArrowFunction:
|
case SyntaxKind.ArrowFunction:
|
||||||
|
@ -203,21 +237,26 @@ module ts.formatting {
|
||||||
case SyntaxKind.CallSignature:
|
case SyntaxKind.CallSignature:
|
||||||
case SyntaxKind.ConstructSignature:
|
case SyntaxKind.ConstructSignature:
|
||||||
if ((<SignatureDeclaration>node.parent).typeParameters && node.end < (<SignatureDeclaration>node.parent).typeParameters.end) {
|
if ((<SignatureDeclaration>node.parent).typeParameters && node.end < (<SignatureDeclaration>node.parent).typeParameters.end) {
|
||||||
return getActualIndentationFromList((<SignatureDeclaration>node.parent).typeParameters);
|
return (<SignatureDeclaration>node.parent).typeParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getActualIndentationFromList((<SignatureDeclaration>node.parent).parameters);
|
return (<SignatureDeclaration>node.parent).parameters;
|
||||||
case SyntaxKind.NewExpression:
|
case SyntaxKind.NewExpression:
|
||||||
case SyntaxKind.CallExpression:
|
case SyntaxKind.CallExpression:
|
||||||
if ((<CallExpression>node.parent).typeArguments && node.end < (<CallExpression>node.parent).typeArguments.end) {
|
if ((<CallExpression>node.parent).typeArguments && node.end < (<CallExpression>node.parent).typeArguments.end) {
|
||||||
return getActualIndentationFromList((<CallExpression>node.parent).typeArguments);
|
return (<CallExpression>node.parent).typeArguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getActualIndentationFromList((<CallExpression>node.parent).arguments);
|
return (<CallExpression>node.parent).arguments;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorOptions): number {
|
||||||
|
var containingList = getContainingList(node, sourceFile);
|
||||||
|
return containingList ? getActualIndentationFromList(containingList) : -1;
|
||||||
|
|
||||||
function getActualIndentationFromList(list: Node[]): number {
|
function getActualIndentationFromList(list: Node[]): number {
|
||||||
var index = indexOf(list, node);
|
var index = indexOf(list, node);
|
||||||
|
@ -226,7 +265,7 @@ module ts.formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function deriveActualIndentationFromList(list: Node[], index: number, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
function deriveActualIndentationFromList(list: Node[], index: number, sourceFile: SourceFile, options: EditorOptions): number {
|
||||||
Debug.assert(index >= 0 && index < list.length);
|
Debug.assert(index >= 0 && index < list.length);
|
||||||
var node = list[index];
|
var node = list[index];
|
||||||
|
|
||||||
|
@ -248,53 +287,34 @@ module ts.formatting {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter: LineAndCharacter, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter: LineAndCharacter, sourceFile: SourceFile, options: EditorOptions): number {
|
||||||
var lineStart = sourceFile.getPositionFromLineAndCharacter(lineAndCharacter.line, 1);
|
var lineStart = sourceFile.getPositionFromLineAndCharacter(lineAndCharacter.line, 1);
|
||||||
|
return findFirstNonWhitespaceColumn(lineStart, lineStart + lineAndCharacter.character, sourceFile, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findFirstNonWhitespaceColumn(startPos: number, endPos: number, sourceFile: SourceFile, options: EditorOptions): number {
|
||||||
var column = 0;
|
var column = 0;
|
||||||
for (var i = 0; i < lineAndCharacter.character; ++i) {
|
for (var pos = startPos; pos < endPos; ++pos) {
|
||||||
var charCode = sourceFile.text.charCodeAt(lineStart + i);
|
var ch = sourceFile.text.charCodeAt(pos);
|
||||||
if (!isWhiteSpace(charCode)) {
|
if (!isWhiteSpace(ch)) {
|
||||||
return column;
|
return column;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (charCode === CharacterCodes.tab) {
|
if (ch === CharacterCodes.tab) {
|
||||||
column += options.spacesPerTab;
|
column += options.TabSize + (column % options.TabSize);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
column++;
|
column++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return column;
|
return column;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nodeContentIsIndented(parent: Node, child: Node): boolean {
|
function nodeContentIsAlwaysIndented(kind: SyntaxKind): boolean {
|
||||||
switch (parent.kind) {
|
switch (kind) {
|
||||||
case SyntaxKind.ClassDeclaration:
|
case SyntaxKind.ClassDeclaration:
|
||||||
case SyntaxKind.InterfaceDeclaration:
|
case SyntaxKind.InterfaceDeclaration:
|
||||||
case SyntaxKind.EnumDeclaration:
|
case SyntaxKind.EnumDeclaration:
|
||||||
return true;
|
|
||||||
case SyntaxKind.ModuleDeclaration:
|
|
||||||
// ModuleBlock should take care of indentation
|
|
||||||
return false;
|
|
||||||
case SyntaxKind.FunctionDeclaration:
|
|
||||||
case SyntaxKind.Method:
|
|
||||||
case SyntaxKind.FunctionExpression:
|
|
||||||
case SyntaxKind.GetAccessor:
|
|
||||||
case SyntaxKind.SetAccessor:
|
|
||||||
case SyntaxKind.Constructor:
|
|
||||||
// FunctionBlock should take care of indentation
|
|
||||||
return false;
|
|
||||||
case SyntaxKind.DoStatement:
|
|
||||||
case SyntaxKind.WhileStatement:
|
|
||||||
case SyntaxKind.ForInStatement:
|
|
||||||
case SyntaxKind.ForStatement:
|
|
||||||
return child && child.kind !== SyntaxKind.Block;
|
|
||||||
case SyntaxKind.IfStatement:
|
|
||||||
return child && child.kind !== SyntaxKind.Block;
|
|
||||||
case SyntaxKind.TryStatement:
|
|
||||||
// TryBlock\CatchBlock\FinallyBlock should take care of indentation
|
|
||||||
return false;
|
|
||||||
case SyntaxKind.ArrayLiteral:
|
case SyntaxKind.ArrayLiteral:
|
||||||
case SyntaxKind.Block:
|
case SyntaxKind.Block:
|
||||||
case SyntaxKind.FunctionBlock:
|
case SyntaxKind.FunctionBlock:
|
||||||
|
@ -312,7 +332,32 @@ module ts.formatting {
|
||||||
case SyntaxKind.NewExpression:
|
case SyntaxKind.NewExpression:
|
||||||
case SyntaxKind.VariableStatement:
|
case SyntaxKind.VariableStatement:
|
||||||
case SyntaxKind.VariableDeclaration:
|
case SyntaxKind.VariableDeclaration:
|
||||||
|
case SyntaxKind.ExportAssignment:
|
||||||
|
case SyntaxKind.ReturnStatement:
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldIndentChildNode(parent: SyntaxKind, child: SyntaxKind): boolean {
|
||||||
|
if (nodeContentIsAlwaysIndented(parent)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
switch (parent) {
|
||||||
|
case SyntaxKind.DoStatement:
|
||||||
|
case SyntaxKind.WhileStatement:
|
||||||
|
case SyntaxKind.ForInStatement:
|
||||||
|
case SyntaxKind.ForStatement:
|
||||||
|
case SyntaxKind.IfStatement:
|
||||||
|
return child !== SyntaxKind.Block;
|
||||||
|
case SyntaxKind.FunctionDeclaration:
|
||||||
|
case SyntaxKind.FunctionExpression:
|
||||||
|
case SyntaxKind.Method:
|
||||||
|
case SyntaxKind.ArrowFunction:
|
||||||
|
case SyntaxKind.Constructor:
|
||||||
|
case SyntaxKind.GetAccessor:
|
||||||
|
case SyntaxKind.SetAccessor:
|
||||||
|
return child !== SyntaxKind.FunctionBlock;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
|
@ -599,30 +599,31 @@ var TypeScript;
|
||||||
SyntaxKind[SyntaxKind["OmittedExpression"] = 187] = "OmittedExpression";
|
SyntaxKind[SyntaxKind["OmittedExpression"] = 187] = "OmittedExpression";
|
||||||
SyntaxKind[SyntaxKind["TemplateExpression"] = 188] = "TemplateExpression";
|
SyntaxKind[SyntaxKind["TemplateExpression"] = 188] = "TemplateExpression";
|
||||||
SyntaxKind[SyntaxKind["TemplateAccessExpression"] = 189] = "TemplateAccessExpression";
|
SyntaxKind[SyntaxKind["TemplateAccessExpression"] = 189] = "TemplateAccessExpression";
|
||||||
SyntaxKind[SyntaxKind["VariableDeclaration"] = 190] = "VariableDeclaration";
|
SyntaxKind[SyntaxKind["YieldExpression"] = 190] = "YieldExpression";
|
||||||
SyntaxKind[SyntaxKind["VariableDeclarator"] = 191] = "VariableDeclarator";
|
SyntaxKind[SyntaxKind["VariableDeclaration"] = 191] = "VariableDeclaration";
|
||||||
SyntaxKind[SyntaxKind["ArgumentList"] = 192] = "ArgumentList";
|
SyntaxKind[SyntaxKind["VariableDeclarator"] = 192] = "VariableDeclarator";
|
||||||
SyntaxKind[SyntaxKind["ParameterList"] = 193] = "ParameterList";
|
SyntaxKind[SyntaxKind["ArgumentList"] = 193] = "ArgumentList";
|
||||||
SyntaxKind[SyntaxKind["TypeArgumentList"] = 194] = "TypeArgumentList";
|
SyntaxKind[SyntaxKind["ParameterList"] = 194] = "ParameterList";
|
||||||
SyntaxKind[SyntaxKind["TypeParameterList"] = 195] = "TypeParameterList";
|
SyntaxKind[SyntaxKind["TypeArgumentList"] = 195] = "TypeArgumentList";
|
||||||
SyntaxKind[SyntaxKind["HeritageClause"] = 196] = "HeritageClause";
|
SyntaxKind[SyntaxKind["TypeParameterList"] = 196] = "TypeParameterList";
|
||||||
SyntaxKind[SyntaxKind["EqualsValueClause"] = 197] = "EqualsValueClause";
|
SyntaxKind[SyntaxKind["HeritageClause"] = 197] = "HeritageClause";
|
||||||
SyntaxKind[SyntaxKind["CaseSwitchClause"] = 198] = "CaseSwitchClause";
|
SyntaxKind[SyntaxKind["EqualsValueClause"] = 198] = "EqualsValueClause";
|
||||||
SyntaxKind[SyntaxKind["DefaultSwitchClause"] = 199] = "DefaultSwitchClause";
|
SyntaxKind[SyntaxKind["CaseSwitchClause"] = 199] = "CaseSwitchClause";
|
||||||
SyntaxKind[SyntaxKind["ElseClause"] = 200] = "ElseClause";
|
SyntaxKind[SyntaxKind["DefaultSwitchClause"] = 200] = "DefaultSwitchClause";
|
||||||
SyntaxKind[SyntaxKind["CatchClause"] = 201] = "CatchClause";
|
SyntaxKind[SyntaxKind["ElseClause"] = 201] = "ElseClause";
|
||||||
SyntaxKind[SyntaxKind["FinallyClause"] = 202] = "FinallyClause";
|
SyntaxKind[SyntaxKind["CatchClause"] = 202] = "CatchClause";
|
||||||
SyntaxKind[SyntaxKind["TemplateClause"] = 203] = "TemplateClause";
|
SyntaxKind[SyntaxKind["FinallyClause"] = 203] = "FinallyClause";
|
||||||
SyntaxKind[SyntaxKind["TypeParameter"] = 204] = "TypeParameter";
|
SyntaxKind[SyntaxKind["TemplateClause"] = 204] = "TemplateClause";
|
||||||
SyntaxKind[SyntaxKind["Constraint"] = 205] = "Constraint";
|
SyntaxKind[SyntaxKind["TypeParameter"] = 205] = "TypeParameter";
|
||||||
SyntaxKind[SyntaxKind["SimplePropertyAssignment"] = 206] = "SimplePropertyAssignment";
|
SyntaxKind[SyntaxKind["Constraint"] = 206] = "Constraint";
|
||||||
SyntaxKind[SyntaxKind["FunctionPropertyAssignment"] = 207] = "FunctionPropertyAssignment";
|
SyntaxKind[SyntaxKind["SimplePropertyAssignment"] = 207] = "SimplePropertyAssignment";
|
||||||
SyntaxKind[SyntaxKind["Parameter"] = 208] = "Parameter";
|
SyntaxKind[SyntaxKind["FunctionPropertyAssignment"] = 208] = "FunctionPropertyAssignment";
|
||||||
SyntaxKind[SyntaxKind["EnumElement"] = 209] = "EnumElement";
|
SyntaxKind[SyntaxKind["Parameter"] = 209] = "Parameter";
|
||||||
SyntaxKind[SyntaxKind["TypeAnnotation"] = 210] = "TypeAnnotation";
|
SyntaxKind[SyntaxKind["EnumElement"] = 210] = "EnumElement";
|
||||||
SyntaxKind[SyntaxKind["ComputedPropertyName"] = 211] = "ComputedPropertyName";
|
SyntaxKind[SyntaxKind["TypeAnnotation"] = 211] = "TypeAnnotation";
|
||||||
SyntaxKind[SyntaxKind["ExternalModuleReference"] = 212] = "ExternalModuleReference";
|
SyntaxKind[SyntaxKind["ComputedPropertyName"] = 212] = "ComputedPropertyName";
|
||||||
SyntaxKind[SyntaxKind["ModuleNameModuleReference"] = 213] = "ModuleNameModuleReference";
|
SyntaxKind[SyntaxKind["ExternalModuleReference"] = 213] = "ExternalModuleReference";
|
||||||
|
SyntaxKind[SyntaxKind["ModuleNameModuleReference"] = 214] = "ModuleNameModuleReference";
|
||||||
SyntaxKind[SyntaxKind["FirstStandardKeyword"] = SyntaxKind.BreakKeyword] = "FirstStandardKeyword";
|
SyntaxKind[SyntaxKind["FirstStandardKeyword"] = SyntaxKind.BreakKeyword] = "FirstStandardKeyword";
|
||||||
SyntaxKind[SyntaxKind["LastStandardKeyword"] = SyntaxKind.WithKeyword] = "LastStandardKeyword";
|
SyntaxKind[SyntaxKind["LastStandardKeyword"] = SyntaxKind.WithKeyword] = "LastStandardKeyword";
|
||||||
SyntaxKind[SyntaxKind["FirstFutureReservedKeyword"] = SyntaxKind.ClassKeyword] = "FirstFutureReservedKeyword";
|
SyntaxKind[SyntaxKind["FirstFutureReservedKeyword"] = SyntaxKind.ClassKeyword] = "FirstFutureReservedKeyword";
|
||||||
|
@ -910,9 +911,9 @@ var definitions = [
|
||||||
baseType: 'ISyntaxNode',
|
baseType: 'ISyntaxNode',
|
||||||
interfaces: ['IModuleReferenceSyntax'],
|
interfaces: ['IModuleReferenceSyntax'],
|
||||||
children: [
|
children: [
|
||||||
{ name: 'requireKeyword', isToken: true, tokenKinds: ['RequireKeyword'], excludeFromAST: true },
|
{ name: 'requireKeyword', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'stringLiteral', isToken: true, tokenKinds: ['StringLiteral'] },
|
{ name: 'stringLiteral', isToken: true },
|
||||||
{ name: 'closeParenToken', isToken: true, excludeFromAST: true }
|
{ name: 'closeParenToken', isToken: true, excludeFromAST: true }
|
||||||
],
|
],
|
||||||
isTypeScriptSpecific: true
|
isTypeScriptSpecific: true
|
||||||
|
@ -933,7 +934,7 @@ var definitions = [
|
||||||
children: [
|
children: [
|
||||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
{ name: 'importKeyword', isToken: true, excludeFromAST: true },
|
{ name: 'importKeyword', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'identifier', isToken: true },
|
||||||
{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'moduleReference', type: 'IModuleReferenceSyntax' },
|
{ name: 'moduleReference', type: 'IModuleReferenceSyntax' },
|
||||||
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||||
|
@ -947,7 +948,7 @@ var definitions = [
|
||||||
children: [
|
children: [
|
||||||
{ name: 'exportKeyword', isToken: true, excludeFromAST: true },
|
{ name: 'exportKeyword', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'identifier', isToken: true },
|
||||||
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||||
],
|
],
|
||||||
isTypeScriptSpecific: true
|
isTypeScriptSpecific: true
|
||||||
|
@ -959,7 +960,7 @@ var definitions = [
|
||||||
children: [
|
children: [
|
||||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
{ name: 'classKeyword', isToken: true, excludeFromAST: true },
|
{ name: 'classKeyword', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'identifier', isToken: true },
|
||||||
{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
||||||
{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
||||||
{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
||||||
|
@ -975,7 +976,7 @@ var definitions = [
|
||||||
children: [
|
children: [
|
||||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
{ name: 'interfaceKeyword', isToken: true, excludeFromAST: true },
|
{ name: 'interfaceKeyword', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'identifier', isToken: true },
|
||||||
{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
||||||
{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
||||||
{ name: 'body', type: 'ObjectTypeSyntax' }
|
{ name: 'body', type: 'ObjectTypeSyntax' }
|
||||||
|
@ -1012,7 +1013,8 @@ var definitions = [
|
||||||
children: [
|
children: [
|
||||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken', isTypeScriptSpecific: true },
|
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken', isTypeScriptSpecific: true },
|
||||||
{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||||
|
{ name: 'identifier', isToken: true },
|
||||||
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||||
{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
||||||
]
|
]
|
||||||
|
@ -1116,7 +1118,7 @@ var definitions = [
|
||||||
children: [
|
children: [
|
||||||
{ name: 'left', type: 'INameSyntax' },
|
{ name: 'left', type: 'INameSyntax' },
|
||||||
{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'right', isToken: true, tokenKinds: ['IdentifierName'] }
|
{ name: 'right', isToken: true }
|
||||||
],
|
],
|
||||||
isTypeScriptSpecific: true
|
isTypeScriptSpecific: true
|
||||||
},
|
},
|
||||||
|
@ -1255,7 +1257,7 @@ var definitions = [
|
||||||
children: [
|
children: [
|
||||||
{ name: 'dotDotDotToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
{ name: 'dotDotDotToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
||||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'identifier', isToken: true },
|
||||||
{ name: 'questionToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
{ name: 'questionToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
||||||
{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecific: true },
|
{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecific: true },
|
||||||
{ name: 'equalsValueClause', type: 'EqualsValueClauseSyntax', isOptional: true, isTypeScriptSpecific: true }
|
{ name: 'equalsValueClause', type: 'EqualsValueClauseSyntax', isOptional: true, isTypeScriptSpecific: true }
|
||||||
|
@ -1268,7 +1270,7 @@ var definitions = [
|
||||||
children: [
|
children: [
|
||||||
{ name: 'expression', type: 'ILeftHandSideExpressionSyntax' },
|
{ name: 'expression', type: 'ILeftHandSideExpressionSyntax' },
|
||||||
{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'name', isToken: true, tokenKinds: ['IdentifierName'] }
|
{ name: 'name', isToken: true }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1434,7 +1436,7 @@ var definitions = [
|
||||||
name: 'TypeParameterSyntax',
|
name: 'TypeParameterSyntax',
|
||||||
baseType: 'ISyntaxNode',
|
baseType: 'ISyntaxNode',
|
||||||
children: [
|
children: [
|
||||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'identifier', isToken: true },
|
||||||
{ name: 'constraint', type: 'ConstraintSyntax', isOptional: true }
|
{ name: 'constraint', type: 'ConstraintSyntax', isOptional: true }
|
||||||
],
|
],
|
||||||
isTypeScriptSpecific: true
|
isTypeScriptSpecific: true
|
||||||
|
@ -1496,6 +1498,7 @@ var definitions = [
|
||||||
interfaces: ['IMemberDeclarationSyntax'],
|
interfaces: ['IMemberDeclarationSyntax'],
|
||||||
children: [
|
children: [
|
||||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
|
{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||||
{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
||||||
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||||
{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
||||||
|
@ -1620,7 +1623,7 @@ var definitions = [
|
||||||
interfaces: ['IStatementSyntax'],
|
interfaces: ['IStatementSyntax'],
|
||||||
children: [
|
children: [
|
||||||
{ name: 'breakKeyword', isToken: true },
|
{ name: 'breakKeyword', isToken: true },
|
||||||
{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'identifier', isToken: true, isOptional: true },
|
||||||
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1630,7 +1633,7 @@ var definitions = [
|
||||||
interfaces: ['IStatementSyntax'],
|
interfaces: ['IStatementSyntax'],
|
||||||
children: [
|
children: [
|
||||||
{ name: 'continueKeyword', isToken: true },
|
{ name: 'continueKeyword', isToken: true },
|
||||||
{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'identifier', isToken: true, isOptional: true },
|
||||||
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1642,9 +1645,9 @@ var definitions = [
|
||||||
{ name: 'forKeyword', isToken: true, excludeFromAST: true },
|
{ name: 'forKeyword', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'initializer', type: 'VariableDeclarationSyntax | IExpressionSyntax', isOptional: true },
|
{ name: 'initializer', type: 'VariableDeclarationSyntax | IExpressionSyntax', isOptional: true },
|
||||||
{ name: 'firstSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true },
|
{ name: 'firstSemicolonToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'condition', type: 'IExpressionSyntax', isOptional: true },
|
{ name: 'condition', type: 'IExpressionSyntax', isOptional: true },
|
||||||
{ name: 'secondSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true },
|
{ name: 'secondSemicolonToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'incrementor', type: 'IExpressionSyntax', isOptional: true },
|
{ name: 'incrementor', type: 'IExpressionSyntax', isOptional: true },
|
||||||
{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'statement', type: 'IStatementSyntax' }
|
{ name: 'statement', type: 'IStatementSyntax' }
|
||||||
|
@ -1695,7 +1698,7 @@ var definitions = [
|
||||||
children: [
|
children: [
|
||||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
{ name: 'enumKeyword', isToken: true, excludeFromAST: true },
|
{ name: 'enumKeyword', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'identifier', isToken: true },
|
||||||
{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'enumElements', isSeparatedList: true, elementType: 'EnumElementSyntax' },
|
{ name: 'enumElements', isSeparatedList: true, elementType: 'EnumElementSyntax' },
|
||||||
{ name: 'closeBraceToken', isToken: true, excludeFromAST: true }
|
{ name: 'closeBraceToken', isToken: true, excludeFromAST: true }
|
||||||
|
@ -1757,6 +1760,7 @@ var definitions = [
|
||||||
baseType: 'ISyntaxNode',
|
baseType: 'ISyntaxNode',
|
||||||
interfaces: ['IPropertyAssignmentSyntax'],
|
interfaces: ['IPropertyAssignmentSyntax'],
|
||||||
children: [
|
children: [
|
||||||
|
{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||||
{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
||||||
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||||
{ name: 'block', type: 'BlockSyntax' }
|
{ name: 'block', type: 'BlockSyntax' }
|
||||||
|
@ -1768,7 +1772,8 @@ var definitions = [
|
||||||
interfaces: ['IPrimaryExpressionSyntax'],
|
interfaces: ['IPrimaryExpressionSyntax'],
|
||||||
children: [
|
children: [
|
||||||
{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||||
|
{ name: 'identifier', isToken: true, isOptional: true },
|
||||||
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||||
{ name: 'block', type: 'BlockSyntax' }
|
{ name: 'block', type: 'BlockSyntax' }
|
||||||
]
|
]
|
||||||
|
@ -1798,7 +1803,7 @@ var definitions = [
|
||||||
children: [
|
children: [
|
||||||
{ name: 'catchKeyword', isToken: true, excludeFromAST: true },
|
{ name: 'catchKeyword', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'identifier', isToken: true },
|
||||||
{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecified: true },
|
{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecified: true },
|
||||||
{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'block', type: 'BlockSyntax' }
|
{ name: 'block', type: 'BlockSyntax' }
|
||||||
|
@ -1817,7 +1822,7 @@ var definitions = [
|
||||||
baseType: 'ISyntaxNode',
|
baseType: 'ISyntaxNode',
|
||||||
interfaces: ['IStatementSyntax'],
|
interfaces: ['IStatementSyntax'],
|
||||||
children: [
|
children: [
|
||||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
{ name: 'identifier', isToken: true },
|
||||||
{ name: 'colonToken', isToken: true, excludeFromAST: true },
|
{ name: 'colonToken', isToken: true, excludeFromAST: true },
|
||||||
{ name: 'statement', type: 'IStatementSyntax' }
|
{ name: 'statement', type: 'IStatementSyntax' }
|
||||||
]
|
]
|
||||||
|
@ -1863,6 +1868,16 @@ var definitions = [
|
||||||
{ name: 'expression', type: 'IUnaryExpressionSyntax' }
|
{ name: 'expression', type: 'IUnaryExpressionSyntax' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'YieldExpressionSyntax',
|
||||||
|
baseType: 'ISyntaxNode',
|
||||||
|
interfaces: ['IExpressionSyntax'],
|
||||||
|
children: [
|
||||||
|
{ name: 'yieldKeyword', isToken: true },
|
||||||
|
{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||||
|
{ name: 'expression', type: 'IExpressionSyntax', isOptional: true }
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'DebuggerStatementSyntax',
|
name: 'DebuggerStatementSyntax',
|
||||||
baseType: 'ISyntaxNode',
|
baseType: 'ISyntaxNode',
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,7 @@
|
||||||
///<reference path='references.ts' />
|
///<reference path='references.ts' />
|
||||||
|
|
||||||
module TypeScript {
|
module TypeScript {
|
||||||
export enum SyntaxConstants {
|
export enum SyntaxNodeConstants {
|
||||||
None = 0,
|
None = 0,
|
||||||
|
|
||||||
// Masks that we use to place information about a node into a single int. The first bit tells
|
// Masks that we use to place information about a node into a single int. The first bit tells
|
||||||
|
@ -15,13 +15,15 @@ module TypeScript {
|
||||||
// only be used by the incremental parser if it is parsed in the same strict context as before.
|
// only be used by the incremental parser if it is parsed in the same strict context as before.
|
||||||
// last masks off the part of the int
|
// last masks off the part of the int
|
||||||
//
|
//
|
||||||
// The width of the node is stored in the remainder of the int. This allows us up to 256MB
|
// The width of the node is stored in the remainder of the int. This allows us up to 128MB
|
||||||
// for a node by using all 28 bits. However, in the common case, we'll use less than 28 bits
|
// for a node by using all 27 bits. However, in the common case, we'll use less than 27 bits
|
||||||
// for the width. Thus, the info will be stored in a single int in chakra.
|
// for the width. Thus, the info will be stored in a single int in chakra.
|
||||||
NodeDataComputed = 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001
|
DataComputed = 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001
|
||||||
NodeIncrementallyUnusableMask = 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010
|
IncrementallyUnusableMask = 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010
|
||||||
NodeParsedInStrictModeMask = 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100
|
ParsedInStrictModeContext = 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100
|
||||||
NodeParsedInDisallowInMask = 0x00000008, // 0000 0000 0000 0000 0000 0000 0000 1000
|
ParsedInDisallowInContext = 0x00000008, // 0000 0000 0000 0000 0000 0000 0000 1000
|
||||||
NodeFullWidthShift = 4, // 1111 1111 1111 1111 1111 1111 1111 0000
|
ParsedInYieldContext = 0x00000010, // 0000 0000 0000 0000 0000 0000 0001 0000
|
||||||
|
ParsedInGeneratorParameterContext = 0x00000020, // 0000 0000 0000 0000 0000 0000 0010 0000
|
||||||
|
FullWidthShift = 1 << 6, // 1111 1111 1111 1111 1111 1111 1100 0000
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -1018,6 +1018,12 @@ module TypeScript.PrettyPrinter {
|
||||||
visitNodeOrToken(this, node.expression);
|
visitNodeOrToken(this, node.expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public visitYieldExpression(node: YieldExpressionSyntax): void {
|
||||||
|
this.appendToken(node.yieldKeyword);
|
||||||
|
this.ensureSpace();
|
||||||
|
visitNodeOrToken(this, node.expression);
|
||||||
|
}
|
||||||
|
|
||||||
public visitDebuggerStatement(node: DebuggerStatementSyntax): void {
|
public visitDebuggerStatement(node: DebuggerStatementSyntax): void {
|
||||||
this.appendToken(node.debuggerKeyword);
|
this.appendToken(node.debuggerKeyword);
|
||||||
this.appendToken(node.semicolonToken);
|
this.appendToken(node.semicolonToken);
|
||||||
|
|
|
@ -17,22 +17,40 @@ module TypeScript {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parsedInStrictMode(node: ISyntaxNode): boolean {
|
export function parsedInStrictModeContext(node: ISyntaxNode): boolean {
|
||||||
var info = node.__data;
|
var info = node.__data;
|
||||||
if (info === undefined) {
|
if (info === undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (info & SyntaxConstants.NodeParsedInStrictModeMask) !== 0;
|
return (info & SyntaxNodeConstants.ParsedInStrictModeContext) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parsedInDisallowInMode(node: ISyntaxNode): boolean {
|
export function parsedInDisallowInContext(node: ISyntaxNode): boolean {
|
||||||
var info = node.__data;
|
var info = node.__data;
|
||||||
if (info === undefined) {
|
if (info === undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (info & SyntaxConstants.NodeParsedInDisallowInMask) !== 0;
|
return (info & SyntaxNodeConstants.ParsedInDisallowInContext) !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parsedInYieldContext(node: ISyntaxNode): boolean {
|
||||||
|
var info = node.__data;
|
||||||
|
if (info === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (info & SyntaxNodeConstants.ParsedInYieldContext) !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parsedInGeneratorParameterContext(node: ISyntaxNode): boolean {
|
||||||
|
var info = node.__data;
|
||||||
|
if (info === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (info & SyntaxNodeConstants.ParsedInGeneratorParameterContext) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function previousToken(token: ISyntaxToken): ISyntaxToken {
|
export function previousToken(token: ISyntaxToken): ISyntaxToken {
|
||||||
|
@ -266,7 +284,7 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
var info = data(element);
|
var info = data(element);
|
||||||
return info >>> SyntaxConstants.NodeFullWidthShift;
|
return (info / SyntaxNodeConstants.FullWidthShift) | 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isIncrementallyUnusable(element: ISyntaxElement): boolean {
|
export function isIncrementallyUnusable(element: ISyntaxElement): boolean {
|
||||||
|
@ -274,7 +292,7 @@ module TypeScript {
|
||||||
return (<ISyntaxToken>element).isIncrementallyUnusable();
|
return (<ISyntaxToken>element).isIncrementallyUnusable();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (data(element) & SyntaxConstants.NodeIncrementallyUnusableMask) !== 0;
|
return (data(element) & SyntaxNodeConstants.IncrementallyUnusableMask) !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function data(element: ISyntaxElement): number {
|
function data(element: ISyntaxElement): number {
|
||||||
|
@ -288,7 +306,7 @@ module TypeScript {
|
||||||
info = 0;
|
info = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((info & SyntaxConstants.NodeDataComputed) === 0) {
|
if ((info & SyntaxNodeConstants.DataComputed) === 0) {
|
||||||
info |= computeData(element);
|
info |= computeData(element);
|
||||||
dataElement.__data = info;
|
dataElement.__data = info;
|
||||||
}
|
}
|
||||||
|
@ -297,9 +315,9 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
function combineData(fullWidth: number, isIncrementallyUnusable: boolean) {
|
function combineData(fullWidth: number, isIncrementallyUnusable: boolean) {
|
||||||
return (fullWidth << SyntaxConstants.NodeFullWidthShift)
|
return (fullWidth * SyntaxNodeConstants.FullWidthShift) +
|
||||||
| (isIncrementallyUnusable ? SyntaxConstants.NodeIncrementallyUnusableMask : 0)
|
(isIncrementallyUnusable ? SyntaxNodeConstants.IncrementallyUnusableMask : 0) +
|
||||||
| SyntaxConstants.NodeDataComputed;
|
SyntaxNodeConstants.DataComputed;
|
||||||
}
|
}
|
||||||
|
|
||||||
function listComputeData(list: ISyntaxNodeOrToken[]): number {
|
function listComputeData(list: ISyntaxNodeOrToken[]): number {
|
||||||
|
|
|
@ -23,7 +23,6 @@ interface IMemberDefinition {
|
||||||
isSeparatedList?: boolean;
|
isSeparatedList?: boolean;
|
||||||
requiresAtLeastOneItem?: boolean;
|
requiresAtLeastOneItem?: boolean;
|
||||||
isOptional?: boolean;
|
isOptional?: boolean;
|
||||||
tokenKinds?: string[];
|
|
||||||
isTypeScriptSpecific: boolean;
|
isTypeScriptSpecific: boolean;
|
||||||
elementType?: string;
|
elementType?: string;
|
||||||
}
|
}
|
||||||
|
@ -56,9 +55,9 @@ var definitions:ITypeDefinition[] = [
|
||||||
baseType: 'ISyntaxNode',
|
baseType: 'ISyntaxNode',
|
||||||
interfaces: ['IModuleReferenceSyntax'],
|
interfaces: ['IModuleReferenceSyntax'],
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'requireKeyword', isToken: true, tokenKinds: ['RequireKeyword'], excludeFromAST: true },
|
<any>{ name: 'requireKeyword', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'stringLiteral', isToken: true, tokenKinds: ['StringLiteral'] },
|
<any>{ name: 'stringLiteral', isToken: true },
|
||||||
<any>{ name: 'closeParenToken', isToken: true, excludeFromAST: true }
|
<any>{ name: 'closeParenToken', isToken: true, excludeFromAST: true }
|
||||||
],
|
],
|
||||||
isTypeScriptSpecific: true
|
isTypeScriptSpecific: true
|
||||||
|
@ -79,7 +78,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
<any>{ name: 'importKeyword', isToken: true, excludeFromAST: true },
|
<any>{ name: 'importKeyword', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'identifier', isToken: true },
|
||||||
<any>{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'moduleReference', type: 'IModuleReferenceSyntax' },
|
<any>{ name: 'moduleReference', type: 'IModuleReferenceSyntax' },
|
||||||
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||||
|
@ -93,7 +92,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'exportKeyword', isToken: true, excludeFromAST: true },
|
<any>{ name: 'exportKeyword', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'identifier', isToken: true },
|
||||||
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||||
],
|
],
|
||||||
isTypeScriptSpecific: true
|
isTypeScriptSpecific: true
|
||||||
|
@ -105,7 +104,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
<any>{ name: 'classKeyword', isToken: true, excludeFromAST: true },
|
<any>{ name: 'classKeyword', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'identifier', isToken: true },
|
||||||
<any>{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
<any>{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
||||||
<any>{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
<any>{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
||||||
<any>{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
||||||
|
@ -121,7 +120,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
<any>{ name: 'interfaceKeyword', isToken: true, excludeFromAST: true },
|
<any>{ name: 'interfaceKeyword', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'identifier', isToken: true },
|
||||||
<any>{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
<any>{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
||||||
<any>{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
<any>{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
||||||
<any>{ name: 'body', type: 'ObjectTypeSyntax' }
|
<any>{ name: 'body', type: 'ObjectTypeSyntax' }
|
||||||
|
@ -158,7 +157,8 @@ var definitions:ITypeDefinition[] = [
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken', isTypeScriptSpecific: true },
|
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken', isTypeScriptSpecific: true },
|
||||||
<any>{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
<any>{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||||
|
<any>{ name: 'identifier', isToken: true },
|
||||||
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||||
<any>{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
<any>{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
||||||
]
|
]
|
||||||
|
@ -262,7 +262,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'left', type: 'INameSyntax' },
|
<any>{ name: 'left', type: 'INameSyntax' },
|
||||||
<any>{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'right', isToken: true, tokenKinds:['IdentifierName'] }
|
<any>{ name: 'right', isToken: true }
|
||||||
],
|
],
|
||||||
// Qualified names only show up in Types, which are TypeScript specific. Note that a dotted
|
// Qualified names only show up in Types, which are TypeScript specific. Note that a dotted
|
||||||
// expression (like A.B.Foo()) is a MemberAccessExpression, not a QualifiedName.
|
// expression (like A.B.Foo()) is a MemberAccessExpression, not a QualifiedName.
|
||||||
|
@ -403,7 +403,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'dotDotDotToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
<any>{ name: 'dotDotDotToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
||||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'identifier', isToken: true },
|
||||||
<any>{ name: 'questionToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
<any>{ name: 'questionToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
||||||
<any>{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecific: true },
|
<any>{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecific: true },
|
||||||
<any>{ name: 'equalsValueClause', type: 'EqualsValueClauseSyntax', isOptional: true, isTypeScriptSpecific: true }
|
<any>{ name: 'equalsValueClause', type: 'EqualsValueClauseSyntax', isOptional: true, isTypeScriptSpecific: true }
|
||||||
|
@ -416,7 +416,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'expression', type: 'ILeftHandSideExpressionSyntax' },
|
<any>{ name: 'expression', type: 'ILeftHandSideExpressionSyntax' },
|
||||||
<any>{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'name', isToken: true, tokenKinds: ['IdentifierName'] }
|
<any>{ name: 'name', isToken: true }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
<any>{
|
<any>{
|
||||||
|
@ -582,7 +582,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
name: 'TypeParameterSyntax',
|
name: 'TypeParameterSyntax',
|
||||||
baseType: 'ISyntaxNode',
|
baseType: 'ISyntaxNode',
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'identifier', isToken: true },
|
||||||
<any>{ name: 'constraint', type: 'ConstraintSyntax', isOptional: true }
|
<any>{ name: 'constraint', type: 'ConstraintSyntax', isOptional: true }
|
||||||
],
|
],
|
||||||
isTypeScriptSpecific: true
|
isTypeScriptSpecific: true
|
||||||
|
@ -645,6 +645,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
interfaces: ['IMemberDeclarationSyntax'],
|
interfaces: ['IMemberDeclarationSyntax'],
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
|
<any>{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||||
<any>{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
<any>{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
||||||
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||||
<any>{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
<any>{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
||||||
|
@ -769,7 +770,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
interfaces: ['IStatementSyntax'],
|
interfaces: ['IStatementSyntax'],
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'breakKeyword', isToken: true },
|
<any>{ name: 'breakKeyword', isToken: true },
|
||||||
<any>{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'identifier', isToken: true, isOptional: true },
|
||||||
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -779,7 +780,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
interfaces: ['IStatementSyntax'],
|
interfaces: ['IStatementSyntax'],
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'continueKeyword', isToken: true },
|
<any>{ name: 'continueKeyword', isToken: true },
|
||||||
<any>{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'identifier', isToken: true, isOptional: true },
|
||||||
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -791,9 +792,9 @@ var definitions:ITypeDefinition[] = [
|
||||||
<any>{ name: 'forKeyword', isToken: true, excludeFromAST: true },
|
<any>{ name: 'forKeyword', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'initializer', type: 'VariableDeclarationSyntax | IExpressionSyntax', isOptional: true },
|
<any>{ name: 'initializer', type: 'VariableDeclarationSyntax | IExpressionSyntax', isOptional: true },
|
||||||
<any>{ name: 'firstSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true },
|
<any>{ name: 'firstSemicolonToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'condition', type: 'IExpressionSyntax', isOptional: true },
|
<any>{ name: 'condition', type: 'IExpressionSyntax', isOptional: true },
|
||||||
<any>{ name: 'secondSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true },
|
<any>{ name: 'secondSemicolonToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'incrementor', type: 'IExpressionSyntax', isOptional: true },
|
<any>{ name: 'incrementor', type: 'IExpressionSyntax', isOptional: true },
|
||||||
<any>{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'statement', type: 'IStatementSyntax' }
|
<any>{ name: 'statement', type: 'IStatementSyntax' }
|
||||||
|
@ -844,7 +845,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||||
<any>{ name: 'enumKeyword', isToken: true, excludeFromAST: true },
|
<any>{ name: 'enumKeyword', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'identifier', isToken: true },
|
||||||
<any>{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'enumElements', isSeparatedList: true, elementType: 'EnumElementSyntax' },
|
<any>{ name: 'enumElements', isSeparatedList: true, elementType: 'EnumElementSyntax' },
|
||||||
<any>{ name: 'closeBraceToken', isToken: true, excludeFromAST: true }
|
<any>{ name: 'closeBraceToken', isToken: true, excludeFromAST: true }
|
||||||
|
@ -906,6 +907,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
baseType: 'ISyntaxNode',
|
baseType: 'ISyntaxNode',
|
||||||
interfaces: ['IPropertyAssignmentSyntax'],
|
interfaces: ['IPropertyAssignmentSyntax'],
|
||||||
children: [
|
children: [
|
||||||
|
<any>{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||||
<any>{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
<any>{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
||||||
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||||
<any>{ name: 'block', type: 'BlockSyntax' }
|
<any>{ name: 'block', type: 'BlockSyntax' }
|
||||||
|
@ -917,7 +919,8 @@ var definitions:ITypeDefinition[] = [
|
||||||
interfaces: ['IPrimaryExpressionSyntax'],
|
interfaces: ['IPrimaryExpressionSyntax'],
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
<any>{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||||
|
<any>{ name: 'identifier', isToken: true, isOptional: true },
|
||||||
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||||
<any>{ name: 'block', type: 'BlockSyntax' }]
|
<any>{ name: 'block', type: 'BlockSyntax' }]
|
||||||
},
|
},
|
||||||
|
@ -944,7 +947,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'catchKeyword', isToken: true, excludeFromAST: true },
|
<any>{ name: 'catchKeyword', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'identifier', isToken: true },
|
||||||
<any>{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecified: true },
|
<any>{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecified: true },
|
||||||
<any>{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'block', type: 'BlockSyntax' }]
|
<any>{ name: 'block', type: 'BlockSyntax' }]
|
||||||
|
@ -961,7 +964,7 @@ var definitions:ITypeDefinition[] = [
|
||||||
baseType: 'ISyntaxNode',
|
baseType: 'ISyntaxNode',
|
||||||
interfaces: ['IStatementSyntax'],
|
interfaces: ['IStatementSyntax'],
|
||||||
children: [
|
children: [
|
||||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
<any>{ name: 'identifier', isToken: true },
|
||||||
<any>{ name: 'colonToken', isToken: true, excludeFromAST: true },
|
<any>{ name: 'colonToken', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'statement', type: 'IStatementSyntax' }]
|
<any>{ name: 'statement', type: 'IStatementSyntax' }]
|
||||||
},
|
},
|
||||||
|
@ -1002,6 +1005,15 @@ var definitions:ITypeDefinition[] = [
|
||||||
<any>{ name: 'voidKeyword', isToken: true, excludeFromAST: true },
|
<any>{ name: 'voidKeyword', isToken: true, excludeFromAST: true },
|
||||||
<any>{ name: 'expression', type: 'IUnaryExpressionSyntax' }]
|
<any>{ name: 'expression', type: 'IUnaryExpressionSyntax' }]
|
||||||
},
|
},
|
||||||
|
<any>{
|
||||||
|
name: 'YieldExpressionSyntax',
|
||||||
|
baseType: 'ISyntaxNode',
|
||||||
|
interfaces: ['IExpressionSyntax'],
|
||||||
|
children: [
|
||||||
|
<any>{ name: 'yieldKeyword', isToken: true },
|
||||||
|
<any>{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||||
|
<any>{ name: 'expression', type: 'IExpressionSyntax', isOptional: true }]
|
||||||
|
},
|
||||||
<any>{
|
<any>{
|
||||||
name: 'DebuggerStatementSyntax',
|
name: 'DebuggerStatementSyntax',
|
||||||
baseType: 'ISyntaxNode',
|
baseType: 'ISyntaxNode',
|
||||||
|
|
|
@ -92,11 +92,12 @@ module TypeScript {
|
||||||
export interface FunctionDeclarationSyntax extends ISyntaxNode, IStatementSyntax {
|
export interface FunctionDeclarationSyntax extends ISyntaxNode, IStatementSyntax {
|
||||||
modifiers: ISyntaxToken[];
|
modifiers: ISyntaxToken[];
|
||||||
functionKeyword: ISyntaxToken;
|
functionKeyword: ISyntaxToken;
|
||||||
|
asterixToken: ISyntaxToken;
|
||||||
identifier: ISyntaxToken;
|
identifier: ISyntaxToken;
|
||||||
callSignature: CallSignatureSyntax;
|
callSignature: CallSignatureSyntax;
|
||||||
body: BlockSyntax | ISyntaxToken;
|
body: BlockSyntax | ISyntaxToken;
|
||||||
}
|
}
|
||||||
export interface FunctionDeclarationConstructor { new (data: number, modifiers: ISyntaxToken[], functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken): FunctionDeclarationSyntax }
|
export interface FunctionDeclarationConstructor { new (data: number, modifiers: ISyntaxToken[], functionKeyword: ISyntaxToken, asterixToken: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken): FunctionDeclarationSyntax }
|
||||||
|
|
||||||
export interface ModuleDeclarationSyntax extends ISyntaxNode, IModuleElementSyntax {
|
export interface ModuleDeclarationSyntax extends ISyntaxNode, IModuleElementSyntax {
|
||||||
modifiers: ISyntaxToken[];
|
modifiers: ISyntaxToken[];
|
||||||
|
@ -150,11 +151,12 @@ module TypeScript {
|
||||||
|
|
||||||
export interface MemberFunctionDeclarationSyntax extends ISyntaxNode, IMemberDeclarationSyntax {
|
export interface MemberFunctionDeclarationSyntax extends ISyntaxNode, IMemberDeclarationSyntax {
|
||||||
modifiers: ISyntaxToken[];
|
modifiers: ISyntaxToken[];
|
||||||
|
asterixToken: ISyntaxToken;
|
||||||
propertyName: IPropertyNameSyntax;
|
propertyName: IPropertyNameSyntax;
|
||||||
callSignature: CallSignatureSyntax;
|
callSignature: CallSignatureSyntax;
|
||||||
body: BlockSyntax | ISyntaxToken;
|
body: BlockSyntax | ISyntaxToken;
|
||||||
}
|
}
|
||||||
export interface MemberFunctionDeclarationConstructor { new (data: number, modifiers: ISyntaxToken[], propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken): MemberFunctionDeclarationSyntax }
|
export interface MemberFunctionDeclarationConstructor { new (data: number, modifiers: ISyntaxToken[], asterixToken: ISyntaxToken, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken): MemberFunctionDeclarationSyntax }
|
||||||
|
|
||||||
export interface MemberVariableDeclarationSyntax extends ISyntaxNode, IMemberDeclarationSyntax {
|
export interface MemberVariableDeclarationSyntax extends ISyntaxNode, IMemberDeclarationSyntax {
|
||||||
modifiers: ISyntaxToken[];
|
modifiers: ISyntaxToken[];
|
||||||
|
@ -498,11 +500,12 @@ module TypeScript {
|
||||||
|
|
||||||
export interface FunctionExpressionSyntax extends ISyntaxNode, IPrimaryExpressionSyntax {
|
export interface FunctionExpressionSyntax extends ISyntaxNode, IPrimaryExpressionSyntax {
|
||||||
functionKeyword: ISyntaxToken;
|
functionKeyword: ISyntaxToken;
|
||||||
|
asterixToken: ISyntaxToken;
|
||||||
identifier: ISyntaxToken;
|
identifier: ISyntaxToken;
|
||||||
callSignature: CallSignatureSyntax;
|
callSignature: CallSignatureSyntax;
|
||||||
block: BlockSyntax;
|
block: BlockSyntax;
|
||||||
}
|
}
|
||||||
export interface FunctionExpressionConstructor { new (data: number, functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax): FunctionExpressionSyntax }
|
export interface FunctionExpressionConstructor { new (data: number, functionKeyword: ISyntaxToken, asterixToken: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax): FunctionExpressionSyntax }
|
||||||
|
|
||||||
export interface OmittedExpressionSyntax extends ISyntaxNode, IExpressionSyntax {
|
export interface OmittedExpressionSyntax extends ISyntaxNode, IExpressionSyntax {
|
||||||
}
|
}
|
||||||
|
@ -520,6 +523,13 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
export interface TemplateAccessExpressionConstructor { new (data: number, expression: ILeftHandSideExpressionSyntax, templateExpression: IPrimaryExpressionSyntax): TemplateAccessExpressionSyntax }
|
export interface TemplateAccessExpressionConstructor { new (data: number, expression: ILeftHandSideExpressionSyntax, templateExpression: IPrimaryExpressionSyntax): TemplateAccessExpressionSyntax }
|
||||||
|
|
||||||
|
export interface YieldExpressionSyntax extends ISyntaxNode, IExpressionSyntax {
|
||||||
|
yieldKeyword: ISyntaxToken;
|
||||||
|
asterixToken: ISyntaxToken;
|
||||||
|
expression: IExpressionSyntax;
|
||||||
|
}
|
||||||
|
export interface YieldExpressionConstructor { new (data: number, yieldKeyword: ISyntaxToken, asterixToken: ISyntaxToken, expression: IExpressionSyntax): YieldExpressionSyntax }
|
||||||
|
|
||||||
export interface VariableDeclarationSyntax extends ISyntaxNode {
|
export interface VariableDeclarationSyntax extends ISyntaxNode {
|
||||||
varKeyword: ISyntaxToken;
|
varKeyword: ISyntaxToken;
|
||||||
variableDeclarators: ISeparatedSyntaxList<VariableDeclaratorSyntax>;
|
variableDeclarators: ISeparatedSyntaxList<VariableDeclaratorSyntax>;
|
||||||
|
@ -637,11 +647,12 @@ module TypeScript {
|
||||||
export interface SimplePropertyAssignmentConstructor { new (data: number, propertyName: IPropertyNameSyntax, colonToken: ISyntaxToken, expression: IExpressionSyntax): SimplePropertyAssignmentSyntax }
|
export interface SimplePropertyAssignmentConstructor { new (data: number, propertyName: IPropertyNameSyntax, colonToken: ISyntaxToken, expression: IExpressionSyntax): SimplePropertyAssignmentSyntax }
|
||||||
|
|
||||||
export interface FunctionPropertyAssignmentSyntax extends ISyntaxNode, IPropertyAssignmentSyntax {
|
export interface FunctionPropertyAssignmentSyntax extends ISyntaxNode, IPropertyAssignmentSyntax {
|
||||||
|
asterixToken: ISyntaxToken;
|
||||||
propertyName: IPropertyNameSyntax;
|
propertyName: IPropertyNameSyntax;
|
||||||
callSignature: CallSignatureSyntax;
|
callSignature: CallSignatureSyntax;
|
||||||
block: BlockSyntax;
|
block: BlockSyntax;
|
||||||
}
|
}
|
||||||
export interface FunctionPropertyAssignmentConstructor { new (data: number, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, block: BlockSyntax): FunctionPropertyAssignmentSyntax }
|
export interface FunctionPropertyAssignmentConstructor { new (data: number, asterixToken: ISyntaxToken, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, block: BlockSyntax): FunctionPropertyAssignmentSyntax }
|
||||||
|
|
||||||
export interface ParameterSyntax extends ISyntaxNode {
|
export interface ParameterSyntax extends ISyntaxNode {
|
||||||
dotDotDotToken: ISyntaxToken;
|
dotDotDotToken: ISyntaxToken;
|
||||||
|
|
|
@ -234,6 +234,7 @@ module TypeScript {
|
||||||
OmittedExpression,
|
OmittedExpression,
|
||||||
TemplateExpression,
|
TemplateExpression,
|
||||||
TemplateAccessExpression,
|
TemplateAccessExpression,
|
||||||
|
YieldExpression,
|
||||||
|
|
||||||
// Variable declarations
|
// Variable declarations
|
||||||
VariableDeclaration,
|
VariableDeclaration,
|
||||||
|
|
|
@ -238,28 +238,31 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export var FunctionDeclarationSyntax: FunctionDeclarationConstructor = <any>function(data: number, modifiers: ISyntaxToken[], functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken) {
|
export var FunctionDeclarationSyntax: FunctionDeclarationConstructor = <any>function(data: number, modifiers: ISyntaxToken[], functionKeyword: ISyntaxToken, asterixToken: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken) {
|
||||||
if (data) { this.__data = data; }
|
if (data) { this.__data = data; }
|
||||||
this.modifiers = modifiers,
|
this.modifiers = modifiers,
|
||||||
this.functionKeyword = functionKeyword,
|
this.functionKeyword = functionKeyword,
|
||||||
|
this.asterixToken = asterixToken,
|
||||||
this.identifier = identifier,
|
this.identifier = identifier,
|
||||||
this.callSignature = callSignature,
|
this.callSignature = callSignature,
|
||||||
this.body = body,
|
this.body = body,
|
||||||
modifiers.parent = this,
|
modifiers.parent = this,
|
||||||
functionKeyword.parent = this,
|
functionKeyword.parent = this,
|
||||||
|
asterixToken && (asterixToken.parent = this),
|
||||||
identifier.parent = this,
|
identifier.parent = this,
|
||||||
callSignature.parent = this,
|
callSignature.parent = this,
|
||||||
body && (body.parent = this);
|
body && (body.parent = this);
|
||||||
};
|
};
|
||||||
FunctionDeclarationSyntax.prototype.kind = SyntaxKind.FunctionDeclaration;
|
FunctionDeclarationSyntax.prototype.kind = SyntaxKind.FunctionDeclaration;
|
||||||
FunctionDeclarationSyntax.prototype.childCount = 5;
|
FunctionDeclarationSyntax.prototype.childCount = 6;
|
||||||
FunctionDeclarationSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
FunctionDeclarationSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: return this.modifiers;
|
case 0: return this.modifiers;
|
||||||
case 1: return this.functionKeyword;
|
case 1: return this.functionKeyword;
|
||||||
case 2: return this.identifier;
|
case 2: return this.asterixToken;
|
||||||
case 3: return this.callSignature;
|
case 3: return this.identifier;
|
||||||
case 4: return this.body;
|
case 4: return this.callSignature;
|
||||||
|
case 5: return this.body;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,25 +406,28 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export var MemberFunctionDeclarationSyntax: MemberFunctionDeclarationConstructor = <any>function(data: number, modifiers: ISyntaxToken[], propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken) {
|
export var MemberFunctionDeclarationSyntax: MemberFunctionDeclarationConstructor = <any>function(data: number, modifiers: ISyntaxToken[], asterixToken: ISyntaxToken, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken) {
|
||||||
if (data) { this.__data = data; }
|
if (data) { this.__data = data; }
|
||||||
this.modifiers = modifiers,
|
this.modifiers = modifiers,
|
||||||
|
this.asterixToken = asterixToken,
|
||||||
this.propertyName = propertyName,
|
this.propertyName = propertyName,
|
||||||
this.callSignature = callSignature,
|
this.callSignature = callSignature,
|
||||||
this.body = body,
|
this.body = body,
|
||||||
modifiers.parent = this,
|
modifiers.parent = this,
|
||||||
|
asterixToken && (asterixToken.parent = this),
|
||||||
propertyName.parent = this,
|
propertyName.parent = this,
|
||||||
callSignature.parent = this,
|
callSignature.parent = this,
|
||||||
body && (body.parent = this);
|
body && (body.parent = this);
|
||||||
};
|
};
|
||||||
MemberFunctionDeclarationSyntax.prototype.kind = SyntaxKind.MemberFunctionDeclaration;
|
MemberFunctionDeclarationSyntax.prototype.kind = SyntaxKind.MemberFunctionDeclaration;
|
||||||
MemberFunctionDeclarationSyntax.prototype.childCount = 4;
|
MemberFunctionDeclarationSyntax.prototype.childCount = 5;
|
||||||
MemberFunctionDeclarationSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
MemberFunctionDeclarationSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: return this.modifiers;
|
case 0: return this.modifiers;
|
||||||
case 1: return this.propertyName;
|
case 1: return this.asterixToken;
|
||||||
case 2: return this.callSignature;
|
case 2: return this.propertyName;
|
||||||
case 3: return this.body;
|
case 3: return this.callSignature;
|
||||||
|
case 4: return this.body;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1355,25 +1361,28 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export var FunctionExpressionSyntax: FunctionExpressionConstructor = <any>function(data: number, functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) {
|
export var FunctionExpressionSyntax: FunctionExpressionConstructor = <any>function(data: number, functionKeyword: ISyntaxToken, asterixToken: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) {
|
||||||
if (data) { this.__data = data; }
|
if (data) { this.__data = data; }
|
||||||
this.functionKeyword = functionKeyword,
|
this.functionKeyword = functionKeyword,
|
||||||
|
this.asterixToken = asterixToken,
|
||||||
this.identifier = identifier,
|
this.identifier = identifier,
|
||||||
this.callSignature = callSignature,
|
this.callSignature = callSignature,
|
||||||
this.block = block,
|
this.block = block,
|
||||||
functionKeyword.parent = this,
|
functionKeyword.parent = this,
|
||||||
|
asterixToken && (asterixToken.parent = this),
|
||||||
identifier && (identifier.parent = this),
|
identifier && (identifier.parent = this),
|
||||||
callSignature.parent = this,
|
callSignature.parent = this,
|
||||||
block.parent = this;
|
block.parent = this;
|
||||||
};
|
};
|
||||||
FunctionExpressionSyntax.prototype.kind = SyntaxKind.FunctionExpression;
|
FunctionExpressionSyntax.prototype.kind = SyntaxKind.FunctionExpression;
|
||||||
FunctionExpressionSyntax.prototype.childCount = 4;
|
FunctionExpressionSyntax.prototype.childCount = 5;
|
||||||
FunctionExpressionSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
FunctionExpressionSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: return this.functionKeyword;
|
case 0: return this.functionKeyword;
|
||||||
case 1: return this.identifier;
|
case 1: return this.asterixToken;
|
||||||
case 2: return this.callSignature;
|
case 2: return this.identifier;
|
||||||
case 3: return this.block;
|
case 3: return this.callSignature;
|
||||||
|
case 4: return this.block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1418,6 +1427,25 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export var YieldExpressionSyntax: YieldExpressionConstructor = <any>function(data: number, yieldKeyword: ISyntaxToken, asterixToken: ISyntaxToken, expression: IExpressionSyntax) {
|
||||||
|
if (data) { this.__data = data; }
|
||||||
|
this.yieldKeyword = yieldKeyword,
|
||||||
|
this.asterixToken = asterixToken,
|
||||||
|
this.expression = expression,
|
||||||
|
yieldKeyword.parent = this,
|
||||||
|
asterixToken && (asterixToken.parent = this),
|
||||||
|
expression && (expression.parent = this);
|
||||||
|
};
|
||||||
|
YieldExpressionSyntax.prototype.kind = SyntaxKind.YieldExpression;
|
||||||
|
YieldExpressionSyntax.prototype.childCount = 3;
|
||||||
|
YieldExpressionSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
||||||
|
switch (index) {
|
||||||
|
case 0: return this.yieldKeyword;
|
||||||
|
case 1: return this.asterixToken;
|
||||||
|
case 2: return this.expression;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export var VariableDeclarationSyntax: VariableDeclarationConstructor = <any>function(data: number, varKeyword: ISyntaxToken, variableDeclarators: ISeparatedSyntaxList<VariableDeclaratorSyntax>) {
|
export var VariableDeclarationSyntax: VariableDeclarationConstructor = <any>function(data: number, varKeyword: ISyntaxToken, variableDeclarators: ISeparatedSyntaxList<VariableDeclaratorSyntax>) {
|
||||||
if (data) { this.__data = data; }
|
if (data) { this.__data = data; }
|
||||||
this.varKeyword = varKeyword,
|
this.varKeyword = varKeyword,
|
||||||
|
@ -1732,22 +1760,25 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export var FunctionPropertyAssignmentSyntax: FunctionPropertyAssignmentConstructor = <any>function(data: number, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, block: BlockSyntax) {
|
export var FunctionPropertyAssignmentSyntax: FunctionPropertyAssignmentConstructor = <any>function(data: number, asterixToken: ISyntaxToken, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, block: BlockSyntax) {
|
||||||
if (data) { this.__data = data; }
|
if (data) { this.__data = data; }
|
||||||
|
this.asterixToken = asterixToken,
|
||||||
this.propertyName = propertyName,
|
this.propertyName = propertyName,
|
||||||
this.callSignature = callSignature,
|
this.callSignature = callSignature,
|
||||||
this.block = block,
|
this.block = block,
|
||||||
|
asterixToken && (asterixToken.parent = this),
|
||||||
propertyName.parent = this,
|
propertyName.parent = this,
|
||||||
callSignature.parent = this,
|
callSignature.parent = this,
|
||||||
block.parent = this;
|
block.parent = this;
|
||||||
};
|
};
|
||||||
FunctionPropertyAssignmentSyntax.prototype.kind = SyntaxKind.FunctionPropertyAssignment;
|
FunctionPropertyAssignmentSyntax.prototype.kind = SyntaxKind.FunctionPropertyAssignment;
|
||||||
FunctionPropertyAssignmentSyntax.prototype.childCount = 3;
|
FunctionPropertyAssignmentSyntax.prototype.childCount = 4;
|
||||||
FunctionPropertyAssignmentSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
FunctionPropertyAssignmentSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: return this.propertyName;
|
case 0: return this.asterixToken;
|
||||||
case 1: return this.callSignature;
|
case 1: return this.propertyName;
|
||||||
case 2: return this.block;
|
case 2: return this.callSignature;
|
||||||
|
case 3: return this.block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1297,7 +1297,7 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
private checkForWithInStrictMode(node: WithStatementSyntax): boolean {
|
private checkForWithInStrictMode(node: WithStatementSyntax): boolean {
|
||||||
if (parsedInStrictMode(node)) {
|
if (parsedInStrictModeContext(node)) {
|
||||||
this.pushDiagnostic(firstToken(node), DiagnosticCode.with_statements_are_not_allowed_in_strict_mode);
|
this.pushDiagnostic(firstToken(node), DiagnosticCode.with_statements_are_not_allowed_in_strict_mode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1509,7 +1509,7 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
public visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): void {
|
public visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): void {
|
||||||
if (parsedInStrictMode(node) && this.isPreIncrementOrDecrementExpression(node) && this.isEvalOrArguments(node.operand)) {
|
if (parsedInStrictModeContext(node) && this.isPreIncrementOrDecrementExpression(node) && this.isEvalOrArguments(node.operand)) {
|
||||||
this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.operand)]);
|
this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.operand)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1517,7 +1517,7 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
public visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): void {
|
public visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): void {
|
||||||
if (parsedInStrictMode(node) && this.isEvalOrArguments(node.operand)) {
|
if (parsedInStrictModeContext(node) && this.isEvalOrArguments(node.operand)) {
|
||||||
this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.operand)]);
|
this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.operand)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1534,7 +1534,7 @@ module TypeScript {
|
||||||
|
|
||||||
private checkForDisallowedEvalOrArguments(node: ISyntaxNode, token: ISyntaxToken): boolean {
|
private checkForDisallowedEvalOrArguments(node: ISyntaxNode, token: ISyntaxToken): boolean {
|
||||||
if (token) {
|
if (token) {
|
||||||
if (parsedInStrictMode(node) && this.isEvalOrArguments(token)) {
|
if (parsedInStrictModeContext(node) && this.isEvalOrArguments(token)) {
|
||||||
this.pushDiagnostic(token, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(token)]);
|
this.pushDiagnostic(token, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(token)]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1554,16 +1554,25 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
public visitDeleteExpression(node: DeleteExpressionSyntax): void {
|
public visitDeleteExpression(node: DeleteExpressionSyntax): void {
|
||||||
if (parsedInStrictMode(node) && node.expression.kind === SyntaxKind.IdentifierName) {
|
if (parsedInStrictModeContext(node) && node.expression.kind === SyntaxKind.IdentifierName) {
|
||||||
this.pushDiagnostic(firstToken(node), DiagnosticCode.delete_cannot_be_called_on_an_identifier_in_strict_mode);
|
this.pushDiagnostic(node.deleteKeyword, DiagnosticCode.delete_cannot_be_called_on_an_identifier_in_strict_mode);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.visitDeleteExpression(node);
|
super.visitDeleteExpression(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public visitYieldExpression(node: YieldExpressionSyntax): void {
|
||||||
|
if (!parsedInYieldContext(node)) {
|
||||||
|
this.pushDiagnostic(node.yieldKeyword, DiagnosticCode.yield_expression_must_be_contained_within_a_generator_declaration);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.visitYieldExpression(node);
|
||||||
|
}
|
||||||
|
|
||||||
private checkIllegalAssignment(node: BinaryExpressionSyntax): boolean {
|
private checkIllegalAssignment(node: BinaryExpressionSyntax): boolean {
|
||||||
if (parsedInStrictMode(node) && SyntaxFacts.isAssignmentOperatorToken(node.operatorToken.kind) && this.isEvalOrArguments(node.left)) {
|
if (parsedInStrictModeContext(node) && SyntaxFacts.isAssignmentOperatorToken(node.operatorToken.kind) && this.isEvalOrArguments(node.left)) {
|
||||||
this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.left)]);
|
this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.left)]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,7 @@ module TypeScript {
|
||||||
case SyntaxKind.OmittedExpression: return visitor.visitOmittedExpression(<OmittedExpressionSyntax>element);
|
case SyntaxKind.OmittedExpression: return visitor.visitOmittedExpression(<OmittedExpressionSyntax>element);
|
||||||
case SyntaxKind.TemplateExpression: return visitor.visitTemplateExpression(<TemplateExpressionSyntax>element);
|
case SyntaxKind.TemplateExpression: return visitor.visitTemplateExpression(<TemplateExpressionSyntax>element);
|
||||||
case SyntaxKind.TemplateAccessExpression: return visitor.visitTemplateAccessExpression(<TemplateAccessExpressionSyntax>element);
|
case SyntaxKind.TemplateAccessExpression: return visitor.visitTemplateAccessExpression(<TemplateAccessExpressionSyntax>element);
|
||||||
|
case SyntaxKind.YieldExpression: return visitor.visitYieldExpression(<YieldExpressionSyntax>element);
|
||||||
case SyntaxKind.VariableDeclaration: return visitor.visitVariableDeclaration(<VariableDeclarationSyntax>element);
|
case SyntaxKind.VariableDeclaration: return visitor.visitVariableDeclaration(<VariableDeclarationSyntax>element);
|
||||||
case SyntaxKind.VariableDeclarator: return visitor.visitVariableDeclarator(<VariableDeclaratorSyntax>element);
|
case SyntaxKind.VariableDeclarator: return visitor.visitVariableDeclarator(<VariableDeclaratorSyntax>element);
|
||||||
case SyntaxKind.ArgumentList: return visitor.visitArgumentList(<ArgumentListSyntax>element);
|
case SyntaxKind.ArgumentList: return visitor.visitArgumentList(<ArgumentListSyntax>element);
|
||||||
|
@ -170,6 +171,7 @@ module TypeScript {
|
||||||
visitOmittedExpression(node: OmittedExpressionSyntax): any;
|
visitOmittedExpression(node: OmittedExpressionSyntax): any;
|
||||||
visitTemplateExpression(node: TemplateExpressionSyntax): any;
|
visitTemplateExpression(node: TemplateExpressionSyntax): any;
|
||||||
visitTemplateAccessExpression(node: TemplateAccessExpressionSyntax): any;
|
visitTemplateAccessExpression(node: TemplateAccessExpressionSyntax): any;
|
||||||
|
visitYieldExpression(node: YieldExpressionSyntax): any;
|
||||||
visitVariableDeclaration(node: VariableDeclarationSyntax): any;
|
visitVariableDeclaration(node: VariableDeclarationSyntax): any;
|
||||||
visitVariableDeclarator(node: VariableDeclaratorSyntax): any;
|
visitVariableDeclarator(node: VariableDeclaratorSyntax): any;
|
||||||
visitArgumentList(node: ArgumentListSyntax): any;
|
visitArgumentList(node: ArgumentListSyntax): any;
|
||||||
|
|
|
@ -97,6 +97,7 @@ module TypeScript {
|
||||||
public visitFunctionDeclaration(node: FunctionDeclarationSyntax): void {
|
public visitFunctionDeclaration(node: FunctionDeclarationSyntax): void {
|
||||||
this.visitList(node.modifiers);
|
this.visitList(node.modifiers);
|
||||||
this.visitToken(node.functionKeyword);
|
this.visitToken(node.functionKeyword);
|
||||||
|
this.visitOptionalToken(node.asterixToken);
|
||||||
this.visitToken(node.identifier);
|
this.visitToken(node.identifier);
|
||||||
visitNodeOrToken(this, node.callSignature);
|
visitNodeOrToken(this, node.callSignature);
|
||||||
visitNodeOrToken(this, node.body);
|
visitNodeOrToken(this, node.body);
|
||||||
|
@ -149,6 +150,7 @@ module TypeScript {
|
||||||
|
|
||||||
public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): void {
|
public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): void {
|
||||||
this.visitList(node.modifiers);
|
this.visitList(node.modifiers);
|
||||||
|
this.visitOptionalToken(node.asterixToken);
|
||||||
visitNodeOrToken(this, node.propertyName);
|
visitNodeOrToken(this, node.propertyName);
|
||||||
visitNodeOrToken(this, node.callSignature);
|
visitNodeOrToken(this, node.callSignature);
|
||||||
visitNodeOrToken(this, node.body);
|
visitNodeOrToken(this, node.body);
|
||||||
|
@ -451,6 +453,7 @@ module TypeScript {
|
||||||
|
|
||||||
public visitFunctionExpression(node: FunctionExpressionSyntax): void {
|
public visitFunctionExpression(node: FunctionExpressionSyntax): void {
|
||||||
this.visitToken(node.functionKeyword);
|
this.visitToken(node.functionKeyword);
|
||||||
|
this.visitOptionalToken(node.asterixToken);
|
||||||
this.visitOptionalToken(node.identifier);
|
this.visitOptionalToken(node.identifier);
|
||||||
visitNodeOrToken(this, node.callSignature);
|
visitNodeOrToken(this, node.callSignature);
|
||||||
visitNodeOrToken(this, node.block);
|
visitNodeOrToken(this, node.block);
|
||||||
|
@ -469,6 +472,12 @@ module TypeScript {
|
||||||
visitNodeOrToken(this, node.templateExpression);
|
visitNodeOrToken(this, node.templateExpression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public visitYieldExpression(node: YieldExpressionSyntax): void {
|
||||||
|
this.visitToken(node.yieldKeyword);
|
||||||
|
this.visitOptionalToken(node.asterixToken);
|
||||||
|
visitNodeOrToken(this, node.expression);
|
||||||
|
}
|
||||||
|
|
||||||
public visitVariableDeclaration(node: VariableDeclarationSyntax): void {
|
public visitVariableDeclaration(node: VariableDeclarationSyntax): void {
|
||||||
this.visitToken(node.varKeyword);
|
this.visitToken(node.varKeyword);
|
||||||
this.visitList(node.variableDeclarators);
|
this.visitList(node.variableDeclarators);
|
||||||
|
@ -569,6 +578,7 @@ module TypeScript {
|
||||||
}
|
}
|
||||||
|
|
||||||
public visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): void {
|
public visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): void {
|
||||||
|
this.visitOptionalToken(node.asterixToken);
|
||||||
visitNodeOrToken(this, node.propertyName);
|
visitNodeOrToken(this, node.propertyName);
|
||||||
visitNodeOrToken(this, node.callSignature);
|
visitNodeOrToken(this, node.callSignature);
|
||||||
visitNodeOrToken(this, node.block);
|
visitNodeOrToken(this, node.block);
|
||||||
|
|
|
@ -5,6 +5,66 @@ module ts {
|
||||||
list: Node;
|
list: Node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getEndLinePosition(line: number, sourceFile: SourceFile): number {
|
||||||
|
Debug.assert(line >= 1);
|
||||||
|
var lineStarts = sourceFile.getLineStarts();
|
||||||
|
|
||||||
|
// lines returned by SourceFile.getLineAndCharacterForPosition are 1-based
|
||||||
|
var lineIndex = line - 1;
|
||||||
|
if (lineIndex === lineStarts.length - 1) {
|
||||||
|
// last line - return EOF
|
||||||
|
return sourceFile.text.length - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// current line start
|
||||||
|
var start = lineStarts[lineIndex];
|
||||||
|
// take the start position of the next line -1 = it should be some line break
|
||||||
|
var pos = lineStarts[lineIndex + 1] - 1;
|
||||||
|
Debug.assert(isLineBreak(sourceFile.text.charCodeAt(pos)));
|
||||||
|
// walk backwards skipping line breaks, stop the the beginning of current line.
|
||||||
|
// i.e:
|
||||||
|
// <some text>
|
||||||
|
// $ <- end of line for this position should match the start position
|
||||||
|
while (start <= pos && isLineBreak(sourceFile.text.charCodeAt(pos))) {
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStartPositionOfLine(line: number, sourceFile: SourceFile): number {
|
||||||
|
Debug.assert(line >= 1);
|
||||||
|
return sourceFile.getLineStarts()[line - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStartLinePositionForPosition(position: number, sourceFile: SourceFile): number {
|
||||||
|
var lineStarts = sourceFile.getLineStarts();
|
||||||
|
var line = sourceFile.getLineAndCharacterFromPosition(position).line;
|
||||||
|
return lineStarts[line - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rangeContainsRange(r1: TextRange, r2: TextRange): boolean {
|
||||||
|
return startEndContainsRange(r1.pos, r1.end, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function startEndContainsRange(start: number, end: number, range: TextRange): boolean {
|
||||||
|
return start <= range.pos && end >= range.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rangeContainsStartEnd(range: TextRange, start: number, end: number): boolean {
|
||||||
|
return range.pos <= start && range.end >= end;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rangeOverlapsWithStartEnd(r1: TextRange, start: number, end: number) {
|
||||||
|
return startEndOverlapsWithStartEnd(r1.pos, r1.end, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function startEndOverlapsWithStartEnd(start1: number, end1: number, start2: number, end2: number) {
|
||||||
|
var start = Math.max(start1, start2);
|
||||||
|
var end = Math.min(end1, end2);
|
||||||
|
return start < end;
|
||||||
|
}
|
||||||
|
|
||||||
export function findListItemInfo(node: Node): ListItemInfo {
|
export function findListItemInfo(node: Node): ListItemInfo {
|
||||||
var syntaxList = findContainingList(node);
|
var syntaxList = findContainingList(node);
|
||||||
|
|
||||||
|
@ -63,14 +123,14 @@ module ts {
|
||||||
* position >= start and (position < end or (position === end && token is keyword or identifier))
|
* position >= start and (position < end or (position === end && token is keyword or identifier))
|
||||||
*/
|
*/
|
||||||
export function getTouchingWord(sourceFile: SourceFile, position: number): Node {
|
export function getTouchingWord(sourceFile: SourceFile, position: number): Node {
|
||||||
return getTouchingToken(sourceFile, position, isWord);
|
return getTouchingToken(sourceFile, position, n => isWord(n.kind));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gets the token whose text has range [start, end) and position >= start
|
/* Gets the token whose text has range [start, end) and position >= start
|
||||||
* and (position < end or (position === end && token is keyword or identifier or numeric\string litera))
|
* and (position < end or (position === end && token is keyword or identifier or numeric\string litera))
|
||||||
*/
|
*/
|
||||||
export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node {
|
export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node {
|
||||||
return getTouchingToken(sourceFile, position, isPropertyName);
|
return getTouchingToken(sourceFile, position, n => isPropertyName(n.kind));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the token if position is in [start, end) or if position === end and includeItemAtEndPosition(token) === true */
|
/** Returns the token if position is in [start, end) or if position === end and includeItemAtEndPosition(token) === true */
|
||||||
|
@ -245,19 +305,19 @@ module ts {
|
||||||
return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken;
|
return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isWord(n: Node): boolean {
|
function isWord(kind: SyntaxKind): boolean {
|
||||||
return n.kind === SyntaxKind.Identifier || isKeyword(n.kind);
|
return kind === SyntaxKind.Identifier || isKeyword(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPropertyName(n: Node): boolean {
|
function isPropertyName(kind: SyntaxKind): boolean {
|
||||||
return n.kind === SyntaxKind.StringLiteral || n.kind === SyntaxKind.NumericLiteral || isWord(n);
|
return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NumericLiteral || isWord(kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isComment(n: Node): boolean {
|
export function isComment(kind: SyntaxKind): boolean {
|
||||||
return n.kind === SyntaxKind.SingleLineCommentTrivia || n.kind === SyntaxKind.MultiLineCommentTrivia;
|
return kind === SyntaxKind.SingleLineCommentTrivia || kind === SyntaxKind.MultiLineCommentTrivia;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isPunctuation(n: Node): boolean {
|
export function isPunctuation(kind: SyntaxKind): boolean {
|
||||||
return SyntaxKind.FirstPunctuation <= n.kind && n.kind <= SyntaxKind.LastPunctuation;
|
return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,12 +1,10 @@
|
||||||
error TS2318: Cannot find global type 'Boolean'.
|
error TS2318: Cannot find global type 'Boolean'.
|
||||||
error TS2318: Cannot find global type 'IArguments'.
|
error TS2318: Cannot find global type 'IArguments'.
|
||||||
error TS2318: Cannot find global type 'TemplateStringsArray'.
|
|
||||||
tests/cases/compiler/noDefaultLib.ts(4,11): error TS2317: Global type 'Array' must have 1 type parameter(s).
|
tests/cases/compiler/noDefaultLib.ts(4,11): error TS2317: Global type 'Array' must have 1 type parameter(s).
|
||||||
|
|
||||||
|
|
||||||
!!! error TS2318: Cannot find global type 'Boolean'.
|
!!! error TS2318: Cannot find global type 'Boolean'.
|
||||||
!!! error TS2318: Cannot find global type 'IArguments'.
|
!!! error TS2318: Cannot find global type 'IArguments'.
|
||||||
!!! error TS2318: Cannot find global type 'TemplateStringsArray'.
|
|
||||||
==== tests/cases/compiler/noDefaultLib.ts (1 errors) ====
|
==== tests/cases/compiler/noDefaultLib.ts (1 errors) ====
|
||||||
/// <reference no-default-lib="true"/>
|
/// <reference no-default-lib="true"/>
|
||||||
var x;
|
var x;
|
||||||
|
|
|
@ -6,7 +6,6 @@ error TS2318: Cannot find global type 'Number'.
|
||||||
error TS2318: Cannot find global type 'Object'.
|
error TS2318: Cannot find global type 'Object'.
|
||||||
error TS2318: Cannot find global type 'RegExp'.
|
error TS2318: Cannot find global type 'RegExp'.
|
||||||
error TS2318: Cannot find global type 'String'.
|
error TS2318: Cannot find global type 'String'.
|
||||||
error TS2318: Cannot find global type 'TemplateStringsArray'.
|
|
||||||
|
|
||||||
|
|
||||||
!!! error TS2318: Cannot find global type 'Array'.
|
!!! error TS2318: Cannot find global type 'Array'.
|
||||||
|
@ -17,7 +16,6 @@ error TS2318: Cannot find global type 'TemplateStringsArray'.
|
||||||
!!! error TS2318: Cannot find global type 'Object'.
|
!!! error TS2318: Cannot find global type 'Object'.
|
||||||
!!! error TS2318: Cannot find global type 'RegExp'.
|
!!! error TS2318: Cannot find global type 'RegExp'.
|
||||||
!!! error TS2318: Cannot find global type 'String'.
|
!!! error TS2318: Cannot find global type 'String'.
|
||||||
!!! error TS2318: Cannot find global type 'TemplateStringsArray'.
|
|
||||||
==== tests/cases/conformance/parser/ecmascript5/RegressionTests/parser509698.ts (0 errors) ====
|
==== tests/cases/conformance/parser/ecmascript5/RegressionTests/parser509698.ts (0 errors) ====
|
||||||
/// <style requireSemi="on" />
|
/// <style requireSemi="on" />
|
||||||
/// <reference no-default-lib="true"/>
|
/// <reference no-default-lib="true"/>
|
||||||
|
|
|
@ -6,7 +6,6 @@ error TS2318: Cannot find global type 'Number'.
|
||||||
error TS2318: Cannot find global type 'Object'.
|
error TS2318: Cannot find global type 'Object'.
|
||||||
error TS2318: Cannot find global type 'RegExp'.
|
error TS2318: Cannot find global type 'RegExp'.
|
||||||
error TS2318: Cannot find global type 'String'.
|
error TS2318: Cannot find global type 'String'.
|
||||||
error TS2318: Cannot find global type 'TemplateStringsArray'.
|
|
||||||
test.ts(3,8): error TS2304: Cannot find name 'Array'.
|
test.ts(3,8): error TS2304: Cannot find name 'Array'.
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +17,6 @@ test.ts(3,8): error TS2304: Cannot find name 'Array'.
|
||||||
!!! error TS2318: Cannot find global type 'Object'.
|
!!! error TS2318: Cannot find global type 'Object'.
|
||||||
!!! error TS2318: Cannot find global type 'RegExp'.
|
!!! error TS2318: Cannot find global type 'RegExp'.
|
||||||
!!! error TS2318: Cannot find global type 'String'.
|
!!! error TS2318: Cannot find global type 'String'.
|
||||||
!!! error TS2318: Cannot find global type 'TemplateStringsArray'.
|
|
||||||
==== test.ts (1 errors) ====
|
==== test.ts (1 errors) ====
|
||||||
/// <reference no-default-lib="true"/>
|
/// <reference no-default-lib="true"/>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ error TS2318: Cannot find global type 'Number'.
|
||||||
error TS2318: Cannot find global type 'Object'.
|
error TS2318: Cannot find global type 'Object'.
|
||||||
error TS2318: Cannot find global type 'RegExp'.
|
error TS2318: Cannot find global type 'RegExp'.
|
||||||
error TS2318: Cannot find global type 'String'.
|
error TS2318: Cannot find global type 'String'.
|
||||||
error TS2318: Cannot find global type 'TemplateStringsArray'.
|
|
||||||
test.ts(3,8): error TS2304: Cannot find name 'Array'.
|
test.ts(3,8): error TS2304: Cannot find name 'Array'.
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +17,6 @@ test.ts(3,8): error TS2304: Cannot find name 'Array'.
|
||||||
!!! error TS2318: Cannot find global type 'Object'.
|
!!! error TS2318: Cannot find global type 'Object'.
|
||||||
!!! error TS2318: Cannot find global type 'RegExp'.
|
!!! error TS2318: Cannot find global type 'RegExp'.
|
||||||
!!! error TS2318: Cannot find global type 'String'.
|
!!! error TS2318: Cannot find global type 'String'.
|
||||||
!!! error TS2318: Cannot find global type 'TemplateStringsArray'.
|
|
||||||
==== test.ts (1 errors) ====
|
==== test.ts (1 errors) ====
|
||||||
/// <reference no-default-lib="true"/>
|
/// <reference no-default-lib="true"/>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts(10,1): error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
|
||||||
|
lib.d.ts(502,11): error TS2300: Duplicate identifier 'TemplateStringsArray'.
|
||||||
|
tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts(2,7): error TS2300: Duplicate identifier 'TemplateStringsArray'.
|
||||||
|
tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts(8,3): error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'TemplateStringsArray'.
|
||||||
|
Property 'raw' is missing in type '{ [x: number]: undefined; }'.
|
||||||
|
|
||||||
|
|
||||||
|
==== tests/cases/compiler/templateStringsArrayTypeDefinedInES5Mode.ts (3 errors) ====
|
||||||
|
|
||||||
|
class TemplateStringsArray {
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
!!! error TS2300: Duplicate identifier 'TemplateStringsArray'.
|
||||||
|
}
|
||||||
|
|
||||||
|
function f(x: TemplateStringsArray, y: number, z: number) {
|
||||||
|
}
|
||||||
|
|
||||||
|
f({}, 10, 10);
|
||||||
|
~~
|
||||||
|
!!! error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'TemplateStringsArray'.
|
||||||
|
!!! error TS2345: Property 'raw' is missing in type '{ [x: number]: undefined; }'.
|
||||||
|
|
||||||
|
f `abcdef${ 1234 }${ 5678 }ghijkl`;
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
!!! error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
|
|
@ -0,0 +1,18 @@
|
||||||
|
tests/cases/compiler/templateStringsArrayTypeNotDefinedES5Mode.ts(7,1): error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
|
||||||
|
tests/cases/compiler/templateStringsArrayTypeNotDefinedES5Mode.ts(5,3): error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'TemplateStringsArray'.
|
||||||
|
Property 'raw' is missing in type '{ [x: number]: undefined; }'.
|
||||||
|
|
||||||
|
|
||||||
|
==== tests/cases/compiler/templateStringsArrayTypeNotDefinedES5Mode.ts (2 errors) ====
|
||||||
|
|
||||||
|
function f(x: TemplateStringsArray, y: number, z: number) {
|
||||||
|
}
|
||||||
|
|
||||||
|
f({}, 10, 10);
|
||||||
|
~~
|
||||||
|
!!! error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'TemplateStringsArray'.
|
||||||
|
!!! error TS2345: Property 'raw' is missing in type '{ [x: number]: undefined; }'.
|
||||||
|
|
||||||
|
f `abcdef${ 1234 }${ 5678 }ghijkl`;
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
!!! error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.
|
|
@ -0,0 +1,22 @@
|
||||||
|
lib.d.ts(502,11): error TS2300: Duplicate identifier 'TemplateStringsArray'.
|
||||||
|
tests/cases/compiler/templateStringsArrayTypeRedefinedInES6Mode.ts(2,7): error TS2300: Duplicate identifier 'TemplateStringsArray'.
|
||||||
|
tests/cases/compiler/templateStringsArrayTypeRedefinedInES6Mode.ts(8,3): error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'TemplateStringsArray'.
|
||||||
|
Property 'raw' is missing in type '{ [x: number]: undefined; }'.
|
||||||
|
|
||||||
|
|
||||||
|
==== tests/cases/compiler/templateStringsArrayTypeRedefinedInES6Mode.ts (2 errors) ====
|
||||||
|
|
||||||
|
class TemplateStringsArray {
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
!!! error TS2300: Duplicate identifier 'TemplateStringsArray'.
|
||||||
|
}
|
||||||
|
|
||||||
|
function f(x: TemplateStringsArray, y: number, z: number) {
|
||||||
|
}
|
||||||
|
|
||||||
|
f({}, 10, 10);
|
||||||
|
~~
|
||||||
|
!!! error TS2345: Argument of type '{ [x: number]: undefined; }' is not assignable to parameter of type 'TemplateStringsArray'.
|
||||||
|
!!! error TS2345: Property 'raw' is missing in type '{ [x: number]: undefined; }'.
|
||||||
|
|
||||||
|
f `abcdef${ 1234 }${ 5678 }ghijkl`;
|
|
@ -0,0 +1,22 @@
|
||||||
|
//// [templateStringsArrayTypeRedefinedInES6Mode.ts]
|
||||||
|
|
||||||
|
class TemplateStringsArray {
|
||||||
|
}
|
||||||
|
|
||||||
|
function f(x: TemplateStringsArray, y: number, z: number) {
|
||||||
|
}
|
||||||
|
|
||||||
|
f({}, 10, 10);
|
||||||
|
|
||||||
|
f `abcdef${ 1234 }${ 5678 }ghijkl`;
|
||||||
|
|
||||||
|
//// [templateStringsArrayTypeRedefinedInES6Mode.js]
|
||||||
|
var TemplateStringsArray = (function () {
|
||||||
|
function TemplateStringsArray() {
|
||||||
|
}
|
||||||
|
return TemplateStringsArray;
|
||||||
|
})();
|
||||||
|
function f(x, y, z) {
|
||||||
|
}
|
||||||
|
f({}, 10, 10);
|
||||||
|
f `abcdef${1234}${5678}ghijkl`;
|
|
@ -6,7 +6,6 @@ error TS2318: Cannot find global type 'Number'.
|
||||||
error TS2318: Cannot find global type 'Object'.
|
error TS2318: Cannot find global type 'Object'.
|
||||||
error TS2318: Cannot find global type 'RegExp'.
|
error TS2318: Cannot find global type 'RegExp'.
|
||||||
error TS2318: Cannot find global type 'String'.
|
error TS2318: Cannot find global type 'String'.
|
||||||
error TS2318: Cannot find global type 'TemplateStringsArray'.
|
|
||||||
tests/cases/compiler/typeCheckTypeArgument.ts(3,19): error TS2304: Cannot find name 'UNKNOWN'.
|
tests/cases/compiler/typeCheckTypeArgument.ts(3,19): error TS2304: Cannot find name 'UNKNOWN'.
|
||||||
tests/cases/compiler/typeCheckTypeArgument.ts(5,26): error TS2304: Cannot find name 'UNKNOWN'.
|
tests/cases/compiler/typeCheckTypeArgument.ts(5,26): error TS2304: Cannot find name 'UNKNOWN'.
|
||||||
tests/cases/compiler/typeCheckTypeArgument.ts(7,21): error TS2304: Cannot find name 'UNKNOWN'.
|
tests/cases/compiler/typeCheckTypeArgument.ts(7,21): error TS2304: Cannot find name 'UNKNOWN'.
|
||||||
|
@ -23,7 +22,6 @@ tests/cases/compiler/typeCheckTypeArgument.ts(15,13): error TS2304: Cannot find
|
||||||
!!! error TS2318: Cannot find global type 'Object'.
|
!!! error TS2318: Cannot find global type 'Object'.
|
||||||
!!! error TS2318: Cannot find global type 'RegExp'.
|
!!! error TS2318: Cannot find global type 'RegExp'.
|
||||||
!!! error TS2318: Cannot find global type 'String'.
|
!!! error TS2318: Cannot find global type 'String'.
|
||||||
!!! error TS2318: Cannot find global type 'TemplateStringsArray'.
|
|
||||||
==== tests/cases/compiler/typeCheckTypeArgument.ts (6 errors) ====
|
==== tests/cases/compiler/typeCheckTypeArgument.ts (6 errors) ====
|
||||||
/// <reference no-default-lib="true"/>
|
/// <reference no-default-lib="true"/>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// @target: es5
|
||||||
|
|
||||||
|
class TemplateStringsArray {
|
||||||
|
}
|
||||||
|
|
||||||
|
function f(x: TemplateStringsArray, y: number, z: number) {
|
||||||
|
}
|
||||||
|
|
||||||
|
f({}, 10, 10);
|
||||||
|
|
||||||
|
f `abcdef${ 1234 }${ 5678 }ghijkl`;
|
|
@ -0,0 +1,8 @@
|
||||||
|
// @target: es5
|
||||||
|
|
||||||
|
function f(x: TemplateStringsArray, y: number, z: number) {
|
||||||
|
}
|
||||||
|
|
||||||
|
f({}, 10, 10);
|
||||||
|
|
||||||
|
f `abcdef${ 1234 }${ 5678 }ghijkl`;
|
|
@ -0,0 +1,11 @@
|
||||||
|
// @target: es6
|
||||||
|
|
||||||
|
class TemplateStringsArray {
|
||||||
|
}
|
||||||
|
|
||||||
|
function f(x: TemplateStringsArray, y: number, z: number) {
|
||||||
|
}
|
||||||
|
|
||||||
|
f({}, 10, 10);
|
||||||
|
|
||||||
|
f `abcdef${ 1234 }${ 5678 }ghijkl`;
|
13
tests/cases/fourslash/formatInTryCatchFinally.ts
Normal file
13
tests/cases/fourslash/formatInTryCatchFinally.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
////try
|
||||||
|
////{
|
||||||
|
//// var x = 1/*1*/
|
||||||
|
////}
|
||||||
|
////catch (e)
|
||||||
|
////{
|
||||||
|
////}
|
||||||
|
|
||||||
|
goTo.marker("1");
|
||||||
|
edit.insert(";")
|
||||||
|
verify.currentLineContentIs(" var x = 1;");
|
12
tests/cases/fourslash/formattingBlockInCaseClauses.ts
Normal file
12
tests/cases/fourslash/formattingBlockInCaseClauses.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
////switch (1) {
|
||||||
|
//// case 1:
|
||||||
|
//// {
|
||||||
|
//// /*1*/
|
||||||
|
//// break;
|
||||||
|
////}
|
||||||
|
|
||||||
|
goTo.marker("1");
|
||||||
|
edit.insert("}");
|
||||||
|
verify.currentLineContentIs(" }");
|
12
tests/cases/fourslash/formattingIfInElseBlock.ts
Normal file
12
tests/cases/fourslash/formattingIfInElseBlock.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/// <reference path='fourslash.ts' />
|
||||||
|
|
||||||
|
////if (true) {
|
||||||
|
////}
|
||||||
|
////else {
|
||||||
|
//// if (true) {
|
||||||
|
//// /*1*/
|
||||||
|
////}
|
||||||
|
|
||||||
|
goTo.marker("1");
|
||||||
|
edit.insert("}")
|
||||||
|
verify.currentLineContentIs(" }");
|
|
@ -11,8 +11,8 @@
|
||||||
debugger;
|
debugger;
|
||||||
format.document();
|
format.document();
|
||||||
goTo.marker('1');
|
goTo.marker('1');
|
||||||
verify.currentLineContentIs('function test() /* %^ */');
|
verify.currentLineContentIs('function test() /* %^ */ {');
|
||||||
goTo.marker('2');
|
goTo.marker('2');
|
||||||
verify.currentLineContentIs(' if (true) /* %^ */');
|
verify.currentLineContentIs(' if (true) /* %^ */ {');
|
||||||
goTo.marker('3');
|
goTo.marker('3');
|
||||||
verify.currentLineContentIs('}');
|
verify.currentLineContentIs('}');
|
8
tests/cases/fourslash/smartIndentStartLineInLists.ts
Normal file
8
tests/cases/fourslash/smartIndentStartLineInLists.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/// <reference path='fourslash.ts'/>
|
||||||
|
////foo(function () {
|
||||||
|
////}).then(function () {/*1*/
|
||||||
|
////})
|
||||||
|
|
||||||
|
goTo.marker("1");
|
||||||
|
edit.insert("\r\n");
|
||||||
|
verify.indentationIs(4);
|
Loading…
Reference in a new issue