From 45ac06a0f217e19e9d86c78cdf5abd455b9d3eb6 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 16 Jan 2015 12:02:12 -0800 Subject: [PATCH 1/6] move line map related function out of SourceFile --- src/compiler/emitter.ts | 10 +++++----- src/compiler/parser.ts | 17 ----------------- src/compiler/scanner.ts | 17 ++++++++++++----- src/compiler/tsc.ts | 4 ++-- src/compiler/types.ts | 7 +++---- src/compiler/utilities.ts | 2 +- src/harness/fourslash.ts | 2 +- src/harness/harnessLanguageService.ts | 4 ++-- src/services/services.ts | 21 +++++++++++++++++---- 9 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index d82e577971..a0c0dc45b1 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -134,7 +134,7 @@ module ts { } function getLineOfLocalPosition(currentSourceFile: SourceFile, pos: number) { - return currentSourceFile.getLineAndCharacterFromPosition(pos).line; + return getLineAndCharacterOfPosition(currentSourceFile, pos).line; } function emitNewLineBeforeLeadingComments(currentSourceFile: SourceFile, writer: EmitTextWriter, node: TextRange, leadingComments: CommentRange[]) { @@ -169,15 +169,15 @@ module ts { function writeCommentRange(currentSourceFile: SourceFile, writer: EmitTextWriter, comment: CommentRange, newLine: string){ if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) { - var firstCommentLineAndCharacter = currentSourceFile.getLineAndCharacterFromPosition(comment.pos); + var firstCommentLineAndCharacter = getLineAndCharacterOfPosition(currentSourceFile, comment.pos); var firstCommentLineIndent: number; for (var pos = comment.pos, currentLine = firstCommentLineAndCharacter.line; pos < comment.end; currentLine++) { - var nextLineStart = currentSourceFile.getPositionFromLineAndCharacter(currentLine + 1, /*character*/1); + var nextLineStart = getPositionFromLineAndCharacter(currentSourceFile, currentLine + 1, /*character*/1); if (pos !== comment.pos) { // If we are not emitting first line, we need to write the spaces to adjust the alignment if (firstCommentLineIndent === undefined) { - firstCommentLineIndent = calculateIndent(currentSourceFile.getPositionFromLineAndCharacter(firstCommentLineAndCharacter.line, /*character*/1), + firstCommentLineIndent = calculateIndent(getPositionFromLineAndCharacter(currentSourceFile, firstCommentLineAndCharacter.line, /*character*/1), comment.pos); } @@ -1644,7 +1644,7 @@ module ts { } function recordSourceMapSpan(pos: number) { - var sourceLinePos = currentSourceFile.getLineAndCharacterFromPosition(pos); + var sourceLinePos = getLineAndCharacterOfPosition(currentSourceFile, pos); var emittedLine = writer.getLine(); var emittedColumn = writer.getColumn(); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5ae44e5ff3..19efe77a27 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -501,7 +501,6 @@ module ts { var identifiers: Map; var identifierCount = 0; var nodeCount = 0; - var lineStarts: number[]; var syntacticDiagnostics: Diagnostic[]; var scanner: Scanner; var token: SyntaxKind; @@ -593,7 +592,6 @@ module ts { sourceText = text; parsingContext = 0; identifiers = {}; - lineStarts = undefined; syntacticDiagnostics = undefined; contextFlags = 0; parseErrorBeforeNextFinishedNode = false; @@ -612,9 +610,6 @@ module ts { sourceFile.filename = normalizePath(filename); sourceFile.text = sourceText; - sourceFile.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition; - sourceFile.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter; - sourceFile.getLineStarts = getLineStarts; sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics; sourceFile.update = update; @@ -1072,18 +1067,6 @@ module ts { return (contextFlags & ParserContextFlags.DisallowIn) !== 0; } - function getLineStarts(): number[] { - return lineStarts || (lineStarts = computeLineStarts(sourceText)); - } - - function getLineAndCharacterFromSourcePosition(position: number) { - return getLineAndCharacterOfPosition(getLineStarts(), position); - } - - function getPositionFromSourceLineAndCharacter(line: number, character: number): number { - return getPositionFromLineAndCharacter(getLineStarts(), line, character); - } - function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): void { var start = scanner.getTokenPos(); var length = scanner.getTextPos() - start; diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 2a0363f7f7..2f475cb676 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -278,12 +278,20 @@ module ts { return result; } - export function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number { + export function getPositionFromLineAndCharacter(sourceFile: SourceFile, line: number, character: number): number { + return computePositionFromLineAndCharacter(getLineStarts(sourceFile), line, character); + } + + export function computePositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number { Debug.assert(line > 0); return lineStarts[line - 1] + character - 1; } - export function getLineAndCharacterOfPosition(lineStarts: number[], position: number) { + export function getLineStarts(sourceFile: SourceFile): number[] { + return sourceFile.lineMap || (sourceFile.lineMap = computeLineStarts(sourceFile.text)); + } + + export function computeLineAndCharacterOfPosition(lineStarts: number[], position: number) { var lineNumber = binarySearch(lineStarts, position); if (lineNumber < 0) { // If the actual position was not found, @@ -298,9 +306,8 @@ module ts { }; } - export function positionToLineAndCharacter(text: string, pos: number) { - var lineStarts = computeLineStarts(text); - return getLineAndCharacterOfPosition(lineStarts, pos); + export function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter { + return computeLineAndCharacterOfPosition(getLineStarts(sourceFile), position); } var hasOwnProperty = Object.prototype.hasOwnProperty; diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 9d03892069..443abf5e57 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -68,7 +68,7 @@ module ts { function countLines(program: Program): number { var count = 0; forEach(program.getSourceFiles(), file => { - count += file.getLineAndCharacterFromPosition(file.end).line; + count += getLineAndCharacterOfPosition(file, file.end).line; }); return count; } @@ -82,7 +82,7 @@ module ts { var output = ""; if (diagnostic.file) { - var loc = diagnostic.file.getLineAndCharacterFromPosition(diagnostic.start); + var loc = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start); output += diagnostic.file.filename + "(" + loc.line + "," + loc.character + "): "; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9ebab8dc22..9d899ccd21 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -881,10 +881,6 @@ module ts { filename: string; text: string; - getLineAndCharacterFromPosition(position: number): LineAndCharacter; - getPositionFromLineAndCharacter(line: number, character: number): number; - getLineStarts(): number[]; - // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter // indicates what changed between the 'text' that this SourceFile has and the 'newText'. // The SourceFile will be created with the compiler attempting to reuse as many nodes from @@ -920,6 +916,9 @@ module ts { symbolCount: number; languageVersion: ScriptTarget; identifiers: Map; + + // Stores a line map for the file. This field should never be used directly to obtain line map, use getLineMap function instead. + lineMap: number[]; } export interface ScriptReferenceHost { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 7494ec9f6c..b451cac542 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -109,7 +109,7 @@ module ts { // This is a useful function for debugging purposes. export function nodePosToString(node: Node): string { var file = getSourceFileOfNode(node); - var loc = file.getLineAndCharacterFromPosition(node.pos); + var loc = getLineAndCharacterOfPosition(file, node.pos); return file.filename + "(" + loc.line + "," + loc.character + ")"; } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index cfc83af76e..d320ceb0d9 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -391,7 +391,7 @@ module FourSlash { this.currentCaretPosition = pos; var lineStarts = ts.computeLineStarts(this.getCurrentFileContent()); - var lineCharPos = ts.getLineAndCharacterOfPosition(lineStarts, pos); + var lineCharPos = ts.computeLineAndCharacterOfPosition(lineStarts, pos); this.scenarioActions.push(''); } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 97885bdd20..9cebfb2078 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -292,7 +292,7 @@ module Harness.LanguageService { assert.isTrue(line >= 1); assert.isTrue(col >= 1); - return ts.getPositionFromLineAndCharacter(script.lineMap, line, col); + return ts.computePositionFromLineAndCharacter(script.lineMap, line, col); } /** @@ -303,7 +303,7 @@ module Harness.LanguageService { var script: ScriptInfo = this.fileNameToScript[fileName]; assert.isNotNull(script); - var result = ts.getLineAndCharacterOfPosition(script.lineMap, position); + var result = ts.computeLineAndCharacterOfPosition(script.lineMap, position); assert.isTrue(result.line >= 1); assert.isTrue(result.character >= 1); diff --git a/src/services/services.ts b/src/services/services.ts index 1618fb6e27..62d55bb1d6 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -61,6 +61,9 @@ module ts { scriptSnapshot: IScriptSnapshot; getNamedDeclarations(): Declaration[]; + getLineAndCharacterFromPosition(pos: number): LineAndCharacter; + getLineStarts(): number[]; + getPositionFromLineAndCharacter(line: number, character: number): number; } /** @@ -721,18 +724,16 @@ module ts { public filename: string; public text: string; public scriptSnapshot: IScriptSnapshot; + public lineMap: number[]; public statements: NodeArray; public endOfFileToken: Node; // These methods will have their implementation provided by the implementation the // compiler actually exports off of SourceFile. - public getLineAndCharacterFromPosition: (position: number) => LineAndCharacter; - public getPositionFromLineAndCharacter: (line: number, character: number) => number; - public getLineStarts: () => number[]; public getSyntacticDiagnostics: () => Diagnostic[]; public update: (newText: string, textChangeRange: TextChangeRange) => SourceFile; - + public amdDependencies: string[]; public amdModuleName: string; public referencedFiles: FileReference[]; @@ -753,6 +754,18 @@ module ts { private namedDeclarations: Declaration[]; + public getLineAndCharacterFromPosition(position: number): LineAndCharacter { + return getLineAndCharacterOfPosition(this, position); + } + + public getLineStarts(): number[] { + return getLineStarts(this); + } + + public getPositionFromLineAndCharacter(line: number, character: number): number { + return getPositionFromLineAndCharacter(this, line, character); + } + public getNamedDeclarations() { if (!this.namedDeclarations) { var sourceFile = this; From c40977c5fb2fad48f398695c15d0fa634352403c Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 16 Jan 2015 12:32:37 -0800 Subject: [PATCH 2/6] move getSyntacticDiagnostics out of SourceFile --- src/compiler/parser.ts | 22 ++++++++++------------ src/compiler/program.ts | 2 +- src/compiler/types.ts | 10 +++++++--- src/harness/fourslash.ts | 4 ++-- src/services/services.ts | 2 +- tests/cases/unittests/incrementalParser.ts | 4 ++-- 6 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 19efe77a27..fc0086eb7d 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -356,6 +356,16 @@ module ts { forEachChild(sourceFile, walk); } + export function getSyntacticDiagnostics(sourceFile: SourceFile) { + if (!sourceFile.syntacticDiagnostics) { + // Don't bother doing any grammar checks if there are already parser errors. + // Otherwise we may end up with too many cascading errors. + sourceFile.syntacticDiagnostics = sourceFile.referenceDiagnostics.concat(sourceFile.parseDiagnostics); + } + return sourceFile.syntacticDiagnostics; + } + + export function isEvalOrArgumentsIdentifier(node: Node): boolean { return node.kind === SyntaxKind.Identifier && ((node).text === "eval" || (node).text === "arguments"); @@ -610,7 +620,6 @@ module ts { sourceFile.filename = normalizePath(filename); sourceFile.text = sourceText; - sourceFile.getSyntacticDiagnostics = getSyntacticDiagnostics; sourceFile.update = update; processReferenceComments(sourceFile); @@ -4724,17 +4733,6 @@ module ts { ? node : undefined); } - - function getSyntacticDiagnostics() { - if (syntacticDiagnostics === undefined) { - // Don't bother doing any grammar checks if there are already parser errors. - // Otherwise we may end up with too many cascading errors. - syntacticDiagnostics = sourceFile.referenceDiagnostics.concat(sourceFile.parseDiagnostics); - } - - Debug.assert(syntacticDiagnostics !== undefined); - return syntacticDiagnostics; - } } export function isLeftHandSideExpression(expr: Expression): boolean { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index fc3cc0682d..67d05b2c57 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -245,7 +245,7 @@ module ts { else { files.push(file); } - forEach(file.getSyntacticDiagnostics(), e => { + forEach(getSyntacticDiagnostics(file), e => { errors.push(e); }); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9d899ccd21..9f127cf2e5 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -903,12 +903,15 @@ module ts { // missing tokens, or tokens it didn't know how to deal with). parseDiagnostics: Diagnostic[]; - // Returns all syntactic diagnostics (i.e. the reference, parser and grammar diagnostics). - getSyntacticDiagnostics(): Diagnostic[]; + //getSyntacticDiagnostics(): Diagnostic[]; // File level diagnostics reported by the binder. semanticDiagnostics: Diagnostic[]; + // Returns all syntactic diagnostics (i.e. the reference, parser and grammar diagnostics). + // This field should never be used directly, use getSyntacticDiagnostics function instead. + syntacticDiagnostics: Diagnostic[]; + hasNoDefaultLib: boolean; externalModuleIndicator: Node; // The first node that causes this file to be an external module nodeCount: number; @@ -917,7 +920,8 @@ module ts { languageVersion: ScriptTarget; identifiers: Map; - // Stores a line map for the file. This field should never be used directly to obtain line map, use getLineMap function instead. + // Stores a line map for the file. + // This field should never be used directly to obtain line map, use getLineMap function instead. lineMap: number[]; } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index d320ceb0d9..2a2a9cd1c2 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1384,7 +1384,7 @@ module FourSlash { var incrementalSourceFile = this.languageService.getSourceFile(this.activeFile.fileName); Utils.assertInvariants(incrementalSourceFile, /*parent:*/ undefined); - var incrementalSyntaxDiagnostics = incrementalSourceFile.getSyntacticDiagnostics(); + var incrementalSyntaxDiagnostics = ts.getSyntacticDiagnostics(incrementalSourceFile); // Check syntactic structure var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName); @@ -1392,7 +1392,7 @@ module FourSlash { var referenceSourceFile = ts.createLanguageServiceSourceFile( this.activeFile.fileName, createScriptSnapShot(content), ts.ScriptTarget.Latest, /*version:*/ "0", /*isOpen:*/ false, /*setNodeParents:*/ false); - var referenceSyntaxDiagnostics = referenceSourceFile.getSyntacticDiagnostics(); + var referenceSyntaxDiagnostics = ts.getSyntacticDiagnostics(referenceSourceFile); Utils.assertDiagnosticsEquals(incrementalSyntaxDiagnostics, referenceSyntaxDiagnostics); Utils.assertStructuralEquals(incrementalSourceFile, referenceSourceFile); diff --git a/src/services/services.ts b/src/services/services.ts index 62d55bb1d6..e72fb7d323 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -731,13 +731,13 @@ module ts { // These methods will have their implementation provided by the implementation the // compiler actually exports off of SourceFile. - public getSyntacticDiagnostics: () => Diagnostic[]; public update: (newText: string, textChangeRange: TextChangeRange) => SourceFile; public amdDependencies: string[]; public amdModuleName: string; public referencedFiles: FileReference[]; + public syntacticDiagnostics: Diagnostic[]; public referenceDiagnostics: Diagnostic[]; public parseDiagnostics: Diagnostic[]; public semanticDiagnostics: Diagnostic[]; diff --git a/tests/cases/unittests/incrementalParser.ts b/tests/cases/unittests/incrementalParser.ts index a3875cf8e8..80ca539b01 100644 --- a/tests/cases/unittests/incrementalParser.ts +++ b/tests/cases/unittests/incrementalParser.ts @@ -24,8 +24,8 @@ module ts { } function assertSameDiagnostics(file1: SourceFile, file2: SourceFile) { - var diagnostics1 = file1.getSyntacticDiagnostics(); - var diagnostics2 = file2.getSyntacticDiagnostics(); + var diagnostics1 = getSyntacticDiagnostics(file1); + var diagnostics2 = getSyntacticDiagnostics(file2); assert.equal(diagnostics1.length, diagnostics2.length, "diagnostics1.length !== diagnostics2.length"); for (var i = 0, n = diagnostics1.length; i < n; i++) { From cf8c21893a07774c48b6051e48f399905e8421e6 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 16 Jan 2015 16:22:11 -0800 Subject: [PATCH 3/6] moved update function out of SourceFile --- src/compiler/parser.ts | 784 +++++++++++++++++++-------------------- src/compiler/types.ts | 11 - src/services/services.ts | 2 +- 3 files changed, 392 insertions(+), 405 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index fc0086eb7d..c5eecd19d0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -365,6 +365,358 @@ module ts { return sourceFile.syntacticDiagnostics; } + function moveElementEntirelyPastChangeRange(element: IncrementalElement, delta: number) { + if (element.length) { + visitArray(element); + } + else { + visitNode(element); + } + + function visitNode(node: IncrementalNode) { + // Ditch any existing LS children we may have created. This way we can avoid + // moving them forward. + node._children = undefined; + node.pos += delta; + node.end += delta; + + forEachChild(node, visitNode, visitArray); + } + + function visitArray(array: IncrementalNodeArray) { + array.pos += delta; + array.end += delta; + + for (var i = 0, n = array.length; i < n; i++) { + visitNode(array[i]); + } + } + } + + function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { + Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); + Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); + + // We have an element that intersects the change range in some way. It may have its + // start, or its end (or both) in the changed range. We want to adjust any part + // that intersects such that the final tree is in a consistent state. i.e. all + // chlidren have spans within the span of their parent, and all siblings are ordered + // properly. + + // We may need to update both the 'pos' and the 'end' of the element. + + // If the 'pos' is before the start of the change, then we don't need to touch it. + // If it isn't, then the 'pos' must be inside the change. How we update it will + // depend if delta is positive or negative. If delta is positive then we have + // something like: + // + // -------------------AAA----------------- + // -------------------BBBCCCCCCC----------------- + // + // In this case, we consider any node that started in the change range to still be + // starting at the same position. + // + // however, if the delta is negative, then we instead have something like this: + // + // -------------------XXXYYYYYYY----------------- + // -------------------ZZZ----------------- + // + // In this case, any element that started in the 'X' range will keep its position. + // However any element htat started after that will have their pos adjusted to be + // at the end of the new range. i.e. any node that started in the 'Y' range will + // be adjusted to have their start at the end of the 'Z' range. + // + // The element will keep its position if possible. Or Move backward to the new-end + // if it's in the 'Y' range. + element.pos = Math.min(element.pos, changeRangeNewEnd); + + // If the 'end' is after the change range, then we always adjust it by the delta + // amount. However, if the end is in the change range, then how we adjust it + // will depend on if delta is positive or negative. If delta is positive then we + // have something like: + // + // -------------------AAA----------------- + // -------------------BBBCCCCCCC----------------- + // + // In this case, we consider any node that ended inside the change range to keep its + // end position. + // + // however, if the delta is negative, then we instead have something like this: + // + // -------------------XXXYYYYYYY----------------- + // -------------------ZZZ----------------- + // + // In this case, any element that ended in the 'X' range will keep its position. + // However any element htat ended after that will have their pos adjusted to be + // at the end of the new range. i.e. any node that ended in the 'Y' range will + // be adjusted to have their end at the end of the 'Z' range. + if (element.end >= changeRangeOldEnd) { + // Element ends after the change range. Always adjust the end pos. + element.end += delta; + } + else { + // Element ends in the change range. The element will keep its position if + // possible. Or Move backward to the new-end if it's in the 'Y' range. + element.end = Math.min(element.end, changeRangeNewEnd); + } + + Debug.assert(element.pos <= element.end); + if (element.parent) { + Debug.assert(element.pos >= element.parent.pos); + Debug.assert(element.end <= element.parent.end); + } + } + + function updateTokenPositionsAndMarkElements(node: IncrementalNode, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number): void { + visitNode(node); + + function visitNode(child: IncrementalNode) { + if (child.pos > changeRangeOldEnd) { + // Node is entirely past the change range. We need to move both its pos and + // end, forward or backward appropriately. + moveElementEntirelyPastChangeRange(child, delta); + return; + } + + // Check if the element intersects the change range. If it does, then it is not + // reusable. Also, we'll need to recurse to see what constituent portions we may + // be able to use. + var fullEnd = child.end; + if (fullEnd >= changeStart) { + child.intersectsChange = true; + + // Adjust the pos or end (or both) of the intersecting element accordingly. + adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); + forEachChild(child, visitNode, visitArray); + return; + } + + // Otherwise, the node is entirely before the change range. No need to do anything with it. + } + + function visitArray(array: IncrementalNodeArray) { + if (array.pos > changeRangeOldEnd) { + // Array is entirely after the change range. We need to move it, and move any of + // its children. + moveElementEntirelyPastChangeRange(array, delta); + } + else { + // Check if the element intersects the change range. If it does, then it is not + // reusable. Also, we'll need to recurse to see what constituent portions we may + // be able to use. + var fullEnd = array.end; + if (fullEnd >= changeStart) { + array.intersectsChange = true; + + // Adjust the pos or end (or both) of the intersecting array accordingly. + adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); + for (var i = 0, n = array.length; i < n; i++) { + visitNode(array[i]); + } + } + // else { + // Otherwise, the array is entirely before the change range. No need to do anything with it. + // } + } + } + } + + + function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange { + // Consider the following code: + // void foo() { /; } + // + // If the text changes with an insertion of / just before the semicolon then we end up with: + // void foo() { //; } + // + // If we were to just use the changeRange a is, then we would not rescan the { token + // (as it does not intersect the actual original change range). Because an edit may + // change the token touching it, we actually need to look back *at least* one token so + // that the prior token sees that change. + var maxLookahead = 1; + + var start = changeRange.span.start; + + // the first iteration aligns us with the change start. subsequent iteration move us to + // the left by maxLookahead tokens. We only need to do this as long as we're not at the + // start of the tree. + for (var i = 0; start > 0 && i <= maxLookahead; i++) { + var nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start); + var position = nearestNode.pos; + + start = Math.max(0, position - 1); + } + + var finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span)); + var finalLength = changeRange.newLength + (changeRange.span.start - start); + + return createTextChangeRange(finalSpan, finalLength); + } + + function findNearestNodeStartingBeforeOrAtPosition(sourceFile: SourceFile, position: number): Node { + var bestResult: Node = sourceFile; + var lastNodeEntirelyBeforePosition: Node; + + forEachChild(sourceFile, visit); + + if (lastNodeEntirelyBeforePosition) { + var lastChildOfLastEntireNodeBeforePosition = getLastChild(lastNodeEntirelyBeforePosition); + if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) { + bestResult = lastChildOfLastEntireNodeBeforePosition; + } + } + + return bestResult; + + function getLastChild(node: Node): Node { + while (true) { + var lastChild = getLastChildWorker(node); + if (lastChild) { + node = lastChild; + } + else { + return node; + } + } + } + + function getLastChildWorker(node: Node): Node { + var last: Node = undefined; + forEachChild(node, child => { + if (nodeIsPresent(child)) { + last = child; + } + }); + return last; + } + + function visit(child: Node) { + if (nodeIsMissing(child)) { + // Missing nodes are effectively invisible to us. We never even consider them + // When trying to find the nearest node before us. + return; + } + + // If the child intersects this position, then this node is currently the nearest + // node that starts before the position. + if (child.pos <= position) { + if (child.pos >= bestResult.pos) { + // This node starts before the position, and is closer to the position than + // the previous best node we found. It is now the new best node. + bestResult = child; + } + + // Now, the node may overlap the position, or it may end entirely before the + // position. If it overlaps with the position, then either it, or one of its + // children must be the nearest node before the position. So we can just + // recurse into this child to see if we can find something better. + if (position < child.end) { + // The nearest node is either this child, or one of the children inside + // of it. We've already marked this child as the best so far. Recurse + // in case one of the children is better. + forEachChild(child, visit); + + // Once we look at the children of this node, then there's no need to + // continue any further. + return true; + } + else { + Debug.assert(child.end <= position); + // The child ends entirely before this position. Say you have the following + // (where $ is the position) + // + // ? $ : <...> <...> + // + // We would want to find the nearest preceding node in "complex expr 2". + // To support that, we keep track of this node, and once we're done searching + // for a best node, we recurse down this node to see if we can find a good + // result in it. + // + // This approach allows us to quickly skip over nodes that are entirely + // before the position, while still allowing us to find any nodes in the + // last one that might be what we want. + lastNodeEntirelyBeforePosition = child; + } + } + else { + Debug.assert(child.pos > position); + // We're now at a node that is entirely past the position we're searching for. + // This node (and all following nodes) could never contribute to the result, + // so just skip them by returning 'true' here. + return true; + } + } + } + + + // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter + // indicates what changed between the 'text' that this SourceFile has and the 'newText'. + // The SourceFile will be created with the compiler attempting to reuse as many nodes from + // this file as possible. + // + // Note: this function mutates nodes from this SourceFile. That means any existing nodes + // from this SourceFile that are being held onto may change as a result (including + // becoming detached from any SourceFile). It is recommended that this SourceFile not + // be used once 'update' is called on it. + export function update(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile { + if (textChangeRangeIsUnchanged(textChangeRange)) { + // if the text didn't change, then we can just return our current source file as-is. + return sourceFile; + } + + if (sourceFile.statements.length === 0) { + // If we don't have any statements in the current source file, then there's no real + // way to incrementally parse. So just do a full parse instead. + return parseSourceFile(sourceFile.filename, newText, sourceFile.languageVersion,/*syntaxCursor*/ undefined, /*setNodeParents*/ true) + } + + var syntaxCursor = createSyntaxCursor(sourceFile); + + // Make the actual change larger so that we know to reparse anything whose lookahead + // might have intersected the change. + var changeRange = extendToAffectedRange(sourceFile, textChangeRange); + + // The is the amount the nodes after the edit range need to be adjusted. It can be + // positive (if the edit added characters), negative (if the edit deleted characters) + // or zero (if this was a pure overwrite with nothing added/removed). + var delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length; + + // If we added or removed characters during the edit, then we need to go and adjust all + // the nodes after the edit. Those nodes may move forward down (if we inserted chars) + // or they may move backward (if we deleted chars). + // + // Doing this helps us out in two ways. First, it means that any nodes/tokens we want + // to reuse are already at the appropriate position in the new text. That way when we + // reuse them, we don't have to figure out if they need to be adjusted. Second, it makes + // it very easy to determine if we can reuse a node. If the node's position is at where + // we are in the text, then we can reuse it. Otherwise we can't. If hte node's position + // is ahead of us, then we'll need to rescan tokens. If the node's position is behind + // us, then we'll need to skip it or crumble it as appropriate + // + // We will also adjust the positions of nodes that intersect the change range as well. + // By doing this, we ensure that all the positions in the old tree are consistent, not + // just the positions of nodes entirely before/after the change range. By being + // consistent, we can then easily map from positions to nodes in the old tree easily. + // + // Also, mark any syntax elements that intersect the changed span. We know, up front, + // that we cannot reuse these elements. + updateTokenPositionsAndMarkElements(sourceFile, + changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta); + + // Now that we've set up our internal incremental state just proceed and parse the + // source file in the normal fashion. When possible the parser will retrieve and + // reuse nodes from the old tree. + // + // Note: passing in 'true' for setNodeParents is very important. When incrementally + // parsing, we will be reusing nodes from the old tree, and placing it into new + // parents. If we don't set the parents now, we'll end up with an observably + // inconsistent tree. Setting the parents on the new tree should be very fast. We + // will immediately bail out of walking any subtrees when we can see that their parents + // are already correct. + var result = parseSourceFile(sourceFile.filename, newText, sourceFile.languageVersion, syntaxCursor, /* setParentNode */ true) + + return result; + } export function isEvalOrArgumentsIdentifier(node: Node): boolean { return node.kind === SyntaxKind.Identifier && @@ -505,16 +857,27 @@ module ts { } } } - export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false): SourceFile { - var parsingContext: ParsingContext; - var identifiers: Map; + return parseSourceFile(filename, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes); + } + + function parseSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: SyntaxCursor, setParentNodes = false): SourceFile { + var parsingContext: ParsingContext = 0; + var identifiers: Map = {}; var identifierCount = 0; var nodeCount = 0; - var syntacticDiagnostics: Diagnostic[]; var scanner: Scanner; var token: SyntaxKind; - var syntaxCursor: SyntaxCursor; + + var sourceFile = createNode(SyntaxKind.SourceFile, /*pos*/ 0); + + sourceFile.pos = sourceFile.end = 0; + sourceFile.referenceDiagnostics = []; + sourceFile.parseDiagnostics = []; + sourceFile.semanticDiagnostics = []; + sourceFile.languageVersion = languageVersion; + sourceFile.filename = normalizePath(filename); + sourceFile.flags = fileExtensionIs(sourceFile.filename, ".d.ts") ? NodeFlags.DeclarationFile : 0; // Flags that dictate what parsing context we're in. For example: // Whether or not we are in strict parsing mode. All that changes in strict parsing mode is @@ -562,7 +925,7 @@ module ts { // Note: it should not be necessary to save/restore these flags during speculative/lookahead // parsing. These context flags are naturally stored and restored through normal recursive // descent parsing and unwinding. - var contextFlags: ParserContextFlags; + var contextFlags: ParserContextFlags = 0; // Whether or not we've had a parse error since creating the last AST node. If we have // encountered an error, it will be stored on the next AST node we create. Parse errors @@ -591,401 +954,36 @@ module ts { // // Note: any errors at the end of the file that do not precede a regular node, should get // attached to the EOF token. - var parseErrorBeforeNextFinishedNode: boolean; + var parseErrorBeforeNextFinishedNode: boolean = false; - var sourceFile: SourceFile; + sourceFile.syntacticDiagnostics = undefined; + sourceFile.referenceDiagnostics = []; + sourceFile.parseDiagnostics = []; + sourceFile.semanticDiagnostics = []; + sourceFile.end = sourceText.length; + sourceFile.text = sourceText; - return parseSourceFile(sourceText, setParentNodes); + // Create and prime the scanner before parsing the source elements. + scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError); + token = nextToken(); - function parseSourceFile(text: string, setParentNodes: boolean): SourceFile { - // Set our initial state before parsing. - sourceText = text; - parsingContext = 0; - identifiers = {}; - syntacticDiagnostics = undefined; - contextFlags = 0; - parseErrorBeforeNextFinishedNode = false; + processReferenceComments(sourceFile); - sourceFile = createNode(SyntaxKind.SourceFile, 0); - sourceFile.referenceDiagnostics = []; - sourceFile.parseDiagnostics = []; - sourceFile.semanticDiagnostics = []; + sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement); + Debug.assert(token === SyntaxKind.EndOfFileToken); + sourceFile.endOfFileToken = parseTokenNode(); - // Create and prime the scanner before parsing the source elements. - scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError); - token = nextToken(); + setExternalModuleIndicator(sourceFile); - sourceFile.flags = fileExtensionIs(filename, ".d.ts") ? NodeFlags.DeclarationFile : 0; - sourceFile.end = sourceText.length; - sourceFile.filename = normalizePath(filename); - sourceFile.text = sourceText; + sourceFile.nodeCount = nodeCount; + sourceFile.identifierCount = identifierCount; + sourceFile.identifiers = identifiers; - sourceFile.update = update; - - processReferenceComments(sourceFile); - - sourceFile.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement); - Debug.assert(token === SyntaxKind.EndOfFileToken); - sourceFile.endOfFileToken = parseTokenNode(); - - setExternalModuleIndicator(sourceFile); - - sourceFile.nodeCount = nodeCount; - sourceFile.identifierCount = identifierCount; - sourceFile.languageVersion = languageVersion; - sourceFile.identifiers = identifiers; - - if (setParentNodes) { - fixupParentReferences(sourceFile); - } - - return sourceFile; + if (setParentNodes) { + fixupParentReferences(sourceFile); } - function update(newText: string, textChangeRange: TextChangeRange) { - if (textChangeRangeIsUnchanged(textChangeRange)) { - // if the text didn't change, then we can just return our current source file as-is. - return sourceFile; - } - - if (sourceFile.statements.length === 0) { - // If we don't have any statements in the current source file, then there's no real - // way to incrementally parse. So just do a full parse instead. - return parseSourceFile(newText, /*setNodeParents*/ true); - } - - syntaxCursor = createSyntaxCursor(sourceFile); - - // Make the actual change larger so that we know to reparse anything whose lookahead - // might have intersected the change. - var changeRange = extendToAffectedRange(textChangeRange); - - // The is the amount the nodes after the edit range need to be adjusted. It can be - // positive (if the edit added characters), negative (if the edit deleted characters) - // or zero (if this was a pure overwrite with nothing added/removed). - var delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length; - - // If we added or removed characters during the edit, then we need to go and adjust all - // the nodes after the edit. Those nodes may move forward down (if we inserted chars) - // or they may move backward (if we deleted chars). - // - // Doing this helps us out in two ways. First, it means that any nodes/tokens we want - // to reuse are already at the appropriate position in the new text. That way when we - // reuse them, we don't have to figure out if they need to be adjusted. Second, it makes - // it very easy to determine if we can reuse a node. If the node's position is at where - // we are in the text, then we can reuse it. Otherwise we can't. If hte node's position - // is ahead of us, then we'll need to rescan tokens. If the node's position is behind - // us, then we'll need to skip it or crumble it as appropriate - // - // We will also adjust the positions of nodes that intersect the change range as well. - // By doing this, we ensure that all the positions in the old tree are consistent, not - // just the positions of nodes entirely before/after the change range. By being - // consistent, we can then easily map from positions to nodes in the old tree easily. - // - // Also, mark any syntax elements that intersect the changed span. We know, up front, - // that we cannot reuse these elements. - updateTokenPositionsAndMarkElements(sourceFile, - changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta); - - // Now that we've set up our internal incremental state just proceed and parse the - // source file in the normal fashion. When possible the parser will retrieve and - // reuse nodes from the old tree. - // - // Note: passing in 'true' for setNodeParents is very important. When incrementally - // parsing, we will be reusing nodes from the old tree, and placing it into new - // parents. If we don't set the parents now, we'll end up with an observably - // inconsistent tree. Setting the parents on the new tree should be very fast. We - // will immediately bail out of walking any subtrees when we can see that their parents - // are already correct. - var result = parseSourceFile(newText, /*setNodeParents*/ true); - - // Clear out the syntax cursor so it doesn't keep anything alive longer than it should. - syntaxCursor = undefined; - - return result; - } - - function updateTokenPositionsAndMarkElements(node: IncrementalNode, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number): void { - visitNode(node); - - function visitNode(child: IncrementalNode) { - if (child.pos > changeRangeOldEnd) { - // Node is entirely past the change range. We need to move both its pos and - // end, forward or backward appropriately. - moveElementEntirelyPastChangeRange(child, delta); - return; - } - - // Check if the element intersects the change range. If it does, then it is not - // reusable. Also, we'll need to recurse to see what constituent portions we may - // be able to use. - var fullEnd = child.end; - if (fullEnd >= changeStart) { - child.intersectsChange = true; - - // Adjust the pos or end (or both) of the intersecting element accordingly. - adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); - forEachChild(child, visitNode, visitArray); - return; - } - - // Otherwise, the node is entirely before the change range. No need to do anything with it. - } - - function visitArray(array: IncrementalNodeArray) { - if (array.pos > changeRangeOldEnd) { - // Array is entirely after the change range. We need to move it, and move any of - // its children. - moveElementEntirelyPastChangeRange(array, delta); - } - else { - // Check if the element intersects the change range. If it does, then it is not - // reusable. Also, we'll need to recurse to see what constituent portions we may - // be able to use. - var fullEnd = array.end; - if (fullEnd >= changeStart) { - array.intersectsChange = true; - - // Adjust the pos or end (or both) of the intersecting array accordingly. - adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); - for (var i = 0, n = array.length; i < n; i++) { - visitNode(array[i]); - } - } - // else { - // Otherwise, the array is entirely before the change range. No need to do anything with it. - // } - } - } - } - - function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) { - Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range"); - Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range"); - - // We have an element that intersects the change range in some way. It may have its - // start, or its end (or both) in the changed range. We want to adjust any part - // that intersects such that the final tree is in a consistent state. i.e. all - // chlidren have spans within the span of their parent, and all siblings are ordered - // properly. - - // We may need to update both the 'pos' and the 'end' of the element. - - // If the 'pos' is before the start of the change, then we don't need to touch it. - // If it isn't, then the 'pos' must be inside the change. How we update it will - // depend if delta is positive or negative. If delta is positive then we have - // something like: - // - // -------------------AAA----------------- - // -------------------BBBCCCCCCC----------------- - // - // In this case, we consider any node that started in the change range to still be - // starting at the same position. - // - // however, if the delta is negative, then we instead have something like this: - // - // -------------------XXXYYYYYYY----------------- - // -------------------ZZZ----------------- - // - // In this case, any element that started in the 'X' range will keep its position. - // However any element htat started after that will have their pos adjusted to be - // at the end of the new range. i.e. any node that started in the 'Y' range will - // be adjusted to have their start at the end of the 'Z' range. - // - // The element will keep its position if possible. Or Move backward to the new-end - // if it's in the 'Y' range. - element.pos = Math.min(element.pos, changeRangeNewEnd); - - // If the 'end' is after the change range, then we always adjust it by the delta - // amount. However, if the end is in the change range, then how we adjust it - // will depend on if delta is positive or negative. If delta is positive then we - // have something like: - // - // -------------------AAA----------------- - // -------------------BBBCCCCCCC----------------- - // - // In this case, we consider any node that ended inside the change range to keep its - // end position. - // - // however, if the delta is negative, then we instead have something like this: - // - // -------------------XXXYYYYYYY----------------- - // -------------------ZZZ----------------- - // - // In this case, any element that ended in the 'X' range will keep its position. - // However any element htat ended after that will have their pos adjusted to be - // at the end of the new range. i.e. any node that ended in the 'Y' range will - // be adjusted to have their end at the end of the 'Z' range. - if (element.end >= changeRangeOldEnd) { - // Element ends after the change range. Always adjust the end pos. - element.end += delta; - } - else { - // Element ends in the change range. The element will keep its position if - // possible. Or Move backward to the new-end if it's in the 'Y' range. - element.end = Math.min(element.end, changeRangeNewEnd); - } - - Debug.assert(element.pos <= element.end); - if (element.parent) { - Debug.assert(element.pos >= element.parent.pos); - Debug.assert(element.end <= element.parent.end); - } - } - - function moveElementEntirelyPastChangeRange(element: IncrementalElement, delta: number) { - if (element.length) { - visitArray(element); - } - else { - visitNode(element); - } - - function visitNode(node: IncrementalNode) { - // Ditch any existing LS children we may have created. This way we can avoid - // moving them forward. - node._children = undefined; - node.pos += delta; - node.end += delta; - - forEachChild(node, visitNode, visitArray); - } - - function visitArray(array: IncrementalNodeArray) { - array.pos += delta; - array.end += delta; - - for (var i = 0, n = array.length; i < n; i++) { - visitNode(array[i]); - } - } - } - - function extendToAffectedRange(changeRange: TextChangeRange): TextChangeRange { - // Consider the following code: - // void foo() { /; } - // - // If the text changes with an insertion of / just before the semicolon then we end up with: - // void foo() { //; } - // - // If we were to just use the changeRange a is, then we would not rescan the { token - // (as it does not intersect the actual original change range). Because an edit may - // change the token touching it, we actually need to look back *at least* one token so - // that the prior token sees that change. - var maxLookahead = 1; - - var start = changeRange.span.start; - - // the first iteration aligns us with the change start. subsequent iteration move us to - // the left by maxLookahead tokens. We only need to do this as long as we're not at the - // start of the tree. - for (var i = 0; start > 0 && i <= maxLookahead; i++) { - var nearestNode = findNearestNodeStartingBeforeOrAtPosition(start); - var position = nearestNode.pos; - - start = Math.max(0, position - 1); - } - - var finalSpan = createTextSpanFromBounds(start, textSpanEnd(changeRange.span)); - var finalLength = changeRange.newLength + (changeRange.span.start - start); - - return createTextChangeRange(finalSpan, finalLength); - } - - function findNearestNodeStartingBeforeOrAtPosition(position: number): Node { - var bestResult: Node = sourceFile; - var lastNodeEntirelyBeforePosition: Node; - - forEachChild(sourceFile, visit); - - if (lastNodeEntirelyBeforePosition) { - var lastChildOfLastEntireNodeBeforePosition = getLastChild(lastNodeEntirelyBeforePosition); - if (lastChildOfLastEntireNodeBeforePosition.pos > bestResult.pos) { - bestResult = lastChildOfLastEntireNodeBeforePosition; - } - } - - return bestResult; - - function getLastChild(node: Node): Node { - while (true) { - var lastChild = getLastChildWorker(node); - if (lastChild) { - node = lastChild; - } - else { - return node; - } - } - } - - function getLastChildWorker(node: Node): Node { - var last:Node = undefined; - forEachChild(node, child => { - if (nodeIsPresent(child)) { - last = child; - } - }); - return last; - } - - function visit(child: Node) { - if (nodeIsMissing(child)) { - // Missing nodes are effectively invisible to us. We never even consider them - // When trying to find the nearest node before us. - return; - } - - // If the child intersects this position, then this node is currently the nearest - // node that starts before the position. - if (child.pos <= position) { - if (child.pos >= bestResult.pos) { - // This node starts before the position, and is closer to the position than - // the previous best node we found. It is now the new best node. - bestResult = child; - } - - // Now, the node may overlap the position, or it may end entirely before the - // position. If it overlaps with the position, then either it, or one of its - // children must be the nearest node before the position. So we can just - // recurse into this child to see if we can find something better. - if (position < child.end) { - // The nearest node is either this child, or one of the children inside - // of it. We've already marked this child as the best so far. Recurse - // in case one of the children is better. - forEachChild(child, visit); - - // Once we look at the children of this node, then there's no need to - // continue any further. - return true; - } - else { - Debug.assert(child.end <= position); - // The child ends entirely before this position. Say you have the following - // (where $ is the position) - // - // ? $ : <...> <...> - // - // We would want to find the nearest preceding node in "complex expr 2". - // To support that, we keep track of this node, and once we're done searching - // for a best node, we recurse down this node to see if we can find a good - // result in it. - // - // This approach allows us to quickly skip over nodes that are entirely - // before the position, while still allowing us to find any nodes in the - // last one that might be what we want. - lastNodeEntirelyBeforePosition = child; - } - } - else { - Debug.assert(child.pos > position); - // We're now at a node that is entirely past the position we're searching for. - // This node (and all following nodes) could never contribute to the result, - // so just skip them by returning 'true' here. - return true; - } - } - } + return sourceFile; function setContextFlag(val: Boolean, flag: ParserContextFlags) { if (val) { @@ -4670,7 +4668,7 @@ module ts { } function processReferenceComments(sourceFile: SourceFile): void { - var triviaScanner = createScanner(languageVersion, /*skipTrivia*/false, sourceText); + var triviaScanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/false, sourceText); var referencedFiles: FileReference[] = []; var amdDependencies: string[] = []; var amdModuleName: string; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9f127cf2e5..82b0a526de 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -881,17 +881,6 @@ module ts { filename: string; text: string; - // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter - // indicates what changed between the 'text' that this SourceFile has and the 'newText'. - // The SourceFile will be created with the compiler attempting to reuse as many nodes from - // this file as possible. - // - // Note: this function mutates nodes from this SourceFile. That means any existing nodes - // from this SourceFile that are being held onto may change as a result (including - // becoming detached from any SourceFile). It is recommended that this SourceFile not - // be used once 'update' is called on it. - update(newText: string, textChangeRange: TextChangeRange): SourceFile; - amdDependencies: string[]; amdModuleName: string; referencedFiles: FileReference[]; diff --git a/src/services/services.ts b/src/services/services.ts index e72fb7d323..79a652bb09 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1587,7 +1587,7 @@ module ts { if (version !== sourceFile.version || isOpen != sourceFile.isOpen) { // Once incremental parsing is ready, then just call into this function. if (!disableIncrementalParsing) { - var newSourceFile = sourceFile.update(scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange); + var newSourceFile = update(sourceFile, scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange); setSourceFileFields(newSourceFile, scriptSnapshot, version, isOpen); return newSourceFile; } From edc65e1753a3e8ae1911a0b9e07b4f2f613de762 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Fri, 16 Jan 2015 18:19:47 -0800 Subject: [PATCH 4/6] addressed CR feedback: renamed update to updateSourceFile --- src/compiler/parser.ts | 2 +- src/services/services.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c5eecd19d0..9ad9067d6f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -658,7 +658,7 @@ module ts { // from this SourceFile that are being held onto may change as a result (including // becoming detached from any SourceFile). It is recommended that this SourceFile not // be used once 'update' is called on it. - export function update(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile { + export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile { if (textChangeRangeIsUnchanged(textChangeRange)) { // if the text didn't change, then we can just return our current source file as-is. return sourceFile; diff --git a/src/services/services.ts b/src/services/services.ts index 79a652bb09..1b94899a1f 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1587,7 +1587,7 @@ module ts { if (version !== sourceFile.version || isOpen != sourceFile.isOpen) { // Once incremental parsing is ready, then just call into this function. if (!disableIncrementalParsing) { - var newSourceFile = update(sourceFile, scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange); + var newSourceFile = updateSourceFile(sourceFile, scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange); setSourceFileFields(newSourceFile, scriptSnapshot, version, isOpen); return newSourceFile; } From e15f9349f9b4237c336a8c50d8b188f94fb22af0 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Thu, 22 Jan 2015 11:10:12 -0800 Subject: [PATCH 5/6] moved all methods of SourceFile to the part exposed on the services layer --- src/services/services.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 1b94899a1f..55aa3d7b7c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -64,6 +64,8 @@ module ts { getLineAndCharacterFromPosition(pos: number): LineAndCharacter; getLineStarts(): number[]; getPositionFromLineAndCharacter(line: number, character: number): number; + getSyntacticDiagnostics(): Diagnostic[]; + update(newText: string, textChangeRange: TextChangeRange): SourceFile; } /** @@ -729,10 +731,6 @@ module ts { public statements: NodeArray; public endOfFileToken: Node; - // These methods will have their implementation provided by the implementation the - // compiler actually exports off of SourceFile. - public update: (newText: string, textChangeRange: TextChangeRange) => SourceFile; - public amdDependencies: string[]; public amdModuleName: string; public referencedFiles: FileReference[]; @@ -754,6 +752,14 @@ module ts { private namedDeclarations: Declaration[]; + public getSyntacticDiagnostics(): Diagnostic[]{ + return getSyntacticDiagnostics(this); + } + + public update(newText: string, textChangeRange: TextChangeRange): SourceFile { + return updateSourceFile(this, newText, textChangeRange); + } + public getLineAndCharacterFromPosition(position: number): LineAndCharacter { return getLineAndCharacterOfPosition(this, position); } From 45defa87418a9dd9da62c28510d302b3961d0a7e Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Tue, 3 Feb 2015 11:33:56 -0800 Subject: [PATCH 6/6] updated tests --- .../baselines/reference/APISample_compile.js | 25 ++-- .../reference/APISample_compile.types | 111 +++++++++++------- tests/baselines/reference/APISample_linter.js | 25 ++-- .../reference/APISample_linter.types | 111 +++++++++++------- .../reference/APISample_transform.js | 25 ++-- .../reference/APISample_transform.types | 111 +++++++++++------- .../baselines/reference/APISample_watcher.js | 25 ++-- .../reference/APISample_watcher.types | 111 +++++++++++------- 8 files changed, 336 insertions(+), 208 deletions(-) diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index f70ee02415..f6a86d4c24 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -725,17 +725,13 @@ declare module "typescript" { endOfFileToken: Node; filename: string; text: string; - getLineAndCharacterFromPosition(position: number): LineAndCharacter; - getPositionFromLineAndCharacter(line: number, character: number): number; - getLineStarts(): number[]; - update(newText: string, textChangeRange: TextChangeRange): SourceFile; amdDependencies: string[]; amdModuleName: string; referencedFiles: FileReference[]; referenceDiagnostics: Diagnostic[]; parseDiagnostics: Diagnostic[]; - getSyntacticDiagnostics(): Diagnostic[]; semanticDiagnostics: Diagnostic[]; + syntacticDiagnostics: Diagnostic[]; hasNoDefaultLib: boolean; externalModuleIndicator: Node; nodeCount: number; @@ -743,6 +739,7 @@ declare module "typescript" { symbolCount: number; languageVersion: ScriptTarget; identifiers: Map; + lineMap: number[]; } interface ScriptReferenceHost { getCompilerOptions(): CompilerOptions; @@ -1393,15 +1390,14 @@ declare module "typescript" { } function tokenToString(t: SyntaxKind): string; function computeLineStarts(text: string): number[]; - function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; - function getLineAndCharacterOfPosition(lineStarts: number[], position: number): { - line: number; - character: number; - }; - function positionToLineAndCharacter(text: string, pos: number): { + function getPositionFromLineAndCharacter(sourceFile: SourceFile, line: number, character: number): number; + function computePositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; + function getLineStarts(sourceFile: SourceFile): number[]; + function computeLineAndCharacterOfPosition(lineStarts: number[], position: number): { line: number; character: number; }; + function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter; function isWhiteSpace(ch: number): boolean; function isLineBreak(ch: number): boolean; function isOctalDigit(ch: number): boolean; @@ -1417,6 +1413,8 @@ declare module "typescript" { function createNode(kind: SyntaxKind): Node; function forEachChild(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T; function modifierToFlag(token: SyntaxKind): NodeFlags; + function getSyntacticDiagnostics(sourceFile: SourceFile): Diagnostic[]; + function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile; function isEvalOrArgumentsIdentifier(node: Node): boolean; function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes?: boolean): SourceFile; function isLeftHandSideExpression(expr: Expression): boolean; @@ -1476,6 +1474,11 @@ declare module "typescript" { scriptSnapshot: IScriptSnapshot; nameTable: Map; getNamedDeclarations(): Declaration[]; + getLineAndCharacterFromPosition(pos: number): LineAndCharacter; + getLineStarts(): number[]; + getPositionFromLineAndCharacter(line: number, character: number): number; + getSyntacticDiagnostics(): Diagnostic[]; + update(newText: string, textChangeRange: TextChangeRange): SourceFile; } /** * Represents an immutable snapshot of a script at a specified time.Once acquired, the diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index 090c42a721..4ef90c6d11 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -90,11 +90,11 @@ export function compile(filenames: string[], options: ts.CompilerOptions): void var lineChar = diagnostic.file.getLineAndCharacterFromPosition(diagnostic.start); >lineChar : ts.LineAndCharacter >diagnostic.file.getLineAndCharacterFromPosition(diagnostic.start) : ts.LineAndCharacter ->diagnostic.file.getLineAndCharacterFromPosition : (position: number) => ts.LineAndCharacter +>diagnostic.file.getLineAndCharacterFromPosition : (pos: number) => ts.LineAndCharacter >diagnostic.file : ts.SourceFile >diagnostic : ts.Diagnostic >file : ts.SourceFile ->getLineAndCharacterFromPosition : (position: number) => ts.LineAndCharacter +>getLineAndCharacterFromPosition : (pos: number) => ts.LineAndCharacter >diagnostic.start : number >diagnostic : ts.Diagnostic >start : number @@ -2209,26 +2209,6 @@ declare module "typescript" { text: string; >text : string - getLineAndCharacterFromPosition(position: number): LineAndCharacter; ->getLineAndCharacterFromPosition : (position: number) => LineAndCharacter ->position : number ->LineAndCharacter : LineAndCharacter - - getPositionFromLineAndCharacter(line: number, character: number): number; ->getPositionFromLineAndCharacter : (line: number, character: number) => number ->line : number ->character : number - - getLineStarts(): number[]; ->getLineStarts : () => number[] - - update(newText: string, textChangeRange: TextChangeRange): SourceFile; ->update : (newText: string, textChangeRange: TextChangeRange) => SourceFile ->newText : string ->textChangeRange : TextChangeRange ->TextChangeRange : TextChangeRange ->SourceFile : SourceFile - amdDependencies: string[]; >amdDependencies : string[] @@ -2245,14 +2225,14 @@ declare module "typescript" { parseDiagnostics: Diagnostic[]; >parseDiagnostics : Diagnostic[] ->Diagnostic : Diagnostic - - getSyntacticDiagnostics(): Diagnostic[]; ->getSyntacticDiagnostics : () => Diagnostic[] >Diagnostic : Diagnostic semanticDiagnostics: Diagnostic[]; >semanticDiagnostics : Diagnostic[] +>Diagnostic : Diagnostic + + syntacticDiagnostics: Diagnostic[]; +>syntacticDiagnostics : Diagnostic[] >Diagnostic : Diagnostic hasNoDefaultLib: boolean; @@ -2278,6 +2258,9 @@ declare module "typescript" { identifiers: Map; >identifiers : Map >Map : Map + + lineMap: number[]; +>lineMap : number[] } interface ScriptReferenceHost { >ScriptReferenceHost : ScriptReferenceHost @@ -4446,14 +4429,26 @@ declare module "typescript" { >computeLineStarts : (text: string) => number[] >text : string - function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; ->getPositionFromLineAndCharacter : (lineStarts: number[], line: number, character: number) => number + function getPositionFromLineAndCharacter(sourceFile: SourceFile, line: number, character: number): number; +>getPositionFromLineAndCharacter : (sourceFile: SourceFile, line: number, character: number) => number +>sourceFile : SourceFile +>SourceFile : SourceFile +>line : number +>character : number + + function computePositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; +>computePositionFromLineAndCharacter : (lineStarts: number[], line: number, character: number) => number >lineStarts : number[] >line : number >character : number - function getLineAndCharacterOfPosition(lineStarts: number[], position: number): { ->getLineAndCharacterOfPosition : (lineStarts: number[], position: number) => { line: number; character: number; } + function getLineStarts(sourceFile: SourceFile): number[]; +>getLineStarts : (sourceFile: SourceFile) => number[] +>sourceFile : SourceFile +>SourceFile : SourceFile + + function computeLineAndCharacterOfPosition(lineStarts: number[], position: number): { +>computeLineAndCharacterOfPosition : (lineStarts: number[], position: number) => { line: number; character: number; } >lineStarts : number[] >position : number @@ -4464,18 +4459,13 @@ declare module "typescript" { >character : number }; - function positionToLineAndCharacter(text: string, pos: number): { ->positionToLineAndCharacter : (text: string, pos: number) => { line: number; character: number; } ->text : string ->pos : number + function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter; +>getLineAndCharacterOfPosition : (sourceFile: SourceFile, position: number) => LineAndCharacter +>sourceFile : SourceFile +>SourceFile : SourceFile +>position : number +>LineAndCharacter : LineAndCharacter - line: number; ->line : number - - character: number; ->character : number - - }; function isWhiteSpace(ch: number): boolean; >isWhiteSpace : (ch: number) => boolean >ch : number @@ -4562,6 +4552,21 @@ declare module "typescript" { >SyntaxKind : SyntaxKind >NodeFlags : NodeFlags + function getSyntacticDiagnostics(sourceFile: SourceFile): Diagnostic[]; +>getSyntacticDiagnostics : (sourceFile: SourceFile) => Diagnostic[] +>sourceFile : SourceFile +>SourceFile : SourceFile +>Diagnostic : Diagnostic + + function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile; +>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange) => SourceFile +>sourceFile : SourceFile +>SourceFile : SourceFile +>newText : string +>textChangeRange : TextChangeRange +>TextChangeRange : TextChangeRange +>SourceFile : SourceFile + function isEvalOrArgumentsIdentifier(node: Node): boolean; >isEvalOrArgumentsIdentifier : (node: Node) => boolean >node : Node @@ -4783,6 +4788,30 @@ declare module "typescript" { getNamedDeclarations(): Declaration[]; >getNamedDeclarations : () => Declaration[] >Declaration : Declaration + + getLineAndCharacterFromPosition(pos: number): LineAndCharacter; +>getLineAndCharacterFromPosition : (pos: number) => LineAndCharacter +>pos : number +>LineAndCharacter : LineAndCharacter + + getLineStarts(): number[]; +>getLineStarts : () => number[] + + getPositionFromLineAndCharacter(line: number, character: number): number; +>getPositionFromLineAndCharacter : (line: number, character: number) => number +>line : number +>character : number + + getSyntacticDiagnostics(): Diagnostic[]; +>getSyntacticDiagnostics : () => Diagnostic[] +>Diagnostic : Diagnostic + + update(newText: string, textChangeRange: TextChangeRange): SourceFile; +>update : (newText: string, textChangeRange: TextChangeRange) => SourceFile +>newText : string +>textChangeRange : TextChangeRange +>TextChangeRange : TextChangeRange +>SourceFile : SourceFile } /** * Represents an immutable snapshot of a script at a specified time.Once acquired, the diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index b3905862c6..aef5c70349 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -754,17 +754,13 @@ declare module "typescript" { endOfFileToken: Node; filename: string; text: string; - getLineAndCharacterFromPosition(position: number): LineAndCharacter; - getPositionFromLineAndCharacter(line: number, character: number): number; - getLineStarts(): number[]; - update(newText: string, textChangeRange: TextChangeRange): SourceFile; amdDependencies: string[]; amdModuleName: string; referencedFiles: FileReference[]; referenceDiagnostics: Diagnostic[]; parseDiagnostics: Diagnostic[]; - getSyntacticDiagnostics(): Diagnostic[]; semanticDiagnostics: Diagnostic[]; + syntacticDiagnostics: Diagnostic[]; hasNoDefaultLib: boolean; externalModuleIndicator: Node; nodeCount: number; @@ -772,6 +768,7 @@ declare module "typescript" { symbolCount: number; languageVersion: ScriptTarget; identifiers: Map; + lineMap: number[]; } interface ScriptReferenceHost { getCompilerOptions(): CompilerOptions; @@ -1422,15 +1419,14 @@ declare module "typescript" { } function tokenToString(t: SyntaxKind): string; function computeLineStarts(text: string): number[]; - function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; - function getLineAndCharacterOfPosition(lineStarts: number[], position: number): { - line: number; - character: number; - }; - function positionToLineAndCharacter(text: string, pos: number): { + function getPositionFromLineAndCharacter(sourceFile: SourceFile, line: number, character: number): number; + function computePositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; + function getLineStarts(sourceFile: SourceFile): number[]; + function computeLineAndCharacterOfPosition(lineStarts: number[], position: number): { line: number; character: number; }; + function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter; function isWhiteSpace(ch: number): boolean; function isLineBreak(ch: number): boolean; function isOctalDigit(ch: number): boolean; @@ -1446,6 +1442,8 @@ declare module "typescript" { function createNode(kind: SyntaxKind): Node; function forEachChild(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T; function modifierToFlag(token: SyntaxKind): NodeFlags; + function getSyntacticDiagnostics(sourceFile: SourceFile): Diagnostic[]; + function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile; function isEvalOrArgumentsIdentifier(node: Node): boolean; function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes?: boolean): SourceFile; function isLeftHandSideExpression(expr: Expression): boolean; @@ -1505,6 +1503,11 @@ declare module "typescript" { scriptSnapshot: IScriptSnapshot; nameTable: Map; getNamedDeclarations(): Declaration[]; + getLineAndCharacterFromPosition(pos: number): LineAndCharacter; + getLineStarts(): number[]; + getPositionFromLineAndCharacter(line: number, character: number): number; + getSyntacticDiagnostics(): Diagnostic[]; + update(newText: string, textChangeRange: TextChangeRange): SourceFile; } /** * Represents an immutable snapshot of a script at a specified time.Once acquired, the diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 5f613ec140..957ccd3c01 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -227,9 +227,9 @@ export function delint(sourceFile: ts.SourceFile) { var lineChar = sourceFile.getLineAndCharacterFromPosition(node.getStart()); >lineChar : ts.LineAndCharacter >sourceFile.getLineAndCharacterFromPosition(node.getStart()) : ts.LineAndCharacter ->sourceFile.getLineAndCharacterFromPosition : (position: number) => ts.LineAndCharacter +>sourceFile.getLineAndCharacterFromPosition : (pos: number) => ts.LineAndCharacter >sourceFile : ts.SourceFile ->getLineAndCharacterFromPosition : (position: number) => ts.LineAndCharacter +>getLineAndCharacterFromPosition : (pos: number) => ts.LineAndCharacter >node.getStart() : number >node.getStart : (sourceFile?: ts.SourceFile) => number >node : ts.Node @@ -2339,26 +2339,6 @@ declare module "typescript" { text: string; >text : string - getLineAndCharacterFromPosition(position: number): LineAndCharacter; ->getLineAndCharacterFromPosition : (position: number) => LineAndCharacter ->position : number ->LineAndCharacter : LineAndCharacter - - getPositionFromLineAndCharacter(line: number, character: number): number; ->getPositionFromLineAndCharacter : (line: number, character: number) => number ->line : number ->character : number - - getLineStarts(): number[]; ->getLineStarts : () => number[] - - update(newText: string, textChangeRange: TextChangeRange): SourceFile; ->update : (newText: string, textChangeRange: TextChangeRange) => SourceFile ->newText : string ->textChangeRange : TextChangeRange ->TextChangeRange : TextChangeRange ->SourceFile : SourceFile - amdDependencies: string[]; >amdDependencies : string[] @@ -2375,14 +2355,14 @@ declare module "typescript" { parseDiagnostics: Diagnostic[]; >parseDiagnostics : Diagnostic[] ->Diagnostic : Diagnostic - - getSyntacticDiagnostics(): Diagnostic[]; ->getSyntacticDiagnostics : () => Diagnostic[] >Diagnostic : Diagnostic semanticDiagnostics: Diagnostic[]; >semanticDiagnostics : Diagnostic[] +>Diagnostic : Diagnostic + + syntacticDiagnostics: Diagnostic[]; +>syntacticDiagnostics : Diagnostic[] >Diagnostic : Diagnostic hasNoDefaultLib: boolean; @@ -2408,6 +2388,9 @@ declare module "typescript" { identifiers: Map; >identifiers : Map >Map : Map + + lineMap: number[]; +>lineMap : number[] } interface ScriptReferenceHost { >ScriptReferenceHost : ScriptReferenceHost @@ -4576,14 +4559,26 @@ declare module "typescript" { >computeLineStarts : (text: string) => number[] >text : string - function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; ->getPositionFromLineAndCharacter : (lineStarts: number[], line: number, character: number) => number + function getPositionFromLineAndCharacter(sourceFile: SourceFile, line: number, character: number): number; +>getPositionFromLineAndCharacter : (sourceFile: SourceFile, line: number, character: number) => number +>sourceFile : SourceFile +>SourceFile : SourceFile +>line : number +>character : number + + function computePositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; +>computePositionFromLineAndCharacter : (lineStarts: number[], line: number, character: number) => number >lineStarts : number[] >line : number >character : number - function getLineAndCharacterOfPosition(lineStarts: number[], position: number): { ->getLineAndCharacterOfPosition : (lineStarts: number[], position: number) => { line: number; character: number; } + function getLineStarts(sourceFile: SourceFile): number[]; +>getLineStarts : (sourceFile: SourceFile) => number[] +>sourceFile : SourceFile +>SourceFile : SourceFile + + function computeLineAndCharacterOfPosition(lineStarts: number[], position: number): { +>computeLineAndCharacterOfPosition : (lineStarts: number[], position: number) => { line: number; character: number; } >lineStarts : number[] >position : number @@ -4594,18 +4589,13 @@ declare module "typescript" { >character : number }; - function positionToLineAndCharacter(text: string, pos: number): { ->positionToLineAndCharacter : (text: string, pos: number) => { line: number; character: number; } ->text : string ->pos : number + function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter; +>getLineAndCharacterOfPosition : (sourceFile: SourceFile, position: number) => LineAndCharacter +>sourceFile : SourceFile +>SourceFile : SourceFile +>position : number +>LineAndCharacter : LineAndCharacter - line: number; ->line : number - - character: number; ->character : number - - }; function isWhiteSpace(ch: number): boolean; >isWhiteSpace : (ch: number) => boolean >ch : number @@ -4692,6 +4682,21 @@ declare module "typescript" { >SyntaxKind : SyntaxKind >NodeFlags : NodeFlags + function getSyntacticDiagnostics(sourceFile: SourceFile): Diagnostic[]; +>getSyntacticDiagnostics : (sourceFile: SourceFile) => Diagnostic[] +>sourceFile : SourceFile +>SourceFile : SourceFile +>Diagnostic : Diagnostic + + function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile; +>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange) => SourceFile +>sourceFile : SourceFile +>SourceFile : SourceFile +>newText : string +>textChangeRange : TextChangeRange +>TextChangeRange : TextChangeRange +>SourceFile : SourceFile + function isEvalOrArgumentsIdentifier(node: Node): boolean; >isEvalOrArgumentsIdentifier : (node: Node) => boolean >node : Node @@ -4913,6 +4918,30 @@ declare module "typescript" { getNamedDeclarations(): Declaration[]; >getNamedDeclarations : () => Declaration[] >Declaration : Declaration + + getLineAndCharacterFromPosition(pos: number): LineAndCharacter; +>getLineAndCharacterFromPosition : (pos: number) => LineAndCharacter +>pos : number +>LineAndCharacter : LineAndCharacter + + getLineStarts(): number[]; +>getLineStarts : () => number[] + + getPositionFromLineAndCharacter(line: number, character: number): number; +>getPositionFromLineAndCharacter : (line: number, character: number) => number +>line : number +>character : number + + getSyntacticDiagnostics(): Diagnostic[]; +>getSyntacticDiagnostics : () => Diagnostic[] +>Diagnostic : Diagnostic + + update(newText: string, textChangeRange: TextChangeRange): SourceFile; +>update : (newText: string, textChangeRange: TextChangeRange) => SourceFile +>newText : string +>textChangeRange : TextChangeRange +>TextChangeRange : TextChangeRange +>SourceFile : SourceFile } /** * Represents an immutable snapshot of a script at a specified time.Once acquired, the diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index 06546d2fdb..33cea1ea0a 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -755,17 +755,13 @@ declare module "typescript" { endOfFileToken: Node; filename: string; text: string; - getLineAndCharacterFromPosition(position: number): LineAndCharacter; - getPositionFromLineAndCharacter(line: number, character: number): number; - getLineStarts(): number[]; - update(newText: string, textChangeRange: TextChangeRange): SourceFile; amdDependencies: string[]; amdModuleName: string; referencedFiles: FileReference[]; referenceDiagnostics: Diagnostic[]; parseDiagnostics: Diagnostic[]; - getSyntacticDiagnostics(): Diagnostic[]; semanticDiagnostics: Diagnostic[]; + syntacticDiagnostics: Diagnostic[]; hasNoDefaultLib: boolean; externalModuleIndicator: Node; nodeCount: number; @@ -773,6 +769,7 @@ declare module "typescript" { symbolCount: number; languageVersion: ScriptTarget; identifiers: Map; + lineMap: number[]; } interface ScriptReferenceHost { getCompilerOptions(): CompilerOptions; @@ -1423,15 +1420,14 @@ declare module "typescript" { } function tokenToString(t: SyntaxKind): string; function computeLineStarts(text: string): number[]; - function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; - function getLineAndCharacterOfPosition(lineStarts: number[], position: number): { - line: number; - character: number; - }; - function positionToLineAndCharacter(text: string, pos: number): { + function getPositionFromLineAndCharacter(sourceFile: SourceFile, line: number, character: number): number; + function computePositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; + function getLineStarts(sourceFile: SourceFile): number[]; + function computeLineAndCharacterOfPosition(lineStarts: number[], position: number): { line: number; character: number; }; + function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter; function isWhiteSpace(ch: number): boolean; function isLineBreak(ch: number): boolean; function isOctalDigit(ch: number): boolean; @@ -1447,6 +1443,8 @@ declare module "typescript" { function createNode(kind: SyntaxKind): Node; function forEachChild(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T; function modifierToFlag(token: SyntaxKind): NodeFlags; + function getSyntacticDiagnostics(sourceFile: SourceFile): Diagnostic[]; + function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile; function isEvalOrArgumentsIdentifier(node: Node): boolean; function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes?: boolean): SourceFile; function isLeftHandSideExpression(expr: Expression): boolean; @@ -1506,6 +1504,11 @@ declare module "typescript" { scriptSnapshot: IScriptSnapshot; nameTable: Map; getNamedDeclarations(): Declaration[]; + getLineAndCharacterFromPosition(pos: number): LineAndCharacter; + getLineStarts(): number[]; + getPositionFromLineAndCharacter(line: number, character: number): number; + getSyntacticDiagnostics(): Diagnostic[]; + update(newText: string, textChangeRange: TextChangeRange): SourceFile; } /** * Represents an immutable snapshot of a script at a specified time.Once acquired, the diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index f92c2f3677..c091af5eff 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -210,11 +210,11 @@ function transform(contents: string, compilerOptions: ts.CompilerOptions = {}) { >filename : string >e.file.getLineAndCharacterFromPosition(e.start).line : number >e.file.getLineAndCharacterFromPosition(e.start) : ts.LineAndCharacter ->e.file.getLineAndCharacterFromPosition : (position: number) => ts.LineAndCharacter +>e.file.getLineAndCharacterFromPosition : (pos: number) => ts.LineAndCharacter >e.file : ts.SourceFile >e : ts.Diagnostic >file : ts.SourceFile ->getLineAndCharacterFromPosition : (position: number) => ts.LineAndCharacter +>getLineAndCharacterFromPosition : (pos: number) => ts.LineAndCharacter >e.start : number >e : ts.Diagnostic >start : number @@ -2287,26 +2287,6 @@ declare module "typescript" { text: string; >text : string - getLineAndCharacterFromPosition(position: number): LineAndCharacter; ->getLineAndCharacterFromPosition : (position: number) => LineAndCharacter ->position : number ->LineAndCharacter : LineAndCharacter - - getPositionFromLineAndCharacter(line: number, character: number): number; ->getPositionFromLineAndCharacter : (line: number, character: number) => number ->line : number ->character : number - - getLineStarts(): number[]; ->getLineStarts : () => number[] - - update(newText: string, textChangeRange: TextChangeRange): SourceFile; ->update : (newText: string, textChangeRange: TextChangeRange) => SourceFile ->newText : string ->textChangeRange : TextChangeRange ->TextChangeRange : TextChangeRange ->SourceFile : SourceFile - amdDependencies: string[]; >amdDependencies : string[] @@ -2323,14 +2303,14 @@ declare module "typescript" { parseDiagnostics: Diagnostic[]; >parseDiagnostics : Diagnostic[] ->Diagnostic : Diagnostic - - getSyntacticDiagnostics(): Diagnostic[]; ->getSyntacticDiagnostics : () => Diagnostic[] >Diagnostic : Diagnostic semanticDiagnostics: Diagnostic[]; >semanticDiagnostics : Diagnostic[] +>Diagnostic : Diagnostic + + syntacticDiagnostics: Diagnostic[]; +>syntacticDiagnostics : Diagnostic[] >Diagnostic : Diagnostic hasNoDefaultLib: boolean; @@ -2356,6 +2336,9 @@ declare module "typescript" { identifiers: Map; >identifiers : Map >Map : Map + + lineMap: number[]; +>lineMap : number[] } interface ScriptReferenceHost { >ScriptReferenceHost : ScriptReferenceHost @@ -4524,14 +4507,26 @@ declare module "typescript" { >computeLineStarts : (text: string) => number[] >text : string - function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; ->getPositionFromLineAndCharacter : (lineStarts: number[], line: number, character: number) => number + function getPositionFromLineAndCharacter(sourceFile: SourceFile, line: number, character: number): number; +>getPositionFromLineAndCharacter : (sourceFile: SourceFile, line: number, character: number) => number +>sourceFile : SourceFile +>SourceFile : SourceFile +>line : number +>character : number + + function computePositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; +>computePositionFromLineAndCharacter : (lineStarts: number[], line: number, character: number) => number >lineStarts : number[] >line : number >character : number - function getLineAndCharacterOfPosition(lineStarts: number[], position: number): { ->getLineAndCharacterOfPosition : (lineStarts: number[], position: number) => { line: number; character: number; } + function getLineStarts(sourceFile: SourceFile): number[]; +>getLineStarts : (sourceFile: SourceFile) => number[] +>sourceFile : SourceFile +>SourceFile : SourceFile + + function computeLineAndCharacterOfPosition(lineStarts: number[], position: number): { +>computeLineAndCharacterOfPosition : (lineStarts: number[], position: number) => { line: number; character: number; } >lineStarts : number[] >position : number @@ -4542,18 +4537,13 @@ declare module "typescript" { >character : number }; - function positionToLineAndCharacter(text: string, pos: number): { ->positionToLineAndCharacter : (text: string, pos: number) => { line: number; character: number; } ->text : string ->pos : number + function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter; +>getLineAndCharacterOfPosition : (sourceFile: SourceFile, position: number) => LineAndCharacter +>sourceFile : SourceFile +>SourceFile : SourceFile +>position : number +>LineAndCharacter : LineAndCharacter - line: number; ->line : number - - character: number; ->character : number - - }; function isWhiteSpace(ch: number): boolean; >isWhiteSpace : (ch: number) => boolean >ch : number @@ -4640,6 +4630,21 @@ declare module "typescript" { >SyntaxKind : SyntaxKind >NodeFlags : NodeFlags + function getSyntacticDiagnostics(sourceFile: SourceFile): Diagnostic[]; +>getSyntacticDiagnostics : (sourceFile: SourceFile) => Diagnostic[] +>sourceFile : SourceFile +>SourceFile : SourceFile +>Diagnostic : Diagnostic + + function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile; +>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange) => SourceFile +>sourceFile : SourceFile +>SourceFile : SourceFile +>newText : string +>textChangeRange : TextChangeRange +>TextChangeRange : TextChangeRange +>SourceFile : SourceFile + function isEvalOrArgumentsIdentifier(node: Node): boolean; >isEvalOrArgumentsIdentifier : (node: Node) => boolean >node : Node @@ -4861,6 +4866,30 @@ declare module "typescript" { getNamedDeclarations(): Declaration[]; >getNamedDeclarations : () => Declaration[] >Declaration : Declaration + + getLineAndCharacterFromPosition(pos: number): LineAndCharacter; +>getLineAndCharacterFromPosition : (pos: number) => LineAndCharacter +>pos : number +>LineAndCharacter : LineAndCharacter + + getLineStarts(): number[]; +>getLineStarts : () => number[] + + getPositionFromLineAndCharacter(line: number, character: number): number; +>getPositionFromLineAndCharacter : (line: number, character: number) => number +>line : number +>character : number + + getSyntacticDiagnostics(): Diagnostic[]; +>getSyntacticDiagnostics : () => Diagnostic[] +>Diagnostic : Diagnostic + + update(newText: string, textChangeRange: TextChangeRange): SourceFile; +>update : (newText: string, textChangeRange: TextChangeRange) => SourceFile +>newText : string +>textChangeRange : TextChangeRange +>TextChangeRange : TextChangeRange +>SourceFile : SourceFile } /** * Represents an immutable snapshot of a script at a specified time.Once acquired, the diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index 9a7064117b..7c70ee1532 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -792,17 +792,13 @@ declare module "typescript" { endOfFileToken: Node; filename: string; text: string; - getLineAndCharacterFromPosition(position: number): LineAndCharacter; - getPositionFromLineAndCharacter(line: number, character: number): number; - getLineStarts(): number[]; - update(newText: string, textChangeRange: TextChangeRange): SourceFile; amdDependencies: string[]; amdModuleName: string; referencedFiles: FileReference[]; referenceDiagnostics: Diagnostic[]; parseDiagnostics: Diagnostic[]; - getSyntacticDiagnostics(): Diagnostic[]; semanticDiagnostics: Diagnostic[]; + syntacticDiagnostics: Diagnostic[]; hasNoDefaultLib: boolean; externalModuleIndicator: Node; nodeCount: number; @@ -810,6 +806,7 @@ declare module "typescript" { symbolCount: number; languageVersion: ScriptTarget; identifiers: Map; + lineMap: number[]; } interface ScriptReferenceHost { getCompilerOptions(): CompilerOptions; @@ -1460,15 +1457,14 @@ declare module "typescript" { } function tokenToString(t: SyntaxKind): string; function computeLineStarts(text: string): number[]; - function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; - function getLineAndCharacterOfPosition(lineStarts: number[], position: number): { - line: number; - character: number; - }; - function positionToLineAndCharacter(text: string, pos: number): { + function getPositionFromLineAndCharacter(sourceFile: SourceFile, line: number, character: number): number; + function computePositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; + function getLineStarts(sourceFile: SourceFile): number[]; + function computeLineAndCharacterOfPosition(lineStarts: number[], position: number): { line: number; character: number; }; + function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter; function isWhiteSpace(ch: number): boolean; function isLineBreak(ch: number): boolean; function isOctalDigit(ch: number): boolean; @@ -1484,6 +1480,8 @@ declare module "typescript" { function createNode(kind: SyntaxKind): Node; function forEachChild(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T; function modifierToFlag(token: SyntaxKind): NodeFlags; + function getSyntacticDiagnostics(sourceFile: SourceFile): Diagnostic[]; + function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile; function isEvalOrArgumentsIdentifier(node: Node): boolean; function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes?: boolean): SourceFile; function isLeftHandSideExpression(expr: Expression): boolean; @@ -1543,6 +1541,11 @@ declare module "typescript" { scriptSnapshot: IScriptSnapshot; nameTable: Map; getNamedDeclarations(): Declaration[]; + getLineAndCharacterFromPosition(pos: number): LineAndCharacter; + getLineStarts(): number[]; + getPositionFromLineAndCharacter(line: number, character: number): number; + getSyntacticDiagnostics(): Diagnostic[]; + update(newText: string, textChangeRange: TextChangeRange): SourceFile; } /** * Represents an immutable snapshot of a script at a specified time.Once acquired, the diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 938db86d09..c3d0325938 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -337,11 +337,11 @@ function watch(rootFilenames: string[], options: ts.CompilerOptions) { var lineChar = diagnostic.file.getLineAndCharacterFromPosition(diagnostic.start); >lineChar : ts.LineAndCharacter >diagnostic.file.getLineAndCharacterFromPosition(diagnostic.start) : ts.LineAndCharacter ->diagnostic.file.getLineAndCharacterFromPosition : (position: number) => ts.LineAndCharacter +>diagnostic.file.getLineAndCharacterFromPosition : (pos: number) => ts.LineAndCharacter >diagnostic.file : ts.SourceFile >diagnostic : ts.Diagnostic >file : ts.SourceFile ->getLineAndCharacterFromPosition : (position: number) => ts.LineAndCharacter +>getLineAndCharacterFromPosition : (pos: number) => ts.LineAndCharacter >diagnostic.start : number >diagnostic : ts.Diagnostic >start : number @@ -2465,26 +2465,6 @@ declare module "typescript" { text: string; >text : string - getLineAndCharacterFromPosition(position: number): LineAndCharacter; ->getLineAndCharacterFromPosition : (position: number) => LineAndCharacter ->position : number ->LineAndCharacter : LineAndCharacter - - getPositionFromLineAndCharacter(line: number, character: number): number; ->getPositionFromLineAndCharacter : (line: number, character: number) => number ->line : number ->character : number - - getLineStarts(): number[]; ->getLineStarts : () => number[] - - update(newText: string, textChangeRange: TextChangeRange): SourceFile; ->update : (newText: string, textChangeRange: TextChangeRange) => SourceFile ->newText : string ->textChangeRange : TextChangeRange ->TextChangeRange : TextChangeRange ->SourceFile : SourceFile - amdDependencies: string[]; >amdDependencies : string[] @@ -2501,14 +2481,14 @@ declare module "typescript" { parseDiagnostics: Diagnostic[]; >parseDiagnostics : Diagnostic[] ->Diagnostic : Diagnostic - - getSyntacticDiagnostics(): Diagnostic[]; ->getSyntacticDiagnostics : () => Diagnostic[] >Diagnostic : Diagnostic semanticDiagnostics: Diagnostic[]; >semanticDiagnostics : Diagnostic[] +>Diagnostic : Diagnostic + + syntacticDiagnostics: Diagnostic[]; +>syntacticDiagnostics : Diagnostic[] >Diagnostic : Diagnostic hasNoDefaultLib: boolean; @@ -2534,6 +2514,9 @@ declare module "typescript" { identifiers: Map; >identifiers : Map >Map : Map + + lineMap: number[]; +>lineMap : number[] } interface ScriptReferenceHost { >ScriptReferenceHost : ScriptReferenceHost @@ -4702,14 +4685,26 @@ declare module "typescript" { >computeLineStarts : (text: string) => number[] >text : string - function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; ->getPositionFromLineAndCharacter : (lineStarts: number[], line: number, character: number) => number + function getPositionFromLineAndCharacter(sourceFile: SourceFile, line: number, character: number): number; +>getPositionFromLineAndCharacter : (sourceFile: SourceFile, line: number, character: number) => number +>sourceFile : SourceFile +>SourceFile : SourceFile +>line : number +>character : number + + function computePositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number; +>computePositionFromLineAndCharacter : (lineStarts: number[], line: number, character: number) => number >lineStarts : number[] >line : number >character : number - function getLineAndCharacterOfPosition(lineStarts: number[], position: number): { ->getLineAndCharacterOfPosition : (lineStarts: number[], position: number) => { line: number; character: number; } + function getLineStarts(sourceFile: SourceFile): number[]; +>getLineStarts : (sourceFile: SourceFile) => number[] +>sourceFile : SourceFile +>SourceFile : SourceFile + + function computeLineAndCharacterOfPosition(lineStarts: number[], position: number): { +>computeLineAndCharacterOfPosition : (lineStarts: number[], position: number) => { line: number; character: number; } >lineStarts : number[] >position : number @@ -4720,18 +4715,13 @@ declare module "typescript" { >character : number }; - function positionToLineAndCharacter(text: string, pos: number): { ->positionToLineAndCharacter : (text: string, pos: number) => { line: number; character: number; } ->text : string ->pos : number + function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter; +>getLineAndCharacterOfPosition : (sourceFile: SourceFile, position: number) => LineAndCharacter +>sourceFile : SourceFile +>SourceFile : SourceFile +>position : number +>LineAndCharacter : LineAndCharacter - line: number; ->line : number - - character: number; ->character : number - - }; function isWhiteSpace(ch: number): boolean; >isWhiteSpace : (ch: number) => boolean >ch : number @@ -4818,6 +4808,21 @@ declare module "typescript" { >SyntaxKind : SyntaxKind >NodeFlags : NodeFlags + function getSyntacticDiagnostics(sourceFile: SourceFile): Diagnostic[]; +>getSyntacticDiagnostics : (sourceFile: SourceFile) => Diagnostic[] +>sourceFile : SourceFile +>SourceFile : SourceFile +>Diagnostic : Diagnostic + + function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile; +>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange) => SourceFile +>sourceFile : SourceFile +>SourceFile : SourceFile +>newText : string +>textChangeRange : TextChangeRange +>TextChangeRange : TextChangeRange +>SourceFile : SourceFile + function isEvalOrArgumentsIdentifier(node: Node): boolean; >isEvalOrArgumentsIdentifier : (node: Node) => boolean >node : Node @@ -5039,6 +5044,30 @@ declare module "typescript" { getNamedDeclarations(): Declaration[]; >getNamedDeclarations : () => Declaration[] >Declaration : Declaration + + getLineAndCharacterFromPosition(pos: number): LineAndCharacter; +>getLineAndCharacterFromPosition : (pos: number) => LineAndCharacter +>pos : number +>LineAndCharacter : LineAndCharacter + + getLineStarts(): number[]; +>getLineStarts : () => number[] + + getPositionFromLineAndCharacter(line: number, character: number): number; +>getPositionFromLineAndCharacter : (line: number, character: number) => number +>line : number +>character : number + + getSyntacticDiagnostics(): Diagnostic[]; +>getSyntacticDiagnostics : () => Diagnostic[] +>Diagnostic : Diagnostic + + update(newText: string, textChangeRange: TextChangeRange): SourceFile; +>update : (newText: string, textChangeRange: TextChangeRange) => SourceFile +>newText : string +>textChangeRange : TextChangeRange +>TextChangeRange : TextChangeRange +>SourceFile : SourceFile } /** * Represents an immutable snapshot of a script at a specified time.Once acquired, the