progressive-zod 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -1
- package/dist/cli/index.js +69 -49
- package/dist/client.cjs +72 -50
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +2 -0
- package/dist/client.d.ts +2 -0
- package/dist/client.js +72 -50
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +72 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +72 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -71,7 +71,7 @@ configure({
|
|
|
71
71
|
});
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
-
For production, you can
|
|
74
|
+
For production, you can use Redis or Amplitude:
|
|
75
75
|
|
|
76
76
|
```bash
|
|
77
77
|
npm install ioredis
|
|
@@ -84,6 +84,46 @@ configure({
|
|
|
84
84
|
});
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
### Amplitude adapter
|
|
88
|
+
|
|
89
|
+
The Amplitude adapter streams type-check results as analytics events instead of storing raw samples locally. This is useful when you want to track conformance rates in a dashboard without managing storage infrastructure.
|
|
90
|
+
|
|
91
|
+
**How it works:** each call to `.parse()` fires a single Amplitude event (default name: `progressive-zod: results`). Conform checks send `{ type_name, result: "conforms" }`. Violations include extra properties: `sample_type`, `field_count`, `sample_preview` (first 256 chars, flattened to a `key=value` string), and `validation_errors`.
|
|
92
|
+
|
|
93
|
+
Read methods (`list`, `infer`, `stats`, `violations`) are no-ops — use the Amplitude dashboard to query your data.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install @amplitude/analytics-node
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
import * as amplitude from "@amplitude/analytics-node";
|
|
101
|
+
import { configure } from "progressive-zod";
|
|
102
|
+
|
|
103
|
+
// Use a separate Amplitude project for observability, not your main product analytics
|
|
104
|
+
const pzodAmplitude = amplitude.createInstance();
|
|
105
|
+
pzodAmplitude.init("YOUR_OBSERVABILITY_PROJECT_API_KEY");
|
|
106
|
+
|
|
107
|
+
configure({
|
|
108
|
+
storage: "amplitude",
|
|
109
|
+
amplitudeClient: pzodAmplitude,
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Works in the browser too — import from `progressive-zod/client` and use `@amplitude/analytics-browser` instead.
|
|
114
|
+
|
|
115
|
+
You can customize the event name:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
configure({
|
|
119
|
+
storage: "amplitude",
|
|
120
|
+
amplitudeClient: pzodAmplitude,
|
|
121
|
+
amplitudeEventName: "my-app: type results",
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Events use whatever `user_id` and `device_id` you configured on your Amplitude client instance.
|
|
126
|
+
|
|
87
127
|
## Track conformance against existing schemas
|
|
88
128
|
|
|
89
129
|
Already have a partial schema? Pass it as the second argument to track how much real data conforms:
|
|
@@ -129,3 +169,5 @@ This package includes a `/instrument` skill for [Claude Code](https://docs.anthr
|
|
|
129
169
|
| `maxSamples` | `PROGRESSIVE_ZOD_MAX_SAMPLES` | `1000` | Max samples per type |
|
|
130
170
|
| `maxViolations` | `PROGRESSIVE_ZOD_MAX_VIOLATIONS` | `1000` | Max violations per type |
|
|
131
171
|
| `dataDir` | `PROGRESSIVE_ZOD_DATA_DIR` | `.progressive-zod` | File persistence path (memory mode) |
|
|
172
|
+
| `amplitudeClient` | — | — | Amplitude SDK instance (required for amplitude storage) |
|
|
173
|
+
| `amplitudeEventName` | — | `"progressive-zod: results"` | Custom event name (amplitude storage only) |
|
package/dist/cli/index.js
CHANGED
|
@@ -28,10 +28,10 @@ var init_amplitude = __esm({
|
|
|
28
28
|
"use strict";
|
|
29
29
|
AmplitudeStorage = class {
|
|
30
30
|
client;
|
|
31
|
-
|
|
31
|
+
eventName;
|
|
32
32
|
constructor(client, config) {
|
|
33
33
|
this.client = client;
|
|
34
|
-
this.
|
|
34
|
+
this.eventName = config.amplitudeEventName ?? "progressive-zod: results";
|
|
35
35
|
}
|
|
36
36
|
addName(_name) {
|
|
37
37
|
}
|
|
@@ -40,16 +40,12 @@ var init_amplitude = __esm({
|
|
|
40
40
|
addViolation(_name, _violation) {
|
|
41
41
|
}
|
|
42
42
|
incrConform(name, _sample) {
|
|
43
|
-
this.client.track(
|
|
44
|
-
"pzod:type_checked",
|
|
45
|
-
{ type_name: name, result: "conform" },
|
|
46
|
-
{ device_id: this.deviceId }
|
|
47
|
-
);
|
|
43
|
+
this.client.track(this.eventName, { type_name: name, result: "conforms" });
|
|
48
44
|
}
|
|
49
45
|
incrViolate(name, sample, errors) {
|
|
50
46
|
const properties = {
|
|
51
47
|
type_name: name,
|
|
52
|
-
result: "
|
|
48
|
+
result: "violation"
|
|
53
49
|
};
|
|
54
50
|
if (sample) {
|
|
55
51
|
try {
|
|
@@ -67,11 +63,7 @@ var init_amplitude = __esm({
|
|
|
67
63
|
if (errors) {
|
|
68
64
|
properties.validation_errors = errors.slice(0, 1024);
|
|
69
65
|
}
|
|
70
|
-
this.client.track(
|
|
71
|
-
"pzod:type_checked",
|
|
72
|
-
properties,
|
|
73
|
-
{ device_id: this.deviceId }
|
|
74
|
-
);
|
|
66
|
+
this.client.track(this.eventName, properties);
|
|
75
67
|
}
|
|
76
68
|
// --- Read methods: no-ops (use Amplitude dashboard) ---
|
|
77
69
|
async getNames() {
|
|
@@ -195,6 +187,9 @@ var init_redis = __esm({
|
|
|
195
187
|
// src/cli/index.ts
|
|
196
188
|
import { Command } from "commander";
|
|
197
189
|
|
|
190
|
+
// src/storage/resolve.ts
|
|
191
|
+
import { z } from "zod";
|
|
192
|
+
|
|
198
193
|
// src/storage/memory.ts
|
|
199
194
|
var MemoryStorage = class {
|
|
200
195
|
names = /* @__PURE__ */ new Set();
|
|
@@ -254,6 +249,31 @@ var MemoryStorage = class {
|
|
|
254
249
|
};
|
|
255
250
|
|
|
256
251
|
// src/storage/resolve.ts
|
|
252
|
+
var progressiveConfigSchema = z.object({
|
|
253
|
+
storage: z.enum(["memory", "redis", "amplitude"]).optional(),
|
|
254
|
+
redisUrl: z.string().optional(),
|
|
255
|
+
keyPrefix: z.string().optional(),
|
|
256
|
+
maxViolations: z.number().optional(),
|
|
257
|
+
maxSamples: z.number().optional(),
|
|
258
|
+
dataDir: z.string().optional(),
|
|
259
|
+
amplitudeClient: z.any().optional(),
|
|
260
|
+
amplitudeEventName: z.string().optional()
|
|
261
|
+
}).superRefine((data, ctx) => {
|
|
262
|
+
if (data.amplitudeEventName && data.storage !== "amplitude") {
|
|
263
|
+
ctx.addIssue({
|
|
264
|
+
code: z.ZodIssueCode.custom,
|
|
265
|
+
message: 'amplitudeEventName can only be used when storage is "amplitude"',
|
|
266
|
+
path: ["amplitudeEventName"]
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
if (data.amplitudeClient && data.storage !== "amplitude") {
|
|
270
|
+
ctx.addIssue({
|
|
271
|
+
code: z.ZodIssueCode.custom,
|
|
272
|
+
message: 'amplitudeClient can only be used when storage is "amplitude"',
|
|
273
|
+
path: ["amplitudeClient"]
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
});
|
|
257
277
|
var currentConfig = {};
|
|
258
278
|
var currentStorage = null;
|
|
259
279
|
var storageFactory = async (config) => new MemoryStorage(config);
|
|
@@ -445,7 +465,7 @@ async function violationsCommand(name, opts) {
|
|
|
445
465
|
}
|
|
446
466
|
|
|
447
467
|
// src/infer-schema.ts
|
|
448
|
-
import { z } from "zod";
|
|
468
|
+
import { z as z2 } from "zod";
|
|
449
469
|
function inferSchema(samples) {
|
|
450
470
|
const objects = samples.filter(
|
|
451
471
|
(s) => typeof s === "object" && s !== null && !Array.isArray(s)
|
|
@@ -459,14 +479,14 @@ function inferSchema(samples) {
|
|
|
459
479
|
}
|
|
460
480
|
const discriminator = findDiscriminator(groups);
|
|
461
481
|
if (discriminator) {
|
|
462
|
-
return
|
|
482
|
+
return z2.discriminatedUnion(
|
|
463
483
|
discriminator,
|
|
464
484
|
groups.map(
|
|
465
485
|
(group) => buildObjectSchema(group)
|
|
466
486
|
)
|
|
467
487
|
);
|
|
468
488
|
}
|
|
469
|
-
return
|
|
489
|
+
return z2.union(
|
|
470
490
|
groups.map((group) => buildObjectSchema(group))
|
|
471
491
|
);
|
|
472
492
|
}
|
|
@@ -525,21 +545,21 @@ function buildObjectSchema(samples) {
|
|
|
525
545
|
const values = samples.map((s) => s[key]);
|
|
526
546
|
const unique = new Set(values);
|
|
527
547
|
if (unique.size === 1 && typeof values[0] === "string") {
|
|
528
|
-
shape[key] =
|
|
548
|
+
shape[key] = z2.literal(values[0]);
|
|
529
549
|
} else {
|
|
530
550
|
shape[key] = inferFieldType(values);
|
|
531
551
|
}
|
|
532
552
|
}
|
|
533
|
-
return
|
|
553
|
+
return z2.object(shape).strict();
|
|
534
554
|
}
|
|
535
555
|
function inferFieldType(values) {
|
|
536
556
|
const types = new Set(values.map(classifyValue));
|
|
537
557
|
if (types.size === 1) {
|
|
538
558
|
const type = [...types][0];
|
|
539
|
-
if (type === "string") return
|
|
540
|
-
if (type === "number") return
|
|
541
|
-
if (type === "boolean") return
|
|
542
|
-
if (type === "null") return
|
|
559
|
+
if (type === "string") return z2.string();
|
|
560
|
+
if (type === "number") return z2.number();
|
|
561
|
+
if (type === "boolean") return z2.boolean();
|
|
562
|
+
if (type === "null") return z2.null();
|
|
543
563
|
if (type === "object") {
|
|
544
564
|
return inferSchema(values);
|
|
545
565
|
}
|
|
@@ -547,21 +567,21 @@ function inferFieldType(values) {
|
|
|
547
567
|
const allItems = values.flatMap(
|
|
548
568
|
(v) => Array.isArray(v) ? v : []
|
|
549
569
|
);
|
|
550
|
-
if (allItems.length === 0) return
|
|
551
|
-
return
|
|
570
|
+
if (allItems.length === 0) return z2.array(z2.unknown());
|
|
571
|
+
return z2.array(inferFieldType(allItems));
|
|
552
572
|
}
|
|
553
573
|
}
|
|
554
574
|
if (types.size === 1 && types.has("string")) {
|
|
555
575
|
const unique = new Set(values);
|
|
556
576
|
if (unique.size === 1) {
|
|
557
|
-
return
|
|
577
|
+
return z2.literal(values[0]);
|
|
558
578
|
}
|
|
559
579
|
}
|
|
560
580
|
const members = [];
|
|
561
|
-
if (types.has("string")) members.push(
|
|
562
|
-
if (types.has("number")) members.push(
|
|
563
|
-
if (types.has("boolean")) members.push(
|
|
564
|
-
if (types.has("null")) members.push(
|
|
581
|
+
if (types.has("string")) members.push(z2.string());
|
|
582
|
+
if (types.has("number")) members.push(z2.number());
|
|
583
|
+
if (types.has("boolean")) members.push(z2.boolean());
|
|
584
|
+
if (types.has("null")) members.push(z2.null());
|
|
565
585
|
if (types.has("object")) {
|
|
566
586
|
const objs = values.filter(
|
|
567
587
|
(v) => typeof v === "object" && v !== null && !Array.isArray(v)
|
|
@@ -572,12 +592,12 @@ function inferFieldType(values) {
|
|
|
572
592
|
const arrs = values.filter(Array.isArray);
|
|
573
593
|
const allItems = arrs.flat();
|
|
574
594
|
members.push(
|
|
575
|
-
|
|
595
|
+
z2.array(allItems.length > 0 ? inferFieldType(allItems) : z2.unknown())
|
|
576
596
|
);
|
|
577
597
|
}
|
|
578
598
|
if (members.length === 1) return members[0];
|
|
579
|
-
if (members.length === 2) return
|
|
580
|
-
return
|
|
599
|
+
if (members.length === 2) return z2.union([members[0], members[1]]);
|
|
600
|
+
return z2.union(members);
|
|
581
601
|
}
|
|
582
602
|
function classifyValue(v) {
|
|
583
603
|
if (v === null) return "null";
|
|
@@ -587,33 +607,33 @@ function classifyValue(v) {
|
|
|
587
607
|
function inferPrimitiveUnion(samples) {
|
|
588
608
|
const types = new Set(samples.map(classifyValue));
|
|
589
609
|
const members = [];
|
|
590
|
-
if (types.has("string")) members.push(
|
|
591
|
-
if (types.has("number")) members.push(
|
|
592
|
-
if (types.has("boolean")) members.push(
|
|
593
|
-
if (types.has("null")) members.push(
|
|
594
|
-
if (members.length === 0) return
|
|
610
|
+
if (types.has("string")) members.push(z2.string());
|
|
611
|
+
if (types.has("number")) members.push(z2.number());
|
|
612
|
+
if (types.has("boolean")) members.push(z2.boolean());
|
|
613
|
+
if (types.has("null")) members.push(z2.null());
|
|
614
|
+
if (members.length === 0) return z2.unknown();
|
|
595
615
|
if (members.length === 1) return members[0];
|
|
596
|
-
return
|
|
616
|
+
return z2.union(members);
|
|
597
617
|
}
|
|
598
618
|
|
|
599
619
|
// src/schema-to-code.ts
|
|
600
|
-
import { z as
|
|
620
|
+
import { z as z3 } from "zod";
|
|
601
621
|
function schemaToCode(schema, indent = 0) {
|
|
602
622
|
const pad = " ".repeat(indent);
|
|
603
|
-
if (schema instanceof
|
|
604
|
-
if (schema instanceof
|
|
605
|
-
if (schema instanceof
|
|
606
|
-
if (schema instanceof
|
|
607
|
-
if (schema instanceof
|
|
608
|
-
if (schema instanceof
|
|
623
|
+
if (schema instanceof z3.ZodString) return "z.string()";
|
|
624
|
+
if (schema instanceof z3.ZodNumber) return "z.number()";
|
|
625
|
+
if (schema instanceof z3.ZodBoolean) return "z.boolean()";
|
|
626
|
+
if (schema instanceof z3.ZodNull) return "z.null()";
|
|
627
|
+
if (schema instanceof z3.ZodUnknown) return "z.unknown()";
|
|
628
|
+
if (schema instanceof z3.ZodLiteral) {
|
|
609
629
|
const val = schema.value;
|
|
610
630
|
return typeof val === "string" ? `z.literal("${val}")` : `z.literal(${val})`;
|
|
611
631
|
}
|
|
612
|
-
if (schema instanceof
|
|
632
|
+
if (schema instanceof z3.ZodArray) {
|
|
613
633
|
const inner = schemaToCode(schema.element, indent);
|
|
614
634
|
return `z.array(${inner})`;
|
|
615
635
|
}
|
|
616
|
-
if (schema instanceof
|
|
636
|
+
if (schema instanceof z3.ZodObject) {
|
|
617
637
|
const shape = schema.shape;
|
|
618
638
|
const keys = Object.keys(shape);
|
|
619
639
|
if (keys.length === 0) return "z.object({})";
|
|
@@ -626,7 +646,7 @@ function schemaToCode(schema, indent = 0) {
|
|
|
626
646
|
${fields.join("\n")}
|
|
627
647
|
${pad}})${strict}`;
|
|
628
648
|
}
|
|
629
|
-
if (schema instanceof
|
|
649
|
+
if (schema instanceof z3.ZodUnion) {
|
|
630
650
|
const opts = schema.options;
|
|
631
651
|
const members = opts.map((o) => schemaToCode(o, indent));
|
|
632
652
|
if (members.every((m) => !m.includes("\n"))) {
|
|
@@ -637,7 +657,7 @@ ${pad}})${strict}`;
|
|
|
637
657
|
${members.map((m) => `${inner}${m},`).join("\n")}
|
|
638
658
|
${pad}])`;
|
|
639
659
|
}
|
|
640
|
-
if (schema instanceof
|
|
660
|
+
if (schema instanceof z3.ZodDiscriminatedUnion) {
|
|
641
661
|
const disc = schema._def.discriminator;
|
|
642
662
|
const opts = schema._def.options;
|
|
643
663
|
const members = opts.map((o) => schemaToCode(o, indent + 1));
|
package/dist/client.cjs
CHANGED
|
@@ -38,10 +38,10 @@ var init_amplitude = __esm({
|
|
|
38
38
|
"use strict";
|
|
39
39
|
AmplitudeStorage = class {
|
|
40
40
|
client;
|
|
41
|
-
|
|
41
|
+
eventName;
|
|
42
42
|
constructor(client, config) {
|
|
43
43
|
this.client = client;
|
|
44
|
-
this.
|
|
44
|
+
this.eventName = config.amplitudeEventName ?? "progressive-zod: results";
|
|
45
45
|
}
|
|
46
46
|
addName(_name) {
|
|
47
47
|
}
|
|
@@ -50,16 +50,12 @@ var init_amplitude = __esm({
|
|
|
50
50
|
addViolation(_name, _violation) {
|
|
51
51
|
}
|
|
52
52
|
incrConform(name, _sample) {
|
|
53
|
-
this.client.track(
|
|
54
|
-
"pzod:type_checked",
|
|
55
|
-
{ type_name: name, result: "conform" },
|
|
56
|
-
{ device_id: this.deviceId }
|
|
57
|
-
);
|
|
53
|
+
this.client.track(this.eventName, { type_name: name, result: "conforms" });
|
|
58
54
|
}
|
|
59
55
|
incrViolate(name, sample, errors) {
|
|
60
56
|
const properties = {
|
|
61
57
|
type_name: name,
|
|
62
|
-
result: "
|
|
58
|
+
result: "violation"
|
|
63
59
|
};
|
|
64
60
|
if (sample) {
|
|
65
61
|
try {
|
|
@@ -77,11 +73,7 @@ var init_amplitude = __esm({
|
|
|
77
73
|
if (errors) {
|
|
78
74
|
properties.validation_errors = errors.slice(0, 1024);
|
|
79
75
|
}
|
|
80
|
-
this.client.track(
|
|
81
|
-
"pzod:type_checked",
|
|
82
|
-
properties,
|
|
83
|
-
{ device_id: this.deviceId }
|
|
84
|
-
);
|
|
76
|
+
this.client.track(this.eventName, properties);
|
|
85
77
|
}
|
|
86
78
|
// --- Read methods: no-ops (use Amplitude dashboard) ---
|
|
87
79
|
async getNames() {
|
|
@@ -115,6 +107,9 @@ __export(client_exports, {
|
|
|
115
107
|
});
|
|
116
108
|
module.exports = __toCommonJS(client_exports);
|
|
117
109
|
|
|
110
|
+
// src/storage/resolve.ts
|
|
111
|
+
var import_zod = require("zod");
|
|
112
|
+
|
|
118
113
|
// src/storage/memory.ts
|
|
119
114
|
var MemoryStorage = class {
|
|
120
115
|
names = /* @__PURE__ */ new Set();
|
|
@@ -174,6 +169,31 @@ var MemoryStorage = class {
|
|
|
174
169
|
};
|
|
175
170
|
|
|
176
171
|
// src/storage/resolve.ts
|
|
172
|
+
var progressiveConfigSchema = import_zod.z.object({
|
|
173
|
+
storage: import_zod.z.enum(["memory", "redis", "amplitude"]).optional(),
|
|
174
|
+
redisUrl: import_zod.z.string().optional(),
|
|
175
|
+
keyPrefix: import_zod.z.string().optional(),
|
|
176
|
+
maxViolations: import_zod.z.number().optional(),
|
|
177
|
+
maxSamples: import_zod.z.number().optional(),
|
|
178
|
+
dataDir: import_zod.z.string().optional(),
|
|
179
|
+
amplitudeClient: import_zod.z.any().optional(),
|
|
180
|
+
amplitudeEventName: import_zod.z.string().optional()
|
|
181
|
+
}).superRefine((data, ctx) => {
|
|
182
|
+
if (data.amplitudeEventName && data.storage !== "amplitude") {
|
|
183
|
+
ctx.addIssue({
|
|
184
|
+
code: import_zod.z.ZodIssueCode.custom,
|
|
185
|
+
message: 'amplitudeEventName can only be used when storage is "amplitude"',
|
|
186
|
+
path: ["amplitudeEventName"]
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (data.amplitudeClient && data.storage !== "amplitude") {
|
|
190
|
+
ctx.addIssue({
|
|
191
|
+
code: import_zod.z.ZodIssueCode.custom,
|
|
192
|
+
message: 'amplitudeClient can only be used when storage is "amplitude"',
|
|
193
|
+
path: ["amplitudeClient"]
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
});
|
|
177
197
|
var currentConfig = {};
|
|
178
198
|
var currentStorage = null;
|
|
179
199
|
var storageFactory = async (config) => new MemoryStorage(config);
|
|
@@ -181,7 +201,9 @@ function _setStorageFactory(factory) {
|
|
|
181
201
|
storageFactory = factory;
|
|
182
202
|
}
|
|
183
203
|
function configure(config) {
|
|
184
|
-
|
|
204
|
+
const merged = { ...currentConfig, ...config };
|
|
205
|
+
progressiveConfigSchema.parse(merged);
|
|
206
|
+
currentConfig = merged;
|
|
185
207
|
if (currentStorage) {
|
|
186
208
|
currentStorage.disconnect();
|
|
187
209
|
currentStorage = null;
|
|
@@ -392,7 +414,7 @@ _setStorageFactory(async (config, userConfig) => {
|
|
|
392
414
|
});
|
|
393
415
|
|
|
394
416
|
// src/infer-schema.ts
|
|
395
|
-
var
|
|
417
|
+
var import_zod2 = require("zod");
|
|
396
418
|
function inferSchema(samples) {
|
|
397
419
|
const objects = samples.filter(
|
|
398
420
|
(s) => typeof s === "object" && s !== null && !Array.isArray(s)
|
|
@@ -406,14 +428,14 @@ function inferSchema(samples) {
|
|
|
406
428
|
}
|
|
407
429
|
const discriminator = findDiscriminator(groups);
|
|
408
430
|
if (discriminator) {
|
|
409
|
-
return
|
|
431
|
+
return import_zod2.z.discriminatedUnion(
|
|
410
432
|
discriminator,
|
|
411
433
|
groups.map(
|
|
412
434
|
(group) => buildObjectSchema(group)
|
|
413
435
|
)
|
|
414
436
|
);
|
|
415
437
|
}
|
|
416
|
-
return
|
|
438
|
+
return import_zod2.z.union(
|
|
417
439
|
groups.map((group) => buildObjectSchema(group))
|
|
418
440
|
);
|
|
419
441
|
}
|
|
@@ -472,21 +494,21 @@ function buildObjectSchema(samples) {
|
|
|
472
494
|
const values = samples.map((s) => s[key]);
|
|
473
495
|
const unique = new Set(values);
|
|
474
496
|
if (unique.size === 1 && typeof values[0] === "string") {
|
|
475
|
-
shape[key] =
|
|
497
|
+
shape[key] = import_zod2.z.literal(values[0]);
|
|
476
498
|
} else {
|
|
477
499
|
shape[key] = inferFieldType(values);
|
|
478
500
|
}
|
|
479
501
|
}
|
|
480
|
-
return
|
|
502
|
+
return import_zod2.z.object(shape).strict();
|
|
481
503
|
}
|
|
482
504
|
function inferFieldType(values) {
|
|
483
505
|
const types = new Set(values.map(classifyValue));
|
|
484
506
|
if (types.size === 1) {
|
|
485
507
|
const type = [...types][0];
|
|
486
|
-
if (type === "string") return
|
|
487
|
-
if (type === "number") return
|
|
488
|
-
if (type === "boolean") return
|
|
489
|
-
if (type === "null") return
|
|
508
|
+
if (type === "string") return import_zod2.z.string();
|
|
509
|
+
if (type === "number") return import_zod2.z.number();
|
|
510
|
+
if (type === "boolean") return import_zod2.z.boolean();
|
|
511
|
+
if (type === "null") return import_zod2.z.null();
|
|
490
512
|
if (type === "object") {
|
|
491
513
|
return inferSchema(values);
|
|
492
514
|
}
|
|
@@ -494,21 +516,21 @@ function inferFieldType(values) {
|
|
|
494
516
|
const allItems = values.flatMap(
|
|
495
517
|
(v) => Array.isArray(v) ? v : []
|
|
496
518
|
);
|
|
497
|
-
if (allItems.length === 0) return
|
|
498
|
-
return
|
|
519
|
+
if (allItems.length === 0) return import_zod2.z.array(import_zod2.z.unknown());
|
|
520
|
+
return import_zod2.z.array(inferFieldType(allItems));
|
|
499
521
|
}
|
|
500
522
|
}
|
|
501
523
|
if (types.size === 1 && types.has("string")) {
|
|
502
524
|
const unique = new Set(values);
|
|
503
525
|
if (unique.size === 1) {
|
|
504
|
-
return
|
|
526
|
+
return import_zod2.z.literal(values[0]);
|
|
505
527
|
}
|
|
506
528
|
}
|
|
507
529
|
const members = [];
|
|
508
|
-
if (types.has("string")) members.push(
|
|
509
|
-
if (types.has("number")) members.push(
|
|
510
|
-
if (types.has("boolean")) members.push(
|
|
511
|
-
if (types.has("null")) members.push(
|
|
530
|
+
if (types.has("string")) members.push(import_zod2.z.string());
|
|
531
|
+
if (types.has("number")) members.push(import_zod2.z.number());
|
|
532
|
+
if (types.has("boolean")) members.push(import_zod2.z.boolean());
|
|
533
|
+
if (types.has("null")) members.push(import_zod2.z.null());
|
|
512
534
|
if (types.has("object")) {
|
|
513
535
|
const objs = values.filter(
|
|
514
536
|
(v) => typeof v === "object" && v !== null && !Array.isArray(v)
|
|
@@ -519,12 +541,12 @@ function inferFieldType(values) {
|
|
|
519
541
|
const arrs = values.filter(Array.isArray);
|
|
520
542
|
const allItems = arrs.flat();
|
|
521
543
|
members.push(
|
|
522
|
-
|
|
544
|
+
import_zod2.z.array(allItems.length > 0 ? inferFieldType(allItems) : import_zod2.z.unknown())
|
|
523
545
|
);
|
|
524
546
|
}
|
|
525
547
|
if (members.length === 1) return members[0];
|
|
526
|
-
if (members.length === 2) return
|
|
527
|
-
return
|
|
548
|
+
if (members.length === 2) return import_zod2.z.union([members[0], members[1]]);
|
|
549
|
+
return import_zod2.z.union(members);
|
|
528
550
|
}
|
|
529
551
|
function classifyValue(v) {
|
|
530
552
|
if (v === null) return "null";
|
|
@@ -534,33 +556,33 @@ function classifyValue(v) {
|
|
|
534
556
|
function inferPrimitiveUnion(samples) {
|
|
535
557
|
const types = new Set(samples.map(classifyValue));
|
|
536
558
|
const members = [];
|
|
537
|
-
if (types.has("string")) members.push(
|
|
538
|
-
if (types.has("number")) members.push(
|
|
539
|
-
if (types.has("boolean")) members.push(
|
|
540
|
-
if (types.has("null")) members.push(
|
|
541
|
-
if (members.length === 0) return
|
|
559
|
+
if (types.has("string")) members.push(import_zod2.z.string());
|
|
560
|
+
if (types.has("number")) members.push(import_zod2.z.number());
|
|
561
|
+
if (types.has("boolean")) members.push(import_zod2.z.boolean());
|
|
562
|
+
if (types.has("null")) members.push(import_zod2.z.null());
|
|
563
|
+
if (members.length === 0) return import_zod2.z.unknown();
|
|
542
564
|
if (members.length === 1) return members[0];
|
|
543
|
-
return
|
|
565
|
+
return import_zod2.z.union(members);
|
|
544
566
|
}
|
|
545
567
|
|
|
546
568
|
// src/schema-to-code.ts
|
|
547
|
-
var
|
|
569
|
+
var import_zod3 = require("zod");
|
|
548
570
|
function schemaToCode(schema, indent = 0) {
|
|
549
571
|
const pad = " ".repeat(indent);
|
|
550
|
-
if (schema instanceof
|
|
551
|
-
if (schema instanceof
|
|
552
|
-
if (schema instanceof
|
|
553
|
-
if (schema instanceof
|
|
554
|
-
if (schema instanceof
|
|
555
|
-
if (schema instanceof
|
|
572
|
+
if (schema instanceof import_zod3.z.ZodString) return "z.string()";
|
|
573
|
+
if (schema instanceof import_zod3.z.ZodNumber) return "z.number()";
|
|
574
|
+
if (schema instanceof import_zod3.z.ZodBoolean) return "z.boolean()";
|
|
575
|
+
if (schema instanceof import_zod3.z.ZodNull) return "z.null()";
|
|
576
|
+
if (schema instanceof import_zod3.z.ZodUnknown) return "z.unknown()";
|
|
577
|
+
if (schema instanceof import_zod3.z.ZodLiteral) {
|
|
556
578
|
const val = schema.value;
|
|
557
579
|
return typeof val === "string" ? `z.literal("${val}")` : `z.literal(${val})`;
|
|
558
580
|
}
|
|
559
|
-
if (schema instanceof
|
|
581
|
+
if (schema instanceof import_zod3.z.ZodArray) {
|
|
560
582
|
const inner = schemaToCode(schema.element, indent);
|
|
561
583
|
return `z.array(${inner})`;
|
|
562
584
|
}
|
|
563
|
-
if (schema instanceof
|
|
585
|
+
if (schema instanceof import_zod3.z.ZodObject) {
|
|
564
586
|
const shape = schema.shape;
|
|
565
587
|
const keys = Object.keys(shape);
|
|
566
588
|
if (keys.length === 0) return "z.object({})";
|
|
@@ -573,7 +595,7 @@ function schemaToCode(schema, indent = 0) {
|
|
|
573
595
|
${fields.join("\n")}
|
|
574
596
|
${pad}})${strict}`;
|
|
575
597
|
}
|
|
576
|
-
if (schema instanceof
|
|
598
|
+
if (schema instanceof import_zod3.z.ZodUnion) {
|
|
577
599
|
const opts = schema.options;
|
|
578
600
|
const members = opts.map((o) => schemaToCode(o, indent));
|
|
579
601
|
if (members.every((m) => !m.includes("\n"))) {
|
|
@@ -584,7 +606,7 @@ ${pad}})${strict}`;
|
|
|
584
606
|
${members.map((m) => `${inner}${m},`).join("\n")}
|
|
585
607
|
${pad}])`;
|
|
586
608
|
}
|
|
587
|
-
if (schema instanceof
|
|
609
|
+
if (schema instanceof import_zod3.z.ZodDiscriminatedUnion) {
|
|
588
610
|
const disc = schema._def.discriminator;
|
|
589
611
|
const opts = schema._def.options;
|
|
590
612
|
const members = opts.map((o) => schemaToCode(o, indent + 1));
|