@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.
Files changed (36) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +35 -5
  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 +2 -0
  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` 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 variant switch** — Changing a discriminated union discriminator alone (e.g. `setType("scroll")` without providing `delta`) is not supported and throws `SmartObjectError`.
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
- - **JSON-only values** — RFC 6902 patches work on JSON-serializable data. `Date`, `Map`, and other non-JSON types are not supported.
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
- └── union-field.ts
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
@@ -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
  }
@@ -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.1",
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",