js-beautify
Advanced tools
Comparing version 1.4.0 to 1.4.1
@@ -72,3 +72,5 @@ /*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */ | ||
var pos = -1, ch; | ||
var pos = -1, | ||
ch; | ||
function next() { | ||
@@ -78,9 +80,11 @@ ch = source_text.charAt(++pos); | ||
} | ||
function peek() { | ||
return source_text.charAt(pos+1); | ||
return source_text.charAt(pos + 1); | ||
} | ||
function eatString(comma) { | ||
var start = pos; | ||
while(next()){ | ||
if (ch === "\\"){ | ||
while (next()) { | ||
if (ch === "\\") { | ||
next(); | ||
@@ -107,4 +111,3 @@ next(); | ||
var start = pos; | ||
do{ | ||
}while (whiteRe.test(next())); | ||
do {} while (whiteRe.test(next())); | ||
return pos !== start + 1; | ||
@@ -118,3 +121,3 @@ } | ||
if (ch === "*" && peek() === "/") { | ||
pos ++; | ||
pos++; | ||
break; | ||
@@ -129,3 +132,3 @@ } | ||
function lookBack(str) { | ||
return source_text.substring(pos-str.length, pos).toLowerCase() === str; | ||
return source_text.substring(pos - str.length, pos).toLowerCase() === str; | ||
} | ||
@@ -137,2 +140,3 @@ | ||
var indentLevel = 0; | ||
function indent() { | ||
@@ -142,2 +146,3 @@ indentLevel++; | ||
} | ||
function outdent() { | ||
@@ -185,3 +190,3 @@ indentLevel--; | ||
while(true) { | ||
while (true) { | ||
var isAfterSpace = skipWhitespace(); | ||
@@ -209,17 +214,17 @@ | ||
if (lookBack("url")) { | ||
output.push(ch); | ||
eatWhitespace(); | ||
if (next()) { | ||
if (ch !== ')' && ch !== '"' && ch !== '\'') { | ||
output.push(eatString(')')); | ||
} else { | ||
pos--; | ||
output.push(ch); | ||
eatWhitespace(); | ||
if (next()) { | ||
if (ch !== ')' && ch !== '"' && ch !== '\'') { | ||
output.push(eatString(')')); | ||
} else { | ||
pos--; | ||
} | ||
} | ||
} | ||
} else { | ||
if (isAfterSpace) { | ||
print.singleSpace(); | ||
} | ||
output.push(ch); | ||
eatWhitespace(); | ||
if (isAfterSpace) { | ||
print.singleSpace(); | ||
} | ||
output.push(ch); | ||
eatWhitespace(); | ||
} | ||
@@ -234,3 +239,3 @@ } else if (ch === ')') { | ||
output.push(ch); | ||
} else if (ch === '[' || ch === '=') { // no whitespace before or after | ||
} else if (ch === '[' || ch === '=') { // no whitespace before or after | ||
eatWhitespace(); | ||
@@ -237,0 +242,0 @@ output.push(ch); |
@@ -43,2 +43,3 @@ /*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */ | ||
The options are: | ||
indent_inner_html (default false) — indent <head> and <body> sections, | ||
indent_size (default 4) — indentation size, | ||
@@ -54,2 +55,3 @@ indent_char (default space) — character to indent with, | ||
max_preserve_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk | ||
indent_handlebars (default false) - format and indent {{#foo}} and {{/foo}} | ||
@@ -59,2 +61,3 @@ e.g. | ||
style_html(html_source, { | ||
'indent_inner_html': false, | ||
'indent_size': 2, | ||
@@ -66,3 +69,4 @@ 'indent_char': ' ', | ||
'preserve_newlines': true, | ||
'max_preserve_newlines': 5 | ||
'max_preserve_newlines': 5, | ||
'indent_handlebars': false | ||
}); | ||
@@ -82,385 +86,453 @@ */ | ||
function style_html(html_source, 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. | ||
var multi_parser, | ||
indent_size, | ||
indent_character, | ||
wrap_line_length, | ||
brace_style, | ||
unformatted, | ||
preserve_newlines, | ||
max_preserve_newlines; | ||
var multi_parser, | ||
indent_inner_html, | ||
indent_size, | ||
indent_character, | ||
wrap_line_length, | ||
brace_style, | ||
unformatted, | ||
preserve_newlines, | ||
max_preserve_newlines; | ||
options = options || {}; | ||
options = options || {}; | ||
// backwards compatibility to 1.3.4 | ||
if(options.wrap_line_length == undefined && options.max_char != undefined) { | ||
options.wrap_line_length = options.max_char; | ||
} | ||
// 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; | ||
} | ||
indent_size = parseInt(options.indent_size || 4); | ||
indent_character = options.indent_char || ' '; | ||
brace_style = options.brace_style || 'collapse'; | ||
wrap_line_length = options.wrap_line_length === 0 ? 32786 : parseInt(options.wrap_line_length || 250); | ||
unformatted = options.unformatted || ['a', 'span', 'bdo', 'em', 'strong', 'dfn', 'code', 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'q', 'sub', 'sup', 'tt', 'i', 'b', 'big', 'small', 'u', 's', 'strike', 'font', 'ins', 'del', 'pre', 'address', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']; | ||
preserve_newlines = options.preserve_newlines || true; | ||
max_preserve_newlines = preserve_newlines ? parseInt(options.max_preserve_newlines || 32786) : 0; | ||
indent_inner_html = options.indent_inner_html || false; | ||
indent_size = parseInt(options.indent_size || 4, 10); | ||
indent_character = options.indent_char || ' '; | ||
brace_style = options.brace_style || 'collapse'; | ||
wrap_line_length = options.wrap_line_length === 0 ? 32786 : parseInt(options.wrap_line_length || 250, 10); | ||
unformatted = options.unformatted || ['a', 'span', 'bdo', 'em', 'strong', 'dfn', 'code', 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'q', 'sub', 'sup', 'tt', 'i', 'b', 'big', 'small', 'u', 's', 'strike', 'font', 'ins', 'del', 'pre', 'address', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']; | ||
preserve_newlines = options.preserve_newlines || true; | ||
max_preserve_newlines = preserve_newlines ? parseInt(options.max_preserve_newlines || 32786, 10) : 0; | ||
indent_handlebars = options.indent_handlebars || false; | ||
function Parser() { | ||
function Parser() { | ||
this.pos = 0; //Parser position | ||
this.token = ''; | ||
this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT | ||
this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values | ||
parent: 'parent1', | ||
parentcount: 1, | ||
parent1: '' | ||
}; | ||
this.tag_type = ''; | ||
this.token_text = this.last_token = this.last_text = this.token_type = ''; | ||
this.newlines = 0; | ||
this.indent_content = false; | ||
this.Utils = { //Uilities made available to the various functions | ||
whitespace: "\n\r\t ".split(''), | ||
single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed,?php,?,?='.split(','), //all the single tags for HTML | ||
extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them | ||
in_array: function (what, arr) { | ||
for (var i=0; i<arr.length; i++) { | ||
if (what === arr[i]) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
}; | ||
this.traverse_whitespace = function() { | ||
var input_char = ''; | ||
input_char = this.input.charAt(this.pos); | ||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) { | ||
this.pos = 0; //Parser position | ||
this.token = ''; | ||
this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT | ||
this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values | ||
parent: 'parent1', | ||
parentcount: 1, | ||
parent1: '' | ||
}; | ||
this.tag_type = ''; | ||
this.token_text = this.last_token = this.last_text = this.token_type = ''; | ||
this.newlines = 0; | ||
while (this.Utils.in_array(input_char, this.Utils.whitespace)) { | ||
if(preserve_newlines && input_char === '\n' && this.newlines <= max_preserve_newlines) { | ||
this.newlines += 1; | ||
} | ||
this.indent_content = indent_inner_html; | ||
this.pos++; | ||
input_char = this.input.charAt(this.pos); | ||
} | ||
return true; | ||
} | ||
return false; | ||
} | ||
this.Utils = { //Uilities made available to the various functions | ||
whitespace: "\n\r\t ".split(''), | ||
single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed,?php,?,?='.split(','), //all the single tags for HTML | ||
extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them | ||
in_array: function(what, arr) { | ||
for (var i = 0; i < arr.length; i++) { | ||
if (what === arr[i]) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
}; | ||
this.get_content = function () { //function to capture regular content between tags | ||
this.traverse_whitespace = function() { | ||
var input_char = ''; | ||
var input_char = '', | ||
content = [], | ||
space = false; //if a space is needed | ||
input_char = this.input.charAt(this.pos); | ||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) { | ||
this.newlines = 0; | ||
while (this.Utils.in_array(input_char, this.Utils.whitespace)) { | ||
if (preserve_newlines && input_char === '\n' && this.newlines <= max_preserve_newlines) { | ||
this.newlines += 1; | ||
} | ||
while (this.input.charAt(this.pos) !== '<') { | ||
if (this.pos >= this.input.length) { | ||
return content.length?content.join(''):['', 'TK_EOF']; | ||
} | ||
this.pos++; | ||
input_char = this.input.charAt(this.pos); | ||
} | ||
return true; | ||
} | ||
return false; | ||
}; | ||
if (this.traverse_whitespace()) { | ||
if (content.length) { | ||
space = true; | ||
} | ||
continue; //don't want to insert unnecessary space | ||
} | ||
this.get_content = function() { //function to capture regular content between tags | ||
input_char = this.input.charAt(this.pos); | ||
this.pos++; | ||
var input_char = '', | ||
content = [], | ||
space = false; //if a space is needed | ||
if (space) { | ||
if (this.line_char_count >= this.wrap_line_length) { //insert a line when the wrap_line_length is reached | ||
this.print_newline(false, content); | ||
this.print_indentation(content); | ||
} | ||
else { | ||
this.line_char_count++; | ||
content.push(' '); | ||
} | ||
space = false; | ||
} | ||
this.line_char_count++; | ||
content.push(input_char); //letter at-a-time (or string) inserted to an array | ||
} | ||
return content.length?content.join(''):''; | ||
}; | ||
while (this.input.charAt(this.pos) !== '<') { | ||
if (this.pos >= this.input.length) { | ||
return content.length ? content.join('') : ['', 'TK_EOF']; | ||
} | ||
this.get_contents_to = function (name) { //get the full content of a script or style to pass to js_beautify | ||
if (this.pos === this.input.length) { | ||
return ['', 'TK_EOF']; | ||
} | ||
var input_char = ''; | ||
var content = ''; | ||
var reg_match = new RegExp('</' + name + '\\s*>', 'igm'); | ||
reg_match.lastIndex = this.pos; | ||
var reg_array = reg_match.exec(this.input); | ||
var end_script = reg_array?reg_array.index:this.input.length; //absolute end of script | ||
if(this.pos < end_script) { //get everything in between the script tags | ||
content = this.input.substring(this.pos, end_script); | ||
this.pos = end_script; | ||
} | ||
return content; | ||
}; | ||
if (this.traverse_whitespace()) { | ||
if (content.length) { | ||
space = true; | ||
} | ||
continue; //don't want to insert unnecessary space | ||
} | ||
this.record_tag = function (tag){ //function to record a tag and its parent in this.tags Object | ||
if (this.tags[tag + 'count']) { //check for the existence of this tag type | ||
this.tags[tag + 'count']++; | ||
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level | ||
} | ||
else { //otherwise initialize this tag type | ||
this.tags[tag + 'count'] = 1; | ||
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level | ||
} | ||
this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent) | ||
this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1') | ||
}; | ||
if (indent_handlebars) { | ||
// Handlebars parsing is complicated. | ||
// {{#foo}} and {{/foo}} are formatted tags. | ||
// {{something}} should get treated as content, except: | ||
// {{else}} specifically behaves like {{#if}} and {{/if}} | ||
var peek3 = this.input.substr(this.pos, 3); | ||
if (peek3 === '{{#' || peek3 === '{{/') { | ||
// These are tags and not content. | ||
break; | ||
} else if (this.input.substr(this.pos, 2) === '{{') { | ||
if (this.get_tag(true) === '{{else}}') { | ||
break; | ||
} | ||
} | ||
} | ||
this.retrieve_tag = function (tag) { //function to retrieve the opening tag to the corresponding closer | ||
if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it | ||
var temp_parent = this.tags.parent; //check to see if it's a closable tag. | ||
while (temp_parent) { //till we reach '' (the initial value); | ||
if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it | ||
break; | ||
} | ||
temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree | ||
} | ||
if (temp_parent) { //if we caught something | ||
this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly | ||
this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent | ||
} | ||
delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference... | ||
delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself | ||
if (this.tags[tag + 'count'] === 1) { | ||
delete this.tags[tag + 'count']; | ||
} | ||
else { | ||
this.tags[tag + 'count']--; | ||
} | ||
} | ||
}; | ||
input_char = this.input.charAt(this.pos); | ||
this.pos++; | ||
this.get_tag = function (peek) { //function to get a full tag and parse its type | ||
var input_char = '', | ||
content = [], | ||
comment = '', | ||
space = false, | ||
tag_start, tag_end, | ||
orig_pos = this.pos, | ||
orig_line_char_count = this.line_char_count; | ||
if (space) { | ||
if (this.line_char_count >= this.wrap_line_length) { //insert a line when the wrap_line_length is reached | ||
this.print_newline(false, content); | ||
this.print_indentation(content); | ||
} else { | ||
this.line_char_count++; | ||
content.push(' '); | ||
} | ||
space = false; | ||
} | ||
this.line_char_count++; | ||
content.push(input_char); //letter at-a-time (or string) inserted to an array | ||
} | ||
return content.length ? content.join('') : ''; | ||
}; | ||
peek = peek !== undefined ? peek : false; | ||
this.get_contents_to = function(name) { //get the full content of a script or style to pass to js_beautify | ||
if (this.pos === this.input.length) { | ||
return ['', 'TK_EOF']; | ||
} | ||
var input_char = ''; | ||
var content = ''; | ||
var reg_match = new RegExp('</' + name + '\\s*>', 'igm'); | ||
reg_match.lastIndex = this.pos; | ||
var reg_array = reg_match.exec(this.input); | ||
var end_script = reg_array ? reg_array.index : this.input.length; //absolute end of script | ||
if (this.pos < end_script) { //get everything in between the script tags | ||
content = this.input.substring(this.pos, end_script); | ||
this.pos = end_script; | ||
} | ||
return content; | ||
}; | ||
do { | ||
if (this.pos >= this.input.length) { | ||
if (peek) { | ||
this.pos = orig_pos; | ||
this.line_char_count = orig_line_char_count; | ||
} | ||
return content.length?content.join(''):['', 'TK_EOF']; | ||
} | ||
this.record_tag = function(tag) { //function to record a tag and its parent in this.tags Object | ||
if (this.tags[tag + 'count']) { //check for the existence of this tag type | ||
this.tags[tag + 'count']++; | ||
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level | ||
} else { //otherwise initialize this tag type | ||
this.tags[tag + 'count'] = 1; | ||
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level | ||
} | ||
this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent) | ||
this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1') | ||
}; | ||
input_char = this.input.charAt(this.pos); | ||
this.pos++; | ||
this.retrieve_tag = function(tag) { //function to retrieve the opening tag to the corresponding closer | ||
if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it | ||
var temp_parent = this.tags.parent; //check to see if it's a closable tag. | ||
while (temp_parent) { //till we reach '' (the initial value); | ||
if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it | ||
break; | ||
} | ||
temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree | ||
} | ||
if (temp_parent) { //if we caught something | ||
this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly | ||
this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent | ||
} | ||
delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference... | ||
delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself | ||
if (this.tags[tag + 'count'] === 1) { | ||
delete this.tags[tag + 'count']; | ||
} else { | ||
this.tags[tag + 'count']--; | ||
} | ||
} | ||
}; | ||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space | ||
space = true; | ||
continue; | ||
} | ||
this.indent_to_tag = function(tag) { | ||
// Match the indentation level to the last use of this tag, but don't remove it. | ||
if (!this.tags[tag + 'count']) { | ||
return; | ||
} | ||
var temp_parent = this.tags.parent; | ||
while (temp_parent) { | ||
if (tag + this.tags[tag + 'count'] === temp_parent) { | ||
break; | ||
} | ||
temp_parent = this.tags[temp_parent + 'parent']; | ||
} | ||
if (temp_parent) { | ||
this.indent_level = this.tags[tag + this.tags[tag + 'count']]; | ||
} | ||
}; | ||
if (input_char === "'" || input_char === '"') { | ||
input_char += this.get_unformatted(input_char); | ||
space = true; | ||
this.get_tag = function(peek) { //function to get a full tag and parse its type | ||
var input_char = '', | ||
content = [], | ||
comment = '', | ||
space = false, | ||
tag_start, tag_end, | ||
tag_start_char, | ||
orig_pos = this.pos, | ||
orig_line_char_count = this.line_char_count; | ||
} | ||
peek = peek !== undefined ? peek : false; | ||
if (input_char === '=') { //no space before = | ||
space = false; | ||
} | ||
do { | ||
if (this.pos >= this.input.length) { | ||
if (peek) { | ||
this.pos = orig_pos; | ||
this.line_char_count = orig_line_char_count; | ||
} | ||
return content.length ? content.join('') : ['', 'TK_EOF']; | ||
} | ||
if (content.length && content[content.length-1] !== '=' && input_char !== '>' && space) { | ||
//no space after = or before > | ||
if (this.line_char_count >= this.wrap_line_length) { | ||
this.print_newline(false, content); | ||
this.print_indentation(content); | ||
} | ||
else { | ||
content.push(' '); | ||
this.line_char_count++; | ||
} | ||
space = false; | ||
} | ||
input_char = this.input.charAt(this.pos); | ||
this.pos++; | ||
if (input_char === '<' && !tag_start) { | ||
tag_start = this.pos - 1; | ||
} | ||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space | ||
space = true; | ||
continue; | ||
} | ||
this.line_char_count++; | ||
content.push(input_char); //inserts character at-a-time (or string) | ||
if (input_char === "'" || input_char === '"') { | ||
input_char += this.get_unformatted(input_char); | ||
space = true; | ||
if (content[1] && content[1] === '!') { //if we're in a comment, do something special | ||
// We treat all comments as literals, even more than preformatted tags | ||
// we just look for the appropriate close tag | ||
content = [this.get_comment(tag_start)]; | ||
break; | ||
} | ||
} | ||
} while (input_char !== '>'); | ||
if (input_char === '=') { //no space before = | ||
space = false; | ||
} | ||
var tag_complete = content.join(''); | ||
var tag_index; | ||
if (tag_complete.indexOf(' ') !== -1) { //if there's whitespace, thats where the tag name ends | ||
tag_index = tag_complete.indexOf(' '); | ||
} | ||
else { //otherwise go with the tag ending | ||
tag_index = tag_complete.indexOf('>'); | ||
} | ||
var tag_check = tag_complete.substring(1, tag_index).toLowerCase(); | ||
if (tag_complete.charAt(tag_complete.length-2) === '/' || | ||
this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /) | ||
if ( ! peek) { | ||
this.tag_type = 'SINGLE'; | ||
} | ||
} | ||
else if (tag_check === 'script') { //for later script handling | ||
if ( ! peek) { | ||
this.record_tag(tag_check); | ||
this.tag_type = 'SCRIPT'; | ||
} | ||
} | ||
else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content) | ||
if ( ! peek) { | ||
this.record_tag(tag_check); | ||
this.tag_type = 'STYLE'; | ||
} | ||
} | ||
else if (this.is_unformatted(tag_check, unformatted)) { // do not reformat the "unformatted" tags | ||
comment = this.get_unformatted('</'+tag_check+'>', tag_complete); //...delegate to get_unformatted function | ||
content.push(comment); | ||
// Preserve collapsed whitespace either before or after this tag. | ||
if (tag_start > 0 && this.Utils.in_array(this.input.charAt(tag_start - 1), this.Utils.whitespace)){ | ||
content.splice(0, 0, this.input.charAt(tag_start - 1)); | ||
} | ||
tag_end = this.pos - 1; | ||
if (this.Utils.in_array(this.input.charAt(tag_end + 1), this.Utils.whitespace)){ | ||
content.push(this.input.charAt(tag_end + 1)); | ||
} | ||
this.tag_type = 'SINGLE'; | ||
} | ||
else if (tag_check.charAt(0) === '!' ) { //peek for <! comment | ||
// for comments content is already correct. | ||
if (! peek) { | ||
this.tag_type = 'SINGLE'; | ||
this.traverse_whitespace(); | ||
} | ||
} | ||
else if ( ! peek) { | ||
if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending | ||
this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors | ||
this.tag_type = 'END'; | ||
this.traverse_whitespace(); | ||
} | ||
else { //otherwise it's a start-tag | ||
this.record_tag(tag_check); //push it on the tag stack | ||
if(tag_check.toLowerCase() !== 'html') { | ||
this.indent_content = true; | ||
} | ||
this.tag_type = 'START'; | ||
if (content.length && content[content.length - 1] !== '=' && input_char !== '>' && space) { | ||
//no space after = or before > | ||
if (this.line_char_count >= this.wrap_line_length) { | ||
this.print_newline(false, content); | ||
this.print_indentation(content); | ||
} else { | ||
content.push(' '); | ||
this.line_char_count++; | ||
} | ||
space = false; | ||
} | ||
// Allow preserving of newlines after a start tag | ||
this.traverse_whitespace(); | ||
} | ||
if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line | ||
this.print_newline(false, this.output); | ||
if(this.output.length && this.output[this.output.length - 2] !== '\n') { | ||
this.print_newline(true, this.output); | ||
} | ||
} | ||
} | ||
if (indent_handlebars && tag_start_char === '<') { | ||
// When inside an angle-bracket tag, put spaces around | ||
// handlebars not inside of strings. | ||
if ((input_char + this.input.charAt(this.pos)) === '{{') { | ||
input_char += this.get_unformatted('}}'); | ||
if (content.length && content[content.length - 1] !== ' ' && content[content.length - 1] !== '<') { | ||
input_char = ' ' + input_char; | ||
} | ||
space = true; | ||
} | ||
} | ||
if (peek) { | ||
this.pos = orig_pos; | ||
this.line_char_count = orig_line_char_count; | ||
} | ||
if (input_char === '<' && !tag_start_char) { | ||
tag_start = this.pos - 1; | ||
tag_start_char = '<'; | ||
} | ||
return content.join(''); //returns fully formatted tag | ||
}; | ||
if (indent_handlebars && !tag_start_char) { | ||
if (content.length >= 2 && content[content.length - 1] === '{' && content[content.length - 2] == '{') { | ||
if (input_char === '#' || input_char === '/') { | ||
tag_start = this.pos - 3; | ||
} else { | ||
tag_start = this.pos - 2; | ||
} | ||
tag_start_char = '{'; | ||
} | ||
} | ||
this.get_comment = function (start_pos) { //function to return comment content in its entirety | ||
// this is will have very poor perf, but will work for now. | ||
var comment = '', | ||
delimiter = '>', | ||
matched = false; | ||
this.line_char_count++; | ||
content.push(input_char); //inserts character at-a-time (or string) | ||
this.pos = start_pos; | ||
input_char = this.input.charAt(this.pos); | ||
this.pos++; | ||
if (content[1] && content[1] === '!') { //if we're in a comment, do something special | ||
// We treat all comments as literals, even more than preformatted tags | ||
// we just look for the appropriate close tag | ||
content = [this.get_comment(tag_start)]; | ||
break; | ||
} | ||
while(this.pos <= this.input.length) { | ||
comment += input_char; | ||
if (indent_handlebars && tag_start_char === '{' && content.length > 2 && content[content.length - 2] === '}' && content[content.length - 1] === '}') { | ||
break; | ||
} | ||
} while (input_char !== '>'); | ||
// only need to check for the delimiter if the last chars match | ||
if(comment[comment.length - 1] === delimiter[delimiter.length - 1] && | ||
comment.indexOf(delimiter) !== -1) { | ||
break; | ||
} | ||
var tag_complete = content.join(''); | ||
var tag_index; | ||
var tag_offset; | ||
// only need to search for custom delimiter for the first few characters | ||
if (!matched && comment.length < 10) { | ||
if (comment.indexOf('<![if') === 0) { //peek for <![if conditional comment | ||
delimiter = '<![endif]>'; | ||
matched = true; | ||
if (tag_complete.indexOf(' ') !== -1) { //if there's whitespace, thats where the tag name ends | ||
tag_index = tag_complete.indexOf(' '); | ||
} else if (tag_complete[0] === '{') { | ||
tag_index = tag_complete.indexOf('}'); | ||
} else { //otherwise go with the tag ending | ||
tag_index = tag_complete.indexOf('>'); | ||
} | ||
else if (comment.indexOf('<![cdata[') === 0) { //if it's a <[cdata[ comment... | ||
delimiter = ']]>'; | ||
matched = true; | ||
if (tag_complete[0] === '<' || !indent_handlebars) { | ||
tag_offset = 1; | ||
} else { | ||
tag_offset = tag_complete[2] === '#' ? 3 : 2; | ||
} | ||
else if (comment.indexOf('<![') === 0) { // some other ![ comment? ... | ||
delimiter = ']>'; | ||
matched = true; | ||
var tag_check = tag_complete.substring(tag_offset, tag_index).toLowerCase(); | ||
if (tag_complete.charAt(tag_complete.length - 2) === '/' || | ||
this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /) | ||
if (!peek) { | ||
this.tag_type = 'SINGLE'; | ||
} | ||
} else if (indent_handlebars && tag_complete[0] === '{' && tag_check === 'else') { | ||
if (!peek) { | ||
this.indent_to_tag('if'); | ||
this.tag_type = 'HANDLEBARS_ELSE'; | ||
this.indent_content = true; | ||
this.traverse_whitespace(); | ||
} | ||
} else if (tag_check === 'script') { //for later script handling | ||
if (!peek) { | ||
this.record_tag(tag_check); | ||
this.tag_type = 'SCRIPT'; | ||
} | ||
} else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content) | ||
if (!peek) { | ||
this.record_tag(tag_check); | ||
this.tag_type = 'STYLE'; | ||
} | ||
} else if (this.is_unformatted(tag_check, unformatted)) { // do not reformat the "unformatted" tags | ||
comment = this.get_unformatted('</' + tag_check + '>', tag_complete); //...delegate to get_unformatted function | ||
content.push(comment); | ||
// Preserve collapsed whitespace either before or after this tag. | ||
if (tag_start > 0 && this.Utils.in_array(this.input.charAt(tag_start - 1), this.Utils.whitespace)) { | ||
content.splice(0, 0, this.input.charAt(tag_start - 1)); | ||
} | ||
tag_end = this.pos - 1; | ||
if (this.Utils.in_array(this.input.charAt(tag_end + 1), this.Utils.whitespace)) { | ||
content.push(this.input.charAt(tag_end + 1)); | ||
} | ||
this.tag_type = 'SINGLE'; | ||
} else if (tag_check.charAt(0) === '!') { //peek for <! comment | ||
// for comments content is already correct. | ||
if (!peek) { | ||
this.tag_type = 'SINGLE'; | ||
this.traverse_whitespace(); | ||
} | ||
} else if (!peek) { | ||
if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending | ||
this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors | ||
this.tag_type = 'END'; | ||
this.traverse_whitespace(); | ||
} else { //otherwise it's a start-tag | ||
this.record_tag(tag_check); //push it on the tag stack | ||
if (tag_check.toLowerCase() !== 'html') { | ||
this.indent_content = true; | ||
} | ||
this.tag_type = 'START'; | ||
// Allow preserving of newlines after a start tag | ||
this.traverse_whitespace(); | ||
} | ||
if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line | ||
this.print_newline(false, this.output); | ||
if (this.output.length && this.output[this.output.length - 2] !== '\n') { | ||
this.print_newline(true, this.output); | ||
} | ||
} | ||
} | ||
else if (comment.indexOf('<!--') === 0) { // <!-- comment ... | ||
delimiter = '-->'; | ||
matched = true; | ||
if (peek) { | ||
this.pos = orig_pos; | ||
this.line_char_count = orig_line_char_count; | ||
} | ||
} | ||
input_char = this.input.charAt(this.pos); | ||
this.pos++; | ||
} | ||
return content.join(''); //returns fully formatted tag | ||
}; | ||
return comment; | ||
}; | ||
this.get_comment = function(start_pos) { //function to return comment content in its entirety | ||
// this is will have very poor perf, but will work for now. | ||
var comment = '', | ||
delimiter = '>', | ||
matched = false; | ||
this.get_unformatted = function (delimiter, orig_tag) { //function to return unformatted content in its entirety | ||
this.pos = start_pos; | ||
input_char = this.input.charAt(this.pos); | ||
this.pos++; | ||
if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) !== -1) { | ||
return ''; | ||
} | ||
var input_char = ''; | ||
var content = ''; | ||
var space = true; | ||
do { | ||
while (this.pos <= this.input.length) { | ||
comment += input_char; | ||
if (this.pos >= this.input.length) { | ||
return content; | ||
} | ||
// only need to check for the delimiter if the last chars match | ||
if (comment[comment.length - 1] === delimiter[delimiter.length - 1] && | ||
comment.indexOf(delimiter) !== -1) { | ||
break; | ||
} | ||
input_char = this.input.charAt(this.pos); | ||
this.pos++; | ||
// only need to search for custom delimiter for the first few characters | ||
if (!matched && comment.length < 10) { | ||
if (comment.indexOf('<![if') === 0) { //peek for <![if conditional comment | ||
delimiter = '<![endif]>'; | ||
matched = true; | ||
} else if (comment.indexOf('<![cdata[') === 0) { //if it's a <[cdata[ comment... | ||
delimiter = ']]>'; | ||
matched = true; | ||
} else if (comment.indexOf('<![') === 0) { // some other ![ comment? ... | ||
delimiter = ']>'; | ||
matched = true; | ||
} else if (comment.indexOf('<!--') === 0) { // <!-- comment ... | ||
delimiter = '-->'; | ||
matched = true; | ||
} | ||
} | ||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) { | ||
if (!space) { | ||
this.line_char_count--; | ||
continue; | ||
} | ||
if (input_char === '\n' || input_char === '\r') { | ||
content += '\n'; | ||
/* Don't change tab indention for unformatted blocks. If using code for html editing, this will greatly affect <pre> tags if they are specified in the 'unformatted array' | ||
input_char = this.input.charAt(this.pos); | ||
this.pos++; | ||
} | ||
return comment; | ||
}; | ||
this.get_unformatted = function(delimiter, orig_tag) { //function to return unformatted content in its entirety | ||
if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) !== -1) { | ||
return ''; | ||
} | ||
var input_char = ''; | ||
var content = ''; | ||
var min_index = 0; | ||
var space = true; | ||
do { | ||
if (this.pos >= this.input.length) { | ||
return content; | ||
} | ||
input_char = this.input.charAt(this.pos); | ||
this.pos++; | ||
if (this.Utils.in_array(input_char, this.Utils.whitespace)) { | ||
if (!space) { | ||
this.line_char_count--; | ||
continue; | ||
} | ||
if (input_char === '\n' || input_char === '\r') { | ||
content += '\n'; | ||
/* Don't change tab indention for unformatted blocks. If using code for html editing, this will greatly affect <pre> tags if they are specified in the 'unformatted array' | ||
for (var i=0; i<this.indent_level; i++) { | ||
@@ -471,257 +543,271 @@ content += this.indent_string; | ||
*/ | ||
this.line_char_count = 0; | ||
continue; | ||
} | ||
} | ||
content += input_char; | ||
this.line_char_count++; | ||
space = true; | ||
this.line_char_count = 0; | ||
continue; | ||
} | ||
} | ||
content += input_char; | ||
this.line_char_count++; | ||
space = true; | ||
if (indent_handlebars && input_char === '{' && content.length && content[content.length - 2] === '{') { | ||
// Handlebars expressions in strings should also be unformatted. | ||
content += this.get_unformatted('}}'); | ||
// These expressions are opaque. Ignore delimiters found in them. | ||
min_index = content.length; | ||
} | ||
} while (content.toLowerCase().indexOf(delimiter, min_index) === -1); | ||
return content; | ||
}; | ||
} while (content.toLowerCase().indexOf(delimiter) === -1); | ||
return content; | ||
}; | ||
this.get_token = function() { //initial handler for token-retrieval | ||
var token; | ||
this.get_token = function () { //initial handler for token-retrieval | ||
var token; | ||
if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript | ||
var type = this.last_token.substr(7); | ||
token = this.get_contents_to(type); | ||
if (typeof token !== 'string') { | ||
return token; | ||
} | ||
return [token, 'TK_' + type]; | ||
} | ||
if (this.current_mode === 'CONTENT') { | ||
token = this.get_content(); | ||
if (typeof token !== 'string') { | ||
return token; | ||
} else { | ||
return [token, 'TK_CONTENT']; | ||
} | ||
} | ||
if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript | ||
var type = this.last_token.substr(7); | ||
token = this.get_contents_to(type); | ||
if (typeof token !== 'string') { | ||
return token; | ||
} | ||
return [token, 'TK_' + type]; | ||
} | ||
if (this.current_mode === 'CONTENT') { | ||
token = this.get_content(); | ||
if (typeof token !== 'string') { | ||
return token; | ||
} | ||
else { | ||
return [token, 'TK_CONTENT']; | ||
} | ||
} | ||
if (this.current_mode === 'TAG') { | ||
token = this.get_tag(); | ||
if (typeof token !== 'string') { | ||
return token; | ||
} else { | ||
var tag_name_type = 'TK_TAG_' + this.tag_type; | ||
return [token, tag_name_type]; | ||
} | ||
} | ||
}; | ||
if (this.current_mode === 'TAG') { | ||
token = this.get_tag(); | ||
if (typeof token !== 'string') { | ||
return token; | ||
} | ||
else { | ||
var tag_name_type = 'TK_TAG_' + this.tag_type; | ||
return [token, tag_name_type]; | ||
} | ||
} | ||
}; | ||
this.get_full_indent = function(level) { | ||
level = this.indent_level + level || 0; | ||
if (level < 1) { | ||
return ''; | ||
} | ||
this.get_full_indent = function (level) { | ||
level = this.indent_level + level || 0; | ||
if (level < 1) { | ||
return ''; | ||
} | ||
return Array(level + 1).join(this.indent_string); | ||
}; | ||
return Array(level + 1).join(this.indent_string); | ||
}; | ||
this.is_unformatted = function(tag_check, unformatted) { | ||
//is this an HTML5 block-level link? | ||
if (!this.Utils.in_array(tag_check, unformatted)) { | ||
return false; | ||
} | ||
this.is_unformatted = function(tag_check, unformatted) { | ||
//is this an HTML5 block-level link? | ||
if (!this.Utils.in_array(tag_check, unformatted)){ | ||
return false; | ||
} | ||
if (tag_check.toLowerCase() !== 'a' || !this.Utils.in_array('a', unformatted)) { | ||
return true; | ||
} | ||
if (tag_check.toLowerCase() !== 'a' || !this.Utils.in_array('a', unformatted)){ | ||
return true; | ||
} | ||
//at this point we have an tag; is its first child something we want to remain | ||
//unformatted? | ||
var next_tag = this.get_tag(true /* peek. */ ); | ||
//at this point we have an tag; is its first child something we want to remain | ||
//unformatted? | ||
var next_tag = this.get_tag(true /* peek. */); | ||
// tets next_tag to see if it is just html tag (no external content) | ||
var tag = (next_tag || "").match(/^\s*<\s*\/?([a-z]*)\s*[^>]*>\s*$/); | ||
// tets next_tag to see if it is just html tag (no external content) | ||
var tag = (next_tag || "").match(/^\s*<\s*\/?([a-z]*)\s*[^>]*>\s*$/); | ||
// if next_tag comes back but is not an isolated tag, then | ||
// let's treat the 'a' tag as having content | ||
// and respect the unformatted option | ||
if (!tag || this.Utils.in_array(tag, unformatted)) { | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
// if next_tag comes back but is not an isolated tag, then | ||
// let's treat the 'a' tag as having content | ||
// and respect the unformatted option | ||
if (!tag || this.Utils.in_array(tag, unformatted)){ | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
this.printer = function(js_source, indent_character, indent_size, wrap_line_length, brace_style) { //handles input/output and some other printing functions | ||
this.printer = function (js_source, indent_character, indent_size, wrap_line_length, brace_style) { //handles input/output and some other printing functions | ||
this.input = js_source || ''; //gets the input for the Parser | ||
this.output = []; | ||
this.indent_character = indent_character; | ||
this.indent_string = ''; | ||
this.indent_size = indent_size; | ||
this.brace_style = brace_style; | ||
this.indent_level = 0; | ||
this.wrap_line_length = wrap_line_length; | ||
this.line_char_count = 0; //count to see if wrap_line_length was exceeded | ||
this.input = js_source || ''; //gets the input for the Parser | ||
this.output = []; | ||
this.indent_character = indent_character; | ||
this.indent_string = ''; | ||
this.indent_size = indent_size; | ||
this.brace_style = brace_style; | ||
this.indent_level = 0; | ||
this.wrap_line_length = wrap_line_length; | ||
this.line_char_count = 0; //count to see if wrap_line_length was exceeded | ||
for (var i = 0; i < this.indent_size; i++) { | ||
this.indent_string += this.indent_character; | ||
} | ||
for (var i=0; i<this.indent_size; i++) { | ||
this.indent_string += this.indent_character; | ||
} | ||
this.print_newline = function(force, arr) { | ||
this.line_char_count = 0; | ||
if (!arr || !arr.length) { | ||
return; | ||
} | ||
if (force || (arr[arr.length - 1] !== '\n')) { //we might want the extra line | ||
arr.push('\n'); | ||
} | ||
}; | ||
this.print_newline = function (force, arr) { | ||
this.line_char_count = 0; | ||
if (!arr || !arr.length) { | ||
return; | ||
} | ||
if (force || (arr[arr.length-1] !== '\n')) { //we might want the extra line | ||
arr.push('\n'); | ||
} | ||
}; | ||
this.print_indentation = function(arr) { | ||
for (var i = 0; i < this.indent_level; i++) { | ||
arr.push(this.indent_string); | ||
this.line_char_count += this.indent_string.length; | ||
} | ||
}; | ||
this.print_indentation = function (arr) { | ||
for (var i=0; i<this.indent_level; i++) { | ||
arr.push(this.indent_string); | ||
this.line_char_count += this.indent_string.length; | ||
} | ||
}; | ||
this.print_token = function(text) { | ||
if (text || text !== '') { | ||
if (this.output.length && this.output[this.output.length - 1] === '\n') { | ||
this.print_indentation(this.output); | ||
text = ltrim(text); | ||
} | ||
} | ||
this.print_token_raw(text); | ||
}; | ||
this.print_token = function (text) { | ||
if (text || text !== '') { | ||
if (this.output.length && this.output[this.output.length-1] === '\n') { | ||
this.print_indentation(this.output); | ||
text = ltrim(text); | ||
} | ||
} | ||
this.print_token_raw(text); | ||
}; | ||
this.print_token_raw = function(text) { | ||
if (text && text !== '') { | ||
if (text.length > 1 && text[text.length - 1] === '\n') { | ||
// unformatted tags can grab newlines as their last character | ||
this.output.push(text.slice(0, -1)); | ||
this.print_newline(false, this.output); | ||
} else { | ||
this.output.push(text); | ||
} | ||
} | ||
this.print_token_raw = function (text) { | ||
if (text && text !== '') { | ||
if(text.length > 1 && text[text.length - 1] === '\n') { | ||
// unformatted tags can grab newlines as their last character | ||
this.output.push(text.slice(0, -1)); | ||
this.print_newline(false, this.output); | ||
} else { | ||
this.output.push(text); | ||
} | ||
} | ||
for (var n = 0; n < this.newlines; n++) { | ||
this.print_newline(n > 0, this.output); | ||
} | ||
this.newlines = 0; | ||
}; | ||
for(var n=0; n < this.newlines; n++) { | ||
this.print_newline(n > 0, this.output); | ||
} | ||
this.newlines = 0; | ||
}; | ||
this.indent = function() { | ||
this.indent_level++; | ||
}; | ||
this.indent = function () { | ||
this.indent_level++; | ||
}; | ||
this.unindent = function() { | ||
if (this.indent_level > 0) { | ||
this.indent_level--; | ||
} | ||
}; | ||
}; | ||
return this; | ||
} | ||
this.unindent = function () { | ||
if (this.indent_level > 0) { | ||
this.indent_level--; | ||
} | ||
}; | ||
}; | ||
return this; | ||
} | ||
/*_____________________--------------------_____________________*/ | ||
/*_____________________--------------------_____________________*/ | ||
multi_parser = new Parser(); //wrapping functions Parser | ||
multi_parser.printer(html_source, indent_character, indent_size, wrap_line_length, brace_style); //initialize starting values | ||
multi_parser = new Parser(); //wrapping functions Parser | ||
multi_parser.printer(html_source, indent_character, indent_size, wrap_line_length, brace_style); //initialize starting values | ||
while (true) { | ||
var t = multi_parser.get_token(); | ||
multi_parser.token_text = t[0]; | ||
multi_parser.token_type = t[1]; | ||
while (true) { | ||
var t = multi_parser.get_token(); | ||
multi_parser.token_text = t[0]; | ||
multi_parser.token_type = t[1]; | ||
if (multi_parser.token_type === 'TK_EOF') { | ||
break; | ||
} | ||
if (multi_parser.token_type === 'TK_EOF') { | ||
break; | ||
} | ||
switch (multi_parser.token_type) { | ||
case 'TK_TAG_START': | ||
multi_parser.print_newline(false, multi_parser.output); | ||
multi_parser.print_token(multi_parser.token_text); | ||
if (multi_parser.indent_content) { | ||
multi_parser.indent(); | ||
multi_parser.indent_content = false; | ||
} | ||
multi_parser.current_mode = 'CONTENT'; | ||
break; | ||
case 'TK_TAG_STYLE': | ||
case 'TK_TAG_SCRIPT': | ||
multi_parser.print_newline(false, multi_parser.output); | ||
multi_parser.print_token(multi_parser.token_text); | ||
multi_parser.current_mode = 'CONTENT'; | ||
break; | ||
case 'TK_TAG_END': | ||
//Print new line only if the tag has no content and has child | ||
if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') { | ||
var tag_name = multi_parser.token_text.match(/\w+/)[0]; | ||
var tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length -1].match(/<\s*(\w+)/); | ||
if (tag_extracted_from_last_output === null || | ||
tag_extracted_from_last_output[1] !== tag_name) { | ||
switch (multi_parser.token_type) { | ||
case 'TK_TAG_START': | ||
multi_parser.print_newline(false, multi_parser.output); | ||
} | ||
} | ||
multi_parser.print_token(multi_parser.token_text); | ||
multi_parser.current_mode = 'CONTENT'; | ||
break; | ||
case 'TK_TAG_SINGLE': | ||
// Don't add a newline before elements that should remain unformatted. | ||
var tag_check = multi_parser.token_text.match(/^\s*<([a-z]+)/i); | ||
if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)){ | ||
multi_parser.print_newline(false, multi_parser.output); | ||
} | ||
multi_parser.print_token(multi_parser.token_text); | ||
multi_parser.current_mode = 'CONTENT'; | ||
break; | ||
case 'TK_CONTENT': | ||
multi_parser.print_token(multi_parser.token_text); | ||
multi_parser.current_mode = 'TAG'; | ||
break; | ||
case 'TK_STYLE': | ||
case 'TK_SCRIPT': | ||
if (multi_parser.token_text !== '') { | ||
multi_parser.print_newline(false, multi_parser.output); | ||
var text = multi_parser.token_text, | ||
_beautifier, | ||
script_indent_level = 1; | ||
if (multi_parser.token_type === 'TK_SCRIPT') { | ||
_beautifier = typeof js_beautify === 'function' && js_beautify; | ||
} else if (multi_parser.token_type === 'TK_STYLE') { | ||
_beautifier = typeof css_beautify === 'function' && css_beautify; | ||
} | ||
multi_parser.print_token(multi_parser.token_text); | ||
if (multi_parser.indent_content) { | ||
multi_parser.indent(); | ||
multi_parser.indent_content = false; | ||
} | ||
multi_parser.current_mode = 'CONTENT'; | ||
break; | ||
case 'TK_TAG_STYLE': | ||
case 'TK_TAG_SCRIPT': | ||
multi_parser.print_newline(false, multi_parser.output); | ||
multi_parser.print_token(multi_parser.token_text); | ||
multi_parser.current_mode = 'CONTENT'; | ||
break; | ||
case 'TK_TAG_END': | ||
//Print new line only if the tag has no content and has child | ||
if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') { | ||
var tag_name = multi_parser.token_text.match(/\w+/)[0]; | ||
var tag_extracted_from_last_output = null; | ||
if (multi_parser.output.length) { | ||
tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length - 1].match(/(?:<|{{#)\s*(\w+)/); | ||
} | ||
if (tag_extracted_from_last_output === null || | ||
tag_extracted_from_last_output[1] !== tag_name) { | ||
multi_parser.print_newline(false, multi_parser.output); | ||
} | ||
} | ||
multi_parser.print_token(multi_parser.token_text); | ||
multi_parser.current_mode = 'CONTENT'; | ||
break; | ||
case 'TK_TAG_SINGLE': | ||
// Don't add a newline before elements that should remain unformatted. | ||
var tag_check = multi_parser.token_text.match(/^\s*<([a-z]+)/i); | ||
if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)) { | ||
multi_parser.print_newline(false, multi_parser.output); | ||
} | ||
multi_parser.print_token(multi_parser.token_text); | ||
multi_parser.current_mode = 'CONTENT'; | ||
break; | ||
case 'TK_TAG_HANDLEBARS_ELSE': | ||
multi_parser.print_token(multi_parser.token_text); | ||
if (multi_parser.indent_content) { | ||
multi_parser.indent(); | ||
multi_parser.indent_content = false; | ||
} | ||
multi_parser.current_mode = 'CONTENT'; | ||
break; | ||
case 'TK_CONTENT': | ||
multi_parser.print_token(multi_parser.token_text); | ||
multi_parser.current_mode = 'TAG'; | ||
break; | ||
case 'TK_STYLE': | ||
case 'TK_SCRIPT': | ||
if (multi_parser.token_text !== '') { | ||
multi_parser.print_newline(false, multi_parser.output); | ||
var text = multi_parser.token_text, | ||
_beautifier, | ||
script_indent_level = 1; | ||
if (multi_parser.token_type === 'TK_SCRIPT') { | ||
_beautifier = typeof js_beautify === 'function' && js_beautify; | ||
} else if (multi_parser.token_type === 'TK_STYLE') { | ||
_beautifier = typeof css_beautify === 'function' && css_beautify; | ||
} | ||
if (options.indent_scripts === "keep") { | ||
script_indent_level = 0; | ||
} else if (options.indent_scripts === "separate") { | ||
script_indent_level = -multi_parser.indent_level; | ||
} | ||
if (options.indent_scripts === "keep") { | ||
script_indent_level = 0; | ||
} else if (options.indent_scripts === "separate") { | ||
script_indent_level = -multi_parser.indent_level; | ||
} | ||
var indentation = multi_parser.get_full_indent(script_indent_level); | ||
if (_beautifier) { | ||
// call the Beautifier if avaliable | ||
text = _beautifier(text.replace(/^\s*/, indentation), options); | ||
} else { | ||
// simply indent the string otherwise | ||
var white = text.match(/^\s*/)[0]; | ||
var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1; | ||
var reindent = multi_parser.get_full_indent(script_indent_level -_level); | ||
text = text.replace(/^\s*/, indentation) | ||
.replace(/\r\n|\r|\n/g, '\n' + reindent) | ||
.replace(/\s+$/, ''); | ||
} | ||
if (text) { | ||
multi_parser.print_token_raw(indentation + trim(text)); | ||
multi_parser.print_newline(false, multi_parser.output); | ||
} | ||
var indentation = multi_parser.get_full_indent(script_indent_level); | ||
if (_beautifier) { | ||
// call the Beautifier if avaliable | ||
text = _beautifier(text.replace(/^\s*/, indentation), options); | ||
} else { | ||
// simply indent the string otherwise | ||
var white = text.match(/^\s*/)[0]; | ||
var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1; | ||
var reindent = multi_parser.get_full_indent(script_indent_level - _level); | ||
text = text.replace(/^\s*/, indentation) | ||
.replace(/\r\n|\r|\n/g, '\n' + reindent) | ||
.replace(/\s+$/, ''); | ||
} | ||
if (text) { | ||
multi_parser.print_token_raw(indentation + trim(text)); | ||
multi_parser.print_newline(false, multi_parser.output); | ||
} | ||
} | ||
multi_parser.current_mode = 'TAG'; | ||
break; | ||
} | ||
multi_parser.current_mode = 'TAG'; | ||
break; | ||
multi_parser.last_token = multi_parser.token_type; | ||
multi_parser.last_text = multi_parser.token_text; | ||
} | ||
multi_parser.last_token = multi_parser.token_type; | ||
multi_parser.last_text = multi_parser.token_text; | ||
} | ||
return multi_parser.output.join(''); | ||
return multi_parser.output.join(''); | ||
} | ||
@@ -731,8 +817,7 @@ | ||
// Add support for require.js | ||
define(function(require, exports, module) { | ||
var js_beautify = require('./beautify.js').js_beautify; | ||
var css_beautify = require('./beautify-css.js').css_beautify; | ||
exports.html_beautify = function(html_source, options) { | ||
define(["./beautify.js", "./beautify-css.js"], function(js_beautify, css_beautify) { | ||
return { | ||
html_beautify: function(html_source, options) { | ||
return style_html(html_source, options, js_beautify, css_beautify); | ||
} | ||
}; | ||
@@ -743,3 +828,3 @@ }); | ||
// and you will be able to `var html_beautify = require("beautify").html_beautify`. | ||
var js_beautify = require('./beautify.js').js_beautify; | ||
var js_beautify = require('./beautify.js').js_beautify; | ||
var css_beautify = require('./beautify-css.js').css_beautify; | ||
@@ -746,0 +831,0 @@ |
@@ -35,5 +35,5 @@ #!/usr/bin/env node | ||
var debug = process.env.DEBUG_JSBEAUTIFY || process.env.JSBEAUTIFY_DEBUG | ||
? function () { console.error.apply(console, arguments); } | ||
: function () {}; | ||
var debug = process.env.DEBUG_JSBEAUTIFY || process.env.JSBEAUTIFY_DEBUG ? function() { | ||
console.error.apply(console, arguments); | ||
} : function() {}; | ||
@@ -66,2 +66,3 @@ var fs = require('fs'), | ||
"unformatted": [String, Array], | ||
"indent_inner_html": [Boolean], | ||
"indent_scripts": ["keep", "separate", "normal"], | ||
@@ -99,2 +100,3 @@ // CLI | ||
"U": ["--unformatted"], | ||
"I": ["--indent_inner_html"], | ||
"S": ["--indent_scripts"], | ||
@@ -107,4 +109,4 @@ // non-dasherized hybrid shortcuts | ||
], | ||
"js" : ["--type", "js"], | ||
"css" : ["--type", "css"], | ||
"js": ["--type", "js"], | ||
"css": ["--type", "css"], | ||
"html": ["--type", "html"], | ||
@@ -122,3 +124,3 @@ // CLI | ||
// var cli = require('js-beautify/cli'); cli.interpret(); | ||
var interpret = exports.interpret = function (argv, slice) { | ||
var interpret = exports.interpret = function(argv, slice) { | ||
var parsed = nopt(knownOpts, shortHands, argv, slice); | ||
@@ -129,4 +131,3 @@ | ||
process.exit(0); | ||
} | ||
else if (parsed.help) { | ||
} else if (parsed.help) { | ||
usage(); | ||
@@ -141,3 +142,3 @@ process.exit(0); | ||
cc.find('.jsbeautifyrc'), | ||
cc.find(path.join(process.env.HOME, ".jsbeautifyrc")), | ||
cc.find(path.join(process.env.HOME || "", ".jsbeautifyrc")), | ||
__dirname + '/../config/defaults.json' | ||
@@ -150,9 +151,9 @@ ).snapshot; | ||
checkFiles(cfg); | ||
checkIndent(cfg); | ||
debug(cfg); | ||
// Process files synchronously to avoid EMFILE error | ||
cfg.files.forEach(processInputSync, { cfg: cfg }); | ||
} | ||
catch (ex) { | ||
cfg.files.forEach(processInputSync, { | ||
cfg: cfg | ||
}); | ||
} catch (ex) { | ||
debug(cfg); | ||
@@ -192,25 +193,26 @@ // usage(ex); | ||
switch (scriptName.split('-').shift()) { | ||
case "js": | ||
msg.push(' -l, --indent-level Initial indentation level [0]'); | ||
msg.push(' -t, --indent-with-tabs Indent with tabs, overrides -s and -c'); | ||
msg.push(' -p, --preserve-newlines Preserve line-breaks (--no-preserve-newlines disables)'); | ||
msg.push(' -m, --max-preserve-newlines Number of line-breaks to be preserved in one chunk [10]'); | ||
msg.push(' -P, --space-in-paren Add padding spaces within paren, ie. f( a, b )'); | ||
msg.push(' -j, --jslint-happy Enable jslint-stricter mode'); | ||
msg.push(' -b, --brace-style [collapse|expand|end-expand] ["collapse"]'); | ||
msg.push(' -B, --break-chained-methods Break chained method calls across subsequent lines'); | ||
msg.push(' -k, --keep-array-indentation Preserve array indentation'); | ||
msg.push(' -x, --unescape-strings Decode printable characters encoded in xNN notation'); | ||
msg.push(' -w, --wrap-line-length Wrap lines at next opportunity after N characters [0]'); | ||
msg.push(' -X, --e4x Pass E4X xml literals through untouched'); | ||
msg.push(' --good-stuff Warm the cockles of Crockford\'s heart'); | ||
break; | ||
case "html": | ||
msg.push(' -b, --brace-style [collapse|expand|end-expand] ["collapse"]'); | ||
msg.push(' -S, --indent-scripts [keep|separate|normal] ["normal"]'); | ||
msg.push(' -w, --wrap-line-length Wrap lines at next opportunity after N characters [0]'); | ||
msg.push(' -p, --preserve-newlines Preserve line-breaks (--no-preserve-newlines disables)'); | ||
msg.push(' -m, --max-preserve-newlines Number of line-breaks to be preserved in one chunk [10]'); | ||
msg.push(' -U, --unformatted List of tags (defaults to inline) that should not be reformatted'); | ||
break; | ||
case "js": | ||
msg.push(' -l, --indent-level Initial indentation level [0]'); | ||
msg.push(' -t, --indent-with-tabs Indent with tabs, overrides -s and -c'); | ||
msg.push(' -p, --preserve-newlines Preserve line-breaks (--no-preserve-newlines disables)'); | ||
msg.push(' -m, --max-preserve-newlines Number of line-breaks to be preserved in one chunk [10]'); | ||
msg.push(' -P, --space-in-paren Add padding spaces within paren, ie. f( a, b )'); | ||
msg.push(' -j, --jslint-happy Enable jslint-stricter mode'); | ||
msg.push(' -b, --brace-style [collapse|expand|end-expand] ["collapse"]'); | ||
msg.push(' -B, --break-chained-methods Break chained method calls across subsequent lines'); | ||
msg.push(' -k, --keep-array-indentation Preserve array indentation'); | ||
msg.push(' -x, --unescape-strings Decode printable characters encoded in xNN notation'); | ||
msg.push(' -w, --wrap-line-length Wrap lines at next opportunity after N characters [0]'); | ||
msg.push(' -X, --e4x Pass E4X xml literals through untouched'); | ||
msg.push(' --good-stuff Warm the cockles of Crockford\'s heart'); | ||
break; | ||
case "html": | ||
msg.push(' -b, --brace-style [collapse|expand|end-expand] ["collapse"]'); | ||
msg.push(' -I, --indent-inner-html Indent body and head sections. Default is false.'); | ||
msg.push(' -S, --indent-scripts [keep|separate|normal] ["normal"]'); | ||
msg.push(' -w, --wrap-line-length Wrap lines at next opportunity after N characters [0]'); | ||
msg.push(' -p, --preserve-newlines Preserve line-breaks (--no-preserve-newlines disables)'); | ||
msg.push(' -m, --max-preserve-newlines Number of line-breaks to be preserved in one chunk [10]'); | ||
msg.push(' -U, --unformatted List of tags (defaults to inline) that should not be reformatted'); | ||
break; | ||
} | ||
@@ -228,2 +230,3 @@ | ||
// main iterator, {cfg} passed as thisArg of forEach call | ||
function processInputSync(filepath) { | ||
@@ -245,11 +248,10 @@ var data = '', | ||
input.on('data', function (chunk) { | ||
input.on('data', function(chunk) { | ||
data += chunk; | ||
}); | ||
input.on('end', function () { | ||
input.on('end', function() { | ||
makePretty(data, config, outfile, writePretty); | ||
}); | ||
} | ||
else { | ||
} else { | ||
var dir = path.dirname(outfile); | ||
@@ -268,7 +270,8 @@ mkdirp.sync(dir); | ||
// ensure newline at end of beautified output | ||
pretty += '\n'; | ||
if (pretty && pretty.charAt(pretty.length - 1) !== '\n') { | ||
pretty += '\n'; | ||
} | ||
callback(null, pretty, outfile, config); | ||
} | ||
catch (ex) { | ||
} catch (ex) { | ||
callback(ex); | ||
@@ -288,8 +291,6 @@ } | ||
logToStdout('beautified ' + path.relative(process.cwd(), outfile), config); | ||
} | ||
catch (ex) { | ||
} catch (ex) { | ||
onOutputError(ex); | ||
} | ||
} | ||
else { | ||
} else { | ||
process.stdout.write(pretty); | ||
@@ -300,2 +301,3 @@ } | ||
// workaround the fact that nopt.clean doesn't return the object passed in :P | ||
function cleanOptions(data, types) { | ||
@@ -308,7 +310,7 @@ nopt.clean(data, types); | ||
// allowing the loop to continue over unwritable files. | ||
function onOutputError(err) { | ||
if (err.code === 'EACCES') { | ||
console.error(err.path + " is not writable. Skipping!"); | ||
} | ||
else { | ||
} else { | ||
console.error(err); | ||
@@ -320,2 +322,3 @@ process.exit(0); | ||
// turn "--foo_bar" into "foo-bar" | ||
function dasherizeFlag(str) { | ||
@@ -327,5 +330,6 @@ return str.replace(/^\-+/, '').replace(/_/g, '-'); | ||
// avoiding single character aliases. | ||
function dasherizeShorthands(hash) { | ||
// operate in-place | ||
Object.keys(hash).forEach(function (key) { | ||
Object.keys(hash).forEach(function(key) { | ||
// each key value is an array | ||
@@ -366,11 +370,2 @@ var val = hash[key][0]; | ||
function checkIndent(parsed) { | ||
if (parsed["indent_with_tabs"]) { | ||
parsed["indent_size"] = 1; | ||
parsed["indent_char"] = "\t"; | ||
} | ||
return parsed; | ||
} | ||
function checkFiles(parsed) { | ||
@@ -381,4 +376,3 @@ var argv = parsed.argv; | ||
parsed.files = []; | ||
} | ||
else { | ||
} else { | ||
if (argv.cooked.indexOf('-') > -1) { | ||
@@ -392,3 +386,3 @@ // strip stdin path eagerly added by nopt in '-f -' case | ||
// assume any remaining args are files | ||
argv.remain.forEach(function (f) { | ||
argv.remain.forEach(function(f) { | ||
parsed.files.push(path.resolve(f)); | ||
@@ -433,4 +427,3 @@ }); | ||
} | ||
} | ||
catch (err) { | ||
} catch (err) { | ||
throw 'Unable to open path "' + filepath + '"'; | ||
@@ -437,0 +430,0 @@ } |
@@ -7,6 +7,7 @@ /*global js_beautify: true */ | ||
js_beautify = require('../index').js_beautify, | ||
html_beautify = require('../index').html_beautify, | ||
run_beautifier_tests = require('./beautify-tests').run_beautifier_tests; | ||
function node_beautifier_tests() { | ||
var results = run_beautifier_tests(new SanityTest(), Urlencoded, js_beautify); | ||
var results = run_beautifier_tests(new SanityTest(), Urlencoded, js_beautify, html_beautify); | ||
console.log(results.results_raw()); | ||
@@ -13,0 +14,0 @@ return results; |
{ | ||
"name": "js-beautify", | ||
"version": "1.4.0", | ||
"version": "1.4.1", | ||
"description": "jsbeautifier.org for node", | ||
@@ -50,4 +50,5 @@ "main": "js/index.js", | ||
"devDependencies": { | ||
"jshint": "1.1.0" | ||
"jshint": "1.1.0", | ||
"node-static": "~0.7.1" | ||
} | ||
} |
@@ -155,2 +155,3 @@ # JS Beautifier | ||
HTML Beautifier Options: | ||
-I, --indent-inner-html Indent <head> and <body> sections. Default is false. | ||
-s, --indent-size Indentation size [4] | ||
@@ -157,0 +158,0 @@ -c, --indent-char Indentation character [" "] |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
244708
4745
183
2