fix: ensure keys are validated

fix-15339
7nik 4 days ago
parent 492b3018fd
commit e541296da4

@ -337,10 +337,6 @@ export function EachBlock(node, context) {
const statements = [add_svelte_meta(b.call('$.each', ...args), node, 'each')];
if (dev && node.metadata.keyed) {
statements.unshift(b.stmt(b.call('$.validate_each_keys', thunk, key_function)));
}
if (has_await) {
context.state.init.push(
b.stmt(

@ -43,6 +43,7 @@ import { DEV } from 'esm-env';
import { derived_safe_equal } from '../../reactivity/deriveds.js';
import { current_batch } from '../../reactivity/batch.js';
import { each_key_duplicate } from '../../errors.js';
import { validate_each_keys } from '../../validate.js';
/**
* The row of a keyed each block that is currently updating. We track this
@ -202,6 +203,11 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
}
was_empty = length === 0;
// skip if #each block isn't keyed
if (DEV && get_key !== index) {
validate_each_keys(array, get_key);
}
/** `true` if there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */
let mismatch = false;

@ -7,35 +7,27 @@ import * as w from './warnings.js';
import { capture_store_binding } from './reactivity/store.js';
/**
* @param {() => any} collection
* @param {Array<any>} array
* @param {(item: any, index: number) => string} key_fn
* @returns {void}
*/
export function validate_each_keys(collection, key_fn) {
render_effect(() => {
const keys = new Map();
const maybe_array = collection();
const array = is_array(maybe_array)
? maybe_array
: maybe_array == null
? []
: Array.from(maybe_array);
const length = array.length;
for (let i = 0; i < length; i++) {
const key = key_fn(array[i], i);
if (keys.has(key)) {
const a = String(keys.get(key));
const b = String(i);
export function validate_each_keys(array, key_fn) {
const keys = new Map();
const length = array.length;
for (let i = 0; i < length; i++) {
const key = key_fn(array[i], i);
if (keys.has(key)) {
const a = String(keys.get(key));
const b = String(i);
/** @type {string | null} */
let k = String(key);
if (k.startsWith('[object ')) k = null;
/** @type {string | null} */
let k = String(key);
if (k.startsWith('[object ')) k = null;
e.each_key_duplicate(a, b, k);
}
keys.set(key, i);
e.each_key_duplicate(a, b, k);
}
});
keys.set(key, i);
}
}
/**

Loading…
Cancel
Save