eventHandler
An on… attribute (onClick={…}): an event handler, which only exists in the browser. Not one given a server
function (onRemove={remove}, onRemove={remove.bind(null, id)}, as isServerFunction says), which a server
component can give a browser component to call.
import type { IR } from "#codebase/tcmts/core/hash"; export function eventHandler( ir: IR, isServerFunction: (hash: string) => boolean = () => false, ): string | undefined { if (typeof ir === "string") return undefined; const child = (node: IR, key: string) => Array.isArray(node) ? (node.find((x) => Array.isArray(x) && x[0] === key) as IR[] | undefined)?.[1] : undefined; if (ir[0] === "JsxAttribute") { const n = child(ir, "name") as IR[] | undefined; const init = child(ir, "initializer"); if (n?.[0] === "N" && typeof n[1] === "string" && /^on[A-Z]/.test(n[1]) && init !== undefined) { const value = init && init[0] === "JsxExpression" ? (child(init, "expression") as IR[] | undefined) : undefined; const bound = value?.[0] === "CallExpression" ? (child(value, "expression") as IR[] | undefined) : undefined; const fn = value?.[0] === "Ref" ? value : bound?.[0] === "PropertyAccessExpression" && (child(bound, "name") as IR[] | undefined)?.[1] === "bind" ? (child(bound, "expression") as IR[] | undefined) : undefined; if (!(fn?.[0] === "Ref" && typeof fn[1] === "string" && isServerFunction(fn[1]))) return n[1]; } } // (a component's props only: an element's (`<button onClick>`) is called with an event) const tag = ir[0] === "JsxSelfClosingElement" || ir[0] === "JsxOpeningElement" ? (child(ir, "tagName") as IR[] | undefined) : undefined; const inner = tag && !(typeof tag[0] === "string" && /^(Ref|Cyc|Ext|L)$/.test(tag[0])) ? () => false : isServerFunction; for (const c of ir) { const found = eventHandler(c, inner); if (found) return found; } return undefined; }