-
-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e8915e7
Showing
16 changed files
with
4,099 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules | ||
*.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# JSON Schema to Yup schema | ||
|
||
Simple JSON Schema to Yup Schema conversion | ||
|
||
[JSON Schema primer](https://support.riverbed.com/apis/steelscript/reschema/jsonschema.html) | ||
|
||
Supports the most commonly used JSON Schema layout. | ||
Also supports some extra convenience schema properties that make it more "smooth" to define validation requirements declaratively (see below). | ||
|
||
Note that is you use these extra properties, the JSON Schema is no longer valid if used in a context where JSON Schema validation is performed. | ||
|
||
We will likely later support normalization and de-normalization. | ||
|
||
```js | ||
const schema = { | ||
$schema: "http://json-schema.org/draft-07/schema#", | ||
$id: "http://example.com/person.schema.json", | ||
title: "Person", | ||
description: "A person", | ||
type: "object", | ||
properties: { | ||
name: { | ||
description: "Name of the person", | ||
type: "string" | ||
}, | ||
age: { | ||
description: "Age of person", | ||
type: "number", | ||
exclusiveMinimum: 0, | ||
required: true | ||
} | ||
}, | ||
required: ["name"] | ||
}; | ||
|
||
const json2yup = require("json-schema-to-yup"); | ||
|
||
const yupSchema = json2yup(json); | ||
// console.dir(schema) | ||
const valid = await yupSchema.isValid({ | ||
name: "jimmy", | ||
age: 24 | ||
}); | ||
|
||
console.log({ | ||
valid | ||
}); | ||
// => {valid: true} | ||
``` | ||
|
||
This would generate the following Yup validation schema: | ||
|
||
```js | ||
const schema = yup.object().shape({ | ||
name: yup.string().required(), | ||
age: yup | ||
.number() | ||
.required() | ||
.positive() | ||
}); | ||
``` | ||
|
||
Note the `"required": true` for the `age` property (not natively supported by JSON schema). | ||
|
||
## Complex example | ||
|
||
Here a more complete example of the variations currently possible | ||
|
||
```json | ||
{ | ||
"title": "Person", | ||
"description": "A person", | ||
"type": "object", | ||
"properties": { | ||
"name": { | ||
"description": "Name of the person", | ||
"type": "string", | ||
"required": true, | ||
"matches": "[a-zA-Z- ]+", | ||
"mix": 3, | ||
"maxLength": 40 | ||
}, | ||
"age": { | ||
"description": "Age of person", | ||
"type": "integer", | ||
"min": 0, | ||
"max": 130, | ||
"required": false | ||
}, | ||
"birthday": { | ||
"type": "date", | ||
"min": "1-1-1900", | ||
"maxDate": "1-1-2015" | ||
}, | ||
"smoker": { | ||
"type": "boolean" | ||
}, | ||
"mother": { | ||
"type": "object", | ||
"properties": {} | ||
}, | ||
"siblings": { | ||
"type": "array", | ||
"items": { | ||
"type": "object", | ||
"properties": {} | ||
} | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## License | ||
|
||
MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module.exports = require('./src') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"name": "json-schema-to-yup", | ||
"version": "1.0.0", | ||
"main": "src/index.js", | ||
"license": "MIT", | ||
"dependencies": { | ||
"yup": "^0.26.3" | ||
}, | ||
"devDependencies": { | ||
"jest": "^23.5.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
const yup = require('yup'); | ||
const { | ||
toYupString, | ||
toYupNumber, | ||
toYupBoolean, | ||
toYupArray, | ||
toYupObject, | ||
toYupMixed, | ||
toYupDate | ||
} = require('./types') | ||
|
||
module.exports = (schema, config = {}) => { | ||
let { | ||
type, | ||
properties | ||
} = schema | ||
if (isObject(type)) { | ||
if (properties) { | ||
properties = normalizeRequired(schema) | ||
const shapeConfig = propsToShape(properties, config) | ||
return yup.object().shape(shapeConfig) | ||
} | ||
} | ||
throw new Error('invalid schema') | ||
} | ||
|
||
function isObject(type) { | ||
return type && type === 'object' | ||
} | ||
|
||
function normalizeRequired(schema) { | ||
const { | ||
properties, | ||
required | ||
} = schema | ||
return Object.keys(properties).reduce((acc, key) => { | ||
const value = properties[key] | ||
const isRequired = required.indexOf(key) >= 0 | ||
value.required = value.required || isRequired | ||
acc[key] = value | ||
return acc | ||
}, {}) | ||
} | ||
|
||
function propsToShape(properties, config = {}) { | ||
return Object.keys(properties).reduce((acc, key) => { | ||
const value = properties[key] | ||
acc[key] = propToYupSchemaEntry(key, value, config) | ||
return acc | ||
}, {}) | ||
} | ||
|
||
function propToYupSchemaEntry(key, value, config = {}) { | ||
return new YupSchemaEntry(key, value, config).toEntry() | ||
} | ||
|
||
class YupSchemaEntry { | ||
constructor(key, value, config) { | ||
this.key = key | ||
this.value = value | ||
this.config = config | ||
this.type = value.type | ||
} | ||
|
||
toEntry() { | ||
const typeSchema = this.typeSchema() | ||
return typeSchema | ||
} | ||
|
||
typeSchema() { | ||
if (this.type) { | ||
return this.string || | ||
this.number || | ||
this.boolean || | ||
this.array || | ||
this.object || | ||
this.date || | ||
this.mixed | ||
} | ||
return this.mixed | ||
} | ||
|
||
get obj() { | ||
return { | ||
key: this.key, | ||
value: this.value, | ||
type: this.type, | ||
config: this.config | ||
} | ||
} | ||
|
||
get string() { | ||
return toYupString(this.obj) | ||
} | ||
|
||
get number() { | ||
return toYupNumber(this.obj) | ||
} | ||
|
||
get boolean() { | ||
return toYupBoolean(this.obj) | ||
} | ||
|
||
get array() { | ||
return toYupArray(this.obj) | ||
} | ||
|
||
get object() { | ||
return toYupObject(this.obj) | ||
} | ||
|
||
get date() { | ||
return toYupDate(this.obj) | ||
} | ||
|
||
get mixed() { | ||
return toYupMixed(this.obj) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// See: http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.4 | ||
|
||
const { | ||
YupMixed | ||
} = require('./mixed') | ||
|
||
function isBoolean(type) { | ||
return type === 'array' | ||
} | ||
|
||
function toYupArray(obj) { | ||
return isArray(obj.type) && YupArray.create(obj).yupped() | ||
} | ||
|
||
class YupArray extends YupMixed { | ||
constructor(obj) { | ||
super(obj) | ||
this.type = 'array' | ||
this.base = this.yup[this.type]() | ||
} | ||
|
||
convert() { | ||
this.items().maxItems().minItems().uniqueItems().contains().additionalItems() | ||
super.convert() | ||
return this | ||
} | ||
|
||
items() { | ||
return this | ||
} | ||
|
||
additionalItems() { | ||
return this | ||
} | ||
|
||
maxItems() { | ||
const { | ||
maxItems, | ||
max | ||
} = this.value | ||
const $max = maxItems || max | ||
$max && this.base.min($max) | ||
return this | ||
} | ||
|
||
minItems() { | ||
const { | ||
minItems, | ||
min | ||
} = this.value | ||
const $min = maxItems || min | ||
$min && this.base.min($min) | ||
return this | ||
} | ||
|
||
uniqueItems() { | ||
return this | ||
} | ||
|
||
contains() { | ||
return this | ||
} | ||
} | ||
|
||
module.exports = { | ||
toYupArray, | ||
YupArray | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
const { | ||
YupMixed | ||
} = require('./mixed') | ||
|
||
function isBoolean(type) { | ||
return type === 'boolean' | ||
} | ||
|
||
function toYupBoolean(obj) { | ||
return isBoolean(obj.type) && YupBoolean.create(obj).yupped() | ||
} | ||
|
||
class YupBoolean extends YupMixed { | ||
constructor(obj) { | ||
super(obj) | ||
this.type = 'boolean' | ||
this.base = this.yup[this.type]() | ||
} | ||
|
||
static create(obj) { | ||
return new YupBoolean(obj) | ||
} | ||
} | ||
|
||
module.exports = { | ||
toYupBoolean, | ||
YupBoolean | ||
} |
Oops, something went wrong.