@ersbeth/picoflow 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/api/doc/picoflow.from.md +55 -0
  2. package/api/doc/picoflow.from_1.md +55 -0
  3. package/api/doc/picoflow.from_2.md +55 -0
  4. package/api/doc/picoflow.from_3.md +55 -0
  5. package/api/doc/picoflow.from_4.md +55 -0
  6. package/api/doc/picoflow.from_5.md +55 -0
  7. package/api/doc/picoflow.md +121 -0
  8. package/api/doc/picoflow.solidderivation._constructor_.md +49 -0
  9. package/api/doc/picoflow.solidderivation.get.md +13 -0
  10. package/api/doc/picoflow.solidderivation.md +94 -0
  11. package/api/doc/picoflow.solidgetter.md +13 -0
  12. package/api/doc/picoflow.solidobservable.get.md +13 -0
  13. package/api/doc/picoflow.solidobservable.md +57 -0
  14. package/api/doc/picoflow.solidresource._constructor_.md +49 -0
  15. package/api/doc/picoflow.solidresource.get.md +13 -0
  16. package/api/doc/picoflow.solidresource.latest.md +13 -0
  17. package/api/doc/picoflow.solidresource.md +157 -0
  18. package/api/doc/picoflow.solidresource.refetch.md +13 -0
  19. package/api/doc/picoflow.solidresource.state.md +13 -0
  20. package/api/doc/picoflow.solidstate._constructor_.md +49 -0
  21. package/api/doc/picoflow.solidstate.get.md +13 -0
  22. package/api/doc/picoflow.solidstate.md +115 -0
  23. package/api/doc/picoflow.solidstate.set.md +13 -0
  24. package/api/picoflow.public.api.md +52 -0
  25. package/dist/picoflow.js +844 -2
  26. package/dist/types/basic/derivation.d.ts.map +1 -1
  27. package/dist/types/index.d.ts +3 -5
  28. package/dist/types/index.d.ts.map +1 -1
  29. package/dist/types/solid/converters.d.ts +64 -0
  30. package/dist/types/solid/converters.d.ts.map +1 -0
  31. package/dist/types/solid/index.d.ts +3 -0
  32. package/dist/types/solid/index.d.ts.map +1 -0
  33. package/dist/types/solid/primitives.d.ts +88 -0
  34. package/dist/types/solid/primitives.d.ts.map +1 -0
  35. package/package.json +4 -1
  36. package/src/basic/derivation.ts +18 -1
  37. package/src/index.ts +18 -12
  38. package/src/solid/converters.ts +159 -0
  39. package/src/solid/index.ts +2 -0
  40. package/src/solid/primitives.ts +109 -0
  41. package/test/derivation.test.ts +98 -0
