UNPKG

@bufbuild/cel

Version:

A CEL evaluator for ECMAScript

205 lines (204 loc) 9.8 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.isOverflowInt = isOverflowInt; exports.isOverflowIntNum = isOverflowIntNum; exports.isOverflowUint = isOverflowUint; exports.isOverflowUintNum = isOverflowUintNum; exports.addMath = addMath; const protobuf_1 = require("@bufbuild/protobuf"); const wkt_1 = require("@bufbuild/protobuf/wkt"); const func_js_1 = require("../func.js"); const opc = require("../gen/dev/cel/expr/operator_const.js"); const type_js_1 = require("../type.js"); const list_js_1 = require("../list.js"); const uint_js_1 = require("../uint.js"); const duration_js_1 = require("../duration.js"); const timestamp_js_1 = require("../timestamp.js"); const MAX_INT = 9223372036854775807n; // biome-ignore lint/correctness/noPrecisionLoss: No symbol exists in the std. const MAX_INT_NUM = 9223372036854775807.0; const MIN_INT = -9223372036854775808n; // biome-ignore lint/correctness/noPrecisionLoss: No symbol exists in the std. const MIN_INT_NUM = -9223372036854775808.0; const MAX_UINT = 18446744073709551615n; // biome-ignore lint/correctness/noPrecisionLoss: No symbol exists in the std. const MAX_UINT_NUM = 18446744073709551616.0; const MIN_UINT = 0n; const MIN_UINT_NUM = 0.0; function isOverflowInt(val) { return val < MIN_INT || val > MAX_INT; } function isOverflowIntNum(val) { return Number.isNaN(val) || val <= MIN_INT_NUM || val >= MAX_INT_NUM; } function isOverflowUint(val) { return val < MIN_UINT || val > MAX_UINT; } function isOverflowUintNum(val) { return Number.isNaN(val) || val < MIN_UINT_NUM || val > MAX_UINT_NUM; } function addMath(funcs) { funcs.add(add); funcs.add(subtract); funcs.add(multiply); funcs.add(divide); funcs.add(modulo); funcs.add(negate); } function addTimestamp(lhs, rhs) { let seconds = lhs.message.seconds + rhs.message.seconds; let nanos = lhs.message.nanos + rhs.message.nanos; if (nanos > 999999999) { seconds += BigInt(Math.floor(nanos / 1000000000)); nanos = nanos % 1000000000; } if (seconds > 253402300799 || seconds < -62135596800) { throw overflow(opc.ADD, type_js_1.TIMESTAMP); } return (0, protobuf_1.create)(wkt_1.TimestampSchema, { seconds: seconds, nanos: nanos }); } function addDuration(lhs, rhs) { let seconds = lhs.message.seconds + rhs.message.seconds; let nanos = lhs.message.nanos + rhs.message.nanos; if (nanos > 999999999) { seconds += BigInt(Math.floor(nanos / 1000000000)); nanos = nanos % 1000000000; } if (seconds > 315576000000 || seconds < -315576000000) { throw overflow(opc.ADD, type_js_1.DURATION); } return (0, protobuf_1.create)(wkt_1.DurationSchema, { seconds: seconds, nanos: nanos }); } function subtractDurationOrTimestamp(lhs, rhs) { return (0, duration_js_1.createDuration)(lhs.message.seconds - rhs.message.seconds, lhs.message.nanos - rhs.message.nanos); } const add = (0, func_js_1.celFunc)(opc.ADD, [ (0, func_js_1.celOverload)([type_js_1.CelScalar.INT, type_js_1.CelScalar.INT], type_js_1.CelScalar.INT, (lhs, rhs) => { const val = lhs + rhs; if (isOverflowInt(val)) { throw overflow(opc.SUBTRACT, type_js_1.CelScalar.INT); } return val; }), (0, func_js_1.celOverload)([type_js_1.CelScalar.UINT, type_js_1.CelScalar.UINT], type_js_1.CelScalar.UINT, (lhs, rhs) => { const val = lhs.value + rhs.value; if (isOverflowUint(val)) { throw overflow(opc.SUBTRACT, type_js_1.CelScalar.UINT); } return (0, uint_js_1.celUint)(val); }), (0, func_js_1.celOverload)([type_js_1.CelScalar.DOUBLE, type_js_1.CelScalar.DOUBLE], type_js_1.CelScalar.DOUBLE, (lhs, rhs) => lhs + rhs), (0, func_js_1.celOverload)([type_js_1.CelScalar.STRING, type_js_1.CelScalar.STRING], type_js_1.CelScalar.STRING, (lhs, rhs) => lhs + rhs), (0, func_js_1.celOverload)([type_js_1.CelScalar.BYTES, type_js_1.CelScalar.BYTES], type_js_1.CelScalar.BYTES, (lhs, rhs) => { const val = new Uint8Array(lhs.length + rhs.length); val.set(lhs); val.set(rhs, lhs.length); return val; }), (0, func_js_1.celOverload)([type_js_1.TIMESTAMP, type_js_1.TIMESTAMP], type_js_1.TIMESTAMP, addTimestamp), (0, func_js_1.celOverload)([type_js_1.TIMESTAMP, type_js_1.DURATION], type_js_1.TIMESTAMP, addTimestamp), (0, func_js_1.celOverload)([type_js_1.DURATION, type_js_1.TIMESTAMP], type_js_1.TIMESTAMP, (lhs, rhs) => addTimestamp(rhs, lhs)), (0, func_js_1.celOverload)([type_js_1.DURATION, type_js_1.DURATION], type_js_1.DURATION, addDuration), (0, func_js_1.celOverload)([(0, type_js_1.listType)(type_js_1.CelScalar.DYN), (0, type_js_1.listType)(type_js_1.CelScalar.DYN)], (0, type_js_1.listType)(type_js_1.CelScalar.DYN), list_js_1.celListConcat), ]); const subtract = (0, func_js_1.celFunc)(opc.SUBTRACT, [ (0, func_js_1.celOverload)([type_js_1.CelScalar.INT, type_js_1.CelScalar.INT], type_js_1.CelScalar.INT, (lhs, rhs) => { const val = lhs - rhs; if (isOverflowInt(val)) { throw overflow(opc.SUBTRACT, type_js_1.CelScalar.INT); } return val; }), (0, func_js_1.celOverload)([type_js_1.CelScalar.UINT, type_js_1.CelScalar.UINT], type_js_1.CelScalar.UINT, (lhs, rhs) => { const val = lhs.value - rhs.value; if (isOverflowUint(val)) { throw overflow(opc.SUBTRACT, type_js_1.CelScalar.UINT); } return (0, uint_js_1.celUint)(val); }), (0, func_js_1.celOverload)([type_js_1.CelScalar.DOUBLE, type_js_1.CelScalar.DOUBLE], type_js_1.CelScalar.DOUBLE, (lhs, rhs) => lhs - rhs), (0, func_js_1.celOverload)([type_js_1.TIMESTAMP, type_js_1.TIMESTAMP], type_js_1.DURATION, subtractDurationOrTimestamp), (0, func_js_1.celOverload)([type_js_1.DURATION, type_js_1.DURATION], type_js_1.DURATION, subtractDurationOrTimestamp), (0, func_js_1.celOverload)([type_js_1.TIMESTAMP, type_js_1.DURATION], type_js_1.TIMESTAMP, (lhs, rhs) => (0, timestamp_js_1.createTimestamp)(lhs.message.seconds - rhs.message.seconds, lhs.message.nanos - rhs.message.nanos)), ]); const multiply = (0, func_js_1.celFunc)(opc.MULTIPLY, [ (0, func_js_1.celOverload)([type_js_1.CelScalar.INT, type_js_1.CelScalar.INT], type_js_1.CelScalar.INT, (lhs, rhs) => { const product = lhs * rhs; if (isOverflowInt(product)) { throw overflow(opc.MULTIPLY, type_js_1.CelScalar.INT); } return product; }), (0, func_js_1.celOverload)([type_js_1.CelScalar.UINT, type_js_1.CelScalar.UINT], type_js_1.CelScalar.UINT, (lhs, rhs) => { const product = lhs.value * rhs.value; if (isOverflowUint(product)) { throw overflow(opc.MULTIPLY, type_js_1.CelScalar.UINT); } return (0, uint_js_1.celUint)(product); }), (0, func_js_1.celOverload)([type_js_1.CelScalar.DOUBLE, type_js_1.CelScalar.DOUBLE], type_js_1.CelScalar.DOUBLE, (lhs, rhs) => lhs * rhs), ]); const divide = (0, func_js_1.celFunc)(opc.DIVIDE, [ (0, func_js_1.celOverload)([type_js_1.CelScalar.INT, type_js_1.CelScalar.INT], type_js_1.CelScalar.INT, (lhs, rhs) => { if (rhs === 0n) { throw divisionByZero(type_js_1.CelScalar.INT); } if (lhs === MIN_INT && rhs === -1n) { throw overflow(opc.DIVIDE, type_js_1.CelScalar.INT); } return lhs / rhs; }), (0, func_js_1.celOverload)([type_js_1.CelScalar.DOUBLE, type_js_1.CelScalar.DOUBLE], type_js_1.CelScalar.DOUBLE, (lhs, rhs) => lhs / rhs), (0, func_js_1.celOverload)([type_js_1.CelScalar.UINT, type_js_1.CelScalar.UINT], type_js_1.CelScalar.UINT, (lhs, rhs) => { if (rhs.value === 0n) { throw divisionByZero(type_js_1.CelScalar.UINT); } return (0, uint_js_1.celUint)(lhs.value / rhs.value); }), ]); const modulo = (0, func_js_1.celFunc)(opc.MODULO, [ (0, func_js_1.celOverload)([type_js_1.CelScalar.INT, type_js_1.CelScalar.INT], type_js_1.CelScalar.INT, (lhs, rhs) => { if (rhs === 0n) { throw moduloByZero(type_js_1.CelScalar.INT); } return lhs % rhs; }), (0, func_js_1.celOverload)([type_js_1.CelScalar.UINT, type_js_1.CelScalar.UINT], type_js_1.CelScalar.UINT, (lhs, rhs) => { if (rhs.value === 0n) { throw moduloByZero(type_js_1.CelScalar.UINT); } return (0, uint_js_1.celUint)(lhs.value % rhs.value); }), ]); const negate = (0, func_js_1.celFunc)(opc.NEGATE, [ (0, func_js_1.celOverload)([type_js_1.CelScalar.INT], type_js_1.CelScalar.INT, (arg) => { const val = -arg; if (isOverflowInt(val)) { throw overflow(opc.NEGATE, type_js_1.CelScalar.INT); } return val; }), (0, func_js_1.celOverload)([type_js_1.CelScalar.DOUBLE], type_js_1.CelScalar.DOUBLE, (arg) => -arg), ]); function overflow(op, type) { return new Error(`${type.name} return error for overflow during ${op}`); } function divisionByZero(type) { return new Error(`${type.name} divide by zero`); } function moduloByZero(type) { return new Error(`${type.name} modulus by zero`); }