@bufbuild/protovalidate
Version:
Protocol Buffer Validation for ECMAScript
188 lines (187 loc) • 7.29 kB
JavaScript
// 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.
import { ScalarType } from "@bufbuild/protobuf";
import { AnySchema, BoolValueSchema, BytesValueSchema, DoubleValueSchema, DurationSchema, FloatValueSchema, Int32ValueSchema, Int64ValueSchema, StringValueSchema, TimestampSchema, UInt32ValueSchema, UInt64ValueSchema, } from "@bufbuild/protobuf/wkt";
import { AnyRulesSchema, BoolRulesSchema, BytesRulesSchema, DoubleRulesSchema, DurationRulesSchema, EnumRulesSchema, FieldRulesSchema, Fixed32RulesSchema, Fixed64RulesSchema, FloatRulesSchema, Int32RulesSchema, Int64RulesSchema, MapRulesSchema, RepeatedRulesSchema, SFixed32RulesSchema, SFixed64RulesSchema, SInt32RulesSchema, SInt64RulesSchema, StringRulesSchema, TimestampRulesSchema, UInt32RulesSchema, UInt64RulesSchema, } from "./gen/buf/validate/validate_pb.js";
import { CompilationError } from "./error.js";
const messageToRuleType = new Map([
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
]);
const scalarToRuleType = new Map([
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
]);
const ruleMessageTypeToScalarType = new Map([
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
]);
/**
* Get the ScalarType for one of the buf.validate.*Rules messages.
*/
export function getRuleScalarType(rule) {
return ruleMessageTypeToScalarType.get(rule.$typeName);
}
/**
* Get the descriptor for one of the buf.validate.*Rules messages.
*/
export function getRuleDescriptor(typeName) {
for (const d of [
FloatRulesSchema,
DoubleRulesSchema,
Int32RulesSchema,
Int64RulesSchema,
UInt32RulesSchema,
UInt64RulesSchema,
SInt32RulesSchema,
SInt64RulesSchema,
Fixed32RulesSchema,
Fixed64RulesSchema,
SFixed32RulesSchema,
SFixed64RulesSchema,
BoolRulesSchema,
StringRulesSchema,
BytesRulesSchema,
EnumRulesSchema,
RepeatedRulesSchema,
MapRulesSchema,
AnyRulesSchema,
DurationRulesSchema,
TimestampRulesSchema,
]) {
if (typeName == d.typeName) {
return d;
}
}
throw new Error(`unable to find descriptor for ${typeName}`);
}
/**
* Get buf.validate.RepeatedRules from FieldRules.
* Returns a tuple with rules, and path to the rules.
* Throws an error if the FieldRules has incompatible rules.
*/
export function getListRules(rulePath, fieldRules, fieldContext) {
const listRules = getRulePath(rulePath, "repeated");
return [
getRules(fieldRules, "repeated", fieldContext),
listRules,
listRules.clone().field(RepeatedRulesSchema.field.items),
];
}
/**
* Get buf.validate.MapRules from FieldRules.
* Returns a tuple with rules, and path to the rules.
* Throws an error if the FieldRules has incompatible rules.
*/
export function getMapRules(rulePath, fieldRules, fieldContext) {
const mapRules = getRulePath(rulePath, "map");
return [
getRules(fieldRules, "map", fieldContext),
mapRules,
mapRules.clone().field(MapRulesSchema.field.keys),
mapRules.clone().field(MapRulesSchema.field.values),
];
}
/**
* Get buf.validate.EnumRules from FieldRules.
* Returns a tuple with rules, and path to the rules.
* Throws an error if the FieldRules has incompatible rules.
*/
export function getEnumRules(rulePath, fieldRules, fieldContext) {
return [
getRules(fieldRules, "enum", fieldContext),
getRulePath(rulePath, "enum"),
];
}
/**
* Get buf.validate.*Rules for the given message type from FieldRules.
* Returns a tuple with rules, and path to the rules.
* Throws an error if the FieldRules has incompatible rules.
*/
export function getMessageRules(descMessage, rulePath, fieldRules, fieldContext) {
const type = messageToRuleType.get(descMessage.typeName);
return [
getRules(fieldRules, type, fieldContext),
getRulePath(rulePath, type),
];
}
/**
* Get buf.validate.*Rules for the given scalar type from FieldRules.
* Returns a tuple with rules, and path to the rules.
* Throws an error if the FieldRules has incompatible rules.
*/
export function getScalarRules(scalar, rulePath, fieldRules, fieldContext) {
const type = scalarToRuleType.get(scalar);
return [
getRules(fieldRules, type, fieldContext),
getRulePath(rulePath, type),
];
}
function getRulePath(base, type) {
if (type == undefined) {
return base;
}
const field = FieldRulesSchema.fields.find((f) => f.name === type);
if (field == undefined) {
throw new CompilationError(`cannot find rule "${type}"`);
}
return base.clone().field(field);
}
function getRules(fieldRules, want, context) {
const got = fieldRules?.type.case;
if (fieldRules == undefined || got == undefined) {
return undefined;
}
if (got != want) {
throw new CompilationError(want == undefined
? `rule "${got}" cannot be used on ${context.toString()}`
: `expected rule "${want}", got "${got}" on ${context.toString()}`);
}
return fieldRules.type.value;
}