Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

json-schema-merge-allof

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

json-schema-merge-allof - npm Package Compare versions

Comparing version 0.5.8 to 0.6.0

2

package.json
{
"name": "json-schema-merge-allof",
"version": "0.5.8",
"version": "0.6.0",
"description": "Simplify your schema by combining allOf into the root schema, safely.",

@@ -5,0 +5,0 @@ "main": "src/index.js",

@@ -94,2 +94,6 @@ # json-schema-merge-allof [![Build Status](https://travis-ci.org/mokkabonna/json-schema-merge-allof.svg?branch=master)](https://travis-ci.org/mokkabonna/json-schema-merge-allof) [![Coverage Status](https://coveralls.io/repos/github/mokkabonna/json-schema-merge-allof/badge.svg?branch=master)](https://coveralls.io/github/mokkabonna/json-schema-merge-allof?branch=master)

## Options
**ignoreAdditionalProperties** default **false**
Allows you to combine schema properties even though some schemas have `additionalProperties: false` This is the most common issue people face when trying to expand schemas using allOf and a limitation of the json schema spec. Be aware though that the schema produced will allow more than the original schema. But this is useful if just want to combine schemas using allOf as if additionalProperties wasn't false during the merge process. The resulting schema will still get additionalProperties set to false.
**resolvers** Object

@@ -101,3 +105,3 @@ Override any default resolver like this:

resolvers: {
title: function(values, key, mergeSchemas) {
title: function(values, path, mergeSchemas, options) {
// choose what title you want to be used based on the conflicting values

@@ -112,6 +116,34 @@ // resolvers MUST return a value other than undefined

- **values**: an array of the conflicting values that need to be resolved
- **key** the name of the keyword that caused the resolver to be called (useful if you use the same resolver for multiple keywords)
- **values** an array of the conflicting values that need to be resolved
- **path** an array of strings containing the path to the position in the schema that caused the resolver to be called (useful if you use the same resolver for multiple keywords, or want to implement specific logic for custom paths)
- **mergeSchemas** a function you can call that merges an array of schemas
- **options** the options mergeAllOf was called with
### Combined resolvers
No separate resolver is called for patternProperties and additionalProperties, only the properties resolver is called. Same for additionalItems, only items resolver is called. This is because those keywords need to be resolved together as they affect each other.
Those two resolvers are expected to return an object containing the resolved values of all the associated keywords. The keys must be the name of the keywords. So the properties resolver need to return an object like this containing the resolved values for each keyword:
```js
{
properties: ...,
patternProperties: ...,
additionalProperties: ...,
}
```
Also the resolve function is not passed **mergeSchemas**, but an object **mergers** that contains mergers for each of the related keywords. So properties get passed an object like this:
```js
var mergers = {
properties: function mergeSchemas(schemas, childSchemaName){...},
patternProperties: function mergeSchemas(schemas, childSchemaName){...},
additionalProperties: function mergeSchemas(schemas){...},
}
```
Some of the mergers requires you to supply a string of the name or index of the subschema you are currently merging. This is to make sure the path passed to child resolvers are correct.
### Default resolver
You can set a default resolver that catches any unknown keyword. Let's say you want to use the same strategy as the ones for the meta keywords, to use the first value found. You can accomplish that like this:

@@ -129,7 +161,3 @@

**ignoreAdditionalProperties** default **false**
Allows you to combine schema properties even though some schemas have `additionalProperties: false` This is the most common issue people face when trying to expand schemas using allOf and a limitation of the json schema spec. Be aware though that the schema produced will allow more than the original schema. But this is useful if just want to combine schemas using allOf as if additionalProperties wasn't false during the merge process. The resulting schema will still get additionalProperties set to false.
## Resolvers

@@ -136,0 +164,0 @@

@@ -43,5 +43,3 @@ var cloneDeep = require('lodash/cloneDeep')

[key]: a
}, {
[key]: b
})
}, {[key]: b})
}

@@ -70,3 +68,5 @@ }

