1
0
Fork 0

Add joi-to-json-schema dep

This commit is contained in:
Alan Plum 2016-01-14 15:24:34 +01:00
parent a00ac0d96f
commit 774a47a185
No known key found for this signature in database
GPG Key ID: 8ED72A9A323B6EFD
16 changed files with 1345 additions and 0 deletions

View File

@ -163,6 +163,11 @@
* GITHUB: https://github.com/hapijs/joi
* License: [BSD-style 3-Clause License](https://github.com/hapijs/joi/blob/master/LICENSE)
### joi-to-json-schema
* GITHUB: https://github.com/lightsofapollo/joi-to-json-schema
* License: [Apache 2 License](https://github.com/lightsofapollo/joi-to-json-schema/blob/master/README.md#license)
#### JS-YAML
* GITHUB: https://github.com/nodeca/js-yaml

1
js/node/node_modules/joi-to-json-schema/.npmignore generated vendored Normal file
View File

@ -0,0 +1 @@

7
js/node/node_modules/joi-to-json-schema/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,7 @@
language: node_js
node_js:
- "0.12"
- "0.11"
- "0.10"
- "iojs"
- "iojs-v1.0.4"

2
js/node/node_modules/joi-to-json-schema/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,2 @@
## [**2.0.0**](https://github.com/lightsofapollo/joi-to-json-schema/commit/620f7f15d6cc28e1e647b2ec9a8355be69af423c)
- [**#2**](https://github.com/lightsofapollo/joi-to-json-schema/issues/2) Added support for joi.forbidden() in object properties

119
js/node/node_modules/joi-to-json-schema/README.md generated vendored Normal file
View File

@ -0,0 +1,119 @@
# joi-to-json-schema
The goal is to provide best effort conversion from Joi objects to JSON
Schema (draft-04) with the understanding that only some of Joi's schematics
can be converted directly. Primarily this module exists to convert Joi schema
objects for existing tools which happen to currently consume JSON Schema.
[![npm version](https://badge.fury.io/js/joi-to-json-schema.svg)](http://badge.fury.io/js/joi-to-json-schema)
[![Build Status](https://travis-ci.org/lightsofapollo/joi-to-json-schema.svg?branch=master)](https://travis-ci.org/lightsofapollo/joi-to-json-schema)
[![Dependencies Status](https://david-dm.org/lightsofapollo/joi-to-json-schema.svg)](https://david-dm.org/lightsofapollo/joi-to-json-schema)
[![DevDependencies Status](https://david-dm.org/lightsofapollo/joi-to-json-schema/dev-status.svg)](https://david-dm.org/lightsofapollo/joi-to-json-schema#info=devDependencies)
[![NPM](https://nodei.co/npm/joi-to-json-schema.png)](https://nodei.co/npm/joi-to-json-schema/)
[![NPM](https://nodei.co/npm-dl/joi-to-json-schema.png)](https://nodei.co/npm-dl/joi-to-json-schema/)
## Installation
> npm install joi-to-json
## Usage
```js
var joi = require('joi'),
convert = require('joi-to-json-schema'),
joiSchema=joi.object({
'name':joi.string().required().regex(/^\w+$/),
'description':joi.string().optional().default('no description provided'),
'a': joi.boolean().required().default(false),
'b': joi.alternatives().when('a', {
is: true,
then: joi.string().default('a is true'),
otherwise: joi.number().default(0)
})
});
convert(joiSchema);
```
which will produce:
```js
{ type: 'object',
properties:
{ name: { type: 'string', pattern: '^\\w+$' },
description: { default: 'no description provided', type: 'string' },
a: { type: 'boolean' },
b: { oneOf: [ { default: 'a is true', type: 'string' }, { type: 'number' } ] } },
additionalProperties: false,
required: [ 'name', 'a' ] }
```
## JSDOC
```javascript
/**
* Converts the supplied joi validation object into a JSON schema object,
* optionally applying a transformation.
*
* @param {JoiValidation} joi
* @param {TransformFunction} [transformer=null]
* @returns {JSONSchema}
*/
export default function convert(joi,transformer=null) {
// ...
};
/**
* Joi Validation Object
* @typedef {object} JoiValidation
*/
/**
* Transformation Function - applied just before `convert()` returns and called as `function(object):object`
* @typedef {function} TransformFunction
*/
/**
* JSON Schema Object
* @typedef {object} JSONSchema
*/
```
## Notes
Joi's conditional form, i.e. `.when('name',{is:cond,then:joi,otherwise:joi})`, is evaluated at runtime
and since, from the perspective of the schema, there is no way of knowing what the condition might resolve to, this
module takes the position that it should provide _all possible resolutions_ in a JSON Schema `oneOf:[]` clause.
Also, while it does not affect consumers, it should be noted that `joi-to-json-schema` is written in ES6 and uses
[6-to-5](https://www.npmjs.com/package/6to5) to convert to ES5 before the module is published to `npm`.
## Testing
All tests cases are first checked against expected results and then validated using
Kris Zyp's excellent [json-schema](https://github.com/kriszyp/json-schema)
## References
- [JSON Schema - Draft 4 from json-schema.org](http://json-schema.org/documentation.html)
- [IETF Draft: JSON Schema: core definitions and terminology - draft-zyp-json-schema-04](https://tools.ietf.org/html/draft-zyp-json-schema-04)
- [Understanding JSON Schema](http://spacetelescope.github.io/understanding-json-schema/UnderstandingJSONSchema.pdf)(pdf)
## LICENSE
Copyright 2014, Mozilla Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

237
js/node/node_modules/joi-to-json-schema/build/index.js generated vendored Normal file
View File

@ -0,0 +1,237 @@
"use strict";
var _interopRequire = function (obj) { return obj && obj.__esModule ? obj["default"] : obj; };
/**
* Converts the supplied joi validation object into a JSON schema object,
* optionally applying a transformation.
*
* @param {JoiValidation} joi
* @param {TransformFunction} [transformer=null]
* @returns {JSONSchema}
*/
module.exports = convert;
var assert = _interopRequire(require("assert"));
// Converter helpers for Joi types.
var TYPES = {
alternatives: function (schema, joi) {
var result = schema.oneOf = [];
joi._inner.matches.forEach(function (match) {
if (match.schema) {
return result.push(convert(match.schema));
}
if (!match.is) {
throw new Error("joi.when requires an \"is\"");
}
if (!(match.then || match.otherwise)) {
throw new Error("joi.when requires one or both of \"then\" and \"otherwise\"");
}
if (match.then) {
result.push(convert(match.then));
}
if (match.otherwise) {
result.push(convert(match.otherwise));
}
});
return schema;
},
date: function (schema) {
schema.type = "string";
schema.format = "date-time";
return schema;
},
any: function (schema) {
schema.type = ["array", "boolean", "number", "object", "string", "null"];
return schema;
},
array: function (schema, joi) {
schema.type = "array";
joi._tests.forEach(function (test) {
switch (test.name) {
case "unique":
schema.uniqueItems = true;
break;
case "length":
schema.minItems = schema.maxItems = test.arg;
break;
case "min":
schema.minItems = test.arg;
break;
case "max":
schema.maxItems = test.arg;
break;
}
});
if (joi._inner) {
var list = undefined;
if (joi._inner.inclusions.length) {
list = joi._inner.inclusions;
} else if (joi._inner.requireds.length) {
list = joi._inner.requireds;
}
if (list) {
schema.items = schema.items || [];
list.forEach(function (i) {
schema.items.push(convert(i));
});
}
}
return schema;
},
boolean: function (schema) {
schema.type = "boolean";
return schema;
},
number: function (schema, joi) {
schema.type = "number";
joi._tests.forEach(function (test) {
switch (test.name) {
case "integer":
schema.type = "integer";
break;
case "less":
schema.exclusiveMaximum = true;
schema.maximum = test.arg;
break;
case "greater":
schema.exclusiveMinimum = true;
schema.minimum = test.arg;
break;
case "min":
schema.minimum = test.arg;
break;
case "max":
schema.maximum = test.arg;
break;
}
});
return schema;
},
string: function (schema, joi) {
schema.type = "string";
joi._tests.forEach(function (test) {
switch (test.name) {
case "email":
schema.format = "email";
break;
case "regex":
schema.pattern = String(test.arg).replace(/^\//, "").replace(/\/$/, "");
break;
case "min":
schema.minLength = test.arg;
break;
case "max":
schema.maxLength = test.arg;
break;
case "length":
schema.minLength = schema.maxLength = test.arg;
break;
}
});
return schema;
},
object: function (schema, joi) {
schema.type = "object";
schema.properties = {};
schema.additionalProperties = joi._flags.allowUnknown || false;
if (!joi._inner.children) {
return schema;
}
joi._inner.children.forEach(function (property) {
if (property.schema._flags.presence !== "forbidden") {
schema.properties[property.key] = convert(property.schema);
if (property.schema._flags.presence === "required") {
schema.required = schema.required || [];
schema.required.push(property.key);
}
}
});
return schema;
}
};function convert(joi) {
var transformer = arguments[1] === undefined ? null : arguments[1];
assert("object" === typeof joi && true === joi.isJoi, "requires a joi schema object");
assert(joi._type, "joi schema object must have a type");
if (!TYPES[joi._type]) {
throw new Error("sorry, do not know how to convert unknown joi type: \"" + joi._type + "\"");
}
if (transformer) {
assert("function" === typeof transformer, "transformer must be a function");
}
// JSON Schema root for this type.
var schema = {};
// Copy over the details that all schemas may have...
if (joi._description) {
schema.description = joi._description;
}
if (joi._flags && joi._flags["default"]) {
schema["default"] = joi._flags["default"];
}
if (joi._valids && joi._valids._set && joi._valids._set.length) {
if (Array.isArray(joi._inner.children)) {
return {
"------oneOf": [{
type: joi._type,
"enum": joi._valids._set
}, TYPES[joi._type](schema, joi)]
};
}
schema["enum"] = joi._valids._set;
}
var result = TYPES[joi._type](schema, joi);
if (transformer) {
result = transformer(result);
}
return result;
}
/**
* Joi Validation Object
* @typedef {object} JoiValidation
*/
/**
* Transformation Function - applied just before `convert()` returns and called as `function(object):object`
* @typedef {function} TransformFunction
*/
/**
* JSON Schema Object
* @typedef {object} JSONSchema
*/
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

63
js/node/node_modules/joi-to-json-schema/package.json generated vendored Normal file
View File

@ -0,0 +1,63 @@
{
"name": "joi-to-json-schema",
"version": "2.0.5",
"description": "Joi -> JSON Schema Converter",
"main": "build/index.js",
"scripts": {
"build": "6to5 -s -e src --out-dir build",
"pretest": "npm run build",
"test": "mocha",
"prepublish": "npm run build"
},
"repository": {
"type": "git",
"url": "git+https://github.com/lightsofapollo/joi-to-json-schema.git"
},
"keywords": [
"joi",
"json-schema",
"json",
"schema"
],
"author": {
"name": "James Lal [:lightsofapollo]"
},
"maintainers": [
{
"name": "lights-of-apollo",
"email": "james@lightsofapollo.com"
},
{
"name": "raisch",
"email": "raisch@gmail.com"
}
],
"license": "Apache2",
"bugs": {
"url": "https://github.com/lightsofapollo/joi-to-json-schema/issues"
},
"homepage": "https://github.com/lightsofapollo/joi-to-json-schema",
"devDependencies": {
"6to5": "^3.6.5",
"joi": "^6.6.0",
"json-schema": "^0.2.2",
"lodash": "^3.9.3",
"mocha": "^2.2.5"
},
"gitHead": "d1cab007ada3ded19a7d4080a93dac8064d4d2d8",
"_id": "joi-to-json-schema@2.0.5",
"_shasum": "9a1203252092d8007792883c07bd652a24b53ced",
"_from": "joi-to-json-schema@*",
"_npmVersion": "2.14.7",
"_nodeVersion": "4.2.0",
"_npmUser": {
"name": "lights-of-apollo",
"email": "james@lightsofapollo.com"
},
"dist": {
"shasum": "9a1203252092d8007792883c07bd652a24b53ced",
"tarball": "http://registry.npmjs.org/joi-to-json-schema/-/joi-to-json-schema-2.0.5.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/joi-to-json-schema/-/joi-to-json-schema-2.0.5.tgz"
}

244
js/node/node_modules/joi-to-json-schema/src/index.js generated vendored Normal file
View File

@ -0,0 +1,244 @@
import assert from 'assert';
// Converter helpers for Joi types.
let TYPES = {
alternatives: (schema, joi) => {
var result = schema.oneOf = [];
joi._inner.matches.forEach(function (match) {
if (match.schema) {
return result.push(convert(match.schema));
}
if (!match.is) {
throw new Error('joi.when requires an "is"');
}
if (!(match.then || match.otherwise)) {
throw new Error('joi.when requires one or both of "then" and "otherwise"');
}
if (match.then) {
result.push(convert(match.then));
}
if (match.otherwise) {
result.push(convert(match.otherwise));
}
});
return schema;
},
date: (schema) => {
schema.type = 'string';
schema.format = 'date-time';
return schema;
},
any: (schema) => {
schema.type = [
"array",
"boolean",
'number',
"object",
'string',
"null"
];
return schema;
},
array: (schema, joi) => {
schema.type = 'array';
joi._tests.forEach((test) => {
switch (test.name) {
case 'unique':
schema.uniqueItems = true;
break;
case 'length':
schema.minItems = schema.maxItems = test.arg;
break;
case 'min':
schema.minItems = test.arg;
break;
case 'max':
schema.maxItems = test.arg;
break;
}
});
if (joi._inner) {
let list;
if (joi._inner.inclusions.length) {
list = joi._inner.inclusions;
} else if (joi._inner.requireds.length) {
list = joi._inner.requireds;
}
if (list) {
schema.items = schema.items || [];
list.forEach((i) => {
schema.items.push(convert(i));
});
}
}
return schema;
},
boolean: (schema) => {
schema.type = 'boolean';
return schema;
},
number: (schema, joi) => {
schema.type = 'number';
joi._tests.forEach((test) => {
switch (test.name) {
case 'integer':
schema.type = 'integer';
break;
case 'less':
schema.exclusiveMaximum = true;
schema.maximum = test.arg;
break;
case 'greater':
schema.exclusiveMinimum = true;
schema.minimum = test.arg;
break;
case 'min':
schema.minimum = test.arg;
break;
case 'max':
schema.maximum = test.arg;
break;
}
});
return schema;
},
string: (schema, joi) => {
schema.type = 'string';
joi._tests.forEach((test) => {
switch (test.name) {
case 'email':
schema.format = 'email';
break;
case 'regex':
schema.pattern = String(test.arg).replace(/^\//,'').replace(/\/$/,'');
break;
case 'min':
schema.minLength = test.arg;
break;
case 'max':
schema.maxLength = test.arg;
break;
case 'length':
schema.minLength = schema.maxLength = test.arg;
break;
}
});
return schema;
},
object: (schema, joi) => {
schema.type = 'object';
schema.properties = {};
schema.additionalProperties = joi._flags.allowUnknown || false;
if (!joi._inner.children) {
return schema;
}
joi._inner.children.forEach((property) => {
if(property.schema._flags.presence !== 'forbidden') {
schema.properties[property.key] = convert(property.schema);
if (property.schema._flags.presence === 'required') {
schema.required = schema.required || [];
schema.required.push(property.key);
}
}
});
return schema;
}
};
/**
* Converts the supplied joi validation object into a JSON schema object,
* optionally applying a transformation.
*
* @param {JoiValidation} joi
* @param {TransformFunction} [transformer=null]
* @returns {JSONSchema}
*/
export default function convert(joi,transformer=null) {
assert('object'===typeof joi && true === joi.isJoi, 'requires a joi schema object');
assert(joi._type, 'joi schema object must have a type');
if(!TYPES[joi._type]){
throw new Error(`sorry, do not know how to convert unknown joi type: "${joi._type}"`);
}
if(transformer){
assert('function'===typeof transformer, 'transformer must be a function');
}
// JSON Schema root for this type.
let schema = {};
// Copy over the details that all schemas may have...
if (joi._description) {
schema.description = joi._description;
}
if (joi._flags && joi._flags.default) {
schema['default'] = joi._flags.default;
}
if (joi._valids && joi._valids._set && joi._valids._set.length){
if(Array.isArray(joi._inner.children)) {
return {
'------oneOf': [
{
'type': joi._type,
'enum': joi._valids._set
},
TYPES[joi._type](schema, joi)
]
};
}
schema['enum']=joi._valids._set;
}
let result = TYPES[joi._type](schema, joi);
if(transformer){
result = transformer(result);
}
return result;
}
/**
* Joi Validation Object
* @typedef {object} JoiValidation
*/
/**
* Transformation Function - applied just before `convert()` returns and called as `function(object):object`
* @typedef {function} TransformFunction
*/
/**
* JSON Schema Object
* @typedef {object} JSONSchema
*/

View File

@ -0,0 +1,414 @@
//@formatter:off
var Joi = require('joi'),
convert = require('../src/index'),
assert = require('assert'),
jsonSchema = require('json-schema');
//@formatter:on
/* jshint mocha:true */
/* global suite, test */
/**
* Throws if schema !== expected or if schema fails to jsonSchema.validate()
* @param {object} schema
* @param {object} expected
*/
assert.validate = function (schema, expected) {
var result = jsonSchema.validate(schema);
assert.deepEqual(schema, expected);
if ('object' === typeof result && Array.isArray(result.errors) && 0 === result.errors.length) {
return;
}
throw new Error('json-schema validation failed: %s', result.errors.join(','));
};
suite('convert', function () {
test('object defaults', function () {
var joi = Joi.object(),
schema = convert(joi),
expected = {
type: 'object',
properties: {},
additionalProperties: false
};
assert.validate(schema, expected);
});
test('object description', function () {
var joi = Joi.object().description('woot'),
schema = convert(joi),
expected = {
type: 'object',
properties: {},
additionalProperties: false,
description: 'woot'
};
assert.validate(schema, expected);
});
test('object allow unknown', function () {
var joi = Joi.object().unknown(true),
schema = convert(joi),
expected = {
type: 'object',
properties: {},
additionalProperties: true
};
assert.validate(schema, expected);
});
test('object', function () {
let joi = Joi.object().keys({
string: Joi.string(),
'string default': Joi.string().default('bar').description('bar desc'),
'number': Joi.number(),
'boolean': Joi.boolean()
}),
schema = convert(joi),
expected = {
type: 'object',
properties: {
'string': {
type: 'string'
},
'string default': {
type: 'string',
'default': 'bar',
description: 'bar desc'
},
'number': {
type: 'number'
},
'boolean': {
type: 'boolean'
}
},
additionalProperties: false
};
assert.validate(schema, expected);
});
test('object property required', function () {
let joi = Joi.object().keys({
string: Joi.string(),
'string default': Joi.string().default('bar').description('bar desc'),
'number': Joi.number(),
'boolean required': Joi.boolean().required()
}),
schema = convert(joi),
expected = {
type: 'object',
required: ['boolean required'],
properties: {
'string': {
type: 'string'
},
'string default': {
type: 'string',
'default': 'bar',
description: 'bar desc'
},
'number': {
type: 'number'
},
'boolean required': {
type: 'boolean'
}
},
additionalProperties: false
};
assert.validate(schema, expected);
});
test('object property forbidden', function(){
let joi = Joi.object().keys({
string: Joi.string(),
'string default': Joi.string().default('bar').description('bar desc'),
'number forbidden': Joi.number().forbidden(),
'boolean required': Joi.boolean().required()
}),
schema = convert(joi),
expected = {
type: 'object',
required: ['boolean required'],
properties: {
'string': {
type: 'string'
},
'string default': {
type: 'string',
'default': 'bar',
description: 'bar desc'
},
'boolean required': {
type: 'boolean'
}
},
additionalProperties: false
};
assert.validate(schema, expected);
});
test('type: array', function () {
var joi = Joi.array(),
schema = convert(joi),
expected = {
type: 'array'
};
assert.validate(schema, expected);
});
test('enum', function () {
var joi = Joi.string().valid(['a', 'b']),
schema = convert(joi),
expected = {
'type': 'string',
'enum': ['a', 'b']
};
//console.log('.enum: %s', util.inspect({type: joi._type, schema: schema}, {depth: 10}));
assert.validate(schema, expected);
});
test('alternatives -> oneOf', function () {
let joi = Joi.object().keys({
value: Joi.alternatives().try(
Joi.string().valid('a'),
Joi.number().valid(100)
)
}),
schema = convert(joi),
expected = {
type: 'object',
additionalProperties: false,
properties: {
value: {
oneOf: [
{
type: 'string',
'enum': ['a']
},
{
type: 'number',
'enum': [100]
}
]
}
}
};
//console.log('alt -> oneOf: %s', util.inspect({type: joi._type, schema: schema}, {depth: 10}));
assert.validate(schema, expected);
});
test('string min/max', function () {
var joi = Joi.string().min(5).max(100),
schema = convert(joi),
expected = {
type: 'string',
minLength: 5,
maxLength: 100
};
assert.validate(schema, expected);
});
test('string -> maxLength', function () {
var joi = Joi.string().length(5),
schema = convert(joi),
expected = {
type: 'string',
maxLength: 5,
minLength: 5
};
assert.validate(schema, expected);
});
test('string email', function () {
var joi = Joi.string().email(),
schema = convert(joi),
expected = {
type: 'string',
format: 'email'
};
assert.validate(schema, expected);
});
test('date', function () {
var joi = Joi.date(),
schema = convert(joi),
expected = {
type: 'string',
format: 'date-time'
};
assert.validate(schema, expected);
});
test('string regex -> pattern', function () {
let joi = Joi.string().regex(/^[a-z]$/),
schema = convert(joi),
expected = {
type: 'string',
pattern: '^[a-z]$'
};
assert.validate(schema, expected);
});
test('string allow', function () {
let joi = Joi.string().allow(['a', 'b', '', null]),
schema = convert(joi),
expected = {
type: 'string',
'enum': ['a', 'b', '', null]
};
//console.log('string allow: %s', util.inspect({type: joi._type, joi:joi, schema: schema}, {depth: 10}));
assert.validate(schema, expected);
});
test('number min/max', function () {
let joi = Joi.number().min(0).max(100),
schema = convert(joi),
expected = {
type: 'number',
minimum: 0,
maximum: 100
};
assert.validate(schema, expected);
});
test('number greater/less', function () {
let joi = Joi.number().greater(0).less(100),
schema = convert(joi),
expected = {
type: 'number',
minimum: 0,
exclusiveMinimum: true,
maximum: 100,
exclusiveMaximum: true
};
assert.validate(schema, expected);
});
test('integer', function () {
var joi = Joi.number().integer(),
schema = convert(joi),
expected = {
type: 'integer'
};
assert.validate(schema, expected);
});
test('array min/max', function () {
let joi = Joi.array().min(5).max(100),
schema = convert(joi),
expected = {
type: 'array',
minItems: 5,
maxItems: 100
};
assert.validate(schema, expected);
});
test('array length', function () {
let joi = Joi.array().length(100),
schema = convert(joi),
expected = {
type: 'array',
minItems: 100,
maxItems: 100
};
assert.validate(schema, expected);
});
test('array unique', function () {
let joi = Joi.array().unique(),
schema = convert(joi),
expected = {
type: 'array',
uniqueItems: true
};
assert.validate(schema, expected);
});
test('array inclusions', function () {
let joi = Joi.array().items(Joi.string()),
schema = convert(joi),
expected = {
type: 'array',
items: [{type: 'string'}]
};
assert.validate(schema, expected);
});
test('joi any', function () {
let joi = Joi.any(),
schema = convert(joi),
expected = {
type: ['array', 'boolean', 'number', 'object', 'string', 'null']
};
assert.validate(schema, expected);
});
test('big and complicated', function () {
let joi = Joi.object({
aFormattedString: Joi.string().regex(/^[ABC]_\w+$/),
aFloat: Joi.number().default(0.8).min(0.0).max(1.0),
anInt: Joi.number().required().precision(0).greater(0),
aForbiddenString: Joi.string().forbidden(),
anArrayOfFloats: Joi.array().items(Joi.number().default(0.8).min(0.0).max(1.0)),
anArrayOfNumbersOrStrings: Joi.array().items(Joi.alternatives(Joi.number(), Joi.string()))
}),
schema = convert(joi),
expected = require('./fixtures/complicated.json');
assert.validate(schema, expected);
// now make it fail
expected.properties.aForbiddenString={type:'string'};
try {
assert.validate(schema,expected);
}
catch(e){
//console.warn(e);
if(e.name !== 'AssertionError' && e.operator !== 'deepEqual'){
throw e;
}
}
});
test('joi.when', function () {
let joi = Joi.object({
'a': Joi.boolean().required().default(false),
'b': Joi.alternatives().when('a', {
is: true,
then: Joi.string().default('a is true'),
otherwise: Joi.number().default(0)
})
}),
schema = convert(joi),
expected = {
type: 'object',
properties: {
a: {type: 'boolean'},
b: {
oneOf: [
{
'default': 'a is true',
type: 'string'
}, {
type: 'number'
}
]
}
},
additionalProperties: false,
required: ['a']
};
//console.log('when: %s', util.inspect({type:joi._type,schema:schema}, {depth: 10}));
assert.validate(schema, expected);
});
});

View File

@ -0,0 +1,50 @@
{
"type": "object",
"properties": {
"aFormattedString": {
"type": "string",
"pattern": "^[ABC]_\\w+$"
},
"aFloat": {
"default": 0.8,
"type": "number",
"minimum": 0,
"maximum": 1
},
"anInt": {
"type": "number",
"exclusiveMinimum": true,
"minimum": 0
},
"anArrayOfFloats": {
"type": "array",
"items": [
{
"default": 0.8,
"type": "number",
"minimum": 0,
"maximum": 1
}
]
},
"anArrayOfNumbersOrStrings": {
"type": "array",
"items": [
{
"oneOf": [
{
"type": "number"
},
{
"type": "string"
}
]
}
]
}
},
"additionalProperties": false,
"required": [
"anInt"
]
}

View File

@ -0,0 +1,84 @@
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"options": {
"oneOf": [
{
"oneOf": [
{
"type": "object",
"properties": {
"name": {
"enum": [
"",
"foo"
],
"type": "string"
},
"size": {
"enum": [
"2x4"
],
"type": "string"
},
"value": {
"type": "string"
}
},
"additionalProperties": false,
"required": [
"name",
"size",
"value"
]
},
{
"type": "object",
"properties": {
"name": {
"enum": [
"foo"
],
"type": "string"
},
"size": {
"enum": [
"4x8"
],
"type": "string"
},
"value": {
"type": "number",
"minimum": 11,
"maximum": 20
}
},
"additionalProperties": false,
"required": [
"name",
"size",
"value"
]
}
]
},
{
"type": "string",
"pattern": "^[a-z]+$"
},
{
"type": "string",
"pattern": "^[A-Z]+$"
}
]
}
},
"additionalProperties": false,
"required": [
"name",
"options"
]
}

View File

@ -0,0 +1 @@
--require test/setup.js --ui tdd

View File

@ -0,0 +1 @@
require('6to5/register');

View File

@ -0,0 +1,115 @@
'use strict';
/*
* Created by raisch on 3/17/15.
*/
/*jshint mocha:true, node:true, bitwise:true, camelcase:false, curly:true, undef:false, unused:false, eqeqeq:true, shadow:true */
/* global suite, test */
//@formatter:off
var Joi = require('joi'),
convert = require('../src/index'),
assert = require('assert'),
jsonSchema = require('json-schema'),
_ = require('lodash');
//@formatter:on
/**
* Throws if schema !== expected or if schema fails to jsonSchema.validate()
* @param {object} schema
* @param {object} expected
*/
assert.validate = function (schema, expected) {
var result = jsonSchema.validate(schema);
assert.deepEqual(schema, expected);
if ('object' === typeof result && Array.isArray(result.errors) && 0 === result.errors.length) {
return;
}
throw new Error('json-schema validation failed: %s', result.errors.join(','));
};
/**
* Removes null values from all arrays.
* @param {object} obj - transformable object
* @returns {*}
*/
var removeNullsFromArrays = function (obj) {
var result;
if (_.isArray(obj)) {
result = [];
for (var i = 0, len = obj.length; i < len; i++) {
var val = obj[i];
if (null !== val) {
result.push(removeNullsFromArrays(val));
}
}
return result;
}
else if (_.isObject(obj)) {
result = {};
_.keys(obj).forEach(function (key) {
result[key] = removeNullsFromArrays(obj[key]);
});
return result;
}
else {
return obj;
}
};
suite('transform', function () {
test('object defaults', function () {
var joi = Joi.object(),
transformer = function (obj) {
obj.additionalProperties = true;
return obj;
},
schema = convert(joi, transformer),
expected = {
type: 'object',
properties: {},
additionalProperties: true // false
};
assert.validate(schema, expected);
});
test('complicated', function () {
var joi = Joi.object({
name: Joi.string().required(),
options: Joi.alternatives()
.when('name', {
is: 'foo',
then: Joi.alternatives().try([
Joi.object({
name: Joi.string().allow([null, '', 'foo']).required(),
size: Joi.string().valid('2x4').required(),
value: Joi.string().required()
}),
Joi.object({
name: Joi.string().valid('foo').required(),
size: Joi.string().valid('4x8').required(),
value: Joi.number().min(11).max(20).required()
})
])
})
.when('name', {
is: 'bar',
then: Joi.string().regex(/^[a-z]+$/)
})
.when('name', {
is: 'baz',
then: Joi.string().regex(/^[A-Z]+$/)
})
.required()
}),
schema = convert(joi, removeNullsFromArrays),
expected = require('./fixtures/transform.json');
assert.validate(schema, expected);
});
});

View File

@ -13,6 +13,7 @@
"http-errors": "1.3.1",
"i": "0.3.3",
"joi": "6.10.1",
"joi-to-json-schema": "2.0.5",
"js-yaml": "3.4.6",
"jshint": "2.8.0",
"lodash": "3.10.1",