All files / lib parse.ts

92.31% Statements 24/26
55.56% Branches 10/18
100% Functions 4/4
96% Lines 24/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113            2x 2x 2x   2x 2x                                                                                   6x 6x 6x 6x 6x 6x 6x               6x 6x 4x 4x                   6x 6x                 4x       4x 4x 18x 10x                         4x    
import {
  RawSourceMap,
  VueTemplateCompiler,
  VueTemplateCompilerParseOptions
} from './types'
 
const hash = require('hash-sum')
const cache = require('lru-cache')(100)
const { SourceMapGenerator } = require('source-map')
 
const splitRE = /\r?\n/g
const 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' },
    sourceRoot = process.cwd(),
    needMap = true
  } = options
  const cacheKey = hash(filename + source)
  let output: SFCDescriptor = cache.get(cacheKey)
  Iif (output) return output
  output = compiler.parseComponent(source, compilerParseOptions)
  Eif (needMap) {
    Iif (output.script && !output.script.src) {
      output.script.map = generateSourceMap(
        filename,
        source,
        output.script.content,
        sourceRoot
      )
    }
    Eif (output.styles) {
      output.styles.forEach(style => {
        Eif (!style.src) {
          style.map = generateSourceMap(
            filename,
            source,
            style.content,
            sourceRoot
          )
        }
      })
    }
  }
  cache.set(cacheKey, output)
  return output
}
 
function generateSourceMap(
  filename: string,
  source: string,
  generated: string,
  sourceRoot: string
): RawSourceMap {
  const map = new SourceMapGenerator({
    file: filename,
    sourceRoot
  })
  map.setSourceContent(filename, source)
  generated.split(splitRE).forEach((line, index) => {
    if (!emptyRE.test(line)) {
      map.addMapping({
        source: filename,
        original: {
          line: index + 1,
          column: 0
        },
        generated: {
          line: index + 1,
          column: 0
        }
      })
    }
  })
  return map.toJSON()
}