@derivesome/core 1.0.0 → 1.0.2

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 (131) hide show
  1. package/.package.json.~undo-tree~ +9 -2
  2. package/dist/cjs/array-proxy.d.ts.map +1 -1
  3. package/dist/cjs/array-proxy.js +7 -1
  4. package/dist/cjs/array-proxy.js.map +1 -1
  5. package/dist/cjs/common/array.d.ts.map +1 -1
  6. package/dist/cjs/common/array.js.map +1 -1
  7. package/dist/cjs/common/diff.d.ts +1 -1
  8. package/dist/cjs/common/diff.js +5 -5
  9. package/dist/cjs/common/diff.js.map +1 -1
  10. package/dist/cjs/common/has.d.ts +2 -2
  11. package/dist/cjs/common/has.d.ts.map +1 -1
  12. package/dist/cjs/common/has.js +2 -2
  13. package/dist/cjs/common/has.js.map +1 -1
  14. package/dist/cjs/common/index.d.ts +11 -11
  15. package/dist/cjs/common/match.d.ts +3 -10
  16. package/dist/cjs/common/match.d.ts.map +1 -1
  17. package/dist/cjs/common/match.js +29 -29
  18. package/dist/cjs/common/match.js.map +1 -1
  19. package/dist/cjs/common/patch.d.ts +1 -1
  20. package/dist/cjs/common/patch.js +5 -5
  21. package/dist/cjs/common/types.d.ts +3 -5
  22. package/dist/cjs/common/types.d.ts.map +1 -1
  23. package/dist/cjs/common/unique-array.js +1 -1
  24. package/dist/cjs/common/unique-array.js.map +1 -1
  25. package/dist/cjs/context.d.ts +2 -1
  26. package/dist/cjs/context.d.ts.map +1 -1
  27. package/dist/cjs/context.js +14 -0
  28. package/dist/cjs/context.js.map +1 -1
  29. package/dist/cjs/derived.d.ts.map +1 -1
  30. package/dist/cjs/derived.js +1 -1
  31. package/dist/cjs/effect.d.ts +2 -2
  32. package/dist/cjs/effect.d.ts.map +1 -1
  33. package/dist/cjs/index.d.ts +7 -7
  34. package/dist/cjs/pubsub.d.ts +3 -2
  35. package/dist/cjs/pubsub.d.ts.map +1 -1
  36. package/dist/cjs/pubsub.js +9 -0
  37. package/dist/cjs/pubsub.js.map +1 -1
  38. package/dist/cjs/utils/findRefs.d.ts.map +1 -1
  39. package/dist/cjs/utils/findRefs.js +3 -3
  40. package/dist/cjs/utils/findRefs.js.map +1 -1
  41. package/dist/cjs/utils/index.d.ts +2 -1
  42. package/dist/cjs/utils/index.d.ts.map +1 -1
  43. package/dist/cjs/utils/index.js +1 -0
  44. package/dist/cjs/utils/index.js.map +1 -1
  45. package/dist/cjs/utils/nextTick.d.ts +2 -0
  46. package/dist/cjs/utils/nextTick.d.ts.map +1 -0
  47. package/dist/cjs/utils/nextTick.js +13 -0
  48. package/dist/cjs/utils/nextTick.js.map +1 -0
  49. package/dist/esm/array-proxy.d.ts.map +1 -1
  50. package/dist/esm/array-proxy.js +7 -1
  51. package/dist/esm/array-proxy.js.map +1 -1
  52. package/dist/esm/common/array.d.ts.map +1 -1
  53. package/dist/esm/common/array.js.map +1 -1
  54. package/dist/esm/common/diff.d.ts +1 -1
  55. package/dist/esm/common/diff.js +6 -6
  56. package/dist/esm/common/diff.js.map +1 -1
  57. package/dist/esm/common/has.d.ts +2 -2
  58. package/dist/esm/common/has.d.ts.map +1 -1
  59. package/dist/esm/common/has.js +2 -2
  60. package/dist/esm/common/has.js.map +1 -1
  61. package/dist/esm/common/index.d.ts +11 -11
  62. package/dist/esm/common/index.js +11 -11
  63. package/dist/esm/common/match.d.ts +3 -10
  64. package/dist/esm/common/match.d.ts.map +1 -1
  65. package/dist/esm/common/match.js +29 -29
  66. package/dist/esm/common/match.js.map +1 -1
  67. package/dist/esm/common/patch.d.ts +1 -1
  68. package/dist/esm/common/patch.js +5 -5
  69. package/dist/esm/common/types.d.ts +3 -5
  70. package/dist/esm/common/types.d.ts.map +1 -1
  71. package/dist/esm/common/unique-array.js +1 -1
  72. package/dist/esm/common/unique-array.js.map +1 -1
  73. package/dist/esm/context.d.ts +2 -1
  74. package/dist/esm/context.d.ts.map +1 -1
  75. package/dist/esm/context.js +14 -0
  76. package/dist/esm/context.js.map +1 -1
  77. package/dist/esm/derived.d.ts.map +1 -1
  78. package/dist/esm/derived.js +1 -1
  79. package/dist/esm/effect.d.ts +2 -2
  80. package/dist/esm/effect.d.ts.map +1 -1
  81. package/dist/esm/index.d.ts +7 -7
  82. package/dist/esm/index.js +7 -7
  83. package/dist/esm/pubsub.d.ts +3 -2
  84. package/dist/esm/pubsub.d.ts.map +1 -1
  85. package/dist/esm/pubsub.js +9 -0
  86. package/dist/esm/pubsub.js.map +1 -1
  87. package/dist/esm/utils/findRefs.d.ts.map +1 -1
  88. package/dist/esm/utils/findRefs.js +3 -3
  89. package/dist/esm/utils/findRefs.js.map +1 -1
  90. package/dist/esm/utils/index.d.ts +2 -1
  91. package/dist/esm/utils/index.d.ts.map +1 -1
  92. package/dist/esm/utils/index.js +2 -1
  93. package/dist/esm/utils/index.js.map +1 -1
  94. package/dist/esm/utils/nextTick.d.ts +2 -0
  95. package/dist/esm/utils/nextTick.d.ts.map +1 -0
  96. package/dist/esm/utils/nextTick.js +9 -0
  97. package/dist/esm/utils/nextTick.js.map +1 -0
  98. package/package.json +13 -11
  99. package/package.json~ +2 -2
  100. package/src/.context.ts.~undo-tree~ +12 -0
  101. package/src/.effect.ts.~undo-tree~ +8 -0
  102. package/src/.pubsub.ts.~undo-tree~ +33 -0
  103. package/src/array-proxy.ts +18 -3
  104. package/src/common/.types.ts.~undo-tree~ +5 -0
  105. package/src/common/array.ts +6 -5
  106. package/src/common/diff.test.ts +40 -43
  107. package/src/common/diff.ts +13 -8
  108. package/src/common/has.ts +15 -5
  109. package/src/common/index.ts +11 -11
  110. package/src/common/match.ts +58 -47
  111. package/src/common/patch.test.ts +26 -24
  112. package/src/common/patch.ts +6 -6
  113. package/src/common/string.test.ts +13 -13
  114. package/src/common/types.ts +32 -34
  115. package/src/common/types.ts~ +61 -0
  116. package/src/common/unique-array.ts +1 -1
  117. package/src/context.ts +18 -2
  118. package/src/context.ts~ +36 -0
  119. package/src/derived.ts +2 -2
  120. package/src/effect.ts +2 -2
  121. package/src/effect.ts~ +9 -0
  122. package/src/index.ts +7 -7
  123. package/src/pubsub.ts +20 -5
  124. package/src/pubsub.ts~ +82 -0
  125. package/src/utils/.index.ts.~undo-tree~ +7 -0
  126. package/src/utils/.nextTick.ts.~undo-tree~ +6 -0
  127. package/src/utils/findRefs.ts +5 -7
  128. package/src/utils/index.ts +2 -1
  129. package/src/utils/index.ts~ +2 -0
  130. package/src/utils/nextTick.ts +7 -0
  131. package/src/utils/nextTick.ts~ +7 -0
