eventHandler

tcmts.cli.placement.eventHandler · #t6x33bgi · term · runs anywhere

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;
}

uses

used by