2025-08-07 21:10:17 +02:00
|
|
|
<!doctype html>
|
|
|
|
|
<html lang="en-US">
|
|
|
|
|
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="utf-8" />
|
2025-08-08 06:56:49 +02:00
|
|
|
<title>CEL evaluator</title>
|
2025-08-07 21:10:17 +02:00
|
|
|
<style type="text/css">
|
|
|
|
|
body {
|
|
|
|
|
font-family: sans-serif;
|
2025-08-08 06:56:49 +02:00
|
|
|
max-width: 1200px;
|
|
|
|
|
margin: 0 auto;
|
|
|
|
|
padding: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.container {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: 1fr 1fr;
|
|
|
|
|
gap: 20px;
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.full-width {
|
|
|
|
|
grid-column: 1 / -1;
|
2025-08-07 21:10:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
textarea {
|
2025-08-08 06:56:49 +02:00
|
|
|
width: 100%;
|
|
|
|
|
height: 15em;
|
2025-08-07 21:10:17 +02:00
|
|
|
box-sizing: border-box;
|
2025-08-08 06:56:49 +02:00
|
|
|
border-radius: 5px;
|
|
|
|
|
padding: 10px;
|
|
|
|
|
border: 2px solid lightgray;
|
|
|
|
|
font-family: 'Courier New', monospace;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
resize: vertical;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#output {
|
|
|
|
|
background-color: #f8f9fa;
|
|
|
|
|
height: 10em;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
label {
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
display: block;
|
|
|
|
|
margin-bottom: 5px;
|
|
|
|
|
color: #333;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.error {
|
|
|
|
|
color: #d32f2f;
|
|
|
|
|
background-color: #ffebee;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.success {
|
|
|
|
|
color: #2e7d32;
|
|
|
|
|
background-color: #e8f5e9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
h1 {
|
|
|
|
|
color: #1976d2;
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p {
|
|
|
|
|
color: #666;
|
|
|
|
|
line-height: 1.4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a {
|
|
|
|
|
color: #1976d2;
|
2025-08-07 21:10:17 +02:00
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
|
|
<body>
|
|
|
|
|
<script>
|
|
|
|
|
function run() {
|
|
|
|
|
WebAssembly.instantiateStreaming(fetch("cel_js_example.wasm"), {}).then(({ instance }) => {
|
|
|
|
|
const readString = (offset) => {
|
|
|
|
|
const memory = instance.exports.memory.buffer;
|
|
|
|
|
const length = new Uint32Array(memory, offset, 1)[0];
|
|
|
|
|
const characters = new Uint8Array(memory, offset + 4, length);
|
|
|
|
|
return new TextDecoder().decode(characters);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const readU8 = (offset) => {
|
|
|
|
|
return new Uint8Array(instance.exports.memory.buffer, offset, 1)[0];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const writeString = (s) => {
|
|
|
|
|
const encoded = new TextEncoder().encode(s.trim());
|
|
|
|
|
const offset = instance.exports.allocation(4 + encoded.byteLength);
|
|
|
|
|
const memory = instance.exports.memory.buffer;
|
|
|
|
|
const uint32s = new Uint32Array(memory, offset, 1);
|
|
|
|
|
uint32s[0] = encoded.byteLength;
|
|
|
|
|
const uint8s = new Uint8Array(memory, offset + 4, encoded.byteLength);
|
|
|
|
|
uint8s.set(encoded);
|
|
|
|
|
return offset;
|
|
|
|
|
};
|
|
|
|
|
|
2025-08-08 06:56:49 +02:00
|
|
|
// Combine CEL expression and JSON context
|
|
|
|
|
const expression = document.getElementById("input").value;
|
|
|
|
|
const context = document.getElementById("context").value;
|
|
|
|
|
|
|
|
|
|
// Create a combined input with expression and context separated by a delimiter
|
|
|
|
|
const combinedInput = expression + "\n---CONTEXT---\n" + context;
|
|
|
|
|
|
|
|
|
|
const offset = instance.exports.evaluate(writeString(combinedInput));
|
2025-08-07 21:10:17 +02:00
|
|
|
const ok = readU8(offset) != 0;
|
|
|
|
|
const result = readString(offset + 4);
|
|
|
|
|
const output = document.getElementById("output");
|
2025-08-08 06:56:49 +02:00
|
|
|
|
|
|
|
|
// Style the output based on success/error
|
|
|
|
|
if (ok) {
|
|
|
|
|
output.className = "success";
|
|
|
|
|
output.value = result;
|
|
|
|
|
} else {
|
|
|
|
|
output.className = "error";
|
|
|
|
|
output.value = "ERROR\n" + result;
|
|
|
|
|
}
|
|
|
|
|
}).catch(error => {
|
|
|
|
|
const output = document.getElementById("output");
|
|
|
|
|
output.className = "error";
|
|
|
|
|
output.value = "WASM Loading Error: " + error.message;
|
2025-08-07 21:10:17 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.addEventListener("load", function () {
|
|
|
|
|
document.getElementById("input").addEventListener("input", run, false);
|
2025-08-08 06:56:49 +02:00
|
|
|
document.getElementById("context").addEventListener("input", run, false);
|
|
|
|
|
run();
|
|
|
|
|
});
|
2025-08-07 21:10:17 +02:00
|
|
|
</script>
|
2025-08-08 06:56:49 +02:00
|
|
|
|
|
|
|
|
<h1>CEL evaluator</h1>
|
2025-08-07 21:10:17 +02:00
|
|
|
<p>
|
2025-08-08 06:56:49 +02:00
|
|
|
Using <a href="https://github.com/cel-rust/cel-rust">cel-rust</a> compiled to WebAssembly.
|
|
|
|
|
Change the CEL expression or JSON context to see it update in real-time.
|
2025-08-07 21:10:17 +02:00
|
|
|
</p>
|
2025-08-08 06:56:49 +02:00
|
|
|
|
|
|
|
|
<div class="container">
|
|
|
|
|
<div>
|
|
|
|
|
<label for="input">CEL Expression:</label>
|
|
|
|
|
<textarea id="input" placeholder="Enter your CEL expression here...">name + " is " + string(age) + " years old"</textarea>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div>
|
|
|
|
|
<label for="context">JSON Context:</label>
|
|
|
|
|
<textarea id="context" placeholder="Enter JSON context here...">{"name": "Alice", "age": 30, "active": true}</textarea>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="full-width">
|
|
|
|
|
<label for="output">Result:</label>
|
|
|
|
|
<textarea id="output" readonly="readonly"></textarea>
|
|
|
|
|
</div>
|
2025-08-07 21:10:17 +02:00
|
|
|
</body>
|
|
|
|
|
|
2025-08-08 06:56:49 +02:00
|
|
|
</html>
|