Coder Social home page Coder Social logo

json-schema-to-zod's People

Contributors

benmccann avatar dzakh avatar grimly avatar helgee avatar iamchandru6470 avatar lstrojny avatar mishrakrishnakant avatar navtoj avatar ncardoso-barracuda avatar stefanterdell avatar werifu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

json-schema-to-zod's Issues

Live demo and local copy of CLI behaves differently

Given this schema:

{
  "title": "PlanRequest",
  "type": "object",
  "properties": {
    "employees": {
      "title": "Employees",
      "type": "array",
      "items": {
        "$ref": "#/definitions/Employee"
      }
    },
    "shifts": {
      "title": "Shifts",
      "type": "array",
      "items": {
        "$ref": "#/definitions/Shift"
      }
    }
  },
  "required": [
    "employees",
    "shifts"
  ],
  "definitions": {
    "NumberRange": {
      "title": "NumberRange",
      "type": "object",
      "properties": {
        "min": {
          "title": "Min",
          "type": "number"
        },
        "max": {
          "title": "Max",
          "type": "number"
        }
      }
    },
    "TimeConstraints": {
      "title": "TimeConstraints",
      "type": "object",
      "properties": {
        "day": {
          "$ref": "#/definitions/NumberRange"
        },
        "week": {
          "$ref": "#/definitions/NumberRange"
        },
        "month": {
          "$ref": "#/definitions/NumberRange"
        }
      }
    },
    "Employee": {
      "title": "Employee",
      "type": "object",
      "properties": {
        "id": {
          "title": "Id",
          "type": "string"
        },
        "name": {
          "title": "Name",
          "type": "string"
        },
        "baseHourlyWage": {
          "title": "Basehourlywage",
          "type": "number"
        },
        "time_constraints": {
          "$ref": "#/definitions/TimeConstraints"
        },
        "roles": {
          "title": "Roles",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "required": [
        "id",
        "name",
        "baseHourlyWage"
      ]
    },
    "Shift": {
      "title": "Shift",
      "type": "object",
      "properties": {
        "id": {
          "title": "Id",
          "type": "string"
        },
        "start": {
          "title": "Start",
          "type": "string",
          "format": "date-time"
        },
        "end": {
          "title": "End",
          "type": "string",
          "format": "date-time"
        },
        "required_roles": {
          "title": "Required Roles",
          "default": [],
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "required": [
        "id",
        "start",
        "end"
      ]
    }
  }
}

The live demo gives me a usable schema with all the nested types parsed properly:

import { z } from "zod";

export default z.object({
  employees: z.array(
    z.object({
      id: z.string(),
      name: z.string(),
      baseHourlyWage: z.number(),
      time_constraints: z
        .object({
          day: z
            .object({ min: z.number().optional(), max: z.number().optional() })
            .optional(),
          week: z
            .object({ min: z.number().optional(), max: z.number().optional() })
            .optional(),
          month: z
            .object({ min: z.number().optional(), max: z.number().optional() })
            .optional(),
        })
        .optional(),
      roles: z.array(z.string()).optional(),
    })
  ),
  shifts: z.array(
    z.object({
      id: z.string(),
      start: z.string(),
      end: z.string(),
      required_roles: z.array(z.string()).optional(),
    })
  ),
});

But running the CLI locally returns the following schema:

import { z } from "zod";

export const schema = z.object({
  employees: z.array(z.any()),
  shifts: z.array(z.any()),
});

From looking through the code, I'm actually confused as to why the online version doesn't return the same schema as I get locally. Given that #1 exists, and the above schema uses $ref, and there is not a single mention of definitions anywhere in the code, I can't see how the online demo can work at all.

I've also traced the flow of execution in my local version, and it's essentially parseSchema -> parseSchema on all properties -> parseArray -> parseSchema on each item in array -> parseDefault because of ref.

Supported JsonSchema Versions

I have a JSONSchema4 object that I need to convert to Zod. The readme.md says draft JSONSchema4+ is supported, but when I try to convert my schema, I get the following error:

Argument of type 'JSONSchema4' is not assignable to parameter of type 'JSONSchema7'.

Indeed, as I see in the code only a JSONSchema7 type is allowed. Is there a way to convert a JSONSchema4 instance?

Getting unexpected zod schema as output

For the below JSON schema. I am getting unexpected zod schema as output.

{ "required": [ "entityIdentification" ], "properties": { "entityIdentification": { "maxLength": 80, "minLength": 1, "type": "string" }, "contentOwner": { "required": [ "gln" ], "properties": { "gln": { "pattern": "\\d{13}", "type": "string" }, "additionalPartyIdentification": { "oneOf": [ { "type": "object", "allOf": [ { "maxLength": 80, "minLength": 1, "type": "string" }, { "required": [ "content", "@additionalPartyIdentificationTypeCode", "@codeListVersion" ], "properties": { "content": { "type": "string" }, "@additionalPartyIdentificationTypeCode": { "enum": [ "BUYER_ASSIGNED_IDENTIFIER_FOR_A_PARTY", "CASHSSP", "CNPJ", "COMPANY_CAD", "DEA_DRUG_ENFORCEMENT_AGENCY", "DUNS", "DUNS_PLUS_FOUR", "EU_VAT_IDENTIFICATION_NUMBER", "FOR_INTERNAL_USE_1", "FOR_INTERNAL_USE_10", "FOR_INTERNAL_USE_11", "FOR_INTERNAL_USE_12", "FOR_INTERNAL_USE_13", "FOR_INTERNAL_USE_14", "FOR_INTERNAL_USE_15", "FOR_INTERNAL_USE_16", "FOR_INTERNAL_USE_17", "FOR_INTERNAL_USE_18", "FOR_INTERNAL_USE_19", "FOR_INTERNAL_USE_2", "FOR_INTERNAL_USE_20", "FOR_INTERNAL_USE_3", "FOR_INTERNAL_USE_4", "FOR_INTERNAL_USE_5", "FOR_INTERNAL_USE_6", "FOR_INTERNAL_USE_7", "FOR_INTERNAL_USE_8", "FOR_INTERNAL_USE_9", "HIN_CANADIAN_HEALTHCARE_IDENTIFICATION_NUMBER", "PARTITA_IVA", "SCAC", "SELLER_ASSIGNED_IDENTIFIER_FOR_A_PARTY", "SIRET", "SRN", "TD_LINK_TRADE_DIMENSIONS", "UCC_COMMUNICATION_IDENTIFICATION", "UN_LOCATION_CODE", "UNKNOWN", "USDA_ESTABLISHMENT_NUMBER" ], "type": "string" }, "@codeListVersion": { "maxLength": 35, "minLength": 1, "type": "string" } } } ] }, { "items": { "type": "object", "allOf": [ { "maxLength": 80, "minLength": 1, "type": "string" }, { "required": [ "content", "@additionalPartyIdentificationTypeCode", "@codeListVersion" ], "properties": { "content": { "type": "string" }, "@additionalPartyIdentificationTypeCode": { "enum": [ "BUYER_ASSIGNED_IDENTIFIER_FOR_A_PARTY", "CASHSSP", "CNPJ", "COMPANY_CAD", "DEA_DRUG_ENFORCEMENT_AGENCY", "DUNS", "DUNS_PLUS_FOUR", "EU_VAT_IDENTIFICATION_NUMBER", "FOR_INTERNAL_USE_1", "FOR_INTERNAL_USE_10", "FOR_INTERNAL_USE_11", "FOR_INTERNAL_USE_12", "FOR_INTERNAL_USE_13", "FOR_INTERNAL_USE_14", "FOR_INTERNAL_USE_15", "FOR_INTERNAL_USE_16", "FOR_INTERNAL_USE_17", "FOR_INTERNAL_USE_18", "FOR_INTERNAL_USE_19", "FOR_INTERNAL_USE_2", "FOR_INTERNAL_USE_20", "FOR_INTERNAL_USE_3", "FOR_INTERNAL_USE_4", "FOR_INTERNAL_USE_5", "FOR_INTERNAL_USE_6", "FOR_INTERNAL_USE_7", "FOR_INTERNAL_USE_8", "FOR_INTERNAL_USE_9", "HIN_CANADIAN_HEALTHCARE_IDENTIFICATION_NUMBER", "PARTITA_IVA", "SCAC", "SELLER_ASSIGNED_IDENTIFIER_FOR_A_PARTY", "SIRET", "SRN", "TD_LINK_TRADE_DIMENSIONS", "UCC_COMMUNICATION_IDENTIFICATION", "UN_LOCATION_CODE", "UNKNOWN", "USDA_ESTABLISHMENT_NUMBER" ], "type": "string" }, "@codeListVersion": { "maxLength": 35, "minLength": 1, "type": "string" } } } ] }, "type": "array" } ] } }, "type": "object" } }, "type": "object" }

`import { z } from "zod";

export default z.object({
entityIdentification: z.string().min(1).max(80),
contentOwner: z
.object({
gln: z.string().regex(new RegExp("\d{13}")),
additionalPartyIdentification: z
.any()
.superRefine((x, ctx) => {
const schemas = [z.record(z.any()), z.array(z.record(z.any()))];
const errors = schemas.reduce(
(errors: z.ZodError[], schema) =>
((result) =>
"error" in result ? [...errors, result.error] : errors)(
schema.safeParse(x)
),
[]
);
if (schemas.length - errors.length !== 1) {
ctx.addIssue({
path: ctx.path,
code: "invalid_union",
unionErrors: errors,
message: "Invalid input: Should pass single schema",
});
}
})
.optional(),
})
.optional(),
});`

Please help me with this.

Use mkdirp or equivalent when creating output directory

If you run json-schema-to-zod with -t set to a directory which doesn't exist yet, it will fail on writeFileSync

Failed to write result to ./src/__generated__/json/deadNotice.ts
Error: ENOENT: no such file or directory, open './src/__generated__/json/deadNotice.ts'
    at Object.openSync (node:fs:585:3)
    at writeFileSync (node:fs:2153:35)
    at Object.<anonymous> (/home/jakobo/code/taskless/monorepo/node_modules/.pnpm/[email protected]/node_modules/json-schema-to-zod/cli.js:98:36)

This can be worked around by creating the directory in advance using a tool such as shx, so it's a low priority bug relative to issues related to parsing / typing.

oneOf/allOf/anyOf not translating to zod equivalent

When working with oneOf/anyOf/allOf, I've noticed these are not translated back into zod. I tested these outputs against the online tool

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": [
    "projectId"
  ],
  "properties": {
    "projectId": {
      "type": "string",
      "format": "uuid"
    }
  },
  "oneOf": [
    {
      "type": "object",
      "properties": {
        "userId": {
          "type": "string",
          "format": "uuid"
        }
      },
      "required": [
        "userId"
      ]
    },
    {
      "type": "object",
      "properties": {
        "userIds": {
          "type": "array",
          "items": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "required": [
        "userIds"
      ]
    }
  ]
}

Expected (kind of subjective, as there's several ways in zod to express this):

import { z } from "zod";

export default z.object({ projectId: z.string().uuid() })
  .and(
    z.union([
      z.object({
        userIds: z.array(z.string().uuid()),
      }),
      z.object({
        userId: z.string().uuid(),
      }),
    ])
  );

Actual (didn't include the additional properties at all):

import { z } from "zod";

export default z.object({ projectId: z.string().uuid() });

Unable to generate zod from JSON schema

Following schema causes issues

{
  "properties": {
    "languageISOCode": {
      "type": "string",
      "description": "The language in which the provider details are provided. For example, a site supports two languages English and French. English being the primary language, the provider response will be provided in French depending on the user's locale. The language follows the two letter ISO code.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "favicon": {
      "type": "string",
      "description": "Favicon link of the provider.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "accountType": {
      "type": "array",
      "contains": {
        "type": "Enum"
      },
      "isReadOnly": true
    },
    "countryISOCode": {
      "type": "string",
      "description": "Country to which the provider belongs.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "isAddedByUser": {
      "type": "string",
      "description": "Indicates that the site has been added by the user at least once.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "PRIORITY": {
      "type": "Enum",
      "isReadOnly": true
    },
    "associatedProviderIds": {
      "type": "array",
      "contains": {
        "type": "number",
        "format": "int64"
      },
      "isReadOnly": true
    },
    "primaryLanguageISOCode": {
      "type": "string",
      "description": "The primary language of the site.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "help": {
      "type": "string",
      "description": "Text to guide user through linking an account that belongs to the site<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "baseUrl": {
      "type": "string",
      "description": "The base URL of the provider's site.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "capability": {
      "type": "array",
      "contains": {
        "type": "Capability"
      },
      "isReadOnly": true
    },
    "loginForm": {
      "type": "array",
      "contains": {
        "type": "LoginForm"
      },
      "isReadOnly": true
    },
    "isConsentRequired": {
      "type": "boolean",
      "description": "Indicates if a provider site requires consent.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "loginUrl": {
      "type": "string",
      "description": "The login URL of the provider's site.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "isAutoRefreshEnabled": {
      "type": "boolean",
      "description": "Indicates if a provider site is auto-refreshed.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "name": {
      "type": "string",
      "description": "The name of a provider site.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "logo": {
      "type": "string",
      "description": "The logo link of the provider institution. The link will return the logo in the PNG format.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "id": {
      "type": "number",
      "description": "Unique identifier for the provider site(e.g., financial institution sites, biller sites, lender sites, etc.).<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true,
      "format": "int64"
    },
    "lastModified": {
      "type": "string",
      "description": "Determines when the provider information was updated by Yodlee. If the customer caches the data, the cache is recommended to be refreshed based on this field.<br><br><b>Endpoints</b>:<ul><li>GET providers/{providerId}</li><li>GET providers</li></ul>",
      "isReadOnly": true
    },
    "authParameter": {
      "type": "array",
      "contains": {
        "type": "Enum"
      },
      "isReadOnly": true
    },
    "authType": {
      "type": "Enum",
      "isReadOnly": true
    },
    "dataset": {
      "type": "array",
      "contains": {
        "type": "ProvidersDataset"
      },
      "isReadOnly": true
    },
    "status": {
      "type": "Enum",
      "isReadOnly": true
    }
  }
}

It generates into zod type any

Add 1-2 more complicated examples to `README.md`

The existing example in the readme is sufficient to get a general idea, but doesn't really show the full extent of what this is capable from. I think this library could benefit from introducing more examples, and maybe even setting up an examples/ directory if someone wants to go overboard on this.

This outputs returns a string, how can I use this with Zod to parse?

I'm trying to do the following

const parsed = parseSchema(schema)
parsed.parse(lonenModel)

But this just returns a string

z.object({"id":z.number().int(),"klant_id":z.union([z.string(),z.null()]).optional(),"lgrp_id":z.union([z.string(),z.null()]).optional(),"wgnr_id":z.union([z.string(),z.null()]).optional(),"klant_naam":z.union([z.string(),z.null()]).optional(),"datum_afdruk":z.union([z.string(),z.null()]).optional(),"tijd_afdruk":z.union([z.string(),z.null()]).optional(),"extensie":z.union([z.string(),z.null()]).optional(),"kopies":z.union([z.string(),z.null()]).optional(),"extra-info":z.union([z.string(),z.null()]).optional(),"opdrachtnr":z.union([z.string(),z.null()]).optional(),"EfichesPdfPcl":z.union([z.string(),z.null()]).optional()})

No support Native enums

Thank you for the awesome library!
I want an Native enums option.

e.g.

input schema

{
	"type": "object",
	"properties": {
		"testType": {
			"type": "number",
			"enum": [
				1,
				2
			]
		}
	}
}

output

import { z } from "zod";

export default z.object({ testType: z.enum([1, 2]).optional() });

Zod enums only support string types, so you will get an error.

expected results

import { z } from "zod";

const testType = {
  NUMBER_1: 1,
  NUMBER_2: 2,
} as const;

export default z.object({ testType: z.nativeEnum(testType).optional() });

Fails to parse JSON Schema from Google

Unable to convert JSONSchemas from googleapis repository

Description

I am trying to batch process the json schema from Google's source:

Example source

https://github.com/googleapis/google-cloudevents/blob/main/jsonschema/google/events/cloud/apigateway/v1/GatewayEventData.json

Problem output

This only generates the following:

import { z } from "zod";

export default z.any();

Example JSON (from link above)

{
  "$id": "https://googleapis.github.io/google-cloudevents/jsonschema/google/events/cloud/apigateway/v1/GatewayEventData.json",
  "name": "GatewayEventData",
  "examples": [],
  "package": "google.events.cloud.apigateway.v1",
  "datatype": "google.events.cloud.apigateway.v1.GatewayEventData",
  "cloudeventTypes": [
    "google.cloud.apigateway.gateway.v1.created",
    "google.cloud.apigateway.gateway.v1.updated",
    "google.cloud.apigateway.gateway.v1.deleted"
  ],
  "product": "API Gateway",
  "$schema": "http://json-schema.org/draft-04/schema#",
  "$ref": "#/definitions/GatewayEventData",
  "definitions": {
    "GatewayEventData": {
      "properties": {
        "payload": {
          "$ref": "#/definitions/Gateway",
          "additionalProperties": true,
          "description": "Optional. The Gateway event payload. Unset for deletion events."
        }
      },
      "additionalProperties": true,
      "type": "object",
      "title": "Gateway Event Data",
      "description": "The data within all Gateway events."
    },
    "Gateway": {
      "properties": {
        "name": {
          "type": "string",
          "description": "Output only. Resource name of the Gateway. Format: projects/{project}/locations/{location}/gateways/{gateway}"
        },
        "createTime": {
          "type": "string",
          "description": "Output only. Created time.",
          "format": "date-time"
        },
        "updateTime": {
          "type": "string",
          "description": "Output only. Updated time.",
          "format": "date-time"
        },
        "labels": {
          "additionalProperties": {
            "type": "string"
          },
          "type": "object",
          "description": "Optional. Resource labels to represent user-provided metadata. Refer to cloud documentation on labels for more details. https://cloud.google.com/compute/docs/labeling-resources"
        },
        "displayName": {
          "type": "string",
          "description": "Optional. Display name."
        },
        "apiConfig": {
          "type": "string",
          "description": "Required. Resource name of the API Config for this Gateway. Format: projects/{project}/locations/global/apis/{api}/configs/{apiConfig}"
        },
        "state": {
          "enum": [
            "STATE_UNSPECIFIED",
            0,
            "CREATING",
            1,
            "ACTIVE",
            2,
            "FAILED",
            3,
            "DELETING",
            4,
            "UPDATING",
            5
          ],
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "integer"
            }
          ],
          "title": "State",
          "description": "All the possible Gateway states."
        },
        "defaultHostname": {
          "type": "string",
          "description": "Output only. The default API Gateway host name of the form `{gateway_id}-{hash}.{region_code}.gateway.dev`."
        }
      },
      "additionalProperties": true,
      "type": "object",
      "title": "Gateway",
      "description": "A Gateway is an API-aware HTTP proxy. It performs API-Method and/or API-Consumer specific actions based on an API Config such as authentication, policy enforcement, and backend selection."
    }
  }
}

Question: How to use at runtime?

Great package, but I was wondering how I can use this library at runtime, because the output will be a string instead of the zod object structure.

We have an endpoint that returns the json schema and I would like to convert the schema runtime to zod.

Thanks in advance

How is zod refine supported

const { z } = require('zod');
const {
  jsonSchemaToZod,
  jsonSchemaToZodDereffed,
  parseSchema,
} = require('json-schema-to-zod');

const myObject = {
  type: 'object',
  properties: {
    custom: {
      type: 'custom',
    },
  }
};

const custom = z
  .string()
  .email()
  .refine(
    data => {
      return data;
    },
    {
      message: "Passwords don't match",
    }
  )
  .optional();

// z.object({"custom":custom})
const schema = parseSchema(myObject);

const fn = new Function('z', 'custom', `return ${schema}`);

const instance = fn(z,custom);

Schema including `patternProperties` resulting in `z.any()`

When processing the compose spec schema (available from https://raw.githubusercontent.com/compose-spec/compose-spec/master/schema/compose-spec.json) all top-level object values will be of type z.any(). The validator will output rich types if we remove patternProperties from the schema.
If I'm not mistaken, we should, however, be able to handle patternProperties by using a z.record(keyType, valueType) (https://github.com/colinhacks/zod#record-key-type).

Why JSON schema keys are misinterpreted?

Is it intended or it's a bug (or a feature)? Or maybe I am missing something? Let's say we have the following input JSON schema:

{
  "$schema": "http://json-schema.org/draft-07/schema",
  "title": "config",
  "description": "~/.bashrc config",
  "definitions": {
    "color": {
      "type": "string",
      "enum": [
        "none",
        "black",
        "red",
        "green",
        "yellow",
        "blue",
        "magenta",
        "cyan",
        "light-gray",
        "gray",
        "light-red",
        "light-green",
        "light-yellow",
        "light-blue",
        "light-magenta",
        "light-cyan",
        "white"
      ]
    }
  },
  "type": "object",
  "properties": {
    "messages": {
      "title": "messages settings",
      "description": "Message's settings",
      "type": "object",
      "properties": {
        "info": {
          "title": "info settings",
          "description": "Info settings",
          "type": "object",
          "properties": {
            "foreground": {
              "description": "An info foreground color",
              "$ref": "#/definitions/color"
            },
            "background": {
              "description": "An info background color",
              "$ref": "#/definitions/color"
            }
          },
          "additionalProperties": false
        },
        "warn": {
          "title": "warning settings",
          "description": "Warning settings",
          "type": "object",
          "properties": {
            "foreground": {
              "description": "A warning foreground color",
              "$ref": "#/definitions/color"
            },
            "background": {
              "description": "A warning background color",
              "$ref": "#/definitions/color"
            }
          },
          "additionalProperties": false
        },
        "error": {
          "title": "error settings",
          "description": "Error settings",
          "type": "object",
          "properties": {
            "foreground": {
              "description": "An error foreground color",
              "$ref": "#/definitions/color"
            },
            "background": {
              "description": "An error background color",
              "$ref": "#/definitions/color"
            }
          },
          "additionalProperties": false
        }
      },
      "additionalProperties": false
    },
    "prompt": {
      "title": "prompt settings",
      "description": "Prompt's settings",
      "type": "object",
      "properties": {
        "format": {
          "title": "format settings",
          "description": "Format settings",
          "type": "array",
          "uniqueItems": true,
          "items": {
            "type": "object",
            "properties": {
              "show": {
                "description": "Whether to show an item",
                "type": "boolean",
                "default": true
              },
              "kind": {
                "description": "A kind of an item",
                "type": "string",
                "enum": [
                  "current-time",
                  "current-device-name",
                  "current-user-name",
                  "current-path",
                  "last-command-status"
                ]
              },
              "colors": {
                "title": "item color settings",
                "description": "Item color settings",
                "type": "object",
                "properties": {
                  "foreground": {
                    "description": "An item foreground color",
                    "$ref": "#/definitions/color",
                    "default": "black"
                  },
                  "background": {
                    "description": "An item background color",
                    "$ref": "#/definitions/color",
                    "default": "white"
                  }
                },
                "additionalProperties": false
              },
              "format": {
                "type": "string",
                "default": "[%s]"
              }
            },
            "required": ["kind"],
            "additionalProperties": false
          }
        }
      },
      "additionalProperties": false
    }
  },
  "additionalProperties": false
}

but it is being converted as:

const schema = z.object({
  $schema: z.string(),
  title: z.string(),
  description: z.string(),
  definitions: z.object({ // I am not sure about it but I guess that `definitions` should be inlined where they are used.
    color: z.object({ type: z.string(), enum: z.array(z.string()) }), // `type`, `enum` are not keys themselves in JSON schemas, they are restrictions applied to surrounding property (in this case to `color`).
  }),
  type: z.string(),
  properties: z.object({
    messages: z.object({
      title: z.string(),
      description: z.string(),
      type: z.string(),
      properties: z.object({
        info: z.object({
          title: z.string(),
          description: z.string(),
          type: z.string(),
          properties: z.object({
            foreground: z.object({ description: z.string(), $ref: z.string() }),
            background: z.object({ description: z.string(), $ref: z.string() }),
          }),
          additionalProperties: z.boolean(), // Again, it's not a key available to the end user, it's a constraint telling that no other properties are allowed except `foreground` and `background` here.
        }),
        warn: z.object({
          title: z.string(),
          description: z.string(),
          type: z.string(),
          properties: z.object({
            foreground: z.object({ description: z.string(), $ref: z.string() }),
            background: z.object({ description: z.string(), $ref: z.string() }),
          }),
          additionalProperties: z.boolean(),
        }),
        error: z.object({
          title: z.string(),
          description: z.string(),
          type: z.string(),
          properties: z.object({
            foreground: z.object({ description: z.string(), $ref: z.string() }),
            background: z.object({ description: z.string(), $ref: z.string() }),
          }),
          additionalProperties: z.boolean(),
        }),
      }),
      additionalProperties: z.boolean(),
    }),
    prompt: z.object({
      title: z.string(),
      description: z.string(),
      type: z.string(),
      properties: z.object({
        format: z.object({
          title: z.string(),
          description: z.string(),
          type: z.string(),
          uniqueItems: z.boolean(),
          items: z.object({
            type: z.string(),
            properties: z.object({
              show: z.object({
                description: z.string(),
                type: z.string(),
                default: z.boolean(),
              }),
              kind: z.object({
                description: z.string(),
                type: z.string(),
                enum: z.array(z.string()),
              }),
              colors: z.object({
                title: z.string(),
                description: z.string(),
                type: z.string(),
                properties: z.object({
                  foreground: z.object({
                    description: z.string(),
                    $ref: z.string(),
                    default: z.string(),
                  }),
                  background: z.object({
                    description: z.string(),
                    $ref: z.string(),
                    default: z.string(),
                  }),
                }),
                additionalProperties: z.boolean(),
              }),
              format: z.object({ type: z.string(), default: z.string() }),
            }),
            required: z.array(z.string()),
            additionalProperties: z.boolean(),
          }),
        }),
      }),
      additionalProperties: z.boolean(),
    }),
  }),
  additionalProperties: z.boolean(),
});

Maybe my expectations are wrong but when I hear JSON schema -> smth conversion I expect correct interpretation of JSON schema according to the specified draft (7 in this case). If there is already some tool that does what I expect please tell me it's name.

How to take output Schema string and parse something with it?

I have this library successfully converting the json schema to a stringified representation of a Zod schema, but am at a loss on how to actually parse something with it. I'm trying to dynamically take a JSON Schema via payload argument, convert it to Zod, and use it to validate all in one web request.

My first thought would be something like eval, but that doesn't seem great from a security standpoint.

const keyword ignored when falsey

Given this JSON Schema:

{
  type: "object",
  properties: {
    s: {
      type: "string",
      const: ""
    }
  }
}

This result is expected (z.literal("")):

import { z } from "zod";

export default z.object({ s: z.literal("").optional() });

However the actual result is (z.string()):

import { z } from "zod";

export default z.object({ s: z.string().optional() });

It seems json-schema-to-zod outputs the incorrect result because the string literal "" is falsey. It seems this is a problem for all falsey values.

Generating zod schema at runtime

The output here appears to be a string defining Zod schema, however I don't always know the JSONschema I am getting ahead of time and it would be incredibly useful to be able to get a zod schema at runtime rather than a string that needs to be put into a file at compile time.

Unclear behavior on what happens if an invalid schema is provided

Could use improved documentation on this scenario. Is an error thrown? Is a z.any() schema output, as implied by this issue and a quick test I just ran?

My use case is that I'm trying to allow consumers of my API to specify a JSON schema as part of their payload, which I then parse with this library and use it to parse something before I return it to them.

add missing IP addresses string validations

Hello Stefan, first of all congrats for your really helpful lib!

It would be great to add the missing string format validations that are part of JSON format assertion vocabulary, maybe starting from the ones that maps easily with zod assertions, such as IP Addresses validations.

That could only require a small change to src/parsers/parseString.ts module:

import { JSONSchema7 } from "json-schema";

export const parseString = (schema: JSONSchema7 & { type: "string" }) => {
  let r = "z.string()";
  if (schema.pattern)
    r += `.regex(new RegExp(${JSON.stringify(schema.pattern)}))`;
  if (schema.format === "email") r += ".email()";
+  if (schema.format === "ip") r += ".ip()";
+  if (schema.format === "ipv4") r += ".ip({ version: "v4" })";
+  if (schema.format === "ipv6") r += ".ip({ version: "v6" })";
  else if (schema.format === "uri") r += ".url()";
  else if (schema.format === "uuid") r += ".uuid()";
  else if (schema.format === "date-time") r += ".datetime()";
  if (typeof schema.minLength === "number") r += `.min(${schema.minLength})`;
  if (typeof schema.maxLength === "number") r += `.max(${schema.maxLength})`;
  return r;
};

Thank you!

Would you consider a change to make the code generation interface generic?

Hello! Thank you for your hard work on this, it's a really great tool.

I'm interested in doing something very similar for generating io-ts codecs and have been fiddling with modifying the parse*.ts files to support generic code generation implementations, e.g. a user could choose between zod, io-ts, or any other option as long as they can conform to the required implementation interface.

Would you consider a pull request with this change or does it go too far outside the relevant scope?

fails when required is used

JSON schema:

  type:       object
  properties:
    id:
      type:     integer
      required: true
    username:
      type:     string
      required: true
    status:
      type:     string
      required: true
  required:   true

Error:

/Users/gajus/Documents/dev/contra/contra-api/node_modules/json-schema-to-zod/parsers/parseObject.js:15
            return `${JSON.stringify(k)}:${(0, parseSchema_1.parseSchema)(v)}${((_a = schema.required) === null || _a === void 0 ? void 0 : _a.includes(k)) ? requiredFlag : ".optional()"}`;
                                                                                                                                               ^

TypeError: _a2.includes is not a function
    at <anonymous> (/Users/gajus/Documents/dev/contra/contra-api/node_modules/json-schema-to-zod/parsers/parseObject.js:15:144)
    at Array.map (<anonymous>)
    at parseObject (/Users/gajus/Documents/dev/contra/contra-api/node_modules/json-schema-to-zod/parsers/parseObject.js:13:149)
    at selectParser (/Users/gajus/Documents/dev/contra/contra-api/node_modules/json-schema-to-zod/parsers/parseSchema.js:34:34)
    at parseSchema (/Users/gajus/Documents/dev/contra/contra-api/node_modules/json-schema-to-zod/parsers/parseSchema.js:22:18)
    at jsonSchemaToZod (/Users/gajus/Documents/dev/contra/contra-api/node_modules/json-schema-to-zod/jsonSchemaToZod.js:14:217)
    at <anonymous> (/Users/gajus/Documents/dev/contra/contra-api/src/bin/generate-zod.ts:45:15)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Reach a decent level of test coverage

The API is stable enough to release major 1, but before that happens we need to have a decent level of tests. I've added a basic jest setup and added a single test to set the pattern, but I have very limited time to work on this myself, so feel free to add to it. Please reference this issue in your PRs. Once this issue has been resolved I will consider releasing 1.0.0.

allOf is not converted properly

There is some issue with 'allOf'

Schema:
"someProperty": { "description": "ABCD", "type": "object", "allOf": [ { "type": "object", "properties": { "entryId": { "description": "id", "type": "string", "example": "VYP3" }, ... }, "required": ["entryId"] }, { "type": "object", "properties": { "otherValues": { "type": "array", "items": { "type": "object", "properties": {...}, "required": ["value", "key"] } }, ... } } ], },

Result:
someProperty: z.record(z.any()).describe("ABCD").optional(),

I probably find where the problem is. It is in 'selectParser' function, where code goes to isObject way and 'allOf' else if is not hit at all.

No support for $ref

Hi, I appreciate the simplicity of this library. But without support for resolving $ref's, it makes it quite limited for anything other than simple schemas. Have you considered adding support for $ref?

Thanks :)

TypeScript errors for 'Programmatic' example in README.md: is not assignable to parameter of type 'JSONSchema7'

I just installed this package, and pasted the example code from README.md into a .ts file in my project:

import {
  jsonSchemaToZod,
  jsonSchemaToZodDereffed,
  parseSchema,
} from "json-schema-to-zod";

const myObject = {
  type: "object",
  properties: {
    hello: {
      type: "string",
    },
  },
};
const module = jsonSchemaToZod(myObject);
const dereffed = await jsonSchemaToZodDereffed(myObject);
const schema = parseSchema(myObject);

The last 3 lines all give TS errors:

Argument of type '{ type: string; properties: { hello: { type: string; }; }; }' is not assignable to parameter of type 'JSONSchema7'.
  Types of property 'type' are incompatible.
    Type 'string' is not assignable to type 'JSONSchema7TypeName | JSONSchema7TypeName[] | undefined'.

Argument of type '{ type: string; properties: { hello: { type: string; }; }; }' is not assignable to parameter of type 'JSONSchema7'.

Argument of type '{ type: string; properties: { hello: { type: string; }; }; }' is not assignable to parameter of type 'boolean | JSONSchema7'.
  Type '{ type: string; properties: { hello: { type: string; }; }; }' is not assignable to type 'JSONSchema7'.

It works ok at runtime though.

I also tried on something larger, i.e. replaced const myObject = {...}` value with this schema. ... same thing.

Conversion of schema results in z.any() with CLI, but a correct schema on demo site

Hello,

I'm having an issue converting a relatively simple JSON schema using the CLI, however the same schema gets converted correctly on the demo site.

I've condensed the schema down to a minimum failing example, which you can find below:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$ref": "#/definitions/Bestiary",
  "definitions": {
    "Bestiary": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        }
      },
      "required": ["name"]
    }
  }
}

This results in an output of export const schema = z.any();

It's quite possible that i'm missing something, but using simple object based schemas that don't use $ref and definitions seems to work fine on the CLI.

Problem parsing FHIR schema

Hi,

Great project!

I'm trying to parse the FHIR JSON schema (attached fhir.schema.zip)

But the output is much smaller than anticpiated.
I'm very new to Zod and FHIR so I'm sure this is user error... but the results of jsonSchemaToZod is "just":

    import { z } from "zod";
    
    export default z
      .any()
      .superRefine((x, ctx) => {
        const schemas = [
          z.any(),
          z.any(),
          // ...
        ];
        const errors = schemas.reduce(
          (errors: z.ZodError[], schema) =>
            ((result) => ("error" in result ? [...errors, result.error] : errors))(
              schema.safeParse(x)
            ),
          []
        );
        if (schemas.length - errors.length !== 1) {
          ctx.addIssue({
            path: ctx.path,
            code: "invalid_union",
            unionErrors: errors,
            message: "Invalid input: Should pass single schema",
          });
        }
      })
      .describe(
        "see http://hl7.org/fhir/json.html#schema for information about the FHIR Json Schemas"
      );
  • I had expected this to be a monster? ๐Ÿ˜„

Any help gratefully received.
Thanks again for a great project.

Support strict option for zod object

Consider the following type DateRangeExtended:

type DateRange = { from?: number; to?: number };

enum DateRangeType  {
  today = 1,
  yesterday = 2,
  tomorrow = 3
}

export type DateRangeExtended = DateRange | { type: DateRangeType };

The generated zod schema:

import { z } from "zod";

export default z
  .union([
    z
      .object({
        from: z.number().optional(),
        to: z.number().optional(),
      })
      .catchall(z.never()),
    z
      .object({
        type: z.union([
          z.literal(1),
          z.literal(2),
          z.literal(3)
        ]),
      })
      .catchall(z.never()),
  ])

Now when the data is parsed I get an empty object because DateRange allows empty properties and other properties are not prohibited by generated schema:

const result = schema.safeParse({ type: 1 });
if (result.success) {
  console.log(result.data); // => { }
}

It would be useful if this library supported strict option.

parseSchema requires second "Refs" argument?

Hi, I'm trying to update to 1.0+, and my code has something like this:

import { parseSchema } from 'json-schema-to-zod';

// ...

// Convert to Zod
const zodSchema = parseSchema(jsonSchema);

As of 1.0.0, I'm seeing a type error that parseSchema requires a second argument.

In the README in the repo here, the sample code seems to just call parseSchema with only one argument. Do you have a code sample for how to pass the refs argument? Or, is it possible to make it so that parseSchema can be called with no arguments?

Let me know if I can help!

`"nullable": true` not parsed

First, thank you for this library!

Currently, "nullable": true is not parsed, even though there is z.nullable() in zod.

I know we can represent null in Json-Schema using a primitive value (similar to javascript) such as:
"type": ["string", "null"].

Example:

input:

{
    "properties": {
        "name": {
            "type": ["string", "null"]
        },
        "surname": {
            "type": "string",
            "nullable": true,
        },
    },
    "required": ["name", "surname"],
    "title": "Person",
    "type": "object"
}

output:

const schema = z.object({
  name: z.union([z.string(), z.null()]),
  surname: z.string(),
});

But my use-case is that an OpenAPI backend is generating the Json-schemas for the payloads I get in the front-end.

And, from my understanding, OpenAPI happens to consider null as a value, and not a type.
So it generates Json-Schemas with this "nullable" field, which features in their "extended subset of JSON Schema Specification".

I'm still learning Typescript, but I think json-schema-to-zod currently uses JSONSchema7 coming from @types/json-schema, which does not mention this "nullable" field.

I'm not sure how I should go about that.

How to use zod string?

I've reviewed other posts on the same issue, but am unable to convert / eval the string zod schema.

  • const zod_schema = eval(parseSchema(schema)) ; results in ReferenceError: z is not defined I also tried:
const import_z = 'import {  z } from "zod";'
const combined = import_z + parseSchema(schema);

This resulted in the same error.

  • const zod_schema = eval(jsonSchemaToZod(schema)) ; results in SyntaxError: Cannot use import statement outside a module

Error Messages are Missing in Zod Schema after conversion

  • while converting json schema to zod schema the error messages are missing in it

JSON Schema

{
"type": "object",
"properties": {
"myString": {
"type": "string",
"minLength": 5,
"errorMessage": {
"minLength": "Minimum 5 required"
}
},
"myUnion": {
"type": [
"number",
"boolean"
]
}
},
"required": [
"myString",
"myUnion"
],
"additionalProperties": false,
"description": "My neat object schema",
"$schema": "http://json-schema.org/draft-07/schema#"
}

ZOD Schema after conversion

z
.object({
myString: z.string().min(5),
myUnion: z.union([z.number(), z.boolean()]),
})
.catchall(z.never())
.describe("My neat object schema");

Difficult to import in browser due to dependencies using node built-in modules like process.

Would it be possible to remove the dependencies that use node built-in modules like process?

Simply importing json-schema-to-zod results in an error:

ReferenceError: process is not defined
    at node_modules/.pnpm/@[email protected]/node_modules/@apidevtools/json-schema-ref-parser/lib/util/url.js (url.js:3:29)
    at __require (chunk-J43GMYXM.js?v=f53e2eac:11:50)
    at node_modules/.pnpm/@[email protected]/node_modules/@apidevtools/json-schema-ref-parser/lib/pointer.js (pointer.js:6:13)
    at __require (chunk-J43GMYXM.js?v=f53e2eac:11:50)
    at node_modules/.pnpm/@[email protected]/node_modules/@apidevtools/json-schema-ref-parser/lib/ref.js (ref.js:5:17)
    at __require (chunk-J43GMYXM.js?v=f53e2eac:11:50)
    at node_modules/.pnpm/@[email protected]/node_modules/@apidevtools/json-schema-ref-parser/lib/refs.js (refs.js:4:14)
    at __require (chunk-J43GMYXM.js?v=f53e2eac:11:50)
    at node_modules/.pnpm/@[email protected]/node_modules/@apidevtools/json-schema-ref-parser/lib/index.js (index.js:4:15)
    at __require (chunk-J43GMYXM.js?v=f53e2eac:11:50)

This is because some dependency is checking the platform via process:

// url.js
let isWindows = /^win/.test(process.platform),

I was able to get json-schema-to-zod working in Parcel via its node emulation, but it required some extra steps: parcel-bundler/parcel#7697 (comment)

I was unable to get similar node emulation working in SvelteKit/Vite. Perhaps because the dependencies don't explicitly import process so Parcel is doing some extra magic.

I am curious how the online demo (https://stefanterdell.github.io/json-schema-to-zod-react/) does not result in the same error. Does this also use node emulation, or was it built with versions of dependencies that didn't use process?

Broken install of CLI on Mac when using Yarn

Prefacing this by making it clear that i'm aware on your docs you provide the command with NPM and not Yarn but I feel like many people will have a preference and will try to do it with Yarn regardless.

When installing the package via yarn global add json-schema-to-zod and attempting to run any associated command with it I get an error env: node\r: No such file or directory. This is due to the fact that NPM auto converts line endings but Yarn does not and requires a bit of help.

The fix for this was to use npx to convert after install like so npx crlf --set=LF /path/to/json-schema-to-zod

Input types not same as AJV

Hi @StefanTerdell,

Unfortunately, mine is just a suggestion -- I don't have the bandwidth currently to open a PR (sorry about this).

However, when trying out the package today, I noticed that I'm getting a TS error when providing the JSON schema that ajv accepts & compiles correctly.
Reproduction here.

So I'm wondering if accepting ajv's input types for the schema could be part of the work you suggested above.

Originally posted by @p6l-richard in #2 (comment)

additionalProperties: false breaks types

Hey there,
I think since version 1.0.0 an object with additionalProperties: false will generate a schema which sets .catchall(z.never()) on the object.

When inferring the TS type from the schema this turns into a union type like this:

type SchemaType = {
    myString: string;
    myUnion: number | boolean;
} & {
    [k: string]: never;
}

which then leads to the following error when using this type:

Type '{ myString: string; myUnion: true; }' is not assignable to type 'objectOutputType<{ myString: ZodString; myUnion: ZodUnion<[ZodNumber, ZodBoolean]>; }, ZodNever, "strip">'.
  Type '{ myString: string; myUnion: true; }' is not assignable to type '{ [k: string]: never; }'.
    Property 'myString' is incompatible with index signature.
      Type 'string' is not assignable to type 'never'.ts(2322)

Previously the object would be marked as .strict() which worked perfectly fine.

Is this expected behavior and I'm holding it wrong? ๐Ÿ˜„ Or is it a bug?

Example

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$ref": "#/definitions/mySchema",
  "definitions": {
    "mySchema": {
      "description": "My neat object schema",
      "type": "object",
      "properties": {
        "myString": {
          "type": "string",
          "minLength": 5
        },
        "myUnion": {
          "type": ["number", "boolean"]
        }
      },
      "additionalProperties": false,
      "required": ["myString", "myUnion"]
    }
  }
}
import { z } from 'zod';

const schema = z
  .object({
    myString: z.string().min(5),
    myUnion: z.union([z.number(), z.boolean()]),
  })
  .catchall(z.never())
  .describe('My neat object schema');

type SchemaType = z.infer<typeof schema>;

const obj: SchemaType = {
  myString: 'asdfs',
  myUnion: true,
};

invalid default value codegen

I compiled a zod validator from a json schema using roughly this snippet:

import jsonSchemaToZod from "json-schema-to-zod";

const schema = await import("schema.json");
const asZod = jsonSchemaToZod(schema);
await writeFile("output.ts");

here's a gist with the 2 other files (for brevity in this issue description) https://gist.github.com/cdmistman/c73e1c66ee02e21235bac109c1a354ce

note that the generated default value is invalid; typescript returns the following error:

output.ts:7:5 - error TS2769: No overload matches this call.
  Overload 2 of 2, '(def: () => objectInputType<{ insert: ZodObject<{ string: ZodString; }, "strip", ZodTypeAny, { string: string; }, { string: string; }>; }, ZodNever, "strip">): ZodDefault<...>', gave the following error.
    Argument of type '{ $schema: string; title: string; oneOf: { type: string; required: string[]; properties: { insert: { type: string; required: string[]; properties: { string: { type: string; }; }; }; }; additionalProperties: boolean; }[]; }' is not assignable to parameter of type '() => objectInputType<{ insert: ZodObject<{ string: ZodString; }, "strip", ZodTypeAny, { string: string; }, { string: string; }>; }, ZodNever, "strip">'.
      Object literal may only specify known properties, and '$schema' does not exist in type '() => objectInputType<{ insert: ZodObject<{ string: ZodString; }, "strip", ZodTypeAny, { string: string; }, { string: string; }>; }, ZodNever, "strip">'.

7     $schema: "http://json-schema.org/draft-07/schema#",
      ~~~~~~~

i'd at least expect an error if a valid default value can be generated! it would also be nice to report in the error that withoutDefaults: true should be passed as an option to jsonSchemaToZod

CLI executable isn't being found

Trying to run the CLI tool, but the command isn't being found.

CleanShot 2022-11-18 at 10 34 53@2x

Looked at the package.json, it's pointing to ./cli.js, but maybe it needs to look at ./src/cli.js?

Running the CLI directly from node_modules works.

CleanShot 2022-11-18 at 10 36 30@2x

Add an option to customize the parsing and output

It would be helpful to be able to customize parsing when needed, i.e. to allow coercing strings to numbers or other less standard behaviour.

My initial PR was reject but I'm happy to rework this if there's an interface you would be open to.
#39

package.json schema doesn't work

I'm trying to create a schema based on the package.json schema, and it has some problems.

The online demo gives InternalError: too much recursion.

Running the cli on it with no "--deref" isn't useful, since it gives things like dependencies: z.any() when it should be a z.object() or z.record().

Running the cli on it with "--deref" gives RangeError: Maximum call stack size exceeded

Web Demo Broken

When trying to interact with the web demo, it seems like it may have broken with the new version?

It still accepts a json, but the zod type is never generated as a result.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.