datum-focus
Version:
Data shape, model, metadata, JSON, JSON Schema, GraphQL, MongoDB query and aggregations, iterator generators
121 lines (112 loc) • 3.83 kB
text/typescript
import { ArrayType, BooleanType, IntegerType, NumberType, ObjectType, StringType } from './domain';
export type SomeJSONSchema = JSONSchemaType<Known, true>
export type PartialSchema<T> = Partial<JSONSchemaType<T, true>>
type JSONType<T extends string, _partial extends boolean> = _partial extends true
? T | undefined
: T
export type JSONSchemaType<T, _partial extends boolean = false> = (T extends number
? {
type: JSONType<NumberType | IntegerType, _partial>
minimum?: number
maximum?: number
exclusiveMinimum?: number
exclusiveMaximum?: number
multipleOf?: number
format?: string
}
: T extends string
? {
type: JSONType<StringType, _partial>
minLength?: number
maxLength?: number
pattern?: string
format?: string
}
: T extends boolean
? {
type: BooleanType
}
: T extends [any, ...any[]]
? {
// JSON AnySchema for tuple
type: JSONType<ArrayType, _partial>
items: {
[K in keyof T]-?: JSONSchemaType<T[K]> & Nullable<T[K]>
} & {length: T['length']}
minItems: T['length']
} & ({maxItems: T['length']} | {additionalItems: false})
: T extends any[]
? {
type: JSONType<ArrayType, _partial>
items: JSONSchemaType<T[0]>
contains?: PartialSchema<T[0]>
minItems?: number
maxItems?: number
minContains?: number
maxContains?: number
uniqueItems?: true
additionalItems?: never
}
: T extends Record<string, any>
? {
// JSON AnySchema for records and dictionaries
// 'required' is not optional because it is often forgotten
// 'properties' are optional for more concise dictionary schemas
// 'patternProperties' and can be only used with interfaces that have string index
type: JSONType<ObjectType, _partial>
// 'required' type does not guarantee that all required properties are listed
// it only asserts that optional cannot be listed
required: _partial extends true ? (keyof T)[] : RequiredMembers<T>[]
additionalProperties?: boolean | JSONSchemaType<T[string]>
unevaluatedProperties?: boolean | JSONSchemaType<T[string]>
properties?: _partial extends true ? Partial<PropertiesSchema<T>> : PropertiesSchema<T>
patternProperties?: {[Pattern in string]?: JSONSchemaType<T[string]>}
propertyNames?: JSONSchemaType<string>
dependencies?: {[K in keyof T]?: (keyof T)[] | PartialSchema<T>}
dependentRequired?: {[K in keyof T]?: (keyof T)[]}
dependentSchemas?: {[K in keyof T]?: PartialSchema<T>}
minProperties?: number
maxProperties?: number
}
: T extends null
? {
nullable: true
}
: never) & {
[keyword: string]: any
$id?: string
$ref?: string
$defs?: {
[Key in string]?: JSONSchemaType<Known, true>
}
definitions?: {
[Key in string]?: JSONSchemaType<Known, true>
}
allOf?: PartialSchema<T>[]
anyOf?: PartialSchema<T>[]
oneOf?: PartialSchema<T>[]
if?: PartialSchema<T>
then?: PartialSchema<T>
else?: PartialSchema<T>
not?: PartialSchema<T>
}
type Known = KnownRecord | [Known, ...Known[]] | Known[] | number | string | boolean | null
interface KnownRecord extends Record<string, Known> {}
type PropertiesSchema<T> = {
[K in keyof T]-?: (JSONSchemaType<T[K]> & Nullable<T[K]>) | {$ref: string}
}
type RequiredMembers<T> = {
[K in keyof T]-?: undefined extends T[K] ? never : K
}[keyof T]
type Nullable<T> = undefined extends T
? {
nullable: true
const?: never // any non-null value would fail `const: null`, `null` would fail any other value in const
enum?: (T | null)[] // `null` must be explicitly included in 'enum' for `null` to pass
default?: T | null
}
: {
const?: T
enum?: T[]
default?: T
}