support aliasing and destructuring

pull/1998/head
Richard Harris 7 years ago
parent 1cb63ed16f
commit 582e8bb5f7

@ -1,27 +1,38 @@
import Node from './shared/Node';
import Expression from './shared/Expression';
import Component from '../Component';
import { walk } from 'estree-walker';
class Pattern {
constructor(node) {
// TODO implement `let:foo={bar}` and `let:contact={{ name, address }}` etc
}
}
const applicable = new Set(['Identifier', 'ObjectExpression', 'ArrayExpression', 'Property']);
export default class Let extends Node {
type: 'Let';
name: string;
pattern: Pattern;
names: string[];
value: string;
names: string[] = [];
constructor(component: Component, parent, scope, info) {
super(component, parent, scope, info);
this.name = info.name;
this.value = info.expression && `[✂${info.expression.start}-${info.expression.end}✂]`;
this.pattern = info.expression && new Pattern(info.expression);
if (info.expression) {
walk(info.expression, {
enter: node => {
if (!applicable.has(node.type)) {
component.error(node, {
code: 'invalid-let',
message: `let directive value must be an identifier or an object/array pattern`
});
}
// TODO
this.names = [this.name];
if (node.type === 'Identifier') {
this.names.push(node.name);
}
}
});
} else {
this.names.push(this.name);
}
}
}

@ -3,5 +3,8 @@ import Let from '../../../nodes/Let';
export function get_context_merger(lets: Let[]) {
if (lets.length === 0) return null;
return `({ ${lets.map(l => l.name).join(', ')} }) => ({ ${lets.map(l => l.name).join(', ')} })`;
const input = lets.map(l => l.value ? `${l.name}: ${l.value}` : l.name).join(', ');
const output = lets.map(l => l.names.join(', ')).join(', ');
return `({ ${input} }) => ({ ${output} })`;
}

@ -4,7 +4,7 @@ import Attribute from '../../nodes/Attribute';
import Node from '../../nodes/shared/Node';
import { snip } from '../utils';
import { stringify_attribute } from './shared/stringify_attribute';
import { get_slot_context } from './shared/get_slot_context';
import { get_slot_scope } from './shared/get_slot_scope';
// source: https://gist.github.com/ArjanSchouten/0b8574a6ad7f5065a5e7
const boolean_attributes = new Set([
@ -59,7 +59,7 @@ export default function(node, renderer, options) {
target.slotStack.push(slotName);
target.slots[slotName] = '';
options.slot_contexts.set(slotName, get_slot_context(node.lets));
options.slot_scopes.set(slotName, get_slot_scope(node.lets));
}
const classExpr = node.classes.map((classDir: Class) => {

@ -3,7 +3,7 @@ import { quoteNameIfNecessary } from '../../../utils/quoteIfNecessary';
import { snip } from '../utils';
import Renderer from '../Renderer';
import stringifyProps from '../../../utils/stringifyProps';
import { get_slot_context } from './shared/get_slot_context';
import { get_slot_scope } from './shared/get_slot_scope';
type AppendTarget = any; // TODO
@ -90,18 +90,18 @@ export default function(node, renderer: Renderer, options) {
renderer.targets.push(target);
const slot_contexts = new Map();
slot_contexts.set('default', get_slot_context(node.lets));
const slot_scopes = new Map();
slot_scopes.set('default', get_slot_scope(node.lets));
renderer.render(node.children, Object.assign({}, options, {
slot_contexts
slot_scopes
}));
Object.keys(target.slots).forEach(name => {
const slot_context = slot_contexts.get(name);
const slot_scope = slot_scopes.get(name);
slot_fns.push(
`${quoteNameIfNecessary(name)}: (${slot_context}) => \`${target.slots[name]}\``
`${quoteNameIfNecessary(name)}: (${slot_scope}) => \`${target.slots[name]}\``
);
});

@ -1,6 +0,0 @@
import Let from '../../../nodes/Let';
export function get_slot_context(lets: Let[]) {
if (lets.length === 0) return '';
return `{ ${lets.map(l => `${l.name}: ${l.name}`)} }`; // TODO support aliased/destructured lets
}

@ -0,0 +1,6 @@
import Let from '../../../nodes/Let';
export function get_slot_scope(lets: Let[]) {
if (lets.length === 0) return '';
return `{ ${lets.map(l => l.value ? `${l.name}: ${l.value}` : l.name).join(', ')} }`;
}

@ -0,0 +1,5 @@
<div>
{#each things as thing}
<slot {thing}/>
{/each}
</div>

@ -0,0 +1,24 @@
export default {
props: {
things: [1, 2, 3]
},
html: `
<div>
<span>1</span>
<span>2</span>
<span>3</span>
</div>`,
test({ assert, component, target }) {
component.things = [1, 2, 3, 4];
assert.htmlEqual(target.innerHTML, `
<div>
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
</div>
`);
}
};

@ -0,0 +1,9 @@
<script>
import Nested from './Nested.html';
export let things;
</script>
<Nested {things} let:thing={x}>
<span>{x}</span>
</Nested>

@ -0,0 +1,5 @@
<div>
{#each things as thing}
<slot {thing}/>
{/each}
</div>

@ -0,0 +1,34 @@
export default {
props: {
things: [
{ num: 1 },
{ num: 2 },
{ num: 3 }
]
},
html: `
<div>
<span>1</span>
<span>2</span>
<span>3</span>
</div>`,
test({ assert, component, target }) {
component.things = [
{ num: 1 },
{ num: 2 },
{ num: 3 },
{ num: 4 }
];
assert.htmlEqual(target.innerHTML, `
<div>
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
</div>
`);
}
};

@ -0,0 +1,9 @@
<script>
import Nested from './Nested.html';
export let things;
</script>
<Nested {things} let:thing="{{ num }}">
<span>{num}</span>
</Nested>

@ -1,15 +0,0 @@
[{
"code": "invalid-slot-placement",
"message": "<slot> cannot be a child of an each-block",
"start": {
"line": 2,
"column": 1,
"character": 25
},
"end": {
"line": 2,
"column": 1,
"character": 25
},
"pos": 25
}]

@ -1,3 +0,0 @@
{#each things as thing}
<slot name='foo'></slot>
{/each}
Loading…
Cancel
Save