@bufbuild/cel
Version:
A CEL evaluator for ECMAScript
374 lines (373 loc) • 14.6 kB
JavaScript
"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 __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _Builder_prevId;
Object.defineProperty(exports, "__esModule", { value: true });
const encoder = new TextEncoder();
class Builder {
constructor() {
_Builder_prevId.set(this, 0n);
this.sourceInfo = {
$typeName: "cel.expr.SourceInfo",
syntaxVersion: "",
location: "",
lineOffsets: [],
positions: {},
macroCalls: {},
extensions: [],
};
}
nextExpr(offset, exprKind) {
var _a;
this.sourceInfo.positions[(__classPrivateFieldSet(this, _Builder_prevId, (_a = __classPrivateFieldGet(this, _Builder_prevId, "f"), ++_a), "f")).toString()] = offset;
return {
$typeName: "cel.expr.Expr",
id: __classPrivateFieldGet(this, _Builder_prevId, "f"),
exprKind,
};
}
nextEntry(offset, keyKind, value) {
var _a;
this.sourceInfo.positions[(__classPrivateFieldSet(this, _Builder_prevId, (_a = __classPrivateFieldGet(this, _Builder_prevId, "f"), ++_a), "f")).toString()] = offset;
return {
$typeName: "cel.expr.Expr.CreateStruct.Entry",
id: __classPrivateFieldGet(this, _Builder_prevId, "f"),
keyKind,
value,
optionalEntry: false,
};
}
newConstExpr(offset, constantKind) {
return this.nextExpr(offset, {
case: "constExpr",
value: { $typeName: "cel.expr.Constant", constantKind },
});
}
newCallExpr(offset, functionName, args) {
if (functionName === "has" &&
args.length === 1 &&
args[0].exprKind?.case === "selectExpr") {
return this.expandHasMacro(offset, args[0]);
}
return this.nextExpr(offset, {
case: "callExpr",
value: {
$typeName: "cel.expr.Expr.Call",
function: functionName,
args,
},
});
}
newMemberCallExpr(offset, target, functionName, args) {
return this.maybeExpand(offset, this.nextExpr(offset, {
case: "callExpr",
value: {
$typeName: "cel.expr.Expr.Call",
function: functionName,
target,
args,
},
}));
}
newStringExpr(offset, sequence) {
return this.newConstExpr(offset, {
case: "stringValue",
value: sequence.reduce((string, chunk) => {
if (typeof chunk !== "string") {
if (chunk.some((cp) => cp >= 0xd800 && cp < 0xe000)) {
// surrogates, whether paired or not, are not allowed in UTF-8
throw new Error("surrogate code points are not allowed");
}
return string + String.fromCodePoint(...chunk);
}
return string + chunk;
}, ""),
});
}
newBytesExpr(offset, sequence) {
const chunks = [];
let totalSize = 0;
for (const rawChunk of sequence) {
const chunk = typeof rawChunk === "string" ? encoder.encode(rawChunk) : rawChunk;
chunks.push(chunk);
totalSize += chunk.length;
}
const value = new Uint8Array(totalSize);
let chunkOffset = 0;
for (const chunk of chunks) {
value.set(chunk, chunkOffset);
chunkOffset += chunk.length;
}
return this.newConstExpr(offset, {
case: "bytesValue",
value,
});
}
newBoolExpr(offset, keyword) {
return this.newConstExpr(offset, {
case: "boolValue",
value: keyword === "true",
});
}
newInt64Expr(offset, digits) {
return this.newConstExpr(offset, {
case: "int64Value",
value: digits[0] === "-" ? -BigInt(digits.slice(1)) : BigInt(digits),
});
}
newUnsignedInt64Expr(offset, digits) {
return this.newConstExpr(offset, {
case: "uint64Value",
value: BigInt(digits),
});
}
newDoubleExpr(offset, digits) {
return this.newConstExpr(offset, {
case: "doubleValue",
value: parseFloat(digits),
});
}
newNullExpr(offset) {
return this.newConstExpr(offset, {
case: "nullValue",
value: 0,
});
}
newIdentExpr(offset, name) {
const expr = this.nextExpr(offset, {
case: "identExpr",
value: { $typeName: "cel.expr.Expr.Ident", name },
});
return expr;
}
newInfixExpr(offset, op, args) {
return this.newCallExpr(offset, op === "in" ? "@in" : `_${op}_`, args);
}
newSelectExpr(offset, operand, field) {
return this.nextExpr(offset, {
case: "selectExpr",
value: {
$typeName: "cel.expr.Expr.Select",
operand,
field,
testOnly: false,
},
});
}
newIndexExpr(offset, operand, index) {
return this.newCallExpr(offset, "_[_]", [operand, index]);
}
expandHasMacro(offset, target) {
if (target.exprKind.case !== "selectExpr") {
return this.newCallExpr(offset, "has", [target]);
}
target.exprKind.value.testOnly = true;
return target;
}
newListExpr(offset, elements) {
return this.nextExpr(offset, {
case: "listExpr",
value: {
$typeName: "cel.expr.Expr.CreateList",
elements,
optionalIndices: [],
},
});
}
newBoolMacro(offset, iterRange, iterVar, init, loopStep, loopCondition) {
return this.nextExpr(offset, {
case: "comprehensionExpr",
value: {
$typeName: "cel.expr.Expr.Comprehension",
accuVar: "__result__",
accuInit: this.newConstExpr(offset, {
case: "boolValue",
value: init,
}),
iterVar,
iterVar2: "", // not yet supported
iterRange,
loopStep,
loopCondition,
result: this.newIdentExpr(offset, "__result__"),
},
});
}
newListMacro(offset, iterRange, iterVar, loopStep) {
return this.nextExpr(offset, {
case: "comprehensionExpr",
value: {
$typeName: "cel.expr.Expr.Comprehension",
accuVar: "__result__",
accuInit: this.newListExpr(offset, []),
iterVar,
iterVar2: "", // not yet supported
iterRange,
loopCondition: this.newConstExpr(offset, {
case: "boolValue",
value: true,
}),
loopStep,
result: this.newIdentExpr(offset, "__result__"),
},
});
}
expandExistsMacro(offset, target, x, test) {
return this.newBoolMacro(offset, target, x, false, this.newCallExpr(offset, "_||_", [
this.newIdentExpr(offset, "__result__"),
test,
]), this.newCallExpr(offset, "@not_strictly_false", [
this.newCallExpr(offset, "!_", [
this.newIdentExpr(offset, "__result__"),
]),
]));
}
expandAllMacro(offset, target, x, test) {
return this.newBoolMacro(offset, target, x, true, this.newCallExpr(offset, "_&&_", [
this.newIdentExpr(offset, "__result__"),
test,
]), this.newCallExpr(offset, "@not_strictly_false", [
this.newIdentExpr(offset, "__result__"),
]));
}
expandMapMacro(offset, target, x, step) {
return this.newListMacro(offset, target, x, this.newCallExpr(offset, "_+_", [
this.newIdentExpr(offset, "__result__"),
this.newListExpr(offset, [step]),
]));
}
expandMapFilterMacro(offset, target, x, test, step) {
return this.newListMacro(offset, target, x, this.newCallExpr(offset, "_?_:_", [
test,
this.newCallExpr(offset, "_+_", [
this.newIdentExpr(offset, "__result__"),
this.newListExpr(offset, [step]),
]),
this.newIdentExpr(offset, "__result__"),
]));
}
expandFilterMacro(offset, target, x, step) {
return this.newListMacro(offset, target, x, this.newCallExpr(offset, "_?_:_", [
step,
this.newCallExpr(offset, "_+_", [
this.newIdentExpr(offset, "__result__"),
this.newListExpr(offset, [this.newIdentExpr(offset, x)]),
]),
this.newIdentExpr(offset, "__result__"),
]));
}
expandExistsOne(offset, iterRange, iterVar, step) {
return this.nextExpr(offset, {
case: "comprehensionExpr",
value: {
$typeName: "cel.expr.Expr.Comprehension",
accuVar: "__result__",
accuInit: this.newConstExpr(offset, {
case: "int64Value",
value: BigInt(0),
}),
iterVar,
iterVar2: "", // not yet supported
iterRange,
loopCondition: this.newConstExpr(offset, {
case: "boolValue",
value: true,
}),
loopStep: this.newCallExpr(offset, "_?_:_", [
step,
this.newCallExpr(offset, "_+_", [
this.newIdentExpr(offset, "__result__"),
this.newConstExpr(offset, {
case: "int64Value",
value: BigInt(1),
}),
]),
this.newIdentExpr(offset, "__result__"),
]),
result: this.newCallExpr(offset, "_==_", [
this.newIdentExpr(offset, "__result__"),
this.newConstExpr(offset, {
case: "int64Value",
value: BigInt(1),
}),
]),
},
});
}
maybeExpand(offset, call) {
if (call.exprKind.case === "callExpr") {
const callExpr = call.exprKind.value;
const varName = callExpr.args[0];
// const varIndex = callExpr.args.length > 1 ? callExpr.args[1] : "";
if (varName !== undefined &&
call.exprKind.value.target !== undefined &&
varName.exprKind?.case === "identExpr") {
if (callExpr.args.length === 2) {
switch (callExpr.function) {
case "exists":
return this.expandExistsMacro(offset, call.exprKind.value.target, varName.exprKind.value.name, call.exprKind.value.args[1]);
case "all":
return this.expandAllMacro(offset, call.exprKind.value.target, varName.exprKind.value.name, call.exprKind.value.args[1]);
case "map":
return this.expandMapMacro(offset, call.exprKind.value.target, varName.exprKind.value.name, call.exprKind.value.args[1]);
case "filter":
return this.expandFilterMacro(offset, call.exprKind.value.target, varName.exprKind.value.name, call.exprKind.value.args[1]);
case "exists_one":
case "existsOne":
return this.expandExistsOne(offset, call.exprKind.value.target, varName.exprKind.value.name, call.exprKind.value.args[1]);
}
}
if (callExpr.args.length === 3 && callExpr.function == "map") {
return this.expandMapFilterMacro(offset, call.exprKind.value.target, varName.exprKind.value.name, call.exprKind.value.args[1], call.exprKind.value.args[2]);
}
}
}
return call;
}
newMapEntry(offset, key, value) {
return this.nextEntry(offset, {
case: "mapKey",
value: key,
}, value);
}
newStructExpr(offset, entries, messageName = "") {
return this.nextExpr(offset, {
case: "structExpr",
value: {
$typeName: "cel.expr.Expr.CreateStruct",
entries,
messageName,
},
});
}
newStructEntry(offset, field, value) {
return this.nextEntry(offset, {
case: "fieldKey",
value: field,
}, value);
}
}
_Builder_prevId = new WeakMap();
exports.default = Builder;