{"version":3,"file":"static.cjs","names":[],"sources":["../src/static/style.ts","../src/static/attribute.ts","../src/utils/index.ts","../src/static/dynamic-resolvers.ts","../src/static/render-map.generated.ts","../src/static/util.ts","../src/static/richtext-renderer.ts"],"sourcesContent":["import type { AttrValue } from './types';\n\n/**\n * Converts a style object to a CSS string.\n * @param style - The style object to convert.\n * @returns A CSS string representation of the style object.\n * @example\n * const styleObj = { color: 'red', fontSize: '16px' };\n * const cssString = styleToString(styleObj);\n * console.log(cssString); // Output: \"color: red; font-size: 16px\"\n */\nexport function styleToString(style: Record<string, AttrValue>) {\n  return Object.entries(style)\n    .filter(([, v]) => isValidStyleValue(v))\n    .map(([k, v]) => `${camelToKebab(k)}: ${v}`)\n    .join('; ');\n}\n\n/**\n * Converts a CSS string to a style object.\n * @param style - The CSS string to convert.\n * @returns A style object representation of the CSS string.\n * @example\n * const cssString = \"color: red; font-size: 16px\";\n * const styleObj = stringToStyle(cssString);\n * console.log(styleObj); // Output: { color: 'red', fontSize: '16px' }\n */\nexport function stringToStyle(style: string): Record<string, string> {\n  return style\n    .split(';')\n    .map(rule => rule.trim())\n    .filter(Boolean)\n    .reduce<Record<string, string>>((acc, rule) => {\n      const colonIdx = rule.indexOf(':');\n\n      // ignore invalid declarations like \"color\" or \": red\"\n      if (colonIdx === -1) {\n        return acc;\n      }\n\n      const key = rule.slice(0, colonIdx).trim();\n      const value = rule.slice(colonIdx + 1).trim();\n\n      if (!key || !value) {\n        return acc;\n      }\n\n      acc[kebabToCamel(key)] = value;\n      return acc;\n    }, {});\n}\n\nfunction kebabToCamel(str: string) {\n  return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());\n}\nfunction camelToKebab(str: string) {\n  return str.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);\n}\nexport function isValidStyleValue(value: unknown) {\n  return value !== null && value !== undefined && value !== '';\n}\n","import { isValidStyleValue } from './style';\nimport type { AttrValue } from './types';\nimport type { TiptapComponentName } from './types.generated';\n\ntype StyleMap = Partial<{\n  [K in TiptapComponentName]: Record<string, string>;\n}>;\nexport type AttrMap = Record<string, string>;\n\nconst STYLE_MAP: StyleMap = {\n  highlight: {\n    color: 'backgroundColor',\n  },\n  textStyle: {\n    color: 'color',\n  },\n  paragraph: {\n    textAlign: 'textAlign',\n  },\n  heading: {\n    textAlign: 'textAlign',\n  },\n  tableCell: {\n    backgroundColor: 'backgroundColor',\n    colwidth: 'width',\n  },\n  tableHeader: {\n    colwidth: 'width',\n  },\n};\n\nconst DEFAULT_ATTR_MAP: AttrMap = {\n  fallbackImage: 'src',\n  meta_data: 'data-meta_data',\n  body: 'data-body',\n  colspan: 'colSpan',\n  rowspan: 'rowSpan',\n};\n\nexport const EXCLUDED_ATTRS = new Set(['level', 'linktype', 'uuid', 'custom', 'anchor']);\n\n/**\n * Process Tiptap attributes into HTML attributes and inline styles.\n * Applies internal style mappings and allows extending or overriding\n * default attribute mappings via `extendAttrMap`.\n *\n * @param type - {@link TiptapComponentName}\n * @param attrs - Attributes from the node/mark\n * @param extendAttrMap - {@link AttrMap} Additional attribute mappings (overrides defaults)\n * @returns Processed attributes with optional `style` object\n */\nexport function processAttrs(\n  type: TiptapComponentName,\n  attrs: Record<string, unknown> = {},\n  extendAttrMap: AttrMap = {},\n) {\n  const style: Record<string, AttrValue> = {};\n  const rest: Record<string, unknown> = {};\n\n  const styleMap = STYLE_MAP[type] || {};\n  const attrMap = { ...DEFAULT_ATTR_MAP, ...extendAttrMap }; // user overrides\n  for (const [key, value] of Object.entries(attrs)) {\n    if (!isValidStyleValue(value) || EXCLUDED_ATTRS.has(key)) {\n      continue;\n    }\n    // STYLE MAP\n    if (key in styleMap) {\n      const cssProp = styleMap[key]!;\n      if (Array.isArray(value)) {\n        const cssValue = value[0] != null ? `${value[0]}px` : undefined;\n        if (cssValue && isValidStyleValue(cssValue)) {\n          style[cssProp] = cssValue;\n        }\n      }\n      else {\n        const cssValue = typeof value === 'number' || typeof value === 'string'\n          ? value\n          : String(value);\n\n        style[cssProp] = cssValue;\n      }\n      continue;\n    }\n\n    // Resolve attribute name first\n    const attrName = attrMap[key] ?? key;\n\n    // stringify objects\n    if (typeof value === 'object' && value !== null) {\n      rest[attrName] = JSON.stringify(value);\n      continue;\n    }\n\n    // DEFAULT PASS THROUGH\n    rest[attrName] = value;\n  }\n  // Special handling for Storyblok links to add anchor to href\n  if (type === 'link' && attrs.linktype === 'story') {\n    rest.href = `${attrs.href ?? ''}#${attrs.anchor ?? ''}`;\n  }\n  return {\n    ...rest,\n    ...(Object.keys(style).length && { style }),\n  };\n}\nexport const escapeAttr = (value: unknown) =>\n  String(value).replace(/[&\"'<>]/g, (s) => {\n    switch (s) {\n      case '&': return '&amp;';\n      case '\"': return '&quot;';\n      case '\\'': return '&#39;';\n      case '<': return '&lt;';\n      case '>': return '&gt;';\n      default: return s;\n    }\n  });\n","import type { BlockAttributes, MarkNode, StoryblokRichTextNode, TextNode } from '../types';\n\n/**\n * Deep equality comparison for plain objects, arrays, and primitives.\n */\nexport function deepEqual(a: any, b: any): boolean {\n  if (a === b) {\n    return true;\n  }\n  if (a === null || a === undefined || b === null || b === undefined) {\n    return a === b;\n  }\n  if (typeof a !== typeof b) {\n    return false;\n  }\n  if (typeof a !== 'object') {\n    return false;\n  }\n  if (Array.isArray(a) !== Array.isArray(b)) {\n    return false;\n  }\n  if (Array.isArray(a)) {\n    if (a.length !== (b as any[]).length) {\n      return false;\n    }\n    return a.every((v: any, i: number) => deepEqual(v, (b as any[])[i]));\n  }\n  const aKeys = Object.keys(a);\n  const bKeys = Object.keys(b);\n  if (aKeys.length !== bKeys.length) {\n    return false;\n  }\n  return aKeys.every(k => Object.prototype.hasOwnProperty.call(b, k) && deepEqual(a[k], b[k]));\n}\n\n/** Checks if two marks are equal by comparing their type and attrs. */\nexport function markEquals<T>(a: MarkNode<T>, b: MarkNode<T>): boolean {\n  return a.type === b.type && deepEqual(a.attrs, b.attrs);\n}\n\n/** Type guard: checks if a node is a text node with at least one mark. */\nexport function isMarkedTextNode<T>(node: StoryblokRichTextNode<T>): node is TextNode<T> {\n  return node.type === 'text' && !!(node as TextNode<T>).marks?.length;\n}\n\n/** Returns marks unique to a node (not in the shared set), or undefined if all marks are shared. */\nexport function getUniqueMarks<T>(marks: MarkNode<T>[], shared: MarkNode<T>[]): MarkNode<T>[] | undefined {\n  const unique = marks.filter(m => !shared.some(s => markEquals(s, m)));\n  return unique.length ? unique : undefined;\n}\n\nexport interface MarkedTextGroup<T> {\n  group: TextNode<T>[];\n  shared: MarkNode<T>[];\n  endIndex: number;\n}\n\n/**\n * Starting at `fromIndex`, collects adjacent marked text nodes that share at least one common mark.\n * Returns null if the node at `fromIndex` is not a marked text node.\n */\nexport function collectMarkedTextGroup<T>(\n  children: StoryblokRichTextNode<T>[],\n  fromIndex: number,\n): MarkedTextGroup<T> | null {\n  const child = children[fromIndex];\n  if (!isMarkedTextNode(child)) {\n    return null;\n  }\n\n  const group: TextNode<T>[] = [child];\n  let shared: MarkNode<T>[] = child.marks!;\n  let j = fromIndex + 1;\n  while (j < children.length) {\n    const next = children[j];\n    if (!isMarkedTextNode(next)) {\n      break;\n    }\n    const nextShared = shared.filter(m =>\n      next.marks!.some(n => markEquals(m, n)),\n    );\n    if (nextShared.length === 0) {\n      break;\n    }\n    shared = nextShared;\n    group.push(next);\n    j++;\n  }\n\n  return { group, shared, endIndex: j };\n}\n\nexport const SELF_CLOSING_TAGS = [\n  'area',\n  'base',\n  'br',\n  'col',\n  'embed',\n  'hr',\n  'img',\n  'input',\n  'link',\n  'meta',\n  'param',\n  'source',\n  'track',\n  'wbr',\n];\n\nexport const BLOCK_LEVEL_TAGS = [\n  'address',\n  'article',\n  'aside',\n  'blockquote',\n  'canvas',\n  'dd',\n  'div',\n  'dl',\n  'dt',\n  'fieldset',\n  'figcaption',\n  'figure',\n  'footer',\n  'form',\n  'h1',\n  'h2',\n  'h3',\n  'h4',\n  'h5',\n  'h6',\n  'header',\n  'hgroup',\n  'hr',\n  'li',\n  'main',\n  'nav',\n  'noscript',\n  'ol',\n  'output',\n  'p',\n  'pre',\n  'section',\n  'table',\n  'tfoot',\n  'ul',\n  'video',\n];\n\n/**\n * Converts an object of attributes to a string.\n *\n * @param {Record<string, string>} [attrs]\n *\n * @returns {string} The string representation of the attributes.\n *\n * @example\n *\n * ```typescript\n * const attrs = {\n *  class: 'text-red',\n *  style: 'color: red',\n * }\n *\n * const attrsString = attrsToString(attrs)\n *\n * console.log(attrsString) // 'class=\"text-red\" style=\"color: red\"'\n *\n * ```\n *\n */\nexport const attrsToString = (attrs: BlockAttributes = {}) => {\n  const { custom, ...attrsWithoutCustom } = attrs;\n  const normalizedAttrs = { ...attrsWithoutCustom, ...custom };\n  return Object.keys(normalizedAttrs)\n    .filter(key => normalizedAttrs[key] != null)\n    .map(key => `${key}=\"${String(normalizedAttrs[key]).replace(/&/g, '&amp;').replace(/\"/g, '&quot;')}\"`)\n    .join(' ');\n};\n\n/**\n * Converts an object of attributes to a CSS style string.\n *\n * @param {Record<string, string>} [attrs]\n *\n * @returns {string} The string representation of the CSS styles.\n *\n * @example\n *\n * ```typescript\n * const attrs = {\n *  color: 'red',\n *  fontSize: '16px',\n * }\n *\n * const styleString = attrsToStyle(attrs)\n *\n * console.log(styleString) // 'color: red; font-size: 16px'\n * ```\n */\nexport const attrsToStyle = (attrs: Record<string, string> = {}) => Object.keys(attrs)\n  .map(key => `${key}: ${attrs[key]}`)\n  .join('; ');\n\n/**\n * Escapes HTML entities in a string.\n *\n * @param {string} unsafeText\n * @return {*}  {string}\n *\n * @example\n *\n * ```typescript\n * const unsafeText = '<script>alert(\"Hello\")</script>'\n *\n * const safeText = escapeHtml(unsafeText)\n *\n * console.log(safeText) // '&lt;script&gt;alert(\"Hello\")&lt;/script&gt;'\n * ```\n */\nexport function escapeHtml(unsafeText: string): string {\n  return unsafeText\n    .replace(/&/g, '&amp;')\n    .replace(/</g, '&lt;')\n    .replace(/>/g, '&gt;')\n    .replace(/\"/g, '&quot;')\n    .replace(/'/g, '&#039;');\n}\n\n/**\n * Removes undefined values from an object.\n *\n * @param {Record<string, any>} obj\n * @return {*}  {Record<string, any>}\n *\n * @example\n *\n * ```typescript\n * const obj = {\n * name: 'John',\n * age: undefined,\n * }\n *\n * const cleanedObj = cleanObject(obj)\n *\n * console.log(cleanedObj) // { name: 'John' }\n * ```\n *\n */\nexport const cleanObject = (obj: Record<string, any>) => {\n  return Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null));\n};\n","export const resolveHeadingTag = (attrs: { level?: number }): string => {\n  const level\n    = typeof attrs?.level === 'number'\n      ? Math.min(6, Math.max(1, attrs.level))\n      : 1;\n\n  return `h${level}`;\n};\n","// THIS FILE IS AUTO-GENERATED. DO NOT EDIT.\nimport { resolveHeadingTag } from './dynamic-resolvers';\n/**\n  * Render config for Tiptap nodes\n  */\n  export const NODE_RENDER_MAP = {\n  paragraph: {\n  \"tag\": \"p\",\n  \"content\": true\n},\n  doc: null,\n  text: null,\n  blockquote: {\n  \"tag\": \"blockquote\",\n  \"content\": true\n},\n  heading: {\n      resolve: resolveHeadingTag,\n      },\n  bullet_list: {\n  \"tag\": \"ul\",\n  \"content\": true\n},\n  ordered_list: {\n  \"tag\": \"ol\",\n  \"attrs\": {\n    \"start\": 1,\n    \"order\": 1\n  },\n  \"content\": true\n},\n  list_item: {\n  \"tag\": \"li\",\n  \"content\": true\n},\n  code_block: {\n  \"tag\": \"pre\",\n  \"children\": [\n    {\n      \"tag\": \"code\",\n      \"content\": true\n    }\n  ]\n},\n  hard_break: {\n  \"tag\": \"br\"\n},\n  horizontal_rule: {\n  \"tag\": \"hr\"\n},\n  image: {\n  \"tag\": \"img\"\n},\n  emoji: {\n  \"tag\": \"span\",\n  \"attrs\": {\n    \"data-type\": \"emoji\"\n  },\n  \"children\": [\n    {\n      \"tag\": \"img\",\n      \"attrs\": {\n        \"style\": \"width: 1.25em; height: 1.25em; vertical-align: text-top\",\n        \"draggable\": \"false\",\n        \"loading\": \"lazy\"\n      }\n    }\n  ]\n},\n  table: {\n  \"tag\": \"table\",\n  \"children\": [\n    {\n      \"tag\": \"tbody\",\n      \"content\": true\n    }\n  ]\n},\n  tableRow: {\n  \"tag\": \"tr\",\n  \"content\": true\n},\n  tableCell: {\n  \"tag\": \"td\",\n  \"content\": true\n},\n  tableHeader: {\n  \"tag\": \"th\",\n  \"content\": true\n},\n  blok: {\n  \"tag\": \"span\",\n  \"attrs\": {\n    \"style\": \"display: none\"\n  }\n},\n  details: {\n  \"tag\": \"details\",\n  \"content\": true\n},\n  detailsContent: {\n  \"tag\": \"div\",\n  \"attrs\": {\n    \"data-type\": \"detailsContent\"\n  },\n  \"content\": true\n},\n  detailsSummary: {\n  \"tag\": \"summary\",\n  \"content\": true\n},\n} as const;\n\n/**\n  * Render config for Tiptap marks\n  */\n  export const MARK_RENDER_MAP = {\n  link: {\n  \"tag\": \"a\",\n  \"content\": true\n},\n  bold: {\n  \"tag\": \"strong\",\n  \"content\": true\n},\n  italic: {\n  \"tag\": \"em\",\n  \"content\": true\n},\n  strike: {\n  \"tag\": \"s\",\n  \"content\": true\n},\n  underline: {\n  \"tag\": \"u\",\n  \"content\": true\n},\n  code: {\n  \"tag\": \"code\",\n  \"content\": true\n},\n  superscript: {\n  \"tag\": \"sup\",\n  \"content\": true\n},\n  subscript: {\n  \"tag\": \"sub\",\n  \"content\": true\n},\n  highlight: {\n  \"tag\": \"mark\",\n  \"content\": true\n},\n  textStyle: {\n  \"tag\": \"span\",\n  \"content\": true\n},\n  anchor: {\n  \"tag\": \"span\",\n  \"content\": true\n},\n  styled: {\n  \"tag\": \"span\",\n  \"content\": true\n},\n  reporter: null,\n} as const;\n\n","import { MARK_RENDER_MAP, NODE_RENDER_MAP } from './render-map.generated';\nimport type { PMMark, PMNode, TiptapComponentName } from './types.generated';\nimport { SELF_CLOSING_TAGS } from '../utils';\nimport type { HtmlTag, StoryblokRichTextComponentMap } from './types';\n\n/**\n * Resolves a component from the provided components map based on the type.\n * @param type - The type of the component to resolve.\n * @param components - The components map to search in.\n * @returns The resolved component or undefined if not found.\n * @example\n * const components = {\n *   'heading': MyCustomHeading,\n * };\n * const resolvedComponent = resolveComponent('heading', components);\n * console.log(resolvedComponent); // Output: MyCustomHeading\n */\nexport function resolveComponent<\n  K extends TiptapComponentName,\n  TComponent,\n  ExtraProps extends Record<string, unknown> = Record<string, unknown>,\n>(\n  type: K,\n  components?: StoryblokRichTextComponentMap<TComponent, ExtraProps>,\n): StoryblokRichTextComponentMap<TComponent, ExtraProps>[K] | undefined {\n  return components?.[type];\n}\n\n/**\n * Resolves the HTML tag for a given Richtext node or mark.\n * @param node - The Richtext node or mark to resolve the tag for.\n * @returns The resolved HTML tag as a string, or null if no tag could be resolved.\n * @example\n * const node = { type: 'paragraph', attrs: {} };\n * const tag = resolveTag(node);\n * console.log(tag); // Output: \"p\"\n */\nexport function resolveTag(node: PMNode | PMMark): HtmlTag | null {\n  const type = node.type;\n\n  const entry\n    = NODE_RENDER_MAP[type as keyof typeof NODE_RENDER_MAP]\n      ?? MARK_RENDER_MAP[type as keyof typeof MARK_RENDER_MAP];\n\n  if (!entry) {\n    return null;\n  }\n\n  if ('resolve' in entry && typeof entry.resolve === 'function') {\n    return entry.resolve(node.attrs as Parameters<typeof entry.resolve>[0]) as HtmlTag;\n  }\n\n  if ('tag' in entry && typeof entry.tag === 'string') {\n    return entry.tag as HtmlTag;\n  }\n\n  return null;\n}\n\n/**\n * Checks if a given HTML tag is self-closing.\n * @param tag - The HTML tag to check.\n * @returns True if the tag is self-closing, false otherwise.\n * @example\n * console.log(isSelfClosing('img')); // Output: true\n * console.log(isSelfClosing('div')); // Output: false\n *\n */\nexport function isSelfClosing(tag: HtmlTag | string): boolean {\n  return SELF_CLOSING_TAGS.includes(tag);\n}\n\n/**\n * Returns static child definitions for a given RichText node.\n *\n * @param node - The RichText node\n * @returns Static child render specs, or null if none exist\n *\n * @example\n * const children = getStaticChildren({ type: 'table', attrs: {} });\n * // [{ tag: 'tbody', content: true }]\n */\nexport function getStaticChildren(node: PMNode) {\n  const renderMap = NODE_RENDER_MAP[node.type as keyof typeof NODE_RENDER_MAP];\n  const staticChildren = renderMap && 'children' in renderMap ? renderMap.children : null;\n  return staticChildren;\n}\n","import { escapeHtml } from '../utils';\nimport { escapeAttr, processAttrs } from './attribute';\nimport { styleToString } from './style';\nimport type { RenderSpec, StoryblokRichTextJson } from './types';\nimport type { PMNode } from './types.generated';\nimport { getStaticChildren, isSelfClosing, resolveTag } from './util';\n\n/**\n * Renders a Storyblok RichText JSON document to an HTML string.\n *\n * This is a framework-agnostic static renderer that supports Storyblok\n * richtext nodes and marks, applies attributes and styles, and safely\n * escapes text content. `blok` nodes are not rendered and will log a warning.\n *\n * @param document - The Storyblok RichText JSON document to render\n * @returns The rendered HTML string\n *  @example\n * ```ts\n * const html = richTextRenderer({\n *   type: 'doc',\n *   content: [\n *     {\n *       type: 'paragraph',\n *       content: [\n *         { type: 'text', text: 'Hello World' }\n *       ]\n *     }\n *   ]\n * });\n *\n * console.log(html);\n * // <p>Hello World</p>\n * ```\n */\nexport function richTextRenderer(document: StoryblokRichTextJson): string {\n  if (!document) {\n    return '';\n  }\n\n  const nodes = document.type === 'doc' ? document.content : [document];\n\n  if (!nodes || nodes.length === 0) {\n    return '';\n  }\n\n  const parts: string[] = [];\n  for (const node of nodes) {\n    parts.push(renderNode(node));\n  }\n  return parts.join('');\n}\n\n/** Renders a single node to HTML. */\nfunction renderNode(node: StoryblokRichTextJson): string {\n  if (node.type === 'text') {\n    return renderText(node);\n  }\n  if (node.type === 'blok') {\n    console.warn('Rendering of \"blok\" nodes is not supported in richTextRenderer.');\n    return '';\n  }\n\n  const tag = resolveTag(node);\n  if (!tag) {\n    return '';\n  }\n\n  const selfClosing = isSelfClosing(tag);\n  const staticChildren = getStaticChildren(node);\n  const attrs = processAttrs(node.type, node.attrs);\n  const styleString = attrs.style ? styleToString(attrs.style) : '';\n  const htmlAttrs = attrsToString({\n    ...attrs,\n    ...(styleString && { style: styleString }),\n  });\n\n  if (selfClosing) {\n    return `<${tag}${htmlAttrs} />`;\n  }\n\n  // Render children content\n  const childContent = node.content\n    ? node.content.map(child => renderNode(child)).join('')\n    : '';\n\n  // Handle static children (e.g., code_block with pre > code structure)\n  // Static children are wrapped inside the parent tag\n  if (staticChildren) {\n    const innerContent = renderStaticChildren(\n      staticChildren,\n      attrs,\n      childContent,\n    );\n    return `<${tag}${htmlAttrs}>${innerContent}</${tag}>`;\n  }\n\n  return `<${tag}${htmlAttrs}>${childContent}</${tag}>`;\n}\n\n/** Renders static children structure (e.g., table > tbody, pre > code). */\nfunction renderStaticChildren(\n  staticChildren: readonly RenderSpec[],\n  attrs: Record<string, unknown>,\n  parentChildren: string = '',\n): string {\n  const parts: string[] = [];\n\n  for (const child of staticChildren) {\n    const tag = child.tag;\n    const selfClosing = isSelfClosing(tag);\n    const mergedAttrs = { ...child.attrs, ...attrs };\n    const htmlAttrs = attrsToString(mergedAttrs);\n\n    if (selfClosing) {\n      parts.push(`<${tag}${htmlAttrs} />`);\n      continue;\n    }\n\n    const children = child.children\n      ? renderStaticChildren(child.children, attrs, parentChildren)\n      : parentChildren;\n\n    parts.push(`<${tag}${htmlAttrs}>${children}</${tag}>`);\n  }\n\n  return parts.join('');\n}\n\n/** Renders a text node with its marks (bold, italic, etc.). */\nfunction renderText(node: PMNode & { type: 'text' }): string {\n  const marks = node.marks;\n  // Escape HTML entities in text content to prevent XSS\n  let result = escapeHtml(node.text);\n\n  if (!marks || marks.length === 0) {\n    return result;\n  }\n\n  // Apply marks in order (innermost first)\n  for (const mark of marks) {\n    const tag = resolveTag(mark);\n    if (!tag) {\n      continue;\n    }\n\n    const attrs = processAttrs(mark.type, mark.attrs);\n    const htmlAttrs = attrsToString(attrs);\n    result = `<${tag}${htmlAttrs}>${result}</${tag}>`;\n  }\n\n  return result;\n}\n\n/** Converts an attributes object to an HTML attribute string. */\nfunction attrsToString(attrs: Record<string, unknown>): string {\n  const entries = Object.entries(attrs).filter(([, v]) => v != null);\n\n  if (entries.length === 0) {\n    return '';\n  }\n  const attrParts: string[] = [];\n  for (const [key, value] of entries) {\n    attrParts.push(`${key}=\"${escapeAttr(value)}\"`);\n  }\n  return ` ${attrParts.join(' ')}`;\n}\n"],"mappings":"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"}