jsonbinpack
Version:
A space-efficient schema-driven binary JSON serialization format based on JSON Schema
150 lines (140 loc) • 4.47 kB
text/typescript
/*
* Copyright 2021 Juan Cruz Viotti
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
strict as assert
} from 'assert'
import {
intersection,
uniqWith,
isEqual
} from 'lodash'
import {
JSONBoolean
} from '../json'
import {
ObjectSchema
} from '../jsonschema'
import {
SimplificationRule
} from './rule'
export const RULES: SimplificationRule[] = [
{
id: 'equal-numeric-bounds-as-const',
condition: (schema: ObjectSchema): JSONBoolean => {
return 'minimum' in schema && 'maximum' in schema &&
schema.minimum === schema.maximum
},
transform: (schema: ObjectSchema): ObjectSchema => {
const value = schema.maximum
Reflect.deleteProperty(schema, 'maximum')
Reflect.deleteProperty(schema, 'minimum')
return Object.assign(schema, {
const: value
})
}
},
{
id: 'empty-string',
condition: (schema: ObjectSchema): JSONBoolean => {
return schema.type === 'string' &&
'maxLength' in schema && schema.maxLength === 0
},
transform: (schema: ObjectSchema): ObjectSchema => {
Reflect.deleteProperty(schema, 'maxLength')
return Object.assign(schema, {
const: ''
})
}
},
{
id: 'empty-array',
condition: (schema: ObjectSchema): JSONBoolean => {
return schema.type === 'array' &&
'maxItems' in schema && schema.maxItems === 0
},
transform: (schema: ObjectSchema): ObjectSchema => {
Reflect.deleteProperty(schema, 'maxItems')
return Object.assign(schema, {
const: []
})
}
},
{
id: 'empty-object',
condition: (schema: ObjectSchema): JSONBoolean => {
return schema.type === 'object' &&
'maxProperties' in schema && schema.maxProperties === 0
},
transform: (schema: ObjectSchema): ObjectSchema => {
Reflect.deleteProperty(schema, 'maxProperties')
return Object.assign(schema, {
const: {}
})
}
},
{
id: 'dependent-required-tautology',
condition: (schema: ObjectSchema): JSONBoolean => {
return typeof schema.dependentRequired === 'object' &&
!Array.isArray(schema.dependentRequired) &&
schema.dependentRequired !== null && Array.isArray(schema.required) &&
intersection(Object.keys(schema.dependentRequired), schema.required).length > 0
},
transform: (schema: ObjectSchema): ObjectSchema => {
assert(Array.isArray(schema.required))
assert(typeof schema.dependentRequired === 'object' &&
!Array.isArray(schema.dependentRequired) &&
schema.dependentRequired !== null)
for (const name of intersection(Object.keys(schema.dependentRequired), schema.required)) {
for (const key of schema.dependentRequired[name]) {
if (!schema.required.includes(key)) {
schema.required.push(key)
}
}
Reflect.deleteProperty(schema.dependentRequired, name)
}
return schema
}
},
{
id: 'duplicate-allof-branches',
condition: (schema: ObjectSchema): JSONBoolean => {
return Array.isArray(schema.allOf) &&
uniqWith(schema.allOf, isEqual).length !== schema.allOf.length
return schema.type === 'object' &&
'maxProperties' in schema && schema.maxProperties === 0
},
transform: (schema: ObjectSchema): ObjectSchema => {
return Object.assign(schema, {
allOf: uniqWith(schema.allOf, isEqual)
})
}
},
{
id: 'duplicate-anyof-branches',
condition: (schema: ObjectSchema): JSONBoolean => {
return Array.isArray(schema.anyOf) &&
uniqWith(schema.anyOf, isEqual).length !== schema.anyOf.length
return schema.type === 'object' &&
'maxProperties' in schema && schema.maxProperties === 0
},
transform: (schema: ObjectSchema): ObjectSchema => {
return Object.assign(schema, {
anyOf: uniqWith(schema.anyOf, isEqual)
})
}
}
]