rdesign/frontend/node_modules/signal-utils/dist/index.ts.js

104 lines
2.2 KiB
JavaScript

import { Signal } from 'signal-polyfill';
/**
* Usage:
* ```js
* export class Counter {
* @signal accessor #value = 0;
*
* get doubled() {
* return this.#value * 2;
* }
*
* increment() {
* this.#value++;
* }
*
* decrement() {
* if (this.#value > 0) {
* this.#value--;
* }
* }
* }
* ```
*/
/**
* Usage:
* ```js
* import { signal } from 'signal-utils';
*
* export class Counter {
* @signal accessor #value = 0;
*
* @signal
* get expensive() {
* // some expensive operation
* return this.#value * 2;
* }
*
* increment() {
* this.#value++;
* }
* }
* ```
*/
function signal(...args) {
if (args[1].kind === "accessor") {
return stateDecorator(...args);
}
if (args[1].kind === "getter") {
return computedDecorator(...args);
}
throw new Error(`@signal can only be used on accessors or getters`);
}
function stateDecorator(target, context) {
const {
get
} = target;
if (context.kind !== "accessor") {
throw new Error(`Expected to be used on an accessor property`);
}
return {
get() {
// SAFETY: does TS not allow us to have a different type internally?
// maybe I did something goofy.
return get.call(this).get();
},
set(value) {
// SAFETY: does TS not allow us to have a different type internally?
// maybe I did something goofy.
get.call(this).set(value);
},
init(value) {
// SAFETY: does TS not allow us to have a different type internally?
// maybe I did something goofy.
return new Signal.State(value);
}
};
}
function computedDecorator(target, context) {
const kind = context.kind;
if (kind !== "getter") {
throw new Error(`Can only use @cached on getters.`);
}
const caches = new WeakMap();
return function () {
let cache = caches.get(target);
if (!cache) {
cache = new WeakMap();
caches.set(target, cache);
}
let effect = cache.get(this);
if (!effect) {
effect = new Signal.Computed(() => target.call(this));
cache.set(this, effect);
}
return effect.get();
};
}
export { signal };
//# sourceMappingURL=index.ts.js.map