diff --git a/packages/babel-generator/src/buffer.js b/packages/babel-generator/src/buffer.js index d7b24a2b65..5bb911bbfc 100644 --- a/packages/babel-generator/src/buffer.js +++ b/packages/babel-generator/src/buffer.js @@ -1,251 +1,99 @@ import Position from "./position"; -import repeat from "lodash/repeat"; +import type SourceMap from "./source-map"; import trimEnd from "lodash/trimEnd"; /** - * Buffer for collecting generated output. + * 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. */ export default class Buffer { - constructor(format: Object) { - this.printedCommentStarts = {}; - this.parenPushNewlineState = null; - this._position = new Position(); - this._indent = format.indent.base; - this.format = format; - this.buf = ""; - - // Maintaining a reference to the last char in the buffer is an optimization - // to make sure that v8 doesn't "flatten" the string more often than needed - // see https://github.com/babel/babel/pull/3283 for details. - this.last = ""; - - this.map = null; - this._sourcePosition = { - line: null, - column: null, - filename: null, - }; - this._endsWithWord = false; + constructor(map: ?SourceMap) { + this._map = map; } - printedCommentStarts: Object; - parenPushNewlineState: ?Object; - position: Position; - _indent: number; - format: Object; - buf: string; - last: string; + _map: SourceMap = null; + _buf: string = ""; + _last: string = ""; + _queue: Array = []; - _catchUp(){ - // catch up to this nodes newline if we're behind - if (this.format.retainLines && this._sourcePosition.line !== null) { - while (this.getCurrentLine() < this._sourcePosition.line) { - this.push("\n"); - } - } - } + _position: Position = new Position; + _sourcePosition: Object = { + line: null, + column: null, + filename: null, + }; /** - * Get the current trimmed buffer. + * Get the final string output from the buffer, along with the sourcemap if one exists. */ - get(): string { - return trimEnd(this.buf); - } - - /** - * Get the current indent. - */ - - getIndent(): string { - if (this.format.compact || this.format.concise) { - return ""; - } else { - return repeat(this.format.indent.style, this._indent); - } - } - - /** - * Get the current indent size. - */ - - indentSize(): number { - return this.getIndent().length; - } - - /** - * Increment indent size. - */ - - indent() { - this._indent++; - } - - /** - * Decrement indent size. - */ - - dedent() { - this._indent--; - } - - /** - * Add a semicolon to the buffer. - */ - - semicolon() { - this.token(";"); - } - - /** - * Add a right brace to the buffer. - */ - - rightBrace() { - if (!this.endsWith("\n")) this.newline(); - - if (this.format.minified && !this._lastPrintedIsEmptyStatement) { - this.removeLast(";"); - } - this.token("}"); - } - - /** - * Add a keyword to the buffer. - */ - - keyword(name: string) { - this.word(name); - this.space(); - } - - /** - * Add a space to the buffer unless it is compact. - */ - - space(force: boolean = false) { - if (this.format.compact) return; - - if ((this.buf && !this.endsWith(" ") && !this.endsWith("\n")) || force) { - this.push(" "); - } - } - - /** - * Writes a token that can't be safely parsed without taking whitespace into account. - */ - - word(str: string) { - if (this._endsWithWord) this.push(" "); - - this.push(str); - this._endsWithWord = true; - } - - /** - * Writes a simple token. - */ - - token(str: string) { - // space is mandatory to avoid outputting