/* eslint-disable @typescript-eslint/no-empty-interface */ type StrictNullChecksWrapper = undefined extends null ? `strictNullChecks must be true in tsconfig to use ${Name}` : Type type UnionToIntersection = (U extends any ? (_: U) => void : never) extends (_: infer I) => void ? I : never export type SomeJSONSchema = UncheckedJSONSchemaType type UncheckedPartialSchema = Partial> export type PartialSchema = StrictNullChecksWrapper<"PartialSchema", UncheckedPartialSchema> type JSONType = IsPartial extends true ? T | undefined : T interface NumberKeywords { minimum?: number maximum?: number exclusiveMinimum?: number exclusiveMaximum?: number multipleOf?: number format?: string } interface StringKeywords { minLength?: number maxLength?: number pattern?: string format?: string } type UncheckedJSONSchemaType = ( | // these two unions allow arbitrary unions of types { anyOf: readonly UncheckedJSONSchemaType[] } | { oneOf: readonly UncheckedJSONSchemaType[] } // this union allows for { type: (primitive)[] } style schemas | ({ type: readonly (T extends number ? JSONType<"number" | "integer", IsPartial> : T extends string ? JSONType<"string", IsPartial> : T extends boolean ? JSONType<"boolean", IsPartial> : never)[] } & UnionToIntersection< T extends number ? NumberKeywords : T extends string ? StringKeywords : T extends boolean ? // eslint-disable-next-line @typescript-eslint/ban-types {} : never >) // this covers "normal" types; it's last so typescript looks to it first for errors | ((T extends number ? { type: JSONType<"number" | "integer", IsPartial> } & NumberKeywords : T extends string ? { type: JSONType<"string", IsPartial> } & StringKeywords : T extends boolean ? { type: JSONType<"boolean", IsPartial> } : T extends readonly [any, ...any[]] ? { // JSON AnySchema for tuple type: JSONType<"array", IsPartial> items: { readonly [K in keyof T]-?: UncheckedJSONSchemaType & Nullable } & {length: T["length"]} minItems: T["length"] } & ({maxItems: T["length"]} | {additionalItems: false}) : T extends readonly any[] ? { type: JSONType<"array", IsPartial> items: UncheckedJSONSchemaType contains?: UncheckedPartialSchema minItems?: number maxItems?: number minContains?: number maxContains?: number uniqueItems?: true additionalItems?: never } : T extends Record ? { // 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<"object", IsPartial> additionalProperties?: boolean | UncheckedJSONSchemaType unevaluatedProperties?: boolean | UncheckedJSONSchemaType properties?: IsPartial extends true ? Partial> : UncheckedPropertiesSchema patternProperties?: Record> propertyNames?: Omit, "type"> & {type?: "string"} dependencies?: {[K in keyof T]?: Readonly<(keyof T)[]> | UncheckedPartialSchema} dependentRequired?: {[K in keyof T]?: Readonly<(keyof T)[]>} dependentSchemas?: {[K in keyof T]?: UncheckedPartialSchema} minProperties?: number maxProperties?: number } & (IsPartial extends true // "required" is not necessary if it's a non-partial type with no required keys // are listed it only asserts that optional cannot be listed. // "required" type does not guarantee that all required properties ? {required: Readonly<(keyof T)[]>} : [UncheckedRequiredMembers] extends [never] ? {required?: Readonly[]>} : {required: Readonly[]>}) : T extends null ? { type: JSONType<"null", IsPartial> nullable: true } : never) & { allOf?: Readonly[]> anyOf?: Readonly[]> oneOf?: Readonly[]> if?: UncheckedPartialSchema then?: UncheckedPartialSchema else?: UncheckedPartialSchema not?: UncheckedPartialSchema }) ) & { [keyword: string]: any $id?: string $ref?: string $defs?: Record> definitions?: Record> } export type JSONSchemaType = StrictNullChecksWrapper< "JSONSchemaType", UncheckedJSONSchemaType > type Known = | {[key: string]: Known} | [Known, ...Known[]] | Known[] | number | string | boolean | null type UncheckedPropertiesSchema = { [K in keyof T]-?: (UncheckedJSONSchemaType & Nullable) | {$ref: string} } export type PropertiesSchema = StrictNullChecksWrapper< "PropertiesSchema", UncheckedPropertiesSchema > type UncheckedRequiredMembers = { [K in keyof T]-?: undefined extends T[K] ? never : K }[keyof T] export type RequiredMembers = StrictNullChecksWrapper< "RequiredMembers", UncheckedRequiredMembers > type Nullable = undefined extends T ? { nullable: true const?: null // any non-null value would fail `const: null`, `null` would fail any other value in const enum?: Readonly<(T | null)[]> // `null` must be explicitly included in "enum" for `null` to pass default?: T | null } : { const?: T enum?: Readonly default?: T }