Add core Options class

This commit is contained in:
Liam Newman 2018-08-24 13:35:15 -07:00
parent d210b6381e
commit 81d3177bff
21 changed files with 1033 additions and 571 deletions

View File

@ -28,13 +28,110 @@
'use strict'; 'use strict';
function Options(options, merge_child_field) {
options = _mergeOpts(options, merge_child_field);
this.raw_options = _normalizeOpts(options);
// Support passing the source text back with no change
this.disabled = this._get_boolean('disabled');
this.eol = this._get_characters('eol', 'auto');
this.end_with_newline = this._get_boolean('end_with_newline');
this.indent_size = this._get_number('indent_size', 4);
this.indent_char = this._get_characters('indent_char', ' ');
this.preserve_newlines = this._get_boolean('preserve_newlines', true);
this.max_preserve_newlines = this.max_preserve_newlines = this._get_number('max_preserve_newlines', 32786);
if (!this.preserve_newlines) {
this.max_preserve_newlines = 0;
}
this.indent_with_tabs = this._get_boolean('indent_with_tabs');
if (this.indent_with_tabs) {
this.indent_char = '\t';
this.indent_size = 1;
}
this.indent_string = this.indent_char;
if (this.indent_size > 1) {
this.indent_string = new Array(this.indent_size + 1).join(this.indent_char);
}
// Backwards compat with 1.3.x
this.wrap_line_length = this._get_number('wrap_line_length', this._get_number('max_char'));
}
Options.prototype._get_array = function(name, default_value) {
var option_value = this.raw_options[name];
var result = default_value || [];
if (typeof option_value === 'object') {
if (option_value !== null && typeof option_value.concat === 'function') {
result = option_value.concat();
}
} else if (typeof option_value === 'string') {
result = option_value.split(/[^a-zA-Z0-9_\/\-]+/);
}
return result;
};
Options.prototype._get_boolean = function(name, default_value) {
var option_value = this.raw_options[name];
var result = option_value === undefined ? !!default_value : !!option_value;
return result;
};
Options.prototype._get_characters = function(name, default_value) {
var option_value = this.raw_options[name];
var result = default_value || '';
if (typeof option_value === 'string') {
result = option_value.replace(/\\r/, '\r').replace(/\\n/, '\n').replace(/\\t/, '\t');
}
return result;
};
Options.prototype._get_number = function(name, default_value) {
var option_value = this.raw_options[name];
default_value = parseInt(default_value, 10);
if (isNaN(default_value)) {
default_value = 0;
}
var result = parseInt(option_value, 10);
if (isNaN(result)) {
result = default_value;
}
return result;
};
Options.prototype._get_selection = function(name, selection_list, default_value) {
default_value = default_value || [selection_list[0]];
if (!this._is_valid_selection(default_value, selection_list)) {
throw new Error("Invalid Default Value!");
}
var result = this._get_array(name, default_value);
if (!this._is_valid_selection(result, selection_list)) {
throw new Error(
"Invalid Option Value: The option '" + name + "' must be one of the following values\n" + selection_list + "\nYou passed in: '" + this.raw_options[name] + "'");
}
return result;
};
Options.prototype._is_valid_selection = function(result, selection_list) {
return result.length && selection_list.length &&
!result.some(function(item) { return selection_list.indexOf(item) === -1; });
};
// merges child options up with the parent options object // merges child options up with the parent options object
// Example: obj = {a: 1, b: {a: 2}} // Example: obj = {a: 1, b: {a: 2}}
// mergeOpts(obj, 'b') // mergeOpts(obj, 'b')
// //
// Returns: {a: 2, b: {a: 2}} // Returns: {a: 2, b: {a: 2}}
function mergeOpts(allOptions, childFieldName) { function _mergeOpts(allOptions, childFieldName) {
var finalOpts = {}; var finalOpts = {};
allOptions = allOptions || {};
var name; var name;
for (name in allOptions) { for (name in allOptions) {
@ -44,7 +141,7 @@ function mergeOpts(allOptions, childFieldName) {
} }
//merge in the per type settings for the childFieldName //merge in the per type settings for the childFieldName
if (childFieldName in allOptions) { if (childFieldName && allOptions[childFieldName]) {
for (name in allOptions[childFieldName]) { for (name in allOptions[childFieldName]) {
finalOpts[name] = allOptions[childFieldName][name]; finalOpts[name] = allOptions[childFieldName][name];
} }
@ -52,7 +149,7 @@ function mergeOpts(allOptions, childFieldName) {
return finalOpts; return finalOpts;
} }
function normalizeOpts(options) { function _normalizeOpts(options) {
var convertedOpts = {}; var convertedOpts = {};
var key; var key;
@ -63,5 +160,6 @@ function normalizeOpts(options) {
return convertedOpts; return convertedOpts;
} }
module.exports.mergeOpts = mergeOpts; module.exports.Options = Options;
module.exports.normalizeOpts = normalizeOpts; module.exports.normalizeOpts = _normalizeOpts;
module.exports.mergeOpts = _mergeOpts;

View File

@ -28,8 +28,7 @@
'use strict'; 'use strict';
var mergeOpts = require('../core/options').mergeOpts; var Options = require('./options').Options;
var normalizeOpts = require('../core/options').normalizeOpts;
var acorn = require('../core/acorn'); var acorn = require('../core/acorn');
var Output = require('../core/output').Output; var Output = require('../core/output').Output;
var InputScanner = require('../core/inputscanner').InputScanner; var InputScanner = require('../core/inputscanner').InputScanner;
@ -39,33 +38,9 @@ var allLineBreaks = acorn.allLineBreaks;
function Beautifier(source_text, options) { function Beautifier(source_text, options) {
this._source_text = source_text || ''; this._source_text = source_text || '';
options = options || {};
// Allow the setting of language/file-type specific options // Allow the setting of language/file-type specific options
// with inheritance of overall settings // with inheritance of overall settings
options = mergeOpts(options, 'css'); this._options = new Options(options);
options = normalizeOpts(options);
this._options = {};
var indentSize = options.indent_size ? parseInt(options.indent_size, 10) : 4;
var indentCharacter = options.indent_char || ' ';
var preserve_newlines = (options.preserve_newlines === undefined) ? false : options.preserve_newlines;
var selectorSeparatorNewline = (options.selector_separator_newline === undefined) ? true : options.selector_separator_newline;
var end_with_newline = (options.end_with_newline === undefined) ? false : options.end_with_newline;
var newline_between_rules = (options.newline_between_rules === undefined) ? true : options.newline_between_rules;
var space_around_combinator = (options.space_around_combinator === undefined) ? false : options.space_around_combinator;
space_around_combinator = space_around_combinator || ((options.space_around_selector_separator === undefined) ? false : options.space_around_selector_separator);
var eol = options.eol ? options.eol : 'auto';
// Support passing the source text back with no change
this._options.disabled = (options.disabled === undefined) ? false : options.disabled;
if (options.indent_with_tabs) {
indentCharacter = '\t';
indentSize = 1;
}
eol = eol.replace(/\\r/, '\r').replace(/\\n/, '\n');
// tokenizer // tokenizer
var whitespaceChar = /\s/; var whitespaceChar = /\s/;
@ -96,21 +71,21 @@ function Beautifier(source_text, options) {
// When allowAtLeastOneNewLine is true, will output new lines for each // When allowAtLeastOneNewLine is true, will output new lines for each
// newline character found; if the user has preserve_newlines off, only // newline character found; if the user has preserve_newlines off, only
// the first newline will be output // the first newline will be output
function eatWhitespace(allowAtLeastOneNewLine) { this.eatWhitespace = function(allowAtLeastOneNewLine) {
var result = whitespaceChar.test(input.peek()); var result = whitespaceChar.test(input.peek());
var isFirstNewLine = true; var isFirstNewLine = true;
while (whitespaceChar.test(input.peek())) { while (whitespaceChar.test(input.peek())) {
ch = input.next(); ch = input.next();
if (allowAtLeastOneNewLine && ch === '\n') { if (allowAtLeastOneNewLine && ch === '\n') {
if (preserve_newlines || isFirstNewLine) { if (this._options.preserve_newlines || isFirstNewLine) {
isFirstNewLine = false; isFirstNewLine = false;
output.add_new_line(true); output.add_new_line(true);
} }
} }
} }
return result; return result;
} };
// Nested pseudo-class if we are insideRule // Nested pseudo-class if we are insideRule
// and the next special character found opens // and the next special character found opens
@ -174,6 +149,7 @@ function Beautifier(source_text, options) {
} }
var source_text = this._source_text; var source_text = this._source_text;
var eol = this._options.eol;
if (eol === 'auto') { if (eol === 'auto') {
eol = '\n'; eol = '\n';
if (source_text && lineBreak.test(source_text || '')) { if (source_text && lineBreak.test(source_text || '')) {
@ -186,19 +162,17 @@ function Beautifier(source_text, options) {
source_text = source_text.replace(allLineBreaks, '\n'); source_text = source_text.replace(allLineBreaks, '\n');
// reset // reset
var singleIndent = new Array(indentSize + 1).join(indentCharacter);
var baseIndentString = ''; var baseIndentString = '';
var preindent_index = 0; var preindent_index = 0;
if (source_text && source_text.length) { if (source_text && source_text.length) {
while ((source_text.charAt(preindent_index) === ' ' || while ((source_text.charAt(preindent_index) === ' ' || source_text.charAt(preindent_index) === '\t')) {
source_text.charAt(preindent_index) === '\t')) {
preindent_index += 1; preindent_index += 1;
} }
baseIndentString = source_text.substring(0, preindent_index); baseIndentString = source_text.substring(0, preindent_index);
source_text = source_text.substring(preindent_index); source_text = source_text.substring(preindent_index);
} }
output = new Output(singleIndent, baseIndentString); output = new Output(this._options.indent_string, baseIndentString);
input = new InputScanner(source_text); input = new InputScanner(source_text);
indentLevel = 0; indentLevel = 0;
nestedLevel = 0; nestedLevel = 0;
@ -235,7 +209,7 @@ function Beautifier(source_text, options) {
print_string(input.read(block_comment_pattern)); print_string(input.read(block_comment_pattern));
// Ensures any new lines following the comment are preserved // Ensures any new lines following the comment are preserved
eatWhitespace(true); this.eatWhitespace(true);
// Block comments are followed by a new line so they don't // Block comments are followed by a new line so they don't
// share a line with other properties // share a line with other properties
@ -249,7 +223,7 @@ function Beautifier(source_text, options) {
print_string(input.read(comment_pattern)); print_string(input.read(comment_pattern));
// Ensures any new lines following the comment are preserved // Ensures any new lines following the comment are preserved
eatWhitespace(true); this.eatWhitespace(true);
} else if (ch === '@') { } else if (ch === '@') {
preserveSingleSpace(isAfterSpace); preserveSingleSpace(isAfterSpace);
@ -309,12 +283,12 @@ function Beautifier(source_text, options) {
// otherwise, declarations are also allowed // otherwise, declarations are also allowed
insideRule = (indentLevel >= nestedLevel); insideRule = (indentLevel >= nestedLevel);
} }
if (newline_between_rules && insideRule) { if (this._options.newline_between_rules && insideRule) {
if (output.previous_line && output.previous_line.item(-1) !== '{') { if (output.previous_line && output.previous_line.item(-1) !== '{') {
output.ensure_empty_line_above('/', ','); output.ensure_empty_line_above('/', ',');
} }
} }
eatWhitespace(true); this.eatWhitespace(true);
output.add_new_line(); output.add_new_line();
} else if (ch === '}') { } else if (ch === '}') {
outdent(); outdent();
@ -334,25 +308,23 @@ function Beautifier(source_text, options) {
nestedLevel--; nestedLevel--;
} }
eatWhitespace(true); this.eatWhitespace(true);
output.add_new_line(); output.add_new_line();
if (newline_between_rules && !output.just_added_blankline()) { if (this._options.newline_between_rules && !output.just_added_blankline()) {
if (input.peek() !== '}') { if (input.peek() !== '}') {
output.add_new_line(true); output.add_new_line(true);
} }
} }
} else if (ch === ":") { } else if (ch === ":") {
if ((insideRule || enteringConditionalGroup) && if ((insideRule || enteringConditionalGroup) && !(input.lookBack("&") || foundNestedPseudoClass()) && !input.lookBack("(") && !insideAtExtend) {
!(input.lookBack("&") || foundNestedPseudoClass()) &&
!input.lookBack("(") && !insideAtExtend) {
// 'property: value' delimiter // 'property: value' delimiter
// which could be in a conditional group query // which could be in a conditional group query
print_string(':'); print_string(':');
if (!insidePropertyValue) { if (!insidePropertyValue) {
insidePropertyValue = true; insidePropertyValue = true;
output.space_before_token = true; output.space_before_token = true;
eatWhitespace(true); this.eatWhitespace(true);
indent(); indent();
} }
} else { } else {
@ -375,7 +347,7 @@ function Beautifier(source_text, options) {
} else if (ch === '"' || ch === '\'') { } else if (ch === '"' || ch === '\'') {
preserveSingleSpace(isAfterSpace); preserveSingleSpace(isAfterSpace);
print_string(ch + eatString(ch)); print_string(ch + eatString(ch));
eatWhitespace(true); this.eatWhitespace(true);
} else if (ch === ';') { } else if (ch === ';') {
if (insidePropertyValue) { if (insidePropertyValue) {
outdent(); outdent();
@ -384,7 +356,7 @@ function Beautifier(source_text, options) {
insideAtExtend = false; insideAtExtend = false;
insideAtImport = false; insideAtImport = false;
print_string(ch); print_string(ch);
eatWhitespace(true); this.eatWhitespace(true);
// This maintains single line comments on the same // This maintains single line comments on the same
// line. Block comments are also affected, but // line. Block comments are also affected, but
@ -396,7 +368,7 @@ function Beautifier(source_text, options) {
} else if (ch === '(') { // may be a url } else if (ch === '(') { // may be a url
if (input.lookBack("url")) { if (input.lookBack("url")) {
print_string(ch); print_string(ch);
eatWhitespace(); this.eatWhitespace();
ch = input.next(); ch = input.next();
if (ch === ')' || ch === '"' || ch !== '\'') { if (ch === ')' || ch === '"' || ch !== '\'') {
input.back(); input.back();
@ -408,29 +380,28 @@ function Beautifier(source_text, options) {
parenLevel++; parenLevel++;
preserveSingleSpace(isAfterSpace); preserveSingleSpace(isAfterSpace);
print_string(ch); print_string(ch);
eatWhitespace(); this.eatWhitespace();
} }
} else if (ch === ')') { } else if (ch === ')') {
print_string(ch); print_string(ch);
parenLevel--; parenLevel--;
} else if (ch === ',') { } else if (ch === ',') {
print_string(ch); print_string(ch);
eatWhitespace(true); this.eatWhitespace(true);
if (selectorSeparatorNewline && !insidePropertyValue && parenLevel < 1 && !insideAtImport) { if (this._options.selector_separator_newline && !insidePropertyValue && parenLevel < 1 && !insideAtImport) {
output.add_new_line(); output.add_new_line();
} else { } else {
output.space_before_token = true; output.space_before_token = true;
} }
} else if ((ch === '>' || ch === '+' || ch === '~') && } else if ((ch === '>' || ch === '+' || ch === '~') && !insidePropertyValue && parenLevel < 1) {
!insidePropertyValue && parenLevel < 1) {
//handle combinator spacing //handle combinator spacing
if (space_around_combinator) { if (this._options.space_around_combinator) {
output.space_before_token = true; output.space_before_token = true;
print_string(ch); print_string(ch);
output.space_before_token = true; output.space_before_token = true;
} else { } else {
print_string(ch); print_string(ch);
eatWhitespace(); this.eatWhitespace();
// squash extra whitespace // squash extra whitespace
if (ch && whitespaceChar.test(ch)) { if (ch && whitespaceChar.test(ch)) {
ch = ''; ch = '';
@ -442,7 +413,7 @@ function Beautifier(source_text, options) {
preserveSingleSpace(isAfterSpace); preserveSingleSpace(isAfterSpace);
print_string(ch); print_string(ch);
} else if (ch === '=') { // no whitespace before or after } else if (ch === '=') { // no whitespace before or after
eatWhitespace(); this.eatWhitespace();
print_string('='); print_string('=');
if (whitespaceChar.test(ch)) { if (whitespaceChar.test(ch)) {
ch = ''; ch = '';
@ -456,7 +427,7 @@ function Beautifier(source_text, options) {
} }
} }
var sweetCode = output.get_code(end_with_newline, eol); var sweetCode = output.get_code(this._options.end_with_newline, eol);
return sweetCode; return sweetCode;
}; };

46
js/src/css/options.js Normal file
View File

@ -0,0 +1,46 @@
/*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';
var BaseOptions = require('../core/options').Options;
function Options(options) {
BaseOptions.call(this, options, 'css');
this.selector_separator_newline = this._get_boolean('selector_separator_newline', true);
this.newline_between_rules = this._get_boolean('newline_between_rules', true);
var space_around_selector_separator = this._get_boolean('space_around_selector_separator');
this.space_around_combinator = this._get_boolean('space_around_combinator') || space_around_selector_separator;
}
Options.prototype = new BaseOptions();
module.exports.Options = Options;

View File

@ -28,8 +28,7 @@
'use strict'; 'use strict';
var mergeOpts = require('../core/options').mergeOpts; var Options = require('../html/options').Options;
var normalizeOpts = require('../core/options').normalizeOpts;
var acorn = require('../core/acorn'); var acorn = require('../core/acorn');
var Output = require('../core/output').Output; var Output = require('../core/output').Output;
var Tokenizer = require('../html/tokenizer').Tokenizer; var Tokenizer = require('../html/tokenizer').Tokenizer;
@ -38,22 +37,15 @@ var TOKEN = require('../html/tokenizer').TOKEN;
var lineBreak = acorn.lineBreak; var lineBreak = acorn.lineBreak;
var allLineBreaks = acorn.allLineBreaks; var allLineBreaks = acorn.allLineBreaks;
var Printer = function(indent_character, indent_size, wrap_line_length, max_preserve_newlines, preserve_newlines) { //handles input/output and some other printing functions var Printer = function(indent_string, wrap_line_length, max_preserve_newlines, preserve_newlines) { //handles input/output and some other printing functions
this.indent_character = indent_character;
this.indent_string = indent_character;
this.indent_size = indent_size;
this.indent_level = 0; this.indent_level = 0;
this.alignment_size = 0; this.alignment_size = 0;
this.wrap_line_length = wrap_line_length; this.wrap_line_length = wrap_line_length;
this.max_preserve_newlines = max_preserve_newlines; this.max_preserve_newlines = max_preserve_newlines;
this.preserve_newlines = preserve_newlines; this.preserve_newlines = preserve_newlines;
if (this.indent_size > 1) { this._output = new Output(indent_string, '');
this.indent_string = new Array(this.indent_size + 1).join(this.indent_character);
}
this._output = new Output(this.indent_string, '');
}; };
@ -98,9 +90,9 @@ Printer.prototype.traverse_whitespace = function(raw_token) {
// at the wrap_line_length, append a newline/indentation. // at the wrap_line_length, append a newline/indentation.
// return true if a newline was added, false if a space was added // return true if a newline was added, false if a space was added
Printer.prototype.print_space_or_wrap = function(text) { Printer.prototype.print_space_or_wrap = function(text) {
if (this.wrap_line_length) {
if (this._output.current_line.get_character_count() + text.length + 1 >= this.wrap_line_length) { //insert a line when the wrap_line_length is reached if (this._output.current_line.get_character_count() + text.length + 1 >= this.wrap_line_length) { //insert a line when the wrap_line_length is reached
if (this._output.add_new_line()) { return this._output.add_new_line();
return true;
} }
} }
return false; return false;
@ -232,18 +224,6 @@ TagStack.prototype.indent_to_tag = function(tag_list) {
} }
}; };
function get_array(input, default_list) {
var result = default_list || [];
if (typeof input === 'object') {
if (input !== null && typeof input.concat === 'function') {
result = input.concat();
}
} else if (typeof input === 'string') {
result = input.trim().replace(/\s*,\s*/g, ',').split(',');
}
return result;
}
function Beautifier(source_text, options, js_beautify, css_beautify) { function Beautifier(source_text, options, js_beautify, css_beautify) {
//Wrapper function to invoke all the necessary constructors and deal with the output. //Wrapper function to invoke all the necessary constructors and deal with the output.
this._source_text = source_text || ''; this._source_text = source_text || '';
@ -254,75 +234,9 @@ function Beautifier(source_text, options, js_beautify, css_beautify) {
// Allow the setting of language/file-type specific options // Allow the setting of language/file-type specific options
// with inheritance of overall settings // with inheritance of overall settings
options = mergeOpts(options, 'html'); var optionHtml = new Options(options, 'html');
options = normalizeOpts(options);
// backwards compatibility to 1.3.4
if ((options.wrap_line_length === undefined || parseInt(options.wrap_line_length, 10) === 0) &&
(options.max_char !== undefined && parseInt(options.max_char, 10) !== 0)) {
options.wrap_line_length = options.max_char;
}
this._options = Object.assign({}, options);
this._options.indent_inner_html = (options.indent_inner_html === undefined) ? false : options.indent_inner_html;
this._options.indent_body_inner_html = (options.indent_body_inner_html === undefined) ? true : options.indent_body_inner_html;
this._options.indent_head_inner_html = (options.indent_head_inner_html === undefined) ? true : options.indent_head_inner_html;
this._options.indent_size = (options.indent_size === undefined) ? 4 : parseInt(options.indent_size, 10);
this._options.indent_character = (options.indent_char === undefined) ? ' ' : options.indent_char;
this._options.wrap_line_length = parseInt(options.wrap_line_length, 10) === 0 ? 32786 : parseInt(options.wrap_line_length || 250, 10);
this._options.preserve_newlines = (options.preserve_newlines === undefined) ? true : options.preserve_newlines;
this._options.max_preserve_newlines = this._options.preserve_newlines ?
(isNaN(parseInt(options.max_preserve_newlines, 10)) ? 32786 : parseInt(options.max_preserve_newlines, 10)) :
0;
this._options.indent_handlebars = (options.indent_handlebars === undefined) ? false : options.indent_handlebars;
this._options.wrap_attributes = (options.wrap_attributes === undefined) ? 'auto' : options.wrap_attributes;
this._options.wrap_attributes_indent_size = (isNaN(parseInt(options.wrap_attributes_indent_size, 10))) ? this._options.indent_size : parseInt(options.wrap_attributes_indent_size, 10);
this._options.end_with_newline = (options.end_with_newline === undefined) ? false : options.end_with_newline;
this._options.extra_liners = get_array(options.extra_liners, ['head', 'body', '/html']);
this._options.eol = options.eol ? options.eol : 'auto';
if (options.indent_with_tabs) {
this._options.indent_character = '\t';
this._options.indent_size = 1;
}
// Support passing the source text back with no change
this._options.disabled = (options.disabled === undefined) ? false : options.disabled;
this._options.eol = this._options.eol.replace(/\\r/, '\r').replace(/\\n/, '\n');
this._options.inline = get_array(options.inline, [
// https://www.w3.org/TR/html5/dom.html#phrasing-content
'a', 'abbr', 'area', 'audio', 'b', 'bdi', 'bdo', 'br', 'button', 'canvas', 'cite',
'code', 'data', 'datalist', 'del', 'dfn', 'em', 'embed', 'i', 'iframe', 'img',
'input', 'ins', 'kbd', 'keygen', 'label', 'map', 'mark', 'math', 'meter', 'noscript',
'object', 'output', 'progress', 'q', 'ruby', 's', 'samp', /* 'script', */ 'select', 'small',
'span', 'strong', 'sub', 'sup', 'svg', 'template', 'textarea', 'time', 'u', 'var',
'video', 'wbr', 'text',
// prexisting - not sure of full effect of removing, leaving in
'acronym', 'address', 'big', 'dt', 'ins', 'strike', 'tt'
]);
this._options.void_elements = get_array(options.void_elements, [
// HTLM void elements - aka self-closing tags - aka singletons
// https://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen',
'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr',
// NOTE: Optional tags are too complex for a simple list
// they are hard coded in _do_optional_end_element
// Doctype and xml elements
'!doctype', '?xml',
// ?php and ?= tags
'?php', '?=',
// other tags that were in this list, keeping just in case
'basefont', 'isindex'
]);
this._options.unformatted = get_array(options.unformatted, []);
this._options.content_unformatted = get_array(options.content_unformatted, [
'pre', 'textarea'
]);
this._options = optionHtml;
this._is_wrap_attributes_force = this._options.wrap_attributes.substr(0, 'force'.length) === 'force'; this._is_wrap_attributes_force = this._options.wrap_attributes.substr(0, 'force'.length) === 'force';
this._is_wrap_attributes_force_expand_multiline = (this._options.wrap_attributes === 'force-expand-multiline'); this._is_wrap_attributes_force_expand_multiline = (this._options.wrap_attributes === 'force-expand-multiline');
@ -356,7 +270,7 @@ Beautifier.prototype.beautify = function() {
var last_tag_token = new TagOpenParserToken(); var last_tag_token = new TagOpenParserToken();
var printer = new Printer(this._options.indent_character, this._options.indent_size, var printer = new Printer(this._options.indent_string,
this._options.wrap_line_length, this._options.max_preserve_newlines, this._options.preserve_newlines); this._options.wrap_line_length, this._options.max_preserve_newlines, this._options.preserve_newlines);
var tokens = new Tokenizer(source_text, this._options).tokenize(); var tokens = new Tokenizer(source_text, this._options).tokenize();
@ -410,7 +324,6 @@ Beautifier.prototype._handle_tag_close = function(printer, raw_token, last_tag_t
if (last_tag_token.indent_content && if (last_tag_token.indent_content &&
!(last_tag_token.is_unformatted || last_tag_token.is_content_unformatted)) { !(last_tag_token.is_unformatted || last_tag_token.is_content_unformatted)) {
printer.indent(); printer.indent();
// only indent once per opened tag // only indent once per opened tag
@ -517,13 +430,13 @@ Beautifier.prototype._print_custom_beatifier_text = function(printer, raw_token,
var Child_options = function() { var Child_options = function() {
this.eol = '\n'; this.eol = '\n';
}; };
Child_options.prototype = this._options; Child_options.prototype = this._options.raw_options;
var child_options = new Child_options(); var child_options = new Child_options();
text = _beautifier(indentation + text, child_options); text = _beautifier(indentation + text, child_options);
} else { } else {
// simply indent the string otherwise // simply indent the string otherwise
var white = text.match(/^\s*/)[0]; var white = text.match(/^\s*/)[0];
var _level = white.match(/[^\n\r]*$/)[0].split(this._indent_string).length - 1; var _level = white.match(/[^\n\r]*$/)[0].split(this._options.indent_string).length - 1;
var reindent = this._get_full_indent(script_indent_level - _level); var reindent = this._get_full_indent(script_indent_level - _level);
text = (indentation + text.trim()) text = (indentation + text.trim())
.replace(/\r\n|\r|\n/g, '\n' + reindent); .replace(/\r\n|\r|\n/g, '\n' + reindent);

81
js/src/html/options.js Normal file
View File

@ -0,0 +1,81 @@
/*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';
var BaseOptions = require('../core/options').Options;
function Options(options) {
BaseOptions.call(this, options, 'html');
this.indent_inner_html = this._get_boolean('indent_inner_html', true);
this.indent_body_inner_html = this._get_boolean('indent_body_inner_html', true);
this.indent_head_inner_html = this._get_boolean('indent_head_inner_html', true);
this.indent_handlebars = this._get_boolean('indent_handlebars', true);
this.wrap_attributes = this._get_selection('wrap_attributes',
['auto', 'force', 'force-aligned', 'force-expand-multiline', 'aligned-multiple'])[0];
this.wrap_attributes_indent_size = this._get_number('wrap_attributes_indent_size', this.indent_size);
this.extra_liners = this._get_array('extra_liners', ['head', 'body', '/html']);
this.inline = this._get_array('inline', [
// https://www.w3.org/TR/html5/dom.html#phrasing-content
'a', 'abbr', 'area', 'audio', 'b', 'bdi', 'bdo', 'br', 'button', 'canvas', 'cite',
'code', 'data', 'datalist', 'del', 'dfn', 'em', 'embed', 'i', 'iframe', 'img',
'input', 'ins', 'kbd', 'keygen', 'label', 'map', 'mark', 'math', 'meter', 'noscript',
'object', 'output', 'progress', 'q', 'ruby', 's', 'samp', /* 'script', */ 'select', 'small',
'span', 'strong', 'sub', 'sup', 'svg', 'template', 'textarea', 'time', 'u', 'var',
'video', 'wbr', 'text',
// prexisting - not sure of full effect of removing, leaving in
'acronym', 'address', 'big', 'dt', 'ins', 'strike', 'tt'
]);
this.void_elements = this._get_array('void_elements', [
// HTLM void elements - aka self-closing tags - aka singletons
// https://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen',
'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr',
// NOTE: Optional tags are too complex for a simple list
// they are hard coded in _do_optional_end_element
// Doctype and xml elements
'!doctype', '?xml',
// ?php and ?= tags
'?php', '?=',
// other tags that were in this list, keeping just in case
'basefont', 'isindex'
]);
this.unformatted = this._get_array('unformatted', []);
this.content_unformatted = this._get_array('content_unformatted', [
'pre', 'textarea'
]);
}
Options.prototype = new BaseOptions();
module.exports.Options = Options;

View File

@ -28,10 +28,9 @@
'use strict'; 'use strict';
var mergeOpts = require('../core/options').mergeOpts;
var normalizeOpts = require('../core/options').normalizeOpts;
var acorn = require('../core/acorn'); var acorn = require('../core/acorn');
var Output = require('../core/output').Output; var Output = require('../core/output').Output;
var Options = require('./options').Options;
var Tokenizer = require('./tokenizer').Tokenizer; var Tokenizer = require('./tokenizer').Tokenizer;
var line_starters = require('./tokenizer').line_starters; var line_starters = require('./tokenizer').line_starters;
var positionable_operators = require('./tokenizer').positionable_operators; var positionable_operators = require('./tokenizer').positionable_operators;
@ -70,18 +69,6 @@ function generateMapFromStrings(list) {
return result; return result;
} }
function sanitizeOperatorPosition(opPosition) {
opPosition = opPosition || OPERATOR_POSITION.before_newline;
if (!in_array(opPosition, validPositionValues)) {
throw new Error("Invalid Option Value: The option 'operator_position' must be one of the following values\n" +
validPositionValues +
"\nYou passed in: '" + opPosition + "'");
}
return opPosition;
}
var validPositionValues = ['before-newline', 'after-newline', 'preserve-newline']; var validPositionValues = ['before-newline', 'after-newline', 'preserve-newline'];
// Generate map from array // Generate map from array
@ -166,74 +153,7 @@ function Beautifier(source_text, options) {
this._previous_flags = null; this._previous_flags = null;
this._flag_store = null; this._flag_store = null;
this._options = {}; this._options = new Options(options);
// Allow the setting of language/file-type specific options
// with inheritance of overall settings
options = mergeOpts(options, 'js');
options = normalizeOpts(options);
// compatibility, re
if (options.brace_style === "expand-strict") { //graceful handling of deprecated option
options.brace_style = "expand";
} else if (options.brace_style === "collapse-preserve-inline") { //graceful handling of deprecated option
options.brace_style = "collapse,preserve-inline";
} else if (options.braces_on_own_line !== undefined) { //graceful handling of deprecated option
options.brace_style = options.braces_on_own_line ? "expand" : "collapse";
} else if (!options.brace_style) { //Nothing exists to set it
options.brace_style = "collapse";
}
//preserve-inline in delimited string will trigger brace_preserve_inline, everything
//else is considered a brace_style and the last one only will have an effect
var brace_style_split = options.brace_style.split(/[^a-zA-Z0-9_\-]+/);
this._options.brace_preserve_inline = false; //Defaults in case one or other was not specified in meta-option
this._options.brace_style = "collapse";
for (var bs = 0; bs < brace_style_split.length; bs++) {
if (brace_style_split[bs] === "preserve-inline") {
this._options.brace_preserve_inline = true;
} else {
this._options.brace_style = brace_style_split[bs];
}
}
this._options.indent_size = options.indent_size ? parseInt(options.indent_size, 10) : 4;
this._options.indent_char = options.indent_char ? options.indent_char : ' ';
this._options.eol = options.eol ? options.eol : 'auto';
this._options.preserve_newlines = (options.preserve_newlines === undefined) ? true : options.preserve_newlines;
this._options.unindent_chained_methods = (options.unindent_chained_methods === undefined) ? false : options.unindent_chained_methods;
this._options.break_chained_methods = (options.break_chained_methods === undefined) ? false : options.break_chained_methods;
this._options.max_preserve_newlines = (options.max_preserve_newlines === undefined) ? 0 : parseInt(options.max_preserve_newlines, 10);
this._options.space_in_paren = (options.space_in_paren === undefined) ? false : options.space_in_paren;
this._options.space_in_empty_paren = (options.space_in_empty_paren === undefined) ? false : options.space_in_empty_paren;
this._options.jslint_happy = (options.jslint_happy === undefined) ? false : options.jslint_happy;
this._options.space_after_anon_function = (options.space_after_anon_function === undefined) ? false : options.space_after_anon_function;
this._options.keep_array_indentation = (options.keep_array_indentation === undefined) ? false : options.keep_array_indentation;
this._options.space_before_conditional = (options.space_before_conditional === undefined) ? true : options.space_before_conditional;
this._options.unescape_strings = (options.unescape_strings === undefined) ? false : options.unescape_strings;
this._options.wrap_line_length = (options.wrap_line_length === undefined) ? 0 : parseInt(options.wrap_line_length, 10);
this._options.e4x = (options.e4x === undefined) ? false : options.e4x;
this._options.end_with_newline = (options.end_with_newline === undefined) ? false : options.end_with_newline;
this._options.comma_first = (options.comma_first === undefined) ? false : options.comma_first;
this._options.operator_position = sanitizeOperatorPosition(options.operator_position);
// Support passing the source text back with no change
this._options.disabled = (options.disabled === undefined) ? false : options.disabled;
// For testing of beautify preserve:start directive
this._options.test_output_raw = (options.test_output_raw === undefined) ? false : options.test_output_raw;
// force this._options.space_after_anon_function to true if this._options.jslint_happy
if (this._options.jslint_happy) {
this._options.space_after_anon_function = true;
}
if (options.indent_with_tabs) {
this._options.indent_char = '\t';
this._options.indent_size = 1;
}
this._options.eol = this._options.eol.replace(/\\r/, '\r').replace(/\\n/, '\n');
} }
Beautifier.prototype.create_flags = function(flags_base, mode) { Beautifier.prototype.create_flags = function(flags_base, mode) {
@ -274,8 +194,6 @@ Beautifier.prototype.create_flags = function(flags_base, mode) {
Beautifier.prototype._reset = function(source_text) { Beautifier.prototype._reset = function(source_text) {
var baseIndentString = ''; var baseIndentString = '';
var indent_string = new Array(this._options.indent_size + 1).join(this._options.indent_char);
var preindent_index = 0; var preindent_index = 0;
if (source_text && source_text.length) { if (source_text && source_text.length) {
while ((source_text.charAt(preindent_index) === ' ' || while ((source_text.charAt(preindent_index) === ' ' ||
@ -288,7 +206,7 @@ Beautifier.prototype._reset = function(source_text) {
this._last_type = TOKEN.START_BLOCK; // last token type this._last_type = TOKEN.START_BLOCK; // last token type
this._last_last_text = ''; // pre-last token text this._last_last_text = ''; // pre-last token text
this._output = new Output(indent_string, baseIndentString); this._output = new Output(this._options.indent_string, baseIndentString);
// If testing the ignore directive, start with output disable set to true // If testing the ignore directive, start with output disable set to true
this._output.raw = this._options.test_output_raw; this._output.raw = this._options.test_output_raw;
@ -306,7 +224,7 @@ Beautifier.prototype._reset = function(source_text) {
// MODE.BlockStatement and continues on. // MODE.BlockStatement and continues on.
this._flag_store = []; this._flag_store = [];
this.set_mode(MODE.BlockStatement); this.set_mode(MODE.BlockStatement);
var tokenizer = new Tokenizer(source_text, this._options, indent_string); var tokenizer = new Tokenizer(source_text, this._options);
this._tokens = tokenizer.tokenize(); this._tokens = tokenizer.tokenize();
return source_text; return source_text;
}; };

View File

@ -0,0 +1,91 @@
/*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';
var BaseOptions = require('../core/options').Options;
var validPositionValues = ['before-newline', 'after-newline', 'preserve-newline'];
function Options(options) {
BaseOptions.call(this, options, 'js');
// compatibility, re
var raw_brace_style = this.raw_options.brace_style || null;
if (raw_brace_style === "expand-strict") { //graceful handling of deprecated option
this.raw_options.brace_style = "expand";
} else if (raw_brace_style === "collapse-preserve-inline") { //graceful handling of deprecated option
this.raw_options.brace_style = "collapse,preserve-inline";
} else if (this.raw_options.braces_on_own_line !== undefined) { //graceful handling of deprecated option
this.raw_options.brace_style = this.raw_options.braces_on_own_line ? "expand" : "collapse";
// } else if (!raw_brace_style) { //Nothing exists to set it
// raw_brace_style = "collapse";
}
//preserve-inline in delimited string will trigger brace_preserve_inline, everything
//else is considered a brace_style and the last one only will have an effect
var brace_style_split = this._get_selection('brace_style', ['collapse', 'expand', 'end-expand', 'none', 'preserve-inline']);
this.brace_preserve_inline = false; //Defaults in case one or other was not specified in meta-option
this.brace_style = "collapse";
for (var bs = 0; bs < brace_style_split.length; bs++) {
if (brace_style_split[bs] === "preserve-inline") {
this.brace_preserve_inline = true;
} else {
this.brace_style = brace_style_split[bs];
}
}
this.unindent_chained_methods = this._get_boolean('unindent_chained_methods');
this.break_chained_methods = this._get_boolean('break_chained_methods');
this.space_in_paren = this._get_boolean('space_in_paren');
this.space_in_empty_paren = this._get_boolean('space_in_empty_paren');
this.jslint_happy = this._get_boolean('jslint_happy');
this.space_after_anon_function = this._get_boolean('space_after_anon_function');
this.keep_array_indentation = this._get_boolean('keep_array_indentation');
this.space_before_conditional = this._get_boolean('space_before_conditional', true);
this.unescape_strings = this._get_boolean('unescape_strings');
this.e4x = this._get_boolean('e4x');
this.comma_first = this._get_boolean('comma_first');
this.operator_position = this._get_selection('operator_position', validPositionValues)[0];
// For testing of beautify preserve:start directive
this.test_output_raw = this._get_boolean('test_output_raw');
// force this._options.space_after_anon_function to true if this._options.jslint_happy
if (this.jslint_happy) {
this.space_after_anon_function = true;
}
}
Options.prototype = new BaseOptions();
module.exports.Options = Options;

View File

@ -39,8 +39,6 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
indent_char: ' ', indent_char: ' ',
preserve_newlines: true, preserve_newlines: true,
jslint_happy: false, jslint_happy: false,
keep_array_indentation: false,
brace_style: 'collapse',
space_before_conditional: true, space_before_conditional: true,
break_chained_methods: false, break_chained_methods: false,
selector_separator: '\n', selector_separator: '\n',
@ -52,9 +50,6 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
default_opts.indent_char = ' '; default_opts.indent_char = ' ';
default_opts.preserve_newlines = true; default_opts.preserve_newlines = true;
default_opts.jslint_happy = false; default_opts.jslint_happy = false;
default_opts.keep_array_indentation = false;
default_opts.brace_style = 'collapse';
default_opts.operator_position = 'before-newline';
function reset_options() function reset_options()
{ {
@ -620,6 +615,48 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
' e();\n' + ' e();\n' +
'}'); '}');
// Brace style permutations - ()
reset_options();
set_name('Brace style permutations - ()');
bt(
'var a ={a: 2};\n' +
'var a ={a: 2};',
// -- output --
'var a = {\n' +
' a: 2\n' +
'};\n' +
'var a = {\n' +
' a: 2\n' +
'};');
bt(
'//case 1\n' +
'if (a == 1){}\n' +
'//case 2\n' +
'else if (a == 2){}',
// -- output --
'//case 1\n' +
'if (a == 1) {}\n' +
'//case 2\n' +
'else if (a == 2) {}');
bt(
'if(1){2}else{3}',
// -- output --
'if (1) {\n' +
' 2\n' +
'} else {\n' +
' 3\n' +
'}');
bt(
'try{a();}catch(b){c();}catch(d){}finally{e();}',
// -- output --
'try {\n' +
' a();\n' +
'} catch (b) {\n' +
' c();\n' +
'} catch (d) {} finally {\n' +
' e();\n' +
'}');
// Brace style permutations - (brace_style = ""collapse"") // Brace style permutations - (brace_style = ""collapse"")
reset_options(); reset_options();
set_name('Brace style permutations - (brace_style = ""collapse"")'); set_name('Brace style permutations - (brace_style = ""collapse"")');
@ -1272,6 +1309,55 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
//============================================================ //============================================================
// operator_position option - ensure no neswlines if preserve_newlines is false - (preserve_newlines = "false")
reset_options();
set_name('operator_position option - ensure no neswlines if preserve_newlines is false - (preserve_newlines = "false")');
opts.preserve_newlines = false;
bt(
'var res = a + b - c / d * e % f;\n' +
'var res = g & h | i ^ j;\n' +
'var res = (k && l || m) ? n : o;\n' +
'var res = p >> q << r >>> s;\n' +
'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' +
'ac + -ad');
bt(
'var res = a + b\n' +
'- c /\n' +
'd * e\n' +
'%\n' +
'f;\n' +
' var res = g & h\n' +
'| i ^\n' +
'j;\n' +
'var res = (k &&\n' +
'l\n' +
'|| m) ?\n' +
'n\n' +
': o\n' +
';\n' +
'var res = p\n' +
'>> q <<\n' +
'r\n' +
'>>> s;\n' +
'var res\n' +
' = t\n' +
'\n' +
' === u !== v\n' +
' !=\n' +
'w\n' +
'== x >=\n' +
'y <= z > aa <\n' +
'ab;\n' +
'ac +\n' +
'-ad',
// -- output --
'var res = a + b - c / d * e % f;\n' +
'var res = g & h | i ^ j;\n' +
'var res = (k && l || m) ? n : o;\n' +
'var res = p >> q << r >>> s;\n' +
'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' +
'ac + -ad');
// operator_position option - ensure no neswlines if preserve_newlines is false - (operator_position = ""before-newline"", preserve_newlines = "false") // operator_position option - ensure no neswlines if preserve_newlines is false - (operator_position = ""before-newline"", preserve_newlines = "false")
reset_options(); reset_options();
set_name('operator_position option - ensure no neswlines if preserve_newlines is false - (operator_position = ""before-newline"", preserve_newlines = "false")'); set_name('operator_position option - ensure no neswlines if preserve_newlines is false - (operator_position = ""before-newline"", preserve_newlines = "false")');
@ -1424,9 +1510,131 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
//============================================================ //============================================================
// operator_position option - set to "before-newline" (default value) // operator_position option - set to "before-newline" (default value) - ()
reset_options(); reset_options();
set_name('operator_position option - set to "before-newline" (default value)'); set_name('operator_position option - set to "before-newline" (default value) - ()');
// comprehensive, various newlines
bt(
'var res = a + b\n' +
'- c /\n' +
'd * e\n' +
'%\n' +
'f;\n' +
' var res = g & h\n' +
'| i ^\n' +
'j;\n' +
'var res = (k &&\n' +
'l\n' +
'|| m) ?\n' +
'n\n' +
': o\n' +
';\n' +
'var res = p\n' +
'>> q <<\n' +
'r\n' +
'>>> s;\n' +
'var res\n' +
' = t\n' +
'\n' +
' === u !== v\n' +
' !=\n' +
'w\n' +
'== x >=\n' +
'y <= z > aa <\n' +
'ab;\n' +
'ac +\n' +
'-ad',
// -- output --
'var res = a + b -\n' +
' c /\n' +
' d * e %\n' +
' f;\n' +
'var res = g & h |\n' +
' i ^\n' +
' j;\n' +
'var res = (k &&\n' +
' l ||\n' +
' m) ?\n' +
' n :\n' +
' o;\n' +
'var res = p >>\n' +
' q <<\n' +
' r >>>\n' +
' s;\n' +
'var res = t\n' +
'\n' +
' ===\n' +
' u !== v !=\n' +
' w ==\n' +
' x >=\n' +
' y <= z > aa <\n' +
' ab;\n' +
'ac +\n' +
' -ad');
// colon special case
bt(
'var a = {\n' +
' b\n' +
': bval,\n' +
' c:\n' +
'cval\n' +
' ,d: dval\n' +
'};\n' +
'var e = f ? g\n' +
': h;\n' +
'var i = j ? k :\n' +
'l;',
// -- output --
'var a = {\n' +
' b: bval,\n' +
' c: cval,\n' +
' d: dval\n' +
'};\n' +
'var e = f ? g :\n' +
' h;\n' +
'var i = j ? k :\n' +
' l;');
// catch-all, includes brackets and other various code
bt(
'var d = 1;\n' +
'if (a === b\n' +
' && c) {\n' +
' d = (c * everything\n' +
' / something_else) %\n' +
' b;\n' +
' e\n' +
' += d;\n' +
'\n' +
'} else if (!(complex && simple) ||\n' +
' (emotion && emotion.name === "happy")) {\n' +
' cryTearsOfJoy(many ||\n' +
' anOcean\n' +
' || aRiver);\n' +
'}',
// -- output --
'var d = 1;\n' +
'if (a === b &&\n' +
' c) {\n' +
' d = (c * everything /\n' +
' something_else) %\n' +
' b;\n' +
' e\n' +
' += d;\n' +
'\n' +
'} else if (!(complex && simple) ||\n' +
' (emotion && emotion.name === "happy")) {\n' +
' cryTearsOfJoy(many ||\n' +
' anOcean ||\n' +
' aRiver);\n' +
'}');
// operator_position option - set to "before-newline" (default value) - (operator_position = ""before-newline"")
reset_options();
set_name('operator_position option - set to "before-newline" (default value) - (operator_position = ""before-newline"")');
opts.operator_position = 'before-newline';
// comprehensive, various newlines // comprehensive, various newlines
bt( bt(

View File

@ -52,7 +52,7 @@ def beautify_file(file_name, opts=default_options()):
raise Exception() raise Exception()
stream = sys.stdin stream = sys.stdin
except Exception as ex: except Exception:
print("Must pipe input or define input file.\n", file=sys.stderr) print("Must pipe input or define input file.\n", file=sys.stderr)
usage(sys.stderr) usage(sys.stderr)
raise Exception() raise Exception()

View File

@ -3,8 +3,6 @@ import sys
import re import re
import copy import copy
from .options import BeautifierOptions from .options import BeautifierOptions
from jsbeautifier.core.options import mergeOpts
from jsbeautifier.core.options import normalizeOpts
from jsbeautifier.core.output import Output from jsbeautifier.core.output import Output
from jsbeautifier.core.inputscanner import InputScanner from jsbeautifier.core.inputscanner import InputScanner
from jsbeautifier.__version__ import __version__ from jsbeautifier.__version__ import __version__
@ -117,12 +115,7 @@ class Beautifier:
self.__source_text = source_text self.__source_text = source_text
opts = mergeOpts(opts, 'css') opts = BeautifierOptions(opts)
opts = normalizeOpts(opts)
# Continue to accept deprecated option
opts.space_around_combinator = opts.space_around_combinator or \
opts.space_around_selector_separator
self.opts = opts self.opts = opts
self.indentSize = opts.indent_size self.indentSize = opts.indent_size
@ -130,12 +123,6 @@ class Beautifier:
self.input = None self.input = None
self.ch = None self.ch = None
if self.opts.indent_with_tabs:
self.indentChar = "\t"
self.indentSize = 1
self.opts.eol = self.opts.eol.replace('\\r', '\r').replace('\\n', '\n')
# https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule # https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
# also in CONDITIONAL_GROUP_RULE below # also in CONDITIONAL_GROUP_RULE below

View File

@ -23,41 +23,18 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
from jsbeautifier.core.options import Options as BaseOptions
class BeautifierOptions: class BeautifierOptions(BaseOptions):
def __init__(self): def __init__(self, options=None):
self.indent_size = 4 super(BeautifierOptions, self).__init__(options, 'css')
self.indent_char = ' '
self.indent_with_tabs = False
self.preserve_newlines = False
self.selector_separator_newline = True
self.end_with_newline = False
self.newline_between_rules = True
self.space_around_combinator = False
self.eol = 'auto'
self.disabled = False
self.css = None self.selector_separator_newline = self._get_boolean('selector_separator_newline', True)
self.js = None self.newline_between_rules = self._get_boolean('newline_between_rules', True)
self.html = None
# deprecated # deprecated
self.space_around_selector_separator = False space_around_selector_separator = self._get_boolean('space_around_selector_separator')
def __repr__(self): # Continue to accept deprecated option
return """indent_size = %d self.space_around_combinator = self._get_boolean('space_around_combinator') or \
indent_char = [%s] space_around_selector_separator
indent_with_tabs = [%s]
preserve_newlines = [%s]
separate_selectors_newline = [%s]
end_with_newline = [%s]
newline_between_rules = [%s]
space_around_combinator = [%s]
""" % (self.indent_size,
self.indent_char,
self.indent_with_tabs,
self.preserve_newlines,
self.selector_separator_newline,
self.end_with_newline,
self.newline_between_rules,
self.space_around_combinator)

View File

@ -9,7 +9,7 @@ import errno
import copy import copy
from jsbeautifier.__version__ import __version__ from jsbeautifier.__version__ import __version__
from jsbeautifier.javascript.options import BeautifierOptions from jsbeautifier.javascript.options import BeautifierOptions
from jsbeautifier.javascript.beautifier import Beautifier, sanitizeOperatorPosition from jsbeautifier.javascript.beautifier import Beautifier
# #
# The MIT License (MIT) # The MIT License (MIT)
@ -275,7 +275,7 @@ def main():
elif opt in ('--comma-first', '-C'): elif opt in ('--comma-first', '-C'):
js_options.comma_first = True js_options.comma_first = True
elif opt in ('--operator-position', '-O'): elif opt in ('--operator-position', '-O'):
js_options.operator_position = sanitizeOperatorPosition(arg) js_options.operator_position = arg
elif opt in ('--wrap-line-length ', '-w'): elif opt in ('--wrap-line-length ', '-w'):
js_options.wrap_line_length = int(arg) js_options.wrap_line_length = int(arg)
elif opt in ('--stdin', '-i'): elif opt in ('--stdin', '-i'):

View File

@ -23,6 +23,106 @@
# SOFTWARE. # SOFTWARE.
import copy import copy
import re
class Options:
def __init__(self, options=None, merge_child_field=None):
self.css = None
self.js = None
self.html = None
options = _mergeOpts(options, merge_child_field)
self.raw_options = _normalizeOpts(options)
# Support passing the source text back with no change
self.disabled = self._get_boolean('disabled')
self.eol = self._get_characters('eol', 'auto')
self.end_with_newline = self._get_boolean('end_with_newline')
self.indent_size = self._get_number('indent_size', 4)
self.indent_char = self._get_characters('indent_char', ' ')
self.preserve_newlines = self._get_boolean('preserve_newlines', True)
# TODO: fix difference in js and python
self.max_preserve_newlines = self.max_preserve_newlines = self._get_number('max_preserve_newlines', 10)
if not self.preserve_newlines:
self.max_preserve_newlines = 0
self.indent_with_tabs = self._get_boolean('indent_with_tabs')
if self.indent_with_tabs:
self.indent_char = '\t'
self.indent_size = 1
self.indent_string = self.indent_char * self.indent_size
# Backwards compat with 1.3.x
self.wrap_line_length = self._get_number('wrap_line_length', self._get_number('max_char'))
def _get_array(self, name, default_value=[]):
option_value = getattr(self.raw_options, name, default_value)
result = []
if isinstance(option_value, list):
result = copy.copy(option_value)
elif isinstance(option_value, str):
result = re.compile(r"[^a-zA-Z0-9_/\-]+").split(option_value)
return result
def _get_boolean(self, name, default_value=False):
option_value = getattr(self.raw_options, name, default_value)
result = False
try:
result = bool(option_value)
except ValueError:
pass
return result
def _get_characters(self, name, default_value=''):
option_value = getattr(self.raw_options, name, default_value)
result = ''
if isinstance(option_value, str):
result = option_value.replace('\\r', '\r').replace('\\n', '\n').replace('\\t', '\t')
return result
def _get_number(self, name, default_value=0):
option_value = getattr(self.raw_options, name, default_value)
result = 0
try:
result = int(option_value)
except ValueError:
pass
return result
def _get_selection(self, name, selection_list, default_value=None):
default_value = default_value or [selection_list[0]]
if not self._is_valid_selection(default_value, selection_list):
raise ValueError("Invalid Default Value!")
result = self._get_array(name, default_value)
self._is_valid_selection(result, selection_list)
if not self._is_valid_selection(result, selection_list):
raise ValueError(
"Invalid Option Value: The option 'operator_position' must be one of the following values\n" +
str(selection_list) +
"\nYou passed in: '" +
str(getattr(self.raw_options, name, None)) +
"'")
return result
def _is_valid_selection(self, result, selection_list):
if len(result) == 0 or len(selection_list) == 0:
return False
for item in result:
if item not in selection_list:
return False
return True
# merges child options up with the parent options object # merges child options up with the parent options object
# Example: obj = {a: 1, b: {a: 2}} # Example: obj = {a: 1, b: {a: 2}}
@ -31,8 +131,8 @@ import copy
# Returns: {a: 2, b: {a: 2}} # Returns: {a: 2, b: {a: 2}}
def mergeOpts(options, childFieldName): def _mergeOpts(options, childFieldName):
finalOpts = copy.copy(options) finalOpts = copy.copy(options) or object()
local = getattr(finalOpts, childFieldName, None) local = getattr(finalOpts, childFieldName, None)
if local: if local:
@ -42,10 +142,10 @@ def mergeOpts(options, childFieldName):
return finalOpts return finalOpts
def normalizeOpts(options): def _normalizeOpts(options):
convertedOpts = copy.copy(options) convertedOpts = copy.copy(options) or object()
option_keys = copy.copy(getattr(convertedOpts, '__dict__', {}))
for key in options.__dict__: for key in option_keys:
if '-' in key: if '-' in key:
delattr(convertedOpts, key) delattr(convertedOpts, key)
setattr(convertedOpts, key.replace('-', '_'), getattr(options, key, None)) setattr(convertedOpts, key.replace('-', '_'), getattr(options, key, None))

View File

@ -28,8 +28,6 @@ import copy
from .tokenizer import Tokenizer from .tokenizer import Tokenizer
from .tokenizer import TOKEN from .tokenizer import TOKEN
from .options import BeautifierOptions from .options import BeautifierOptions
from ..core.options import mergeOpts
from ..core.options import normalizeOpts
from ..core.output import Output from ..core.output import Output
@ -82,21 +80,6 @@ OPERATOR_POSITION_BEFORE_OR_PRESERVE = [
OPERATOR_POSITION['preserve_newline']] OPERATOR_POSITION['preserve_newline']]
def sanitizeOperatorPosition(opPosition):
if not opPosition:
return OPERATOR_POSITION['before_newline']
elif opPosition not in OPERATOR_POSITION.values():
raise ValueError(
"Invalid Option Value: The option 'operator_position' must be one of the following values\n" +
str(
OPERATOR_POSITION.values()) +
"\nYou passed in: '" +
opPosition +
"'")
return opPosition
class MODE: class MODE:
BlockStatement, Statement, ObjectLiteral, ArrayLiteral, \ BlockStatement, Statement, ObjectLiteral, ArrayLiteral, \
ForInitializer, Conditional, Expression = range(7) ForInitializer, Conditional, Expression = range(7)
@ -119,10 +102,10 @@ def remove_redundant_indentation(output, frame):
class Beautifier: class Beautifier:
def __init__(self, opts=default_options()): def __init__(self, opts=None):
import jsbeautifier.core.acorn as acorn import jsbeautifier.core.acorn as acorn
self.acorn = acorn self.acorn = acorn
self._options = copy.copy(opts) self._options = BeautifierOptions(opts)
self._blank_state() self._blank_state()
@ -136,23 +119,12 @@ class Beautifier:
self._flag_store = [] self._flag_store = []
self._tokens = None self._tokens = None
# force opts.space_after_anon_function to true if opts.jslint_happy
if self._options.jslint_happy:
self._options.space_after_anon_function = True
if self._options.indent_with_tabs:
self._options.indent_char = "\t"
self._options.indent_size = 1
if self._options.eol == 'auto': if self._options.eol == 'auto':
self._options.eol = '\n' self._options.eol = '\n'
if self.acorn.lineBreak.search(js_source_text or ''): if self.acorn.lineBreak.search(js_source_text or ''):
self._options.eol = self.acorn.lineBreak.search( self._options.eol = self.acorn.lineBreak.search(
js_source_text).group() js_source_text).group()
self._options.eol = self._options.eol.replace('\\r', '\r').replace('\\n', '\n')
indent_string = self._options.indent_char * self._options.indent_size
baseIndentString = '' baseIndentString = ''
self._last_type = TOKEN.START_BLOCK # last token type self._last_type = TOKEN.START_BLOCK # last token type
@ -166,7 +138,7 @@ class Beautifier:
preindent_index += 1 preindent_index += 1
js_source_text = js_source_text[preindent_index:] js_source_text = js_source_text[preindent_index:]
self._output = Output(indent_string, baseIndentString) self._output = Output(self._options.indent_string, baseIndentString)
# If testing the ignore directive, start with output disable set to # If testing the ignore directive, start with output disable set to
# true # true
self._output.raw = self._options.test_output_raw self._output.raw = self._options.test_output_raw
@ -176,32 +148,8 @@ class Beautifier:
def beautify(self, source_text='', opts=None): def beautify(self, source_text='', opts=None):
if opts is not None: if opts is not None:
opts = mergeOpts(opts, 'js') self._options = BeautifierOptions(opts)
opts = normalizeOpts(opts)
self._options = copy.copy(opts)
# Compat with old form
if self._options.brace_style == 'collapse-preserve-inline':
self._options.brace_style = 'collapse,preserve-inline'
# split always returns at least one value
split = re.compile(r"[^a-zA-Z0-9_\-]+").split(self._options.brace_style)
# preserve-inline in delimited string will trigger brace_preserve_inline
# Everything else is considered a brace_style and the last one only will
# have an effect
# specify defaults in case one half of meta-option is missing
self._options.brace_style = "collapse"
self._options.brace_preserve_inline = False
for bs in split:
if bs == "preserve-inline":
self._options.brace_preserve_inline = True
else:
# validate each brace_style that's not a preserve-inline
# (results in very similar validation as js version)
if bs not in ['expand', 'collapse', 'end-expand', 'none']:
raise(Exception(
'opts.brace_style must be "expand", "collapse", "end-expand", or "none".'))
self._options.brace_style = bs
source_text = source_text or '' source_text = source_text or ''
if self._options.disabled: if self._options.disabled:

View File

@ -23,67 +23,71 @@
# SOFTWARE. # SOFTWARE.
class BeautifierOptions: from ..core.options import Options as BaseOptions
def __init__(self):
self.indent_size = 4 OPERATOR_POSITION = [
self.indent_char = ' ' 'before-newline',
self.indent_with_tabs = False 'after-newline',
self.eol = 'auto' 'preserve-newline'
self.preserve_newlines = True ]
self.max_preserve_newlines = 10
self.space_in_paren = False class BeautifierOptions(BaseOptions):
self.space_in_empty_paren = False def __init__(self, options=None):
self.e4x = False super(BeautifierOptions, self).__init__(options, 'js')
self.jslint_happy = False
self.space_after_anon_function = False
self.brace_style = 'collapse'
self.keep_array_indentation = False
self.space_before_conditional = True
self.keep_function_indentation = False
self.eval_code = False
self.unescape_strings = False
self.wrap_line_length = 0
self.unindent_chained_methods = False
self.break_chained_methods = False
self.end_with_newline = False
self.comma_first = False
self.operator_position = 'before-newline'
self.disabled = False
self.css = None self.css = None
self.js = None self.js = None
self.html = None self.html = None
# compatibility, re
raw_brace_style = getattr(self.raw_options, 'brace_style', None)
if raw_brace_style == "expand-strict": # graceful handling of deprecated option
setattr(self.raw_options, 'brace_style', "expand")
elif raw_brace_style == "collapse-preserve-inline": # graceful handling of deprecated option
setattr(self.raw_options, 'brace_style', "collapse,preserve-inline")
# elif bool(self.raw_options.braces_on_own_line): # graceful handling of deprecated option
# raw_brace_style = "expand": "collapse"
# elif raw_brace_style is None: # Nothing exists to set it
# setattr(self.raw_options, 'brace_style', "collapse")
# preserve-inline in delimited string will trigger brace_preserve_inline, everything
# else is considered a brace_style and the last one only will have an effect
brace_style_split = self._get_selection('brace_style', ['collapse', 'expand', 'end-expand', 'none', 'preserve-inline'])
# preserve-inline in delimited string will trigger brace_preserve_inline
# Everything else is considered a brace_style and the last one only will
# have an effect
# specify defaults in case one half of meta-option is missing
self.brace_preserve_inline = False
self.brace_style = "collapse"
for bs in brace_style_split:
if bs == "preserve-inline":
self.brace_preserve_inline = True
else:
self.brace_style = bs
self.unindent_chained_methods = self._get_boolean('unindent_chained_methods')
self.break_chained_methods = self._get_boolean('break_chained_methods')
self.space_in_paren = self._get_boolean('space_in_paren')
self.space_in_empty_paren = self._get_boolean('space_in_empty_paren')
self.jslint_happy = self._get_boolean('jslint_happy')
self.space_after_anon_function = self._get_boolean('space_after_anon_function')
self.keep_array_indentation = self._get_boolean('keep_array_indentation')
self.space_before_conditional = self._get_boolean('space_before_conditional', True)
self.unescape_strings = self._get_boolean('unescape_strings')
self.e4x = self._get_boolean('e4x')
self.comma_first = self._get_boolean('comma_first')
self.operator_position = self._get_selection('operator_position', OPERATOR_POSITION)[0]
# For testing of beautify preserve:start directive # For testing of beautify preserve:start directive
self.test_output_raw = False self.test_output_raw = False
self.editorconfig = False self.editorconfig = False
def __repr__(self): # force opts.space_after_anon_function to true if opts.jslint_happy
return \ if self.jslint_happy:
"""indent_size = %d self.space_after_anon_function = True
indent_char = [%s]
preserve_newlines = %s self.eval_code = False
max_preserve_newlines = %d
space_in_paren = %s
jslint_happy = %s
space_after_anon_function = %s
indent_with_tabs = %s
brace_style = %s
keep_array_indentation = %s
eval_code = %s
wrap_line_length = %s
unescape_strings = %s
""" % (self.indent_size,
self.indent_char,
self.preserve_newlines,
self.max_preserve_newlines,
self.space_in_paren,
self.jslint_happy,
self.space_after_anon_function,
self.indent_with_tabs,
self.brace_style,
self.keep_array_indentation,
self.eval_code,
self.wrap_line_length,
self.unescape_strings,
)

View File

@ -115,7 +115,7 @@ class Tokenizer(BaseTokenizer):
line_starters = line_starters line_starters = line_starters
def __init__(self, input_string, opts): def __init__(self, input_string, opts):
BaseTokenizer.__init__(self, input_string, opts) super(Tokenizer, self).__init__(input_string, opts)
self.in_html_comment = False self.in_html_comment = False
self.has_char_escapes = False self.has_char_escapes = False

View File

@ -55,8 +55,6 @@ class TestJSBeautifier(unittest.TestCase):
default_options.indent_char = ' ' default_options.indent_char = ' '
default_options.preserve_newlines = true default_options.preserve_newlines = true
default_options.jslint_happy = false default_options.jslint_happy = false
default_options.keep_array_indentation = true
default_options.brace_style = 'collapse'
default_options.indent_level = 0 default_options.indent_level = 0
default_options.break_chained_methods = false default_options.break_chained_methods = false
default_options.eol = '\n' default_options.eol = '\n'
@ -65,9 +63,6 @@ class TestJSBeautifier(unittest.TestCase):
default_options.indent_char = ' ' default_options.indent_char = ' '
default_options.preserve_newlines = true default_options.preserve_newlines = true
default_options.jslint_happy = false default_options.jslint_happy = false
default_options.keep_array_indentation = false
default_options.brace_style = 'collapse'
default_options.operator_position = 'before-newline'
self.options = copy.copy(default_options) self.options = copy.copy(default_options)
@ -416,6 +411,47 @@ class TestJSBeautifier(unittest.TestCase):
' e();\n' + ' e();\n' +
'}') '}')
# Brace style permutations - ()
self.reset_options()
bt(
'var a ={a: 2};\n' +
'var a ={a: 2};',
# -- output --
'var a = {\n' +
' a: 2\n' +
'};\n' +
'var a = {\n' +
' a: 2\n' +
'};')
bt(
'//case 1\n' +
'if (a == 1){}\n' +
'//case 2\n' +
'else if (a == 2){}',
# -- output --
'//case 1\n' +
'if (a == 1) {}\n' +
'//case 2\n' +
'else if (a == 2) {}')
bt(
'if(1){2}else{3}',
# -- output --
'if (1) {\n' +
' 2\n' +
'} else {\n' +
' 3\n' +
'}')
bt(
'try{a();}catch(b){c();}catch(d){}finally{e();}',
# -- output --
'try {\n' +
' a();\n' +
'} catch (b) {\n' +
' c();\n' +
'} catch (d) {} finally {\n' +
' e();\n' +
'}')
# Brace style permutations - (brace_style = ""collapse"") # Brace style permutations - (brace_style = ""collapse"")
self.reset_options() self.reset_options()
self.options.brace_style = 'collapse' self.options.brace_style = 'collapse'
@ -1059,6 +1095,54 @@ class TestJSBeautifier(unittest.TestCase):
#============================================================ #============================================================
# operator_position option - ensure no neswlines if preserve_newlines is false - (preserve_newlines = "false")
self.reset_options()
self.options.preserve_newlines = false
bt(
'var res = a + b - c / d * e % f;\n' +
'var res = g & h | i ^ j;\n' +
'var res = (k && l || m) ? n : o;\n' +
'var res = p >> q << r >>> s;\n' +
'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' +
'ac + -ad')
bt(
'var res = a + b\n' +
'- c /\n' +
'd * e\n' +
'%\n' +
'f;\n' +
' var res = g & h\n' +
'| i ^\n' +
'j;\n' +
'var res = (k &&\n' +
'l\n' +
'|| m) ?\n' +
'n\n' +
': o\n' +
';\n' +
'var res = p\n' +
'>> q <<\n' +
'r\n' +
'>>> s;\n' +
'var res\n' +
' = t\n' +
'\n' +
' === u !== v\n' +
' !=\n' +
'w\n' +
'== x >=\n' +
'y <= z > aa <\n' +
'ab;\n' +
'ac +\n' +
'-ad',
# -- output --
'var res = a + b - c / d * e % f;\n' +
'var res = g & h | i ^ j;\n' +
'var res = (k && l || m) ? n : o;\n' +
'var res = p >> q << r >>> s;\n' +
'var res = t === u !== v != w == x >= y <= z > aa < ab;\n' +
'ac + -ad')
# operator_position option - ensure no neswlines if preserve_newlines is false - (operator_position = ""before-newline"", preserve_newlines = "false") # operator_position option - ensure no neswlines if preserve_newlines is false - (operator_position = ""before-newline"", preserve_newlines = "false")
self.reset_options() self.reset_options()
self.options.operator_position = 'before-newline' self.options.operator_position = 'before-newline'
@ -1208,7 +1292,7 @@ class TestJSBeautifier(unittest.TestCase):
#============================================================ #============================================================
# operator_position option - set to "before-newline" (default value) # operator_position option - set to "before-newline" (default value) - ()
self.reset_options() self.reset_options()
# comprehensive, various newlines # comprehensive, various newlines
@ -1328,6 +1412,127 @@ class TestJSBeautifier(unittest.TestCase):
' aRiver);\n' + ' aRiver);\n' +
'}') '}')
# operator_position option - set to "before-newline" (default value) - (operator_position = ""before-newline"")
self.reset_options()
self.options.operator_position = 'before-newline'
# comprehensive, various newlines
bt(
'var res = a + b\n' +
'- c /\n' +
'd * e\n' +
'%\n' +
'f;\n' +
' var res = g & h\n' +
'| i ^\n' +
'j;\n' +
'var res = (k &&\n' +
'l\n' +
'|| m) ?\n' +
'n\n' +
': o\n' +
';\n' +
'var res = p\n' +
'>> q <<\n' +
'r\n' +
'>>> s;\n' +
'var res\n' +
' = t\n' +
'\n' +
' === u !== v\n' +
' !=\n' +
'w\n' +
'== x >=\n' +
'y <= z > aa <\n' +
'ab;\n' +
'ac +\n' +
'-ad',
# -- output --
'var res = a + b -\n' +
' c /\n' +
' d * e %\n' +
' f;\n' +
'var res = g & h |\n' +
' i ^\n' +
' j;\n' +
'var res = (k &&\n' +
' l ||\n' +
' m) ?\n' +
' n :\n' +
' o;\n' +
'var res = p >>\n' +
' q <<\n' +
' r >>>\n' +
' s;\n' +
'var res = t\n' +
'\n' +
' ===\n' +
' u !== v !=\n' +
' w ==\n' +
' x >=\n' +
' y <= z > aa <\n' +
' ab;\n' +
'ac +\n' +
' -ad')
# colon special case
bt(
'var a = {\n' +
' b\n' +
': bval,\n' +
' c:\n' +
'cval\n' +
' ,d: dval\n' +
'};\n' +
'var e = f ? g\n' +
': h;\n' +
'var i = j ? k :\n' +
'l;',
# -- output --
'var a = {\n' +
' b: bval,\n' +
' c: cval,\n' +
' d: dval\n' +
'};\n' +
'var e = f ? g :\n' +
' h;\n' +
'var i = j ? k :\n' +
' l;')
# catch-all, includes brackets and other various code
bt(
'var d = 1;\n' +
'if (a === b\n' +
' && c) {\n' +
' d = (c * everything\n' +
' / something_else) %\n' +
' b;\n' +
' e\n' +
' += d;\n' +
'\n' +
'} else if (!(complex && simple) ||\n' +
' (emotion && emotion.name === "happy")) {\n' +
' cryTearsOfJoy(many ||\n' +
' anOcean\n' +
' || aRiver);\n' +
'}',
# -- output --
'var d = 1;\n' +
'if (a === b &&\n' +
' c) {\n' +
' d = (c * everything /\n' +
' something_else) %\n' +
' b;\n' +
' e\n' +
' += d;\n' +
'\n' +
'} else if (!(complex && simple) ||\n' +
' (emotion && emotion.name === "happy")) {\n' +
' cryTearsOfJoy(many ||\n' +
' anOcean ||\n' +
' aRiver);\n' +
'}')
#============================================================ #============================================================
# operator_position option - set to "after_newline" # operator_position option - set to "after_newline"

View File

@ -685,26 +685,12 @@ exports.test_data = {
], ],
tests: [{ tests: [{
fragment: true, fragment: true,
input_: '{{#if 0}}\n' + input_: '{{#if 0}}\n' + ' <div>\n' + ' </div>\n' + '{{/if}}',
' <div>\n' + output: '{{#if 0}}\n' + '<div>\n' + '</div>\n' + '{{/if}}'
' </div>\n' +
'{{/if}}',
output: '{{#if 0}}\n' +
'<div>\n' +
'</div>\n' +
'{{/if}}'
}, { }, {
fragment: true, fragment: true,
input_: '<div>\n' + input_: '<div>\n' + '{{#each thing}}\n' + ' {{name}}\n' + '{{/each}}\n' + '</div>',
'{{#each thing}}\n' + output: '<div>\n' + ' {{#each thing}}\n' + ' {{name}}\n' + ' {{/each}}\n' + '</div>'
' {{name}}\n' +
'{{/each}}\n' +
'</div>',
output: '<div>\n' +
' {{#each thing}}\n' +
' {{name}}\n' +
' {{/each}}\n' +
'</div>'
}, },
{ {
input_: [ input_: [
@ -858,59 +844,20 @@ exports.test_data = {
input_: '{{#if words}}^^^&content$$${{/if}}', input_: '{{#if words}}^^^&content$$${{/if}}',
output: '{{#if words}}^^^&content$$${{/if}}' output: '{{#if words}}^^^&content$$${{/if}}'
}, { }, {
unchanged: '{{#if 1}}\n' + unchanged: '{{#if 1}}\n' + ' <div>\n' + ' </div>\n' + '{{/if}}'
' <div>\n' +
' </div>\n' +
'{{/if}}'
}, { }, {
input_: '{{#if 1}}\n' + input_: '{{#if 1}}\n' + '<div>\n' + '</div>\n' + '{{/if}}',
'<div>\n' + output: '{{#if 1}}\n' + ' <div>\n' + ' </div>\n' + '{{/if}}'
'</div>\n' +
'{{/if}}',
output: '{{#if 1}}\n' +
' <div>\n' +
' </div>\n' +
'{{/if}}'
}, { }, {
unchanged: '<div>\n' + unchanged: '<div>\n' + ' {{#if 1}}\n' + ' {{/if}}\n' + '</div>'
' {{#if 1}}\n' +
' {{/if}}\n' +
'</div>'
}, { }, {
input_: '<div>\n' + input_: '<div>\n' + '{{#if 1}}\n' + '{{/if}}\n' + '</div>',
'{{#if 1}}\n' + output: '<div>\n' + ' {{#if 1}}\n' + ' {{/if}}\n' + '</div>'
'{{/if}}\n' +
'</div>',
output: '<div>\n' +
' {{#if 1}}\n' +
' {{/if}}\n' +
'</div>'
}, { }, {
input_: '{{#if}}\n' + input_: '{{#if}}\n' + '{{#each}}\n' + '{{#if}}\n' + '^^^&content$$$\n' + '{{/if}}\n' + '{{#if}}\n' + '^^^&content$$$\n' + '{{/if}}\n' + '{{/each}}\n' + '{{/if}}',
'{{#each}}\n' + output: '{{#if}}\n' + ' {{#each}}\n' + ' {{#if}}\n' + ' ^^^&content$$$\n' + ' {{/if}}\n' + ' {{#if}}\n' + ' ^^^&content$$$\n' + ' {{/if}}\n' + ' {{/each}}\n' + '{{/if}}'
'{{#if}}\n' +
'^^^&content$$$\n' +
'{{/if}}\n' +
'{{#if}}\n' +
'^^^&content$$$\n' +
'{{/if}}\n' +
'{{/each}}\n' +
'{{/if}}',
output: '{{#if}}\n' +
' {{#each}}\n' +
' {{#if}}\n' +
' ^^^&content$$$\n' +
' {{/if}}\n' +
' {{#if}}\n' +
' ^^^&content$$$\n' +
' {{/if}}\n' +
' {{/each}}\n' +
'{{/if}}'
}, { }, {
unchanged: '{{#if 1}}\n' + unchanged: '{{#if 1}}\n' + ' <div>\n' + ' </div>\n' + '{{/if}}'
' <div>\n' +
' </div>\n' +
'{{/if}}'
}, },
// Issue #576 -- Indent Formatting with Handlebars // Issue #576 -- Indent Formatting with Handlebars
@ -982,42 +929,14 @@ exports.test_data = {
// Test {{else}} aligned with {{#if}} and {{/if}} // Test {{else}} aligned with {{#if}} and {{/if}}
{ {
input_: '{{#if 1}}\n' + input_: '{{#if 1}}\n' + ' ^^^&content$$$\n' + ' {{else}}\n' + ' ^^^&content$$$\n' + '{{/if}}',
' ^^^&content$$$\n' + output: '{{#if 1}}\n' + ' ^^^&content$$$\n' + '{{else}}\n' + ' ^^^&content$$$\n' + '{{/if}}'
' {{else}}\n' +
' ^^^&content$$$\n' +
'{{/if}}',
output: '{{#if 1}}\n' +
' ^^^&content$$$\n' +
'{{else}}\n' +
' ^^^&content$$$\n' +
'{{/if}}'
}, { }, {
input_: '{{#if 1}}\n' + input_: '{{#if 1}}\n' + ' {{else}}\n' + ' {{/if}}',
' {{else}}\n' + output: '{{#if 1}}\n' + '{{else}}\n' + '{{/if}}'
' {{/if}}',
output: '{{#if 1}}\n' +
'{{else}}\n' +
'{{/if}}'
}, { }, {
input_: '{{#if thing}}\n' + input_: '{{#if thing}}\n' + '{{#if otherthing}}\n' + ' ^^^&content$$$\n' + ' {{else}}\n' + '^^^&content$$$\n' + ' {{/if}}\n' + ' {{else}}\n' + '^^^&content$$$\n' + '{{/if}}',
'{{#if otherthing}}\n' + output: '{{#if thing}}\n' + ' {{#if otherthing}}\n' + ' ^^^&content$$$\n' + ' {{else}}\n' + ' ^^^&content$$$\n' + ' {{/if}}\n' + '{{else}}\n' + ' ^^^&content$$$\n' + '{{/if}}'
' ^^^&content$$$\n' +
' {{else}}\n' +
'^^^&content$$$\n' +
' {{/if}}\n' +
' {{else}}\n' +
'^^^&content$$$\n' +
'{{/if}}',
output: '{{#if thing}}\n' +
' {{#if otherthing}}\n' +
' ^^^&content$$$\n' +
' {{else}}\n' +
' ^^^&content$$$\n' +
' {{/if}}\n' +
'{{else}}\n' +
' ^^^&content$$$\n' +
'{{/if}}'
}, },
{ {
comment: 'ISSUE #800 and #1123: else if and #unless', comment: 'ISSUE #800 and #1123: else if and #unless',
@ -1089,11 +1008,7 @@ exports.test_data = {
], ],
tests: [{ tests: [{
input_: '{{#if test}}<div></div>{{else}}<div></div>{{/if}}', input_: '{{#if test}}<div></div>{{else}}<div></div>{{/if}}',
output: '{{#if test}}\n' + output: '{{#if test}}\n' + ' <div></div>\n' + '{{else}}\n' + ' <div></div>\n' + '{{/if}}'
' <div></div>\n' +
'{{else}}\n' +
' <div></div>\n' +
'{{/if}}'
}, { }, {
unchanged: '{{#if test}}<span></span>{{else}}<span></span>{{/if}}' unchanged: '{{#if test}}<span></span>{{else}}<span></span>{{/if}}'
}, },
@ -1835,14 +1750,8 @@ exports.test_data = {
], ],
tests: [{ tests: [{
fragment: true, fragment: true,
input_: '<div>\n' + input_: '<div>\n' + '<div>\n' + '</div>\n' + '</div>',
'<div>\n' + output: '<div>\n' + ' <div>\n' + ' </div>\n' + '</div>'
'</div>\n' +
'</div>',
output: '<div>\n' +
' <div>\n' +
' </div>\n' +
'</div>'
}] }]
}, { }, {
name: "Do not indent html inner html by default", name: "Do not indent html inner html by default",
@ -1935,10 +1844,8 @@ exports.test_data = {
input: '<div>\n\tfoo\n</div>', input: '<div>\n\tfoo\n</div>',
output: '<div> foo </div>' output: '<div> foo </div>'
}, { }, {
input_: '<div>Should not</div>\n\n\n' + input_: '<div>Should not</div>\n\n\n' + '<div>preserve newlines</div>',
'<div>preserve newlines</div>', output: '<div>Should not</div>\n' + '<div>preserve newlines</div>'
output: '<div>Should not</div>\n' +
'<div>preserve newlines</div>'
}, { }, {
input: [ input: [
'<header>', '<header>',
@ -1993,10 +1900,8 @@ exports.test_data = {
{ name: 'indent_size', value: "2" } { name: 'indent_size', value: "2" }
], ],
tests: [{ tests: [{
input_: '<div>Should</div>\n\n\n' + input_: '<div>Should</div>\n\n\n' + '<div>preserve zero newlines</div>',
'<div>preserve zero newlines</div>', output: '<div>Should</div>\n' + '<div>preserve zero newlines</div>'
output: '<div>Should</div>\n' +
'<div>preserve zero newlines</div>'
}, { }, {
input: [ input: [
'<header>', '<header>',
@ -2039,10 +1944,8 @@ exports.test_data = {
{ name: 'max_preserve_newlines', value: "1" } { name: 'max_preserve_newlines', value: "1" }
], ],
tests: [{ tests: [{
input_: '<div>Should</div>\n\n\n' + input_: '<div>Should</div>\n\n\n' + '<div>preserve one newline</div>',
'<div>preserve one newline</div>', output: '<div>Should</div>\n\n' + '<div>preserve one newline</div>'
output: '<div>Should</div>\n\n' +
'<div>preserve one newline</div>'
}, { }, {
input: [ input: [
'<header>', '<header>',
@ -2088,8 +1991,7 @@ exports.test_data = {
{ name: 'max_preserve_newlines', value: "null" } { name: 'max_preserve_newlines', value: "null" }
], ],
tests: [{ tests: [{
unchanged: '<div>Should</div>\n\n\n' + unchanged: '<div>Should</div>\n\n\n' + '<div>preserve zero newlines</div>'
'<div>preserve zero newlines</div>'
}, { }, {
unchanged: [ unchanged: [
'<header>', '<header>',

View File

@ -36,8 +36,6 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
indent_char: ' ', indent_char: ' ',
preserve_newlines: true, preserve_newlines: true,
jslint_happy: false, jslint_happy: false,
keep_array_indentation: false,
brace_style: 'collapse',
space_before_conditional: true, space_before_conditional: true,
break_chained_methods: false, break_chained_methods: false,
selector_separator: '\n', selector_separator: '\n',

View File

@ -52,8 +52,6 @@ class TestJSBeautifier(unittest.TestCase):
default_options.indent_char = ' ' default_options.indent_char = ' '
default_options.preserve_newlines = true default_options.preserve_newlines = true
default_options.jslint_happy = false default_options.jslint_happy = false
default_options.keep_array_indentation = true
default_options.brace_style = 'collapse'
default_options.indent_level = 0 default_options.indent_level = 0
default_options.break_chained_methods = false default_options.break_chained_methods = false
default_options.eol = '\n' default_options.eol = '\n'

View File

@ -31,10 +31,7 @@ exports.test_data = {
{ name: "indent_size", value: "4" }, { name: "indent_size", value: "4" },
{ name: "indent_char", value: "' '" }, { name: "indent_char", value: "' '" },
{ name: "preserve_newlines", value: "true" }, { name: "preserve_newlines", value: "true" },
{ name: "jslint_happy", value: "false" }, { name: "jslint_happy", value: "false" }
{ name: "keep_array_indentation", value: "false" },
{ name: "brace_style", value: "'collapse'" },
{ name: "operator_position", value: "'before-newline'" }
], ],
groups: [{ groups: [{
name: "Unicode Support", name: "Unicode Support",
@ -257,6 +254,17 @@ exports.test_data = {
}, },
// brace_style collapse - Shouldn't preserve if no newlines (uses collapse styling) // brace_style collapse - Shouldn't preserve if no newlines (uses collapse styling)
{
options: [],
ibo: '',
iao: '',
ibc: '',
iac: '',
obo: ' ',
oao: '\n ',
obc: '\n',
oac: ' '
},
{ {
options: [ options: [
{ name: "brace_style", value: "'collapse'" } { name: "brace_style", value: "'collapse'" }
@ -301,16 +309,10 @@ exports.test_data = {
output: 'if (1)<obo>{<oao>2<obc>}<oac>else<obo>{<oao>3<obc>}' output: 'if (1)<obo>{<oao>2<obc>}<oac>else<obo>{<oao>3<obc>}'
}, },
{ {
input: 'try<ibo>{<iao>a();<ibc>}<iac>' + input: 'try<ibo>{<iao>a();<ibc>}<iac>' + 'catch(b)<ibo>{<iao>c();<ibc>}<iac>' + 'catch(d)<ibo>{}<iac>' + 'finally<ibo>{<iao>e();<ibc>}',
'catch(b)<ibo>{<iao>c();<ibc>}<iac>' +
'catch(d)<ibo>{}<iac>' +
'finally<ibo>{<iao>e();<ibc>}',
output: output:
// expected // expected
'try<obo>{<oao>a();<obc>}<oac>' + 'try<obo>{<oao>a();<obc>}<oac>' + 'catch (b)<obo>{<oao>c();<obc>}<oac>' + 'catch (d)<obo>{}<oac>' + 'finally<obo>{<oao>e();<obc>}'
'catch (b)<obo>{<oao>c();<obc>}<oac>' +
'catch (d)<obo>{}<oac>' +
'finally<obo>{<oao>e();<obc>}'
} }
] ]
}, { }, {
@ -573,6 +575,12 @@ exports.test_data = {
}, { }, {
name: "operator_position option - ensure no neswlines if preserve_newlines is false", name: "operator_position option - ensure no neswlines if preserve_newlines is false",
matrix: [{ matrix: [{
options: [
// test for default
// { name: "operator_position", value: "'before-newline'" },
{ name: "preserve_newlines", value: "false" }
]
}, {
options: [ options: [
{ name: "operator_position", value: "'before-newline'" }, { name: "operator_position", value: "'before-newline'" },
{ name: "preserve_newlines", value: "false" } { name: "preserve_newlines", value: "false" }
@ -596,6 +604,16 @@ exports.test_data = {
}] }]
}, { }, {
name: 'operator_position option - set to "before-newline" (default value)', name: 'operator_position option - set to "before-newline" (default value)',
matrix: [{
options: [
// test for default
// { name: "operator_position", value: "'before-newline'" }
]
}, {
options: [
{ name: "operator_position", value: "'before-newline'" }
]
}],
tests: [{ tests: [{
comment: 'comprehensive, various newlines', comment: 'comprehensive, various newlines',
input: inputlib.operator_position.comprehensive, input: inputlib.operator_position.comprehensive,
@ -2749,8 +2767,7 @@ exports.test_data = {
' var obj = {<oao>' + //NL in templates ' var obj = {<oao>' + //NL in templates
'<oaot><oaot>a: function() { console.log("test"); },', '<oaot><oaot>a: function() { console.log("test"); },',
' b()<obo><obot><obot>{<oao>' + //NL in templates ' b()<obo><obot><obot>{<oao>' + //NL in templates
'<oaot><oaot><oaot>console.log("test2");' + '<oaot><oaot><oaot>console.log("test2");' + '<obc> }' + //NL in templates
'<obc> }' + //NL in templates
'<obc> };' + //NL in templates '<obc> };' + //NL in templates
'<obc>}' '<obc>}'
] ]