UNPKG

@bufbuild/cel

Version:

A CEL evaluator for ECMAScript

193 lines (192 loc) 6.22 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. var _a, _b; Object.defineProperty(exports, "__esModule", { value: true }); exports.EMPTY_MAP = void 0; exports.celMap = celMap; exports.isCelMap = isCelMap; const reflect_1 = require("@bufbuild/protobuf/reflect"); const uint_js_1 = require("./uint.js"); const protobuf_1 = require("@bufbuild/protobuf"); const proto_js_1 = require("./proto.js"); const value_js_1 = require("./value.js"); const privateSymbol = Symbol.for("@bufbuild/cel/map"); /** * Create a new map from a native map or a ReflectMap. */ function celMap(mapOrReflectMap) { if ((0, reflect_1.isReflectMap)(mapOrReflectMap)) { return new ProtoMap(mapOrReflectMap); } return new NativeMap(mapOrReflectMap); } /** * Returns true if the given value is a CelMap. */ function isCelMap(v) { return typeof v === "object" && v !== null && privateSymbol in v; } class NativeMap { constructor(_map) { this._map = _map; this[_a] = {}; } get size() { return this._map.size; } get(key) { if ((0, uint_js_1.isCelUint)(key)) { key = key.value; } // According to CEL equality all numerical types are // equal if they have the same value. if (typeof key === "number") { if (!Number.isInteger(key)) { return undefined; } key = BigInt(key); } // Direct check for maps with string, boolean, and bigint keys. const value = this._map.get(key); if (value !== undefined) { return (0, value_js_1.toCel)(value); } // For maps with CelUint keys we have to loop through all keys to check because // JS maps use SameValueZero algorithm which is the same as '===' for objects. // // Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#key_equality if (typeof key === "bigint") { for (const mapKey of this._map.keys()) { if (!(0, uint_js_1.isCelUint)(mapKey)) { continue; } if (mapKey.value === key) { return (0, value_js_1.toCel)(this._map.get(mapKey)); } } } return undefined; } has(key) { return this.get(key) != undefined; } forEach(callback, // biome-ignore lint/suspicious/noExplicitAny: Part of the Map interface. thisArg) { this._map.forEach((value, key, _) => callback.call(thisArg, (0, value_js_1.toCel)(value), key, this)); } *entries() { for (const [key, value] of this._map.entries()) { yield [key, (0, value_js_1.toCel)(value)]; } } keys() { return this._map.keys(); } *values() { for (const value of this._map.values()) { yield (0, value_js_1.toCel)(value); } } [(_a = privateSymbol, Symbol.iterator)]() { return this.entries(); } } class ProtoMap { constructor(_map) { this._map = _map; this[_b] = {}; } get size() { return this._map.size; } get(key) { const value = this._map.get(mapKeyFromCel(this._map.field(), key)); if (value === undefined) { return undefined; } return celFromMapValue(this._map.field(), value); } has(key) { return this._map.has(mapKeyFromCel(this._map.field(), key)); } forEach(callback, // biome-ignore lint/suspicious/noExplicitAny: Part of the Map interface. thisArg) { this._map.forEach((value, key, _) => callback.call(thisArg, celFromMapValue(this._map.field(), value), celFromMapKey(this._map.field(), key), this)); } *entries() { for (const [key, value] of this._map.entries()) { yield [ celFromMapKey(this._map.field(), key), celFromMapValue(this._map.field(), value), ]; } } *keys() { for (const key of this._map.keys()) { yield celFromMapKey(this._map.field(), key); } } *values() { for (const value of this._map.keys()) { yield celFromMapValue(this._map.field(), value); } } [(_b = privateSymbol, Symbol.iterator)]() { return this.entries(); } } function mapKeyFromCel(desc, v) { if ((0, uint_js_1.isCelUint)(v)) { v = v.value; } switch (desc.mapKey) { case protobuf_1.ScalarType.SINT32: case protobuf_1.ScalarType.INT32: case protobuf_1.ScalarType.FIXED32: case protobuf_1.ScalarType.UINT32: case protobuf_1.ScalarType.SFIXED32: if (typeof v === "bigint") { return Number(v); } return v; case protobuf_1.ScalarType.SINT64: case protobuf_1.ScalarType.INT64: case protobuf_1.ScalarType.FIXED64: case protobuf_1.ScalarType.UINT64: case protobuf_1.ScalarType.SFIXED64: if (v === "number" && Number.isInteger(v)) { return BigInt(v); } return v; default: return v; } } function celFromMapKey(desc, v) { return (0, proto_js_1.celFromScalar)(desc.mapKey, v); } function celFromMapValue(desc, v) { switch (desc.mapKind) { case "enum": return BigInt(v); case "message": return (0, value_js_1.reflectMsgToCel)(v); case "scalar": return (0, proto_js_1.celFromScalar)(desc.scalar, v); } } exports.EMPTY_MAP = celMap(new Map());