"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateProperties = exports.error = void 0; const code_1 = require("../code"); const util_1 = require("../../compile/util"); const codegen_1 = require("../../compile/codegen"); const metadata_1 = require("./metadata"); const nullable_1 = require("./nullable"); const error_1 = require("./error"); var PropError; (function (PropError) { PropError["Additional"] = "additional"; PropError["Missing"] = "missing"; })(PropError || (PropError = {})); exports.error = { message: (cxt) => { const { params } = cxt; return params.propError ? params.propError === PropError.Additional ? "must NOT have additional properties" : `must have property '${params.missingProperty}'` : error_1.typeErrorMessage(cxt, "object"); }, params: (cxt) => { const { params } = cxt; return params.propError ? params.propError === PropError.Additional ? codegen_1._ `{error: ${params.propError}, additionalProperty: ${params.additionalProperty}}` : codegen_1._ `{error: ${params.propError}, missingProperty: ${params.missingProperty}}` : error_1.typeErrorParams(cxt, "object"); }, }; const def = { keyword: "properties", schemaType: "object", error: exports.error, code: validateProperties, }; // const error: KeywordErrorDefinition = { // message: "should NOT have additional properties", // params: ({params}) => _`{additionalProperty: ${params.additionalProperty}}`, // } function validateProperties(cxt) { metadata_1.checkMetadata(cxt); const { gen, data, parentSchema, it } = cxt; const { additionalProperties, nullable } = parentSchema; if (it.jtdDiscriminator && nullable) throw new Error("JTD: nullable inside discriminator mapping"); if (commonProperties()) { throw new Error("JTD: properties and optionalProperties have common members"); } const [allProps, properties] = schemaProperties("properties"); const [allOptProps, optProperties] = schemaProperties("optionalProperties"); if (properties.length === 0 && optProperties.length === 0 && additionalProperties) { return; } const [valid, cond] = it.jtdDiscriminator === undefined ? nullable_1.checkNullableObject(cxt, data) : [gen.let("valid", false), true]; gen.if(cond, () => gen.assign(valid, true).block(() => { validateProps(properties, "properties", true); validateProps(optProperties, "optionalProperties"); if (!additionalProperties) validateAdditional(); })); cxt.pass(valid); function commonProperties() { const props = parentSchema.properties; const optProps = parentSchema.optionalProperties; if (!(props && optProps)) return false; for (const p in props) { if (Object.prototype.hasOwnProperty.call(optProps, p)) return true; } return false; } function schemaProperties(keyword) { const schema = parentSchema[keyword]; const allPs = schema ? code_1.allSchemaProperties(schema) : []; if (it.jtdDiscriminator && allPs.some((p) => p === it.jtdDiscriminator)) { throw new Error(`JTD: discriminator tag used in ${keyword}`); } const ps = allPs.filter((p) => !util_1.alwaysValidSchema(it, schema[p])); return [allPs, ps]; } function validateProps(props, keyword, required) { const _valid = gen.var("valid"); for (const prop of props) { gen.if(code_1.propertyInData(gen, data, prop, it.opts.ownProperties), () => applyPropertySchema(prop, keyword, _valid), () => missingProperty(prop)); cxt.ok(_valid); } function missingProperty(prop) { if (required) { gen.assign(_valid, false); cxt.error(false, { propError: PropError.Missing, missingProperty: prop }, { schemaPath: prop }); } else { gen.assign(_valid, true); } } } function applyPropertySchema(prop, keyword, _valid) { cxt.subschema({ keyword, schemaProp: prop, dataProp: prop, }, _valid); } function validateAdditional() { gen.forIn("key", data, (key) => { const _allProps = it.jtdDiscriminator === undefined ? allProps : [it.jtdDiscriminator].concat(allProps); const addProp = isAdditional(key, _allProps, "properties"); const addOptProp = isAdditional(key, allOptProps, "optionalProperties"); const extra = addProp === true ? addOptProp : addOptProp === true ? addProp : codegen_1.and(addProp, addOptProp); gen.if(extra, () => { if (it.opts.removeAdditional) { gen.code(codegen_1._ `delete ${data}[${key}]`); } else { cxt.error(false, { propError: PropError.Additional, additionalProperty: key }, { instancePath: key, parentSchema: true }); if (!it.opts.allErrors) gen.break(); } }); }); } function isAdditional(key, props, keyword) { let additional; if (props.length > 8) { // TODO maybe an option instead of hard-coded 8? const propsSchema = util_1.schemaRefOrVal(it, parentSchema[keyword], keyword); additional = codegen_1.not(code_1.isOwnProperty(gen, propsSchema, key)); } else if (props.length) { additional = codegen_1.and(...props.map((p) => codegen_1._ `${key} !== ${p}`)); } else { additional = true; } return additional; } } exports.validateProperties = validateProperties; exports.default = def; //# sourceMappingURL=properties.js.map