Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/takitotech/schemez

This library allows users to create JSON schemas and respective TypeScript types in a manner consistent with TypeScript coding. Not only does this reduce code duplication, it makes it simpler for TypeScript developers to learn it.
https://github.com/takitotech/schemez

jsonschema typescript typescript-library validate

Last synced: 3 months ago
JSON representation

This library allows users to create JSON schemas and respective TypeScript types in a manner consistent with TypeScript coding. Not only does this reduce code duplication, it makes it simpler for TypeScript developers to learn it.

Awesome Lists containing this project

README

        

# schemez



Version


License: MIT

Main

codecov

This library allows users to create JSON schemas and respective TypeScript types in a manner consistent with TypeScript coding. Not only does this reduce code duplication, it makes it simpler for TypeScript developers to learn it.

Heavily based on seemingly abandoned project [jsonschema-definer](https://github.com/Sujimoshi/jsonschema-definer).

Added features like "pick", "omit", and etc, improved code and typescript support, and removed validator to avoid dependency.

## ๐Ÿ”ฅ Install

```sh
npm i -D schemez
yarn add -D schemez
pnpm i -D schemez
```

## ๐Ÿ‘Œ Usage
Basic example

```ts
import s from "schemez";

// Lets define a simple object schema
const UserSchema = s.shape({
name: s.string(),
email: s.string().format('email').optional(),
password: s.string().minLength(8),
role: s.enum('client', 'supplier'),
birthday: s.instanceOf(Date)
});

// Now lets get interface from schema
type User = typeof UserSchema.type
/*
type User = {
name: string,
email?: string | undefined,
password: string,
role: 'client' | 'supplier',
birthday: Date
}
*/

// Get plain JSON Schema using .valueOf()
console.log(UserSchema.valueOf())

const AdminUserSchema = UserSchema.andShape({
company: s.string().minLength(3),
});

// Now lets get interface from schema
type AdminUser = typeof AdminUserSchema.type
/*
type AdminUser = {
name: string,
email?: string | undefined,
password: string,
role: 'client' | 'supplier',
birthday: Date,
}
*/

// Get plain JSON Schema using .valueOf()
console.log(AdminUserSchema.valueOf())

const BotUserSchema = UserSchema.pick("name", "role");

// Now lets get interface from schema
type BotUser = typeof BotUserSchema.type
/*
type BotUser = {
name: string,
role: 'client' | 'supplier',
}
*/

// Get plain JSON Schema using .valueOf()
console.log(BotUserSchema.valueOf())

```

## ๐Ÿ‘ Reasons for using schemez

- Sensible defaults (ie properties are required by default)
- Built in TypeScript and TypeScript Support
- Reduced code duplication with TypeScript-like utilities (ie pick, omit, etc)
- Less code overall
- Can be easily extended to include UI via JSON Schema prop "description"

## ๐Ÿ‘Ž Reasons against using schemez

- New
- Existing libraries with similar features (find more below)

## ๐Ÿ‘€ Comparison against similar libraries (fluent-json-schema vs schemez vs typebox)

[Comparison](https://stackblitz.com/edit/typescript-5bksyx?file=index.ts)

## โญ๏ธ Show your support

Give a โญ๏ธ if this project helped you!
## ๐Ÿ“š Documentation

Full documentation available [here](https://takitotech.github.io/schemez/)
### Main exported variable s: SchemaFactory extends BaseSchema. Examples found in test files.


Method
Description
TypeScript
JSON Schema


s.any(): BaseSchema
Correspond to any type
any
{ }


s.string(): StringSchema
For strings validation
string
{ "type": "string" }


s.number(): NumericSchema
For float/integer validation
number
{ "type": "number" }


s.integer(): NumericSchema
For integer values validation
number
{ "type": "integer" }


s.boolean(): BaseSchema
For boolean values
boolean
{ "type": "boolean" }


s.null(): BaseSchema
For null value validation
null
{ "type": "null" }


s.array(): ArraySchema
Array validation (more likely you are looking for s.list)
[]
{ "type": "array" }


s.list(itemType: T): ArraySchema
Validation of lists. Example: s.list(s.string()): ArraySchema
T[]
{ "type": "array", "items": { ... } }


s.object(): ObjectSchema
Object creation (more likely you are looking for s.shape)
{}
{ "type": "object" }


s.shape({ key: Schema }: T): ObjectSchema
Object creation
{ ... }
{ "type": "object", properties: T, additionalProperties: false } }


s.pick(...fields: string[]: T): ObjectSchema
Create a new object with chosen fields
{ ... }
{ "type": "object", properties: T, additionalProperties: false } }


s.omit(...fields: string[]: T): ObjectSchema
Create a new object with not-chosen fields
{ ... }
{ "type": "object", properties: T, additionalProperties: false } }


