cleaner error messages

Jack Goodall 2 months ago
parent c8294cc632
commit a9ffe159ec

@ -1,4 +1,4 @@
/** @import { Expression, MemberExpression, SequenceExpression, SpreadElement, Literal, Super, UpdateExpression, ExpressionStatement } from 'estree' */ /** @import { CallExpression, Expression, SpreadElement, Super } from 'estree' */
/** @import { ComponentClientTransformState } from '../client/types.js' */ /** @import { ComponentClientTransformState } from '../client/types.js' */
/** @import { ComponentServerTransformState } from '../server/types.js' */ /** @import { ComponentServerTransformState } from '../server/types.js' */
import * as b from '#compiler/builders'; import * as b from '#compiler/builders';
@ -17,20 +17,33 @@ export function handle_spread_binding(spread_expression, state, visit) {
const visited_expression = /** @type {Expression} */ (visit(spread_expression.argument)); const visited_expression = /** @type {Expression} */ (visit(spread_expression.argument));
state.init.push(b.const(id, visited_expression)); state.init.push(b.const(id, visited_expression));
// Create conditional expressions that work for both arrays and objects const noop = b.arrow([], b.block([]));
// Array.isArray($$bindings) ? $$bindings[0] : $$bindings.get
const get = b.conditional( // Generate helper variables for clearer error messages
const get = b.id(state.scope.generate(id.name + '_get'));
const set = b.id(state.scope.generate(id.name + '_set'));
const getter = b.logical(
'??',
b.conditional(
b.call('Array.isArray', id), b.call('Array.isArray', id),
b.member(id, b.literal(0), true), b.member(id, b.literal(0), true),
b.member(id, b.id('get')) b.member(id, b.id('get'))
),
noop
); );
const setter = b.logical(
// Array.isArray($$bindings) ? $$bindings[1] : $$bindings.set '??',
const set = b.conditional( b.conditional(
b.call('Array.isArray', id), b.call('Array.isArray', id),
b.member(id, b.literal(1), true), b.member(id, b.literal(1), true),
b.member(id, b.id('set')) b.member(id, b.id('set'))
),
noop
); );
state.init.push(b.const(get, getter));
state.init.push(b.const(set, setter));
return { get, set }; return { get, set };
} }

@ -9,9 +9,8 @@ export default test({
assert.htmlEqual(target.innerHTML, `<input type="checkbox" >`.repeat(checkboxes.length)); assert.htmlEqual(target.innerHTML, `<input type="checkbox" >`.repeat(checkboxes.length));
flushSync(() => {
checkboxes.forEach((checkbox) => checkbox.click()); checkboxes.forEach((checkbox) => checkbox.click());
});
assert.deepEqual(logs, [ assert.deepEqual(logs, [
'getArrayBindings', 'getArrayBindings',
'getObjectBindings', 'getObjectBindings',

@ -1,33 +1,35 @@
<script> <script>
let check = $state(true); let check = $state(true);
let check_bindings = [ const get = () => check;
() => check, const set = (v) => {
(v) => {
console.log('check', v); console.log('check', v);
check = v; check = v;
} };
]; const bindings = [get, set];
const nested = {deep: {
bindings: [get, set],}
};
function getArrayBindings() { function getArrayBindings() {
console.log('getArrayBindings'); console.log('getArrayBindings');
return check_bindings; return [get, set];
} }
function getObjectBindings() { function getObjectBindings() {
console.log('getObjectBindings'); console.log('getObjectBindings');
const [get, set] = check_bindings;
return { get, set }; return { get, set };
} }
</script> </script>
<input type="checkbox" bind:checked={get, set} />
<input type="checkbox" bind:checked={check_bindings[0], check_bindings[1]} /> <input type="checkbox" bind:checked={...bindings} />
<input type="checkbox" bind:checked={...check_bindings} /> <input type="checkbox" bind:checked={...nested.deep.bindings} />
<input type="checkbox" bind:checked={...getArrayBindings()} /> <input type="checkbox" bind:checked={...getArrayBindings()} />
<input type="checkbox" bind:checked={...(() => check_bindings)()} /> <input type="checkbox" bind:checked={...(() => [get, set])()} />
<input type="checkbox" bind:checked={...getObjectBindings()} /> <input type="checkbox" bind:checked={...getObjectBindings()} />

Loading…
Cancel
Save