123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- /*jshint node:true */
- /*
- The MIT License (MIT)
- Copyright (c) 2007-2018 Einar Lielmanis, Liam Newman, and contributors.
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation files
- (the "Software"), to deal in the Software without restriction,
- including without limitation the rights to use, copy, modify, merge,
- publish, distribute, sublicense, and/or sell copies of the Software,
- and to permit persons to whom the Software is furnished to do so,
- subject to the following conditions:
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
- 'use strict';
- function OutputLine(parent) {
- this.__parent = parent;
- this.__character_count = 0;
- // use indent_count as a marker for this.__lines that have preserved indentation
- this.__indent_count = -1;
- this.__alignment_count = 0;
- this.__wrap_point_index = 0;
- this.__wrap_point_character_count = 0;
- this.__wrap_point_indent_count = -1;
- this.__wrap_point_alignment_count = 0;
- this.__items = [];
- }
- OutputLine.prototype.clone_empty = function() {
- var line = new OutputLine(this.__parent);
- line.set_indent(this.__indent_count, this.__alignment_count);
- return line;
- };
- OutputLine.prototype.item = function(index) {
- if (index < 0) {
- return this.__items[this.__items.length + index];
- } else {
- return this.__items[index];
- }
- };
- OutputLine.prototype.has_match = function(pattern) {
- for (var lastCheckedOutput = this.__items.length - 1; lastCheckedOutput >= 0; lastCheckedOutput--) {
- if (this.__items[lastCheckedOutput].match(pattern)) {
- return true;
- }
- }
- return false;
- };
- OutputLine.prototype.set_indent = function(indent, alignment) {
- if (this.is_empty()) {
- this.__indent_count = indent || 0;
- this.__alignment_count = alignment || 0;
- this.__character_count = this.__parent.get_indent_size(this.__indent_count, this.__alignment_count);
- }
- };
- OutputLine.prototype._set_wrap_point = function() {
- if (this.__parent.wrap_line_length) {
- this.__wrap_point_index = this.__items.length;
- this.__wrap_point_character_count = this.__character_count;
- this.__wrap_point_indent_count = this.__parent.next_line.__indent_count;
- this.__wrap_point_alignment_count = this.__parent.next_line.__alignment_count;
- }
- };
- OutputLine.prototype._should_wrap = function() {
- return this.__wrap_point_index &&
- this.__character_count > this.__parent.wrap_line_length &&
- this.__wrap_point_character_count > this.__parent.next_line.__character_count;
- };
- OutputLine.prototype._allow_wrap = function() {
- if (this._should_wrap()) {
- this.__parent.add_new_line();
- var next = this.__parent.current_line;
- next.set_indent(this.__wrap_point_indent_count, this.__wrap_point_alignment_count);
- next.__items = this.__items.slice(this.__wrap_point_index);
- this.__items = this.__items.slice(0, this.__wrap_point_index);
- next.__character_count += this.__character_count - this.__wrap_point_character_count;
- this.__character_count = this.__wrap_point_character_count;
- if (next.__items[0] === " ") {
- next.__items.splice(0, 1);
- next.__character_count -= 1;
- }
- return true;
- }
- return false;
- };
- OutputLine.prototype.is_empty = function() {
- return this.__items.length === 0;
- };
- OutputLine.prototype.last = function() {
- if (!this.is_empty()) {
- return this.__items[this.__items.length - 1];
- } else {
- return null;
- }
- };
- OutputLine.prototype.push = function(item) {
- this.__items.push(item);
- var last_newline_index = item.lastIndexOf('\n');
- if (last_newline_index !== -1) {
- this.__character_count = item.length - last_newline_index;
- } else {
- this.__character_count += item.length;
- }
- };
- OutputLine.prototype.pop = function() {
- var item = null;
- if (!this.is_empty()) {
- item = this.__items.pop();
- this.__character_count -= item.length;
- }
- return item;
- };
- OutputLine.prototype._remove_indent = function() {
- if (this.__indent_count > 0) {
- this.__indent_count -= 1;
- this.__character_count -= this.__parent.indent_size;
- }
- };
- OutputLine.prototype._remove_wrap_indent = function() {
- if (this.__wrap_point_indent_count > 0) {
- this.__wrap_point_indent_count -= 1;
- }
- };
- OutputLine.prototype.trim = function() {
- while (this.last() === ' ') {
- this.__items.pop();
- this.__character_count -= 1;
- }
- };
- OutputLine.prototype.toString = function() {
- var result = '';
- if (this.is_empty()) {
- if (this.__parent.indent_empty_lines) {
- result = this.__parent.get_indent_string(this.__indent_count);
- }
- } else {
- result = this.__parent.get_indent_string(this.__indent_count, this.__alignment_count);
- result += this.__items.join('');
- }
- return result;
- };
- function IndentStringCache(options, baseIndentString) {
- this.__cache = [''];
- this.__indent_size = options.indent_size;
- this.__indent_string = options.indent_char;
- if (!options.indent_with_tabs) {
- this.__indent_string = new Array(options.indent_size + 1).join(options.indent_char);
- }
- // Set to null to continue support for auto detection of base indent
- baseIndentString = baseIndentString || '';
- if (options.indent_level > 0) {
- baseIndentString = new Array(options.indent_level + 1).join(this.__indent_string);
- }
- this.__base_string = baseIndentString;
- this.__base_string_length = baseIndentString.length;
- }
- IndentStringCache.prototype.get_indent_size = function(indent, column) {
- var result = this.__base_string_length;
- column = column || 0;
- if (indent < 0) {
- result = 0;
- }
- result += indent * this.__indent_size;
- result += column;
- return result;
- };
- IndentStringCache.prototype.get_indent_string = function(indent_level, column) {
- var result = this.__base_string;
- column = column || 0;
- if (indent_level < 0) {
- indent_level = 0;
- result = '';
- }
- column += indent_level * this.__indent_size;
- this.__ensure_cache(column);
- result += this.__cache[column];
- return result;
- };
- IndentStringCache.prototype.__ensure_cache = function(column) {
- while (column >= this.__cache.length) {
- this.__add_column();
- }
- };
- IndentStringCache.prototype.__add_column = function() {
- var column = this.__cache.length;
- var indent = 0;
- var result = '';
- if (this.__indent_size && column >= this.__indent_size) {
- indent = Math.floor(column / this.__indent_size);
- column -= indent * this.__indent_size;
- result = new Array(indent + 1).join(this.__indent_string);
- }
- if (column) {
- result += new Array(column + 1).join(' ');
- }
- this.__cache.push(result);
- };
- function Output(options, baseIndentString) {
- this.__indent_cache = new IndentStringCache(options, baseIndentString);
- this.raw = false;
- this._end_with_newline = options.end_with_newline;
- this.indent_size = options.indent_size;
- this.wrap_line_length = options.wrap_line_length;
- this.indent_empty_lines = options.indent_empty_lines;
- this.__lines = [];
- this.previous_line = null;
- this.current_line = null;
- this.next_line = new OutputLine(this);
- this.space_before_token = false;
- this.non_breaking_space = false;
- this.previous_token_wrapped = false;
- // initialize
- this.__add_outputline();
- }
- Output.prototype.__add_outputline = function() {
- this.previous_line = this.current_line;
- this.current_line = this.next_line.clone_empty();
- this.__lines.push(this.current_line);
- };
- Output.prototype.get_line_number = function() {
- return this.__lines.length;
- };
- Output.prototype.get_indent_string = function(indent, column) {
- return this.__indent_cache.get_indent_string(indent, column);
- };
- Output.prototype.get_indent_size = function(indent, column) {
- return this.__indent_cache.get_indent_size(indent, column);
- };
- Output.prototype.is_empty = function() {
- return !this.previous_line && this.current_line.is_empty();
- };
- Output.prototype.add_new_line = function(force_newline) {
- // never newline at the start of file
- // otherwise, newline only if we didn't just add one or we're forced
- if (this.is_empty() ||
- (!force_newline && this.just_added_newline())) {
- return false;
- }
- // if raw output is enabled, don't print additional newlines,
- // but still return True as though you had
- if (!this.raw) {
- this.__add_outputline();
- }
- return true;
- };
- Output.prototype.get_code = function(eol) {
- this.trim(true);
- // handle some edge cases where the last tokens
- // has text that ends with newline(s)
- var last_item = this.current_line.pop();
- if (last_item) {
- if (last_item[last_item.length - 1] === '\n') {
- last_item = last_item.replace(/\n+$/g, '');
- }
- this.current_line.push(last_item);
- }
- if (this._end_with_newline) {
- this.__add_outputline();
- }
- var sweet_code = this.__lines.join('\n');
- if (eol !== '\n') {
- sweet_code = sweet_code.replace(/[\n]/g, eol);
- }
- return sweet_code;
- };
- Output.prototype.set_wrap_point = function() {
- this.current_line._set_wrap_point();
- };
- Output.prototype.set_indent = function(indent, alignment) {
- indent = indent || 0;
- alignment = alignment || 0;
- // Next line stores alignment values
- this.next_line.set_indent(indent, alignment);
- // Never indent your first output indent at the start of the file
- if (this.__lines.length > 1) {
- this.current_line.set_indent(indent, alignment);
- return true;
- }
- this.current_line.set_indent();
- return false;
- };
- Output.prototype.add_raw_token = function(token) {
- for (var x = 0; x < token.newlines; x++) {
- this.__add_outputline();
- }
- this.current_line.set_indent(-1);
- this.current_line.push(token.whitespace_before);
- this.current_line.push(token.text);
- this.space_before_token = false;
- this.non_breaking_space = false;
- this.previous_token_wrapped = false;
- };
- Output.prototype.add_token = function(printable_token) {
- this.__add_space_before_token();
- this.current_line.push(printable_token);
- this.space_before_token = false;
- this.non_breaking_space = false;
- this.previous_token_wrapped = this.current_line._allow_wrap();
- };
- Output.prototype.__add_space_before_token = function() {
- if (this.space_before_token && !this.just_added_newline()) {
- if (!this.non_breaking_space) {
- this.set_wrap_point();
- }
- this.current_line.push(' ');
- }
- };
- Output.prototype.remove_indent = function(index) {
- var output_length = this.__lines.length;
- while (index < output_length) {
- this.__lines[index]._remove_indent();
- index++;
- }
- this.current_line._remove_wrap_indent();
- };
- Output.prototype.trim = function(eat_newlines) {
- eat_newlines = (eat_newlines === undefined) ? false : eat_newlines;
- this.current_line.trim();
- while (eat_newlines && this.__lines.length > 1 &&
- this.current_line.is_empty()) {
- this.__lines.pop();
- this.current_line = this.__lines[this.__lines.length - 1];
- this.current_line.trim();
- }
- this.previous_line = this.__lines.length > 1 ?
- this.__lines[this.__lines.length - 2] : null;
- };
- Output.prototype.just_added_newline = function() {
- return this.current_line.is_empty();
- };
- Output.prototype.just_added_blankline = function() {
- return this.is_empty() ||
- (this.current_line.is_empty() && this.previous_line.is_empty());
- };
- Output.prototype.ensure_empty_line_above = function(starts_with, ends_with) {
- var index = this.__lines.length - 2;
- while (index >= 0) {
- var potentialEmptyLine = this.__lines[index];
- if (potentialEmptyLine.is_empty()) {
- break;
- } else if (potentialEmptyLine.item(0).indexOf(starts_with) !== 0 &&
- potentialEmptyLine.item(-1) !== ends_with) {
- this.__lines.splice(index + 1, 0, new OutputLine(this));
- this.previous_line = this.__lines[this.__lines.length - 2];
- break;
- }
- index--;
- }
- };
- module.exports.Output = Output;
|