fatsify核心功能示例测试!!!

This commit is contained in:
2025-09-21 14:50:41 +08:00
commit 9145aea047
1958 changed files with 230098 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
# Set default behavior to automatically convert line endings
* text=auto eol=lf

View File

@@ -0,0 +1,13 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 10
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10

View File

@@ -0,0 +1,23 @@
name: CI
on:
push:
branches:
- main
- master
- next
- 'v*'
paths-ignore:
- 'docs/**'
- '*.md'
pull_request:
paths-ignore:
- 'docs/**'
- '*.md'
jobs:
test:
uses: fastify/workflows/.github/workflows/plugins-ci.yml@v5
with:
license-check: true
lint: true

21
node_modules/@fastify/merge-json-schemas/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Fastify
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

119
node_modules/@fastify/merge-json-schemas/README.md generated vendored Normal file
View File

@@ -0,0 +1,119 @@
# @fastify/merge-json-schemas
[![CI](https://github.com/fastify/merge-json-schemas/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/merge-json-schemas/actions/workflows/ci.yml)
[![npm version](https://img.shields.io/npm/v/@fastify/merge-json-schemas)](https://www.npmjs.com/package/@fastify/merge-json-schemas)
[![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)
__merge-json-schemas__ is a JavaScript library that builds a logical product (AND) for multiple [JSON schemas](https://json-schema.org/draft/2020-12/json-schema-core#name-introduction).
- [Installation](#installation)
- [Usage](#usage)
- [API](#api)
- [mergeSchemas(schemas, options)](#mergeschemasschemas-options)
- [resolvers](#resolvers)
- [defaultResolver](#defaultresolver)
- [License](#license)
<a name="installation"></a>
## Installation
```bash
npm i @fastify/merge-json-schemas
```
<a name="usage"></a>
## Usage
```javascript
const assert = require('node:assert')
const { mergeSchemas } = require('@fastify/merge-json-schemas');
const schema1 = {
$id: 'schema1',
type: 'object',
properties: {
foo: { type: 'string', enum: ['foo1', 'foo2'] },
bar: { type: 'string', minLength: 3 }
}
}
const schema2 = {
$id: 'schema1',
type: 'object',
properties: {
foo: { type: 'string', enum: ['foo1', 'foo3'] },
bar: { type: 'string', minLength: 5 }
},
required: ['foo']
}
const mergedSchema = mergeSchemas([schema1, schema2])
assert.deepStrictEqual(mergedSchema, {
$id: 'schema1',
type: 'object',
properties: {
foo: { type: 'string', enum: ['foo1'] },
bar: { type: 'string', minLength: 5 }
},
required: ['foo']
})
```
<a name="api"></a>
## API
<a name="merge-schemas"></a>
#### mergeSchemas(schemas, options)
Builds a logical conjunction (AND) of multiple [JSON schemas](https://json-schema.org/draft/2020-12/json-schema-core#name-introduction).
- `schemas` __\<objects[]\>__ - list of JSON schemas to merge
- `options` __\<object\>__ - optional options
- `resolvers` __\<object\>__ - custom resolvers for JSON schema keywords. Each key is the name of a JSON schema keyword. Each value is a resolver function. See [keywordResolver](#keywordresolver-keyword-values-mergedschema-parentschemas-options)
- `defaultResolver` __\<function\>__ - custom default resolver for JSON schema keywords. See [keywordResolver](#keywordresolver-keyword-values-mergedschema-parentschemas-options)
- `onConflict` __\<string\>__ - action to take when a conflict is found. Used by the default `defaultResolver`. Default is `throw`. Possible values are:
- `throw` - throws an error multiple different schemas for the same keyword are found
- `ignore` - do nothing if multiple different schemas for the same keyword are found
- `first` - use the value of the first schema if multiple different schemas for the same keyword are found
#### resolvers
A list of default resolvers that __merge-json-schema__ uses to merge JSON schemas. You can override the default resolvers by passing a list of custom resolvers in the `options` argument of `mergeSchemas`. See [keywordResolver](#keywordresolver-keyword-values-mergedschema-parentschemas-options).
#### defaultResolver
A default resolver that __merge-json-schema__ uses to merge JSON schemas. Default resolver is used when no custom resolver is defined for a JSON schema keyword. By default, the default resolver works as follows:
- If only one schema contains the keyword, the value of the keyword is used as the merged value
- If multiple schemas contain the exact same value for the keyword, the value of the keyword is used as the merged value
- If multiple schemas contain different values for the keyword, it throws an error
#### keywordResolver (keyword, values, mergedSchema, parentSchemas, options)
__merge-json-schema__ uses a set of resolvers to merge JSON schemas. Each resolver is associated with a JSON schema keyword. The resolver is called when the keyword is found in the schemas to merge. The resolver is called with the following arguments:
- `keyword` __\<string\>__ - the name of the keyword to merge
- `values` __\<any[]\>__ - the values of the keyword to merge. The length of the array is equal to the number of schemas to merge. If a schema does not contain the keyword, the value is `undefined`
- `mergedSchema` __\<object\>__ - an instance of the merged schema
- `parentSchemas` __\<object[]\>__ - the list of parent schemas
- `options` __\<object\>__ - the options passed to `mergeSchemas`
The resolver must set the merged value of the `keyword` in the `mergedSchema` object.
__Example:__ resolver for the `minNumber` keyword.
```javascript
function minNumberResolver (keyword, values, mergedSchema) {
mergedSchema[keyword] = Math.min(...values)
}
```
<a name="license"></a>
## License
Licensed under [MIT](./LICENSE).

View File

@@ -0,0 +1,6 @@
'use strict'
module.exports = require('neostandard')({
ignores: require('neostandard').resolveIgnoresFromGitignore(),
ts: true
})

357
node_modules/@fastify/merge-json-schemas/index.js generated vendored Normal file
View File

@@ -0,0 +1,357 @@
'use strict'
const { dequal: deepEqual } = require('dequal')
const resolvers = require('./lib/resolvers')
const errors = require('./lib/errors')
const keywordsResolvers = {
$id: resolvers.skip,
type: resolvers.hybridArraysIntersection,
enum: resolvers.arraysIntersection,
minLength: resolvers.maxNumber,
maxLength: resolvers.minNumber,
minimum: resolvers.maxNumber,
maximum: resolvers.minNumber,
multipleOf: resolvers.commonMultiple,
exclusiveMinimum: resolvers.maxNumber,
exclusiveMaximum: resolvers.minNumber,
minItems: resolvers.maxNumber,
maxItems: resolvers.minNumber,
maxProperties: resolvers.minNumber,
minProperties: resolvers.maxNumber,
const: resolvers.allEqual,
default: resolvers.allEqual,
format: resolvers.allEqual,
required: resolvers.arraysUnion,
properties: mergeProperties,
patternProperties: mergeObjects,
additionalProperties: mergeSchemasResolver,
items: mergeItems,
additionalItems: mergeAdditionalItems,
definitions: mergeObjects,
$defs: mergeObjects,
nullable: resolvers.booleanAnd,
oneOf: mergeOneOf,
anyOf: mergeOneOf,
allOf: resolvers.arraysUnion,
not: mergeSchemasResolver,
if: mergeIfThenElseSchemas,
then: resolvers.skip,
else: resolvers.skip,
dependencies: mergeDependencies,
dependentRequired: mergeDependencies,
dependentSchemas: mergeObjects,
propertyNames: mergeSchemasResolver,
uniqueItems: resolvers.booleanOr,
contains: mergeSchemasResolver
}
function mergeSchemasResolver (keyword, values, mergedSchema, _schemas, options) {
mergedSchema[keyword] = _mergeSchemas(values, options)
}
function cartesianProduct (arrays) {
let result = [[]]
for (const array of arrays) {
const temp = []
for (const x of result) {
for (const y of array) {
temp.push([...x, y])
}
}
result = temp
}
return result
}
function mergeOneOf (keyword, values, mergedSchema, _schemas, options) {
if (values.length === 1) {
mergedSchema[keyword] = values[0]
return
}
const product = cartesianProduct(values)
const mergedOneOf = []
for (const combination of product) {
try {
const mergedSchema = _mergeSchemas(combination, options)
if (mergedSchema !== undefined) {
mergedOneOf.push(mergedSchema)
}
} catch (error) {
// If this combination is not valid, we can ignore it.
if (error instanceof errors.MergeError) continue
throw error
}
}
mergedSchema[keyword] = mergedOneOf
}
function getSchemaForItem (schema, index) {
const { items, additionalItems } = schema
if (Array.isArray(items)) {
if (index < items.length) {
return items[index]
}
return additionalItems
}
if (items !== undefined) {
return items
}
return additionalItems
}
function mergeItems (keyword, values, mergedSchema, schemas, options) {
let maxArrayItemsLength = 0
for (const itemsSchema of values) {
if (Array.isArray(itemsSchema)) {
maxArrayItemsLength = Math.max(maxArrayItemsLength, itemsSchema.length)
}
}
if (maxArrayItemsLength === 0) {
mergedSchema[keyword] = _mergeSchemas(values, options)
return
}
const mergedItemsSchemas = []
for (let i = 0; i < maxArrayItemsLength; i++) {
const indexItemSchemas = []
for (const schema of schemas) {
const itemSchema = getSchemaForItem(schema, i)
if (itemSchema !== undefined) {
indexItemSchemas.push(itemSchema)
}
}
mergedItemsSchemas[i] = _mergeSchemas(indexItemSchemas, options)
}
mergedSchema[keyword] = mergedItemsSchemas
}
function mergeAdditionalItems (keyword, values, mergedSchema, schemas, options) {
let hasArrayItems = false
for (const schema of schemas) {
if (Array.isArray(schema.items)) {
hasArrayItems = true
break
}
}
if (!hasArrayItems) {
mergedSchema[keyword] = _mergeSchemas(values, options)
return
}
const mergedAdditionalItemsSchemas = []
for (const schema of schemas) {
let additionalItemsSchema = schema.additionalItems
if (
additionalItemsSchema === undefined &&
!Array.isArray(schema.items)
) {
additionalItemsSchema = schema.items
}
if (additionalItemsSchema !== undefined) {
mergedAdditionalItemsSchemas.push(additionalItemsSchema)
}
}
mergedSchema[keyword] = _mergeSchemas(mergedAdditionalItemsSchemas, options)
}
function getSchemaForProperty (schema, propertyName) {
const { properties, patternProperties, additionalProperties } = schema
if (properties?.[propertyName] !== undefined) {
return properties[propertyName]
}
for (const pattern of Object.keys(patternProperties ?? {})) {
const regexp = new RegExp(pattern)
if (regexp.test(propertyName)) {
return patternProperties[pattern]
}
}
return additionalProperties
}
function mergeProperties (keyword, _values, mergedSchema, schemas, options) {
const foundProperties = {}
for (const currentSchema of schemas) {
const properties = currentSchema.properties ?? {}
for (const propertyName of Object.keys(properties)) {
if (foundProperties[propertyName] !== undefined) continue
const propertySchema = properties[propertyName]
foundProperties[propertyName] = [propertySchema]
for (const anotherSchema of schemas) {
if (currentSchema === anotherSchema) continue
const propertySchema = getSchemaForProperty(anotherSchema, propertyName)
if (propertySchema !== undefined) {
foundProperties[propertyName].push(propertySchema)
}
}
}
}
const mergedProperties = {}
for (const property of Object.keys(foundProperties)) {
const propertySchemas = foundProperties[property]
mergedProperties[property] = _mergeSchemas(propertySchemas, options)
}
mergedSchema[keyword] = mergedProperties
}
function mergeObjects (keyword, values, mergedSchema, _schemas, options) {
const objectsProperties = {}
for (const properties of values) {
for (const propertyName of Object.keys(properties)) {
if (objectsProperties[propertyName] === undefined) {
objectsProperties[propertyName] = []
}
objectsProperties[propertyName].push(properties[propertyName])
}
}
const mergedProperties = {}
for (const propertyName of Object.keys(objectsProperties)) {
const propertySchemas = objectsProperties[propertyName]
const mergedPropertySchema = _mergeSchemas(propertySchemas, options)
mergedProperties[propertyName] = mergedPropertySchema
}
mergedSchema[keyword] = mergedProperties
}
function mergeIfThenElseSchemas (_keyword, _values, mergedSchema, schemas, options) {
for (let i = 0; i < schemas.length; i++) {
const subSchema = {
if: schemas[i].if,
then: schemas[i].then,
else: schemas[i].else
}
if (subSchema.if === undefined) continue
if (mergedSchema.if === undefined) {
mergedSchema.if = subSchema.if
if (subSchema.then !== undefined) {
mergedSchema.then = subSchema.then
}
if (subSchema.else !== undefined) {
mergedSchema.else = subSchema.else
}
continue
}
if (mergedSchema.then !== undefined) {
mergedSchema.then = _mergeSchemas([mergedSchema.then, subSchema], options)
}
if (mergedSchema.else !== undefined) {
mergedSchema.else = _mergeSchemas([mergedSchema.else, subSchema], options)
}
}
}
function mergeDependencies (keyword, values, mergedSchema) {
const mergedDependencies = {}
for (const dependencies of values) {
for (const propertyName of Object.keys(dependencies)) {
if (mergedDependencies[propertyName] === undefined) {
mergedDependencies[propertyName] = []
}
const mergedPropertyDependencies = mergedDependencies[propertyName]
for (const propertyDependency of dependencies[propertyName]) {
if (!mergedPropertyDependencies.includes(propertyDependency)) {
mergedPropertyDependencies.push(propertyDependency)
}
}
}
}
mergedSchema[keyword] = mergedDependencies
}
function _mergeSchemas (schemas, options) {
if (schemas.length === 0) return {}
if (schemas.length === 1) return schemas[0]
const mergedSchema = {}
const keywords = {}
let allSchemasAreTrue = true
for (const schema of schemas) {
if (schema === false) return false
if (schema === true) continue
allSchemasAreTrue = false
for (const keyword of Object.keys(schema)) {
if (keywords[keyword] === undefined) {
keywords[keyword] = []
}
keywords[keyword].push(schema[keyword])
}
}
if (allSchemasAreTrue) return true
for (const keyword of Object.keys(keywords)) {
const keywordValues = keywords[keyword]
const resolver = options.resolvers[keyword] ?? options.defaultResolver
resolver(keyword, keywordValues, mergedSchema, schemas, options)
}
return mergedSchema
}
function defaultResolver (keyword, values, mergedSchema, _schemas, options) {
const onConflict = options.onConflict ?? 'throw'
if (values.length === 1 || onConflict === 'first') {
mergedSchema[keyword] = values[0]
return
}
let allValuesEqual = true
for (let i = 1; i < values.length; i++) {
if (!deepEqual(values[i], values[0])) {
allValuesEqual = false
break
}
}
if (allValuesEqual) {
mergedSchema[keyword] = values[0]
return
}
if (onConflict === 'throw') {
throw new errors.ResolverNotFoundError(keyword, values)
}
if (onConflict === 'skip') {
return
}
throw new errors.InvalidOnConflictOptionError(onConflict)
}
function mergeSchemas (schemas, options = {}) {
if (options.defaultResolver === undefined) {
options.defaultResolver = defaultResolver
}
options.resolvers = { ...keywordsResolvers, ...options.resolvers }
const mergedSchema = _mergeSchemas(schemas, options)
return mergedSchema
}
module.exports = { mergeSchemas, keywordsResolvers, defaultResolver, ...errors }

36
node_modules/@fastify/merge-json-schemas/lib/errors.js generated vendored Normal file
View File

@@ -0,0 +1,36 @@
'use strict'
class MergeError extends Error {
constructor (keyword, schemas) {
super()
this.name = 'JsonSchemaMergeError'
this.code = 'JSON_SCHEMA_MERGE_ERROR'
this.message = `Failed to merge "${keyword}" keyword schemas.`
this.schemas = schemas
}
}
class ResolverNotFoundError extends Error {
constructor (keyword, schemas) {
super()
this.name = 'JsonSchemaMergeError'
this.code = 'JSON_SCHEMA_MERGE_ERROR'
this.message = `Resolver for "${keyword}" keyword not found.`
this.schemas = schemas
}
}
class InvalidOnConflictOptionError extends Error {
constructor (onConflict) {
super()
this.name = 'JsonSchemaMergeError'
this.code = 'JSON_SCHEMA_MERGE_ERROR'
this.message = `Invalid "onConflict" option: "${onConflict}".`
}
}
module.exports = {
MergeError,
ResolverNotFoundError,
InvalidOnConflictOptionError
}

View File

@@ -0,0 +1,127 @@
'use strict'
const { dequal: deepEqual } = require('dequal')
const { MergeError } = require('./errors')
function _arraysIntersection (arrays) {
let intersection = arrays[0]
for (let i = 1; i < arrays.length; i++) {
intersection = intersection.filter(
value => arrays[i].includes(value)
)
}
return intersection
}
function arraysIntersection (keyword, values, mergedSchema) {
const intersection = _arraysIntersection(values)
if (intersection.length === 0) {
throw new MergeError(keyword, values)
}
mergedSchema[keyword] = intersection
}
function hybridArraysIntersection (keyword, values, mergedSchema) {
for (let i = 0; i < values.length; i++) {
if (!Array.isArray(values[i])) {
values[i] = [values[i]]
}
}
const intersection = _arraysIntersection(values)
if (intersection.length === 0) {
throw new MergeError(keyword, values)
}
if (intersection.length === 1) {
mergedSchema[keyword] = intersection[0]
} else {
mergedSchema[keyword] = intersection
}
}
function arraysUnion (keyword, values, mergedSchema) {
const union = []
for (const array of values) {
for (const value of array) {
if (!union.includes(value)) {
union.push(value)
}
}
}
mergedSchema[keyword] = union
}
function minNumber (keyword, values, mergedSchema) {
mergedSchema[keyword] = Math.min(...values)
}
function maxNumber (keyword, values, mergedSchema) {
mergedSchema[keyword] = Math.max(...values)
}
function commonMultiple (keyword, values, mergedSchema) {
const gcd = (a, b) => (!b ? a : gcd(b, a % b))
const lcm = (a, b) => (a * b) / gcd(a, b)
let scale = 1
for (const value of values) {
while (value * scale % 1 !== 0) {
scale *= 10
}
}
let multiple = values[0] * scale
for (const value of values) {
multiple = lcm(multiple, value * scale)
}
mergedSchema[keyword] = multiple / scale
}
function allEqual (keyword, values, mergedSchema) {
const firstValue = values[0]
for (let i = 1; i < values.length; i++) {
if (!deepEqual(values[i], firstValue)) {
throw new MergeError(keyword, values)
}
}
mergedSchema[keyword] = firstValue
}
function skip () {}
function booleanAnd (keyword, values, mergedSchema) {
for (const value of values) {
if (value === false) {
mergedSchema[keyword] = false
return
}
}
mergedSchema[keyword] = true
}
function booleanOr (keyword, values, mergedSchema) {
for (const value of values) {
if (value === true) {
mergedSchema[keyword] = true
return
}
}
mergedSchema[keyword] = false
}
module.exports = {
arraysIntersection,
hybridArraysIntersection,
arraysUnion,
minNumber,
maxNumber,
commonMultiple,
allEqual,
booleanAnd,
booleanOr,
skip
}

67
node_modules/@fastify/merge-json-schemas/package.json generated vendored Normal file
View File

@@ -0,0 +1,67 @@
{
"name": "@fastify/merge-json-schemas",
"version": "0.2.1",
"description": "Builds a logical conjunction (AND) of multiple JSON schemas",
"main": "index.js",
"type": "commonjs",
"types": "types/index.d.ts",
"scripts": {
"lint": "eslint",
"lint:fix": "eslint --fix",
"test": "npm run test:unit && npm run test:types",
"test:unit": "c8 --100 node --test",
"test:types": "tsd"
},
"repository": {
"type": "git",
"url": "git+https://github.com/fastify/merge-json-schemas.git"
},
"keywords": [
"json",
"schema",
"merge",
"allOf"
],
"author": "Ivan Tymoshenko <ivan@tymoshenko.me>",
"contributors": [
{
"name": "Matteo Collina",
"email": "hello@matteocollina.com"
},
{
"name": "Frazer Smith",
"email": "frazer.dev@icloud.com",
"url": "https://github.com/fdawgs"
},
{
"name": "Gürgün Dayıoğlu",
"email": "hey@gurgun.day",
"url": "https://heyhey.to/G"
}
],
"license": "MIT",
"bugs": {
"url": "https://github.com/fastify/merge-json-schemas/issues"
},
"homepage": "https://github.com/fastify/merge-json-schemas#readme",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"devDependencies": {
"@fastify/pre-commit": "^2.1.0",
"c8": "^10.1.3",
"eslint": "^9.17.0",
"neostandard": "^0.12.0",
"tsd": "^0.31.2"
},
"dependencies": {
"dequal": "^2.0.3"
}
}

View File

@@ -0,0 +1,164 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and additionalItems = false keyword', () => {
const schema1 = { type: 'array' }
const schema2 = {
type: 'array',
additionalItems: false
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
additionalItems: false
})
})
test('should merge two schemas with boolean additionalItems', () => {
const schema1 = {
type: 'array',
additionalItems: true
}
const schema2 = {
type: 'array',
additionalItems: false
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
additionalItems: false
})
})
test('should merge additionalItems schema with false value', () => {
const schema1 = {
type: 'array',
additionalItems: {
type: 'string'
}
}
const schema2 = {
type: 'array',
additionalItems: false
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
additionalItems: false
})
})
test('should merge additionalItems schema with true value', () => {
const schema1 = {
type: 'array',
additionalItems: {
type: 'string'
}
}
const schema2 = {
type: 'array',
additionalItems: true
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
additionalItems: {
type: 'string'
}
})
})
test('should merge two additionalItems schemas', () => {
const schema1 = {
type: 'array',
additionalItems: {
type: 'string'
}
}
const schema2 = {
type: 'array',
additionalItems: {
type: 'string', minLength: 1
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
additionalItems: {
type: 'string', minLength: 1
}
})
})
test('should merge additionalItems with items array', () => {
const schema1 = {
type: 'array',
items: [
{ type: 'string', const: 'foo1' },
{ type: 'string', const: 'foo2' },
{ type: 'string', const: 'foo3' }
]
}
const schema2 = {
type: 'array',
additionalItems: {
type: 'string', minLength: 42
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
items: [
{ type: 'string', const: 'foo1', minLength: 42 },
{ type: 'string', const: 'foo2', minLength: 42 },
{ type: 'string', const: 'foo3', minLength: 42 }
],
additionalItems: {
type: 'string', minLength: 42
}
})
})
test('should merge items array and additionalItems with items array', () => {
const schema1 = {
type: 'array',
items: [
{ type: 'string', const: 'foo1' },
{ type: 'string', const: 'foo2' },
{ type: 'string', const: 'foo3' }
]
}
const schema2 = {
type: 'array',
items: [
{ type: 'string', minLength: 1 },
{ type: 'string', minLength: 2 }
],
additionalItems: {
type: 'string', minLength: 3
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
items: [
{ type: 'string', const: 'foo1', minLength: 1 },
{ type: 'string', const: 'foo2', minLength: 2 },
{ type: 'string', const: 'foo3', minLength: 3 }
],
additionalItems: {
type: 'string', minLength: 3
}
})
})

View File

@@ -0,0 +1,129 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and additionalProperties=false keyword', () => {
const schema1 = { type: 'object' }
const schema2 = {
type: 'object',
additionalProperties: false
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
additionalProperties: false
})
})
test('should merge two schemas with boolean additionalProperties', () => {
const schema1 = {
type: 'object',
additionalProperties: true
}
const schema2 = {
type: 'object',
additionalProperties: false
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
additionalProperties: false
})
})
test('should merge additionalProperties schema with false value', () => {
const schema1 = {
type: 'object',
additionalProperties: {
type: 'string'
}
}
const schema2 = {
type: 'object',
additionalProperties: false
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
additionalProperties: false
})
})
test('should merge additionalProperties schema with true value', () => {
const schema1 = {
type: 'object',
additionalProperties: {
type: 'string'
}
}
const schema2 = {
type: 'object',
additionalProperties: true
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
additionalProperties: {
type: 'string'
}
})
})
test('should merge two additionalProperties schemas', () => {
const schema1 = {
type: 'object',
additionalProperties: {
type: 'string'
}
}
const schema2 = {
type: 'object',
additionalProperties: {
type: 'string', minLength: 1
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
additionalProperties: {
type: 'string', minLength: 1
}
})
})
test('should merge two additionalProperties and properties schemas', () => {
const schema1 = {
type: 'object',
additionalProperties: {
type: 'string'
}
}
const schema2 = {
type: 'object',
properties: {
foo: { type: ['string', 'number'] }
},
additionalProperties: {
type: 'string', minLength: 1
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string' }
},
additionalProperties: {
type: 'string', minLength: 1
}
})
})

View File

@@ -0,0 +1,43 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and allOf keyword', () => {
const schema1 = {}
const schema2 = {
allOf: [
{ type: 'string', const: 'foo' }
]
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
allOf: [
{ type: 'string', const: 'foo' }
]
})
})
test('should merge schemas with allOfs schemas', () => {
const schema1 = {
allOf: [
{ type: 'number', minimum: 0 }
]
}
const schema2 = {
allOf: [
{ type: 'string', const: 'foo' }
]
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
allOf: [
{ type: 'number', minimum: 0 },
{ type: 'string', const: 'foo' }
]
})
})

