@derivesome/core 1.0.0

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 (217) hide show
  1. package/.README.md.~undo-tree~ +4 -0
  2. package/.package.json.~undo-tree~ +30 -0
  3. package/.tsconfig.cjs.json.~undo-tree~ +8 -0
  4. package/.tsconfig.json.~undo-tree~ +14 -0
  5. package/README.md +355 -0
  6. package/README.md~ +355 -0
  7. package/dist/cjs/array-proxy.d.ts +56 -0
  8. package/dist/cjs/array-proxy.d.ts.map +1 -0
  9. package/dist/cjs/array-proxy.js +72 -0
  10. package/dist/cjs/array-proxy.js.map +1 -0
  11. package/dist/cjs/common/array.d.ts +11 -0
  12. package/dist/cjs/common/array.d.ts.map +1 -0
  13. package/dist/cjs/common/array.js +57 -0
  14. package/dist/cjs/common/array.js.map +1 -0
  15. package/dist/cjs/common/compare.d.ts +2 -0
  16. package/dist/cjs/common/compare.d.ts.map +1 -0
  17. package/dist/cjs/common/compare.js +8 -0
  18. package/dist/cjs/common/compare.js.map +1 -0
  19. package/dist/cjs/common/diff.d.ts +9 -0
  20. package/dist/cjs/common/diff.d.ts.map +1 -0
  21. package/dist/cjs/common/diff.js +63 -0
  22. package/dist/cjs/common/diff.js.map +1 -0
  23. package/dist/cjs/common/has.d.ts +4 -0
  24. package/dist/cjs/common/has.d.ts.map +1 -0
  25. package/dist/cjs/common/has.js +11 -0
  26. package/dist/cjs/common/has.js.map +1 -0
  27. package/dist/cjs/common/index.d.ts +12 -0
  28. package/dist/cjs/common/index.d.ts.map +1 -0
  29. package/dist/cjs/common/index.js +28 -0
  30. package/dist/cjs/common/index.js.map +1 -0
  31. package/dist/cjs/common/is.d.ts +5 -0
  32. package/dist/cjs/common/is.d.ts.map +1 -0
  33. package/dist/cjs/common/is.js +18 -0
  34. package/dist/cjs/common/is.js.map +1 -0
  35. package/dist/cjs/common/match.d.ts +23 -0
  36. package/dist/cjs/common/match.d.ts.map +1 -0
  37. package/dist/cjs/common/match.js +49 -0
  38. package/dist/cjs/common/match.js.map +1 -0
  39. package/dist/cjs/common/patch.d.ts +3 -0
  40. package/dist/cjs/common/patch.d.ts.map +1 -0
  41. package/dist/cjs/common/patch.js +44 -0
  42. package/dist/cjs/common/patch.js.map +1 -0
  43. package/dist/cjs/common/stack.d.ts +8 -0
  44. package/dist/cjs/common/stack.d.ts.map +1 -0
  45. package/dist/cjs/common/stack.js +24 -0
  46. package/dist/cjs/common/stack.js.map +1 -0
  47. package/dist/cjs/common/string.d.ts +2 -0
  48. package/dist/cjs/common/string.d.ts.map +1 -0
  49. package/dist/cjs/common/string.js +36 -0
  50. package/dist/cjs/common/string.js.map +1 -0
  51. package/dist/cjs/common/types.d.ts +27 -0
  52. package/dist/cjs/common/types.d.ts.map +1 -0
  53. package/dist/cjs/common/types.js +3 -0
  54. package/dist/cjs/common/types.js.map +1 -0
  55. package/dist/cjs/common/unique-array.d.ts +17 -0
  56. package/dist/cjs/common/unique-array.d.ts.map +1 -0
  57. package/dist/cjs/common/unique-array.js +73 -0
  58. package/dist/cjs/common/unique-array.js.map +1 -0
  59. package/dist/cjs/context.d.ts +15 -0
  60. package/dist/cjs/context.d.ts.map +1 -0
  61. package/dist/cjs/context.js +33 -0
  62. package/dist/cjs/context.js.map +1 -0
  63. package/dist/cjs/derived.d.ts +11 -0
  64. package/dist/cjs/derived.d.ts.map +1 -0
  65. package/dist/cjs/derived.js +26 -0
  66. package/dist/cjs/derived.js.map +1 -0
  67. package/dist/cjs/effect.d.ts +7 -0
  68. package/dist/cjs/effect.d.ts.map +1 -0
  69. package/dist/cjs/effect.js +7 -0
  70. package/dist/cjs/effect.js.map +1 -0
  71. package/dist/cjs/index.d.ts +8 -0
  72. package/dist/cjs/index.d.ts.map +1 -0
  73. package/dist/cjs/index.js +24 -0
  74. package/dist/cjs/index.js.map +1 -0
  75. package/dist/cjs/observable.d.ts +12 -0
  76. package/dist/cjs/observable.d.ts.map +1 -0
  77. package/dist/cjs/observable.js +24 -0
  78. package/dist/cjs/observable.js.map +1 -0
  79. package/dist/cjs/pubsub.d.ts +11 -0
  80. package/dist/cjs/pubsub.d.ts.map +1 -0
  81. package/dist/cjs/pubsub.js +50 -0
  82. package/dist/cjs/pubsub.js.map +1 -0
  83. package/dist/cjs/reference.d.ts +15 -0
  84. package/dist/cjs/reference.d.ts.map +1 -0
  85. package/dist/cjs/reference.js +49 -0
  86. package/dist/cjs/reference.js.map +1 -0
  87. package/dist/cjs/utils/findRefs.d.ts +3 -0
  88. package/dist/cjs/utils/findRefs.d.ts.map +1 -0
  89. package/dist/cjs/utils/findRefs.js +23 -0
  90. package/dist/cjs/utils/findRefs.js.map +1 -0
  91. package/dist/cjs/utils/index.d.ts +2 -0
  92. package/dist/cjs/utils/index.d.ts.map +1 -0
  93. package/dist/cjs/utils/index.js +18 -0
  94. package/dist/cjs/utils/index.js.map +1 -0
  95. package/dist/esm/array-proxy.d.ts +56 -0
  96. package/dist/esm/array-proxy.d.ts.map +1 -0
  97. package/dist/esm/array-proxy.js +68 -0
  98. package/dist/esm/array-proxy.js.map +1 -0
  99. package/dist/esm/common/array.d.ts +11 -0
  100. package/dist/esm/common/array.d.ts.map +1 -0
  101. package/dist/esm/common/array.js +48 -0
  102. package/dist/esm/common/array.js.map +1 -0
  103. package/dist/esm/common/compare.d.ts +2 -0
  104. package/dist/esm/common/compare.d.ts.map +1 -0
  105. package/dist/esm/common/compare.js +4 -0
  106. package/dist/esm/common/compare.js.map +1 -0
  107. package/dist/esm/common/diff.d.ts +9 -0
  108. package/dist/esm/common/diff.d.ts.map +1 -0
  109. package/dist/esm/common/diff.js +59 -0
  110. package/dist/esm/common/diff.js.map +1 -0
  111. package/dist/esm/common/has.d.ts +4 -0
  112. package/dist/esm/common/has.d.ts.map +1 -0
  113. package/dist/esm/common/has.js +8 -0
  114. package/dist/esm/common/has.js.map +1 -0
  115. package/dist/esm/common/index.d.ts +12 -0
  116. package/dist/esm/common/index.d.ts.map +1 -0
  117. package/dist/esm/common/index.js +12 -0
  118. package/dist/esm/common/index.js.map +1 -0
  119. package/dist/esm/common/is.d.ts +5 -0
  120. package/dist/esm/common/is.d.ts.map +1 -0
  121. package/dist/esm/common/is.js +13 -0
  122. package/dist/esm/common/is.js.map +1 -0
  123. package/dist/esm/common/match.d.ts +23 -0
  124. package/dist/esm/common/match.d.ts.map +1 -0
  125. package/dist/esm/common/match.js +46 -0
  126. package/dist/esm/common/match.js.map +1 -0
  127. package/dist/esm/common/patch.d.ts +3 -0
  128. package/dist/esm/common/patch.d.ts.map +1 -0
  129. package/dist/esm/common/patch.js +40 -0
  130. package/dist/esm/common/patch.js.map +1 -0
  131. package/dist/esm/common/stack.d.ts +8 -0
  132. package/dist/esm/common/stack.d.ts.map +1 -0
  133. package/dist/esm/common/stack.js +20 -0
  134. package/dist/esm/common/stack.js.map +1 -0
  135. package/dist/esm/common/string.d.ts +2 -0
  136. package/dist/esm/common/string.d.ts.map +1 -0
  137. package/dist/esm/common/string.js +32 -0
  138. package/dist/esm/common/string.js.map +1 -0
  139. package/dist/esm/common/types.d.ts +27 -0
  140. package/dist/esm/common/types.d.ts.map +1 -0
  141. package/dist/esm/common/types.js +2 -0
  142. package/dist/esm/common/types.js.map +1 -0
  143. package/dist/esm/common/unique-array.d.ts +17 -0
  144. package/dist/esm/common/unique-array.d.ts.map +1 -0
  145. package/dist/esm/common/unique-array.js +69 -0
  146. package/dist/esm/common/unique-array.js.map +1 -0
  147. package/dist/esm/context.d.ts +15 -0
  148. package/dist/esm/context.d.ts.map +1 -0
  149. package/dist/esm/context.js +28 -0
  150. package/dist/esm/context.js.map +1 -0
  151. package/dist/esm/derived.d.ts +11 -0
  152. package/dist/esm/derived.d.ts.map +1 -0
  153. package/dist/esm/derived.js +21 -0
  154. package/dist/esm/derived.js.map +1 -0
  155. package/dist/esm/effect.d.ts +7 -0
  156. package/dist/esm/effect.d.ts.map +1 -0
  157. package/dist/esm/effect.js +3 -0
  158. package/dist/esm/effect.js.map +1 -0
  159. package/dist/esm/index.d.ts +8 -0
  160. package/dist/esm/index.d.ts.map +1 -0
  161. package/dist/esm/index.js +8 -0
  162. package/dist/esm/index.js.map +1 -0
  163. package/dist/esm/observable.d.ts +12 -0
  164. package/dist/esm/observable.d.ts.map +1 -0
  165. package/dist/esm/observable.js +19 -0
  166. package/dist/esm/observable.js.map +1 -0
  167. package/dist/esm/package.json +1 -0
  168. package/dist/esm/pubsub.d.ts +11 -0
  169. package/dist/esm/pubsub.d.ts.map +1 -0
  170. package/dist/esm/pubsub.js +47 -0
  171. package/dist/esm/pubsub.js.map +1 -0
  172. package/dist/esm/reference.d.ts +15 -0
  173. package/dist/esm/reference.d.ts.map +1 -0
  174. package/dist/esm/reference.js +44 -0
  175. package/dist/esm/reference.js.map +1 -0
  176. package/dist/esm/utils/findRefs.d.ts +3 -0
  177. package/dist/esm/utils/findRefs.d.ts.map +1 -0
  178. package/dist/esm/utils/findRefs.js +19 -0
  179. package/dist/esm/utils/findRefs.js.map +1 -0
  180. package/dist/esm/utils/index.d.ts +2 -0
  181. package/dist/esm/utils/index.d.ts.map +1 -0
  182. package/dist/esm/utils/index.js +2 -0
  183. package/dist/esm/utils/index.js.map +1 -0
  184. package/package.json +41 -0
  185. package/package.json~ +42 -0
  186. package/src/array-proxy.ts +94 -0
  187. package/src/common/array.ts +72 -0
  188. package/src/common/compare.ts +3 -0
  189. package/src/common/diff.test.ts +114 -0
  190. package/src/common/diff.ts +85 -0
  191. package/src/common/has.ts +7 -0
  192. package/src/common/index.ts +11 -0
  193. package/src/common/is.ts +14 -0
  194. package/src/common/match.ts +90 -0
  195. package/src/common/patch.test.ts +118 -0
  196. package/src/common/patch.ts +47 -0
  197. package/src/common/stack.ts +22 -0
  198. package/src/common/string.test.ts +46 -0
  199. package/src/common/string.ts +35 -0
  200. package/src/common/types.ts +61 -0
  201. package/src/common/unique-array.ts +80 -0
  202. package/src/context.ts +36 -0
  203. package/src/derived.test.ts +45 -0
  204. package/src/derived.ts +35 -0
  205. package/src/effect.ts +9 -0
  206. package/src/index.ts +7 -0
  207. package/src/observable.ts +40 -0
  208. package/src/pubsub.test.ts +29 -0
  209. package/src/pubsub.ts +71 -0
  210. package/src/reference.test.ts +32 -0
  211. package/src/reference.ts +63 -0
  212. package/src/utils/findRefs.ts +22 -0
  213. package/src/utils/index.ts +1 -0
  214. package/tsconfig.cjs.json +8 -0
  215. package/tsconfig.cjs.json~ +0 -0
  216. package/tsconfig.json +24 -0
  217. package/tsconfig.json~ +24 -0
