{"version":3,"file":"index.cjs","sources":["../src/parse.ts"],"sourcesContent":["import type { ElementNode } from '@vue/compiler-core'\nimport { parse as fallback } from '@vue/compiler-dom'\nimport type {\n  CompilerError,\n  SFCBlock,\n  SFCParseOptions,\n  SFCScriptBlock,\n  SFCStyleBlock,\n  SFCTemplateBlock,\n} from '@vue/compiler-sfc'\nimport { first, last } from '@vuedx/shared'\nimport { NodeTypes } from '@vuedx/template-ast-types'\n\nexport interface SFCParseResult {\n  descriptor: SFCDescriptor\n  errors: Array<CompilerError | SyntaxError>\n}\n\nexport interface SFCDescriptor {\n  script: SFCScriptBlock | null\n  scriptSetup: SFCScriptBlock | null\n  template: SFCTemplateBlock | null\n  styles: SFCStyleBlock[]\n  customBlocks: SFCBlock[]\n}\n\nexport type Parser = Pick<Required<SFCParseOptions>['compiler'], 'parse'>\n\nlet isParsingBrokenTemplate = false\n\nexport function parse(\n  source: string,\n  compiler: Parser = {\n    parse: fallback,\n  },\n): SFCParseResult {\n  const descriptor: SFCDescriptor = {\n    script: null,\n    scriptSetup: null,\n    template: null,\n    styles: [],\n    customBlocks: [],\n  }\n  const errors: Array<CompilerError | SyntaxError> = []\n  const ast = compiler.parse(source, {\n    // there are no components at SFC parsing level\n    isNativeTag: () => true,\n    decodeEntities: (string) => string,\n    // preserve all whitespace\n    isPreTag: () => true,\n    getTextMode: ({ tag, props }, parent) => {\n      // all top level elements except <template> are parsed as raw text\n      // containers\n      if (\n        (parent == null && tag !== 'template') ||\n        // <template lang=\"xxx\"> should also be treated as raw text\n        (tag === 'template' &&\n          props.some(\n            (p) =>\n              p.type === NodeTypes.ATTRIBUTE &&\n              p.name === 'lang' &&\n              p.value != null &&\n              p.value.content.length > 0 &&\n              p.value.content !== 'html',\n          ))\n      ) {\n        return 2 /* RAWTEXT */\n      } else {\n        return 0 /* DATA */\n      }\n    },\n    onError: (e) => {\n      errors.push(e)\n    },\n  })\n\n  ast.children.forEach((node) => {\n    if (node.type !== 1 /* ELEMENT */) {\n      return\n    }\n\n    switch (node.tag) {\n      case 'template':\n        if (descriptor.template == null) {\n          descriptor.template = createBlock(node, source) as SFCTemplateBlock\n        } else {\n          errors.push(createDuplicateBlockError(node))\n        }\n        break\n      case 'script':\n        {\n          const scriptBlock = createBlock(node, source) as SFCScriptBlock\n          const isSetup = scriptBlock.attrs['setup'] != null\n          if (isSetup) {\n            if (descriptor.scriptSetup == null) {\n              descriptor.scriptSetup = scriptBlock\n            } else {\n              errors.push(createDuplicateBlockError(node, isSetup))\n            }\n          } else {\n            if (descriptor.script == null) {\n              descriptor.script = scriptBlock\n            } else {\n              errors.push(createDuplicateBlockError(node, isSetup))\n            }\n          }\n        }\n        break\n      case 'style':\n        {\n          const styleBlock = createBlock(node, source) as SFCStyleBlock\n          descriptor.styles.push(styleBlock)\n        }\n        break\n      default:\n        descriptor.customBlocks.push(createBlock(node, source))\n        break\n    }\n  })\n\n  if (descriptor.template != null && !isParsingBrokenTemplate) {\n    const start = descriptor.template.loc.start.offset\n    const end = source.lastIndexOf('</template')\n    if (end < descriptor.template.loc.end.offset) {\n      // There is an parsing error in the template.\n      const proxy =\n        source.slice(0, start) +\n        placeholder(source.slice(start, end)) +\n        source.slice(end)\n\n      isParsingBrokenTemplate = true\n      try {\n        const result = parse(proxy, compiler)\n\n        if (result.descriptor.template != null) {\n          result.descriptor.template.content = source.slice(start, end)\n          result.descriptor.template.loc.source = source.slice(start, end)\n        }\n\n        return result\n      } finally {\n        isParsingBrokenTemplate = false\n      }\n    }\n  }\n\n  if (descriptor.scriptSetup != null) {\n    if (descriptor.scriptSetup.src != null) {\n      errors.push(\n        new SyntaxError(\n          `<script setup> cannot use the \"src\" attribute because ` +\n            `its syntax will be ambiguous outside of the component.`,\n        ),\n      )\n      descriptor.scriptSetup = null\n    }\n    if (descriptor.script?.src != null) {\n      errors.push(\n        new SyntaxError(\n          `<script> cannot use the \"src\" attribute when <script setup> is ` +\n            `also present because they must be processed together.`,\n        ),\n      )\n      descriptor.script = null\n    }\n  }\n\n  return { descriptor, errors }\n}\nfunction createDuplicateBlockError(\n  node: ElementNode,\n  isScriptSetup = false,\n): CompilerError {\n  const err = new SyntaxError(\n    `Single file component can contain only one <${node.tag}${\n      isScriptSetup ? ` setup` : ``\n    }> element`,\n  ) as CompilerError\n  err.loc = node.loc\n  return err\n}\nfunction createBlock(node: ElementNode, source: string): SFCBlock {\n  const type = node.tag\n  let { start, end } = node.loc\n  let content = ''\n  if (node.children.length > 0) {\n    start = first(node.children).loc.start\n    end = last(node.children).loc.end\n    content = source.slice(start.offset, end.offset)\n  } else {\n    const offset = node.loc.source.indexOf(`</`)\n    if (offset > -1) {\n      start = {\n        line: start.line,\n        column: start.column + offset,\n        offset: start.offset + offset,\n      }\n    }\n    end = { ...start }\n  }\n  const loc = {\n    source: content,\n    start,\n    end,\n  }\n  const attrs: Record<string, string | true> = {}\n  const block: SFCBlock = {\n    type,\n    content,\n    loc,\n    attrs,\n  }\n  node.props.forEach((p) => {\n    if (p.type === NodeTypes.ATTRIBUTE) {\n      attrs[p.name] =\n        p.value != null && p.value.content.trim() !== ''\n          ? p.value.content\n          : true\n\n      if (p.name === 'lang') {\n        if (p.value != null) block.lang = p.value.content\n      } else if (p.name === 'src') {\n        if (p.value != null) block.src = p.value.content\n      } else if (type === 'style') {\n        if (p.name === 'scoped') {\n          ;(block as SFCStyleBlock).scoped = true\n        } else if (p.name === 'module') {\n          ;(block as SFCStyleBlock).module = attrs[p.name]\n        }\n      } else if (type === 'script' && p.name === 'setup') {\n        ;(block as SFCScriptBlock).setup = attrs['setup']\n      }\n    }\n  })\n  return block\n}\n\nfunction placeholder(content: string): string {\n  let output = ''\n  const nl = '\\n'.charCodeAt(0)\n  for (let i = 0; i < content.length; i++) {\n    output += content.charCodeAt(i) === nl ? '\\n' : ' '\n  }\n  return output\n}\n"],"names":["fallback","NodeTypes"],"mappings":"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"}