json-schema-library
Advanced tools
Comparing version 4.1.0 to 4.1.1
module.exports = { | ||
DECLARATOR_ONEOF: "oneOfProperty", | ||
GET_TEMPLATE_RECURSION_LIMIT: 2, | ||
GET_TEMPLATE_RECURSION_LIMIT: 1, | ||
floatingPointPrecision: 10000, | ||
propertyBlacklist: ["_id"] | ||
}; |
@@ -1,2 +0,2 @@ | ||
/* eslint quote-props: 0 */ | ||
/* eslint quote-props: 0, max-statements-per-line: ["error", { "max": 2 }] */ | ||
const resolveOneOfFuzzy = require("./resolveOneOf.fuzzy"); | ||
@@ -10,17 +10,28 @@ const getTypeOf = require("./getTypeOf"); | ||
let cache; | ||
function resolveRef(core, schema) { | ||
if (schema.$ref == null) { | ||
return schema; | ||
} | ||
function shouldResolveRef(schema, pointer) { | ||
// ensure we refactored consistently | ||
if (pointer == null) { throw new Error("Missing pointer"); } | ||
const id = JSON.stringify(schema); | ||
if (cache[id] == null || cache[id] < settings.GET_TEMPLATE_RECURSION_LIMIT) { | ||
cache[id] = cache[id] || 0; | ||
cache[id] += 1; | ||
return core.resolveRef(schema); | ||
} | ||
return schema; | ||
const { $ref } = schema; | ||
if ($ref == null) { return true; } | ||
const value = (cache[pointer] == null || cache[pointer][$ref] == null) ? 0 : cache[pointer][$ref]; | ||
return value < settings.GET_TEMPLATE_RECURSION_LIMIT; | ||
} | ||
function resolveRef(core, schema, pointer) { | ||
// ensure we refactored consistently | ||
if (pointer == null) { throw new Error("missing pointer", pointer); } | ||
const { $ref } = schema; | ||
if ($ref == null) { return schema; } | ||
// @todo pointer + ref is redundant? | ||
cache[pointer] = cache[pointer] || {}; | ||
cache[pointer][$ref] = cache[pointer][$ref] || 0; | ||
cache[pointer][$ref] += 1; | ||
return core.resolveRef(schema); | ||
} | ||
function convertValue(type, value) { | ||
@@ -41,18 +52,42 @@ if (type === "string") { | ||
function createTemplateSchema(core, schema) { | ||
/** | ||
* Resolves $ref, allOf and anyOf schema-options, returning a combined json-schema. | ||
* Also returns a pointer-property on schema, that must be used as current pointer. | ||
* @param {Core} core | ||
* @param {JSONSchema} schema | ||
* @param {any} data | ||
* @param {JSONPointer} pointer | ||
* @return {JSONSchem} resolved json-schema or input-schema | ||
*/ | ||
function createTemplateSchema(core, schema, data, pointer) { | ||
// invalid schema | ||
if (getTypeOf(schema) !== "object") { | ||
return schema; | ||
return Object.assign({ pointer }, schema); | ||
} | ||
// return if reached recursion limit | ||
if (shouldResolveRef(schema, pointer) === false && data == null) { return false; } | ||
let templateSchema = copy(resolveRef(core, schema)); | ||
// resolve $ref and copy schema | ||
let templateSchema = copy(resolveRef(core, schema, pointer)); | ||
if (Array.isArray(schema.anyOf) && schema.anyOf.length > 0) { | ||
templateSchema = merge(templateSchema, resolveRef(core, schema.anyOf[0])); | ||
// test if we may resolve | ||
if (shouldResolveRef(schema.anyOf[0], `${pointer}/anyOf/0`)) { | ||
const resolvedAnyOf = resolveRef(core, schema.anyOf[0], `${pointer}/anyOf/0`); | ||
templateSchema = merge(templateSchema, resolvedAnyOf); | ||
// add pointer return-value, if any | ||
templateSchema.pointer = schema.anyOf[0].$ref || templateSchema.pointer; | ||
} | ||
delete templateSchema.anyOf; | ||
} | ||
// resolve allOf | ||
if (Array.isArray(schema.allOf)) { | ||
for (let i = 0, l = schema.allOf.length; i < l; i += 1) { | ||
templateSchema = merge(templateSchema, resolveRef(core, schema.allOf[i])); | ||
// test if we may resolve | ||
if (shouldResolveRef(schema.allOf[i], `${pointer}/allOf/${i}`)) { | ||
templateSchema = merge(templateSchema, resolveRef(core, schema.allOf[i], `${pointer}/allOf/${i}`)); | ||
// add pointer return-value, if any | ||
templateSchema.pointer = schema.allOf[i].$ref || templateSchema.pointer; | ||
} | ||
} | ||
@@ -62,6 +97,6 @@ delete templateSchema.allOf; | ||
templateSchema.pointer = templateSchema.pointer || schema.$ref || pointer; | ||
return templateSchema; | ||
} | ||
/** | ||
@@ -75,11 +110,10 @@ * Create data object matching the given schema | ||
*/ | ||
function getTemplate(core, data, schema) { | ||
if (schema == null) { | ||
throw new Error("getTemplate: missing schema for data", data); | ||
} | ||
function getTemplate(core, data, schema, pointer) { | ||
if (schema == null) { throw new Error("getTemplate: missing schema for data", data); } | ||
if (pointer == null) { throw new Error("Missing pointer"); } | ||
// resolve $ref references | ||
schema = resolveRef(core, schema); | ||
// resolve allOf and first anyOf definitions | ||
schema = createTemplateSchema(core, schema); | ||
// resolve $ref references, allOf and first anyOf definitions | ||
schema = createTemplateSchema(core, schema, data, pointer); | ||
if (schema === false) { return undefined; } | ||
pointer = schema.pointer; | ||
@@ -92,4 +126,4 @@ if (schema.oneOf) { | ||
} else if (resolvedSchema.type === "error") { | ||
return resolvedSchema; | ||
// @todo - check: do not return schema, but either input-data or undefined (clearing wrong data) | ||
return data; | ||
} else { | ||
@@ -101,19 +135,16 @@ schema = resolvedSchema; | ||
if (schema.type == null) { | ||
console.warn(`Invalid json-schema: missing property 'type' for ${data && JSON.stringify(data)}`); | ||
return ""; | ||
return undefined; | ||
} | ||
// reset invalid type | ||
if (data != null && getTypeOf(data) !== schema.type) { | ||
// reset invalid type | ||
// console.error("Schema does not match data", data, "schema:", schema); | ||
data = convertValue(schema.type, data); | ||
} | ||
// eslint-disable-next-line no-use-before-define | ||
if (TYPE[schema.type] == null) { | ||
if (TYPE[schema.type] == null) { // eslint-disable-line no-use-before-define | ||
throw new Error(`Unsupported type '${schema.type} in ${JSON.stringify(schema)}'`); | ||
} | ||
// eslint-disable-next-line no-use-before-define | ||
return TYPE[schema.type](core, schema, data); | ||
const templateData = TYPE[schema.type](core, schema, data, pointer); // eslint-disable-line no-use-before-define | ||
return templateData; | ||
} | ||
@@ -127,19 +158,19 @@ | ||
"boolean": (core, schema, data) => getDefault(schema, data, false), | ||
"object": (core, schema, data) => { | ||
"object": (core, schema, data, pointer) => { | ||
const template = schema.default === undefined ? {} : schema.default; | ||
data = data || {}; | ||
const d = data || {}; | ||
if (schema.properties) { | ||
Object.keys(schema.properties).forEach(key => { | ||
const value = data[key] == null ? template[key] : data[key]; | ||
data[key] = getTemplate(core, value, schema.properties[key]); | ||
const value = (data == null || data[key] == null) ? template[key] : data[key]; | ||
d[key] = getTemplate(core, value, schema.properties[key], `${pointer}/properties/${key}`); | ||
}); | ||
} | ||
return data; | ||
return d; | ||
}, | ||
// build array type of items, ignores additionalItems | ||
"array": (core, schema, data) => { | ||
"array": (core, schema, data, pointer) => { | ||
const template = schema.default === undefined ? [] : schema.default; | ||
data = data || []; | ||
const d = data || []; | ||
schema.minItems = schema.minItems || 0; | ||
@@ -149,3 +180,3 @@ | ||
if (schema.items == null) { | ||
return data; | ||
return d; | ||
} | ||
@@ -156,5 +187,5 @@ | ||
for (let i = 0, l = Math.min(schema.minItems, schema.items.length); i < l; i += 1) { | ||
data[i] = getTemplate(core, data[i] == null ? template[i] : data[i], schema.items[i]); | ||
d[i] = getTemplate(core, d[i] == null ? template[i] : d[i], schema.items[i], `${pointer}/items/${i}`); | ||
} | ||
return data; | ||
return d; | ||
} | ||
@@ -164,28 +195,33 @@ | ||
if (getTypeOf(schema.items) !== "object") { | ||
return data; | ||
return d; | ||
} | ||
// resolve allOf and first anyOf definition | ||
const templateSchema = createTemplateSchema(core, schema.items); | ||
const templateSchema = createTemplateSchema(core, schema.items, data, pointer); | ||
if (templateSchema === false) { | ||
return d; | ||
} | ||
pointer = templateSchema.pointer || pointer; | ||
// build oneOf | ||
if (templateSchema.oneOf && data.length === 0) { | ||
if (templateSchema.oneOf && d.length === 0) { | ||
const oneOfSchema = templateSchema.oneOf[0]; | ||
for (let i = 0; i < schema.minItems; i += 1) { | ||
data[i] = getTemplate(core, data[i] == null ? template[i] : data[i], templateSchema.oneOf[0]); | ||
d[i] = getTemplate(core, d[i] == null ? template[i] : d[i], oneOfSchema, `${pointer}/oneOf/0`); | ||
} | ||
return data; | ||
return d; | ||
} | ||
if (templateSchema.oneOf && data.length > 0) { | ||
const itemCount = Math.max(schema.minItems, data.length); | ||
if (templateSchema.oneOf && d.length > 0) { | ||
const itemCount = Math.max(schema.minItems, d.length); | ||
for (let i = 0; i < itemCount; i += 1) { | ||
const value = data[i] == null ? template[i] : data[i]; | ||
const value = d[i] == null ? template[i] : d[i]; | ||
const one = resolveOneOfFuzzy(core, value, templateSchema); | ||
if (one) { | ||
data[i] = getTemplate(core, value, one); | ||
d[i] = getTemplate(core, value, one, `${pointer}/oneOf/${i}`); | ||
} else { | ||
data[i] = value; | ||
d[i] = value; | ||
} | ||
} | ||
return data; | ||
return d; | ||
} | ||
@@ -195,9 +231,9 @@ | ||
if (templateSchema.type) { | ||
for (let i = 0, l = Math.max(schema.minItems, data.length); i < l; i += 1) { | ||
data[i] = getTemplate(core, data[i] == null ? template[i] : data[i], templateSchema); | ||
for (let i = 0, l = Math.max(schema.minItems, d.length); i < l; i += 1) { | ||
d[i] = getTemplate(core, d[i] == null ? template[i] : d[i], templateSchema, `${pointer}/items`); | ||
} | ||
return data; | ||
return d; | ||
} | ||
return data; | ||
return d; | ||
} | ||
@@ -221,3 +257,3 @@ }; | ||
cache = { "mi": ".." }; | ||
return getTemplate(core, data, schema); | ||
return getTemplate(core, data, schema, "#"); | ||
}; |
@@ -102,3 +102,3 @@ const getTypeOf = require("./getTypeOf"); | ||
// check if there is a oneOf selection, which must be resolved | ||
if (targetSchema.oneOf && Array.isArray(targetSchema.oneOf)) { | ||
if (targetSchema && Array.isArray(targetSchema.oneOf)) { | ||
// @special case: this is a mix of a schema and optional definitions | ||
@@ -105,0 +105,0 @@ // we resolve the schema here and add the original schema to `oneOfSchema` |
{ | ||
"name": "json-schema-library", | ||
"version": "4.1.0", | ||
"version": "4.1.1", | ||
"description": "Customizable and hackable json-validator and json-schema utilities for traversal, data generation and validation", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "npm run test-unit && npm run test-spec && npm run test-integration", | ||
"test": "mocha --recursive -R dot 'test/**/*.test.js'", | ||
"test-integration": "mocha --recursive -R spec 'test/integration/**/*.test.js'", | ||
@@ -24,3 +24,3 @@ "test-unit": "mocha --recursive -R spec 'test/unit/**/*.test.js'", | ||
"author": "Sascha Goldhofer <noreply@saschagoldhofer.de> (https://github.com/sagold/)", | ||
"license": "ISC", | ||
"license": "MIT", | ||
"bugs": { | ||
@@ -33,3 +33,3 @@ "url": "https://github.com/sagold/json-schema-library/issues" | ||
"chalk": "^2.3.0", | ||
"eslint": "^2.7.0", | ||
"eslint": "^6.6.0", | ||
"glob": "^7.1.2", | ||
@@ -36,0 +36,0 @@ "json-schema-test-suite": "json-schema-org/JSON-Schema-Test-Suite.git#master", |
2273
119197
58