Mari's guided journal software.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

63 lines
3.2 KiB

import AJV, {ValidateFunction, JTDSchemaType} from "ajv/dist/jtd.js";
const ajv = new AJV();
interface BaseSchemaData<RepresentedT, ReferenceT extends string> {
value?: RepresentedT,
schema: unknown,
key: ReferenceT,
definition: { [key in ReferenceT]: unknown }
reference: { "ref": ReferenceT }
validate: ValidateFunction<RepresentedT>
requiredReferences: AnyReferenceList
}
export interface SchemaData<RepresentedT, ReferenceT extends string, ReferencesT extends AnyReferenceList, DefinitionsT extends ReferencedTypes<ReferencesT>> extends BaseSchemaData<RepresentedT, ReferenceT> {
value?: RepresentedT,
schema: JTDSchemaType<RepresentedT, DefinitionsT>,
key: ReferenceT,
definition: { [key in ReferenceT]: JTDSchemaType<RepresentedT, DefinitionsT> }
reference: { "ref": ReferenceT },
validate: ValidateFunction<RepresentedT>
requiredReferences: ReferencesT
}
export type AnySchemaDataFor<RepresentedT> = BaseSchemaData<RepresentedT, string>
export type AnySchemaData = AnySchemaDataFor<unknown>
export type AnyReferenceList = AnySchemaData[]
export type AnyDefinitions = Record<string, unknown>
export type Schema<DataT extends AnySchemaData> = Exclude<DataT["schema"], undefined>
export type Value<DataT extends AnySchemaData> = Exclude<DataT["value"], undefined>
export type Definition<DataT extends AnySchemaData> = Exclude<DataT["definition"], undefined>
export type Reference<DataT extends AnySchemaData> = Exclude<DataT["reference"], undefined>
export type ReferenceKey<DataT extends AnySchemaData> = Exclude<DataT["key"], undefined>
export type ReferencedSchemaMap<ReferencesT extends AnyReferenceList> = {
[Property in keyof ReferencesT as ReferencesT[Property] extends AnySchemaData ? ReferenceKey<ReferencesT[Property]> : never]: ReferencesT[Property] extends AnySchemaData ? ReferencesT[Property] : never
}
export type ReferencedSchema<ReferencesT extends AnyReferenceList> = ReferencedSchemaMap<ReferencesT>[keyof ReferencedSchemaMap<ReferencesT>]
export type ReferencedTypes<ReferencesT extends AnyReferenceList> = {
[Property in keyof ReferencedSchemaMap<ReferencesT>]?: Value<ReferencedSchemaMap<ReferencesT>[Property]>
}
// TODO: Add a test for a circular definition (i.e., an object that contains a reference to itself, for recursive objects like trees) in both one- and two-object loops
export function schema<
RepresentedT,
KeyT extends string,
ReferencesT extends AnySchemaData[],
>({schema, key, references}: { schema: JTDSchemaType<RepresentedT, ReferencedTypes<ReferencesT>>, key: KeyT, references: ReferencesT, typeHint?: RepresentedT|null }): SchemaData<RepresentedT, KeyT, ReferencesT, ReferencedTypes<ReferencesT>> {
const definition = {[key]: schema} as Definition<SchemaData<RepresentedT, KeyT, ReferencesT, ReferencedTypes<ReferencesT>>>
const reference = {ref: key}
const definitions = references.reduce<AnyDefinitions>((definitions, reference) => ({...reference.definition, ...definitions}), definition)
const validate = ajv.compile<RepresentedT>({ ...reference, definitions })
return {
schema,
key,
definition,
reference,
validate,
requiredReferences: references
}
}