Giter Site home page Giter Site logo

vitalics / ajv-ts Goto Github PK

View Code? Open in Web Editor NEW
39.0 2.0 1.0 380 KB

First-class ajv typescript JSON-schema builder inspired from Zod

Home Page: https://www.npmjs.com/package/ajv-ts

License: MIT License

TypeScript 100.00%
ajv ajv-validation builder jsonschema typescript

ajv-ts's Introduction

Hi there ๐Ÿ‘‹

Vitali Haradkou GitHub stats

I am Vitali Haradkou

I'm SDET, Passions about Frontend.

Certified Node.js Application Developer (JSNAD)

I love โค๏ธ TypeScript. Master's degree in Typescript and recursive types.

Check out my recent blog posts:

Tech Stack

JavaScript, TypeScript, Node.js, Selenium, Webdriver, WebdriverIO, Playwright, Puppeteer, TestCafe, Docker, Containers, AWS, Azure DevOps, Git

ajv-ts's People

Contributors

github-actions[bot] avatar vitalics 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

Watchers

 avatar  avatar

Forkers

teploniweta

ajv-ts's Issues

Zod Progress

As a part of this issue, we need to propose a way to compatibility of zod API.

issue motivated from #32

here is a list of features that zod has:

  • superRefine
  • #54
  • void, undefined, function, Set, Map, NaN - possibly it's never be released, since it is not a part of JSON-schema standard - expose empty functions?
  • custom types (aka, z.custom)
  • #41
  • expose date as string().date()
  • z.string - datetime, it's parameters
  • #38
  • #43
  • s.deepPartial need to research
  • z.strip
  • z.catchall
  • #46
  • z.nullish - research
  • z.lazy - need to research
  • expose transform function
  • expose z.ZodType<T> type
  • z.promise - uses $async schema?
  • z.instanceOf - research
  • z.preprocess port to s.preprocess
  • expose z.parseAsync
  • refine compatibility
  • expose z.catch
  • expose z.brand
  • expose z.pipe

Add comments if I missed something

Merge is not like for like with Zod

Describe the bug
I was just trying this as an alternative to Zod, but the merge schema method isn't working in like for like fashion. Am I missing something?

To Reproduce
Clone the repo at https://github.com/thoroc/zod-is-dead

Expected behavior
All test passess

Desktop (please complete the following information):

  • JS runtime Nodejs
  • Version v20.11.0

Additional context
I have put some log output to see what's the object on the Ajv truck in the example and this is what I get:

Vehicle Schema

export const AjvVehicleSchema = s.object({
  make: s.string(),
  model: s.string(),
  year: s.number(),
});

export type AjvVehicle = s.infer<typeof AjvVehicleSchema>;

Truck Schema

export const AjvTruckSchema = s
  .object({
    commercialCapacity: s.number(),
    forwardCabin: s.boolean(),
    wheels: s.number(),
  })
  .merge(AjvVehicleSchema);

export type AjvTruck = s.infer<typeof AjvTruckSchema>;

Truck instance

{
  make: 'Bugatti',
  model: 'Model T',
  year: 2020,
  commercialCapacity: 1000,
  forwardCabin: true,
  wheels: 4
}

AjvTruckSchema.schema

{
  type: 'object',
  properties: {
    commercialCapacity: { type: 'number' },
    forwardCabin: { type: 'boolean' },
    wheels: { type: 'number' },
    type: undefined,
    properties: undefined
  }
}

Couldn't Install Package because of Typescript Version

Describe the bug
npm install ajv-ts didn't succeed.

npm install ajv-ts
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: hyperbola-investor@undefined
npm ERR! Found: [email protected]
npm ERR! node_modules/typescript
npm ERR!   dev typescript@"^5.1.6" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer typescript@"5.0.0" from [email protected]
npm ERR! node_modules/ajv-ts
npm ERR!   ajv-ts@"*" from the root project

To Reproduce
Steps to reproduce the behavior:

  1. Install latest Remix application
  2. Run npm install ajv-ts
  3. Notice above error

Expected behavior
Installation should work, shouldn't depend on a single version of Typescript?

Desktop (please complete the following information):

  • JS runtime : NodeJS

Bug: enum nullable don't work & optional

