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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | 5x 3x 3x 3x 3x 3x 3x 721x 103x 206x 103x 103x 103x 103x 103x 309x 3x 3x 3x 3x 306x 103x 103x 3x 3x 3x 3x 3x 103x 103x 412x 100x 100x 100x 100x 312x 103x 3x | import type { z } from 'zod'
import { DataSchema, type StringOptions, type NumberOptions, type BooleanOptions } from '../schema/data'
import { DateGenerator, StringGenerator, BooleanGenerator, NumberGenerator, PersonGenerator } from '../generator'
import RNG from '../util/rng'
export default class DataParser {
protected schema: z.infer<typeof DataSchema>
constructor(schema: unknown) {
// Parse to validate and capture defaults/coercions
this.schema = DataSchema.parse(schema)
}
generate(): unknown {
const rng = new RNG(this.schema.seed)
const stringGen = new StringGenerator({ locale: this.schema.locale, seed: this.schema.seed })
const booleanGen = new BooleanGenerator({ locale: this.schema.locale, seed: this.schema.seed })
const numberGen = new NumberGenerator({ locale: this.schema.locale, seed: this.schema.seed })
const personGen = new PersonGenerator({ locale: this.schema.locale, seed: this.schema.seed })
type ObjectNode = { type: 'object'; properties?: Record<string, Node>; required?: string[] }
type ArrayNode = { type: 'array'; items: Node; minItems?: number; maxItems?: number }
type DateNode = { type: 'date'; format?: 'dateTime' | 'time' | 'date' }
type IntNode = { type: 'integer' } & Partial<NumberOptions>
type FloatNode = { type: 'float' } & Partial<NumberOptions>
type BoolNode = { type: 'boolean' } & Partial<BooleanOptions>
type StrNode = { type: 'string' } & Partial<StringOptions>
type PersonNode = { type: 'person' } & Partial<{ value?: 'email' | 'prefix' | 'firstName' | 'lastName' | 'phone' | 'address'; fields?: ('email' | 'prefix' | 'firstName' | 'lastName' | 'phone' | 'address')[]; pattern?: string }>
type Node = StrNode | BoolNode | IntNode | FloatNode | DateNode | ArrayNode | ObjectNode | PersonNode
const generateValue = (node: Node): unknown => {
switch (node.type) {
case 'person':
return personGen.generate(node)
case 'string':
return stringGen.generate(node)
case 'boolean':
return booleanGen.generate(node)
case 'integer':
case 'float':
return numberGen.generate(node) as number
case 'object': {
const out: Record<string, unknown> = {}
const props = node.properties ?? {}
for (const [k, v] of Object.entries(props)) {
if (k === '...') {
// Object spreading: generate the value and spread its properties
const spreadValue = generateValue(v as Node)
Eif (spreadValue && typeof spreadValue === 'object' && !Array.isArray(spreadValue)) {
Object.assign(out, spreadValue as Record<string, unknown>)
}
continue
}
out[k] = generateValue(v as Node)
}
return out
}
case 'array': {
const min = Math.max(0, node.minItems ?? 1)
const max = Math.max(min, node.maxItems ?? Math.max(min, 3))
const len = min === max ? min : rng.uniformInt(min, max)
const items: unknown[] = []
for (let i = 0; i < len; i++) {
items.push(generateValue(node.items as Node))
}
return items
}
case 'date':
return new DateGenerator({ locale: this.schema.locale, seed: this.schema.seed, refDate: this.schema.refDate }).generate(node)
default:
throw new Error('Unsupported type')
}
}
const rootProps = (this.schema as unknown as { properties?: Record<string, unknown> }).properties ?? {}
const count = this.schema.count ?? 1
Iif (count === 1) {
const result: Record<string, unknown> = {}
for (const [key, value] of Object.entries(rootProps)) {
if (key === '...') {
// Object spreading at root level: generate the value and spread its properties
const spreadValue = generateValue(value as Node)
if (spreadValue && typeof spreadValue === 'object' && !Array.isArray(spreadValue)) {
Object.assign(result, spreadValue as Record<string, unknown>)
}
continue
}
result[key] = generateValue(value as Node)
}
return result
} else {
// Generate multiple records
const results: Record<string, unknown>[] = []
for (let i = 0; i < count; i++) {
const result: Record<string, unknown> = {}
for (const [key, value] of Object.entries(rootProps)) {
if (key === '...') {
// Object spreading at root level: generate the value and spread its properties
const spreadValue = generateValue(value as Node)
Eif (spreadValue && typeof spreadValue === 'object' && !Array.isArray(spreadValue)) {
Object.assign(result, spreadValue as Record<string, unknown>)
}
continue
}
result[key] = generateValue(value as Node)
}
results.push(result)
}
return results
}
}
}
|