@naturalcycles/nodejs-lib
Version:
Standard library for Node.js
104 lines (92 loc) • 2.49 kB
text/typescript
import { _uniq } from '@naturalcycles/js-lib/array'
import { _filterNullishValues } from '@naturalcycles/js-lib/object'
import type { AnyObject } from '@naturalcycles/js-lib/types'
import type { JsonSchema } from './jSchema.js'
export const JSON_SCHEMA_ORDER = [
'$schema',
'$id',
'title',
'description',
'deprecated',
'readOnly',
'writeOnly',
'type',
'default',
// Object,
'properties',
'required',
'minProperties',
'maxProperties',
'patternProperties',
'propertyNames',
// Array
'properties',
'required',
'minProperties',
'maxProperties',
'patternProperties',
'propertyNames',
// String
'pattern',
'minLength',
'maxLength',
'format',
'transform',
// Number
'format',
'multipleOf',
'minimum',
'exclusiveMinimum',
'maximum',
'exclusiveMaximum',
]
/**
* Merges s2 into s1 (mutates s1) and returns s1.
* Does not mutate s2.
* API similar to Object.assign(s1, s2)
*/
export function mergeJsonSchemaObjects<T1 extends AnyObject, T2 extends AnyObject>(
schema1: JsonSchema<T1>,
schema2: JsonSchema<T2>,
): JsonSchema<T1 & T2> {
const s1 = schema1 as any
const s2 = schema2 as any
// Merge `properties`
// Not vulnerable to prototype pollution: writes to s1.properties (a nested object),
// where __proto__ assignment only changes that object's prototype, not Object.prototype.
Object.entries(s2.properties).forEach(([k, v]) => {
s1.properties[k] = v
})
// Merge `patternProperties`
Object.entries(s2.patternProperties || {}).forEach(([k, v]) => {
s1.patternProperties[k] = v
})
s1.propertyNames = s2.propertyNames || s1.propertyNames
s1.minProperties = s2.minProperties ?? s1.minProperties
s1.maxProperties = s2.maxProperties ?? s1.maxProperties
// Merge `required`
s1.required.push(...s2.required)
s1.required = _uniq(s1.required).sort()
// `additionalProperties` remains the same
return _filterNullishValues(s1, { mutate: true })
}
export function isEveryItemString(arr: any[]): boolean {
for (const item of arr) {
if (typeof item !== 'string') return false
}
return true
}
export function isEveryItemNumber(arr: any[]): boolean {
for (const item of arr) {
if (typeof item !== 'number') return false
}
return true
}
export function isEveryItemPrimitive(arr: any[]): boolean {
for (const item of arr) {
if (typeof item !== 'number' && typeof item !== 'string' && typeof item !== 'symbol') {
return false
}
}
return true
}