disallow named slots inheriting let: scope from default slots

pull/6049/head
Tan Li Hau 6 years ago committed by tanhauhau
parent 9a28416aa3
commit 2c41d2e377

@ -5,7 +5,6 @@ import Binding from './Binding';
import EventHandler from './EventHandler'; import EventHandler from './EventHandler';
import Expression from './shared/Expression'; import Expression from './shared/Expression';
import Component from '../Component'; import Component from '../Component';
import Let from './Let';
import TemplateScope from './shared/TemplateScope'; import TemplateScope from './shared/TemplateScope';
import { INode } from './interfaces'; import { INode } from './interfaces';
import { TemplateNode } from '../../interfaces'; import { TemplateNode } from '../../interfaces';
@ -18,7 +17,6 @@ export default class InlineComponent extends Node {
attributes: Attribute[] = []; attributes: Attribute[] = [];
bindings: Binding[] = []; bindings: Binding[] = [];
handlers: EventHandler[] = []; handlers: EventHandler[] = [];
lets: Let[] = [];
css_custom_properties: Attribute[] = []; css_custom_properties: Attribute[] = [];
children: INode[]; children: INode[];
scope: TemplateScope; scope: TemplateScope;
@ -40,6 +38,7 @@ export default class InlineComponent extends Node {
? new Expression(component, this, scope, info.expression) ? new Expression(component, this, scope, info.expression)
: null; : null;
const let_attributes = [];
info.attributes.forEach(node => { info.attributes.forEach(node => {
/* eslint-disable no-fallthrough */ /* eslint-disable no-fallthrough */
switch (node.type) { switch (node.type) {
@ -68,7 +67,7 @@ export default class InlineComponent extends Node {
break; break;
case 'Let': case 'Let':
this.lets.push(new Let(component, this, scope, node)); let_attributes.push(node);
break; break;
case 'Transition': case 'Transition':
@ -83,19 +82,7 @@ export default class InlineComponent extends Node {
/* eslint-enable no-fallthrough */ /* eslint-enable no-fallthrough */
}); });
if (this.lets.length > 0) { this.scope = scope;
this.scope = scope.child();
this.lets.forEach(l => {
const dependencies = new Set([l.name.name]);
l.names.forEach(name => {
this.scope.add(name, dependencies, this);
});
});
} else {
this.scope = scope;
}
this.handlers.forEach(handler => { this.handlers.forEach(handler => {
handler.modifiers.forEach(modifier => { handler.modifiers.forEach(modifier => {
@ -156,6 +143,24 @@ export default class InlineComponent extends Node {
}); });
} }
if (let_attributes.length) {
let warned = false;
// copy let: attribute from <Component /> to <svelte:fragment slot="default" />
// as they are for `slot="default"` only
children.forEach(child => {
const slot = child.attributes.find(attribute => attribute.name === 'slot');
if (!slot || slot.value[0].data === 'default') {
child.attributes.push(...let_attributes);
} else if (!warned) {
component.warn(info, {
code: 'let-on-component',
message: 'let: bindings on Component are meant for default slot template only, it is better to define them on <svelte:fragment slot="default"> instead.'
});
warned = true;
}
});
}
this.children = map_children(component, this, this.scope, children); this.children = map_children(component, this, this.scope, children);
} }

@ -14,7 +14,6 @@ import is_dynamic from '../shared/is_dynamic';
import bind_this from '../shared/bind_this'; import bind_this from '../shared/bind_this';
import { Node, Identifier, ObjectExpression } from 'estree'; import { Node, Identifier, ObjectExpression } from 'estree';
import EventHandler from '../Element/EventHandler'; import EventHandler from '../Element/EventHandler';
import { extract_names } from 'periscopic';
import mark_each_block_bindings from '../shared/mark_each_block_bindings'; import mark_each_block_bindings from '../shared/mark_each_block_bindings';
import { string_to_member_expression } from '../../../utils/string_to_member_expression'; import { string_to_member_expression } from '../../../utils/string_to_member_expression';
import SlotTemplate from '../../../nodes/SlotTemplate'; import SlotTemplate from '../../../nodes/SlotTemplate';
@ -80,12 +79,6 @@ export default class InlineComponentWrapper extends Wrapper {
}; };
if (this.node.children.length) { if (this.node.children.length) {
this.node.lets.forEach(l => {
extract_names(l.value || l.name).forEach(name => {
renderer.add_to_context(name, true);
});
});
this.children = this.node.children.map(child => new SlotTemplateWrapper(renderer, block, this, child as SlotTemplate, strip_whitespace, next_sibling)); this.children = this.node.children.map(child => new SlotTemplateWrapper(renderer, block, this, child as SlotTemplate, strip_whitespace, next_sibling));
} }

@ -47,11 +47,6 @@ export default class SlotTemplateWrapper extends Wrapper {
}); });
this.renderer.blocks.push(this.block); this.renderer.blocks.push(this.block);
const seen = new Set(lets.map(l => l.name.name));
this.parent.node.lets.forEach(l => {
if (!seen.has(l.name.name)) lets.push(l);
});
this.parent.set_slot( this.parent.set_slot(
slot_template_name, slot_template_name,
get_slot_definition(this.block, scope, lets) get_slot_definition(this.block, scope, lets)

@ -14,12 +14,6 @@ export default function(node: SlotTemplate, renderer: Renderer, options: RenderO
renderer.push(); renderer.push();
renderer.render(children, options); renderer.render(children, options);
const lets = node.lets;
const seen = new Set(lets.map(l => l.name.name));
parent_inline_component.lets.forEach(l => {
if (!seen.has(l.name.name)) lets.push(l);
});
const slot_fragment_content = renderer.pop(); const slot_fragment_content = renderer.pop();
if (!is_empty_template_literal(slot_fragment_content)) { if (!is_empty_template_literal(slot_fragment_content)) {
if (options.slot_scopes.has(node.slot_template_name)) { if (options.slot_scopes.has(node.slot_template_name)) {

@ -3,7 +3,7 @@ export default {
<div> <div>
<p>count in default slot: 0</p> <p>count in default slot: 0</p>
<p slot="foo">count in foo slot: 0</p> <p slot="foo">count in foo slot: 0</p>
<p slot="bar">count in bar slot: undefined</p> <p slot="bar">count in bar slot: 42</p>
<button>+1</button> <button>+1</button>
</div> </div>
`, `,
@ -17,7 +17,7 @@ export default {
<div> <div>
<p>count in default slot: 1</p> <p>count in default slot: 1</p>
<p slot="foo">count in foo slot: 1</p> <p slot="foo">count in foo slot: 1</p>
<p slot="bar">count in bar slot: undefined</p> <p slot="bar">count in bar slot: 42</p>
<button>+1</button> <button>+1</button>
</div> </div>
`); `);

@ -1,5 +1,6 @@
<script> <script>
import Nested from './Nested.svelte'; import Nested from './Nested.svelte';
let count = 42;
</script> </script>
<Nested let:count> <Nested let:count>

@ -0,0 +1,27 @@
<script>
import Nested from './Nested.svelte';
</script>
<Nested let:count>
<p>
count in default slot: {count}
</p>
<p slot="bar">
count in bar slot: {count}
</p>
</Nested>
<Nested let:count>
<p>
count in default slot: {count}
</p>
<p>
count in bar slot: {count}
</p>
</Nested>
<Nested let:count>
<p slot="bar">
count in bar slot: {count}
</p>
</Nested>

@ -0,0 +1,62 @@
[
{
"code": "let-on-component",
"message": "let: bindings on Component are meant for default slot template only, it is better to define them on <svelte:fragment slot=\"default\"> instead.",
"pos": 59,
"start": {
"character": 59,
"column": 0,
"line": 5
},
"end": {
"character": 182,
"column": 9,
"line": 12
}
},
{
"code": "missing-declaration",
"message": "'count' is not defined",
"pos": 160,
"start": {
"character": 160,
"column": 22,
"line": 10
},
"end": {
"character": 165,
"column": 27,
"line": 10
}
},
{
"code": "let-on-component",
"message": "let: bindings on Component are meant for default slot template only, it is better to define them on <svelte:fragment slot=\"default\"> instead.",
"pos": 298,
"start": {
"character": 298,
"column": 0,
"line": 23
},
"end": {
"character": 377,
"column": 9,
"line": 27
}
},
{
"code": "missing-declaration",
"message": "'count' is not defined",
"pos": 355,
"start": {
"character": 355,
"column": 22,
"line": 25
},
"end": {
"character": 360,
"column": 27,
"line": 25
}
}
]
Loading…
Cancel
Save