mirror of
https://github.com/beautifier/js-beautify.git
synced 2025-02-25 23:57:14 +00:00
Support wrapping script and style content
Content inside style and script tags can be wrapped in comment or cdata to allow the text to contain characters and string that would otherwise not be allowed in html. Before this change the html beautifier would not see the wrappers. This meant that it could incorrectly terminate script or style tags. It also meant that the wrapper would be passed to child beautifiers and they would have to handle them. This change makes the html beautfier recognize the wrappers and correctly handle formatting of them itself. The child beautifiers see only the content not the wrapper. Fixes #1641
This commit is contained in:
parent
d88c6a6462
commit
3296dd0d85
@ -442,10 +442,12 @@ Beautifier.prototype._handle_text = function(printer, raw_token, last_tag_token)
|
||||
Beautifier.prototype._print_custom_beatifier_text = function(printer, raw_token, last_tag_token) {
|
||||
var local = this;
|
||||
if (raw_token.text !== '') {
|
||||
printer.print_newline(false);
|
||||
|
||||
var text = raw_token.text,
|
||||
_beautifier,
|
||||
script_indent_level = 1;
|
||||
script_indent_level = 1,
|
||||
pre = '',
|
||||
post = '';
|
||||
if (last_tag_token.custom_beautifier_name === 'javascript' && typeof this._js_beautify === 'function') {
|
||||
_beautifier = this._js_beautify;
|
||||
} else if (last_tag_token.custom_beautifier_name === 'css' && typeof this._css_beautify === 'function') {
|
||||
@ -457,7 +459,6 @@ Beautifier.prototype._print_custom_beatifier_text = function(printer, raw_token,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
if (this._options.indent_scripts === "keep") {
|
||||
script_indent_level = 0;
|
||||
} else if (this._options.indent_scripts === "separate") {
|
||||
@ -470,24 +471,67 @@ Beautifier.prototype._print_custom_beatifier_text = function(printer, raw_token,
|
||||
// we'll be adding one back after the text but before the containing tag.
|
||||
text = text.replace(/\n[ \t]*$/, '');
|
||||
|
||||
if (_beautifier) {
|
||||
// Handle the case where content is wrapped in a comment or cdata.
|
||||
if (last_tag_token.custom_beautifier_name !== 'html' &&
|
||||
text[0] === '<' && text.match(/^(<!--|<!\[CDATA\[)/)) {
|
||||
var matched = /^(<!--[^\n]*|<!\[CDATA\[)(\n?)([ \t\n]*)([\s\S]*)(-->|]]>)$/.exec(text);
|
||||
|
||||
// call the Beautifier if avaliable
|
||||
var Child_options = function() {
|
||||
this.eol = '\n';
|
||||
};
|
||||
Child_options.prototype = this._options.raw_options;
|
||||
var child_options = new Child_options();
|
||||
text = _beautifier(indentation + text, child_options);
|
||||
} else {
|
||||
// simply indent the string otherwise
|
||||
var white = raw_token.whitespace_before;
|
||||
if (white) {
|
||||
text = text.replace(new RegExp('\n(' + white + ')?', 'g'), '\n');
|
||||
// if we start to wrap but don't finish, print raw
|
||||
if (!matched) {
|
||||
printer.add_raw_token(raw_token);
|
||||
return;
|
||||
}
|
||||
|
||||
text = indentation + text.replace(/\n/g, '\n' + indentation);
|
||||
pre = indentation + matched[1] + '\n';
|
||||
text = matched[4];
|
||||
if (matched[5]) {
|
||||
post = indentation + matched[5];
|
||||
}
|
||||
|
||||
// if there is at least one empty line at the end of this text, strip it
|
||||
// we'll be adding one back after the text but before the containing tag.
|
||||
text = text.replace(/\n[ \t]*$/, '');
|
||||
|
||||
if (matched[2] || matched[3].indexOf('\n') !== -1) {
|
||||
// if the first line of the non-comment text has spaces
|
||||
// use that as the basis for indenting in null case.
|
||||
matched = matched[3].match(/[ \t]+$/);
|
||||
if (matched) {
|
||||
raw_token.whitespace_before = matched[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (text) {
|
||||
if (_beautifier) {
|
||||
|
||||
// call the Beautifier if avaliable
|
||||
var Child_options = function() {
|
||||
this.eol = '\n';
|
||||
};
|
||||
Child_options.prototype = this._options.raw_options;
|
||||
var child_options = new Child_options();
|
||||
text = _beautifier(indentation + text, child_options);
|
||||
} else {
|
||||
// simply indent the string otherwise
|
||||
var white = raw_token.whitespace_before;
|
||||
if (white) {
|
||||
text = text.replace(new RegExp('\n(' + white + ')?', 'g'), '\n');
|
||||
}
|
||||
|
||||
text = indentation + text.replace(/\n/g, '\n' + indentation);
|
||||
}
|
||||
}
|
||||
|
||||
if (pre) {
|
||||
if (!text) {
|
||||
text = pre + post;
|
||||
} else {
|
||||
text = pre + text + '\n' + post;
|
||||
}
|
||||
}
|
||||
|
||||
printer.print_newline(false);
|
||||
if (text) {
|
||||
raw_token.text = text;
|
||||
raw_token.whitespace_before = '';
|
||||
|
@ -122,7 +122,7 @@ Tokenizer.prototype._get_next_token = function(previous_token, open_token) { //
|
||||
|
||||
token = token || this._read_open_handlebars(c, open_token);
|
||||
token = token || this._read_attribute(c, previous_token, open_token);
|
||||
token = token || this._read_raw_content(previous_token, open_token);
|
||||
token = token || this._read_raw_content(c, previous_token, open_token);
|
||||
token = token || this._read_close(c, open_token);
|
||||
token = token || this._read_content_word(c);
|
||||
token = token || this._read_comment(c);
|
||||
@ -258,19 +258,27 @@ Tokenizer.prototype._is_content_unformatted = function(tag_name) {
|
||||
// script and style tags should always be read as unformatted content
|
||||
// finally content_unformatted and unformatted element contents are unformatted
|
||||
return this._options.void_elements.indexOf(tag_name) === -1 &&
|
||||
(tag_name === 'script' || tag_name === 'style' ||
|
||||
this._options.content_unformatted.indexOf(tag_name) !== -1 ||
|
||||
(this._options.content_unformatted.indexOf(tag_name) !== -1 ||
|
||||
this._options.unformatted.indexOf(tag_name) !== -1);
|
||||
};
|
||||
|
||||
|
||||
Tokenizer.prototype._read_raw_content = function(previous_token, open_token) { // jshint unused:false
|
||||
Tokenizer.prototype._read_raw_content = function(c, previous_token, open_token) { // jshint unused:false
|
||||
var resulting_string = '';
|
||||
if (open_token && open_token.text[0] === '{') {
|
||||
resulting_string = this.__patterns.handlebars_raw_close.read();
|
||||
} else if (previous_token.type === TOKEN.TAG_CLOSE && (previous_token.opened.text[0] === '<')) {
|
||||
var tag_name = previous_token.opened.text.substr(1).toLowerCase();
|
||||
if (this._is_content_unformatted(tag_name)) {
|
||||
if (tag_name === 'script' || tag_name === 'style') {
|
||||
// Script and style tags are allowed to have comments wrapping their content
|
||||
// or just have regular content.
|
||||
var token = this._read_comment(c);
|
||||
if (token) {
|
||||
token.type = TOKEN.TEXT;
|
||||
return token;
|
||||
}
|
||||
resulting_string = this._input.readUntil(new RegExp('</' + tag_name + '[\\n\\r\\t ]*?>', 'ig'));
|
||||
} else if (this._is_content_unformatted(tag_name)) {
|
||||
resulting_string = this._input.readUntil(new RegExp('</' + tag_name + '[\\n\\r\\t ]*?>', 'ig'));
|
||||
}
|
||||
}
|
||||
|
@ -412,6 +412,161 @@ function run_html_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_be
|
||||
'</html>');
|
||||
|
||||
|
||||
//============================================================
|
||||
// Tests for script and style Commented and cdata wapping (#1641)
|
||||
reset_options();
|
||||
set_name('Tests for script and style Commented and cdata wapping (#1641)');
|
||||
bth(
|
||||
'<style><!----></style>',
|
||||
// -- output --
|
||||
'<style>\n' +
|
||||
' <!--\n' +
|
||||
' -->\n' +
|
||||
'</style>');
|
||||
bth(
|
||||
'<style><!--\n' +
|
||||
'--></style>',
|
||||
// -- output --
|
||||
'<style>\n' +
|
||||
' <!--\n' +
|
||||
' -->\n' +
|
||||
'</style>');
|
||||
bth(
|
||||
'<style><!-- the rest of this line is ignored\n' +
|
||||
'\n' +
|
||||
'\n' +
|
||||
'\n' +
|
||||
'--></style>',
|
||||
// -- output --
|
||||
'<style>\n' +
|
||||
' <!-- the rest of this line is ignored\n' +
|
||||
' -->\n' +
|
||||
'</style>');
|
||||
bth(
|
||||
'<style type="test/null"><!--\n' +
|
||||
'\n' +
|
||||
'\t \n' +
|
||||
'\n' +
|
||||
'--></style>',
|
||||
// -- output --
|
||||
'<style type="test/null">\n' +
|
||||
' <!--\n' +
|
||||
' -->\n' +
|
||||
'</style>');
|
||||
bth(
|
||||
'<script><!--\n' +
|
||||
'console.log("</script>" + "</style>");\n' +
|
||||
'--></script>',
|
||||
// -- output --
|
||||
'<script>\n' +
|
||||
' <!--\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' -->\n' +
|
||||
'</script>');
|
||||
|
||||
// If wrapping is incomplete, print remaining unchanged.
|
||||
test_fragment(
|
||||
'<div>\n' +
|
||||
'<script><!--\n' +
|
||||
'console.log("</script>" + "</style>");\n' +
|
||||
' </script>\n' +
|
||||
'</div>',
|
||||
// -- output --
|
||||
'<div>\n' +
|
||||
' <script><!--\n' +
|
||||
'console.log("</script>" + "</style>");\n' +
|
||||
' </script>\n' +
|
||||
'</div>');
|
||||
bth(
|
||||
'<style><!--\n' +
|
||||
'.selector {\n' +
|
||||
' font-family: "</script></style>";\n' +
|
||||
' }\n' +
|
||||
'--></style>',
|
||||
// -- output --
|
||||
'<style>\n' +
|
||||
' <!--\n' +
|
||||
' .selector {\n' +
|
||||
' font-family: "</script></style>";\n' +
|
||||
' }\n' +
|
||||
' -->\n' +
|
||||
'</style>');
|
||||
bth(
|
||||
'<script type="test/null">\n' +
|
||||
' <!--\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
'--></script>',
|
||||
// -- output --
|
||||
'<script type="test/null">\n' +
|
||||
' <!--\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' -->\n' +
|
||||
'</script>');
|
||||
bth(
|
||||
'<script type="test/null"><!--\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
'--></script>',
|
||||
// -- output --
|
||||
'<script type="test/null">\n' +
|
||||
' <!--\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' -->\n' +
|
||||
'</script>');
|
||||
bth(
|
||||
'<script><![CDATA[\n' +
|
||||
'console.log("</script>" + "</style>");\n' +
|
||||
']]></script>',
|
||||
// -- output --
|
||||
'<script>\n' +
|
||||
' <![CDATA[\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' ]]>\n' +
|
||||
'</script>');
|
||||
bth(
|
||||
'<style><![CDATA[\n' +
|
||||
'.selector {\n' +
|
||||
' font-family: "</script></style>";\n' +
|
||||
' }\n' +
|
||||
']]></style>',
|
||||
// -- output --
|
||||
'<style>\n' +
|
||||
' <![CDATA[\n' +
|
||||
' .selector {\n' +
|
||||
' font-family: "</script></style>";\n' +
|
||||
' }\n' +
|
||||
' ]]>\n' +
|
||||
'</style>');
|
||||
bth(
|
||||
'<script type="test/null">\n' +
|
||||
' <![CDATA[\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
']]></script>',
|
||||
// -- output --
|
||||
'<script type="test/null">\n' +
|
||||
' <![CDATA[\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' ]]>\n' +
|
||||
'</script>');
|
||||
bth(
|
||||
'<script type="test/null"><![CDATA[\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
']]></script>',
|
||||
// -- output --
|
||||
'<script type="test/null">\n' +
|
||||
' <![CDATA[\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' console.log("</script>" + "</style>");\n' +
|
||||
' ]]>\n' +
|
||||
'</script>');
|
||||
|
||||
|
||||
//============================================================
|
||||
// Tests for script and style types (issue 453, 821)
|
||||
reset_options();
|
||||
|
@ -214,6 +214,198 @@ exports.test_data = {
|
||||
input: '<html><head><meta></head><body><div><p>x</p></div></body></html>',
|
||||
output: '<html>\n<head>\n <meta>\n</head>\n<body>\n <div>\n\n <p>x\n\n </p>\n </div>\n</body>\n</html>'
|
||||
}]
|
||||
}, {
|
||||
name: "Tests for script and style Commented and cdata wapping (#1641)",
|
||||
description: "Repect comment and cdata wrapping regardless of beautifier",
|
||||
tests: [{
|
||||
input: [
|
||||
'<style><!----></style>'
|
||||
],
|
||||
output: [
|
||||
'<style>',
|
||||
' <!--',
|
||||
' -->',
|
||||
'</style>'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'<style><!--',
|
||||
'--></style>'
|
||||
],
|
||||
output: [
|
||||
'<style>',
|
||||
' <!--',
|
||||
' -->',
|
||||
'</style>'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'<style><!-- the rest of this line is ignored',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'--></style>'
|
||||
],
|
||||
output: [
|
||||
'<style>',
|
||||
' <!-- the rest of this line is ignored',
|
||||
' -->',
|
||||
'</style>'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'<style type="test/null"><!--',
|
||||
'',
|
||||
'\t ',
|
||||
'',
|
||||
'--></style>'
|
||||
],
|
||||
output: [
|
||||
'<style type="test/null">',
|
||||
' <!--',
|
||||
' -->',
|
||||
'</style>'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'<script><!--',
|
||||
'console.log("</script>" + "</style>");',
|
||||
'--></script>'
|
||||
],
|
||||
output: [
|
||||
'<script>',
|
||||
' <!--',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' -->',
|
||||
'</script>'
|
||||
]
|
||||
}, {
|
||||
fragment: true,
|
||||
comment: 'If wrapping is incomplete, print remaining unchanged.',
|
||||
input: [
|
||||
'<div>',
|
||||
'<script><!--',
|
||||
'console.log("</script>" + "</style>");',
|
||||
' </script>',
|
||||
'</div>'
|
||||
],
|
||||
output: [
|
||||
'<div>',
|
||||
' <script><!--',
|
||||
'console.log("</script>" + "</style>");',
|
||||
' </script>',
|
||||
'</div>'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'<style><!--',
|
||||
'.selector {',
|
||||
' font-family: "</script></style>";',
|
||||
' }',
|
||||
'--></style>'
|
||||
],
|
||||
output: [
|
||||
'<style>',
|
||||
' <!--',
|
||||
' .selector {',
|
||||
' font-family: "</script></style>";',
|
||||
' }',
|
||||
' -->',
|
||||
'</style>'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'<script type="test/null">',
|
||||
' <!--',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' console.log("</script>" + "</style>");',
|
||||
'--></script>'
|
||||
],
|
||||
output: [
|
||||
'<script type="test/null">',
|
||||
' <!--',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' -->',
|
||||
'</script>'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'<script type="test/null"><!--',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' console.log("</script>" + "</style>");',
|
||||
'--></script>'
|
||||
],
|
||||
output: [
|
||||
'<script type="test/null">',
|
||||
' <!--',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' -->',
|
||||
'</script>'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'<script><![CDATA[',
|
||||
'console.log("</script>" + "</style>");',
|
||||
']]></script>'
|
||||
],
|
||||
output: [
|
||||
'<script>',
|
||||
' <![CDATA[',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' ]]>',
|
||||
'</script>'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'<style><![CDATA[',
|
||||
'.selector {',
|
||||
' font-family: "</script></style>";',
|
||||
' }',
|
||||
']]></style>'
|
||||
],
|
||||
output: [
|
||||
'<style>',
|
||||
' <![CDATA[',
|
||||
' .selector {',
|
||||
' font-family: "</script></style>";',
|
||||
' }',
|
||||
' ]]>',
|
||||
'</style>'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'<script type="test/null">',
|
||||
' <![CDATA[',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' console.log("</script>" + "</style>");',
|
||||
']]></script>'
|
||||
],
|
||||
output: [
|
||||
'<script type="test/null">',
|
||||
' <![CDATA[',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' ]]>',
|
||||
'</script>'
|
||||
]
|
||||
}, {
|
||||
input: [
|
||||
'<script type="test/null"><![CDATA[',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' console.log("</script>" + "</style>");',
|
||||
']]></script>'
|
||||
],
|
||||
output: [
|
||||
'<script type="test/null">',
|
||||
' <![CDATA[',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' console.log("</script>" + "</style>");',
|
||||
' ]]>',
|
||||
'</script>'
|
||||
]
|
||||
}]
|
||||
}, {
|
||||
name: "Tests for script and style types (issue 453, 821)",
|
||||
description: "Only format recognized script types",
|
||||
|
Loading…
x
Reference in New Issue
Block a user