@@ -1,6 +1,6 @@
1
- import { isPlainObject } from './is';
1
+ import { isPlainObject } from "./is";
2
2
 
3
- export type DiffType = 'added' | 'removed' | 'changed';
3
+ export type DiffType = "added" | "removed" | "changed";
4
4
 
5
5
  export type Diff = {
6
6
  type: DiffType;
@@ -15,7 +15,12 @@ export const diff = <T>(a: T, b: T): Diff[] => {
15
15
  return diffs;
16
16
  };
17
17
 
18
- const diffRecursive = (a: unknown, b: unknown, path: PropertyKey[], diffs: Diff[]): void => {
18
+ const diffRecursive = (
19
+ a: unknown,
20
+ b: unknown,
21
+ path: PropertyKey[],
22
+ diffs: Diff[],
23
+ ): void => {
19
24
  if (a === b) return;
20
25
 
21
26
  const aIsArray = Array.isArray(a);
@@ -34,7 +39,7 @@ const diffRecursive = (a: unknown, b: unknown, path: PropertyKey[], diffs: Diff[
34
39
  return;
35
40
  }
36
41
 
37
- diffs.push({ type: 'changed', path, oldValue: a, newValue: b });
42
+ diffs.push({ type: "changed", path, oldValue: a, newValue: b });
38
43
  };
39
44
 
40
45
  const diffObjects = (
@@ -50,7 +55,7 @@ const diffObjects = (
50
55
  for (const key of aKeys) {
51
56
  const childPath = [...path, key];
52
57
  if (!bKeySet.has(key)) {
53
- diffs.push({ type: 'removed', path: childPath, oldValue: a[key] });
58
+ diffs.push({ type: "removed", path: childPath, oldValue: a[key] });
54
59
  } else {
55
60
  diffRecursive(a[key], b[key], childPath, diffs);
56
61
  }
@@ -59,7 +64,7 @@ const diffObjects = (
59
64
  const aKeySet = new Set(aKeys);
60
65
  for (const key of bKeys) {
61
66
  if (!aKeySet.has(key)) {
62
- diffs.push({ type: 'added', path: [...path, key], newValue: b[key] });
67
+ diffs.push({ type: "added", path: [...path, key], newValue: b[key] });
63
68
  }
64
69
  }
65
70
  };
@@ -75,9 +80,9 @@ const diffArrays = (
75
80
  for (let i = 0; i < maxLen; i++) {
76
81
  const childPath = [...path, i];
77
82
  if (i >= a.length) {
78
- diffs.push({ type: 'added', path: childPath, newValue: b[i] });
83
+ diffs.push({ type: "added", path: childPath, newValue: b[i] });
79
84
  } else if (i >= b.length) {
80
- diffs.push({ type: 'removed', path: childPath, oldValue: a[i] });
85
+ diffs.push({ type: "removed", path: childPath, oldValue: a[i] });
81
86
  } else {
82
87
  diffRecursive(a[i], b[i], childPath, diffs);
83
88
  }
package/src/common/has.ts CHANGED
@@ -1,7 +1,17 @@
1
- export function has<Keys extends [...PropertyKey[]]>(x: unknown, ...keys: Keys): x is ({
2
- [Prop in keyof Keys as [Keys[Prop]] extends [string] ? Keys[Prop] : never]: unknown
3
- }) {
4
- if (typeof x === 'undefined' || x === null) return false;
5
- if (keys.every(key => Object.hasOwn(x, key) || (typeof x === 'object' && (key in x)))) return true;
1
+ export function has<Keys extends [...PropertyKey[]]>(
2
+ x: unknown,
3
+ ...keys: Keys
4
+ ): x is {
5
+ [Prop in keyof Keys as [Keys[Prop]] extends [string]
6
+ ? Keys[Prop]
7
+ : never]: unknown;
8
+ } {
9
+ if (typeof x === "undefined" || x === null) return false;
10
+ if (
11
+ keys.every(
12
+ (key) => Object.hasOwn(x, key) || (typeof x === "object" && key in x),
13
+ )
14
+ )
15
+ return true;
6
16
  return false;
7
17
  }
@@ -1,11 +1,11 @@
1
- export * from './types';
2
- export * from './is';
3
- export * from './stack';
4
- export * from './compare';
5
- export * from './unique-array';
6
- export * from './has';
7
- export * from './array';
8
- export * from './diff';
9
- export * from './patch';
10
- export * from './match';
11
- export * from './string';
1
+ export * from "./types";
2
+ export * from "./is";
3
+ export * from "./stack";
4
+ export * from "./compare";
5
+ export * from "./unique-array";
6
+ export * from "./has";
7
+ export * from "./array";
8
+ export * from "./diff";
9
+ export * from "./patch";
10
+ export * from "./match";
11
+ export * from "./string";
@@ -4,43 +4,51 @@ import { IsLiteral } from "./types";
4
4
  export type ToPattern<
5
5
  T,
6
6
  U extends Exclude<T, undefined> = Exclude<T, undefined>,
7
- > =
8
- [IsLiteral<T>] extends [true] ? U
9
- : [U] extends [string] ? string
10
- : [U] extends [number] ? number
11
- : [U] extends [boolean] ? boolean
12
- : [U] extends [BigInt] ? BigInt
13
- : [U] extends [null] ? null
14
- : [U] extends [Array<infer A>] ? Array<ToPattern<A>>
15
- : [U] extends [Record<PropertyKey, unknown>] ?
16
- {
17
- [P in keyof U]?: ToPattern<U[P]>;
18
- }
19
- : T;
7
+ > = [IsLiteral<T>] extends [true]
8
+ ? U
9
+ : [U] extends [string]
10
+ ? string
11
+ : [U] extends [number]
12
+ ? number
13
+ : [U] extends [boolean]
14
+ ? boolean
15
+ : [U] extends [BigInt]
16
+ ? BigInt
17
+ : [U] extends [null]
18
+ ? null
19
+ : [U] extends [Array<infer A>]
20
+ ? Array<ToPattern<A>>
21
+ : [U] extends [Record<PropertyKey, unknown>]
22
+ ? {
23
+ [P in keyof U]?: ToPattern<U[P]>;
24
+ }
25
+ : T;
20
26
 
21
- export type Unpattern<I, P> =
22
- [IsLiteral<I>, IsLiteral<P>] extends [true, true] ?
23
- [I] extends [P] ?
24
- P
27
+ export type Unpattern<I, P> = [IsLiteral<I>, IsLiteral<P>] extends [true, true]
28
+ ? [I] extends [P]
29
+ ? P
25
30
  : never
26
- : [I, P] extends [string, string] ? P
27
- : [I, P] extends [number, number] ? P
28
- : [I, P] extends [boolean, boolean] ? P
29
- : [I, P] extends [BigInt, BigInt] ? P
30
- : [I, P] extends [Array<infer AI>, Array<infer AP>] ? Array<Unpattern<AI, AP>>
31
- : [[I], [P]] extends (
32
- [
33
- [infer AI extends Record<PropertyKey, unknown>],
34
- [infer AP extends Record<PropertyKey, unknown>],
35
- ]
36
- ) ?
37
- Extract<
38
- AI,
39
- {
40
- [KP in keyof AP]: AP[KP];
41
- }
42
- >
43
- : "ERROR";
31
+ : [I, P] extends [string, string]
32
+ ? P
33
+ : [I, P] extends [number, number]
34
+ ? P
35
+ : [I, P] extends [boolean, boolean]
36
+ ? P
37
+ : [I, P] extends [BigInt, BigInt]
38
+ ? P
39
+ : [I, P] extends [Array<infer AI>, Array<infer AP>]
40
+ ? Array<Unpattern<AI, AP>>
41
+ : [[I], [P]] extends [
42
+ [infer AI extends Record<PropertyKey, unknown>],
43
+ [infer AP extends Record<PropertyKey, unknown>],
44
+ ]
45
+ ? Extract<
46
+ AI,
47
+ {
48
+ [KP in keyof AP]: AP[KP];
49
+ }
50
+ >
51
+ : "ERROR";
44
52
 
45
53
  export function match<Input, const Pattern extends ToPattern<Input>>(
46
54
  input: Input | Unpattern<Input, Pattern>,
@@ -54,14 +62,18 @@ export function match<Input, const Pattern extends ToPattern<Input>>(
54
62
  }
55
63
 
56
64
  switch (typeof pattern) {
57
- case 'string':
58
- case 'boolean':
59
- case 'undefined':
60
- case 'function':
61
- case 'symbol':
62
- case 'number': return input === pattern;
63
- case 'bigint': return (typeof input === 'bigint') && input.toString() === pattern.toString();
64
- case 'object': {
65
+ case "string":
66
+ case "boolean":
67
+ case "undefined":
68
+ case "function":
69
+ case "symbol":
70
+ case "number":
71
+ return input === pattern;
72
+ case "bigint":
73
+ return (
74
+ typeof input === "bigint" && input.toString() === pattern.toString()
75
+ );
76
+ case "object": {
65
77
  if (isPlainObject(input) && isPlainObject(pattern)) {
66
78
  for (const [k, pv] of Object.entries(pattern)) {
67
79
  const iv = input[k];
@@ -76,15 +88,14 @@ export function match<Input, const Pattern extends ToPattern<Input>>(
76
88
  const pv = pattern[symbol];
77
89
  if (!match(iv, pv)) return false;
78
90
  }
79
-
91
+
80
92
  return true;
81
93
  } else {
82
94
  console.error(`Tried to match`, input, pattern);
83
95
  throw new Error(`Cannot match`);
84
96
  }
85
- };
97
+ }
86
98
  }
87
-
88
-
99
+
89
100
  return false;
90
101
  }
@@ -1,15 +1,15 @@
1
- import { describe, it, assert } from 'vitest';
2
- import { diff } from './diff';
3
- import { patch } from './patch';
1
+ import { describe, it, assert } from "vitest";
2
+ import { diff } from "./diff";
3
+ import { patch } from "./patch";
4
4
 
5
- describe('patch', () => {
6
- it('should patch a changed primitive at root', () => {
5
+ describe("patch", () => {
6
+ it("should patch a changed primitive at root", () => {
7
7
  const diffs = diff(1, 2);
8
8
  const result = patch(1, diffs);
9
9
  assert.equal(result, 2);
10
10
  });
11
11
 
12
- it('should patch changed object properties in-place', () => {
12
+ it("should patch changed object properties in-place", () => {
13
13
  const target = { a: 1, b: 2 };
14
14
  const ref = target;
15
15
  const diffs = diff(target, { a: 1, b: 99 });
@@ -18,7 +18,7 @@ describe('patch', () => {
18
18
  assert.deepEqual(result, { a: 1, b: 99 });
19
19
  });
20
20
 
21
- it('should add new properties in-place', () => {
21
+ it("should add new properties in-place", () => {
22
22
  const target: Record<string, number> = { a: 1 };
23
23
  const ref = target;
24
24
  const diffs = diff(target, { a: 1, b: 2 });
@@ -27,17 +27,17 @@ describe('patch', () => {
27
27
  assert.deepEqual(result, { a: 1, b: 2 });
28
28
  });
29
29
 
30
- it('should remove properties in-place', () => {
30
+ it("should remove properties in-place", () => {
31
31
  const target: Record<string, number> = { a: 1, b: 2 };
32
32
  const ref = target;
33
33
  const diffs = diff(target, { a: 1 });
34
34
  const result = patch(target, diffs);
35
35
  assert.strictEqual(result, ref);
36
36
  assert.deepEqual(result, { a: 1 });
37
- assert.isFalse('b' in result);
37
+ assert.isFalse("b" in result);
38
38
  });
39
39
 
40
- it('should patch nested objects in-place', () => {
40
+ it("should patch nested objects in-place", () => {
41
41
  const target = { x: { y: { z: 1 } } };
42
42
  const innerRef = target.x.y;
43
43
  const diffs = diff(target, { x: { y: { z: 42 } } });
@@ -46,7 +46,7 @@ describe('patch', () => {
46
46
  assert.deepEqual(result, { x: { y: { z: 42 } } });
47
47
  });
48
48
 
49
- it('should patch array elements in-place', () => {
49
+ it("should patch array elements in-place", () => {
50
50
  const target = [1, 2, 3];
51
51
  const ref = target;
52
52
  const diffs = diff(target, [1, 99, 3]);
@@ -55,7 +55,7 @@ describe('patch', () => {
55
55
  assert.deepEqual(result, [1, 99, 3]);
56
56
  });
57
57
 
58
- it('should add array elements in-place', () => {
58
+ it("should add array elements in-place", () => {
59
59
  const target = [1, 2];
60
60
  const ref = target;
61
61
  const diffs = diff(target, [1, 2, 3]);
@@ -64,7 +64,7 @@ describe('patch', () => {
64
64
  assert.deepEqual(result, [1, 2, 3]);
65
65
  });
66
66
 
67
- it('should remove array elements in-place', () => {
67
+ it("should remove array elements in-place", () => {
68
68
  const target = [1, 2, 3];
69
69
  const ref = target;
70
70
  const diffs = diff(target, [1, 2]);
@@ -73,7 +73,7 @@ describe('patch', () => {
73
73
  assert.deepEqual(result, [1, 2]);
74
74
  });
75
75
 
76
- it('should patch nested arrays inside objects in-place', () => {
76
+ it("should patch nested arrays inside objects in-place", () => {
77
77
  const target = { items: [10, 20, 30] };
78
78
  const arrRef = target.items;
79
79
  const diffs = diff(target, { items: [10, 25, 30] });
@@ -82,24 +82,26 @@ describe('patch', () => {
82
82
  assert.deepEqual(result, { items: [10, 25, 30] });
83
83
  });
84
84
 
85
- it('should patch deeply nested mixed structures in-place', () => {
86
- const target = { users: [{ name: 'Alice', scores: [10, 20] }] };
85
+ it("should patch deeply nested mixed structures in-place", () => {
86
+ const target = { users: [{ name: "Alice", scores: [10, 20] }] };
87
87
  const scoresRef = target.users[0]!.scores;
88
- const diffs = diff(target, { users: [{ name: 'Alice', scores: [10, 30] }] });
88
+ const diffs = diff(target, {
89
+ users: [{ name: "Alice", scores: [10, 30] }],
90
+ });
89
91
  const result = patch(target, diffs);
90
92
  assert.strictEqual(result.users[0]!.scores, scoresRef);
91
- assert.deepEqual(result, { users: [{ name: 'Alice', scores: [10, 30] }] });
93
+ assert.deepEqual(result, { users: [{ name: "Alice", scores: [10, 30] }] });
92
94
  });
93
95
 
94
- it('should handle type change from object to primitive', () => {
96
+ it("should handle type change from object to primitive", () => {
95
97
  const target: any = { a: { b: 1 } };
96
98
  const diffs = diff(target, { a: 42 } as any);
97
99
  const result = patch(target, diffs);
98
100
  assert.deepEqual(result, { a: 42 });
99
101
  });
100
102
 
101
- it('should handle symbol keys', () => {
102
- const sym = Symbol('test');
103
+ it("should handle symbol keys", () => {
104
+ const sym = Symbol("test");
103
105
  const target = { [sym]: 1 };
104
106
  const ref = target;
105
107
  const diffs = diff(target, { [sym]: 2 });
@@ -108,9 +110,9 @@ describe('patch', () => {
108
110
  assert.equal(result[sym], 2);
109
111
  });
110
112
 
111
- it('should produce the same result as b when diffing a->b and patching a', () => {
112
- const a = { x: 1, y: [1, 2, 3], z: { nested: true, value: 'hello' } };
113
- const b = { x: 2, y: [1, 3], z: { nested: false, extra: 'world' } };
113
+ it("should produce the same result as b when diffing a->b and patching a", () => {
114
+ const a = { x: 1, y: [1, 2, 3], z: { nested: true, value: "hello" } };
115
+ const b = { x: 2, y: [1, 3], z: { nested: false, extra: "world" } };
114
116
  const diffs = diff(a, b as any);
115
117
  const result = patch(a, diffs);
116
118
  assert.deepEqual(result, b as unknown);
@@ -1,4 +1,4 @@
1
- import type { Diff } from './diff';
1
+ import type { Diff } from "./diff";
2
2
 
3
3
  export const patch = <T>(target: T, diffs: Diff[]): T => {
4
4
  for (const d of diffs) {
@@ -9,7 +9,7 @@ export const patch = <T>(target: T, diffs: Diff[]): T => {
9
9
 
10
10
  const applyDiff = <T>(target: T, d: Diff, depth: number): T => {
11
11
  if (depth === d.path.length) {
12
- if (d.type === 'changed' || d.type === 'added') {
12
+ if (d.type === "changed" || d.type === "added") {
13
13
  return d.newValue as T;
14
14
  }
15
15
  return undefined as T;
@@ -20,9 +20,9 @@ const applyDiff = <T>(target: T, d: Diff, depth: number): T => {
20
20
  if (Array.isArray(target)) {
21
21
  const index = key as number;
22
22
 
23
- if (d.type === 'removed' && depth === d.path.length - 1) {
23
+ if (d.type === "removed" && depth === d.path.length - 1) {
24
24
  target.splice(index, 1);
25
- } else if (d.type === 'added' && depth === d.path.length - 1) {
25
+ } else if (d.type === "added" && depth === d.path.length - 1) {
26
26
  target.splice(index, 0, d.newValue);
27
27
  } else {
28
28
  target[index] = applyDiff(target[index], d, depth + 1);
@@ -31,10 +31,10 @@ const applyDiff = <T>(target: T, d: Diff, depth: number): T => {
31
31
  return target;
32
32
  }
33
33
 
34
- if (typeof target === 'object' && target !== null) {
34
+ if (typeof target === "object" && target !== null) {
35
35
  const obj = target as Record<PropertyKey, unknown>;
36
36
 
37
- if (d.type === 'removed' && depth === d.path.length - 1) {
37
+ if (d.type === "removed" && depth === d.path.length - 1) {
38
38
  delete obj[key];
39
39
  } else {
40
40
  obj[key] = applyDiff(obj[key], d, depth + 1);
@@ -1,14 +1,14 @@
1
- import { describe, assert } from 'vitest';
2
- import { unjoin } from './string';
1
+ import { describe, assert } from "vitest";
2
+ import { unjoin } from "./string";
3
3
 
4
4
  describe("unjoin", (it) => {
5
5
  it("unjoins a '/' joined string", () => {
6
- const path: string = 'foo/bar/baz';
7
- const parts = unjoin(path, '/');
6
+ const path: string = "foo/bar/baz";
7
+ const parts = unjoin(path, "/");
8
8
 
9
9
  console.log(parts);
10
10
 
11
- const expected: string[] = ['foo', '/', 'bar', '/', 'baz'];
11
+ const expected: string[] = ["foo", "/", "bar", "/", "baz"];
12
12
  assert.strictEqual(parts.length, expected.length);
13
13
 
14
14
  for (let i = 0; i < expected.length; i++) {
@@ -17,12 +17,12 @@ describe("unjoin", (it) => {
17
17
  });
18
18
 
19
19
  it("unjoins a '/' joined string starting with '/'", () => {
20
- const path: string = '/foo/bar/baz';
21
- const parts = unjoin(path, '/');
20
+ const path: string = "/foo/bar/baz";
21
+ const parts = unjoin(path, "/");
22
22
 
23
23
  console.log(parts);
24
24
 
25
- const expected: string[] = ['/', 'foo', '/', 'bar', '/', 'baz'];
25
+ const expected: string[] = ["/", "foo", "/", "bar", "/", "baz"];
26
26
  assert.strictEqual(parts.length, expected.length);
27
27
 
28
28
  for (let i = 0; i < expected.length; i++) {
@@ -31,16 +31,16 @@ describe("unjoin", (it) => {
31
31
  });
32
32
 
33
33
  it("unjoins a non-joined string", () => {
34
- const path: string = 'foobar';
35
- const parts = unjoin(path, '/');
34
+ const path: string = "foobar";
35
+ const parts = unjoin(path, "/");
36
36
 
37
37
  console.log(parts);
38
38
 
39
- const expected: string[] = ['foobar'];
39
+ const expected: string[] = ["foobar"];
40
40
  assert.strictEqual(parts.length, expected.length);
41
41
 
42
42
  for (let i = 0; i < expected.length; i++) {
43
43
  assert.strictEqual(parts[i], expected[i]);
44
44
  }
45
- })
46
- })
45
+ });
46
+ });
@@ -1,6 +1,6 @@
1
1
  export type Loose = any;
2
2
  export type Boxed<T> = { value: T };
3
- export type Subscription<T> = (value: T) => void;
3
+ export type Subscription<T> = (value: T) => void | Promise<void>;
4
4
  export type SubscriptionCaller<T> = (fn: Subscription<T>, value: T) => void;
5
5
  export type ReturningFunction<T> = () => T;
6
6
  export type VoidFunction = () => void;
@@ -15,15 +15,14 @@ export type LooseDict = Record<string, Loose>;
15
15
  export type SubscribeOptions = {
16
16
  cleanup?: VoidFunction;
17
17
  immediate?: boolean;
18
- }
18
+ };
19
19
 
20
20
  export type Distribute<T> = T extends T ? T : never;
21
21
 
22
- export type UnionToIntersection<union> =
23
- (union extends Loose ? (k: union) => void : never) extends (
24
- (k: infer intersection) => void
25
- ) ?
26
- intersection
22
+ export type UnionToIntersection<union> = (
23
+ union extends Loose ? (k: union) => void : never
24
+ ) extends (k: infer intersection) => void
25
+ ? intersection
27
26
  : never;
28
27
 
29
28
  export type IsUnion<a> = [a] extends [UnionToIntersection<a>] ? false : true;
@@ -31,31 +30,30 @@ export type IsUnion<a> = [a] extends [UnionToIntersection<a>] ? false : true;
31
30
  export type UnionToTuple<union, output extends Loose[] = []> =
32
31
  UnionToIntersection<
33
32
  union extends Loose ? (t: union) => union : never
34
- > extends (_: Loose) => infer elem ?
35
- UnionToTuple<Exclude<union, elem>, [elem, ...output]>
36
- : output;
33
+ > extends (_: Loose) => infer elem
34
+ ? UnionToTuple<Exclude<union, elem>, [elem, ...output]>
35
+ : output;
37
36
 
38
-
39
- export type IsLiteral<a> =
40
- [a] extends [null | undefined] ? true
41
- : [a] extends [string] ?
42
- string extends a ?
43
- false
44
- : true
45
- : [a] extends [number] ?
46
- number extends a ?
47
- false
48
- : true
49
- : [a] extends [boolean] ?
50
- boolean extends a ?
51
- false
52
- : true
53
- : [a] extends [symbol] ?
54
- symbol extends a ?
55
- false
56
- : true
57
- : [a] extends [bigint] ?
58
- bigint extends a ?
59
- false
60
- : true
61
- : false;
37
+ export type IsLiteral<a> = [a] extends [null | undefined]
38
+ ? true
39
+ : [a] extends [string]
40
+ ? string extends a
41
+ ? false
42
+ : true
43
+ : [a] extends [number]
44
+ ? number extends a
45
+ ? false
46
+ : true
47
+ : [a] extends [boolean]
48
+ ? boolean extends a
49
+ ? false
50
+ : true
51
+ : [a] extends [symbol]
52
+ ? symbol extends a
53
+ ? false
54
+ : true
55
+ : [a] extends [bigint]
56
+ ? bigint extends a
57
+ ? false
58
+ : true
59
+ : false;
@@ -0,0 +1,61 @@
1
+ export type Loose = any;
2
+ export type Boxed<T> = { value: T };
3
+ export type Subscription<T> = (value: T) => void;
4
+ export type SubscriptionCaller<T> = (fn: Subscription<T>, value: T) => void;
5
+ export type ReturningFunction<T> = () => T;
6
+ export type VoidFunction = () => void;
7
+ export type VoidAsyncFunction = () => void;
8
+ export type VoidSyncOrAsyncFunction = () => void | Promise<void>;
9
+ export type LooseFunction = (...args: Loose[]) => Loose;
10
+ export type SetStateAction<S> = S | ((prevState: S) => S);
11
+ export type Dispatch<A> = (value: A) => void;
12
+ export type UnknownDict = Record<string, unknown>;
13
+ export type LooseDict = Record<string, Loose>;
14
+
15
+ export type SubscribeOptions = {
16
+ cleanup?: VoidFunction;
17
+ immediate?: boolean;
18
+ }
19
+
20
+ export type Distribute<T> = T extends T ? T : never;
21
+
22
+ export type UnionToIntersection<union> =
23
+ (union extends Loose ? (k: union) => void : never) extends (
24
+ (k: infer intersection) => void
25
+ ) ?
26
+ intersection
27
+ : never;
28
+
29
+ export type IsUnion<a> = [a] extends [UnionToIntersection<a>] ? false : true;
30
+
31
+ export type UnionToTuple<union, output extends Loose[] = []> =
32
+ UnionToIntersection<
33
+ union extends Loose ? (t: union) => union : never
34
+ > extends (_: Loose) => infer elem ?
35
+ UnionToTuple<Exclude<union, elem>, [elem, ...output]>
36
+ : output;
37
+
38
+
39
+ export type IsLiteral<a> =
40
+ [a] extends [null | undefined] ? true
41
+ : [a] extends [string] ?
42
+ string extends a ?
43
+ false
44
+ : true
45
+ : [a] extends [number] ?
46
+ number extends a ?
47
+ false
48
+ : true
49
+ : [a] extends [boolean] ?
50
+ boolean extends a ?
51
+ false
52
+ : true
53
+ : [a] extends [symbol] ?
54
+ symbol extends a ?
55
+ false
56
+ : true
57
+ : [a] extends [bigint] ?
58
+ bigint extends a ?
59
+ false
60
+ : true
61
+ : false;
@@ -71,7 +71,7 @@ export class UniqueArray<T> {
71
71
  if (offset < 0 || offset >= this.length) {
72
72
  return this.push(...values);
73
73
  }
74
- const items = Array.from(new Set(values.filter(x => !this.includes(x))));
74
+ const items = Array.from(new Set(values.filter((x) => !this.includes(x))));
75
75
  const left = this.items.slice(0, offset);
76
76
  const right = this.items.slice(offset);
77
77
  this.clear();
package/src/context.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { isFunction } from "./common/is";
2
2
  import { Stack } from "./common/stack";
3
- import { VoidFunction } from "./common/types";
3
+ import { VoidFunction, VoidSyncOrAsyncFunction } from "./common/types";
4
4
  import { Effect } from "./effect";
5
5
 
6
6
  export type ScopeData = {
@@ -20,7 +20,23 @@ export class Context {
20
20
  return this.scopes.current;
21
21
  }
22
22
 
23
- static runEffect(effect: VoidFunction | Effect) {
23
+ static async runEffectAsync(
24
+ effect: VoidSyncOrAsyncFunction | Effect,
25
+ ): Promise<void> {
26
+ if (isFunction(effect)) {
27
+ const prev = this.scope.current.effect;
28
+ this.scope.current.effect = { run: effect };
29
+ await effect();
30
+ this.scope.current.effect = prev;
31
+ } else {
32
+ const prev = this.scope.current.effect;
33
+ this.scope.current.effect = effect;
34
+ await effect.run();
35
+ this.scope.current.effect = prev;
36
+ }
37
+ }
38
+
39
+ static runEffect(effect: VoidFunction | Effect): void {
24
40
  if (isFunction(effect)) {
25
41
  const prev = this.scope.current.effect;
26
42
  this.scope.current.effect = { run: effect };