implement Dev mode validation of {#each} block argument (#4419)

pull/4429/head
swyx 5 years ago committed by GitHub
parent 30b09f3182
commit 3fbafe33c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -204,6 +204,9 @@ export default class EachBlockWrapper extends Wrapper {
const snippet = this.node.expression.manipulate(block);
block.chunks.init.push(b`let ${this.vars.each_block_value} = ${snippet};`);
if (this.renderer.options.dev) {
block.chunks.init.push(b`@validate_each_argument(${this.vars.each_block_value});`);
}
// TODO which is better — Object.create(array) or array.slice()?
renderer.blocks.push(b`
@ -421,6 +424,7 @@ export default class EachBlockWrapper extends Wrapper {
block.chunks.update.push(b`
if (${block.renderer.dirty(Array.from(all_dependencies))}) {
const ${this.vars.each_block_value} = ${snippet};
${this.renderer.options.dev && b`@validate_each_argument(${this.vars.each_block_value});`}
${this.block.has_outros && b`@group_outros();`}
${this.node.has_animation && b`for (let #i = 0; #i < ${view_length}; #i += 1) ${iterations}[#i].r();`}
@ -572,6 +576,7 @@ export default class EachBlockWrapper extends Wrapper {
const update = b`
${!this.block.has_update_method && b`const #old_length = ${this.vars.each_block_value}.length;`}
${this.vars.each_block_value} = ${snippet};
${this.renderer.options.dev && b`@validate_each_argument(${this.vars.each_block_value});`}
let #i;
for (#i = ${start}; #i < ${data_length}; #i += 1) {

@ -79,6 +79,16 @@ export function set_data_dev(text, data) {
text.data = data;
}
export function validate_each_argument(arg) {
if (!arg || !('length' in arg)) {
let msg = '{#each} only iterates over array-like objects.';
if (typeof Symbol === 'function' && arg && Symbol.iterator in arg) {
msg += ' You can use a spread to convert this iterable into an array.';
}
throw new Error(msg);
}
}
type Props = Record<string, any>;
export interface SvelteComponentDev {

@ -13,7 +13,8 @@ import {
safe_not_equal,
set_data_dev,
space,
text
text,
validate_each_argument
} from "svelte/internal";
const file = undefined;
@ -88,6 +89,7 @@ function create_fragment(ctx) {
let t1;
let t2;
let each_value = /*things*/ ctx[0];
validate_each_argument(each_value);
let each_blocks = [];
for (let i = 0; i < each_value.length; i += 1) {
@ -122,6 +124,7 @@ function create_fragment(ctx) {
p: function update(ctx, [dirty]) {
if (dirty & /*things*/ 1) {
each_value = /*things*/ ctx[0];
validate_each_argument(each_value);
let i;
for (i = 0; i < each_value.length; i += 1) {

@ -13,7 +13,8 @@ import {
safe_not_equal,
set_data_dev,
space,
text
text,
validate_each_argument
} from "svelte/internal";
const file = undefined;
@ -82,6 +83,7 @@ function create_fragment(ctx) {
let t1;
let t2;
let each_value = /*things*/ ctx[0];
validate_each_argument(each_value);
let each_blocks = [];
for (let i = 0; i < each_value.length; i += 1) {
@ -116,6 +118,7 @@ function create_fragment(ctx) {
p: function update(ctx, [dirty]) {
if (dirty & /*things*/ 1) {
each_value = /*things*/ ctx[0];
validate_each_argument(each_value);
let i;
for (i = 0; i < each_value.length; i += 1) {

@ -10,7 +10,8 @@ import {
noop,
safe_not_equal,
space,
text
text,
validate_each_argument
} from "svelte/internal";
const file = undefined;
@ -64,6 +65,7 @@ function create_each_block(ctx) {
function create_fragment(ctx) {
let each_1_anchor;
let each_value = things;
validate_each_argument(each_value);
let each_blocks = [];
for (let i = 0; i < each_value.length; i += 1) {
@ -91,6 +93,7 @@ function create_fragment(ctx) {
p: function update(ctx, [dirty]) {
if (dirty & /*things*/ 0) {
each_value = things;
validate_each_argument(each_value);
let i;
for (i = 0; i < each_value.length; i += 1) {

@ -0,0 +1,6 @@
export default {
compileOptions: {
dev: true
},
error: `{#each} only iterates over array-like objects. You can use a spread to convert this iterable into an array.`
};

@ -0,0 +1,7 @@
<script>
const foo = new Set([1, 2, 3]);
</script>
{#each foo as item}
<div>{item}</div>
{/each}

@ -0,0 +1,6 @@
export default {
compileOptions: {
dev: true
},
error: `{#each} only iterates over array-like objects.`
};

@ -0,0 +1,3 @@
{#each {} as item}
<div>{item}</div>
{/each}
Loading…
Cancel
Save