{"version":3,"file":"wrapTokenFragments.js","names":["NO_TOKEN: unique symbol","MULTIPLE_TOKENS: unique symbol","containerTokenState: TokenFragmentState","wrappedChildren: ElementContent[]","currentTokenChildren: ElementContent[]","currentTokenChar: number | undefined","childTokenState: TokenFragmentState"],"sources":["../../src/utils/wrapTokenFragments.ts"],"sourcesContent":["import type { ElementContent, Element as HASTElement } from 'hast';\n\nimport { createHastElement } from './hast_utils';\n\nconst NO_TOKEN: unique symbol = Symbol('no-token');\nconst MULTIPLE_TOKENS: unique symbol = Symbol('multiple-tokens');\n\ntype TokenFragmentState = number | typeof NO_TOKEN | typeof MULTIPLE_TOKENS;\n\n// Walk a rendered line and add a single outer token wrapper around all\n// fragments that still belong to the same original Shiki token.\nexport function wrapTokenFragments(container: HASTElement): TokenFragmentState {\n  const ownTokenChar = getTokenChar(container);\n  if (ownTokenChar != null) {\n    return ownTokenChar;\n  }\n\n  let containerTokenState: TokenFragmentState = NO_TOKEN;\n  const wrappedChildren: ElementContent[] = [];\n  let currentTokenChildren: ElementContent[] = [];\n  let currentTokenChar: number | undefined;\n\n  const flushTokenChildren = () => {\n    if (currentTokenChildren.length === 0 || currentTokenChar == null) {\n      currentTokenChildren = [];\n      currentTokenChar = undefined;\n      return;\n    }\n\n    if (currentTokenChildren.length === 1) {\n      const child = currentTokenChildren[0];\n      if (child?.type === 'element') {\n        setTokenChar(child, currentTokenChar);\n        for (const grandChild of child.children) {\n          stripTokenChar(grandChild);\n        }\n      } else {\n        stripTokenChar(child);\n      }\n      wrappedChildren.push(child);\n      currentTokenChildren = [];\n      currentTokenChar = undefined;\n      return;\n    }\n\n    for (const child of currentTokenChildren) {\n      stripTokenChar(child);\n    }\n\n    wrappedChildren.push(\n      createHastElement({\n        tagName: 'span',\n        properties: { 'data-char': currentTokenChar },\n        children: currentTokenChildren,\n      })\n    );\n\n    currentTokenChildren = [];\n    currentTokenChar = undefined;\n  };\n\n  const mergeContainerTokenState = (childTokenState: TokenFragmentState) => {\n    if (childTokenState === NO_TOKEN) {\n      return;\n    }\n    if (childTokenState === MULTIPLE_TOKENS) {\n      containerTokenState = MULTIPLE_TOKENS;\n      return;\n    }\n    if (containerTokenState === NO_TOKEN) {\n      containerTokenState = childTokenState;\n      return;\n    }\n    if (containerTokenState !== childTokenState) {\n      containerTokenState = MULTIPLE_TOKENS;\n    }\n  };\n\n  for (const child of container.children) {\n    const childTokenState: TokenFragmentState =\n      child.type === 'element' ? wrapTokenFragments(child) : NO_TOKEN;\n    mergeContainerTokenState(childTokenState);\n\n    if (typeof childTokenState !== 'number') {\n      flushTokenChildren();\n      wrappedChildren.push(child);\n      continue;\n    }\n\n    if (currentTokenChar != null && currentTokenChar !== childTokenState) {\n      flushTokenChildren();\n    }\n\n    currentTokenChar ??= childTokenState;\n    currentTokenChildren.push(child);\n  }\n\n  flushTokenChildren();\n  container.children = wrappedChildren;\n  return containerTokenState;\n}\n\nfunction getTokenChar(node: HASTElement): number | undefined {\n  const value = node.properties['data-char'];\n  if (typeof value === 'number') {\n    return value;\n  }\n  return undefined;\n}\n\nfunction stripTokenChar(node: ElementContent): void {\n  if (node.type !== 'element') return;\n  node.properties['data-char'] = undefined;\n  for (const child of node.children) {\n    stripTokenChar(child);\n  }\n}\n\nfunction setTokenChar(node: HASTElement, char: number): void {\n  node.properties['data-char'] = char;\n}\n"],"mappings":";;;AAIA,MAAMA,WAA0B,OAAO,WAAW;AAClD,MAAMC,kBAAiC,OAAO,kBAAkB;AAMhE,SAAgB,mBAAmB,WAA4C;CAC7E,MAAM,eAAe,aAAa,UAAU;AAC5C,KAAI,gBAAgB,KAClB,QAAO;CAGT,IAAIC,sBAA0C;CAC9C,MAAMC,kBAAoC,EAAE;CAC5C,IAAIC,uBAAyC,EAAE;CAC/C,IAAIC;CAEJ,MAAM,2BAA2B;AAC/B,MAAI,qBAAqB,WAAW,KAAK,oBAAoB,MAAM;AACjE,0BAAuB,EAAE;AACzB,sBAAmB;AACnB;;AAGF,MAAI,qBAAqB,WAAW,GAAG;GACrC,MAAM,QAAQ,qBAAqB;AACnC,OAAI,OAAO,SAAS,WAAW;AAC7B,iBAAa,OAAO,iBAAiB;AACrC,SAAK,MAAM,cAAc,MAAM,SAC7B,gBAAe,WAAW;SAG5B,gBAAe,MAAM;AAEvB,mBAAgB,KAAK,MAAM;AAC3B,0BAAuB,EAAE;AACzB,sBAAmB;AACnB;;AAGF,OAAK,MAAM,SAAS,qBAClB,gBAAe,MAAM;AAGvB,kBAAgB,KACd,kBAAkB;GAChB,SAAS;GACT,YAAY,EAAE,aAAa,kBAAkB;GAC7C,UAAU;GACX,CAAC,CACH;AAED,yBAAuB,EAAE;AACzB,qBAAmB;;CAGrB,MAAM,4BAA4B,oBAAwC;AACxE,MAAI,oBAAoB,SACtB;AAEF,MAAI,oBAAoB,iBAAiB;AACvC,yBAAsB;AACtB;;AAEF,MAAI,wBAAwB,UAAU;AACpC,yBAAsB;AACtB;;AAEF,MAAI,wBAAwB,gBAC1B,uBAAsB;;AAI1B,MAAK,MAAM,SAAS,UAAU,UAAU;EACtC,MAAMC,kBACJ,MAAM,SAAS,YAAY,mBAAmB,MAAM,GAAG;AACzD,2BAAyB,gBAAgB;AAEzC,MAAI,OAAO,oBAAoB,UAAU;AACvC,uBAAoB;AACpB,mBAAgB,KAAK,MAAM;AAC3B;;AAGF,MAAI,oBAAoB,QAAQ,qBAAqB,gBACnD,qBAAoB;AAGtB,uBAAqB;AACrB,uBAAqB,KAAK,MAAM;;AAGlC,qBAAoB;AACpB,WAAU,WAAW;AACrB,QAAO;;AAGT,SAAS,aAAa,MAAuC;CAC3D,MAAM,QAAQ,KAAK,WAAW;AAC9B,KAAI,OAAO,UAAU,SACnB,QAAO;;AAKX,SAAS,eAAe,MAA4B;AAClD,KAAI,KAAK,SAAS,UAAW;AAC7B,MAAK,WAAW,eAAe;AAC/B,MAAK,MAAM,SAAS,KAAK,SACvB,gBAAe,MAAM;;AAIzB,SAAS,aAAa,MAAmB,MAAoB;AAC3D,MAAK,WAAW,eAAe"}