{"version":3,"file":"index.mjs","names":[],"sources":["../../../forge-jsx-components/src/runtime/jsx-runtime.ts"],"sourcesContent":["/**\n * The forge JSX runtime - compiles JSX straight to escaped HTML strings, with no\n * framework underneath.\n *\n * TypeScript's automatic JSX transform (`\"jsx\": \"react-jsx\"` with `\"jsxImportSource\"`\n * pointing at this package) rewrites `<div class=\"x\">{y}</div>` into calls to the\n * `jsx`/`jsxs` functions in this module, so this file's name and export names are a\n * compiler contract, not a style choice.\n *\n * @experimental Part of the experimental JSX component API - may change or be removed\n * in a minor release.\n */\nimport type { IntrinsicElementAttributes } from './types/intrinsicElements.type'\n\n/**\n * Elements with no closing tag, per the HTML spec - rendered as `<tag>` with\n * children ignored.\n */\nconst VOID_ELEMENTS = new Set([\n  'area',\n  'base',\n  'br',\n  'col',\n  'embed',\n  'hr',\n  'img',\n  'input',\n  'link',\n  'meta',\n  'source',\n  'track',\n  'wbr',\n])\n\nconst HTML_ENTITY_MAP: Record<string, string> = {\n  '<': '&lt;',\n  '>': '&gt;',\n  '&': '&amp;',\n  '\"': '&quot;',\n  \"'\": '&#39;',\n}\n\nconst escapeHtmlEntities = (value: string): string => value.replace(/[<>&\"']/g, char => HTML_ENTITY_MAP[char])\n\n/**\n * Identifies `RawHtml` across bundle copies of this module - `Symbol.for` keys into the\n * global symbol registry, so the check holds even when two entrypoints each bundle\n * their own copy of the class.\n */\nconst RAW_HTML_BRAND = Symbol.for('forge.jsx.rawHtml')\n\n/**\n * A string of HTML that is already safe to embed - the serializer includes it verbatim\n * instead of escaping it. Every JSX expression evaluates to one of these.\n *\n * @experimental Part of the experimental JSX component API - may change or be removed\n * in a minor release.\n */\nexport class RawHtml {\n  readonly [RAW_HTML_BRAND] = true\n\n  constructor(readonly html: string) {}\n\n  toString(): string {\n    return this.html\n  }\n}\n\nconst isRawHtml = (value: unknown): value is RawHtml =>\n  typeof value === 'object' && value !== null && RAW_HTML_BRAND in value\n\n/**\n * Marks trusted markup as safe to embed without escaping - the HTML of an\n * already-rendered child block, for instance. Everything not wrapped in `raw()`\n * is escaped.\n *\n * @experimental Part of the experimental JSX component API - may change or be removed\n * in a minor release.\n *\n * @example\n * ```tsx\n * <div class=\"card__body\">{raw(renderedChildBlock.html)}</div>\n * ```\n */\nexport const raw = (html: string): RawHtml => new RawHtml(html)\n\n/**\n * Anything a JSX expression can nest inside an element. Strings and numbers are\n * escaped, `RawHtml` is embedded verbatim, and `null`/`undefined`/booleans render\n * as nothing (so `{condition && <p>...</p>}` works).\n */\nexport type JsxChild = string | number | boolean | null | undefined | RawHtml | JsxChild[]\n\n/**\n * The props a JSX element receives: attributes plus the nested children. The\n * automatic transform passes children inside props rather than as extra arguments.\n */\nexport interface JsxProps {\n  children?: JsxChild\n  [attribute: string]: unknown\n}\n\ntype FunctionComponent = (props: JsxProps) => RawHtml\n\nconst serializeChildren = (child: JsxChild): string => {\n  if (child === null || child === undefined || typeof child === 'boolean') {\n    return ''\n  }\n\n  if (Array.isArray(child)) {\n    return child.map(serializeChildren).join('')\n  }\n\n  if (isRawHtml(child)) {\n    return child.html\n  }\n\n  return escapeHtmlEntities(String(child))\n}\n\nconst serializeAttributes = (props: JsxProps): string =>\n  Object.entries(props)\n    .filter(([name, value]) => name !== 'children' && value !== undefined && value !== null && value !== false)\n    .map(([name, value]) =>\n      value === true\n        ? ` ${escapeHtmlEntities(name)}`\n        : ` ${escapeHtmlEntities(name)}=\"${escapeHtmlEntities(String(value))}\"`,\n    )\n    .join('')\n\n/**\n * The automatic JSX transform's element factory - `<div class=\"x\">{y}</div>` compiles\n * to `jsx('div', { class: 'x', children: y })`. Not called directly from user code.\n *\n * The transform passes JSX `key` attributes as a third argument; keys are meaningless\n * when rendering to a string, so the extra argument is ignored.\n *\n * @experimental Part of the experimental JSX component API - may change or be removed\n * in a minor release.\n */\nexport const jsx = (tag: string | FunctionComponent, props: JsxProps): RawHtml => {\n  if (typeof tag === 'function') {\n    return tag(props)\n  }\n\n  const attributes = serializeAttributes(props)\n\n  if (VOID_ELEMENTS.has(tag)) {\n    return new RawHtml(`<${tag}${attributes}>`)\n  }\n\n  return new RawHtml(`<${tag}${attributes}>${serializeChildren(props.children)}</${tag}>`)\n}\n\n/**\n * The transform calls `jsxs` instead of `jsx` when an element has multiple static\n * children - the distinction only matters to frameworks that key children, so both\n * share one implementation here.\n *\n * @experimental Part of the experimental JSX component API - may change or be removed\n * in a minor release.\n */\nexport const jsxs = jsx\n\n/**\n * Renders fragment children (`<>...</>`) with no wrapping element.\n *\n * @experimental Part of the experimental JSX component API - may change or be removed\n * in a minor release.\n */\nexport const Fragment = (props: JsxProps): RawHtml => new RawHtml(serializeChildren(props.children))\n\n/**\n * Development-mode entry point - dev transforms (Vite, esbuild with jsxDev,\n * TypeScript's \"react-jsxdev\") import `<jsxImportSource>/jsx-dev-runtime` and call\n * `jsxDEV` instead of `jsx`/`jsxs`. Its extra arguments (key, static-children flag,\n * source location) only matter to frameworks that diff and re-render, so it is the\n * production implementation under the dev name - the package's `jsx-dev-runtime`\n * subpath resolves to this same module.\n *\n * @experimental Part of the experimental JSX component API - may change or be removed\n * in a minor release.\n */\nexport const jsxDEV = jsx\n\n/**\n * The types TypeScript reads from the `jsxImportSource` module to type-check JSX\n * expressions: what an expression evaluates to, which tags exist with which\n * attributes, and which prop carries nested children.\n *\n * The namespace, its name and its member names are all part of the compiler's JSX\n * contract, hence the lint exemptions.\n */\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport declare namespace JSX {\n  type Element = RawHtml\n\n  // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n  interface IntrinsicElements extends IntrinsicElementAttributes {}\n\n  interface ElementChildrenAttribute {\n    children: unknown\n  }\n}\n"],"mappings":";;;;;AAkBA,MAAM,gCAAgB,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,kBAA0C;CAC9C,KAAK;CACL,KAAK;CACL,KAAK;CACL,MAAK;CACL,KAAK;AACP;AAEA,MAAM,sBAAsB,UAA0B,MAAM,QAAQ,aAAY,SAAQ,gBAAgB,KAAK;;;;;;AAO7G,MAAM,iBAAiB,OAAO,IAAI,mBAAmB;;;;;;;;AASrD,IAAa,UAAb,MAAqB;CAGE;CAFrB,CAAU,kBAAkB;CAE5B,YAAY,MAAuB;EAAd,KAAA,OAAA;CAAe;CAEpC,WAAmB;EACjB,OAAO,KAAK;CACd;AACF;AAEA,MAAM,aAAa,UACjB,OAAO,UAAU,YAAY,UAAU,QAAQ,kBAAkB;;;;;;;;;;;;;;AAenE,MAAa,OAAO,SAA0B,IAAI,QAAQ,IAAI;AAoB9D,MAAM,qBAAqB,UAA4B;CACrD,IAAI,UAAU,QAAQ,UAAU,KAAA,KAAa,OAAO,UAAU,WAC5D,OAAO;CAGT,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,MAAM,IAAI,iBAAiB,CAAC,CAAC,KAAK,EAAE;CAG7C,IAAI,UAAU,KAAK,GACjB,OAAO,MAAM;CAGf,OAAO,mBAAmB,OAAO,KAAK,CAAC;AACzC;AAEA,MAAM,uBAAuB,UAC3B,OAAO,QAAQ,KAAK,CAAC,CAClB,QAAQ,CAAC,MAAM,WAAW,SAAS,cAAc,UAAU,KAAA,KAAa,UAAU,QAAQ,UAAU,KAAK,CAAC,CAC1G,KAAK,CAAC,MAAM,WACX,UAAU,OACN,IAAI,mBAAmB,IAAI,MAC3B,IAAI,mBAAmB,IAAI,EAAE,IAAI,mBAAmB,OAAO,KAAK,CAAC,EAAE,EACzE,CAAC,CACA,KAAK,EAAE;;;;;;;;;;;AAYZ,MAAa,OAAO,KAAiC,UAA6B;CAChF,IAAI,OAAO,QAAQ,YACjB,OAAO,IAAI,KAAK;CAGlB,MAAM,aAAa,oBAAoB,KAAK;CAE5C,IAAI,cAAc,IAAI,GAAG,GACvB,OAAO,IAAI,QAAQ,IAAI,MAAM,WAAW,EAAE;CAG5C,OAAO,IAAI,QAAQ,IAAI,MAAM,WAAW,GAAG,kBAAkB,MAAM,QAAQ,EAAE,IAAI,IAAI,EAAE;AACzF;;;;;;;;;AAUA,MAAa,OAAO;;;;;;;AAQpB,MAAa,YAAY,UAA6B,IAAI,QAAQ,kBAAkB,MAAM,QAAQ,CAAC;;;;;;;;;;;;AAanG,MAAa,SAAS"}