shinkansen-transmission
Version:
Shinkansen Transmission
1,007 lines (848 loc) • 22.7 kB
JavaScript
/**
* @typedef {TransmissionTypes.ObjectLiteralType} ObjectLiteralType
* @typedef {TransmissionTypes.ObjectType} ObjectType
*
* @typedef {TransmissionTypes.MemberArrayType} MemberArrayType
* @typedef {TransmissionTypes.MemberType} MemberType
*
* @typedef {TransmissionTypes.Transmission.StringMetaType} TransmissionStringMetaType
* @typedef {TransmissionTypes.Transmission.NumberMetaType} TransmissionNumberMetaType
* @typedef {TransmissionTypes.Transmission.ArrayMetaType} TransmissionArrayMetaType
* @typedef {TransmissionTypes.Transmission.ObjectMetaType} TransmissionObjectMetaType
* @typedef {TransmissionTypes.Transmission.BooleanMetaType} TransmissionBooleanMetaType
* @typedef {TransmissionTypes.Transmission.NullMetaType} TransmissionNullMetaType
*
* @typedef {TransmissionTypes.Transmission.StringElementsType} TransmissionStringElementsType
* @typedef {TransmissionTypes.Transmission.NumberElementsType} TransmissionNumberElementsType
* @typedef {TransmissionTypes.Transmission.ArrayElementsType} TransmissionArrayElementsType
* @typedef {TransmissionTypes.Transmission.ObjectElementsType} TransmissionObjectElementsType
* @typedef {TransmissionTypes.Transmission.BooleanElementsType} TransmissionBooleanElementsType
* @typedef {TransmissionTypes.Transmission.NullElementsType} TransmissionNullElementsType
*
* @typedef {TransmissionTypes.EnumType} EnumType
* @typedef {TransmissionTypes.AnyOfType} AnyOfType
* @typedef {TransmissionTypes.OneOfType} OneOfType
* @typedef {TransmissionTypes.FieldType} FieldType
*
* @typedef {TransmissionTypes.SchemaType} SchemaType
*
* @typedef {TransmissionTypes.StringSchemaType} StringSchemaType
* @typedef {TransmissionTypes.NumberSchemaType} NumberSchemaType
* @typedef {TransmissionTypes.ArraySchemaType} ArraySchemaType
* @typedef {TransmissionTypes.ObjectSchemaType} ObjectSchemaType
* @typedef {TransmissionTypes.BooleanSchemaType} BooleanSchemaType
* @typedef {TransmissionTypes.NullSchemaType} NullSchemaType
*
* @typedef {TransmissionTypes.ValuesType} ValuesType
* @typedef {TransmissionTypes.ParamsType} ParamsType
*/
import debug from 'debug'
import equal from 'fast-deep-equal'
const log = debug('shinkansen-transmission/transmission/common')
log('`shinkansen` is awake')
/**
* @param {unknown} [v]
* @returns {v is (MemberArrayType)} // | SchemaType)[]}
*/
export const isArray = (v) => Array.isArray(v)
/**
* @param {unknown} [v]
* @returns {v is (Record<PropertyKey, MemberType | MemberArrayType> | Record<PropertyKey, never>)}
*/
export const isObject = (v) => typeof (v || false) === 'object' && !isArray(v)
/**
* @param {unknown} [v]
* @returns {v is (string | number | boolean | null)}
*/
export const isPrimitive = (v) => !isObject(v) && !isArray(v)
/**
* @param {SchemaType | object} [v]
* @returns {v is SchemaType}
*/
export const isSchema = (v = {}) => 'type' in v
/**
* @param {SchemaType} schema
* @returns {schema is StringSchemaType}
*/
export const isStringSchema = ({ type } = {}) => type === 'string'
/**
* @param {SchemaType} schema
* @returns {schema is NumberSchemaType}
*/
export const isNumberSchema = ({ type } = {}) => type === 'number'
/**
* @param {SchemaType} schema
* @returns {schema is ArraySchemaType}
*/
export const isArraySchema = ({ type } = {}) => type === 'array'
/**
* @param {SchemaType} schema
* @returns {schema is ObjectSchemaType}
*/
export const isObjectSchema = ({ type } = {}) => type === 'object'
/**
* @param {SchemaType} schema
* @returns {schema is BooleanSchemaType}
*/
export const isBooleanSchema = ({ type } = {}) => type === 'boolean'
/**
* @param {SchemaType} schema
* @returns {schema is NullSchemaType}
*/
export const isNullSchema = ({ type } = {}) => type === 'null'
/**
* @param {SchemaType} schema
* @returns {{ title: string} | {}}
*/
export const getTitle = ({ title } = {}) => (title ? { title } : {})
/**
* @param {SchemaType} schema
* @returns {{ description: string} | {}}
*/
export const getDescription = ({ description } = {}) => (description ? { description } : {})
/**
* @param {SchemaType} schema
* @returns {{ readOnly: boolean } | {}}
*/
export const getIsReadOnly = ({ readOnly = false } = {}) => (readOnly ? { readOnly } : {})
/**
* @param {SchemaType} schema
* @returns {{ writeOnly: boolean } | {}}
*/
export const getIsWriteOnly = ({ writeOnly = false } = {}) => (writeOnly ? { writeOnly } : {})
/**
* @param {string} uri
* @returns {string}
*/
const getUriForRegExp = (uri) => uri.endsWith('/') ? uri : uri + '/'
/**
* @param {Record<string, string | number | boolean | null | string[] | number[] | boolean[] | null[]>} [values]
* @param {string} [uri]
* @returns {(
* string |
* number |
* boolean |
* null
* )[]}
*/
export function getSelectedItems (values = {}, uri = '#') {
const u = normaliseUri(uri)
if (u in values) {
const v = values[u]
if (isPrimitive(v)) {
const n = Number(v)
return isNaN(n)
? [v]
: [n]
}
return v.map((v) => {
const n = Number(v)
return isNaN(n)
? v
: n
})
}
/*
* Given the uri `#/`
*
* Get the values `#/n` (where `n` is a number)
*/
const pattern = new RegExp(`^${getUriForRegExp(u)}\\d+$`)
return (
Object
.entries(values)
.filter(([key]) => pattern.test(key)) // uri
.map(([key, value]) => {
const i = Number(key.slice(key.lastIndexOf('/') + 1))
const v = isArray(value) ? value[i] : value
const n = Number(v)
return isNaN(n)
? v
: n
})
)
}
/**
* @param {string} [parentUri]
* @param {string} [uri]
* @returns {boolean}
*/
export function isParentUri (parentUri = '#', uri = '#') {
return (
parentUri !== '#' &&
parentUri !== uri
)
}
/**
* @param {ParamsType} [params]
* @param {string} [uri]
* @returns {TransmissionStringMetaType | TransmissionNumberMetaType | TransmissionArrayMetaType | TransmissionObjectMetaType | TransmissionBooleanMetaType | TransmissionNullMetaType | Record<string, never>}
*/
export function getMetaProps (params = {}, uri = '#') {
if (uri in params) {
const {
meta = {}
} = params[uri]
return meta
}
return {}
}
/**
* @param {SchemaType} [schema]
* @returns {boolean}
*/
export function hasMetaDefaultValue (schema = {}) {
if ('default' in schema) {
const defaultValue = schema.default
return isPrimitive(defaultValue)
}
return false
}
/**
* @param {SchemaType} [schema]
* @returns {{ defaultValue: string } | {}}
*/
export function getMetaDefaultValue (schema = {}) {
if ('default' in schema) {
const defaultValue = schema.default
return { defaultValue: String(defaultValue) }
}
return {}
}
/**
* @param {ValuesType} [values]
* @param {string} [uri]
* @param {SchemaType} [schema]
* @returns {boolean}
*/
export function hasMetaValue (values = {}, uri = '#', schema = {}) {
if (uri in values) {
const value = values[uri]
return isPrimitive(value)
}
if ('const' in schema) {
const constValue = schema.const
return isPrimitive(constValue)
}
return false
}
/**
* @param {ValuesType} [values]
* @param {string} [uri]
* @param {SchemaType} [schema]
* @returns {{ value: string } | {}}
*/
export function getMetaValue (values = {}, uri = '#', schema = {}) {
if (uri in values) {
const value = values[uri]
if (isPrimitive(value)) {
return { value: String(value) }
}
}
if ('const' in schema) {
const constValue = schema.const
if (isPrimitive(constValue)) {
return { value: String(constValue) }
}
}
return {}
}
/**
* @param {MemberType} [item]
* @returns {MemberType | undefined}
*/
export function transformToValue (item) {
if (item === undefined) return item
if (isPrimitive(item)) return item
if (isArray(item)) return item
if (isObject(item)) {
if (hasConst(item)) {
return getConst(item)
} else {
if (hasDefault(item)) {
return getDefault(item)
}
}
return item
}
}
/**
* @param {string} parentUri
* @param {string} uri
* @returns {(key: string | number) => boolean}
*/
export function getFindByKey (parentUri, uri) {
/*
* log('getFindByKey')
*/
return function find (key) {
/*
* log('find')
*/
return (
getUri(parentUri, key) === uri
)
}
}
/**
* @param {string} parentUri
* @param {string} uri
* @returns {(schema: SchemaType, index: number) => boolean}
*/
export function getFindByIndex (parentUri, uri) {
/*
* log('getFindByIndex')
*/
return function find (schema, index) {
/*
* log('find')
*/
return (
getUri(parentUri, index) === uri
)
}
}
/**
* @param {MemberType} [value]
* @returns {(item?: MemberType | MemberArrayType) => boolean}
*/
export function getFindByValue (value) {
/*
* log('getFindByValue')
*/
return function find (item) {
/*
* log('find')
*/
return (
value === transformToValue(item)
)
}
}
/**
* @param {MemberType} [value]
* @returns {(item?: MemberType | MemberArrayType) => boolean}
*/
export function getFindByEqual (value) {
/*
* log('getFindByEqual')
*/
return function find (item) {
/*
* log('find')
*/
return (
equal(value, transformToValue(item))
)
}
}
/**
* @param {MemberType} [value]
* @returns {string}
*/
export function toString (value) {
/*
* log('toString')
*/
return (value !== undefined) ? String(value) : ''
}
/**
* @param {{ items?: SchemaType | SchemaType[] }} schema
* @param {string} parentUri
* @param {string} uri
* @returns {SchemaType | undefined}
*/
export function getSchemaFromItems ({ items /* array or object */ }, parentUri, uri) {
/*
* log('getSchemaFromItems')
*/
if (isArray(items)) {
return (
items.find(getFindByIndex(parentUri, uri))
)
} else {
if (isObject(items)) {
return (
items
)
}
}
return undefined
}
/**
* @param {{ properties?: Record<string, SchemaType> }} schema
* @param {string} parentUri
* @param {string} uri
* @returns {SchemaType | undefined}
*/
export function getSchemaFromProperties ({ properties /* object */ }, parentUri, uri) {
/*
* log('getSchemaFromProperties')
*/
if (isObject(properties)) {
const key = Object.keys(properties).find(getFindByKey(parentUri, uri))
if (key) {
return (
properties[key]
)
}
}
return undefined
}
/**
* @param {MemberArrayType} array
* @param {MemberType} [value]
* @returns {string}
*/
export function transformIndexToValueByFindValue (array, value) {
/*
* log('transformIndexToValueByFindValue')
*/
const index = findIndexByValue(array, value)
/*
* Transform a number to a string
*/
return String(index)
}
/**
* @param {MemberArrayType} array
* @param {MemberType} [value]
* @returns {number}
*/
export function findIndexByValue (array, value) {
/*
* log('findIndexByValue')
*/
const find = getFindByValue(value)
return (
array.findIndex(find)
)
}
/**
* @param {MemberArrayType} array
* @param {MemberType} [value]
* @returns {string}
*/
export function transformIndexToValueByFindEqual (array, value) {
/*
* log('transformIndexToValueByFindEqual')
*/
const index = findIndexByEqual(array, value)
/*
* Transform a number to a string
*/
return String(index)
}
/**
* @param {MemberArrayType} array
* @param {MemberType} [value]
* @returns {MemberType}
*/
export function findIndexByEqual (array, value) {
/*
* log('findIndexByEqual')
*/
const find = getFindByEqual(value)
return (
array.findIndex(find)
)
}
/**
* @deprecated
*
* @param {ValuesType} [values]
* @param {string} [uri]
* @param {SchemaType} [schema]
* @returns {boolean}
*/
export function hasValue (values = {}, uri = '#', schema = {}) {
if (uri in values) {
const value = values[uri]
return isPrimitive(value)
}
if ('const' in schema) {
const constValue = schema.const
return isPrimitive(constValue)
}
return false
}
/**
* @deprecated
*
* @param {ValuesType} [values]
* @param {string} [uri]
* @param {SchemaType} [schema]
* @returns {string}
*/
export function getValue (values = {}, uri = '#', schema = {}) {
if (uri in values) {
const value = values[uri]
if (isPrimitive(value)) {
return String(value)
}
}
if ('const' in schema) {
const constValue = schema.const
if (isPrimitive(constValue)) {
return String(constValue)
}
}
return ''
}
/**
* @param {ParamsType} [params]
* @param {string} [uri]
* @returns {TransmissionStringElementsType | TransmissionNumberElementsType | TransmissionArrayElementsType | TransmissionObjectElementsType | TransmissionBooleanElementsType | TransmissionNullElementsType | Record<string, never>}
*/
export function getElementsProps (params = {}, uri = '#') {
if (uri in params) {
const {
elements = {}
} = params[uri]
return elements
}
return {}
}
/**
* @param {ParamsType} [params]
* @param {string} [uri]
* @returns {EnumType | ObjectLiteralType}
*/
export function getElementsFieldPropsForEnum (params = {}, uri = '#') {
if (uri in params) {
/**
* @type {{ elements?: { enum?: EnumType | ObjectLiteralType } }}
*/
const {
elements: {
enum: value = {}
} = {}
} = params[uri]
return value
}
return {}
}
/**
* @param {ParamsType} [params]
* @param {string} [uri]
* @returns {OneOfType | ObjectLiteralType}
*/
export function getElementsFieldPropsForOneOf (params = {}, uri = '#') {
if (uri in params) {
/**
* @type {{ elements?: { oneOf?: OneOfType | ObjectLiteralType } }}
*/
const {
elements: {
oneOf: value = {}
} = {}
} = params[uri]
return value
}
return {}
}
/**
* @param {ParamsType} [params]
* @param {string} [uri]
* @returns {AnyOfType | ObjectLiteralType}
*/
export function getElementsFieldPropsForAnyOf (params = {}, uri = '#') {
if (uri in params) {
/**
* @type {{ elements?: { anyOf?: AnyOfType | ObjectLiteralType } }}
*/
const {
elements: {
anyOf: value = {}
} = {}
} = params[uri]
return value
}
return {}
}
/**
* @param {ParamsType} [params]
* @param {string} [uri]
* @returns {FieldType | ObjectLiteralType}
*/
export function getElementsFieldPropsForAllOf (params = {}, uri = '#') {
if (uri in params) {
/**
* @type {{ elements?: { field?: FieldType | ObjectLiteralType } }}
*/
const {
elements: {
field: value = {}
} = {}
} = params[uri]
return value
}
return {}
}
/**
* @param {ParamsType} [params]
* @param {string} [uri]
* @returns {FieldType | ObjectLiteralType}
*/
export function getElementsFieldProps (params = {}, uri = '#') {
if (uri in params) {
/**
* @type {{ elements?: { field?: FieldType | ObjectLiteralType } }}
*/
const {
elements: {
field: value = {}
} = {}
} = params[uri]
return value
}
return {}
}
/**
* @param {ValuesType} [values]
* @param {string} [uri]
* @param {SchemaType} [schema]
* @returns {{ value: string } | {}}
*/
export function getElementsFieldValue (values = {}, uri = '#', schema = {}) {
if (uri in values) {
const value = values[uri]
if (isPrimitive(value)) {
return { value: String(value) }
}
}
if ('const' in schema) {
const constValue = schema.const
if (isPrimitive(constValue)) {
return { value: String(constValue) }
}
}
if ('default' in schema) {
const defaultValue = schema.default
if (isPrimitive(defaultValue)) {
return { value: String(defaultValue) }
}
}
return {}
}
/**
* @param {{ 'enum'?: MemberArrayType }} [schema]
* @returns {schema is { 'enum': MemberArrayType }}
*/
export const hasEnum = (schema = {}) => 'enum' in schema
/**
* @overload
* @param {{ 'enum': MemberArrayType }} schema
* @returns {MemberArrayType}
*
* @param {{ 'enum'?: MemberArrayType }} [schema]
* @returns {MemberArrayType | undefined}
*/
export const getEnum = (schema = {}) => schema.enum
/**
* @param {{ 'anyOf'?: MemberArrayType }} [schema]
* @returns {schema is { 'anyOf': MemberArrayType }}
*/
export const hasAnyOf = (schema = {}) => 'anyOf' in schema
/**
* @overload
* @param {{ 'anyOf': MemberArrayType }} schema
* @returns {MemberArrayType}
*
* @param {{ 'anyOf'?: MemberArrayType }} [schema]
* @returns {MemberArrayType | undefined}
*/
export const getAnyOf = (schema = {}) => schema.anyOf
/**
* @param {{ 'oneOf'?: MemberArrayType }} [schema]
* @returns {schema is { 'oneOf': MemberArrayType }}
*/
export const hasOneOf = (schema = {}) => 'oneOf' in schema
/**
* @overload
* @param {{ 'oneOf': MemberArrayType }} schema
* @returns {MemberArrayType}
*
* @param {{ 'oneOf'?: MemberArrayType }} schema
* @returns {MemberArrayType | undefined}
*/
export const getOneOf = (schema = {}) => schema.oneOf
/**
* @param {{ 'allOf'?: MemberArrayType }} [schema]
* @returns {schema is { 'allOf': MemberArrayType }}
*/
export const hasAllOf = (schema = {}) => 'allOf' in schema
/**
* @overload
* @param {{ 'allOf': MemberArrayType }} schema
* @returns {MemberArrayType}
*
* @param {{ 'allOf'?: MemberArrayType }} [schema]
* @returns {MemberArrayType | undefined}
*/
export const getAllOf = (schema = {}) => schema.allOf
/**
* @param {{ 'const'?: MemberType }} [schema]
* @returns {schema is { 'const': MemberType }}
*/
export const hasConst = (schema = {}) => 'const' in schema
/**
* @overload
* @param {{ 'const': MemberType }} schema
* @returns {MemberType}
*
* @param {{ 'const'?: MemberType }} [schema]
* @returns {MemberType | undefined}
*/
export const getConst = (schema = {}) => schema.const
/**
* @param {{ 'default'?: MemberType }} [schema]
* @returns {schema is { 'default': MemberType }}
*/
export const hasDefault = (schema = {}) => 'default' in schema
/**
* @overload
* @param {{ 'default': MemberType }} schema
* @returns {MemberType}
*
* @param {{ 'default'?: MemberType }} [schema]
* @returns {MemberType | undefined}
*/
export const getDefault = (schema = {}) => schema.default
/**
* @param {string} [uri]
* @param {string | number} [resource]
* @returns {string}
*/
export const getUri = (uri = '#', resource = '') => (uri.endsWith('/') ? uri : uri + '/') + String(resource)
/**
* @param {string} [uri]
* @returns {string}
*/
export const normaliseUri = (uri = '#') => uri === '#' ? '#/' : uri
/**
* @param {{ minimum?: number }} schema
* @returns {{ min: number } | {}}
*/
export function getMin ({ minimum } = {}) {
const value = Number(minimum)
return isNaN(value) ? {} : { min: value }
}
/**
* @param {{ maximum?: number }} schema
* @returns {{ max: number } | {}}
*/
export function getMax ({ maximum } = {}) {
const value = Number(maximum)
return isNaN(value) ? {} : { max: value }
}
/**
* @param {{ minLength?: number }} schema
* @returns {{ minLength: number } | {}}
*/
export function getMinLength ({ minLength } = {}) {
const value = Number(minLength)
return isNaN(value) ? {} : { minLength: value }
}
/**
* @param {{ maxLength?: number }} schema
* @returns {{ maxLength: number } | {}}
*/
export function getMaxLength ({ maxLength } = {}) {
const value = Number(maxLength)
return isNaN(value) ? {} : { maxLength: value }
}
/**
* @param {{ minItems?: number }} schema
* @returns {{ minItems: number } | {}}
*/
export function getMinItems ({ minItems } = {}) {
const value = Number(minItems)
return isNaN(value) ? {} : { minItems: value }
}
/**
* @param {{ maxItems?: number }} schema
* @returns {{ maxItems: number } | {}}
*/
export function getMaxItems ({ maxItems } = {}) {
const value = Number(maxItems)
return isNaN(value) ? {} : { maxItems: value }
}
/**
* @param {{ uniqueItems?: boolean }} schema
* @returns {{ hasUniqueItems: boolean } | {}}
*/
export function getHasUniqueItems (schema = {}) {
if ('uniqueItems' in schema) {
const value = schema.uniqueItems
return (typeof value === 'boolean') ? { hasUniqueItems: value } : {}
}
return {}
}
/**
* @param {{ minContains?: number }} schema
* @returns {{ minContains: number } | {}}
*/
export function getMinContains ({ minContains } = {}) {
const value = Number(minContains)
return isNaN(value) ? {} : { minContains: value }
}
/**
* @param {{ maxContains?: number }} schema
* @returns {{ maxContains: number } | {}}
*/
export function getMaxContains ({ maxContains } = {}) {
const value = Number(maxContains)
return isNaN(value) ? {} : { maxContains: value }
}
/**
* @param {{ minProperties?: number }} schema
* @returns {{ minProperties: number } | {}}
*/
export function getMinProperties ({ minProperties } = {}) {
const value = Number(minProperties)
return isNaN(value) ? {} : { minProperties: value }
}
/**
* @param {{ maxProperties?: number }} schema
* @returns {{ maxProperties: number } | {}}
*/
export function getMaxProperties ({ maxProperties } = {}) {
const value = Number(maxProperties)
return isNaN(value) ? {} : { maxProperties: value }
}
/**
* @param {{ exclusiveMinimum?: boolean }} schema
* @returns {{ isExclusiveMin: boolean } | {}}
*/
export function getIsExclusiveMin (schema = {}) {
if ('exclusiveMinimum' in schema) {
const value = schema.exclusiveMinimum
return (typeof value === 'boolean') ? { isExclusiveMin: value } : {}
}
return {}
}
/**
* @param {{ exclusiveMaximum?: boolean }} schema
* @returns {{ isExclusiveMax: boolean } | {}}
*/
export function getIsExclusiveMax (schema = {}) {
if ('exclusiveMaximum' in schema) {
const value = schema.exclusiveMaximum
return (typeof value === 'boolean') ? { isExclusiveMax: value } : {}
}
return {}
}
/**
* @param {{ pattern?: RegExp }} schema
* @returns {{ pattern: RegExp } | {}}
*/
export const getPattern = ({ pattern } = {}) => (pattern ? { pattern } : {})
/**
* @param {{ multipleOf?: number }} schema
* @returns {{ step: number } | {}}
*/
export function getStep ({ multipleOf } = {}) {
const value = Number(multipleOf)
return isNaN(value) ? {} : { step: value }
}