update binding syntax

pull/1864/head
Rich Harris 7 years ago
parent 2b15ae3ad1
commit b5a42e6cf7

@ -4,7 +4,7 @@ import Expression from './shared/Expression';
export default class Binding extends Node {
name: string;
value: Expression;
expression: Expression;
isContextual: boolean;
usesContext: boolean;
obj: string;
@ -14,18 +14,18 @@ export default class Binding extends Node {
super(component, parent, scope, info);
this.name = info.name;
this.value = new Expression(component, this, scope, info.value);
this.expression = new Expression(component, this, scope, info.expression);
let obj;
let prop;
const { name } = getObject(this.value.node);
const { name } = getObject(this.expression.node);
this.isContextual = scope.names.has(name);
if (this.value.node.type === 'MemberExpression') {
prop = `[✂${this.value.node.property.start}-${this.value.node.property.end}✂]`;
if (!this.value.node.computed) prop = `'${prop}'`;
obj = `[✂${this.value.node.object.start}-${this.value.node.object.end}✂]`;
if (this.expression.node.type === 'MemberExpression') {
prop = `[✂${this.expression.node.property.start}-${this.expression.node.property.end}✂]`;
if (!this.expression.node.computed) prop = `'${prop}'`;
obj = `[✂${this.expression.node.object.start}-${this.expression.node.object.end}✂]`;
this.usesContext = true;
} else {

@ -31,7 +31,7 @@ export default class BindingWrapper {
this.node = node;
this.parent = parent;
const { dependencies } = this.node.value;
const { dependencies } = this.node.expression;
block.addDependencies(dependencies);
@ -46,7 +46,7 @@ export default class BindingWrapper {
if (node.isContextual) {
// we need to ensure that the each block creates a context including
// the list and the index, if they're not otherwise referenced
const { name } = getObject(this.node.value.node);
const { name } = getObject(this.node.expression.node);
const eachBlock = block.contextOwners.get(name);
eachBlock.hasBinding = true;
@ -73,17 +73,17 @@ export default class BindingWrapper {
let updateConditions: string[] = [];
const { name } = getObject(this.node.value.node);
const { snippet } = this.node.value;
const { name } = getObject(this.node.expression.node);
const { snippet } = this.node.expression;
// special case: if you have e.g. `<input type=checkbox bind:checked=selected.done>`
// and `selected` is an object chosen with a <select>, then when `checked` changes,
// we need to tell the component to update all the values `selected` might be
// pointing to
// TODO should this happen in preprocess?
const dependencies = new Set(this.node.value.dependencies);
const dependencies = new Set(this.node.expression.dependencies);
this.node.value.dependencies.forEach((prop: string) => {
this.node.expression.dependencies.forEach((prop: string) => {
const indirectDependencies = renderer.component.indirectDependencies.get(prop);
if (indirectDependencies) {
indirectDependencies.forEach(indirectDependency => {
@ -102,7 +102,7 @@ export default class BindingWrapper {
// special cases
if (this.node.name === 'group') {
const bindingGroup = getBindingGroup(renderer, this.node.value.node);
const bindingGroup = getBindingGroup(renderer, this.node.expression.node);
block.builders.hydrate.addLine(
`(#component.$$bindingGroups[${bindingGroup}] || (#component.$$bindingGroups[${bindingGroup}] = [])).push(${parent.var});`
@ -135,7 +135,7 @@ export default class BindingWrapper {
updateDom = null;
}
const dependencyArray = [...this.node.value.dependencies]
const dependencyArray = [...this.node.expression.dependencies]
if (dependencyArray.length === 1) {
updateConditions.push(`changed.${dependencyArray[0]}`)
@ -217,8 +217,8 @@ function getEventHandler(
let dependenciesArray = [...dependencies].filter(prop => prop[0] !== '$');
if (binding.node.isContextual) {
const tail = binding.node.value.node.type === 'MemberExpression'
? getTailSnippet(binding.node.value.node)
const tail = binding.node.expression.node.type === 'MemberExpression'
? getTailSnippet(binding.node.expression.node)
: '';
const head = block.bindings.get(name);
@ -233,7 +233,7 @@ function getEventHandler(
};
}
if (binding.node.value.node.type === 'MemberExpression') {
if (binding.node.expression.node.type === 'MemberExpression') {
// This is a little confusing, and should probably be tidied up
// at some point. It addresses a tricky bug (#893), wherein
// Svelte tries to `set()` a computed property, which throws an
@ -293,7 +293,7 @@ function getValueFromDom(
// <input type='checkbox' bind:group='foo'>
if (name === 'group') {
const bindingGroup = getBindingGroup(renderer, binding.node.value.node);
const bindingGroup = getBindingGroup(renderer, binding.node.expression.node);
if (type === 'checkbox') {
return `@getBindingGroupValue(#component.$$bindingGroups[${bindingGroup}])`;
}

@ -388,23 +388,9 @@ function readAttribute(parser: Parser, uniqueNames: Set<string>) {
const colon_index = name.indexOf(':');
const type = colon_index !== 1 && get_directive_type(name.slice(0, colon_index));
let value;
if (parser.eat('=')) {
if (type === 'Binding') {
// TODO should this be a special case? tbh this whole thing
// could use a lil refactoring probably
const quote = parser.read(/['"']/);
const expression = readExpression(parser);
value = [{ type: 'MustacheTag', start: expression.start, end: expression.end, expression }];
if (quote) parser.eat(quote, true);
} else {
value = readAttributeValue(parser);
}
} else {
value = true;
}
const value = parser.eat('=')
? readAttributeValue(parser)
: true;
const end = parser.index;
@ -415,21 +401,25 @@ function readAttribute(parser: Parser, uniqueNames: Set<string>) {
start,
end,
type,
name: directive_name
name: directive_name,
expression: value[0] && value[0].expression
};
if (type === 'Binding') {
directive.value = value[0] && value[0].expression;
} else {
directive.expression = value[0] && value[0].expression;
}
if (type === 'Transition') {
const direction = name.slice(0, colon_index);
directive.intro = direction === 'in' || direction === 'transition';
directive.outro = direction === 'out' || direction === 'transition';
}
if (!directive.expression && (type === 'Binding' || type === 'Class')) {
directive.expression = {
start: directive.start + colon_index + 1,
end: directive.end,
type: 'Identifier',
name: directive.name
};
}
return directive;
}

@ -1,2 +1,2 @@
<input bind:value='name'>
<input bind:value={name}>
<p>Hello {name}!</p>

@ -1,3 +1,3 @@
<div bind:offsetWidth=w bind:offsetHeight=h>
<div bind:offsetWidth={w} bind:offsetHeight={h}>
some content
</div>

@ -1 +1 @@
<input type='checkbox' bind:checked='foo'>
<input type='checkbox' bind:checked={foo}>

@ -1,3 +1,3 @@
<svelte:window bind:scrollY=y/>
<svelte:window bind:scrollY={y}/>
<p>scrolled to {y}</p>

@ -1 +1 @@
<input bind:value='name'>
<input bind:value={name}>

@ -1 +1 @@
<input bind:value='name'>
<input bind:value={name}>

@ -1,2 +1,2 @@
<input type='radio' bind:group='foo' value='{false}'>
<input type='radio' bind:group='foo' value='{true}'>
<input type='radio' bind:group={foo} value='{false}'>
<input type='radio' bind:group={foo} value='{true}'>

@ -1,2 +1,2 @@
<audio bind:currentTime='t' bind:duration='d' bind:paused bind:volume='v'
<audio bind:currentTime={t} bind:duration={d} bind:paused bind:volume={v}
src='music.mp3'></audio>

@ -1,4 +1,4 @@
<select bind:value='selected'>
<select bind:value={selected}>
{#each tasks as task}
<option value='{task}'>{task.description}</option>
{/each}

@ -1,13 +1,13 @@
<label>
<input type="checkbox" value="{values[0]}" bind:group='selected' /> {values[0].name}
<input type="checkbox" value="{values[0]}" bind:group={selected} /> {values[0].name}
</label>
<label>
<input type="checkbox" value="{values[1]}" bind:group='selected' /> {values[1].name}
<input type="checkbox" value="{values[1]}" bind:group={selected} /> {values[1].name}
</label>
<label>
<input type="checkbox" value="{values[2]}" bind:group='selected' /> {values[2].name}
<input type="checkbox" value="{values[2]}" bind:group={selected} /> {values[2].name}
</label>
<p>{selected.map( function ( value ) { return value.name; }).join( ', ' ) }</p>

@ -1,6 +1,6 @@
{#each values as value}
<label>
<input type="checkbox" value="{value}" bind:group='selected' /> {value.name}
<input type="checkbox" value="{value}" bind:group={selected} /> {value.name}
</label>
{/each}

@ -1,2 +1,2 @@
<input type='checkbox' bind:checked='foo'>
<input type='checkbox' bind:checked={foo}>
<p>{foo}</p>

@ -1,2 +1,2 @@
<input type='number' bind:value='count'>
<input type='number' bind:value={count}>
<p>{typeof count} {count}</p>

@ -1,6 +1,6 @@
{#each values as value}
<label>
<input type="radio" value="{value}" bind:group='selected' /> {value.name}
<input type="radio" value="{value}" bind:group={selected} /> {value.name}
</label>
{/each}

@ -1,2 +1,2 @@
<input type='range' bind:value='count'>
<input type='range' bind:value={count}>
<p>{typeof count} {count}</p>

@ -1,2 +1,2 @@
<input type='range' bind:value='count'>
<input type='range' bind:value={count}>
<p>{typeof count} {count}</p>

@ -1,3 +1,3 @@
{#each items as item}
<div><input bind:value='item'><p>{item}</p></div>
<div><input bind:value={item}><p>{item}</p></div>
{/each}

@ -1,2 +1,2 @@
<input bind:value='name'>
<input bind:value={name}>
<p>hello {name}</p>

@ -1 +1 @@
<input bind:value='a' on:input='{() => b = 0}'>
<input bind:value={a} on:input='{() => b = 0}'>

@ -1,4 +1,4 @@
<select bind:value='foo'>
<select bind:value={foo}>
{#each values as v}
<option>{v}</option>
{/each}

@ -7,7 +7,7 @@
<Modal ref:modal>
<span>{letter}</span>
<select bind:value='letter'>
<select bind:value={letter}>
{#each letters as letter}
<option value="{letter}">{letter}</option>
{/each}

@ -1,6 +1,6 @@
<p>selected: {selected}</p>
<select bind:value='selected'>
<select bind:value={selected}>
<option>a</option>
<option>b</option>
<option>c</option>

@ -1,6 +1,6 @@
<p>selected: {selected}</p>
<select bind:value='selected'>
<select bind:value={selected}>
<option>a</option>
<option>b</option>
<option>c</option>

@ -1,4 +1,4 @@
<select bind:value='selected'>
<select bind:value={selected}>
{#each items as item}
<option>{item}</option>
{/each}

@ -1,4 +1,4 @@
<select multiple bind:value='selected'>
<select multiple bind:value={selected}>
<option>one</option>
<option>two</option>
<option>three</option>

@ -1,6 +1,6 @@
<h1>Hello {name}!</h1>
<select bind:value="name">
<select bind:value={name}>
<option value="Harry">Harry</option>
<optgroup label="Group">
<option value="World">World</option>

@ -1,6 +1,6 @@
<p>selected: {selected}</p>
<select bind:value='selected'>
<select bind:value={selected}>
<option>one</option>
<option>two</option>
<option>three</option>

@ -1,6 +1,6 @@
<script>
import Nested from './Nested.html';
export let count;
export let idToValue = Object.create(null);
@ -11,7 +11,7 @@
}
</script>
<input type='number' bind:value='count'>
<input type='number' bind:value={count}>
<ol>
{#each ids as id}

@ -12,7 +12,7 @@
}
</script>
<input type='number' bind:value='count'>
<input type='number' bind:value={count}>
<ol>
{#each ids as object (object.id)}

@ -1,4 +1,4 @@
<select bind:value='selectedComponent'>
<select bind:value={selectedComponent}>
{#each components as component}
<option value='{component}'>{component.name}.html</option>
{/each}

@ -1 +1 @@
<textarea bind:value='code'></textarea>
<textarea bind:value={code}></textarea>

@ -5,5 +5,5 @@
</script>
{#each a as x}
<Widget bind:value='x'/>
<Widget bind:value={x}/>
{/each}

@ -5,7 +5,7 @@
</script>
{#each a as x}
<Widget bind:value='x'/>
<Widget bind:value={x}/>
{/each}
<p>{a.join(', ')}</p>

@ -4,5 +4,5 @@
export let x = 10;
</script>
<Counter bind:count='x'/>
<Counter bind:count={x}/>
<p>count: {x}</p>

@ -4,5 +4,5 @@
export let x;
</script>
<Counter bind:count='x'/>
<Counter bind:count={x}/>
<p>count: {x}</p>

@ -2,7 +2,7 @@
{#each components as component}
<li>
{#if component.edit}
<input ref:name bind:value=component.name />
<input ref:name bind:value={component}.name />
{:else}
{component.name}
{/if}

@ -1 +1 @@
<svelte:window bind:innerWidth='width'/>
<svelte:window bind:innerWidth={width}/>

@ -1,2 +1,2 @@
<p>bar</p>
<input type='checkbox' bind:checked='z'>
<input type='checkbox' bind:checked={z}>

@ -1,2 +1,2 @@
<p>foo</p>
<input bind:value='y'>
<input bind:value={y}>

@ -1,3 +1,3 @@
{#each foo.bar as bar}
<input bind:value='bar'>
<input bind:value={bar}>
{/each}

@ -1,5 +1,5 @@
{#each people as { name: { first: f, last: l } } }
<input bind:value=f>
<input bind:value=l>
<input bind:value={f}>
<input bind:value={l}>
<p>{f} {l}</p>
{/each}

@ -15,4 +15,4 @@
});
</script>
<Nested bind:visibleThings="visibleThings" />
<Nested bind:visibleThings={visibleThings} />

@ -10,5 +10,5 @@
{:else}
<Widget/>
<p>{x}</p>
<input type="text" bind:value=x />
<input type="text" bind:value={x} />
{/if}

@ -1 +1 @@
<input type="number" bind:value="field1">
<input type="number" bind:value={field1}>

@ -1,4 +1,4 @@
<select bind:value="foo">
<select bind:value={foo}>
{#each items as item}
<option value='{item.id}'>{item.id}</option>
{/each}

@ -8,7 +8,7 @@
}
</script>
<select bind:value="selected" on:change="{() => updateLastChangedTo(selected)}">
<select bind:value={selected} on:change="{() => updateLastChangedTo(selected)}">
{#each options as option}
<option value="{option.id}">{option.id}</option>
{/each}

@ -5,4 +5,4 @@
export let x = 'foo';
</script>
<svelte:component this={Widget} {...props} bind:value="x" />
<svelte:component this={Widget} {...props} bind:value={x} />

@ -1,3 +1,3 @@
<svelte:window bind:innerWidth='width' bind:innerHeight='height'/>
<svelte:window bind:innerWidth={width} bind:innerHeight={height}/>
<div>{width}x{height}</div>

@ -2,4 +2,4 @@
export let foo = 'bar';
</script>
<input bind:value=foo >
<input bind:value={foo} >

@ -5,4 +5,4 @@
export let x;
</script>
{y}<Foo bind:y='x'/>{y}
{y}<Foo bind:y={x}/>{y}

@ -1 +1 @@
<input bind:checked='foo'>
<input bind:checked={foo}>

@ -1 +1 @@
<input bind:value='foo' type>
<input bind:value={foo} type>

@ -1 +1 @@
<input bind:value='foo' type='{inputType}'>
<input bind:value={foo} type='{inputType}'>

@ -1 +1 @@
<svelte:window bind:innerwidth='w'/>
<svelte:window bind:innerwidth={w}/>

@ -1 +1 @@
<svelte:window bind:width='w'/>
<svelte:window bind:width={w}/>

@ -1 +1 @@
<svelte:window bind:potato='foo'/>
<svelte:window bind:potato={foo}/>
Loading…
Cancel
Save