value-enhancer
Advanced tools
+5
-18
@@ -199,3 +199,3 @@ /** | ||
| */ | ||
| declare function flatten<TSrcValue = any, TValOrValue = any>(val: ReadonlyVal<TSrcValue>, get: (value: TSrcValue) => TValOrValue, config?: ValConfig<UnwrapVal<TValOrValue>>): ReadonlyVal<UnwrapVal<TValOrValue>>; | ||
| declare function flatten<TSrcValue = any, TValOrValue = any>(val: ReadonlyVal<TSrcValue>, get?: (value: TSrcValue) => TValOrValue, config?: ValConfig<UnwrapVal<TValOrValue>>): ReadonlyVal<UnwrapVal<TValOrValue>>; | ||
@@ -208,3 +208,3 @@ /** | ||
| * If the value is a val, it will be auto-flattened. | ||
| * @param listen A function that takes a notify function and returns a disposer. | ||
| * @param onChange A function that takes a notify function and returns a disposer. | ||
| * The notify function should be called when the value changes. | ||
@@ -214,14 +214,3 @@ * @param config custom config for the val. | ||
| */ | ||
| /** | ||
| * Creates a readonly val from a getter function and a listener function. | ||
| * If the value is a val, it will be auto-flattened. | ||
| * | ||
| * @param getValue A function that returns the current value. | ||
| * If the value is a val, it will be auto-flattened. | ||
| * @param listen A function that takes a notify function and returns a disposer. | ||
| * The notify function should be called when the value changes. | ||
| * @param config custom config for the val. | ||
| * @returns A readonly val with value of inner val. | ||
| */ | ||
| declare const flattenFrom: <TValOrValue = any>(getValue: () => TValOrValue, listen: (notify: () => void) => ValDisposer | void | undefined, config?: ValConfig<UnwrapVal<TValOrValue>> | undefined) => ReadonlyVal<UnwrapVal<TValOrValue>>; | ||
| declare const flattenFrom: <TValOrValue = any>(getValue: () => TValOrValue, onChange: (notify: () => void) => ValDisposer | void | undefined, config?: ValConfig<UnwrapVal<TValOrValue>> | undefined) => ReadonlyVal<UnwrapVal<TValOrValue>>; | ||
@@ -232,3 +221,3 @@ /** | ||
| * @param getValue A function that returns the current value. | ||
| * @param listen A function that takes a notify function and returns a disposer. | ||
| * @param onChange A function that takes a notify function and returns a disposer. | ||
| * The notify function should be called when the value changes. | ||
@@ -259,3 +248,3 @@ * @param config custom config for the val. | ||
| */ | ||
| declare const from: <TValue = any>(getValue: () => TValue, listen: (handler: () => void) => ValDisposer | void | undefined, config?: ValConfig<TValue> | undefined) => ReadonlyVal<TValue>; | ||
| declare const from: <TValue = any>(getValue: () => TValue, onChange: (notify: () => void) => ValDisposer | void | undefined, config?: ValConfig<TValue> | undefined) => ReadonlyVal<TValue>; | ||
@@ -265,4 +254,2 @@ declare const nextTick: () => Promise<void>; | ||
| /** | ||
| * @deprecated | ||
| * @ignore | ||
| * Set the value of a val. | ||
@@ -269,0 +256,0 @@ * It works for both `Val` and `ReadonlyVal` type (if the `ReadonlyVal` is actually a `Val`). |
+68
-76
@@ -107,12 +107,33 @@ 'use strict'; | ||
| // src/agent.ts | ||
| var registry = /* @__PURE__ */ new FinalizationRegistry(invoke); | ||
| var ValAgent = class { | ||
| constructor(getValue2, config, onStart) { | ||
| this.#onStart = onStart; | ||
| constructor(getValue2, config, onChange) { | ||
| this.#getValue = getValue2; | ||
| this.q = (config?.equal ?? strictEqual) || void 0; | ||
| this.e = config?.eager; | ||
| if (onChange) { | ||
| const ref = new WeakRef(this); | ||
| const disposeEffect = () => { | ||
| if (disposeListen) { | ||
| const dispose = disposeListen; | ||
| disposeListen = void 0; | ||
| dispose(); | ||
| } | ||
| }; | ||
| let disposeListen = onChange(() => { | ||
| const agent = ref.deref(); | ||
| if (agent) { | ||
| agent.n(); | ||
| } else { | ||
| disposeEffect(); | ||
| } | ||
| }); | ||
| if (disposeListen) { | ||
| registry.register(this, this.#disposeEffect = disposeEffect); | ||
| } | ||
| } | ||
| } | ||
| s = /* @__PURE__ */ new Map(); | ||
| b = 2 /* ValueDirty */; | ||
| v = INIT_VALUE; | ||
| b = 4 /* NeedResolveValue */; | ||
| v; | ||
| c = INIT_VALUE; | ||
@@ -122,21 +143,20 @@ q; | ||
| u = () => { | ||
| if (this.b & 2 /* ValueDirty */) { | ||
| if (this.b & 4 /* NeedResolveValue */) { | ||
| this.b &= ~4 /* NeedResolveValue */; | ||
| const newValue = this.#getValue(); | ||
| if (this.c === INIT_VALUE) { | ||
| this.d(newValue); | ||
| this.f(newValue); | ||
| } else if (!this.q?.(newValue, this.c)) { | ||
| this.d(newValue); | ||
| this.b |= 12 /* ShouldInvoke */; | ||
| this.f(newValue); | ||
| if (this.b & 1 /* Notifying */) { | ||
| this.b |= 2 /* ValueChanged */; | ||
| } | ||
| } | ||
| if (this.s.size) { | ||
| this.b &= ~2 /* ValueDirty */; | ||
| } | ||
| } | ||
| this.b &= ~1 /* Notified */; | ||
| return this.c; | ||
| }; | ||
| n = () => { | ||
| this.b |= 2 /* ValueDirty */; | ||
| if (!(this.b & 1 /* Notified */)) { | ||
| this.b |= 1 /* Notified */; | ||
| this.b |= 4 /* NeedResolveValue */; | ||
| if (this.s.size) { | ||
| this.b |= 1 /* Notifying */; | ||
| if (this[3 /* Computed */]) { | ||
@@ -147,21 +167,10 @@ this.#invoke(3 /* Computed */); | ||
| this.u(); | ||
| if (this.b & 4 /* ShouldInvokeEager */) { | ||
| this.b &= ~4 /* ShouldInvokeEager */; | ||
| if (this.b & 2 /* ValueChanged */) { | ||
| this.#invoke(2 /* Eager */); | ||
| } else { | ||
| this.b &= ~12 /* ShouldInvoke */; | ||
| return; | ||
| } | ||
| } else { | ||
| this.b &= ~4 /* ShouldInvokeEager */; | ||
| } | ||
| if (this[1 /* Async */]) { | ||
| schedule(this); | ||
| } else { | ||
| this.b &= ~8 /* ShouldInvokeAsync */; | ||
| } | ||
| schedule(this); | ||
| } | ||
| }; | ||
| a(subscriber, mode) { | ||
| const oldSize = this.s.size; | ||
| const currentMode = this.s.get(subscriber); | ||
@@ -173,8 +182,2 @@ if (currentMode) { | ||
| this[mode]++; | ||
| if (!oldSize) { | ||
| this.u(); | ||
| this.b &= ~12 /* ShouldInvoke */; | ||
| this.#onStartDisposer?.(); | ||
| this.#onStartDisposer = this.#onStart?.(this.n); | ||
| } | ||
| return () => this.r(subscriber); | ||
@@ -194,9 +197,2 @@ } | ||
| } | ||
| if (!this.s.size) { | ||
| this.b |= 2 /* ValueDirty */; | ||
| if (this.#onStartDisposer) { | ||
| this.#onStartDisposer(); | ||
| this.#onStartDisposer = null; | ||
| } | ||
| } | ||
| } | ||
@@ -206,19 +202,22 @@ t() { | ||
| this.u(); | ||
| if (this.b & 8 /* ShouldInvokeAsync */) { | ||
| this.b &= ~8 /* ShouldInvokeAsync */; | ||
| if (this.b & 2 /* ValueChanged */) { | ||
| this.#invoke(1 /* Async */); | ||
| } | ||
| } else { | ||
| this.b &= ~8 /* ShouldInvokeAsync */; | ||
| } | ||
| this.b &= ~(1 /* Notifying */ | 2 /* ValueChanged */); | ||
| } | ||
| d(value) { | ||
| this.d = this.q?.(value, value) ? this.f : this.g; | ||
| this.d(value); | ||
| d() { | ||
| this.r(); | ||
| registry.unregister(this); | ||
| this.#disposeEffect?.(); | ||
| } | ||
| g(value) { | ||
| f(value) { | ||
| this.f = this.q?.(value, value) ? this.g : this.h; | ||
| this.f(value); | ||
| } | ||
| h(value) { | ||
| this.c = value; | ||
| this.v = this.#numberVersion++ | 0; | ||
| } | ||
| f(value) { | ||
| g(value) { | ||
| this.c = this.v = value; | ||
@@ -230,5 +229,4 @@ } | ||
| #numberVersion = 0; | ||
| #disposeEffect; | ||
| #getValue; | ||
| #onStart; | ||
| #onStartDisposer; | ||
| #invoke(mode) { | ||
@@ -275,2 +273,5 @@ for (const [sub, subMode] of this.s) { | ||
| } | ||
| d() { | ||
| this.r(); | ||
| } | ||
| }; | ||
@@ -287,2 +288,3 @@ | ||
| this.get = agent.u; | ||
| agent.u(); | ||
| } | ||
@@ -320,3 +322,3 @@ get $version() { | ||
| dispose() { | ||
| this.#agent.r(); | ||
| this.#agent.d(); | ||
| } | ||
@@ -378,5 +380,3 @@ /** | ||
| // src/from.ts | ||
| var from = (getValue2, listen, config) => { | ||
| return new ValImpl(new ValAgent(getValue2, config, listen)); | ||
| }; | ||
| var from = (getValue2, onChange, config) => new ValImpl(new ValAgent(getValue2, config, onChange)); | ||
@@ -423,14 +423,12 @@ // src/combine.ts | ||
| // src/flatten-from.ts | ||
| var flattenFrom = (getValue2, listen, config) => { | ||
| var flattenFrom = (getValue2, onChange, config) => { | ||
| let innerDisposer; | ||
| let currentValVersion = INIT_VALUE; | ||
| let currentMaybeVal = INIT_VALUE; | ||
| let dirty = true; | ||
| let needCheckOuterVal = true; | ||
| const useDefaultEqual = config?.equal == null; | ||
| const subs = new ValAgent( | ||
| const agent = new ValAgent( | ||
| () => { | ||
| if (dirty) { | ||
| if (subs.s.size) { | ||
| dirty = false; | ||
| } | ||
| if (needCheckOuterVal) { | ||
| needCheckOuterVal = false; | ||
| const lastMaybeVal = currentMaybeVal; | ||
@@ -440,6 +438,4 @@ currentMaybeVal = getValue2(); | ||
| if (!strictEqual(currentMaybeVal, lastMaybeVal)) { | ||
| innerDisposer &&= innerDisposer(); | ||
| if (subs.s.size) { | ||
| innerDisposer = currentMaybeVal.$valCompute(subs.n); | ||
| } | ||
| innerDisposer?.(); | ||
| innerDisposer = currentMaybeVal.$valCompute(agent.n); | ||
| } | ||
@@ -453,4 +449,4 @@ } else { | ||
| currentValVersion = currentMaybeVal.$version; | ||
| if (useDefaultEqual && !strictEqual(currentValVersion, lastValVersion)) { | ||
| subs.b |= 12 /* ShouldInvoke */; | ||
| if (useDefaultEqual && agent.b & 1 /* Notifying */ && !strictEqual(currentValVersion, lastValVersion)) { | ||
| agent.b |= 2 /* ValueChanged */; | ||
| } | ||
@@ -465,11 +461,7 @@ return currentMaybeVal.value; | ||
| (notify) => { | ||
| const outerDisposer = listen(() => { | ||
| dirty = true; | ||
| const outerDisposer = onChange(() => { | ||
| needCheckOuterVal = true; | ||
| notify(); | ||
| }); | ||
| if (!innerDisposer && isVal(currentMaybeVal)) { | ||
| innerDisposer = currentMaybeVal.$valCompute(notify); | ||
| } | ||
| return () => { | ||
| dirty = true; | ||
| innerDisposer &&= innerDisposer(); | ||
@@ -480,3 +472,3 @@ outerDisposer?.(); | ||
| ); | ||
| return new ValImpl(subs); | ||
| return new ValImpl(agent); | ||
| }; | ||
@@ -483,0 +475,0 @@ |
+68
-76
@@ -105,12 +105,33 @@ // src/utils.ts | ||
| // src/agent.ts | ||
| var registry = /* @__PURE__ */ new FinalizationRegistry(invoke); | ||
| var ValAgent = class { | ||
| constructor(getValue2, config, onStart) { | ||
| this.#onStart = onStart; | ||
| constructor(getValue2, config, onChange) { | ||
| this.#getValue = getValue2; | ||
| this.q = (config?.equal ?? strictEqual) || void 0; | ||
| this.e = config?.eager; | ||
| if (onChange) { | ||
| const ref = new WeakRef(this); | ||
| const disposeEffect = () => { | ||
| if (disposeListen) { | ||
| const dispose = disposeListen; | ||
| disposeListen = void 0; | ||
| dispose(); | ||
| } | ||
| }; | ||
| let disposeListen = onChange(() => { | ||
| const agent = ref.deref(); | ||
| if (agent) { | ||
| agent.n(); | ||
| } else { | ||
| disposeEffect(); | ||
| } | ||
| }); | ||
| if (disposeListen) { | ||
| registry.register(this, this.#disposeEffect = disposeEffect); | ||
| } | ||
| } | ||
| } | ||
| s = /* @__PURE__ */ new Map(); | ||
| b = 2 /* ValueDirty */; | ||
| v = INIT_VALUE; | ||
| b = 4 /* NeedResolveValue */; | ||
| v; | ||
| c = INIT_VALUE; | ||
@@ -120,21 +141,20 @@ q; | ||
| u = () => { | ||
| if (this.b & 2 /* ValueDirty */) { | ||
| if (this.b & 4 /* NeedResolveValue */) { | ||
| this.b &= ~4 /* NeedResolveValue */; | ||
| const newValue = this.#getValue(); | ||
| if (this.c === INIT_VALUE) { | ||
| this.d(newValue); | ||
| this.f(newValue); | ||
| } else if (!this.q?.(newValue, this.c)) { | ||
| this.d(newValue); | ||
| this.b |= 12 /* ShouldInvoke */; | ||
| this.f(newValue); | ||
| if (this.b & 1 /* Notifying */) { | ||
| this.b |= 2 /* ValueChanged */; | ||
| } | ||
| } | ||
| if (this.s.size) { | ||
| this.b &= ~2 /* ValueDirty */; | ||
| } | ||
| } | ||
| this.b &= ~1 /* Notified */; | ||
| return this.c; | ||
| }; | ||
| n = () => { | ||
| this.b |= 2 /* ValueDirty */; | ||
| if (!(this.b & 1 /* Notified */)) { | ||
| this.b |= 1 /* Notified */; | ||
| this.b |= 4 /* NeedResolveValue */; | ||
| if (this.s.size) { | ||
| this.b |= 1 /* Notifying */; | ||
| if (this[3 /* Computed */]) { | ||
@@ -145,21 +165,10 @@ this.#invoke(3 /* Computed */); | ||
| this.u(); | ||
| if (this.b & 4 /* ShouldInvokeEager */) { | ||
| this.b &= ~4 /* ShouldInvokeEager */; | ||
| if (this.b & 2 /* ValueChanged */) { | ||
| this.#invoke(2 /* Eager */); | ||
| } else { | ||
| this.b &= ~12 /* ShouldInvoke */; | ||
| return; | ||
| } | ||
| } else { | ||
| this.b &= ~4 /* ShouldInvokeEager */; | ||
| } | ||
| if (this[1 /* Async */]) { | ||
| schedule(this); | ||
| } else { | ||
| this.b &= ~8 /* ShouldInvokeAsync */; | ||
| } | ||
| schedule(this); | ||
| } | ||
| }; | ||
| a(subscriber, mode) { | ||
| const oldSize = this.s.size; | ||
| const currentMode = this.s.get(subscriber); | ||
@@ -171,8 +180,2 @@ if (currentMode) { | ||
| this[mode]++; | ||
| if (!oldSize) { | ||
| this.u(); | ||
| this.b &= ~12 /* ShouldInvoke */; | ||
| this.#onStartDisposer?.(); | ||
| this.#onStartDisposer = this.#onStart?.(this.n); | ||
| } | ||
| return () => this.r(subscriber); | ||
@@ -192,9 +195,2 @@ } | ||
| } | ||
| if (!this.s.size) { | ||
| this.b |= 2 /* ValueDirty */; | ||
| if (this.#onStartDisposer) { | ||
| this.#onStartDisposer(); | ||
| this.#onStartDisposer = null; | ||
| } | ||
| } | ||
| } | ||
@@ -204,19 +200,22 @@ t() { | ||
| this.u(); | ||
| if (this.b & 8 /* ShouldInvokeAsync */) { | ||
| this.b &= ~8 /* ShouldInvokeAsync */; | ||
| if (this.b & 2 /* ValueChanged */) { | ||
| this.#invoke(1 /* Async */); | ||
| } | ||
| } else { | ||
| this.b &= ~8 /* ShouldInvokeAsync */; | ||
| } | ||
| this.b &= ~(1 /* Notifying */ | 2 /* ValueChanged */); | ||
| } | ||
| d(value) { | ||
| this.d = this.q?.(value, value) ? this.f : this.g; | ||
| this.d(value); | ||
| d() { | ||
| this.r(); | ||
| registry.unregister(this); | ||
| this.#disposeEffect?.(); | ||
| } | ||
| g(value) { | ||
| f(value) { | ||
| this.f = this.q?.(value, value) ? this.g : this.h; | ||
| this.f(value); | ||
| } | ||
| h(value) { | ||
| this.c = value; | ||
| this.v = this.#numberVersion++ | 0; | ||
| } | ||
| f(value) { | ||
| g(value) { | ||
| this.c = this.v = value; | ||
@@ -228,5 +227,4 @@ } | ||
| #numberVersion = 0; | ||
| #disposeEffect; | ||
| #getValue; | ||
| #onStart; | ||
| #onStartDisposer; | ||
| #invoke(mode) { | ||
@@ -273,2 +271,5 @@ for (const [sub, subMode] of this.s) { | ||
| } | ||
| d() { | ||
| this.r(); | ||
| } | ||
| }; | ||
@@ -285,2 +286,3 @@ | ||
| this.get = agent.u; | ||
| agent.u(); | ||
| } | ||
@@ -318,3 +320,3 @@ get $version() { | ||
| dispose() { | ||
| this.#agent.r(); | ||
| this.#agent.d(); | ||
| } | ||
@@ -376,5 +378,3 @@ /** | ||
| // src/from.ts | ||
| var from = (getValue2, listen, config) => { | ||
| return new ValImpl(new ValAgent(getValue2, config, listen)); | ||
| }; | ||
| var from = (getValue2, onChange, config) => new ValImpl(new ValAgent(getValue2, config, onChange)); | ||
@@ -421,14 +421,12 @@ // src/combine.ts | ||
| // src/flatten-from.ts | ||
| var flattenFrom = (getValue2, listen, config) => { | ||
| var flattenFrom = (getValue2, onChange, config) => { | ||
| let innerDisposer; | ||
| let currentValVersion = INIT_VALUE; | ||
| let currentMaybeVal = INIT_VALUE; | ||
| let dirty = true; | ||
| let needCheckOuterVal = true; | ||
| const useDefaultEqual = config?.equal == null; | ||
| const subs = new ValAgent( | ||
| const agent = new ValAgent( | ||
| () => { | ||
| if (dirty) { | ||
| if (subs.s.size) { | ||
| dirty = false; | ||
| } | ||
| if (needCheckOuterVal) { | ||
| needCheckOuterVal = false; | ||
| const lastMaybeVal = currentMaybeVal; | ||
@@ -438,6 +436,4 @@ currentMaybeVal = getValue2(); | ||
| if (!strictEqual(currentMaybeVal, lastMaybeVal)) { | ||
| innerDisposer &&= innerDisposer(); | ||
| if (subs.s.size) { | ||
| innerDisposer = currentMaybeVal.$valCompute(subs.n); | ||
| } | ||
| innerDisposer?.(); | ||
| innerDisposer = currentMaybeVal.$valCompute(agent.n); | ||
| } | ||
@@ -451,4 +447,4 @@ } else { | ||
| currentValVersion = currentMaybeVal.$version; | ||
| if (useDefaultEqual && !strictEqual(currentValVersion, lastValVersion)) { | ||
| subs.b |= 12 /* ShouldInvoke */; | ||
| if (useDefaultEqual && agent.b & 1 /* Notifying */ && !strictEqual(currentValVersion, lastValVersion)) { | ||
| agent.b |= 2 /* ValueChanged */; | ||
| } | ||
@@ -463,11 +459,7 @@ return currentMaybeVal.value; | ||
| (notify) => { | ||
| const outerDisposer = listen(() => { | ||
| dirty = true; | ||
| const outerDisposer = onChange(() => { | ||
| needCheckOuterVal = true; | ||
| notify(); | ||
| }); | ||
| if (!innerDisposer && isVal(currentMaybeVal)) { | ||
| innerDisposer = currentMaybeVal.$valCompute(notify); | ||
| } | ||
| return () => { | ||
| dirty = true; | ||
| innerDisposer &&= innerDisposer(); | ||
@@ -478,3 +470,3 @@ outerDisposer?.(); | ||
| ); | ||
| return new ValImpl(subs); | ||
| return new ValImpl(agent); | ||
| }; | ||
@@ -481,0 +473,0 @@ |
+15
-14
| { | ||
| "name": "value-enhancer", | ||
| "version": "5.2.1", | ||
| "version": "5.3.0", | ||
| "private": false, | ||
@@ -44,2 +44,15 @@ "description": "A tiny library to enhance value with reactive wrapper.", | ||
| ], | ||
| "scripts": { | ||
| "prepublishOnly": "pnpm run build", | ||
| "lint": "eslint --ext .ts,.tsx . && prettier --check . && tsc --noEmit", | ||
| "test": "node --expose-gc ./node_modules/jest/bin/jest.js", | ||
| "test:CI": "tsc --noEmit -p ./test/tsconfig.json && node --expose-gc ./node_modules/jest/bin/jest.js --collect-coverage", | ||
| "docs": "typedoc --options typedoc.json", | ||
| "types": "cross-env NODE_ENV=production tsc --declaration --emitDeclarationOnly --jsx react --esModuleInterop --outDir dist", | ||
| "build:index": "tsup --config tsup-config/index.tsup.config.ts", | ||
| "build:collections": "tsup --config tsup-config/collections.tsup.config.ts", | ||
| "build": "cross-env NODE_ENV=production pnpm run build:index && cross-env NODE_ENV=production pnpm run build:collections", | ||
| "build:min": "cross-env NODE_ENV=production MINIFY=true pnpm run build:index && cross-env NODE_ENV=production MINIFY=true pnpm run build:collections && node scripts/gzip.mjs", | ||
| "release": "standard-version" | ||
| }, | ||
| "devDependencies": { | ||
@@ -63,15 +76,3 @@ "@jest/globals": "^29.5.0", | ||
| "yoctocolors": "^1.0.0" | ||
| }, | ||
| "scripts": { | ||
| "lint": "eslint --ext .ts,.tsx . && prettier --check . && tsc --noEmit", | ||
| "test": "jest", | ||
| "test:CI": "tsc --noEmit -p ./test/tsconfig.json && jest --collect-coverage", | ||
| "docs": "typedoc --options typedoc.json", | ||
| "types": "cross-env NODE_ENV=production tsc --declaration --emitDeclarationOnly --jsx react --esModuleInterop --outDir dist", | ||
| "build:index": "tsup --config tsup-config/index.tsup.config.ts", | ||
| "build:collections": "tsup --config tsup-config/collections.tsup.config.ts", | ||
| "build": "cross-env NODE_ENV=production pnpm run build:index && cross-env NODE_ENV=production pnpm run build:collections", | ||
| "build:min": "cross-env NODE_ENV=production MINIFY=true pnpm run build:index && cross-env NODE_ENV=production MINIFY=true pnpm run build:collections && node scripts/gzip.mjs", | ||
| "release": "standard-version" | ||
| } | ||
| } | ||
| } |
+56
-51
@@ -11,2 +11,4 @@ import type { Task } from "./scheduler"; | ||
| const registry = /* @__PURE__ */ new FinalizationRegistry<() => void>(invoke); | ||
| export enum SubMode { | ||
@@ -19,7 +21,5 @@ Async = 1, | ||
| export enum AgentStatus { | ||
| Notified = 1 << 0, | ||
| ValueDirty = 1 << 1, | ||
| ShouldInvokeEager = 1 << 2, | ||
| ShouldInvokeAsync = 1 << 3, | ||
| ShouldInvoke = AgentStatus.ShouldInvokeEager | AgentStatus.ShouldInvokeAsync, | ||
| Notifying = 1 << 0, | ||
| ValueChanged = 1 << 1, | ||
| NeedResolveValue = 1 << 2, | ||
| } | ||
@@ -35,2 +35,3 @@ | ||
| remove_(subscriber?: (...args: any[]) => any): void; | ||
| dispose_(): void; | ||
| } | ||
@@ -42,13 +43,35 @@ | ||
| config?: ValConfig<TValue>, | ||
| onStart?: (notify: () => void) => ValDisposer | void | undefined | ||
| onChange?: (notify: () => void) => ValDisposer | void | undefined | ||
| ) { | ||
| this.#onStart = onStart; | ||
| this.#getValue = getValue; | ||
| this.equal_ = (config?.equal ?? strictEqual) || void 0; | ||
| this.eager_ = config?.eager; | ||
| if (onChange) { | ||
| const ref = new WeakRef(this); | ||
| const disposeEffect = () => { | ||
| if (disposeListen) { | ||
| // prevent infinite recursion if user returns the notify function | ||
| const dispose = disposeListen; | ||
| disposeListen = void 0; | ||
| dispose(); | ||
| } | ||
| }; | ||
| let disposeListen = onChange(() => { | ||
| const agent = ref.deref(); | ||
| if (agent) { | ||
| agent.notify_(); | ||
| } else { | ||
| disposeEffect(); | ||
| } | ||
| }); | ||
| if (disposeListen) { | ||
| registry.register(this, (this.#disposeEffect = disposeEffect)); | ||
| } | ||
| } | ||
| } | ||
| public readonly subs_ = new Map<ValSubscriber<TValue>, SubMode>(); | ||
| public status_: number = AgentStatus.ValueDirty; | ||
| public version_: ValVersion = INIT_VALUE; | ||
| public status_ = AgentStatus.NeedResolveValue; | ||
| public version_: ValVersion; | ||
| public value_: TValue = INIT_VALUE; | ||
@@ -59,3 +82,4 @@ public equal_?: (newValue: TValue, oldValue: TValue) => boolean; | ||
| public resolveValue_ = (): TValue => { | ||
| if (this.status_ & AgentStatus.ValueDirty) { | ||
| if (this.status_ & AgentStatus.NeedResolveValue) { | ||
| this.status_ &= ~AgentStatus.NeedResolveValue; | ||
| const newValue = this.#getValue(); | ||
@@ -66,9 +90,7 @@ if (this.value_ === INIT_VALUE) { | ||
| this._bumpVersion_(newValue); | ||
| this.status_ |= AgentStatus.ShouldInvoke; | ||
| if (this.status_ & AgentStatus.Notifying) { | ||
| this.status_ |= AgentStatus.ValueChanged; | ||
| } | ||
| } | ||
| if (this.subs_.size) { | ||
| this.status_ &= ~AgentStatus.ValueDirty; | ||
| } | ||
| } | ||
| this.status_ &= ~AgentStatus.Notified; | ||
| return this.value_; | ||
@@ -78,5 +100,5 @@ }; | ||
| public notify_ = (): void => { | ||
| this.status_ |= AgentStatus.ValueDirty; | ||
| if (!(this.status_ & AgentStatus.Notified)) { | ||
| this.status_ |= AgentStatus.Notified; | ||
| this.status_ |= AgentStatus.NeedResolveValue; | ||
| if (this.subs_.size) { | ||
| this.status_ |= AgentStatus.Notifying; | ||
| if (this[SubMode.Computed]) { | ||
@@ -87,17 +109,8 @@ this.#invoke(SubMode.Computed); | ||
| this.resolveValue_(); | ||
| if (this.status_ & AgentStatus.ShouldInvokeEager) { | ||
| this.status_ &= ~AgentStatus.ShouldInvokeEager; | ||
| if (this.status_ & AgentStatus.ValueChanged) { | ||
| this.#invoke(SubMode.Eager); | ||
| } else { | ||
| this.status_ &= ~AgentStatus.ShouldInvoke; | ||
| return; | ||
| } | ||
| } else { | ||
| this.status_ &= ~AgentStatus.ShouldInvokeEager; | ||
| } | ||
| if (this[SubMode.Async]) { | ||
| schedule(this); | ||
| } else { | ||
| this.status_ &= ~AgentStatus.ShouldInvokeAsync; | ||
| } | ||
| // always schedule an async task for cleaning the Notifying status | ||
| schedule(this); | ||
| } | ||
@@ -107,3 +120,2 @@ }; | ||
| public add_(subscriber: ValSubscriber, mode: SubMode): () => void { | ||
| const oldSize = this.subs_.size; | ||
| const currentMode = this.subs_.get(subscriber); | ||
@@ -116,9 +128,2 @@ if (currentMode) { | ||
| if (!oldSize) { | ||
| this.resolveValue_(); | ||
| this.status_ &= ~AgentStatus.ShouldInvoke; | ||
| this.#onStartDisposer?.(); | ||
| this.#onStartDisposer = this.#onStart?.(this.notify_); | ||
| } | ||
| return () => this.remove_(subscriber); | ||
@@ -139,9 +144,2 @@ } | ||
| } | ||
| if (!this.subs_.size) { | ||
| this.status_ |= AgentStatus.ValueDirty; | ||
| if (this.#onStartDisposer) { | ||
| this.#onStartDisposer(); | ||
| this.#onStartDisposer = null; | ||
| } | ||
| } | ||
| } | ||
@@ -152,11 +150,15 @@ | ||
| this.resolveValue_(); | ||
| if (this.status_ & AgentStatus.ShouldInvokeAsync) { | ||
| this.status_ &= ~AgentStatus.ShouldInvokeAsync; | ||
| if (this.status_ & AgentStatus.ValueChanged) { | ||
| this.#invoke(SubMode.Async); | ||
| } | ||
| } else { | ||
| this.status_ &= ~AgentStatus.ShouldInvokeAsync; | ||
| } | ||
| this.status_ &= ~(AgentStatus.Notifying | AgentStatus.ValueChanged); | ||
| } | ||
| public dispose_(): void { | ||
| this.remove_(); | ||
| registry.unregister(this); | ||
| this.#disposeEffect?.(); | ||
| } | ||
| private _bumpVersion_(value: TValue): void { | ||
@@ -183,6 +185,5 @@ this._bumpVersion_ = this.equal_?.(value, value) | ||
| #numberVersion = 0; | ||
| #disposeEffect?: () => void; | ||
| readonly #getValue: () => TValue; | ||
| readonly #onStart?: (notify: () => void) => ValDisposer | void | undefined; | ||
| #onStartDisposer?: ValDisposer | void | null; | ||
@@ -236,2 +237,6 @@ #invoke(mode: SubMode): void { | ||
| } | ||
| public dispose_(): void { | ||
| this.remove_(); | ||
| } | ||
| } |
+1
-1
| import type { ReadonlyVal, ValConfig } from "./typings"; | ||
| import { from } from "./from"; | ||
| import { INIT_VALUE, identity, strictEqual } from "./utils"; | ||
| import { identity, INIT_VALUE, strictEqual } from "./utils"; | ||
@@ -6,0 +6,0 @@ export type DerivedValTransform<TValue = any, TDerivedValue = any> = ( |
+13
-38
@@ -19,3 +19,3 @@ import type { | ||
| * If the value is a val, it will be auto-flattened. | ||
| * @param listen A function that takes a notify function and returns a disposer. | ||
| * @param onChange A function that takes a notify function and returns a disposer. | ||
| * The notify function should be called when the value changes. | ||
@@ -25,23 +25,5 @@ * @param config custom config for the val. | ||
| */ | ||
| // export const flattenFrom2 = <TValOrValue = any>( | ||
| // getValue: () => TValOrValue, | ||
| // listen: (notify: () => void) => ValDisposer | void | undefined, | ||
| // config?: ValConfig<UnwrapVal<TValOrValue>> | ||
| // ): ReadonlyVal<UnwrapVal<TValOrValue>> => | ||
| // new FlattenFromImpl(getValue, listen, config); | ||
| /** | ||
| * Creates a readonly val from a getter function and a listener function. | ||
| * If the value is a val, it will be auto-flattened. | ||
| * | ||
| * @param getValue A function that returns the current value. | ||
| * If the value is a val, it will be auto-flattened. | ||
| * @param listen A function that takes a notify function and returns a disposer. | ||
| * The notify function should be called when the value changes. | ||
| * @param config custom config for the val. | ||
| * @returns A readonly val with value of inner val. | ||
| */ | ||
| export const flattenFrom = <TValOrValue = any>( | ||
| getValue: () => TValOrValue, | ||
| listen: (notify: () => void) => ValDisposer | void | undefined, | ||
| onChange: (notify: () => void) => ValDisposer | void | undefined, | ||
| config?: ValConfig<UnwrapVal<TValOrValue>> | ||
@@ -52,11 +34,9 @@ ): ReadonlyVal<UnwrapVal<TValOrValue>> => { | ||
| let currentMaybeVal: TValOrValue = INIT_VALUE; | ||
| let dirty = true; | ||
| let needCheckOuterVal = true; | ||
| const useDefaultEqual = config?.equal == null; | ||
| const subs = new ValAgent( | ||
| const agent = new ValAgent( | ||
| () => { | ||
| if (dirty) { | ||
| if (subs.subs_.size) { | ||
| dirty = false; | ||
| } | ||
| if (needCheckOuterVal) { | ||
| needCheckOuterVal = false; | ||
@@ -68,6 +48,4 @@ const lastMaybeVal = currentMaybeVal; | ||
| if (!strictEqual(currentMaybeVal, lastMaybeVal)) { | ||
| innerDisposer &&= innerDisposer(); | ||
| if (subs.subs_.size) { | ||
| innerDisposer = currentMaybeVal.$valCompute(subs.notify_); | ||
| } | ||
| innerDisposer?.(); | ||
| innerDisposer = currentMaybeVal.$valCompute(agent.notify_); | ||
| } | ||
@@ -84,5 +62,6 @@ } else { | ||
| useDefaultEqual && | ||
| agent.status_ & AgentStatus.Notifying && | ||
| !strictEqual(currentValVersion, lastValVersion) | ||
| ) { | ||
| subs.status_ |= AgentStatus.ShouldInvoke; | ||
| agent.status_ |= AgentStatus.ValueChanged; | ||
| } | ||
@@ -97,11 +76,7 @@ return currentMaybeVal.value; | ||
| notify => { | ||
| const outerDisposer = listen(() => { | ||
| dirty = true; | ||
| const outerDisposer = onChange(() => { | ||
| needCheckOuterVal = true; | ||
| notify(); | ||
| }); | ||
| if (!innerDisposer && isVal(currentMaybeVal)) { | ||
| innerDisposer = currentMaybeVal.$valCompute(notify); | ||
| } | ||
| return () => { | ||
| dirty = true; | ||
| innerDisposer &&= innerDisposer(); | ||
@@ -113,3 +88,3 @@ outerDisposer?.(); | ||
| return new ValImpl(subs); | ||
| return new ValImpl(agent); | ||
| }; |
+1
-1
@@ -47,3 +47,3 @@ import type { ReadonlyVal, UnwrapVal, ValConfig } from "./typings"; | ||
| val: ReadonlyVal<TSrcValue>, | ||
| get: (value: TSrcValue) => TValOrValue, | ||
| get?: (value: TSrcValue) => TValOrValue, | ||
| config?: ValConfig<UnwrapVal<TValOrValue>> | ||
@@ -50,0 +50,0 @@ ): ReadonlyVal<UnwrapVal<TValOrValue>>; |
+3
-5
@@ -9,3 +9,3 @@ import { ValAgent } from "./agent"; | ||
| * @param getValue A function that returns the current value. | ||
| * @param listen A function that takes a notify function and returns a disposer. | ||
| * @param onChange A function that takes a notify function and returns a disposer. | ||
| * The notify function should be called when the value changes. | ||
@@ -38,6 +38,4 @@ * @param config custom config for the val. | ||
| getValue: () => TValue, | ||
| listen: (handler: () => void) => ValDisposer | void | undefined, | ||
| onChange: (notify: () => void) => ValDisposer | void | undefined, | ||
| config?: ValConfig<TValue> | ||
| ): ReadonlyVal<TValue> => { | ||
| return new ValImpl(new ValAgent(getValue, config, listen)); | ||
| }; | ||
| ): ReadonlyVal<TValue> => new ValImpl(new ValAgent(getValue, config, onChange)); |
+8
-5
@@ -13,4 +13,2 @@ import type { | ||
| /** | ||
| * @deprecated | ||
| * @ignore | ||
| * Set the value of a val. | ||
@@ -107,5 +105,10 @@ * It works for both `Val` and `ReadonlyVal` type (if the `ReadonlyVal` is actually a `Val`). | ||
| export const invoke = <TValue>( | ||
| fn: (value: TValue) => void, | ||
| value: TValue | ||
| export interface Invoke { | ||
| (fn: () => void): void; | ||
| <TValue>(fn: (value: TValue) => void, value: TValue): void; | ||
| } | ||
| export const invoke: Invoke = <TValue>( | ||
| fn: (value?: TValue) => void, | ||
| value?: TValue | ||
| ): void => { | ||
@@ -112,0 +115,0 @@ try { |
+2
-1
@@ -29,2 +29,3 @@ import type { | ||
| this.get = agent.resolveValue_; | ||
| agent.resolveValue_(); | ||
| } | ||
@@ -80,3 +81,3 @@ | ||
| public dispose(): void { | ||
| this.#agent.remove_(); | ||
| this.#agent.dispose_(); | ||
| } | ||
@@ -83,0 +84,0 @@ |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
154273
-1.18%4476
-1.1%