mirror of
https://github.com/sveltejs/svelte.git
synced 2024-11-29 00:22:05 +01:00
Merge pull request #2664 from EmilTholin/each-block-destructuring-rest
Add support for object-rest in each destructuring
This commit is contained in:
commit
78332cf5b0
@ -5,6 +5,7 @@ import map_children from './shared/map_children';
|
||||
import TemplateScope from './shared/TemplateScope';
|
||||
import AbstractBlock from './shared/AbstractBlock';
|
||||
import { Node as INode } from '../../interfaces';
|
||||
import { new_tail } from '../utils/tail';
|
||||
|
||||
function unpack_destructuring(contexts: Array<{ name: string, tail: string }>, node: INode, tail: string) {
|
||||
if (!node) return;
|
||||
@ -19,8 +20,20 @@ function unpack_destructuring(contexts: Array<{ name: string, tail: string }>, n
|
||||
unpack_destructuring(contexts, element, `${tail}[${i}]`);
|
||||
});
|
||||
} else if (node.type === 'ObjectPattern') {
|
||||
const used_properties = [];
|
||||
|
||||
node.properties.forEach((property) => {
|
||||
unpack_destructuring(contexts, property.value, `${tail}.${property.key.name}`);
|
||||
if (property.kind === 'rest') {
|
||||
unpack_destructuring(
|
||||
contexts,
|
||||
property.value,
|
||||
`@object_without_properties(${tail}, ${JSON.stringify(used_properties)})`
|
||||
);
|
||||
} else {
|
||||
used_properties.push(property.key.name);
|
||||
|
||||
unpack_destructuring(contexts, property.value,`${tail}.${property.key.name}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -53,7 +66,7 @@ export default class EachBlock extends AbstractBlock {
|
||||
this.scope = scope.child();
|
||||
|
||||
this.contexts = [];
|
||||
unpack_destructuring(this.contexts, info.context, '');
|
||||
unpack_destructuring(this.contexts, info.context, new_tail());
|
||||
|
||||
this.contexts.forEach(context => {
|
||||
this.scope.add(context.key.name, this.expression.dependencies, this);
|
||||
|
@ -6,6 +6,7 @@ import EachBlock from '../../nodes/EachBlock';
|
||||
import FragmentWrapper from './Fragment';
|
||||
import deindent from '../../utils/deindent';
|
||||
import ElseBlock from '../../nodes/ElseBlock';
|
||||
import { attach_head } from '../../utils/tail';
|
||||
|
||||
class ElseBlockWrapper extends Wrapper {
|
||||
node: ElseBlock;
|
||||
@ -127,7 +128,7 @@ export default class EachBlockWrapper extends Wrapper {
|
||||
this.block.bindings.set(prop.key.name, {
|
||||
object: this.vars.each_block_value,
|
||||
property: this.index_name,
|
||||
snippet: `${this.vars.each_block_value}[${this.index_name}]${prop.tail}`
|
||||
snippet: attach_head(`${this.vars.each_block_value}[${this.index_name}]`, prop.tail)
|
||||
});
|
||||
});
|
||||
|
||||
@ -177,7 +178,7 @@ export default class EachBlockWrapper extends Wrapper {
|
||||
? block.get_unique_name(`${this.var}_anchor`)
|
||||
: (this.next && this.next.var) || 'null';
|
||||
|
||||
this.context_props = this.node.contexts.map(prop => `child_ctx.${prop.key.name} = list[i]${prop.tail};`);
|
||||
this.context_props = this.node.contexts.map(prop => `child_ctx.${prop.key.name} = ${attach_head('list[i]', prop.tail)};`);
|
||||
|
||||
if (this.node.has_binding) this.context_props.push(`child_ctx.${this.vars.each_block_value} = list;`);
|
||||
if (this.node.has_binding || this.node.index) this.context_props.push(`child_ctx.${this.index_name} = i;`);
|
||||
|
7
src/compile/utils/tail.ts
Normal file
7
src/compile/utils/tail.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export function new_tail(): string {
|
||||
return '%%tail_head%%';
|
||||
}
|
||||
|
||||
export function attach_head(head: string, tail: string): string {
|
||||
return tail.replace('%%tail_head%%', head);
|
||||
}
|
@ -38,6 +38,16 @@ export function element(name) {
|
||||
return document.createElement(name);
|
||||
}
|
||||
|
||||
export function object_without_properties(obj, exclude) {
|
||||
const target = {};
|
||||
for (const k in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, k) && exclude.indexOf(k) === -1) {
|
||||
target[k] = obj[k];
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
export function svg_element(name) {
|
||||
return document.createElementNS('http://www.w3.org/2000/svg', name);
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ type Property = {
|
||||
start: number;
|
||||
end: number;
|
||||
type: 'Property';
|
||||
kind: string;
|
||||
kind: 'init' | 'rest';
|
||||
shorthand: boolean;
|
||||
key: Identifier;
|
||||
value: Context;
|
||||
@ -69,6 +69,41 @@ export default function read_context(parser: Parser) {
|
||||
do {
|
||||
parser.allow_whitespace();
|
||||
|
||||
if (parser.eat('...')) {
|
||||
parser.allow_whitespace();
|
||||
|
||||
const start = parser.index;
|
||||
const name = parser.read_identifier();
|
||||
const key: Identifier = {
|
||||
start,
|
||||
end: parser.index,
|
||||
type: 'Identifier',
|
||||
name
|
||||
}
|
||||
const property: Property = {
|
||||
start,
|
||||
end: parser.index,
|
||||
type: 'Property',
|
||||
kind: 'rest',
|
||||
shorthand: true,
|
||||
key,
|
||||
value: key
|
||||
}
|
||||
|
||||
context.properties.push(property);
|
||||
|
||||
parser.allow_whitespace();
|
||||
|
||||
if (parser.eat(',')) {
|
||||
parser.error({
|
||||
code: `comma-after-rest`,
|
||||
message: `Comma is not permitted after the rest element`
|
||||
}, parser.index - 1);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
const start = parser.index;
|
||||
const name = parser.read_identifier();
|
||||
const key: Identifier = {
|
||||
@ -122,4 +157,4 @@ export default function read_context(parser: Parser) {
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
export default {
|
||||
props: {
|
||||
animalEntries: [
|
||||
{ animal: 'raccoon', class: 'mammal' },
|
||||
{ animal: 'eagle', class: 'bird' }
|
||||
]
|
||||
},
|
||||
|
||||
html: `
|
||||
<p class="mammal">raccoon</p>
|
||||
<p class="bird">eagle</p>
|
||||
`,
|
||||
|
||||
test({ assert, component, target }) {
|
||||
component.animalEntries = [{ animal: 'cow', class: 'mammal' }];
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p class="mammal">cow</p>
|
||||
`);
|
||||
},
|
||||
};
|
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
export let animalEntries;
|
||||
</script>
|
||||
|
||||
{#each animalEntries as { animal, ...props } }
|
||||
<p {...props}>{animal}</p>
|
||||
{/each}
|
@ -0,0 +1,15 @@
|
||||
[{
|
||||
"code": "comma-after-rest",
|
||||
"message": "Comma is not permitted after the rest element",
|
||||
"pos": 100,
|
||||
"start": {
|
||||
"line": 5,
|
||||
"column": 53,
|
||||
"character": 100
|
||||
},
|
||||
"end": {
|
||||
"line": 5,
|
||||
"column": 53,
|
||||
"character": 100
|
||||
}
|
||||
}]
|
@ -0,0 +1,7 @@
|
||||
<script>
|
||||
export let animalEntries;
|
||||
</script>
|
||||
|
||||
{#each animalEntries as { animal, features: { ...rest, eyes } } }
|
||||
<p {...rest}>{animal} {eyes}</p>
|
||||
{/each}
|
Loading…
Reference in New Issue
Block a user