///
import {
computed,
Default,
handler,
NAME,
pattern,
Stream,
UI,
type VNode,
Writable,
} from "commontools";
const VERSION = "v26";
function describeValue(val: any): string {
const type = typeof val;
let repr: string;
if (val === undefined) repr = "undefined";
else if (val === null) repr = "null";
else if (val !== val) repr = "NaN";
else if (val === Infinity) repr = "Infinity";
else if (val === -Infinity) repr = "-Infinity";
else {
try {
repr = JSON.stringify(val, null, 2);
} catch {
repr = String(val);
}
}
return `typeof: ${type}\n\nvalue: ${repr}`;
}
function nowTimestamp(): string {
const d = new Date();
const pad = (n: number) => String(n).padStart(2, "0");
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${
pad(d.getHours())
}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}
interface Input {
value?: Writable>;
inputText?: Writable>;
errorMsg?: Writable>;
evalTime?: Writable>;
}
interface Output {
[NAME]: string;
[UI]: VNode;
value: any;
evalAndStore: Stream;
rerenderDisplay: Stream;
}
const evalAndStore = handler<
void,
{
value: Writable;
inputText: Writable;
errorMsg: Writable;
evalTime: Writable;
}
>((_, { value, inputText, errorMsg, evalTime }) => {
const expr = inputText.get();
console.log(`[data-model-test] evaluating: ${expr}`);
try {
// Intentional use of `new Function` for testing: This pattern exists to
// exercise the data model's serialization of arbitrary JS values. Patterns
// run inside the sandboxed piece runtime, not the host.
const result = new Function(`return (${expr})`)();
console.log(`[data-model-test] result:`, result);
value.set(result);
errorMsg.set("");
evalTime.set(nowTimestamp());
} catch (e: any) {
console.log(`[data-model-test] error:`, e);
errorMsg.set(String(e));
}
});
const rerenderDisplay = handler<
void,
{ value: Writable; evalTime: Writable }
>(
(_, { value, evalTime }) => {
const v = value.get();
console.log(`[data-model-test] rerender from stored value:`, v);
evalTime.set(nowTimestamp());
},
);
export default pattern(
({ value, inputText, errorMsg, evalTime }) => {
console.log(`[data-model-test] loaded ${VERSION}`);
const boundEvalAndStore = evalAndStore({
value,
inputText,
errorMsg,
evalTime,
});
const boundRerenderDisplay = rerenderDisplay({ value, evalTime });
const display = computed(() => {
const ts = evalTime.get();
const desc = describeValue(value.get());
return `evaluated at: ${ts}\n${desc}`;
});
return {
[NAME]: "Data Model Test",
[UI]: (
Data Model Test
Evaluate & Store
Rerender Display
{display}
{errorMsg}
{VERSION}
),
value,
evalAndStore: boundEvalAndStore,
rerenderDisplay: boundRerenderDisplay,
};
},
);