blob: b8596900d503a6e0ca924e4b09238391343d0d06 [file] [log] [blame]
import { SourceMapGenerator } from 'source-map'
export class ScriptMap {
constructor (filename, content) {
this.filename = filename
this.content = content
const generator = new SourceMapGenerator()
generator.setSourceContent(filename, content)
this.generator = generator
this.history = []
this.elements = {}
this.enabled = false
}
enable () {
this.enabled = true
}
start () {
if (!this.enabled) { return }
this.current = { elements: [], scripts: [] }
}
end () {
if (!this.enabled) { return }
const current = this.current
this.current = {}
// re-order the elements and scripts into history
const length = current.elements.length
if (length > 0) {
const children = this.history.splice(-length, length)
current.children = children
}
current.elements.concat(current.scripts).forEach(item => {
current.name = item.name
delete item.name
})
current.elements.forEach((info, index) => {
current.children[index].length = info.length
current.children[index].line = info.line
})
delete current.elements
this.history.push(current)
}
addElement (name, index, line, length) {
if (!this.enabled) { return }
this.current.elements.push({ name, index, line, length })
}
addScript (name, info, externalOffset) {
if (!this.enabled) { return }
this.current.scripts.push({ name, info, externalOffset })
}
setElementPosition (name, line, column) {
if (!this.enabled) { return }
this.elements[name] = { line, column }
}
parse (target, startLine) {
if (!this.enabled) { return }
target = target || this.history[0]
if (!target) { return }
startLine = startLine || 0
const { name, line, scripts, children } = target
const elInfo = this.elements[name] || {};
(scripts || []).forEach(script => {
const { info, externalOffset } = script
const { original, generated } = info
const scriptLength = info.length
this.add(
original.line + (elInfo.line || 1) - 1,
scriptLength,
generated.line + startLine + (line || 1) - 1 + externalOffset
)
});
(children || []).forEach(child => {
this.parse(child, startLine + (line || 1) - 1)
})
this.json = true
}
add (originalLine, length, generatedLine) {
if (!this.enabled) { return }
const option = {
source: this.filename,
original: { line: originalLine, column: 1 },
generated: { line: generatedLine, column: 1 }
}
for (let i = 0; i < length; i++) {
option.original.line = originalLine + i
option.generated.line = generatedLine + i
this.generator.addMapping(option)
}
}
toJSON () {
return this.json ? this.generator.toJSON() : null
}
}