diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 74d6600448d..ee089e6eae4 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -244,7 +244,7 @@ namespace ts { * @param keyfn A callback used to select the key for an element. * @param mapfn A callback used to map a contiguous chunk of values to a single value. */ - export function spanMap(array: T[], keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K) => U): U[] { + export function spanMap(array: T[], keyfn: (x: T, i: number) => K, mapfn: (chunk: T[], key: K, start: number, end: number) => U): U[] { let result: U[]; if (array) { result = []; @@ -268,7 +268,7 @@ namespace ts { } if (start < pos) { - const v = mapfn(array.slice(start, pos), previousKey); + const v = mapfn(array.slice(start, pos), previousKey, start, pos); if (v) { result.push(v); } diff --git a/src/compiler/transformers/es6.ts b/src/compiler/transformers/es6.ts index 0ee50a75a35..b53b3602556 100644 --- a/src/compiler/transformers/es6.ts +++ b/src/compiler/transformers/es6.ts @@ -1436,7 +1436,7 @@ namespace ts { */ function visitArrayLiteralExpression(node: ArrayLiteralExpression): Expression { // We are here because we contain a SpreadElementExpression. - return transformAndSpreadElements(node.elements, /*needsUniqueCopy*/ true, node.multiLine); + return transformAndSpreadElements(node.elements, /*needsUniqueCopy*/ true, node.multiLine, /*hasTrailingComma*/ node.elements.hasTrailingComma); } /** @@ -1523,7 +1523,7 @@ namespace ts { * @param needsUniqueCopy A value indicating whether to ensure that the result is a fresh array. * @param multiLine A value indicating whether the result should be emitted on multiple lines. */ - function transformAndSpreadElements(elements: NodeArray, needsUniqueCopy: boolean, multiLine: boolean): Expression { + function transformAndSpreadElements(elements: NodeArray, needsUniqueCopy: boolean, multiLine: boolean, hasTrailingComma?: boolean): Expression { // [source] // [a, ...b, c] // @@ -1532,10 +1532,12 @@ namespace ts { // Map spans of spread expressions into their expressions and spans of other // expressions into an array literal. + const numElements = elements.length; const segments = flatten( - spanMap(elements, isSpreadElementExpression, (chunk: Expression[], isSpread: boolean) => isSpread - ? map(chunk, visitExpressionOfSpreadElement) - : createArrayLiteral(visitNodes(createNodeArray(chunk), visitor, isExpression), /*location*/ undefined, multiLine))); + spanMap(elements, partitionSpreadElement, (partition, visitPartition, start, end) => + visitPartition(partition, multiLine, hasTrailingComma && end === numElements) + ) + ); if (segments.length === 1) { return needsUniqueCopy && isSpreadElementExpression(elements[0]) @@ -1547,6 +1549,24 @@ namespace ts { return createArrayConcat(segments.shift(), segments); } + function partitionSpreadElement(node: Expression) { + return isSpreadElementExpression(node) + ? visitSpanOfSpreadElements + : visitSpanOfNonSpreadElements; + } + + function visitSpanOfSpreadElements(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult { + return map(chunk, visitExpressionOfSpreadElement); + } + + function visitSpanOfNonSpreadElements(chunk: Expression[], multiLine: boolean, hasTrailingComma: boolean): VisitResult { + return createArrayLiteral( + visitNodes(createNodeArray(chunk, /*location*/ undefined, hasTrailingComma), visitor, isExpression), + /*location*/ undefined, + multiLine + ); + } + /** * Transforms the expression of a SpreadElementExpression node. * diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f3093a899a3..5f3899f4e24 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1825,6 +1825,7 @@ namespace ts { case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.TemplateExpression: case SyntaxKind.ParenthesizedExpression: + case SyntaxKind.OmittedExpression: return 19; case SyntaxKind.TaggedTemplateExpression: