value-enhancer
Advanced tools
Comparing version 5.4.0 to 5.4.1
@@ -392,2 +392,2 @@ /** | ||
export { ReactiveList, ReactiveMap, ReactiveSet, ReadonlyReactiveList, ReadonlyReactiveMap, ReadonlyReactiveSet, reactiveList, reactiveMap, reactiveSet }; | ||
export { ReactiveList, ReactiveMap, ReactiveMapConfig, ReactiveSet, ReactiveSetConfig, ReadonlyReactiveList, ReadonlyReactiveMap, ReadonlyReactiveSet, reactiveList, reactiveMap, reactiveSet }; |
@@ -123,185 +123,40 @@ /** | ||
type FlattenVal<T> = ReadonlyVal<UnwrapVal<UnwrapVal<T>>>; | ||
/** @internal */ | ||
/** | ||
* @internal | ||
* @ignore | ||
*/ | ||
type ValInputsValueTuple<TValInputs extends readonly ReadonlyVal[]> = Readonly<{ | ||
[K in keyof TValInputs]: ExtractValValue<TValInputs[K]>; | ||
}>; | ||
/** @internal */ | ||
type ExtractValValue<TVal> = TVal extends ReadonlyVal<infer TValue> ? TValue : never; | ||
type NoInfer<T> = [T][T extends any ? 0 : never]; | ||
type CombineValTransform<TCombinedValue = any, TValues extends readonly any[] = any[]> = (newValues: TValues) => TCombinedValue; | ||
/** | ||
* Combines an array of vals into a single val with the array of values. | ||
* @param valInputs An array of vals to combine. | ||
* @returns A readonly val with the combined values. | ||
* @internal | ||
* @ignore | ||
*/ | ||
declare function combine<TValInputs extends readonly ReadonlyVal[] = ReadonlyVal[]>(valInputs: readonly [...TValInputs]): ReadonlyVal<[...ValInputsValueTuple<TValInputs>]>; | ||
type ExtractValValue<TVal> = TVal extends ReadonlyVal<infer TValue> ? TValue : never; | ||
/** | ||
* Combines an array of vals into a single val with transformed value. | ||
* @param valInputs An array of vals to combine. | ||
* @param transform A pure function that takes an array of values and returns a new value. | ||
* @param config custom config for the combined val. | ||
* @returns A readonly val with the transformed values. | ||
* @internal | ||
* @ignore | ||
*/ | ||
declare function combine<TValInputs extends readonly ReadonlyVal[] = ReadonlyVal[], TValue = any>(valInputs: readonly [...TValInputs], transform: CombineValTransform<TValue, [...ValInputsValueTuple<TValInputs>]>, config?: ValConfig<TValue>): ReadonlyVal<TValue>; | ||
type NoInfer<T> = [T][T extends any ? 0 : never]; | ||
declare const nextTick: () => Promise<void>; | ||
declare enum SubMode { | ||
Async = 1, | ||
Eager = 2, | ||
Computed = 3 | ||
} | ||
interface IValAgent<TValue = any> { | ||
subs_: Map<ValSubscriber<TValue>, SubMode>; | ||
version_: ValVersion; | ||
eager_?: boolean; | ||
resolveValue_: () => TValue; | ||
notify_: () => void; | ||
add_(subscriber: ValSubscriber, mode: SubMode): () => void; | ||
remove_(subscriber?: (...args: any[]) => any): void; | ||
dispose_(): void; | ||
} | ||
/** | ||
* Bare minimum implementation of a readonly val. | ||
* Generally, you should use `readonlyVal` and `ReadonlyVal` instead of this class. | ||
*/ | ||
declare class ValImpl<TValue = any> implements ReadonlyVal<TValue> { | ||
#private; | ||
constructor(agent: IValAgent<TValue>); | ||
get $version(): ValVersion; | ||
get value(): TValue; | ||
set value(value: TValue); | ||
set?: ValSetValue<TValue>; | ||
get: (this: void) => TValue; | ||
ref(writable?: boolean): ReadonlyVal<TValue>; | ||
reaction(subscriber: ValSubscriber<TValue>, eager?: boolean | undefined): ValDisposer; | ||
subscribe(subscriber: ValSubscriber<TValue>, eager?: boolean | undefined): ValDisposer; | ||
$valCompute(subscriber: ValSubscriber<void>): ValDisposer; | ||
unsubscribe(subscriber?: (...args: any[]) => any): void; | ||
dispose(): void; | ||
type CombineValTransform<TCombinedValue = any, TValues extends readonly any[] = any[]> = (newValues: TValues) => TCombinedValue; | ||
interface Combine { | ||
/** | ||
* @returns the string representation of `this.value`. | ||
* | ||
* @example | ||
* ```js | ||
* const v$ = val(val(val(1))); | ||
* console.log(`${v$}`); // "1" | ||
* ``` | ||
* Combines an array of vals into a single val with the array of values. | ||
* @param valInputs An array of vals to combine. | ||
* @returns A readonly val with the combined values. | ||
*/ | ||
toString(): string; | ||
<TValInputs extends readonly ReadonlyVal[] = ReadonlyVal[]>(valInputs: readonly [...TValInputs]): ReadonlyVal<[...ValInputsValueTuple<TValInputs>]>; | ||
/** | ||
* @returns the JSON representation of `this.value`. | ||
* | ||
* @example | ||
* ```js | ||
* const v$ = val(val(val({ a: 1 }))); | ||
* JSON.stringify(v$); // '{"a":1}' | ||
* ``` | ||
* Combines an array of vals into a single val with transformed value. | ||
* @param valInputs An array of vals to combine. | ||
* @param transform A pure function that takes an array of values and returns a new value. | ||
* @param config custom config for the combined val. | ||
* @returns A readonly val with the transformed values. | ||
*/ | ||
toJSON(key: string): unknown; | ||
<TValInputs extends readonly ReadonlyVal[] = ReadonlyVal[], TValue = any>(valInputs: readonly [...TValInputs], transform: CombineValTransform<TValue, [ | ||
...ValInputsValueTuple<TValInputs> | ||
]>, config?: ValConfig<TValue>): ReadonlyVal<TValue>; | ||
} | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
declare function readonlyVal<TValue = any>(): [ | ||
ReadonlyVal<NoInfer<TValue> | undefined>, | ||
ValSetValue<NoInfer<TValue> | undefined> | ||
]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
declare function readonlyVal(value: [], config?: ValConfig<any[]>): [ReadonlyVal<any[]>, ValSetValue<any[]>]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
declare function readonlyVal<TValue = any>(value: TValue, config?: ValConfig<TValue>): [ReadonlyVal<NoInfer<TValue>>, ValSetValue<NoInfer<TValue>>]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Optional value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
declare function readonlyVal<TValue = any>(value?: TValue, config?: ValConfig<TValue>): [ | ||
ReadonlyVal<NoInfer<TValue | undefined>>, | ||
ValSetValue<NoInfer<TValue | undefined>> | ||
]; | ||
/** | ||
* Creates a writable val. | ||
* @returns A val with undefined value. | ||
*/ | ||
declare function val<TValue = any>(): Val<NoInfer<TValue> | undefined>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
declare function val(value: [], config?: ValConfig<any[]>): Val<any[]>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
declare function val<TValue = any>(value: TValue, config?: ValConfig<TValue>): Val<NoInfer<TValue>>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
declare function val<TValue = any>(value?: TValue, config?: ValConfig<TValue | undefined>): Val<NoInfer<TValue>>; | ||
/** | ||
* Takes an object of key-value pairs containing `ReadonlyVal` instances and their corresponding `ValSetValue` functions, | ||
* and returns a tuple containing an array of the `ReadonlyVal` instances and a function to set their values. | ||
* | ||
* @example | ||
* ```ts | ||
* const [vals, setVals] = groupVals({ | ||
* a: readonlyVal(1), | ||
* b: readonlyVal(2), | ||
* c: readonlyVal(3), | ||
* }); | ||
* | ||
* vals.a.value; // 1 | ||
* | ||
* setVals.a(2); | ||
* ``` | ||
* | ||
* This is useful for classes that have multiple `ReadonlyVal` instances as properties. | ||
* | ||
* ```ts | ||
* export interface Foo$ { | ||
* a: ReadonlyVal<number>; | ||
* b: ReadonlyVal<number>; | ||
* c: ReadonlyVal<number>; | ||
* } | ||
* | ||
* export class Foo { | ||
* public $: Foo$; | ||
* private setVals: { [K in keyof Foo$]: ValSetValue<UnwrapVal<Foo$[K]>> }; | ||
* | ||
* public constructor() { | ||
* const [vals, setVals] = groupVals({ | ||
* a: readonlyVal(1), | ||
* b: readonlyVal(2), | ||
* c: readonlyVal(3), | ||
* }); | ||
* | ||
* this.$ = vals; | ||
* this.setVals = setVals; | ||
* } | ||
* ``` | ||
*/ | ||
declare const groupVals: <TValues extends {}>(valPairs: { [K in keyof TValues]: [ReadonlyVal<TValues[K]>, ValSetValue<TValues[K]>]; }) => [{ [K_1 in keyof TValues]: ReadonlyVal<TValues[K_1]>; }, { [K_2 in keyof TValues]: ValSetValue<TValues[K_2]>; }]; | ||
declare const combine: Combine; | ||
@@ -329,57 +184,63 @@ /** | ||
*/ | ||
declare const compute: <TValue = any>(effect: (get: <T = any>(val$: ReadonlyVal<T>) => T) => TValue, config?: ValConfig<TValue>) => ValImpl<TValue>; | ||
declare const compute: <TValue = any>(effect: (get: <T = any>(val$: ReadonlyVal<T>) => T) => TValue, config?: ValConfig<TValue>) => ReadonlyVal<TValue>; | ||
type DerivedValTransform<TValue = any, TDerivedValue = any> = (newValue: TValue) => TDerivedValue; | ||
/** | ||
* Derive a new val with same value from the given val. | ||
* @param val Input value. | ||
* @returns A readonly val with same value as the input val. | ||
*/ | ||
declare function derive<TSrcValue = any, TValue = any>(val: ReadonlyVal<TSrcValue>): ReadonlyVal<TValue>; | ||
/** | ||
* Derive a new val with transformed value from the given val. | ||
* @param val Input value. | ||
* @param transform A pure function that takes an input value and returns a new value. | ||
* @param config custom config for the combined val. | ||
* @returns A readonly val with transformed value from the input val. | ||
*/ | ||
declare function derive<TSrcValue = any, TValue = any>(val: ReadonlyVal<TSrcValue>, transform: DerivedValTransform<TSrcValue, TValue>, config?: ValConfig<TValue>): ReadonlyVal<TValue>; | ||
interface Derive { | ||
/** | ||
* Derive a new val with same value from the given val. | ||
* @param val Input value. | ||
* @returns A readonly val with same value as the input val. | ||
*/ | ||
<TSrcValue = any, TValue = any>(val: ReadonlyVal<TSrcValue>): ReadonlyVal<TValue>; | ||
/** | ||
* Derive a new val with transformed value from the given val. | ||
* @param val Input value. | ||
* @param transform A pure function that takes an input value and returns a new value. | ||
* @param config custom config for the combined val. | ||
* @returns A readonly val with transformed value from the input val. | ||
*/ | ||
<TSrcValue = any, TValue = any>(val: ReadonlyVal<TSrcValue>, transform: DerivedValTransform<TSrcValue, TValue>, config?: ValConfig<TValue>): ReadonlyVal<TValue>; | ||
} | ||
declare const derive: Derive; | ||
/** | ||
* Flatten a val of val to a val of the inner val value. | ||
* @param val Input value. | ||
* @returns A readonly val with value of inner val. | ||
* | ||
* @example | ||
* ```js | ||
* import { flatten, val } from "value-enhancer"; | ||
* | ||
* const inner$ = val(12); | ||
* const outer$ = val(inner$); | ||
* | ||
* const flattened$ = flatten(outer$); | ||
* | ||
* inner$.value === flattened$.value; // true | ||
* ``` | ||
*/ | ||
declare function flatten<TValOrValue = any>(val: ReadonlyVal<TValOrValue>): ReadonlyVal<UnwrapVal<TValOrValue>>; | ||
/** | ||
* Flatten an inner val extracted from a source val to a val of the inner val value. | ||
* @param val Input value. | ||
* @param get extract inner val or value from source val. | ||
* @returns A readonly val with value of inner val. | ||
* | ||
* @example | ||
* ```js | ||
* import { flatten, val } from "value-enhancer"; | ||
* | ||
* const inner$ = val(12); | ||
* const outer$ = val({ inner$ }); | ||
* | ||
* const flattened$ = flatten(outer$, ({ inner$ }) => inner$); | ||
* | ||
* inner$.value === flattened$.value; // true | ||
* ``` | ||
*/ | ||
declare function flatten<TSrcValue = any, TValOrValue = any>(val: ReadonlyVal<TSrcValue>, get?: (value: TSrcValue) => TValOrValue, config?: ValConfig<UnwrapVal<TValOrValue>>): ReadonlyVal<UnwrapVal<TValOrValue>>; | ||
interface Flatten { | ||
/** | ||
* Flatten a val of val to a val of the inner val value. | ||
* @param val Input value. | ||
* @returns A readonly val with value of inner val. | ||
* | ||
* @example | ||
* ```js | ||
* import { flatten, val } from "value-enhancer"; | ||
* | ||
* const inner$ = val(12); | ||
* const outer$ = val(inner$); | ||
* | ||
* const flattened$ = flatten(outer$); | ||
* | ||
* inner$.value === flattened$.value; // true | ||
* ``` | ||
*/ | ||
<TValOrValue = any>(val: ReadonlyVal<TValOrValue>): ReadonlyVal<UnwrapVal<TValOrValue>>; | ||
/** | ||
* Flatten an inner val extracted from a source val to a val of the inner val value. | ||
* @param val Input value. | ||
* @param get extract inner val or value from source val. | ||
* @returns A readonly val with value of inner val. | ||
* | ||
* @example | ||
* ```js | ||
* import { flatten, val } from "value-enhancer"; | ||
* | ||
* const inner$ = val(12); | ||
* const outer$ = val({ inner$ }); | ||
* | ||
* const flattened$ = flatten(outer$, ({ inner$ }) => inner$); | ||
* | ||
* inner$.value === flattened$.value; // true | ||
* ``` | ||
*/ | ||
<TSrcValue = any, TValOrValue = any>(val: ReadonlyVal<TSrcValue>, get?: (value: TSrcValue) => TValOrValue, config?: ValConfig<UnwrapVal<TValOrValue>>): ReadonlyVal<UnwrapVal<TValOrValue>>; | ||
} | ||
declare const flatten: Flatten; | ||
@@ -419,14 +280,7 @@ /** | ||
* ``` | ||
* | ||
* @example An implementation of the `derive` function: | ||
* ```ts | ||
* const derive = (val, transform, config) => from( | ||
* () => transform(val.value), | ||
* notify => val.subscribe(notify), | ||
* config, | ||
* ); | ||
* ``` | ||
*/ | ||
declare const from: <TValue = any>(getValue: () => TValue, onChange: (notify: () => void) => ValDisposer | void | undefined, config?: ValConfig<TValue>) => ReadonlyVal<TValue>; | ||
declare const nextTick: () => Promise<void>; | ||
/** | ||
@@ -501,2 +355,117 @@ * Set the value of a val. | ||
interface CreateReadonlyVal { | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
<TValue = any>(): [ | ||
ReadonlyVal<NoInfer<TValue> | undefined>, | ||
ValSetValue<NoInfer<TValue> | undefined> | ||
]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
(value: [], config?: ValConfig<any[]>): [ | ||
ReadonlyVal<any[]>, | ||
ValSetValue<any[]> | ||
]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
<TValue = any>(value: TValue, config?: ValConfig<TValue>): [ | ||
ReadonlyVal<NoInfer<TValue>>, | ||
ValSetValue<NoInfer<TValue>> | ||
]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Optional value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
<TValue = any>(value?: TValue, config?: ValConfig<TValue>): [ | ||
ReadonlyVal<NoInfer<TValue | undefined>>, | ||
ValSetValue<NoInfer<TValue | undefined>> | ||
]; | ||
} | ||
declare const readonlyVal: CreateReadonlyVal; | ||
interface CreateVal { | ||
/** | ||
* Creates a writable val. | ||
* @returns A val with undefined value. | ||
*/ | ||
<TValue = any>(): Val<NoInfer<TValue> | undefined>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
(value: [], config?: ValConfig<any[]>): Val<any[]>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
<TValue = any>(value: TValue, config?: ValConfig<TValue>): Val<NoInfer<TValue>>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
<TValue = any>(value?: TValue, config?: ValConfig<TValue | undefined>): Val<NoInfer<TValue>>; | ||
} | ||
declare const val: CreateVal; | ||
/** | ||
* Takes an object of key-value pairs containing `ReadonlyVal` instances and their corresponding `ValSetValue` functions, | ||
* and returns a tuple containing an array of the `ReadonlyVal` instances and a function to set their values. | ||
* | ||
* @example | ||
* ```ts | ||
* const [vals, setVals] = groupVals({ | ||
* a: readonlyVal(1), | ||
* b: readonlyVal(2), | ||
* c: readonlyVal(3), | ||
* }); | ||
* | ||
* vals.a.value; // 1 | ||
* | ||
* setVals.a(2); | ||
* ``` | ||
* | ||
* This is useful for classes that have multiple `ReadonlyVal` instances as properties. | ||
* | ||
* ```ts | ||
* export interface Foo$ { | ||
* a: ReadonlyVal<number>; | ||
* b: ReadonlyVal<number>; | ||
* c: ReadonlyVal<number>; | ||
* } | ||
* | ||
* export class Foo { | ||
* public $: Foo$; | ||
* private setVals: { [K in keyof Foo$]: ValSetValue<UnwrapVal<Foo$[K]>> }; | ||
* | ||
* public constructor() { | ||
* const [vals, setVals] = groupVals({ | ||
* a: readonlyVal(1), | ||
* b: readonlyVal(2), | ||
* c: readonlyVal(3), | ||
* }); | ||
* | ||
* this.$ = vals; | ||
* this.setVals = setVals; | ||
* } | ||
* ``` | ||
*/ | ||
declare const groupVals: <TValues extends {}>(valPairs: { [K in keyof TValues]: [ReadonlyVal<TValues[K]>, ValSetValue<TValues[K]>]; }) => [{ [K_1 in keyof TValues]: ReadonlyVal<TValues[K_1]>; }, { [K_2 in keyof TValues]: ValSetValue<TValues[K_2]>; }]; | ||
export { CombineValTransform, DerivedValTransform, FlattenVal, ReadonlyVal, UnwrapVal, Val, ValConfig, ValDisposer, ValEqual, ValSetValue, ValSubscriber, ValVersion, arrayShallowEqual, attachSetter, combine, compute, derive, flatten, flattenFrom, from, groupVals, identity, isVal, isWritable, nextTick, reaction, readonlyVal, setValue, strictEqual, subscribe, unsubscribe, val }; |
@@ -350,3 +350,3 @@ 'use strict'; | ||
}; | ||
function readonlyVal(value, config) { | ||
var readonlyVal = (value, config) => { | ||
let currentValue = value; | ||
@@ -363,7 +363,4 @@ const get = () => currentValue; | ||
return [val2, set]; | ||
} | ||
function val(value, config) { | ||
const [val$, set] = readonlyVal(value, config); | ||
return attachSetter(val$, set); | ||
} | ||
}; | ||
var val = (value, config) => attachSetter(...readonlyVal(value, config)); | ||
var groupVals = (valPairs) => { | ||
@@ -384,3 +381,3 @@ const vals = {}; | ||
// src/combine.ts | ||
function combine(valInputs, transform = identity, config) { | ||
var combine = (valInputs, transform = identity, config) => { | ||
let cachedValue; | ||
@@ -403,3 +400,3 @@ let cachedSrcVersions; | ||
); | ||
} | ||
}; | ||
@@ -449,3 +446,3 @@ // src/compute.ts | ||
// src/derive.ts | ||
function derive(val2, transform = identity, config) { | ||
var derive = (val2, transform = identity, config) => { | ||
let cachedValue; | ||
@@ -465,3 +462,3 @@ let cachedSrcVersion = INIT_VALUE; | ||
); | ||
} | ||
}; | ||
@@ -518,9 +515,7 @@ // src/flatten-from.ts | ||
// src/flatten.ts | ||
function flatten(val2, get = identity, config) { | ||
return flattenFrom( | ||
() => get(val2.value), | ||
(notify) => val2.$valCompute(notify), | ||
config | ||
); | ||
} | ||
var flatten = (val2, get = identity, config) => flattenFrom( | ||
() => get(val2.value), | ||
(notify) => val2.$valCompute(notify), | ||
config | ||
); | ||
@@ -527,0 +522,0 @@ // src/index.ts |
{ | ||
"name": "value-enhancer", | ||
"version": "5.4.0", | ||
"version": "5.4.1", | ||
"private": false, | ||
@@ -47,4 +47,5 @@ "description": "Enhance value with plain and explicit reactive wrapper. Think of it as hook-style signals.", | ||
"lint": "eslint --ext .ts,.tsx . && prettier --check . && tsc --noEmit", | ||
"size-limit": "size-limit", | ||
"test": "node --expose-gc ./node_modules/jest/bin/jest.js --runInBand", | ||
"test:CI": "tsc --noEmit -p ./test/tsconfig.json && node --expose-gc ./node_modules/jest/bin/jest.js --collect-coverage", | ||
"test:coverage": "tsc --noEmit -p ./test/tsconfig.json && node --expose-gc ./node_modules/jest/bin/jest.js --collect-coverage", | ||
"docs": "typedoc --options typedoc.json", | ||
@@ -54,4 +55,4 @@ "types": "cross-env NODE_ENV=production tsc --declaration --emitDeclarationOnly --jsx react --esModuleInterop --outDir dist", | ||
"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", | ||
"build": "cross-env NODE_ENV=production pnpm run build:index && cross-env NODE_ENV=production pnpm run build:collections && node scripts/size.mjs", | ||
"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/size.mjs", | ||
"release": "standard-version" | ||
@@ -61,2 +62,4 @@ }, | ||
"@jest/globals": "^29.5.0", | ||
"@size-limit/esbuild": "^11.1.4", | ||
"@size-limit/file": "^11.1.4", | ||
"@types/node": "^18.15.0", | ||
@@ -68,10 +71,10 @@ "@typescript-eslint/eslint-plugin": "7.9.0", | ||
"eslint-config-prettier": "8.10.0", | ||
"gzip-size": "^7.0.0", | ||
"jest": "^29.5.0", | ||
"prettier": "^2.8.4", | ||
"pretty-bytes": "^6.1.0", | ||
"size-limit": "^11.1.4", | ||
"standard-version": "^9.5.0", | ||
"ts-jest": "^29.1.2", | ||
"tsup": "^6.6.3", | ||
"typedoc": "0.25.13", | ||
"typedoc": "^0.25.13", | ||
"typescript": "5.4.5", | ||
@@ -78,0 +81,0 @@ "yoctocolors": "^1.0.0" |
@@ -10,5 +10,2 @@ # [value-enhancer](https://github.com/crimx/value-enhancer) | ||
[![Coverage Status](https://img.shields.io/coveralls/github/crimx/value-enhancer/main)](https://coveralls.io/github/crimx/value-enhancer?branch=main) | ||
[![full-size](https://img.shields.io/bundlephobia/minzip/value-enhancer)](https://bundlejs.com/?q=value-enhancer) | ||
[![core-size](https://img.shields.io/bundlejs/size/value-enhancer?exports=val&label=core%20size)](https://bundlejs.com/?q=value-enhancer&treeshake=%5B%7Bval%7D%5D) | ||
[![tree-shakable](https://img.shields.io/badge/%20tree-shakable-success)](https://bundlejs.com/?q=value-enhancer) | ||
@@ -32,6 +29,2 @@ [![no-dependencies](https://img.shields.io/badge/dependencies-none-success)](https://bundlejs.com/?q=value-enhancer) | ||
## Docs | ||
<https://value-enhancer.js.org/> | ||
## Features | ||
@@ -44,5 +37,5 @@ | ||
- Safe and fast lazy computation. | ||
It solves multi-level derivation issue (like in Svelte Stores) with smart lazy value evaluation. | ||
- Side effect free. | ||
`Val`s are created without side effects, which means you can create and access derived `Val.value` without worrying about memory leaks. Disposers returned by subscriptions can be easily managed with libraries like [`@wopjs/disposable`](https://github.com/wopjs/disposable). | ||
It solves multi-level derivation issue (like in [Svelte Stores](<(https://svelte.dev/repl/6218ae0ecf5c455195b4a76d7f0cff9f?version=3.49.0)>)) with smart lazy value evaluation. | ||
- Weak side effects. | ||
`Val`s are managed with `FinalizationRegistry` and `WeakRef` which means you can create and access derived `Val.value` without worrying about memory leaks. Disposers returned by subscriptions can also be easily managed with libraries like [`@wopjs/disposable`](https://github.com/wopjs/disposable). | ||
- Explicit. | ||
@@ -53,2 +46,22 @@ Reactive objects are easy to tell since their types are different from normal objects. Subscription also requires explicit dependency declaration which reduce the work of repetitive dynamic dependency collection in Proxy/Signal implementations. | ||
## Sizes | ||
<!-- size-section-start --> | ||
| import | size(brotli) | | ||
| ----------------------------- | ------------ | | ||
| `*` | 1.77 kB | | ||
| `{ readonlyVal, val }` (core) | 1.02 kB | | ||
| `{ from }` | 26 B | | ||
| `{ derive }` | 93 B | | ||
| `{ combine }` | 204 B | | ||
| `{ compute }` | 192 B | | ||
| `{ flattenFrom }` | 227 B | | ||
| `{ flatten }` | 36 B | | ||
| `{ reactiveMap }` | 479 B | | ||
| `{ reactiveSet }` | 359 B | | ||
| `{ reactiveList }` | 528 B | | ||
<!-- size-section-end --> | ||
## Quick Q&A | ||
@@ -310,6 +323,4 @@ | ||
Pipe-able style with functional lib like `rubico`: | ||
Pipe-able style with functional lib like `rubico`: [(CodeSandbox)](https://codesandbox.io/p/sandbox/value-enhancer-derive-functional-with-rubico-t7d4gm?file=%2Fsrc%2Findex.ts%3A15%2C1) | ||
<https://codesandbox.io/p/sandbox/value-enhancer-derive-functional-with-rubico-t7d4gm?file=%2Fsrc%2Findex.ts%3A15%2C1> | ||
```ts | ||
@@ -316,0 +327,0 @@ import { derive, val } from "value-enhancer"; |
@@ -6,3 +6,13 @@ export { | ||
} from "./list"; | ||
export { reactiveMap, type ReactiveMap, type ReadonlyReactiveMap } from "./map"; | ||
export { reactiveSet, type ReactiveSet, type ReadonlyReactiveSet } from "./set"; | ||
export { | ||
reactiveMap, | ||
type ReactiveMap, | ||
type ReactiveMapConfig, | ||
type ReadonlyReactiveMap, | ||
} from "./map"; | ||
export { | ||
reactiveSet, | ||
type ReactiveSet, | ||
type ReactiveSetConfig, | ||
type ReadonlyReactiveSet, | ||
} from "./set"; |
@@ -22,20 +22,29 @@ import type { | ||
/** | ||
* Combines an array of vals into a single val with the array of values. | ||
* @param valInputs An array of vals to combine. | ||
* @returns A readonly val with the combined values. | ||
*/ | ||
export function combine< | ||
TValInputs extends readonly ReadonlyVal[] = ReadonlyVal[] | ||
>( | ||
valInputs: readonly [...TValInputs] | ||
): ReadonlyVal<[...ValInputsValueTuple<TValInputs>]>; | ||
/** | ||
* Combines an array of vals into a single val with transformed value. | ||
* @param valInputs An array of vals to combine. | ||
* @param transform A pure function that takes an array of values and returns a new value. | ||
* @param config custom config for the combined val. | ||
* @returns A readonly val with the transformed values. | ||
*/ | ||
export function combine< | ||
export interface Combine { | ||
/** | ||
* Combines an array of vals into a single val with the array of values. | ||
* @param valInputs An array of vals to combine. | ||
* @returns A readonly val with the combined values. | ||
*/ | ||
<TValInputs extends readonly ReadonlyVal[] = ReadonlyVal[]>( | ||
valInputs: readonly [...TValInputs] | ||
): ReadonlyVal<[...ValInputsValueTuple<TValInputs>]>; | ||
/** | ||
* Combines an array of vals into a single val with transformed value. | ||
* @param valInputs An array of vals to combine. | ||
* @param transform A pure function that takes an array of values and returns a new value. | ||
* @param config custom config for the combined val. | ||
* @returns A readonly val with the transformed values. | ||
*/ | ||
<TValInputs extends readonly ReadonlyVal[] = ReadonlyVal[], TValue = any>( | ||
valInputs: readonly [...TValInputs], | ||
transform: CombineValTransform< | ||
TValue, | ||
[...ValInputsValueTuple<TValInputs>] | ||
>, | ||
config?: ValConfig<TValue> | ||
): ReadonlyVal<TValue>; | ||
} | ||
export const combine: Combine = < | ||
TValInputs extends readonly ReadonlyVal[] = ReadonlyVal[], | ||
@@ -45,10 +54,2 @@ TValue = any | ||
valInputs: readonly [...TValInputs], | ||
transform: CombineValTransform<TValue, [...ValInputsValueTuple<TValInputs>]>, | ||
config?: ValConfig<TValue> | ||
): ReadonlyVal<TValue>; | ||
export function combine< | ||
TValInputs extends readonly ReadonlyVal[] = ReadonlyVal[], | ||
TValue = any | ||
>( | ||
valInputs: readonly [...TValInputs], | ||
transform: CombineValTransform< | ||
@@ -62,3 +63,3 @@ TValue, | ||
config?: ValConfig<TValue> | ||
): ReadonlyVal<TValue> { | ||
): ReadonlyVal<TValue> => { | ||
let cachedValue: TValue; | ||
@@ -85,2 +86,2 @@ let cachedSrcVersions: readonly ValVersion[] | undefined; | ||
); | ||
} | ||
}; |
@@ -30,3 +30,3 @@ import { ValAgent } from "./agent"; | ||
config?: ValConfig<TValue> | ||
) => { | ||
): ReadonlyVal<TValue> => { | ||
let scopeLevel = 0; | ||
@@ -33,0 +33,0 @@ |
@@ -10,23 +10,26 @@ import type { ReadonlyVal, ValConfig } from "./typings"; | ||
/** | ||
* Derive a new val with same value from the given val. | ||
* @param val Input value. | ||
* @returns A readonly val with same value as the input val. | ||
*/ | ||
export function derive<TSrcValue = any, TValue = any>( | ||
val: ReadonlyVal<TSrcValue> | ||
): ReadonlyVal<TValue>; | ||
/** | ||
* Derive a new val with transformed value from the given val. | ||
* @param val Input value. | ||
* @param transform A pure function that takes an input value and returns a new value. | ||
* @param config custom config for the combined val. | ||
* @returns A readonly val with transformed value from the input val. | ||
*/ | ||
export function derive<TSrcValue = any, TValue = any>( | ||
val: ReadonlyVal<TSrcValue>, | ||
transform: DerivedValTransform<TSrcValue, TValue>, | ||
config?: ValConfig<TValue> | ||
): ReadonlyVal<TValue>; | ||
export function derive< | ||
interface Derive { | ||
/** | ||
* Derive a new val with same value from the given val. | ||
* @param val Input value. | ||
* @returns A readonly val with same value as the input val. | ||
*/ | ||
<TSrcValue = any, TValue = any>( | ||
val: ReadonlyVal<TSrcValue> | ||
): ReadonlyVal<TValue>; | ||
/** | ||
* Derive a new val with transformed value from the given val. | ||
* @param val Input value. | ||
* @param transform A pure function that takes an input value and returns a new value. | ||
* @param config custom config for the combined val. | ||
* @returns A readonly val with transformed value from the input val. | ||
*/ | ||
<TSrcValue = any, TValue = any>( | ||
val: ReadonlyVal<TSrcValue>, | ||
transform: DerivedValTransform<TSrcValue, TValue>, | ||
config?: ValConfig<TValue> | ||
): ReadonlyVal<TValue>; | ||
} | ||
export const derive: Derive = < | ||
TSrcValue = any, | ||
@@ -42,3 +45,3 @@ TValue = any, | ||
config?: ValConfig<TValue> | ||
): ReadonlyVal<TValue> { | ||
): ReadonlyVal<TValue> => { | ||
let cachedValue: TValue; | ||
@@ -59,2 +62,2 @@ let cachedSrcVersion: TSrcValue = INIT_VALUE; | ||
); | ||
} | ||
}; |
@@ -7,46 +7,49 @@ import type { ReadonlyVal, UnwrapVal, ValConfig } from "./typings"; | ||
/** | ||
* Flatten a val of val to a val of the inner val value. | ||
* @param val Input value. | ||
* @returns A readonly val with value of inner val. | ||
* | ||
* @example | ||
* ```js | ||
* import { flatten, val } from "value-enhancer"; | ||
* | ||
* const inner$ = val(12); | ||
* const outer$ = val(inner$); | ||
* | ||
* const flattened$ = flatten(outer$); | ||
* | ||
* inner$.value === flattened$.value; // true | ||
* ``` | ||
*/ | ||
export function flatten<TValOrValue = any>( | ||
val: ReadonlyVal<TValOrValue> | ||
): ReadonlyVal<UnwrapVal<TValOrValue>>; | ||
/** | ||
* Flatten an inner val extracted from a source val to a val of the inner val value. | ||
* @param val Input value. | ||
* @param get extract inner val or value from source val. | ||
* @returns A readonly val with value of inner val. | ||
* | ||
* @example | ||
* ```js | ||
* import { flatten, val } from "value-enhancer"; | ||
* | ||
* const inner$ = val(12); | ||
* const outer$ = val({ inner$ }); | ||
* | ||
* const flattened$ = flatten(outer$, ({ inner$ }) => inner$); | ||
* | ||
* inner$.value === flattened$.value; // true | ||
* ``` | ||
*/ | ||
export function flatten<TSrcValue = any, TValOrValue = any>( | ||
val: ReadonlyVal<TSrcValue>, | ||
get?: (value: TSrcValue) => TValOrValue, | ||
config?: ValConfig<UnwrapVal<TValOrValue>> | ||
): ReadonlyVal<UnwrapVal<TValOrValue>>; | ||
export function flatten< | ||
interface Flatten { | ||
/** | ||
* Flatten a val of val to a val of the inner val value. | ||
* @param val Input value. | ||
* @returns A readonly val with value of inner val. | ||
* | ||
* @example | ||
* ```js | ||
* import { flatten, val } from "value-enhancer"; | ||
* | ||
* const inner$ = val(12); | ||
* const outer$ = val(inner$); | ||
* | ||
* const flattened$ = flatten(outer$); | ||
* | ||
* inner$.value === flattened$.value; // true | ||
* ``` | ||
*/ | ||
<TValOrValue = any>(val: ReadonlyVal<TValOrValue>): ReadonlyVal< | ||
UnwrapVal<TValOrValue> | ||
>; | ||
/** | ||
* Flatten an inner val extracted from a source val to a val of the inner val value. | ||
* @param val Input value. | ||
* @param get extract inner val or value from source val. | ||
* @returns A readonly val with value of inner val. | ||
* | ||
* @example | ||
* ```js | ||
* import { flatten, val } from "value-enhancer"; | ||
* | ||
* const inner$ = val(12); | ||
* const outer$ = val({ inner$ }); | ||
* | ||
* const flattened$ = flatten(outer$, ({ inner$ }) => inner$); | ||
* | ||
* inner$.value === flattened$.value; // true | ||
* ``` | ||
*/ | ||
<TSrcValue = any, TValOrValue = any>( | ||
val: ReadonlyVal<TSrcValue>, | ||
get?: (value: TSrcValue) => TValOrValue, | ||
config?: ValConfig<UnwrapVal<TValOrValue>> | ||
): ReadonlyVal<UnwrapVal<TValOrValue>>; | ||
} | ||
export const flatten: Flatten = < | ||
TSrcValue = any, | ||
@@ -59,4 +62,4 @@ TValOrValue = any, | ||
config?: ValConfig<UnwrapVal<TValOrValue>> | ||
): ReadonlyVal<UnwrapVal<TValOrValue>> { | ||
return flattenFrom( | ||
): ReadonlyVal<UnwrapVal<TValOrValue>> => | ||
flattenFrom( | ||
() => get(val.value), | ||
@@ -66,2 +69,1 @@ notify => val.$valCompute(notify), | ||
); | ||
} |
@@ -25,11 +25,2 @@ import { ValAgent } from "./agent"; | ||
* ``` | ||
* | ||
* @example An implementation of the `derive` function: | ||
* ```ts | ||
* const derive = (val, transform, config) => from( | ||
* () => transform(val.value), | ||
* notify => val.subscribe(notify), | ||
* config, | ||
* ); | ||
* ``` | ||
*/ | ||
@@ -36,0 +27,0 @@ export const from = <TValue = any>( |
@@ -136,3 +136,6 @@ /** | ||
/** @internal */ | ||
/** | ||
* @internal | ||
* @ignore | ||
*/ | ||
export type ValInputsValueTuple<TValInputs extends readonly ReadonlyVal[]> = | ||
@@ -143,3 +146,6 @@ Readonly<{ | ||
/** @internal */ | ||
/** | ||
* @internal | ||
* @ignore | ||
*/ | ||
export type ExtractValValue<TVal> = TVal extends ReadonlyVal<infer TValue> | ||
@@ -149,2 +155,6 @@ ? TValue | ||
/** | ||
* @internal | ||
* @ignore | ||
*/ | ||
export type NoInfer<T> = [T][T extends any ? 0 : never]; |
161
src/val.ts
@@ -114,49 +114,49 @@ import type { | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
export function readonlyVal<TValue = any>(): [ | ||
ReadonlyVal<NoInfer<TValue> | undefined>, | ||
ValSetValue<NoInfer<TValue> | undefined> | ||
]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
export function readonlyVal( | ||
value: [], | ||
config?: ValConfig<any[]> | ||
): [ReadonlyVal<any[]>, ValSetValue<any[]>]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
export function readonlyVal<TValue = any>( | ||
value: TValue, | ||
config?: ValConfig<TValue> | ||
): [ReadonlyVal<NoInfer<TValue>>, ValSetValue<NoInfer<TValue>>]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Optional value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
export function readonlyVal<TValue = any>( | ||
interface CreateReadonlyVal { | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
<TValue = any>(): [ | ||
ReadonlyVal<NoInfer<TValue> | undefined>, | ||
ValSetValue<NoInfer<TValue> | undefined> | ||
]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
(value: [], config?: ValConfig<any[]>): [ | ||
ReadonlyVal<any[]>, | ||
ValSetValue<any[]> | ||
]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
<TValue = any>(value: TValue, config?: ValConfig<TValue>): [ | ||
ReadonlyVal<NoInfer<TValue>>, | ||
ValSetValue<NoInfer<TValue>> | ||
]; | ||
/** | ||
* Creates a readonly val with the given value. | ||
* | ||
* @param value Optional value for the val | ||
* @param config Optional custom config for the val. | ||
* @returns A tuple with the readonly val and a function to set the value. | ||
*/ | ||
<TValue = any>(value?: TValue, config?: ValConfig<TValue>): [ | ||
ReadonlyVal<NoInfer<TValue | undefined>>, | ||
ValSetValue<NoInfer<TValue | undefined>> | ||
]; | ||
} | ||
export const readonlyVal: CreateReadonlyVal = <TValue = any>( | ||
value?: TValue, | ||
config?: ValConfig<TValue> | ||
): [ | ||
ReadonlyVal<NoInfer<TValue | undefined>>, | ||
ValSetValue<NoInfer<TValue | undefined>> | ||
]; | ||
export function readonlyVal<TValue = any>( | ||
value?: TValue, | ||
config?: ValConfig<TValue | undefined> | ||
@@ -166,3 +166,3 @@ ): [ | ||
ValSetValue<NoInfer<TValue> | undefined> | ||
] { | ||
] => { | ||
let currentValue = value; | ||
@@ -184,40 +184,39 @@ | ||
return [val, set]; | ||
}; | ||
interface CreateVal { | ||
/** | ||
* Creates a writable val. | ||
* @returns A val with undefined value. | ||
*/ | ||
<TValue = any>(): Val<NoInfer<TValue> | undefined>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
(value: [], config?: ValConfig<any[]>): Val<any[]>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
<TValue = any>(value: TValue, config?: ValConfig<TValue>): Val< | ||
NoInfer<TValue> | ||
>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
<TValue = any>(value?: TValue, config?: ValConfig<TValue | undefined>): Val< | ||
NoInfer<TValue> | ||
>; | ||
} | ||
/** | ||
* Creates a writable val. | ||
* @returns A val with undefined value. | ||
*/ | ||
export function val<TValue = any>(): Val<NoInfer<TValue> | undefined>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
export function val(value: [], config?: ValConfig<any[]>): Val<any[]>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
export function val<TValue = any>( | ||
value: TValue, | ||
config?: ValConfig<TValue> | ||
): Val<NoInfer<TValue>>; | ||
/** | ||
* Creates a writable val. | ||
* @param value Initial value. | ||
* @param config Optional custom config. | ||
*/ | ||
export function val<TValue = any>( | ||
export const val: CreateVal = <TValue = any>( | ||
value?: TValue, | ||
config?: ValConfig<TValue | undefined> | ||
): Val<NoInfer<TValue>>; | ||
export function val<TValue = any>( | ||
value?: TValue, | ||
config?: ValConfig<TValue> | ||
): Val<NoInfer<TValue | undefined>> { | ||
const [val$, set] = readonlyVal(value, config); | ||
return attachSetter(val$, set); | ||
} | ||
): Val<NoInfer<TValue | undefined>> => | ||
attachSetter(...readonlyVal(value, config)); | ||
@@ -224,0 +223,0 @@ /** |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
696
163403
19
4734