@gabrielbryk/json-schema-to-zod 2.10.0 → 2.11.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.
Files changed (138) hide show
  1. package/AGENTS.md +44 -0
  2. package/CHANGELOG.md +35 -0
  3. package/README.md +6 -33
  4. package/check-types-lift.sh +23 -0
  5. package/check-types.sh +20 -0
  6. package/dist/{esm/cli.js → cli.js} +0 -6
  7. package/dist/{esm/core → core}/analyzeSchema.js +4 -5
  8. package/dist/core/emitZod.js +263 -0
  9. package/dist/{esm/generators → generators}/generateBundle.js +225 -67
  10. package/dist/{esm/index.js → index.js} +6 -0
  11. package/dist/jsonSchemaToZod.js +17 -0
  12. package/dist/parsers/parseAllOf.js +125 -0
  13. package/dist/parsers/parseAnyOf.js +28 -0
  14. package/dist/{esm/parsers → parsers}/parseArray.js +27 -11
  15. package/dist/parsers/parseBoolean.js +4 -0
  16. package/dist/parsers/parseConst.js +22 -0
  17. package/dist/parsers/parseEnum.js +35 -0
  18. package/dist/{esm/parsers → parsers}/parseIfThenElse.js +11 -7
  19. package/dist/parsers/parseMultipleType.js +10 -0
  20. package/dist/parsers/parseNot.js +14 -0
  21. package/dist/parsers/parseNull.js +4 -0
  22. package/dist/parsers/parseNullable.js +12 -0
  23. package/dist/{esm/parsers → parsers}/parseNumber.js +4 -1
  24. package/dist/{esm/parsers → parsers}/parseObject.js +168 -29
  25. package/dist/parsers/parseOneOf.js +365 -0
  26. package/dist/{esm/parsers → parsers}/parseSchema.js +56 -110
  27. package/dist/parsers/parseSimpleDiscriminatedOneOf.js +24 -0
  28. package/dist/{esm/parsers → parsers}/parseString.js +29 -18
  29. package/dist/types/Types.d.ts +32 -4
  30. package/dist/types/core/analyzeSchema.d.ts +3 -2
  31. package/dist/types/generators/generateBundle.d.ts +0 -2
  32. package/dist/types/index.d.ts +6 -0
  33. package/dist/types/parsers/parseAllOf.d.ts +2 -2
  34. package/dist/types/parsers/parseAnyOf.d.ts +2 -2
  35. package/dist/types/parsers/parseArray.d.ts +2 -2
  36. package/dist/types/parsers/parseBoolean.d.ts +2 -1
  37. package/dist/types/parsers/parseConst.d.ts +2 -2
  38. package/dist/types/parsers/parseDefault.d.ts +2 -2
  39. package/dist/types/parsers/parseEnum.d.ts +2 -2
  40. package/dist/types/parsers/parseIfThenElse.d.ts +2 -2
  41. package/dist/types/parsers/parseMultipleType.d.ts +2 -2
  42. package/dist/types/parsers/parseNot.d.ts +2 -2
  43. package/dist/types/parsers/parseNull.d.ts +2 -1
  44. package/dist/types/parsers/parseNullable.d.ts +2 -2
  45. package/dist/types/parsers/parseNumber.d.ts +2 -2
  46. package/dist/types/parsers/parseObject.d.ts +2 -2
  47. package/dist/types/parsers/parseOneOf.d.ts +2 -2
  48. package/dist/types/parsers/parseSchema.d.ts +2 -2
  49. package/dist/types/parsers/parseSimpleDiscriminatedOneOf.d.ts +2 -2
  50. package/dist/types/parsers/parseString.d.ts +2 -2
  51. package/dist/types/utils/anyOrUnknown.d.ts +5 -4
  52. package/dist/types/utils/esmEmitter.d.ts +29 -0
  53. package/dist/types/utils/extractInlineObject.d.ts +15 -0
  54. package/dist/types/utils/liftInlineObjects.d.ts +21 -0
  55. package/dist/types/utils/namingService.d.ts +21 -0
  56. package/dist/types/utils/resolveRef.d.ts +7 -0
  57. package/dist/types/utils/schemaRepresentation.d.ts +71 -0
  58. package/dist/utils/anyOrUnknown.js +13 -0
  59. package/dist/{esm/utils → utils}/buildRefRegistry.js +4 -0
  60. package/dist/utils/esmEmitter.js +87 -0
  61. package/dist/utils/extractInlineObject.js +119 -0
  62. package/dist/utils/liftInlineObjects.js +476 -0
  63. package/dist/utils/namingService.js +58 -0
  64. package/dist/utils/resolveRef.js +92 -0
  65. package/dist/utils/schemaRepresentation.js +569 -0
  66. package/docs/IMPROVEMENT-PLAN.md +243 -0
  67. package/docs/ZOD-V4-RECURSIVE-TYPE-LIMITATIONS.md +292 -0
  68. package/docs/proposals/bundle-refactor.md +1 -1
  69. package/docs/proposals/discriminated-union-with-default.md +248 -0
  70. package/docs/proposals/inline-object-lifting.md +77 -0
  71. package/eslint.config.js +4 -2
  72. package/jest.config.mjs +19 -0
  73. package/package.json +17 -20
  74. package/scripts/generateWorkflowSchema.ts +0 -1
  75. package/dist/cjs/Types.js +0 -2
  76. package/dist/cjs/cli.js +0 -70
  77. package/dist/cjs/core/analyzeSchema.js +0 -62
  78. package/dist/cjs/core/emitZod.js +0 -141
  79. package/dist/cjs/generators/generateBundle.js +0 -365
  80. package/dist/cjs/index.js +0 -50
  81. package/dist/cjs/jsonSchemaToZod.js +0 -10
  82. package/dist/cjs/package.json +0 -1
  83. package/dist/cjs/parsers/parseAllOf.js +0 -46
  84. package/dist/cjs/parsers/parseAnyOf.js +0 -18
  85. package/dist/cjs/parsers/parseArray.js +0 -90
  86. package/dist/cjs/parsers/parseBoolean.js +0 -5
  87. package/dist/cjs/parsers/parseConst.js +0 -7
  88. package/dist/cjs/parsers/parseDefault.js +0 -8
  89. package/dist/cjs/parsers/parseEnum.js +0 -21
  90. package/dist/cjs/parsers/parseIfThenElse.js +0 -35
  91. package/dist/cjs/parsers/parseMultipleType.js +0 -10
  92. package/dist/cjs/parsers/parseNot.js +0 -12
  93. package/dist/cjs/parsers/parseNull.js +0 -5
  94. package/dist/cjs/parsers/parseNullable.js +0 -12
  95. package/dist/cjs/parsers/parseNumber.js +0 -116
  96. package/dist/cjs/parsers/parseObject.js +0 -315
  97. package/dist/cjs/parsers/parseOneOf.js +0 -53
  98. package/dist/cjs/parsers/parseSchema.js +0 -411
  99. package/dist/cjs/parsers/parseSimpleDiscriminatedOneOf.js +0 -21
  100. package/dist/cjs/parsers/parseString.js +0 -317
  101. package/dist/cjs/utils/anyOrUnknown.js +0 -14
  102. package/dist/cjs/utils/buildRefRegistry.js +0 -56
  103. package/dist/cjs/utils/cliTools.js +0 -108
  104. package/dist/cjs/utils/cycles.js +0 -113
  105. package/dist/cjs/utils/half.js +0 -7
  106. package/dist/cjs/utils/jsdocs.js +0 -20
  107. package/dist/cjs/utils/omit.js +0 -11
  108. package/dist/cjs/utils/resolveUri.js +0 -16
  109. package/dist/cjs/utils/withMessage.js +0 -21
  110. package/dist/cjs/zodToJsonSchema.js +0 -89
  111. package/dist/esm/core/emitZod.js +0 -137
  112. package/dist/esm/jsonSchemaToZod.js +0 -6
  113. package/dist/esm/package.json +0 -1
  114. package/dist/esm/parsers/parseAllOf.js +0 -43
  115. package/dist/esm/parsers/parseAnyOf.js +0 -14
  116. package/dist/esm/parsers/parseBoolean.js +0 -1
  117. package/dist/esm/parsers/parseConst.js +0 -3
  118. package/dist/esm/parsers/parseEnum.js +0 -17
  119. package/dist/esm/parsers/parseMultipleType.js +0 -6
  120. package/dist/esm/parsers/parseNot.js +0 -8
  121. package/dist/esm/parsers/parseNull.js +0 -1
  122. package/dist/esm/parsers/parseNullable.js +0 -8
  123. package/dist/esm/parsers/parseOneOf.js +0 -49
  124. package/dist/esm/parsers/parseSimpleDiscriminatedOneOf.js +0 -17
  125. package/dist/esm/utils/anyOrUnknown.js +0 -10
  126. package/jest.config.cjs +0 -4
  127. package/postcjs.cjs +0 -1
  128. package/postesm.cjs +0 -1
  129. /package/dist/{esm/Types.js → Types.js} +0 -0
  130. /package/dist/{esm/parsers → parsers}/parseDefault.js +0 -0
  131. /package/dist/{esm/utils → utils}/cliTools.js +0 -0
  132. /package/dist/{esm/utils → utils}/cycles.js +0 -0
  133. /package/dist/{esm/utils → utils}/half.js +0 -0
  134. /package/dist/{esm/utils → utils}/jsdocs.js +0 -0
  135. /package/dist/{esm/utils → utils}/omit.js +0 -0
  136. /package/dist/{esm/utils → utils}/resolveUri.js +0 -0
  137. /package/dist/{esm/utils → utils}/withMessage.js +0 -0
  138. /package/dist/{esm/zodToJsonSchema.js → zodToJsonSchema.js} +0 -0
