diff --git a/Jakefile.js b/Jakefile.js index 69510545ea3..1929a3a475f 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -238,6 +238,7 @@ function concatenateFiles(destinationFile, sourceFiles) { } var useDebugMode = true; +var useTransforms = process.env.USE_TRANSFORMS || false; var host = (process.env.host || process.env.TYPESCRIPT_HOST || "node"); var compilerFilename = "tsc.js"; var LKGCompiler = path.join(LKGDirectory, compilerFilename); @@ -297,6 +298,10 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOu options += " --stripInternal" } + if (useBuiltCompiler && useTransforms) { + options += " --experimentalTransforms" + } + var cmd = host + " " + compilerPath + " " + options + " "; cmd = cmd + sources.join(" "); console.log(cmd + "\n"); @@ -420,6 +425,10 @@ task("setDebugMode", function() { useDebugMode = true; }); +task("setTransforms", function() { + useTransforms = true; +}); + task("configure-nightly", [configureNightlyJs], function() { var cmd = host + " " + configureNightlyJs + " " + packageJson + " " + programTs; console.log(cmd); diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b0ae5804b5f..4ea2489de88 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1798,7 +1798,7 @@ namespace ts { * @param node The node to analyze * @param subtreeFlags Transform flags computed for this node's subtree */ - export function computeTransformFlagsForNode(node: Node, subtreeFlags: TransformFlags) { + export function computeTransformFlagsForNode(node: Node, subtreeFlags: TransformFlags): TransformFlags { // Ambient nodes are TypeScript syntax and the flags of their subtree are ignored. if (node.flags & NodeFlags.Ambient) { return (node.transformFlags = TransformFlags.AssertTypeScript) @@ -1971,20 +1971,6 @@ namespace ts { break; - case SyntaxKind.ExpressionStatement: - if (nodeIsSynthesized(node)) { - const expression = (node).expression; - if (nodeIsSynthesized(expression) - && isCallExpression(expression) - && expression.expression.kind === SyntaxKind.SuperKeyword) { - // A synthesized call to `super` should be transformed to a cleaner emit - // when transpiling to ES5/3. - transformFlags |= TransformFlags.AssertES6; - } - } - - break; - case SyntaxKind.BinaryExpression: if (isDestructuringAssignment(node)) { // Destructuring assignments are ES6 syntax. @@ -2093,7 +2079,7 @@ namespace ts { case SyntaxKind.VariableDeclarationList: // If a VariableDeclarationList is `let` or `const`, then it is ES6 syntax. if (node.flags & NodeFlags.BlockScoped) { - transformFlags |= TransformFlags.AssertES6; + transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsBlockScopedBinding; } break; @@ -2106,6 +2092,26 @@ namespace ts { break; + case SyntaxKind.LabeledStatement: + // A labeled statement containing a block scoped binding *may* need to be transformed from ES6. + if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding + && isIterationStatement(this, /*lookInLabeledStatements*/ true)) { + transformFlags |= TransformFlags.AssertES6; + } + + break; + + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + // A loop containing a block scoped binding *may* need to be transformed from ES6. + if (subtreeFlags & TransformFlags.ContainsBlockScopedBinding) { + transformFlags |= TransformFlags.AssertES6; + } + + break; + case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: // A ClassDeclarations or ClassExpression is ES6 syntax. diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index d5bf95a6405..c65466f00de 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -320,6 +320,11 @@ namespace ts { name: "allowSyntheticDefaultImports", type: "boolean", description: Diagnostics.Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typechecking + }, + { + name: "experimentalTransforms", + type: "boolean", + experimental: true } ]; diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts index 2b51e937fad..a680d01e102 100644 --- a/src/compiler/comments.ts +++ b/src/compiler/comments.ts @@ -5,11 +5,15 @@ namespace ts { export interface CommentWriter { reset(): void; setSourceFile(sourceFile: SourceFile): void; - getLeadingCommentsToEmit(node: TextRange): CommentRange[]; - getTrailingCommentsToEmit(node: TextRange): CommentRange[]; - emitDetachedComments(node: TextRange): void; - emitLeadingComments(node: TextRange, comments?: CommentRange[]): void; - emitTrailingComments(node: TextRange, comments?: CommentRange[]): void; + getLeadingComments(range: Node, getAdditionalRange?: (range: Node) => Node): CommentRange[]; + getLeadingComments(range: TextRange): CommentRange[]; + getLeadingCommentsOfPosition(pos: number): CommentRange[]; + getTrailingComments(range: Node, getAdditionalRange?: (range: Node) => Node): CommentRange[]; + getTrailingComments(range: TextRange): CommentRange[]; + getTrailingCommentsOfPosition(pos: number): CommentRange[]; + emitLeadingComments(range: TextRange, comments?: CommentRange[]): void; + emitTrailingComments(range: TextRange, comments?: CommentRange[]): void; + emitDetachedComments(range: TextRange): void; } export function createCommentWriter(host: EmitHost, writer: EmitTextWriter, sourceMap: SourceMapWriter): CommentWriter { @@ -25,8 +29,8 @@ namespace ts { // This maps start->end for a comment range. See `hasConsumedCommentRange` and // `consumeCommentRange` for usage. let consumedCommentRanges: number[]; - let leadingCommentRangeNodeStarts: boolean[]; - let trailingCommentRangeNodeEnds: boolean[]; + let leadingCommentRangePositions: boolean[]; + let trailingCommentRangePositions: boolean[]; return compilerOptions.removeComments ? createCommentRemovingWriter() @@ -36,11 +40,13 @@ namespace ts { return { reset, setSourceFile, - getLeadingCommentsToEmit(node: TextRange): CommentRange[] { return undefined; }, - getTrailingCommentsToEmit(node: TextRange): CommentRange[] { return undefined; }, + getLeadingComments(range: TextRange, getAdditionalRange?: (range: TextRange) => TextRange): CommentRange[] { return undefined; }, + getLeadingCommentsOfPosition(pos: number): CommentRange[] { return undefined; }, + getTrailingComments(range: TextRange, getAdditionalRange?: (range: TextRange) => TextRange): CommentRange[] { return undefined; }, + getTrailingCommentsOfPosition(pos: number): CommentRange[] { return undefined; }, + emitLeadingComments(range: TextRange, comments?: CommentRange[]): void { }, + emitTrailingComments(range: TextRange, comments?: CommentRange[]): void { }, emitDetachedComments, - emitLeadingComments(node: TextRange, comments?: CommentRange[]): void { }, - emitTrailingComments(node: TextRange, comments?: CommentRange[]): void { }, }; function emitDetachedComments(node: TextRange): void { @@ -53,41 +59,85 @@ namespace ts { return { reset, setSourceFile, - getLeadingCommentsToEmit, - getTrailingCommentsToEmit, - emitDetachedComments, + getLeadingComments, + getLeadingCommentsOfPosition, + getTrailingComments, + getTrailingCommentsOfPosition, emitLeadingComments, emitTrailingComments, + emitDetachedComments, }; - function getLeadingCommentsToEmit(node: TextRange) { - if (nodeIsSynthesized(node)) { - return; + function getLeadingComments(range: TextRange | Node, getAdditionalRange?: (range: Node) => Node) { + let comments = getLeadingCommentsOfPosition(range.pos); + if (getAdditionalRange) { + let additionalRange = getAdditionalRange(range); + while (additionalRange) { + comments = concatenate( + getLeadingCommentsOfPosition(additionalRange.pos), + comments + ); + + additionalRange = getAdditionalRange(additionalRange); + } } - if (!leadingCommentRangeNodeStarts[node.pos]) { - leadingCommentRangeNodeStarts[node.pos] = true; - const comments = hasDetachedComments(node.pos) - ? getLeadingCommentsWithoutDetachedComments() - : getLeadingCommentRanges(currentText, node.pos); - return consumeCommentRanges(comments); - } - - return noComments; + return comments; } - function getTrailingCommentsToEmit(node: TextRange) { - if (nodeIsSynthesized(node)) { - return; + function getTrailingComments(range: TextRange | Node, getAdditionalRange?: (range: Node) => Node) { + let comments = getTrailingCommentsOfPosition(range.end); + if (getAdditionalRange) { + let additionalRange = getAdditionalRange(range); + while (additionalRange) { + comments = concatenate( + comments, + getTrailingCommentsOfPosition(additionalRange.end) + ); + + additionalRange = getAdditionalRange(additionalRange); + } } - if (!trailingCommentRangeNodeEnds[node.end]) { - trailingCommentRangeNodeEnds[node.end] = true; - const comments = getTrailingCommentRanges(currentText, node.end); - return consumeCommentRanges(comments); + return comments; + } + + function getLeadingCommentsOfPosition(pos: number) { + if (positionIsSynthesized(pos) || leadingCommentRangePositions[pos]) { + return undefined; } - return noComments; + leadingCommentRangePositions[pos] = true; + const comments = hasDetachedComments(pos) + ? getLeadingCommentsWithoutDetachedComments() + : getLeadingCommentRanges(currentText, pos); + return consumeCommentRanges(comments); + } + + function getTrailingCommentsOfPosition(pos: number) { + if (positionIsSynthesized(pos) || trailingCommentRangePositions[pos]) { + return undefined; + } + + trailingCommentRangePositions[pos] = true; + const comments = getTrailingCommentRanges(currentText, pos); + return consumeCommentRanges(comments); + } + + function emitLeadingComments(range: TextRange, comments = getLeadingComments(range)) { + emitNewLineBeforeLeadingComments(currentLineMap, writer, range, comments); + + // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space + emitComments(currentText, currentLineMap, writer, comments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); + } + + function emitTrailingComments(range: TextRange, comments = getTrailingComments(range)) { + // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/ + emitComments(currentText, currentLineMap, writer, comments, /*leadingSeparator*/ true, /*trailingSeparator*/ false, newLine, writeComment); + } + + function emitDetachedComments(range: TextRange) { + emitDetachedCommentsAndUpdateCommentsInfo(range, /*removeComments*/ false); } function hasConsumedCommentRange(comment: CommentRange) { @@ -136,22 +186,6 @@ namespace ts { return noComments; } - - function emitLeadingComments(range: TextRange, leadingComments: CommentRange[] = getLeadingCommentsToEmit(range)) { - emitNewLineBeforeLeadingComments(currentLineMap, writer, range, leadingComments); - - // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space - emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment); - } - - function emitTrailingComments(range: TextRange, trailingComments = getTrailingCommentsToEmit(range)) { - // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/ - emitComments(currentText, currentLineMap, writer, trailingComments, /*trailingSeparator*/ false, newLine, writeComment); - } - - function emitDetachedComments(range: TextRange) { - emitDetachedCommentsAndUpdateCommentsInfo(range, /*removeComments*/ false); - } } function reset() { @@ -160,8 +194,8 @@ namespace ts { currentLineMap = undefined; detachedCommentsInfo = undefined; consumedCommentRanges = undefined; - trailingCommentRangeNodeEnds = undefined; - leadingCommentRangeNodeStarts = undefined; + trailingCommentRangePositions = undefined; + leadingCommentRangePositions = undefined; } function setSourceFile(sourceFile: SourceFile) { @@ -170,8 +204,8 @@ namespace ts { currentLineMap = getLineStarts(sourceFile); detachedCommentsInfo = undefined; consumedCommentRanges = []; - leadingCommentRangeNodeStarts = []; - trailingCommentRangeNodeEnds = []; + leadingCommentRangePositions = []; + trailingCommentRangePositions = []; } function hasDetachedComments(pos: number) { diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 19726482cb3..a464bd86682 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -130,11 +130,12 @@ namespace ts { return -1; } - export function countWhere(array: T[], predicate: (x: T) => boolean): number { + export function countWhere(array: T[], predicate: (x: T, i: number) => boolean): number { let count = 0; if (array) { - for (const v of array) { - if (predicate(v)) { + for (let i = 0; i < array.length; i++) { + const v = array[i]; + if (predicate(v, i)) { count++; } } @@ -170,7 +171,10 @@ namespace ts { return result; } - export function flatMap(array: T[], f: (x: T, i: number) => U[]): U[] { + /** + * Maps an array. If the mapped value is an array, it is spread into the result. + */ + export function flatMap(array: T[], f: (x: T, i: number) => U | U[]): U[] { let result: U[]; if (array) { result = []; @@ -178,7 +182,9 @@ namespace ts { const v = array[i]; const ar = f(v, i); if (ar) { - result = result.concat(ar); + // We cast to here to leverage the behavior of Array#concat + // which will append a single value here. + result = result.concat(ar); } } } @@ -191,18 +197,6 @@ namespace ts { return [...array1, ...array2]; } - export function append(array: T[], value: T): T[] { - if (value === undefined) return array; - if (!array || !array.length) return [value]; - return [...array, value]; - } - - export function prepend(array: T[], value: T): T[] { - if (value === undefined) return array; - if (!array || !array.length) return [value]; - return [value, ...array]; - } - export function deduplicate(array: T[]): T[] { let result: T[]; if (array) { @@ -216,6 +210,27 @@ namespace ts { return result; } + /** + * Compacts an array, removing any falsey elements. + */ + export function compact(array: T[]): T[] { + let result: T[]; + if (array) { + for (let i = 0; i < array.length; i++) { + const v = array[i]; + if (result || !v) { + if (!result) { + result = array.slice(0, i); + } + if (v) { + result.push(v); + } + } + } + } + return result || array; + } + export function sum(array: any[], prop: string): number { let result = 0; for (const v of array) { @@ -292,9 +307,9 @@ namespace ts { return ~low; } - export function reduceLeft(array: T[], f: (memo: U, value: T) => U, initial: U): U; - export function reduceLeft(array: T[], f: (memo: T, value: T) => T): T; - export function reduceLeft(array: T[], f: (memo: T, value: T) => T, initial?: T): T { + export function reduceLeft(array: T[], f: (memo: U, value: T, i: number) => U, initial: U): U; + export function reduceLeft(array: T[], f: (memo: T, value: T, i: number) => T): T; + export function reduceLeft(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T): T { if (array) { const count = array.length; if (count > 0) { @@ -308,7 +323,7 @@ namespace ts { result = initial; } while (pos < count) { - result = f(result, array[pos]); + result = f(result, array[pos], pos); pos++; } return result; @@ -317,9 +332,9 @@ namespace ts { return initial; } - export function reduceRight(array: T[], f: (memo: U, value: T) => U, initial: U): U; - export function reduceRight(array: T[], f: (memo: T, value: T) => T): T; - export function reduceRight(array: T[], f: (memo: T, value: T) => T, initial?: T): T { + export function reduceRight(array: T[], f: (memo: U, value: T, i: number) => U, initial: U): U; + export function reduceRight(array: T[], f: (memo: T, value: T, i: number) => T): T; + export function reduceRight(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T): T { if (array) { let pos = array.length - 1; if (pos >= 0) { @@ -332,7 +347,7 @@ namespace ts { result = initial; } while (pos >= 0) { - result = f(result, array[pos]); + result = f(result, array[pos], pos); pos--; } return result; diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index ab0b16947fc..c89b7579d52 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -91,7 +91,7 @@ namespace ts { // Emit reference in dts, if the file reference was not already emitted if (referencedFile && !contains(emittedReferencedFiles, referencedFile)) { // Add a reference to generated dts file, - // global file reference is added only + // global file reference is added only // - if it is not bundled emit (because otherwise it would be self reference) // - and it is not already added if (writeReferencePath(referencedFile, !isBundledEmit && !addedGlobalFileReference)) { @@ -144,7 +144,7 @@ namespace ts { if (!isBundledEmit && isExternalModule(sourceFile) && sourceFile.moduleAugmentations.length && !resultHasExternalModuleIndicator) { // if file was external module with augmentations - this fact should be preserved in .d.ts as well. - // in case if we didn't write any external module specifiers in .d.ts we need to emit something + // in case if we didn't write any external module specifiers in .d.ts we need to emit something // that will force compiler to think that this file is an external module - 'export {}' is a reasonable choice here. write("export {};"); writeLine(); @@ -349,7 +349,7 @@ namespace ts { const jsDocComments = getJsDocCommentsFromText(declaration, currentText); emitNewLineBeforeLeadingComments(currentLineMap, writer, declaration, jsDocComments); // jsDoc comments are emitted at /*leading comment1 */space/*leading comment*/space - emitComments(currentText, currentLineMap, writer, jsDocComments, /*trailingSeparator*/ true, newLine, writeCommentRange); + emitComments(currentText, currentLineMap, writer, jsDocComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeCommentRange); } } @@ -736,7 +736,7 @@ namespace ts { function emitExternalModuleSpecifier(parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration) { // emitExternalModuleSpecifier is usually called when we emit something in the.d.ts file that will make it an external module (i.e. import/export declarations). - // the only case when it is not true is when we call it to emit correct name for module augmentation - d.ts files with just module augmentations are not considered + // the only case when it is not true is when we call it to emit correct name for module augmentation - d.ts files with just module augmentations are not considered // external modules since they are indistingushable from script files with ambient modules. To fix this in such d.ts files we'll emit top level 'export {}' // so compiler will treat them as external modules. resultHasExternalModuleIndicator = resultHasExternalModuleIndicator || parent.kind !== SyntaxKind.ModuleDeclaration; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index ebac2996765..3edbc2c6cce 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1919,7 +1919,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge if (multiLine) { decreaseIndent(); - writeLine(); } write(")"); @@ -2246,6 +2245,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge return node; } + function skipAssertions(node: Expression): Expression { + while (node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression) { + node = (node).expression; + } + return node; + } + function emitCallTarget(node: Expression): Expression { if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword) { emit(node); @@ -2695,7 +2701,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge } function synthesizedNodeStartsOnNewLine(node: Node) { - return nodeIsSynthesized(node) && (node).startsOnNewLine; + return nodeIsSynthesized(node) && node.startsOnNewLine; } function emitConditionalExpression(node: ConditionalExpression) { @@ -3312,8 +3318,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge // we can't reuse 'arr' because it might be modified within the body of the loop. const counter = createTempVariable(TempFlags._i); const rhsReference = createSynthesizedNode(SyntaxKind.Identifier) as Identifier; - rhsReference.text = node.expression.kind === SyntaxKind.Identifier ? - makeUniqueName((node.expression).text) : + const expressionWithoutAssertions = skipAssertions(node.expression); + rhsReference.text = expressionWithoutAssertions.kind === SyntaxKind.Identifier ? + makeUniqueName((expressionWithoutAssertions).text) : makeTempVariableName(TempFlags.Auto); // This is the let keyword for the counter and rhsReference. The let keyword for @@ -4328,7 +4335,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge writeLine(); emitStart(restParam); emitNodeWithCommentsAndWithoutSourcemap(restParam.name); - write("[" + tempName + " - " + restIndex + "] = arguments[" + tempName + "];"); + write(restIndex > 0 + ? `[${tempName} - ${restIndex}] = arguments[${tempName}];` + : `[${tempName}] = arguments[${tempName}];`); emitEnd(restParam); decreaseIndent(); writeLine(); @@ -5344,6 +5353,18 @@ const _super = (function (geti, seti) { write(" = "); } + const staticProperties = getInitializedProperties(node, /*isStatic*/ true); + const isClassExpressionWithStaticProperties = staticProperties.length > 0 && node.kind === SyntaxKind.ClassExpression; + let tempVariable: Identifier; + + if (isClassExpressionWithStaticProperties) { + tempVariable = createAndRecordTempVariable(TempFlags.Auto); + write("("); + increaseIndent(); + emit(tempVariable); + write(" = "); + } + write("(function ("); const baseTypeNode = getClassExtendsHeritageClauseElement(node); if (baseTypeNode) { @@ -5373,9 +5394,6 @@ const _super = (function (geti, seti) { writeLine(); emitConstructor(node, baseTypeNode); emitMemberFunctionsForES5AndLower(node); - emitPropertyDeclarations(node, getInitializedProperties(node, /*isStatic*/ true)); - writeLine(); - emitDecoratorsOfClass(node, /*decoratedClassAlias*/ undefined); writeLine(); emitToken(SyntaxKind.CloseBraceToken, node.members.end, () => { write("return "); @@ -5402,7 +5420,23 @@ const _super = (function (geti, seti) { write("))"); if (node.kind === SyntaxKind.ClassDeclaration) { write(";"); + emitPropertyDeclarations(node, staticProperties); + writeLine(); + emitDecoratorsOfClass(node, /*decoratedClassAlias*/ undefined); } + else if (isClassExpressionWithStaticProperties) { + for (const property of staticProperties) { + write(","); + writeLine(); + emitPropertyDeclaration(node, property, /*receiver*/ tempVariable, /*isExpression*/ true); + } + write(","); + writeLine(); + emit(tempVariable); + decreaseIndent(); + write(")"); + } + emitEnd(node); if (node.kind === SyntaxKind.ClassDeclaration) { @@ -7941,7 +7975,7 @@ const _super = (function (geti, seti) { emitNewLineBeforeLeadingComments(currentLineMap, writer, node, leadingComments); // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space - emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment); + emitComments(currentText, currentLineMap, writer, leadingComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); } function emitTrailingComments(node: Node) { @@ -7953,7 +7987,7 @@ const _super = (function (geti, seti) { const trailingComments = getTrailingCommentsToEmit(node); // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/ - emitComments(currentText, currentLineMap, writer, trailingComments, /*trailingSeparator*/ false, newLine, writeComment); + emitComments(currentText, currentLineMap, writer, trailingComments, /*leadingSeparator*/ true, /*trailingSeparator*/ false, newLine, writeComment); } /** @@ -7968,8 +8002,8 @@ const _super = (function (geti, seti) { const trailingComments = getTrailingCommentRanges(currentText, pos); - // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/ - emitComments(currentText, currentLineMap, writer, trailingComments, /*trailingSeparator*/ true, newLine, writeComment); + // trailing comments of a position are emitted at /*trailing comment1 */space/*trailing comment*/space + emitComments(currentText, currentLineMap, writer, trailingComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); } function emitLeadingCommentsOfPositionWorker(pos: number) { @@ -7990,7 +8024,7 @@ const _super = (function (geti, seti) { emitNewLineBeforeLeadingComments(currentLineMap, writer, { pos: pos, end: pos }, leadingComments); // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space - emitComments(currentText, currentLineMap, writer, leadingComments, /*trailingSeparator*/ true, newLine, writeComment); + emitComments(currentText, currentLineMap, writer, leadingComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); } function emitDetachedCommentsAndUpdateCommentsInfo(node: TextRange) { diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 0b0505bb50f..809f5e425e7 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -22,7 +22,7 @@ namespace ts { return node; } - export function createNodeArray(elements?: T[], location?: TextRange): NodeArray { + export function createNodeArray(elements?: T[], location?: TextRange, hasTrailingComma?: boolean): NodeArray { if (elements) { if (isNodeArray(elements)) { return elements; @@ -42,6 +42,10 @@ namespace ts { array.end = -1; } + if (hasTrailingComma) { + array.hasTrailingComma = true; + } + array.arrayKind = ArrayKind.NodeArray; return array; } @@ -92,7 +96,7 @@ namespace ts { } export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node { - const node = createNode(kind, /*location*/ undefined); + const node = createNode(kind, /*location*/ undefined); node.startsOnNewLine = startsOnNewLine; return node; } @@ -145,6 +149,13 @@ namespace ts { return clone; } + /** + * Creates a shallow, memberwise clone of a node for mutation. + */ + export function getMutableNode(node: T): T { + return cloneNode(node, node, node.flags, node.parent, node); + } + export function createNodeArrayNode(elements: T[]): NodeArrayNode { const node = >createSynthesizedNode(SyntaxKind.NodeArrayNode); node.nodes = createNodeArray(elements); @@ -153,20 +164,20 @@ namespace ts { // Literals - export function createLiteral(value: string): StringLiteral; - export function createLiteral(value: number): LiteralExpression; - export function createLiteral(value: string | number | boolean): PrimaryExpression; - export function createLiteral(value: string | number | boolean): PrimaryExpression { + export function createLiteral(value: string, location?: TextRange): StringLiteral; + export function createLiteral(value: number, location?: TextRange): LiteralExpression; + export function createLiteral(value: string | number | boolean, location?: TextRange): PrimaryExpression; + export function createLiteral(value: string | number | boolean, location?: TextRange): PrimaryExpression { if (typeof value === "number") { - const node = createNode(SyntaxKind.NumericLiteral); + const node = createNode(SyntaxKind.NumericLiteral, location); node.text = value.toString(); return node; } else if (typeof value === "boolean") { - return createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword); + return createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword, location); } else { - const node = createNode(SyntaxKind.StringLiteral); + const node = createNode(SyntaxKind.StringLiteral, location); node.text = String(value); return node; } @@ -203,8 +214,8 @@ namespace ts { return node; } - export function createThis() { - const node = createNode(SyntaxKind.ThisKeyword); + export function createThis(location?: TextRange) { + const node = createNode(SyntaxKind.ThisKeyword, location); return node; } @@ -267,8 +278,8 @@ namespace ts { return node; } - export function createParameter(name: string | Identifier | BindingPattern, initializer?: Expression) { - const node = createNode(SyntaxKind.Parameter); + export function createParameter(name: string | Identifier | BindingPattern, initializer?: Expression, location?: TextRange) { + const node = createNode(SyntaxKind.Parameter, location); node.decorators = undefined; node.modifiers = undefined; node.dotDotDotToken = undefined; @@ -279,7 +290,6 @@ namespace ts { return node; } - // Expression export function createArrayLiteral(elements?: Expression[]) { @@ -288,8 +298,8 @@ namespace ts { return node; } - export function createObjectLiteral(properties?: ObjectLiteralElement[]) { - const node = createNode(SyntaxKind.ObjectLiteralExpression); + export function createObjectLiteral(properties?: ObjectLiteralElement[], location?: TextRange) { + const node = createNode(SyntaxKind.ObjectLiteralExpression, location); node.properties = createNodeArray(properties); return node; } @@ -316,6 +326,13 @@ namespace ts { return node; } + export function createNew(expression: Expression, argumentsArray: Expression[], location?: TextRange) { + const node = createNode(SyntaxKind.NewExpression, location); + node.expression = parenthesizeForAccess(expression); + node.arguments = argumentsArray ? createNodeArray(argumentsArray) : undefined; + return node; + } + export function createParen(expression: Expression, location?: TextRange) { const node = createNode(SyntaxKind.ParenthesizedExpression, location); node.expression = expression; @@ -347,13 +364,27 @@ namespace ts { export function createTypeOf(expression: Expression) { const node = createNode(SyntaxKind.TypeOfExpression); - node.expression = parenthesizeForUnary(expression); + node.expression = parenthesizePrefixOperand(expression); return node; } export function createVoid(expression: Expression) { const node = createNode(SyntaxKind.VoidExpression); - node.expression = parenthesizeForUnary(expression); + node.expression = parenthesizePrefixOperand(expression); + return node; + } + + export function createPrefix(operator: SyntaxKind, operand: Expression, location?: TextRange) { + const node = createNode(SyntaxKind.PrefixUnaryExpression, location); + node.operator = operator; + node.operand = parenthesizePrefixOperand(operand); + return node; + } + + export function createPostfix(operand: Expression, operator: SyntaxKind, location?: TextRange) { + const node = createNode(SyntaxKind.PostfixUnaryExpression, location); + node.operand = parenthesizePostfixOperand(operand); + node.operator = operator; return node; } @@ -442,14 +473,72 @@ namespace ts { return node; } + export function createEmptyStatement(location: TextRange) { + return createNode(SyntaxKind.EmptyStatement, location); + } + export function createStatement(expression: Expression, location?: TextRange): ExpressionStatement { const node = createNode(SyntaxKind.ExpressionStatement, location); node.expression = expression; return node; } - export function createReturn(expression?: Expression): ReturnStatement { - const node = createSynthesizedNode(SyntaxKind.ReturnStatement); + export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement, location?: TextRange) { + const node = createNode(SyntaxKind.IfStatement, location); + node.expression = expression; + node.thenStatement = thenStatement; + node.elseStatement = elseStatement; + return node; + } + + export function createFor(initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement, location?: TextRange) { + const node = createNode(SyntaxKind.ForStatement, location); + node.initializer = initializer; + node.condition = condition; + node.incrementor = incrementor; + node.statement = statement; + return node; + } + + export function createLabel(label: string | Identifier, statement: Statement, location?: TextRange) { + const node = createNode(SyntaxKind.LabeledStatement, location); + node.label = typeof label === "string" ? createIdentifier(label) : label; + node.statement = statement; + return node; + } + + export function createDo(expression: Expression, statement: Statement, location?: TextRange) { + const node = createNode(SyntaxKind.DoStatement, location); + node.expression = expression; + node.statement = statement; + return node; + } + + export function createWhile(statement: Statement, expression: Expression, location?: TextRange) { + const node = createNode(SyntaxKind.WhileStatement, location); + node.statement = statement; + node.expression = expression; + return node; + } + + export function createForIn(initializer: ForInitializer, expression: Expression, statement: Statement, location?: TextRange) { + const node = createNode(SyntaxKind.ForInStatement, location); + node.initializer = initializer; + node.expression = expression; + node.statement = statement; + return node; + } + + export function createForOf(initializer: ForInitializer, expression: Expression, statement: Statement, location?: TextRange) { + const node = createNode(SyntaxKind.ForOfStatement, location); + node.initializer = initializer; + node.expression = expression; + node.statement = statement; + return node; + } + + export function createReturn(expression?: Expression, location?: TextRange): ReturnStatement { + const node = createNode(SyntaxKind.ReturnStatement, location); node.expression = expression; return node; } @@ -516,9 +605,9 @@ namespace ts { // Property assignments - export function createPropertyAssignment(name: PropertyName, initializer: Expression) { - const node = createNode(SyntaxKind.PropertyAssignment); - node.name = name; + export function createPropertyAssignment(name: string | PropertyName, initializer: Expression, location?: TextRange) { + const node = createNode(SyntaxKind.PropertyAssignment, location); + node.name = typeof name === "string" ? createIdentifier(name) : name; node.questionToken = undefined; node.initializer = initializer; return node; @@ -526,18 +615,18 @@ namespace ts { // Compound nodes + export function createComma(left: Expression, right: Expression) { + return createBinary(left, SyntaxKind.CommaToken, right); + } + + export function createLessThan(left: Expression, right: Expression, location?: TextRange) { + return createBinary(left, SyntaxKind.LessThanToken, right, location); + } + export function createAssignment(left: Expression, right: Expression, location?: TextRange) { return createBinary(left, SyntaxKind.EqualsToken, right, location); } - export function createLogicalAnd(left: Expression, right: Expression) { - return createBinary(left, SyntaxKind.AmpersandAmpersandToken, right); - } - - export function createLogicalOr(left: Expression, right: Expression) { - return createBinary(left, SyntaxKind.BarBarToken, right); - } - export function createStrictEquality(left: Expression, right: Expression) { return createBinary(left, SyntaxKind.EqualsEqualsEqualsToken, right); } @@ -546,8 +635,28 @@ namespace ts { return createBinary(left, SyntaxKind.ExclamationEqualsEqualsToken, right); } - export function createComma(left: Expression, right: Expression) { - return createBinary(left, SyntaxKind.CommaToken, right); + export function createAdd(left: Expression, right: Expression) { + return createBinary(left, SyntaxKind.PlusToken, right); + } + + export function createSubtract(left: Expression, right: Expression) { + return createBinary(left, SyntaxKind.MinusToken, right); + } + + export function createPostfixIncrement(operand: Expression, location?: TextRange) { + return createPostfix(operand, SyntaxKind.PlusPlusToken, location); + } + + export function createLogicalAnd(left: Expression, right: Expression) { + return createBinary(left, SyntaxKind.AmpersandAmpersandToken, right); + } + + export function createLogicalOr(left: Expression, right: Expression) { + return createBinary(left, SyntaxKind.BarBarToken, right); + } + + export function createLogicalNot(operand: Expression) { + return createPrefix(SyntaxKind.ExclamationToken, operand); } export function createVoidZero() { @@ -566,6 +675,28 @@ namespace ts { return node; } + export function createFunctionCall(func: Expression, thisArg: Expression, argumentsList: Expression[], location?: TextRange) { + return createCall( + createPropertyAccess(func, "call"), + [ + thisArg, + ...argumentsList + ], + location + ); + } + + export function createFunctionApply(func: Expression, thisArg: Expression, argumentsExpression: Expression, location?: TextRange) { + return createCall( + createPropertyAccess(func, "apply"), + [ + thisArg, + argumentsExpression + ], + location + ); + } + export function createArraySlice(array: Expression, start?: number | Expression) { const argumentsList: Expression[] = []; if (start !== undefined) { @@ -575,6 +706,13 @@ namespace ts { return createCall(createPropertyAccess(array, "slice"), argumentsList); } + export function createArrayConcat(array: Expression, values: Expression[]) { + return createCall( + createPropertyAccess(array, "concat"), + values + ); + } + export function createMathPow(left: Expression, right: Expression, location?: TextRange) { return createCall( createPropertyAccess(createIdentifier("Math"), "pow"), @@ -618,6 +756,16 @@ namespace ts { // Helpers + export function createExtendsHelper(name: Identifier) { + return createCall( + createIdentifier("__extends"), + [ + name, + createIdentifier("_super") + ] + ); + } + export function createParamHelper(expression: Expression, parameterOffset: number) { return createCall( createIdentifier("__param"), @@ -671,6 +819,63 @@ namespace ts { ); } + export function createHasOwnProperty(target: LeftHandSideExpression, propertyName: Expression) { + return createCall( + createPropertyAccess(target, "hasOwnProperty"), + [propertyName] + ); + } + + function createPropertyDescriptor({ get, set, value, enumerable, configurable, writable }: PropertyDescriptorOptions, preferNewLine?: boolean, location?: TextRange) { + const properties: ObjectLiteralElement[] = []; + addPropertyAssignment(properties, "get", get, preferNewLine); + addPropertyAssignment(properties, "set", set, preferNewLine); + addPropertyAssignment(properties, "value", value, preferNewLine); + addPropertyAssignment(properties, "enumerable", enumerable, preferNewLine); + addPropertyAssignment(properties, "configurable", configurable, preferNewLine); + addPropertyAssignment(properties, "writable", writable, preferNewLine); + return createObjectLiteral(properties, location); + } + + function addPropertyAssignment(properties: ObjectLiteralElement[], name: string, value: boolean | Expression, preferNewLine: boolean) { + if (value !== undefined) { + const property = createPropertyAssignment( + name, + typeof value === "boolean" ? createLiteral(value) : value + ); + + if (preferNewLine) { + property.startsOnNewLine = true; + } + + addNode(properties, property); + } + } + + export interface PropertyDescriptorOptions { + get?: Expression; + set?: Expression; + value?: Expression; + enumerable?: boolean | Expression; + configurable?: boolean | Expression; + writable?: boolean | Expression; + } + + export function createObjectDefineProperty(target: Expression, memberName: Expression, descriptor: PropertyDescriptorOptions, preferNewLine?: boolean, location?: TextRange) { + return createCall( + createPropertyAccess( + createIdentifier("Object"), + "defineProperty" + ), + [ + target, + memberName, + createPropertyDescriptor(descriptor, preferNewLine) + ], + location + ); + } + function createObjectCreate(prototype: Expression) { return createCall( createPropertyAccess(createIdentifier("Object"), "create"), @@ -686,7 +891,7 @@ namespace ts { target, createIdentifier("name") ) - ) + ); } function createSeti(target: LeftHandSideExpression) { @@ -839,8 +1044,15 @@ namespace ts { : cloneNode(node); } + export function createExpressionForPropertyName(memberName: PropertyName, location?: TextRange): Expression { + return isIdentifier(memberName) ? createLiteral(memberName.text, location) + : isComputedPropertyName(memberName) ? cloneNode(memberName.expression, location) + : cloneNode(memberName, location); + } + // Utilities + /** * Wraps the operand to a BinaryExpression in parentheses if they are needed to preserve the intended * order of operations. @@ -850,11 +1062,7 @@ namespace ts { * @param isLeftSideOfBinary A value indicating whether the operand is the left side of the * BinaryExpression. */ - function parenthesizeBinaryOperand(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean) { - // When diagnosing whether the expression needs parentheses, the decision should be based - // on the innermost expression in a chain of nested type assertions. - operand = skipAssertions(operand); - + export function parenthesizeBinaryOperand(binaryOperator: SyntaxKind, operand: Expression, isLeftSideOfBinary: boolean) { // If the resulting expression is already parenthesized, we do not need to do any further processing. if (operand.kind === SyntaxKind.ParenthesizedExpression) { return operand; @@ -968,11 +1176,7 @@ namespace ts { * * @param expr The expression node. */ - function parenthesizeForAccess(expr: Expression): LeftHandSideExpression { - // When diagnosing whether the expression needs parentheses, the decision should be based - // on the innermost expression in a chain of nested type assertions. - expr = skipAssertions(expr); - + export function parenthesizeForAccess(expression: Expression): LeftHandSideExpression { // isLeftHandSideExpression is almost the correct criterion for when it is not necessary // to parenthesize the expression before a dot. The known exceptions are: // @@ -981,38 +1185,90 @@ namespace ts { // NumericLiteral // 1.x -> not the same as (1).x // - if (isLeftHandSideExpression(expr) && - expr.kind !== SyntaxKind.NewExpression && - expr.kind !== SyntaxKind.NumericLiteral) { - return expr; + if (isLeftHandSideExpression(expression) && + expression.kind !== SyntaxKind.NewExpression && + expression.kind !== SyntaxKind.NumericLiteral) { + return expression; } - return createParen(expr); + return createParen(expression, /*location*/ expression); } - function parenthesizeForUnary(operand: Expression) { - if (isUnaryExpression(operand)) { - return operand; + export function parenthesizePostfixOperand(operand: Expression) { + return isLeftHandSideExpression(operand) + ? operand + : createParen(operand, /*location*/ operand); + } + + export function parenthesizePrefixOperand(operand: Expression) { + return isUnaryExpression(operand) + ? operand + : createParen(operand, /*location*/ operand); + } + + export function parenthesizeExpressionForList(expression: Expression) { + const expressionPrecedence = getExpressionPrecedence(expression); + const commaPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, SyntaxKind.CommaToken); + return expressionPrecedence > commaPrecedence + ? expression + : createParen(expression, /*location*/ expression); + } + + export function parenthesizeExpressionForExpressionStatement(expression: Expression) { + if (isCallExpression(expression)) { + const callee = expression.expression; + if (callee.kind === SyntaxKind.FunctionExpression + || callee.kind === SyntaxKind.ArrowFunction) { + const clone = cloneNode(expression, expression, expression.flags, expression.parent, expression); + clone.expression = createParen(callee, /*location*/ callee); + return clone; + } + } + else if (getLeftmostExpression(expression).kind === SyntaxKind.ObjectLiteralExpression) { + return createParen(expression, /*location*/ expression); } - return createParen(operand); + return expression; } - /** - * Skips past any TypeAssertionExpression or AsExpression nodes to their inner expression. - * - * @param node The expression node. - */ - function skipAssertions(node: Expression) { - while (node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression) { - node = (node).expression; + function getLeftmostExpression(node: Expression): Expression { + while (true) { + switch (node.kind) { + case SyntaxKind.PostfixUnaryExpression: + node = (node).operand; + continue; + + case SyntaxKind.BinaryExpression: + node = (node).left; + continue; + + case SyntaxKind.ConditionalExpression: + node = (node).condition; + continue; + + case SyntaxKind.CallExpression: + case SyntaxKind.ElementAccessExpression: + case SyntaxKind.PropertyAccessExpression: + node = (node).expression; + continue; + } + + return node; + } + } + + export function skipParentheses(node: Expression): Expression { + while (node.kind === SyntaxKind.ParenthesizedExpression + || node.kind === SyntaxKind.TypeAssertionExpression + || node.kind === SyntaxKind.AsExpression) { + node = (node).expression; } return node; } export function startOnNewLine(node: T): T { - (node).startsOnNewLine = true; + node.startsOnNewLine = true; return node; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index b21f9919f45..c4813ac9932 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4069,6 +4069,10 @@ namespace ts { function parseBlock(ignoreMissingOpenBrace: boolean, diagnosticMessage?: DiagnosticMessage): Block { const node = createNode(SyntaxKind.Block); if (parseExpected(SyntaxKind.OpenBraceToken, diagnosticMessage) || ignoreMissingOpenBrace) { + if (scanner.hasPrecedingLineBreak()) { + node.multiLine = true; + } + node.statements = parseList(ParsingContext.BlockStatements, parseStatement); parseExpected(SyntaxKind.CloseBraceToken); } diff --git a/src/compiler/printer.ts b/src/compiler/printer.ts index 8a0725f5236..a1d284dd42b 100644 --- a/src/compiler/printer.ts +++ b/src/compiler/printer.ts @@ -119,13 +119,30 @@ const _super = (function (geti, seti) { const transformers = getTransformers(compilerOptions).concat(initializePrinter); const writer = createTextWriter(newLine); - const { write, writeTextOfNode, writeLine, increaseIndent, decreaseIndent } = writer; + const { + write, + writeTextOfNode, + writeLine, + increaseIndent, + decreaseIndent + } = writer; const sourceMap = compilerOptions.sourceMap || compilerOptions.inlineSourceMap ? createSourceMapWriter(host, writer) : getNullSourceMapWriter(); - const { emitStart, emitEnd, emitPos } = sourceMap; + const { + emitStart, + emitEnd, + emitPos + } = sourceMap; const comments = createCommentWriter(host, writer, sourceMap); - const { emitDetachedComments, emitLeadingComments, emitTrailingComments, getLeadingCommentsToEmit, getTrailingCommentsToEmit } = comments; + const { + getLeadingComments, + getTrailingComments, + getTrailingCommentsOfPosition, + emitLeadingComments, + emitTrailingComments, + emitDetachedComments + } = comments; let context: TransformationContext; let startLexicalEnvironment: () => void; @@ -198,7 +215,7 @@ const _super = (function (geti, seti) { onAfterEmitNode = undefined; isUniqueName = undefined; temporaryVariables = undefined; - tempFlags = 0; + tempFlags = TempFlags.Auto; currentSourceFile = undefined; currentText = undefined; extendsEmitted = false; @@ -233,14 +250,22 @@ const _super = (function (geti, seti) { } function emit(node: Node) { + emitWithWorker(node, emitWorker); + } + + function emitExpression(node: Expression) { + emitWithWorker(node, emitExpressionWorker); + } + + function emitWithWorker(node: Node, emitWorker: (node: Node) => void) { if (node) { const adviseOnEmit = isEmitNotificationEnabled(node); if (adviseOnEmit && onBeforeEmitNode) { onBeforeEmitNode(node); } - const leadingComments = getLeadingCommentsToEmit(node); - const trailingComments = getTrailingCommentsToEmit(node); + const leadingComments = getLeadingComments(node, getNotEmittedParent); + const trailingComments = getTrailingComments(node, getNotEmittedParent); emitLeadingComments(node, leadingComments); emitStart(node); emitWorker(node); @@ -253,7 +278,18 @@ const _super = (function (geti, seti) { } } - function emitWorker(node: Node) { + function getNotEmittedParent(node: Node): Node { + if (getNodeEmitFlags(node) & NodeEmitFlags.EmitCommentsOfNotEmittedParent) { + const parent = getOriginalNode(node).parent; + if (getNodeEmitFlags(parent) & NodeEmitFlags.IsNotEmittedNode) { + return parent; + } + } + + return undefined; + } + + function emitWorker(node: Node): void { const kind = node.kind; switch (kind) { // Pseudo-literals @@ -358,7 +394,7 @@ const _super = (function (geti, seti) { case SyntaxKind.ExpressionWithTypeArguments: return emitExpressionWithTypeArguments(node); case SyntaxKind.ThisType: - return write("this"); + return emitThisType(node); case SyntaxKind.StringLiteralType: return emitLiteral(node); @@ -374,7 +410,7 @@ const _super = (function (geti, seti) { case SyntaxKind.TemplateSpan: return emitTemplateSpan(node); case SyntaxKind.SemicolonClassElement: - return write(";"); + return emitSemicolonClassElement(node); // Statements case SyntaxKind.Block: @@ -382,7 +418,7 @@ const _super = (function (geti, seti) { case SyntaxKind.VariableStatement: return emitVariableStatement(node); case SyntaxKind.EmptyStatement: - return write(";"); + return emitEmptyStatement(node); case SyntaxKind.ExpressionStatement: return emitExpressionStatement(node); case SyntaxKind.IfStatement: @@ -501,23 +537,11 @@ const _super = (function (geti, seti) { // JSDoc nodes (ignored) } - if (isExpressionKind(kind)) { + if (isExpression(node)) { return emitExpressionWorker(node); } } - function emitExpression(node: Expression) { - if (node) { - const leadingComments = getLeadingCommentsToEmit(node); - const trailingComments = getTrailingCommentsToEmit(node); - emitLeadingComments(node, leadingComments); - emitStart(node); - emitExpressionWorker(node); - emitEnd(node); - emitTrailingComments(node, trailingComments); - } - } - function emitExpressionWorker(node: Node) { const kind = node.kind; if (isExpressionSubstitutionEnabled(node) && tryEmitSubstitute(node, expressionSubstitution)) { @@ -641,7 +665,7 @@ const _super = (function (geti, seti) { const text = temporaryVariables[nodeId] || (temporaryVariables[nodeId] = makeTempVariableName(tempKindToFlags(node.tempKind))); write(text); } - else if (nodeIsSynthesized(node)) { + else if (nodeIsSynthesized(node) || !node.parent) { if (getNodeEmitFlags(node) & NodeEmitFlags.UMDDefine) { writeLines(umdHelper); } @@ -741,13 +765,13 @@ const _super = (function (geti, seti) { emitModifiers(node, node.modifiers); writeIfPresent(node.asteriskToken, "*"); emit(node.name); - emitSignatureAndBody(node); + emitSignatureAndBody(node, emitSignatureHead); } function emitConstructor(node: ConstructorDeclaration) { emitModifiers(node, node.modifiers); write("constructor"); - emitSignatureAndBody(node); + emitSignatureAndBody(node, emitSignatureHead); } function emitAccessorDeclaration(node: AccessorDeclaration) { @@ -755,7 +779,7 @@ const _super = (function (geti, seti) { emitModifiers(node, node.modifiers); write(node.kind === SyntaxKind.GetAccessor ? "get " : "set "); emit(node.name); - emitSignatureAndBody(node); + emitSignatureAndBody(node, emitSignatureHead); } function emitCallSignature(node: CallSignatureDeclaration) { @@ -785,6 +809,10 @@ const _super = (function (geti, seti) { write(";"); } + function emitSemicolonClassElement(node: SemicolonClassElement) { + write(";"); + } + // // Types // @@ -851,6 +879,10 @@ const _super = (function (geti, seti) { write(")"); } + function emitThisType(node: ThisTypeNode) { + write("this"); + } + // // Binding patterns // @@ -896,7 +928,7 @@ const _super = (function (geti, seti) { write("[]"); } else { - const preferNewLine = getNodeEmitFlags(node) & NodeEmitFlags.MultiLine ? ListFormat.PreferNewLine : ListFormat.None; + const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; emitExpressionList(node, elements, ListFormat.ArrayLiteralExpressionElements | preferNewLine); } } @@ -907,7 +939,7 @@ const _super = (function (geti, seti) { write("{}"); } else { - const preferNewLine = getNodeEmitFlags(node) & NodeEmitFlags.MultiLine ? ListFormat.PreferNewLine : ListFormat.None; + const preferNewLine = node.multiLine ? ListFormat.PreferNewLine : ListFormat.None; const allowTrailingComma = languageVersion >= ScriptTarget.ES5 ? ListFormat.AllowTrailingComma : ListFormat.None; emitList(node, properties, ListFormat.ObjectLiteralExpressionProperties | allowTrailingComma | preferNewLine); } @@ -998,27 +1030,8 @@ const _super = (function (geti, seti) { function emitArrowFunction(node: ArrowFunction) { emitDecorators(node, node.decorators); emitModifiers(node, node.modifiers); - const body = node.body; - if (isBlock(body)) { - const savedTempFlags = tempFlags; - tempFlags = 0; - startLexicalEnvironment(); - emitArrowFunctionHead(node); - write(" {"); + emitSignatureAndBody(node, emitArrowFunctionHead); - const startingLine = writer.getLine(); - emitBlockFunctionBody(node, body); - - const endingLine = writer.getLine(); - emitLexicalEnvironment(endLexicalEnvironment(), /*newLine*/ startingLine !== endingLine); - tempFlags = savedTempFlags; - write("}"); - } - else { - emitArrowFunctionHead(node); - write(" "); - emitExpression(body); - } } function emitArrowFunctionHead(node: ArrowFunction) { @@ -1186,6 +1199,10 @@ const _super = (function (geti, seti) { write(";"); } + function emitEmptyStatement(node: EmptyStatement) { + write(";"); + } + function emitExpressionStatement(node: ExpressionStatement) { emitExpression(node.expression); write(";"); @@ -1353,25 +1370,27 @@ const _super = (function (geti, seti) { emitModifiers(node, node.modifiers); write(node.asteriskToken ? "function* " : "function "); emit(node.name); - emitSignatureAndBody(node); + emitSignatureAndBody(node, emitSignatureHead); } - function emitSignatureAndBody(node: FunctionDeclaration | FunctionExpression | MethodDeclaration | AccessorDeclaration | ConstructorDeclaration) { + function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) { const body = node.body; if (body) { - const savedTempFlags = tempFlags; - tempFlags = 0; - startLexicalEnvironment(); - emitSignatureHead(node); - write(" {"); - - const startingLine = writer.getLine(); - emitBlockFunctionBody(node, body); - - const endingLine = writer.getLine(); - emitLexicalEnvironment(endLexicalEnvironment(), /*newLine*/ startingLine !== endingLine); - write("}"); - tempFlags = savedTempFlags; + if (isBlock(body)) { + const savedTempFlags = tempFlags; + tempFlags = 0; + startLexicalEnvironment(); + emitSignatureHead(node); + write(" {"); + emitBlockFunctionBody(node, body); + write("}"); + tempFlags = savedTempFlags; + } + else { + emitSignatureHead(node); + write(" "); + emitExpression(body); + } } else { emitSignatureHead(node); @@ -1388,37 +1407,49 @@ const _super = (function (geti, seti) { function shouldEmitBlockFunctionBodyOnSingleLine(parentNode: Node, body: Block) { const originalNode = getOriginalNode(parentNode); - if (isFunctionLike(originalNode) && !nodeIsSynthesized(originalNode) && rangeEndIsOnSameLineAsRangeStart(originalNode.body, originalNode.body)) { - for (const statement of body.statements) { - if (synthesizedNodeStartsOnNewLine(statement)) { - return false; + if (isFunctionLike(originalNode) && !nodeIsSynthesized(originalNode)) { + const body = originalNode.body; + if (isBlock(body)) { + if (rangeEndIsOnSameLineAsRangeStart(body, body)) { + for (const statement of body.statements) { + if (synthesizedNodeStartsOnNewLine(statement)) { + return false; + } + } + + return true; } } - - if (originalNode.kind === SyntaxKind.ArrowFunction && !rangeEndIsOnSameLineAsRangeStart((originalNode).equalsGreaterThanToken, originalNode.body)) { - return false; + else { + return rangeEndIsOnSameLineAsRangeStart((originalNode).equalsGreaterThanToken, originalNode.body); } - - return true; } return false; } function emitBlockFunctionBody(parentNode: Node, body: Block) { - // Emit all the prologue directives (like "use strict"). + const startingLine = writer.getLine(); increaseIndent(); - const statements = body.statements; - const statementOffset = emitPrologueDirectives(statements, /*startWithNewLine*/ true); + emitDetachedComments(body.statements); + + // Emit all the prologue directives (like "use strict"). + const statementOffset = emitPrologueDirectives(body.statements, /*startWithNewLine*/ true); const helpersEmitted = emitHelpers(body); - decreaseIndent(); if (statementOffset === 0 && !helpersEmitted && shouldEmitBlockFunctionBodyOnSingleLine(parentNode, body)) { - emitList(body, statements, ListFormat.SingleLineFunctionBodyStatements); + decreaseIndent(); + emitList(body, body.statements, ListFormat.SingleLineFunctionBodyStatements); + increaseIndent(); } else { - emitList(body, statements, ListFormat.MultiLineFunctionBodyStatements, statementOffset); + emitList(body, body.statements, ListFormat.MultiLineFunctionBodyStatements, statementOffset); } + + const endingLine = writer.getLine(); + emitLexicalEnvironment(endLexicalEnvironment(), /*newLine*/ startingLine !== endingLine); + emitLeadingComments(collapseTextRange(body.statements, TextRangeCollapse.CollapseToEnd)); + decreaseIndent(); } function emitClassDeclaration(node: ClassDeclaration) { @@ -1688,6 +1719,8 @@ const _super = (function (geti, seti) { write("case "); emitExpression(node.expression); write(":"); + + debugger; emitCaseOrDefaultClauseStatements(node, node.statements); } @@ -1804,7 +1837,11 @@ const _super = (function (geti, seti) { } } - function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean) { + /** + * Emits any prologue directives at the start of a Statement list, returning the + * number of prologue directives written to the output. + */ + function emitPrologueDirectives(statements: Node[], startWithNewLine?: boolean): number { for (let i = 0; i < statements.length; i++) { if (isPrologueDirective(statements[i])) { if (startWithNewLine || i > 0) { @@ -2051,8 +2088,10 @@ const _super = (function (geti, seti) { } else { // Write the opening line terminator or leading whitespace. + let shouldEmitInterveningComments = true; if (shouldWriteLeadingLineTerminator(parentNode, children, format)) { writeLine(); + shouldEmitInterveningComments = false; } else if (format & ListFormat.SpaceBetweenBraces) { write(" "); @@ -2076,12 +2115,20 @@ const _super = (function (geti, seti) { // Write either a line terminator or whitespace to separate the elements. if (shouldWriteSeparatingLineTerminator(previousSibling, child, format)) { writeLine(); + shouldEmitInterveningComments = false; } else if (previousSibling) { write(" "); } } + if (shouldEmitInterveningComments) { + emitLeadingComments(child, getTrailingCommentsOfPosition(child.pos)); + } + else { + shouldEmitInterveningComments = true; + } + // Emit this child. emit(child); @@ -2175,7 +2222,7 @@ const _super = (function (geti, seti) { return true; } else if (format & ListFormat.PreserveLines) { - if (getNodeEmitFlags(parentNode) & NodeEmitFlags.MultiLine) { + if (format & ListFormat.PreferNewLine) { return true; } @@ -2217,10 +2264,10 @@ const _super = (function (geti, seti) { function shouldWriteClosingLineTerminator(parentNode: Node, children: NodeArray, format: ListFormat) { if (format & ListFormat.MultiLine) { - return true; + return (format & ListFormat.NoTrailingNewLine) === 0; } else if (format & ListFormat.PreserveLines) { - if (getNodeEmitFlags(parentNode) & NodeEmitFlags.MultiLine) { + if (format & ListFormat.PreferNewLine) { return true; } @@ -2242,7 +2289,7 @@ const _super = (function (geti, seti) { function synthesizedNodeStartsOnNewLine(node: Node, format?: ListFormat) { if (nodeIsSynthesized(node)) { - const startsOnNewLine = (node).startsOnNewLine; + const startsOnNewLine = node.startsOnNewLine; if (startsOnNewLine === undefined) { return (format & ListFormat.PreferNewLine) !== 0; } @@ -2274,8 +2321,12 @@ const _super = (function (geti, seti) { } function needsIndentation(parent: Node, node1: Node, node2: Node): boolean { + parent = skipSynthesizedParentheses(parent); + node1 = skipSynthesizedParentheses(node1); + node2 = skipSynthesizedParentheses(node2); + // Always use a newline for synthesized code if the synthesizer desires it. - if (synthesizedNodeStartsOnNewLine(node2)) { + if (node2.startsOnNewLine) { return true; } @@ -2285,6 +2336,14 @@ const _super = (function (geti, seti) { && !rangeEndIsOnSameLineAsRangeStart(node1, node2); } + function skipSynthesizedParentheses(node: Node) { + while (node.kind === SyntaxKind.ParenthesizedExpression && nodeIsSynthesized(node)) { + node = (node).expression; + } + + return node; + } + function getTextOfNode(node: Node, includeTrivia?: boolean) { if (nodeIsSynthesized(node) && (isLiteralExpression(node) || isIdentifier(node))) { return node.text; @@ -2304,9 +2363,9 @@ const _super = (function (geti, seti) { } function isSingleLineEmptyBlock(block: Block) { - return (getNodeEmitFlags(block) & NodeEmitFlags.MultiLine) === 0 && - block.statements.length === 0 && - rangeEndIsOnSameLineAsRangeStart(block, block); + return !block.multiLine + && block.statements.length === 0 + && rangeEndIsOnSameLineAsRangeStart(block, block); } function tempKindToFlags(kind: TempVariableKind) { @@ -2407,6 +2466,7 @@ const _super = (function (geti, seti) { // Other PreferNewLine = 1 << 15, // Prefer adding a LineTerminator between synthesized nodes. + NoTrailingNewLine = 1 << 16, // Do not emit a trailing NewLine for a MultiLine list. // Precomputed Formats TypeLiteralMembers = MultiLine | Indented, @@ -2424,7 +2484,7 @@ const _super = (function (geti, seti) { MultiLineBlockStatements = Indented | MultiLine, VariableDeclarationList = CommaDelimited | SingleLine, SingleLineFunctionBodyStatements = SingleLine | SpaceBetweenBraces, - MultiLineFunctionBodyStatements = MultiLine | Indented, + MultiLineFunctionBodyStatements = MultiLine, ClassHeritageClauses = SingleLine, ClassMembers = Indented | MultiLine, InterfaceMembers = Indented | MultiLine, @@ -2433,9 +2493,9 @@ const _super = (function (geti, seti) { NamedImportsOrExportsElements = CommaDelimited | AllowTrailingComma | SingleLine | SpaceBetweenBraces, JsxElementChildren = SingleLine, JsxElementAttributes = SingleLine, - CaseOrDefaultClauseStatements = Indented | MultiLine, + CaseOrDefaultClauseStatements = Indented | MultiLine | NoTrailingNewLine | OptionalIfEmpty, HeritageClauseTypes = CommaDelimited | SingleLine, - SourceFileStatements = MultiLine, + SourceFileStatements = MultiLine | NoTrailingNewLine, Decorators = MultiLine | Optional, TypeArguments = CommaDelimited | SingleLine | Indented | AngleBrackets | Optional, TypeParameters = CommaDelimited | SingleLine | Indented | AngleBrackets | Optional, diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 4a3d0cbc164..f10c327faa7 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -968,7 +968,8 @@ namespace ts { const start = new Date().getTime(); - const emitResult = emitFiles( + const fileEmitter = options.experimentalTransforms ? printFiles : emitFiles; + const emitResult = fileEmitter( emitResolver, getEmitHost(writeFileCallback), sourceFile); diff --git a/src/compiler/sourcemap.ts b/src/compiler/sourcemap.ts index 5e453b1b101..3866e4f9566 100644 --- a/src/compiler/sourcemap.ts +++ b/src/compiler/sourcemap.ts @@ -310,13 +310,13 @@ namespace ts { function emitStart(range: TextRange) { emitPos(getStartPos(range)); - if ((range).disableSourceMap) { + if (range.disableSourceMap) { disable(); } } function emitEnd(range: TextRange, stopOverridingEnd?: boolean) { - if ((range).disableSourceMap) { + if (range.disableSourceMap) { enable(); } diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index b2c1007b716..7d91fc7e474 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -1,50 +1,15 @@ /// -/// -/// -/// -/// -/// -/// -/// - /* @internal */ namespace ts { - const moduleTransformerMap: Map = { - [ModuleKind.ES6]: transformES6Module, - [ModuleKind.System]: transformSystemModule, - [ModuleKind.AMD]: transformModule, - [ModuleKind.CommonJS]: transformModule, - [ModuleKind.UMD]: transformModule, - [ModuleKind.None]: transformModule - }; - const enum SyntaxKindFeatureFlags { ExpressionSubstitution = 1 << 0, EmitNotifications = 1 << 1, } - export function getTransformers(compilerOptions: CompilerOptions) { - const jsx = compilerOptions.jsx; - const languageVersion = getEmitScriptTarget(compilerOptions); - const moduleKind = getEmitModuleKind(compilerOptions); const transformers: Transformer[] = []; - - transformers.push(transformTypeScript); - transformers.push(moduleTransformerMap[moduleKind]); - if (jsx === JsxEmit.React) { - transformers.push(transformJsx); - } - - if (languageVersion < ScriptTarget.ES7) { - transformers.push(transformES7); - } - - if (languageVersion < ScriptTarget.ES6) { - transformers.push(transformES6); - } - + // TODO(rbuckton): Add transformers return transformers; } @@ -63,7 +28,6 @@ namespace ts { const lexicalEnvironmentVariableDeclarationsStack: VariableDeclaration[][] = []; const lexicalEnvironmentFunctionDeclarationsStack: FunctionDeclaration[][] = []; const enabledSyntaxKindFeatures = new Array(SyntaxKind.Count); - let lexicalEnvironmentStackOffset = 0; let hoistedVariableDeclarations: VariableDeclaration[]; let hoistedFunctionDeclarations: FunctionDeclaration[]; @@ -84,8 +48,12 @@ namespace ts { hoistFunctionDeclaration, startLexicalEnvironment, endLexicalEnvironment, + identifierSubstitution: node => node, + expressionSubstitution: node => node, enableExpressionSubstitution, isExpressionSubstitutionEnabled, + onBeforeEmitNode: node => { }, + onAfterEmitNode: node => { }, enableEmitNotification, isEmitNotificationEnabled, }; @@ -148,8 +116,9 @@ namespace ts { /** * Sets flags that control emit behavior of a node. */ - function setNodeEmitFlags(node: Node, flags: NodeEmitFlags) { + function setNodeEmitFlags(node: T, flags: NodeEmitFlags) { nodeEmitFlags[getNodeId(node)] = flags; + return node; } /** @@ -317,12 +286,17 @@ namespace ts { } if (hoistedVariableDeclarations) { - statements = append(statements, - createVariableStatement( - /*modifiers*/ undefined, - createVariableDeclarationList(hoistedVariableDeclarations) - ) + const statement = createVariableStatement( + /*modifiers*/ undefined, + createVariableDeclarationList(hoistedVariableDeclarations) ); + + if (!statements) { + statements = [statement]; + } + else { + statements.push(statement); + } } } diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index c21d81ac4d5..05b2350226b 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -50,7 +50,7 @@ namespace ts { function emitAssignment(name: Identifier, value: Expression, location: TextRange) { const expression = createAssignment(name, value, location); if (isSimpleExpression(value)) { - (expression).disableSourceMap = true; + expression.disableSourceMap = true; } aggregateTransformFlags(expression); @@ -82,7 +82,7 @@ namespace ts { function emitAssignment(name: Identifier, value: Expression, location: TextRange) { const declaration = createVariableDeclaration(name, value, location); if (isSimpleExpression(value)) { - (declaration).disableSourceMap = true; + declaration.disableSourceMap = true; } aggregateTransformFlags(declaration); @@ -117,7 +117,7 @@ namespace ts { } if (isSimpleExpression(value)) { - (declaration).disableSourceMap = true; + declaration.disableSourceMap = true; } declaration.original = original; @@ -169,7 +169,7 @@ namespace ts { function emitPendingAssignment(name: Expression, value: Expression, location: TextRange, original: Node) { const expression = createAssignment(name, value, location); if (isSimpleExpression(value)) { - (expression).disableSourceMap = true; + expression.disableSourceMap = true; } expression.original = original; @@ -199,7 +199,7 @@ namespace ts { function emitDestructuringAssignment(bindingTarget: Expression | ShorthandPropertyAssignment, value: Expression, location: TextRange) { // When emitting target = value use source map node to highlight, including any temporary assignments needed for this let target: Expression; - if (isShortHandPropertyAssignment(bindingTarget)) { + if (isShorthandPropertyAssignment(bindingTarget)) { const initializer = visitor ? visitNode(bindingTarget.objectAssignmentInitializer, visitor, isExpression) : bindingTarget.objectAssignmentInitializer; diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index 8ad85f153c9..00df9c8abdc 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -85,14 +85,14 @@ namespace ts { properties = undefined; } - addNode(segments, transformJsxSpreadAttributeToExpression(attr), isExpression); + addNode(segments, transformJsxSpreadAttributeToExpression(attr)); } else { if (!properties) { properties = []; } - addNode(properties, transformJsxAttributeToObjectLiteralElement(attr), isObjectLiteralElement); + addNode(properties, transformJsxAttributeToObjectLiteralElement(attr)); } } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 616457e8b32..8618e71f921 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -1772,7 +1772,7 @@ namespace ts { * * @param node The function node. */ - function visitFunctionDeclaration(node: FunctionDeclaration): OneOrMore { + function visitFunctionDeclaration(node: FunctionDeclaration): OneOrMany { if (shouldElideFunctionLikeDeclaration(node)) { return undefined; } @@ -2389,7 +2389,7 @@ namespace ts { * * @param node The import equals declaration node. */ - function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): OneOrMore { + function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): OneOrMany { Debug.assert(!isExternalModuleImportEqualsDeclaration(node)); if (shouldElideImportEqualsDeclaration(node)) { return undefined; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 847b00a1c97..2348c4d2b03 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -20,6 +20,7 @@ namespace ts { export interface TextRange { pos: number; end: number; + /* @internal */ disableSourceMap?: boolean; // Whether a synthesized text range disables source maps for its contents (used by transforms). } // token > SyntaxKind.Identifer => token is a keyword @@ -449,6 +450,7 @@ namespace ts { /* @internal */ id?: number; // Unique id (used to look up NodeLinks) parent?: Node; // Parent node (initialized by binding) /* @internal */ original?: Node; // The original node if this is an updated node. + /* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms). /* @internal */ jsDocComment?: JSDocComment; // JSDoc for the node, if it has any. Only for .js files. /* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding) /* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding) @@ -1124,6 +1126,7 @@ namespace ts { // @kind(SyntaxKind.Block) export interface Block extends Statement { statements: NodeArray; + /*@internal*/ multiLine?: boolean; } // @kind(SyntaxKind.VariableStatement) @@ -2466,6 +2469,7 @@ namespace ts { allowSyntheticDefaultImports?: boolean; allowJs?: boolean; /* @internal */ stripInternal?: boolean; + /* @internal */ experimentalTransforms?: boolean; // Skip checking lib.d.ts to help speed up tests. /* @internal */ skipDefaultLibCheck?: boolean; @@ -2508,10 +2512,8 @@ namespace ts { ES3 = 0, ES5 = 1, ES6 = 2, - ES7 = 3, ES2015 = ES6, - ES2016 = ES7, - Latest = ES7, + Latest = ES6, } export const enum LanguageVariant { @@ -2767,6 +2769,7 @@ namespace ts { ContainsParameterPropertyAssignments = 1 << 13, ContainsSpreadElementExpression = 1 << 14, ContainsComputedPropertyName = 1 << 15, + ContainsBlockScopedBinding = 1 << 16, // Assertions // - Bitmasks that are used to assert facts about the syntax of a node and its subtree. @@ -2779,12 +2782,12 @@ namespace ts { // - Bitmasks that exclude flags from propagating out of a specific context // into the subtree flags of their container. NodeExcludes = TypeScript | Jsx | ES7 | ES6, - ArrowFunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments, - FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments, - ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsParameterPropertyAssignments, - MethodOrAccessorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis, + ArrowFunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding, + FunctionExcludes = ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding, + ConstructorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding, + MethodOrAccessorExcludes = ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding, ClassExcludes = ContainsDecorators | ContainsPropertyInitializer | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsParameterPropertyAssignments, - ModuleExcludes = ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis, + ModuleExcludes = ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding, TypeExcludes = ~ContainsTypeScript, ObjectLiteralExcludes = ContainsDecorators | ContainsComputedPropertyName, ArrayLiteralOrCallOrNewExcludes = ContainsSpreadElementExpression, @@ -2792,15 +2795,16 @@ namespace ts { /* @internal */ export const enum NodeEmitFlags { - EmitEmitHelpers = 1 << 0, // Any emit helpers should be written to this node. - EmitExportStar = 1 << 1, // The export * helper should be written to this node. - EmitSuperHelper = 1 << 2, // Emit the basic _super helper for async methods. - EmitAdvancedSuperHelper = 1 << 3, // Emit the advanced _super helper for async methods. - UMDDefine = 1 << 4, // This node should be replaced with the UMD define helper. - NoLexicalEnvironment = 1 << 5, // A new LexicalEnvironment should *not* be introduced when emitting this node, this is primarily used when printing a SystemJS module. - SingleLine = 1 << 6, // The contents of this node should be emit on a single line. - MultiLine = 1 << 7, // The contents of this node should be emit on multiple lines. - AdviseOnEmitNode = 1 << 8, // The node printer should invoke the onBeforeEmitNode and onAfterEmitNode callbacks when printing this node. + EmitEmitHelpers = 1 << 0, // Any emit helpers should be written to this node. + EmitExportStar = 1 << 1, // The export * helper should be written to this node. + EmitSuperHelper = 1 << 2, // Emit the basic _super helper for async methods. + EmitAdvancedSuperHelper = 1 << 3, // Emit the advanced _super helper for async methods. + UMDDefine = 1 << 4, // This node should be replaced with the UMD define helper. + NoLexicalEnvironment = 1 << 5, // A new LexicalEnvironment should *not* be introduced when emitting this node, this is primarily used when printing a SystemJS module. + SingleLine = 1 << 6, // The contents of this node should be emit on a single line. + AdviseOnEmitNode = 1 << 7, // The node printer should invoke the onBeforeEmitNode and onAfterEmitNode callbacks when printing this node. + IsNotEmittedNode = 1 << 8, // Is a node that is not emitted but whose comments should be preserved if possible. + EmitCommentsOfNotEmittedParent = 1 << 8, // Emits comments of missing parent nodes. } /** Additional context provided to `visitEachChild` */ @@ -2817,7 +2821,7 @@ namespace ts { getCompilerOptions(): CompilerOptions; getEmitResolver(): EmitResolver; getNodeEmitFlags(node: Node): NodeEmitFlags; - setNodeEmitFlags(node: Node, flags: NodeEmitFlags): void; + setNodeEmitFlags(node: T, flags: NodeEmitFlags): T; hoistFunctionDeclaration(node: FunctionDeclaration): void; hoistVariableDeclaration(node: Identifier): void; isUniqueName(name: string): boolean; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b84feea4153..446bddbff10 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -8,13 +8,6 @@ namespace ts { isNoDefaultLib?: boolean; } - export interface SynthesizedNode extends Node { - leadingCommentRanges?: CommentRange[]; - trailingCommentRanges?: CommentRange[]; - startsOnNewLine?: boolean; - disableSourceMap?: boolean; - } - export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration { const declarations = symbol.declarations; if (declarations) { @@ -1733,7 +1726,7 @@ namespace ts { return getOperatorPrecedence(expression.kind, operator, hasArguments); } - function getOperator(expression: Expression) { + export function getOperator(expression: Expression) { if (expression.kind === SyntaxKind.BinaryExpression) { return (expression).operatorToken.kind; } @@ -2318,26 +2311,33 @@ namespace ts { } } - export function emitComments(text: string, lineMap: number[], writer: EmitTextWriter, comments: CommentRange[], trailingSeparator: boolean, newLine: string, + export function emitComments(text: string, lineMap: number[], writer: EmitTextWriter, comments: CommentRange[], leadingSeparator: boolean, trailingSeparator: boolean, newLine: string, writeComment: (text: string, lineMap: number[], writer: EmitTextWriter, comment: CommentRange, newLine: string) => void) { - let emitLeadingSpace = !trailingSeparator; - forEach(comments, comment => { - if (emitLeadingSpace) { - writer.write(" "); - emitLeadingSpace = false; - } - writeComment(text, lineMap, writer, comment, newLine); - if (comment.hasTrailingNewLine) { - writer.writeLine(); - } - else if (trailingSeparator) { + if (comments && comments.length > 0) { + if (leadingSeparator) { writer.write(" "); } - else { - // Emit leading space to separate comment during next comment emit - emitLeadingSpace = true; + + let emitInterveningSeperator = false; + for (const comment of comments) { + if (emitInterveningSeperator) { + writer.write(" "); + emitInterveningSeperator = false; + } + + writeComment(text, lineMap, writer, comment, newLine); + if (comment.hasTrailingNewLine) { + writer.writeLine(); + } + else { + emitInterveningSeperator = true; + } } - }); + + if (emitInterveningSeperator && trailingSeparator) { + writer.write(" "); + } + } } /** @@ -2394,7 +2394,7 @@ namespace ts { if (nodeLine >= lastCommentLine + 2) { // Valid detachedComments emitNewLineBeforeLeadingComments(lineMap, writer, node, leadingComments); - emitComments(text, lineMap, writer, detachedComments, /*trailingSeparator*/ true, newLine, writeComment); + emitComments(text, lineMap, writer, detachedComments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); currentDetachedCommentInfo = { nodePos: node.pos, detachedCommentEndPos: lastOrUndefined(detachedComments).end }; } } @@ -2733,6 +2733,21 @@ namespace ts { return carriageReturnLineFeed; } + export const enum TextRangeCollapse { + CollapseToStart, + CollapseToEnd, + } + + export function collapseTextRange(range: TextRange, collapse: TextRangeCollapse) { + if (range.pos === range.end) { + return range; + } + + return collapse === TextRangeCollapse.CollapseToStart + ? { pos: range.pos, end: range.end } + : { pos: range.end, end: range.end }; + } + /** * Tests whether a node and its subtree is simple enough to have its position * information ignored when emitting source maps in a destructuring assignment. @@ -2812,6 +2827,10 @@ namespace ts { // Literals + export function isNoSubstitutionTemplateLiteral(node: Node): node is LiteralExpression { + return node.kind === SyntaxKind.NoSubstitutionTemplateLiteral; + } + export function isLiteralKind(kind: SyntaxKind): boolean { return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken; } @@ -2905,6 +2924,10 @@ namespace ts { // Type members + export function isMethodDeclaration(node: Node): node is MethodDeclaration { + return node.kind === SyntaxKind.MethodDeclaration; + } + export function isClassElement(node: Node): node is ClassElement { const kind = node.kind; return kind === SyntaxKind.Constructor @@ -2991,11 +3014,16 @@ namespace ts { || kind === SyntaxKind.NoSubstitutionTemplateLiteral; } + export function isSpreadElementExpression(node: Node): node is SpreadElementExpression { + return node.kind === SyntaxKind.SpreadElementExpression; + } + export function isExpressionWithTypeArguments(node: Node): node is ExpressionWithTypeArguments { return node.kind === SyntaxKind.ExpressionWithTypeArguments; } - function isLeftHandSideExpressionKind(kind: SyntaxKind) { + export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression { + const kind = node.kind; return kind === SyntaxKind.PropertyAccessExpression || kind === SyntaxKind.ElementAccessExpression || kind === SyntaxKind.NewExpression @@ -3021,11 +3049,8 @@ namespace ts { || kind === SyntaxKind.SuperKeyword; } - export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression { - return isLeftHandSideExpressionKind(node.kind); - } - - function isUnaryExpressionKind(kind: SyntaxKind): boolean { + export function isUnaryExpression(node: Node): node is UnaryExpression { + const kind = node.kind; return kind === SyntaxKind.PrefixUnaryExpression || kind === SyntaxKind.PostfixUnaryExpression || kind === SyntaxKind.DeleteExpression @@ -3033,14 +3058,11 @@ namespace ts { || kind === SyntaxKind.VoidExpression || kind === SyntaxKind.AwaitExpression || kind === SyntaxKind.TypeAssertionExpression - || isLeftHandSideExpressionKind(kind); + || isLeftHandSideExpression(node); } - export function isUnaryExpression(node: Node): node is UnaryExpression { - return isUnaryExpressionKind(node.kind); - } - - export function isExpressionKind(kind: SyntaxKind): boolean { + export function isExpression(node: Node): node is Expression { + const kind = node.kind; return kind === SyntaxKind.ConditionalExpression || kind === SyntaxKind.YieldExpression || kind === SyntaxKind.ArrowFunction @@ -3048,11 +3070,7 @@ namespace ts { || kind === SyntaxKind.SpreadElementExpression || kind === SyntaxKind.AsExpression || kind === SyntaxKind.OmittedExpression - || isUnaryExpressionKind(kind); - } - - export function isExpression(node: Node): node is Expression { - return isExpressionKind(node.kind); + || isUnaryExpression(node); } // Misc @@ -3264,9 +3282,12 @@ namespace ts { // Property assignments - export function isShortHandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment { - const kind = node.kind; - return kind === SyntaxKind.ShorthandPropertyAssignment; + export function isPropertyAssignment(node: Node): node is PropertyAssignment { + return node.kind === SyntaxKind.PropertyAssignment; + } + + export function isShorthandPropertyAssignment(node: Node): node is ShorthandPropertyAssignment { + return node.kind === SyntaxKind.ShorthandPropertyAssignment; } // Enum diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 0ddcc770a9f..838f00cd1b1 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -2,7 +2,7 @@ /* @internal */ namespace ts { - export type OneOrMore = T | NodeArrayNode; + export type OneOrMany = T | NodeArrayNode; /** * Describes an edge of a Node, used when traversing a syntax tree. @@ -19,6 +19,9 @@ namespace ts { /** A callback used to lift a NodeArrayNode into a valid node. */ lift?: (nodes: NodeArray) => Node; + + /** A callback used to parenthesize a node to preserve the intended order of operations. */ + parenthesize?: (value: Node, parentNode: Node) => Node; }; /** @@ -52,7 +55,7 @@ namespace ts { { name: "modifiers", test: isModifier }, { name: "name", test: isBindingName }, { name: "type", test: isTypeNode, optional: true }, - { name: "initializer", test: isExpression, optional: true }, + { name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList }, ], [SyntaxKind.Decorator]: [ { name: "expression", test: isLeftHandSideExpression }, @@ -108,34 +111,34 @@ namespace ts { [SyntaxKind.BindingElement]: [ { name: "propertyName", test: isPropertyName, optional: true }, { name: "name", test: isBindingName }, - { name: "initializer", test: isExpression, optional: true }, + { name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList }, ], [SyntaxKind.ArrayLiteralExpression]: [ - { name: "elements", test: isExpression }, + { name: "elements", test: isExpression, parenthesize: parenthesizeExpressionForList }, ], [SyntaxKind.ObjectLiteralExpression]: [ { name: "properties", test: isObjectLiteralElement }, ], [SyntaxKind.PropertyAccessExpression]: [ - { name: "expression", test: isLeftHandSideExpression }, + { name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess }, { name: "name", test: isIdentifier }, ], [SyntaxKind.ElementAccessExpression]: [ - { name: "expression", test: isLeftHandSideExpression }, + { name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess }, { name: "argumentExpression", test: isExpression }, ], [SyntaxKind.CallExpression]: [ - { name: "expression", test: isLeftHandSideExpression }, + { name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess }, { name: "typeArguments", test: isTypeNode }, { name: "arguments", test: isExpression }, ], [SyntaxKind.NewExpression]: [ - { name: "expression", test: isLeftHandSideExpression }, + { name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess }, { name: "typeArguments", test: isTypeNode }, { name: "arguments", test: isExpression }, ], [SyntaxKind.TaggedTemplateExpression]: [ - { name: "tag", test: isLeftHandSideExpression }, + { name: "tag", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess }, { name: "template", test: isTemplate }, ], [SyntaxKind.TypeAssertionExpression]: [ @@ -163,26 +166,26 @@ namespace ts { { name: "body", test: isConciseBody, lift: liftToBlock }, ], [SyntaxKind.DeleteExpression]: [ - { name: "expression", test: isUnaryExpression }, + { name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand }, ], [SyntaxKind.TypeOfExpression]: [ - { name: "expression", test: isUnaryExpression }, + { name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand }, ], [SyntaxKind.VoidExpression]: [ - { name: "expression", test: isUnaryExpression }, + { name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand }, ], [SyntaxKind.AwaitExpression]: [ - { name: "expression", test: isUnaryExpression }, + { name: "expression", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand }, ], [SyntaxKind.PrefixUnaryExpression]: [ - { name: "operand", test: isUnaryExpression }, + { name: "operand", test: isUnaryExpression, parenthesize: parenthesizePrefixOperand }, ], [SyntaxKind.PostfixUnaryExpression]: [ - { name: "operand", test: isLeftHandSideExpression }, + { name: "operand", test: isLeftHandSideExpression, parenthesize: parenthesizePostfixOperand }, ], [SyntaxKind.BinaryExpression]: [ - { name: "left", test: isExpression }, - { name: "right", test: isExpression }, + { name: "left", test: isExpression, parenthesize: (node: Expression, parent: BinaryExpression) => parenthesizeBinaryOperand(getOperator(parent), node, true) }, + { name: "right", test: isExpression, parenthesize: (node: Expression, parent: BinaryExpression) => parenthesizeBinaryOperand(getOperator(parent), node, false) }, ], [SyntaxKind.ConditionalExpression]: [ { name: "condition", test: isExpression }, @@ -197,7 +200,7 @@ namespace ts { { name: "expression", test: isExpression, optional: true }, ], [SyntaxKind.SpreadElementExpression]: [ - { name: "expression", test: isExpression }, + { name: "expression", test: isExpression, parenthesize: parenthesizeExpressionForList }, ], [SyntaxKind.ClassExpression]: [ { name: "decorators", test: isDecorator }, @@ -208,7 +211,7 @@ namespace ts { { name: "members", test: isClassElement }, ], [SyntaxKind.ExpressionWithTypeArguments]: [ - { name: "expression", test: isLeftHandSideExpression }, + { name: "expression", test: isLeftHandSideExpression, parenthesize: parenthesizeForAccess }, { name: "typeArguments", test: isTypeNode }, ], [SyntaxKind.AsExpression]: [ @@ -228,7 +231,7 @@ namespace ts { { name: "declarationList", test: isVariableDeclarationList }, ], [SyntaxKind.ExpressionStatement]: [ - { name: "expression", test: isExpression }, + { name: "expression", test: isExpression, parenthesize: parenthesizeExpressionForExpressionStatement }, ], [SyntaxKind.IfStatement]: [ { name: "expression", test: isExpression }, @@ -291,7 +294,7 @@ namespace ts { [SyntaxKind.VariableDeclaration]: [ { name: "name", test: isBindingName }, { name: "type", test: isTypeNode, optional: true }, - { name: "initializer", test: isExpression, optional: true }, + { name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList }, ], [SyntaxKind.VariableDeclarationList]: [ { name: "declarations", test: isVariableDeclaration }, @@ -420,7 +423,7 @@ namespace ts { ], [SyntaxKind.PropertyAssignment]: [ { name: "name", test: isPropertyName }, - { name: "initializer", test: isExpression }, + { name: "initializer", test: isExpression, parenthesize: parenthesizeExpressionForList }, ], [SyntaxKind.ShorthandPropertyAssignment]: [ { name: "name", test: isIdentifier }, @@ -428,7 +431,7 @@ namespace ts { ], [SyntaxKind.EnumMember]: [ { name: "name", test: isPropertyName }, - { name: "initializer", test: isExpression, optional: true }, + { name: "initializer", test: isExpression, optional: true, parenthesize: parenthesizeExpressionForList }, ], [SyntaxKind.SourceFile]: [ { name: "statements", test: isStatement }, @@ -530,7 +533,7 @@ namespace ts { // Visit each original node. for (let i = 0; i < count; i++) { const node = nodes[i + start]; - const visited = node && >visitor(node); + const visited = node && >visitor(node); if (updated !== undefined || visited === undefined || visited !== node) { if (updated === undefined) { // Ensure we have a copy of `nodes`, up to the current index. @@ -541,14 +544,14 @@ namespace ts { aggregateTransformFlags(visited); } - addNode(updated, visited, test); + addNodeWorker(updated, visited, /*addOnNewLine*/ undefined, test); } } if (updated !== undefined) { return (isModifiersArray(nodes) ? createModifiersArray(updated, nodes) - : createNodeArray(updated, nodes)); + : createNodeArray(updated, nodes, nodes.hasTrailingComma)); } return nodes; @@ -577,21 +580,28 @@ namespace ts { const edgeTraversalPath = nodeEdgeTraversalMap[node.kind]; if (edgeTraversalPath) { + let modifiers: NodeFlags; for (const edge of edgeTraversalPath) { const value = >node[edge.name]; if (value !== undefined) { const visited = visitEdge(edge, value, visitor); + if (visited && isArray(visited) && isModifiersArray(visited)) { + modifiers = visited.flags; + } + if (updated !== undefined || visited !== value) { if (updated === undefined) { - updated = cloneNode(node, /*location*/ node, node.flags & ~NodeFlags.Modifier, /*parent*/ undefined, /*original*/ node); + updated = getMutableNode(node); + updated.flags &= ~NodeFlags.Modifier; } - if (visited && isArray(visited) && isModifiersArray(visited)) { - updated[edge.name] = visited; - updated.flags |= visited.flags; + if (modifiers) { + updated.flags |= modifiers; + modifiers = undefined; } - else { - updated[edge.name] = visited; + + if (visited !== value) { + setEdgeValue(updated, edge, visited); } } } @@ -630,6 +640,26 @@ namespace ts { : visitNode(value, visitor, edge.test, edge.optional, edge.lift); } + /** + * Sets the value of an edge, adjusting the value as necessary for cases such as expression precedence. + */ + function setEdgeValue(parentNode: Node & Map, edge: NodeEdge, value: Node | NodeArray) { + if (value && edge.parenthesize && !isArray(value)) { + value = parenthesizeEdge(value, parentNode, edge.parenthesize, edge.test); + } + + parentNode[edge.name] = value; + } + + /** + * Applies parentheses to a node to ensure the correct precedence. + */ + function parenthesizeEdge(node: Node, parentNode: Node, parenthesize: (node: Node, parentNode: Node) => Node, test: (node: Node) => boolean) { + node = parenthesize(node, parentNode); + Debug.assert(test === undefined || test(node), "Unexpected node kind after visit."); + return node; + } + /** * Appends a node to an array. * @@ -637,16 +667,8 @@ namespace ts { * @param from The source Node or NodeArrayNode. * @param test The node test used to validate each node. */ - export function addNode(to: T[], from: OneOrMore, test?: (node: Node) => boolean) { - if (to && from) { - if (isNodeArrayNode(from)) { - addNodes(to, from.nodes, test); - } - else { - Debug.assert(test === undefined || test(from), "Wrong node type after visit."); - to.push(from); - } - } + export function addNode(to: T[], from: OneOrMany, startOnNewLine?: boolean) { + addNodeWorker(to, from, startOnNewLine, /*test*/ undefined); } /** @@ -656,10 +678,30 @@ namespace ts { * @param from The source array of Node or NodeArrayNode. * @param test The node test used to validate each node. */ - export function addNodes(to: T[], from: OneOrMore[], test?: (node: Node) => boolean) { + export function addNodes(to: T[], from: OneOrMany[], startOnNewLine?: boolean) { + addNodesWorker(to, from, startOnNewLine, /*test*/ undefined); + } + + function addNodeWorker(to: T[], from: OneOrMany, startOnNewLine: boolean, test: (node: Node) => boolean) { + if (to && from) { + if (isNodeArrayNode(from)) { + addNodesWorker(to, from.nodes, startOnNewLine, test); + } + else { + Debug.assert(test === undefined || test(from), "Wrong node type after visit."); + if (startOnNewLine) { + from.startsOnNewLine = true; + } + + to.push(from); + } + } + } + + function addNodesWorker(to: T[], from: OneOrMany[], startOnNewLine: boolean, test: (node: Node) => boolean) { if (to && from) { for (const node of from) { - addNode(to, node, test); + addNodeWorker(to, node, startOnNewLine, test); } } } @@ -824,7 +866,7 @@ namespace ts { * * @param nodes The NodeArray. */ - function liftToBlock(nodes: NodeArray) { + export function liftToBlock(nodes: NodeArray) { Debug.assert(every(nodes, isStatement), "Cannot lift nodes to a Block."); return createBlock(>nodes); } diff --git a/src/server/protocol.d.ts b/src/server/protocol.d.ts index 3a669753323..19ede892daf 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.d.ts @@ -1,54 +1,54 @@ -/** - * Declaration module describing the TypeScript Server protocol +/** + * Declaration module describing the TypeScript Server protocol */ declare namespace ts.server.protocol { - /** - * A TypeScript Server message + /** + * A TypeScript Server message */ export interface Message { - /** - * Sequence number of the message + /** + * Sequence number of the message */ seq: number; /** - * One of "request", "response", or "event" + * One of "request", "response", or "event" */ type: string; } - /** - * Client-initiated request message + /** + * Client-initiated request message */ export interface Request extends Message { /** - * The command to execute + * The command to execute */ command: string; - /** - * Object containing arguments for the command + /** + * Object containing arguments for the command */ arguments?: any; } /** - * Request to reload the project structure for all the opened files + * Request to reload the project structure for all the opened files */ export interface ReloadProjectsRequest extends Message { } - /** - * Server-initiated event message + /** + * Server-initiated event message */ export interface Event extends Message { - /** - * Name of event + /** + * Name of event */ event: string; - /** - * Event-specific information + /** + * Event-specific information */ body?: any; } @@ -62,18 +62,18 @@ declare namespace ts.server.protocol { */ request_seq: number; - /** - * Outcome of the request. + /** + * Outcome of the request. */ success: boolean; - /** + /** * The command requested. */ command: string; - /** - * Contains error message if success === false. + /** + * Contains error message if success === false. */ message?: string; @@ -83,7 +83,7 @@ declare namespace ts.server.protocol { body?: any; } - /** + /** * Arguments for FileRequest messages. */ export interface FileRequestArgs { @@ -93,7 +93,7 @@ declare namespace ts.server.protocol { file: string; } - /** + /** * Arguments for ProjectInfoRequest request. */ export interface ProjectInfoRequestArgs extends FileRequestArgs { @@ -110,7 +110,7 @@ declare namespace ts.server.protocol { arguments: ProjectInfoRequestArgs; } - /** + /** * Response message body for "projectInfo" request */ export interface ProjectInfo { @@ -125,7 +125,7 @@ declare namespace ts.server.protocol { fileNames?: string[]; } - /** + /** * Response message for "projectInfo" request */ export interface ProjectInfoResponse extends Response { @@ -144,12 +144,12 @@ declare namespace ts.server.protocol { * (file, line, character offset), where line and character offset are 1-based. */ export interface FileLocationRequestArgs extends FileRequestArgs { - /** + /** * The line number for the request (1-based). */ line: number; - /** + /** * The character offset (on the line) for the request (1-based). */ offset: number; @@ -216,7 +216,7 @@ declare namespace ts.server.protocol { * Object found in response messages defining a span of text in a specific source file. */ export interface FileSpan extends TextSpan { - /** + /** * File containing text span. */ file: string; @@ -300,14 +300,14 @@ declare namespace ts.server.protocol { */ lineText: string; - /** + /** * True if reference is a write location, false otherwise. */ isWriteAccess: boolean; } /** - * The body of a "references" response message. + * The body of a "references" response message. */ export interface ReferencesResponseBody { /** @@ -325,7 +325,7 @@ declare namespace ts.server.protocol { */ symbolStartOffset: number; - /** + /** * The full display name of the symbol. */ symbolDisplayString: string; @@ -355,7 +355,7 @@ declare namespace ts.server.protocol { } /** - * Information about the item to be renamed. + * Information about the item to be renamed. */ export interface RenameInfo { /** @@ -373,7 +373,7 @@ declare namespace ts.server.protocol { */ displayName: string; - /** + /** * Full display name of item to be renamed. */ fullDisplayName: string; @@ -383,7 +383,7 @@ declare namespace ts.server.protocol { */ kind: string; - /** + /** * Optional modifiers for the kind (such as 'public'). */ kindModifiers: string; @@ -469,7 +469,7 @@ declare namespace ts.server.protocol { placeOpenBraceOnNewLineForControlBlocks?: boolean; /** Index operator */ - [key: string] : string | number | boolean; + [key: string]: string | number | boolean; } /** @@ -477,7 +477,7 @@ declare namespace ts.server.protocol { */ export interface ConfigureRequestArguments { - /** + /** * Information about the host, for example 'Emacs 24.4' or * 'Sublime Text version 3075' */ @@ -495,7 +495,7 @@ declare namespace ts.server.protocol { } /** - * Configure request; value of command field is "configure". Specifies + * Configure request; value of command field is "configure". Specifies * host information, such as host type, tab size, and indent size. */ export interface ConfigureRequest extends Request { @@ -514,8 +514,8 @@ declare namespace ts.server.protocol { */ export interface OpenRequestArgs extends FileRequestArgs { /** - * Used when a version of the file content is known to be more up to date than the one on disk. - * Then the known content will be used upon opening instead of the disk copy + * Used when a version of the file content is known to be more up to date than the one on disk. + * Then the known content will be used upon opening instead of the disk copy */ fileContent?: string; } @@ -751,7 +751,7 @@ declare namespace ts.server.protocol { * Optional modifiers for the kind (such as 'public'). */ kindModifiers: string; - /** + /** * A string that is used for comparing completion items so that they can be ordered. This * is often the same as the name but may be different in certain circumstances. */ @@ -794,7 +794,7 @@ declare namespace ts.server.protocol { } /** - * Signature help information for a single parameter + * Signature help information for a single parameter */ export interface SignatureHelpParameter { @@ -814,18 +814,18 @@ declare namespace ts.server.protocol { displayParts: SymbolDisplayPart[]; /** - * Whether the parameter is optional or not. + * Whether the parameter is optional or not. */ isOptional: boolean; } /** - * Represents a single signature to show in signature help. + * Represents a single signature to show in signature help. */ export interface SignatureHelpItem { /** - * Whether the signature accepts a variable number of arguments. + * Whether the signature accepts a variable number of arguments. */ isVariadic: boolean; @@ -845,7 +845,7 @@ declare namespace ts.server.protocol { separatorDisplayParts: SymbolDisplayPart[]; /** - * The signature helps items for the parameters. + * The signature helps items for the parameters. */ parameters: SignatureHelpParameter[]; @@ -861,17 +861,17 @@ declare namespace ts.server.protocol { export interface SignatureHelpItems { /** - * The signature help items. + * The signature help items. */ items: SignatureHelpItem[]; /** - * The span for which signature help should appear on a signature + * The span for which signature help should appear on a signature */ applicableSpan: TextSpan; /** - * The item selected in the set of available help items. + * The item selected in the set of available help items. */ selectedItemIndex: number; @@ -895,7 +895,7 @@ declare namespace ts.server.protocol { /** * Signature help request; value of command field is "signatureHelp". - * Given a file location (file, line, col), return the signature + * Given a file location (file, line, col), return the signature * help. */ export interface SignatureHelpRequest extends FileLocationRequest { @@ -926,8 +926,8 @@ declare namespace ts.server.protocol { } /** - * GeterrForProjectRequest request; value of command field is - * "geterrForProject". It works similarly with 'Geterr', only + * GeterrForProjectRequest request; value of command field is + * "geterrForProject". It works similarly with 'Geterr', only * it request for every file in this project. */ export interface GeterrForProjectRequest extends Request { @@ -997,7 +997,7 @@ declare namespace ts.server.protocol { diagnostics: Diagnostic[]; } - /** + /** * Event message for "syntaxDiag" and "semanticDiag" event types. * These events provide syntactic and semantic errors for a file. */ @@ -1033,7 +1033,7 @@ declare namespace ts.server.protocol { export interface ReloadResponse extends Response { } - /** + /** * Arguments for saveto request. */ export interface SavetoRequestArgs extends FileRequestArgs { @@ -1109,7 +1109,7 @@ declare namespace ts.server.protocol { */ kindModifiers?: string; - /** + /** * The file in which the symbol is found. */ file: string; @@ -1156,7 +1156,7 @@ declare namespace ts.server.protocol { /** * Change request message; value of command field is "change". - * Update the server's view of the file named by argument 'file'. + * Update the server's view of the file named by argument 'file'. * Server does not currently send a response to a change request. */ export interface ChangeRequest extends FileLocationRequest {