View File

@@ -0,0 +1,81 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and anyOf keyword', () => {
const schema1 = {}
const schema2 = {
anyOf: [
{ type: 'string', const: 'foo' }
]
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
anyOf: [
{ type: 'string', const: 'foo' }
]
})
})
test('should merge two schemas with anyOfs schemas', () => {
const schema1 = {
anyOf: [
{ type: 'string', enum: ['foo1', 'foo2', 'foo3'] },
{ type: 'string', enum: ['foo3', 'foo4', 'foo5'] }
]
}
const schema2 = {
anyOf: [
{ type: 'string', enum: ['foo2', 'foo3', 'foo4'] },
{ type: 'string', enum: ['foo3', 'foo6', 'foo7'] }
]
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
anyOf: [
{ type: 'string', enum: ['foo2', 'foo3'] },
{ type: 'string', enum: ['foo3'] },
{ type: 'string', enum: ['foo3', 'foo4'] },
{ type: 'string', enum: ['foo3'] }
]
})
})
test('should merge three schemas with anyOfs schemas', () => {
const schema1 = {
anyOf: [
{ type: 'string', enum: ['foo1', 'foo2', 'foo3', 'foo4'] },
{ type: 'string', enum: ['foo3', 'foo4', 'foo5', 'foo7'] }
]
}
const schema2 = {
anyOf: [
{ type: 'string', enum: ['foo2', 'foo3', 'foo4', 'foo5'] },
{ type: 'string', enum: ['foo3', 'foo6', 'foo7', 'foo8'] }
]
}
const schema3 = {
anyOf: [
{ type: 'string', enum: ['foo1', 'foo3', 'foo5', 'foo7'] },
{ type: 'string', enum: ['foo2', 'foo4', 'foo6', 'foo8'] }
]
}
const mergedSchema = mergeSchemas([schema1, schema2, schema3], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
anyOf: [
{ type: 'string', enum: ['foo3'] },
{ type: 'string', enum: ['foo2', 'foo4'] },
{ type: 'string', enum: ['foo3'] },
{ type: 'string', enum: ['foo3', 'foo5'] },
{ type: 'string', enum: ['foo4'] },
{ type: 'string', enum: ['foo3', 'foo7'] }
]
})
})

View File

@@ -0,0 +1,58 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and string const keyword', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'string', const: 'foo' }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', const: 'foo' })
})
test('should merge equal string const keywords', () => {
const schema1 = { type: 'string', const: 'foo' }
const schema2 = { type: 'string', const: 'foo' }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', const: 'foo' })
})
test('should merge equal object const keywords', () => {
const schema1 = { type: 'string', const: { foo: 'bar' } }
const schema2 = { type: 'string', const: { foo: 'bar' } }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', const: { foo: 'bar' } })
})
test('should throw an error if const string values are different', () => {
const schema1 = { type: 'string', const: 'foo' }
const schema2 = { type: 'string', const: 'bar' }
assert.throws(() => {
mergeSchemas([schema1, schema2], { defaultResolver })
}, {
name: 'JsonSchemaMergeError',
code: 'JSON_SCHEMA_MERGE_ERROR',
message: 'Failed to merge "const" keyword schemas.',
schemas: ['foo', 'bar']
})
})
test('should throw an error if const object values are different', () => {
const schema1 = { type: 'object', const: { foo: 'bar' } }
const schema2 = { type: 'object', const: { foo: 'baz' } }
assert.throws(() => {
mergeSchemas([schema1, schema2], { defaultResolver })
}, {
name: 'JsonSchemaMergeError',
code: 'JSON_SCHEMA_MERGE_ERROR',
message: 'Failed to merge "const" keyword schemas.',
schemas: [{ foo: 'bar' }, { foo: 'baz' }]
})
})

View File

@@ -0,0 +1,55 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and contains keyword', () => {
const schema1 = {}
const schema2 = {
type: 'array',
contains: {
type: 'integer',
minimum: 5
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
contains: {
type: 'integer',
minimum: 5
}
})
})
test('should merge two contains keyword schemas', () => {
const schema1 = {
type: 'array',
contains: {
type: 'integer',
minimum: 5,
maximum: 14
}
}
const schema2 = {
type: 'array',
contains: {
type: 'integer',
minimum: 9,
maximum: 10
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
contains: {
type: 'integer',
minimum: 9,
maximum: 10
}
})
})

View File

@@ -0,0 +1,50 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should use a custom resolver instead of default one', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'number' }
const mergedSchema = mergeSchemas(
[schema1, schema2],
{
resolvers: {
type: (keyword, values, mergedSchema, schemas) => {
assert.strictEqual(keyword, 'type')
assert.deepStrictEqual(values, ['string', 'number'])
assert.deepStrictEqual(schemas, [schema1, schema2])
mergedSchema[keyword] = 'custom-type'
}
},
defaultResolver
}
)
assert.deepStrictEqual(mergedSchema, { type: 'custom-type' })
})
test('should use a custom resolver for unknown keyword', () => {
const schema1 = { customKeyword: 'string' }
const schema2 = { customKeyword: 'number' }
const mergedSchema = mergeSchemas(
[schema1, schema2],
{
resolvers: {
customKeyword: (keyword, values, mergedSchema, schemas) => {
assert.strictEqual(keyword, 'customKeyword')
assert.deepStrictEqual(values, ['string', 'number'])
assert.deepStrictEqual(schemas, [schema1, schema2])
mergedSchema[keyword] = 'custom-type'
}
},
defaultResolver
}
)
assert.deepStrictEqual(mergedSchema, { customKeyword: 'custom-type' })
})

View File

@@ -0,0 +1,111 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
test('should merge an unknown keyword with an empty schema', () => {
const schema1 = {}
const schema2 = { customKeyword: 42 }
const mergedSchema = mergeSchemas([schema1, schema2])
assert.deepStrictEqual(mergedSchema, { customKeyword: 42 })
})
test('should merge two equal unknown keywords', () => {
const schema1 = { customKeyword: 42 }
const schema2 = { customKeyword: 42 }
const mergedSchema = mergeSchemas([schema1, schema2])
assert.deepStrictEqual(mergedSchema, { customKeyword: 42 })
})
test('should merge two equal unknown object keywords', () => {
const schema1 = { type: 'string', customKeyword: { foo: 'bar' } }
const schema2 = { type: 'string', customKeyword: { foo: 'bar' } }
const mergedSchema = mergeSchemas([schema1, schema2])
assert.deepStrictEqual(mergedSchema, {
type: 'string',
customKeyword: { foo: 'bar' }
})
})
test('should use custom defaultResolver if passed', () => {
const schema1 = { type: 'string', customKeyword: 42 }
const schema2 = { type: 'string', customKeyword: 43 }
const mergedSchema = mergeSchemas(
[schema1, schema2],
{
defaultResolver: (keyword, values, mergedSchema, schemas) => {
assert.strictEqual(keyword, 'customKeyword')
assert.deepStrictEqual(values, [42, 43])
assert.deepStrictEqual(schemas, [schema1, schema2])
mergedSchema.customKeyword = 'custom-value-42'
}
}
)
assert.deepStrictEqual(mergedSchema, {
type: 'string',
customKeyword: 'custom-value-42'
})
})
test('should trow an error when merging two different unknown keywords', () => {
const schema1 = { customKeyword: 42 }
const schema2 = { customKeyword: 43 }
assert.throws(() => {
mergeSchemas([schema1, schema2])
}, {
name: 'JsonSchemaMergeError',
code: 'JSON_SCHEMA_MERGE_ERROR',
message: 'Resolver for "customKeyword" keyword not found.',
schemas: [42, 43]
})
})
test('should trow an error when merging two different unknown keywords with onConflict = throw', () => {
const schema1 = { customKeyword: 42 }
const schema2 = { customKeyword: 43 }
assert.throws(() => {
mergeSchemas([schema1, schema2], { onConflict: 'throw' })
}, {
name: 'JsonSchemaMergeError',
code: 'JSON_SCHEMA_MERGE_ERROR',
message: 'Resolver for "customKeyword" keyword not found.',
schemas: [42, 43]
})
})
test('should skip the keyword schemas if onConflict = skip', () => {
const schema1 = { customKeyword: 42 }
const schema2 = { customKeyword: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { onConflict: 'skip' })
assert.deepStrictEqual(mergedSchema, {})
})
test('should pick first schema if onConflict = first', () => {
const schema1 = { customKeyword: 42 }
const schema2 = { customKeyword: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { onConflict: 'first' })
assert.deepStrictEqual(mergedSchema, { customKeyword: 42 })
})
test('should throw an error if pass wrong onConflict value', () => {
const schema1 = { customKeyword: 42 }
const schema2 = { customKeyword: 43 }
assert.throws(() => {
mergeSchemas([schema1, schema2], { onConflict: 'foo' })
}, {
name: 'JsonSchemaMergeError',
code: 'JSON_SCHEMA_MERGE_ERROR',
message: 'Invalid "onConflict" option: "foo".'
})
})

View File

@@ -0,0 +1,50 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and string default keyword', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'string', default: 'foo' }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', default: 'foo' })
})
test('should merge equal string default keywords', () => {
const schema1 = { type: 'string', default: 'foo' }
const schema2 = { type: 'string', default: 'foo' }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', default: 'foo' })
})
test('should throw an error if default string values are different', () => {
const schema1 = { type: 'string', default: 'foo' }
const schema2 = { type: 'string', default: 'bar' }
assert.throws(() => {
mergeSchemas([schema1, schema2], { defaultResolver })
}, {
name: 'JsonSchemaMergeError',
code: 'JSON_SCHEMA_MERGE_ERROR',
message: 'Failed to merge "default" keyword schemas.',
schemas: ['foo', 'bar']
})
})
test('should throw an error if default object values are different', () => {
const schema1 = { type: 'object', default: { foo: 'bar' } }
const schema2 = { type: 'object', default: { foo: 'baz' } }
assert.throws(() => {
mergeSchemas([schema1, schema2], { defaultResolver })
}, {
name: 'JsonSchemaMergeError',
code: 'JSON_SCHEMA_MERGE_ERROR',
message: 'Failed to merge "default" keyword schemas.',
schemas: [{ foo: 'bar' }, { foo: 'baz' }]
})
})

View File

@@ -0,0 +1,46 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and definitions keyword', () => {
const schema1 = {}
const schema2 = {
definitions: {
foo: { type: 'string', const: 'foo' }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
definitions: {
foo: { type: 'string', const: 'foo' }
}
})
})
test('should merge two definition schemas', () => {
const schema1 = {
definitions: {
foo: { type: 'string', enum: ['foo', 'bar'] },
bar: { type: 'string', enum: ['foo', 'bar'] }
}
}
const schema2 = {
definitions: {
foo: { type: 'string', enum: ['foo'] },
baz: { type: 'string' }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
definitions: {
foo: { type: 'string', enum: ['foo'] },
bar: { type: 'string', enum: ['foo', 'bar'] },
baz: { type: 'string' }
}
})
})

View File

@@ -0,0 +1,46 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and $defs keyword', () => {
const schema1 = {}
const schema2 = {
$defs: {
foo: { type: 'string', const: 'foo' }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
$defs: {
foo: { type: 'string', const: 'foo' }
}
})
})
test('should merge two definition schemas', () => {
const schema1 = {
$defs: {
foo: { type: 'string', enum: ['foo', 'bar'] },
bar: { type: 'string', enum: ['foo', 'bar'] }
}
}
const schema2 = {
$defs: {
foo: { type: 'string', enum: ['foo'] },
baz: { type: 'string' }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
$defs: {
foo: { type: 'string', enum: ['foo'] },
bar: { type: 'string', enum: ['foo', 'bar'] },
baz: { type: 'string' }
}
})
})

View File

@@ -0,0 +1,75 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and dependencies keyword', () => {
const schema1 = {}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' }
},
dependencies: {
foo: ['bar']
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' }
},
dependencies: {
foo: ['bar']
}
})
})
test('should merge two dependencies keyword schemas', () => {
const schema1 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' },
que: { type: 'string' }
},
dependencies: {
foo: ['bar', 'que'],
bar: ['que']
}
}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' },
baz: { type: 'string' }
},
dependencies: {
foo: ['baz'],
baz: ['foo']
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' },
que: { type: 'string' },
baz: { type: 'string' }
},
dependencies: {
foo: ['bar', 'que', 'baz'],
bar: ['que'],
baz: ['foo']
}
})
})

View File

@@ -0,0 +1,75 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and dependentRequired keyword', () => {
const schema1 = {}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' }
},
dependentRequired: {
foo: ['bar']
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' }
},
dependentRequired: {
foo: ['bar']
}
})
})
test('should merge two dependentRequired keyword schemas', () => {
const schema1 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' },
que: { type: 'string' }
},
dependentRequired: {
foo: ['bar', 'que'],
bar: ['que']
}
}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' },
baz: { type: 'string' }
},
dependentRequired: {
foo: ['baz'],
baz: ['foo']
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' },
que: { type: 'string' },
baz: { type: 'string' }
},
dependentRequired: {
foo: ['bar', 'que', 'baz'],
bar: ['que'],
baz: ['foo']
}
})
})

View File

@@ -0,0 +1,76 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and dependentRequired keyword', () => {
const schema1 = {}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' }
},
dependentSchemas: {
foo: { required: ['bar'] }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' }
},
dependentSchemas: {
foo: { required: ['bar'] }
}
})
})
test('should merge two dependentRequired keyword schemas', () => {
const schema1 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' },
que: { type: 'string' }
},
dependentSchemas: {
foo: { required: ['bar', 'que'] },
bar: { required: ['que'] }
}
}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' },
baz: { type: 'string' }
},
dependentSchemas: {
foo: { required: ['baz'] },
baz: { required: ['foo'] }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' },
que: { type: 'string' },
baz: { type: 'string' }
},
dependentSchemas: {
foo: { required: ['bar', 'que', 'baz'] },
bar: { required: ['que'] },
baz: { required: ['foo'] }
}
})
})

View File

@@ -0,0 +1,44 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and string enum values', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'string', enum: ['foo', 'bar'] }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', enum: ['foo', 'bar'] })
})
test('should merge equal string enum values', () => {
const schema1 = { type: 'string', enum: ['foo', 'bar'] }
const schema2 = { type: 'string', enum: ['foo', 'bar'] }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', enum: ['foo', 'bar'] })
})
test('should merge different string enum values', () => {
const schema1 = { type: 'string', enum: ['foo', 'bar'] }
const schema2 = { type: 'string', enum: ['foo', 'baz'] }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', enum: ['foo'] })
})
test('should throw an error if can not merge enum values', () => {
const schema1 = { type: 'string', enum: ['foo', 'bar'] }
const schema2 = { type: 'string', enum: ['baz', 'qux'] }
assert.throws(() => {
mergeSchemas([schema1, schema2], { defaultResolver })
}, {
name: 'JsonSchemaMergeError',
code: 'JSON_SCHEMA_MERGE_ERROR',
message: 'Failed to merge "enum" keyword schemas.',
schemas: [['foo', 'bar'], ['baz', 'qux']]
})
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and exclusiveMaximum keyword', () => {
const schema1 = { type: 'number' }
const schema2 = { type: 'number', exclusiveMaximum: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'number', exclusiveMaximum: 42 })
})
test('should merge equal exclusiveMaximum values', () => {
const schema1 = { type: 'number', exclusiveMaximum: 42 }
const schema2 = { type: 'number', exclusiveMaximum: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'number', exclusiveMaximum: 42 })
})
test('should merge different exclusiveMaximum values', () => {
const schema1 = { type: 'integer', exclusiveMaximum: 42 }
const schema2 = { type: 'integer', exclusiveMaximum: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'integer', exclusiveMaximum: 42 })
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and exclusiveMinimum keyword', () => {
const schema1 = { type: 'number' }
const schema2 = { type: 'number', exclusiveMinimum: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'number', exclusiveMinimum: 42 })
})
test('should merge equal exclusiveMinimum values', () => {
const schema1 = { type: 'number', exclusiveMinimum: 42 }
const schema2 = { type: 'number', exclusiveMinimum: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'number', exclusiveMinimum: 42 })
})
test('should merge different exclusiveMinimum values', () => {
const schema1 = { type: 'integer', exclusiveMinimum: 42 }
const schema2 = { type: 'integer', exclusiveMinimum: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'integer', exclusiveMinimum: 43 })
})

View File

@@ -0,0 +1,36 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and string format keyword', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'string', format: 'date-time' }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', format: 'date-time' })
})
test('should merge equal string format keywords', () => {
const schema1 = { type: 'string', format: 'date-time' }
const schema2 = { type: 'string', format: 'date-time' }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', format: 'date-time' })
})
test('should throw an error if format keyword values are different', () => {
const schema1 = { type: 'string', format: 'date-time' }
const schema2 = { type: 'string', format: 'date' }
assert.throws(() => {
mergeSchemas([schema1, schema2], { defaultResolver })
}, {
name: 'JsonSchemaMergeError',
code: 'JSON_SCHEMA_MERGE_ERROR',
message: 'Failed to merge "format" keyword schemas.',
schemas: ['date-time', 'date']
})
})

View File

@@ -0,0 +1,22 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should skip $id keyword if they are equal', () => {
const schema1 = { $id: 'foo', type: 'string' }
const schema2 = { $id: 'foo', type: 'string' }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string' })
})
test('should skip $id keyword if they are different', () => {
const schema1 = { $id: 'foo', type: 'string' }
const schema2 = { $id: 'bar', type: 'string' }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string' })
})

View File

@@ -0,0 +1,550 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and if/then/else keywords', () => {
const schema1 = {}
const schema2 = {
if: {
type: 'string',
const: 'foo'
},
then: {
type: 'string',
const: 'bar'
},
else: {
type: 'string',
const: 'baz'
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
if: {
type: 'string',
const: 'foo'
},
then: {
type: 'string',
const: 'bar'
},
else: {
type: 'string',
const: 'baz'
}
})
})
test('should merge if/then/else schema with an empty schema', () => {
const schema1 = {
if: {
type: 'string',
const: 'foo'
},
then: {
type: 'string',
const: 'bar'
},
else: {
type: 'string',
const: 'baz'
}
}
const schema2 = {}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
if: {
type: 'string',
const: 'foo'
},
then: {
type: 'string',
const: 'bar'
},
else: {
type: 'string',
const: 'baz'
}
})
})
test('should merge two if/then/else schemas', () => {
const schema1 = {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
then: {
properties: {
bar1: { type: 'string', const: 'bar1' }
}
},
else: {
properties: {
baz1: { type: 'string', const: 'baz1' }
}
}
}
const schema2 = {
type: 'object',
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
then: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
},
else: {
properties: {
baz2: { type: 'string', const: 'baz2' }
}
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
then: {
properties: {
bar1: { type: 'string', const: 'bar1' }
},
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
then: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
},
else: {
properties: {
baz2: { type: 'string', const: 'baz2' }
}
}
},
else: {
properties: {
baz1: { type: 'string', const: 'baz1' }
},
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
then: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
},
else: {
properties: {
baz2: { type: 'string', const: 'baz2' }
}
}
}
})
})
test('should merge three if/then/else schemas', () => {
const schema1 = {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
then: {
properties: {
bar1: { type: 'string', const: 'bar1' }
}
},
else: {
properties: {
baz1: { type: 'string', const: 'baz1' }
}
}
}
const schema2 = {
type: 'object',
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
then: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
},
else: {
properties: {
baz2: { type: 'string', const: 'baz2' }
}
}
}
const schema3 = {
type: 'object',
if: {
properties: {
foo3: { type: 'string', const: 'foo3' }
}
},
then: {
properties: {
bar3: { type: 'string', const: 'bar3' }
}
},
else: {
properties: {
baz3: { type: 'string', const: 'baz3' }
}
}
}
const mergedSchema = mergeSchemas([schema1, schema2, schema3], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
then: {
properties: {
bar1: { type: 'string', const: 'bar1' }
},
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
then: {
properties: {
bar2: { type: 'string', const: 'bar2' }
},
if: {
properties: {
foo3: { type: 'string', const: 'foo3' }
}
},
then: {
properties: {
bar3: { type: 'string', const: 'bar3' }
}
},
else: {
properties: {
baz3: { type: 'string', const: 'baz3' }
}
}
},
else: {
properties: {
baz2: { type: 'string', const: 'baz2' }
},
if: {
properties: {
foo3: { type: 'string', const: 'foo3' }
}
},
then: {
properties: {
bar3: { type: 'string', const: 'bar3' }
}
},
else: {
properties: {
baz3: { type: 'string', const: 'baz3' }
}
}
}
},
else: {
properties: {
baz1: { type: 'string', const: 'baz1' }
},
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
then: {
properties: {
bar2: { type: 'string', const: 'bar2' }
},
if: {
properties: {
foo3: { type: 'string', const: 'foo3' }
}
},
then: {
properties: {
bar3: { type: 'string', const: 'bar3' }
}
},
else: {
properties: {
baz3: { type: 'string', const: 'baz3' }
}
}
},
else: {
properties: {
baz2: { type: 'string', const: 'baz2' }
},
if: {
properties: {
foo3: { type: 'string', const: 'foo3' }
}
},
then: {
properties: {
bar3: { type: 'string', const: 'bar3' }
}
},
else: {
properties: {
baz3: { type: 'string', const: 'baz3' }
}
}
}
}
})
})
test('should two if/then keyword schemas', () => {
const schema1 = {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
then: {
properties: {
bar1: { type: 'string', const: 'bar1' }
}
}
}
const schema2 = {
type: 'object',
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
then: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
then: {
properties: {
bar1: { type: 'string', const: 'bar1' }
},
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
then: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
}
}
})
})
test('should two if/else keyword schemas', () => {
const schema1 = {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
else: {
properties: {
bar1: { type: 'string', const: 'bar1' }
}
}
}
const schema2 = {
type: 'object',
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
else: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
else: {
properties: {
bar1: { type: 'string', const: 'bar1' }
},
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
else: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
}
}
})
})
test('should two if/then and if/else keyword schemas', () => {
const schema1 = {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
then: {
properties: {
bar1: { type: 'string', const: 'bar1' }
}
}
}
const schema2 = {
type: 'object',
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
else: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
then: {
properties: {
bar1: { type: 'string', const: 'bar1' }
},
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
else: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
}
}
})
})
test('should two if/else and if/then keyword schemas', () => {
const schema1 = {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
else: {
properties: {
bar1: { type: 'string', const: 'bar1' }
}
}
}
const schema2 = {
type: 'object',
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
then: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
if: {
properties: {
foo1: { type: 'string', const: 'foo1' }
}
},
else: {
properties: {
bar1: { type: 'string', const: 'bar1' }
},
if: {
properties: {
foo2: { type: 'string', const: 'foo2' }
}
},
then: {
properties: {
bar2: { type: 'string', const: 'bar2' }
}
}
}
})
})

View File

@@ -0,0 +1,152 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and items keyword', () => {
const schema1 = { type: 'array' }
const schema2 = {
type: 'array',
items: {
type: 'object',
properties: {
foo: { type: 'string' }
}
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
items: {
type: 'object',
properties: {
foo: { type: 'string' }
}
}
})
})
test('should merge two equal item schemas', () => {
const schema1 = {
type: 'array',
items: {
type: 'object',
properties: {
foo: { type: 'string' }
}
}
}
const schema2 = {
type: 'array',
items: {
type: 'object',
properties: {
foo: { type: 'string' }
}
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
items: {
type: 'object',
properties: {
foo: { type: 'string' }
}
}
})
})
test('should merge two different sets of item schemas', () => {
const schema1 = {
type: 'array',
items: {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' }
}
}
}
const schema2 = {
type: 'array',
items: {
type: 'object',
properties: {
foo: { type: 'string' },
baz: { type: 'boolean' }
}
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
items: {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' },
baz: { type: 'boolean' }
}
}
})
})
test('should merge two different sets of item schemas with additionalItems', () => {
const schema1 = {
type: 'array',
items: [
{
type: 'object',
properties: {
foo: { type: 'string', const: 'foo' }
}
}
],
additionalItems: {
type: 'object',
properties: {
baz: { type: 'string', const: 'baz' }
}
}
}
const schema2 = {
type: 'array',
items: {
type: 'object',
properties: {
foo: { type: 'string' },
baz: { type: 'string' }
}
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
items: [
{
type: 'object',
properties: {
foo: { type: 'string', const: 'foo' },
baz: { type: 'string' }
}
}
],
additionalItems: {
type: 'object',
properties: {
foo: { type: 'string' },
baz: { type: 'string', const: 'baz' }
}
}
})
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and maxItems keyword', () => {
const schema1 = { type: 'array' }
const schema2 = { type: 'array', maxItems: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'array', maxItems: 42 })
})
test('should merge equal maxItems values', () => {
const schema1 = { type: 'array', maxItems: 42 }
const schema2 = { type: 'array', maxItems: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'array', maxItems: 42 })
})
test('should merge different maxItems values', () => {
const schema1 = { type: 'array', maxItems: 42 }
const schema2 = { type: 'array', maxItems: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'array', maxItems: 42 })
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and maxLength keyword', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'string', maxLength: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', maxLength: 42 })
})
test('should merge equal maxLength values', () => {
const schema1 = { type: 'string', maxLength: 42 }
const schema2 = { type: 'string', maxLength: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', maxLength: 42 })
})
test('should merge different maxLength values', () => {
const schema1 = { type: 'string', maxLength: 42 }
const schema2 = { type: 'string', maxLength: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', maxLength: 42 })
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and maxProperties keyword', () => {
const schema1 = { type: 'object' }
const schema2 = { type: 'object', maxProperties: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'object', maxProperties: 42 })
})
test('should merge equal maxProperties values', () => {
const schema1 = { type: 'object', maxProperties: 42 }
const schema2 = { type: 'object', maxProperties: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'object', maxProperties: 42 })
})
test('should merge different maxProperties values', () => {
const schema1 = { type: 'object', maxProperties: 42 }
const schema2 = { type: 'object', maxProperties: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'object', maxProperties: 42 })
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and maximum keyword', () => {
const schema1 = { type: 'number' }
const schema2 = { type: 'number', maximum: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'number', maximum: 42 })
})
test('should merge equal maximum values', () => {
const schema1 = { type: 'number', maximum: 42 }
const schema2 = { type: 'number', maximum: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'number', maximum: 42 })
})
test('should merge different maximum values', () => {
const schema1 = { type: 'integer', maximum: 42 }
const schema2 = { type: 'integer', maximum: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'integer', maximum: 42 })
})

View File

@@ -0,0 +1,29 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should return an empty schema if passing an empty array', () => {
const mergedSchema = mergeSchemas([], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {})
})
test('should return true if passing all true values', () => {
const mergedSchema = mergeSchemas([true, true, true], { defaultResolver })
assert.deepStrictEqual(mergedSchema, true)
})
test('should return true if passing all false values', () => {
const mergedSchema = mergeSchemas([false, false, false], { defaultResolver })
assert.deepStrictEqual(mergedSchema, false)
})
test('should return true if passing at least one false schema', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'number' }
const mergedSchema = mergeSchemas([schema1, schema2, false], { defaultResolver })
assert.deepStrictEqual(mergedSchema, false)
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and minItems keyword', () => {
const schema1 = { type: 'array' }
const schema2 = { type: 'array', minItems: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'array', minItems: 42 })
})
test('should merge equal minItems values', () => {
const schema1 = { type: 'array', minItems: 42 }
const schema2 = { type: 'array', minItems: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'array', minItems: 42 })
})
test('should merge different minItems values', () => {
const schema1 = { type: 'array', minItems: 42 }
const schema2 = { type: 'array', minItems: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'array', minItems: 43 })
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and minLength keyword', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'string', minLength: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', minLength: 42 })
})
test('should merge equal minLength values', () => {
const schema1 = { type: 'string', minLength: 42 }
const schema2 = { type: 'string', minLength: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', minLength: 42 })
})
test('should merge different minLength values', () => {
const schema1 = { type: 'string', minLength: 42 }
const schema2 = { type: 'string', minLength: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', minLength: 43 })
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and minProperties keyword', () => {
const schema1 = { type: 'object' }
const schema2 = { type: 'object', minProperties: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'object', minProperties: 42 })
})
test('should merge equal minItems values', () => {
const schema1 = { type: 'object', minProperties: 42 }
const schema2 = { type: 'object', minProperties: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'object', minProperties: 42 })
})
test('should merge different minItems values', () => {
const schema1 = { type: 'object', minProperties: 42 }
const schema2 = { type: 'object', minProperties: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'object', minProperties: 43 })
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and minimum keyword', () => {
const schema1 = { type: 'number' }
const schema2 = { type: 'number', minimum: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'number', minimum: 42 })
})
test('should merge equal minimum values', () => {
const schema1 = { type: 'number', minimum: 42 }
const schema2 = { type: 'number', minimum: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'number', minimum: 42 })
})
test('should merge different minimum values', () => {
const schema1 = { type: 'integer', minimum: 42 }
const schema2 = { type: 'integer', minimum: 43 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'integer', minimum: 43 })
})

View File

@@ -0,0 +1,36 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and multipleOf keyword', () => {
const schema1 = { type: 'number' }
const schema2 = { type: 'number', multipleOf: 42 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'number', multipleOf: 42 })
})
test('should merge two schemas with multipleOf keywords', () => {
const schema1 = { type: 'number', multipleOf: 2 }
const schema2 = { type: 'number', multipleOf: 3 }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'number', multipleOf: 6 })
})
test('should merge multiple schemas with float multipleOf keywords', () => {
const schema1 = { type: 'number', multipleOf: 0.2 }
const schema2 = { type: 'number', multipleOf: 2 }
const schema3 = { type: 'number', multipleOf: 2 }
const schema4 = { type: 'number', multipleOf: 0.5 }
const schema5 = { type: 'number', multipleOf: 1.5 }
const mergedSchema = mergeSchemas(
[schema1, schema2, schema3, schema4, schema5],
{ defaultResolver }
)
assert.deepStrictEqual(mergedSchema, { type: 'number', multipleOf: 6 })
})

View File

@@ -0,0 +1,29 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge two "not" keyword schemas', () => {
const schema1 = {
type: 'array',
not: {
type: 'string'
}
}
const schema2 = {
type: 'array',
not: {
type: 'string', minLength: 1
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'array',
not: {
type: 'string', minLength: 1
}
})
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and nullable = true keyword', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'string', nullable: true }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', nullable: true })
})
test('should merge empty schema and nullable = false keyword', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'string', nullable: false }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', nullable: false })
})
test('should merge schemas with nullable true and false values', () => {
const schema1 = { type: 'string', nullable: false }
const schema2 = { type: 'string', nullable: true }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string', nullable: false })
})

View File

@@ -0,0 +1,144 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas, MergeError } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and oneOf keyword', () => {
const schema1 = {}
const schema2 = {
oneOf: [
{ type: 'string', const: 'foo' }
]
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
oneOf: [
{ type: 'string', const: 'foo' }
]
})
})
test('should merge two schemas with oneOfs schemas', () => {
const schema1 = {
oneOf: [
{ type: 'string', enum: ['foo1', 'foo2', 'foo3'] },
{ type: 'string', enum: ['foo3', 'foo4', 'foo5'] }
]
}
const schema2 = {
oneOf: [
{ type: 'string', enum: ['foo2', 'foo3', 'foo4'] },
{ type: 'string', enum: ['foo3', 'foo6', 'foo7'] }
]
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
oneOf: [
{ type: 'string', enum: ['foo2', 'foo3'] },
{ type: 'string', enum: ['foo3'] },
{ type: 'string', enum: ['foo3', 'foo4'] },
{ type: 'string', enum: ['foo3'] }
]
})
})
test('should merge three schemas with oneOfs schemas', () => {
const schema1 = {
oneOf: [
{ type: 'string', enum: ['foo1', 'foo2', 'foo3', 'foo4'] },
{ type: 'string', enum: ['foo3', 'foo4', 'foo5', 'foo7'] }
]
}
const schema2 = {
oneOf: [
{ type: 'string', enum: ['foo2', 'foo3', 'foo4', 'foo5'] },
{ type: 'string', enum: ['foo3', 'foo6', 'foo7', 'foo8'] }
]
}
const schema3 = {
oneOf: [
{ type: 'string', enum: ['foo1', 'foo3', 'foo5', 'foo7'] },
{ type: 'string', enum: ['foo2', 'foo4', 'foo6', 'foo8'] }
]
}
const mergedSchema = mergeSchemas(
[schema1, schema2, schema3],
{ defaultResolver }
)
assert.deepStrictEqual(mergedSchema, {
oneOf: [
{ type: 'string', enum: ['foo3'] },
{ type: 'string', enum: ['foo2', 'foo4'] },
{ type: 'string', enum: ['foo3'] },
{ type: 'string', enum: ['foo3', 'foo5'] },
{ type: 'string', enum: ['foo4'] },
{ type: 'string', enum: ['foo3', 'foo7'] }
]
})
})
test('should throw a non MergeError error during oneOf merge', () => {
const schema1 = {
oneOf: [
{ type: 'string', customKeyword: 42 },
{ type: 'string', customKeyword: 43 }
]
}
const schema2 = {
oneOf: [
{ type: 'string', customKeyword: 44 },
{ type: 'string', customKeyword: 45 }
]
}
assert.throws(() => {
mergeSchemas(
[schema1, schema2],
{
resolvers: {
customKeyword: () => {
throw new Error('Custom error')
}
},
defaultResolver
}
)
}, {
name: 'Error',
message: 'Custom error'
})
})
test('should not throw a MergeError error during oneOf merge', () => {
const schema1 = {
oneOf: [
{ type: 'string', customKeyword: 42 },
{ type: 'string', customKeyword: 43 }
]
}
const schema2 = {
oneOf: [
{ type: 'string', customKeyword: 44 },
{ type: 'string', customKeyword: 45 }
]
}
const mergedSchema = mergeSchemas(
[schema1, schema2],
{
resolvers: {
customKeyword: (keyword, values) => {
throw new MergeError(keyword, values)
}
},
defaultResolver
}
)
assert.deepStrictEqual(mergedSchema, { oneOf: [] })
})

View File

@@ -0,0 +1,312 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and properties keyword', () => {
const schema1 = { type: 'object' }
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string' }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string' }
}
})
})
test('should merge two equal property schemas', () => {
const schema1 = {
type: 'object',
properties: {
foo: { type: 'string' }
}
}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string' }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string' }
}
})
})
test('should merge two different sets of property schemas', () => {
const schema1 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' }
}
}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string' },
baz: { type: 'boolean' }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' },
baz: { type: 'boolean' }
}
})
})
test('should merge property with different schemas', () => {
const schema1 = {
type: 'object',
properties: {
foo: {
type: ['string', 'number'],
enum: ['42', 2, 3]
}
}
}
const schema2 = {
type: 'object',
properties: {
foo: {
type: ['number', 'null'],
enum: [1, 2, 3, null]
}
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'number', enum: [2, 3] }
}
})
})
test('should merge properties if one schema has additionalProperties = false', () => {
const schema1 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' }
},
additionalProperties: false
}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
baz: { type: 'string' }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
bar: { type: 'number' },
baz: false
},
additionalProperties: false
})
})
test('should merge properties if both schemas have additionalProperties = false', () => {
const schema1 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' }
},
additionalProperties: false
}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
baz: { type: 'string' }
},
additionalProperties: false
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
bar: false,
baz: false
},
additionalProperties: false
})
})
test('should merge properties if one schema has additionalProperties schema', () => {
const schema1 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' }
},
additionalProperties: { type: 'string', enum: ['43'] }
}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
baz: { type: 'string' }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
bar: { type: 'number' },
baz: { type: 'string', enum: ['43'] }
},
additionalProperties: { type: 'string', enum: ['43'] }
})
})
test('should merge properties if both schemas have additionalProperties schemas', () => {
const schema1 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' }
},
additionalProperties: {
type: ['string', 'number', 'null'],
enum: ['45', '43', 41, null]
}
}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
baz: { type: 'string' }
},
additionalProperties: {
type: ['string', 'boolean', 'number'],
enum: ['44', '43', true, 41]
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
bar: { type: 'number', enum: ['44', '43', true, 41] },
baz: { type: 'string', enum: ['45', '43', 41, null] }
},
additionalProperties: { type: ['string', 'number'], enum: ['43', 41] }
})
})
test('should merge properties if one schema has patternProperties schema', () => {
const schema1 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' }
},
patternProperties: {
'^baz$': { type: 'string', enum: ['43'] }
}
}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
baz: { type: 'string' },
qux: { type: 'string' }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
bar: { type: 'number' },
baz: { type: 'string', enum: ['43'] },
qux: { type: 'string' }
},
patternProperties: {
'^baz$': { type: 'string', enum: ['43'] }
}
})
})
test('should merge properties if both schemas have patternProperties schemas', () => {
const schema1 = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' },
bak: { type: 'number' }
},
patternProperties: {
'^baz$': { type: 'string', enum: ['43'] }
}
}
const schema2 = {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
baz: { type: 'string' },
qux: { type: 'string' }
},
patternProperties: {
'^bar$': { type: 'number', minimum: 2 }
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
properties: {
foo: { type: 'string', enum: ['42'] },
bar: { type: 'number', minimum: 2 },
bak: { type: 'number' },
baz: { type: 'string', enum: ['43'] },
qux: { type: 'string' }
},
patternProperties: {
'^bar$': { type: 'number', minimum: 2 },
'^baz$': { type: 'string', enum: ['43'] }
}
})
})

View File

@@ -0,0 +1,49 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and propertyNames keyword', () => {
const schema1 = {}
const schema2 = {
type: 'object',
propertyNames: {
pattern: '^[a-zA-Z]+$',
minLength: 42
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
propertyNames: {
pattern: '^[a-zA-Z]+$',
minLength: 42
}
})
})
test('should merge two propertyNames keyword schemas', () => {
const schema1 = {
type: 'object',
propertyNames: {
minLength: 42
}
}
const schema2 = {
type: 'object',
propertyNames: {
minLength: 43
}
}
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, {
type: 'object',
propertyNames: {
minLength: 43
}
})
})

View File

@@ -0,0 +1,30 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and required keyword', () => {
const schema1 = { type: 'object' }
const schema2 = { type: 'object', required: ['foo'] }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'object', required: ['foo'] })
})
test('should merge two equal required keywords', () => {
const schema1 = { type: 'object', required: ['foo'] }
const schema2 = { type: 'object', required: ['foo'] }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'object', required: ['foo'] })
})
test('should merge two different required keywords', () => {
const schema1 = { type: 'object', required: ['foo', 'bar'] }
const schema2 = { type: 'object', required: ['foo', 'baz'] }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'object', required: ['foo', 'bar', 'baz'] })
})

View File

@@ -0,0 +1,52 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge equal type values', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'string' }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string' })
})
test('should merge array type values', () => {
const schema1 = { type: ['string', 'number'] }
const schema2 = { type: ['null', 'string'] }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string' })
})
test('should merge array type values', () => {
const schema1 = { type: ['string', 'number'] }
const schema2 = { type: 'string' }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'string' })
})
test('should merge array type values', () => {
const schema1 = { type: ['number', 'string', 'boolean'] }
const schema2 = { type: ['string', 'number', 'null'] }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: ['number', 'string'] })
})
test('should throw an error if can not merge type values', () => {
const schema1 = { type: 'string' }
const schema2 = { type: 'number' }
assert.throws(() => {
mergeSchemas([schema1, schema2], { defaultResolver })
}, {
name: 'JsonSchemaMergeError',
code: 'JSON_SCHEMA_MERGE_ERROR',
message: 'Failed to merge "type" keyword schemas.',
schemas: [['string'], ['number']]
})
})

View File

@@ -0,0 +1,38 @@
'use strict'
const assert = require('node:assert/strict')
const { test } = require('node:test')
const { mergeSchemas } = require('../index')
const { defaultResolver } = require('./utils')
test('should merge empty schema and uniqueItems keyword', () => {
const schema1 = { type: 'array' }
const schema2 = { type: 'array', uniqueItems: true }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'array', uniqueItems: true })
})
test('should merge two equal uniqueItems keyword schemas = true', () => {
const schema1 = { type: 'array', uniqueItems: true }
const schema2 = { type: 'array', uniqueItems: true }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'array', uniqueItems: true })
})
test('should merge two equal uniqueItems keyword schemas = false', () => {
const schema1 = { type: 'array', uniqueItems: false }
const schema2 = { type: 'array', uniqueItems: false }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'array', uniqueItems: false })
})
test('should merge two equal uniqueItems keyword schemas', () => {
const schema1 = { type: 'array', uniqueItems: false }
const schema2 = { type: 'array', uniqueItems: true }
const mergedSchema = mergeSchemas([schema1, schema2], { defaultResolver })
assert.deepStrictEqual(mergedSchema, { type: 'array', uniqueItems: true })
})

View File

@@ -0,0 +1,9 @@
'use strict'
function defaultResolver () {
throw new Error('Default resolver should not be called.')
}
module.exports = {
defaultResolver
}

View File

@@ -0,0 +1,61 @@
export type KeywordResolver = (
keyword: string,
keywordValues: any[],
mergedSchema: any,
parentSchemas: any[],
options: MergeOptions
) => any
export type KeywordResolvers = {
$id: KeywordResolver,
type: KeywordResolver,
enum: KeywordResolver,
minLength: KeywordResolver,
maxLength: KeywordResolver,
minimum: KeywordResolver,
maximum: KeywordResolver,
multipleOf: KeywordResolver,
exclusiveMinimum: KeywordResolver,
exclusiveMaximum: KeywordResolver,
minItems: KeywordResolver,
maxItems: KeywordResolver,
maxProperties: KeywordResolver,
minProperties: KeywordResolver,
const: KeywordResolver,
default: KeywordResolver,
format: KeywordResolver,
required: KeywordResolver,
properties: KeywordResolver,
patternProperties: KeywordResolver,
additionalProperties: KeywordResolver,
items: KeywordResolver,
additionalItems: KeywordResolver,
definitions: KeywordResolver,
$defs: KeywordResolver,
nullable: KeywordResolver,
oneOf: KeywordResolver,
anyOf: KeywordResolver,
allOf: KeywordResolver,
not: KeywordResolver,
if: KeywordResolver,
then: KeywordResolver,
else: KeywordResolver,
dependencies: KeywordResolver,
dependentRequired: KeywordResolver,
dependentSchemas: KeywordResolver,
propertyNames: KeywordResolver,
uniqueItems: KeywordResolver,
contains: KeywordResolver
}
export type MergeOptions = {
defaultResolver?: KeywordResolver,
resolvers?: Partial<KeywordResolvers>,
// enum of ["throw", "skip", "first"]
onConflict?: 'throw' | 'skip' | 'first'
}
export function mergeSchemas (schemas: any[], options?: MergeOptions): any
export const keywordsResolvers: KeywordResolvers
export const defaultResolver: KeywordResolver

View File

@@ -0,0 +1,52 @@
import { mergeSchemas, MergeOptions } from '..'
import { expectType } from 'tsd'
{
const schema1 = { type: 'string', enum: ['foo', 'bar'] }
const schema2 = { type: 'string', enum: ['foo', 'baz'] }
mergeSchemas([schema1, schema2])
}
{
const schema1 = { type: 'string', enum: ['foo', 'bar'] }
const schema2 = { type: 'string', enum: ['foo', 'baz'] }
const mergeOptions: MergeOptions = {
resolvers: {
enum: (
keyword: string,
keywordValues: any[],
mergedSchema: any,
parentSchemas: any[],
options: MergeOptions
) => {
expectType<string>(keyword)
expectType<any[]>(keywordValues)
expectType<any>(mergedSchema)
expectType<any[]>(parentSchemas)
expectType<MergeOptions>(options)
return keywordValues
}
},
defaultResolver: (
keyword: string,
keywordValues: any[],
mergedSchema: any,
parentSchemas: any[],
options: MergeOptions
) => {
expectType<string>(keyword)
expectType<any[]>(keywordValues)
expectType<any>(mergedSchema)
expectType<any[]>(parentSchemas)
expectType<MergeOptions>(options)
return keywordValues
},
onConflict: 'throw'
}
mergeSchemas([schema1, schema2], mergeOptions)
}