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/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' } 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())
- }
|