From 58125279cdb3d6712d5789260fbb346e4800d975 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 26 Apr 2016 15:29:46 -0700 Subject: [PATCH] Adjusts source map emit for members --- src/compiler/binder.ts | 21 +- src/compiler/comments.ts | 44 ++-- src/compiler/factory.ts | 119 +-------- src/compiler/printer.ts | 36 +-- src/compiler/transformer.ts | 86 +++---- src/compiler/transformers/destructuring.ts | 40 ++-- src/compiler/transformers/es6.ts | 226 ++++++++++++------ src/compiler/transformers/module/module.ts | 30 ++- src/compiler/transformers/module/system.ts | 7 +- src/compiler/transformers/ts.ts | 133 +++++------ src/compiler/types.ts | 23 +- src/compiler/utilities.ts | 40 +++- .../FunctionPropertyAssignments6_es6.js | 2 +- .../MemberFunctionDeclaration7_es6.js | 2 +- 14 files changed, 427 insertions(+), 382 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index c48aef371a7..f813e572093 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1989,7 +1989,7 @@ namespace ts { case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: // These nodes are ES6 syntax. - transformFlags = TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6 | TransformFlags.ContainsBindingPattern; break; case SyntaxKind.Decorator: @@ -2068,9 +2068,14 @@ namespace ts { return computeVariableDeclaration(node, subtreeFlags); case SyntaxKind.VariableDeclarationList: + excludeFlags = TransformFlags.VariableDeclarationListExcludes; + if (subtreeFlags & TransformFlags.ContainsBindingPattern) { + transformFlags |= TransformFlags.AssertES6; + } + // If a VariableDeclarationList is `let` or `const`, then it is ES6 syntax. if (node.flags & NodeFlags.BlockScoped) { - transformFlags = TransformFlags.AssertES6 | TransformFlags.ContainsBlockScopedBinding; + transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsBlockScopedBinding; } break; @@ -2172,7 +2177,7 @@ namespace ts { // A GetAccessor or SetAccessor is TypeScript syntax if it is either abstract, // or has a decorator. if ((node).body === undefined - || hasModifier(node, ModifierFlags.Abstract) + || hasModifier(node, ModifierFlags.Async | ModifierFlags.Abstract) || subtreeFlags & TransformFlags.ContainsDecorators) { transformFlags = TransformFlags.AssertTypeScript; } @@ -2279,11 +2284,11 @@ namespace ts { // If a parameter has an initializer, a binding pattern or a dotDotDot token, then // it is ES6 syntax and its container must emit default value assignments or parameter destructuring downlevel. - if (isDefined(node.initializer) || isDefined(node.dotDotDotToken) || isBindingPattern(node.name)) { + if (subtreeFlags & TransformFlags.ContainsBindingPattern || isDefined(node.initializer) || isDefined(node.dotDotDotToken)) { transformFlags |= TransformFlags.AssertES6 | TransformFlags.ContainsDefaultValueAssignments; } - return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None); + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.ParameterExcludes); } function computeParenthesizedExpression(node: ParenthesizedExpression, subtreeFlags: TransformFlags) { @@ -2426,7 +2431,7 @@ namespace ts { // A VariableDeclaration with a binding pattern is ES6 syntax. if (isBindingPattern((node).name)) { - transformFlags = TransformFlags.AssertES6; + transformFlags = TransformFlags.AssertES6 | TransformFlags.ContainsBindingPattern; } return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None); @@ -2446,6 +2451,10 @@ namespace ts { transformFlags = TransformFlags.AssertES6 | TransformFlags.AssertTypeScript; } + if (node.declarationList.transformFlags & TransformFlags.ContainsBindingPattern) { + transformFlags |= TransformFlags.AssertES6; + } + return updateTransformFlags(node, subtreeFlags, transformFlags, TransformFlags.None); } diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts index 5d3d84963b5..cc7dd2cd5da 100644 --- a/src/compiler/comments.ts +++ b/src/compiler/comments.ts @@ -5,12 +5,13 @@ namespace ts { export interface CommentWriter { reset(): void; setSourceFile(sourceFile: SourceFile): void; - getLeadingComments(range: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[]; + getLeadingComments(range: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomTextRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[]; getLeadingComments(range: TextRange): CommentRange[]; getLeadingCommentsOfPosition(pos: number): CommentRange[]; - getTrailingComments(range: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[]; + getTrailingComments(range: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomTextRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[]; getTrailingComments(range: TextRange): CommentRange[]; getTrailingCommentsOfPosition(pos: number): CommentRange[]; + emitLeadingComments(range: Node, comments: CommentRange[], getCustomTextRangeForNodeCallback?: (node: Node) => TextRange): void; emitLeadingComments(range: TextRange, comments: CommentRange[]): void; emitTrailingComments(range: TextRange, comments: CommentRange[]): void; emitLeadingDetachedComments(range: TextRange): void; @@ -43,11 +44,11 @@ namespace ts { return { reset, setSourceFile, - getLeadingComments(range: TextRange, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[] { return undefined; }, + getLeadingComments(range: TextRange, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomTextRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[] { return undefined; }, getLeadingCommentsOfPosition(pos: number): CommentRange[] { return undefined; }, - getTrailingComments(range: TextRange, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[] { return undefined; }, + getTrailingComments(range: TextRange, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomTextRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[] { return undefined; }, getTrailingCommentsOfPosition(pos: number): CommentRange[] { return undefined; }, - emitLeadingComments(range: TextRange, comments: CommentRange[]): void { }, + emitLeadingComments(range: Node | TextRange, comments: CommentRange[], getCustomTextRangeForNodeCallback?: (node: Node) => TextRange): void { }, emitTrailingComments(range: TextRange, comments: CommentRange[]): void { }, emitLeadingDetachedComments, emitTrailingDetachedComments(node: TextRange, contextNode?: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean): void {} @@ -78,11 +79,11 @@ namespace ts { }; function getLeadingComments(range: TextRange): CommentRange[]; - function getLeadingComments(node: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[]; - function getLeadingComments(nodeOrRange: TextRange | Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange) { + function getLeadingComments(node: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomTextRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[]; + function getLeadingComments(nodeOrRange: TextRange | Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomTextRangeForNodeCallback?: (node: Node) => TextRange) { let range = nodeOrRange; - if (getCustomCommentRangeForNodeCallback) { - range = getCustomCommentRangeForNodeCallback(nodeOrRange) || range; + if (getCustomTextRangeForNodeCallback) { + range = getCustomTextRangeForNodeCallback(nodeOrRange) || range; } if (shouldSkipCommentsForNodeCallback && shouldSkipCommentsForNodeCallback(nodeOrRange)) { @@ -125,15 +126,15 @@ namespace ts { } function getTrailingComments(range: TextRange): CommentRange[]; - function getTrailingComments(node: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[]; - function getTrailingComments(nodeOrRange: TextRange | Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange) { + function getTrailingComments(node: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomTextRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[]; + function getTrailingComments(nodeOrRange: TextRange | Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomTextRangeForNodeCallback?: (node: Node) => TextRange) { let range = nodeOrRange; if (shouldSkipCommentsForNodeCallback && shouldSkipCommentsForNodeCallback(nodeOrRange)) { return undefined; } - if (getCustomCommentRangeForNodeCallback) { - range = getCustomCommentRangeForNodeCallback(nodeOrRange) || range; + if (getCustomTextRangeForNodeCallback) { + range = getCustomTextRangeForNodeCallback(nodeOrRange) || range; } return getTrailingCommentsOfPosition(range.end); @@ -161,11 +162,20 @@ namespace ts { return consumeCommentRanges(comments); } - function emitLeadingComments(range: TextRange, comments: CommentRange[]) { - emitNewLineBeforeLeadingComments(currentLineMap, writer, range, comments); + function emitLeadingComments(range: Node, comments: CommentRange[], getCustomTextRangeForNodeCallback?: (node: Node) => TextRange): void; + function emitLeadingComments(range: TextRange, comments: CommentRange[]): void; + function emitLeadingComments(nodeOrRange: Node | TextRange, comments: CommentRange[], getCustomTextRangeForNodeCallback?: (node: Node) => TextRange) { + if (comments && comments.length > 0) { + let range = nodeOrRange; + if (getCustomTextRangeForNodeCallback) { + range = getCustomTextRangeForNodeCallback(nodeOrRange); + } - // Leading comments are emitted at /*leading comment1 */space/*leading comment*/space - emitComments(currentText, currentLineMap, writer, comments, /*leadingSeparator*/ false, /*trailingSeparator*/ true, newLine, writeComment); + 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: CommentRange[]) { diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index affd9baf16e..6f77af9e1b1 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -205,10 +205,11 @@ namespace ts { // Type members - export function createMethod(modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange) { + export function createMethod(modifiers: Modifier[], asteriskToken: Node, name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange) { const node = createNode(SyntaxKind.MethodDeclaration, location); node.decorators = undefined; node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; + node.asteriskToken = asteriskToken; node.name = typeof name === "string" ? createIdentifier(name) : name; node.typeParameters = undefined; node.parameters = createNodeArray(parameters); @@ -227,24 +228,24 @@ namespace ts { return node; } - export function createGetAccessor(modifiers: Modifier[], name: string | PropertyName, body: Block, location?: TextRange) { + export function createGetAccessor(modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange) { const node = createNode(SyntaxKind.GetAccessor, location); node.decorators = undefined; node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.name = typeof name === "string" ? createIdentifier(name) : name; node.typeParameters = undefined; - node.parameters = createNodeArray(); + node.parameters = createNodeArray(parameters); node.body = body; return node; } - export function createSetAccessor(modifiers: Modifier[], name: string | PropertyName, parameter: ParameterDeclaration, body: Block, location?: TextRange) { + export function createSetAccessor(modifiers: Modifier[], name: string | PropertyName, parameters: ParameterDeclaration[], body: Block, location?: TextRange) { const node = createNode(SyntaxKind.SetAccessor, location); node.decorators = undefined; node.modifiers = modifiers ? createNodeArray(modifiers) : undefined; node.name = typeof name === "string" ? createIdentifier(name) : name; node.typeParameters = undefined; - node.parameters = createNodeArray([parameter]); + node.parameters = createNodeArray(parameters); node.body = body; return node; } @@ -503,8 +504,8 @@ namespace ts { return node; } - export function createFor(initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement, location?: TextRange) { - const node = createNode(SyntaxKind.ForStatement, location); + export function createFor(initializer: ForInitializer, condition: Expression, incrementor: Expression, statement: Statement, location?: TextRange, emitOptions?: NodeEmitOptions) { + const node = createNode(SyntaxKind.ForStatement, location, /*flags*/ undefined, emitOptions); node.initializer = initializer; node.condition = condition; node.incrementor = incrementor; @@ -923,105 +924,6 @@ namespace ts { ); } - export interface PropertyDescriptorOptions { - [key: string]: boolean | Expression; - get?: Expression; - set?: Expression; - value?: Expression; - enumerable?: boolean | Expression; - configurable?: boolean | Expression; - writable?: boolean | Expression; - } - - export interface PropertyDescriptorExtendedOptions { - [key: string]: PropertyDescriptorExtendedOption; - get?: PropertyDescriptorExtendedOption; - set?: PropertyDescriptorExtendedOption; - value?: PropertyDescriptorExtendedOption; - enumerable?: PropertyDescriptorExtendedOption; - configurable?: PropertyDescriptorExtendedOption; - writable?: PropertyDescriptorExtendedOption; - } - - export interface PropertyDescriptorExtendedOption { - location?: TextRange; - original?: Node; - emitFlags?: NodeEmitFlags; - newLine?: boolean; - } - - export function createObjectDefineProperty(target: Expression, memberName: Expression, descriptor: PropertyDescriptorOptions, preferNewLine?: boolean, location?: TextRange, descriptorOptions?: PropertyDescriptorExtendedOptions, context?: TransformationContext) { - return createCall( - createPropertyAccess( - createIdentifier("Object"), - "defineProperty" - ), - [ - target, - memberName, - createObjectLiteral( - createPropertyDescriptorProperties(descriptor, descriptorOptions, preferNewLine, context), - /*location*/ undefined, - /*multiLine*/ preferNewLine - ) - ], - location - ); - } - - function createPropertyDescriptorProperties(descriptor: PropertyDescriptorOptions, descriptorExtendedOptions: PropertyDescriptorExtendedOptions, preferNewLine: boolean, context: TransformationContext) { - const properties: ObjectLiteralElement[] = []; - addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "get", descriptor, descriptorExtendedOptions, preferNewLine, context); - addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "set", descriptor, descriptorExtendedOptions, preferNewLine, context); - addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "value", descriptor, descriptorExtendedOptions, preferNewLine, context); - addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "enumerable", descriptor, descriptorExtendedOptions, preferNewLine, context); - addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "configurable", descriptor, descriptorExtendedOptions, preferNewLine, context); - addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "writable", descriptor, descriptorExtendedOptions, preferNewLine, context); - return properties; - } - - function addPropertyDescriptorPropertyAssignmentIfNeeded(properties: ObjectLiteralElement[], name: string, descriptor: PropertyDescriptorOptions, descriptorExtendedOptions: PropertyDescriptorExtendedOptions, preferNewLine: boolean, context: TransformationContext) { - const value = getProperty(descriptor, name); - if (value !== undefined) { - let options: PropertyDescriptorExtendedOption; - let location: TextRange; - let original: Node; - let emitFlags: NodeEmitFlags; - if (descriptorExtendedOptions !== undefined) { - options = getProperty(descriptorExtendedOptions, name); - if (options !== undefined) { - location = options.location; - original = options.original; - emitFlags = options.emitFlags; - if (options.newLine !== undefined) { - preferNewLine = options.newLine; - } - } - } - - const property = createPropertyAssignment( - name, - typeof value === "boolean" ? createLiteral(value) : value, - location - ); - - if (emitFlags !== undefined) { - Debug.assert(context !== undefined, "TransformationContext must be supplied when emitFlags are provided."); - context.setNodeEmitFlags(property, emitFlags); - } - - if (original) { - property.original = original; - } - - if (preferNewLine) { - startOnNewLine(property); - } - - properties.push(property); - } - } - function createObjectCreate(prototype: Expression) { return createCall( createPropertyAccess(createIdentifier("Object"), "create"), @@ -1078,6 +980,7 @@ namespace ts { const getter = createGetAccessor( /*modifiers*/ undefined, "value", + [], createBlock([ createReturn( createCall( @@ -1092,7 +995,7 @@ namespace ts { const setter = createSetAccessor( /*modifiers*/ undefined, "value", - createParameter("v"), + [createParameter("v")], createBlock([ createStatement( createCall( @@ -1276,7 +1179,7 @@ namespace ts { : getSynthesizedClone(node); } - export function createExpressionForPropertyName(memberName: PropertyName, emitOptions: NodeEmitOptions): Expression { + export function createExpressionForPropertyName(memberName: PropertyName, emitOptions?: NodeEmitOptions): Expression { if (isIdentifier(memberName)) { return createLiteral(memberName, /*location*/ undefined, emitOptions); } diff --git a/src/compiler/printer.ts b/src/compiler/printer.ts index dbd02ef1542..f617019fccb 100644 --- a/src/compiler/printer.ts +++ b/src/compiler/printer.ts @@ -291,7 +291,7 @@ const _super = (function (geti, seti) { if (node) { const flagsToAdd = flags & ~getNodeEmitFlags(node); if (flagsToAdd) { - setNodeEmitFlags(node, flagsToAdd); + setNodeEmitFlags(node, getNodeEmitFlags(node) | flagsToAdd); emit(node); setNodeEmitFlags(node, getNodeEmitFlags(node) & ~flagsToAdd); return; @@ -342,7 +342,7 @@ const _super = (function (geti, seti) { if (node) { const leadingComments = getLeadingComments(node, shouldSkipLeadingCommentsForNode, getCommentRange); const trailingComments = getTrailingComments(node, shouldSkipTrailingCommentsForNode, getCommentRange); - emitLeadingComments(node, leadingComments); + emitLeadingComments(node, leadingComments, getCommentRange); emitStart(node, shouldSkipLeadingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange); emitWorker(node); emitEnd(node, shouldSkipTrailingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange); @@ -1305,14 +1305,14 @@ const _super = (function (geti, seti) { function emitBlock(node: Block, format?: ListFormat) { if (isSingleLineEmptyBlock(node)) { - writeToken(SyntaxKind.OpenBraceToken, node.pos); + writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node); write(" "); - writeToken(SyntaxKind.CloseBraceToken, node.statements.end); + writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node); } else { - writeToken(SyntaxKind.OpenBraceToken, node.pos); + writeToken(SyntaxKind.OpenBraceToken, node.pos, /*contextNode*/ node); emitBlockStatements(node); - writeToken(SyntaxKind.CloseBraceToken, node.statements.end); + writeToken(SyntaxKind.CloseBraceToken, node.statements.end, /*contextNode*/ node); } } @@ -1408,7 +1408,7 @@ const _super = (function (geti, seti) { const openParenPos = writeToken(SyntaxKind.ForKeyword, node.pos); write(" "); - writeToken(SyntaxKind.OpenParenToken, openParenPos); + writeToken(SyntaxKind.OpenParenToken, openParenPos, /*contextNode*/ node); emitForBinding(node.initializer); write(";"); emitExpressionWithPrefix(" ", node.condition); @@ -1464,7 +1464,7 @@ const _super = (function (geti, seti) { } function emitReturnStatement(node: ReturnStatement) { - writeToken(SyntaxKind.ReturnKeyword, node.pos, node, shouldSkipSourceMapForToken); + writeToken(SyntaxKind.ReturnKeyword, node.pos, /*contextNode*/ node); emitExpressionWithPrefix(" ", node.expression); write(";"); } @@ -1992,7 +1992,7 @@ const _super = (function (geti, seti) { // "comment1" is not considered to be leading comment for node.initializer // but rather a trailing comment on the previous node. if (!shouldSkipLeadingCommentsForNode(node.initializer)) { - emitLeadingComments(node.initializer, getTrailingComments(collapseRangeToStart(node.initializer))); + emitLeadingComments(node.initializer, getTrailingComments(collapseRangeToStart(node.initializer)), getCommentRange); } emitExpression(node.initializer); } @@ -2356,7 +2356,7 @@ const _super = (function (geti, seti) { } if (shouldEmitInterveningComments) { - emitLeadingComments(child, getTrailingCommentsOfPosition(child.pos)); + emitLeadingComments(child, getTrailingCommentsOfPosition(child.pos), getCommentRange); } else { shouldEmitInterveningComments = true; @@ -2410,18 +2410,20 @@ const _super = (function (geti, seti) { } } - function writeToken(token: SyntaxKind, tokenStartPos: number): number; - function writeToken(token: SyntaxKind, tokenStartPos: number, contextNode: Node, shouldIgnoreSourceMapForTokenCallback: (contextNode: Node) => boolean): number; - function writeToken(token: SyntaxKind, tokenStartPos: number, contextNode?: Node, shouldIgnoreSourceMapForTokenCallback?: (contextNode: Node) => boolean) { + function writeToken(token: SyntaxKind, tokenStartPos: number, contextNode?: Node) { tokenStartPos = skipTrivia(currentText, tokenStartPos); - emitPos(tokenStartPos, contextNode, shouldIgnoreSourceMapForTokenCallback); + emitPos(tokenStartPos, contextNode, shouldSkipLeadingSourceMapForToken); const tokenEndPos = writeTokenText(token, tokenStartPos); - emitPos(tokenEndPos, contextNode, shouldIgnoreSourceMapForTokenCallback); + emitPos(tokenEndPos, contextNode, shouldSkipTrailingSourceMapForToken); return tokenEndPos; } - function shouldSkipSourceMapForToken(contextNode: Node) { - return (getNodeEmitFlags(contextNode) & NodeEmitFlags.NoTokenSourceMaps) !== 0; + function shouldSkipLeadingSourceMapForToken(contextNode: Node) { + return (getNodeEmitFlags(contextNode) & NodeEmitFlags.NoTokenLeadingSourceMaps) !== 0; + } + + function shouldSkipTrailingSourceMapForToken(contextNode: Node) { + return (getNodeEmitFlags(contextNode) & NodeEmitFlags.NoTokenTrailingSourceMaps) !== 0; } function writeTokenText(token: SyntaxKind, pos?: number) { diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index d4fc65395a4..f103103995e 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -168,22 +168,12 @@ namespace ts { emit(node); } - function getNodeEmitOptions(node: Node, createIfMissing: boolean) { - // Keeps track of the nearest set of options - let options: NodeEmitOptions; - let currentNode = node; - while (currentNode) { - const currentOptions = currentNode.emitOptions || nodeEmitOptions[getNodeId(currentNode)]; - if (currentOptions) { - options = currentOptions; - break; - } - - currentNode = currentNode.original; - } - - if (currentNode !== node && createIfMissing) { - options = options ? clone(options) : { }; + function getEmitOptions(node: Node, create?: boolean) { + let options = isSourceTreeNode(node) + ? nodeEmitOptions[getNodeId(node)] + : node.emitOptions; + if (!options && create) { + options = { }; if (isSourceTreeNode(node)) { nodeEmitOptions[getNodeId(node)] = options; } @@ -191,22 +181,6 @@ namespace ts { node.emitOptions = options; } } - - // Merge with previous options on get. - if (options && options.flags & NodeEmitFlags.Merge) { - const previousOptions = getNodeEmitOptions(currentNode.original, /*createIfMissing*/ false); - if (previousOptions) { - options.flags = (options.flags | previousOptions.flags) & ~NodeEmitFlags.Merge; - if (!options.sourceMapRange && (options.flags & NodeEmitFlags.NoSourceMap) === 0) { - options.sourceMapRange = previousOptions.sourceMapRange; - } - - if (!options.commentRange && (options.flags & NodeEmitFlags.NoComments) === 0) { - options.commentRange = previousOptions.commentRange; - } - } - } - return options; } @@ -214,15 +188,27 @@ namespace ts { * Gets flags that control emit behavior of a node. */ function getNodeEmitFlags(node: Node) { - const options = getNodeEmitOptions(node, /*createIfMissing*/ false); - return options && options.flags; + while (node) { + const options = getEmitOptions(node, /*create*/ false); + if (options && options.flags !== undefined) { + if (options.flags & NodeEmitFlags.Merge) { + options.flags = (options.flags | getNodeEmitFlags(node.original)) & ~NodeEmitFlags.Merge; + } + + return options.flags; + } + + node = node.original; + } + + return undefined; } /** * Sets flags that control emit behavior of a node. */ function setNodeEmitFlags(node: T, flags: NodeEmitFlags) { - getNodeEmitOptions(node, /*createIfMissing*/ true).flags = flags; + getEmitOptions(node, /*create*/ true).flags = flags; return node; } @@ -230,15 +216,24 @@ namespace ts { * Gets a custom text range to use when emitting source maps. */ function getSourceMapRange(node: Node) { - const options = getNodeEmitOptions(node, /*createIfMissing*/ false); - return options && options.sourceMapRange; + let current = node; + while (current) { + const options = getEmitOptions(current); + if (options && options.sourceMapRange !== undefined) { + return options.sourceMapRange; + } + + current = current.original; + } + + return node; } /** * Sets a custom text range to use when emitting source maps. */ function setSourceMapRange(node: T, range: TextRange) { - getNodeEmitOptions(node, /*createIfMissing*/ true).sourceMapRange = range; + getEmitOptions(node, /*create*/ true).sourceMapRange = range; return node; } @@ -246,15 +241,24 @@ namespace ts { * Gets a custom text range to use when emitting comments. */ function getCommentRange(node: Node) { - const options = getNodeEmitOptions(node, /*createIfMissing*/ false); - return options && options.commentRange; + let current = node; + while (current) { + const options = getEmitOptions(current, /*create*/ false); + if (options && options.commentRange !== undefined) { + return options.commentRange; + } + + current = current.original; + } + + return node; } /** * Sets a custom text range to use when emitting comments. */ function setCommentRange(node: T, range: TextRange) { - getNodeEmitOptions(node, /*createIfMissing*/ true).commentRange = range; + getEmitOptions(node, /*create*/ true).commentRange = range; return node; } diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 5e9e51da951..4ff32ac9380 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -63,9 +63,10 @@ namespace ts { function emitAssignment(name: Identifier, value: Expression, location: TextRange) { const expression = createAssignment(name, value, location); - if (isSimpleExpression(value)) { - context.setNodeEmitFlags(expression, NodeEmitFlags.NoNestedSourceMaps); - } + + // NOTE: this completely disables source maps, but aligns with the behavior of + // `emitAssignment` in the old emitter. + context.setNodeEmitFlags(expression, NodeEmitFlags.NoNestedSourceMaps); aggregateTransformFlags(expression); expressions.push(expression); @@ -98,9 +99,10 @@ namespace ts { function emitAssignment(name: Identifier, value: Expression, location: TextRange) { const declaration = createVariableDeclaration(name, value, location); - if (isSimpleExpression(value)) { - context.setNodeEmitFlags(declaration, NodeEmitFlags.NoNestedSourceMaps); - } + + // NOTE: this completely disables source maps, but aligns with the behavior of + // `emitAssignment` in the old emitter. + context.setNodeEmitFlags(declaration, NodeEmitFlags.NoNestedSourceMaps); aggregateTransformFlags(declaration); declarations.push(declaration); @@ -132,16 +134,14 @@ namespace ts { return declarations; function emitAssignment(name: Identifier, value: Expression, location: TextRange, original: Node) { + debugger; const declaration = createVariableDeclaration(name, value, location); - if (declarations.length === 0) { - declaration.pos = -1; - } - - if (isSimpleExpression(value)) { - context.setNodeEmitFlags(declaration, NodeEmitFlags.NoNestedSourceMaps); - } - declaration.original = original; + + // NOTE: this completely disables source maps, but aligns with the behavior of + // `emitAssignment` in the old emitter. + context.setNodeEmitFlags(declaration, NodeEmitFlags.NoNestedSourceMaps); + declarations.push(declaration); aggregateTransformFlags(declaration); } @@ -189,11 +189,12 @@ namespace ts { function emitPendingAssignment(name: Expression, value: Expression, location: TextRange, original: Node) { const expression = createAssignment(name, value, location); - if (isSimpleExpression(value)) { - context.setNodeEmitFlags(expression, NodeEmitFlags.NoNestedSourceMaps); - } - expression.original = original; + + // NOTE: this completely disables source maps, but aligns with the behavior of + // `emitAssignment` in the old emitter. + context.setNodeEmitFlags(expression, NodeEmitFlags.NoNestedSourceMaps); + pendingAssignments.push(expression); return expression; } @@ -341,8 +342,7 @@ namespace ts { } } else { - const clonedName = getSynthesizedClone(name); - emitAssignment(clonedName, value, target, target); + emitAssignment(name, value, target, target); } } diff --git a/src/compiler/transformers/es6.ts b/src/compiler/transformers/es6.ts index a61667b1be1..d3bd755414d 100644 --- a/src/compiler/transformers/es6.ts +++ b/src/compiler/transformers/es6.ts @@ -145,8 +145,10 @@ namespace ts { hoistVariableDeclaration, getNodeEmitFlags, setNodeEmitFlags, + getCommentRange, setCommentRange, - setSourceMapRange + getSourceMapRange, + setSourceMapRange, } = context; const resolver = context.getEmitResolver(); @@ -311,7 +313,7 @@ namespace ts { return visitFunctionExpression(node); case SyntaxKind.VariableDeclaration: - return visitVariableDeclaration(node); + return visitVariableDeclaration(node, /*offset*/ undefined); case SyntaxKind.Identifier: return visitIdentifier(node); @@ -387,7 +389,7 @@ namespace ts { return visitSourceFileNode(node); case SyntaxKind.VariableStatement: - return visitEachChild(node, visitor, context); + return visitVariableStatement(node); default: Debug.failBadSyntaxKind(node); @@ -836,18 +838,24 @@ namespace ts { else if (isBindingPattern(node.name)) { // Binding patterns are converted into a generated name and are // evaluated inside the function body. - return createParameter( - getGeneratedNameForNode(node), - /*initializer*/ undefined, - /*location*/ node + return setOriginalNode( + createParameter( + getGeneratedNameForNode(node), + /*initializer*/ undefined, + /*location*/ node + ), + /*original*/ node ); } else if (node.initializer) { // Initializers are elided - return createParameter( - node.name, - /*initializer*/ undefined, - /*location*/ node + return setOriginalNode( + createParameter( + node.name, + /*initializer*/ undefined, + /*location*/ node + ), + /*original*/ node ); } else { @@ -1127,6 +1135,13 @@ namespace ts { * @param member The MethodDeclaration node. */ function transformClassMethodDeclarationToStatement(receiver: LeftHandSideExpression, member: MethodDeclaration) { + const commentRange = getCommentRange(member); + const sourceMapRange = getSourceMapRange(member); + + const func = transformFunctionLikeToExpression(member, /*location*/ member, /*name*/ undefined); + setNodeEmitFlags(func, NodeEmitFlags.NoComments); + setSourceMapRange(func, sourceMapRange); + const statement = createStatement( createAssignment( createMemberAccessForPropertyName( @@ -1134,13 +1149,13 @@ namespace ts { visitNode(member.name, visitor, isPropertyName), /*location*/ member.name ), - transformFunctionLikeToExpression(member, /*location*/ member, /*name*/ undefined), - /*location*/ moveRangeEnd(member, -1) + func ), /*location*/ member ); setOriginalNode(statement, member); + setCommentRange(statement, commentRange); // The location for the statement is used to emit comments only. // No source map should be emitted for this statement to align with the @@ -1158,7 +1173,7 @@ namespace ts { function transformAccessorsToStatement(receiver: LeftHandSideExpression, accessors: AllAccessorDeclarations): Statement { const statement = createStatement( transformAccessorsToExpression(receiver, accessors), - /*location*/ accessors.firstAccessor + /*location*/ getSourceMapRange(accessors.firstAccessor) ); // The location for the statement is used to emit source maps only. @@ -1177,40 +1192,43 @@ namespace ts { function transformAccessorsToExpression(receiver: LeftHandSideExpression, { firstAccessor, getAccessor, setAccessor }: AllAccessorDeclarations): Expression { // To align with source maps in the old emitter, the receiver and property name // arguments are both mapped contiguously to the accessor name. - const target = getMutableClone(receiver, { flags: NodeEmitFlags.Merge | NodeEmitFlags.NoComments, sourceMapRange: moveRangeEnd(firstAccessor.name, -1) }); - const propertyName = createExpressionForPropertyName(visitNode(firstAccessor.name, visitor, isPropertyName), { flags: NodeEmitFlags.NoComments, sourceMapRange: moveRangePos(firstAccessor.name, -1) }); + const target = getMutableClone(receiver); + setNodeEmitFlags(target, NodeEmitFlags.NoComments | NodeEmitFlags.NoTrailingSourceMap); + setSourceMapRange(target, firstAccessor.name); - let getAccessorExpression: FunctionExpression; + const propertyName = createExpressionForPropertyName(visitNode(firstAccessor.name, visitor, isPropertyName)); + setNodeEmitFlags(propertyName, NodeEmitFlags.NoComments | NodeEmitFlags.NoLeadingSourceMap); + setSourceMapRange(propertyName, firstAccessor.name); + + const properties: ObjectLiteralElement[] = []; if (getAccessor) { - getAccessorExpression = transformFunctionLikeToExpression(getAccessor, /*location*/ getAccessor, /*name*/ undefined); - setNodeEmitFlags(getAccessorExpression, NodeEmitFlags.NoLeadingComments | getNodeEmitFlags(getAccessorExpression)); + const getterFunction = transformFunctionLikeToExpression(getAccessor, /*location*/ undefined, /*name*/ undefined); + setSourceMapRange(getterFunction, getSourceMapRange(getAccessor)); + const getter = createPropertyAssignment("get", getterFunction); + setCommentRange(getter, getCommentRange(getAccessor)); + properties.push(getter); } - let setAccessorExpression: FunctionExpression; if (setAccessor) { - setAccessorExpression = transformFunctionLikeToExpression(setAccessor, /*location*/ setAccessor, /*name*/ undefined); - setNodeEmitFlags(setAccessorExpression, NodeEmitFlags.NoLeadingComments | getNodeEmitFlags(setAccessorExpression)); + const setterFunction = transformFunctionLikeToExpression(setAccessor, /*location*/ undefined, /*name*/ undefined); + setSourceMapRange(setterFunction, getSourceMapRange(setAccessor)); + const setter = createPropertyAssignment("set", setterFunction); + setCommentRange(setter, getCommentRange(setAccessor)); + properties.push(setter); } - return setNodeEmitFlags( - createObjectDefineProperty( + properties.push( + createPropertyAssignment("enumerable", createLiteral(true)), + createPropertyAssignment("configurable", createLiteral(true)) + ); + + return createCall( + createPropertyAccess(createIdentifier("Object"), "defineProperty"), + [ target, propertyName, - /*descriptor*/ { - get: getAccessorExpression, - set: setAccessorExpression, - enumerable: true, - configurable: true - }, - /*preferNewLine*/ true, - /*location*/ undefined, - /*descriptorLocations*/ { - get: { location: getAccessor, emitFlags: NodeEmitFlags.NoSourceMap, original: getAccessor }, - set: { location: setAccessor, emitFlags: NodeEmitFlags.NoSourceMap, original: getAccessor } - }, - context - ), - NodeEmitFlags.NoComments + createObjectLiteral(properties, /*location*/ undefined, /*multiLine*/ true) + ] ); } @@ -1459,7 +1477,16 @@ namespace ts { return undefined; } } - return visitEachChild(node, visitor, context); + + const visited = visitEachChild(node, visitor, context); + + // if (node.declarationList.transformFlags & TransformFlags.ContainsBindingPattern) { + // // To align with source maps from the old emitter, we do not emit the start pos + // // for the statement if it contains a binding pattern. + // setNodeEmitFlags(visited, NodeEmitFlags.NoLeadingSourceMap); + // } + + return visited; } /** @@ -1468,17 +1495,36 @@ namespace ts { * @param node A VariableDeclarationList node. */ function visitVariableDeclarationList(node: VariableDeclarationList): VariableDeclarationList { - // If we are here it is because the list is defined as `let` or `const`. - Debug.assert((node.flags & NodeFlags.BlockScoped) !== 0); + if (node.flags & NodeFlags.BlockScoped) { + enableSubstitutionsForBlockScopedBindings(); + } - enableSubstitutionsForBlockScopedBindings(); - return setOriginalNode( - createVariableDeclarationList( - flatten(map(node.declarations, visitVariableDeclarationInLetDeclarationList)), - /*location*/ node - ), - node - ); + const declarations = flatten(map(node.declarations, node.flags & NodeFlags.Let + ? visitVariableDeclarationInLetDeclarationList + : visitVariableDeclaration)); + + const declarationList = createVariableDeclarationList(declarations, /*location*/ node); + setOriginalNode(declarationList, node); + + // if (node.transformFlags & TransformFlags.ContainsBindingPattern) { + // const firstOriginalDeclaration = node.declarations[0]; + // if (isBindingPattern(firstOriginalDeclaration.name)) { + // // // If the first var declaration is a binding pattern, we need to emit source maps + // // // at var/let/const keyword instead + // // const firstDeclaration = declarations[0]; + // // const range = getSourceMapRange(firstDeclaration); + // // if (firstOriginalDeclaration.initializer && isIdentifier(firstOriginalDeclaration.initializer)) { + // // // setSourceMapRange(declarationList, createRange(-1, node.end)); + // // // setSourceMapRange(declarationList, createRange(range.pos, node.end)); + // // // setSourceMapRange(firstDeclaration, createRange(-1, range.end)); + // // } + // // else { + // // setSourceMapRange(firstDeclaration, createRange(node.pos, range.end)); + // // } + // } + // } + + return declarationList; } /** @@ -1555,13 +1601,13 @@ namespace ts { * * @param node A VariableDeclaration node. */ - function visitVariableDeclarationInLetDeclarationList(node: VariableDeclaration) { + function visitVariableDeclarationInLetDeclarationList(node: VariableDeclaration, offset: number) { // For binding pattern names that lack initializers there is no point to emit // explicit initializer since downlevel codegen for destructuring will fail // in the absence of initializer so all binding elements will say uninitialized const name = node.name; if (isBindingPattern(name)) { - return visitVariableDeclaration(node); + return visitVariableDeclaration(node, offset); } if (!node.initializer && shouldEmitExplicitInitializerForLetDeclaration(node)) { @@ -1578,11 +1624,13 @@ namespace ts { * * @param node A VariableDeclaration node. */ - function visitVariableDeclaration(node: VariableDeclaration): VisitResult { + function visitVariableDeclaration(node: VariableDeclaration, offset: number): VisitResult { // If we are here it is because the name contains a binding pattern. - Debug.assert(isBindingPattern(node.name)); + if (isBindingPattern(node.name)) { + return flattenVariableDestructuring(context, node, /*value*/ undefined, visitor); + } - return flattenVariableDestructuring(context, node, /*value*/ undefined, visitor); + return visitEachChild(node, visitor, context); } function visitLabeledStatement(node: LabeledStatement): VisitResult { @@ -1672,25 +1720,33 @@ namespace ts { // Initialize LHS // var v = _a[_i]; if (isVariableDeclarationList(initializer)) { - const firstDeclaration = firstOrUndefined(initializer.declarations); + const firstOriginalDeclaration = firstOrUndefined(initializer.declarations); if (initializer.flags & NodeFlags.BlockScoped) { enableSubstitutionsForBlockScopedBindings(); } - if (firstDeclaration && isBindingPattern(firstDeclaration.name)) { + if (firstOriginalDeclaration && isBindingPattern(firstOriginalDeclaration.name)) { // This works whether the declaration is a var, let, or const. // It will use rhsIterationValue _a[_i] as the initializer. + const declarationList = createVariableDeclarationList( + flattenVariableDestructuring( + context, + firstOriginalDeclaration, + createElementAccess(rhsReference, counter), + visitor + ), + /*location*/ moveRangeEnd(initializer, -1) + ); + + // Adjust the source map range for the first declaration to align with the old + // emitter. + const firstDeclaration = declarationList.declarations[0]; + const range = getSourceMapRange(firstDeclaration); + setSourceMapRange(firstDeclaration, createRange(-1, range.end)); + statements.push( createVariableStatement( /*modifiers*/ undefined, - createVariableDeclarationList( - flattenVariableDestructuring( - context, - firstDeclaration, - createElementAccess(rhsReference, counter), - visitor - ) - ), - /*location*/ moveRangeEnd(initializer, -1) + declarationList ) ); } @@ -1702,7 +1758,7 @@ namespace ts { /*modifiers*/ undefined, createVariableDeclarationList([ createVariableDeclaration( - firstDeclaration ? firstDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined), + firstOriginalDeclaration ? firstOriginalDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined), createElementAccess(rhsReference, counter) ) ], /*location*/ moveRangePos(initializer, -1)), @@ -1735,13 +1791,17 @@ namespace ts { } } + let bodyLocation: TextRange; + let statementsLocation: TextRange; if (convertedLoopBodyStatements) { addRange(statements, convertedLoopBodyStatements); } else { const statement = visitNode(node.statement, visitor, isStatement); if (isBlock(statement)) { - addRange(statements, (statement).statements); + addRange(statements, statement.statements); + bodyLocation = statement; + statementsLocation = statement.statements; } else { statements.push(statement); @@ -1751,25 +1811,33 @@ namespace ts { // The old emitter does not emit source maps for the expression setNodeEmitFlags(expression, NodeEmitFlags.NoSourceMap | getNodeEmitFlags(expression)); - return createFor( - createVariableDeclarationList( - [ - createVariableDeclaration(counter, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)), - createVariableDeclaration(rhsReference, expression, /*location*/ node.expression) - ], - /*location*/ node.expression - ), + // The old emitter does not emit source maps for the block. + // We add the location to preserve comments. + const body = createBlock( + createNodeArray(statements, /*location*/ statementsLocation), + /*location*/ bodyLocation + ); + + setNodeEmitFlags(body, NodeEmitFlags.NoSourceMap | NodeEmitFlags.NoTokenSourceMaps); + + const forStatement = createFor( + createVariableDeclarationList([ + createVariableDeclaration(counter, createLiteral(0), /*location*/ moveRangePos(node.expression, -1)), + createVariableDeclaration(rhsReference, expression, /*location*/ node.expression) + ], /*location*/ node.expression), createLessThan( counter, createPropertyAccess(rhsReference, "length"), /*location*/ node.expression ), createPostfixIncrement(counter, /*location*/ node.expression), - createBlock( - statements - ), + body, /*location*/ node ); + + // Disable trailing source maps for the OpenParenToken to align source map emit with the old emitter. + setNodeEmitFlags(forStatement, NodeEmitFlags.NoTokenTrailingSourceMaps); + return forStatement; } /** diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 9b3385f3b6d..9447c3ee654 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -507,10 +507,15 @@ namespace ts { else { statements.push( createStatement( - createObjectDefineProperty( - createIdentifier("exports"), - createLiteral("__esModule"), - { value: createLiteral(true) } + createCall( + createPropertyAccess(createIdentifier("Object"), "defineProperty"), + [ + createIdentifier("exports"), + createLiteral("__esModule"), + createObjectLiteral([ + createPropertyAssignment("value", createLiteral(true)) + ]) + ] ) ) ); @@ -651,13 +656,16 @@ namespace ts { const name = node.name || getGeneratedNameForNode(node); if (hasModifier(node, ModifierFlags.Export)) { statements.push( - createFunctionDeclaration( - /*modifiers*/ undefined, - /*asteriskToken*/ undefined, - name, - node.parameters, - node.body, - /*location*/ node + setOriginalNode( + createFunctionDeclaration( + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + name, + node.parameters, + node.body, + /*location*/ node + ), + /*original*/ node ) ); diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index 1fc94b3061e..4da4c7d0ed7 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -11,11 +11,15 @@ namespace ts { const { getNodeEmitFlags, + setNodeEmitFlags, + getCommentRange, + setCommentRange, + getSourceMapRange, + setSourceMapRange, startLexicalEnvironment, endLexicalEnvironment, hoistVariableDeclaration, hoistFunctionDeclaration, - setNodeEmitFlags } = context; const compilerOptions = context.getCompilerOptions(); @@ -661,6 +665,7 @@ namespace ts { recordExportName(name); } + setOriginalNode(newNode, node); node = newNode; } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 0246fdcd212..c6c3403c234 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -225,7 +225,7 @@ namespace ts { * @param node The node to visit. */ function visitTypeScript(node: Node): VisitResult { - if (hasModifier(node, ModifierFlags.Ambient)) { + if (hasModifier(node, ModifierFlags.Ambient) && isStatement(node)) { // TypeScript ambient declarations are elided, but some comments may be preserved. // See the implementation of `getLeadingComments` in comments.ts for more details. return isStatement(node) @@ -598,7 +598,7 @@ namespace ts { // --------------------------------------------------------------------- // - const location = getUndecoratedRange(node); + const location = moveRangePastDecorators(node); // ... = class ${name} ${heritageClauses} { // ${members} @@ -914,8 +914,12 @@ namespace ts { function transformParameterWithPropertyAssignment(node: ParameterDeclaration) { Debug.assert(isIdentifier(node.name)); const name = node.name as Identifier; - const propertyName = getMutableClone(name, { flags: NodeEmitFlags.NoComments | NodeEmitFlags.NoSourceMap }); - const localName = getMutableClone(name, { flags: NodeEmitFlags.NoComments }); + const propertyName = getMutableClone(name); + setNodeEmitFlags(propertyName, NodeEmitFlags.NoComments | NodeEmitFlags.NoSourceMap); + + const localName = getMutableClone(name); + setNodeEmitFlags(localName, NodeEmitFlags.NoComments); + return startOnNewLine( createStatement( createAssignment( @@ -926,7 +930,7 @@ namespace ts { ), localName ), - /*location*/ node + /*location*/ moveRangePos(node, -1) ) ); } @@ -980,12 +984,10 @@ namespace ts { */ function addInitializedPropertyStatements(statements: Statement[], node: ClassExpression | ClassDeclaration, properties: PropertyDeclaration[], receiver: LeftHandSideExpression) { for (const property of properties) { - statements.push( - createStatement( - transformInitializedProperty(node, property, receiver), - /*location*/ property - ) - ); + const statement = createStatement(transformInitializedProperty(node, property, receiver)); + setSourceMapRange(statement, moveRangePastModifiers(property)); + setCommentRange(statement, property); + statements.push(statement); } } @@ -999,7 +1001,10 @@ namespace ts { function generateInitializedPropertyExpressions(node: ClassExpression | ClassDeclaration, properties: PropertyDeclaration[], receiver: LeftHandSideExpression) { const expressions: Expression[] = []; for (const property of properties) { - expressions.push(transformInitializedProperty(node, property, receiver, /*location*/ property)); + const expression = transformInitializedProperty(node, property, receiver); + setSourceMapRange(expression, moveRangePastModifiers(property)); + setCommentRange(expression, property); + expressions.push(expression); } return expressions; @@ -1012,7 +1017,7 @@ namespace ts { * @param property The property declaration. * @param receiver The object receiving the property assignment. */ - function transformInitializedProperty(node: ClassExpression | ClassDeclaration, property: PropertyDeclaration, receiver: LeftHandSideExpression, location?: TextRange) { + function transformInitializedProperty(node: ClassExpression | ClassDeclaration, property: PropertyDeclaration, receiver: LeftHandSideExpression) { const propertyName = visitPropertyNameOfClassElement(property); const initializer = visitNode(property.initializer, visitor, isExpression); const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName); @@ -1020,11 +1025,7 @@ namespace ts { setNodeEmitFlags(memberAccess, NodeEmitFlags.NoNestedSourceMaps); } - return createAssignment( - memberAccess, - initializer, - location - ); + return createAssignment(memberAccess, initializer); } /** @@ -1321,7 +1322,7 @@ namespace ts { prefix, memberName, descriptor, - getUndecoratedRange(member) + moveRangePastDecorators(member) ); setNodeEmitFlags(helper, NodeEmitFlags.NoComments); @@ -1371,7 +1372,7 @@ namespace ts { ) ); - const result = createAssignment(getDeclarationName(node), expression, getUndecoratedRange(node)); + const result = createAssignment(getDeclarationName(node), expression, moveRangePastDecorators(node)); setNodeEmitFlags(result, NodeEmitFlags.NoComments); return result; } @@ -1392,7 +1393,7 @@ namespace ts { decoratorExpressions, getDeclarationName(node) ), - getUndecoratedRange(node) + moveRangePastDecorators(node) ); setNodeEmitFlags(result, NodeEmitFlags.NoComments); @@ -1903,8 +1904,7 @@ namespace ts { * * This function will be called when one of the following conditions are met: * - The node is an overload - * - The node is marked as abstract - * - The node is marked as async + * - The node is marked as abstract, async, public, private, protected, or readonly * - The node has both a decorator and a computed property name * * @param node The method node. @@ -1916,20 +1916,18 @@ namespace ts { const method = createMethod( visitNodes(node.modifiers, visitor, isModifier), + node.asteriskToken, visitPropertyNameOfClassElement(node), visitNodes(node.parameters, visitor, isParameter), transformFunctionBody(node), - /*location*/ getUndecoratedRange(node) + /*location*/ node ); - setOriginalNode(method, node); - - // While we emit the source map for the node after skipping the decorators, + // While we emit the source map for the node after skipping decorators and modifiers, // we need to emit the comments for the original range. - if (node.decorators) { - setCommentRange(method, node); - setSourceMapRange(method, getUndecoratedRange(node)); - } + setCommentRange(method, node); + setSourceMapRange(method, moveRangePastDecorators(node)); + setOriginalNode(method, node); return method; } @@ -1948,7 +1946,7 @@ namespace ts { * Visits a get accessor declaration of a class. * * This function will be called when one of the following conditions are met: - * - The node is marked as abstract + * - The node is marked as abstract, public, private, or protected * - The node has both a decorator and a computed property name * * @param node The get accessor node. @@ -1961,18 +1959,16 @@ namespace ts { const accessor = createGetAccessor( visitNodes(node.modifiers, visitor, isModifier), visitPropertyNameOfClassElement(node), + visitNodes(node.parameters, visitor, isParameter), node.body ? visitEachChild(node.body, visitor, context) : createBlock([]), - /*location*/ getUndecoratedRange(node) + /*location*/ node ); - setOriginalNode(accessor, node); - - // While we emit the source map for the node after skipping the decorators, + // While we emit the source map for the node after skipping decorators and modifiers, // we need to emit the comments for the original range. - if (node.decorators) { - setCommentRange(accessor, node); - setSourceMapRange(accessor, getUndecoratedRange(node)); - } + setCommentRange(accessor, node); + setSourceMapRange(accessor, moveRangePastDecorators(node)); + setOriginalNode(accessor, node); return accessor; } @@ -1981,7 +1977,7 @@ namespace ts { * Visits a set accessor declaration of a class. * * This function will be called when one of the following conditions are met: - * - The node is marked as abstract + * - The node is marked as abstract, public, private, or protected * - The node has both a decorator and a computed property name * * @param node The set accessor node. @@ -1994,19 +1990,16 @@ namespace ts { const accessor = createSetAccessor( visitNodes(node.modifiers, visitor, isModifier), visitPropertyNameOfClassElement(node), - visitNode(firstOrUndefined(node.parameters), visitor, isParameter), + visitNodes(node.parameters, visitor, isParameter), node.body ? visitEachChild(node.body, visitor, context) : createBlock([]), - /*location*/ getUndecoratedRange(node) + /*location*/ node ); - setOriginalNode(accessor, node); - - // While we emit the source map for the node after skipping the decorators, + // While we emit the source map for the node after skipping decorators and modifiers, // we need to emit the comments for the original range. - if (node.decorators) { - setCommentRange(accessor, node); - setSourceMapRange(accessor, getUndecoratedRange(node)); - } + setCommentRange(accessor, node); + setSourceMapRange(accessor, moveRangePastDecorators(node)); + setOriginalNode(accessor, node); return accessor; } @@ -2032,8 +2025,9 @@ namespace ts { node.name, visitNodes(node.parameters, visitor, isParameter), transformFunctionBody(node), - node + /*location*/ node ); + setOriginalNode(func, node); if (isNamespaceExport(node)) { const statements: Statement[] = [func]; @@ -2054,17 +2048,20 @@ namespace ts { */ function visitFunctionExpression(node: FunctionExpression) { if (nodeIsMissing(node.body)) { - return createNode(SyntaxKind.OmittedExpression); - // return createOmittedExpression(/*location*/ node); + return createOmittedExpression(); } - return createFunctionExpression( + const func = createFunctionExpression( node.asteriskToken, node.name, visitNodes(node.parameters, visitor, isParameter), transformFunctionBody(node), - node + /*location*/ node ); + + setOriginalNode(func, node); + + return func; } /** @@ -2073,11 +2070,15 @@ namespace ts { * - The node is marked async */ function visitArrowFunction(node: ArrowFunction) { - return createArrowFunction( + const func = createArrowFunction( visitNodes(node.parameters, visitor, isParameter), transformConciseBody(node), - node + /*location*/ node ); + + setOriginalNode(func, node); + + return func; } function transformFunctionBody(node: MethodDeclaration | AccessorDeclaration | FunctionDeclaration | FunctionExpression): FunctionBody { @@ -2196,17 +2197,15 @@ namespace ts { node.dotDotDotToken, visitNode(node.name, visitor, isBindingName), visitNode(node.initializer, visitor, isExpression), - /*location*/ getUndecoratedRange(node) + /*location*/ moveRangePastModifiers(node) ); - setOriginalNode(parameter, node); - - // While we emit the source map for the node after skipping the decorators, + // While we emit the source map for the node after skipping decorators and modifiers, // we need to emit the comments for the original range. - if (node.decorators) { - setCommentRange(parameter, node); - setSourceMapRange(parameter, getUndecoratedRange(node)); - } + setCommentRange(parameter, node); + setSourceMapRange(parameter, moveRangePastModifiers(node)); + setNodeEmitFlags(parameter.name, NodeEmitFlags.NoTrailingSourceMap); + setOriginalNode(parameter, node); return parameter; } @@ -2777,9 +2776,9 @@ namespace ts { createAssignment( getExportName(node), getLocalName(node, /*noSourceMaps*/ true), - /*location*/ node + /*location*/ createRange(node.name.pos, node.end) ), - /*location*/ moveRangePos(node, -1) + /*location*/ createRange(-1, node.end) ) ); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 67a9c209699..058646658fb 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2894,6 +2894,7 @@ namespace ts { ContainsSpreadElementExpression = 1 << 16, ContainsComputedPropertyName = 1 << 17, ContainsBlockScopedBinding = 1 << 18, + ContainsBindingPattern = 1 << 19, HasComputedFlags = 1 << 31, // Transform flags have been computed. @@ -2917,6 +2918,8 @@ namespace ts { TypeExcludes = ~ContainsTypeScript, ObjectLiteralExcludes = ContainsDecorators | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName, ArrayLiteralOrCallOrNewExcludes = ContainsSpreadElementExpression, + VariableDeclarationListExcludes = ContainsBindingPattern, + ParameterExcludes = ContainsBindingPattern, } /* @internal */ @@ -2935,21 +2938,23 @@ namespace ts { NoTrailingSourceMap = 1 << 11, // Do not emit a trailing source map location for this node. NoSourceMap = NoLeadingSourceMap | NoTrailingSourceMap, // Do not emit a source map location for this node. NoNestedSourceMaps = 1 << 12, // Do not emit source map locations for children of this node. - NoTokenSourceMaps = 1 << 13, // Do not emit source map locations for tokens of this node. - NoLeadingComments = 1 << 14, // Do not emit leading comments for this node. - NoTrailingComments = 1 << 15, // Do not emit trailing comments for this node. + NoTokenLeadingSourceMaps = 1 << 13, // Do not emit leading source map location for token nodes. + NoTokenTrailingSourceMaps = 1 << 14, // Do not emit trailing source map location for token nodes. + NoTokenSourceMaps = NoTokenLeadingSourceMaps | NoTokenTrailingSourceMaps, // Do not emit source map locations for tokens of this node. + NoLeadingComments = 1 << 15, // Do not emit leading comments for this node. + NoTrailingComments = 1 << 16, // Do not emit trailing comments for this node. NoComments = NoLeadingComments | NoTrailingComments, // Do not emit comments for this node. - ExportName = 1 << 16, // Ensure an export prefix is added for an identifier that points to an exported declaration with a local name (see SymbolFlags.ExportHasLocal). - LocalName = 1 << 17, // Ensure an export prefix is not added for an identifier that points to an exported declaration. - Indented = 1 << 18, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter). - Merge = 1 << 19, // When getting emit options, merge with existing emit options. + ExportName = 1 << 17, // Ensure an export prefix is added for an identifier that points to an exported declaration with a local name (see SymbolFlags.ExportHasLocal). + LocalName = 1 << 18, // Ensure an export prefix is not added for an identifier that points to an exported declaration. + Indented = 1 << 19, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter). + Merge = 1 << 20, // When getting emit options, merge with existing emit options. // SourceMap Specialization. // TODO(rbuckton): These should be removed once source maps are aligned with the old // emitter and new baselines are taken. This exists solely to // align with the old emitter. - SourceMapEmitOpenBraceAsToken = 1 << 20, // Emits the open brace of a block function body as a source mapped token. - SourceMapAdjustRestParameterLoop = 1 << 21, // Emits adjusted source map positions for a ForStatement generated when transforming a rest parameter for ES5/3. + SourceMapEmitOpenBraceAsToken = 1 << 21, // Emits the open brace of a block function body as a source mapped token. + SourceMapAdjustRestParameterLoop = 1 << 22, // Emits adjusted source map positions for a ForStatement generated when transforming a rest parameter for ES5/3. } /* @internal */ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 98767eb0659..20a2e9dc2a7 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3026,6 +3026,19 @@ namespace ts { else if (kind === SyntaxKind.ObjectLiteralExpression) { return (node).properties.length === 0; } + else if (kind === SyntaxKind.CallExpression) { + if (!isSimpleExpressionWorker((node).expression, depth + 1)) { + return false; + } + + for (const argument of (node).arguments) { + if (!isSimpleExpressionWorker(argument, depth + 1)) { + return false; + } + } + + return true; + } } return false; @@ -3045,6 +3058,16 @@ namespace ts { } } + /** + * Creates a new TextRange from the provided pos and end. + * + * @param pos The start position. + * @param end The end position. + */ + export function createRange(pos: number, end: number): TextRange { + return { pos, end }; + } + /** * Creates a new TextRange from a provided range with a new end position. * @@ -3052,7 +3075,7 @@ namespace ts { * @param end The new end position. */ export function moveRangeEnd(range: TextRange, end: number): TextRange { - return { pos: range.pos, end }; + return createRange(range.pos, end); } /** @@ -3062,18 +3085,27 @@ namespace ts { * @param pos The new Start position. */ export function moveRangePos(range: TextRange, pos: number): TextRange { - return { pos, end: range.end }; + return createRange(pos, range.end); } /** * Moves the start position of a range past any decorators. */ - export function getUndecoratedRange(node: Node): TextRange { + export function moveRangePastDecorators(node: Node): TextRange { return node.decorators && node.decorators.length > 0 ? moveRangePos(node, node.decorators.end) : node; } + /** + * Moves the start position of a range past any decorators or modifiers. + */ + export function moveRangePastModifiers(node: Node): TextRange { + return node.modifiers && node.modifiers.length > 0 + ? moveRangePos(node, node.modifiers.end) + : moveRangePastDecorators(node); + } + /** * Determines whether a TextRange has the same start and end positions. * @@ -3110,7 +3142,7 @@ namespace ts { * @param token The token. */ export function createTokenRange(pos: number, token: SyntaxKind): TextRange { - return { pos, end: pos + tokenToString(token).length }; + return createRange(pos, pos + tokenToString(token).length); } export function rangeIsOnSingleLine(range: TextRange, sourceFile: SourceFile) { diff --git a/tests/baselines/reference/FunctionPropertyAssignments6_es6.js b/tests/baselines/reference/FunctionPropertyAssignments6_es6.js index 60f3677f108..edcd227f7b9 100644 --- a/tests/baselines/reference/FunctionPropertyAssignments6_es6.js +++ b/tests/baselines/reference/FunctionPropertyAssignments6_es6.js @@ -2,4 +2,4 @@ var v = { *() { } } //// [FunctionPropertyAssignments6_es6.js] -var v = { : function () { } }; +var v = { : function* () { } }; diff --git a/tests/baselines/reference/MemberFunctionDeclaration7_es6.js b/tests/baselines/reference/MemberFunctionDeclaration7_es6.js index a7d80ae974b..8e19f0db333 100644 --- a/tests/baselines/reference/MemberFunctionDeclaration7_es6.js +++ b/tests/baselines/reference/MemberFunctionDeclaration7_es6.js @@ -7,6 +7,6 @@ class C { var C = (function () { function C() { } - C.prototype.foo = function () { }; + C.prototype.foo = function* () { }; return C; }());