Skip to content

Instantly share code, notes, and snippets.

@minenwerfer
Created August 19, 2024 05:24
Show Gist options
  • Save minenwerfer/d5733b47785ae1042c2d82fc6245c1ce to your computer and use it in GitHub Desktop.
Save minenwerfer/d5733b47785ae1042c2d82fc6245c1ce to your computer and use it in GitHub Desktop.
export type ObjectToSchema<TObject, TRequired extends string[] | null = null> = TObject extends readonly [infer K]
? ValueToProperty<[K]>
: keyof TObject extends never
? { type: 'object' }
: {
[P in keyof TObject]: TObject[P] extends infer Value
? ValueToProperty<Value>
: never
} extends infer Properties
? TRequired extends null
? { type: 'object',
properties: Properties }
: { type: 'object',
required: TRequired,
properties: Properties }
: never
export type ValueToProperty<TValue> = TValue extends `$${infer Ref}`
? { $ref: Ref } : TValue extends string
? { type: 'string' } : TValue extends number
? { type: 'number' } : TValue extends boolean
? { type: 'boolean' } : TValue extends new ()=> Date
? { type: 'string',
format: 'date' } : TValue extends readonly [infer K]
? { type: 'array',
items: ValueToProperty<K> } : TValue extends (infer K)[]
? { enum: K } : TValue extends Record<string, any>
? keyof TValue extends never
? { type: 'object' }
: { type: 'object' } & ObjectToSchema<TValue> : never
const mapValueToProperty = (value: any): any => {
if( value.constructor === Object ) {
return Object.assign({
type: 'object',
}, fromLiteral(value))
}
if( value === Date ) {
return {
type: 'string',
format: 'date-time',
}
}
if( Array.isArray(value) ) {
return {
type: 'array',
items: mapValueToProperty(value[0]),
}
}
if( value && typeof value === 'string' ) {
return {
$ref: value,
}
}
return {
type: typeof value,
}
}
export const fromLiteral = <
const TObject,
TRequired extends (keyof TObject & string)[],
>(object: TObject, required?: TRequired) => {
const entries: [string, Property][] = []
for( const propName in object ) {
const value: any = object[propName]
if( value === null || value === undefined ) {
continue
}
entries.push([
propName,
mapValueToProperty(value),
])
}
const properties = Object.fromEntries(entries)
return {
type: 'object',
required,
properties,
} as ObjectToSchema<TObject, TRequired>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment