@gialicus/smart-object 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -1
- package/README.md +97 -19
- package/dist/errors.d.ts +20 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +40 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/smart-object/apply-operations.d.ts +5 -0
- package/dist/smart-object/apply-operations.d.ts.map +1 -0
- package/dist/smart-object/apply-operations.js +19 -0
- package/dist/smart-object/build-class.d.ts +3 -0
- package/dist/smart-object/build-class.d.ts.map +1 -0
- package/dist/smart-object/build-class.js +33 -0
- package/dist/smart-object/define-prototype.d.ts +4 -0
- package/dist/smart-object/define-prototype.d.ts.map +1 -0
- package/dist/smart-object/define-prototype.js +24 -0
- package/dist/{smart-object.d.ts → smart-object/factory.d.ts} +2 -2
- package/dist/smart-object/factory.d.ts.map +1 -0
- package/dist/smart-object/factory.js +15 -0
- package/dist/smart-object/index.d.ts +2 -0
- package/dist/smart-object/index.d.ts.map +1 -0
- package/dist/smart-object/index.js +1 -0
- package/dist/smart-object/instance-state.d.ts +9 -0
- package/dist/smart-object/instance-state.d.ts.map +1 -0
- package/dist/smart-object/instance-state.js +23 -0
- package/dist/smart-object/json-patch.d.ts +3 -0
- package/dist/smart-object/json-patch.d.ts.map +1 -0
- package/dist/smart-object/json-patch.js +2 -0
- package/dist/smart-object/read-field.d.ts +2 -0
- package/dist/smart-object/read-field.d.ts.map +1 -0
- package/dist/smart-object/read-field.js +7 -0
- package/dist/smart-object/setters/object-field.d.ts +4 -0
- package/dist/smart-object/setters/object-field.d.ts.map +1 -0
- package/dist/smart-object/setters/object-field.js +24 -0
- package/dist/smart-object/setters/union-field.d.ts +4 -0
- package/dist/smart-object/setters/union-field.d.ts.map +1 -0
- package/dist/smart-object/setters/union-field.js +25 -0
- package/dist/smart-object/union-variant.d.ts +5 -0
- package/dist/smart-object/union-variant.d.ts.map +1 -0
- package/dist/smart-object/union-variant.js +38 -0
- package/dist/types.d.ts +7 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/zod-introspect.d.ts +14 -0
- package/dist/zod-introspect.d.ts.map +1 -0
- package/dist/zod-introspect.js +36 -0
- package/package.json +1 -1
- package/dist/smart-object.d.ts.map +0 -1
- package/dist/smart-object.js +0 -157
package/CHANGELOG.md
CHANGED
|
@@ -5,14 +5,39 @@ 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.0] - 2026-06-27
|
|
9
|
+
|
|
10
|
+
### Breaking
|
|
11
|
+
|
|
12
|
+
- Getters for object and array fields always return deep clones; in-place mutation no longer affects internal state
|
|
13
|
+
- Removed `SmartObjectOptions` and the `immutableReads` factory option
|
|
14
|
+
- `operations` getter returns a defensive copy instead of the internal array reference
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- `toJSON()` instance method for deep-cloned, JSON-safe snapshots (also used by `JSON.stringify`)
|
|
19
|
+
- `SmartObjectError` with structured `code`, optional `field`, and `cause` for programmatic error handling
|
|
20
|
+
- Zod schema introspection isolated in `src/zod-introspect.ts`
|
|
21
|
+
- CI matrix job testing Zod peer compatibility (`4.0.0` and `latest`)
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Getter and setter methods are defined on the class prototype (one definition per schema, not per instance)
|
|
26
|
+
- Object field setters use a single `deepClone` per write instead of two
|
|
27
|
+
- `fromOperations` re-validates state with Zod after applying patches; invalid replay throws `SmartObjectError` and rolls back
|
|
28
|
+
- Setter and union validation errors throw `SmartObjectError` instead of generic `Error`
|
|
29
|
+
- Unsupported schema at factory time throws `SmartObjectError` with code `UnsupportedSchema`
|
|
30
|
+
|
|
8
31
|
## [1.0.0] - 2026-06-27
|
|
9
32
|
|
|
10
33
|
### Added
|
|
11
34
|
|
|
12
35
|
- `SmartObject(schema)` factory: typed getters and `set*` methods generated from a Zod object schema
|
|
36
|
+
- Support for `z.union([...])` and `z.discriminatedUnion(...)` at schema root
|
|
13
37
|
- RFC 6902 operation log (`operations`) for every validated change
|
|
14
38
|
- `clearOperations()` to reset the audit trail without rolling back state
|
|
15
39
|
- `fromOperations(initial, operations)` static method for deterministic replay
|
|
16
|
-
- Exported types: `Operation`, `SetMethods`, `OperationsAccessor`, `SmartObjectConstructor`, `SmartObjectInstance`
|
|
40
|
+
- Exported types: `Operation`, `SetMethods`, `SetMethodsUnion`, `AllKeys`, `UnionDataShape`, `OperationsAccessor`, `SmartObjectConstructor`, `SmartObjectInstance`
|
|
17
41
|
|
|
42
|
+
[2.0.0]: https://github.com/gialicus/smart-object/compare/v1.0.0...v2.0.0
|
|
18
43
|
[1.0.0]: https://github.com/gialicus/smart-object/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ const Person = SmartObject(z.object({
|
|
|
23
23
|
|
|
24
24
|
const person = new Person({ name: "Mario", age: 30 });
|
|
25
25
|
|
|
26
|
-
// Reads expose validated state
|
|
26
|
+
// Reads expose validated state
|
|
27
27
|
console.log(person.name); // "Mario"
|
|
28
28
|
|
|
29
29
|
// Writes validate first, then append patches to person.operations
|
|
@@ -40,6 +40,9 @@ person.setName("Luigi"); // Unchanged value — no operation added (keeps sync p
|
|
|
40
40
|
|
|
41
41
|
person.clearOperations(); // Drops the audit trail after persist/sync; state is unchanged
|
|
42
42
|
|
|
43
|
+
// Snapshot for serialization — deep clone, safe for JSON.stringify
|
|
44
|
+
console.log(person.toJSON());
|
|
45
|
+
|
|
43
46
|
// Initial construction is the replay baseline — it never emits operations
|
|
44
47
|
console.log(new Person({ name: "Mario", age: 30 }).operations); // []
|
|
45
48
|
|
|
@@ -48,37 +51,66 @@ const initial = { name: "Mario", age: 30 };
|
|
|
48
51
|
const person2 = Person.fromOperations(initial, [...person.operations]);
|
|
49
52
|
```
|
|
50
53
|
|
|
54
|
+
### Union root schemas
|
|
55
|
+
|
|
56
|
+
`SmartObject` also accepts `z.discriminatedUnion(...)` and `z.union([...])` when every option is a `z.object(...)`:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const Event = SmartObject(z.discriminatedUnion("type", [
|
|
60
|
+
z.object({ type: z.literal("click"), x: z.number(), y: z.number() }),
|
|
61
|
+
z.object({ type: z.literal("scroll"), delta: z.number() }),
|
|
62
|
+
]));
|
|
63
|
+
|
|
64
|
+
const event = new Event({ type: "click", x: 10, y: 20 });
|
|
65
|
+
event.setX(15);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
See [`examples/event.ts`](examples/event.ts) and [`examples/profile.ts`](examples/profile.ts) for full demos.
|
|
69
|
+
|
|
70
|
+
Object and array getters always return deep clones — in-place mutation does not affect internal state or the operation log. Only `set*` methods generate RFC 6902 operations.
|
|
71
|
+
|
|
51
72
|
## API
|
|
52
73
|
|
|
53
74
|
### `SmartObject(schema)`
|
|
54
75
|
|
|
55
|
-
Factory that accepts a
|
|
76
|
+
Factory that accepts a Zod schema and returns an instantiable class.
|
|
56
77
|
|
|
57
78
|
| Parameter | Type | Description |
|
|
58
79
|
|-----------|------|-------------|
|
|
59
|
-
| `schema` | `z.ZodObject` | Zod schema defining the object shape |
|
|
80
|
+
| `schema` | `z.ZodObject` \| `z.ZodUnion` \| `z.ZodDiscriminatedUnion` | Zod schema defining the object shape |
|
|
60
81
|
|
|
61
82
|
**Members generated for each schema field `foo`:**
|
|
62
83
|
|
|
63
84
|
| Member | Type | Description |
|
|
64
85
|
|--------|------|-------------|
|
|
65
|
-
| `foo` | getter | Exposes the current validated field value |
|
|
86
|
+
| `foo` | getter | Exposes the current validated field value (deep clone for objects and arrays) |
|
|
66
87
|
| `setFoo(value)` | `(value: T) => void` | Validates, updates state, and records patches only when the value actually changes |
|
|
67
88
|
|
|
89
|
+
`set*` method names follow camelCase with the field name capitalized (`name` → `setName`, `userId` → `setUserId`).
|
|
90
|
+
|
|
68
91
|
**Instance members:**
|
|
69
92
|
|
|
70
93
|
| Member | Type | Description |
|
|
71
94
|
|--------|------|-------------|
|
|
72
|
-
| `operations` | `readonly Operation[]` | Chronological RFC 6902 patch log |
|
|
95
|
+
| `operations` | `readonly Operation[]` | Chronological RFC 6902 patch log (defensive copy) |
|
|
73
96
|
| `clearOperations()` | `() => void` | Clears the patch log without rolling back state |
|
|
74
|
-
|
|
75
|
-
`set*` method names follow camelCase with the field name capitalized (`name` → `setName`, `address` → `setAddress`).
|
|
97
|
+
| `toJSON()` | `() => T` | Deep clone of current state, safe for `JSON.stringify` |
|
|
76
98
|
|
|
77
99
|
**Static members:**
|
|
78
100
|
|
|
79
101
|
| Member | Type | Description |
|
|
80
102
|
|--------|------|-------------|
|
|
81
|
-
| `fromOperations(initial, operations)` | `(initial, Operation[]) => Instance` | Builds an instance from a baseline, replays operations, and copies them into the accumulator |
|
|
103
|
+
| `fromOperations(initial, operations)` | `(initial, Operation[]) => Instance` | Builds an instance from a baseline, replays and validates operations, and copies them into the accumulator |
|
|
104
|
+
|
|
105
|
+
### `SmartObjectError`
|
|
106
|
+
|
|
107
|
+
Structured error thrown on validation failures, invalid union field access, and failed replay:
|
|
108
|
+
|
|
109
|
+
| Property | Type | Description |
|
|
110
|
+
|----------|------|-------------|
|
|
111
|
+
| `code` | `"InvalidValue"` \| `"InvalidUnionField"` \| `"InvalidReplay"` \| `"UnsupportedSchema"` | Error category |
|
|
112
|
+
| `field` | `string` \| `undefined` | Schema field path when applicable |
|
|
113
|
+
| `cause` | `unknown` | Original error (e.g. `ZodError`) |
|
|
82
114
|
|
|
83
115
|
### `Operation`
|
|
84
116
|
|
|
@@ -93,8 +125,19 @@ RFC 6902 operation emitted by [fast-json-patch](https://github.com/Starcounter-J
|
|
|
93
125
|
|
|
94
126
|
- `Operation` — JSON Patch operation (re-export from `fast-json-patch`)
|
|
95
127
|
- `SetMethods<T>` — mapped type of inferred `set*` methods for shape `T`
|
|
128
|
+
- `SetMethodsUnion<T>` — `set*` methods for union root schemas
|
|
129
|
+
- `AllKeys<T>` — all keys across union members
|
|
130
|
+
- `UnionDataShape<U>` — flattened data shape for union roots
|
|
96
131
|
- `OperationsAccessor` — `operations` and `clearOperations()`
|
|
132
|
+
- `SnapshotAccessor<T>` — `toJSON()`
|
|
97
133
|
- `SmartObjectConstructor<T>` — constructor type including `fromOperations`
|
|
134
|
+
- `SmartObjectInstance<T>` — full instance type (getters + set* + operations + toJSON)
|
|
135
|
+
|
|
136
|
+
## Limitations
|
|
137
|
+
|
|
138
|
+
- **Partial variant switch** — Changing a discriminated union discriminator alone (e.g. `setType("scroll")` without providing `delta`) is not supported and throws `SmartObjectError`.
|
|
139
|
+
- **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.
|
|
98
141
|
|
|
99
142
|
## Design rationale
|
|
100
143
|
|
|
@@ -103,25 +146,60 @@ RFC 6902 operation emitted by [fast-json-patch](https://github.com/Starcounter-J
|
|
|
103
146
|
3. **No-op writes** — Identical values are skipped to keep the patch log minimal and suitable for network sync.
|
|
104
147
|
4. **Patch-based updates** — Changes are expressed as RFC 6902 operations so deltas are standard, composable, and replayable.
|
|
105
148
|
5. **Operation accumulation** — Patches from `compare` are appended in order, preserving causality for audit and replay.
|
|
106
|
-
6. **Replay** — `fromOperations(initial, operations)` requires the same baseline used when the operations were produced
|
|
107
|
-
|
|
108
|
-
- `SmartObjectInstance<T>` — full instance type (getters + set* + operations)
|
|
149
|
+
6. **Replay** — `fromOperations(initial, operations)` replays patches, re-validates with Zod, and requires the same baseline used when the operations were produced.
|
|
109
150
|
|
|
110
|
-
##
|
|
151
|
+
## Examples
|
|
111
152
|
|
|
112
|
-
|
|
153
|
+
- [`examples/person.ts`](examples/person.ts) — primitives, nested objects, and arrays
|
|
154
|
+
- [`examples/event.ts`](examples/event.ts) — discriminated union root
|
|
155
|
+
- [`examples/profile.ts`](examples/profile.ts) — generic union root
|
|
113
156
|
|
|
114
157
|
## Project structure
|
|
115
158
|
|
|
116
159
|
```
|
|
117
160
|
smart-object/
|
|
118
161
|
├── src/
|
|
119
|
-
│ ├── index.ts
|
|
120
|
-
│ ├──
|
|
121
|
-
│
|
|
162
|
+
│ ├── index.ts # Public API barrel export
|
|
163
|
+
│ ├── types.ts # Operation and inferred types
|
|
164
|
+
│ ├── errors.ts # SmartObjectError
|
|
165
|
+
│ ├── zod-introspect.ts # Zod schema introspection
|
|
166
|
+
│ └── smart-object/
|
|
167
|
+
│ ├── index.ts # Re-export SmartObject
|
|
168
|
+
│ ├── factory.ts # Public SmartObject() factory
|
|
169
|
+
│ ├── build-class.ts # Class generation orchestration
|
|
170
|
+
│ ├── instance-state.ts # WeakMap-backed instance storage
|
|
171
|
+
│ ├── read-field.ts # Defensive getter reads
|
|
172
|
+
│ ├── json-patch.ts # fast-json-patch wrapper
|
|
173
|
+
│ ├── apply-operations.ts # Replay and rollback
|
|
174
|
+
│ ├── union-variant.ts # Union variant matching
|
|
175
|
+
│ ├── define-prototype.ts # Getter/setter prototype setup
|
|
176
|
+
│ └── setters/
|
|
177
|
+
│ ├── object-field.ts
|
|
178
|
+
│ └── union-field.ts
|
|
122
179
|
├── examples/
|
|
123
|
-
│
|
|
180
|
+
│ ├── person.ts
|
|
181
|
+
│ ├── event.ts
|
|
182
|
+
│ └── profile.ts
|
|
124
183
|
├── tests/
|
|
125
|
-
│
|
|
126
|
-
|
|
184
|
+
│ ├── fixtures/
|
|
185
|
+
│ │ ├── person.ts
|
|
186
|
+
│ │ ├── entity.ts
|
|
187
|
+
│ │ ├── event.ts
|
|
188
|
+
│ │ └── profile.ts
|
|
189
|
+
│ ├── smart-object/
|
|
190
|
+
│ │ ├── construction.test.ts
|
|
191
|
+
│ │ ├── getters.test.ts
|
|
192
|
+
│ │ ├── setters.test.ts
|
|
193
|
+
│ │ ├── clear-operations.test.ts
|
|
194
|
+
│ │ ├── from-operations.test.ts
|
|
195
|
+
│ │ ├── union-fields.test.ts
|
|
196
|
+
│ │ ├── discriminated-union-root.test.ts
|
|
197
|
+
│ │ ├── generic-union-root.test.ts
|
|
198
|
+
│ │ ├── robustness.test.ts
|
|
199
|
+
│ │ ├── setter-naming.test.ts
|
|
200
|
+
│ │ ├── to-json.test.ts
|
|
201
|
+
│ │ ├── schema-variants.test.ts
|
|
202
|
+
│ │ └── types.test.ts
|
|
203
|
+
│ └── zod-introspect.test.ts
|
|
204
|
+
└── dist/ # Build output (generated)
|
|
127
205
|
```
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type SmartObjectErrorCode = "InvalidValue" | "InvalidUnionField" | "InvalidReplay" | "UnsupportedSchema";
|
|
2
|
+
/**
|
|
3
|
+
* Structured error for SmartObject operations — enables programmatic handling
|
|
4
|
+
* without parsing generic Error messages.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SmartObjectError extends Error {
|
|
7
|
+
readonly code: SmartObjectErrorCode;
|
|
8
|
+
readonly field?: string;
|
|
9
|
+
readonly cause?: unknown;
|
|
10
|
+
constructor(code: SmartObjectErrorCode, message: string, options?: {
|
|
11
|
+
field?: string;
|
|
12
|
+
cause?: unknown;
|
|
13
|
+
});
|
|
14
|
+
static invalidValue(field: string, cause: unknown): SmartObjectError;
|
|
15
|
+
static invalidUnionField(field: string, message?: string): SmartObjectError;
|
|
16
|
+
static invalidUnionState(): SmartObjectError;
|
|
17
|
+
static invalidReplay(cause: unknown): SmartObjectError;
|
|
18
|
+
static unsupportedSchema(message: string): SmartObjectError;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,oBAAoB,GAC5B,cAAc,GACd,mBAAmB,GACnB,eAAe,GACf,mBAAmB,CAAC;AAExB;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBAGvB,IAAI,EAAE,oBAAoB,EAC1B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;IAS/C,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,gBAAgB;IAapE,MAAM,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB;IAQ3E,MAAM,CAAC,iBAAiB,IAAI,gBAAgB;IAI5C,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB;IAStD,MAAM,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB;CAG5D"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error for SmartObject operations — enables programmatic handling
|
|
3
|
+
* without parsing generic Error messages.
|
|
4
|
+
*/
|
|
5
|
+
export class SmartObjectError extends Error {
|
|
6
|
+
code;
|
|
7
|
+
field;
|
|
8
|
+
cause;
|
|
9
|
+
constructor(code, message, options) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "SmartObjectError";
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.field = options?.field;
|
|
14
|
+
this.cause = options?.cause;
|
|
15
|
+
}
|
|
16
|
+
static invalidValue(field, cause) {
|
|
17
|
+
if (cause instanceof SmartObjectError) {
|
|
18
|
+
return cause;
|
|
19
|
+
}
|
|
20
|
+
const message = cause instanceof Error && "issues" in cause
|
|
21
|
+
? `Invalid value for "${field}": ${cause.issues.map((i) => i.message).join(", ")}`
|
|
22
|
+
: `Invalid value for "${field}"`;
|
|
23
|
+
return new SmartObjectError("InvalidValue", message, { field, cause });
|
|
24
|
+
}
|
|
25
|
+
static invalidUnionField(field, message) {
|
|
26
|
+
return new SmartObjectError("InvalidUnionField", message ?? `Cannot set "${field}" on the active union variant`, { field });
|
|
27
|
+
}
|
|
28
|
+
static invalidUnionState() {
|
|
29
|
+
return new SmartObjectError("InvalidUnionField", "Cannot set field on invalid union state");
|
|
30
|
+
}
|
|
31
|
+
static invalidReplay(cause) {
|
|
32
|
+
const message = cause instanceof Error
|
|
33
|
+
? `Operation replay failed: ${cause.message}`
|
|
34
|
+
: "Operation replay failed";
|
|
35
|
+
return new SmartObjectError("InvalidReplay", message, { cause });
|
|
36
|
+
}
|
|
37
|
+
static unsupportedSchema(message) {
|
|
38
|
+
return new SmartObjectError("UnsupportedSchema", message);
|
|
39
|
+
}
|
|
40
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export
|
|
1
|
+
export type { SmartObjectErrorCode } from "./errors.js";
|
|
2
|
+
export { SmartObjectError } from "./errors.js";
|
|
3
|
+
export { SmartObject } from "./smart-object/index.js";
|
|
4
|
+
export type { AllKeys, Operation, OperationsAccessor, SetMethods, SetMethodsUnion, SmartObjectConstructor, SmartObjectInstance, SmartObjectSchema, SnapshotAccessor, UnionDataShape, } from "./types.js";
|
|
3
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,
|
|
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"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { SmartObjectError } from "./errors.js";
|
|
2
|
+
export { SmartObject } from "./smart-object/index.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Operation } from "fast-json-patch";
|
|
2
|
+
import type { SmartObjectSchema } from "../types.js";
|
|
3
|
+
import type { InstanceState } from "./instance-state.js";
|
|
4
|
+
export declare function applyOperations<T>(state: InstanceState<T>, zodSchema: SmartObjectSchema, instance: object, operations: Operation[]): void;
|
|
5
|
+
//# sourceMappingURL=apply-operations.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { SmartObjectError } from "../errors.js";
|
|
2
|
+
import { applyPatch, deepClone } from "./json-patch.js";
|
|
3
|
+
export function applyOperations(state, zodSchema, instance, operations) {
|
|
4
|
+
if (operations.length === 0) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
const data = state.getData(instance);
|
|
8
|
+
const snapshot = deepClone(data);
|
|
9
|
+
try {
|
|
10
|
+
applyPatch(data, operations, false, true);
|
|
11
|
+
const validated = zodSchema.parse(data);
|
|
12
|
+
state.setData(instance, validated);
|
|
13
|
+
state.getOperations(instance).push(...operations);
|
|
14
|
+
}
|
|
15
|
+
catch (cause) {
|
|
16
|
+
state.setData(instance, snapshot);
|
|
17
|
+
throw SmartObjectError.invalidReplay(cause);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { getObjectShapeKeys, getUnionObjectKeys, isZodObject } from "../zod-introspect.js";
|
|
2
|
+
import { applyOperations } from "./apply-operations.js";
|
|
3
|
+
import { definePrototype } from "./define-prototype.js";
|
|
4
|
+
import { createInstanceState } from "./instance-state.js";
|
|
5
|
+
import { deepClone } from "./json-patch.js";
|
|
6
|
+
export function buildSmartObjectClass(zodSchema) {
|
|
7
|
+
const keys = isZodObject(zodSchema)
|
|
8
|
+
? getObjectShapeKeys(zodSchema)
|
|
9
|
+
: getUnionObjectKeys(zodSchema);
|
|
10
|
+
const state = createInstanceState();
|
|
11
|
+
class SmartObjectClass {
|
|
12
|
+
static fromOperations(initial, operations) {
|
|
13
|
+
const instance = new SmartObjectClass(initial);
|
|
14
|
+
applyOperations(state, zodSchema, instance, operations);
|
|
15
|
+
return instance;
|
|
16
|
+
}
|
|
17
|
+
get operations() {
|
|
18
|
+
return [...state.getOperations(this)];
|
|
19
|
+
}
|
|
20
|
+
clearOperations() {
|
|
21
|
+
state.getOperations(this).length = 0;
|
|
22
|
+
}
|
|
23
|
+
toJSON() {
|
|
24
|
+
return deepClone(state.getData(this));
|
|
25
|
+
}
|
|
26
|
+
constructor(initial) {
|
|
27
|
+
state.setData(this, zodSchema.parse(initial ?? {}));
|
|
28
|
+
state.initOperations(this);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
definePrototype(SmartObjectClass.prototype, state, zodSchema, keys);
|
|
32
|
+
return SmartObjectClass;
|
|
33
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SmartObjectSchema } from "../types.js";
|
|
2
|
+
import type { InstanceState } from "./instance-state.js";
|
|
3
|
+
export declare function definePrototype<T>(prototype: object, state: InstanceState<T>, zodSchema: SmartObjectSchema, keys: string[]): void;
|
|
4
|
+
//# sourceMappingURL=define-prototype.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { isZodObject, toSetterMethodName, } from "../zod-introspect.js";
|
|
2
|
+
import { readFieldValue } from "./read-field.js";
|
|
3
|
+
import { createObjectFieldSetter } from "./setters/object-field.js";
|
|
4
|
+
import { createUnionFieldSetter } from "./setters/union-field.js";
|
|
5
|
+
export function definePrototype(prototype, state, zodSchema, keys) {
|
|
6
|
+
for (const key of keys) {
|
|
7
|
+
const setMethodName = toSetterMethodName(key);
|
|
8
|
+
Object.defineProperty(prototype, key, {
|
|
9
|
+
get() {
|
|
10
|
+
return readFieldValue(state.getData(this)[key]);
|
|
11
|
+
},
|
|
12
|
+
enumerable: true,
|
|
13
|
+
configurable: true,
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(prototype, setMethodName, {
|
|
16
|
+
value: isZodObject(zodSchema)
|
|
17
|
+
? createObjectFieldSetter(state, zodSchema, key)
|
|
18
|
+
: createUnionFieldSetter(state, zodSchema, key),
|
|
19
|
+
enumerable: false,
|
|
20
|
+
configurable: true,
|
|
21
|
+
writable: true,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
|
-
import type { SmartObjectConstructor } from "
|
|
2
|
+
import type { SmartObjectConstructor } from "../types.js";
|
|
3
3
|
/**
|
|
4
4
|
* Builds a typed SmartObject class from a Zod schema.
|
|
5
5
|
*
|
|
@@ -33,4 +33,4 @@ 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
|
-
//# sourceMappingURL=
|
|
36
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SmartObjectError } from "../errors.js";
|
|
2
|
+
import { isZodObject, isZodUnionOfObjects, isZodUnionRoot } from "../zod-introspect.js";
|
|
3
|
+
import { buildSmartObjectClass } from "./build-class.js";
|
|
4
|
+
export function SmartObject(zodSchema) {
|
|
5
|
+
if (isZodObject(zodSchema)) {
|
|
6
|
+
return buildSmartObjectClass(zodSchema);
|
|
7
|
+
}
|
|
8
|
+
if (isZodUnionRoot(zodSchema)) {
|
|
9
|
+
if (!isZodUnionOfObjects(zodSchema)) {
|
|
10
|
+
throw SmartObjectError.unsupportedSchema("SmartObject union root requires all options to be z.object(...)");
|
|
11
|
+
}
|
|
12
|
+
return buildSmartObjectClass(zodSchema);
|
|
13
|
+
}
|
|
14
|
+
throw SmartObjectError.unsupportedSchema("SmartObject requires a z.object(...), z.union([...]), or z.discriminatedUnion(...) schema");
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/smart-object/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SmartObject } from "./factory.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Operation } from "fast-json-patch";
|
|
2
|
+
export type InstanceState<T> = {
|
|
3
|
+
getData(instance: object): T;
|
|
4
|
+
setData(instance: object, data: T): void;
|
|
5
|
+
getOperations(instance: object): Operation[];
|
|
6
|
+
initOperations(instance: object): void;
|
|
7
|
+
};
|
|
8
|
+
export declare function createInstanceState<T>(): InstanceState<T>;
|
|
9
|
+
//# sourceMappingURL=instance-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-state.d.ts","sourceRoot":"","sources":["../../src/smart-object/instance-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAC7B,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACzC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,CAAC;IAC7C,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACxC,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC,CA0BzD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function createInstanceState() {
|
|
2
|
+
const instanceData = new WeakMap();
|
|
3
|
+
const instanceOperations = new WeakMap();
|
|
4
|
+
return {
|
|
5
|
+
getData(instance) {
|
|
6
|
+
return instanceData.get(instance);
|
|
7
|
+
},
|
|
8
|
+
setData(instance, data) {
|
|
9
|
+
instanceData.set(instance, data);
|
|
10
|
+
},
|
|
11
|
+
getOperations(instance) {
|
|
12
|
+
let operations = instanceOperations.get(instance);
|
|
13
|
+
if (!operations) {
|
|
14
|
+
operations = [];
|
|
15
|
+
instanceOperations.set(instance, operations);
|
|
16
|
+
}
|
|
17
|
+
return operations;
|
|
18
|
+
},
|
|
19
|
+
initOperations(instance) {
|
|
20
|
+
instanceOperations.set(instance, []);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ZodObjectLike } from "../../zod-introspect.js";
|
|
2
|
+
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
|
+
//# sourceMappingURL=object-field.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
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];
|
|
5
|
+
return function (value) {
|
|
6
|
+
let parsed;
|
|
7
|
+
try {
|
|
8
|
+
parsed = fieldSchema.parse(value);
|
|
9
|
+
}
|
|
10
|
+
catch (cause) {
|
|
11
|
+
throw SmartObjectError.invalidValue(key, cause);
|
|
12
|
+
}
|
|
13
|
+
const data = state.getData(this);
|
|
14
|
+
const beforeData = deepClone(data);
|
|
15
|
+
const afterData = deepClone(data);
|
|
16
|
+
afterData[key] = parsed;
|
|
17
|
+
const patch = compare(beforeData, afterData);
|
|
18
|
+
if (patch.length === 0) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
applyPatch(data, patch, false, true);
|
|
22
|
+
state.getOperations(this).push(...patch);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ZodUnionRootLike } from "../../zod-introspect.js";
|
|
2
|
+
import type { InstanceState } from "../instance-state.js";
|
|
3
|
+
export declare function createUnionFieldSetter<T>(state: InstanceState<T>, schema: ZodUnionRootLike, key: string): (this: object, value: unknown) => void;
|
|
4
|
+
//# sourceMappingURL=union-field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"union-field.d.ts","sourceRoot":"","sources":["../../../src/smart-object/setters/union-field.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,wBAAgB,sBAAsB,CAAC,CAAC,EACtC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,MAAM,EAAE,gBAAgB,EACxB,GAAG,EAAE,MAAM,IAEM,MAAM,MAAM,EAAE,OAAO,OAAO,UAyB9C"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { SmartObjectError } from "../../errors.js";
|
|
2
|
+
import { compare, deepClone } from "../json-patch.js";
|
|
3
|
+
import { assertKeyAllowedOnMatchingVariants, getMatchingVariantObjects } from "../union-variant.js";
|
|
4
|
+
export function createUnionFieldSetter(state, schema, key) {
|
|
5
|
+
return function (value) {
|
|
6
|
+
const matchingVariants = getMatchingVariantObjects(state, this, schema);
|
|
7
|
+
assertKeyAllowedOnMatchingVariants(matchingVariants, key);
|
|
8
|
+
const data = state.getData(this);
|
|
9
|
+
const beforeData = deepClone(data);
|
|
10
|
+
const candidate = { ...deepClone(data), [key]: value };
|
|
11
|
+
let parsed;
|
|
12
|
+
try {
|
|
13
|
+
parsed = schema.parse(candidate);
|
|
14
|
+
}
|
|
15
|
+
catch (cause) {
|
|
16
|
+
throw SmartObjectError.invalidValue(key, cause);
|
|
17
|
+
}
|
|
18
|
+
const patch = compare(beforeData, parsed);
|
|
19
|
+
if (patch.length === 0) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
state.setData(this, parsed);
|
|
23
|
+
state.getOperations(this).push(...patch);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type ZodObjectLike, type ZodUnionRootLike } from "../zod-introspect.js";
|
|
2
|
+
import type { InstanceState } from "./instance-state.js";
|
|
3
|
+
export declare function getMatchingVariantObjects<T>(state: InstanceState<T>, instance: object, schema: ZodUnionRootLike): ZodObjectLike[];
|
|
4
|
+
export declare function assertKeyAllowedOnMatchingVariants(matchingVariants: ZodObjectLike[], key: string): void;
|
|
5
|
+
//# sourceMappingURL=union-variant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"union-variant.d.ts","sourceRoot":"","sources":["../../src/smart-object/union-variant.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACtB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAuBzD,wBAAgB,yBAAyB,CAAC,CAAC,EACzC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,gBAAgB,GACvB,aAAa,EAAE,CASjB;AAED,wBAAgB,kCAAkC,CAChD,gBAAgB,EAAE,aAAa,EAAE,EACjC,GAAG,EAAE,MAAM,GACV,IAAI,CAeN"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { SmartObjectError } from "../errors.js";
|
|
2
|
+
import { getDiscriminator, isZodDiscriminatedUnion, isZodObject, } from "../zod-introspect.js";
|
|
3
|
+
function getActiveVariantViaDiscriminator(schema, data) {
|
|
4
|
+
const discriminator = getDiscriminator(schema);
|
|
5
|
+
const tag = data[discriminator];
|
|
6
|
+
for (const option of schema.options) {
|
|
7
|
+
if (!isZodObject(option)) {
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
const tagSchema = option.shape[discriminator];
|
|
11
|
+
if (tagSchema?.safeParse(tag).success) {
|
|
12
|
+
return option;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
export function getMatchingVariantObjects(state, instance, schema) {
|
|
18
|
+
const data = state.getData(instance);
|
|
19
|
+
if (isZodDiscriminatedUnion(schema)) {
|
|
20
|
+
const activeVariant = getActiveVariantViaDiscriminator(schema, data);
|
|
21
|
+
return activeVariant ? [activeVariant] : [];
|
|
22
|
+
}
|
|
23
|
+
return schema.options.filter(isZodObject).filter((option) => option.safeParse(data).success);
|
|
24
|
+
}
|
|
25
|
+
export function assertKeyAllowedOnMatchingVariants(matchingVariants, key) {
|
|
26
|
+
if (matchingVariants.length === 0) {
|
|
27
|
+
throw SmartObjectError.invalidUnionState();
|
|
28
|
+
}
|
|
29
|
+
if (matchingVariants.length === 1) {
|
|
30
|
+
if (!(key in matchingVariants[0].shape)) {
|
|
31
|
+
throw SmartObjectError.invalidUnionField(key);
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (!matchingVariants.some((variant) => key in variant.shape)) {
|
|
36
|
+
throw SmartObjectError.invalidUnionField(key);
|
|
37
|
+
}
|
|
38
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -38,6 +38,12 @@ export type OperationsAccessor = {
|
|
|
38
38
|
/** Drops accumulated patches after persist/sync without rolling back state */
|
|
39
39
|
clearOperations(): void;
|
|
40
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Snapshot serialization — returns a deep clone safe for JSON.stringify.
|
|
43
|
+
*/
|
|
44
|
+
export type SnapshotAccessor<T extends SmartObjectSchema> = {
|
|
45
|
+
toJSON(): z.infer<T>;
|
|
46
|
+
};
|
|
41
47
|
/**
|
|
42
48
|
* Flattened data shape for union roots — exposes all variant keys on one surface.
|
|
43
49
|
*/
|
|
@@ -49,7 +55,7 @@ export type UnionDataShape<U> = {
|
|
|
49
55
|
*
|
|
50
56
|
* Intersection types merge these concerns into one consumable surface for callers.
|
|
51
57
|
*/
|
|
52
|
-
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
|
|
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>;
|
|
53
59
|
/**
|
|
54
60
|
* Constructor type for a SmartObject class, including replay as a first-class capability.
|
|
55
61
|
*
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B;;GAEG;AACH,MAAM,MAAM,iBAAiB,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,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,CAAC;
|
|
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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { SmartObjectSchema } from "./types.js";
|
|
3
|
+
export type ZodObjectLike = z.ZodObject;
|
|
4
|
+
export type ZodUnionRootLike = z.ZodUnion;
|
|
5
|
+
export type ZodDiscriminatedUnionLike = z.ZodDiscriminatedUnion;
|
|
6
|
+
export declare function isZodObject(schema: unknown): schema is ZodObjectLike;
|
|
7
|
+
export declare function isZodUnionRoot(schema: SmartObjectSchema): schema is ZodUnionRootLike;
|
|
8
|
+
export declare function isZodDiscriminatedUnion(schema: ZodUnionRootLike): schema is ZodDiscriminatedUnionLike;
|
|
9
|
+
export declare function isZodUnionOfObjects(schema: ZodUnionRootLike): boolean;
|
|
10
|
+
export declare function getObjectShapeKeys(schema: ZodObjectLike): string[];
|
|
11
|
+
export declare function getUnionObjectKeys(schema: ZodUnionRootLike): string[];
|
|
12
|
+
export declare function getDiscriminator(schema: ZodDiscriminatedUnionLike): string;
|
|
13
|
+
export declare function toSetterMethodName(key: string): string;
|
|
14
|
+
//# sourceMappingURL=zod-introspect.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function isZodObject(schema) {
|
|
2
|
+
return (typeof schema === "object" &&
|
|
3
|
+
schema !== null &&
|
|
4
|
+
"_zod" in schema &&
|
|
5
|
+
schema._zod.def.type === "object");
|
|
6
|
+
}
|
|
7
|
+
export function isZodUnionRoot(schema) {
|
|
8
|
+
return schema._zod.def.type === "union";
|
|
9
|
+
}
|
|
10
|
+
export function isZodDiscriminatedUnion(schema) {
|
|
11
|
+
return "discriminator" in schema._zod.def;
|
|
12
|
+
}
|
|
13
|
+
export function isZodUnionOfObjects(schema) {
|
|
14
|
+
return schema.options.length > 0 && schema.options.every(isZodObject);
|
|
15
|
+
}
|
|
16
|
+
export function getObjectShapeKeys(schema) {
|
|
17
|
+
return Object.keys(schema.shape);
|
|
18
|
+
}
|
|
19
|
+
export function getUnionObjectKeys(schema) {
|
|
20
|
+
const keys = new Set();
|
|
21
|
+
for (const option of schema.options) {
|
|
22
|
+
if (!isZodObject(option)) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
for (const key of Object.keys(option.shape)) {
|
|
26
|
+
keys.add(key);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return [...keys];
|
|
30
|
+
}
|
|
31
|
+
export function getDiscriminator(schema) {
|
|
32
|
+
return schema._zod.def.discriminator;
|
|
33
|
+
}
|
|
34
|
+
export function toSetterMethodName(key) {
|
|
35
|
+
return `set${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
36
|
+
}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"smart-object.d.ts","sourceRoot":"","sources":["../src/smart-object.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,sBAAsB,EAA0C,MAAM,YAAY,CAAC;AAsMjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
|
package/dist/smart-object.js
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import jsonPatch from "fast-json-patch";
|
|
2
|
-
const { applyPatch, compare, deepClone } = jsonPatch;
|
|
3
|
-
function isZodObject(schema) {
|
|
4
|
-
return (typeof schema === "object" &&
|
|
5
|
-
schema !== null &&
|
|
6
|
-
"_zod" in schema &&
|
|
7
|
-
schema._zod.def.type === "object");
|
|
8
|
-
}
|
|
9
|
-
function isZodUnionRoot(schema) {
|
|
10
|
-
return schema._zod.def.type === "union";
|
|
11
|
-
}
|
|
12
|
-
function isZodDiscriminatedUnion(schema) {
|
|
13
|
-
return "discriminator" in schema._zod.def;
|
|
14
|
-
}
|
|
15
|
-
function isZodUnionOfObjects(schema) {
|
|
16
|
-
return schema.options.length > 0 && schema.options.every(isZodObject);
|
|
17
|
-
}
|
|
18
|
-
function getObjectShapeKeys(schema) {
|
|
19
|
-
return Object.keys(schema.shape);
|
|
20
|
-
}
|
|
21
|
-
function getUnionObjectKeys(schema) {
|
|
22
|
-
const keys = new Set();
|
|
23
|
-
for (const option of schema.options) {
|
|
24
|
-
if (!isZodObject(option)) {
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
for (const key of Object.keys(option.shape)) {
|
|
28
|
-
keys.add(key);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return [...keys];
|
|
32
|
-
}
|
|
33
|
-
function buildSmartObjectClass(zodSchema) {
|
|
34
|
-
const keys = isZodObject(zodSchema)
|
|
35
|
-
? getObjectShapeKeys(zodSchema)
|
|
36
|
-
: getUnionObjectKeys(zodSchema);
|
|
37
|
-
class SmartObjectClass {
|
|
38
|
-
#data;
|
|
39
|
-
#operations = [];
|
|
40
|
-
static fromOperations(initial, operations) {
|
|
41
|
-
const instance = new SmartObjectClass(initial);
|
|
42
|
-
instance.#applyOperations(operations);
|
|
43
|
-
return instance;
|
|
44
|
-
}
|
|
45
|
-
#applyOperations(operations) {
|
|
46
|
-
if (operations.length === 0) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
applyPatch(this.#data, operations, false, true);
|
|
50
|
-
this.#operations.push(...operations);
|
|
51
|
-
}
|
|
52
|
-
get operations() {
|
|
53
|
-
return this.#operations;
|
|
54
|
-
}
|
|
55
|
-
clearOperations() {
|
|
56
|
-
this.#operations.length = 0;
|
|
57
|
-
}
|
|
58
|
-
constructor(initial) {
|
|
59
|
-
for (const key of keys) {
|
|
60
|
-
const setMethodName = `set${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
61
|
-
Object.defineProperty(this, key, {
|
|
62
|
-
get: () => this.#data[key],
|
|
63
|
-
enumerable: true,
|
|
64
|
-
configurable: true,
|
|
65
|
-
});
|
|
66
|
-
Object.defineProperty(this, setMethodName, {
|
|
67
|
-
value: isZodObject(zodSchema)
|
|
68
|
-
? this.#createObjectFieldSetter(zodSchema, key)
|
|
69
|
-
: this.#createUnionFieldSetter(zodSchema, key),
|
|
70
|
-
enumerable: false,
|
|
71
|
-
configurable: true,
|
|
72
|
-
writable: true,
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
this.#data = zodSchema.parse(initial ?? {});
|
|
76
|
-
}
|
|
77
|
-
#createObjectFieldSetter(schema, key) {
|
|
78
|
-
const fieldSchema = schema.shape[key];
|
|
79
|
-
return (value) => {
|
|
80
|
-
const parsed = fieldSchema.parse(value);
|
|
81
|
-
const beforeData = deepClone(this.#data);
|
|
82
|
-
const afterData = { ...deepClone(this.#data), [key]: parsed };
|
|
83
|
-
const patch = compare(beforeData, afterData);
|
|
84
|
-
if (patch.length === 0) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
applyPatch(this.#data, patch, false, true);
|
|
88
|
-
this.#operations.push(...patch);
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
#getActiveVariantViaDiscriminator(schema, data) {
|
|
92
|
-
const discriminator = schema._zod.def.discriminator;
|
|
93
|
-
const tag = data[discriminator];
|
|
94
|
-
for (const option of schema.options) {
|
|
95
|
-
if (!isZodObject(option)) {
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
const tagSchema = option.shape[discriminator];
|
|
99
|
-
if (tagSchema?.safeParse(tag).success) {
|
|
100
|
-
return option;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return undefined;
|
|
104
|
-
}
|
|
105
|
-
#getMatchingVariantObjects(schema) {
|
|
106
|
-
if (isZodDiscriminatedUnion(schema)) {
|
|
107
|
-
const activeVariant = this.#getActiveVariantViaDiscriminator(schema, this.#data);
|
|
108
|
-
return activeVariant ? [activeVariant] : [];
|
|
109
|
-
}
|
|
110
|
-
return schema.options
|
|
111
|
-
.filter(isZodObject)
|
|
112
|
-
.filter((option) => option.safeParse(this.#data).success);
|
|
113
|
-
}
|
|
114
|
-
#assertKeyAllowedOnMatchingVariants(matchingVariants, key) {
|
|
115
|
-
if (matchingVariants.length === 0) {
|
|
116
|
-
throw new Error("Cannot set field on invalid union state");
|
|
117
|
-
}
|
|
118
|
-
if (matchingVariants.length === 1) {
|
|
119
|
-
if (!(key in matchingVariants[0].shape)) {
|
|
120
|
-
throw new Error(`Cannot set "${key}" on the active union variant`);
|
|
121
|
-
}
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (!matchingVariants.some((variant) => key in variant.shape)) {
|
|
125
|
-
throw new Error(`Cannot set "${key}" on the active union variant`);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
#createUnionFieldSetter(schema, key) {
|
|
129
|
-
return (value) => {
|
|
130
|
-
const matchingVariants = this.#getMatchingVariantObjects(schema);
|
|
131
|
-
this.#assertKeyAllowedOnMatchingVariants(matchingVariants, key);
|
|
132
|
-
const beforeData = deepClone(this.#data);
|
|
133
|
-
const candidate = { ...deepClone(this.#data), [key]: value };
|
|
134
|
-
const parsed = schema.parse(candidate);
|
|
135
|
-
const patch = compare(beforeData, parsed);
|
|
136
|
-
if (patch.length === 0) {
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
this.#data = parsed;
|
|
140
|
-
this.#operations.push(...patch);
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return SmartObjectClass;
|
|
145
|
-
}
|
|
146
|
-
export function SmartObject(zodSchema) {
|
|
147
|
-
if (isZodObject(zodSchema)) {
|
|
148
|
-
return buildSmartObjectClass(zodSchema);
|
|
149
|
-
}
|
|
150
|
-
if (isZodUnionRoot(zodSchema)) {
|
|
151
|
-
if (!isZodUnionOfObjects(zodSchema)) {
|
|
152
|
-
throw new TypeError("SmartObject union root requires all options to be z.object(...)");
|
|
153
|
-
}
|
|
154
|
-
return buildSmartObjectClass(zodSchema);
|
|
155
|
-
}
|
|
156
|
-
throw new TypeError("SmartObject requires a z.object(...), z.union([...]), or z.discriminatedUnion(...) schema");
|
|
157
|
-
}
|