123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- "use strict";
- var Source = require("./Source");
- var SourceNode = require("source-map").SourceNode;
- class Replacement {
- constructor(start, end, content, insertIndex, name) {
- this.start = start;
- this.end = end;
- this.content = content;
- this.insertIndex = insertIndex;
- this.name = name;
- }
- }
- class ReplaceSource extends Source {
- constructor(source, name) {
- super();
- this._source = source;
- this._name = name;
-
- this.replacements = [];
- }
- replace(start, end, newValue, name) {
- if(typeof newValue !== "string")
- throw new Error("insertion must be a string, but is a " + typeof newValue);
- this.replacements.push(new Replacement(start, end, newValue, this.replacements.length, name));
- }
- insert(pos, newValue, name) {
- if(typeof newValue !== "string")
- throw new Error("insertion must be a string, but is a " + typeof newValue + ": " + newValue);
- this.replacements.push(new Replacement(pos, pos - 1, newValue, this.replacements.length, name));
- }
- source(options) {
- return this._replaceString(this._source.source());
- }
- original() {
- return this._source;
- }
- _sortReplacements() {
- this.replacements.sort(function(a, b) {
- var diff = b.end - a.end;
- if(diff !== 0)
- return diff;
- diff = b.start - a.start;
- if(diff !== 0)
- return diff;
- return b.insertIndex - a.insertIndex;
- });
- }
- _replaceString(str) {
- if(typeof str !== "string")
- throw new Error("str must be a string, but is a " + typeof str + ": " + str);
- this._sortReplacements();
- var result = [str];
- this.replacements.forEach(function(repl) {
- var remSource = result.pop();
- var splitted1 = this._splitString(remSource, Math.floor(repl.end + 1));
- var splitted2 = this._splitString(splitted1[0], Math.floor(repl.start));
- result.push(splitted1[1], repl.content, splitted2[0]);
- }, this);
-
- let resultStr = "";
- for(let i = result.length - 1; i >= 0; --i) {
- resultStr += result[i];
- }
- return resultStr;
- }
- node(options) {
- var node = this._source.node(options);
- if(this.replacements.length === 0) {
- return node;
- }
- this._sortReplacements();
- var replace = new ReplacementEnumerator(this.replacements);
- var output = [];
- var position = 0;
- var sources = Object.create(null);
- var sourcesInLines = Object.create(null);
-
-
- var result = new SourceNode();
-
-
- node.walkSourceContents(function(sourceFile, sourceContent) {
- result.setSourceContent(sourceFile, sourceContent);
- sources["$" + sourceFile] = sourceContent;
- });
- var replaceInStringNode = this._replaceInStringNode.bind(this, output, replace, function getOriginalSource(mapping) {
- var key = "$" + mapping.source;
- var lines = sourcesInLines[key];
- if(!lines) {
- var source = sources[key];
- if(!source) return null;
- lines = source.split("\n").map(function(line) {
- return line + "\n";
- });
- sourcesInLines[key] = lines;
- }
-
- if(mapping.line > lines.length) return null;
- var line = lines[mapping.line - 1];
- return line.substr(mapping.column);
- });
- node.walk(function(chunk, mapping) {
- position = replaceInStringNode(chunk, position, mapping);
- });
-
-
- var remaining = replace.footer();
- if(remaining) {
- output.push(remaining);
- }
- result.add(output);
- return result;
- }
- listMap(options) {
- this._sortReplacements();
- var map = this._source.listMap(options);
- var currentIndex = 0;
- var replacements = this.replacements;
- var idxReplacement = replacements.length - 1;
- var removeChars = 0;
- map = map.mapGeneratedCode(function(str) {
- var newCurrentIndex = currentIndex + str.length;
- if(removeChars > str.length) {
- removeChars -= str.length;
- str = "";
- } else {
- if(removeChars > 0) {
- str = str.substr(removeChars);
- currentIndex += removeChars;
- removeChars = 0;
- }
- var finalStr = "";
- while(idxReplacement >= 0 && replacements[idxReplacement].start < newCurrentIndex) {
- var repl = replacements[idxReplacement];
- var start = Math.floor(repl.start);
- var end = Math.floor(repl.end + 1);
- var before = str.substr(0, Math.max(0, start - currentIndex));
- if(end <= newCurrentIndex) {
- var after = str.substr(Math.max(0, end - currentIndex));
- finalStr += before + repl.content;
- str = after;
- currentIndex = Math.max(currentIndex, end);
- } else {
- finalStr += before + repl.content;
- str = "";
- removeChars = end - newCurrentIndex;
- }
- idxReplacement--;
- }
- str = finalStr + str;
- }
- currentIndex = newCurrentIndex;
- return str;
- });
- var extraCode = "";
- while(idxReplacement >= 0) {
- extraCode += replacements[idxReplacement].content;
- idxReplacement--;
- }
- if(extraCode) {
- map.add(extraCode);
- }
- return map;
- }
- _splitString(str, position) {
- return position <= 0 ? ["", str] : [str.substr(0, position), str.substr(position)];
- }
- _replaceInStringNode(output, replace, getOriginalSource, node, position, mapping) {
- var original = undefined;
- do {
- var splitPosition = replace.position - position;
-
-
- if(splitPosition < 0) {
- splitPosition = 0;
- }
- if(splitPosition >= node.length || replace.done) {
- if(replace.emit) {
- var nodeEnd = new SourceNode(
- mapping.line,
- mapping.column,
- mapping.source,
- node,
- mapping.name
- );
- output.push(nodeEnd);
- }
- return position + node.length;
- }
- var originalColumn = mapping.column;
-
-
-
- var nodePart;
- if(splitPosition > 0) {
- nodePart = node.slice(0, splitPosition);
- if(original === undefined) {
- original = getOriginalSource(mapping);
- }
- if(original && original.length >= splitPosition && original.startsWith(nodePart)) {
- mapping.column += splitPosition;
- original = original.substr(splitPosition);
- }
- }
- var emit = replace.next();
- if(!emit) {
-
-
- if(splitPosition > 0) {
- var nodeStart = new SourceNode(
- mapping.line,
- originalColumn,
- mapping.source,
- nodePart,
- mapping.name
- );
- output.push(nodeStart);
- }
-
- if(replace.value) {
- output.push(new SourceNode(
- mapping.line,
- mapping.column,
- mapping.source,
- replace.value,
- mapping.name || replace.name
- ));
- }
- }
-
- node = node.substr(splitPosition);
- position += splitPosition;
- } while (true);
- }
- }
- class ReplacementEnumerator {
-
- constructor(replacements) {
- this.replacements = replacements || [];
- this.index = this.replacements.length;
- this.done = false;
- this.emit = false;
-
- this.next();
- }
- next() {
- if(this.done)
- return true;
- if(this.emit) {
-
- var repl = this.replacements[this.index];
- var end = Math.floor(repl.end + 1);
- this.position = end;
- this.value = repl.content;
- this.name = repl.name;
- } else {
-
- this.index--;
- if(this.index < 0) {
- this.done = true;
- } else {
- var nextRepl = this.replacements[this.index];
- var start = Math.floor(nextRepl.start);
- this.position = start;
- }
- }
- if(this.position < 0)
- this.position = 0;
- this.emit = !this.emit;
- return this.emit;
- }
- footer() {
- if(!this.done && !this.emit)
- this.next();
- if(this.done) {
- return [];
- } else {
- var resultStr = "";
- for(var i = this.index; i >= 0; i--) {
- var repl = this.replacements[i];
-
-
- resultStr += repl.content;
- }
- return resultStr;
- }
- }
- }
- require("./SourceAndMapMixin")(ReplaceSource.prototype);
- module.exports = ReplaceSource;
|