@cypress/schema-tools
Advanced tools
Comparing version 1.6.0 to 1.7.0
@@ -122,9 +122,17 @@ "use strict"; | ||
exports.SchemaError = SchemaError; | ||
exports.assertBySchema = function (schema, example, substitutions, label, formats, schemaVersion) { | ||
var AssertBySchemaDefaults = { | ||
substitutions: [], | ||
omit: { | ||
errors: false, | ||
object: false, | ||
example: false, | ||
}, | ||
}; | ||
exports.assertBySchema = function (schema, example, options, label, formats, schemaVersion) { | ||
if (example === void 0) { example = {}; } | ||
if (substitutions === void 0) { substitutions = []; } | ||
return function (object) { | ||
var allOptions = ramda_1.mergeDeepLeft(options || AssertBySchemaDefaults, AssertBySchemaDefaults); | ||
var replace = function () { | ||
var cloned = lodash_clonedeep_1.default(object); | ||
substitutions.forEach(function (property) { | ||
allOptions.substitutions.forEach(function (property) { | ||
var value = lodash_get_1.default(example, property); | ||
@@ -135,3 +143,3 @@ lodash_set_1.default(cloned, property, value); | ||
}; | ||
var replaced = substitutions.length ? replace() : object; | ||
var replaced = allOptions.substitutions.length ? replace() : object; | ||
var result = exports.validateBySchema(schema, formats)(replaced); | ||
@@ -142,28 +150,32 @@ if (result === true) { | ||
var title = label ? "Schema " + label + " violated" : 'Schema violated'; | ||
var start = [title, '', 'Errors:'] | ||
.concat(result) | ||
.concat(['', 'Current object:']); | ||
var objectString = json_stable_stringify_1.default(replaced, { space: ' ' }); | ||
var exampleString = json_stable_stringify_1.default(example, { space: ' ' }); | ||
var message = start.join('\n') + | ||
'\n' + | ||
objectString + | ||
'\n\n' + | ||
'Expected object like this:\n' + | ||
exampleString; | ||
throw new SchemaError(message, result, object, example, schema.title, schemaVersion); | ||
var emptyLine = ''; | ||
var parts = [title]; | ||
if (!allOptions.omit.errors) { | ||
parts = parts.concat([emptyLine, 'Errors:']).concat(result); | ||
} | ||
if (!allOptions.omit.object) { | ||
var objectString = json_stable_stringify_1.default(replaced, { space: ' ' }); | ||
parts = parts.concat([emptyLine, 'Current object:', objectString]); | ||
} | ||
if (!allOptions.omit.example) { | ||
var exampleString = json_stable_stringify_1.default(example, { space: ' ' }); | ||
parts = parts.concat([ | ||
emptyLine, | ||
'Expected object like this:', | ||
exampleString, | ||
]); | ||
} | ||
var message = parts.join('\n'); | ||
throw new SchemaError(message, result, replaced, example, schema.title, schemaVersion); | ||
}; | ||
}; | ||
exports.assertSchema = function (schemas, formats) { return function (name, version, substitutions) { | ||
if (substitutions === void 0) { substitutions = []; } | ||
return function (object) { | ||
var example = exports.getExample(schemas)(name)(version); | ||
var schema = exports.getObjectSchema(schemas)(name)(version); | ||
if (!schema) { | ||
throw new Error("Could not find schema " + name + "@" + version); | ||
} | ||
var label = name + "@" + version; | ||
return exports.assertBySchema(schema.schema, example, substitutions, label, formats, utils.semverToString(schema.version))(object); | ||
}; | ||
}; }; | ||
exports.assertSchema = function (schemas, formats) { return function (name, version, options) { return function (object) { | ||
var example = exports.getExample(schemas)(name)(version); | ||
var schema = exports.getObjectSchema(schemas)(name)(version); | ||
if (!schema) { | ||
throw new Error("Could not find schema " + name + "@" + version); | ||
} | ||
var label = name + "@" + version; | ||
return exports.assertBySchema(schema.schema, example, options, label, formats, utils.semverToString(schema.version))(object); | ||
}; }; }; | ||
var mergeSchemas = function (schemas) { | ||
@@ -170,0 +182,0 @@ return ramda_1.mergeAll(schemas); |
{ | ||
"name": "@cypress/schema-tools", | ||
"version": "1.6.0", | ||
"version": "1.7.0", | ||
"description": "Validate, sanitize and document JSON schemas", | ||
@@ -47,3 +47,3 @@ "main": "dist", | ||
"@types/lodash.camelcase": "4.3.3", | ||
"@types/node": "9.6.8", | ||
"@types/node": "9.6.9", | ||
"@types/ramda": "0.25.24", | ||
@@ -50,0 +50,0 @@ "ava": "0.25.0", |
@@ -101,3 +101,3 @@ # @cypress/schema-tools [](https://circleci.com/gh/cypress-io/schema-tools) [![renovate-app badge][renovate-badge]][renovate-app] | ||
// example JSON schema using uuid custom format | ||
const person100: ObjectSchema = { | ||
const employee100: ObjectSchema = { | ||
// has semantic version numbers | ||
@@ -112,3 +112,3 @@ version: { | ||
type: 'object', | ||
title: 'Person', | ||
title: 'Employee', | ||
properties: { | ||
@@ -125,4 +125,4 @@ id: { | ||
} | ||
// person100 goes into "schemas", then | ||
assertSchema(schemas, formats)('person', '1.0.0')(someObject) | ||
// employee100 goes into "schemas", then | ||
assertSchema(schemas, formats)('Employee', '1.0.0')(someObject) | ||
``` | ||
@@ -213,2 +213,32 @@ | ||
You can substitute some fields from example object to help with dynamic data. For example, to avoid breaking on invalid `id` value, we can tell `assertSchema` to use `id` value from the example object. | ||
```js | ||
const o = { | ||
name: 'Mary', | ||
age: -1, | ||
} | ||
assertSchema(schemas, formats)('Person', '1.0.0', { | ||
substitutions: ['age'], | ||
})(o) | ||
// everything is good, because the actual object asserted was | ||
// {name: 'Mary', age: 10} | ||
``` | ||
You can also limit the error message and omit some properties. Typically the error message with include list of errors, current and example objects, which might create a wall of text. To omit `object` and `example` but leave other fields when forming error message use | ||
```js | ||
const o = { | ||
name: 'Mary', | ||
age: -1, | ||
} | ||
assertSchema(schemas, formats)('Person', '1.0.0', { | ||
omit: { | ||
object: true, | ||
example: true, | ||
}, | ||
})(o) | ||
// Error message is much much shorter, only "errors" and label will be there | ||
``` | ||
### bind | ||
@@ -215,0 +245,0 @@ |
@@ -34,2 +34,3 @@ import { | ||
filter, | ||
mergeDeepLeft, | ||
} from 'ramda' | ||
@@ -274,6 +275,26 @@ import stringify from 'json-stable-stringify' | ||
type ErrorMessageWhiteList = { | ||
errors: boolean | ||
object: boolean | ||
example: boolean | ||
} | ||
type AssertBySchemaOptions = { | ||
substitutions: string[] | ||
omit: Partial<ErrorMessageWhiteList> | ||
} | ||
const AssertBySchemaDefaults: AssertBySchemaOptions = { | ||
substitutions: [], | ||
omit: { | ||
errors: false, | ||
object: false, | ||
example: false, | ||
}, | ||
} | ||
export const assertBySchema = ( | ||
schema: JsonSchema, | ||
example: PlainObject = {}, | ||
substitutions: string[] = [], | ||
options?: Partial<AssertBySchemaOptions>, | ||
label?: string, | ||
@@ -283,5 +304,10 @@ formats?: JsonSchemaFormats, | ||
) => (object: PlainObject) => { | ||
const allOptions = mergeDeepLeft( | ||
options || AssertBySchemaDefaults, | ||
AssertBySchemaDefaults, | ||
) | ||
const replace = () => { | ||
const cloned = cloneDeep(object) | ||
substitutions.forEach(property => { | ||
allOptions.substitutions.forEach(property => { | ||
const value = get(example, property) | ||
@@ -293,3 +319,3 @@ set(cloned, property, value) | ||
const replaced = substitutions.length ? replace() : object | ||
const replaced = allOptions.substitutions.length ? replace() : object | ||
const result = validateBySchema(schema, formats)(replaced) | ||
@@ -301,20 +327,29 @@ if (result === true) { | ||
const title = label ? `Schema ${label} violated` : 'Schema violated' | ||
const start = [title, '', 'Errors:'] | ||
.concat(result) | ||
.concat(['', 'Current object:']) | ||
const objectString = stringify(replaced, { space: ' ' }) | ||
const exampleString = stringify(example, { space: ' ' }) | ||
const emptyLine = '' | ||
let parts = [title] | ||
const message = | ||
start.join('\n') + | ||
'\n' + | ||
objectString + | ||
'\n\n' + | ||
'Expected object like this:\n' + | ||
exampleString | ||
if (!allOptions.omit.errors) { | ||
parts = parts.concat([emptyLine, 'Errors:']).concat(result) | ||
} | ||
if (!allOptions.omit.object) { | ||
const objectString = stringify(replaced, { space: ' ' }) | ||
parts = parts.concat([emptyLine, 'Current object:', objectString]) | ||
} | ||
if (!allOptions.omit.example) { | ||
const exampleString = stringify(example, { space: ' ' }) | ||
parts = parts.concat([ | ||
emptyLine, | ||
'Expected object like this:', | ||
exampleString, | ||
]) | ||
} | ||
const message = parts.join('\n') | ||
throw new SchemaError( | ||
message, | ||
result, | ||
object, | ||
replaced, | ||
example, | ||
@@ -346,5 +381,7 @@ schema.title, | ||
formats?: JsonSchemaFormats, | ||
) => (name: string, version: string, substitutions: string[] = []) => ( | ||
object: PlainObject, | ||
) => { | ||
) => ( | ||
name: string, | ||
version: string, | ||
options?: Partial<AssertBySchemaOptions>, | ||
) => (object: PlainObject) => { | ||
const example = getExample(schemas)(name)(version) | ||
@@ -361,3 +398,3 @@ const schema = getObjectSchema(schemas)(name)(version) | ||
example, | ||
substitutions, | ||
options, | ||
label, | ||
@@ -364,0 +401,0 @@ formats, |
66276
1646
287