UNPKG

interface-forge

Version:

A TypeScript library for creating strongly typed mock data factories using Faker.js for test data generation

1 lines 19.5 kB
{"version":3,"file":"json-schema.mjs","names":["#factory","#rootSchema","#resolveReference","#getType","#generateArray","#generateNumber","#generateObject","#generateString","#generateFormattedString","#generatePattern","#buildSimpleCharacterClass","#buildPrefixedDigitPattern","#schema","#validator","#validate"],"sources":["../src/json-schema.ts"],"sourcesContent":["import Ajv from 'ajv';\nimport addFormats from 'ajv-formats';\nimport type { Options, ValidateFunction } from 'ajv';\nimport { isFunction, isObject, isRecord } from '@tool-belt/type-predicates';\n\nimport { COLLECTION_SIZES, DEFAULT_MAX_DEPTH, NUMBER_CONSTRAINTS, STRING_LENGTHS } from './constants';\nimport { ConfigurationError, ValidationError } from './errors';\nimport { Factory, type FactoryFunction, type FactoryOptions, type PartialFactoryFunction } from './index';\n\nexport type JsonSchemaPrimitiveType = 'array' | 'boolean' | 'integer' | 'null' | 'number' | 'object' | 'string';\n\nexport type JsonSchema = boolean | JsonSchemaObject;\n\nexport interface JsonSchemaObject {\n $defs?: Record<string, JsonSchema>;\n $ref?: string;\n additionalProperties?: boolean | JsonSchema;\n anyOf?: JsonSchema[];\n const?: unknown;\n definitions?: Record<string, JsonSchema>;\n enum?: unknown[];\n exclusiveMaximum?: boolean | number;\n exclusiveMinimum?: boolean | number;\n format?: 'date' | 'date-time' | 'email' | 'time' | 'uri' | 'uuid' | string;\n items?: JsonSchema | JsonSchema[];\n maxItems?: number;\n maxLength?: number;\n maximum?: number;\n minItems?: number;\n minLength?: number;\n minimum?: number;\n multipleOf?: number;\n oneOf?: JsonSchema[];\n pattern?: string;\n properties?: Record<string, JsonSchema>;\n required?: string[];\n type?: JsonSchemaPrimitiveType | JsonSchemaPrimitiveType[];\n}\n\nexport interface JsonSchemaFactoryOptions extends FactoryOptions {\n ajv?: Options;\n}\n\nfunction mergeGenerated<T>(generated: unknown, factoryValues: unknown): T {\n if (isRecord(generated) && isRecord(factoryValues)) {\n return {\n ...generated,\n ...factoryValues,\n } as T;\n }\n return (factoryValues === undefined || (isRecord(factoryValues) && Object.keys(factoryValues).length === 0)\n ? generated\n : factoryValues) as T;\n}\n\nclass JsonSchemaGenerator {\n readonly #factory: Factory<unknown>;\n readonly #rootSchema: JsonSchema;\n\n constructor(factory: Factory<unknown>, rootSchema: JsonSchema) {\n this.#factory = factory;\n this.#rootSchema = rootSchema;\n }\n\n generate(schema: JsonSchema = this.#rootSchema, currentDepth = 0): unknown {\n if (currentDepth >= (this.#factory.options?.maxDepth ?? DEFAULT_MAX_DEPTH)) {\n return null;\n }\n\n if (schema === true) {\n return {};\n }\n\n if (schema === false) {\n throw new ConfigurationError('Cannot generate data for boolean false JSON Schema');\n }\n\n const resolvedSchema = this.#resolveReference(schema);\n\n if ('const' in resolvedSchema) {\n return resolvedSchema.const;\n }\n\n if (resolvedSchema.enum && resolvedSchema.enum.length > 0) {\n return this.#factory.helpers.arrayElement(resolvedSchema.enum);\n }\n\n const unionSchema = resolvedSchema.oneOf?.[0] ?? resolvedSchema.anyOf?.[0];\n if (unionSchema) {\n return this.generate(unionSchema, currentDepth + 1);\n }\n\n const type = this.#getType(resolvedSchema);\n\n switch (type) {\n case 'array':\n return this.#generateArray(resolvedSchema, currentDepth);\n case 'boolean':\n return this.#factory.datatype.boolean();\n case 'integer':\n return this.#generateNumber(resolvedSchema, true);\n case 'null':\n return null;\n case 'number':\n return this.#generateNumber(resolvedSchema, false);\n case 'object':\n return this.#generateObject(resolvedSchema, currentDepth);\n case 'string':\n return this.#generateString(resolvedSchema);\n default:\n return {};\n }\n }\n\n #generateArray(schema: JsonSchemaObject, currentDepth: number): unknown[] {\n const min = schema.minItems ?? COLLECTION_SIZES.DEFAULT_ARRAY_MIN;\n const max = schema.maxItems ?? Math.max(min, COLLECTION_SIZES.DEFAULT_ARRAY_MAX);\n const length = this.#factory.number.int({ max, min });\n\n if (Array.isArray(schema.items)) {\n const values = schema.items.map((item) => this.generate(item, currentDepth + 1));\n return values.slice(0, length);\n }\n\n const itemSchema = schema.items ?? {};\n return Array.from({ length }, () => this.generate(itemSchema, currentDepth + 1));\n }\n\n #generateNumber(schema: JsonSchemaObject, integer: boolean): number {\n let min = schema.minimum ?? (integer ? NUMBER_CONSTRAINTS.DEFAULT_INT_MIN : NUMBER_CONSTRAINTS.DEFAULT_MIN);\n let max = schema.maximum ?? (integer ? NUMBER_CONSTRAINTS.DEFAULT_INT_MAX : NUMBER_CONSTRAINTS.DEFAULT_MAX);\n\n if (typeof schema.exclusiveMinimum === 'number') {\n min = integer ? Math.floor(schema.exclusiveMinimum) + 1 : schema.exclusiveMinimum + NUMBER_CONSTRAINTS.PRECISION_OFFSET;\n } else if (schema.exclusiveMinimum === true) {\n min = integer ? min + 1 : min + NUMBER_CONSTRAINTS.PRECISION_OFFSET;\n }\n\n if (typeof schema.exclusiveMaximum === 'number') {\n max = integer ? Math.ceil(schema.exclusiveMaximum) - 1 : schema.exclusiveMaximum - NUMBER_CONSTRAINTS.PRECISION_OFFSET;\n } else if (schema.exclusiveMaximum === true) {\n max = integer ? max - 1 : max - NUMBER_CONSTRAINTS.PRECISION_OFFSET;\n }\n\n if (schema.multipleOf) {\n const minMultiple = Math.ceil(min / schema.multipleOf);\n const maxMultiple = Math.floor(max / schema.multipleOf);\n return this.#factory.number.int({ max: maxMultiple, min: minMultiple }) * schema.multipleOf;\n }\n\n return integer\n ? this.#factory.number.int({ max: Math.floor(max), min: Math.ceil(min) })\n : this.#factory.number.float({ max, min });\n }\n\n #generateObject(schema: JsonSchemaObject, currentDepth: number): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, propertySchema] of Object.entries(schema.properties ?? {})) {\n result[key] = this.generate(propertySchema, currentDepth + 1);\n }\n return result;\n }\n\n #generateString(schema: JsonSchemaObject): string {\n const min = schema.minLength ?? 1;\n const max = schema.maxLength ?? Math.max(min, STRING_LENGTHS.DEFAULT);\n\n const formatted = this.#generateFormattedString(schema.format);\n if (formatted && formatted.length >= min && (schema.maxLength === undefined || formatted.length <= schema.maxLength)) {\n return formatted;\n }\n\n if (schema.pattern) {\n const patterned = this.#generatePattern(schema.pattern, min, max);\n if (patterned) {\n return patterned;\n }\n }\n\n return this.#factory.string.alpha({ length: { max, min } });\n }\n\n #generateFormattedString(format: JsonSchemaObject['format']): string | undefined {\n switch (format) {\n case 'date':\n return '2026-01-01';\n case 'date-time':\n return '2026-01-01T00:00:00Z';\n case 'email':\n return 'user@example.com';\n case 'time':\n return '00:00:00Z';\n case 'uri':\n return 'https://example.com';\n case 'uuid':\n return '00000000-0000-4000-8000-000000000000';\n default:\n return undefined;\n }\n }\n\n #generatePattern(pattern: string, minLength: number, maxLength: number): string | undefined {\n const regex = new RegExp(pattern);\n const candidates = [\n this.#buildSimpleCharacterClass(pattern),\n this.#buildPrefixedDigitPattern(pattern),\n 'mock-value',\n 'aaaaa',\n '0000',\n ].filter((candidate): candidate is string => typeof candidate === 'string');\n\n return candidates.find((candidate) => candidate.length >= minLength && candidate.length <= maxLength && regex.test(candidate));\n }\n\n #buildPrefixedDigitPattern(pattern: string): string | undefined {\n const match = /^\\^?([\\w .-]*)\\[0-9\\]\\{(\\d+)\\}\\$?$/.exec(pattern);\n if (!match) {\n return undefined;\n }\n return `${match[1]}${'0'.repeat(Number(match[2]))}`;\n }\n\n #buildSimpleCharacterClass(pattern: string): string | undefined {\n const match = /^\\^\\[([A-Za-z0-9-]+)\\]\\{(\\d+)\\}\\$$/.exec(pattern);\n if (!match) {\n return undefined;\n }\n\n const [, characterClass, rawLength] = match;\n const length = Number(rawLength);\n if (characterClass.includes('0-9')) {\n return '0'.repeat(length);\n }\n if (characterClass.includes('A-Z')) {\n return 'A'.repeat(length);\n }\n return 'a'.repeat(length);\n }\n\n #getType(schema: JsonSchemaObject): JsonSchemaPrimitiveType | undefined {\n const rawType = Array.isArray(schema.type) ? schema.type.find((type) => type !== 'null') : schema.type;\n if (rawType) {\n return rawType;\n }\n if (schema.properties) {\n return 'object';\n }\n if (schema.items) {\n return 'array';\n }\n return undefined;\n }\n\n #resolveReference(schema: JsonSchemaObject): JsonSchemaObject {\n if (!schema.$ref) {\n return schema;\n }\n\n const match = /^#\\/(\\$defs|definitions)\\/(.+)$/.exec(schema.$ref);\n if (!match || typeof this.#rootSchema === 'boolean') {\n throw new ConfigurationError(`Unsupported JSON Schema reference: ${schema.$ref}`);\n }\n\n const collection = match[1] === '$defs' ? this.#rootSchema.$defs : this.#rootSchema.definitions;\n const resolved = collection?.[decodeURIComponent(match[2])];\n if (!resolved || typeof resolved === 'boolean') {\n throw new ConfigurationError(`Unable to resolve JSON Schema reference: ${schema.$ref}`);\n }\n return resolved;\n }\n}\n\nexport class JsonSchemaFactory<\n T = unknown,\n O extends JsonSchemaFactoryOptions = JsonSchemaFactoryOptions,\n> extends Factory<T, O> {\n readonly #schema: JsonSchema;\n readonly #validator: ValidateFunction;\n declare batch: (size: number, kwargs?: Partial<T> | Partial<T>[]) => T[];\n declare batchAsync: (size: number, kwargs?: Partial<T> | Partial<T>[]) => Promise<T[]>;\n declare build: (kwargs?: Partial<T>, options?: Partial<O>) => T;\n declare buildAsync: (kwargs?: Partial<T>, options?: Partial<O>) => Promise<T>;\n\n constructor(schema: JsonSchema, optionsOrFactory?: O | PartialFactoryFunction<T>, options?: O) {\n let generator: JsonSchemaGenerator;\n const factoryFunction = isFunction(optionsOrFactory)\n ? optionsOrFactory\n : ((() => ({})) as PartialFactoryFunction<T>);\n const factoryOptions = isObject(options)\n ? options\n : isObject(optionsOrFactory) && !isFunction(optionsOrFactory)\n ? (optionsOrFactory as O)\n : ({} as O);\n\n super(((factory, iteration, kwargs) => {\n const generated = generator.generate(schema);\n const factoryValues = (factoryFunction as FactoryFunction<T>)(factory as Factory<T>, iteration, kwargs);\n if (factoryValues instanceof Promise) {\n return factoryValues.then((values) => mergeGenerated<T>(generated, values)) as Promise<T>;\n }\n return mergeGenerated<T>(generated, factoryValues);\n }) as FactoryFunction<T>, factoryOptions);\n\n this.#schema = schema;\n generator = new JsonSchemaGenerator(this as unknown as Factory<unknown>, schema);\n\n const ajv = new Ajv({\n allErrors: true,\n strict: false,\n ...factoryOptions.ajv,\n });\n addFormats(ajv);\n this.#validator = ajv.compile(schema);\n\n const baseBatch = this.batch.bind(this);\n const baseBatchAsync = this.batchAsync.bind(this);\n const baseBuild = this.build.bind(this);\n const baseBuildAsync = this.buildAsync.bind(this);\n\n this.batch = (size, kwargs) => baseBatch(size, kwargs).map((result) => this.#validate(result as T));\n this.batchAsync = async (size, kwargs) => {\n const results = await baseBatchAsync(size, kwargs);\n return results.map((result) => this.#validate(result as T));\n };\n this.build = (kwargs, options) => this.#validate(baseBuild(kwargs, options) as T);\n this.buildAsync = async (kwargs, options) => this.#validate((await baseBuildAsync(kwargs, options)) as T);\n }\n\n #validate(value: T): T {\n if (!this.#validator(value)) {\n throw new ValidationError(`Generated value does not match JSON Schema: ${JSON.stringify(this.#validator.errors)}`);\n }\n return value;\n }\n\n get schema(): JsonSchema {\n return this.#schema;\n }\n}\n"],"mappings":"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"}