UNPKG

kitchensink

Version:

Dispatch's awesome components and style guide

193 lines (146 loc) 5.56 kB
"use strict"; exports.__esModule = true; var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _position = require("./position"); var _position2 = _interopRequireDefault(_position); var _trimEnd = require("lodash/trimEnd"); var _trimEnd2 = _interopRequireDefault(_trimEnd); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var SPACES_RE = /^[ \t]+$/; /** * The Buffer class exists to manage the queue of tokens being pushed onto the output string * in such a way that the final string buffer is treated as write-only until the final .get() * call. This allows V8 to optimize the output efficiently by not requiring it to store the * string in contiguous memory. */ var Buffer = function () { function Buffer(map) { (0, _classCallCheck3.default)(this, Buffer); this._map = null; this._buf = ""; this._last = ""; this._queue = []; this._position = new _position2.default(); this._sourcePosition = { line: null, column: null, filename: null }; this._map = map; } /** * Get the final string output from the buffer, along with the sourcemap if one exists. */ Buffer.prototype.get = function get() { this._flush(); return { code: (0, _trimEnd2.default)(this._buf), map: this._map ? this._map.get() : null }; }; /** * Add a string to the buffer that cannot be reverted. */ Buffer.prototype.append = function append(str) { this._flush(); this._append(str, this._sourcePosition.line, this._sourcePosition.column, this._sourcePosition.filename); }; /** * Add a string to the buffer than can be reverted. */ Buffer.prototype.queue = function queue(str) { this._queue.unshift([str, this._sourcePosition.line, this._sourcePosition.column, this._sourcePosition.filename]); }; Buffer.prototype._flush = function _flush() { var item = void 0; while (item = this._queue.pop()) { this._append.apply(this, item); } }; Buffer.prototype._append = function _append(str, line, column, filename) { // If there the line is ending, adding a new mapping marker is redundant if (this._map && str[0] !== "\n") this._map.mark(this._position, line, column, filename); this._buf += str; this._last = str[str.length - 1]; this._position.push(str); }; Buffer.prototype.removeTrailingSpaces = function removeTrailingSpaces() { while (this._queue.length > 0 && SPACES_RE.test(this._queue[0][0])) { this._queue.shift(); } }; Buffer.prototype.removeTrailingNewline = function removeTrailingNewline() { if (this._queue.length > 0 && this._queue[0][0] === "\n") this._queue.shift(); }; Buffer.prototype.removeLastSemicolon = function removeLastSemicolon() { if (this._queue.length > 0 && this._queue[0][0] === ";") this._queue.shift(); }; Buffer.prototype.endsWith = function endsWith(str) { var end = this._last + this._queue.reduce(function (acc, item) { return item[0] + acc; }, ""); if (str.length <= end.length) { return end.slice(-str.length) === str; } // We assume that everything being matched is at most a single token plus some whitespace, // which everything currently is, but otherwise we'd have to expand _last or check _buf. return false; }; Buffer.prototype.getLast = function getLast() { if (this._queue.length > 0) { var last = this._queue[0][0]; return last[last.length - 1]; } return this._last; }; Buffer.prototype.hasContent = function hasContent() { return this._queue.length > 0 || !!this._last; }; /** * Sets a given position as the current source location so generated code after this call * will be given this position in the sourcemap. */ Buffer.prototype.source = function source(prop, loc) { if (prop && !loc) return; var pos = loc ? loc[prop] : null; this._sourcePosition.line = pos ? pos.line : null; this._sourcePosition.column = pos ? pos.column : null; this._sourcePosition.filename = loc && loc.filename || null; }; /** * Call a callback with a specific source location and restore on completion. */ Buffer.prototype.withSource = function withSource(prop, loc, cb) { if (!this._map) return cb(); // Use the call stack to manage a stack of "source location" data. var originalLine = this._sourcePosition.line; var originalColumn = this._sourcePosition.column; var originalFilename = this._sourcePosition.filename; this.source(prop, loc); cb(); this._sourcePosition.line = originalLine; this._sourcePosition.column = originalColumn; this._sourcePosition.filename = originalFilename; }; Buffer.prototype.getCurrentColumn = function getCurrentColumn() { var extra = this._queue.reduce(function (acc, item) { return item[0] + acc; }, ""); var lastIndex = extra.lastIndexOf("\n"); return lastIndex === -1 ? this._position.column + extra.length : extra.length - 1 - lastIndex; }; Buffer.prototype.getCurrentLine = function getCurrentLine() { var extra = this._queue.reduce(function (acc, item) { return item[0] + acc; }, ""); var count = 0; for (var i = 0; i < extra.length; i++) { if (extra[i] === "\n") count++; } return this._position.line + count; }; return Buffer; }(); exports.default = Buffer; module.exports = exports["default"];