Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use maketypes library for json-to-ts and json-to-zod transformations. #402

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@babel/standalone": "^7.14.7",
"@graphql-codegen/core": "^1.17.10",
"@graphql-codegen/flow": "^1.19.3",
"maketypes": "1.1.2",
"@graphql-codegen/flow-operations": "^1.18.11",
"@graphql-codegen/flow-resolvers": "^1.17.16",
"@graphql-codegen/fragment-matcher": "^2.0.1",
Expand Down Expand Up @@ -68,7 +69,6 @@
"json-schema-to-typescript": "^10.1.4",
"json-schema-to-zod": "^0.1.2",
"json-to-go": "gist:0d0b8324131c80eeb7e1df20001be32f",
"json-to-zod": "^1.1.2",
"json-ts": "^1.6.4",
"json_typegen_wasm": "^0.7.0",
"jsonld": "^5.2.0",
Expand Down
32 changes: 18 additions & 14 deletions pages/api/typescript-to-zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,9 @@ export default (req: NextApiRequest, res: NextApiResponse) => {
const { query, body } = req;
const { skipParseJSDoc, keepComments } = query;

const filePath =
path.join(tmpDir, crypto.randomBytes(16).toString("hex")) + ".ts";

try {
const schemaGenerator = generate({
sourceText: body,
keepComments: keepComments === "true",
skipParseJSDoc: skipParseJSDoc === "true"
});

const schema = schemaGenerator.getZodSchemasFile(filePath);

const formattedSchema = schema
.split(/\r?\n/)
.slice(1)
.join("\n");
const { formattedSchema, schemaGenerator } = tsToZod(body, keepComments, skipParseJSDoc);

res
.status(200)
Expand All @@ -34,3 +21,20 @@ export default (req: NextApiRequest, res: NextApiResponse) => {
res.status(200).json({ error: e.message });
}
};
function tsToZod(body: any, keepComments: string | string[] = "true", skipParseJSDoc: string | string[] = "true") {
const schemaGenerator = generate({
sourceText: body,
keepComments: keepComments === "true",
skipParseJSDoc: skipParseJSDoc === "true"
});

const filePath = path.join(tmpDir, crypto.randomBytes(16).toString("hex")) + ".ts";
const schema = schemaGenerator.getZodSchemasFile(filePath);

const formattedSchema = schema
.split(/\r?\n/)
.slice(1)
.join("\n");
return { formattedSchema, schemaGenerator };
}

37 changes: 27 additions & 10 deletions pages/json-to-typescript.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Form, { InputType } from "@components/Form";
import { useSettings } from "@hooks/useSettings";
import * as React from "react";
import { useCallback } from "react";
import { Writable } from "stream";

interface Settings {
typealias: boolean;
Expand All @@ -17,6 +18,24 @@ const formFields = [
}
];

class StringWriter extends Writable {
_data: string;

constructor(options: any) {
super(options);
this._data = '';
}

_write(chunk, _encoding, callback) {
this._data += chunk;
callback();
}

getData() {
return this._data;
}
}

export default function JsonToTypescript() {
const name = "JSON to Typescript";

Expand All @@ -26,16 +45,14 @@ export default function JsonToTypescript() {

const transformer = useCallback(
async ({ value }) => {
const { run } = await import("json_typegen_wasm");
return run(
"Root",
value,
JSON.stringify({
output_mode: settings.typealias
? "typescript/typealias"
: "typescript"
})
);
const mt = await import("maketypes")
const w = new StringWriter({})
const emitter = new mt.Emitter( new mt.StreamWriter(w), new mt.NopWriter() );

emitter.emit(JSON.parse(value), "RootObject")

return w.getData()

},
[settings]
);
Expand Down
57 changes: 55 additions & 2 deletions pages/json-to-zod.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { generate } from "ts-to-zod";
import crypto from "crypto";
import path from "path";
import ConversionPanel from "@components/ConversionPanel";
import { EditorPanelProps } from "@components/EditorPanel";
import Form, { InputType } from "@components/Form";
import { useSettings } from "@hooks/useSettings";
import * as React from "react";
import os from "os";
import { useCallback } from "react";
import { Writable } from "stream";

interface Settings {
rootName: string;
Expand All @@ -17,6 +22,43 @@ const formFields = [
}
];

const tmpDir = os.tmpdir?.();

function tsToZod(body: any, keepComments: string | string[] = "true", skipParseJSDoc: string | string[] = "true") {
const schemaGenerator = generate({
sourceText: body,
keepComments: keepComments === "true",
skipParseJSDoc: skipParseJSDoc === "true"
});

const filePath = path.join(tmpDir, crypto.randomBytes(16).toString("hex")) + ".ts";
const schema = schemaGenerator.getZodSchemasFile(filePath);

const formattedSchema = schema
.split(/\r?\n/)
.slice(1)
.join("\n");
return { formattedSchema, schemaGenerator };
}

class StringWriter extends Writable {
_data: string;

constructor(options: any) {
super(options);
this._data = '';
}

_write(chunk, _encoding, callback) {
this._data += chunk;
callback();
}

getData() {
return this._data;
}
}

export default function JsonToZod() {
const name = "JSON to Zod Schema";

Expand All @@ -26,8 +68,19 @@ export default function JsonToZod() {

const transformer = useCallback(
async ({ value }) => {
const { jsonToZod } = await import("json-to-zod");
return jsonToZod(JSON.parse(value), settings.rootName, true);
// first transform to typescript interface
const mt = await import("maketypes")
const w = new StringWriter({})
const emitter = new mt.Emitter( new mt.StreamWriter(w), new mt.NopWriter() );

emitter.emit(JSON.parse(value), "RootObject")

const tsInterface = w.getData()

// then convert the interface to zod schema. We do this in two steps because
// the libraries that convert directly from JSON to Zod are not as mature
const {formattedSchema} = tsToZod(tsInterface)
return formattedSchema
},
[settings]
);
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"noUnusedLocals": false,
"noUnusedParameters": true,
"noUnusedParameters": false,
"removeComments": false,
"preserveConstEnums": true,
"sourceMap": true,
Expand Down
54 changes: 45 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4824,6 +4824,11 @@ gensync@^1.0.0-beta.2:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==

get-caller-file@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==

get-caller-file@^2.0.1, get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
Expand Down Expand Up @@ -6191,13 +6196,6 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
version "1.0.0"
resolved "https://gist.github.com/0d0b8324131c80eeb7e1df20001be32f.git#3c19dec6061daff466b13783fea94c49e4f62e86"

json-to-zod@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/json-to-zod/-/json-to-zod-1.1.2.tgz#626d4432f329c51089120858c9404234567dda1b"
integrity sha512-6YDvnY8oOS5v1H1CWUvfNJkCI3SGbmCwWMytndPHzwyrr1K9ayNXL4rvOSf7WCy3c3Pxu2brvt4idZCkKh9gfQ==
dependencies:
prettier "^2.3.2"

json-ts@^1.6.4:
version "1.6.4"
resolved "https://registry.yarnpkg.com/json-ts/-/json-ts-1.6.4.tgz#e4423b8ccdb3069306f4727d6a579790675abbd0"
Expand Down Expand Up @@ -6654,6 +6652,13 @@ make-dir@^3.0.2:
dependencies:
semver "^6.0.0"

[email protected]:
version "1.1.2"
resolved "https://registry.yarnpkg.com/maketypes/-/maketypes-1.1.2.tgz#126b0dbf70301cffc02ce7895c10a17b0d5646a5"
integrity sha512-7JWq5PX9sMXI4s2XZFLHpLaWDd/QwPdE/FDT4EkuFXs5NdWDmJF0ogM+/2o7VQoPSWRnznEJZodFW6g/aF3pvw==
dependencies:
yargs "^6.5.0"

map-cache@^0.2.0, map-cache@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
Expand Down Expand Up @@ -8028,7 +8033,7 @@ prettier@^2.1.1, prettier@^2.2.0:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d"
integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==

prettier@^2.3.2, prettier@^2.4.1:
prettier@^2.4.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
Expand Down Expand Up @@ -9212,7 +9217,7 @@ [email protected]:
resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=

string-width@^1.0.1:
string-width@^1.0.1, string-width@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
Expand Down Expand Up @@ -10347,6 +10352,11 @@ which-boxed-primitive@^1.0.2:
is-string "^1.0.5"
is-symbol "^1.0.3"

which-module@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
integrity sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==

which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
Expand Down Expand Up @@ -10525,6 +10535,13 @@ yargs-parser@^20.2.2:
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==

yargs-parser@^4.2.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
integrity sha512-+QQWqC2xeL0N5/TE+TY6OGEqyNRM+g2/r712PDNYgiCdXYCApXf1vzfmDSLBxfGRwV+moTq/V8FnMI24JCm2Yg==
dependencies:
camelcase "^3.0.0"

yargs@^15.3.1:
version "15.4.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
Expand Down Expand Up @@ -10555,6 +10572,25 @@ yargs@^16.1.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"

yargs@^6.5.0:
version "6.6.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
integrity sha512-6/QWTdisjnu5UHUzQGst+UOEuEVwIzFVGBjq3jMTFNs5WJQsH/X6nMURSaScIdF5txylr1Ao9bvbWiKi2yXbwA==
dependencies:
camelcase "^3.0.0"
cliui "^3.2.0"
decamelize "^1.1.1"
get-caller-file "^1.0.1"
os-locale "^1.4.0"
read-pkg-up "^1.0.1"
require-directory "^2.1.1"
require-main-filename "^1.0.1"
set-blocking "^2.0.0"
string-width "^1.0.2"
which-module "^1.0.0"
y18n "^3.2.1"
yargs-parser "^4.2.0"

yargs@~4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-4.6.0.tgz#cb4050c0159bfb6bb649c0f4af550526a84619dc"
Expand Down