@@ -1,90 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseArray = void 0;
4
- const withMessage_js_1 = require("../utils/withMessage.js");
5
- const parseSchema_js_1 = require("./parseSchema.js");
6
- const anyOrUnknown_js_1 = require("../utils/anyOrUnknown.js");
7
- const parseArray = (schema, refs) => {
8
- if (Array.isArray(schema.items)) {
9
- let tuple = `z.tuple([${schema.items.map((v, i) => (0, parseSchema_js_1.parseSchema)(v, { ...refs, path: [...refs.path, "items", i] }))}])`;
10
- if (schema.contains) {
11
- const containsSchema = (0, parseSchema_js_1.parseSchema)(schema.contains, {
12
- ...refs,
13
- path: [...refs.path, "contains"],
14
- });
15
- const minContains = schema.minContains ?? (schema.contains ? 1 : undefined);
16
- const maxContains = schema.maxContains;
17
- tuple += `.superRefine((arr, ctx) => {
18
- const matches = arr.filter((item) => ${containsSchema}.safeParse(item).success).length;
19
- if (${minContains ?? 0} && matches < ${minContains ?? 0}) {
20
- ctx.addIssue({ code: "custom", message: "Array contains too few matching items" });
21
- }
22
- if (${maxContains ?? "undefined"} !== undefined && matches > ${maxContains ?? "undefined"}) {
23
- ctx.addIssue({ code: "custom", message: "Array contains too many matching items" });
24
- }
25
- })`;
26
- }
27
- return tuple;
28
- }
29
- let r = !schema.items
30
- ? `z.array(${(0, anyOrUnknown_js_1.anyOrUnknown)(refs)})`
31
- : `z.array(${(0, parseSchema_js_1.parseSchema)(schema.items, {
32
- ...refs,
33
- path: [...refs.path, "items"],
34
- })})`;
35
- r += (0, withMessage_js_1.withMessage)(schema, "minItems", ({ json }) => ({
36
- opener: `.min(${json}`,
37
- closer: ")",
38
- messagePrefix: ", { error: ",
39
- messageCloser: " })",
40
- }));
41
- r += (0, withMessage_js_1.withMessage)(schema, "maxItems", ({ json }) => ({
42
- opener: `.max(${json}`,
43
- closer: ")",
44
- messagePrefix: ", { error: ",
45
- messageCloser: " })",
46
- }));
47
- if (schema.uniqueItems === true) {
48
- r += `.superRefine((arr, ctx) => {
49
- const seen = new Set();
50
- for (const [index, value] of arr.entries()) {
51
- let key;
52
- if (value && typeof value === "object") {
53
- try {
54
- key = JSON.stringify(value);
55
- } catch {
56
- key = String(value);
57
- }
58
- } else {
59
- key = JSON.stringify(value);
60
- }
61
-
62
- if (seen.has(key)) {
63
- ctx.addIssue({ code: "custom", message: "Array items must be unique", path: [index] });
64
- return;
65
- }
66
-
67
- seen.add(key);
68
- }
69
- })`;
70
- }
71
- if (schema.contains) {
72
- const containsSchema = (0, parseSchema_js_1.parseSchema)(schema.contains, {
73
- ...refs,
74
- path: [...refs.path, "contains"],
75
- });
76
- const minContains = schema.minContains ?? (schema.contains ? 1 : undefined);
77
- const maxContains = schema.maxContains;
78
- r += `.superRefine((arr, ctx) => {
79
- const matches = arr.filter((item) => ${containsSchema}.safeParse(item).success).length;
80
- if (${minContains ?? 0} && matches < ${minContains ?? 0}) {
81
- ctx.addIssue({ code: "custom", message: "Array contains too few matching items" });
82
- }
83
- if (${maxContains ?? "undefined"} !== undefined && matches > ${maxContains ?? "undefined"}) {
84
- ctx.addIssue({ code: "custom", message: "Array contains too many matching items" });
85
- }
86
- })`;
87
- }
88
- return r;
89
- };
90
- exports.parseArray = parseArray;
@@ -1,5 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseBoolean = void 0;
4
- const parseBoolean = () => "z.boolean()";
5
- exports.parseBoolean = parseBoolean;
@@ -1,7 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseConst = void 0;
4
- const parseConst = (schema) => {
5
- return `z.literal(${JSON.stringify(schema.const)})`;
6
- };
7
- exports.parseConst = parseConst;
@@ -1,8 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseDefault = void 0;
4
- const anyOrUnknown_js_1 = require("../utils/anyOrUnknown.js");
5
- const parseDefault = (_schema, refs) => {
6
- return (0, anyOrUnknown_js_1.anyOrUnknown)(refs);
7
- };
8
- exports.parseDefault = parseDefault;
@@ -1,21 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseEnum = void 0;
4
- const parseEnum = (schema) => {
5
- if (schema.enum.length === 0) {
6
- return "z.never()";
7
- }
8
- else if (schema.enum.length === 1) {
9
- // union does not work when there is only one element
10
- return `z.literal(${JSON.stringify(schema.enum[0])})`;
11
- }
12
- else if (schema.enum.every((x) => typeof x === "string")) {
13
- return `z.enum([${schema.enum.map((x) => JSON.stringify(x))}])`;
14
- }
15
- else {
16
- return `z.union([${schema.enum
17
- .map((x) => `z.literal(${JSON.stringify(x)})`)
18
- .join(", ")}])`;
19
- }
20
- };
21
- exports.parseEnum = parseEnum;
@@ -1,35 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseIfThenElse = void 0;
4
- const parseSchema_js_1 = require("./parseSchema.js");
5
- const parseIfThenElse = (schema, refs) => {
6
- const $if = (0, parseSchema_js_1.parseSchema)(schema.if, { ...refs, path: [...refs.path, "if"] });
7
- const $then = (0, parseSchema_js_1.parseSchema)(schema.then, {
8
- ...refs,
9
- path: [...refs.path, "then"],
10
- });
11
- const $else = (0, parseSchema_js_1.parseSchema)(schema.else, {
12
- ...refs,
13
- path: [...refs.path, "else"],
14
- });
15
- let result = `z.union([${$then}, ${$else}]).superRefine((value,ctx) => {
16
- const result = ${$if}.safeParse(value).success
17
- ? ${$then}.safeParse(value)
18
- : ${$else}.safeParse(value);
19
- if (!result.success) {
20
- const issues = result.error.issues;
21
- issues.forEach((issue) => ctx.addIssue(issue))
22
- }
23
- })`;
24
- // Store original if/then/else for JSON Schema round-trip
25
- if (refs.preserveJsonSchemaForRoundTrip) {
26
- const conditionalMeta = JSON.stringify({
27
- if: schema.if,
28
- then: schema.then,
29
- else: schema.else,
30
- });
31
- result += `.meta({ __jsonSchema: { conditional: ${conditionalMeta} } })`;
32
- }
33
- return result;
34
- };
35
- exports.parseIfThenElse = parseIfThenElse;
@@ -1,10 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseMultipleType = void 0;
4
- const parseSchema_js_1 = require("./parseSchema.js");
5
- const parseMultipleType = (schema, refs) => {
6
- return `z.union([${schema.type
7
- .map((type) => (0, parseSchema_js_1.parseSchema)({ ...schema, type }, { ...refs, withoutDefaults: true }))
8
- .join(", ")}])`;
9
- };
10
- exports.parseMultipleType = parseMultipleType;
@@ -1,12 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseNot = void 0;
4
- const parseSchema_js_1 = require("./parseSchema.js");
5
- const anyOrUnknown_js_1 = require("../utils/anyOrUnknown.js");
6
- const parseNot = (schema, refs) => {
7
- return `${(0, anyOrUnknown_js_1.anyOrUnknown)(refs)}.refine((value) => !${(0, parseSchema_js_1.parseSchema)(schema.not, {
8
- ...refs,
9
- path: [...refs.path, "not"],
10
- })}.safeParse(value).success, "Invalid input: Should NOT be valid against schema")`;
11
- };
12
- exports.parseNot = parseNot;
@@ -1,5 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseNull = void 0;
4
- const parseNull = () => "z.null()";
5
- exports.parseNull = parseNull;
@@ -1,12 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseNullable = void 0;
4
- const omit_js_1 = require("../utils/omit.js");
5
- const parseSchema_js_1 = require("./parseSchema.js");
6
- /**
7
- * For compatibility with open api 3.0 nullable
8
- */
9
- const parseNullable = (schema, refs) => {
10
- return `${(0, parseSchema_js_1.parseSchema)((0, omit_js_1.omit)(schema, "nullable"), refs, true)}.nullable()`;
11
- };
12
- exports.parseNullable = parseNullable;
@@ -1,116 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseNumber = void 0;
4
- const withMessage_js_1 = require("../utils/withMessage.js");
5
- const parseNumber = (schema) => {
6
- const formatError = schema.errorMessage?.format;
7
- const numericFormatMap = {
8
- int32: "z.int32",
9
- uint32: "z.uint32",
10
- float32: "z.float32",
11
- float64: "z.float64",
12
- safeint: "z.safeint",
13
- int64: "z.int64",
14
- uint64: "z.uint64",
15
- };
16
- const mappedFormat = schema.format && numericFormatMap[schema.format] ? numericFormatMap[schema.format] : undefined;
17
- const formatParams = formatError !== undefined ? `{ error: ${JSON.stringify(formatError)} }` : "";
18
- let r = mappedFormat ? `${mappedFormat}(${formatParams})` : "z.number()";
19
- if (schema.type === "integer") {
20
- if (!mappedFormat) {
21
- r += (0, withMessage_js_1.withMessage)(schema, "type", () => ({
22
- opener: ".int(",
23
- closer: ")",
24
- messagePrefix: "{ error: ",
25
- messageCloser: " })",
26
- }));
27
- }
28
- }
29
- else {
30
- if (!mappedFormat) {
31
- r += (0, withMessage_js_1.withMessage)(schema, "format", ({ value }) => {
32
- if (value === "int64") {
33
- return {
34
- opener: ".int(",
35
- closer: ")",
36
- messagePrefix: "{ error: ",
37
- messageCloser: " })",
38
- };
39
- }
40
- });
41
- }
42
- }
43
- r += (0, withMessage_js_1.withMessage)(schema, "multipleOf", ({ value, json }) => {
44
- if (value === 1) {
45
- if (r.startsWith("z.number().int(")) {
46
- return;
47
- }
48
- return {
49
- opener: ".int(",
50
- closer: ")",
51
- messagePrefix: "{ error: ",
52
- messageCloser: " })",
53
- };
54
- }
55
- return {
56
- opener: `.multipleOf(${json}`,
57
- closer: ")",
58
- messagePrefix: ", { error: ",
59
- messageCloser: " })",
60
- };
61
- });
62
- if (typeof schema.minimum === "number") {
63
- if (schema.exclusiveMinimum === true) {
64
- r += (0, withMessage_js_1.withMessage)(schema, "minimum", ({ json }) => ({
65
- opener: `.gt(${json}`,
66
- closer: ")",
67
- messagePrefix: ", { error: ",
68
- messageCloser: " })",
69
- }));
70
- }
71
- else {
72
- r += (0, withMessage_js_1.withMessage)(schema, "minimum", ({ json }) => ({
73
- opener: `.gte(${json}`,
74
- closer: ")",
75
- messagePrefix: ", { error: ",
76
- messageCloser: " })",
77
- }));
78
- }
79
- }
80
- else if (typeof schema.exclusiveMinimum === "number") {
81
- r += (0, withMessage_js_1.withMessage)(schema, "exclusiveMinimum", ({ json }) => ({
82
- opener: `.gt(${json}`,
83
- closer: ")",
84
- messagePrefix: ", { error: ",
85
- messageCloser: " })",
86
- }));
87
- }
88
- if (typeof schema.maximum === "number") {
89
- if (schema.exclusiveMaximum === true) {
90
- r += (0, withMessage_js_1.withMessage)(schema, "maximum", ({ json }) => ({
91
- opener: `.lt(${json}`,
92
- closer: ")",
93
- messagePrefix: ", { error: ",
94
- messageCloser: " })",
95
- }));
96
- }
97
- else {
98
- r += (0, withMessage_js_1.withMessage)(schema, "maximum", ({ json }) => ({
99
- opener: `.lte(${json}`,
100
- closer: ")",
101
- messagePrefix: ", { error: ",
102
- messageCloser: " })",
103
- }));
104
- }
105
- }
106
- else if (typeof schema.exclusiveMaximum === "number") {
107
- r += (0, withMessage_js_1.withMessage)(schema, "exclusiveMaximum", ({ json }) => ({
108
- opener: `.lt(${json}`,
109
- closer: ")",
110
- messagePrefix: ", { error: ",
111
- messageCloser: " })",
112
- }));
113
- }
114
- return r;
115
- };
116
- exports.parseNumber = parseNumber;
@@ -1,315 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseObject = parseObject;
4
- const parseAnyOf_js_1 = require("./parseAnyOf.js");
5
- const parseOneOf_js_1 = require("./parseOneOf.js");
6
- const parseSchema_js_1 = require("./parseSchema.js");
7
- const parseAllOf_js_1 = require("./parseAllOf.js");
8
- const parseIfThenElse_js_1 = require("./parseIfThenElse.js");
9
- const jsdocs_js_1 = require("../utils/jsdocs.js");
10
- const anyOrUnknown_js_1 = require("../utils/anyOrUnknown.js");
11
- function parseObject(objectSchema, refs) {
12
- let properties = undefined;
13
- if (objectSchema.properties) {
14
- if (!Object.keys(objectSchema.properties).length) {
15
- properties = "z.object({})";
16
- }
17
- else {
18
- properties = "z.object({ ";
19
- properties += Object.keys(objectSchema.properties)
20
- .map((key) => {
21
- const propSchema = objectSchema.properties[key];
22
- const parsedProp = (0, parseSchema_js_1.parseSchema)(propSchema, {
23
- ...refs,
24
- path: [...refs.path, "properties", key],
25
- });
26
- const hasDefault = typeof propSchema === "object" && propSchema.default !== undefined;
27
- const required = Array.isArray(objectSchema.required)
28
- ? objectSchema.required.includes(key)
29
- : typeof propSchema === "object" && propSchema.required === true;
30
- const optional = !hasDefault && !required;
31
- const valueWithOptional = optional
32
- ? `${parsedProp}.optional()`
33
- : parsedProp;
34
- let result = shouldUseGetter(valueWithOptional, refs)
35
- ? `get ${JSON.stringify(key)}(){ return ${valueWithOptional} }`
36
- : `${JSON.stringify(key)}: ${valueWithOptional}`;
37
- if (refs.withJsdocs && typeof propSchema === "object") {
38
- result = (0, jsdocs_js_1.addJsdocs)(propSchema, result);
39
- }
40
- return result;
41
- })
42
- .join(", ");
43
- properties += " })";
44
- }
45
- }
46
- const additionalProperties = objectSchema.additionalProperties !== undefined
47
- ? (0, parseSchema_js_1.parseSchema)(objectSchema.additionalProperties, {
48
- ...refs,
49
- path: [...refs.path, "additionalProperties"],
50
- })
51
- : undefined;
52
- const unevaluated = objectSchema.unevaluatedProperties;
53
- let patternProperties = undefined;
54
- if (objectSchema.patternProperties) {
55
- const parsedPatternProperties = Object.fromEntries(Object.entries(objectSchema.patternProperties).map(([key, value]) => {
56
- return [
57
- key,
58
- (0, parseSchema_js_1.parseSchema)(value, {
59
- ...refs,
60
- path: [...refs.path, "patternProperties", key],
61
- }),
62
- ];
63
- }, {}));
64
- patternProperties = "";
65
- if (properties) {
66
- if (additionalProperties) {
67
- patternProperties += `.catchall(z.union([${[
68
- ...Object.values(parsedPatternProperties),
69
- additionalProperties,
70
- ].join(", ")}]))`;
71
- }
72
- else if (Object.keys(parsedPatternProperties).length > 1) {
73
- patternProperties += `.catchall(z.union([${Object.values(parsedPatternProperties).join(", ")}]))`;
74
- }
75
- else {
76
- patternProperties += `.catchall(${Object.values(parsedPatternProperties)})`;
77
- }
78
- }
79
- else {
80
- if (additionalProperties) {
81
- patternProperties += `z.record(z.string(), z.union([${[
82
- ...Object.values(parsedPatternProperties),
83
- additionalProperties,
84
- ].join(", ")}]))`;
85
- }
86
- else if (Object.keys(parsedPatternProperties).length > 1) {
87
- patternProperties += `z.record(z.string(), z.union([${Object.values(parsedPatternProperties).join(", ")}]))`;
88
- }
89
- else {
90
- patternProperties += `z.record(z.string(), ${Object.values(parsedPatternProperties)})`;
91
- }
92
- }
93
- patternProperties += ".superRefine((value, ctx) => {\n";
94
- patternProperties += "for (const key in value) {\n";
95
- if (additionalProperties) {
96
- if (objectSchema.properties) {
97
- patternProperties += `let evaluated = [${Object.keys(objectSchema.properties)
98
- .map((key) => JSON.stringify(key))
99
- .join(", ")}].includes(key)\n`;
100
- }
101
- else {
102
- patternProperties += `let evaluated = false\n`;
103
- }
104
- }
105
- for (const key in objectSchema.patternProperties) {
106
- patternProperties +=
107
- "if (key.match(new RegExp(" + JSON.stringify(key) + "))) {\n";
108
- if (additionalProperties) {
109
- patternProperties += "evaluated = true\n";
110
- }
111
- patternProperties +=
112
- "const result = " +
113
- parsedPatternProperties[key] +
114
- ".safeParse(value[key])\n";
115
- patternProperties += "if (!result.success) {\n";
116
- patternProperties += `ctx.addIssue({
117
- path: [...(ctx.path ?? []), key],
118
- code: 'custom',
119
- message: \`Invalid input: Key matching regex /\${key}/ must match schema\`,
120
- params: {
121
- issues: result.error.issues
122
- }
123
- })\n`;
124
- patternProperties += "}\n";
125
- patternProperties += "}\n";
126
- }
127
- if (additionalProperties) {
128
- patternProperties += "if (!evaluated) {\n";
129
- patternProperties +=
130
- "const result = " + additionalProperties + ".safeParse(value[key])\n";
131
- patternProperties += "if (!result.success) {\n";
132
- patternProperties += `ctx.addIssue({
133
- path: [...(ctx.path ?? []), key],
134
- code: 'custom',
135
- message: \`Invalid input: must match catchall schema\`,
136
- params: {
137
- issues: result.error.issues
138
- }
139
- })\n`;
140
- patternProperties += "}\n";
141
- patternProperties += "}\n";
142
- }
143
- patternProperties += "}\n";
144
- patternProperties += "})";
145
- // Store original patternProperties in meta for JSON Schema round-trip
146
- if (refs.preserveJsonSchemaForRoundTrip) {
147
- const patternPropsJson = JSON.stringify(Object.fromEntries(Object.entries(objectSchema.patternProperties).map(([pattern, schema]) => [
148
- pattern,
149
- schema
150
- ])));
151
- patternProperties += `.meta({ __jsonSchema: { patternProperties: ${patternPropsJson} } })`;
152
- }
153
- }
154
- // Check if there will be an .and() call that adds properties from oneOf/anyOf/allOf/if-then-else
155
- // In that case, we should NOT use .strict() because it will reject the additional keys
156
- // before the union gets a chance to validate them.
157
- const hasCompositionKeywords = parseSchema_js_1.its.an.anyOf(objectSchema) || parseSchema_js_1.its.a.oneOf(objectSchema) || parseSchema_js_1.its.an.allOf(objectSchema) || parseSchema_js_1.its.a.conditional(objectSchema);
158
- let output = properties
159
- ? patternProperties
160
- ? properties + patternProperties
161
- : additionalProperties
162
- ? additionalProperties === "z.never()"
163
- // Don't use .strict() if there are composition keywords that add properties
164
- ? hasCompositionKeywords
165
- ? properties
166
- : properties + ".strict()"
167
- : properties + `.catchall(${additionalProperties})`
168
- : properties
169
- : patternProperties
170
- ? patternProperties
171
- : additionalProperties
172
- ? `z.record(z.string(), ${additionalProperties})`
173
- : `z.record(z.string(), ${(0, anyOrUnknown_js_1.anyOrUnknown)(refs)})`;
174
- if (unevaluated === false && properties && !hasCompositionKeywords) {
175
- output += ".strict()";
176
- }
177
- else if (unevaluated && typeof unevaluated !== 'boolean') {
178
- const unevaluatedSchema = (0, parseSchema_js_1.parseSchema)(unevaluated, {
179
- ...refs,
180
- path: [...refs.path, "unevaluatedProperties"],
181
- });
182
- const knownKeys = objectSchema.properties ? Object.keys(objectSchema.properties) : [];
183
- const patterns = objectSchema.patternProperties
184
- ? Object.keys(objectSchema.patternProperties).map((p) => new RegExp(p))
185
- : [];
186
- output += `.superRefine((value, ctx) => {
187
- for (const key in value) {
188
- const isKnown = ${JSON.stringify(knownKeys)}.includes(key);
189
- const matchesPattern = ${patterns.length ? "[" + patterns.map((r) => r.toString()).join(",") + "]" : "[]"}.some((r) => r.test(key));
190
- if (!isKnown && !matchesPattern) {
191
- const result = ${unevaluatedSchema}.safeParse(value[key]);
192
- if (!result.success) {
193
- ctx.addIssue({ code: "custom", path: [key], message: "Invalid unevaluated property", params: { issues: result.error.issues } });
194
- }
195
- }
196
- }
197
- })`;
198
- }
199
- if (parseSchema_js_1.its.an.anyOf(objectSchema)) {
200
- output += `.and(${(0, parseAnyOf_js_1.parseAnyOf)({
201
- ...objectSchema,
202
- anyOf: objectSchema.anyOf.map((x) => typeof x === "object" &&
203
- x !== null &&
204
- !x.type &&
205
- (x.properties || x.additionalProperties || x.patternProperties)
206
- ? { ...x, type: "object" }
207
- : x),
208
- }, refs)})`;
209
- }
210
- if (parseSchema_js_1.its.a.oneOf(objectSchema)) {
211
- output += `.and(${(0, parseOneOf_js_1.parseOneOf)({
212
- ...objectSchema,
213
- oneOf: objectSchema.oneOf.map((x) => typeof x === "object" &&
214
- x !== null &&
215
- !x.type &&
216
- (x.properties || x.additionalProperties || x.patternProperties)
217
- ? { ...x, type: "object" }
218
- : x),
219
- }, refs)})`;
220
- }
221
- if (parseSchema_js_1.its.an.allOf(objectSchema)) {
222
- output += `.and(${(0, parseAllOf_js_1.parseAllOf)({
223
- ...objectSchema,
224
- allOf: objectSchema.allOf.map((x) => typeof x === "object" &&
225
- x !== null &&
226
- !x.type &&
227
- (x.properties || x.additionalProperties || x.patternProperties)
228
- ? { ...x, type: "object" }
229
- : x),
230
- }, refs)})`;
231
- }
232
- // Handle if/then/else conditionals on object schemas
233
- if (parseSchema_js_1.its.a.conditional(objectSchema)) {
234
- output += `.and(${(0, parseIfThenElse_js_1.parseIfThenElse)(objectSchema, refs)})`;
235
- }
236
- // propertyNames
237
- if (objectSchema.propertyNames) {
238
- const normalizedPropNames = typeof objectSchema.propertyNames === "object" &&
239
- objectSchema.propertyNames !== null &&
240
- !objectSchema.propertyNames.type &&
241
- objectSchema.propertyNames.pattern
242
- ? { ...objectSchema.propertyNames, type: "string" }
243
- : objectSchema.propertyNames;
244
- const propNameSchema = (0, parseSchema_js_1.parseSchema)(normalizedPropNames, {
245
- ...refs,
246
- path: [...refs.path, "propertyNames"],
247
- });
248
- output += `.superRefine((value, ctx) => {
249
- for (const key in value) {
250
- const result = ${propNameSchema}.safeParse(key);
251
- if (!result.success) {
252
- ctx.addIssue({
253
- path: [key],
254
- code: "custom",
255
- message: "Invalid property name",
256
- params: { issues: result.error.issues }
257
- });
258
- }
259
- }
260
- })`;
261
- }
262
- // dependentSchemas
263
- if (objectSchema.dependentSchemas && typeof objectSchema.dependentSchemas === "object") {
264
- const entries = Object.entries(objectSchema.dependentSchemas);
265
- if (entries.length) {
266
- output += `.superRefine((obj, ctx) => {
267
- ${entries
268
- .map(([key, schema]) => {
269
- const parsed = (0, parseSchema_js_1.parseSchema)(schema, { ...refs, path: [...refs.path, "dependentSchemas", key] });
270
- return `if (Object.prototype.hasOwnProperty.call(obj, ${JSON.stringify(key)})) {
271
- const result = ${parsed}.safeParse(obj);
272
- if (!result.success) {
273
- ctx.addIssue({ code: "custom", message: ${objectSchema.errorMessage?.dependentSchemas ?? JSON.stringify("Dependent schema failed")}, path: [], params: { issues: result.error.issues } });
274
- }
275
- }`;
276
- })
277
- .join("\n ")}
278
- })`;
279
- }
280
- }
281
- // dependentRequired
282
- if (objectSchema.dependentRequired && typeof objectSchema.dependentRequired === "object") {
283
- const entries = Object.entries(objectSchema.dependentRequired);
284
- if (entries.length) {
285
- const depRequiredMessage = objectSchema.errorMessage?.dependentRequired ??
286
- "Dependent required properties missing";
287
- output += `.superRefine((obj, ctx) => {
288
- ${entries
289
- .map(([prop, deps]) => {
290
- const arr = Array.isArray(deps) ? deps : [];
291
- if (!arr.length)
292
- return "";
293
- const jsonDeps = JSON.stringify(arr);
294
- return `if (Object.prototype.hasOwnProperty.call(obj, ${JSON.stringify(prop)})) {
295
- const missing = ${jsonDeps}.filter((d) => !Object.prototype.hasOwnProperty.call(obj, d));
296
- if (missing.length) {
297
- ctx.addIssue({ code: "custom", message: ${JSON.stringify(depRequiredMessage)}, path: [], params: { missing } });
298
- }
299
- }`;
300
- })
301
- .filter(Boolean)
302
- .join("\n ")}
303
- })`;
304
- }
305
- }
306
- return output;
307
- }
308
- const shouldUseGetter = (parsed, refs) => {
309
- if (!parsed)
310
- return false;
311
- if (refs.currentSchemaName && parsed.includes(refs.currentSchemaName)) {
312
- return true;
313
- }
314
- return Boolean(refs.inProgress && refs.inProgress.has(parsed));
315
- };