Ajv supports json-schema draft-7 (2020-12), and I think it would be better to rewrite it, since it is more convenient and flexible
And I think that the methods should not modify the scheme, but should return a new scheme, as is done in other validators

import { s } from 'ajv-ts';
import { assertEquals } from 'https://deno.land/[email protected]/assert/mod.ts';

Deno.test('from JSON', async t => {
	const sexJsonSchema = {
		type: 'string',
		enum: ['male', 'female'],
		title: 'Sex',
	};

	const nullableSexJsonSchema = {
		anyOf: [sexJsonSchema, { type: 'null' }],
	};

	const sex = s.fromJSON(sexJsonSchema);
	const nullableSex = s.fromJSON(nullableSexJsonSchema);

	const optionalNullableObj = s.fromJSON({
		type: 'object',
		properties: {
			sex: nullableSexJsonSchema,
		},
	});

	const requiredNullableObj = s.fromJSON({
		type: 'object',
		properties: {
			sex: nullableSexJsonSchema,
		},
		required: ['sex'],
	});

	await t.step('enum', () => {
		assertEquals(sex.parse('male'), 'male');
		assertEquals(sex.parse('female'), 'female');
		assertEquals(sex.validate(null), false);
		assertEquals(sex.validate(undefined), false);
	});

	await t.step('nullable enum', () => {
		assertEquals(nullableSex.parse('male'), 'male');
		assertEquals(nullableSex.parse('female'), 'female');
		assertEquals(nullableSex.validate(null), true);
		assertEquals(nullableSex.validate(undefined), false);
	});

	await t.step('optionalNullableObj', () => {
		assertEquals(optionalNullableObj.validate({}), true);
		assertEquals(optionalNullableObj.validate({ sex: null }), true);
		assertEquals(optionalNullableObj.validate({ sex: 'male' }), true);
	});

	await t.step('requiredNullableObj', () => {
		assertEquals(requiredNullableObj.validate({}), false);
		assertEquals(requiredNullableObj.validate({ sex: null }), true);
		assertEquals(requiredNullableObj.validate({ sex: 'male' }), true);
	});
});

Deno.test('from ajv-ts', async t => {
	const sex = s.enum(['male', 'female']);
	const nullableSex = s.enum(['male', 'female']).nullable();

	const optionalNullableObj = s.object({
		sex: s.enum(['male', 'female']).nullable().optional(),
	});

	await t.step('enum', () => {
		assertEquals(sex.parse('male'), 'male');
		assertEquals(sex.parse('female'), 'female');
		assertEquals(sex.validate(null), false);
		assertEquals(sex.validate(undefined), false);
	});

	// fail
	await t.step('nullable enum', () => {
		assertEquals(nullableSex.parse('male'), 'male');
		assertEquals(nullableSex.parse('female'), 'female');
		assertEquals(nullableSex.validate(null), true);
		assertEquals(nullableSex.validate(undefined), false);
	});

	// fail
	await t.step('optionalNullableObj', () => {
		assertEquals(optionalNullableObj.parse({}), {});
		assertEquals(optionalNullableObj.parse({ sex: 'male' }), { sex: 'male' });
		assertEquals(optionalNullableObj.parse({ sex: null }), { sex: null });
	});
});
const sexJsonSchema = {
	type: 'string',
	enum: ['male', 'female'],
	title: 'Sex',
};

const nullableSexJsonSchema = {
	anyOf: [sexJsonSchema, { type: 'null' }],
};

// Required nullable enum
{
	const a = s.fromJSON({
		type: 'object',
		properties: {
			sex: nullableSexJsonSchema,
		},
		required: ['sex'],
	});

	const b = s.object({
		sex: s.enum(['male', 'female']).nullable(),
	});

	console.log(a.validate({ sex: null })); // true
	console.log(a.validate({ sex: 'male' })); // true

	console.log(b.validate({ sex: null })); // false
	console.log(b.validate({ sex: 'male' })); // false

	console.log(a.schema, b.schema);
}

// Optional nullable enum
{
	const a = s.fromJSON({
		type: 'object',
		properties: {
			sex: nullableSexJsonSchema,
		},
	});

	const b = s.object({
		sex: s.enum(['male', 'female']).nullable().optional(),
	});

	console.log(a.validate({})); // true
	console.log(a.validate({ sex: null })); // true

	console.log(b.validate({})); // false
	console.log(b.validate({ sex: null })); // false

	console.log(a.schema, b.schema);
}

