@aarunyaapps/json-to-types 1.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/dist/index.d.mts +33 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +243 -0
- package/dist/index.mjs +212 -0
- package/package.json +31 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type PrimitiveKind = "string" | "number" | "boolean" | "null" | "unknown";
|
|
2
|
+
type TypeRef = {
|
|
3
|
+
kind: "primitive";
|
|
4
|
+
type: PrimitiveKind;
|
|
5
|
+
} | {
|
|
6
|
+
kind: "array";
|
|
7
|
+
elementType: TypeRef;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "ref";
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
interface FieldDef {
|
|
13
|
+
key: string;
|
|
14
|
+
type: TypeRef;
|
|
15
|
+
nullable: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface TypeDef {
|
|
18
|
+
name: string;
|
|
19
|
+
fields: FieldDef[];
|
|
20
|
+
}
|
|
21
|
+
interface ParseResult {
|
|
22
|
+
defs: TypeDef[];
|
|
23
|
+
rootRef: TypeRef;
|
|
24
|
+
}
|
|
25
|
+
declare function parseJson(json: unknown, rootName?: string): ParseResult;
|
|
26
|
+
declare function generateTypeScript(result: ParseResult, rootName: string): string;
|
|
27
|
+
declare function generateZod(result: ParseResult, rootName: string): string;
|
|
28
|
+
declare function generateJsonSchema(result: ParseResult, rootName: string): string;
|
|
29
|
+
declare function generateOpenApi(result: ParseResult, rootName: string): string;
|
|
30
|
+
declare function generateYup(result: ParseResult, rootName: string): string;
|
|
31
|
+
declare function generateValibot(result: ParseResult, rootName: string): string;
|
|
32
|
+
|
|
33
|
+
export { type FieldDef, type ParseResult, type PrimitiveKind, type TypeDef, type TypeRef, generateJsonSchema, generateOpenApi, generateTypeScript, generateValibot, generateYup, generateZod, parseJson };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
type PrimitiveKind = "string" | "number" | "boolean" | "null" | "unknown";
|
|
2
|
+
type TypeRef = {
|
|
3
|
+
kind: "primitive";
|
|
4
|
+
type: PrimitiveKind;
|
|
5
|
+
} | {
|
|
6
|
+
kind: "array";
|
|
7
|
+
elementType: TypeRef;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "ref";
|
|
10
|
+
name: string;
|
|
11
|
+
};
|
|
12
|
+
interface FieldDef {
|
|
13
|
+
key: string;
|
|
14
|
+
type: TypeRef;
|
|
15
|
+
nullable: boolean;
|
|
16
|
+
}
|
|
17
|
+
interface TypeDef {
|
|
18
|
+
name: string;
|
|
19
|
+
fields: FieldDef[];
|
|
20
|
+
}
|
|
21
|
+
interface ParseResult {
|
|
22
|
+
defs: TypeDef[];
|
|
23
|
+
rootRef: TypeRef;
|
|
24
|
+
}
|
|
25
|
+
declare function parseJson(json: unknown, rootName?: string): ParseResult;
|
|
26
|
+
declare function generateTypeScript(result: ParseResult, rootName: string): string;
|
|
27
|
+
declare function generateZod(result: ParseResult, rootName: string): string;
|
|
28
|
+
declare function generateJsonSchema(result: ParseResult, rootName: string): string;
|
|
29
|
+
declare function generateOpenApi(result: ParseResult, rootName: string): string;
|
|
30
|
+
declare function generateYup(result: ParseResult, rootName: string): string;
|
|
31
|
+
declare function generateValibot(result: ParseResult, rootName: string): string;
|
|
32
|
+
|
|
33
|
+
export { type FieldDef, type ParseResult, type PrimitiveKind, type TypeDef, type TypeRef, generateJsonSchema, generateOpenApi, generateTypeScript, generateValibot, generateYup, generateZod, parseJson };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
generateJsonSchema: () => generateJsonSchema,
|
|
24
|
+
generateOpenApi: () => generateOpenApi,
|
|
25
|
+
generateTypeScript: () => generateTypeScript,
|
|
26
|
+
generateValibot: () => generateValibot,
|
|
27
|
+
generateYup: () => generateYup,
|
|
28
|
+
generateZod: () => generateZod,
|
|
29
|
+
parseJson: () => parseJson
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
function toPascalCase(str) {
|
|
33
|
+
if (!str) return "Unknown";
|
|
34
|
+
return str.split(/[_\-\s.[\]]+/).filter(Boolean).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
|
|
35
|
+
}
|
|
36
|
+
function inferRef(value, hint, defs, seen) {
|
|
37
|
+
if (value === null || value === void 0) return { kind: "primitive", type: "null" };
|
|
38
|
+
if (typeof value === "boolean") return { kind: "primitive", type: "boolean" };
|
|
39
|
+
if (typeof value === "number") return { kind: "primitive", type: "number" };
|
|
40
|
+
if (typeof value === "string") return { kind: "primitive", type: "string" };
|
|
41
|
+
if (Array.isArray(value)) {
|
|
42
|
+
if (value.length === 0) return { kind: "array", elementType: { kind: "primitive", type: "unknown" } };
|
|
43
|
+
return { kind: "array", elementType: inferRef(value[0], hint + "Item", defs, seen) };
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === "object") {
|
|
46
|
+
const obj = value;
|
|
47
|
+
let name = toPascalCase(hint);
|
|
48
|
+
let n = 2;
|
|
49
|
+
while (seen.has(name)) name = toPascalCase(hint) + String(n++);
|
|
50
|
+
seen.add(name);
|
|
51
|
+
const fields = Object.entries(obj).map(([k, v]) => ({
|
|
52
|
+
key: k,
|
|
53
|
+
type: inferRef(v, k, defs, seen),
|
|
54
|
+
nullable: v === null
|
|
55
|
+
}));
|
|
56
|
+
defs.push({ name, fields });
|
|
57
|
+
return { kind: "ref", name };
|
|
58
|
+
}
|
|
59
|
+
return { kind: "primitive", type: "unknown" };
|
|
60
|
+
}
|
|
61
|
+
function parseJson(json, rootName = "Root") {
|
|
62
|
+
const defs = [];
|
|
63
|
+
const seen = /* @__PURE__ */ new Set();
|
|
64
|
+
const rootRef = inferRef(json, rootName, defs, seen);
|
|
65
|
+
return { defs, rootRef };
|
|
66
|
+
}
|
|
67
|
+
function refToTs(ref) {
|
|
68
|
+
if (ref.kind === "primitive") return ref.type === "null" ? "null" : ref.type;
|
|
69
|
+
if (ref.kind === "array") {
|
|
70
|
+
const i = refToTs(ref.elementType);
|
|
71
|
+
return i.includes("|") ? `(${i})[]` : `${i}[]`;
|
|
72
|
+
}
|
|
73
|
+
return ref.name;
|
|
74
|
+
}
|
|
75
|
+
function generateTypeScript(result, rootName) {
|
|
76
|
+
const { defs, rootRef } = result;
|
|
77
|
+
const parts = [];
|
|
78
|
+
if (rootRef.kind !== "ref" && defs.length === 0) return `export type ${rootName} = ${refToTs(rootRef)};`;
|
|
79
|
+
if (rootRef.kind === "array") parts.push(`export type ${rootName} = ${refToTs(rootRef)};`);
|
|
80
|
+
for (const { name, fields } of defs) {
|
|
81
|
+
const lines = fields.map(({ key, type, nullable }) => {
|
|
82
|
+
const t = nullable ? `${refToTs(type)} | null` : refToTs(type);
|
|
83
|
+
const k = /[^a-zA-Z0-9_$]/.test(key) ? `"${key}"` : key;
|
|
84
|
+
return ` ${k}: ${t};`;
|
|
85
|
+
});
|
|
86
|
+
parts.push(`export interface ${name} {
|
|
87
|
+
${lines.join("\n")}
|
|
88
|
+
}`);
|
|
89
|
+
}
|
|
90
|
+
return parts.join("\n\n");
|
|
91
|
+
}
|
|
92
|
+
function refToZod(ref) {
|
|
93
|
+
if (ref.kind === "primitive") {
|
|
94
|
+
const m = { string: "z.string()", number: "z.number()", boolean: "z.boolean()", null: "z.null()", unknown: "z.unknown()" };
|
|
95
|
+
return m[ref.type];
|
|
96
|
+
}
|
|
97
|
+
if (ref.kind === "array") return `z.array(${refToZod(ref.elementType)})`;
|
|
98
|
+
return `${ref.name}Schema`;
|
|
99
|
+
}
|
|
100
|
+
function generateZod(result, rootName) {
|
|
101
|
+
const { defs, rootRef } = result;
|
|
102
|
+
if (defs.length === 0) return `import { z } from "zod";
|
|
103
|
+
|
|
104
|
+
export const ${rootName}Schema = ${refToZod(rootRef)};`;
|
|
105
|
+
const schemas = defs.map(({ name, fields }) => {
|
|
106
|
+
const lines = fields.map(({ key, type, nullable }) => {
|
|
107
|
+
const t = nullable ? `${refToZod(type)}.nullable()` : refToZod(type);
|
|
108
|
+
const k = /[^a-zA-Z0-9_$]/.test(key) ? `"${key}"` : key;
|
|
109
|
+
return ` ${k}: ${t},`;
|
|
110
|
+
});
|
|
111
|
+
return `export const ${name}Schema = z.object({
|
|
112
|
+
${lines.join("\n")}
|
|
113
|
+
});`;
|
|
114
|
+
});
|
|
115
|
+
const rootAlias = rootRef.kind === "array" ? `
|
|
116
|
+
export const ${rootName}Schema = z.array(${refToZod(rootRef.elementType)});` : "";
|
|
117
|
+
return `import { z } from "zod";
|
|
118
|
+
|
|
119
|
+
${schemas.join("\n\n")}${rootAlias}`;
|
|
120
|
+
}
|
|
121
|
+
function refToJsonSchema(ref) {
|
|
122
|
+
if (ref.kind === "primitive") {
|
|
123
|
+
if (ref.type === "null") return { type: "null" };
|
|
124
|
+
if (ref.type === "unknown") return {};
|
|
125
|
+
return { type: ref.type };
|
|
126
|
+
}
|
|
127
|
+
if (ref.kind === "array") return { type: "array", items: refToJsonSchema(ref.elementType) };
|
|
128
|
+
return { "$ref": `#/definitions/${ref.name}` };
|
|
129
|
+
}
|
|
130
|
+
function generateJsonSchema(result, rootName) {
|
|
131
|
+
const { defs, rootRef } = result;
|
|
132
|
+
const definitions = {};
|
|
133
|
+
for (const { name, fields } of defs) {
|
|
134
|
+
const properties = {};
|
|
135
|
+
const required = [];
|
|
136
|
+
for (const { key, type, nullable } of fields) {
|
|
137
|
+
properties[key] = nullable ? { anyOf: [refToJsonSchema(type), { type: "null" }] } : refToJsonSchema(type);
|
|
138
|
+
if (!nullable) required.push(key);
|
|
139
|
+
}
|
|
140
|
+
definitions[name] = { type: "object", properties, ...required.length > 0 ? { required } : {}, additionalProperties: false };
|
|
141
|
+
}
|
|
142
|
+
const root = {
|
|
143
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
144
|
+
title: rootName,
|
|
145
|
+
...rootRef.kind === "ref" ? { "$ref": `#/definitions/${rootRef.name}` } : rootRef.kind === "array" ? { type: "array", items: refToJsonSchema(rootRef.elementType) } : refToJsonSchema(rootRef),
|
|
146
|
+
...Object.keys(definitions).length > 0 ? { definitions } : {}
|
|
147
|
+
};
|
|
148
|
+
return JSON.stringify(root, null, 2);
|
|
149
|
+
}
|
|
150
|
+
function refToOas(ref) {
|
|
151
|
+
if (ref.kind === "primitive") {
|
|
152
|
+
if (ref.type === "null") return { nullable: true };
|
|
153
|
+
if (ref.type === "unknown") return {};
|
|
154
|
+
return { type: ref.type };
|
|
155
|
+
}
|
|
156
|
+
if (ref.kind === "array") return { type: "array", items: refToOas(ref.elementType) };
|
|
157
|
+
return { "$ref": `#/components/schemas/${ref.name}` };
|
|
158
|
+
}
|
|
159
|
+
function generateOpenApi(result, rootName) {
|
|
160
|
+
const { defs, rootRef } = result;
|
|
161
|
+
const schemas = {};
|
|
162
|
+
for (const { name, fields } of defs) {
|
|
163
|
+
const properties = {};
|
|
164
|
+
const required = [];
|
|
165
|
+
for (const { key, type, nullable } of fields) {
|
|
166
|
+
properties[key] = nullable ? { ...refToOas(type), nullable: true } : refToOas(type);
|
|
167
|
+
if (!nullable) required.push(key);
|
|
168
|
+
}
|
|
169
|
+
schemas[name] = { type: "object", properties, ...required.length > 0 ? { required } : {} };
|
|
170
|
+
}
|
|
171
|
+
if (rootRef.kind !== "ref") {
|
|
172
|
+
schemas[rootName] = rootRef.kind === "array" ? { type: "array", items: refToOas(rootRef.elementType) } : refToOas(rootRef);
|
|
173
|
+
}
|
|
174
|
+
return JSON.stringify({ openapi: "3.0.3", info: { title: `${rootName} API`, version: "1.0.0" }, paths: {}, components: { schemas } }, null, 2);
|
|
175
|
+
}
|
|
176
|
+
function refToYup(ref) {
|
|
177
|
+
if (ref.kind === "primitive") {
|
|
178
|
+
const m = { string: "yup.string()", number: "yup.number()", boolean: "yup.boolean()", null: "yup.mixed().nullable()", unknown: "yup.mixed()" };
|
|
179
|
+
return m[ref.type];
|
|
180
|
+
}
|
|
181
|
+
if (ref.kind === "array") return `yup.array().of(${refToYup(ref.elementType)})`;
|
|
182
|
+
return `${ref.name}Schema`;
|
|
183
|
+
}
|
|
184
|
+
function generateYup(result, rootName) {
|
|
185
|
+
const { defs, rootRef } = result;
|
|
186
|
+
if (defs.length === 0) return `import * as yup from "yup";
|
|
187
|
+
|
|
188
|
+
export const ${rootName}Schema = ${refToYup(rootRef)};`;
|
|
189
|
+
const schemas = defs.map(({ name, fields }) => {
|
|
190
|
+
const lines = fields.map(({ key, type, nullable }) => {
|
|
191
|
+
const t = nullable ? `${refToYup(type)}.nullable()` : refToYup(type);
|
|
192
|
+
const k = /[^a-zA-Z0-9_$]/.test(key) ? `"${key}"` : key;
|
|
193
|
+
return ` ${k}: ${t},`;
|
|
194
|
+
});
|
|
195
|
+
return `export const ${name}Schema = yup.object({
|
|
196
|
+
${lines.join("\n")}
|
|
197
|
+
}).required();`;
|
|
198
|
+
});
|
|
199
|
+
const rootAlias = rootRef.kind === "array" ? `
|
|
200
|
+
export const ${rootName}Schema = yup.array().of(${refToYup(rootRef.elementType)}).required();` : "";
|
|
201
|
+
return `import * as yup from "yup";
|
|
202
|
+
|
|
203
|
+
${schemas.join("\n\n")}${rootAlias}`;
|
|
204
|
+
}
|
|
205
|
+
function refToValibot(ref) {
|
|
206
|
+
if (ref.kind === "primitive") {
|
|
207
|
+
const m = { string: "v.string()", number: "v.number()", boolean: "v.boolean()", null: "v.null_()", unknown: "v.unknown()" };
|
|
208
|
+
return m[ref.type];
|
|
209
|
+
}
|
|
210
|
+
if (ref.kind === "array") return `v.array(${refToValibot(ref.elementType)})`;
|
|
211
|
+
return `${ref.name}Schema`;
|
|
212
|
+
}
|
|
213
|
+
function generateValibot(result, rootName) {
|
|
214
|
+
const { defs, rootRef } = result;
|
|
215
|
+
if (defs.length === 0) return `import * as v from "valibot";
|
|
216
|
+
|
|
217
|
+
export const ${rootName}Schema = ${refToValibot(rootRef)};`;
|
|
218
|
+
const schemas = defs.map(({ name, fields }) => {
|
|
219
|
+
const lines = fields.map(({ key, type, nullable }) => {
|
|
220
|
+
const t = nullable ? `v.nullable(${refToValibot(type)})` : refToValibot(type);
|
|
221
|
+
const k = /[^a-zA-Z0-9_$]/.test(key) ? `"${key}"` : key;
|
|
222
|
+
return ` ${k}: ${t},`;
|
|
223
|
+
});
|
|
224
|
+
return `export const ${name}Schema = v.object({
|
|
225
|
+
${lines.join("\n")}
|
|
226
|
+
});`;
|
|
227
|
+
});
|
|
228
|
+
const rootAlias = rootRef.kind === "array" ? `
|
|
229
|
+
export const ${rootName}Schema = v.array(${refToValibot(rootRef.elementType)});` : "";
|
|
230
|
+
return `import * as v from "valibot";
|
|
231
|
+
|
|
232
|
+
${schemas.join("\n\n")}${rootAlias}`;
|
|
233
|
+
}
|
|
234
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
235
|
+
0 && (module.exports = {
|
|
236
|
+
generateJsonSchema,
|
|
237
|
+
generateOpenApi,
|
|
238
|
+
generateTypeScript,
|
|
239
|
+
generateValibot,
|
|
240
|
+
generateYup,
|
|
241
|
+
generateZod,
|
|
242
|
+
parseJson
|
|
243
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
function toPascalCase(str) {
|
|
3
|
+
if (!str) return "Unknown";
|
|
4
|
+
return str.split(/[_\-\s.[\]]+/).filter(Boolean).map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
|
|
5
|
+
}
|
|
6
|
+
function inferRef(value, hint, defs, seen) {
|
|
7
|
+
if (value === null || value === void 0) return { kind: "primitive", type: "null" };
|
|
8
|
+
if (typeof value === "boolean") return { kind: "primitive", type: "boolean" };
|
|
9
|
+
if (typeof value === "number") return { kind: "primitive", type: "number" };
|
|
10
|
+
if (typeof value === "string") return { kind: "primitive", type: "string" };
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
if (value.length === 0) return { kind: "array", elementType: { kind: "primitive", type: "unknown" } };
|
|
13
|
+
return { kind: "array", elementType: inferRef(value[0], hint + "Item", defs, seen) };
|
|
14
|
+
}
|
|
15
|
+
if (typeof value === "object") {
|
|
16
|
+
const obj = value;
|
|
17
|
+
let name = toPascalCase(hint);
|
|
18
|
+
let n = 2;
|
|
19
|
+
while (seen.has(name)) name = toPascalCase(hint) + String(n++);
|
|
20
|
+
seen.add(name);
|
|
21
|
+
const fields = Object.entries(obj).map(([k, v]) => ({
|
|
22
|
+
key: k,
|
|
23
|
+
type: inferRef(v, k, defs, seen),
|
|
24
|
+
nullable: v === null
|
|
25
|
+
}));
|
|
26
|
+
defs.push({ name, fields });
|
|
27
|
+
return { kind: "ref", name };
|
|
28
|
+
}
|
|
29
|
+
return { kind: "primitive", type: "unknown" };
|
|
30
|
+
}
|
|
31
|
+
function parseJson(json, rootName = "Root") {
|
|
32
|
+
const defs = [];
|
|
33
|
+
const seen = /* @__PURE__ */ new Set();
|
|
34
|
+
const rootRef = inferRef(json, rootName, defs, seen);
|
|
35
|
+
return { defs, rootRef };
|
|
36
|
+
}
|
|
37
|
+
function refToTs(ref) {
|
|
38
|
+
if (ref.kind === "primitive") return ref.type === "null" ? "null" : ref.type;
|
|
39
|
+
if (ref.kind === "array") {
|
|
40
|
+
const i = refToTs(ref.elementType);
|
|
41
|
+
return i.includes("|") ? `(${i})[]` : `${i}[]`;
|
|
42
|
+
}
|
|
43
|
+
return ref.name;
|
|
44
|
+
}
|
|
45
|
+
function generateTypeScript(result, rootName) {
|
|
46
|
+
const { defs, rootRef } = result;
|
|
47
|
+
const parts = [];
|
|
48
|
+
if (rootRef.kind !== "ref" && defs.length === 0) return `export type ${rootName} = ${refToTs(rootRef)};`;
|
|
49
|
+
if (rootRef.kind === "array") parts.push(`export type ${rootName} = ${refToTs(rootRef)};`);
|
|
50
|
+
for (const { name, fields } of defs) {
|
|
51
|
+
const lines = fields.map(({ key, type, nullable }) => {
|
|
52
|
+
const t = nullable ? `${refToTs(type)} | null` : refToTs(type);
|
|
53
|
+
const k = /[^a-zA-Z0-9_$]/.test(key) ? `"${key}"` : key;
|
|
54
|
+
return ` ${k}: ${t};`;
|
|
55
|
+
});
|
|
56
|
+
parts.push(`export interface ${name} {
|
|
57
|
+
${lines.join("\n")}
|
|
58
|
+
}`);
|
|
59
|
+
}
|
|
60
|
+
return parts.join("\n\n");
|
|
61
|
+
}
|
|
62
|
+
function refToZod(ref) {
|
|
63
|
+
if (ref.kind === "primitive") {
|
|
64
|
+
const m = { string: "z.string()", number: "z.number()", boolean: "z.boolean()", null: "z.null()", unknown: "z.unknown()" };
|
|
65
|
+
return m[ref.type];
|
|
66
|
+
}
|
|
67
|
+
if (ref.kind === "array") return `z.array(${refToZod(ref.elementType)})`;
|
|
68
|
+
return `${ref.name}Schema`;
|
|
69
|
+
}
|
|
70
|
+
function generateZod(result, rootName) {
|
|
71
|
+
const { defs, rootRef } = result;
|
|
72
|
+
if (defs.length === 0) return `import { z } from "zod";
|
|
73
|
+
|
|
74
|
+
export const ${rootName}Schema = ${refToZod(rootRef)};`;
|
|
75
|
+
const schemas = defs.map(({ name, fields }) => {
|
|
76
|
+
const lines = fields.map(({ key, type, nullable }) => {
|
|
77
|
+
const t = nullable ? `${refToZod(type)}.nullable()` : refToZod(type);
|
|
78
|
+
const k = /[^a-zA-Z0-9_$]/.test(key) ? `"${key}"` : key;
|
|
79
|
+
return ` ${k}: ${t},`;
|
|
80
|
+
});
|
|
81
|
+
return `export const ${name}Schema = z.object({
|
|
82
|
+
${lines.join("\n")}
|
|
83
|
+
});`;
|
|
84
|
+
});
|
|
85
|
+
const rootAlias = rootRef.kind === "array" ? `
|
|
86
|
+
export const ${rootName}Schema = z.array(${refToZod(rootRef.elementType)});` : "";
|
|
87
|
+
return `import { z } from "zod";
|
|
88
|
+
|
|
89
|
+
${schemas.join("\n\n")}${rootAlias}`;
|
|
90
|
+
}
|
|
91
|
+
function refToJsonSchema(ref) {
|
|
92
|
+
if (ref.kind === "primitive") {
|
|
93
|
+
if (ref.type === "null") return { type: "null" };
|
|
94
|
+
if (ref.type === "unknown") return {};
|
|
95
|
+
return { type: ref.type };
|
|
96
|
+
}
|
|
97
|
+
if (ref.kind === "array") return { type: "array", items: refToJsonSchema(ref.elementType) };
|
|
98
|
+
return { "$ref": `#/definitions/${ref.name}` };
|
|
99
|
+
}
|
|
100
|
+
function generateJsonSchema(result, rootName) {
|
|
101
|
+
const { defs, rootRef } = result;
|
|
102
|
+
const definitions = {};
|
|
103
|
+
for (const { name, fields } of defs) {
|
|
104
|
+
const properties = {};
|
|
105
|
+
const required = [];
|
|
106
|
+
for (const { key, type, nullable } of fields) {
|
|
107
|
+
properties[key] = nullable ? { anyOf: [refToJsonSchema(type), { type: "null" }] } : refToJsonSchema(type);
|
|
108
|
+
if (!nullable) required.push(key);
|
|
109
|
+
}
|
|
110
|
+
definitions[name] = { type: "object", properties, ...required.length > 0 ? { required } : {}, additionalProperties: false };
|
|
111
|
+
}
|
|
112
|
+
const root = {
|
|
113
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
114
|
+
title: rootName,
|
|
115
|
+
...rootRef.kind === "ref" ? { "$ref": `#/definitions/${rootRef.name}` } : rootRef.kind === "array" ? { type: "array", items: refToJsonSchema(rootRef.elementType) } : refToJsonSchema(rootRef),
|
|
116
|
+
...Object.keys(definitions).length > 0 ? { definitions } : {}
|
|
117
|
+
};
|
|
118
|
+
return JSON.stringify(root, null, 2);
|
|
119
|
+
}
|
|
120
|
+
function refToOas(ref) {
|
|
121
|
+
if (ref.kind === "primitive") {
|
|
122
|
+
if (ref.type === "null") return { nullable: true };
|
|
123
|
+
if (ref.type === "unknown") return {};
|
|
124
|
+
return { type: ref.type };
|
|
125
|
+
}
|
|
126
|
+
if (ref.kind === "array") return { type: "array", items: refToOas(ref.elementType) };
|
|
127
|
+
return { "$ref": `#/components/schemas/${ref.name}` };
|
|
128
|
+
}
|
|
129
|
+
function generateOpenApi(result, rootName) {
|
|
130
|
+
const { defs, rootRef } = result;
|
|
131
|
+
const schemas = {};
|
|
132
|
+
for (const { name, fields } of defs) {
|
|
133
|
+
const properties = {};
|
|
134
|
+
const required = [];
|
|
135
|
+
for (const { key, type, nullable } of fields) {
|
|
136
|
+
properties[key] = nullable ? { ...refToOas(type), nullable: true } : refToOas(type);
|
|
137
|
+
if (!nullable) required.push(key);
|
|
138
|
+
}
|
|
139
|
+
schemas[name] = { type: "object", properties, ...required.length > 0 ? { required } : {} };
|
|
140
|
+
}
|
|
141
|
+
if (rootRef.kind !== "ref") {
|
|
142
|
+
schemas[rootName] = rootRef.kind === "array" ? { type: "array", items: refToOas(rootRef.elementType) } : refToOas(rootRef);
|
|
143
|
+
}
|
|
144
|
+
return JSON.stringify({ openapi: "3.0.3", info: { title: `${rootName} API`, version: "1.0.0" }, paths: {}, components: { schemas } }, null, 2);
|
|
145
|
+
}
|
|
146
|
+
function refToYup(ref) {
|
|
147
|
+
if (ref.kind === "primitive") {
|
|
148
|
+
const m = { string: "yup.string()", number: "yup.number()", boolean: "yup.boolean()", null: "yup.mixed().nullable()", unknown: "yup.mixed()" };
|
|
149
|
+
return m[ref.type];
|
|
150
|
+
}
|
|
151
|
+
if (ref.kind === "array") return `yup.array().of(${refToYup(ref.elementType)})`;
|
|
152
|
+
return `${ref.name}Schema`;
|
|
153
|
+
}
|
|
154
|
+
function generateYup(result, rootName) {
|
|
155
|
+
const { defs, rootRef } = result;
|
|
156
|
+
if (defs.length === 0) return `import * as yup from "yup";
|
|
157
|
+
|
|
158
|
+
export const ${rootName}Schema = ${refToYup(rootRef)};`;
|
|
159
|
+
const schemas = defs.map(({ name, fields }) => {
|
|
160
|
+
const lines = fields.map(({ key, type, nullable }) => {
|
|
161
|
+
const t = nullable ? `${refToYup(type)}.nullable()` : refToYup(type);
|
|
162
|
+
const k = /[^a-zA-Z0-9_$]/.test(key) ? `"${key}"` : key;
|
|
163
|
+
return ` ${k}: ${t},`;
|
|
164
|
+
});
|
|
165
|
+
return `export const ${name}Schema = yup.object({
|
|
166
|
+
${lines.join("\n")}
|
|
167
|
+
}).required();`;
|
|
168
|
+
});
|
|
169
|
+
const rootAlias = rootRef.kind === "array" ? `
|
|
170
|
+
export const ${rootName}Schema = yup.array().of(${refToYup(rootRef.elementType)}).required();` : "";
|
|
171
|
+
return `import * as yup from "yup";
|
|
172
|
+
|
|
173
|
+
${schemas.join("\n\n")}${rootAlias}`;
|
|
174
|
+
}
|
|
175
|
+
function refToValibot(ref) {
|
|
176
|
+
if (ref.kind === "primitive") {
|
|
177
|
+
const m = { string: "v.string()", number: "v.number()", boolean: "v.boolean()", null: "v.null_()", unknown: "v.unknown()" };
|
|
178
|
+
return m[ref.type];
|
|
179
|
+
}
|
|
180
|
+
if (ref.kind === "array") return `v.array(${refToValibot(ref.elementType)})`;
|
|
181
|
+
return `${ref.name}Schema`;
|
|
182
|
+
}
|
|
183
|
+
function generateValibot(result, rootName) {
|
|
184
|
+
const { defs, rootRef } = result;
|
|
185
|
+
if (defs.length === 0) return `import * as v from "valibot";
|
|
186
|
+
|
|
187
|
+
export const ${rootName}Schema = ${refToValibot(rootRef)};`;
|
|
188
|
+
const schemas = defs.map(({ name, fields }) => {
|
|
189
|
+
const lines = fields.map(({ key, type, nullable }) => {
|
|
190
|
+
const t = nullable ? `v.nullable(${refToValibot(type)})` : refToValibot(type);
|
|
191
|
+
const k = /[^a-zA-Z0-9_$]/.test(key) ? `"${key}"` : key;
|
|
192
|
+
return ` ${k}: ${t},`;
|
|
193
|
+
});
|
|
194
|
+
return `export const ${name}Schema = v.object({
|
|
195
|
+
${lines.join("\n")}
|
|
196
|
+
});`;
|
|
197
|
+
});
|
|
198
|
+
const rootAlias = rootRef.kind === "array" ? `
|
|
199
|
+
export const ${rootName}Schema = v.array(${refToValibot(rootRef.elementType)});` : "";
|
|
200
|
+
return `import * as v from "valibot";
|
|
201
|
+
|
|
202
|
+
${schemas.join("\n\n")}${rootAlias}`;
|
|
203
|
+
}
|
|
204
|
+
export {
|
|
205
|
+
generateJsonSchema,
|
|
206
|
+
generateOpenApi,
|
|
207
|
+
generateTypeScript,
|
|
208
|
+
generateValibot,
|
|
209
|
+
generateYup,
|
|
210
|
+
generateZod,
|
|
211
|
+
parseJson
|
|
212
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aarunyaapps/json-to-types",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Infer TypeScript, Zod, Valibot, Yup, JSON Schema, and OpenAPI 3 schemas from any JSON value. Zero dependencies.",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist", "README.md"],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
18
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
19
|
+
"type-check": "tsc --noEmit"
|
|
20
|
+
},
|
|
21
|
+
"keywords": ["typescript", "zod", "valibot", "json-schema", "openapi", "type-generation", "codegen"],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/aarunyaapps/json-to-types"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"tsup": "^8.0.0",
|
|
29
|
+
"typescript": "^5.8.3"
|
|
30
|
+
}
|
|
31
|
+
}
|