@voidhash/mimic 0.0.7 → 0.0.9
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.
- package/.turbo/turbo-build.log +15 -15
- package/dist/Presence.d.mts.map +1 -1
- package/dist/Primitive.d.cts +2 -2
- package/dist/Primitive.d.mts +2 -2
- package/dist/primitives/Struct.cjs +31 -0
- package/dist/primitives/Struct.d.cts +16 -1
- package/dist/primitives/Struct.d.cts.map +1 -1
- package/dist/primitives/Struct.d.mts +16 -1
- package/dist/primitives/Struct.d.mts.map +1 -1
- package/dist/primitives/Struct.mjs +31 -0
- package/dist/primitives/Struct.mjs.map +1 -1
- package/package.json +2 -2
- package/src/primitives/Struct.ts +58 -0
- package/tests/primitives/Struct.test.ts +346 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @voidhash/mimic@0.0.
|
|
2
|
+
> @voidhash/mimic@0.0.9 build /home/runner/work/mimic/mimic/packages/mimic
|
|
3
3
|
> tsdown
|
|
4
4
|
|
|
5
5
|
[34mℹ[39m tsdown [2mv0.18.2[22m powered by rolldown [2mv1.0.0-beta.55[22m
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mutils/tree-helpers.cjs [2m13.42 kB[22m [2m│ gzip: 3.18 kB[22m
|
|
18
18
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mprimitives/Array.cjs [2m12.21 kB[22m [2m│ gzip: 2.66 kB[22m
|
|
19
19
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mclient/WebSocketTransport.cjs [2m10.98 kB[22m [2m│ gzip: 2.71 kB[22m
|
|
20
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22mprimitives/Struct.cjs [
|
|
20
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22mprimitives/Struct.cjs [2m10.24 kB[22m [2m│ gzip: 2.33 kB[22m
|
|
21
21
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mprimitives/Either.cjs [2m 8.06 kB[22m [2m│ gzip: 2.04 kB[22m
|
|
22
22
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mclient/Rebase.cjs [2m 7.85 kB[22m [2m│ gzip: 1.76 kB[22m
|
|
23
23
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mprimitives/Union.cjs [2m 7.47 kB[22m [2m│ gzip: 1.77 kB[22m
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mOperationDefinition.cjs [2m 0.22 kB[22m [2m│ gzip: 0.16 kB[22m
|
|
53
53
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mclient/Transport.cjs [2m 0.21 kB[22m [2m│ gzip: 0.16 kB[22m
|
|
54
54
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mTransform.cjs [2m 0.20 kB[22m [2m│ gzip: 0.16 kB[22m
|
|
55
|
-
[34mℹ[39m [33m[CJS][39m 44 files, total:
|
|
55
|
+
[34mℹ[39m [33m[CJS][39m 44 files, total: 213.69 kB
|
|
56
56
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mprimitives/Tree.d.cts.map [2m 6.90 kB[22m [2m│ gzip: 2.60 kB[22m
|
|
57
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22mprimitives/Struct.d.cts.map [2m
|
|
57
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22mprimitives/Struct.d.cts.map [2m 4.62 kB[22m [2m│ gzip: 1.95 kB[22m
|
|
58
58
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mutils/tree-helpers.d.cts.map [2m 3.61 kB[22m [2m│ gzip: 1.31 kB[22m
|
|
59
59
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mprimitives/Array.d.cts.map [2m 3.27 kB[22m [2m│ gzip: 1.36 kB[22m
|
|
60
60
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22mprimitives/Union.d.cts.map [2m 3.16 kB[22m [2m│ gzip: 1.38 kB[22m
|
|
@@ -91,15 +91,15 @@
|
|
|
91
91
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mprimitives/Tree.d.cts[39m [2m13.50 kB[22m [2m│ gzip: 3.50 kB[22m
|
|
92
92
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mutils/tree-helpers.d.cts[39m [2m12.18 kB[22m [2m│ gzip: 2.52 kB[22m
|
|
93
93
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mclient/Transport.d.cts[39m [2m 7.30 kB[22m [2m│ gzip: 1.84 kB[22m
|
|
94
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mprimitives/Struct.d.cts[39m [2m 6.93 kB[22m [2m│ gzip: 1.84 kB[22m
|
|
94
95
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mprimitives/shared.d.cts[39m [2m 6.89 kB[22m [2m│ gzip: 2.09 kB[22m
|
|
95
96
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mclient/ClientDocument.d.cts[39m [2m 6.07 kB[22m [2m│ gzip: 1.68 kB[22m
|
|
96
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mprimitives/Struct.d.cts[39m [2m 5.96 kB[22m [2m│ gzip: 1.59 kB[22m
|
|
97
97
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mprimitives/Either.d.cts[39m [2m 5.44 kB[22m [2m│ gzip: 1.54 kB[22m
|
|
98
98
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mprimitives/Array.d.cts[39m [2m 5.01 kB[22m [2m│ gzip: 1.44 kB[22m
|
|
99
99
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mclient/Rebase.d.cts[39m [2m 4.88 kB[22m [2m│ gzip: 1.14 kB[22m
|
|
100
100
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mprimitives/Union.d.cts[39m [2m 4.58 kB[22m [2m│ gzip: 1.26 kB[22m
|
|
101
101
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mprimitives/TreeNode.d.cts[39m [2m 4.28 kB[22m [2m│ gzip: 1.29 kB[22m
|
|
102
|
-
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mPrimitive.d.cts[39m [2m 3.
|
|
102
|
+
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mPrimitive.d.cts[39m [2m 3.79 kB[22m [2m│ gzip: 0.82 kB[22m
|
|
103
103
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mserver/ServerDocument.d.cts[39m [2m 3.58 kB[22m [2m│ gzip: 1.19 kB[22m
|
|
104
104
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mclient/StateMonitor.d.cts[39m [2m 3.33 kB[22m [2m│ gzip: 1.07 kB[22m
|
|
105
105
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mEffectSchema.d.cts[39m [2m 3.20 kB[22m [2m│ gzip: 0.92 kB[22m
|
|
@@ -120,8 +120,8 @@
|
|
|
120
120
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mclient/WebSocketTransport.d.cts[39m [2m 1.22 kB[22m [2m│ gzip: 0.55 kB[22m
|
|
121
121
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mTransform.d.cts[39m [2m 0.48 kB[22m [2m│ gzip: 0.26 kB[22m
|
|
122
122
|
[34mℹ[39m [33m[CJS][39m [2mdist/[22m[32mOperationDefinition.d.cts[39m [2m 0.36 kB[22m [2m│ gzip: 0.21 kB[22m
|
|
123
|
-
[34mℹ[39m [33m[CJS][39m 67 files, total:
|
|
124
|
-
[32m✔[39m Build complete in [
|
|
123
|
+
[34mℹ[39m [33m[CJS][39m 67 files, total: 181.04 kB
|
|
124
|
+
[32m✔[39m Build complete in [32m5818ms[39m
|
|
125
125
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[1mindex.mjs[22m [2m 1.01 kB[22m [2m│ gzip: 0.28 kB[22m
|
|
126
126
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[1mclient/index.mjs[22m [2m 0.99 kB[22m [2m│ gzip: 0.28 kB[22m
|
|
127
127
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[1mserver/index.mjs[22m [2m 0.41 kB[22m [2m│ gzip: 0.17 kB[22m
|
|
@@ -130,9 +130,9 @@
|
|
|
130
130
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mclient/ClientDocument.mjs.map [2m46.96 kB[22m [2m│ gzip: 10.85 kB[22m
|
|
131
131
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Tree.mjs [2m28.12 kB[22m [2m│ gzip: 4.93 kB[22m
|
|
132
132
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Array.mjs.map [2m26.02 kB[22m [2m│ gzip: 6.47 kB[22m
|
|
133
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Struct.mjs.map [2m25.45 kB[22m [2m│ gzip: 6.50 kB[22m
|
|
133
134
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mutils/tree-helpers.mjs.map [2m24.70 kB[22m [2m│ gzip: 5.20 kB[22m
|
|
134
135
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mclient/WebSocketTransport.mjs.map [2m23.44 kB[22m [2m│ gzip: 5.75 kB[22m
|
|
135
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Struct.mjs.map [2m22.62 kB[22m [2m│ gzip: 5.82 kB[22m
|
|
136
136
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mclient/ClientDocument.mjs [2m20.03 kB[22m [2m│ gzip: 4.49 kB[22m
|
|
137
137
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Union.mjs.map [2m18.55 kB[22m [2m│ gzip: 4.63 kB[22m
|
|
138
138
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Either.mjs.map [2m16.78 kB[22m [2m│ gzip: 4.12 kB[22m
|
|
@@ -147,9 +147,9 @@
|
|
|
147
147
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mserver/ServerDocument.mjs.map [2m10.44 kB[22m [2m│ gzip: 2.95 kB[22m
|
|
148
148
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mclient/StateMonitor.mjs.map [2m10.39 kB[22m [2m│ gzip: 3.04 kB[22m
|
|
149
149
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/String.mjs.map [2m 9.70 kB[22m [2m│ gzip: 2.70 kB[22m
|
|
150
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Struct.mjs [2m 9.30 kB[22m [2m│ gzip: 2.31 kB[22m
|
|
150
151
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mclient/Transport.mjs.map [2m 9.09 kB[22m [2m│ gzip: 1.86 kB[22m
|
|
151
152
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Number.mjs.map [2m 8.71 kB[22m [2m│ gzip: 2.41 kB[22m
|
|
152
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Struct.mjs [2m 8.32 kB[22m [2m│ gzip: 2.10 kB[22m
|
|
153
153
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mclient/Rebase.mjs [2m 7.61 kB[22m [2m│ gzip: 1.73 kB[22m
|
|
154
154
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Either.mjs [2m 7.47 kB[22m [2m│ gzip: 2.02 kB[22m
|
|
155
155
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Boolean.mjs.map [2m 7.45 kB[22m [2m│ gzip: 2.13 kB[22m
|
|
@@ -160,6 +160,7 @@
|
|
|
160
160
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mEffectSchema.mjs [2m 6.47 kB[22m [2m│ gzip: 1.59 kB[22m
|
|
161
161
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/TreeNode.mjs.map [2m 6.47 kB[22m [2m│ gzip: 2.05 kB[22m
|
|
162
162
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mclient/errors.mjs.map [2m 5.68 kB[22m [2m│ gzip: 1.37 kB[22m
|
|
163
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Struct.d.mts.map [2m 4.63 kB[22m [2m│ gzip: 1.96 kB[22m
|
|
163
164
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Lazy.mjs.map [2m 4.59 kB[22m [2m│ gzip: 1.40 kB[22m
|
|
164
165
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mPresence.mjs.map [2m 4.56 kB[22m [2m│ gzip: 1.30 kB[22m
|
|
165
166
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/String.mjs [2m 4.42 kB[22m [2m│ gzip: 1.34 kB[22m
|
|
@@ -167,7 +168,6 @@
|
|
|
167
168
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mOperationPath.mjs [2m 4.03 kB[22m [2m│ gzip: 1.13 kB[22m
|
|
168
169
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mDocument.mjs [2m 4.00 kB[22m [2m│ gzip: 1.40 kB[22m
|
|
169
170
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Number.mjs [2m 3.99 kB[22m [2m│ gzip: 1.19 kB[22m
|
|
170
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22mprimitives/Struct.d.mts.map [2m 3.90 kB[22m [2m│ gzip: 1.66 kB[22m
|
|
171
171
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mserver/errors.mjs.map [2m 3.86 kB[22m [2m│ gzip: 0.96 kB[22m
|
|
172
172
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mtypes/index.mjs.map [2m 3.74 kB[22m [2m│ gzip: 0.79 kB[22m
|
|
173
173
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22mutils/tree-helpers.d.mts.map [2m 3.61 kB[22m [2m│ gzip: 1.31 kB[22m
|
|
@@ -237,15 +237,15 @@
|
|
|
237
237
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mprimitives/Tree.d.mts[39m [2m13.50 kB[22m [2m│ gzip: 3.50 kB[22m
|
|
238
238
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mutils/tree-helpers.d.mts[39m [2m12.18 kB[22m [2m│ gzip: 2.52 kB[22m
|
|
239
239
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mclient/Transport.d.mts[39m [2m 7.30 kB[22m [2m│ gzip: 1.84 kB[22m
|
|
240
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mprimitives/Struct.d.mts[39m [2m 6.96 kB[22m [2m│ gzip: 1.85 kB[22m
|
|
240
241
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mprimitives/shared.d.mts[39m [2m 6.89 kB[22m [2m│ gzip: 2.09 kB[22m
|
|
241
242
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mclient/ClientDocument.d.mts[39m [2m 6.09 kB[22m [2m│ gzip: 1.69 kB[22m
|
|
242
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mprimitives/Struct.d.mts[39m [2m 5.99 kB[22m [2m│ gzip: 1.60 kB[22m
|
|
243
243
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mprimitives/Either.d.mts[39m [2m 5.44 kB[22m [2m│ gzip: 1.54 kB[22m
|
|
244
244
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mprimitives/Array.d.mts[39m [2m 5.04 kB[22m [2m│ gzip: 1.45 kB[22m
|
|
245
245
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mclient/Rebase.d.mts[39m [2m 4.91 kB[22m [2m│ gzip: 1.15 kB[22m
|
|
246
246
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mprimitives/Union.d.mts[39m [2m 4.61 kB[22m [2m│ gzip: 1.27 kB[22m
|
|
247
247
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mprimitives/TreeNode.d.mts[39m [2m 4.31 kB[22m [2m│ gzip: 1.29 kB[22m
|
|
248
|
-
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mPrimitive.d.mts[39m [2m 3.
|
|
248
|
+
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mPrimitive.d.mts[39m [2m 3.79 kB[22m [2m│ gzip: 0.82 kB[22m
|
|
249
249
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mserver/ServerDocument.d.mts[39m [2m 3.61 kB[22m [2m│ gzip: 1.19 kB[22m
|
|
250
250
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mclient/StateMonitor.d.mts[39m [2m 3.33 kB[22m [2m│ gzip: 1.07 kB[22m
|
|
251
251
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mEffectSchema.d.mts[39m [2m 3.20 kB[22m [2m│ gzip: 0.92 kB[22m
|
|
@@ -266,5 +266,5 @@
|
|
|
266
266
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mclient/WebSocketTransport.d.mts[39m [2m 1.22 kB[22m [2m│ gzip: 0.55 kB[22m
|
|
267
267
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mTransform.d.mts[39m [2m 0.48 kB[22m [2m│ gzip: 0.26 kB[22m
|
|
268
268
|
[34mℹ[39m [34m[ESM][39m [2mdist/[22m[32mOperationDefinition.d.mts[39m [2m 0.36 kB[22m [2m│ gzip: 0.22 kB[22m
|
|
269
|
-
[34mℹ[39m [34m[ESM][39m 144 files, total:
|
|
270
|
-
[32m✔[39m Build complete in [
|
|
269
|
+
[34mℹ[39m [34m[ESM][39m 144 files, total: 845.46 kB
|
|
270
|
+
[32m✔[39m Build complete in [32m5846ms[39m
|
package/dist/Presence.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Presence.d.mts","names":[],"sources":["../src/Presence.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAeiB;;;mBAGE,MAAA,CAAO,OAAO;;EAHhB,SAAA,KAAQ,EAKP,KALO;;;;;AAWR,UAAA,eAAe,CAAA,
|
|
1
|
+
{"version":3,"file":"Presence.d.mts","names":[],"sources":["../src/Presence.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAeiB;;;mBAGE,MAAA,CAAO,OAAO;;EAHhB,SAAA,KAAQ,EAKP,KALO;;;;;AAWR,UAAA,eAAe,CAAA,KAEC,CAAA,CAAA;EAMrB;EAKA,SAAA,MAAW,EAXJ,MAAA,CAAO,MAWA,CAXO,KAWC,CAAA;AASlC;AA8BA;;;AAAwE,KA5C5D,KA4C4D,CAAA,UA5C5C,QA4C4C,CAAA,GAAA,CAAA,CAAA,GA5C3B,CA4C2B,CAAA,OAAA,CAAA;;;AAmBxE;AACqB,KA3DT,WAAA,GAAc,QA2DL,CAAA,GAAA,CAAA;;;;AAcR,UAhEI,aAyEhB,CAAA,QAAA,OAAA,CAAA,CAAA;EARoB;EAAT,SAAA,IAAA,EA/DK,KA+DL;EAET;EAAK,SAAA,MAAA,CAAA,EAAA,MAAA;AAeR;;;;;;;;;;;;;;;;;;;;cApDa,uBAAyB,gBAAgB,WAAS,SAAS;;;;;;;;;;cAmB3D,4BACD,SAAS,0BAElB;;;;;;;;;cAYU,gCACD,SAAS,0BAElB;;;;;;;;cAeU,2BACD,SAAS,kCAEV"}
|
package/dist/Primitive.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnyPrimitive, HasDefault, InferProxy, InferSetInput, InferSnapshot, InferState, InferUpdateInput, IsDefined, IsRequired, MaybeUndefined, NeedsValue, Optional, Primitive, PrimitiveInternal, ValidationError, Validator, applyDefaults, isCompatibleOperation, runValidators } from "./primitives/shared.cjs";
|
|
2
2
|
import { String, StringPrimitive, StringProxy } from "./primitives/String.cjs";
|
|
3
|
-
import { InferStructSnapshot, InferStructState, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue } from "./primitives/Struct.cjs";
|
|
3
|
+
import { InferStructSnapshot, InferStructState, MakeOptional, PartialFields, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue } from "./primitives/Struct.cjs";
|
|
4
4
|
import { Boolean, BooleanPrimitive, BooleanProxy } from "./primitives/Boolean.cjs";
|
|
5
5
|
import { Number, NumberPrimitive, NumberProxy } from "./primitives/Number.cjs";
|
|
6
6
|
import { Literal, LiteralPrimitive, LiteralProxy, LiteralValue } from "./primitives/Literal.cjs";
|
|
@@ -13,7 +13,7 @@ import { InferTreeSetInput, InferTreeSnapshot, Tree, TreeNodeDataSetInput, TreeN
|
|
|
13
13
|
|
|
14
14
|
//#region src/Primitive.d.ts
|
|
15
15
|
declare namespace Primitive_d_exports {
|
|
16
|
-
export { AnyPrimitive, AnyTreeNodePrimitive, Array, ArrayElementSetInput, ArrayEntry, ArrayEntrySnapshot, ArrayPrimitive, ArrayProxy, ArraySetInput, ArraySnapshot, ArrayState, ArrayUpdateInput, Boolean, BooleanPrimitive, BooleanProxy, Either, EitherMatchHandlers, EitherPrimitive, EitherProxy, HasDefault, InferEitherSnapshot, InferEitherState, InferLazyProxy, InferLazySetInput, InferLazySnapshot, InferLazyState, InferLazyUpdateInput, InferProxy, InferSetInput, InferSnapshot, InferState, InferStructSnapshot, InferStructState, InferTreeNodeChildren, InferTreeNodeDataState, InferTreeNodeType, InferTreeSetInput, InferTreeSnapshot, InferUnionSnapshot, InferUnionState, InferUpdateInput, IsDefined, IsRequired, Lazy, LazyPrimitive, Literal, LiteralPrimitive, LiteralProxy, LiteralValue, MaybeUndefined, NeedsValue, Number, NumberPrimitive, NumberProxy, Optional, Primitive, PrimitiveInternal, ScalarPrimitive, String, StringPrimitive, StringProxy, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue, Tree, TreeNode, TreeNodeChildrenInput, TreeNodeConfig, TreeNodeDataSetInput, TreeNodePrimitive, TreeNodeProxyBase, TreeNodeSelf, TreeNodeSelfType, TreeNodeSetInput, TreeNodeSetInputUnion, TreeNodeSnapshot, TreeNodeState, TreeNodeUpdateValue, TreeOptions, TreePrimitive, TreeProxy, TreeSetInput, TreeState, TreeUpdateInput, TypedNodeProxy, TypedTreeNodeState, Union, UnionOptions, UnionPrimitive, UnionProxy, UnionSetInput, UnionVariants, ValidationError, Validator, applyDefaults, isCompatibleOperation, runValidators };
|
|
16
|
+
export { AnyPrimitive, AnyTreeNodePrimitive, Array, ArrayElementSetInput, ArrayEntry, ArrayEntrySnapshot, ArrayPrimitive, ArrayProxy, ArraySetInput, ArraySnapshot, ArrayState, ArrayUpdateInput, Boolean, BooleanPrimitive, BooleanProxy, Either, EitherMatchHandlers, EitherPrimitive, EitherProxy, HasDefault, InferEitherSnapshot, InferEitherState, InferLazyProxy, InferLazySetInput, InferLazySnapshot, InferLazyState, InferLazyUpdateInput, InferProxy, InferSetInput, InferSnapshot, InferState, InferStructSnapshot, InferStructState, InferTreeNodeChildren, InferTreeNodeDataState, InferTreeNodeType, InferTreeSetInput, InferTreeSnapshot, InferUnionSnapshot, InferUnionState, InferUpdateInput, IsDefined, IsRequired, Lazy, LazyPrimitive, Literal, LiteralPrimitive, LiteralProxy, LiteralValue, MakeOptional, MaybeUndefined, NeedsValue, Number, NumberPrimitive, NumberProxy, Optional, PartialFields, Primitive, PrimitiveInternal, ScalarPrimitive, String, StringPrimitive, StringProxy, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue, Tree, TreeNode, TreeNodeChildrenInput, TreeNodeConfig, TreeNodeDataSetInput, TreeNodePrimitive, TreeNodeProxyBase, TreeNodeSelf, TreeNodeSelfType, TreeNodeSetInput, TreeNodeSetInputUnion, TreeNodeSnapshot, TreeNodeState, TreeNodeUpdateValue, TreeOptions, TreePrimitive, TreeProxy, TreeSetInput, TreeState, TreeUpdateInput, TypedNodeProxy, TypedTreeNodeState, Union, UnionOptions, UnionPrimitive, UnionProxy, UnionSetInput, UnionVariants, ValidationError, Validator, applyDefaults, isCompatibleOperation, runValidators };
|
|
17
17
|
}
|
|
18
18
|
//#endregion
|
|
19
19
|
export { Primitive_d_exports };
|
package/dist/Primitive.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AnyPrimitive, HasDefault, InferProxy, InferSetInput, InferSnapshot, InferState, InferUpdateInput, IsDefined, IsRequired, MaybeUndefined, NeedsValue, Optional, Primitive, PrimitiveInternal, ValidationError, Validator, applyDefaults, isCompatibleOperation, runValidators } from "./primitives/shared.mjs";
|
|
2
2
|
import { String, StringPrimitive, StringProxy } from "./primitives/String.mjs";
|
|
3
|
-
import { InferStructSnapshot, InferStructState, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue } from "./primitives/Struct.mjs";
|
|
3
|
+
import { InferStructSnapshot, InferStructState, MakeOptional, PartialFields, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue } from "./primitives/Struct.mjs";
|
|
4
4
|
import { Boolean, BooleanPrimitive, BooleanProxy } from "./primitives/Boolean.mjs";
|
|
5
5
|
import { Number, NumberPrimitive, NumberProxy } from "./primitives/Number.mjs";
|
|
6
6
|
import { Literal, LiteralPrimitive, LiteralProxy, LiteralValue } from "./primitives/Literal.mjs";
|
|
@@ -13,7 +13,7 @@ import { InferTreeSetInput, InferTreeSnapshot, Tree, TreeNodeDataSetInput, TreeN
|
|
|
13
13
|
|
|
14
14
|
//#region src/Primitive.d.ts
|
|
15
15
|
declare namespace Primitive_d_exports {
|
|
16
|
-
export { AnyPrimitive, AnyTreeNodePrimitive, Array, ArrayElementSetInput, ArrayEntry, ArrayEntrySnapshot, ArrayPrimitive, ArrayProxy, ArraySetInput, ArraySnapshot, ArrayState, ArrayUpdateInput, Boolean, BooleanPrimitive, BooleanProxy, Either, EitherMatchHandlers, EitherPrimitive, EitherProxy, HasDefault, InferEitherSnapshot, InferEitherState, InferLazyProxy, InferLazySetInput, InferLazySnapshot, InferLazyState, InferLazyUpdateInput, InferProxy, InferSetInput, InferSnapshot, InferState, InferStructSnapshot, InferStructState, InferTreeNodeChildren, InferTreeNodeDataState, InferTreeNodeType, InferTreeSetInput, InferTreeSnapshot, InferUnionSnapshot, InferUnionState, InferUpdateInput, IsDefined, IsRequired, Lazy, LazyPrimitive, Literal, LiteralPrimitive, LiteralProxy, LiteralValue, MaybeUndefined, NeedsValue, Number, NumberPrimitive, NumberProxy, Optional, Primitive, PrimitiveInternal, ScalarPrimitive, String, StringPrimitive, StringProxy, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue, Tree, TreeNode, TreeNodeChildrenInput, TreeNodeConfig, TreeNodeDataSetInput, TreeNodePrimitive, TreeNodeProxyBase, TreeNodeSelf, TreeNodeSelfType, TreeNodeSetInput, TreeNodeSetInputUnion, TreeNodeSnapshot, TreeNodeState, TreeNodeUpdateValue, TreeOptions, TreePrimitive, TreeProxy, TreeSetInput, TreeState, TreeUpdateInput, TypedNodeProxy, TypedTreeNodeState, Union, UnionOptions, UnionPrimitive, UnionProxy, UnionSetInput, UnionVariants, ValidationError, Validator, applyDefaults, isCompatibleOperation, runValidators };
|
|
16
|
+
export { AnyPrimitive, AnyTreeNodePrimitive, Array, ArrayElementSetInput, ArrayEntry, ArrayEntrySnapshot, ArrayPrimitive, ArrayProxy, ArraySetInput, ArraySnapshot, ArrayState, ArrayUpdateInput, Boolean, BooleanPrimitive, BooleanProxy, Either, EitherMatchHandlers, EitherPrimitive, EitherProxy, HasDefault, InferEitherSnapshot, InferEitherState, InferLazyProxy, InferLazySetInput, InferLazySnapshot, InferLazyState, InferLazyUpdateInput, InferProxy, InferSetInput, InferSnapshot, InferState, InferStructSnapshot, InferStructState, InferTreeNodeChildren, InferTreeNodeDataState, InferTreeNodeType, InferTreeSetInput, InferTreeSnapshot, InferUnionSnapshot, InferUnionState, InferUpdateInput, IsDefined, IsRequired, Lazy, LazyPrimitive, Literal, LiteralPrimitive, LiteralProxy, LiteralValue, MakeOptional, MaybeUndefined, NeedsValue, Number, NumberPrimitive, NumberProxy, Optional, PartialFields, Primitive, PrimitiveInternal, ScalarPrimitive, String, StringPrimitive, StringProxy, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue, Tree, TreeNode, TreeNodeChildrenInput, TreeNodeConfig, TreeNodeDataSetInput, TreeNodePrimitive, TreeNodeProxyBase, TreeNodeSelf, TreeNodeSelfType, TreeNodeSetInput, TreeNodeSetInputUnion, TreeNodeSnapshot, TreeNodeState, TreeNodeUpdateValue, TreeOptions, TreePrimitive, TreeProxy, TreeSetInput, TreeState, TreeUpdateInput, TypedNodeProxy, TypedTreeNodeState, Union, UnionOptions, UnionPrimitive, UnionProxy, UnionSetInput, UnionVariants, ValidationError, Validator, applyDefaults, isCompatibleOperation, runValidators };
|
|
17
17
|
}
|
|
18
18
|
//#endregion
|
|
19
19
|
export { Primitive_d_exports };
|
|
@@ -193,6 +193,37 @@ var StructPrimitive = class StructPrimitive {
|
|
|
193
193
|
message
|
|
194
194
|
}] }));
|
|
195
195
|
}
|
|
196
|
+
/** Extend this struct with additional fields */
|
|
197
|
+
extend(newFields) {
|
|
198
|
+
return new StructPrimitive({
|
|
199
|
+
required: this._schema.required,
|
|
200
|
+
defaultValue: void 0,
|
|
201
|
+
fields: require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, this._schema.fields), newFields),
|
|
202
|
+
validators: []
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/** Make all properties of this struct optional (TRequired = false for all fields) */
|
|
206
|
+
partial() {
|
|
207
|
+
const partialFields = {};
|
|
208
|
+
for (const key in this._schema.fields) {
|
|
209
|
+
const field = this._schema.fields[key];
|
|
210
|
+
partialFields[key] = this._makeFieldOptional(field);
|
|
211
|
+
}
|
|
212
|
+
return new StructPrimitive({
|
|
213
|
+
required: this._schema.required,
|
|
214
|
+
defaultValue: void 0,
|
|
215
|
+
fields: partialFields,
|
|
216
|
+
validators: []
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
_makeFieldOptional(field) {
|
|
220
|
+
const fieldAny = field;
|
|
221
|
+
if (fieldAny._schema && typeof fieldAny._schema === "object") {
|
|
222
|
+
const Constructor = field.constructor;
|
|
223
|
+
return new Constructor(require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, fieldAny._schema), {}, { required: false }));
|
|
224
|
+
}
|
|
225
|
+
return field;
|
|
226
|
+
}
|
|
196
227
|
};
|
|
197
228
|
/** Creates a new StructPrimitive with the given fields */
|
|
198
229
|
const Struct = (fields) => new StructPrimitive({
|
|
@@ -48,6 +48,16 @@ type InferStructSnapshot<TFields extends Record<string, AnyPrimitive>> = { reado
|
|
|
48
48
|
* Uses each field's TUpdateInput type, which handles nested updates recursively.
|
|
49
49
|
*/
|
|
50
50
|
type StructUpdateValue<TFields extends Record<string, AnyPrimitive>> = { readonly [K in keyof TFields]?: InferUpdateInput<TFields[K]> };
|
|
51
|
+
/**
|
|
52
|
+
* Transforms a primitive type to make it optional (TRequired = false).
|
|
53
|
+
* Preserves the primitive structure while changing the required flag.
|
|
54
|
+
*/
|
|
55
|
+
type MakeOptional<T extends AnyPrimitive> = T extends Primitive<infer S, infer P, any, infer H, infer SI, infer UI> ? Primitive<S, P, false, H, SI, UI> : T;
|
|
56
|
+
/**
|
|
57
|
+
* Maps each field in a struct to its optional version.
|
|
58
|
+
* All fields become optional (TRequired = false).
|
|
59
|
+
*/
|
|
60
|
+
type PartialFields<TFields extends Record<string, AnyPrimitive>> = { [K in keyof TFields]: MakeOptional<TFields[K]> };
|
|
51
61
|
/**
|
|
52
62
|
* Maps a schema definition to its proxy type.
|
|
53
63
|
* Provides nested field access + get()/set()/toSnapshot() methods for the whole struct.
|
|
@@ -87,10 +97,15 @@ declare class StructPrimitive<TFields extends Record<string, AnyPrimitive>, TReq
|
|
|
87
97
|
get fields(): TFields;
|
|
88
98
|
/** Add a custom validation rule (useful for cross-field validation) */
|
|
89
99
|
refine(fn: (value: InferStructState<TFields>) => boolean, message: string): StructPrimitive<TFields, TRequired, THasDefault>;
|
|
100
|
+
/** Extend this struct with additional fields */
|
|
101
|
+
extend<TNewFields extends Record<string, AnyPrimitive>>(newFields: TNewFields): StructPrimitive<TFields & TNewFields, TRequired, THasDefault>;
|
|
102
|
+
/** Make all properties of this struct optional (TRequired = false for all fields) */
|
|
103
|
+
partial(): StructPrimitive<PartialFields<TFields>, TRequired, THasDefault>;
|
|
104
|
+
private _makeFieldOptional;
|
|
90
105
|
readonly _internal: PrimitiveInternal<InferStructState<TFields>, StructProxy<TFields, TRequired, THasDefault>>;
|
|
91
106
|
}
|
|
92
107
|
/** Creates a new StructPrimitive with the given fields */
|
|
93
108
|
declare const Struct: <TFields extends Record<string, AnyPrimitive>>(fields: TFields) => StructPrimitive<TFields, false, false>;
|
|
94
109
|
//#endregion
|
|
95
|
-
export { InferStructSnapshot, InferStructState, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue };
|
|
110
|
+
export { InferStructSnapshot, InferStructState, MakeOptional, PartialFields, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue };
|
|
96
111
|
//# sourceMappingURL=Struct.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Struct.d.cts","names":[],"sources":["../../src/primitives/Struct.ts"],"sourcesContent":[],"mappings":";;;;;;AAM8L;AAYhJ;KAAzC,gBAK+C,CAAA,CAAA,CAAA,GALzB,CAKyB,SALf,SAKe,CAAA,GAAA,EAAA,GAAA,EAAA,IAAA,EAAA,KAAA,CAAA,GAAA,IAAA,GAAA,KAAA;;;;KAA/C,eAC4C,CAAA,gBADZ,MACY,CAAA,MAAA,EADG,YACH,CAAA,CAAA,GAAA,QAAzB,MAAV,OAAU,GAAA,gBAAA,CAAiB,OAAjB,CAAyB,CAAzB,CAAA,CAAA,SAAA,IAAA,GAA4C,CAA5C,GAAA,KAAA,EAA4C,CAAA,MAC5D,OAD4D,CAAA;;;AACrD;KAKV,eAA+C,CAAA,gBAAf,MAAe,CAAA,MAAA,EAAA,YAAA,CAAA,CAAA,GAAA,QAAf,MACvB,OADuB,GACb,gBADa,CACI,OADJ,CACY,CADZ,CAAA,CAAA,SAAA,IAAA,GAAA,KAAA,GACuC,CADvC,EACvB,CAAA,MACN,OADM,CAAA;;;;;;;AASF,KAAA,cAAc,CAAA,gBAAiB,MAAjB,CAAA,MAAA,EAAgC,YAAhC,CAAA,CAAA,GAAA,iBACP,eADuC,CACvB,OADuB,CAAA,GACZ,aADY,CACE,OADF,CACU,CADV,CAAA,CAAA,EAAf,GAAA,iBAExB,eADgB,CACA,OADA,CAAA,IACY,aADZ,CAC0B,OAD1B,CACkC,CADlC,CAAA,CAAA,EAAhB;;;;;;KAQd,mBAPwD,CAAA,gBAOpB,MAPoB,CAAA,MAAA,EAOL,YAPK,CAAA,EAAA,kBAAA,OAAA,EAAA,oBAAA,OAAA,CAAA,GAQ3D,UAR2D,CAQhD,cARgD,CAQjC,OARiC,CAAA,EAQvB,SARuB,EAQZ,WARY,CAAA;;;;AAAc;KActE,sBAPmD,CAAA,gBAOZ,MAPY,CAAA,MAAA,EAOG,YAPH,CAAA,CAAA,GAOoB,iBAPpB,CAOsC,OAPtC,CAAA;;;;;AACP,KAarC,gBAbqC,CAAA,gBAaJ,MAbI,CAAA,MAAA,EAaW,YAbX,CAAA,CAAA,GAAA,iBAA/C,MAcqB,OAdrB,GAc+B,UAd/B,CAc0C,OAd1C,CAckD,CAdlD,CAAA,CAAA,EAAU;AAAA;;;;AAMgE,KAehE,mBAfgE,CAAA,gBAe5B,MAf4B,CAAA,MAAA,EAeb,YAfa,CAAA,CAAA,GAAA,iBAAiB,MAgBtE,OAhBsE,GAgB5D,aAhB4D,CAgB9C,OAhB8C,CAgBtC,CAhBsC,CAAA,CAAA,EAO7F;;;;;AACoD,KAexC,iBAfwC,CAAA,gBAeN,MAfM,CAAA,MAAA,EAeS,YAfT,CAAA,CAAA,GAAA,iBAAnB,MAgBV,OAhBU,IAgBC,gBAhBD,CAgBkB,OAhBlB,CAgB0B,CAhB1B,CAAA,CAAA,EAAU;AAO3C;;;;AAC+C,KAenC,
|
|
1
|
+
{"version":3,"file":"Struct.d.cts","names":[],"sources":["../../src/primitives/Struct.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -49,6 +49,16 @@ type InferStructSnapshot<TFields extends Record<string, AnyPrimitive>> = { reado
|
|
|
49
49
|
* Uses each field's TUpdateInput type, which handles nested updates recursively.
|
|
50
50
|
*/
|
|
51
51
|
type StructUpdateValue<TFields extends Record<string, AnyPrimitive>> = { readonly [K in keyof TFields]?: InferUpdateInput<TFields[K]> };
|
|
52
|
+
/**
|
|
53
|
+
* Transforms a primitive type to make it optional (TRequired = false).
|
|
54
|
+
* Preserves the primitive structure while changing the required flag.
|
|
55
|
+
*/
|
|
56
|
+
type MakeOptional<T extends AnyPrimitive> = T extends Primitive<infer S, infer P, any, infer H, infer SI, infer UI> ? Primitive<S, P, false, H, SI, UI> : T;
|
|
57
|
+
/**
|
|
58
|
+
* Maps each field in a struct to its optional version.
|
|
59
|
+
* All fields become optional (TRequired = false).
|
|
60
|
+
*/
|
|
61
|
+
type PartialFields<TFields extends Record<string, AnyPrimitive>> = { [K in keyof TFields]: MakeOptional<TFields[K]> };
|
|
52
62
|
/**
|
|
53
63
|
* Maps a schema definition to its proxy type.
|
|
54
64
|
* Provides nested field access + get()/set()/toSnapshot() methods for the whole struct.
|
|
@@ -88,10 +98,15 @@ declare class StructPrimitive<TFields extends Record<string, AnyPrimitive>, TReq
|
|
|
88
98
|
get fields(): TFields;
|
|
89
99
|
/** Add a custom validation rule (useful for cross-field validation) */
|
|
90
100
|
refine(fn: (value: InferStructState<TFields>) => boolean, message: string): StructPrimitive<TFields, TRequired, THasDefault>;
|
|
101
|
+
/** Extend this struct with additional fields */
|
|
102
|
+
extend<TNewFields extends Record<string, AnyPrimitive>>(newFields: TNewFields): StructPrimitive<TFields & TNewFields, TRequired, THasDefault>;
|
|
103
|
+
/** Make all properties of this struct optional (TRequired = false for all fields) */
|
|
104
|
+
partial(): StructPrimitive<PartialFields<TFields>, TRequired, THasDefault>;
|
|
105
|
+
private _makeFieldOptional;
|
|
91
106
|
readonly _internal: PrimitiveInternal<InferStructState<TFields>, StructProxy<TFields, TRequired, THasDefault>>;
|
|
92
107
|
}
|
|
93
108
|
/** Creates a new StructPrimitive with the given fields */
|
|
94
109
|
declare const Struct: <TFields extends Record<string, AnyPrimitive>>(fields: TFields) => StructPrimitive<TFields, false, false>;
|
|
95
110
|
//#endregion
|
|
96
|
-
export { InferStructSnapshot, InferStructState, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue };
|
|
111
|
+
export { InferStructSnapshot, InferStructState, MakeOptional, PartialFields, Struct, StructPrimitive, StructProxy, StructSetInput, StructUpdateValue };
|
|
97
112
|
//# sourceMappingURL=Struct.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Struct.d.mts","names":[],"sources":["../../src/primitives/Struct.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAM8L;AAYhJ,KAAzC,gBAKA,CAAe,CAAA,CAAA,GALO,CAKP,SALiB,SAKjB,CAAA,GAAA,EAAA,GAAA,EAAA,IAAA,EAAA,KAAA,CAAA,GAAA,IAAA,GAAA,KAAA;;;;KAAf,eACoC,CAAA,gBADJ,MACI,CAAA,MAAA,EADW,YACX,CAAA,CAAA,GAAA,QAAQ,MAAnC,OAAmC,GAAzB,gBAAyB,CAAR,OAAQ,CAAA,CAAA,CAAA,CAAA,SAAA,IAAA,GAAmB,CAAnB,GAAA,KAAA,EAAzB,CAAA,MAChB,OADgB,CAAA;;;;AACT,KAKV,eAAA,CAAA,gBAAgC,MAAjB,CAAA,MAAA,EAAgC,YAAhC,CAAA,CAAA,GAAA,QAAgC,MACtC,OADsC,GAC5B,gBAD4B,CACX,OADW,CACH,CADG,CAAA,CAAA,SAAA,IAAA,GAAA,KAAA,GACwB,CADxB,EAAf,CAAA,MAE7B,OAF6B,CAAA;;;;;;;AAEtB,KAQH,cARG,CAAA,gBAQ4B,MAR5B,CAAA,MAAA,EAQ2C,YAR3C,CAAA,CAAA,GAAA,iBASI,eADO,CACS,OADT,CAAA,GACoB,aADpB,CACkC,OADlC,CAC0C,CAD1C,CAAA,CAAA,EAAgC,GAAA,iBAEvC,eAFwB,CAER,OAFQ,CAAA,IAEI,aAFJ,CAEkB,OAFlB,CAE0B,CAF1B,CAAA,CAAA,EACR;;;;;;KAQ9B,mBAPc,CAAA,gBAOsB,MAPtB,CAAA,MAAA,EAOqC,YAPrC,CAAA,EAAA,kBAAA,OAAA,EAAA,oBAAA,OAAA,CAAA,GAQjB,UARiB,CAQN,cARM,CAQS,OART,CAAA,EAQmB,SARnB,EAQ8B,WAR9B,CAAA;;;;;AAAwD,KActE,sBAPmB,CAAA,gBAOoB,MAPpB,CAAA,MAAA,EAOmC,YAPnC,CAAA,CAAA,GAOoD,iBAPpD,CAOsE,OAPtE,CAAA;;;;;AACc,KAa1B,gBAb0B,CAAA,gBAaO,MAbP,CAAA,MAAA,EAasB,YAbtB,CAAA,CAAA,GAAA,iBAAW,MAc1B,OAd0B,GAchB,UAdgB,CAcL,OAdK,CAcG,CAdH,CAAA,CAAA,EAA/C;;AAAU;;;AAMkF,KAelF,mBAfkF,CAAA,gBAe9C,MAf8C,CAAA,MAAA,EAe/B,YAf+B,CAAA,CAAA,GAAA,iBAAlB,MAgBrD,OAhBqD,GAgB3C,aAhB2C,CAgB7B,OAhB6B,CAgBrB,CAhBqB,CAAA,CAAA,EAAiB;AAO7F;;;;AAC4C,KAehC,iBAfgC,CAAA,gBAeE,MAfF,CAAA,MAAA,EAeiB,YAfjB,CAAA,CAAA,GAAA,iBAAQ,MAgB7B,OAhB6B,IAgBlB,gBAhBkB,CAgBD,OAhBC,CAgBO,CAhBP,CAAA,CAAA,EAAnB;;AAOjC;;;AACuB,KAeX,
|
|
1
|
+
{"version":3,"file":"Struct.d.mts","names":[],"sources":["../../src/primitives/Struct.ts"],"sourcesContent":[],"mappings":"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"}
|
|
@@ -192,6 +192,37 @@ var StructPrimitive = class StructPrimitive {
|
|
|
192
192
|
message
|
|
193
193
|
}] }));
|
|
194
194
|
}
|
|
195
|
+
/** Extend this struct with additional fields */
|
|
196
|
+
extend(newFields) {
|
|
197
|
+
return new StructPrimitive({
|
|
198
|
+
required: this._schema.required,
|
|
199
|
+
defaultValue: void 0,
|
|
200
|
+
fields: _objectSpread2(_objectSpread2({}, this._schema.fields), newFields),
|
|
201
|
+
validators: []
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
/** Make all properties of this struct optional (TRequired = false for all fields) */
|
|
205
|
+
partial() {
|
|
206
|
+
const partialFields = {};
|
|
207
|
+
for (const key in this._schema.fields) {
|
|
208
|
+
const field = this._schema.fields[key];
|
|
209
|
+
partialFields[key] = this._makeFieldOptional(field);
|
|
210
|
+
}
|
|
211
|
+
return new StructPrimitive({
|
|
212
|
+
required: this._schema.required,
|
|
213
|
+
defaultValue: void 0,
|
|
214
|
+
fields: partialFields,
|
|
215
|
+
validators: []
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
_makeFieldOptional(field) {
|
|
219
|
+
const fieldAny = field;
|
|
220
|
+
if (fieldAny._schema && typeof fieldAny._schema === "object") {
|
|
221
|
+
const Constructor = field.constructor;
|
|
222
|
+
return new Constructor(_objectSpread2(_objectSpread2({}, fieldAny._schema), {}, { required: false }));
|
|
223
|
+
}
|
|
224
|
+
return field;
|
|
225
|
+
}
|
|
195
226
|
};
|
|
196
227
|
/** Creates a new StructPrimitive with the given fields */
|
|
197
228
|
const Struct = (fields) => new StructPrimitive({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Struct.mjs","names":["OperationDefinition.make","snapshot: Record<string, unknown>","Operation.fromDefinition","newState: InferStructState<TFields>","initialState: Record<string, unknown>","OperationPath.pathsOverlap"],"sources":["../../src/primitives/Struct.ts"],"sourcesContent":["import { Schema } from \"effect\";\nimport * as OperationDefinition from \"../OperationDefinition\";\nimport * as Operation from \"../Operation\";\nimport * as OperationPath from \"../OperationPath\";\nimport * as ProxyEnvironment from \"../ProxyEnvironment\";\nimport * as Transform from \"../Transform\";\nimport type { Primitive, PrimitiveInternal, MaybeUndefined, AnyPrimitive, Validator, InferState, InferProxy, InferSnapshot, NeedsValue, InferUpdateInput, InferSetInput } from \"../Primitive\";\nimport { ValidationError } from \"../Primitive\";\nimport { runValidators, applyDefaults } from \"./shared\";\n\n// =============================================================================\n// Struct Set Input Types\n// =============================================================================\n\n/**\n * Determines if a field is required for set() operations.\n * A field is required if: TRequired is true AND THasDefault is false\n */\ntype IsRequiredForSet<T> = T extends Primitive<any, any, true, false> ? true : false;\n\n/**\n * Extract keys of fields that are required for set() (required without default).\n */\ntype RequiredSetKeys<TFields extends Record<string, AnyPrimitive>> = {\n [K in keyof TFields]: IsRequiredForSet<TFields[K]> extends true ? K : never;\n}[keyof TFields];\n\n/**\n * Extract keys of fields that are optional for set() (has default OR not required).\n */\ntype OptionalSetKeys<TFields extends Record<string, AnyPrimitive>> = {\n [K in keyof TFields]: IsRequiredForSet<TFields[K]> extends true ? never : K;\n}[keyof TFields];\n\n/**\n * Compute the input type for set() operations on a struct.\n * Required fields (required without default) must be provided.\n * Optional fields (has default or not required) can be omitted.\n * Uses each field's TSetInput type to handle nested structs correctly.\n */\nexport type StructSetInput<TFields extends Record<string, AnyPrimitive>> = \n { readonly [K in RequiredSetKeys<TFields>]: InferSetInput<TFields[K]> } &\n { readonly [K in OptionalSetKeys<TFields>]?: InferSetInput<TFields[K]> };\n\n/**\n * Input type for set() - respects required/default status of the struct.\n * If the struct is required without a default, the value must be provided.\n * The value itself uses StructSetInput which handles field-level required/default logic.\n */\ntype InferStructSetInput<TFields extends Record<string, AnyPrimitive>, TRequired extends boolean, THasDefault extends boolean> = \n NeedsValue<StructSetInput<TFields>, TRequired, THasDefault>;\n\n/**\n * Input type for update() - always partial since update only modifies specified fields.\n * For nested structs, allows recursive partial updates.\n */\ntype InferStructUpdateInput<TFields extends Record<string, AnyPrimitive>> = StructUpdateValue<TFields>;\n\n\n/**\n * Maps a schema definition to its state type.\n * { name: StringPrimitive, age: NumberPrimitive } -> { name: string, age: number }\n */\nexport type InferStructState<TFields extends Record<string, AnyPrimitive>> = {\n readonly [K in keyof TFields]: InferState<TFields[K]>;\n};\n\n/**\n * Maps a schema definition to its snapshot type.\n * Each field's snapshot type is inferred from the field primitive.\n */\nexport type InferStructSnapshot<TFields extends Record<string, AnyPrimitive>> = {\n readonly [K in keyof TFields]: InferSnapshot<TFields[K]>;\n};\n\n/**\n * Maps a schema definition to a partial update type.\n * Uses each field's TUpdateInput type, which handles nested updates recursively.\n */\nexport type StructUpdateValue<TFields extends Record<string, AnyPrimitive>> = {\n readonly [K in keyof TFields]?: InferUpdateInput<TFields[K]>;\n};\n\n/**\n * Maps a schema definition to its proxy type.\n * Provides nested field access + get()/set()/toSnapshot() methods for the whole struct.\n */\nexport type StructProxy<TFields extends Record<string, AnyPrimitive>, TRequired extends boolean = false, THasDefault extends boolean = false> = {\n readonly [K in keyof TFields]: InferProxy<TFields[K]>;\n} & {\n /** Gets the entire struct value */\n get(): MaybeUndefined<InferStructState<TFields>, TRequired, THasDefault>;\n /** Sets the entire struct value (only fields that are required without defaults must be provided) */\n set(value: InferStructSetInput<TFields, TRequired, THasDefault>): void;\n /** Updates only the specified fields (partial update, handles nested structs recursively) */\n update(value: InferStructUpdateInput<TFields>): void;\n /** Returns a readonly snapshot of the struct for rendering */\n toSnapshot(): MaybeUndefined<InferStructSnapshot<TFields>, TRequired, THasDefault>;\n};\n\ninterface StructPrimitiveSchema<TFields extends Record<string, AnyPrimitive>> {\n readonly required: boolean;\n readonly defaultValue: InferStructState<TFields> | undefined;\n readonly fields: TFields;\n readonly validators: readonly Validator<InferStructState<TFields>>[];\n}\n\nexport class StructPrimitive<TFields extends Record<string, AnyPrimitive>, TRequired extends boolean = false, THasDefault extends boolean = false>\n implements Primitive<InferStructState<TFields>, StructProxy<TFields, TRequired, THasDefault>, TRequired, THasDefault, InferStructSetInput<TFields, TRequired, THasDefault>, InferStructUpdateInput<TFields>>\n{\n readonly _tag = \"StructPrimitive\" as const;\n readonly _State!: InferStructState<TFields>;\n readonly _Proxy!: StructProxy<TFields, TRequired, THasDefault>;\n readonly _TRequired!: TRequired;\n readonly _THasDefault!: THasDefault;\n readonly TSetInput!: InferStructSetInput<TFields, TRequired, THasDefault>;\n readonly TUpdateInput!: InferStructUpdateInput<TFields>;\n\n private readonly _schema: StructPrimitiveSchema<TFields>;\n\n private readonly _opDefinitions = {\n set: OperationDefinition.make({\n kind: \"struct.set\" as const,\n payload: Schema.Unknown,\n target: Schema.Unknown,\n apply: (payload) => payload,\n }),\n };\n\n constructor(schema: StructPrimitiveSchema<TFields>) {\n this._schema = schema;\n }\n\n /** Mark this struct as required */\n required(): StructPrimitive<TFields, true, THasDefault> {\n return new StructPrimitive({\n ...this._schema,\n required: true,\n });\n }\n\n /** Set a default value for this struct */\n default(defaultValue: StructSetInput<TFields>): StructPrimitive<TFields, TRequired, true> {\n // Apply defaults to the provided value\n const merged = applyDefaults(this as AnyPrimitive, defaultValue as Partial<InferStructState<TFields>>) as InferStructState<TFields>;\n return new StructPrimitive({\n ...this._schema,\n defaultValue: merged,\n });\n }\n\n /** Get the fields schema */\n get fields(): TFields {\n return this._schema.fields;\n }\n\n /** Add a custom validation rule (useful for cross-field validation) */\n refine(fn: (value: InferStructState<TFields>) => boolean, message: string): StructPrimitive<TFields, TRequired, THasDefault> {\n return new StructPrimitive({\n ...this._schema,\n validators: [...this._schema.validators, { validate: fn, message }],\n });\n }\n\n readonly _internal: PrimitiveInternal<InferStructState<TFields>, StructProxy<TFields, TRequired, THasDefault>> = {\n createProxy: (env: ProxyEnvironment.ProxyEnvironment, operationPath: OperationPath.OperationPath): StructProxy<TFields, TRequired, THasDefault> => {\n const fields = this._schema.fields;\n const defaultValue = this._schema.defaultValue;\n\n // Helper to build a snapshot by calling toSnapshot on each field\n const buildSnapshot = (): InferStructSnapshot<TFields> | undefined => {\n const state = env.getState(operationPath);\n \n // Build snapshot from field proxies (they handle their own defaults)\n const snapshot: Record<string, unknown> = {};\n let hasAnyDefinedField = false;\n \n for (const key in fields) {\n const fieldPrimitive = fields[key]!;\n const fieldPath = operationPath.append(key);\n const fieldProxy = fieldPrimitive._internal.createProxy(env, fieldPath);\n const fieldSnapshot = (fieldProxy as { toSnapshot(): unknown }).toSnapshot();\n snapshot[key] = fieldSnapshot;\n if (fieldSnapshot !== undefined) {\n hasAnyDefinedField = true;\n }\n }\n \n // Return undefined only if there's no state, no struct default, and no field snapshots\n if (state === undefined && defaultValue === undefined && !hasAnyDefinedField) {\n return undefined;\n }\n \n return snapshot as InferStructSnapshot<TFields>;\n };\n\n // Create the base object with get/set/update/toSnapshot methods\n const base = {\n get: (): MaybeUndefined<InferStructState<TFields>, TRequired, THasDefault> => {\n const state = env.getState(operationPath) as InferStructState<TFields> | undefined;\n return (state ?? defaultValue) as MaybeUndefined<InferStructState<TFields>, TRequired, THasDefault>;\n },\n set: (value: InferStructSetInput<TFields, TRequired, THasDefault>) => {\n // Apply defaults for missing fields\n const merged = applyDefaults(this as AnyPrimitive, value as Partial<InferStructState<TFields>>) as InferStructState<TFields>;\n env.addOperation(\n Operation.fromDefinition(operationPath, this._opDefinitions.set, merged)\n );\n },\n update: (value: InferStructUpdateInput<TFields>) => {\n for (const key in value) {\n if (Object.prototype.hasOwnProperty.call(value, key)) {\n const fieldValue = value[key as keyof TFields];\n if (fieldValue === undefined) continue; // Skip undefined values\n\n const fieldPrimitive = fields[key as keyof TFields];\n if (!fieldPrimitive) continue; // Skip unknown fields\n\n const fieldPath = operationPath.append(key);\n const fieldProxy = fieldPrimitive._internal.createProxy(env, fieldPath);\n\n // Check if this is a nested struct and value is a plain object (partial update)\n if (\n fieldPrimitive._tag === \"StructPrimitive\" &&\n typeof fieldValue === \"object\" &&\n fieldValue !== null &&\n !Array.isArray(fieldValue)\n ) {\n // Recursively update nested struct\n (fieldProxy as { update: (v: unknown) => void }).update(fieldValue);\n } else {\n // Set the field value directly\n (fieldProxy as { set: (v: unknown) => void }).set(fieldValue);\n }\n }\n }\n },\n toSnapshot: (): MaybeUndefined<InferStructSnapshot<TFields>, TRequired, THasDefault> => {\n const snapshot = buildSnapshot();\n return snapshot as MaybeUndefined<InferStructSnapshot<TFields>, TRequired, THasDefault>;\n },\n };\n\n // Use a JavaScript Proxy to intercept field access\n return new globalThis.Proxy(base as StructProxy<TFields, TRequired, THasDefault>, {\n get: (target, prop, _receiver) => {\n // Return base methods (get, set, update, toSnapshot)\n if (prop === \"get\") {\n return target.get;\n }\n if (prop === \"set\") {\n return target.set;\n }\n if (prop === \"update\") {\n return target.update;\n }\n if (prop === \"toSnapshot\") {\n return target.toSnapshot;\n }\n\n // Handle symbol properties (like Symbol.toStringTag)\n if (typeof prop === \"symbol\") {\n return undefined;\n }\n\n // Check if prop is a field in the schema\n if (prop in fields) {\n const fieldPrimitive = fields[prop as keyof TFields]!;\n const fieldPath = operationPath.append(prop as string);\n return fieldPrimitive._internal.createProxy(env, fieldPath);\n }\n\n return undefined;\n },\n has: (_target, prop) => {\n if (prop === \"get\" || prop === \"set\" || prop === \"update\" || prop === \"toSnapshot\") return true;\n if (typeof prop === \"string\" && prop in fields) return true;\n return false;\n },\n });\n },\n\n applyOperation: (\n state: InferStructState<TFields> | undefined,\n operation: Operation.Operation<any, any, any>\n ): InferStructState<TFields> => {\n const path = operation.path;\n const tokens = path.toTokens().filter((t: string) => t !== \"\");\n\n let newState: InferStructState<TFields>;\n\n // If path is empty or root, this is a struct.set operation\n if (tokens.length === 0) {\n if (operation.kind !== \"struct.set\") {\n throw new ValidationError(`StructPrimitive root cannot apply operation of kind: ${operation.kind}`);\n }\n\n const payload = operation.payload;\n if (typeof payload !== \"object\" || payload === null) {\n throw new ValidationError(`StructPrimitive.set requires an object payload`);\n }\n\n newState = payload as InferStructState<TFields>;\n } else {\n // Otherwise, delegate to the appropriate field primitive\n const fieldName = tokens[0] as keyof TFields;\n if (!(fieldName in this._schema.fields)) {\n throw new ValidationError(`Unknown field: ${globalThis.String(fieldName)}`);\n }\n\n const fieldPrimitive = this._schema.fields[fieldName]!;\n const remainingPath = path.shift();\n const fieldOperation = {\n ...operation,\n path: remainingPath,\n };\n\n // Get the current field state\n const currentState = state ?? ({} as InferStructState<TFields>);\n const currentFieldState = currentState[fieldName] as InferState<typeof fieldPrimitive> | undefined;\n\n // Apply the operation to the field\n const newFieldState = fieldPrimitive._internal.applyOperation(currentFieldState, fieldOperation);\n\n // Build updated state\n newState = {\n ...currentState,\n [fieldName]: newFieldState,\n };\n }\n\n // Run validators on the new state\n runValidators(newState, this._schema.validators);\n\n return newState;\n },\n\n getInitialState: (): InferStructState<TFields> | undefined => {\n if (this._schema.defaultValue !== undefined) {\n return this._schema.defaultValue;\n }\n\n // Build initial state from field defaults\n const fields = this._schema.fields;\n const initialState: Record<string, unknown> = {};\n let hasAnyDefault = false;\n\n for (const key in fields) {\n const fieldDefault = fields[key]!._internal.getInitialState();\n if (fieldDefault !== undefined) {\n initialState[key] = fieldDefault;\n hasAnyDefault = true;\n }\n }\n\n return hasAnyDefault ? (initialState as InferStructState<TFields>) : undefined;\n },\n\n transformOperation: (\n clientOp: Operation.Operation<any, any, any>,\n serverOp: Operation.Operation<any, any, any>\n ): Transform.TransformResult => {\n const clientPath = clientOp.path;\n const serverPath = serverOp.path;\n\n // If paths don't overlap at all, no transformation needed\n if (!OperationPath.pathsOverlap(clientPath, serverPath)) {\n return { type: \"transformed\", operation: clientOp };\n }\n\n const clientTokens = clientPath.toTokens().filter((t: string) => t !== \"\");\n const serverTokens = serverPath.toTokens().filter((t: string) => t !== \"\");\n\n // If both are at root level (struct.set operations)\n if (clientTokens.length === 0 && serverTokens.length === 0) {\n // Client wins (last-write-wins)\n return { type: \"transformed\", operation: clientOp };\n }\n\n // If server set entire struct and client is updating a field\n if (serverTokens.length === 0 && serverOp.kind === \"struct.set\") {\n // Client's field operation proceeds - optimistic update\n // Server will validate/reject if needed\n return { type: \"transformed\", operation: clientOp };\n }\n\n // If client set entire struct and server is updating a field\n if (clientTokens.length === 0 && clientOp.kind === \"struct.set\") {\n // Client's struct.set supersedes server's field update\n return { type: \"transformed\", operation: clientOp };\n }\n\n // Both operations target fields\n if (clientTokens.length > 0 && serverTokens.length > 0) {\n const clientField = clientTokens[0] as keyof TFields;\n const serverField = serverTokens[0] as keyof TFields;\n\n // Different fields - no conflict\n if (clientField !== serverField) {\n return { type: \"transformed\", operation: clientOp };\n }\n\n // Same field - delegate to field primitive\n const fieldPrimitive = this._schema.fields[clientField];\n if (!fieldPrimitive) {\n return { type: \"transformed\", operation: clientOp };\n }\n\n const clientOpForField = {\n ...clientOp,\n path: clientOp.path.shift(),\n };\n const serverOpForField = {\n ...serverOp,\n path: serverOp.path.shift(),\n };\n\n const result = fieldPrimitive._internal.transformOperation(clientOpForField, serverOpForField);\n\n if (result.type === \"transformed\") {\n // Restore the original path\n return {\n type: \"transformed\",\n operation: {\n ...result.operation,\n path: clientOp.path,\n },\n };\n }\n\n return result;\n }\n\n // Default: no transformation needed\n return { type: \"transformed\", operation: clientOp };\n },\n };\n}\n\n/** Creates a new StructPrimitive with the given fields */\nexport const Struct = <TFields extends Record<string, AnyPrimitive>>(\n fields: TFields\n): StructPrimitive<TFields, false, false> =>\n new StructPrimitive({ required: false, defaultValue: undefined, fields, validators: [] });\n\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Struct.mjs","names":["OperationDefinition.make","snapshot: Record<string, unknown>","Operation.fromDefinition","newState: InferStructState<TFields>","initialState: Record<string, unknown>","OperationPath.pathsOverlap","partialFields: Record<string, AnyPrimitive>"],"sources":["../../src/primitives/Struct.ts"],"sourcesContent":["import { Schema } from \"effect\";\nimport * as OperationDefinition from \"../OperationDefinition\";\nimport * as Operation from \"../Operation\";\nimport * as OperationPath from \"../OperationPath\";\nimport * as ProxyEnvironment from \"../ProxyEnvironment\";\nimport * as Transform from \"../Transform\";\nimport type { Primitive, PrimitiveInternal, MaybeUndefined, AnyPrimitive, Validator, InferState, InferProxy, InferSnapshot, NeedsValue, InferUpdateInput, InferSetInput } from \"../Primitive\";\nimport { ValidationError } from \"../Primitive\";\nimport { runValidators, applyDefaults } from \"./shared\";\n\n// =============================================================================\n// Struct Set Input Types\n// =============================================================================\n\n/**\n * Determines if a field is required for set() operations.\n * A field is required if: TRequired is true AND THasDefault is false\n */\ntype IsRequiredForSet<T> = T extends Primitive<any, any, true, false> ? true : false;\n\n/**\n * Extract keys of fields that are required for set() (required without default).\n */\ntype RequiredSetKeys<TFields extends Record<string, AnyPrimitive>> = {\n [K in keyof TFields]: IsRequiredForSet<TFields[K]> extends true ? K : never;\n}[keyof TFields];\n\n/**\n * Extract keys of fields that are optional for set() (has default OR not required).\n */\ntype OptionalSetKeys<TFields extends Record<string, AnyPrimitive>> = {\n [K in keyof TFields]: IsRequiredForSet<TFields[K]> extends true ? never : K;\n}[keyof TFields];\n\n/**\n * Compute the input type for set() operations on a struct.\n * Required fields (required without default) must be provided.\n * Optional fields (has default or not required) can be omitted.\n * Uses each field's TSetInput type to handle nested structs correctly.\n */\nexport type StructSetInput<TFields extends Record<string, AnyPrimitive>> = \n { readonly [K in RequiredSetKeys<TFields>]: InferSetInput<TFields[K]> } &\n { readonly [K in OptionalSetKeys<TFields>]?: InferSetInput<TFields[K]> };\n\n/**\n * Input type for set() - respects required/default status of the struct.\n * If the struct is required without a default, the value must be provided.\n * The value itself uses StructSetInput which handles field-level required/default logic.\n */\ntype InferStructSetInput<TFields extends Record<string, AnyPrimitive>, TRequired extends boolean, THasDefault extends boolean> = \n NeedsValue<StructSetInput<TFields>, TRequired, THasDefault>;\n\n/**\n * Input type for update() - always partial since update only modifies specified fields.\n * For nested structs, allows recursive partial updates.\n */\ntype InferStructUpdateInput<TFields extends Record<string, AnyPrimitive>> = StructUpdateValue<TFields>;\n\n\n/**\n * Maps a schema definition to its state type.\n * { name: StringPrimitive, age: NumberPrimitive } -> { name: string, age: number }\n */\nexport type InferStructState<TFields extends Record<string, AnyPrimitive>> = {\n readonly [K in keyof TFields]: InferState<TFields[K]>;\n};\n\n/**\n * Maps a schema definition to its snapshot type.\n * Each field's snapshot type is inferred from the field primitive.\n */\nexport type InferStructSnapshot<TFields extends Record<string, AnyPrimitive>> = {\n readonly [K in keyof TFields]: InferSnapshot<TFields[K]>;\n};\n\n/**\n * Maps a schema definition to a partial update type.\n * Uses each field's TUpdateInput type, which handles nested updates recursively.\n */\nexport type StructUpdateValue<TFields extends Record<string, AnyPrimitive>> = {\n readonly [K in keyof TFields]?: InferUpdateInput<TFields[K]>;\n};\n\n/**\n * Transforms a primitive type to make it optional (TRequired = false).\n * Preserves the primitive structure while changing the required flag.\n */\nexport type MakeOptional<T extends AnyPrimitive> = T extends Primitive<infer S, infer P, any, infer H, infer SI, infer UI>\n ? Primitive<S, P, false, H, SI, UI>\n : T;\n\n/**\n * Maps each field in a struct to its optional version.\n * All fields become optional (TRequired = false).\n */\nexport type PartialFields<TFields extends Record<string, AnyPrimitive>> = {\n [K in keyof TFields]: MakeOptional<TFields[K]>;\n};\n\n/**\n * Maps a schema definition to its proxy type.\n * Provides nested field access + get()/set()/toSnapshot() methods for the whole struct.\n */\nexport type StructProxy<TFields extends Record<string, AnyPrimitive>, TRequired extends boolean = false, THasDefault extends boolean = false> = {\n readonly [K in keyof TFields]: InferProxy<TFields[K]>;\n} & {\n /** Gets the entire struct value */\n get(): MaybeUndefined<InferStructState<TFields>, TRequired, THasDefault>;\n /** Sets the entire struct value (only fields that are required without defaults must be provided) */\n set(value: InferStructSetInput<TFields, TRequired, THasDefault>): void;\n /** Updates only the specified fields (partial update, handles nested structs recursively) */\n update(value: InferStructUpdateInput<TFields>): void;\n /** Returns a readonly snapshot of the struct for rendering */\n toSnapshot(): MaybeUndefined<InferStructSnapshot<TFields>, TRequired, THasDefault>;\n};\n\ninterface StructPrimitiveSchema<TFields extends Record<string, AnyPrimitive>> {\n readonly required: boolean;\n readonly defaultValue: InferStructState<TFields> | undefined;\n readonly fields: TFields;\n readonly validators: readonly Validator<InferStructState<TFields>>[];\n}\n\nexport class StructPrimitive<TFields extends Record<string, AnyPrimitive>, TRequired extends boolean = false, THasDefault extends boolean = false>\n implements Primitive<InferStructState<TFields>, StructProxy<TFields, TRequired, THasDefault>, TRequired, THasDefault, InferStructSetInput<TFields, TRequired, THasDefault>, InferStructUpdateInput<TFields>>\n{\n readonly _tag = \"StructPrimitive\" as const;\n readonly _State!: InferStructState<TFields>;\n readonly _Proxy!: StructProxy<TFields, TRequired, THasDefault>;\n readonly _TRequired!: TRequired;\n readonly _THasDefault!: THasDefault;\n readonly TSetInput!: InferStructSetInput<TFields, TRequired, THasDefault>;\n readonly TUpdateInput!: InferStructUpdateInput<TFields>;\n\n private readonly _schema: StructPrimitiveSchema<TFields>;\n\n private readonly _opDefinitions = {\n set: OperationDefinition.make({\n kind: \"struct.set\" as const,\n payload: Schema.Unknown,\n target: Schema.Unknown,\n apply: (payload) => payload,\n }),\n };\n\n constructor(schema: StructPrimitiveSchema<TFields>) {\n this._schema = schema;\n }\n\n /** Mark this struct as required */\n required(): StructPrimitive<TFields, true, THasDefault> {\n return new StructPrimitive({\n ...this._schema,\n required: true,\n });\n }\n\n /** Set a default value for this struct */\n default(defaultValue: StructSetInput<TFields>): StructPrimitive<TFields, TRequired, true> {\n // Apply defaults to the provided value\n const merged = applyDefaults(this as AnyPrimitive, defaultValue as Partial<InferStructState<TFields>>) as InferStructState<TFields>;\n return new StructPrimitive({\n ...this._schema,\n defaultValue: merged,\n });\n }\n\n /** Get the fields schema */\n get fields(): TFields {\n return this._schema.fields;\n }\n\n /** Add a custom validation rule (useful for cross-field validation) */\n refine(fn: (value: InferStructState<TFields>) => boolean, message: string): StructPrimitive<TFields, TRequired, THasDefault> {\n return new StructPrimitive({\n ...this._schema,\n validators: [...this._schema.validators, { validate: fn, message }],\n });\n }\n\n /** Extend this struct with additional fields */\n extend<TNewFields extends Record<string, AnyPrimitive>>(\n newFields: TNewFields\n ): StructPrimitive<TFields & TNewFields, TRequired, THasDefault> {\n return new StructPrimitive<TFields & TNewFields, TRequired, THasDefault>({\n required: this._schema.required,\n defaultValue: undefined,\n fields: { ...this._schema.fields, ...newFields } as TFields & TNewFields,\n validators: [],\n });\n }\n\n /** Make all properties of this struct optional (TRequired = false for all fields) */\n partial(): StructPrimitive<PartialFields<TFields>, TRequired, THasDefault> {\n const partialFields: Record<string, AnyPrimitive> = {};\n for (const key in this._schema.fields) {\n const field = this._schema.fields[key]!;\n // Create a new field that is not required (optional)\n partialFields[key] = this._makeFieldOptional(field);\n }\n return new StructPrimitive<PartialFields<TFields>, TRequired, THasDefault>({\n required: this._schema.required,\n defaultValue: undefined,\n fields: partialFields as PartialFields<TFields>,\n validators: [],\n });\n }\n\n private _makeFieldOptional(field: AnyPrimitive): AnyPrimitive {\n // Create a new primitive with required: false\n // We access the _schema property if available, otherwise return as-is\n const fieldAny = field as any;\n if (fieldAny._schema && typeof fieldAny._schema === \"object\") {\n const Constructor = field.constructor as new (schema: any) => AnyPrimitive;\n return new Constructor({\n ...fieldAny._schema,\n required: false,\n });\n }\n return field;\n }\n\n readonly _internal: PrimitiveInternal<InferStructState<TFields>, StructProxy<TFields, TRequired, THasDefault>> = {\n createProxy: (env: ProxyEnvironment.ProxyEnvironment, operationPath: OperationPath.OperationPath): StructProxy<TFields, TRequired, THasDefault> => {\n const fields = this._schema.fields;\n const defaultValue = this._schema.defaultValue;\n\n // Helper to build a snapshot by calling toSnapshot on each field\n const buildSnapshot = (): InferStructSnapshot<TFields> | undefined => {\n const state = env.getState(operationPath);\n \n // Build snapshot from field proxies (they handle their own defaults)\n const snapshot: Record<string, unknown> = {};\n let hasAnyDefinedField = false;\n \n for (const key in fields) {\n const fieldPrimitive = fields[key]!;\n const fieldPath = operationPath.append(key);\n const fieldProxy = fieldPrimitive._internal.createProxy(env, fieldPath);\n const fieldSnapshot = (fieldProxy as { toSnapshot(): unknown }).toSnapshot();\n snapshot[key] = fieldSnapshot;\n if (fieldSnapshot !== undefined) {\n hasAnyDefinedField = true;\n }\n }\n \n // Return undefined only if there's no state, no struct default, and no field snapshots\n if (state === undefined && defaultValue === undefined && !hasAnyDefinedField) {\n return undefined;\n }\n \n return snapshot as InferStructSnapshot<TFields>;\n };\n\n // Create the base object with get/set/update/toSnapshot methods\n const base = {\n get: (): MaybeUndefined<InferStructState<TFields>, TRequired, THasDefault> => {\n const state = env.getState(operationPath) as InferStructState<TFields> | undefined;\n return (state ?? defaultValue) as MaybeUndefined<InferStructState<TFields>, TRequired, THasDefault>;\n },\n set: (value: InferStructSetInput<TFields, TRequired, THasDefault>) => {\n // Apply defaults for missing fields\n const merged = applyDefaults(this as AnyPrimitive, value as Partial<InferStructState<TFields>>) as InferStructState<TFields>;\n env.addOperation(\n Operation.fromDefinition(operationPath, this._opDefinitions.set, merged)\n );\n },\n update: (value: InferStructUpdateInput<TFields>) => {\n for (const key in value) {\n if (Object.prototype.hasOwnProperty.call(value, key)) {\n const fieldValue = value[key as keyof TFields];\n if (fieldValue === undefined) continue; // Skip undefined values\n\n const fieldPrimitive = fields[key as keyof TFields];\n if (!fieldPrimitive) continue; // Skip unknown fields\n\n const fieldPath = operationPath.append(key);\n const fieldProxy = fieldPrimitive._internal.createProxy(env, fieldPath);\n\n // Check if this is a nested struct and value is a plain object (partial update)\n if (\n fieldPrimitive._tag === \"StructPrimitive\" &&\n typeof fieldValue === \"object\" &&\n fieldValue !== null &&\n !Array.isArray(fieldValue)\n ) {\n // Recursively update nested struct\n (fieldProxy as { update: (v: unknown) => void }).update(fieldValue);\n } else {\n // Set the field value directly\n (fieldProxy as { set: (v: unknown) => void }).set(fieldValue);\n }\n }\n }\n },\n toSnapshot: (): MaybeUndefined<InferStructSnapshot<TFields>, TRequired, THasDefault> => {\n const snapshot = buildSnapshot();\n return snapshot as MaybeUndefined<InferStructSnapshot<TFields>, TRequired, THasDefault>;\n },\n };\n\n // Use a JavaScript Proxy to intercept field access\n return new globalThis.Proxy(base as StructProxy<TFields, TRequired, THasDefault>, {\n get: (target, prop, _receiver) => {\n // Return base methods (get, set, update, toSnapshot)\n if (prop === \"get\") {\n return target.get;\n }\n if (prop === \"set\") {\n return target.set;\n }\n if (prop === \"update\") {\n return target.update;\n }\n if (prop === \"toSnapshot\") {\n return target.toSnapshot;\n }\n\n // Handle symbol properties (like Symbol.toStringTag)\n if (typeof prop === \"symbol\") {\n return undefined;\n }\n\n // Check if prop is a field in the schema\n if (prop in fields) {\n const fieldPrimitive = fields[prop as keyof TFields]!;\n const fieldPath = operationPath.append(prop as string);\n return fieldPrimitive._internal.createProxy(env, fieldPath);\n }\n\n return undefined;\n },\n has: (_target, prop) => {\n if (prop === \"get\" || prop === \"set\" || prop === \"update\" || prop === \"toSnapshot\") return true;\n if (typeof prop === \"string\" && prop in fields) return true;\n return false;\n },\n });\n },\n\n applyOperation: (\n state: InferStructState<TFields> | undefined,\n operation: Operation.Operation<any, any, any>\n ): InferStructState<TFields> => {\n const path = operation.path;\n const tokens = path.toTokens().filter((t: string) => t !== \"\");\n\n let newState: InferStructState<TFields>;\n\n // If path is empty or root, this is a struct.set operation\n if (tokens.length === 0) {\n if (operation.kind !== \"struct.set\") {\n throw new ValidationError(`StructPrimitive root cannot apply operation of kind: ${operation.kind}`);\n }\n\n const payload = operation.payload;\n if (typeof payload !== \"object\" || payload === null) {\n throw new ValidationError(`StructPrimitive.set requires an object payload`);\n }\n\n newState = payload as InferStructState<TFields>;\n } else {\n // Otherwise, delegate to the appropriate field primitive\n const fieldName = tokens[0] as keyof TFields;\n if (!(fieldName in this._schema.fields)) {\n throw new ValidationError(`Unknown field: ${globalThis.String(fieldName)}`);\n }\n\n const fieldPrimitive = this._schema.fields[fieldName]!;\n const remainingPath = path.shift();\n const fieldOperation = {\n ...operation,\n path: remainingPath,\n };\n\n // Get the current field state\n const currentState = state ?? ({} as InferStructState<TFields>);\n const currentFieldState = currentState[fieldName] as InferState<typeof fieldPrimitive> | undefined;\n\n // Apply the operation to the field\n const newFieldState = fieldPrimitive._internal.applyOperation(currentFieldState, fieldOperation);\n\n // Build updated state\n newState = {\n ...currentState,\n [fieldName]: newFieldState,\n };\n }\n\n // Run validators on the new state\n runValidators(newState, this._schema.validators);\n\n return newState;\n },\n\n getInitialState: (): InferStructState<TFields> | undefined => {\n if (this._schema.defaultValue !== undefined) {\n return this._schema.defaultValue;\n }\n\n // Build initial state from field defaults\n const fields = this._schema.fields;\n const initialState: Record<string, unknown> = {};\n let hasAnyDefault = false;\n\n for (const key in fields) {\n const fieldDefault = fields[key]!._internal.getInitialState();\n if (fieldDefault !== undefined) {\n initialState[key] = fieldDefault;\n hasAnyDefault = true;\n }\n }\n\n return hasAnyDefault ? (initialState as InferStructState<TFields>) : undefined;\n },\n\n transformOperation: (\n clientOp: Operation.Operation<any, any, any>,\n serverOp: Operation.Operation<any, any, any>\n ): Transform.TransformResult => {\n const clientPath = clientOp.path;\n const serverPath = serverOp.path;\n\n // If paths don't overlap at all, no transformation needed\n if (!OperationPath.pathsOverlap(clientPath, serverPath)) {\n return { type: \"transformed\", operation: clientOp };\n }\n\n const clientTokens = clientPath.toTokens().filter((t: string) => t !== \"\");\n const serverTokens = serverPath.toTokens().filter((t: string) => t !== \"\");\n\n // If both are at root level (struct.set operations)\n if (clientTokens.length === 0 && serverTokens.length === 0) {\n // Client wins (last-write-wins)\n return { type: \"transformed\", operation: clientOp };\n }\n\n // If server set entire struct and client is updating a field\n if (serverTokens.length === 0 && serverOp.kind === \"struct.set\") {\n // Client's field operation proceeds - optimistic update\n // Server will validate/reject if needed\n return { type: \"transformed\", operation: clientOp };\n }\n\n // If client set entire struct and server is updating a field\n if (clientTokens.length === 0 && clientOp.kind === \"struct.set\") {\n // Client's struct.set supersedes server's field update\n return { type: \"transformed\", operation: clientOp };\n }\n\n // Both operations target fields\n if (clientTokens.length > 0 && serverTokens.length > 0) {\n const clientField = clientTokens[0] as keyof TFields;\n const serverField = serverTokens[0] as keyof TFields;\n\n // Different fields - no conflict\n if (clientField !== serverField) {\n return { type: \"transformed\", operation: clientOp };\n }\n\n // Same field - delegate to field primitive\n const fieldPrimitive = this._schema.fields[clientField];\n if (!fieldPrimitive) {\n return { type: \"transformed\", operation: clientOp };\n }\n\n const clientOpForField = {\n ...clientOp,\n path: clientOp.path.shift(),\n };\n const serverOpForField = {\n ...serverOp,\n path: serverOp.path.shift(),\n };\n\n const result = fieldPrimitive._internal.transformOperation(clientOpForField, serverOpForField);\n\n if (result.type === \"transformed\") {\n // Restore the original path\n return {\n type: \"transformed\",\n operation: {\n ...result.operation,\n path: clientOp.path,\n },\n };\n }\n\n return result;\n }\n\n // Default: no transformation needed\n return { type: \"transformed\", operation: clientOp };\n },\n };\n}\n\n/** Creates a new StructPrimitive with the given fields */\nexport const Struct = <TFields extends Record<string, AnyPrimitive>>(\n fields: TFields\n): StructPrimitive<TFields, false, false> =>\n new StructPrimitive({ required: false, defaultValue: undefined, fields, validators: [] });\n\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voidhash/mimic",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"typescript": "5.8.3",
|
|
32
32
|
"vite-tsconfig-paths": "^5.1.4",
|
|
33
33
|
"vitest": "^3.2.4",
|
|
34
|
-
"@voidhash/tsconfig": "0.0.
|
|
34
|
+
"@voidhash/tsconfig": "0.0.9"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
37
|
"effect": "^3.19.12"
|
package/src/primitives/Struct.ts
CHANGED
|
@@ -81,6 +81,22 @@ export type StructUpdateValue<TFields extends Record<string, AnyPrimitive>> = {
|
|
|
81
81
|
readonly [K in keyof TFields]?: InferUpdateInput<TFields[K]>;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Transforms a primitive type to make it optional (TRequired = false).
|
|
86
|
+
* Preserves the primitive structure while changing the required flag.
|
|
87
|
+
*/
|
|
88
|
+
export type MakeOptional<T extends AnyPrimitive> = T extends Primitive<infer S, infer P, any, infer H, infer SI, infer UI>
|
|
89
|
+
? Primitive<S, P, false, H, SI, UI>
|
|
90
|
+
: T;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Maps each field in a struct to its optional version.
|
|
94
|
+
* All fields become optional (TRequired = false).
|
|
95
|
+
*/
|
|
96
|
+
export type PartialFields<TFields extends Record<string, AnyPrimitive>> = {
|
|
97
|
+
[K in keyof TFields]: MakeOptional<TFields[K]>;
|
|
98
|
+
};
|
|
99
|
+
|
|
84
100
|
/**
|
|
85
101
|
* Maps a schema definition to its proxy type.
|
|
86
102
|
* Provides nested field access + get()/set()/toSnapshot() methods for the whole struct.
|
|
@@ -162,6 +178,48 @@ export class StructPrimitive<TFields extends Record<string, AnyPrimitive>, TRequ
|
|
|
162
178
|
});
|
|
163
179
|
}
|
|
164
180
|
|
|
181
|
+
/** Extend this struct with additional fields */
|
|
182
|
+
extend<TNewFields extends Record<string, AnyPrimitive>>(
|
|
183
|
+
newFields: TNewFields
|
|
184
|
+
): StructPrimitive<TFields & TNewFields, TRequired, THasDefault> {
|
|
185
|
+
return new StructPrimitive<TFields & TNewFields, TRequired, THasDefault>({
|
|
186
|
+
required: this._schema.required,
|
|
187
|
+
defaultValue: undefined,
|
|
188
|
+
fields: { ...this._schema.fields, ...newFields } as TFields & TNewFields,
|
|
189
|
+
validators: [],
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** Make all properties of this struct optional (TRequired = false for all fields) */
|
|
194
|
+
partial(): StructPrimitive<PartialFields<TFields>, TRequired, THasDefault> {
|
|
195
|
+
const partialFields: Record<string, AnyPrimitive> = {};
|
|
196
|
+
for (const key in this._schema.fields) {
|
|
197
|
+
const field = this._schema.fields[key]!;
|
|
198
|
+
// Create a new field that is not required (optional)
|
|
199
|
+
partialFields[key] = this._makeFieldOptional(field);
|
|
200
|
+
}
|
|
201
|
+
return new StructPrimitive<PartialFields<TFields>, TRequired, THasDefault>({
|
|
202
|
+
required: this._schema.required,
|
|
203
|
+
defaultValue: undefined,
|
|
204
|
+
fields: partialFields as PartialFields<TFields>,
|
|
205
|
+
validators: [],
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private _makeFieldOptional(field: AnyPrimitive): AnyPrimitive {
|
|
210
|
+
// Create a new primitive with required: false
|
|
211
|
+
// We access the _schema property if available, otherwise return as-is
|
|
212
|
+
const fieldAny = field as any;
|
|
213
|
+
if (fieldAny._schema && typeof fieldAny._schema === "object") {
|
|
214
|
+
const Constructor = field.constructor as new (schema: any) => AnyPrimitive;
|
|
215
|
+
return new Constructor({
|
|
216
|
+
...fieldAny._schema,
|
|
217
|
+
required: false,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
return field;
|
|
221
|
+
}
|
|
222
|
+
|
|
165
223
|
readonly _internal: PrimitiveInternal<InferStructState<TFields>, StructProxy<TFields, TRequired, THasDefault>> = {
|
|
166
224
|
createProxy: (env: ProxyEnvironment.ProxyEnvironment, operationPath: OperationPath.OperationPath): StructProxy<TFields, TRequired, THasDefault> => {
|
|
167
225
|
const fields = this._schema.fields;
|
|
@@ -554,6 +554,352 @@ describe("StructPrimitive", () => {
|
|
|
554
554
|
expect(operations[0]!.path.toTokens()).toEqual(["users", "0", "name"]);
|
|
555
555
|
});
|
|
556
556
|
});
|
|
557
|
+
describe("extend", () => {
|
|
558
|
+
it("extends struct with additional fields", () => {
|
|
559
|
+
const basePrimitive = Primitive.Struct({
|
|
560
|
+
name: Primitive.String().required(),
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
const extendedPrimitive = basePrimitive.extend({
|
|
564
|
+
email: Primitive.String().required(),
|
|
565
|
+
age: Primitive.Number(),
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
// Verify fields exist
|
|
569
|
+
expect(extendedPrimitive.fields).toHaveProperty("name");
|
|
570
|
+
expect(extendedPrimitive.fields).toHaveProperty("email");
|
|
571
|
+
expect(extendedPrimitive.fields).toHaveProperty("age");
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
it("extended struct generates correct operations", () => {
|
|
575
|
+
const operations: Operation.Operation<any, any, any>[] = [];
|
|
576
|
+
const env = ProxyEnvironment.make((op) => {
|
|
577
|
+
operations.push(op);
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
const basePrimitive = Primitive.Struct({
|
|
581
|
+
name: Primitive.String(),
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
const extendedPrimitive = basePrimitive.extend({
|
|
585
|
+
email: Primitive.String(),
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
const proxy = extendedPrimitive._internal.createProxy(env, OperationPath.make(""));
|
|
589
|
+
|
|
590
|
+
proxy.name.set("John");
|
|
591
|
+
proxy.email.set("john@example.com");
|
|
592
|
+
|
|
593
|
+
expect(operations).toHaveLength(2);
|
|
594
|
+
expect(operations[0]!.kind).toBe("string.set");
|
|
595
|
+
expect(operations[0]!.payload).toBe("John");
|
|
596
|
+
expect(operations[0]!.path.toTokens()).toEqual(["name"]);
|
|
597
|
+
expect(operations[1]!.kind).toBe("string.set");
|
|
598
|
+
expect(operations[1]!.payload).toBe("john@example.com");
|
|
599
|
+
expect(operations[1]!.path.toTokens()).toEqual(["email"]);
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
it("extended struct set() works with all fields", () => {
|
|
603
|
+
const operations: Operation.Operation<any, any, any>[] = [];
|
|
604
|
+
const env = ProxyEnvironment.make((op) => {
|
|
605
|
+
operations.push(op);
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
const basePrimitive = Primitive.Struct({
|
|
609
|
+
name: Primitive.String(),
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
const extendedPrimitive = basePrimitive.extend({
|
|
613
|
+
email: Primitive.String(),
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
const proxy = extendedPrimitive._internal.createProxy(env, OperationPath.make(""));
|
|
617
|
+
|
|
618
|
+
proxy.set({ name: "John", email: "john@example.com" });
|
|
619
|
+
|
|
620
|
+
expect(operations).toHaveLength(1);
|
|
621
|
+
expect(operations[0]!.kind).toBe("struct.set");
|
|
622
|
+
expect(operations[0]!.payload).toEqual({ name: "John", email: "john@example.com" });
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
it("extended struct preserves required status", () => {
|
|
626
|
+
const basePrimitive = Primitive.Struct({
|
|
627
|
+
name: Primitive.String(),
|
|
628
|
+
}).required();
|
|
629
|
+
|
|
630
|
+
const extendedPrimitive = basePrimitive.extend({
|
|
631
|
+
email: Primitive.String(),
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
// The extended struct should still be required - verify via type system
|
|
635
|
+
// Compile-time check: if the type doesn't match, this would be a type error
|
|
636
|
+
type ExtendedTRequired = typeof extendedPrimitive._TRequired;
|
|
637
|
+
const _typeCheck: ExtendedTRequired = true as const;
|
|
638
|
+
expect(_typeCheck).toBe(true);
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
it("extended struct applyOperation works for both base and new fields", () => {
|
|
642
|
+
const basePrimitive = Primitive.Struct({
|
|
643
|
+
name: Primitive.String(),
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
const extendedPrimitive = basePrimitive.extend({
|
|
647
|
+
email: Primitive.String(),
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
const nameOperation: Operation.Operation<any, any, any> = {
|
|
651
|
+
kind: "string.set",
|
|
652
|
+
path: OperationPath.make("name"),
|
|
653
|
+
payload: "John",
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
const emailOperation: Operation.Operation<any, any, any> = {
|
|
657
|
+
kind: "string.set",
|
|
658
|
+
path: OperationPath.make("email"),
|
|
659
|
+
payload: "john@example.com",
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
let state = extendedPrimitive._internal.applyOperation(undefined, nameOperation);
|
|
663
|
+
state = extendedPrimitive._internal.applyOperation(state, emailOperation);
|
|
664
|
+
|
|
665
|
+
expect(state).toEqual({ name: "John", email: "john@example.com" });
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
it("can chain multiple extend calls", () => {
|
|
669
|
+
const basePrimitive = Primitive.Struct({
|
|
670
|
+
id: Primitive.String(),
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
const extendedOnce = basePrimitive.extend({
|
|
674
|
+
name: Primitive.String(),
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
const extendedTwice = extendedOnce.extend({
|
|
678
|
+
email: Primitive.String(),
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
expect(extendedTwice.fields).toHaveProperty("id");
|
|
682
|
+
expect(extendedTwice.fields).toHaveProperty("name");
|
|
683
|
+
expect(extendedTwice.fields).toHaveProperty("email");
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
it("extend with nested struct works correctly", () => {
|
|
687
|
+
const operations: Operation.Operation<any, any, any>[] = [];
|
|
688
|
+
const env = ProxyEnvironment.make((op) => {
|
|
689
|
+
operations.push(op);
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
const basePrimitive = Primitive.Struct({
|
|
693
|
+
name: Primitive.String(),
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
const addressPrimitive = Primitive.Struct({
|
|
697
|
+
city: Primitive.String(),
|
|
698
|
+
zip: Primitive.String(),
|
|
699
|
+
});
|
|
700
|
+
|
|
701
|
+
const extendedPrimitive = basePrimitive.extend({
|
|
702
|
+
address: addressPrimitive,
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
const proxy = extendedPrimitive._internal.createProxy(env, OperationPath.make(""));
|
|
706
|
+
|
|
707
|
+
proxy.address.city.set("New York");
|
|
708
|
+
|
|
709
|
+
expect(operations).toHaveLength(1);
|
|
710
|
+
expect(operations[0]!.kind).toBe("string.set");
|
|
711
|
+
expect(operations[0]!.payload).toBe("New York");
|
|
712
|
+
expect(operations[0]!.path.toTokens()).toEqual(["address", "city"]);
|
|
713
|
+
});
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
describe("partial", () => {
|
|
717
|
+
it("makes all fields optional", () => {
|
|
718
|
+
const structPrimitive = Primitive.Struct({
|
|
719
|
+
name: Primitive.String().required(),
|
|
720
|
+
email: Primitive.String().required(),
|
|
721
|
+
age: Primitive.Number().required(),
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
const partialPrimitive = structPrimitive.partial();
|
|
725
|
+
|
|
726
|
+
// All fields should now be optional (not required)
|
|
727
|
+
expect(partialPrimitive.fields).toHaveProperty("name");
|
|
728
|
+
expect(partialPrimitive.fields).toHaveProperty("email");
|
|
729
|
+
expect(partialPrimitive.fields).toHaveProperty("age");
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
it("partial struct allows empty set()", () => {
|
|
733
|
+
const operations: Operation.Operation<any, any, any>[] = [];
|
|
734
|
+
const env = ProxyEnvironment.make((op) => {
|
|
735
|
+
operations.push(op);
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
const structPrimitive = Primitive.Struct({
|
|
739
|
+
name: Primitive.String().required(),
|
|
740
|
+
email: Primitive.String().required(),
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
const partialPrimitive = structPrimitive.partial();
|
|
744
|
+
|
|
745
|
+
const proxy = partialPrimitive._internal.createProxy(env, OperationPath.make(""));
|
|
746
|
+
|
|
747
|
+
// This should work without providing any fields since all are optional
|
|
748
|
+
proxy.set({});
|
|
749
|
+
|
|
750
|
+
expect(operations).toHaveLength(1);
|
|
751
|
+
expect(operations[0]!.kind).toBe("struct.set");
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
it("partial struct allows partial set()", () => {
|
|
755
|
+
const operations: Operation.Operation<any, any, any>[] = [];
|
|
756
|
+
const env = ProxyEnvironment.make((op) => {
|
|
757
|
+
operations.push(op);
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
const structPrimitive = Primitive.Struct({
|
|
761
|
+
name: Primitive.String().required(),
|
|
762
|
+
email: Primitive.String().required(),
|
|
763
|
+
age: Primitive.Number().required(),
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
const partialPrimitive = structPrimitive.partial();
|
|
767
|
+
|
|
768
|
+
const proxy = partialPrimitive._internal.createProxy(env, OperationPath.make(""));
|
|
769
|
+
|
|
770
|
+
// Only provide some fields
|
|
771
|
+
proxy.set({ name: "John" });
|
|
772
|
+
|
|
773
|
+
expect(operations).toHaveLength(1);
|
|
774
|
+
expect(operations[0]!.kind).toBe("struct.set");
|
|
775
|
+
expect(operations[0]!.payload).toHaveProperty("name", "John");
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
it("partial struct field access still works", () => {
|
|
779
|
+
const operations: Operation.Operation<any, any, any>[] = [];
|
|
780
|
+
const env = ProxyEnvironment.make((op) => {
|
|
781
|
+
operations.push(op);
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
const structPrimitive = Primitive.Struct({
|
|
785
|
+
name: Primitive.String().required(),
|
|
786
|
+
email: Primitive.String().required(),
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
const partialPrimitive = structPrimitive.partial();
|
|
790
|
+
|
|
791
|
+
const proxy = partialPrimitive._internal.createProxy(env, OperationPath.make(""));
|
|
792
|
+
|
|
793
|
+
proxy.name.set("John");
|
|
794
|
+
|
|
795
|
+
expect(operations).toHaveLength(1);
|
|
796
|
+
expect(operations[0]!.kind).toBe("string.set");
|
|
797
|
+
expect(operations[0]!.payload).toBe("John");
|
|
798
|
+
expect(operations[0]!.path.toTokens()).toEqual(["name"]);
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
it("partial struct preserves required/default status of struct itself", () => {
|
|
802
|
+
const structPrimitive = Primitive.Struct({
|
|
803
|
+
name: Primitive.String().required(),
|
|
804
|
+
}).required();
|
|
805
|
+
|
|
806
|
+
const partialPrimitive = structPrimitive.partial();
|
|
807
|
+
// The struct itself should still be required - verify via type system
|
|
808
|
+
// Compile-time check: if the type doesn't match, this would be a type error
|
|
809
|
+
type PartialTRequired = typeof partialPrimitive._TRequired;
|
|
810
|
+
const _typeCheck: PartialTRequired = true as const;
|
|
811
|
+
expect(_typeCheck).toBe(true);
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
it("partial struct applyOperation works correctly", () => {
|
|
815
|
+
const structPrimitive = Primitive.Struct({
|
|
816
|
+
name: Primitive.String().required(),
|
|
817
|
+
email: Primitive.String().required(),
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
const partialPrimitive = structPrimitive.partial();
|
|
821
|
+
|
|
822
|
+
const operation: Operation.Operation<any, any, any> = {
|
|
823
|
+
kind: "string.set",
|
|
824
|
+
path: OperationPath.make("name"),
|
|
825
|
+
payload: "John",
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
const result = partialPrimitive._internal.applyOperation(undefined, operation);
|
|
829
|
+
|
|
830
|
+
expect(result).toEqual({ name: "John" });
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
it("partial can be combined with extend", () => {
|
|
834
|
+
const basePrimitive = Primitive.Struct({
|
|
835
|
+
id: Primitive.String().required(),
|
|
836
|
+
name: Primitive.String().required(),
|
|
837
|
+
});
|
|
838
|
+
|
|
839
|
+
// First extend, then partial
|
|
840
|
+
const extendedPartial = basePrimitive
|
|
841
|
+
.extend({
|
|
842
|
+
email: Primitive.String().required(),
|
|
843
|
+
})
|
|
844
|
+
.partial();
|
|
845
|
+
|
|
846
|
+
expect(extendedPartial.fields).toHaveProperty("id");
|
|
847
|
+
expect(extendedPartial.fields).toHaveProperty("name");
|
|
848
|
+
expect(extendedPartial.fields).toHaveProperty("email");
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
it("partial works with nested structs", () => {
|
|
852
|
+
const addressPrimitive = Primitive.Struct({
|
|
853
|
+
city: Primitive.String().required(),
|
|
854
|
+
zip: Primitive.String().required(),
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
const personPrimitive = Primitive.Struct({
|
|
858
|
+
name: Primitive.String().required(),
|
|
859
|
+
address: addressPrimitive.required(),
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
const partialPrimitive = personPrimitive.partial();
|
|
863
|
+
|
|
864
|
+
const operations: Operation.Operation<any, any, any>[] = [];
|
|
865
|
+
const env = ProxyEnvironment.make((op) => {
|
|
866
|
+
operations.push(op);
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
const proxy = partialPrimitive._internal.createProxy(env, OperationPath.make(""));
|
|
870
|
+
|
|
871
|
+
// Nested struct access should still work
|
|
872
|
+
proxy.address.city.set("New York");
|
|
873
|
+
|
|
874
|
+
expect(operations).toHaveLength(1);
|
|
875
|
+
expect(operations[0]!.kind).toBe("string.set");
|
|
876
|
+
expect(operations[0]!.payload).toBe("New York");
|
|
877
|
+
expect(operations[0]!.path.toTokens()).toEqual(["address", "city"]);
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
it("partial struct update() works correctly", () => {
|
|
881
|
+
const operations: Operation.Operation<any, any, any>[] = [];
|
|
882
|
+
const env = ProxyEnvironment.make((op) => {
|
|
883
|
+
operations.push(op);
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
const structPrimitive = Primitive.Struct({
|
|
887
|
+
name: Primitive.String().required(),
|
|
888
|
+
email: Primitive.String().required(),
|
|
889
|
+
age: Primitive.Number().required(),
|
|
890
|
+
});
|
|
891
|
+
|
|
892
|
+
const partialPrimitive = structPrimitive.partial();
|
|
893
|
+
|
|
894
|
+
const proxy = partialPrimitive._internal.createProxy(env, OperationPath.make(""));
|
|
895
|
+
|
|
896
|
+
proxy.update({ name: "Jane" });
|
|
897
|
+
|
|
898
|
+
expect(operations).toHaveLength(1);
|
|
899
|
+
expect(operations[0]!.kind).toBe("string.set");
|
|
900
|
+
expect(operations[0]!.payload).toBe("Jane");
|
|
901
|
+
});
|
|
902
|
+
});
|
|
557
903
|
});
|
|
558
904
|
|
|
559
905
|
// =============================================================================
|