magic-string-stack
Version:
magic-string with the capability of committing changes
101 lines (98 loc) • 3.17 kB
JavaScript
import remapping from '@ampproject/remapping';
import MagicString, { SourceMap } from 'magic-string';
class MagicStringStack {
constructor(content, _options) {
this._options = _options;
this._current = new MagicString(content, this._options);
this._stack.unshift(this._current);
const proxy = new Proxy(new MagicString(""), {
get: (_, p, receiver) => {
if (Reflect.has(this, p))
return Reflect.get(this, p, receiver);
const parent = Reflect.get(this._current, p, receiver);
if (typeof parent === "function") {
return (...args) => {
const result = parent.apply(this._current, args);
if (result === this._current)
return proxy;
return result;
};
}
return parent;
},
set: (_, p, value) => {
if (Reflect.has(this, p))
return Reflect.set(this, p, value, this);
return Reflect.set(this._current, p, value);
}
});
return proxy;
}
/**
* The stack of MagicString instances.
* Lastest instance is pushed to the front of the array.
*/
_stack = [];
/**
* Prepresents the current MagicString instance.
* It should be in the this._stack[0]
*/
_current;
/**
* Commit current changes and reset the `.original` property and the indices.
*
* When running `generateMap`, the sourcemaps will be generated and merged into a single sourcemap.
*/
commit() {
const newOne = new MagicString(this._current.toString(), this._options);
newOne.offset = this._current.offset;
this._current = newOne;
this._stack.unshift(newOne);
return this;
}
/**
* Rollback to the previous commit.
*/
rollback() {
if (this._stack.length <= 1)
throw new Error("Cannot rollback on the first commit");
this._stack.shift();
this._current = this._stack[0];
return this;
}
get original() {
return this._current.original;
}
toString() {
return this._current.toString();
}
clone() {
const s = new MagicStringStack(this._current.toString(), this._options);
s._stack = this._stack.map((s2) => s2.clone());
s._current = s._stack[0];
return s;
}
/**
* Generates a version 3 sourcemap.
*/
generateMap(options) {
return new SourceMap(this.generateDecodedMap(options));
}
/**
* Generates a sourcemap object with raw mappings in array form, rather than encoded as a string.
* Useful if you need to manipulate the sourcemap further, but most of the time you will use `generateMap` instead.
*/
generateDecodedMap(options) {
if (this._stack.length === 1)
return this._current.generateDecodedMap(options);
const SOURCE_PLACEHOLDER = "__magic_string_placeholder__.js";
const maps = this._stack.map((s) => s.generateDecodedMap({ source: SOURCE_PLACEHOLDER, ...options }));
const merged = remapping(maps, () => null, { decodedMappings: true });
merged.sources = merged.sources.map((source) => source === SOURCE_PLACEHOLDER ? "" : source);
delete merged.version;
return {
...merged
};
}
}
export { MagicStringStack as default };