[question] 100% compatibility with `zod` API?

I understand that the ajv-ts API is a subset of the larger zod API by design, since ajv-ts should only support what is defined in JSON schema, and not the extra stuff zod adds. However, it would be great for this library to achieve 100% compatibility with the zod API in what they do have in common. This would allow using ajv-ts as a drop-in replacement for zod for the vast ecosystem of zod packages. For example, auto-form should ideally simply work:

import AutoForm, { AutoFormSubmit } from "./components/ui/auto-form";
import s from "ajv-ts";

const formSchema = s.object({ name: s.string(), age: s.number().optional() });

function App() {
  return <AutoForm formSchema={formSchema} />;
}

Expected Result:

image

However, this is throwing errors since the ajv-ts schema does not match the same zod schema (the s.object() has another form than z.object()).

Would this compatibility desired? This could be a good design decision (to align 100% with zod) in order to benefit from its vast ecosystem.

[Deep] Parse JSON Schema to Builder/s to facilitate a hybrid approach to composition in Typescript

Is your feature request related to a problem? Please describe.
Being able to use an existing JSON schema is certainly useful, however it does not appear that it is possible further modify the schema using the builder pattern. Both approaches are really useful independently, but would be so much more beneficial to a host of use cases which I have if it were possible to combine them.

Describe the solution you'd like
I would like to be able to write something along the lines of:

const composedSchema = s.jsonSchema(PERSON_JSON_SCHEMA) .omit({ middleNames: true }) .extend({ nameOfFavouriteShop: s.string(), addressOfFavouriteShop: s.jsonSchema(ADDRESS_JSON_SCHEMA), }) .requiredFor('nameOfFavouriteShop');

Describe alternatives you've considered
Composing derived JSON schemas on using pure JSON and then setting the ObjectBuilder schema to this new JSON schema. It arguably has greater utility since it is library/framework agnostic, but it somewhat undermines the point of using a library such as ajv-ts to create a better, more guided developer experience through [strongly-typed] Typescript.

Additional context
I am using fragments of JSON schema derived from Open API specifications and re-hashing them for use in HTML forms which are validated using AJV.

Three shake support

Is your feature request related to a problem? Please describe.
The issue is about using ajv-ts for frontend code base. All code will be included in output bundle

Describe the solution you'd like
Add three shake support by splitting classes to a different once

Describe alternatives you've considered
None

Additional context
None

[feature] add support for generating schemas from JSON/objects of JSON schema

Is your feature request related to a problem? Please describe.
One of the major benefits of using JSON Schema in contrast to libraries like zod, is that JSON schema is serializable, and thus, it's easy to persist in a database and expose via an API. What's missing (at least I couldn't find it) is a way to generate ajv-ts schemas at runtime from this serialized JSON schemas (coming from a database or an API, or even a file).

Describe the solution you'd like
A utility function (e.g. parseSchema, fromJSONSchema, or similar) to generate a schema from a serialized representation of the JSON schema definition would be great. It could look something like the following:

import { parseSchema } from "ajv-ts";

const MyJsonSchema = {
  "title": "Example Schema",
  "type": "object",
  "properties": {
    "name": {
      "type": "string"
    },
    "age": {
      "description": "Age in years",
      "type": "integer",
      "minimum": 0
    },
  },
  "required": ["name", "age"]
}

// creating a schema from the JSON schema object
const mySchema = parseSchema(MyJsonSchema); // usage of "mySchema" is the same

What do you think? Is this even possible with the current implementation? How complex might it be to add a feature like this? I do see it has very valid use cases...

Describe alternatives you've considered
Alternatively, one could use online tools likeJSON to Zod Tool or a library like json-schema-to-zod, however, they both have the issue that zod is not 100% JSON-schema compatible, so there might be some "information-loss". On the other hand, if ajv-ts is 100% JSON schema compatible then we don't have this issue anymore.


In any case, this library is great! Congrats @vitalics, I'm glad I found it. I stumbled with ajv-ts after looking for solutions to the problem above and reading the blogpost. ajv-ts was a great idea! It solves the shortcommings of zod, while using its strengths (great API for developers), and all while aligning to the JSON schema standard ๐Ÿ’ฏ

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.