[feat] support const tag for if block (#7451)

pull/7505/head
Tan Li Hau 2 years ago committed by GitHub
parent 61d1467c25
commit a2de3894c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -465,16 +465,16 @@ The `{@const ...}` tag defines a local constant.
```sv
<script>
export let boxes;
export let boxes;
</script>
{#each boxes as box}
{@const area = box.width * box.height}
{@const area = box.width * box.height}
{box.width} * {box.height} = {area}
{/each}
```
`{@const}` is only allowed as direct child of `{#each}`, `{:then}`, `{:catch}`, `<Component />` or `<svelte:fragment />`.
`{@const}` is only allowed as direct child of `{#if}`, `{:else if}`, `{:else}`, `{#each}`, `{:then}`, `{:catch}`, `<Component />` or `<svelte:fragment />`.
### Element directives

@ -260,7 +260,7 @@ export default {
},
invalid_const_placement: {
code: 'invalid-const-placement',
message: '{@const} must be the immediate child of {#each}, {:then}, {:catch}, <svelte:fragment> or <Component>'
message: '{@const} must be the immediate child of {#if}, {:else if}, {:else}, {#each}, {:then}, {:catch}, <svelte:fragment> or <Component>'
},
invalid_const_declaration: (name: string) => ({
code: 'invalid-const-declaration',

@ -11,7 +11,7 @@ import is_reference, { NodeWithPropertyDefinition } from 'is-reference';
import get_object from '../utils/get_object';
import compiler_errors from '../compiler_errors';
const allowed_parents = new Set(['EachBlock', 'CatchBlock', 'ThenBlock', 'InlineComponent', 'SlotTemplate']);
const allowed_parents = new Set(['EachBlock', 'CatchBlock', 'ThenBlock', 'InlineComponent', 'SlotTemplate', 'IfBlock', 'ElseBlock']);
export default class ConstTag extends Node {
type: 'ConstTag';

@ -1,16 +1,21 @@
import map_children from './shared/map_children';
import AbstractBlock from './shared/AbstractBlock';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
import Node from './shared/Node';
import ConstTag from './ConstTag';
import get_const_tags from './shared/get_const_tags';
export default class ElseBlock extends AbstractBlock {
type: 'ElseBlock';
scope: TemplateScope;
const_tags: ConstTag[];
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.children = map_children(component, this, scope, info.children);
this.scope = scope.child();
([this.const_tags, this.children] = get_const_tags(info.children, component, this, this));
this.warn_if_empty_block();
}

@ -1,22 +1,26 @@
import ElseBlock from './ElseBlock';
import Expression from './shared/Expression';
import map_children from './shared/map_children';
import AbstractBlock from './shared/AbstractBlock';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import { TemplateNode } from '../../interfaces';
import Node from './shared/Node';
import ConstTag from './ConstTag';
import get_const_tags from './shared/get_const_tags';
export default class IfBlock extends AbstractBlock {
type: 'IfBlock';
expression: Expression;
else: ElseBlock;
scope: TemplateScope;
const_tags: ConstTag[];
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
super(component, parent, scope, info);
this.scope = scope.child();
this.expression = new Expression(component, this, scope, info.expression);
this.children = map_children(component, this, scope, info.children);
this.expression = new Expression(component, this, this.scope, info.expression);
([this.const_tags, this.children] = get_const_tags(info.children, component, this, this));
this.else = info.else
? new ElseBlock(component, this, scope, info.else)

@ -72,6 +72,8 @@ export type INode = Action
| Window;
export type INodeAllowConstTag =
| IfBlock
| ElseBlock
| EachBlock
| CatchBlock
| ThenBlock

@ -27,6 +27,7 @@ export class ElseBlockWrapper extends Wrapper {
next_sibling: Wrapper
) {
super(renderer, block, parent, node);
add_const_tags_context(renderer, this.node.const_tags);
this.block = block.child({
comment: create_debugging_comment(node, this.renderer.component),
@ -257,6 +258,18 @@ export default class EachBlockWrapper extends Wrapper {
}
if (this.else) {
let else_ctx = x`#ctx`;
if (this.else.node.const_tags.length > 0) {
const get_ctx_name = this.renderer.component.get_unique_name('get_else_ctx');
this.renderer.blocks.push(b`
function ${get_ctx_name}(#ctx) {
const child_ctx = #ctx.slice();
${add_const_tags(block, this.else.node.const_tags, 'child_ctx')}
return child_ctx;
}
`);
else_ctx = x`${get_ctx_name}(#ctx)`;
}
const each_block_else = component.get_unique_name(`${this.var.name}_else`);
block.chunks.init.push(b`let ${each_block_else} = null;`);
@ -264,7 +277,7 @@ export default class EachBlockWrapper extends Wrapper {
// TODO neaten this up... will end up with an empty line in the block
block.chunks.init.push(b`
if (!${this.vars.data_length}) {
${each_block_else} = ${this.else.block.name}(#ctx);
${each_block_else} = ${this.else.block.name}(${else_ctx});
}
`);
@ -304,9 +317,9 @@ export default class EachBlockWrapper extends Wrapper {
if (this.else.block.has_update_method) {
this.updates.push(b`
if (!${this.vars.data_length} && ${each_block_else}) {
${each_block_else}.p(#ctx, #dirty);
${each_block_else}.p(${else_ctx}, #dirty);
} else if (!${this.vars.data_length}) {
${each_block_else} = ${this.else.block.name}(#ctx);
${each_block_else} = ${this.else.block.name}(${else_ctx});
${each_block_else}.c();
${has_transitions && b`@transition_in(${each_block_else}, 1);`}
${each_block_else}.m(${update_mount_node}, ${update_anchor_node});
@ -321,7 +334,7 @@ export default class EachBlockWrapper extends Wrapper {
${destroy_block_else};
}
} else if (!${each_block_else}) {
${each_block_else} = ${this.else.block.name}(#ctx);
${each_block_else} = ${this.else.block.name}(${else_ctx});
${each_block_else}.c();
${has_transitions && b`@transition_in(${each_block_else}, 1);`}
${each_block_else}.m(${update_mount_node}, ${update_anchor_node});

@ -11,6 +11,7 @@ import { walk } from 'estree-walker';
import { is_head } from './shared/is_head';
import { Identifier, Node } from 'estree';
import { push_array } from '../../../utils/push_array';
import { add_const_tags, add_const_tags_context } from './shared/add_const_tags';
function is_else_if(node: ElseBlock) {
return (
@ -25,8 +26,10 @@ class IfBlockBranch extends Wrapper {
condition?: any;
snippet?: Node;
is_dynamic: boolean;
node: IfBlock | ElseBlock;
var = null;
get_ctx_name: Node | undefined;
constructor(
renderer: Renderer,
@ -63,6 +66,8 @@ class IfBlockBranch extends Wrapper {
}
}
add_const_tags_context(renderer, this.node.const_tags);
this.block = block.child({
comment: create_debugging_comment(node, parent.renderer.component),
name: parent.renderer.component.get_unique_name(
@ -74,6 +79,10 @@ class IfBlockBranch extends Wrapper {
this.fragment = new FragmentWrapper(renderer, this.block, node.children, parent, strip_whitespace, next_sibling);
this.is_dynamic = this.block.dependencies.size > 0;
if (node.const_tags.length > 0) {
this.get_ctx_name = parent.renderer.component.get_unique_name(is_else ? 'get_else_ctx' : 'get_if_ctx');
}
}
}
@ -190,6 +199,18 @@ export default class IfBlockWrapper extends Wrapper {
const has_outros = this.branches[0].block.has_outro_method;
const has_transitions = has_intros || has_outros;
this.branches.forEach(branch => {
if (branch.get_ctx_name) {
this.renderer.blocks.push(b`
function ${branch.get_ctx_name}(#ctx) {
const child_ctx = #ctx.slice();
${add_const_tags(block, branch.node.const_tags, 'child_ctx')}
return child_ctx;
}
`);
}
});
const vars = { name, anchor, if_exists_condition, has_else, has_transitions };
const detaching = parent_node && !is_head(parent_node) ? null : 'detaching';
@ -260,9 +281,13 @@ export default class IfBlockWrapper extends Wrapper {
) {
const select_block_type = this.renderer.component.get_unique_name('select_block_type');
const current_block_type = block.get_unique_name('current_block_type');
const need_select_block_ctx = this.branches.some(branch => branch.get_ctx_name);
const select_block_ctx = need_select_block_ctx ? block.get_unique_name('select_block_ctx') : null;
const if_ctx = select_block_ctx ? x`${select_block_ctx}(#ctx, ${current_block_type})` : x`#ctx`;
const get_block = has_else
? x`${current_block_type}(#ctx)`
: x`${current_block_type} && ${current_block_type}(#ctx)`;
? x`${current_block_type}(${if_ctx})`
: x`${current_block_type} && ${current_block_type}(${if_ctx})`;
if (this.needs_update) {
block.chunks.init.push(b`
@ -271,10 +296,10 @@ export default class IfBlockWrapper extends Wrapper {
return b`${snippet && dependencies.length > 0 ? b`if (${block.renderer.dirty(dependencies)}) ${condition} = null;` : null}`;
})}
${this.branches.map(({ condition, snippet, block }) => condition
? b`
${snippet && b`if (${condition} == null) ${condition} = !!${snippet}`}
if (${condition}) return ${block.name};`
: b`return ${block.name};`
? b`
${snippet && b`if (${condition} == null) ${condition} = !!${snippet}`}
if (${condition}) return ${block.name};`
: b`return ${block.name};`
)}
}
`);
@ -282,12 +307,40 @@ export default class IfBlockWrapper extends Wrapper {
block.chunks.init.push(b`
function ${select_block_type}(#ctx, #dirty) {
${this.branches.map(({ condition, snippet, block }) => condition
? b`if (${snippet || condition}) return ${block.name};`
: b`return ${block.name};`)}
? b`if (${snippet || condition}) return ${block.name};`
: b`return ${block.name};`)}
}
`);
}
if (need_select_block_ctx) {
// if all branches needs create a context
if (this.branches.every(branch => branch.get_ctx_name)) {
block.chunks.init.push(b`
function ${select_block_ctx}(#ctx, #type) {
${this.branches.map(({ condition, get_ctx_name, block }) => {
return condition
? b`if (#type === ${block.name}) return ${get_ctx_name}(#ctx);`
: b`return ${get_ctx_name}(#ctx);`;
}).filter(Boolean)}
}
`);
} else {
// when not all branches need to create a new context,
// this code is simpler
block.chunks.init.push(b`
function ${select_block_ctx}(#ctx, #type) {
${this.branches.map(({ get_ctx_name, block }) => {
return get_ctx_name
? b`if (#type === ${block.name}) return ${get_ctx_name}(#ctx);`
: null;
}).filter(Boolean)}
return #ctx;
}
`);
}
}
block.chunks.init.push(b`
let ${current_block_type} = ${select_block_type}(#ctx, ${this.renderer.get_initial_dirty()});
let ${name} = ${get_block};
@ -322,7 +375,7 @@ export default class IfBlockWrapper extends Wrapper {
if (dynamic) {
block.chunks.update.push(b`
if (${current_block_type} === (${current_block_type} = ${select_block_type}(#ctx, #dirty)) && ${name}) {
${name}.p(#ctx, #dirty);
${name}.p(${if_ctx}, #dirty);
} else {
${change_block}
}
@ -336,9 +389,9 @@ export default class IfBlockWrapper extends Wrapper {
}
} else if (dynamic) {
if (if_exists_condition) {
block.chunks.update.push(b`if (${if_exists_condition}) ${name}.p(#ctx, #dirty);`);
block.chunks.update.push(b`if (${if_exists_condition}) ${name}.p(${if_ctx}, #dirty);`);
} else {
block.chunks.update.push(b`${name}.p(#ctx, #dirty);`);
block.chunks.update.push(b`${name}.p(${if_ctx}, #dirty);`);
}
}
@ -370,6 +423,9 @@ export default class IfBlockWrapper extends Wrapper {
const previous_block_index = block.get_unique_name('previous_block_index');
const if_block_creators = block.get_unique_name('if_block_creators');
const if_blocks = block.get_unique_name('if_blocks');
const need_select_block_ctx = this.branches.some(branch => branch.get_ctx_name);
const select_block_ctx = need_select_block_ctx ? block.get_unique_name('select_block_ctx') : null;
const if_ctx = select_block_ctx ? x`${select_block_ctx}(#ctx, ${current_block_type_index})` : x`#ctx`;
const if_current_block_type_index = has_else
? nodes => nodes
@ -392,32 +448,60 @@ export default class IfBlockWrapper extends Wrapper {
return b`${snippet && dependencies.length > 0 ? b`if (${block.renderer.dirty(dependencies)}) ${condition} = null;` : null}`;
})}
${this.branches.map(({ condition, snippet }, i) => condition
? b`
${snippet && b`if (${condition} == null) ${condition} = !!${snippet}`}
if (${condition}) return ${i};`
: b`return ${i};`)}
${!has_else && b`return -1;`}
}
`
? b`
${snippet && b`if (${condition} == null) ${condition} = !!${snippet}`}
if (${condition}) return ${i};`
: b`return ${i};`)}
${!has_else && b`return -1;`}
}
`
: b`
function ${select_block_type}(#ctx, #dirty) {
${this.branches.map(({ condition, snippet }, i) => condition
? b`if (${snippet || condition}) return ${i};`
: b`return ${i};`)}
? b`if (${snippet || condition}) return ${i};`
: b`return ${i};`)}
${!has_else && b`return -1;`}
}
`}
`);
if (need_select_block_ctx) {
// if all branches needs create a context
if (this.branches.every(branch => branch.get_ctx_name)) {
block.chunks.init.push(b`
function ${select_block_ctx}(#ctx, #index) {
${this.branches.map(({ condition, get_ctx_name }, i) => {
return condition
? b`if (#index === ${i}) return ${get_ctx_name}(#ctx);`
: b`return ${get_ctx_name}(#ctx);`;
}).filter(Boolean)}
}
`);
} else {
// when not all branches need to create a new context,
// this code is simpler
block.chunks.init.push(b`
function ${select_block_ctx}(#ctx, #index) {
${this.branches.map(({ get_ctx_name }, i) => {
return get_ctx_name
? b`if (#index === ${i}) return ${get_ctx_name}(#ctx);`
: null;
}).filter(Boolean)}
return #ctx;
}
`);
}
}
if (has_else) {
block.chunks.init.push(b`
${current_block_type_index} = ${select_block_type}(#ctx, ${this.renderer.get_initial_dirty()});
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](#ctx);
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](${if_ctx});
`);
} else {
block.chunks.init.push(b`
if (~(${current_block_type_index} = ${select_block_type}(#ctx, ${this.renderer.get_initial_dirty()}))) {
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](#ctx);
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](${if_ctx});
}
`);
}
@ -445,10 +529,10 @@ export default class IfBlockWrapper extends Wrapper {
const create_new_block = b`
${name} = ${if_blocks}[${current_block_type_index}];
if (!${name}) {
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](#ctx);
${name} = ${if_blocks}[${current_block_type_index}] = ${if_block_creators}[${current_block_type_index}](${if_ctx});
${name}.c();
} else {
${dynamic && b`${name}.p(#ctx, #dirty);`}
${dynamic && b`${name}.p(${if_ctx}, #dirty);`}
}
${has_transitions && b`@transition_in(${name}, 1);`}
${name}.m(${update_mount_node}, ${anchor});
@ -480,7 +564,7 @@ export default class IfBlockWrapper extends Wrapper {
if (dynamic) {
block.chunks.update.push(b`
if (${current_block_type_index} === ${previous_block_index}) {
${if_current_block_type_index(b`${if_blocks}[${current_block_type_index}].p(#ctx, #dirty);`)}
${if_current_block_type_index(b`${if_blocks}[${current_block_type_index}].p(${if_ctx}, #dirty);`)}
} else {
${change_block}
}
@ -494,9 +578,9 @@ export default class IfBlockWrapper extends Wrapper {
}
} else if (dynamic) {
if (if_exists_condition) {
block.chunks.update.push(b`if (${if_exists_condition}) ${name}.p(#ctx, #dirty);`);
block.chunks.update.push(b`if (${if_exists_condition}) ${name}.p(${if_ctx}, #dirty);`);
} else {
block.chunks.update.push(b`${name}.p(#ctx, #dirty);`);
block.chunks.update.push(b`${name}.p(${if_ctx}, #dirty);`);
}
}
@ -514,11 +598,12 @@ export default class IfBlockWrapper extends Wrapper {
detaching
) {
const branch = this.branches[0];
const if_ctx = branch.get_ctx_name ? x`${branch.get_ctx_name}(#ctx)` : x`#ctx`;
if (branch.snippet) block.add_variable(branch.condition, branch.snippet);
block.chunks.init.push(b`
let ${name} = ${branch.condition} && ${branch.block.name}(#ctx);
let ${name} = ${branch.condition} && ${branch.block.name}(${if_ctx});
`);
const initial_mount_node = parent_node || '#target';
@ -533,15 +618,14 @@ export default class IfBlockWrapper extends Wrapper {
const enter = b`
if (${name}) {
${dynamic && b`${name}.p(#ctx, #dirty);`}
${
has_transitions &&
${dynamic && b`${name}.p(${if_ctx}, #dirty);`}
${has_transitions &&
b`if (${block.renderer.dirty(branch.dependencies)}) {
@transition_in(${name}, 1);
}`
}
@transition_in(${name}, 1);
}`
}
} else {
${name} = ${branch.block.name}(#ctx);
${name} = ${branch.block.name}(${if_ctx});
${name}.c();
${has_transitions && b`@transition_in(${name}, 1);`}
${name}.m(${update_mount_node}, ${anchor});
@ -578,7 +662,7 @@ export default class IfBlockWrapper extends Wrapper {
}
} else if (dynamic) {
block.chunks.update.push(b`
if (${branch.condition}) ${name}.p(#ctx, #dirty);
if (${branch.condition}) ${name}.p(${if_ctx}, #dirty);
`);
}

@ -2,6 +2,7 @@ import Renderer, { RenderOptions } from '../Renderer';
import EachBlock from '../../nodes/EachBlock';
import { x } from 'code-red';
import { get_const_tags } from './shared/get_const_tags';
import { Node } from 'estree';
export default function(node: EachBlock, renderer: Renderer, options: RenderOptions) {
const args = [node.context_node];
@ -16,7 +17,8 @@ export default function(node: EachBlock, renderer: Renderer, options: RenderOpti
if (node.else) {
renderer.push();
renderer.render(node.else.children, options);
const alternate = renderer.pop();
let alternate: Node = renderer.pop();
if (node.else.const_tags.length > 0) alternate = x`(() => { ${get_const_tags(node.else.const_tags)}; return ${alternate} })()`;
renderer.add_expression(x`${node.expression.node}.length ? ${consequent} : ${alternate}`);
} else {

@ -1,17 +1,21 @@
import IfBlock from '../../nodes/IfBlock';
import Renderer, { RenderOptions } from '../Renderer';
import { x } from 'code-red';
import { get_const_tags } from './shared/get_const_tags';
import { Node } from 'estree';
export default function(node: IfBlock, renderer: Renderer, options: RenderOptions) {
export default function (node: IfBlock, renderer: Renderer, options: RenderOptions) {
const condition = node.expression.node;
renderer.push();
renderer.render(node.children, options);
const consequent = renderer.pop();
let consequent: Node = renderer.pop();
if (node.const_tags.length > 0) consequent = x`(() => { ${get_const_tags(node.const_tags)}; return ${consequent} })()`;
renderer.push();
if (node.else) renderer.render(node.else.children, options);
const alternate = renderer.pop();
let alternate: Node = renderer.pop();
if (node.else && node.else.const_tags.length > 0) alternate = x`(() => { ${get_const_tags(node.else.const_tags)}; return ${alternate} })()`;
renderer.add_expression(x`${condition} ? ${consequent} : ${alternate}`);
}

@ -0,0 +1,26 @@
export default {
html: `
<div>12 120 70, 30+4=34</div>
<div>35 350 120, 50+7=57</div>
<div>48 480 140, 60+8=68</div>
`,
async test({ component, target, assert }) {
component.boxes = [];
assert.htmlEqual(target.innerHTML, `
<div>10 * 2 = 20</div>
`);
component.constant = 35;
assert.htmlEqual(target.innerHTML, `
<div>35 * 2 = 70</div>
`);
component.boxes = [
{width: 3, height: 4}
];
assert.htmlEqual(target.innerHTML, `
<div>12 420 245, 105+4=109</div>
`);
}
};

@ -0,0 +1,22 @@
<script>
export let boxes = [
{width: 3, height: 4},
{width: 5, height: 7},
{width: 6, height: 8},
];
export let constant = 10;
function calculate(width, height, constant) {
return { area: width * height, volume: width * height * constant };
}
</script>
{#each boxes as box}
{@const {area, volume} = calculate(box.width, box.height, constant)}
{@const perimeter = (box.width + box.height) * constant}
{@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]}
<div>{area} {volume} {perimeter}, {width}+{height}={sum}</div>
{:else}
{@const double = constant + constant}
<div>{constant} * 2 = {double}</div>
{/each}

@ -0,0 +1,56 @@
export default {
html: `
<div>20 x 40</div>
<div>20 x 40</div>
`,
props: {
boxes: [{ width: 20, height: 40 }]
},
async test({ component, target, assert }) {
component.boxes = [{ width: 40, height: 70 }];
assert.htmlEqual(
target.innerHTML,
`
<div>40 x 70</div>
<div>40 x 70</div>
`
);
component.boxes = [];
assert.htmlEqual(target.innerHTML, '');
component.boxes = [
{ width: 20, height: 40 },
{ width: 30, height: 50 }
];
assert.htmlEqual(
target.innerHTML,
`
<div>20 x 40</div>
<div>30 x 50</div>
<div>20 x 40</div>
<div>30 x 50</div>
`
);
component.boxes = [
{ width: 80, height: 70 },
{ width: 90, height: 60 }
];
assert.htmlEqual(
target.innerHTML,
`
<div>80 x 70</div>
<div>90 x 60</div>
<div>80 x 70</div>
<div>90 x 60</div>
`
);
component.boxes = [];
assert.htmlEqual(target.innerHTML, '');
}
};

@ -0,0 +1,24 @@
<script>
export let boxes;
</script>
{#if boxes.length > 1}
{@const box1 = boxes[0]}
{@const box2 = boxes[1]}
{@const { width, height } = box1}
<div>{width} x {height}</div>
<div>{box2.width} x {box2.height}</div>
{:else if boxes.length > 0}
{@const box = boxes[0]}
{@const { width, height } = box}
<div>{width} x {height}</div>
{/if}
{#if boxes.length > 1}
<div>{boxes[0].width} x {boxes[0].height}</div>
<div>{boxes[1].width} x {boxes[1].height}</div>
{:else if boxes.length > 0}
{@const box = boxes[0]}
{@const { width, height } = box}
<div>{width} x {height}</div>
{/if}

@ -0,0 +1,57 @@
export default {
html: `
<div>20 x 40</div>
<div>20 x 40</div>
`,
props: {
boxes: [{ width: 20, height: 40 }]
},
async test({ component, target, assert, raf }) {
component.boxes = [{ width: 40, height: 70 }];
assert.htmlEqual(
target.innerHTML,
`
<div>40 x 70</div>
<div>40 x 70</div>
`
);
component.boxes = [];
raf.tick(0);
assert.htmlEqual(target.innerHTML, '');
component.boxes = [
{ width: 20, height: 40 },
{ width: 30, height: 50 }
];
assert.htmlEqual(
target.innerHTML,
`
<div>20 x 40</div>
<div>30 x 50</div>
<div>20 x 40</div>
<div>30 x 50</div>
`
);
component.boxes = [
{ width: 80, height: 70 },
{ width: 90, height: 60 }
];
assert.htmlEqual(
target.innerHTML,
`
<div>80 x 70</div>
<div>90 x 60</div>
<div>80 x 70</div>
<div>90 x 60</div>
`
);
component.boxes = [];
assert.htmlEqual(target.innerHTML, '');
}
};

@ -0,0 +1,29 @@
<script>
export let boxes;
function fade() {
return {
duration: 0,
}
}
</script>
{#if boxes.length > 1}
{@const box1 = boxes[0]}
{@const box2 = boxes[1]}
{@const { width, height } = box1}
<div>{width} x {height}</div>
<div>{box2.width} x {box2.height}</div>
{:else if boxes.length > 0}
{@const box = boxes[0]}
{@const { width, height } = box}
<div out:fade>{width} x {height}</div>
{/if}
{#if boxes.length > 1}
<div>{boxes[0].width} x {boxes[0].height}</div>
<div>{boxes[1].width} x {boxes[1].height}</div>
{:else if boxes.length > 0}
{@const box = boxes[0]}
{@const { width, height } = box}
<div out:fade>{width} x {height}</div>
{/if}

@ -0,0 +1,43 @@
export default {
html: '<div>20 x 40</div>',
props: {
boxes: [{ width: 20, height: 40 }]
},
async test({ component, target, assert }) {
component.boxes = [{ width: 30, height: 60 }];
assert.htmlEqual(target.innerHTML, `
<div>30 x 60</div>
`);
component.boxes = [
{ width: 20, height: 40 },
{ width: 30, height: 50 }
];
assert.htmlEqual(target.innerHTML, `
<div>20 x 40</div>
<div>30 x 50</div>
`);
component.boxes = [
{ width: 80, height: 70 },
{ width: 90, height: 60 }
];
assert.htmlEqual(target.innerHTML, `
<div>80 x 70</div>
<div>90 x 60</div>
`);
component.boxes = [
{ width: 20, height: 40 },
{ width: 30, height: 50 },
{ width: 30, height: 50 }
];
assert.htmlEqual(target.innerHTML, '<div>3</div>');
component.boxes = [];
assert.htmlEqual(target.innerHTML, '<div>0</div>');
}
};

@ -0,0 +1,18 @@
<script>
export let boxes;
</script>
{#if boxes.length === 2}
{@const box1 = boxes[0]}
{@const box2 = boxes[1]}
{@const { width, height } = box1}
<div>{width} x {height}</div>
<div>{box2.width} x {box2.height}</div>
{:else if boxes.length === 1}
{@const box = boxes[0]}
{@const { width, height } = box}
<div>{width} x {height}</div>
{:else}
{@const length = boxes.length}
<div>{length}</div>
{/if}

@ -0,0 +1,28 @@
export default {
html: '<div>10 x 34</div>',
props: {
boxes: [{ width: 10, height: 34 }]
},
async test({ component, target, assert }) {
component.boxes = [{ width: 20, height: 40 }];
assert.htmlEqual(
target.innerHTML,
`
<div>20 x 40</div>
`
);
component.boxes = [];
assert.htmlEqual(target.innerHTML, '');
component.boxes = [{ width: 18, height: 48 }];
assert.htmlEqual(
target.innerHTML,
`
<div>18 x 48</div>
`
);
}
};

@ -0,0 +1,9 @@
<script>
export let boxes;
</script>
{#if boxes.length > 0}
{@const box = boxes[0]}
{@const { width, height } = box}
<div>{width} x {height}</div>
{/if}

@ -1,7 +1,7 @@
[
{
"code": "invalid-const-placement",
"message": "{@const} must be the immediate child of {#each}, {:then}, {:catch}, <svelte:fragment> or <Component>",
"message": "{@const} must be the immediate child of {#if}, {:else if}, {:else}, {#each}, {:then}, {:catch}, <svelte:fragment> or <Component>",
"start": { "line": 5, "column": 0, "character": 36 },
"end": { "line": 5, "column": 18, "character": 54 },
"pos": 36

@ -1,9 +1,9 @@
[
{
"code": "invalid-const-placement",
"message": "{@const} must be the immediate child of {#each}, {:then}, {:catch}, <svelte:fragment> or <Component>",
"start": { "line": 6, "column": 2, "character": 46 },
"end": { "line": 6, "column": 20, "character": 64 },
"pos": 46
"message": "{@const} must be the immediate child of {#if}, {:else if}, {:else}, {#each}, {:then}, {:catch}, <svelte:fragment> or <Component>",
"start": { "line": 7, "column": 4, "character": 63 },
"end": { "line": 7, "column": 18, "character": 77 },
"pos": 63
}
]

@ -2,6 +2,8 @@
export let a;
</script>
{#if a}
{@const b = a + 1}
{/if}
{#each a as i}
<div>
{@const b = i}
</div>
{/each}

@ -1,9 +0,0 @@
[
{
"code": "invalid-const-placement",
"message": "{@const} must be the immediate child of {#each}, {:then}, {:catch}, <svelte:fragment> or <Component>",
"start": { "line": 7, "column": 4, "character": 63 },
"end": { "line": 7, "column": 18, "character": 77 },
"pos": 63
}
]

@ -1,9 +0,0 @@
<script>
export let a;
</script>
{#each a as i}
<div>
{@const b = i}
</div>
{/each}
Loading…
Cancel
Save