@gialicus/smart-object 2.0.0 → 2.0.1
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/CHANGELOG.md +12 -0
- package/README.md +35 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/smart-object/apply-operations.d.ts.map +1 -1
- package/dist/smart-object/apply-operations.js +3 -1
- package/dist/smart-object/build-class.d.ts.map +1 -1
- package/dist/smart-object/build-class.js +2 -4
- package/dist/smart-object/codecs.d.ts +15 -0
- package/dist/smart-object/codecs.d.ts.map +1 -0
- package/dist/smart-object/codecs.js +163 -0
- package/dist/smart-object/define-prototype.d.ts.map +1 -1
- package/dist/smart-object/define-prototype.js +55 -3
- package/dist/smart-object/factory.d.ts +2 -0
- package/dist/smart-object/factory.d.ts.map +1 -1
- package/dist/smart-object/factory.js +20 -8
- package/dist/smart-object/json-patch.d.ts +2 -1
- package/dist/smart-object/json-patch.d.ts.map +1 -1
- package/dist/smart-object/json-patch.js +26 -1
- package/dist/smart-object/read-field.d.ts.map +1 -1
- package/dist/smart-object/read-field.js +6 -0
- package/dist/smart-object/setters/object-field.d.ts +3 -2
- package/dist/smart-object/setters/object-field.d.ts.map +1 -1
- package/dist/smart-object/setters/object-field.js +37 -5
- package/dist/smart-object/setters/record-field.d.ts +7 -0
- package/dist/smart-object/setters/record-field.d.ts.map +1 -0
- package/dist/smart-object/setters/record-field.js +133 -0
- package/dist/smart-object/setters/variant-switch.d.ts +5 -0
- package/dist/smart-object/setters/variant-switch.d.ts.map +1 -0
- package/dist/smart-object/setters/variant-switch.js +37 -0
- package/dist/types.d.ts +30 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/zod-introspect.d.ts +36 -0
- package/dist/zod-introspect.d.ts.map +1 -1
- package/dist/zod-introspect.js +216 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.0.1] - 2026-06-27
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Support for `z.date()` and `z.coerce.date()` with ISO 8601 operation values and `Date` getters
|
|
13
|
+
- Support for `z.bigint()`, `z.map` (string keys), and `z.set` via explicit JSON-safe codecs
|
|
14
|
+
- Per-entry API for `z.record` fields: `get{Field}Entry`, `set{Field}Entry`, `delete{Field}Entry`
|
|
15
|
+
- Union variant switching: `switchVariant` and generated `switchTo{Variant}` for discriminated unions
|
|
16
|
+
- Root schema variants: `z.intersection` and `z.lazy`
|
|
17
|
+
- Zod schema introspection module (`src/zod-introspect.ts`) and codec layer (`src/smart-object/codecs.ts`)
|
|
18
|
+
|
|
8
19
|
## [2.0.0] - 2026-06-27
|
|
9
20
|
|
|
10
21
|
### Breaking
|
|
@@ -39,5 +50,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
39
50
|
- `fromOperations(initial, operations)` static method for deterministic replay
|
|
40
51
|
- Exported types: `Operation`, `SetMethods`, `SetMethodsUnion`, `AllKeys`, `UnionDataShape`, `OperationsAccessor`, `SmartObjectConstructor`, `SmartObjectInstance`
|
|
41
52
|
|
|
53
|
+
[2.0.1]: https://github.com/gialicus/smart-object/compare/v2.0.0...v2.0.1
|
|
42
54
|
[2.0.0]: https://github.com/gialicus/smart-object/compare/v1.0.0...v2.0.0
|
|
43
55
|
[1.0.0]: https://github.com/gialicus/smart-object/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -63,6 +63,10 @@ const Event = SmartObject(z.discriminatedUnion("type", [
|
|
|
63
63
|
|
|
64
64
|
const event = new Event({ type: "click", x: 10, y: 20 });
|
|
65
65
|
event.setX(15);
|
|
66
|
+
|
|
67
|
+
// Switch the active union variant atomically
|
|
68
|
+
event.switchToScroll({ delta: 5 });
|
|
69
|
+
// or: event.switchVariant({ type: "scroll", delta: 5 });
|
|
66
70
|
```
|
|
67
71
|
|
|
68
72
|
See [`examples/event.ts`](examples/event.ts) and [`examples/profile.ts`](examples/profile.ts) for full demos.
|
|
@@ -77,7 +81,7 @@ Factory that accepts a Zod schema and returns an instantiable class.
|
|
|
77
81
|
|
|
78
82
|
| Parameter | Type | Description |
|
|
79
83
|
|-----------|------|-------------|
|
|
80
|
-
| `schema` | `z.ZodObject` \| `z.ZodUnion` \| `z.ZodDiscriminatedUnion` | Zod schema defining the object shape |
|
|
84
|
+
| `schema` | `z.ZodObject` \| `z.ZodUnion` \| `z.ZodDiscriminatedUnion` \| `z.ZodIntersection` \| `z.ZodLazy` | Zod schema defining the object shape |
|
|
81
85
|
|
|
82
86
|
**Members generated for each schema field `foo`:**
|
|
83
87
|
|
|
@@ -88,6 +92,21 @@ Factory that accepts a Zod schema and returns an instantiable class.
|
|
|
88
92
|
|
|
89
93
|
`set*` method names follow camelCase with the field name capitalized (`name` → `setName`, `userId` → `setUserId`).
|
|
90
94
|
|
|
95
|
+
**Union root extras** (discriminated and generic unions):
|
|
96
|
+
|
|
97
|
+
| Member | Type | Description |
|
|
98
|
+
|--------|------|-------------|
|
|
99
|
+
| `switchVariant(value)` | `(variant) => void` | Replaces the entire active variant after full schema validation |
|
|
100
|
+
| `switchTo{Variant}(fields)` | `(fields) => void` | Discriminated unions only — switches to a variant without repeating the discriminator (e.g. `switchToScroll({ delta: 5 })`) |
|
|
101
|
+
|
|
102
|
+
**Record field extras** (for each `z.record(...)` field `tags`):
|
|
103
|
+
|
|
104
|
+
| Member | Type | Description |
|
|
105
|
+
|--------|------|-------------|
|
|
106
|
+
| `getTagsEntry(key)` | `(key: string) => V \| undefined` | Reads a single record entry |
|
|
107
|
+
| `setTagsEntry(key, value)` | `(key: string, value: V) => void` | Validates and patches a single entry (`/tags/{key}`) |
|
|
108
|
+
| `deleteTagsEntry(key)` | `(key: string) => void` | Removes a record entry |
|
|
109
|
+
|
|
91
110
|
**Instance members:**
|
|
92
111
|
|
|
93
112
|
| Member | Type | Description |
|
|
@@ -128,6 +147,9 @@ RFC 6902 operation emitted by [fast-json-patch](https://github.com/Starcounter-J
|
|
|
128
147
|
- `SetMethodsUnion<T>` — `set*` methods for union root schemas
|
|
129
148
|
- `AllKeys<T>` — all keys across union members
|
|
130
149
|
- `UnionDataShape<U>` — flattened data shape for union roots
|
|
150
|
+
- `VariantSwitchMethods<T>` — `switchVariant` for union roots
|
|
151
|
+
- `DiscriminatedVariantSwitchMethods<T, D>` — `switchVariant` plus generated `switchTo*` methods
|
|
152
|
+
- `RecordFieldMethods<T>` — dynamic entry accessors for `z.record` fields
|
|
131
153
|
- `OperationsAccessor` — `operations` and `clearOperations()`
|
|
132
154
|
- `SnapshotAccessor<T>` — `toJSON()`
|
|
133
155
|
- `SmartObjectConstructor<T>` — constructor type including `fromOperations`
|
|
@@ -135,9 +157,11 @@ RFC 6902 operation emitted by [fast-json-patch](https://github.com/Starcounter-J
|
|
|
135
157
|
|
|
136
158
|
## Limitations
|
|
137
159
|
|
|
138
|
-
- **Partial
|
|
160
|
+
- **Partial discriminator write** — Changing a discriminated union discriminator alone via `setType(...)` without providing the new variant fields throws `SmartObjectError`. Use `switchVariant(...)` or `switchTo{Variant}(...)` instead.
|
|
139
161
|
- **Union field on wrong variant** — Setting a field that does not exist on the active variant throws `SmartObjectError`.
|
|
140
|
-
- **
|
|
162
|
+
- **Date fields** — `z.date()` and `z.coerce.date()` are supported; operations store ISO 8601 strings while getters return `Date` instances.
|
|
163
|
+
- **Map, Set, and bigint** — `z.map` (string keys), `z.set`, and `z.bigint()` are supported with explicit codecs; operations use JSON-safe plain objects, arrays, and decimal strings respectively. Whole-field replace is used for Map/Set updates. Non-string map keys are not supported.
|
|
164
|
+
- **Transforms** — `z.transform` / `z.pipe` with preprocessing work at runtime; operations store the **output** value after validation. TypeScript setter input types may not reflect transforms.
|
|
141
165
|
|
|
142
166
|
## Design rationale
|
|
143
167
|
|
|
@@ -169,13 +193,16 @@ smart-object/
|
|
|
169
193
|
│ ├── build-class.ts # Class generation orchestration
|
|
170
194
|
│ ├── instance-state.ts # WeakMap-backed instance storage
|
|
171
195
|
│ ├── read-field.ts # Defensive getter reads
|
|
172
|
-
│ ├── json-patch.ts # fast-json-patch wrapper
|
|
196
|
+
│ ├── json-patch.ts # fast-json-patch wrapper + Date-safe deepClone
|
|
197
|
+
│ ├── codecs.ts # ISO 8601 serialization for date fields
|
|
173
198
|
│ ├── apply-operations.ts # Replay and rollback
|
|
174
199
|
│ ├── union-variant.ts # Union variant matching
|
|
175
200
|
│ ├── define-prototype.ts # Getter/setter prototype setup
|
|
176
201
|
│ └── setters/
|
|
177
202
|
│ ├── object-field.ts
|
|
178
|
-
│
|
|
203
|
+
│ ├── union-field.ts
|
|
204
|
+
│ ├── variant-switch.ts
|
|
205
|
+
│ └── record-field.ts
|
|
179
206
|
├── examples/
|
|
180
207
|
│ ├── person.ts
|
|
181
208
|
│ ├── event.ts
|
|
@@ -199,6 +226,9 @@ smart-object/
|
|
|
199
226
|
│ │ ├── setter-naming.test.ts
|
|
200
227
|
│ │ ├── to-json.test.ts
|
|
201
228
|
│ │ ├── schema-variants.test.ts
|
|
229
|
+
│ │ ├── record-fields.test.ts
|
|
230
|
+
│ │ ├── date-codec.test.ts
|
|
231
|
+
│ │ ├── intersection-lazy.test.ts
|
|
202
232
|
│ │ └── types.test.ts
|
|
203
233
|
│ └── zod-introspect.test.ts
|
|
204
234
|
└── dist/ # Build output (generated)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { SmartObjectErrorCode } from "./errors.js";
|
|
2
2
|
export { SmartObjectError } from "./errors.js";
|
|
3
3
|
export { SmartObject } from "./smart-object/index.js";
|
|
4
|
-
export type { AllKeys, Operation, OperationsAccessor, SetMethods, SetMethodsUnion, SmartObjectConstructor, SmartObjectInstance, SmartObjectSchema, SnapshotAccessor, UnionDataShape, } from "./types.js";
|
|
4
|
+
export type { AllKeys, DiscriminatedVariantSwitchMethods, Operation, OperationsAccessor, RecordFieldMethods, SetMethods, SetMethodsUnion, SmartObjectConstructor, SmartObjectInstance, SmartObjectSchema, SnapshotAccessor, UnionDataShape, VariantSwitchMethods, } from "./types.js";
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,YAAY,EACV,OAAO,EACP,SAAS,EACT,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,YAAY,EACV,OAAO,EACP,iCAAiC,EACjC,SAAS,EACT,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-operations.d.ts","sourceRoot":"","sources":["../../src/smart-object/apply-operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"apply-operations.d.ts","sourceRoot":"","sources":["../../src/smart-object/apply-operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,wBAAgB,eAAe,CAAC,CAAC,EAC/B,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,SAAS,EAAE,iBAAiB,EAC5B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,SAAS,EAAE,GACtB,IAAI,CAkBN"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { SmartObjectError } from "../errors.js";
|
|
2
|
+
import { deserializeDataFromPatch } from "./codecs.js";
|
|
2
3
|
import { applyPatch, deepClone } from "./json-patch.js";
|
|
3
4
|
export function applyOperations(state, zodSchema, instance, operations) {
|
|
4
5
|
if (operations.length === 0) {
|
|
@@ -8,7 +9,8 @@ export function applyOperations(state, zodSchema, instance, operations) {
|
|
|
8
9
|
const snapshot = deepClone(data);
|
|
9
10
|
try {
|
|
10
11
|
applyPatch(data, operations, false, true);
|
|
11
|
-
const
|
|
12
|
+
const deserialized = deserializeDataFromPatch(data, zodSchema);
|
|
13
|
+
const validated = zodSchema.parse(deserialized);
|
|
12
14
|
state.setData(instance, validated);
|
|
13
15
|
state.getOperations(instance).push(...operations);
|
|
14
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-class.d.ts","sourceRoot":"","sources":["../../src/smart-object/build-class.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAuB,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAOlG,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,iBAAiB,EAC/D,SAAS,EAAE,CAAC,GACX,sBAAsB,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"build-class.d.ts","sourceRoot":"","sources":["../../src/smart-object/build-class.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAuB,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAOlG,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,iBAAiB,EAC/D,SAAS,EAAE,CAAC,GACX,sBAAsB,CAAC,CAAC,CAAC,CAqC3B"}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getSchemaShapeKeys } from "../zod-introspect.js";
|
|
2
2
|
import { applyOperations } from "./apply-operations.js";
|
|
3
3
|
import { definePrototype } from "./define-prototype.js";
|
|
4
4
|
import { createInstanceState } from "./instance-state.js";
|
|
5
5
|
import { deepClone } from "./json-patch.js";
|
|
6
6
|
export function buildSmartObjectClass(zodSchema) {
|
|
7
|
-
const keys =
|
|
8
|
-
? getObjectShapeKeys(zodSchema)
|
|
9
|
-
: getUnionObjectKeys(zodSchema);
|
|
7
|
+
const keys = getSchemaShapeKeys(zodSchema);
|
|
10
8
|
const state = createInstanceState();
|
|
11
9
|
class SmartObjectClass {
|
|
12
10
|
static fromOperations(initial, operations) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { SmartObjectSchema } from "../types.js";
|
|
3
|
+
export declare function serializeValue(schema: z.ZodType, value: unknown): unknown;
|
|
4
|
+
export declare function deserializeValue(schema: z.ZodType, value: unknown): unknown;
|
|
5
|
+
export declare function serializeDataForPatch<T extends Record<string, unknown>>(data: T, rootSchema: SmartObjectSchema): T;
|
|
6
|
+
export declare function deserializeDataFromPatch<T extends Record<string, unknown>>(data: T, rootSchema: SmartObjectSchema): T;
|
|
7
|
+
export declare function serializePatchValue(rootSchema: SmartObjectSchema, key: string, value: unknown): unknown;
|
|
8
|
+
export declare function serializeEntryPatchValue(fieldSchema: z.ZodType, valueSchema: z.ZodType, value: unknown): unknown;
|
|
9
|
+
/** Serialize a single entry container for RFC 6902 compare (record or map field). */
|
|
10
|
+
export declare function serializeEntryContainer(fieldSchema: z.ZodType, container: unknown): Record<string, unknown>;
|
|
11
|
+
/** @deprecated Use serializeValue */
|
|
12
|
+
export declare function serializeFieldValue(fieldSchema: z.ZodType, value: unknown): unknown;
|
|
13
|
+
/** @deprecated Use deserializeValue */
|
|
14
|
+
export declare function deserializeFieldValue(fieldSchema: z.ZodType, value: unknown): unknown;
|
|
15
|
+
//# sourceMappingURL=codecs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codecs.d.ts","sourceRoot":"","sources":["../../src/smart-object/codecs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAwBrD,wBAAgB,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CA6DzE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAmE3E;AAED,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrE,IAAI,EAAE,CAAC,EACP,UAAU,EAAE,iBAAiB,GAC5B,CAAC,CAeH;AAED,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACxE,IAAI,EAAE,CAAC,EACP,UAAU,EAAE,iBAAiB,GAC5B,CAAC,CAeH;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,iBAAiB,EAC7B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,GACb,OAAO,CAQT;AAED,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,CAAC,CAAC,OAAO,EACtB,WAAW,EAAE,CAAC,CAAC,OAAO,EACtB,KAAK,EAAE,OAAO,GACb,OAAO,CAYT;AAED,qFAAqF;AACrF,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,CAAC,CAAC,OAAO,EACtB,SAAS,EAAE,OAAO,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGzB;AAED,qCAAqC;AACrC,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAEnF;AAED,uCAAuC;AACvC,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAErF"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { getFieldSchema, getMergedObjectShape, isZodRecord, unwrapFieldSchema, } from "../zod-introspect.js";
|
|
2
|
+
function getSchemaDef(schema) {
|
|
3
|
+
return schema._zod.def;
|
|
4
|
+
}
|
|
5
|
+
function isPlainObject(value) {
|
|
6
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
export function serializeValue(schema, value) {
|
|
9
|
+
const inner = unwrapFieldSchema(schema);
|
|
10
|
+
const def = getSchemaDef(inner);
|
|
11
|
+
if (value instanceof Date && def.type === "date") {
|
|
12
|
+
return value.toISOString();
|
|
13
|
+
}
|
|
14
|
+
if (typeof value === "bigint" && def.type === "bigint") {
|
|
15
|
+
return value.toString();
|
|
16
|
+
}
|
|
17
|
+
if (value instanceof Map && def.type === "map") {
|
|
18
|
+
const keySchema = def.keyType;
|
|
19
|
+
const valueSchema = def.valueType;
|
|
20
|
+
const result = {};
|
|
21
|
+
for (const [key, entryValue] of value.entries()) {
|
|
22
|
+
const serializedKey = serializeValue(keySchema, key);
|
|
23
|
+
if (typeof serializedKey === "string") {
|
|
24
|
+
result[serializedKey] = serializeValue(valueSchema, entryValue);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
if (value instanceof Set && def.type === "set") {
|
|
30
|
+
const valueSchema = def.valueType;
|
|
31
|
+
return [...value].map((item) => serializeValue(valueSchema, item));
|
|
32
|
+
}
|
|
33
|
+
if (def.type === "object" && isPlainObject(value)) {
|
|
34
|
+
const shape = def.shape ?? {};
|
|
35
|
+
const result = {};
|
|
36
|
+
for (const [key, fieldValue] of Object.entries(value)) {
|
|
37
|
+
const fieldSchema = shape[key];
|
|
38
|
+
result[key] = fieldSchema ? serializeValue(fieldSchema, fieldValue) : fieldValue;
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
if (def.type === "array" && Array.isArray(value)) {
|
|
43
|
+
const elementSchema = def.element;
|
|
44
|
+
return value.map((item) => serializeValue(elementSchema, item));
|
|
45
|
+
}
|
|
46
|
+
if (def.type === "record" && isPlainObject(value)) {
|
|
47
|
+
const valueSchema = def.valueType;
|
|
48
|
+
const result = {};
|
|
49
|
+
for (const [key, fieldValue] of Object.entries(value)) {
|
|
50
|
+
result[key] = serializeValue(valueSchema, fieldValue);
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
export function deserializeValue(schema, value) {
|
|
57
|
+
const inner = unwrapFieldSchema(schema);
|
|
58
|
+
const def = getSchemaDef(inner);
|
|
59
|
+
if (def.type === "date" && typeof value === "string") {
|
|
60
|
+
const parsed = new Date(value);
|
|
61
|
+
if (!Number.isNaN(parsed.getTime())) {
|
|
62
|
+
return parsed;
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
if (def.type === "bigint" && typeof value === "string") {
|
|
67
|
+
try {
|
|
68
|
+
return BigInt(value);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (def.type === "map" && isPlainObject(value)) {
|
|
75
|
+
const keySchema = def.keyType;
|
|
76
|
+
const valueSchema = def.valueType;
|
|
77
|
+
const map = new Map();
|
|
78
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
79
|
+
map.set(deserializeValue(keySchema, key), deserializeValue(valueSchema, entryValue));
|
|
80
|
+
}
|
|
81
|
+
return map;
|
|
82
|
+
}
|
|
83
|
+
if (def.type === "set" && Array.isArray(value)) {
|
|
84
|
+
const valueSchema = def.valueType;
|
|
85
|
+
return new Set(value.map((item) => deserializeValue(valueSchema, item)));
|
|
86
|
+
}
|
|
87
|
+
if (def.type === "object" && isPlainObject(value)) {
|
|
88
|
+
const shape = def.shape ?? {};
|
|
89
|
+
const result = {};
|
|
90
|
+
for (const [key, fieldValue] of Object.entries(value)) {
|
|
91
|
+
const fieldSchema = shape[key];
|
|
92
|
+
result[key] = fieldSchema ? deserializeValue(fieldSchema, fieldValue) : fieldValue;
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
if (def.type === "array" && Array.isArray(value)) {
|
|
97
|
+
const elementSchema = def.element;
|
|
98
|
+
return value.map((item) => deserializeValue(elementSchema, item));
|
|
99
|
+
}
|
|
100
|
+
if (def.type === "record" && isPlainObject(value)) {
|
|
101
|
+
const valueSchema = def.valueType;
|
|
102
|
+
const result = {};
|
|
103
|
+
for (const [key, fieldValue] of Object.entries(value)) {
|
|
104
|
+
result[key] = deserializeValue(valueSchema, fieldValue);
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
export function serializeDataForPatch(data, rootSchema) {
|
|
111
|
+
const shape = getMergedObjectShape(rootSchema);
|
|
112
|
+
if (Object.keys(shape).length === 0) {
|
|
113
|
+
return data;
|
|
114
|
+
}
|
|
115
|
+
const result = {};
|
|
116
|
+
for (const [key, fieldValue] of Object.entries(data)) {
|
|
117
|
+
const fieldSchema = shape[key];
|
|
118
|
+
result[key] = fieldSchema ? serializeValue(fieldSchema, fieldValue) : fieldValue;
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
export function deserializeDataFromPatch(data, rootSchema) {
|
|
123
|
+
const shape = getMergedObjectShape(rootSchema);
|
|
124
|
+
if (Object.keys(shape).length === 0) {
|
|
125
|
+
return data;
|
|
126
|
+
}
|
|
127
|
+
const result = {};
|
|
128
|
+
for (const [key, fieldValue] of Object.entries(data)) {
|
|
129
|
+
const fieldSchema = shape[key];
|
|
130
|
+
result[key] = fieldSchema ? deserializeValue(fieldSchema, fieldValue) : fieldValue;
|
|
131
|
+
}
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
export function serializePatchValue(rootSchema, key, value) {
|
|
135
|
+
const fieldSchema = getFieldSchema(rootSchema, key);
|
|
136
|
+
if (!fieldSchema) {
|
|
137
|
+
return value;
|
|
138
|
+
}
|
|
139
|
+
return serializeValue(fieldSchema, value);
|
|
140
|
+
}
|
|
141
|
+
export function serializeEntryPatchValue(fieldSchema, valueSchema, value) {
|
|
142
|
+
const inner = unwrapFieldSchema(fieldSchema);
|
|
143
|
+
if (isZodRecord(inner)) {
|
|
144
|
+
return serializeValue(valueSchema, value);
|
|
145
|
+
}
|
|
146
|
+
if (isPlainObject(value)) {
|
|
147
|
+
return serializeValue(fieldSchema, value);
|
|
148
|
+
}
|
|
149
|
+
return serializeValue(valueSchema, value);
|
|
150
|
+
}
|
|
151
|
+
/** Serialize a single entry container for RFC 6902 compare (record or map field). */
|
|
152
|
+
export function serializeEntryContainer(fieldSchema, container) {
|
|
153
|
+
const serialized = serializeValue(fieldSchema, container);
|
|
154
|
+
return isPlainObject(serialized) ? serialized : {};
|
|
155
|
+
}
|
|
156
|
+
/** @deprecated Use serializeValue */
|
|
157
|
+
export function serializeFieldValue(fieldSchema, value) {
|
|
158
|
+
return serializeValue(fieldSchema, value);
|
|
159
|
+
}
|
|
160
|
+
/** @deprecated Use deserializeValue */
|
|
161
|
+
export function deserializeFieldValue(fieldSchema, value) {
|
|
162
|
+
return deserializeValue(fieldSchema, value);
|
|
163
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-prototype.d.ts","sourceRoot":"","sources":["../../src/smart-object/define-prototype.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"define-prototype.d.ts","sourceRoot":"","sources":["../../src/smart-object/define-prototype.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAarD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAoEzD,wBAAgB,eAAe,CAAC,CAAC,EAC/B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,SAAS,EAAE,iBAAiB,EAC5B,IAAI,EAAE,MAAM,EAAE,GACb,IAAI,CAiCN"}
|
|
@@ -1,10 +1,56 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getDiscriminatedVariants, getDiscriminator, getFieldSchema, getRecordFieldsFromSchema, isObjectLikeRoot, isZodDiscriminatedUnion, isZodUnionRoot, toRecordEntryMethodPrefix, toSetterMethodName, } from "../zod-introspect.js";
|
|
2
2
|
import { readFieldValue } from "./read-field.js";
|
|
3
3
|
import { createObjectFieldSetter } from "./setters/object-field.js";
|
|
4
|
+
import { createRecordEntryDeleter, createRecordEntryGetter, createRecordEntrySetter, } from "./setters/record-field.js";
|
|
4
5
|
import { createUnionFieldSetter } from "./setters/union-field.js";
|
|
6
|
+
import { createSwitchToVariant, createSwitchVariant } from "./setters/variant-switch.js";
|
|
7
|
+
function defineRecordFieldMethods(prototype, state, zodSchema) {
|
|
8
|
+
for (const field of getRecordFieldsFromSchema(zodSchema)) {
|
|
9
|
+
const prefix = toRecordEntryMethodPrefix(field.fieldName);
|
|
10
|
+
Object.defineProperty(prototype, `get${prefix}Entry`, {
|
|
11
|
+
value: createRecordEntryGetter(state, field),
|
|
12
|
+
enumerable: false,
|
|
13
|
+
configurable: true,
|
|
14
|
+
writable: true,
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(prototype, `set${prefix}Entry`, {
|
|
17
|
+
value: createRecordEntrySetter(state, zodSchema, field),
|
|
18
|
+
enumerable: false,
|
|
19
|
+
configurable: true,
|
|
20
|
+
writable: true,
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(prototype, `delete${prefix}Entry`, {
|
|
23
|
+
value: createRecordEntryDeleter(state, zodSchema, field),
|
|
24
|
+
enumerable: false,
|
|
25
|
+
configurable: true,
|
|
26
|
+
writable: true,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function defineUnionRootMethods(prototype, state, zodSchema) {
|
|
31
|
+
Object.defineProperty(prototype, "switchVariant", {
|
|
32
|
+
value: createSwitchVariant(state, zodSchema),
|
|
33
|
+
enumerable: false,
|
|
34
|
+
configurable: true,
|
|
35
|
+
writable: true,
|
|
36
|
+
});
|
|
37
|
+
if (isZodDiscriminatedUnion(zodSchema)) {
|
|
38
|
+
const discriminator = getDiscriminator(zodSchema);
|
|
39
|
+
for (const variant of getDiscriminatedVariants(zodSchema)) {
|
|
40
|
+
Object.defineProperty(prototype, variant.methodName, {
|
|
41
|
+
value: createSwitchToVariant(state, zodSchema, variant.schema, variant.tag, discriminator),
|
|
42
|
+
enumerable: false,
|
|
43
|
+
configurable: true,
|
|
44
|
+
writable: true,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
5
49
|
export function definePrototype(prototype, state, zodSchema, keys) {
|
|
50
|
+
const objectSchema = isObjectLikeRoot(zodSchema) ? zodSchema : undefined;
|
|
6
51
|
for (const key of keys) {
|
|
7
52
|
const setMethodName = toSetterMethodName(key);
|
|
53
|
+
const fieldSchema = getFieldSchema(zodSchema, key);
|
|
8
54
|
Object.defineProperty(prototype, key, {
|
|
9
55
|
get() {
|
|
10
56
|
return readFieldValue(state.getData(this)[key]);
|
|
@@ -13,12 +59,18 @@ export function definePrototype(prototype, state, zodSchema, keys) {
|
|
|
13
59
|
configurable: true,
|
|
14
60
|
});
|
|
15
61
|
Object.defineProperty(prototype, setMethodName, {
|
|
16
|
-
value:
|
|
17
|
-
? createObjectFieldSetter(state,
|
|
62
|
+
value: fieldSchema && isObjectLikeRoot(zodSchema)
|
|
63
|
+
? createObjectFieldSetter(state, key, fieldSchema, zodSchema)
|
|
18
64
|
: createUnionFieldSetter(state, zodSchema, key),
|
|
19
65
|
enumerable: false,
|
|
20
66
|
configurable: true,
|
|
21
67
|
writable: true,
|
|
22
68
|
});
|
|
23
69
|
}
|
|
70
|
+
if (objectSchema) {
|
|
71
|
+
defineRecordFieldMethods(prototype, state, zodSchema);
|
|
72
|
+
}
|
|
73
|
+
if (isZodUnionRoot(zodSchema)) {
|
|
74
|
+
defineUnionRootMethods(prototype, state, zodSchema);
|
|
75
|
+
}
|
|
24
76
|
}
|
|
@@ -33,4 +33,6 @@ import type { SmartObjectConstructor } from "../types.js";
|
|
|
33
33
|
export declare function SmartObject<T extends z.ZodObject>(zodSchema: T): SmartObjectConstructor<T>;
|
|
34
34
|
export declare function SmartObject<T extends z.ZodDiscriminatedUnion>(zodSchema: T): SmartObjectConstructor<T>;
|
|
35
35
|
export declare function SmartObject<T extends z.ZodUnion>(zodSchema: T): SmartObjectConstructor<T>;
|
|
36
|
+
export declare function SmartObject<T extends z.ZodIntersection>(zodSchema: T): SmartObjectConstructor<T>;
|
|
37
|
+
export declare function SmartObject<T extends z.ZodLazy>(zodSchema: T): SmartObjectConstructor<T>;
|
|
36
38
|
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/smart-object/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,sBAAsB,EAAqB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/smart-object/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,sBAAsB,EAAqB,MAAM,aAAa,CAAC;AAwC7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;AAC5F,wBAAgB,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,qBAAqB,EAC3D,SAAS,EAAE,CAAC,GACX,sBAAsB,CAAC,CAAC,CAAC,CAAC;AAC7B,wBAAgB,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;AAC3F,wBAAgB,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,eAAe,EAAE,SAAS,EAAE,CAAC,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;AAClG,wBAAgB,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import { SmartObjectError } from "../errors.js";
|
|
2
|
-
import { isZodObject, isZodUnionOfObjects, isZodUnionRoot } from "../zod-introspect.js";
|
|
2
|
+
import { isZodIntersection, isZodObject, isZodUnionOfObjects, isZodUnionRoot, resolveLazySchema, } from "../zod-introspect.js";
|
|
3
3
|
import { buildSmartObjectClass } from "./build-class.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
function assertBuildableSchema(schema) {
|
|
5
|
+
const resolved = resolveLazySchema(schema);
|
|
6
|
+
if (isZodObject(resolved)) {
|
|
7
|
+
return;
|
|
7
8
|
}
|
|
8
|
-
if (isZodUnionRoot(
|
|
9
|
-
if (!isZodUnionOfObjects(
|
|
9
|
+
if (isZodUnionRoot(resolved)) {
|
|
10
|
+
if (!isZodUnionOfObjects(resolved)) {
|
|
10
11
|
throw SmartObjectError.unsupportedSchema("SmartObject union root requires all options to be z.object(...)");
|
|
11
12
|
}
|
|
12
|
-
return
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (isZodIntersection(resolved)) {
|
|
16
|
+
const left = resolved._zod.def.left;
|
|
17
|
+
const right = resolved._zod.def.right;
|
|
18
|
+
assertBuildableSchema(left);
|
|
19
|
+
assertBuildableSchema(right);
|
|
20
|
+
return;
|
|
13
21
|
}
|
|
14
|
-
throw SmartObjectError.unsupportedSchema("SmartObject requires a z.object(...), z.union([...]), or z.
|
|
22
|
+
throw SmartObjectError.unsupportedSchema("SmartObject requires a buildable z.object(...), z.union([...]), z.discriminatedUnion(...), z.intersection(...), or z.lazy(...) schema");
|
|
23
|
+
}
|
|
24
|
+
export function SmartObject(zodSchema) {
|
|
25
|
+
assertBuildableSchema(zodSchema);
|
|
26
|
+
return buildSmartObjectClass(zodSchema);
|
|
15
27
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import jsonPatch from "fast-json-patch";
|
|
2
|
-
export declare const applyPatch: typeof jsonPatch.applyPatch, compare: typeof jsonPatch.compare
|
|
2
|
+
export declare const applyPatch: typeof jsonPatch.applyPatch, compare: typeof jsonPatch.compare;
|
|
3
|
+
export declare function deepClone<T>(value: T): T;
|
|
3
4
|
//# sourceMappingURL=json-patch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json-patch.d.ts","sourceRoot":"","sources":["../../src/smart-object/json-patch.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AAExC,eAAO,MAAQ,UAAU,+BAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"json-patch.d.ts","sourceRoot":"","sources":["../../src/smart-object/json-patch.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,iBAAiB,CAAC;AAExC,eAAO,MAAQ,UAAU,+BAAE,OAAO,0BAAc,CAAC;AAEjD,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAkCxC"}
|
|
@@ -1,2 +1,27 @@
|
|
|
1
1
|
import jsonPatch from "fast-json-patch";
|
|
2
|
-
export const { applyPatch, compare
|
|
2
|
+
export const { applyPatch, compare } = jsonPatch;
|
|
3
|
+
export function deepClone(value) {
|
|
4
|
+
if (value instanceof Date) {
|
|
5
|
+
return new Date(value.getTime());
|
|
6
|
+
}
|
|
7
|
+
if (typeof value === "bigint") {
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
if (value instanceof Map) {
|
|
11
|
+
return new Map([...value.entries()].map(([key, nestedValue]) => [key, deepClone(nestedValue)]));
|
|
12
|
+
}
|
|
13
|
+
if (value instanceof Set) {
|
|
14
|
+
return new Set([...value].map((item) => deepClone(item)));
|
|
15
|
+
}
|
|
16
|
+
if (Array.isArray(value)) {
|
|
17
|
+
return value.map((item) => deepClone(item));
|
|
18
|
+
}
|
|
19
|
+
if (typeof value === "object" && value !== null) {
|
|
20
|
+
const result = {};
|
|
21
|
+
for (const [key, nestedValue] of Object.entries(value)) {
|
|
22
|
+
result[key] = deepClone(nestedValue);
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-field.d.ts","sourceRoot":"","sources":["../../src/smart-object/read-field.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"read-field.d.ts","sourceRoot":"","sources":["../../src/smart-object/read-field.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAetD"}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { deepClone } from "./json-patch.js";
|
|
2
2
|
export function readFieldValue(value) {
|
|
3
|
+
if (value instanceof Date ||
|
|
4
|
+
value instanceof Map ||
|
|
5
|
+
value instanceof Set ||
|
|
6
|
+
typeof value === "bigint") {
|
|
7
|
+
return deepClone(value);
|
|
8
|
+
}
|
|
3
9
|
if (typeof value === "object" && value !== null) {
|
|
4
10
|
return deepClone(value);
|
|
5
11
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { SmartObjectSchema } from "../../types.js";
|
|
2
3
|
import type { InstanceState } from "../instance-state.js";
|
|
3
|
-
export declare function createObjectFieldSetter<T>(state: InstanceState<T>,
|
|
4
|
+
export declare function createObjectFieldSetter<T>(state: InstanceState<T>, key: string, fieldSchema: z.ZodType, rootSchema: SmartObjectSchema): (this: object, value: unknown) => void;
|
|
4
5
|
//# sourceMappingURL=object-field.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"object-field.d.ts","sourceRoot":"","sources":["../../../src/smart-object/setters/object-field.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"object-field.d.ts","sourceRoot":"","sources":["../../../src/smart-object/setters/object-field.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA8C1D,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,CAAC,CAAC,OAAO,EACtB,UAAU,EAAE,iBAAiB,IAEZ,MAAM,MAAM,EAAE,OAAO,OAAO,UAoC9C"}
|
|
@@ -1,7 +1,36 @@
|
|
|
1
1
|
import { SmartObjectError } from "../../errors.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { unwrapFieldSchema } from "../../zod-introspect.js";
|
|
3
|
+
import { serializeDataForPatch, serializeValue } from "../codecs.js";
|
|
4
|
+
import { compare, deepClone } from "../json-patch.js";
|
|
5
|
+
function normalizeFieldPatch(patch, key, fieldSchema, parsed, beforeSerialized) {
|
|
6
|
+
const inner = unwrapFieldSchema(fieldSchema);
|
|
7
|
+
const defType = inner._zod.def.type;
|
|
8
|
+
if (defType !== "set" && defType !== "map") {
|
|
9
|
+
return patch.map((operation) => {
|
|
10
|
+
if ("value" in operation && operation.path === `/${key}`) {
|
|
11
|
+
return {
|
|
12
|
+
...operation,
|
|
13
|
+
value: serializeValue(fieldSchema, parsed),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return operation;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
const prefix = `/${key}`;
|
|
20
|
+
const touchesField = patch.some((operation) => operation.path === prefix || operation.path.startsWith(`${prefix}/`));
|
|
21
|
+
if (!touchesField) {
|
|
22
|
+
return patch;
|
|
23
|
+
}
|
|
24
|
+
const hadField = Object.hasOwn(beforeSerialized, key) && beforeSerialized[key] !== undefined;
|
|
25
|
+
return [
|
|
26
|
+
{
|
|
27
|
+
op: hadField ? "replace" : "add",
|
|
28
|
+
path: prefix,
|
|
29
|
+
value: serializeValue(fieldSchema, parsed),
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
export function createObjectFieldSetter(state, key, fieldSchema, rootSchema) {
|
|
5
34
|
return function (value) {
|
|
6
35
|
let parsed;
|
|
7
36
|
try {
|
|
@@ -14,11 +43,14 @@ export function createObjectFieldSetter(state, schema, key) {
|
|
|
14
43
|
const beforeData = deepClone(data);
|
|
15
44
|
const afterData = deepClone(data);
|
|
16
45
|
afterData[key] = parsed;
|
|
17
|
-
const
|
|
46
|
+
const beforeSerialized = serializeDataForPatch(beforeData, rootSchema);
|
|
47
|
+
const afterSerialized = serializeDataForPatch(afterData, rootSchema);
|
|
48
|
+
const patch = normalizeFieldPatch(compare(beforeSerialized, afterSerialized), key, fieldSchema, parsed, beforeSerialized);
|
|
18
49
|
if (patch.length === 0) {
|
|
19
50
|
return;
|
|
20
51
|
}
|
|
21
|
-
|
|
52
|
+
afterData[key] = parsed;
|
|
53
|
+
state.setData(this, afterData);
|
|
22
54
|
state.getOperations(this).push(...patch);
|
|
23
55
|
};
|
|
24
56
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SmartObjectSchema } from "../../types.js";
|
|
2
|
+
import type { RecordFieldInfo } from "../../zod-introspect.js";
|
|
3
|
+
import type { InstanceState } from "../instance-state.js";
|
|
4
|
+
export declare function createRecordEntryGetter<T>(state: InstanceState<T>, field: RecordFieldInfo): (this: object, key: string) => unknown;
|
|
5
|
+
export declare function createRecordEntrySetter<T>(state: InstanceState<T>, rootSchema: SmartObjectSchema, field: RecordFieldInfo): (this: object, key: string, value: unknown) => void;
|
|
6
|
+
export declare function createRecordEntryDeleter<T>(state: InstanceState<T>, rootSchema: SmartObjectSchema, field: RecordFieldInfo): (this: object, key: string) => void;
|
|
7
|
+
//# sourceMappingURL=record-field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-field.d.ts","sourceRoot":"","sources":["../../../src/smart-object/setters/record-field.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAuH1D,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,eAAe,IACvE,MAAM,MAAM,EAAE,KAAK,MAAM,aAU3C;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,UAAU,EAAE,iBAAiB,EAC7B,KAAK,EAAE,eAAe,IAIL,MAAM,MAAM,EAAE,KAAK,MAAM,EAAE,OAAO,OAAO,UA0C3D;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EACxC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,UAAU,EAAE,iBAAiB,EAC7B,KAAK,EAAE,eAAe,IAIL,MAAM,MAAM,EAAE,KAAK,MAAM,UA0B3C"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { SmartObjectError } from "../../errors.js";
|
|
2
|
+
import { serializeDataForPatch, serializeEntryPatchValue } from "../codecs.js";
|
|
3
|
+
import { compare, deepClone } from "../json-patch.js";
|
|
4
|
+
import { readFieldValue } from "../read-field.js";
|
|
5
|
+
function getEntryContainer(data, fieldName, storage) {
|
|
6
|
+
const container = data[fieldName];
|
|
7
|
+
if (storage === "map") {
|
|
8
|
+
return container instanceof Map
|
|
9
|
+
? container
|
|
10
|
+
: new Map();
|
|
11
|
+
}
|
|
12
|
+
if (typeof container === "object" && container !== null && !Array.isArray(container)) {
|
|
13
|
+
return container;
|
|
14
|
+
}
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
function hasEntry(container, key, storage) {
|
|
18
|
+
if (storage === "map") {
|
|
19
|
+
return container instanceof Map && container.has(key);
|
|
20
|
+
}
|
|
21
|
+
return typeof container === "object" && container !== null && Object.hasOwn(container, key);
|
|
22
|
+
}
|
|
23
|
+
function getEntry(container, key, storage) {
|
|
24
|
+
if (storage === "map" && container instanceof Map) {
|
|
25
|
+
return container.get(key);
|
|
26
|
+
}
|
|
27
|
+
if (typeof container === "object" && container !== null) {
|
|
28
|
+
return container[key];
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
function cloneContainer(container, storage) {
|
|
33
|
+
if (storage === "map") {
|
|
34
|
+
return deepClone(container instanceof Map ? container : new Map());
|
|
35
|
+
}
|
|
36
|
+
return deepClone(typeof container === "object" && container !== null
|
|
37
|
+
? container
|
|
38
|
+
: {});
|
|
39
|
+
}
|
|
40
|
+
function setEntry(container, key, value, storage) {
|
|
41
|
+
if (storage === "map" && container instanceof Map) {
|
|
42
|
+
container.set(key, value);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
container[key] = value;
|
|
46
|
+
}
|
|
47
|
+
function deleteEntry(container, key, storage) {
|
|
48
|
+
if (storage === "map" && container instanceof Map) {
|
|
49
|
+
container.delete(key);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
delete container[key];
|
|
53
|
+
}
|
|
54
|
+
function normalizeEntryPatches(patch, fieldName, fieldSchema, valueSchema, nextContainer, storage) {
|
|
55
|
+
const prefix = `/${fieldName}/`;
|
|
56
|
+
return patch.map((operation) => {
|
|
57
|
+
if (!("value" in operation) || !operation.path.startsWith(prefix)) {
|
|
58
|
+
return operation;
|
|
59
|
+
}
|
|
60
|
+
const remainder = operation.path.slice(prefix.length);
|
|
61
|
+
if (remainder.includes("/")) {
|
|
62
|
+
return operation;
|
|
63
|
+
}
|
|
64
|
+
const entryKey = remainder.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
65
|
+
const entryValue = storage === "map" && nextContainer instanceof Map
|
|
66
|
+
? nextContainer.get(entryKey)
|
|
67
|
+
: nextContainer[entryKey];
|
|
68
|
+
return {
|
|
69
|
+
...operation,
|
|
70
|
+
value: serializeEntryPatchValue(fieldSchema, valueSchema, entryValue),
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
export function createRecordEntryGetter(state, field) {
|
|
75
|
+
return function (key) {
|
|
76
|
+
const data = state.getData(this);
|
|
77
|
+
const value = getEntry(data[field.fieldName], key, field.storage);
|
|
78
|
+
if (value === undefined) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
return readFieldValue(value);
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function createRecordEntrySetter(state, rootSchema, field) {
|
|
85
|
+
const { fieldName, fieldSchema, valueSchema, storage } = field;
|
|
86
|
+
return function (key, value) {
|
|
87
|
+
let parsed;
|
|
88
|
+
try {
|
|
89
|
+
parsed = valueSchema.parse(value);
|
|
90
|
+
}
|
|
91
|
+
catch (cause) {
|
|
92
|
+
throw SmartObjectError.invalidValue(`${fieldName}.${key}`, cause);
|
|
93
|
+
}
|
|
94
|
+
const data = state.getData(this);
|
|
95
|
+
const container = getEntryContainer(data, fieldName, storage);
|
|
96
|
+
const previousValue = getEntry(container, key, storage);
|
|
97
|
+
if (hasEntry(container, key, storage) && Object.is(previousValue, parsed)) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const beforeData = deepClone(data);
|
|
101
|
+
const afterData = deepClone(data);
|
|
102
|
+
const nextContainer = cloneContainer(container, storage);
|
|
103
|
+
setEntry(nextContainer, key, parsed, storage);
|
|
104
|
+
afterData[fieldName] = nextContainer;
|
|
105
|
+
const patch = normalizeEntryPatches(compare(serializeDataForPatch(beforeData, rootSchema), serializeDataForPatch(afterData, rootSchema)), fieldName, fieldSchema, valueSchema, nextContainer, storage);
|
|
106
|
+
if (patch.length === 0) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
data[fieldName] = nextContainer;
|
|
110
|
+
state.getOperations(this).push(...patch);
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export function createRecordEntryDeleter(state, rootSchema, field) {
|
|
114
|
+
const { fieldName, storage } = field;
|
|
115
|
+
return function (key) {
|
|
116
|
+
const data = state.getData(this);
|
|
117
|
+
const container = data[fieldName];
|
|
118
|
+
if (!hasEntry(container, key, storage)) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const beforeData = deepClone(data);
|
|
122
|
+
const afterData = deepClone(data);
|
|
123
|
+
const nextContainer = cloneContainer(getEntryContainer(afterData, fieldName, storage), storage);
|
|
124
|
+
deleteEntry(nextContainer, key, storage);
|
|
125
|
+
afterData[fieldName] = nextContainer;
|
|
126
|
+
const patch = compare(serializeDataForPatch(beforeData, rootSchema), serializeDataForPatch(afterData, rootSchema));
|
|
127
|
+
if (patch.length === 0) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
data[fieldName] = nextContainer;
|
|
131
|
+
state.getOperations(this).push(...patch);
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ZodDiscriminatedUnionLike, ZodObjectLike, ZodUnionRootLike } from "../../zod-introspect.js";
|
|
2
|
+
import type { InstanceState } from "../instance-state.js";
|
|
3
|
+
export declare function createSwitchVariant<T>(state: InstanceState<T>, schema: ZodUnionRootLike): (this: object, value: unknown) => void;
|
|
4
|
+
export declare function createSwitchToVariant<T>(state: InstanceState<T>, schema: ZodDiscriminatedUnionLike, variantSchema: ZodObjectLike, tagValue: string | number | boolean, discriminator: string): (this: object, partial: Record<string, unknown>) => void;
|
|
5
|
+
//# sourceMappingURL=variant-switch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"variant-switch.d.ts","sourceRoot":"","sources":["../../../src/smart-object/setters/variant-switch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,aAAa,EACb,gBAAgB,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA8B1D,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,gBAAgB,IACrE,MAAM,MAAM,EAAE,OAAO,OAAO,UAG9C;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,MAAM,EAAE,yBAAyB,EACjC,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EACnC,aAAa,EAAE,MAAM,IAEJ,MAAM,MAAM,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,UAahE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { SmartObjectError } from "../../errors.js";
|
|
2
|
+
import { compare, deepClone } from "../json-patch.js";
|
|
3
|
+
function applyVariantSwitch(state, instance, schema, value) {
|
|
4
|
+
const data = state.getData(instance);
|
|
5
|
+
const beforeData = deepClone(data);
|
|
6
|
+
let parsed;
|
|
7
|
+
try {
|
|
8
|
+
parsed = schema.parse(value);
|
|
9
|
+
}
|
|
10
|
+
catch (cause) {
|
|
11
|
+
throw SmartObjectError.invalidValue("variant", cause);
|
|
12
|
+
}
|
|
13
|
+
const patch = compare(beforeData, parsed);
|
|
14
|
+
if (patch.length === 0) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
state.setData(instance, parsed);
|
|
18
|
+
state.getOperations(instance).push(...patch);
|
|
19
|
+
}
|
|
20
|
+
export function createSwitchVariant(state, schema) {
|
|
21
|
+
return function (value) {
|
|
22
|
+
applyVariantSwitch(state, this, schema, value);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function createSwitchToVariant(state, schema, variantSchema, tagValue, discriminator) {
|
|
26
|
+
return function (partial) {
|
|
27
|
+
const candidate = { ...partial, [discriminator]: tagValue };
|
|
28
|
+
let parsed;
|
|
29
|
+
try {
|
|
30
|
+
parsed = variantSchema.parse(candidate);
|
|
31
|
+
}
|
|
32
|
+
catch (cause) {
|
|
33
|
+
throw SmartObjectError.invalidValue("variant", cause);
|
|
34
|
+
}
|
|
35
|
+
applyVariantSwitch(state, this, schema, parsed);
|
|
36
|
+
};
|
|
37
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -2,9 +2,9 @@ import type { Operation } from "fast-json-patch";
|
|
|
2
2
|
import type { z } from "zod";
|
|
3
3
|
export type { Operation };
|
|
4
4
|
/**
|
|
5
|
-
* Schemas accepted by SmartObject: plain objects
|
|
5
|
+
* Schemas accepted by SmartObject: plain objects, unions of objects, intersections, or lazy wrappers at root.
|
|
6
6
|
*/
|
|
7
|
-
export type SmartObjectSchema = z.ZodObject | z.ZodDiscriminatedUnion | z.ZodUnion;
|
|
7
|
+
export type SmartObjectSchema = z.ZodObject | z.ZodDiscriminatedUnion | z.ZodUnion | z.ZodIntersection | z.ZodLazy;
|
|
8
8
|
/**
|
|
9
9
|
* Compile-time map of `set*` methods for each schema key.
|
|
10
10
|
*
|
|
@@ -26,6 +26,30 @@ export type AllKeys<T> = T extends unknown ? keyof T : never;
|
|
|
26
26
|
export type SetMethodsUnion<T> = {
|
|
27
27
|
[K in AllKeys<T> as `set${Capitalize<string & K>}`]: (value: T extends unknown ? (K extends keyof T ? T[K] : never) : never) => void;
|
|
28
28
|
};
|
|
29
|
+
type UnionToIntersection<U> = (U extends unknown ? (value: U) => void : never) extends (value: infer I) => void ? I : never;
|
|
30
|
+
type OmitDiscriminator<T, D extends PropertyKey> = Omit<T, D & keyof T>;
|
|
31
|
+
type PerVariantSwitchMethod<T, D extends PropertyKey> = T extends Record<D, infer Tag extends string> ? Tag extends string ? {
|
|
32
|
+
[K in `switchTo${Capitalize<Tag>}`]: (value: OmitDiscriminator<T, D>) => void;
|
|
33
|
+
} : never : never;
|
|
34
|
+
/**
|
|
35
|
+
* Variant switching for union root schemas.
|
|
36
|
+
*/
|
|
37
|
+
export type VariantSwitchMethods<T> = {
|
|
38
|
+
switchVariant(value: T): void;
|
|
39
|
+
};
|
|
40
|
+
export type DiscriminatedVariantSwitchMethods<T, D extends PropertyKey> = VariantSwitchMethods<T> & UnionToIntersection<PerVariantSwitchMethod<T, D>>;
|
|
41
|
+
type EntryValue<T> = T extends Record<string, infer V> ? V : T extends Map<string, infer V> ? V : never;
|
|
42
|
+
type IsEntryField<T> = NonNullable<T> extends Record<string, unknown> ? true : NonNullable<T> extends Map<string, infer _V> ? true : false;
|
|
43
|
+
/**
|
|
44
|
+
* Dynamic entry accessors for `z.record` and string-key `z.map` fields.
|
|
45
|
+
*/
|
|
46
|
+
export type RecordFieldMethods<T> = {
|
|
47
|
+
[K in keyof T as IsEntryField<T[K]> extends true ? `get${Capitalize<string & K>}Entry` : never]: (key: string) => EntryValue<NonNullable<T[K]>> | undefined;
|
|
48
|
+
} & {
|
|
49
|
+
[K in keyof T as IsEntryField<T[K]> extends true ? `set${Capitalize<string & K>}Entry` : never]: (key: string, value: EntryValue<NonNullable<T[K]>>) => void;
|
|
50
|
+
} & {
|
|
51
|
+
[K in keyof T as IsEntryField<T[K]> extends true ? `delete${Capitalize<string & K>}Entry` : never]: (key: string) => void;
|
|
52
|
+
};
|
|
29
53
|
/**
|
|
30
54
|
* Read/write surface and audit trail are separate concerns in the public API.
|
|
31
55
|
*
|
|
@@ -50,12 +74,15 @@ export type SnapshotAccessor<T extends SmartObjectSchema> = {
|
|
|
50
74
|
export type UnionDataShape<U> = {
|
|
51
75
|
[K in AllKeys<U>]: U extends unknown ? (K extends keyof U ? U[K] : never) : never;
|
|
52
76
|
};
|
|
77
|
+
type ObjectLikeSchema<T extends SmartObjectSchema> = T extends z.ZodObject | z.ZodIntersection | z.ZodLazy ? z.infer<T> : never;
|
|
78
|
+
type UnionRootExtras<T extends SmartObjectSchema> = T extends z.ZodDiscriminatedUnion<infer _Options, infer Discriminator extends string> ? DiscriminatedVariantSwitchMethods<z.infer<T>, Discriminator> : T extends z.ZodUnion ? VariantSwitchMethods<z.infer<T>> : Record<string, never>;
|
|
79
|
+
type ObjectRootExtras<T extends SmartObjectSchema> = T extends z.ZodObject ? RecordFieldMethods<z.infer<T>> : T extends z.ZodIntersection | z.ZodLazy ? RecordFieldMethods<ObjectLikeSchema<T>> : Record<string, never>;
|
|
53
80
|
/**
|
|
54
81
|
* Full instance contract: validated data shape, typed mutators, and patch log.
|
|
55
82
|
*
|
|
56
83
|
* Intersection types merge these concerns into one consumable surface for callers.
|
|
57
84
|
*/
|
|
58
|
-
export type SmartObjectInstance<T extends SmartObjectSchema> = (T extends z.ZodObject ? z.infer<T> : UnionDataShape<z.infer<T>>) & (T extends z.ZodObject ? SetMethods<z.infer<T>> : SetMethodsUnion<z.infer<T>>) & OperationsAccessor & SnapshotAccessor<T>;
|
|
85
|
+
export type SmartObjectInstance<T extends SmartObjectSchema> = (T extends z.ZodObject ? z.infer<T> : T extends z.ZodIntersection | z.ZodLazy ? z.infer<T> : UnionDataShape<z.infer<T>>) & (T extends z.ZodObject | z.ZodIntersection | z.ZodLazy ? SetMethods<z.infer<T>> : SetMethodsUnion<z.infer<T>>) & ObjectRootExtras<T> & UnionRootExtras<T> & OperationsAccessor & SnapshotAccessor<T>;
|
|
59
86
|
/**
|
|
60
87
|
* Constructor type for a SmartObject class, including replay as a first-class capability.
|
|
61
88
|
*
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B;;GAEG;AACH,MAAM,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/zod-introspect.d.ts
CHANGED
|
@@ -3,6 +3,19 @@ import type { SmartObjectSchema } from "./types.js";
|
|
|
3
3
|
export type ZodObjectLike = z.ZodObject;
|
|
4
4
|
export type ZodUnionRootLike = z.ZodUnion;
|
|
5
5
|
export type ZodDiscriminatedUnionLike = z.ZodDiscriminatedUnion;
|
|
6
|
+
export type ZodIntersectionLike = z.ZodIntersection;
|
|
7
|
+
export type ZodLazyLike = z.ZodLazy;
|
|
8
|
+
export type DiscriminatedVariantInfo = {
|
|
9
|
+
tag: string | number | boolean;
|
|
10
|
+
schema: ZodObjectLike;
|
|
11
|
+
methodName: string;
|
|
12
|
+
};
|
|
13
|
+
export type RecordFieldInfo = {
|
|
14
|
+
fieldName: string;
|
|
15
|
+
fieldSchema: z.ZodType;
|
|
16
|
+
valueSchema: z.ZodType;
|
|
17
|
+
storage: "record" | "map";
|
|
18
|
+
};
|
|
6
19
|
export declare function isZodObject(schema: unknown): schema is ZodObjectLike;
|
|
7
20
|
export declare function isZodUnionRoot(schema: SmartObjectSchema): schema is ZodUnionRootLike;
|
|
8
21
|
export declare function isZodDiscriminatedUnion(schema: ZodUnionRootLike): schema is ZodDiscriminatedUnionLike;
|
|
@@ -11,4 +24,27 @@ export declare function getObjectShapeKeys(schema: ZodObjectLike): string[];
|
|
|
11
24
|
export declare function getUnionObjectKeys(schema: ZodUnionRootLike): string[];
|
|
12
25
|
export declare function getDiscriminator(schema: ZodDiscriminatedUnionLike): string;
|
|
13
26
|
export declare function toSetterMethodName(key: string): string;
|
|
27
|
+
export declare function toVariantSwitchMethodName(tag: string | number | boolean): string;
|
|
28
|
+
export declare function toRecordEntryMethodPrefix(fieldName: string): string;
|
|
29
|
+
export declare function getLiteralValue(schema: unknown): string | number | boolean | undefined;
|
|
30
|
+
export declare function getDiscriminatedVariants(schema: ZodDiscriminatedUnionLike): DiscriminatedVariantInfo[];
|
|
31
|
+
export declare function isZodRecord(schema: unknown): schema is z.ZodRecord;
|
|
32
|
+
export declare function isZodDate(schema: unknown): boolean;
|
|
33
|
+
export declare function isZodMap(schema: unknown): schema is z.ZodMap;
|
|
34
|
+
export declare function isZodSet(schema: unknown): schema is z.ZodSet;
|
|
35
|
+
export declare function isZodBigInt(schema: unknown): boolean;
|
|
36
|
+
export declare function isStringKeyMap(schema: unknown): schema is z.ZodMap;
|
|
37
|
+
export declare function unwrapFieldSchema(schema: z.ZodType): z.ZodType;
|
|
38
|
+
/** @deprecated Use unwrapFieldSchema */
|
|
39
|
+
export declare function unwrapOptionalNullable(schema: z.ZodType): z.ZodType;
|
|
40
|
+
export declare function isZodIntersection(schema: SmartObjectSchema): schema is ZodIntersectionLike;
|
|
41
|
+
export declare function isZodLazy(schema: SmartObjectSchema): schema is ZodLazyLike;
|
|
42
|
+
export declare function resolveLazySchema(schema: SmartObjectSchema): SmartObjectSchema;
|
|
43
|
+
export declare function getRecordFields(schema: ZodObjectLike): RecordFieldInfo[];
|
|
44
|
+
export declare function getRecordFieldsFromSchema(schema: SmartObjectSchema): RecordFieldInfo[];
|
|
45
|
+
export declare function getMergedObjectShape(schema: SmartObjectSchema): Record<string, z.ZodType>;
|
|
46
|
+
export declare function getSchemaShapeKeys(schema: SmartObjectSchema): string[];
|
|
47
|
+
export declare function getFieldSchema(schema: SmartObjectSchema, key: string): z.ZodType | undefined;
|
|
48
|
+
export declare function getObjectSchemaForFields(schema: SmartObjectSchema): ZodObjectLike | undefined;
|
|
49
|
+
export declare function isObjectLikeRoot(schema: SmartObjectSchema): boolean;
|
|
14
50
|
//# sourceMappingURL=zod-introspect.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zod-introspect.d.ts","sourceRoot":"","sources":["../src/zod-introspect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,SAAS,CAAC;AACxC,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,QAAQ,CAAC;AAC1C,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"zod-introspect.d.ts","sourceRoot":"","sources":["../src/zod-introspect.ts"],"names":[],"mappings":"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"}
|
package/dist/zod-introspect.js
CHANGED
|
@@ -34,3 +34,219 @@ export function getDiscriminator(schema) {
|
|
|
34
34
|
export function toSetterMethodName(key) {
|
|
35
35
|
return `set${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
36
36
|
}
|
|
37
|
+
export function toVariantSwitchMethodName(tag) {
|
|
38
|
+
const label = typeof tag === "string" ? tag : String(tag);
|
|
39
|
+
return `switchTo${label.charAt(0).toUpperCase()}${label.slice(1)}`;
|
|
40
|
+
}
|
|
41
|
+
export function toRecordEntryMethodPrefix(fieldName) {
|
|
42
|
+
return fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
|
|
43
|
+
}
|
|
44
|
+
export function getLiteralValue(schema) {
|
|
45
|
+
if (typeof schema !== "object" || schema === null || !("_zod" in schema)) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
const def = schema._zod.def;
|
|
49
|
+
if (def.type === "literal" && Array.isArray(def.values) && def.values.length === 1) {
|
|
50
|
+
const value = def.values[0];
|
|
51
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
export function getDiscriminatedVariants(schema) {
|
|
58
|
+
const discriminator = getDiscriminator(schema);
|
|
59
|
+
const variants = [];
|
|
60
|
+
for (const option of schema.options) {
|
|
61
|
+
if (!isZodObject(option)) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const tagSchema = option.shape[discriminator];
|
|
65
|
+
const tag = getLiteralValue(tagSchema);
|
|
66
|
+
if (tag === undefined) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
variants.push({
|
|
70
|
+
tag,
|
|
71
|
+
schema: option,
|
|
72
|
+
methodName: toVariantSwitchMethodName(tag),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return variants;
|
|
76
|
+
}
|
|
77
|
+
export function isZodRecord(schema) {
|
|
78
|
+
return (typeof schema === "object" &&
|
|
79
|
+
schema !== null &&
|
|
80
|
+
"_zod" in schema &&
|
|
81
|
+
schema._zod.def.type === "record");
|
|
82
|
+
}
|
|
83
|
+
export function isZodDate(schema) {
|
|
84
|
+
if (typeof schema !== "object" || schema === null || !("_zod" in schema)) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
const def = schema._zod.def;
|
|
88
|
+
return def.type === "date";
|
|
89
|
+
}
|
|
90
|
+
export function isZodMap(schema) {
|
|
91
|
+
return (typeof schema === "object" &&
|
|
92
|
+
schema !== null &&
|
|
93
|
+
"_zod" in schema &&
|
|
94
|
+
schema._zod.def.type === "map");
|
|
95
|
+
}
|
|
96
|
+
export function isZodSet(schema) {
|
|
97
|
+
return (typeof schema === "object" &&
|
|
98
|
+
schema !== null &&
|
|
99
|
+
"_zod" in schema &&
|
|
100
|
+
schema._zod.def.type === "set");
|
|
101
|
+
}
|
|
102
|
+
export function isZodBigInt(schema) {
|
|
103
|
+
if (typeof schema !== "object" || schema === null || !("_zod" in schema)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
return schema._zod.def.type === "bigint";
|
|
107
|
+
}
|
|
108
|
+
export function isStringKeyMap(schema) {
|
|
109
|
+
if (!isZodMap(schema)) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
const keyType = unwrapFieldSchema(schema._zod.def.keyType);
|
|
113
|
+
return keyType._zod.def.type === "string";
|
|
114
|
+
}
|
|
115
|
+
export function unwrapFieldSchema(schema) {
|
|
116
|
+
const def = schema._zod.def;
|
|
117
|
+
if (def.type === "optional" || def.type === "nullable" || def.type === "default") {
|
|
118
|
+
return unwrapFieldSchema(def.innerType);
|
|
119
|
+
}
|
|
120
|
+
if (def.type === "lazy") {
|
|
121
|
+
return unwrapFieldSchema(def.getter?.());
|
|
122
|
+
}
|
|
123
|
+
if (def.type === "pipe") {
|
|
124
|
+
const outType = def.out?._zod.def.type;
|
|
125
|
+
if (outType === "transform") {
|
|
126
|
+
return unwrapFieldSchema(def.in);
|
|
127
|
+
}
|
|
128
|
+
return unwrapFieldSchema(def.out);
|
|
129
|
+
}
|
|
130
|
+
return schema;
|
|
131
|
+
}
|
|
132
|
+
/** @deprecated Use unwrapFieldSchema */
|
|
133
|
+
export function unwrapOptionalNullable(schema) {
|
|
134
|
+
return unwrapFieldSchema(schema);
|
|
135
|
+
}
|
|
136
|
+
export function isZodIntersection(schema) {
|
|
137
|
+
return schema._zod.def.type === "intersection";
|
|
138
|
+
}
|
|
139
|
+
export function isZodLazy(schema) {
|
|
140
|
+
return schema._zod.def.type === "lazy";
|
|
141
|
+
}
|
|
142
|
+
export function resolveLazySchema(schema) {
|
|
143
|
+
if (isZodLazy(schema)) {
|
|
144
|
+
return resolveLazySchema(schema._zod.def.getter());
|
|
145
|
+
}
|
|
146
|
+
return schema;
|
|
147
|
+
}
|
|
148
|
+
function collectEntryField(fieldName, fieldSchema, unwrapped) {
|
|
149
|
+
if (isZodRecord(unwrapped)) {
|
|
150
|
+
return {
|
|
151
|
+
fieldName,
|
|
152
|
+
fieldSchema,
|
|
153
|
+
valueSchema: unwrapped._zod.def.valueType,
|
|
154
|
+
storage: "record",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (isStringKeyMap(unwrapped)) {
|
|
158
|
+
return {
|
|
159
|
+
fieldName,
|
|
160
|
+
fieldSchema,
|
|
161
|
+
valueSchema: unwrapped._zod.def.valueType,
|
|
162
|
+
storage: "map",
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
export function getRecordFields(schema) {
|
|
168
|
+
const fields = [];
|
|
169
|
+
for (const [fieldName, fieldSchema] of Object.entries(schema.shape)) {
|
|
170
|
+
const unwrapped = unwrapFieldSchema(fieldSchema);
|
|
171
|
+
const entryField = collectEntryField(fieldName, fieldSchema, unwrapped);
|
|
172
|
+
if (entryField) {
|
|
173
|
+
fields.push(entryField);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return fields;
|
|
177
|
+
}
|
|
178
|
+
export function getRecordFieldsFromSchema(schema) {
|
|
179
|
+
const resolved = resolveLazySchema(schema);
|
|
180
|
+
if (isZodObject(resolved)) {
|
|
181
|
+
return getRecordFields(resolved);
|
|
182
|
+
}
|
|
183
|
+
if (isZodIntersection(resolved)) {
|
|
184
|
+
const left = resolved._zod.def.left;
|
|
185
|
+
const right = resolved._zod.def.right;
|
|
186
|
+
return [...getRecordFieldsFromSchema(left), ...getRecordFieldsFromSchema(right)];
|
|
187
|
+
}
|
|
188
|
+
return [];
|
|
189
|
+
}
|
|
190
|
+
export function getMergedObjectShape(schema) {
|
|
191
|
+
const resolved = resolveLazySchema(schema);
|
|
192
|
+
if (isZodObject(resolved)) {
|
|
193
|
+
return resolved.shape;
|
|
194
|
+
}
|
|
195
|
+
if (isZodIntersection(resolved)) {
|
|
196
|
+
const left = resolved._zod.def.left;
|
|
197
|
+
const right = resolved._zod.def.right;
|
|
198
|
+
return {
|
|
199
|
+
...getMergedObjectShape(left),
|
|
200
|
+
...getMergedObjectShape(right),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return {};
|
|
204
|
+
}
|
|
205
|
+
export function getSchemaShapeKeys(schema) {
|
|
206
|
+
const resolved = resolveLazySchema(schema);
|
|
207
|
+
if (isZodObject(resolved)) {
|
|
208
|
+
return getObjectShapeKeys(resolved);
|
|
209
|
+
}
|
|
210
|
+
if (isZodUnionRoot(resolved)) {
|
|
211
|
+
return getUnionObjectKeys(resolved);
|
|
212
|
+
}
|
|
213
|
+
if (isZodIntersection(resolved)) {
|
|
214
|
+
const left = resolved._zod.def.left;
|
|
215
|
+
const right = resolved._zod.def.right;
|
|
216
|
+
return [...new Set([...getSchemaShapeKeys(left), ...getSchemaShapeKeys(right)])];
|
|
217
|
+
}
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
export function getFieldSchema(schema, key) {
|
|
221
|
+
const resolved = resolveLazySchema(schema);
|
|
222
|
+
if (isZodObject(resolved)) {
|
|
223
|
+
return resolved.shape[key];
|
|
224
|
+
}
|
|
225
|
+
if (isZodIntersection(resolved)) {
|
|
226
|
+
const left = resolved._zod.def.left;
|
|
227
|
+
const right = resolved._zod.def.right;
|
|
228
|
+
return getFieldSchema(left, key) ?? getFieldSchema(right, key);
|
|
229
|
+
}
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
export function getObjectSchemaForFields(schema) {
|
|
233
|
+
const resolved = resolveLazySchema(schema);
|
|
234
|
+
if (isZodObject(resolved)) {
|
|
235
|
+
return resolved;
|
|
236
|
+
}
|
|
237
|
+
if (isZodIntersection(resolved)) {
|
|
238
|
+
const left = resolved._zod.def.left;
|
|
239
|
+
const right = resolved._zod.def.right;
|
|
240
|
+
const leftObject = getObjectSchemaForFields(left);
|
|
241
|
+
const rightObject = getObjectSchemaForFields(right);
|
|
242
|
+
if (leftObject && rightObject) {
|
|
243
|
+
return leftObject;
|
|
244
|
+
}
|
|
245
|
+
return leftObject ?? rightObject;
|
|
246
|
+
}
|
|
247
|
+
return undefined;
|
|
248
|
+
}
|
|
249
|
+
export function isObjectLikeRoot(schema) {
|
|
250
|
+
const resolved = resolveLazySchema(schema);
|
|
251
|
+
return isZodObject(resolved) || isZodIntersection(resolved);
|
|
252
|
+
}
|
package/package.json
CHANGED