import getTypeOf from "./getTypeOf"; import createSchemaOf from "./createSchemaOf"; import { isJsonError } from "./types"; import { reduceSchema } from "./reduceSchema"; const stepType = { array: (draft, key, schema, data, pointer) => { const itemValue = data === null || data === void 0 ? void 0 : data[key]; const itemsType = getTypeOf(schema.items); if (itemsType === "object") { // @spec: ignore additionalItems, when items is schema-object return (reduceSchema(draft, schema.items, itemValue, `${pointer}/${key}`) || draft.resolveRef(schema.items)); } if (itemsType === "array") { // @draft >= 7 bool schema, items:[true, false] if (schema.items[key] === true) { return createSchemaOf(itemValue); } // @draft >= 7 bool schema, items:[true, false] if (schema.items[key] === false) { return draft.errors.invalidDataError({ key, value: itemValue, pointer, schema }); } if (schema.items[key]) { return draft.resolveRef(schema.items[key]); } if (schema.additionalItems === false) { return draft.errors.additionalItemsError({ key, value: itemValue, pointer, schema }); } if (schema.additionalItems === true || schema.additionalItems === undefined) { return createSchemaOf(itemValue); } if (getTypeOf(schema.additionalItems) === "object") { return schema.additionalItems; } throw new Error(`Invalid schema ${JSON.stringify(schema, null, 2)} for ${JSON.stringify(data, null, 2)}`); } if (schema.additionalItems !== false && itemValue) { // @todo reevaluate: incomplete schema is created here // @todo support additionalItems: {schema} return createSchemaOf(itemValue); } return new Error(`Invalid array schema for ${key} at ${pointer}`); }, object: (draft, key, schema, data, pointer) => { var _a; schema = reduceSchema(draft, schema, data, pointer); // @feature properties const property = (_a = schema === null || schema === void 0 ? void 0 : schema.properties) === null || _a === void 0 ? void 0 : _a[key]; if (property !== undefined) { // @todo patternProperties also validate properties // @feature boolean schema if (property === false) { return draft.errors.forbiddenPropertyError({ property: key, value: data, pointer, schema }); } else if (property === true) { return createSchemaOf(data === null || data === void 0 ? void 0 : data[key]); } const targetSchema = draft.resolveRef(property); if (isJsonError(targetSchema)) { return targetSchema; } // check if there is a oneOf selection, which must be resolved if (targetSchema && Array.isArray(targetSchema.oneOf)) { // @special case: this is a mix of a schema and optional definitions // we resolve the schema here and add the original schema to `oneOfSchema` const resolvedSchema = draft.resolveOneOf(data[key], targetSchema, `${pointer}/${key}`); for (const p in targetSchema) { if (p !== "oneOf" && resolvedSchema[p] === undefined) { resolvedSchema[p] = targetSchema[p]; } } return resolvedSchema; } // resolved schema or error if (targetSchema) { return targetSchema; } } // @feature patternProperties const { patternProperties } = schema; if (getTypeOf(patternProperties) === "object") { // find matching property key let regex; const patterns = Object.keys(patternProperties); for (let i = 0, l = patterns.length; i < l; i += 1) { regex = new RegExp(patterns[i]); if (regex.test(key)) { return patternProperties[patterns[i]]; } } } // @feature additionalProperties const { additionalProperties } = schema; if (getTypeOf(additionalProperties) === "object") { return schema.additionalProperties; } if (data && (additionalProperties === undefined || additionalProperties === true)) { return createSchemaOf(data[key]); } return draft.errors.unknownPropertyError({ property: key, value: data, pointer: `${pointer}`, schema }); } }; /** * Returns the json-schema of the given object property or array item. * e.g. it steps by one key into the data * * This helper determines the location of the property within the schema (additional properties, oneOf, ...) and * returns the correct schema. * * @param draft - validator * @param key - property-name or array-index * @param schema - json schema of current data * @param data - parent of key * @param [pointer] - pointer to schema and data (parent of key) * @return Schema or Error if failed resolving key */ export default function step(draft, key, schema, data, pointer = "#") { var _a; const typeOfData = getTypeOf(data); let schemaType = (_a = schema.type) !== null && _a !== void 0 ? _a : typeOfData; // @draft >= 4 ? if (Array.isArray(schemaType)) { if (!schemaType.includes(typeOfData)) { return draft.errors.typeError({ value: data, pointer, expected: schema.type, received: typeOfData, schema }); } schemaType = typeOfData; } const stepFunction = stepType[schemaType]; if (stepFunction) { const schemaResult = stepFunction(draft, `${key}`, schema, data, pointer); if (schemaResult === undefined) { return draft.errors.schemaWarning({ pointer, value: data, schema, key }); } return schemaResult; } return new Error(`Unsupported schema type ${schema.type} for key ${key}`); }