Fix 6860: Warn user when binding rest operator

pull/7526/head
vaibhav rai 4 years ago committed by tanhauhau
parent 34eb6efedc
commit 4af59e463f

@ -6,7 +6,7 @@
export default { export default {
custom_element_no_tag: { custom_element_no_tag: {
code: 'custom-element-no-tag', code: 'custom-element-no-tag',
message: 'No custom element \'tag\' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. <svelte:options tag="my-thing"/>. To hide this warning, use <svelte:options tag={null}/>' message: 'No custom element \'tag\' option was specified. To automatically register a custom element, specify a name with a hyphen in it, e.g. <svelte:options tag="my-thing"/>. To hide this warning, use <svelte:options tag={null}/>'
}, },
unused_export_let: (component: string, property: string) => ({ unused_export_let: (component: string, property: string) => ({
code: 'unused-export-let', code: 'unused-export-let',
@ -143,5 +143,9 @@ export default {
redundant_event_modifier_passive: { redundant_event_modifier_passive: {
code: 'redundant-event-modifier', code: 'redundant-event-modifier',
message: 'The passive modifier only works with wheel and touch events' message: 'The passive modifier only works with wheel and touch events'
} },
invalid_rest_eachblock_binding: (rest_element_name: string) => ({
code: 'invalid-rest-eachblock-binding',
message: `...${rest_element_name} operator will create a new object and binding propogation with original object will not work`
})
}; };

@ -5,7 +5,7 @@ import AbstractBlock from './shared/AbstractBlock';
import Element from './Element'; import Element from './Element';
import ConstTag from './ConstTag'; import ConstTag from './ConstTag';
import { Context, unpack_destructuring } from './shared/Context'; import { Context, unpack_destructuring } from './shared/Context';
import { Node } from 'estree'; import { Node, Identifier } from 'estree';
import Component from '../Component'; import Component from '../Component';
import { TemplateNode } from '../../interfaces'; import { TemplateNode } from '../../interfaces';
import compiler_errors from '../compiler_errors'; import compiler_errors from '../compiler_errors';
@ -28,7 +28,7 @@ export default class EachBlock extends AbstractBlock {
has_animation: boolean; has_animation: boolean;
has_binding = false; has_binding = false;
has_index_binding = false; has_index_binding = false;
context_rest_properties: Map<string, Node>;
else?: ElseBlock; else?: ElseBlock;
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) { constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
@ -40,10 +40,17 @@ export default class EachBlock extends AbstractBlock {
this.index = info.index; this.index = info.index;
this.scope = scope.child(); this.scope = scope.child();
this.context_rest_properties = new Map();
this.contexts = []; this.contexts = [];
unpack_destructuring({ contexts: this.contexts, node: info.context, scope, component }); unpack_destructuring({ contexts: this.contexts, node: info.context, scope, component });
if (this.context_node.type === 'ObjectPattern') {
this.context_node.properties.forEach(i => {
if (i.type === 'RestElement') {
this.context_rest_properties.set((i.argument as Identifier).name, i);
}
});
}
this.contexts.forEach(context => { this.contexts.forEach(context => {
this.scope.add(context.key.name, this.expression.dependencies, this); this.scope.add(context.key.name, this.expression.dependencies, this);
}); });

@ -2,6 +2,7 @@ import EachBlock from '../../../nodes/EachBlock';
import InlineComponentWrapper from '../InlineComponent'; import InlineComponentWrapper from '../InlineComponent';
import ElementWrapper from '../Element'; import ElementWrapper from '../Element';
import Binding from '../../../nodes/Binding'; import Binding from '../../../nodes/Binding';
import compiler_warnings from '../../../compiler_warnings';
export default function mark_each_block_bindings( export default function mark_each_block_bindings(
parent: ElementWrapper | InlineComponentWrapper, parent: ElementWrapper | InlineComponentWrapper,
@ -11,6 +12,12 @@ export default function mark_each_block_bindings(
// the list and the index, if they're not otherwise referenced // the list and the index, if they're not otherwise referenced
binding.expression.references.forEach(name => { binding.expression.references.forEach(name => {
const each_block = parent.node.scope.get_owner(name); const each_block = parent.node.scope.get_owner(name);
if (each_block && each_block.type === 'EachBlock') {
const rest_node = each_block.context_rest_properties.get(name);
if (rest_node) {
parent.renderer.component.warn(rest_node as any, compiler_warnings.invalid_rest_eachblock_binding(name));
}
}
if (each_block) { if (each_block) {
(each_block as EachBlock).has_binding = true; (each_block as EachBlock).has_binding = true;
} }

@ -0,0 +1,8 @@
<script>
let objArray = [{foo: '1', id: 0, innerValue: "test"}, {foo: '2', id:1, innerValue: "Somethin"}]
</script>
{#each objArray as { id, ...rest } (id)}
<input bind:value={rest.innerValue} type="text" placeholder={rest.foo}/>
<br/>
{/each}

@ -0,0 +1,6 @@
[
{
"code": "invalid-rest-eachblock-binding",
"message": "...rest operator will create a new object and binding propogation with original object will not work"
}
]
Loading…
Cancel
Save