import { NodeTypes, ElementNode, SourceLocation, CompilerError, TextModes, BindingMetadata } from '@vue/compiler-core' import * as CompilerDOM from '@vue/compiler-dom' import { RawSourceMap, SourceMapGenerator } from 'source-map' import { TemplateCompiler } from './compileTemplate' import { Statement } from '@babel/types' import { parseCssVars } from './cssVars' export interface SFCParseOptions { filename?: string sourceMap?: boolean sourceRoot?: string pad?: boolean | 'line' | 'space' compiler?: TemplateCompiler } export interface SFCDescriptor { filename: string source: string template: SFCTemplateBlock | null script: SFCScriptBlock | null scriptSetup: SFCScriptBlock | null scriptCompiled: SFCScriptBlock | null styles: SFCStyleBlock[] customBlocks: SFCBlock[] cssVars: string[] } export interface SFCBlock { type: string content: string attrs: Record loc: SourceLocation map?: RawSourceMap lang?: string src?: string } export interface SFCTemplateBlock extends SFCBlock { type: 'template' functional?: boolean } export interface SFCScriptBlock extends SFCBlock { type: 'script' setup?: string | boolean bindings?: BindingMetadata scriptAst?: Statement[] scriptSetupAst?: Statement[] } export interface SFCStyleBlock extends SFCBlock { type: 'style' scoped?: boolean module?: string | boolean } export interface SFCParseResult { descriptor: SFCDescriptor errors: (CompilerError | SyntaxError)[] } const SFC_CACHE_MAX_SIZE = 500 const sourceToSFC = __GLOBAL__ || __ESM_BROWSER__ ? new Map() : (new (require('lru-cache'))(SFC_CACHE_MAX_SIZE) as Map< string, SFCParseResult >) export function parse( source: string, { sourceMap = true, filename = 'component.vue', sourceRoot = '', pad = false, compiler = CompilerDOM }: SFCParseOptions = {} ): SFCParseResult { const sourceKey = source + sourceMap + filename + sourceRoot + pad + compiler.parse const cache = sourceToSFC.get(sourceKey) if (cache) { return cache } const descriptor: SFCDescriptor = { filename, source, template: null, script: null, scriptSetup: null, scriptCompiled: null, styles: [], customBlocks: [], cssVars: [] } const errors: (CompilerError | SyntaxError)[] = [] const ast = compiler.parse(source, { // there are no components at SFC parsing level isNativeTag: () => true, // preserve all whitespaces isPreTag: () => true, getTextMode: ({ tag, props }, parent) => { // all top level elements except