Spaces:
Running
Running
| 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()) | |
| } | |