@voidhash/mimic 1.0.0-beta.16 → 1.0.0-beta.17

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 (95) hide show
  1. package/dist/EffectSchema.cjs +3 -3
  2. package/dist/EffectSchema.d.cts +5 -5
  3. package/dist/EffectSchema.d.cts.map +1 -1
  4. package/dist/EffectSchema.d.mts +5 -5
  5. package/dist/EffectSchema.d.mts.map +1 -1
  6. package/dist/EffectSchema.mjs +3 -3
  7. package/dist/EffectSchema.mjs.map +1 -1
  8. package/dist/FractionalIndex.mjs.map +1 -1
  9. package/dist/Operation.d.cts +4 -4
  10. package/dist/Operation.d.cts.map +1 -1
  11. package/dist/Operation.d.mts +4 -4
  12. package/dist/Operation.d.mts.map +1 -1
  13. package/dist/Operation.mjs.map +1 -1
  14. package/dist/OperationDefinition.d.cts +2 -2
  15. package/dist/OperationDefinition.d.cts.map +1 -1
  16. package/dist/OperationDefinition.d.mts +2 -2
  17. package/dist/OperationDefinition.d.mts.map +1 -1
  18. package/dist/OperationDefinition.mjs.map +1 -1
  19. package/dist/Presence.mjs.map +1 -1
  20. package/dist/SchemaJSON.cjs +305 -0
  21. package/dist/SchemaJSON.d.cts +11 -0
  22. package/dist/SchemaJSON.d.cts.map +1 -0
  23. package/dist/SchemaJSON.d.mts +11 -0
  24. package/dist/SchemaJSON.d.mts.map +1 -0
  25. package/dist/SchemaJSON.mjs +301 -0
  26. package/dist/SchemaJSON.mjs.map +1 -0
  27. package/dist/index.cjs +7 -0
  28. package/dist/index.d.cts +2 -1
  29. package/dist/index.d.mts +2 -1
  30. package/dist/index.mjs +2 -1
  31. package/dist/primitives/Array.cjs +12 -2
  32. package/dist/primitives/Array.d.cts.map +1 -1
  33. package/dist/primitives/Array.d.mts.map +1 -1
  34. package/dist/primitives/Array.mjs +12 -2
  35. package/dist/primitives/Array.mjs.map +1 -1
  36. package/dist/primitives/Boolean.mjs.map +1 -1
  37. package/dist/primitives/Either.mjs.map +1 -1
  38. package/dist/primitives/Literal.mjs.map +1 -1
  39. package/dist/primitives/Number.cjs +27 -5
  40. package/dist/primitives/Number.d.cts.map +1 -1
  41. package/dist/primitives/Number.d.mts.map +1 -1
  42. package/dist/primitives/Number.mjs +27 -5
  43. package/dist/primitives/Number.mjs.map +1 -1
  44. package/dist/primitives/String.cjs +44 -13
  45. package/dist/primitives/String.d.cts.map +1 -1
  46. package/dist/primitives/String.d.mts.map +1 -1
  47. package/dist/primitives/String.mjs +44 -13
  48. package/dist/primitives/String.mjs.map +1 -1
  49. package/dist/primitives/Union.mjs.map +1 -1
  50. package/dist/primitives/shared.d.cts +2 -0
  51. package/dist/primitives/shared.d.cts.map +1 -1
  52. package/dist/primitives/shared.d.mts +2 -0
  53. package/dist/primitives/shared.d.mts.map +1 -1
  54. package/dist/primitives/shared.mjs.map +1 -1
  55. package/package.json +15 -8
  56. package/src/EffectSchema.ts +3 -3
  57. package/src/FractionalIndex.ts +18 -18
  58. package/src/Operation.ts +5 -5
  59. package/src/OperationDefinition.ts +2 -2
  60. package/src/Presence.ts +3 -3
  61. package/src/SchemaJSON.ts +396 -0
  62. package/src/index.ts +1 -0
  63. package/src/primitives/Array.ts +18 -8
  64. package/src/primitives/Boolean.ts +2 -2
  65. package/src/primitives/Either.ts +2 -2
  66. package/src/primitives/Literal.ts +2 -2
  67. package/src/primitives/Number.ts +44 -22
  68. package/src/primitives/String.ts +61 -34
  69. package/src/primitives/Union.ts +1 -1
  70. package/src/primitives/shared.ts +2 -0
  71. package/.turbo/turbo-build.log +0 -270
  72. package/tests/Document.test.ts +0 -557
  73. package/tests/EffectSchema.test.ts +0 -546
  74. package/tests/FractionalIndex.test.ts +0 -377
  75. package/tests/OperationPath.test.ts +0 -151
  76. package/tests/Presence.test.ts +0 -321
  77. package/tests/Primitive.test.ts +0 -381
  78. package/tests/client/ClientDocument.test.ts +0 -1981
  79. package/tests/client/WebSocketTransport.test.ts +0 -1217
  80. package/tests/primitives/Array.test.ts +0 -526
  81. package/tests/primitives/Boolean.test.ts +0 -126
  82. package/tests/primitives/Either.test.ts +0 -707
  83. package/tests/primitives/Lazy.test.ts +0 -143
  84. package/tests/primitives/Literal.test.ts +0 -122
  85. package/tests/primitives/Number.test.ts +0 -133
  86. package/tests/primitives/String.test.ts +0 -128
  87. package/tests/primitives/Struct.test.ts +0 -1154
  88. package/tests/primitives/Tree.test.ts +0 -1139
  89. package/tests/primitives/TreeNode.test.ts +0 -50
  90. package/tests/primitives/Union.test.ts +0 -554
  91. package/tests/server/ServerDocument.test.ts +0 -903
  92. package/tsconfig.build.json +0 -24
  93. package/tsconfig.json +0 -8
  94. package/tsdown.config.ts +0 -18
  95. package/vitest.mts +0 -11
