import type {MacroKeywordDefinition, SchemaObject, Schema} from "ajv" import type {DefinitionOptions} from "./_types" import {metaSchemaRef} from "./_util" export default function getDef(opts?: DefinitionOptions): MacroKeywordDefinition { return { keyword: "deepProperties", type: "object", schemaType: "object", macro: function (schema: Record) { const allOf = [] for (const pointer in schema) allOf.push(getSchema(pointer, schema[pointer])) return {allOf} }, metaSchema: { type: "object", propertyNames: {type: "string", format: "json-pointer"}, additionalProperties: metaSchemaRef(opts), }, } } function getSchema(jsonPointer: string, schema: SchemaObject): SchemaObject { const segments = jsonPointer.split("/") const rootSchema: SchemaObject = {} let pointerSchema: SchemaObject = rootSchema for (let i = 1; i < segments.length; i++) { let segment: string = segments[i] const isLast = i === segments.length - 1 segment = unescapeJsonPointer(segment) const properties: Record = (pointerSchema.properties = {}) let items: SchemaObject[] | undefined if (/[0-9]+/.test(segment)) { let count = +segment items = pointerSchema.items = [] pointerSchema.type = ["object", "array"] while (count--) items.push({}) } else { pointerSchema.type = "object" } pointerSchema = isLast ? schema : {} properties[segment] = pointerSchema if (items) items.push(pointerSchema) } return rootSchema } function unescapeJsonPointer(str: string): string { return str.replace(/~1/g, "/").replace(/~0/g, "~") } module.exports = getDef