json-schema-to-typescript
Version:
compile json schema to typescript typings
153 lines (134 loc) • 3.83 kB
text/typescript
import {JSONSchema4, JSONSchema4Type, JSONSchema4TypeName} from 'json-schema'
import {isPlainObject, memoize} from 'lodash'
export type SchemaType =
| 'ALL_OF'
| 'UNNAMED_SCHEMA'
| 'ANY'
| 'ANY_OF'
| 'BOOLEAN'
| 'NAMED_ENUM'
| 'NAMED_SCHEMA'
| 'NEVER'
| 'NULL'
| 'NUMBER'
| 'STRING'
| 'OBJECT'
| 'ONE_OF'
| 'TYPED_ARRAY'
| 'REFERENCE'
| 'UNION'
| 'UNNAMED_ENUM'
| 'UNTYPED_ARRAY'
| 'CUSTOM_TYPE'
export type JSONSchemaTypeName = JSONSchema4TypeName
export type JSONSchemaType = JSONSchema4Type
export interface JSONSchema extends JSONSchema4 {
/**
* schema extension to support numeric enums
*/
tsEnumNames?: string[]
/**
* schema extension to support custom types
*/
tsType?: string
/**
* property exists at least in https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.3
*/
deprecated?: boolean
}
export const Parent = Symbol('Parent')
export interface LinkedJSONSchema extends JSONSchema {
/**
* A reference to this schema's parent node, for convenience.
* `null` when this is the root schema.
*/
[Parent]: LinkedJSONSchema | null
additionalItems?: boolean | LinkedJSONSchema
additionalProperties?: boolean | LinkedJSONSchema
items?: LinkedJSONSchema | LinkedJSONSchema[]
definitions?: {
[k: string]: LinkedJSONSchema
}
properties?: {
[k: string]: LinkedJSONSchema
}
patternProperties?: {
[k: string]: LinkedJSONSchema
}
dependencies?: {
[k: string]: LinkedJSONSchema | string[]
}
allOf?: LinkedJSONSchema[]
anyOf?: LinkedJSONSchema[]
oneOf?: LinkedJSONSchema[]
not?: LinkedJSONSchema
}
export const Types = Symbol('Types')
export const Intersection = Symbol('Intersection')
/**
* Normalized JSON schema.
*
* Note: `definitions` and `id` are removed by the normalizer. Use `$defs` and `$id` instead.
*/
export interface NormalizedJSONSchema extends Omit<LinkedJSONSchema, 'definitions' | 'id'> {
[Intersection]?: NormalizedJSONSchema
[Parent]: NormalizedJSONSchema | null
[Types]: ReadonlySet<SchemaType>
additionalItems?: boolean | NormalizedJSONSchema
additionalProperties: boolean | NormalizedJSONSchema
extends?: string[]
items?: NormalizedJSONSchema | NormalizedJSONSchema[]
$defs?: {
[k: string]: NormalizedJSONSchema
}
properties?: {
[k: string]: NormalizedJSONSchema
}
patternProperties?: {
[k: string]: NormalizedJSONSchema
}
dependencies?: {
[k: string]: NormalizedJSONSchema | string[]
}
allOf?: NormalizedJSONSchema[]
anyOf?: NormalizedJSONSchema[]
oneOf?: NormalizedJSONSchema[]
not?: NormalizedJSONSchema
required: string[]
}
export interface EnumJSONSchema extends NormalizedJSONSchema {
enum: JSONSchema4Type[]
}
export interface NamedEnumJSONSchema extends NormalizedJSONSchema {
tsEnumNames: string[]
}
export interface SchemaSchema extends NormalizedJSONSchema {
properties: {
[k: string]: NormalizedJSONSchema
}
required: string[]
}
export interface JSONSchemaWithDefinitions extends NormalizedJSONSchema {
$defs: {
[k: string]: NormalizedJSONSchema
}
}
export interface CustomTypeJSONSchema extends NormalizedJSONSchema {
tsType: string
}
export const getRootSchema = memoize((schema: NormalizedJSONSchema): NormalizedJSONSchema => {
const parent = schema[Parent]
if (!parent) {
return schema
}
return getRootSchema(parent)
})
export function isBoolean(schema: LinkedJSONSchema | JSONSchemaType): schema is boolean {
return schema === true || schema === false
}
export function isPrimitive(schema: LinkedJSONSchema | JSONSchemaType): schema is JSONSchemaType {
return !isPlainObject(schema)
}
export function isCompound(schema: JSONSchema): boolean {
return Array.isArray(schema.type) || 'anyOf' in schema || 'oneOf' in schema
}