@gialicus/smart-object 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +42 -7
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/smart-object/apply-operations.d.ts.map +1 -1
  6. package/dist/smart-object/apply-operations.js +3 -1
  7. package/dist/smart-object/build-class.d.ts.map +1 -1
  8. package/dist/smart-object/build-class.js +2 -4
  9. package/dist/smart-object/codecs.d.ts +15 -0
  10. package/dist/smart-object/codecs.d.ts.map +1 -0
  11. package/dist/smart-object/codecs.js +163 -0
  12. package/dist/smart-object/define-prototype.d.ts.map +1 -1
  13. package/dist/smart-object/define-prototype.js +55 -3
  14. package/dist/smart-object/factory.d.ts +4 -2
  15. package/dist/smart-object/factory.d.ts.map +1 -1
  16. package/dist/smart-object/factory.js +20 -8
  17. package/dist/smart-object/json-patch.d.ts +2 -1
  18. package/dist/smart-object/json-patch.d.ts.map +1 -1
  19. package/dist/smart-object/json-patch.js +26 -1
  20. package/dist/smart-object/read-field.d.ts.map +1 -1
  21. package/dist/smart-object/read-field.js +6 -0
  22. package/dist/smart-object/setters/object-field.d.ts +3 -2
  23. package/dist/smart-object/setters/object-field.d.ts.map +1 -1
  24. package/dist/smart-object/setters/object-field.js +37 -5
  25. package/dist/smart-object/setters/record-field.d.ts +7 -0
  26. package/dist/smart-object/setters/record-field.d.ts.map +1 -0
  27. package/dist/smart-object/setters/record-field.js +133 -0
  28. package/dist/smart-object/setters/variant-switch.d.ts +5 -0
  29. package/dist/smart-object/setters/variant-switch.d.ts.map +1 -0
  30. package/dist/smart-object/setters/variant-switch.js +37 -0
  31. package/dist/types.d.ts +30 -3
  32. package/dist/types.d.ts.map +1 -1
  33. package/dist/zod-introspect.d.ts +36 -0
  34. package/dist/zod-introspect.d.ts.map +1 -1
  35. package/dist/zod-introspect.js +216 -0
  36. 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` and string-key `z.map` 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
@@ -8,7 +8,7 @@ Typed TypeScript objects backed by Zod schemas, with an RFC 6902 operation log f
8
8
  npm install @gialicus/smart-object zod
9
9
  ```
10
10
 
