@bufbuild/cel
Version:
A CEL evaluator for ECMAScript
186 lines (185 loc) • 8.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.
Object.defineProperty(exports, "__esModule", { value: true });
exports.addCasts = addCasts;
const protobuf_1 = require("@bufbuild/protobuf");
const wkt_1 = require("@bufbuild/protobuf/wkt");
const func_js_1 = require("../func.js");
const math_js_1 = require("./math.js");
const type_js_1 = require("../type.js");
const uint_js_1 = require("../uint.js");
const eval_js_1 = require("../eval.js");
const duration_js_1 = require("../duration.js");
const INT = "int";
const UINT = "uint";
const DOUBLE = "double";
const BOOL = "bool";
const STRING = "string";
const BYTES = "bytes";
const TIMESTAMP = "timestamp";
const DURATION = "duration";
const TYPE = "type";
const DYN = "dyn";
const intFunc = (0, func_js_1.celFunc)(INT, [
(0, func_js_1.celOverload)([type_js_1.CelScalar.INT], type_js_1.CelScalar.INT, (x) => x),
(0, func_js_1.celOverload)([type_js_1.CelScalar.UINT], type_js_1.CelScalar.INT, (x) => {
const val = x.value;
if ((0, math_js_1.isOverflowInt)(val)) {
throw overflow(INT, type_js_1.CelScalar.INT);
}
return x.value;
}),
(0, func_js_1.celOverload)([type_js_1.CelScalar.DOUBLE], type_js_1.CelScalar.INT, (x) => {
if ((0, math_js_1.isOverflowIntNum)(x)) {
throw overflow(INT, type_js_1.CelScalar.INT);
}
return BigInt(Math.trunc(x));
}),
(0, func_js_1.celOverload)([type_js_1.CelScalar.STRING], type_js_1.CelScalar.INT, (x) => {
const val = BigInt(x);
if ((0, math_js_1.isOverflowInt)(val)) {
throw overflow(INT, type_js_1.CelScalar.INT);
}
return val;
}),
(0, func_js_1.celOverload)([type_js_1.TIMESTAMP], type_js_1.CelScalar.INT, (x) => {
const val = x.message.seconds;
if ((0, math_js_1.isOverflowInt)(val)) {
throw overflow(INT, type_js_1.CelScalar.INT);
}
return BigInt(val);
}),
(0, func_js_1.celOverload)([type_js_1.DURATION], type_js_1.CelScalar.INT, (x) => {
const val = x.message.seconds;
if ((0, math_js_1.isOverflowInt)(val)) {
throw overflow(INT, type_js_1.CelScalar.INT);
}
return BigInt(val);
}),
]);
const uintFunc = (0, func_js_1.celFunc)(UINT, [
(0, func_js_1.celOverload)([type_js_1.CelScalar.UINT], type_js_1.CelScalar.UINT, (x) => x),
(0, func_js_1.celOverload)([type_js_1.CelScalar.INT], type_js_1.CelScalar.UINT, (x) => {
if ((0, math_js_1.isOverflowUint)(x)) {
throw overflow(UINT, type_js_1.CelScalar.UINT);
}
return (0, uint_js_1.celUint)(x);
}),
(0, func_js_1.celOverload)([type_js_1.CelScalar.DOUBLE], type_js_1.CelScalar.UINT, (x) => {
if ((0, math_js_1.isOverflowUintNum)(x)) {
throw overflow(UINT, type_js_1.CelScalar.UINT);
}
return (0, uint_js_1.celUint)(BigInt(Math.trunc(x)));
}),
(0, func_js_1.celOverload)([type_js_1.CelScalar.STRING], type_js_1.CelScalar.UINT, (x) => {
const val = BigInt(x);
if ((0, math_js_1.isOverflowUint)(val)) {
throw overflow(UINT, type_js_1.CelScalar.UINT);
}
return (0, uint_js_1.celUint)(val);
}),
]);
const doubleFunc = (0, func_js_1.celFunc)(DOUBLE, [
(0, func_js_1.celOverload)([type_js_1.CelScalar.DOUBLE], type_js_1.CelScalar.DOUBLE, (x) => x),
(0, func_js_1.celOverload)([type_js_1.CelScalar.INT], type_js_1.CelScalar.DOUBLE, (x) => Number(x)),
(0, func_js_1.celOverload)([type_js_1.CelScalar.UINT], type_js_1.CelScalar.DOUBLE, (x) => Number(x.value)),
(0, func_js_1.celOverload)([type_js_1.CelScalar.STRING], type_js_1.CelScalar.DOUBLE, (x) => Number(x)),
]);
const boolFunc = (0, func_js_1.celFunc)(BOOL, [
(0, func_js_1.celOverload)([type_js_1.CelScalar.BOOL], type_js_1.CelScalar.BOOL, (x) => x),
(0, func_js_1.celOverload)([type_js_1.CelScalar.STRING], type_js_1.CelScalar.BOOL, (x) => {
switch (x) {
case "true":
case "True":
case "TRUE":
case "t":
case "1":
return true;
case "false":
case "False":
case "FALSE":
case "f":
case "0":
return false;
default:
throw new Error(`Unable to convert string '${x}' to bool`);
}
}),
]);
const bytesFunc = (0, func_js_1.celFunc)(BYTES, [
(0, func_js_1.celOverload)([type_js_1.CelScalar.BYTES], type_js_1.CelScalar.BYTES, (x) => x),
(0, func_js_1.celOverload)([type_js_1.CelScalar.STRING], type_js_1.CelScalar.BYTES, (x) => Buffer.from(x)),
]);
const stringFunc = (0, func_js_1.celFunc)(STRING, [
(0, func_js_1.celOverload)([type_js_1.CelScalar.STRING], type_js_1.CelScalar.STRING, (x) => x),
(0, func_js_1.celOverload)([type_js_1.CelScalar.BOOL], type_js_1.CelScalar.STRING, (x) => x ? "true" : "false"),
(0, func_js_1.celOverload)([type_js_1.CelScalar.INT], type_js_1.CelScalar.STRING, (x) => x.toString()),
(0, func_js_1.celOverload)([type_js_1.CelScalar.UINT], type_js_1.CelScalar.STRING, (x) => x.value.toString()),
(0, func_js_1.celOverload)([type_js_1.CelScalar.DOUBLE], type_js_1.CelScalar.STRING, (x) => x.toString()),
(0, func_js_1.celOverload)([type_js_1.CelScalar.BYTES], type_js_1.CelScalar.STRING, (x) => {
const coder = new TextDecoder(undefined, { fatal: true });
try {
return coder.decode(x);
}
catch (e) {
throw new Error(`Failed to decode bytes as string: ${e}`);
}
}),
(0, func_js_1.celOverload)([type_js_1.TIMESTAMP], type_js_1.CelScalar.STRING, (x) => (0, protobuf_1.toJson)(wkt_1.TimestampSchema, x.message)),
(0, func_js_1.celOverload)([type_js_1.DURATION], type_js_1.CelScalar.STRING, (x) => (0, protobuf_1.toJson)(wkt_1.DurationSchema, x.message)),
]);
const timestampFunc = (0, func_js_1.celFunc)(TIMESTAMP, [
(0, func_js_1.celOverload)([type_js_1.TIMESTAMP], type_js_1.TIMESTAMP, (x) => x),
(0, func_js_1.celOverload)([type_js_1.CelScalar.STRING], type_js_1.TIMESTAMP, (x) => {
try {
return (0, protobuf_1.fromJson)(wkt_1.TimestampSchema, x);
}
catch (e) {
throw new Error(`Failed to parse timestamp: ${e}`);
}
}),
(0, func_js_1.celOverload)([type_js_1.CelScalar.INT], type_js_1.TIMESTAMP, (x) => (0, wkt_1.timestampFromMs)(Number(x))),
]);
const durationFunc = (0, func_js_1.celFunc)(DURATION, [
(0, func_js_1.celOverload)([type_js_1.DURATION], type_js_1.DURATION, (x) => x),
(0, func_js_1.celOverload)([type_js_1.CelScalar.STRING], type_js_1.DURATION, duration_js_1.parseDuration),
(0, func_js_1.celOverload)([type_js_1.CelScalar.INT], type_js_1.DURATION, (x) => (0, protobuf_1.create)(wkt_1.DurationSchema, { seconds: x })),
]);
const typeFunc = (0, func_js_1.celFunc)(TYPE, [
(0, func_js_1.celOverload)([type_js_1.CelScalar.DYN], type_js_1.CelScalar.TYPE, (v) => {
if ((0, protobuf_1.isMessage)(v)) {
return (0, type_js_1.objectType)((0, eval_js_1.getMsgDesc)(v.$typeName));
}
return (0, type_js_1.celType)(v);
}),
]);
const dynFunc = (0, func_js_1.celFunc)(DYN, [
(0, func_js_1.celOverload)([type_js_1.CelScalar.DYN], type_js_1.CelScalar.DYN, (x) => x),
]);
function addCasts(funcs) {
funcs.add(intFunc);
funcs.add(uintFunc);
funcs.add(doubleFunc);
funcs.add(boolFunc);
funcs.add(bytesFunc);
funcs.add(stringFunc);
funcs.add(timestampFunc);
funcs.add(durationFunc);
funcs.add(typeFunc);
funcs.add(dynFunc);
}
function overflow(op, type) {
return new Error(`${type} return error for overflow during ${op}`);
}