(expr: Expr)
| 4 | } from "@/types/proto-es/google/api/expr/v1alpha1/syntax_pb"; |
| 5 | |
| 6 | function stringifyExpr(expr: Expr): string { |
| 7 | if (expr.exprKind?.case === "constExpr") { |
| 8 | return stringifyConstant(expr.exprKind.value); |
| 9 | } else if (expr.exprKind?.case === "identExpr") { |
| 10 | return expr.exprKind.value.name; |
| 11 | } else if (expr.exprKind?.case === "selectExpr") { |
| 12 | const selectExpr = expr.exprKind.value; |
| 13 | // Check if testOnly flag is used to denote a 'has' operation. |
| 14 | if (selectExpr.testOnly) { |
| 15 | return `has(${stringifyExpr(selectExpr.operand!)}.${selectExpr.field})`; |
| 16 | } else { |
| 17 | return `${stringifyExpr(selectExpr.operand!)}.${selectExpr.field}`; |
| 18 | } |
| 19 | } else if (expr.exprKind?.case === "callExpr") { |
| 20 | const callExpr = expr.exprKind.value; |
| 21 | // Remove underscores from function name. e.g. "_&&_" -> "&&" |
| 22 | // Reference: https://github.com/google/cel-spec/blob/master/doc/langdef.md#list-of-standard-definitions |
| 23 | const functionName = callExpr.function.replace(/_/g, ""); |
| 24 | if (callExpr.target) { |
| 25 | const target = stringifyExpr(callExpr.target); |
| 26 | const args = callExpr.args.map((arg) => stringifyExpr(arg)).join(", "); |
| 27 | return `${target}.${functionName}(${args})`; |
| 28 | } else { |
| 29 | const args = callExpr.args.map((arg) => stringifyExpr(arg)); |
| 30 | if (functionName === "&&" || functionName === "||") { |
| 31 | return `(${args.join(` ${functionName} `)})`; |
| 32 | } else { |
| 33 | return args.join(` ${functionName} `); |
| 34 | } |
| 35 | } |
| 36 | } else if (expr.exprKind?.case === "listExpr") { |
| 37 | const listExpr = expr.exprKind.value; |
| 38 | const elements = listExpr.elements |
| 39 | .map((el) => stringifyExpr(el)) |
| 40 | .join(", "); |
| 41 | return `[${elements}]`; |
| 42 | } else if (expr.exprKind?.case === "structExpr") { |
| 43 | const structExpr = expr.exprKind.value; |
| 44 | const entries = structExpr.entries |
| 45 | .map((entry) => { |
| 46 | const key = |
| 47 | entry.keyKind?.case === "fieldKey" |
| 48 | ? entry.keyKind.value |
| 49 | : entry.keyKind?.case === "mapKey" |
| 50 | ? stringifyExpr(entry.keyKind.value) |
| 51 | : ""; |
| 52 | const value = stringifyExpr(entry.value!); |
| 53 | return `${key}: ${value}`; |
| 54 | }) |
| 55 | .join(", "); |
| 56 | return `{${entries}}`; |
| 57 | } else if (expr.exprKind?.case === "comprehensionExpr") { |
| 58 | const comprehensionExpr = expr.exprKind.value; |
| 59 | const iterRange = stringifyExpr(comprehensionExpr.iterRange!); |
| 60 | const accuInit = stringifyExpr(comprehensionExpr.accuInit!); |
| 61 | const loopCondition = stringifyExpr(comprehensionExpr.loopCondition!); |
| 62 | const loopStep = stringifyExpr(comprehensionExpr.loopStep!); |
| 63 | const result = stringifyExpr(comprehensionExpr.result!); |
no test coverage detected