return subSchemas.map(function(sub) {
if (!sub) return
if (!sub) {
return
}

@@ -87,5 +87,5 @@ if (Array.isArray(sub.items)) {

function tryMergeSchemaGroups(schemaGroups, mergeSchemas) {
return schemaGroups.map(function(schemas) {
return schemaGroups.map(function(schemas, index) {
try {
return mergeSchemas(schemas)
return mergeSchemas(schemas, index)
} catch (e) {

@@ -99,3 +99,5 @@ return undefined

return subSchemas.map(function(sub) {
if (!sub) return
if (!sub) {
return
}
if (Array.isArray(sub.items)) {

@@ -139,10 +141,12 @@ return sub.additionalItems

function throwIncompatible(values, key) {
function throwIncompatible(values, paths) {
var asJSON
try {
asJSON = JSON.stringify(values, null, 2)
asJSON = values.map(function(val) {
return JSON.stringify(val, null, 2)
}).join('\n')
} catch (variable) {
asJSON = values.join(', ')
}
throw new Error('Could not resolve values for keyword:"' + key + '". They are probably incompatible. Values: ' + asJSON)
throw new Error('Could not resolve values for path:"' + paths.join('.') + '". They are probably incompatible. Values: \n' + asJSON)
}

@@ -160,3 +164,13 @@

function callGroupResolver(keys, resolverName, schemas, mergeSchemas, options) {
function createRequiredSubMerger(mergeSchemas, key, parents) {
return function(schemas, subKey) {
if (subKey === undefined) {
throw new Error('You need to call merger with a key for the property name or index if array.')
}
subKey = String(subKey)
return mergeSchemas(schemas, null, parents.concat(key, subKey))
}
}
function callGroupResolver(keys, resolverName, schemas, mergeSchemas, options, parents) {
if (keys.length) {

@@ -177,6 +191,28 @@ var resolver = options.resolvers[resolverName]

var result = resolver(compacted, resolverName, mergeSchemas, options)
var related = resolverName === 'properties'
? propertyRelated
: itemsRelated
var mergers = related.reduce(function(all, key) {
if (contains(schemaGroupProps, key)) {
all[key] = createRequiredSubMerger(mergeSchemas, key, parents)
} else {
all[key] = function(schemas) {
return mergeSchemas(schemas, null, parents.concat(key))
}
}
return all
}, {})
if (resolverName === 'items') {
mergers.itemsArray = createRequiredSubMerger(mergeSchemas, 'items', parents)
mergers.items = function(schemas) {
return mergeSchemas(schemas, null, parents.concat('items'))
}
}
var result = resolver(compacted, parents.concat(resolverName), mergers, options)
if (!isPlainObject(result)) {
throwIncompatible(compacted, resolverName)
throwIncompatible(compacted, parents.concat(resolverName))
}

@@ -191,9 +227,13 @@

var allKeys = allUniqueKeys(source || group)
var extractor = source ? getItemSchemas : getValues
var extractor = source
? getItemSchemas
: getValues
return allKeys.reduce(function(all, key) {
var schemas = extractor(group, key)
var compacted = uniqWith(schemas.filter(notUndefined), compare)
all[key] = mergeSchemas(compacted)
all[key] = mergeSchemas(compacted, key)
return all
}, source ? [] : {})
}, source
? []
: {})
}

@@ -218,5 +258,3 @@

function createRequiredMetaArray(arr) {
return {
required: arr
}
return {required: arr}
}

@@ -238,6 +276,8 @@

var defaultResolvers = {
type(compacted, key) {
type(compacted) {
if (compacted.some(Array.isArray)) {
var normalized = compacted.map(function(val) {
return Array.isArray(val) ? val : [val]
return Array.isArray(val)
? val
: [val]
})

@@ -253,3 +293,3 @@ var common = intersection.apply(null, normalized)

},
properties(values, key, mergeSchemas, options) {
properties(values, key, mergers, options) {
// first get rid of all non permitted properties

@@ -267,3 +307,5 @@ if (!options.ignoreAdditionalProperties) {

additionalKeys.forEach(function(key) {
other.properties[key] = mergeSchemas([other.properties[key], subSchema.additionalProperties])
other.properties[key] = mergers.properties([
other.properties[key], subSchema.additionalProperties
], key)
})

@@ -288,5 +330,5 @@ })

var returnObject = {
additionalProperties: mergeSchemas(values.map(s => s.additionalProperties)),
patternProperties: mergeSchemaGroup(values.map(s => s.patternProperties), mergeSchemas),
properties: mergeSchemaGroup(values.map(s => s.properties), mergeSchemas)
additionalProperties: mergers.additionalProperties(values.map(s => s.additionalProperties)),
patternProperties: mergeSchemaGroup(values.map(s => s.patternProperties), mergers.patternProperties),
properties: mergeSchemaGroup(values.map(s => s.properties), mergers.properties)
}

@@ -300,3 +342,3 @@

},
dependencies(compacted, key, mergeSchemas) {
dependencies(compacted, paths, mergeSchemas) {
var allChildren = allUniqueKeys(compacted)

@@ -317,3 +359,3 @@

var arrayMetaScheams = innerArrays.map(createRequiredMetaArray)
all[childKey] = mergeSchemas(innerSchemas.concat(arrayMetaScheams))
all[childKey] = mergeSchemas(innerSchemas.concat(arrayMetaScheams), childKey)
}

@@ -325,7 +367,7 @@ return all

all[childKey] = mergeSchemas(innerCompacted)
all[childKey] = mergeSchemas(innerCompacted, childKey)
return all
}, {})
},
items(values, key, mergeSchemas) {
items(values, paths, mergers) {
var items = values.map(s => s.items)

@@ -336,5 +378,5 @@ var itemsCompacted = items.filter(notUndefined)

if (itemsCompacted.every(isSchema)) {
returnObject.items = mergeSchemas(items)
returnObject.items = mergers.items(items)
} else {
returnObject.items = mergeSchemaGroup(values, mergeSchemas, items)
returnObject.items = mergeSchemaGroup(values, mergers.itemsArray, items)
}

@@ -350,3 +392,3 @@

if (schemasAtLastPos) {
returnObject.additionalItems = mergeSchemas(schemasAtLastPos)
returnObject.additionalItems = mergers.additionalItems(schemasAtLastPos)
}

@@ -360,3 +402,3 @@

},
oneOf(compacted, key, mergeSchemas) {
oneOf(compacted, paths, mergeSchemas) {
var combinations = getAnyOfCombinations(cloneDeep(compacted))

@@ -371,11 +413,8 @@ var result = tryMergeSchemaGroups(combinations, mergeSchemas)

not(compacted) {
return {
anyOf: compacted
}
return {anyOf: compacted}
},
pattern(compacted, key, mergeSchemas, totalSchemas, reportUnresolved) {
pattern(compacted, paths, mergeSchemas, options, reportUnresolved) {
var key = paths.pop()
reportUnresolved(compacted.map(function(regexp) {
return {
[key]: regexp
}
return {[key]: regexp}
}))

@@ -392,3 +431,3 @@ },

},
enum(compacted, key) {
enum(compacted) {
var enums = intersectionWith.apply(null, compacted.concat(isEqual))

@@ -434,6 +473,8 @@ if (enums.length) {

function mergeSchemas(schemas, base) {
function mergeSchemas(schemas, base, parents) {
schemas = cloneDeep(schemas.filter(notUndefined))
parents = parents || []
var merged = isPlainObject(base)
? base : {}
? base
: {}

@@ -490,4 +531,14 @@ // return undefined, an empty schema

var merger
// get custom merger for groups
if (contains(schemaGroupProps, key) || contains(schemaArrays, key)) {
merger = createRequiredSubMerger(mergeSchemas, key, parents)
} else {
merger = function(schemas) {
return mergeSchemas(schemas, null, parents.concat(key))
}
}
var calledWithArray = false
merged[key] = resolver(compacted, key, mergeSchemas, totalSchemas, function(unresolvedSchemas) {
merged[key] = resolver(compacted, parents.concat(key), merger, options, function(unresolvedSchemas) {
calledWithArray = Array.isArray(unresolvedSchemas)

@@ -498,3 +549,3 @@ return addToAllOf(unresolvedSchemas)

if (merged[key] === undefined && !calledWithArray) {
throwIncompatible(compacted, key)
throwIncompatible(compacted, parents.concat(key))
} else if (merged[key] === undefined) {

@@ -506,4 +557,4 @@ delete merged[key]

Object.assign(merged, callGroupResolver(propertyKeys, 'properties', schemas, mergeSchemas, options))
Object.assign(merged, callGroupResolver(itemKeys, 'items', schemas, mergeSchemas, options))
Object.assign(merged, callGroupResolver(propertyKeys, 'properties', schemas, mergeSchemas, options, parents))
Object.assign(merged, callGroupResolver(itemKeys, 'items', schemas, mergeSchemas, options, parents))

@@ -510,0 +561,0 @@ function addToAllOf(unresolvedSchemas) {

@@ -752,3 +752,3 @@ var chai = require('chai')

it('merges contains using allOf', function() {
it('merges contains', function() {
var result = merger({

@@ -857,3 +857,3 @@ allOf: [{}, {

it('merges multipleOf by finding common lowest number', function() {
it('merges multipleOf by finding lowest common multiple (LCM)', function() {
var result = merger({

@@ -860,0 +860,0 @@ allOf: [{}, {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc