Skip to content

Commit

Permalink
Feature: Arrays as tuples
Browse files Browse the repository at this point in the history
  • Loading branch information
slavivanov committed Apr 26, 2019
1 parent 5edb492 commit 7ec237d
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 1 deletion.
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ const schema = toJsonSchema(instance, options);

### Arrays options

**arrays.mode** (`all|first|uniform` default is `all`)
**arrays.mode** (`all|first|uniform|tuple` default is `all`)

`all` option causes parser to go through all array items, finding the most compatible yet most descriptive schema possible.

Expand Down Expand Up @@ -214,6 +214,29 @@ const schema = toJsonSchema(arr, {arrays: {mode: 'uniform'}});
*/
```

`tuple` option generates a [tuple array](https://json-schema.org/understanding-json-schema/reference/array.html#tuple-validation)
(array of objects) from arrays.

```javascript
const arr = ['str', 11, 30];
const schema = toJsonSchema(arr, {arrays: {mode: 'tuple'}});
/*
{
"type": "array",
"items": [
{
"type": "string"
},
{
"type": "integer"
},
{
"type": "integer"
}
]
}
*/
```
### Objects options


Expand Down
9 changes: 9 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ class ToJsonSchema {
return schema
}

getArraySchemaTuple(arr) {
const schema = {type: 'array'}
if (arr.length > 0) {
schema.items = arr.map(item => this.getSchema(item))
}
return schema
}

getArraySchemaUniform(arr) {
const schema = this.getArraySchemaNoMerging(arr)

Expand All @@ -134,6 +142,7 @@ class ToJsonSchema {
case 'all': return this.getArraySchemaMerging(arr)
case 'first': return this.getArraySchemaNoMerging(arr)
case 'uniform': return this.getArraySchemaUniform(arr)
case 'tuple': return this.getArraySchemaTuple(arr)
default: throw new Error(`Unknown array mode option '${this.options.arrays.mode}'`)
}
}
Expand Down
2 changes: 2 additions & 0 deletions test/helpers/testSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function testSchema(options) {
const testSchemaWithArrayMerge = testSchema({arrays: {mode: 'all'}})
const testSchemaWithoutArrayMerge = testSchema({arrays: {mode: 'first'}})
const testSchemaArrayUniform = testSchema({arrays: {mode: 'uniform'}})
const testSchemaArrayTuple = testSchema({arrays: {mode: 'tuple'}})

const tesSchemaWithAndWithoutArrayMerge = (instance, jsonSchema, additionalOptions) => {
testSchemaWithArrayMerge(instance, jsonSchema, additionalOptions)
Expand All @@ -31,4 +32,5 @@ module.exports = {
testSchemaWithoutArrayMerge,
tesSchemaWithAndWithoutArrayMerge,
testSchemaArrayUniform,
testSchemaArrayTuple,
}
111 changes: 111 additions & 0 deletions test/schema/arrays.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const should = require('chai').should()
const testSchema = require('../helpers/testSchema').testSchemaWithoutArrayMerge
const testSchemaMerge = require('../helpers/testSchema').testSchemaWithArrayMerge
const testSchemaBoth = require('../helpers/testSchema').tesSchemaWithAndWithoutArrayMerge
const testSchemaTuple = require('../helpers/testSchema').testSchemaArrayTuple

describe('Array', () => {

Expand All @@ -23,6 +24,23 @@ describe('Array', () => {
})
})

it('should get tuple of integers schema for array of ints', () => {
testSchemaTuple([11, 12, 4], {
type: 'array',
items: [
{
type: 'integer',
},
{
type: 'integer',
},
{
type: 'integer',
},
],
})
})

it('should get array of numbers schema for array of floats', () => {
testSchemaBoth([11.3, 12.4, 11.3], {
type: 'array',
Expand All @@ -32,6 +50,23 @@ describe('Array', () => {
})
})

it('should get tuple of floats schema for array of floats', () => {
testSchemaTuple([11.3, 12.4, 11.3], {
type: 'array',
items: [
{
type: 'number',
},
{
type: 'number',
},
{
type: 'number',
},
],
})
})

it('should get array of numbers schema for array of mixed ints and floats with float first', () => {
const data = [11.3, 12.4, 4]
testSchemaMerge(data, {
Expand Down Expand Up @@ -63,6 +98,23 @@ describe('Array', () => {
})
})

it('should get tuple of mixed types schema for array of mixed types', () => {
testSchemaTuple([11, 'hello', 0.1], {
type: 'array',
items: [
{
type: 'integer',
},
{
type: 'string',
},
{
type: 'number',
},
],
})
})

it('should get simple array schema for array of mixed types', () => {
const data = ['hello', 'hi', 11]
testSchemaMerge(data, {type: 'array'})
Expand All @@ -87,6 +139,21 @@ describe('Array', () => {
})
})

it('should get tuple of object schema for array containing just one object', () => {
testSchemaTuple([{id: 11, title: 'test'}], {
type: 'array',
items: [
{
type: 'object',
properties: {
id: {type: 'integer'},
title: {type: 'string'},
},
},
],
})
})

it('should get array of specific objects schema for array of objects of same type', () => {
testSchemaBoth([
{id: 11, title: 'test'},
Expand All @@ -103,6 +170,28 @@ describe('Array', () => {
})
})

it('should get tuple of specific objects schema for array of objects of same type', () => {
testSchemaTuple([
{id: 11, title: 'test'},
{id: 12, title: 'test 2'},
], {
type: 'array',
items: [{
type: 'object',
properties: {
id: {type: 'integer'},
title: {type: 'string'},
},
}, {
type: 'object',
properties: {
id: {type: 'integer'},
title: {type: 'string'},
},
}],
})
})

it('should get array of specific objects schema for array of objects of same schema', () => {
const data = [
{id: 11, title: 'test'},
Expand All @@ -121,6 +210,28 @@ describe('Array', () => {
should.throw(() => testSchema(data), Error)
})

it('should get tuple of specific objects schema for array of objects of different schema', () => {
testSchemaTuple([
{id: 11.1, title: 'test'},
{id: 12, title: 'test 2'},
], {
type: 'array',
items: [{
type: 'object',
properties: {
id: {type: 'number'},
title: {type: 'string'},
},
}, {
type: 'object',
properties: {
id: {type: 'integer'},
title: {type: 'string'},
},
}],
})
})

it('should get array of generic objects schema for array of objects of incompatible schemas', () => {
const data = [
{id: 11, title: 'test'},
Expand Down

0 comments on commit 7ec237d

Please sign in to comment.