UNPKG

@bufbuild/cel

Version:

A CEL evaluator for ECMAScript

157 lines (156 loc) 4.24 kB
// 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 { isCelList } from "./list.js"; import { isCelMap } from "./map.js"; import { isCelUint } from "./uint.js"; import { isReflectMessage, } from "@bufbuild/protobuf/reflect"; import { TimestampSchema, DurationSchema } from "@bufbuild/protobuf/wkt"; const privateSymbol = Symbol.for("@bufbuild/cel/type"); /** * Scalar CEL value types. */ // biome-ignore format: indented for readability export const CelScalar = { INT: celScalarType("int"), UINT: celScalarType("uint"), BOOL: celScalarType("bool"), STRING: celScalarType("string"), BYTES: celScalarType("bytes"), DOUBLE: celScalarType("double"), NULL: celScalarType("null_type"), DYN: celScalarType("dyn"), TYPE: celScalarType("type"), }; /** * Represents the CEL type google.protobuf.Timestamp. */ export const TIMESTAMP = objectType(TimestampSchema); /** * Represents the CEL type google.protobuf.Duration. */ export const DURATION = objectType(DurationSchema); /** * Creates a new CelMapType. */ export function mapType(key, value) { return { [privateSymbol]: {}, kind: "map", key, value, name: "map", toString() { return `map(${key}, ${value})`; }, }; } /** * Creates a new CelListType. */ export function listType(element) { return { [privateSymbol]: {}, kind: "list", element, name: "list", toString() { return `list(${element})`; }, }; } /** * Creates a new CelTypeType */ export function typeType(type) { return { [privateSymbol]: {}, kind: "type", type, name: "type", toString() { return "type"; }, }; } /** * Creates a new CelObjectType. */ export function objectType(desc) { return { [privateSymbol]: {}, kind: "object", desc, name: desc.typeName, toString() { return desc.name; }, }; } function celScalarType(scalar) { return { [privateSymbol]: {}, kind: "scalar", scalar, name: scalar, toString() { return scalar; }, }; } /** * Get the CelType of a CelValue. */ export function celType(v) { switch (typeof v) { case "bigint": return CelScalar.INT; case "boolean": return CelScalar.BOOL; case "number": return CelScalar.DOUBLE; case "string": return CelScalar.STRING; case "object": switch (true) { case v === null: return CelScalar.NULL; case v instanceof Uint8Array: return CelScalar.BYTES; case isReflectMessage(v): return objectType(v.desc); case isCelList(v): return listType(CelScalar.DYN); case isCelMap(v): return mapType(CelScalar.DYN, CelScalar.DYN); case isCelUint(v): return CelScalar.UINT; default: // This can also be a case statement, but TS fails to // narrow the type. if (isObjectCelType(v)) { return typeType(v); } } } throw new Error(`Not a CEL value: ${v}`); } /** * Returns true if the given value is a CelType. */ export function isCelType(v) { return typeof v === "object" && v !== null && isObjectCelType(v); } export function isObjectCelType(v) { return privateSymbol in v; }