diff --git a/src/compile/nodes/EachBlock.ts b/src/compile/nodes/EachBlock.ts index ce9b63fe47..74a58fff38 100644 --- a/src/compile/nodes/EachBlock.ts +++ b/src/compile/nodes/EachBlock.ts @@ -9,14 +9,18 @@ import { Node as INode } from '../../interfaces'; function unpack_destructuring(contexts: Array<{ name: string, tail: string }>, node: INode, tail: string) { if (!node) return; - if (node.type === 'Identifier') { + if (node.type === 'Identifier' || node.type === 'RestIdentifier') { contexts.push({ key: node, tail }); } else if (node.type === 'ArrayPattern') { node.elements.forEach((element, i) => { - unpack_destructuring(contexts, element, `${tail}[${i}]`); + if (element.type === 'RestIdentifier') { + unpack_destructuring(contexts, element, `${tail}.slice(${i})`) + } else { + unpack_destructuring(contexts, element, `${tail}[${i}]`); + } }); } else if (node.type === 'ObjectPattern') { node.properties.forEach((property) => { diff --git a/src/parse/read/context.ts b/src/parse/read/context.ts index cece1c42d6..9f74059132 100644 --- a/src/parse/read/context.ts +++ b/src/parse/read/context.ts @@ -20,7 +20,7 @@ type Property = { type Context = { start: number; end: number; - type: 'Identifier' | 'ArrayPattern' | 'ObjectPattern'; + type: 'Identifier' | 'ArrayPattern' | 'ObjectPattern' | 'RestIdentifier'; name?: string; elements?: Context[]; properties?: Property[]; @@ -35,6 +35,13 @@ function error_on_assignment_pattern(parser: Parser) { } } +function error_on_rest_pattern_not_last(parser: Parser) { + parser.error({ + code: 'rest-pattern-not-last', + message: 'Rest destructuring expected to be last' + }, parser.index); +} + export default function read_context(parser: Parser) { const context: Context = { start: parser.index, @@ -49,6 +56,11 @@ export default function read_context(parser: Parser) { do { parser.allow_whitespace(); + const lastContext = context.elements[context.elements.length - 1]; + if (lastContext && lastContext.type === 'RestIdentifier') { + error_on_rest_pattern_not_last(parser); + } + if (parser.template[parser.index] === ',') { context.elements.push(null); } else { @@ -103,6 +115,22 @@ export default function read_context(parser: Parser) { context.end = parser.index; } + else if (parser.eat('...')) { + const name = parser.read_identifier(); + if (name) { + context.type = 'RestIdentifier'; + context.end = parser.index; + context.name = name; + } + + else { + parser.error({ + code: 'invalid-context', + message: 'Expected a rest pattern' + }); + } + } + else { const name = parser.read_identifier(); if (name) { @@ -122,4 +150,4 @@ export default function read_context(parser: Parser) { } return context; -} \ No newline at end of file +} diff --git a/test/parser/samples/each-block-destructured/input.svelte b/test/parser/samples/each-block-destructured/input.svelte index 4ddf33ef85..09e9885be0 100644 --- a/test/parser/samples/each-block-destructured/input.svelte +++ b/test/parser/samples/each-block-destructured/input.svelte @@ -1,3 +1,3 @@ -{#each animals as [key, value]} +{#each animals as [key, value, ...rest]}

{key}: {value}

{/each} diff --git a/test/parser/samples/each-block-destructured/output.json b/test/parser/samples/each-block-destructured/output.json index b9efc18906..0c4b1a5c54 100644 --- a/test/parser/samples/each-block-destructured/output.json +++ b/test/parser/samples/each-block-destructured/output.json @@ -1,12 +1,12 @@ { "html": { "start": 0, - "end": 62, + "end": 71, "type": "Fragment", "children": [ { "start": 0, - "end": 62, + "end": 71, "type": "EachBlock", "expression": { "type": "Identifier", @@ -16,37 +16,37 @@ }, "children": [ { - "start": 33, - "end": 54, + "start": 42, + "end": 63, "type": "Element", "name": "p", "attributes": [], "children": [ { - "start": 36, - "end": 41, + "start": 45, + "end": 50, "type": "MustacheTag", "expression": { "type": "Identifier", - "start": 37, - "end": 40, + "start": 46, + "end": 49, "name": "key" } }, { - "start": 41, - "end": 43, + "start": 50, + "end": 52, "type": "Text", "data": ": " }, { - "start": 43, - "end": 50, + "start": 52, + "end": 59, "type": "MustacheTag", "expression": { "type": "Identifier", - "start": 44, - "end": 49, + "start": 53, + "end": 58, "name": "value" } } @@ -55,7 +55,7 @@ ], "context": { "start": 18, - "end": 30, + "end": 39, "type": "ArrayPattern", "elements": [ { @@ -69,6 +69,12 @@ "end": 29, "type": "Identifier", "name": "value" + }, + { + "start": 31, + "end": 38, + "type": "RestIdentifier", + "name": "rest" } ] } @@ -78,4 +84,4 @@ "css": null, "instance": null, "module": null -} \ No newline at end of file +}