@@ -1,526 +0,0 @@
1
- import { describe, expect, it } from "@effect/vitest";
2
- import * as Primitive from "../../src/Primitive";
3
- import * as ProxyEnvironment from "../../src/ProxyEnvironment";
4
- import * as OperationPath from "../../src/OperationPath";
5
- import * as Operation from "../../src/Operation";
6
-
7
- describe("ArrayPrimitive", () => {
8
- // Helper to create a mock environment with state access
9
- const createEnvWithState = (
10
- state: Primitive.ArrayEntry<any>[] = []
11
- ): { env: ReturnType<typeof ProxyEnvironment.make>; operations: Operation.Operation<any, any, any>[] } => {
12
- const operations: Operation.Operation<any, any, any>[] = [];
13
- let currentState = [...state];
14
-
15
- const env = ProxyEnvironment.make({
16
- onOperation: (op) => {
17
- operations.push(op);
18
- // Apply operation to keep state in sync for subsequent operations
19
- if (op.kind === "array.insert") {
20
- currentState.push(op.payload);
21
- } else if (op.kind === "array.remove") {
22
- currentState = currentState.filter(e => e.id !== op.payload.id);
23
- } else if (op.kind === "array.move") {
24
- currentState = currentState.map(e =>
25
- e.id === op.payload.id ? { ...e, pos: op.payload.pos } : e
26
- );
27
- } else if (op.kind === "array.set") {
28
- currentState = op.payload;
29
- }
30
- },
31
- getState: () => currentState,
32
- generateId: () => crypto.randomUUID(),
33
- });
34
-
35
- return { env, operations };
36
- };
37
-
38
- describe("proxy", () => {
39
- it("set() generates array.set operation with entries", () => {
40
- const { env, operations } = createEnvWithState();
41
- const arrayPrimitive = Primitive.Array(Primitive.String());
42
- const proxy = arrayPrimitive._internal.createProxy(env, OperationPath.make(""));
43
-
44
- proxy.set(["a", "b", "c"]);
45
-
46
- expect(operations).toHaveLength(1);
47
- expect(operations[0]!.kind).toBe("array.set");
48
-
49
- const entries = operations[0]!.payload as Primitive.ArrayEntry<string>[];
50
- expect(entries).toHaveLength(3);
51
- expect(entries[0]!.value).toBe("a");
52
- expect(entries[1]!.value).toBe("b");
53
- expect(entries[2]!.value).toBe("c");
54
-
55
- // Each entry should have an ID and position
56
- entries.forEach((entry: Primitive.ArrayEntry<string>) => {
57
- expect(typeof entry.id).toBe("string");
58
- expect(typeof entry.pos).toBe("string");
59
- });
60
-
61
- // Positions should be in order
62
- expect(entries[0]!.pos < entries[1]!.pos).toBe(true);
63
- expect(entries[1]!.pos < entries[2]!.pos).toBe(true);
64
- });
65
-
66
- it("push() generates array.insert operation with ID and position", () => {
67
- const { env, operations } = createEnvWithState();
68
- const arrayPrimitive = Primitive.Array(Primitive.String());
69
- const proxy = arrayPrimitive._internal.createProxy(env, OperationPath.make(""));
70
-
71
- proxy.push("newItem");
72
-
73
- expect(operations).toHaveLength(1);
74
- expect(operations[0]!.kind).toBe("array.insert");
75
-
76
- const payload = operations[0]!.payload as { id: string; pos: string; value: string };
77
- expect(payload.value).toBe("newItem");
78
- expect(typeof payload.id).toBe("string");
79
- expect(typeof payload.pos).toBe("string");
80
- });
81
-
82
- it("push() generates position after last element", () => {
83
- const existingEntry = { id: "existing-id", pos: "a0", value: "existing" };
84
- const { env, operations } = createEnvWithState([existingEntry]);
85
- const arrayPrimitive = Primitive.Array(Primitive.String());
86
- const proxy = arrayPrimitive._internal.createProxy(env, OperationPath.make(""));
87
-
88
- proxy.push("newItem");
89
-
90
- const payload = operations[0]!.payload as { id: string; pos: string; value: string };
91
- expect(payload.pos > existingEntry.pos).toBe(true);
92
- });
93
-
94
- it("insertAt() generates array.insert with position between neighbors", () => {
95
- const entries = [
96
- { id: "id1", pos: "a0", value: "first" },
97
- { id: "id2", pos: "a2", value: "third" },
98
- ];
99
- const { env, operations } = createEnvWithState(entries);
100
- const arrayPrimitive = Primitive.Array(Primitive.String());
101
- const proxy = arrayPrimitive._internal.createProxy(env, OperationPath.make(""));
102
-
103
- proxy.insertAt(1, "second");
104
-
105
- expect(operations).toHaveLength(1);
106
- expect(operations[0]!.kind).toBe("array.insert");
107
-
108
- const payload = operations[0]!.payload as { id: string; pos: string; value: string };
109
- expect(payload.value).toBe("second");
110
- // Position should be between a0 and a2
111
- expect(payload.pos > "a0").toBe(true);
112
- expect(payload.pos < "a2").toBe(true);
113
- });
114
-
115
- it("insertAt(0) generates position before first element", () => {
116
- const entries = [{ id: "id1", pos: "a0", value: "existing" }];
117
- const { env, operations } = createEnvWithState(entries);
118
- const arrayPrimitive = Primitive.Array(Primitive.String());
119
- const proxy = arrayPrimitive._internal.createProxy(env, OperationPath.make(""));
120
-
121
- proxy.insertAt(0, "first");
122
-
123
- const payload = operations[0]!.payload as { id: string; pos: string; value: string };
124
- expect(payload.pos < "a0").toBe(true);
125
- });
126
-
127
- it("remove() generates array.remove operation with ID", () => {
128
- const { env, operations } = createEnvWithState();
129
- const arrayPrimitive = Primitive.Array(Primitive.String());
130
- const proxy = arrayPrimitive._internal.createProxy(env, OperationPath.make(""));
131
-
132
- proxy.remove("some-id");
133
-
134
- expect(operations).toHaveLength(1);
135
- expect(operations[0]!.kind).toBe("array.remove");
136
- expect(operations[0]!.payload).toEqual({ id: "some-id" });
137
- });
138
-
139
- it("move() generates array.move operation with new position", () => {
140
- const entries = [
141
- { id: "id1", pos: "a0", value: "first" },
142
- { id: "id2", pos: "a1", value: "second" },
143
- { id: "id3", pos: "a2", value: "third" },
144
- ];
145
- const { env, operations } = createEnvWithState(entries);
146
- const arrayPrimitive = Primitive.Array(Primitive.String());
147
- const proxy = arrayPrimitive._internal.createProxy(env, OperationPath.make(""));
148
-
149
- // Move first element to end
150
- proxy.move("id1", 3);
151
-
152
- expect(operations).toHaveLength(1);
153
- expect(operations[0]!.kind).toBe("array.move");
154
-
155
- const payload = operations[0]!.payload as { id: string; pos: string };
156
- expect(payload.id).toBe("id1");
157
- // New position should be after a2
158
- expect(payload.pos > "a2").toBe(true);
159
- });
160
-
161
- it("at() returns element proxy with ID in path", () => {
162
- const { env, operations } = createEnvWithState();
163
- const arrayPrimitive = Primitive.Array(Primitive.String());
164
- const proxy = arrayPrimitive._internal.createProxy(env, OperationPath.make("items"));
165
-
166
- const elementProxy = proxy.at("some-uuid");
167
- elementProxy.set("element value");
168
-
169
- expect(operations).toHaveLength(1);
170
- expect(operations[0]!.kind).toBe("string.set");
171
- expect(operations[0]!.path.toTokens()).toEqual(["items", "some-uuid"]);
172
- });
173
-
174
- it("at() with nested struct returns nested proxy", () => {
175
- const { env, operations } = createEnvWithState();
176
- const arrayPrimitive = Primitive.Array(
177
- Primitive.Struct({
178
- name: Primitive.String(),
179
- age: Primitive.Number(),
180
- })
181
- );
182
- const proxy = arrayPrimitive._internal.createProxy(env, OperationPath.make("users"));
183
-
184
- proxy.at("user-id-123").name.set("John");
185
-
186
- expect(operations).toHaveLength(1);
187
- expect(operations[0]!.kind).toBe("string.set");
188
- expect(operations[0]!.path.toTokens()).toEqual(["users", "user-id-123", "name"]);
189
- });
190
-
191
- it("find() returns proxy for matching element", () => {
192
- const entries = [
193
- { id: "id1", pos: "a0", value: "alice" },
194
- { id: "id2", pos: "a1", value: "bob" },
195
- ];
196
- const { env, operations } = createEnvWithState(entries);
197
- const arrayPrimitive = Primitive.Array(Primitive.String());
198
- const proxy = arrayPrimitive._internal.createProxy(env, OperationPath.make(""));
199
-
200
- const found = proxy.find((value) => value === "bob");
201
- expect(found).toBeDefined();
202
-
203
- found!.set("robert");
204
-
205
- expect(operations[0]!.path.toTokens()).toEqual(["id2"]);
206
- });
207
- });
208
-
209
- describe("applyOperation", () => {
210
- it("array.set replaces entire array with entries", () => {
211
- const arrayPrimitive = Primitive.Array(Primitive.String());
212
- const newEntries: Primitive.ArrayEntry<string>[] = [
213
- { id: "id1", pos: "a0", value: "x" },
214
- { id: "id2", pos: "a1", value: "y" },
215
- ];
216
- const operation: Operation.Operation<any, any, any> = {
217
- kind: "array.set",
218
- path: OperationPath.make(""),
219
- payload: newEntries,
220
- };
221
-
222
- const result = arrayPrimitive._internal.applyOperation([], operation);
223
- expect(result).toEqual(newEntries);
224
- });
225
-
226
- it("array.insert adds new entry to array", () => {
227
- const arrayPrimitive = Primitive.Array(Primitive.String());
228
- const existingEntries: Primitive.ArrayEntry<string>[] = [
229
- { id: "id1", pos: "a0", value: "existing" },
230
- ];
231
- const operation: Operation.Operation<any, any, any> = {
232
- kind: "array.insert",
233
- path: OperationPath.make(""),
234
- payload: { id: "id2", pos: "a1", value: "new" },
235
- };
236
-
237
- const result = arrayPrimitive._internal.applyOperation(existingEntries, operation);
238
- expect(result).toHaveLength(2);
239
- expect(result[1]).toEqual({ id: "id2", pos: "a1", value: "new" });
240
- });
241
-
242
- it("array.insert works with undefined state", () => {
243
- const arrayPrimitive = Primitive.Array(Primitive.String());
244
- const operation: Operation.Operation<any, any, any> = {
245
- kind: "array.insert",
246
- path: OperationPath.make(""),
247
- payload: { id: "id1", pos: "a0", value: "first" },
248
- };
249
-
250
- const result = arrayPrimitive._internal.applyOperation(undefined, operation);
251
- expect(result).toHaveLength(1);
252
- expect(result[0]).toEqual({ id: "id1", pos: "a0", value: "first" });
253
- });
254
-
255
- it("array.remove removes entry by ID", () => {
256
- const arrayPrimitive = Primitive.Array(Primitive.String());
257
- const entries: Primitive.ArrayEntry<string>[] = [
258
- { id: "id1", pos: "a0", value: "a" },
259
- { id: "id2", pos: "a1", value: "b" },
260
- { id: "id3", pos: "a2", value: "c" },
261
- ];
262
- const operation: Operation.Operation<any, any, any> = {
263
- kind: "array.remove",
264
- path: OperationPath.make(""),
265
- payload: { id: "id2" },
266
- };
267
-
268
- const result = arrayPrimitive._internal.applyOperation(entries, operation);
269
- expect(result).toHaveLength(2);
270
- expect(result.map(e => e.id)).toEqual(["id1", "id3"]);
271
- });
272
-
273
- it("array.move updates entry position", () => {
274
- const arrayPrimitive = Primitive.Array(Primitive.String());
275
- const entries: Primitive.ArrayEntry<string>[] = [
276
- { id: "id1", pos: "a0", value: "first" },
277
- { id: "id2", pos: "a1", value: "second" },
278
- ];
279
- const operation: Operation.Operation<any, any, any> = {
280
- kind: "array.move",
281
- path: OperationPath.make(""),
282
- payload: { id: "id1", pos: "a2" },
283
- };
284
-
285
- const result = arrayPrimitive._internal.applyOperation(entries, operation);
286
- const movedEntry = result.find(e => e.id === "id1");
287
- expect(movedEntry!.pos).toBe("a2");
288
- expect(movedEntry!.value).toBe("first");
289
- });
290
-
291
- it("delegates element operations by ID", () => {
292
- const arrayPrimitive = Primitive.Array(Primitive.String());
293
- const entries: Primitive.ArrayEntry<string>[] = [
294
- { id: "id1", pos: "a0", value: "a" },
295
- { id: "id2", pos: "a1", value: "b" },
296
- ];
297
- const operation: Operation.Operation<any, any, any> = {
298
- kind: "string.set",
299
- path: OperationPath.make("id2"),
300
- payload: "updated",
301
- };
302
-
303
- const result = arrayPrimitive._internal.applyOperation(entries, operation);
304
- expect(result[1]!.value).toBe("updated");
305
- expect(result[1]!.id).toBe("id2");
306
- expect(result[1]!.pos).toBe("a1");
307
- });
308
-
309
- it("delegates nested struct operations by ID", () => {
310
- const arrayPrimitive = Primitive.Array(
311
- Primitive.Struct({
312
- name: Primitive.String(),
313
- })
314
- );
315
- const entries: Primitive.ArrayEntry<{ name: string }>[] = [
316
- { id: "user-1", pos: "a0", value: { name: "Original" } },
317
- ];
318
- const operation: Operation.Operation<any, any, any> = {
319
- kind: "string.set",
320
- path: OperationPath.make("user-1/name"),
321
- payload: "Updated Name",
322
- };
323
-
324
- const result = arrayPrimitive._internal.applyOperation(entries, operation);
325
- expect(result[0]!.value.name).toBe("Updated Name");
326
- });
327
-
328
- it("throws ValidationError for non-array payload on set", () => {
329
- const arrayPrimitive = Primitive.Array(Primitive.String());
330
- const operation: Operation.Operation<any, any, any> = {
331
- kind: "array.set",
332
- path: OperationPath.make(""),
333
- payload: "not an array",
334
- };
335
-
336
- expect(() => arrayPrimitive._internal.applyOperation(undefined, operation)).toThrow(
337
- Primitive.ValidationError
338
- );
339
- });
340
-
341
- it("throws ValidationError for unknown element ID", () => {
342
- const arrayPrimitive = Primitive.Array(Primitive.String());
343
- const entries: Primitive.ArrayEntry<string>[] = [
344
- { id: "id1", pos: "a0", value: "a" },
345
- ];
346
- const operation: Operation.Operation<any, any, any> = {
347
- kind: "string.set",
348
- path: OperationPath.make("unknown-id"),
349
- payload: "value",
350
- };
351
-
352
- expect(() => arrayPrimitive._internal.applyOperation(entries, operation)).toThrow(
353
- Primitive.ValidationError
354
- );
355
- });
356
- });
357
-
358
- describe("getInitialState", () => {
359
- it("returns undefined when no default is set", () => {
360
- const arrayPrimitive = Primitive.Array(Primitive.String());
361
- expect(arrayPrimitive._internal.getInitialState()).toBeUndefined();
362
- });
363
-
364
- it("returns the default value when set", () => {
365
- const defaultEntries: Primitive.ArrayEntry<string>[] = [
366
- { id: "id1", pos: "a0", value: "a" },
367
- { id: "id2", pos: "a1", value: "b" },
368
- ];
369
- const arrayPrimitive = Primitive.Array(Primitive.String()).default(defaultEntries);
370
- expect(arrayPrimitive._internal.getInitialState()).toEqual(defaultEntries);
371
- });
372
- });
373
-
374
- describe("fractional index ordering", () => {
375
- it("entries are sorted by position when accessed", () => {
376
- const arrayPrimitive = Primitive.Array(Primitive.String());
377
- // Entries stored out of order
378
- const entries: Primitive.ArrayEntry<string>[] = [
379
- { id: "id3", pos: "a2", value: "third" },
380
- { id: "id1", pos: "a0", value: "first" },
381
- { id: "id2", pos: "a1", value: "second" },
382
- ];
383
-
384
- // Apply a move operation - it should work regardless of storage order
385
- const operation: Operation.Operation<any, any, any> = {
386
- kind: "array.move",
387
- path: OperationPath.make(""),
388
- payload: { id: "id1", pos: "a3" },
389
- };
390
-
391
- const result = arrayPrimitive._internal.applyOperation(entries, operation);
392
- const movedEntry = result.find(e => e.id === "id1");
393
- expect(movedEntry!.pos).toBe("a3");
394
- });
395
-
396
- it("multiple inserts generate valid ordering", () => {
397
- const { env, operations } = createEnvWithState();
398
- const arrayPrimitive = Primitive.Array(Primitive.String());
399
- const proxy = arrayPrimitive._internal.createProxy(env, OperationPath.make(""));
400
-
401
- // Push multiple items
402
- proxy.push("first");
403
- proxy.push("second");
404
- proxy.push("third");
405
-
406
- expect(operations).toHaveLength(3);
407
-
408
- const positions = operations.map(op => (op.payload as { pos: string }).pos);
409
- // All positions should be different and in order
410
- expect(positions[0]! < positions[1]!).toBe(true);
411
- expect(positions[1]! < positions[2]!).toBe(true);
412
- });
413
- });
414
- describe("struct elements with defaults", () => {
415
- // Define a struct element with required and optional fields
416
- const TaskStruct = Primitive.Struct({
417
- title: Primitive.String().required(), // Must provide
418
- priority: Primitive.Number().default(0), // Has default, optional
419
- completed: Primitive.Boolean().default(false), // Has default, optional
420
- });
421
-
422
- const taskArray = Primitive.Array(TaskStruct);
423
-
424
- // Helper to create environment for task array
425
- const createTaskEnv = (
426
- state: Primitive.ArrayEntry<{ title: string; priority: number; completed: boolean }>[] = []
427
- ): { env: ReturnType<typeof ProxyEnvironment.make>; operations: Operation.Operation<any, any, any>[] } => {
428
- const operations: Operation.Operation<any, any, any>[] = [];
429
- let currentState = [...state];
430
- let idCounter = 0;
431
-
432
- const env = ProxyEnvironment.make({
433
- onOperation: (op) => {
434
- operations.push(op);
435
- if (op.kind === "array.insert") {
436
- currentState.push(op.payload);
437
- } else if (op.kind === "array.set") {
438
- currentState = op.payload;
439
- }
440
- },
441
- getState: () => currentState,
442
- generateId: () => `task-${++idCounter}`,
443
- });
444
-
445
- return { env, operations };
446
- };
447
-
448
- it("push() only requires fields without defaults", () => {
449
- const { env, operations } = createTaskEnv();
450
- const proxy = taskArray._internal.createProxy(env, OperationPath.make(""));
451
-
452
- // Only provide required 'title', priority and completed should use defaults
453
- proxy.push({ title: "New Task" });
454
-
455
- expect(operations).toHaveLength(1);
456
- expect(operations[0]!.kind).toBe("array.insert");
457
-
458
- const payload = operations[0]!.payload as { value: { title: string; priority: number; completed: boolean } };
459
- expect(payload.value.title).toBe("New Task");
460
- expect(payload.value.priority).toBe(0); // Default value
461
- expect(payload.value.completed).toBe(false); // Default value
462
- });
463
-
464
- it("push() allows overriding defaults", () => {
465
- const { env, operations } = createTaskEnv();
466
- const proxy = taskArray._internal.createProxy(env, OperationPath.make(""));
467
-
468
- // Provide title and override priority, let completed use default
469
- proxy.push({ title: "Important Task", priority: 10 });
470
-
471
- const payload = operations[0]!.payload as { value: { title: string; priority: number; completed: boolean } };
472
- expect(payload.value.title).toBe("Important Task");
473
- expect(payload.value.priority).toBe(10); // Overridden
474
- expect(payload.value.completed).toBe(false); // Default value
475
- });
476
-
477
- it("insertAt() applies defaults for omitted fields", () => {
478
- const existingEntry = {
479
- id: "existing",
480
- pos: "a0",
481
- value: { title: "Existing", priority: 5, completed: true },
482
- };
483
- const { env, operations } = createTaskEnv([existingEntry]);
484
- const proxy = taskArray._internal.createProxy(env, OperationPath.make(""));
485
-
486
- // Insert with only required field
487
- proxy.insertAt(0, { title: "First Task" });
488
-
489
- const payload = operations[0]!.payload as { value: { title: string; priority: number; completed: boolean } };
490
- expect(payload.value.title).toBe("First Task");
491
- expect(payload.value.priority).toBe(0); // Default
492
- expect(payload.value.completed).toBe(false); // Default
493
- });
494
-
495
- it("set() applies defaults to each element", () => {
496
- const { env, operations } = createTaskEnv();
497
- const proxy = taskArray._internal.createProxy(env, OperationPath.make(""));
498
-
499
- // Set array with items that only have required fields
500
- proxy.set([
501
- { title: "Task 1" },
502
- { title: "Task 2", priority: 5 },
503
- { title: "Task 3", completed: true },
504
- ]);
505
-
506
- expect(operations).toHaveLength(1);
507
- expect(operations[0]!.kind).toBe("array.set");
508
-
509
- const entries = operations[0]!.payload as { value: { title: string; priority: number; completed: boolean } }[];
510
- expect(entries).toHaveLength(3);
511
-
512
- // First item: only title, defaults for others
513
- expect(entries[0]!.value).toEqual({ title: "Task 1", priority: 0, completed: false });
514
-
515
- // Second item: title and priority, default for completed
516
- expect(entries[1]!.value).toEqual({ title: "Task 2", priority: 5, completed: false });
517
-
518
- // Third item: title and completed, default for priority
519
- expect(entries[2]!.value).toEqual({ title: "Task 3", priority: 0, completed: true });
520
- });
521
- });
522
- });
523
-
524
- // =============================================================================
525
- // Lazy Primitive Tests
526
- // =============================================================================
@@ -1,126 +0,0 @@
1
- import { describe, expect, it } from "@effect/vitest";
2
- import * as Primitive from "../../src/Primitive";
3
- import * as ProxyEnvironment from "../../src/ProxyEnvironment";
4
- import * as OperationPath from "../../src/OperationPath";
5
- import * as Operation from "../../src/Operation";
6
-
7
- describe("BooleanPrimitive", () => {
8
- describe("proxy", () => {
9
- it("set() generates correct operation with path and payload", () => {
10
- const operations: Operation.Operation<any, any, any>[] = [];
11
- const env = ProxyEnvironment.make((op) => operations.push(op));
12
-
13
- const booleanPrimitive = Primitive.Boolean().required();
14
- const proxy = booleanPrimitive._internal.createProxy(env, OperationPath.make(""));
15
-
16
- proxy.set(true);
17
-
18
- expect(operations).toHaveLength(1);
19
- expect(operations[0]!.kind).toBe("boolean.set");
20
- expect(operations[0]!.payload).toBe(true);
21
- });
22
-
23
- it("set() includes the correct path in operation", () => {
24
- const operations: Operation.Operation<any, any, any>[] = [];
25
- const env = ProxyEnvironment.make((op) => operations.push(op));
26
-
27
- const booleanPrimitive = Primitive.Boolean();
28
- const proxy = booleanPrimitive._internal.createProxy(env, OperationPath.make("visible"));
29
-
30
- proxy.set(false);
31
-
32
- expect(operations[0]!.path.toTokens()).toEqual(["visible"]);
33
- });
34
- });
35
-
36
- describe("applyOperation", () => {
37
- it("returns the new boolean value from boolean.set operation", () => {
38
- const booleanPrimitive = Primitive.Boolean();
39
- const operation: Operation.Operation<any, any, any> = {
40
- kind: "boolean.set",
41
- path: OperationPath.make(""),
42
- payload: true,
43
- };
44
-
45
- const result = booleanPrimitive._internal.applyOperation(undefined, operation);
46
- expect(result).toBe(true);
47
- });
48
-
49
- it("replaces existing state with new value", () => {
50
- const booleanPrimitive = Primitive.Boolean();
51
- const operation: Operation.Operation<any, any, any> = {
52
- kind: "boolean.set",
53
- path: OperationPath.make(""),
54
- payload: false,
55
- };
56
-
57
- const result = booleanPrimitive._internal.applyOperation(true, operation);
58
- expect(result).toBe(false);
59
- });
60
-
61
- it("throws ValidationError for non-boolean payload", () => {
62
- const booleanPrimitive = Primitive.Boolean();
63
- const operation: Operation.Operation<any, any, any> = {
64
- kind: "boolean.set",
65
- path: OperationPath.make(""),
66
- payload: "true",
67
- };
68
-
69
- expect(() => booleanPrimitive._internal.applyOperation(undefined, operation)).toThrow(
70
- Primitive.ValidationError
71
- );
72
- });
73
-
74
- it("throws ValidationError for wrong operation kind", () => {
75
- const booleanPrimitive = Primitive.Boolean();
76
- const operation: Operation.Operation<any, any, any> = {
77
- kind: "string.set",
78
- path: OperationPath.make(""),
79
- payload: true,
80
- };
81
-
82
- expect(() => booleanPrimitive._internal.applyOperation(undefined, operation)).toThrow(
83
- Primitive.ValidationError
84
- );
85
- });
86
- });
87
-
88
- describe("getInitialState", () => {
89
- it("returns undefined when no default is set", () => {
90
- const booleanPrimitive = Primitive.Boolean();
91
- expect(booleanPrimitive._internal.getInitialState()).toBeUndefined();
92
- });
93
-
94
- it("returns the default value when set", () => {
95
- const booleanPrimitive = Primitive.Boolean().default(true);
96
- expect(booleanPrimitive._internal.getInitialState()).toBe(true);
97
- });
98
-
99
- it("returns false as default when explicitly set", () => {
100
- const booleanPrimitive = Primitive.Boolean().default(false);
101
- expect(booleanPrimitive._internal.getInitialState()).toBe(false);
102
- });
103
- });
104
-
105
- describe("schema modifiers", () => {
106
- it("required() returns a new BooleanPrimitive", () => {
107
- const original = Primitive.Boolean();
108
- const required = original.required();
109
-
110
- expect(required).toBeInstanceOf(Primitive.BooleanPrimitive);
111
- expect(required).not.toBe(original);
112
- });
113
-
114
- it("default() returns a new BooleanPrimitive with default value", () => {
115
- const original = Primitive.Boolean();
116
- const withDefault = original.default(true);
117
-
118
- expect(withDefault).toBeInstanceOf(Primitive.BooleanPrimitive);
119
- expect(withDefault._internal.getInitialState()).toBe(true);
120
- });
121
- });
122
- });
123
-
124
- // =============================================================================
125
- // Number Primitive Tests
126
- // =============================================================================