UNPKG

nestjs-typebox

Version:

This library provides helper utilities for writing and validating NestJS APIs using [TypeBox](https://github.com/sinclairzx81/typebox) as an alternative to class-validator/class-transformer. Can be configured to patch @nestjs/swagger allowing OpenAPI gene

88 lines (73 loc) 3.09 kB
import type { TArray, TIntersect, TObject, TRecord, TRef, TSchema, TTuple, TUnion } from '@sinclair/typebox'; import { Kind, TypeGuard } from '@sinclair/typebox'; function FromArray(schema: TArray, analysis: SchemaAnalysis): void { Visit(schema.items, analysis); } function FromIntersect(schema: TIntersect, analysis: SchemaAnalysis) { analysis.hasTransform = analysis.hasTransform || TypeGuard.IsTransform(schema.unevaluatedProperties); schema.allOf.forEach(schema => Visit(schema, analysis)); } function FromObject(schema: TObject, analysis: SchemaAnalysis) { Object.values(schema.properties).forEach(schema => Visit(schema, analysis)); if (TypeGuard.IsSchema(schema.additionalProperties)) { Visit(schema.additionalProperties, analysis); } } function FromRecord(schema: TRecord, analysis: SchemaAnalysis) { if (!analysis.hasTransform && TypeGuard.IsSchema(schema.additionalProperties)) { analysis.hasTransform = TypeGuard.IsTransform(schema.additionalProperties); } const pattern = Object.getOwnPropertyNames(schema.patternProperties)[0]; const property = schema.patternProperties[pattern ?? '']; if (TypeGuard.IsSchema(property)) { Visit(property, analysis); } } function FromRef(schema: TRef, analysis: SchemaAnalysis) { const target = analysis.references.get(schema.$ref); if (target) { Visit(target, analysis); } } function FromTuple(schema: TTuple, analysis: SchemaAnalysis) { if (schema.items) { schema.items.forEach(schema => Visit(schema, analysis)); } } function FromUnion(schema: TUnion, analysis: SchemaAnalysis) { schema.anyOf.forEach(schema => Visit(schema, analysis)); } function Visit(schema: TSchema, analysis: SchemaAnalysis): void { analysis.hasTransform = analysis.hasTransform || TypeGuard.IsTransform(schema); analysis.hasDefault = analysis.hasDefault || 'default' in schema; if (schema.$id) { if (analysis.references.has(schema.$id)) return; analysis.references.set(schema.$id, schema); } switch (schema[Kind]) { case 'Array': return FromArray(schema as TSchema as TArray, analysis); case 'Intersect': return FromIntersect(schema as TSchema as TIntersect, analysis); case 'Object': return FromObject(schema as TSchema as TObject, analysis); case 'Record': return FromRecord(schema as TSchema as TRecord, analysis); case 'Ref': return FromRef(schema as TSchema as TRef, analysis); case 'Tuple': return FromTuple(schema as TSchema as TTuple, analysis); case 'Union': return FromUnion(schema as TSchema as TUnion, analysis); } } export interface SchemaAnalysis { hasTransform: boolean; hasDefault: boolean; references: Map<string, TSchema>; } export const analyzeSchema = (schema: TSchema): SchemaAnalysis => { const analysis = { hasTransform: false, hasDefault: false, references: new Map() }; Visit(schema, analysis); return analysis; };