fix: handle basic assignment of deriveds on the server

pull/15964/head
paoloricciuti 4 months ago
parent e6c4e8c5c5
commit 69bd060c96

@ -44,6 +44,8 @@ function build_assignment(operator, left, right, context) {
/** @type {Expression} */ (context.visit(right)) /** @type {Expression} */ (context.visit(right))
); );
} }
} else if (field && (field.type === '$derived' || field.type === '$derived.by')) {
return b.call(b.member(b.this, name), right);
} }
} }

@ -31,7 +31,7 @@ export function CallExpression(node, context) {
if (rune === '$derived' || rune === '$derived.by') { if (rune === '$derived' || rune === '$derived.by') {
const fn = /** @type {Expression} */ (context.visit(node.arguments[0])); const fn = /** @type {Expression} */ (context.visit(node.arguments[0]));
return b.call('$.once', rune === '$derived' ? b.thunk(fn) : fn); return b.call('$.derived', rune === '$derived' ? b.thunk(fn) : fn);
} }
if (rune === '$state.snapshot') { if (rune === '$state.snapshot') {

@ -22,6 +22,10 @@ export function ClassBody(node, context) {
const child_state = { ...context.state, state_fields }; const child_state = { ...context.state, state_fields };
for (const [name, field] of state_fields) { for (const [name, field] of state_fields) {
if (name[0] === '#') {
continue;
}
// insert backing fields for stuff declared in the constructor // insert backing fields for stuff declared in the constructor
if ( if (
field && field &&

@ -28,7 +28,7 @@ export function PropertyDefinition(node, context) {
value: value:
node.value.arguments.length === 0 node.value.arguments.length === 0
? null ? null
: b.call('$.once', rune === '$derived' ? b.thunk(fn) : fn) : b.call('$.derived', rune === '$derived' ? b.thunk(fn) : fn)
}; };
} }
} }

@ -514,3 +514,23 @@ export {
} from '../shared/validate.js'; } from '../shared/validate.js';
export { escape_html as escape }; export { escape_html as escape };
/**
* @template T
* @param {()=>T} fn
* @returns {(new_value?: T) => (T | void)}
*/
export function derived(fn) {
/**
* @type {T | undefined}
*/
let updated_value;
return function (new_value) {
if (arguments.length === 0) {
return updated_value ?? fn();
}
updated_value = new_value;
return updated_value;
};
}

@ -5,7 +5,7 @@ export default test({
html: ` html: `
<button>0</button> <button>0</button>
<p>doubled: 0</p> <p>doubled: 0</p>
<p>trippled: 0</p> <p>tripled: 0</p>
`, `,
test({ assert, target }) { test({ assert, target }) {
@ -18,7 +18,7 @@ export default test({
` `
<button>1</button> <button>1</button>
<p>doubled: 2</p> <p>doubled: 2</p>
<p>trippled: 3</p> <p>tripled: 3</p>
` `
); );
@ -29,7 +29,7 @@ export default test({
` `
<button>2</button> <button>2</button>
<p>doubled: 4</p> <p>doubled: 4</p>
<p>trippled: 9</p> <p>tripled: 6</p>
` `
); );
} }

@ -2,7 +2,7 @@
class Counter { class Counter {
count = $state(0); count = $state(0);
#doubled = $derived(this.count * 2); #doubled = $derived(this.count * 2);
#trippled = $derived.by(() => this.count * this.by); #tripled = $derived.by(() => this.count * this.by);
constructor(by) { constructor(by) {
this.by = by; this.by = by;
@ -13,7 +13,7 @@
} }
get embiggened2() { get embiggened2() {
return this.#trippled; return this.#tripled;
} }
} }
@ -22,4 +22,4 @@
<button on:click={() => counter.count++}>{counter.count}</button> <button on:click={() => counter.count++}>{counter.count}</button>
<p>doubled: {counter.embiggened1}</p> <p>doubled: {counter.embiggened1}</p>
<p>trippled: {counter.embiggened2}</p> <p>tripled: {counter.embiggened2}</p>

Loading…
Cancel
Save