@@ -0,0 +1,40 @@
1
+ import { has } from "./common";
2
+ import {
3
+ Boxed,
4
+ SubscribeOptions,
5
+ Subscription,
6
+ VoidFunction,
7
+ } from "./common/types";
8
+ import { PubSub } from "./pubsub";
9
+
10
+ export const OBSERVABLE = Symbol("Observable");
11
+ export type OBSERVABLE = typeof OBSERVABLE;
12
+
13
+ export interface Observable<T> extends PubSub<T> {
14
+ [OBSERVABLE]: true;
15
+ observe: (fn: Subscription<T>, options?: SubscribeOptions) => VoidFunction;
16
+ }
17
+
18
+ export function observable<T>(state: Boxed<T>, ps: PubSub<T>): Observable<T> {
19
+ const observe = (
20
+ fn: Subscription<T>,
21
+ options: SubscribeOptions = {},
22
+ ): VoidFunction => {
23
+ if (options.immediate) {
24
+ fn(state.value);
25
+ }
26
+ return ps.subscribe(fn, options.cleanup);
27
+ };
28
+
29
+ return {
30
+ [OBSERVABLE]: true,
31
+ ...ps,
32
+ observe,
33
+ };
34
+ }
35
+
36
+ export function isObservable<X extends Observable<unknown>>(x: X): x is X;
37
+ export function isObservable(x: unknown): x is Observable<unknown>;
38
+ export function isObservable(x: unknown): x is Observable<unknown> {
39
+ return has(x, OBSERVABLE);
40
+ }
@@ -0,0 +1,29 @@
1
+ import { describe, assert } from "vitest";
2
+ import { pubsub } from "./pubsub";
3
+
4
+ describe("pubsub", (it) => {
5
+ it("notifies subscribers", () => {
6
+ const ps = pubsub<number>();
7
+
8
+ let last: number = -1;
9
+
10
+ const unsub = ps.subscribe((value) => {
11
+ last = value;
12
+ });
13
+ assert.strictEqual(last, -1);
14
+
15
+ ps.publish(1);
16
+ assert.strictEqual(last, 1);
17
+
18
+ ps.publish(2);
19
+ assert.strictEqual(last, 2);
20
+
21
+ ps.publish(3);
22
+ assert.strictEqual(last, 3);
23
+
24
+ unsub();
25
+
26
+ ps.publish(4);
27
+ assert.strictEqual(last, 3);
28
+ });
29
+ });
package/src/pubsub.ts ADDED
@@ -0,0 +1,71 @@
1
+ import { Subscription, VoidFunction } from "./common/types";
2
+ import { Context } from "./context";
3
+
4
+ export interface PubSub<T> {
5
+ subscribers: Set<Subscription<T>>;
6
+ effects: Set<VoidFunction>;
7
+ publish: (value: T) => void;
8
+ subscribe: (fn: Subscription<T>, cleanup?: VoidFunction) => VoidFunction;
9
+ addEffect: (effect: VoidFunction, cleanup?: VoidFunction) => VoidFunction;
10
+ dispose: () => void;
11
+ }
12
+
13
+ export function pubsub<T>(): PubSub<T> {
14
+ const subscribers = new Set<Subscription<T>>();
15
+ const effects = new Set<VoidFunction>();
16
+ const trash = new Set<VoidFunction>();
17
+
18
+ const addTrash = (fn: VoidFunction): VoidFunction => {
19
+ trash.add(fn);
20
+ return fn;
21
+ };
22
+
23
+ const publish = (value: T): void => {
24
+ effects.forEach((fx) => {
25
+ Context.runEffect(fx);
26
+ });
27
+ subscribers.forEach((sub) => {
28
+ sub(value);
29
+ });
30
+ };
31
+
32
+ const addEffect = (
33
+ effect: VoidFunction,
34
+ cleanup?: VoidFunction,
35
+ ): VoidFunction => {
36
+ effects.add(effect);
37
+
38
+ return addTrash(() => {
39
+ effects.delete(effect);
40
+ cleanup?.();
41
+ });
42
+ };
43
+
44
+ const subscribe = (
45
+ fn: Subscription<T>,
46
+ cleanup?: VoidFunction,
47
+ ): VoidFunction => {
48
+ subscribers.add(fn);
49
+
50
+ return addTrash(() => {
51
+ subscribers.delete(fn);
52
+ cleanup?.();
53
+ });
54
+ };
55
+
56
+ const dispose = (): void => {
57
+ trash.forEach((fn) => fn());
58
+ trash.clear();
59
+ subscribers.clear();
60
+ effects.clear();
61
+ };
62
+
63
+ return {
64
+ subscribers,
65
+ effects,
66
+ publish,
67
+ subscribe,
68
+ addEffect,
69
+ dispose,
70
+ };
71
+ }
@@ -0,0 +1,32 @@
1
+ import { describe, assert } from "vitest";
2
+ import { ref } from "./reference";
3
+ import { Context } from "./context";
4
+
5
+ describe("reference", (it) => {
6
+ it("notifies subscribers through context", () => {
7
+ const r = ref<number>(0);
8
+
9
+ let last: number = -1;
10
+
11
+ Context.runEffect(() => {
12
+ const next = r.get();
13
+ last = next;
14
+ });
15
+
16
+ assert.strictEqual(last, 0);
17
+
18
+ r.set(1);
19
+ assert.strictEqual(last, 1);
20
+
21
+ r.set(2);
22
+ assert.strictEqual(last, 2);
23
+
24
+ r.set(3);
25
+ assert.strictEqual(last, 3);
26
+
27
+ r.dispose();
28
+
29
+ r.set(4);
30
+ assert.strictEqual(last, 3);
31
+ });
32
+ });
@@ -0,0 +1,63 @@
1
+ import { has } from "./common";
2
+ import { compare } from "./common/compare";
3
+ import { isFunction } from "./common/is";
4
+ import { Boxed, Dispatch, Loose, SetStateAction } from "./common/types";
5
+ import { Context } from "./context";
6
+ import { Effect } from "./effect";
7
+ import { observable, Observable } from "./observable";
8
+ import { pubsub } from "./pubsub";
9
+
10
+ export const REFERENCE = Symbol("Reference");
11
+ export type REFERENCE = typeof REFERENCE;
12
+
13
+ export interface Reference<T> extends Observable<T> {
14
+ [REFERENCE]: true;
15
+ get: () => T;
16
+ set: Dispatch<SetStateAction<T>>;
17
+ peek: () => T;
18
+ }
19
+
20
+ export function ref<T>(value: T): Reference<T> {
21
+ const ps = pubsub<T>();
22
+ const state: Boxed<T> = { value };
23
+ const obs = observable<T>(state, ps);
24
+
25
+ const addEffectDependency = (fx: Effect) => {
26
+ ps.addEffect(fx.run, fx.cleanup);
27
+ };
28
+
29
+ const get = (): T => {
30
+ const fx = Context.scope.current.effect;
31
+ if (fx) addEffectDependency(fx);
32
+ return state.value;
33
+ };
34
+
35
+ const set: Dispatch<SetStateAction<T>> = (fn) => {
36
+ const prev = state.value;
37
+ const next = isFunction(fn) ? fn(state.value) : fn;
38
+ if (!compare(next, prev)) {
39
+ state.value = next;
40
+ ps.publish(state.value);
41
+ }
42
+ };
43
+
44
+ const peek = (): T => {
45
+ return state.value;
46
+ };
47
+
48
+ return {
49
+ [REFERENCE]: true,
50
+ ...ps,
51
+ ...obs,
52
+ get,
53
+ set,
54
+ peek,
55
+ };
56
+ }
57
+
58
+ export function isReference(x: Loose): x is Reference<Loose>;
59
+ export function isReference(x: unknown): x is Reference<unknown>;
60
+ export function isReference<X extends Reference<unknown>>(x: X): x is X;
61
+ export function isReference(x: unknown): x is Reference<unknown> {
62
+ return has(x, REFERENCE);
63
+ }
@@ -0,0 +1,22 @@
1
+ import { isReference, Reference } from "../reference";
2
+
3
+ export const findRefs = (x: unknown): Reference<unknown>[] => {
4
+
5
+ if (typeof x === 'undefined' || x === null) return [];
6
+ if (isReference(x)) return [x];
7
+
8
+
9
+ if (Array.isArray(x)) {
10
+ return x.map(it => findRefs(it)).flat();
11
+ }
12
+
13
+ if (typeof x === 'object' && x !== null) {
14
+ const refs: Array<Reference<unknown>> = [];
15
+ for (const [_k, v] of Object.entries(x)) {
16
+ refs.push(...findRefs(v));
17
+ }
18
+ return refs;
19
+ }
20
+
21
+ return [];
22
+ }
@@ -0,0 +1 @@
1
+ export * from './findRefs';
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "moduleResolution": "node10",
6
+ "outDir": "./dist/cjs"
7
+ }
8
+ }
File without changes
package/tsconfig.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir": "./src",
4
+ "outDir": "./dist/esm",
5
+ "module": "esnext",
6
+ "moduleResolution": "bundler",
7
+ "target": "esnext",
8
+ "lib": ["esnext"],
9
+ "types": ["node"],
10
+ "sourceMap": true,
11
+ "declaration": true,
12
+ "declarationMap": true,
13
+ "noUncheckedIndexedAccess": true,
14
+ "exactOptionalPropertyTypes": true,
15
+ "strict": true,
16
+ "isolatedModules": true,
17
+ "esModuleInterop": true,
18
+ "noUncheckedSideEffectImports": true,
19
+ "moduleDetection": "force",
20
+ "skipLibCheck": true
21
+ },
22
+ "include": ["./src/**/*.ts"],
23
+ "exclude": ["./src/**/*.test.ts"]
24
+ }
package/tsconfig.json~ ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir": "./src",
4
+ "outDir": "./dist/esm",
5
+ "module": "nodenext",
6
+ "moduleResolution": "bundler",
7
+ "target": "esnext",
8
+ "lib": ["esnext"],
9
+ "types": ["node"],
10
+ "sourceMap": true,
11
+ "declaration": true,
12
+ "declarationMap": true,
13
+ "noUncheckedIndexedAccess": true,
14
+ "exactOptionalPropertyTypes": true,
15
+ "strict": true,
16
+ "isolatedModules": true,
17
+ "esModuleInterop": true,
18
+ "noUncheckedSideEffectImports": true,
19
+ "moduleDetection": "force",
20
+ "skipLibCheck": true
21
+ },
22
+ "include": ["./src/**/*.ts"],
23
+ "exclude": ["./src/**/*.test.ts"]
24
+ }