@@ -1 +1 @@
1
- {"version":3,"file":"derivation.d.ts","sourceRoot":"","sources":["../../../src/basic/derivation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;;;;;GAQG;AACH,qBAAa,cAAc,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IACpD;;;;;OAKG;gBACS,OAAO,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,KAAK,CAAC;IAK/D;;;;;;;OAOG;IACI,GAAG,IAAI,CAAC;IASf,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,WAAW,CAAyD;IAC5E,OAAO,CAAC,aAAa,CAAoD;IACzE,OAAO,CAAC,aAAa,CAAgD;IACrE,OAAO,CAAC,eAAe,CAA4C;IACnE,OAAO,CAAC,eAAe,CAAW;IAClC,OAAO,CAAC,iBAAiB,CAAW;IAEpC,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,SAAS;CAyBpB"}
1
+ {"version":3,"file":"derivation.d.ts","sourceRoot":"","sources":["../../../src/basic/derivation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;;;;;GAQG;AACH,qBAAa,cAAc,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IACpD;;;;;OAKG;gBACS,OAAO,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,KAAK,CAAC;IAK/D;;;;;;;OAOG;IACI,GAAG,IAAI,CAAC;IASf,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,WAAW,CAAyD;IAC5E,OAAO,CAAC,aAAa,CAAoD;IACzE,OAAO,CAAC,aAAa,CAAgD;IACrE,OAAO,CAAC,eAAe,CAA4C;IACnE,OAAO,CAAC,eAAe,CAAW;IAClC,OAAO,CAAC,iBAAiB,CAAW;IAEpC,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,SAAS;CA0CpB"}
@@ -7,9 +7,7 @@
7
7
  *
8
8
  */
9
9
  export { signal, state, constant, resource, stream, derivation, effect, map, array, streamAsync, resourceAsync, } from './creators';
10
- export { isDisposable } from './basic';
11
- export { FlowDerivation, FlowEffect, FlowObservable, FlowSignal, FlowState, FlowConstant, } from './basic/';
12
- export type { FlowGetter, FlowWatcher, FlowDisposable, } from './basic/';
13
- export { FlowResource, FlowMap, FlowResourceAsync, FlowStreamAsync, FlowStream, FlowArray, } from './advanced/';
14
- export type { FlowStreamDisposer, FlowStreamSetter, FlowStreamUpdater, FlowArrayAction, } from './advanced/';
10
+ export { isDisposable, FlowDerivation, FlowEffect, FlowObservable, FlowSignal, FlowState, FlowConstant, type FlowGetter, type FlowWatcher, type FlowDisposable, } from './basic/';
11
+ export { FlowResource, FlowMap, FlowResourceAsync, FlowStreamAsync, FlowStream, FlowArray, type FlowStreamDisposer, type FlowStreamSetter, type FlowStreamUpdater, type FlowArrayAction, } from './advanced/';
12
+ export { from, SolidState, SolidResource, SolidDerivation, type SolidObservable, type SolidGetter, } from './solid/';
15
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACH,MAAM,EACN,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,UAAU,EACV,MAAM,EACN,GAAG,EACH,KAAK,EACL,WAAW,EACX,aAAa,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EACH,cAAc,EACd,UAAU,EACV,cAAc,EACd,UAAU,EACV,SAAS,EACT,YAAY,GACf,MAAM,UAAU,CAAC;AAElB,YAAY,EACR,UAAU,EACV,WAAW,EACX,cAAc,GACjB,MAAM,UAAU,CAAC;AAClB,OAAO,EACH,YAAY,EACZ,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,UAAU,EACV,SAAS,GACZ,MAAM,aAAa,CAAC;AACrB,YAAY,EACR,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,GAClB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACH,MAAM,EACN,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,UAAU,EACV,MAAM,EACN,GAAG,EACH,KAAK,EACL,WAAW,EACX,aAAa,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACH,YAAY,EACZ,cAAc,EACd,UAAU,EACV,cAAc,EACd,UAAU,EACV,SAAS,EACT,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,cAAc,GACtB,MAAM,UAAU,CAAC;AAElB,OAAO,EACH,YAAY,EACZ,OAAO,EACP,iBAAiB,EACjB,eAAe,EACf,UAAU,EACV,SAAS,EACT,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,eAAe,GACvB,MAAM,aAAa,CAAC;AAErB,OAAO,EACH,IAAI,EACJ,UAAU,EACV,aAAa,EACb,eAAe,EACf,KAAK,eAAe,EACpB,KAAK,WAAW,GACnB,MAAM,UAAU,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { FlowObservable, FlowGetter } from '@ersbeth/picoflow';
2
+ import { SolidResource, SolidDerivation } from './primitives';
3
+ /**
4
+ * Utility type that excludes Promise types from T.
5
+ * Used to ensure type safety for synchronous derivations/resources.
6
+ *
7
+ * @public
8
+ */
9
+ export type NotPromise<T> = T extends Promise<unknown> ? never : T;
10
+ /**
11
+ * Converts a FlowObservable of a Promise value into a SolidResource.
12
+ *
13
+ * @param flow - The FlowObservable to convert.
14
+ * @returns A SolidResource wrapping the observable.
15
+ *
16
+ * @public
17
+ */
18
+ export declare function from<T>(flow: FlowObservable<Promise<NotPromise<T>>>): SolidResource<NotPromise<T>>;
19
+ /**
20
+ * Converts a FlowObservable of a non-Promise value into a SolidDerivation.
21
+ *
22
+ * @param flow - The FlowObservable to convert.
23
+ * @returns A SolidDerivation wrapping the observable.
24
+ *
25
+ * @public
26
+ */
27
+ export declare function from<T>(flow: FlowObservable<NotPromise<T>>): SolidDerivation<NotPromise<T>>;
28
+ /**
29
+ * Converts a FlowObservable into a Solid derivation or resource, depending on whether the value is synchronous or asynchronous.
30
+ *
31
+ * @param flow - The FlowObservable to convert.
32
+ * @returns A SolidDerivation or SolidResource, depending on the input type.
33
+ *
34
+ * @public
35
+ */
36
+ export declare function from<T>(flow: FlowObservable<Promise<NotPromise<T>>> | FlowObservable<NotPromise<T>>): SolidDerivation<NotPromise<T>> | SolidResource<NotPromise<T>>;
37
+ /**
38
+ * Converts a getter function returning a non-Promise value into a SolidDerivation.
39
+ *
40
+ * @param flow - The getter function to convert.
41
+ * @returns A SolidDerivation wrapping the getter.
42
+ *
43
+ * @public
44
+ */
45
+ export declare function from<T>(flow: (get: FlowGetter) => NotPromise<T>): SolidDerivation<NotPromise<T>>;
46
+ /**
47
+ * Converts a getter function returning a Promise into a SolidResource.
48
+ *
49
+ * @param flow - The getter function to convert.
50
+ * @returns A SolidResource wrapping the getter.
51
+ *
52
+ * @public
53
+ */
54
+ export declare function from<T>(flow: (get: FlowGetter) => Promise<NotPromise<T>>): SolidResource<NotPromise<T>>;
55
+ /**
56
+ * Converts a getter function into a Solid derivation or resource, depending on whether the returned value is synchronous or asynchronous.
57
+ *
58
+ * @param flow - The getter function to convert.
59
+ * @returns A SolidDerivation or SolidResource, depending on the input type.
60
+ *
61
+ * @public
62
+ */
63
+ export declare function from<T>(flow: ((get: FlowGetter) => NotPromise<T>) | ((get: FlowGetter) => Promise<NotPromise<T>>)): SolidDerivation<T> | SolidResource<T>;
64
+ //# sourceMappingURL=converters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converters.d.ts","sourceRoot":"","sources":["../../../src/solid/converters.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEhG,OAAO,EAAE,aAAa,EAAc,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAsE/E;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,OAAO,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;AAEnE;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACpG;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7F;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAClB,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAC7E,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAClG;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACzG;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAClB,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAC3F,eAAe,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { from } from './converters';
2
+ export { SolidState, SolidResource, SolidDerivation, type SolidObservable, type SolidGetter } from './primitives';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/solid/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,88 @@
1
+ import { ResourceFetcher } from 'solid-js';
2
+ /**
3
+ * A getter function or value for Solid state/derivation.
4
+ *
5
+ * @typeParam T - The value type.
6
+ * @public
7
+ */
8
+ export type SolidGetter<T> = ((previous: T) => T) | T;
9
+ /**
10
+ * Interface for a Solid-style observable value.
11
+ *
12
+ * @typeParam T - The value type.
13
+ * @public
14
+ */
15
+ export interface SolidObservable<T> {
16
+ /**
17
+ * Returns the current value.
18
+ */
19
+ get: () => T;
20
+ }
21
+ /**
22
+ * Solid-style state container, similar to a writable signal.
23
+ *
24
+ * @typeParam T - The value type.
25
+ * @public
26
+ */
27
+ export declare class SolidState<T> implements SolidObservable<T> {
28
+ /**
29
+ * Returns the current value.
30
+ */
31
+ readonly get: () => T;
32
+ /**
33
+ * Sets the value or updates it using a getter function.
34
+ */
35
+ readonly set: (param: SolidGetter<T>) => void;
36
+ /**
37
+ * Creates a new SolidState with the given initial value.
38
+ * @param initialValue - The initial value.
39
+ */
40
+ constructor(initialValue: T);
41
+ }
42
+ /**
43
+ * Solid-style derivation, similar to a computed/memoized value.
44
+ *
45
+ * @typeParam T - The value type.
46
+ * @public
47
+ */
48
+ export declare class SolidDerivation<T> implements SolidObservable<T> {
49
+ /**
50
+ * Returns the current derived value.
51
+ */
52
+ readonly get: () => T;
53
+ /**
54
+ * Creates a new SolidDerivation from a getter function or value.
55
+ * @param calculator - The getter function or value.
56
+ */
57
+ constructor(calculator: SolidGetter<T>);
58
+ }
59
+ /**
60
+ * Solid-style resource, similar to an async resource or data loader.
61
+ *
62
+ * @typeParam T - The value type.
63
+ * @public
64
+ */
65
+ export declare class SolidResource<T> implements SolidObservable<T | undefined> {
66
+ /**
67
+ * Returns the current value (or undefined if not yet loaded).
68
+ */
69
+ readonly get: () => T | undefined;
70
+ /**
71
+ * Returns the current resource state.
72
+ */
73
+ readonly state: () => 'unresolved' | 'pending' | 'errored' | 'ready' | 'refreshing';
74
+ /**
75
+ * Returns the latest successfully loaded value (or undefined).
76
+ */
77
+ readonly latest: () => T | undefined;
78
+ /**
79
+ * Triggers a refetch of the resource.
80
+ */
81
+ readonly refetch: () => void;
82
+ /**
83
+ * Creates a new SolidResource from a fetcher function.
84
+ * @param fetcher - The async fetcher function.
85
+ */
86
+ constructor(fetcher: ResourceFetcher<true, T, unknown>);
87
+ }
88
+ //# sourceMappingURL=primitives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../../src/solid/primitives.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,eAAe,EAAG,MAAM,UAAU,CAAC;AAE3F;;;;;GAKG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IAC9B;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC,CAAC;CAChB;AAED;;;;;GAKG;AACH,qBAAa,UAAU,CAAC,CAAC,CAAE,YAAW,eAAe,CAAC,CAAC,CAAC;IACpD;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACtB;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAE9C;;;OAGG;gBACS,YAAY,EAAE,CAAC;CAK9B;AAGD;;;;;GAKG;AACH,qBAAa,eAAe,CAAC,CAAC,CAAE,YAAW,eAAe,CAAC,CAAC,CAAC;IACzD;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAEtB;;;OAGG;gBACS,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;CAIzC;AAED;;;;;GAKG;AACH,qBAAa,aAAa,CAAC,CAAC,CAAE,YAAW,eAAe,CAAC,CAAC,GAAG,SAAS,CAAC;IACnE;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAClC;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,CAAC;IACpF;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IACrC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAE7B;;;OAGG;gBACS,OAAO,EAAE,eAAe,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC;CAOzD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ersbeth/picoflow",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Minimal Dataflow librairy for TypeScript",
5
5
  "type": "module",
6
6
  "exports": {
@@ -20,6 +20,9 @@
20
20
  "api:clean": "rm ./api/temp/*",
21
21
  "api": "npm run api:extract && npm run api:generate && npm run api:clean"
22
22
  },
23
+ "peerDependencies": {
24
+ "solid-js": "^1.9.7"
25
+ },
23
26
  "devDependencies": {
24
27
  "@biomejs/biome": "^1.9.4",
25
28
  "@vitest/coverage-v8": "^3.0.9",
@@ -67,7 +67,24 @@ export class FlowDerivation<T> extends FlowObservable<T> {
67
67
 
68
68
  /* @internal */ _compute(): void {
69
69
  if (this._dirty) {
70
- this._value = this._untrackedCompute();
70
+ // we cant use untrackedCompute because it will not track dependencies
71
+ // that changed dynamically
72
+
73
+ // store current dependencies
74
+ const dependencies = [...this._dependencies];
75
+
76
+ // clear current dependencies, compute and retrack dependencies
77
+ this._dependencies.clear();
78
+ this._value = this._trackedCompute();
79
+
80
+ // unsubscribe from dependencies that are no longer needed
81
+ const dependenciesToRemove = dependencies.filter(
82
+ (dependency) => !this._dependencies.has(dependency),
83
+ );
84
+ dependenciesToRemove.forEach((dependency) =>
85
+ dependency._unregisterDependency(this),
86
+ );
87
+
71
88
  this._dirty = false;
72
89
  }
73
90
  }
package/src/index.ts CHANGED
@@ -19,21 +19,20 @@ export {
19
19
  streamAsync,
20
20
  resourceAsync,
21
21
  } from "./creators";
22
- export { isDisposable } from "./basic";
22
+
23
23
  export {
24
+ isDisposable,
24
25
  FlowDerivation,
25
26
  FlowEffect,
26
27
  FlowObservable,
27
28
  FlowSignal,
28
29
  FlowState,
29
30
  FlowConstant,
31
+ type FlowGetter,
32
+ type FlowWatcher,
33
+ type FlowDisposable,
30
34
  } from "./basic/";
31
35
 
32
- export type {
33
- FlowGetter,
34
- FlowWatcher,
35
- FlowDisposable,
36
- } from "./basic/";
37
36
  export {
38
37
  FlowResource,
39
38
  FlowMap,
@@ -41,10 +40,17 @@ export {
41
40
  FlowStreamAsync,
42
41
  FlowStream,
43
42
  FlowArray,
43
+ type FlowStreamDisposer,
44
+ type FlowStreamSetter,
45
+ type FlowStreamUpdater,
46
+ type FlowArrayAction,
44
47
  } from "./advanced/";
45
- export type {
46
- FlowStreamDisposer,
47
- FlowStreamSetter,
48
- FlowStreamUpdater,
49
- FlowArrayAction,
50
- } from "./advanced/";
48
+
49
+ export {
50
+ from,
51
+ SolidState,
52
+ SolidResource,
53
+ SolidDerivation,
54
+ type SolidObservable,
55
+ type SolidGetter,
56
+ } from "./solid/";
@@ -0,0 +1,159 @@
1
+ import { FlowDerivation, FlowEffect, FlowObservable, type FlowGetter } from '@ersbeth/picoflow';
2
+ import { onCleanup, onMount } from 'solid-js';
3
+ import { SolidResource, SolidState, type SolidDerivation } from './primitives';
4
+
5
+
6
+ function fromSync<T>(state: FlowObservable<T>): SolidDerivation<T> {
7
+
8
+ const solidState = new SolidState<T>(state.get());
9
+
10
+ let fx: FlowEffect;
11
+
12
+ onMount(() => {
13
+ fx = new FlowEffect((get) => {
14
+ const value = get(state);
15
+ solidState.set(() => value);
16
+ });
17
+ });
18
+
19
+ onCleanup(() => fx.dispose());
20
+
21
+ return solidState
22
+ }
23
+
24
+ function fromAsync<T>(derivation: FlowObservable<Promise<T>>): SolidResource<T> {
25
+
26
+ const solidResource = new SolidResource<T>(async () => {
27
+ const value = await derivation.get();
28
+ return value;
29
+ });
30
+
31
+ let fx: FlowEffect;
32
+
33
+ onMount(() => {
34
+ fx = new FlowEffect(async (get) => {
35
+ await get(derivation);
36
+ solidResource.refetch();
37
+ });
38
+ });
39
+
40
+ onCleanup(() => fx.dispose());
41
+
42
+ return solidResource;
43
+ }
44
+
45
+ function shallowFrom<T>(flow: FlowObservable<Promise<T>>): SolidResource<T>;
46
+ function shallowFrom<T>(flow: FlowObservable<T>): SolidDerivation<T>;
47
+ function shallowFrom<T>(flow: FlowObservable<Promise<T>> | FlowObservable<T>): SolidDerivation<T> | SolidResource<T> {
48
+ const initialValue = flow.get();
49
+ const isAsync = initialValue instanceof Promise;
50
+ if (isAsync) {
51
+ return fromAsync(flow as FlowObservable<Promise<T>>);
52
+ }
53
+ return fromSync(flow as FlowObservable<T>);
54
+ }
55
+
56
+ function deepFrom<T>(getter: (get: FlowGetter) => T): SolidDerivation<T>;
57
+ function deepFrom<T>(getter: (get: FlowGetter) => Promise<T>): SolidResource<T>;
58
+ function deepFrom<T>(getter: (get: FlowGetter) => T | Promise<T>): SolidDerivation<T> | SolidResource<T> {
59
+ const derivation = new FlowDerivation((get) => {
60
+ return getter(get);
61
+ });
62
+
63
+ const initialValue = derivation.get();
64
+ const isAsync = initialValue instanceof Promise;
65
+
66
+ if (isAsync) {
67
+ return fromAsync(derivation as FlowObservable<Promise<T>>);
68
+ }
69
+
70
+ return fromSync(derivation as FlowObservable<T>);
71
+ }
72
+
73
+ /**
74
+ * Utility type that excludes Promise types from T.
75
+ * Used to ensure type safety for synchronous derivations/resources.
76
+ *
77
+ * @public
78
+ */
79
+ export type NotPromise<T> = T extends Promise<unknown> ? never : T;
80
+
81
+ /**
82
+ * Converts a FlowObservable of a Promise value into a SolidResource.
83
+ *
84
+ * @param flow - The FlowObservable to convert.
85
+ * @returns A SolidResource wrapping the observable.
86
+ *
87
+ * @public
88
+ */
89
+ export function from<T>(flow: FlowObservable<Promise<NotPromise<T>>>): SolidResource<NotPromise<T>>;
90
+ /**
91
+ * Converts a FlowObservable of a non-Promise value into a SolidDerivation.
92
+ *
93
+ * @param flow - The FlowObservable to convert.
94
+ * @returns A SolidDerivation wrapping the observable.
95
+ *
96
+ * @public
97
+ */
98
+ export function from<T>(flow: FlowObservable<NotPromise<T>>): SolidDerivation<NotPromise<T>>;
99
+ /**
100
+ * Converts a FlowObservable into a Solid derivation or resource, depending on whether the value is synchronous or asynchronous.
101
+ *
102
+ * @param flow - The FlowObservable to convert.
103
+ * @returns A SolidDerivation or SolidResource, depending on the input type.
104
+ *
105
+ * @public
106
+ */
107
+ export function from<T>(
108
+ flow: FlowObservable<Promise<NotPromise<T>>> | FlowObservable<NotPromise<T>>,
109
+ ): SolidDerivation<NotPromise<T>> | SolidResource<NotPromise<T>>;
110
+ /**
111
+ * Converts a getter function returning a non-Promise value into a SolidDerivation.
112
+ *
113
+ * @param flow - The getter function to convert.
114
+ * @returns A SolidDerivation wrapping the getter.
115
+ *
116
+ * @public
117
+ */
118
+ export function from<T>(flow: (get: FlowGetter) => NotPromise<T>): SolidDerivation<NotPromise<T>>;
119
+ /**
120
+ * Converts a getter function returning a Promise into a SolidResource.
121
+ *
122
+ * @param flow - The getter function to convert.
123
+ * @returns A SolidResource wrapping the getter.
124
+ *
125
+ * @public
126
+ */
127
+ export function from<T>(flow: (get: FlowGetter) => Promise<NotPromise<T>>): SolidResource<NotPromise<T>>;
128
+ /**
129
+ * Converts a getter function into a Solid derivation or resource, depending on whether the returned value is synchronous or asynchronous.
130
+ *
131
+ * @param flow - The getter function to convert.
132
+ * @returns A SolidDerivation or SolidResource, depending on the input type.
133
+ *
134
+ * @public
135
+ */
136
+ export function from<T>(
137
+ flow: ((get: FlowGetter) => NotPromise<T>) | ((get: FlowGetter) => Promise<NotPromise<T>>),
138
+ ): SolidDerivation<T> | SolidResource<T>;
139
+ /**
140
+ * Converts a FlowObservable or getter function into a Solid derivation or resource, depending on whether the value is synchronous or asynchronous.
141
+ *
142
+ * - If passed a FlowObservable of a non-Promise value, returns a SolidDerivation.
143
+ * - If passed a FlowObservable of a Promise, returns a SolidResource.
144
+ * - If passed a getter function returning a non-Promise value, returns a SolidDerivation.
145
+ * - If passed a getter function returning a Promise, returns a SolidResource.
146
+ *
147
+ * @param flow - The FlowObservable or getter function to convert.
148
+ * @returns A SolidDerivation or SolidResource, depending on the input type.
149
+ * @public
150
+ */
151
+ export function from<T>(
152
+ flow: FlowObservable<Promise<T>> | FlowObservable<T> | ((get: FlowGetter) => T) | ((get: FlowGetter) => Promise<T>),
153
+ ): SolidDerivation<T> | SolidResource<T> {
154
+ if (flow instanceof FlowObservable) {
155
+ return shallowFrom(flow as FlowObservable<T | Promise<T>>) as SolidDerivation<T> | SolidResource<T>;
156
+ }
157
+
158
+ return deepFrom(flow as (get: FlowGetter) => T | Promise<T>) as SolidDerivation<T> | SolidResource<T>;
159
+ }
@@ -0,0 +1,2 @@
1
+ export { from } from './converters';
2
+ export { SolidState, SolidResource, SolidDerivation, type SolidObservable, type SolidGetter } from './primitives';
@@ -0,0 +1,109 @@
1
+ import { createMemo, createResource, createSignal, type ResourceFetcher, } from "solid-js";
2
+
3
+ /**
4
+ * A getter function or value for Solid state/derivation.
5
+ *
6
+ * @typeParam T - The value type.
7
+ * @public
8
+ */
9
+ export type SolidGetter<T> = ((previous: T) => T) | T;
10
+
11
+ /**
12
+ * Interface for a Solid-style observable value.
13
+ *
14
+ * @typeParam T - The value type.
15
+ * @public
16
+ */
17
+ export interface SolidObservable<T> {
18
+ /**
19
+ * Returns the current value.
20
+ */
21
+ get: () => T;
22
+ }
23
+
24
+ /**
25
+ * Solid-style state container, similar to a writable signal.
26
+ *
27
+ * @typeParam T - The value type.
28
+ * @public
29
+ */
30
+ export class SolidState<T> implements SolidObservable<T> {
31
+ /**
32
+ * Returns the current value.
33
+ */
34
+ readonly get: () => T;
35
+ /**
36
+ * Sets the value or updates it using a getter function.
37
+ */
38
+ readonly set: (param: SolidGetter<T>) => void;
39
+
40
+ /**
41
+ * Creates a new SolidState with the given initial value.
42
+ * @param initialValue - The initial value.
43
+ */
44
+ constructor(initialValue: T) {
45
+ const [get, set] = createSignal<T>(initialValue);
46
+ this.get = get;
47
+ this.set = set;
48
+ }
49
+ }
50
+
51
+ type EffectFunction<Prev, Next extends Prev = Prev> = (v: Prev) => Next;
52
+ /**
53
+ * Solid-style derivation, similar to a computed/memoized value.
54
+ *
55
+ * @typeParam T - The value type.
56
+ * @public
57
+ */
58
+ export class SolidDerivation<T> implements SolidObservable<T> {
59
+ /**
60
+ * Returns the current derived value.
61
+ */
62
+ readonly get: () => T;
63
+
64
+ /**
65
+ * Creates a new SolidDerivation from a getter function or value.
66
+ * @param calculator - The getter function or value.
67
+ */
68
+ constructor(calculator: SolidGetter<T>) {
69
+ const get = createMemo<T>(calculator as EffectFunction<T | undefined, T>);
70
+ this.get = get;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Solid-style resource, similar to an async resource or data loader.
76
+ *
77
+ * @typeParam T - The value type.
78
+ * @public
79
+ */
80
+ export class SolidResource<T> implements SolidObservable<T | undefined> {
81
+ /**
82
+ * Returns the current value (or undefined if not yet loaded).
83
+ */
84
+ readonly get: () => T | undefined;
85
+ /**
86
+ * Returns the current resource state.
87
+ */
88
+ readonly state: () => 'unresolved' | 'pending' | 'errored' | 'ready' | 'refreshing';
89
+ /**
90
+ * Returns the latest successfully loaded value (or undefined).
91
+ */
92
+ readonly latest: () => T | undefined;
93
+ /**
94
+ * Triggers a refetch of the resource.
95
+ */
96
+ readonly refetch: () => void;
97
+
98
+ /**
99
+ * Creates a new SolidResource from a fetcher function.
100
+ * @param fetcher - The async fetcher function.
101
+ */
102
+ constructor(fetcher: ResourceFetcher<true, T, unknown>) {
103
+ const [get, set] = createResource<T>(fetcher);
104
+ this.get = get;
105
+ this.state = () => get.state;
106
+ this.latest = () => get.latest;
107
+ this.refetch = () => set.refetch();
108
+ }
109
+ }
@@ -443,4 +443,102 @@ describe("effect", () => {
443
443
  expect(effectFn).toHaveBeenLastCalledWith(4);
444
444
  });
445
445
  });
446
+
447
+ describe("complex test", () => {
448
+ test("test", () => {
449
+ const obj1 = {
450
+ cond: state(false),
451
+ num: state(2),
452
+ dispose: (options: { self: boolean }) => {
453
+ obj1.cond.dispose(options);
454
+ obj1.num.dispose(options);
455
+ }
456
+ }
457
+ const obj2 = {
458
+ cond: state(false),
459
+ num: state(4),
460
+ dispose: (options: { self: boolean }) => {
461
+ obj2.cond.dispose(options);
462
+ obj2.num.dispose(options);
463
+ }
464
+ }
465
+ const $state = state(obj1);
466
+ const $derivationCond = derivation((get) => get(get($state).cond));
467
+ const $derivationNum = derivation((get) => get(get($state).num) * 2);
468
+ const effectCondFn = vi.fn();
469
+ const effectNumFn = vi.fn();
470
+ effect((get) => effectCondFn(get($derivationCond)));
471
+ effect((get) => effectNumFn(get($derivationNum)));
472
+
473
+ expect(effectCondFn).toHaveBeenCalledTimes(1);
474
+ expect(effectCondFn).toHaveBeenLastCalledWith(false);
475
+ expect(effectNumFn).toHaveBeenCalledTimes(1);
476
+ expect(effectNumFn).toHaveBeenLastCalledWith(4);
477
+
478
+ $state.get().num.set(3);
479
+ expect(effectCondFn).toHaveBeenCalledTimes(1);
480
+ expect(effectCondFn).toHaveBeenLastCalledWith(false);
481
+ expect(effectNumFn).toHaveBeenCalledTimes(2);
482
+ expect(effectNumFn).toHaveBeenLastCalledWith(6);
483
+
484
+ $state.get().cond.set(true);
485
+ expect(effectCondFn).toHaveBeenCalledTimes(2);
486
+ expect(effectCondFn).toHaveBeenLastCalledWith(true);
487
+ expect(effectNumFn).toHaveBeenCalledTimes(2);
488
+ expect(effectNumFn).toHaveBeenLastCalledWith(6);
489
+
490
+ $state.set(obj2)
491
+ expect(effectCondFn).toHaveBeenCalledTimes(3);
492
+ expect(effectCondFn).toHaveBeenLastCalledWith(false);
493
+ expect(effectNumFn).toHaveBeenCalledTimes(3);
494
+ expect(effectNumFn).toHaveBeenLastCalledWith(8);
495
+
496
+ $state.get().cond.set(true);
497
+ expect(effectCondFn).toHaveBeenCalledTimes(4); // fails -> called 3 times
498
+ expect(effectCondFn).toHaveBeenLastCalledWith(true);
499
+ expect(effectNumFn).toHaveBeenCalledTimes(3);
500
+ expect(effectNumFn).toHaveBeenLastCalledWith(8);
501
+
502
+ $state.get().num.set(5);
503
+ expect(effectCondFn).toHaveBeenCalledTimes(4);
504
+ expect(effectCondFn).toHaveBeenLastCalledWith(true);
505
+ expect(effectNumFn).toHaveBeenCalledTimes(4);
506
+ expect(effectNumFn).toHaveBeenLastCalledWith(10);
507
+ });
508
+
509
+ test("test", () => {
510
+ const obj = {
511
+ cond: state(false),
512
+ b: state(2)
513
+ }
514
+
515
+ const $state = state(obj);
516
+ const $derivation = derivation((get) => {
517
+ const cond = get(get($state).cond);
518
+ if (cond) {
519
+ return get(get($state).b) * 2;
520
+ }
521
+ return 0;
522
+ });
523
+
524
+
525
+ const effectFn = vi.fn();
526
+ effect((get) => effectFn(get($derivation)));
527
+
528
+ expect(effectFn).toHaveBeenCalledTimes(1);
529
+ expect(effectFn).toHaveBeenLastCalledWith(0);
530
+
531
+ $state.get().cond.set(true);
532
+ expect(effectFn).toHaveBeenCalledTimes(2);
533
+ expect(effectFn).toHaveBeenLastCalledWith(4);
534
+
535
+ $state.set({ cond: state(false), b: state(3) })
536
+ expect(effectFn).toHaveBeenCalledTimes(3);
537
+ expect(effectFn).toHaveBeenLastCalledWith(0);
538
+
539
+ $state.get().cond.set(true);
540
+ expect(effectFn).toHaveBeenCalledTimes(4);
541
+ expect(effectFn).toHaveBeenLastCalledWith(6);
542
+ });
543
+ });
446
544
  });