{"version":3,"sources":["../../../src/json/html-string/index.ts","../../../src/json/renderer.ts","../../../src/json/html-string/string.ts"],"sourcesContent":["export * from '../renderer.js'\nexport * from './string.js'\n","/* oslint-disableno-explicit-any */\nimport type { JSONContent } from '@tiptap/core'\n\n/**\n * A JSON representation of a mark (a Tiptap/ProseMirror mark serialized to JSON).\n */\nexport type JSONMarkType = NonNullable<JSONContent['marks']>[number]\n\n/**\n * A JSON representation of a node (a Tiptap/ProseMirror node serialized to JSON).\n *\n * `marks` is tied to the `TMark` type parameter so the node<->mark relationship\n * stays sound. This is also why we cannot simply default `TNodeType` to\n * `JSONContent`: the generic constraint references `TMarkType` via\n * `marks?: readonly TMarkType[]`, and `JSONContent.marks` is a *concrete* array,\n * which TypeScript rejects (\"TMarkType could be instantiated with a different\n * subtype of constraint\"). Parameterizing the node type by the same `TMark`\n * avoids that bivariance error. Please don't \"simplify\" this back to\n * `JSONContent` — it won't type-check.\n */\nexport type JSONNodeType<TMark extends { type: string | { name: string } } = JSONMarkType> = {\n  type?: string\n  attrs?: Record<string, any>\n  content?: JSONNodeType<TMark>[]\n  marks?: readonly TMark[]\n  text?: string\n  [key: string]: any\n}\n\n/**\n * Props for a node renderer\n */\nexport type NodeProps<TNodeType = any, TChildren = any> = {\n  /**\n   * The current node to render\n   */\n  node: TNodeType\n  /**\n   * Unless the node is the root node, this will always be defined\n   */\n  parent?: TNodeType\n  /**\n   * The children of the current node\n   */\n  children?: TChildren\n  /**\n   * Render a child element\n   */\n  renderElement: (props: {\n    /**\n     * Tiptap JSON content to render\n     */\n    content: TNodeType\n    /**\n     * The parent node of the current node\n     */\n    parent?: TNodeType\n  }) => TChildren\n}\n\n/**\n * Props for a mark renderer\n */\nexport type MarkProps<TMarkType = any, TChildren = any, TNodeType = any> = {\n  /**\n   * The current mark to render\n   */\n  mark: TMarkType\n  /**\n   * The children of the current mark\n   */\n  children?: TChildren\n  /**\n   * The node the current mark is applied to\n   */\n  node: TNodeType\n  /**\n   * The node the current mark is applied to\n   */\n  parent?: TNodeType\n}\n\nexport type TiptapStaticRendererOptions<\n  /**\n   * The return type of the render function (e.g. React.ReactNode, string)\n   */\n  TReturnType,\n  /**\n   * A mark type is either a JSON representation of a mark or a Prosemirror mark instance\n   */\n  TMarkType extends { type: any } = JSONMarkType,\n  /**\n   * A node type is either a JSON representation of a node or a Prosemirror node instance\n   */\n  TNodeType extends {\n    content?: { forEach: (cb: (node: TNodeType) => void) => void }\n    marks?: readonly TMarkType[]\n    type?: string | { name: string }\n  } = JSONNodeType<TMarkType>,\n  /**\n   * A node renderer is a function that takes a node and its children and returns the rendered output\n   */\n  TNodeRender extends (ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>) => TReturnType = (\n    ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>,\n  ) => TReturnType,\n  /**\n   * A mark renderer is a function that takes a mark and its children and returns the rendered output\n   */\n  TMarkRender extends (\n    ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>,\n  ) => TReturnType = (\n    ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>,\n  ) => TReturnType,\n> = {\n  /**\n   * Mapping of node types to react components\n   */\n  nodeMapping: Record<string, NoInfer<TNodeRender>>\n  /**\n   * Mapping of mark types to react components\n   */\n  markMapping: Record<string, NoInfer<TMarkRender>>\n  /**\n   * Component to render if a node type is not handled\n   */\n  unhandledNode?: NoInfer<TNodeRender>\n  /**\n   * Component to render if a mark type is not handled\n   */\n  unhandledMark?: NoInfer<TMarkRender>\n}\n\n/**\n * Tiptap Static Renderer\n * ----------------------\n *\n * This function is a basis to allow for different renderers to be created.\n * Generic enough to be able to statically render Prosemirror JSON or Prosemirror Nodes.\n *\n * Using this function, you can create a renderer that takes a JSON representation of a Prosemirror document\n * and renders it using a mapping of node types to React components or even to a string.\n * This function is used as the basis to create the `reactRenderer` and `stringRenderer` functions.\n */\nexport function TiptapStaticRenderer<\n  /**\n   * The return type of the render function (e.g. React.ReactNode, string)\n   */\n  TReturnType,\n  /**\n   * A mark type is either a JSON representation of a mark or a Prosemirror mark instance\n   */\n  TMarkType extends { type: string | { name: string } } = JSONMarkType,\n  /**\n   * A node type is either a JSON representation of a node or a Prosemirror node instance\n   */\n  TNodeType extends {\n    content?: { forEach: (cb: (node: TNodeType) => void) => void }\n    marks?: readonly TMarkType[]\n    type?: string | { name: string }\n  } = JSONNodeType<TMarkType>,\n  /**\n   * A node renderer is a function that takes a node and its children and returns the rendered output\n   */\n  TNodeRender extends (ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>) => TReturnType = (\n    ctx: NodeProps<TNodeType, TReturnType | TReturnType[]>,\n  ) => TReturnType,\n  /**\n   * A mark renderer is a function that takes a mark and its children and returns the rendered output\n   */\n  TMarkRender extends (\n    ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>,\n  ) => TReturnType = (\n    ctx: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>,\n  ) => TReturnType,\n>(\n  /**\n   * The function that actually renders the component\n   */\n  renderComponent: (\n    ctx:\n      | {\n          component: TNodeRender\n          props: NodeProps<TNodeType, TReturnType | TReturnType[]>\n        }\n      | {\n          component: TMarkRender\n          props: MarkProps<TMarkType, TReturnType | TReturnType[], TNodeType>\n        },\n  ) => TReturnType,\n  {\n    nodeMapping,\n    markMapping,\n    unhandledNode,\n    unhandledMark,\n  }: TiptapStaticRendererOptions<TReturnType, TMarkType, TNodeType, TNodeRender, TMarkRender>,\n) {\n  /**\n   * Render Tiptap JSON and all its children using the provided node and mark mappings.\n   */\n  return function renderContent({\n    content,\n    parent,\n  }: {\n    /**\n     * Tiptap JSON content to render\n     */\n    content: TNodeType\n    /**\n     * The parent node of the current node\n     */\n    parent?: TNodeType\n  }): TReturnType {\n    const nodeType = typeof content.type === 'string' ? content.type : (content.type?.name ?? '')\n    const NodeHandler = nodeMapping[nodeType] ?? unhandledNode\n\n    if (!NodeHandler) {\n      throw new Error(`missing handler for node type ${nodeType}`)\n    }\n\n    const nodeContent = renderComponent({\n      component: NodeHandler,\n      props: {\n        node: content,\n        parent,\n        renderElement: renderContent,\n        // Lazily compute the children to avoid unnecessary recursion\n        get children() {\n          // recursively render child content nodes\n          const children: TReturnType[] = []\n\n          if (content.content) {\n            content.content.forEach(child => {\n              children.push(\n                renderContent({\n                  content: child,\n                  parent: content,\n                }),\n              )\n            })\n          }\n\n          return children\n        },\n      },\n    })\n\n    // apply marks to the content\n    const markedContent = content.marks\n      ? content.marks.reduce((acc, mark) => {\n          const markType = typeof mark.type === 'string' ? mark.type : mark.type.name\n          const MarkHandler = markMapping[markType] ?? unhandledMark\n\n          if (!MarkHandler) {\n            throw new Error(`missing handler for mark type ${markType}`)\n          }\n\n          return renderComponent({\n            component: MarkHandler,\n            props: {\n              mark,\n              parent,\n              node: content,\n              children: acc,\n            },\n          })\n        }, nodeContent)\n      : nodeContent\n\n    return markedContent\n  }\n}\n","/* oslint-disableno-explicit-any */\nimport type { JSONMarkType, JSONNodeType, TiptapStaticRendererOptions } from '../renderer.js'\nimport { TiptapStaticRenderer } from '../renderer.js'\n\nexport function renderJSONContentToString<\n  /**\n   * A mark type is either a JSON representation of a mark or a Prosemirror mark instance\n   */\n  TMarkType extends { type: any } = JSONMarkType,\n  /**\n   * A node type is either a JSON representation of a node or a Prosemirror node instance\n   */\n  TNodeType extends {\n    content?: { forEach: (cb: (node: TNodeType) => void) => void }\n    marks?: readonly TMarkType[]\n    type?: string | { name: string }\n  } = JSONNodeType<TMarkType>,\n>(options: TiptapStaticRendererOptions<string, TMarkType, TNodeType>) {\n  return TiptapStaticRenderer(ctx => {\n    return ctx.component(ctx.props as any)\n  }, options)\n}\n\n/**\n * Escape text for HTML text content.\n * @param value The text to escape\n * @returns The escaped text\n */\nexport function escapeHTML(value: string): string {\n  return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')\n}\n\n/**\n * Escape values for quoted HTML attributes.\n * @param value The attribute value to escape\n * @returns The escaped attribute value\n */\nexport function escapeHTMLAttribute(value: string): string {\n  return escapeHTML(value).replace(/\"/g, '&quot;')\n}\n\n/**\n * Serialize the attributes of a node or mark to a string\n * @param attrs The attributes to serialize\n * @returns The serialized attributes as a string\n */\nexport function serializeAttrsToHTMLString(attrs: Record<string, any> | undefined | null): string {\n  // Match ProseMirror's DOMSerializer.renderSpec, which omits null/undefined attribute\n  // values rather than stringifying them — otherwise we emit attrs like class=\"null\".\n  const output = Object.entries(attrs || {})\n    .filter(([, value]) => value != null)\n    .map(([key, value]) => `${key.split(' ').at(-1)}=\"${escapeHTMLAttribute(String(value))}\"`)\n    .join(' ')\n\n  return output ? ` ${output}` : ''\n}\n\n/**\n * Serialize the children of a node or mark to a string\n * @param children The children to serialize\n * @returns The serialized children as a string\n */\nexport function serializeChildrenToHTMLString(children?: string | string[]): string {\n  return ([] as string[])\n    .concat(children || '')\n    .filter(Boolean)\n    .join('')\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC+IO,SAAS,qBAmCd,iBAWA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GACA;AAIA,SAAO,SAAS,cAAc;AAAA,IAC5B;AAAA,IACA;AAAA,EACF,GASgB;AAnNlB;AAoNI,UAAM,WAAW,OAAO,QAAQ,SAAS,WAAW,QAAQ,QAAQ,mBAAQ,SAAR,mBAAc,SAAd,YAAsB;AAC1F,UAAM,eAAc,iBAAY,QAAQ,MAApB,YAAyB;AAE7C,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI,MAAM,iCAAiC,QAAQ,EAAE;AAAA,IAC7D;AAEA,UAAM,cAAc,gBAAgB;AAAA,MAClC,WAAW;AAAA,MACX,OAAO;AAAA,QACL,MAAM;AAAA,QACN;AAAA,QACA,eAAe;AAAA;AAAA,QAEf,IAAI,WAAW;AAEb,gBAAM,WAA0B,CAAC;AAEjC,cAAI,QAAQ,SAAS;AACnB,oBAAQ,QAAQ,QAAQ,WAAS;AAC/B,uBAAS;AAAA,gBACP,cAAc;AAAA,kBACZ,SAAS;AAAA,kBACT,QAAQ;AAAA,gBACV,CAAC;AAAA,cACH;AAAA,YACF,CAAC;AAAA,UACH;AAEA,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,CAAC;AAGD,UAAM,gBAAgB,QAAQ,QAC1B,QAAQ,MAAM,OAAO,CAAC,KAAK,SAAS;AAxP5C,UAAAA;AAyPU,YAAM,WAAW,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,KAAK,KAAK;AACvE,YAAM,eAAcA,MAAA,YAAY,QAAQ,MAApB,OAAAA,MAAyB;AAE7C,UAAI,CAAC,aAAa;AAChB,cAAM,IAAI,MAAM,iCAAiC,QAAQ,EAAE;AAAA,MAC7D;AAEA,aAAO,gBAAgB;AAAA,QACrB,WAAW;AAAA,QACX,OAAO;AAAA,UACL;AAAA,UACA;AAAA,UACA,MAAM;AAAA,UACN,UAAU;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH,GAAG,WAAW,IACd;AAEJ,WAAO;AAAA,EACT;AACF;;;AC1QO,SAAS,0BAad,SAAoE;AACpE,SAAO,qBAAqB,SAAO;AACjC,WAAO,IAAI,UAAU,IAAI,KAAY;AAAA,EACvC,GAAG,OAAO;AACZ;AAOO,SAAS,WAAW,OAAuB;AAChD,SAAO,MAAM,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM;AAChF;AAOO,SAAS,oBAAoB,OAAuB;AACzD,SAAO,WAAW,KAAK,EAAE,QAAQ,MAAM,QAAQ;AACjD;AAOO,SAAS,2BAA2B,OAAuD;AAGhG,QAAM,SAAS,OAAO,QAAQ,SAAS,CAAC,CAAC,EACtC,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,SAAS,IAAI,EACnC,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,IAAI,MAAM,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK,oBAAoB,OAAO,KAAK,CAAC,CAAC,GAAG,EACxF,KAAK,GAAG;AAEX,SAAO,SAAS,IAAI,MAAM,KAAK;AACjC;AAOO,SAAS,8BAA8B,UAAsC;AAClF,SAAQ,CAAC,EACN,OAAO,YAAY,EAAE,EACrB,OAAO,OAAO,EACd,KAAK,EAAE;AACZ;","names":["_a"]}