UNPKG

@bufbuild/protovalidate

Version:

Protocol Buffer Validation for ECMAScript

249 lines (248 loc) 7.82 kB
"use strict"; // Copyright 2024-2025 Buf Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. Object.defineProperty(exports, "__esModule", { value: true }); exports.EvalMessageOneofRule = exports.EvalAnyRules = exports.EvalEnumDefinedOnly = exports.EvalOneofRequired = exports.EvalFieldLegacyRequired = exports.EvalFieldRequired = exports.EvalField = exports.EvalMapEntries = exports.EvalListItems = exports.EvalMany = exports.EvalNoop = void 0; const validate_pb_js_1 = require("./gen/buf/validate/validate_pb.js"); /** * The no-op evaluator. */ class EvalNoop { static get() { return EvalNoop.instance; } eval() { // } prune() { return true; } } exports.EvalNoop = EvalNoop; EvalNoop.instance = new EvalNoop(); /** * Evaluate many. */ class EvalMany { constructor(...evals) { this.many = evals.flat(); } add(...evals) { this.many.push(...evals); return this; } eval(val, cursor) { for (const e of this.many) { e.eval(val, cursor); } } prune() { this.many = this.many.filter((e) => !e.prune()); return this.many.length == 0; } } exports.EvalMany = EvalMany; /** * Evaluated all items in a list. */ class EvalListItems { constructor(condition, pass) { this.condition = condition; this.pass = pass; } eval(val, cursor) { for (let i = 0; i < val.size; i++) { const t = val.get(i); if (this.condition.check(t)) { this.pass.eval(t, cursor.list(i)); } } } prune() { return this.pass.prune() || this.condition.never; } } exports.EvalListItems = EvalListItems; /** * Evaluate key and value of all entries in a map. */ class EvalMapEntries { constructor(keyCondition, key, valueCondition, value) { this.keyCondition = keyCondition; this.key = key; this.valueCondition = valueCondition; this.value = value; } eval(val, cursor) { if (this.keyCondition.never && this.valueCondition.never) { return; } for (const [key, value] of val) { const c = cursor.mapKey(key); if (this.keyCondition.check(key)) { this.key.eval(key, c); } if (this.valueCondition.check(value)) { this.value.eval(value, c); } } } prune() { const key = this.key.prune() || this.keyCondition.never; const value = this.value.prune() || this.valueCondition.never; return key && value; } } exports.EvalMapEntries = EvalMapEntries; /** * Evaluate field. If the condition passes, evaluate the field's value. */ class EvalField { constructor(field, condition, pass) { this.field = field; this.condition = condition; this.pass = pass; } eval(val, cursor) { if (this.condition.check(val)) { const fieldVal = val.get(this.field); this.pass.eval(fieldVal, cursor.field(this.field)); } } prune() { return this.condition.never; } } exports.EvalField = EvalField; class EvalFieldRequired { constructor(field) { this.field = field; } eval(val, cursor) { if (!val.isSet(this.field)) { cursor .field(this.field) .violate("value is required", "required", [ validate_pb_js_1.FieldRulesSchema.field.required, ]); } } prune() { return false; } } exports.EvalFieldRequired = EvalFieldRequired; class EvalFieldLegacyRequired { constructor(field) { this.field = field; } eval(val, cursor) { if (!val.isSet(this.field)) { cursor .field(this.field) .violate("value is required", "legacy_required", []); } } prune() { return false; } } exports.EvalFieldLegacyRequired = EvalFieldLegacyRequired; class EvalOneofRequired { constructor(oneof) { this.oneof = oneof; } eval(val, cursor) { if (this.oneof.fields.some((f) => val.isSet(f))) { return; } cursor .oneof(this.oneof) .violate("exactly one field is required in oneof", "required", []); } prune() { return false; } } exports.EvalOneofRequired = EvalOneofRequired; /** * buf.validate.EnumRules.defined_only does not use CEL expressions. This implements custom logic for this field. */ class EvalEnumDefinedOnly { constructor(descEnum, rulePath, rules) { this.rulePath = rulePath; this.definedOnly = rules.definedOnly ? new Set(descEnum.values.map((v) => v.number)) : undefined; } eval(val, cursor) { if (this.definedOnly !== undefined && !this.definedOnly.has(val)) { // value must be one of the defined enum values [enum.defined_only] cursor.violate("value must be one of the defined enum values", "enum.defined_only", this.rulePath.clone().field(validate_pb_js_1.EnumRulesSchema.field.definedOnly).toPath()); } } prune() { return this.definedOnly == undefined; } } exports.EvalEnumDefinedOnly = EvalEnumDefinedOnly; /** * buf.validate.AnyRules.in and not_in do not use CEL expressions. This implements custom logic for these fields. */ class EvalAnyRules { constructor(rulePath, rules) { this.rulePath = rulePath; this.in = rules.in; this.notIn = rules.notIn; } eval(val, cursor) { const any = val.message; if (this.in.length > 0 && !this.in.includes(any.typeUrl)) { // type URL must be in the allow list [any.in] cursor.violate("type URL must be in the allow list", "any.in", this.rulePath.clone().field(validate_pb_js_1.AnyRulesSchema.field.in).toPath()); } if (this.notIn.length > 0 && this.notIn.includes(any.typeUrl)) { // type URL must not be in the block list [any.not_in] cursor.violate("type URL must not be in the block list", "any.not_in", this.rulePath.clone().field(validate_pb_js_1.AnyRulesSchema.field.notIn).toPath()); } } prune() { return this.in.length + this.notIn.length == 0; } } exports.EvalAnyRules = EvalAnyRules; /** * buf.validate.MessageOneofRule does not use CEL expressions. This implements custom logic for this rule. */ class EvalMessageOneofRule { constructor(fields, required) { this.fields = fields; this.required = required; } eval(val, cursor) { const setFields = this.fields.filter((field) => val.isSet(field)); if (setFields.length > 1) { const oneofNames = this.fields.map((f) => f.name).join(", "); cursor.violate(`only one of ${oneofNames} can be set`, "message.oneof", []); } if (this.required && setFields.length == 0) { const oneofNames = this.fields.map((f) => f.name).join(", "); cursor.violate(`one of ${oneofNames} must be set`, "message.oneof", []); } } prune() { return this.fields.length == 0; } } exports.EvalMessageOneofRule = EvalMessageOneofRule;