| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 | import { SourceMapGenerator } from 'source-map'import {  RawSourceMap,  VueTemplateCompiler,  VueTemplateCompilerParseOptions} from './types'const hash = require('hash-sum')const cache = new (require('lru-cache'))(100)const splitRE = /\r?\n/gconst emptyRE = /^(?:\/\/)?\s*$/export interface ParseOptions {  source: string  filename?: string  compiler: VueTemplateCompiler  compilerParseOptions?: VueTemplateCompilerParseOptions  sourceRoot?: string  needMap?: boolean}export interface SFCCustomBlock {  type: string  content: string  attrs: { [key: string]: string | true }  start: number  end: number  map?: RawSourceMap}export interface SFCBlock extends SFCCustomBlock {  lang?: string  src?: string  scoped?: boolean  module?: string | boolean}export interface SFCDescriptor {  template: SFCBlock | null  script: SFCBlock | null  styles: SFCBlock[]  customBlocks: SFCCustomBlock[]}export function parse(options: ParseOptions): SFCDescriptor {  const {    source,    filename = '',    compiler,    compilerParseOptions = { pad: 'line' } as VueTemplateCompilerParseOptions,    sourceRoot = '',    needMap = true  } = options  const cacheKey = hash(    filename + source + JSON.stringify(compilerParseOptions)  )  let output: SFCDescriptor = cache.get(cacheKey)  if (output) return output  output = compiler.parseComponent(source, compilerParseOptions)  if (needMap) {    if (output.script && !output.script.src) {      output.script.map = generateSourceMap(        filename,        source,        output.script.content,        sourceRoot,        compilerParseOptions.pad      )    }    if (output.styles) {      output.styles.forEach(style => {        if (!style.src) {          style.map = generateSourceMap(            filename,            source,            style.content,            sourceRoot,            compilerParseOptions.pad          )        }      })    }  }  cache.set(cacheKey, output)  return output}function generateSourceMap(  filename: string,  source: string,  generated: string,  sourceRoot: string,  pad?: 'line' | 'space'): RawSourceMap {  const map = new SourceMapGenerator({    file: filename.replace(/\\/g, '/'),    sourceRoot: sourceRoot.replace(/\\/g, '/')  })  let offset = 0  if (!pad) {    offset =      source        .split(generated)        .shift()!        .split(splitRE).length - 1  }  map.setSourceContent(filename, source)  generated.split(splitRE).forEach((line, index) => {    if (!emptyRE.test(line)) {      map.addMapping({        source: filename,        original: {          line: index + 1 + offset,          column: 0        },        generated: {          line: index + 1,          column: 0        }      })    }  })  return JSON.parse(map.toString())}
 |