11
- Dependencies: [Zod](https://zod.dev) (peer dependency — schema validation) and [fast-json-patch](https://github.com/Starcounter-Jack/JSON-Patch) (RFC 6902 patch application, bundled).
11
+ Dependencies: [Zod](https://zod.dev) `^4.0.0` (peer dependency — schema validation) and [fast-json-patch](https://github.com/Starcounter-Jack/JSON-Patch) (RFC 6902 patch application, bundled).
12
12
 
13
13
  ## Usage
14
14
 
@@ -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 and Map field extras** (for each `z.record(...)` field or string-key `z.map(...)` field `tags`):
103
+
104
+ | Member | Type | Description |
105
+ |--------|------|-------------|
106
+ | `getTagsEntry(key)` | `(key: string) => V \| undefined` | Reads a single 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 an entry |
109
+
91
110
  **Instance members:**
92
111
 
93
112
  | Member | Type | Description |
@@ -124,10 +143,15 @@ RFC 6902 operation emitted by [fast-json-patch](https://github.com/Starcounter-J
124
143
  ### Exported types
125
144
 
126
145
  - `Operation` — JSON Patch operation (re-export from `fast-json-patch`)
146
+ - `SmartObjectSchema` — union of Zod schema types accepted by `SmartObject()`
147
+ - `SmartObjectErrorCode` — `"InvalidValue"` \| `"InvalidUnionField"` \| `"InvalidReplay"` \| `"UnsupportedSchema"`
127
148
  - `SetMethods<T>` — mapped type of inferred `set*` methods for shape `T`
128
149
  - `SetMethodsUnion<T>` — `set*` methods for union root schemas
129
150
  - `AllKeys<T>` — all keys across union members
130
151
  - `UnionDataShape<U>` — flattened data shape for union roots
152
+ - `VariantSwitchMethods<T>` — `switchVariant` for union roots
153
+ - `DiscriminatedVariantSwitchMethods<T, D>` — `switchVariant` plus generated `switchTo*` methods
154
+ - `RecordFieldMethods<T>` — dynamic entry accessors for `z.record` and string-key `z.map` fields
131
155
  - `OperationsAccessor` — `operations` and `clearOperations()`
132
156
  - `SnapshotAccessor<T>` — `toJSON()`
133
157
  - `SmartObjectConstructor<T>` — constructor type including `fromOperations`
@@ -135,9 +159,11 @@ RFC 6902 operation emitted by [fast-json-patch](https://github.com/Starcounter-J
135
159
 
136
160
  ## Limitations
137
161
 
138
- - **Partial variant switch** — Changing a discriminated union discriminator alone (e.g. `setType("scroll")` without providing `delta`) is not supported and throws `SmartObjectError`.
162
+ - **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
163
  - **Union field on wrong variant** — Setting a field that does not exist on the active variant throws `SmartObjectError`.
140
- - **JSON-only values** — RFC 6902 patches work on JSON-serializable data. `Date`, `Map`, and other non-JSON types are not supported.
164
+ - **Date fields** — `z.date()` and `z.coerce.date()` are supported; operations store ISO 8601 strings while getters return `Date` instances.
165
+ - **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. String-key `z.map` fields also expose per-entry `get/set/delete*Entry` methods; whole-field `set*` is used for `z.set` and for map fields with non-string keys (not supported). Non-string map keys are not supported.
166
+ - **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
167
 
142
168
  ## Design rationale
143
169
 
@@ -153,6 +179,7 @@ RFC 6902 operation emitted by [fast-json-patch](https://github.com/Starcounter-J
153
179
  - [`examples/person.ts`](examples/person.ts) — primitives, nested objects, and arrays
154
180
  - [`examples/event.ts`](examples/event.ts) — discriminated union root
155
181
  - [`examples/profile.ts`](examples/profile.ts) — generic union root
182
+ - [`examples/record.ts`](examples/record.ts) — `z.record` and string-key `z.map` entry API
156
183
 
157
184
  ## Project structure
158
185
 
@@ -169,17 +196,21 @@ smart-object/
169
196
  │ ├── build-class.ts # Class generation orchestration
170
197
  │ ├── instance-state.ts # WeakMap-backed instance storage
171
198
  │ ├── read-field.ts # Defensive getter reads
172
- │ ├── json-patch.ts # fast-json-patch wrapper
199
+ │ ├── json-patch.ts # fast-json-patch wrapper + Date-safe deepClone
200
+ │ ├── codecs.ts # JSON-safe codecs for Date, Map, Set, and bigint
173
201
  │ ├── apply-operations.ts # Replay and rollback
174
202
  │ ├── union-variant.ts # Union variant matching
175
203
  │ ├── define-prototype.ts # Getter/setter prototype setup
176
204
  │ └── setters/
177
205
  │ ├── object-field.ts
178
- └── union-field.ts
206
+ ├── union-field.ts
207
+ │ ├── variant-switch.ts
208
+ │ └── record-field.ts
179
209
  ├── examples/
180
210
  │ ├── person.ts
181
211
  │ ├── event.ts
182
- └── profile.ts
212
+ ├── profile.ts
213
+ │ └── record.ts
183
214
  ├── tests/
184
215
  │ ├── fixtures/
185
216
  │ │ ├── person.ts
@@ -199,6 +230,10 @@ smart-object/
199
230
  │ │ ├── setter-naming.test.ts
200
231
  │ │ ├── to-json.test.ts
201
232
  │ │ ├── schema-variants.test.ts
233
+ │ │ ├── record-fields.test.ts
234
+ │ │ ├── date-codec.test.ts
235
+ │ │ ├── complex-schema-types.test.ts
236
+ │ │ ├── intersection-lazy.test.ts
202
237
  │ │ └── types.test.ts
203
238
  │ └── zod-introspect.test.ts
204
239
  └── 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
@@ -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,GACf,MAAM,YAAY,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;AACrD,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,CAiBN"}
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 validated = zodSchema.parse(data);
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,CAuC3B"}
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 { getObjectShapeKeys, getUnionObjectKeys, isZodObject } from "../zod-introspect.js";
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 = isZodObject(zodSchema)
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;AAOrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKzD,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,CAqBN"}
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 { isZodObject, toSetterMethodName, } from "../zod-introspect.js";
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: isZodObject(zodSchema)
17
- ? createObjectFieldSetter(state, zodSchema, key)
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
  }
@@ -13,8 +13,8 @@ import type { SmartObjectConstructor } from "../types.js";
13
13
  * Initial construction does not emit operations because that state is the baseline
14
14
  * every subsequent patch is measured against.
15
15
  *
16
- * @typeParam T - Zod object or union-of-objects schema that defines the instance shape
17
- * @param zodSchema - A `z.object({ ... })`, `z.union([...])`, or `z.discriminatedUnion(...)` schema
16
+ * @typeParam T - Zod schema that defines the instance shape (object, union, intersection, or lazy root)
17
+ * @param zodSchema - A `z.object({ ... })`, `z.union([...])`, `z.discriminatedUnion(...)`, `z.intersection(...)`, or `z.lazy(...)` schema
18
18
  * @returns An instantiable class with types inferred from the schema
19
19
  *
20
20
  * @example
@@ -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;AAI7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
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
- export function SmartObject(zodSchema) {
5
- if (isZodObject(zodSchema)) {
6
- return buildSmartObjectClass(zodSchema);
4
+ function assertBuildableSchema(schema) {
5
+ const resolved = resolveLazySchema(schema);
6
+ if (isZodObject(resolved)) {
7
+ return;
7
8
  }
8
- if (isZodUnionRoot(zodSchema)) {
9
- if (!isZodUnionOfObjects(zodSchema)) {
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 buildSmartObjectClass(zodSchema);
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.discriminatedUnion(...) schema");
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, deepClone: typeof jsonPatch.deepClone;
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,4BAAE,SAAS,4BAAc,CAAC"}
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, deepClone } = jsonPatch;
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,CAMtD"}
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 { ZodObjectLike } from "../../zod-introspect.js";
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>, schema: ZodObjectLike, key: string): (this: object, value: unknown) => void;
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,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAG1D,wBAAgB,uBAAuB,CAAC,CAAC,EACvC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,MAAM,EAAE,aAAa,EACrB,GAAG,EAAE,MAAM,IAIM,MAAM,MAAM,EAAE,OAAO,OAAO,UAsB9C"}
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 { applyPatch, compare, deepClone } from "../json-patch.js";
3
- export function createObjectFieldSetter(state, schema, key) {
4
- const fieldSchema = schema.shape[key];
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 patch = compare(beforeData, afterData);
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
- applyPatch(data, patch, false, true);
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 or unions of objects at root.
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
  *
@@ -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,GAAG,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,qBAAqB,GAAG,CAAC,CAAC,QAAQ,CAAC;AAEnF;;;;;GAKG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI;KACzB,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI;CACxE,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,OAAO,GAAG,MAAM,CAAC,GAAG,KAAK,CAAC;AAE7D;;;;GAIG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;KAC9B,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,GAAG,CACnD,KAAK,EAAE,CAAC,SAAS,OAAO,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,KAClE,IAAI;CACV,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,qEAAqE;IACrE,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,8EAA8E;IAC9E,eAAe,IAAI,IAAI,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,iBAAiB,IAAI;IAC1D,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;KAC7B,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,OAAO,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK;CAClF,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,iBAAiB,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,GACjF,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GACV,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAC7B,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAC9E,kBAAkB,GAClB,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAEtB;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,CAAC,CAAC,SAAS,iBAAiB,IAAI;IAChE,KAAK,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC;IACnD,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC;CAClG,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -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;AAEhE,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,aAAa,CAOpE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,IAAI,gBAAgB,CAEpF;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,gBAAgB,GACvB,MAAM,IAAI,yBAAyB,CAErC;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAErE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CAElE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAcrE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,yBAAyB,GAAG,MAAM,CAE1E;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD"}
1
+ {"version":3,"file":"zod-introspect.d.ts","sourceRoot":"","sources":["../src/zod-introspect.ts"],"names":[],"mappings":"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"}
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gialicus/smart-object",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Oggetti TypeScript generati da schemi Zod con getter, set* tipizzati e operazioni JSON Patch",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",