All files / schema data.ts

100% Statements 14/14
100% Branches 0/0
100% Functions 4/4
100% Lines 14/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100                        2x                     2x                     2x         2x                       2x   2x             2x 2x               2x 2x             2x                     2x 2x             2x      
import { z } from 'zod'
 
export type StringOptions = z.input<typeof StringSchema>
export type NumberOptions = z.input<typeof NumberSchema>
export type BooleanOptions = z.input<typeof BooleanSchema>
export type DateOptions = z.input<typeof DateSchema>
export type PersonOptions = z.input<typeof PersonSchema>
export type ArrayOptions = z.input<typeof ArraySchema>
export type ObjectOptions = z.input<typeof ObjectSchema>
export type PropertyOptions = z.input<typeof PropertySchema>
export type InputOptions = z.input<typeof DataSchema>
 
const StringSchema = z.object({
  type: z.enum(['string']),
  enum: z.array(z.string()).optional(),
  minLength: z.number().optional(),
  maxLength: z.number().optional(),
  pattern: z.string().optional(),
  format: z
    .enum(['lorem', 'email', 'uuid', 'url', 'ipv4', 'ipv6', 'hostname'])
    .optional(),
})
 
const NumberSchema = z.object({
  type: z.enum(['float', 'integer']).default('integer'),
  minimum: z.number().optional().default(0),
  maximum: z.number().optional().default(200),
  distribution: z.enum(['normal', 'uniform']).optional().default('uniform'),
  mean: z.number().optional().default(100),
  stddev: z.number().optional().default(20),
  precision: z.number().optional().default(1),
  count: z.number().optional().default(1)
})
 
const BooleanSchema = z.object({
  type: z.enum(['boolean']),
  probability: z.number().min(0).max(1).optional().default(0.5)
})
 
const DateSchema = z.object({
  type: z.enum(['date']),
  format: z.enum(['dateTime', 'time', 'date']).optional(),
  when: z.enum(['recent', 'soon', 'past', 'future']).optional(),
  between: z
    .object({
      start: z.string(),
      end: z.string(),
    })
    .optional(),
})
 
const PersonFields = z.enum(['prefix', 'firstName', 'lastName', 'email', 'phone', 'address'])
 
const PersonSchema = z.object({
  type: z.enum(['person']),
  value: PersonFields.optional().describe('Generate a single field'),
  fields: z.array(PersonFields).optional().describe('Generate multiple fields'),
  pattern: z.string().optional().describe('Substitution pattern for generated value')
})
 
const ArraySchema: z.ZodTypeAny = z.lazy(() =>
  z.object({
    type: z.enum(['array']),
    items: z.array(PropertySchema),
    minItems: z.number().optional(),
    maxItems: z.number().optional(),
  })
)
 
const ObjectSchema: z.ZodTypeAny = z.lazy(() =>
  z.object({
    type: z.enum(['object']),
    properties: z.record(z.string(), PropertySchema).optional(),
    required: z.array(z.string()).optional(),
  })
)
 
const PropertySchema: z.ZodTypeAny = z.union([
  StringSchema,
  NumberSchema,
  BooleanSchema,
  DateSchema,
  PersonSchema,
  ArraySchema,
  ObjectSchema,
])
 
// Recursive JSON Schema validator
export const DataSchema = z.lazy(() =>
  z.object({
    type: z.enum(['object']).default('object'), // root must be an object
    locale: z.enum(['en', 'es', 'fr', 'de', 'it']).optional().default('en'),
    seed: z.number().optional(),
    refDate: z.string().optional(),
    count: z.number().optional().default(1),
    index: z.string().optional().describe('A property to use as index for item lookup'),
    properties: z.record(z.string(), z.lazy(() => PropertySchema)).optional(),
  })
)