kpdecker 94e7e4da8e Update source map handling to be reentrant
Rather than repeating the original location when we exit a node, we need to restore the previous parent’s original line location, since the source map format denotes the start location.
2015-12-18 01:11:32 -06:00

83 lines
1.7 KiB
JavaScript

import sourceMap from "source-map";
import * as t from "babel-types";
/**
* Build a sourcemap.
*/
export default class SourceMap {
constructor(position, opts, code) {
this.position = position;
this.opts = opts;
this.last = {generated: {}, original: {}};
if (opts.sourceMaps) {
this.map = new sourceMap.SourceMapGenerator({
file: opts.sourceMapTarget,
sourceRoot: opts.sourceRoot
});
this.map.setSourceContent(opts.sourceFileName, code);
} else {
this.map = null;
}
}
/**
* Get the sourcemap.
*/
get() {
let map = this.map;
if (map) {
return map.toJSON();
} else {
return map;
}
}
/**
* Mark a node's generated position, and add it to the sourcemap.
*/
mark(node) {
let loc = node.loc;
if (!loc) return; // no location info
let map = this.map;
if (!map) return; // no source map
if (t.isProgram(node) || t.isFile(node)) return; // illegal mapping nodes
let position = this.position;
let generated = {
line: position.line,
column: position.column
};
let original = loc.start;
// Avoid emitting duplicates on either side. Duplicated
// original values creates unnecesssarily large source maps
// and increases compile time. Duplicates on the generated
// side can lead to incorrect mappings.
if (comparePosition(original, this.last.original)
|| comparePosition(generated, this.last.generated)) {
return;
}
this.last = {
source: this.opts.sourceFileName,
generated: generated,
original: original
};
map.addMapping(this.last);
}
}
function comparePosition(a, b) {
return a.line === b.line && a.column === b.column;
}