s.and(mergeWith: ObjectSchema): ObjectSchema
Create a new object that merges with both ObjectSchemas. Similar to typescript's intersection operator (&)
& (aka. intersection)
{ "type": "object", properties: T, additionalProperties: false } }


s.andShape({ key: Schema }: T): ObjectSchema
Create a new object that merges with ObjectSchema and new ObjectSchema. Similar to and + shape.
& (aka. intersection)
{ "type": "object", properties: T, additionalProperties: false } }


s.enum(...constants: T[]): BaseSchema
Enumerable schema
A | B | C
{ enum: [ T[0], T[1] ] }


s.const(constant: T): BaseSchema
Constant value
const
{ const: T }


s.anyOf(...schemas: BaseSchema[]): BaseSchema
Any (one or more) of given types
any
{ anyOf: [ T[0], T[1], ... ] }


s.oneOf(...schemas: BaseSchema[]): BaseSchema
Value shoud correspond to ONE of given types
any
{ oneOf: [ T[0], T[1], ... ] }


s.allOf(...schemas: BaseSchema[]): BaseSchema
Value should correspond to ALL of given type
any
{ allOf: [ T[0], T[1], ... ] }


s.raw(values: any): BaseSchema
Set custom schema values (For Swagger definitions for example)
any
{ ...values }


s.title(value: string): BaseSchema
Add title to schema
N/A
{ "title": "string" }


s.description(value: string): BaseSchema
Add description (either string or object that is stringified) to schema
N/A
{ "description": "string" }


s.optional(): BaseSchema
Optional (similar to optional (?) typescript type and NOT partial type)
T | undefined
{ "required": [ ... ] }


s.partial(): ObjectSchema
Sets object's fields as optional; Does NOT set object itself as optional
{ ...? } (aka. optional fields)
{ "type": "object", properties: T, additionalProperties: false, "required": [] } }


s.partialDeep(): ObjectSchema
Sets object's fields and fields' fields recursively as optional; Does NOT set object itself as optional
{ ...? } (aka. optional fields)
{ "type": "object", properties: T, additionalProperties: false, "required": [] } }

## ๐Ÿญ Release setup
Uses semantic-release to manage releases.

### ๐Ÿ” Commit message format

**semantic-release** uses the commit messages to determine the consumer impact of changes in the codebase.
Following formalized conventions for commit messages, **semantic-release** automatically determines the next [semantic version](https://semver.org) number, generates a changelog and publishes the release.

By default, **semantic-release** uses [Angular Commit Message Conventions](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-format).
The commit message format can be changed with the [`preset` or `config` options](docs/usage/configuration.md#options) of the [@semantic-release/commit-analyzer](https://github.com/semantic-release/commit-analyzer#options) and [@semantic-release/release-notes-generator](https://github.com/semantic-release/release-notes-generator#options) plugins.

Tools such as [commitizen](https://github.com/commitizen/cz-cli) or [commitlint](https://github.com/conventional-changelog/commitlint) can be used to help contributors and enforce valid commit messages.

The table below shows which commit message gets you which release type when `semantic-release` runs (using the default configuration):

| Commit message | Release type |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------- |
| `fix(pencil): stop graphite breaking when too much pressure applied` | ~~Patch~~ Fix Release |
| `feat(pencil): add 'graphiteWidth' option` | ~~Minor~~ Feature Release |
| `perf(pencil): remove graphiteWidth option`

`BREAKING CHANGE: The graphiteWidth option has been removed.`
`The default graphite width of 10mm is always used for performance reasons.` | ~~Major~~ Breaking Release
(Note that the `BREAKING CHANGE: ` token must be in the footer of the commit) |

Ref: https://github.com/semantic-release/semantic-release#commit-message-format

## ๐Ÿค Contributing

Contributions, issues and feature requests are welcome!
Feel free to check [issues page](https://github.com/TakitoTech/schemez/issues).

### ๐Ÿงช Run tests

```sh
pnpm test
```

## โœ๏ธ Author

๐Ÿ‘ค TriStarGod

* Github: [@TriStarGod](https://github.com/TriStarGod)