Add templating language config option

1.9.x added better support for templating and turned it on for
Javascript by default. This caused formatting problems for code bases that
included template markers inside strings.

This change adds a templating option to control which languages are
recognized.  This setting defaults to "auto".  For JavaScript
"auto" means no templating languages, for HTML (and embedded script),
"auto" means all of them.  This basically preserves the existing
behavior before 1.9.x.

Fixes #1647
This commit is contained in:
Liam Newman 2019-04-29 12:44:54 -07:00
parent caac81e7fb
commit e60611044b
16 changed files with 4026 additions and 3233 deletions

View File

@ -191,6 +191,7 @@ Beautifier Options:
-C, --comma-first Put commas at the beginning of new line instead of end -C, --comma-first Put commas at the beginning of new line instead of end
-O, --operator-position Set operator position (before-newline|after-newline|preserve-newline) [before-newline] -O, --operator-position Set operator position (before-newline|after-newline|preserve-newline) [before-newline]
--indent-empty-lines Keep indentation on empty lines --indent-empty-lines Keep indentation on empty lines
--templating List of templating languages (auto,django,erb,handlebars,php) ["auto"] auto = none in JavaScript, all in html
``` ```
Which correspond to the underscored option keys for both library interfaces Which correspond to the underscored option keys for both library interfaces
@ -221,7 +222,8 @@ Which correspond to the underscored option keys for both library interfaces
"e4x": false, "e4x": false,
"comma_first": false, "comma_first": false,
"operator_position": "before-newline", "operator_position": "before-newline",
"indent_empty_lines": false "indent_empty_lines": false,
"templating": ["auto"]
} }
``` ```
@ -342,15 +344,16 @@ HTML Beautifier Options:
--indent_scripts Sets indent level inside script tags ("normal", "keep", "separate") --indent_scripts Sets indent level inside script tags ("normal", "keep", "separate")
--unformatted_content_delimiter Keep text content together between this string [""] --unformatted_content_delimiter Keep text content together between this string [""]
--indent-empty-lines Keep indentation on empty lines --indent-empty-lines Keep indentation on empty lines
--templating List of templating languages (auto,none,django,erb,handlebars,php) ["auto"] auto = none in JavaScript, all in html
``` ```
## Directives ## Directives
Directives let you control the behavior of the Beautifier from within your source files. Directives are placed in comments inside the file. Directives are in the format `/* beautify {name}:{value} */` in CSS and JavaScript. In HTML they are formatted as `<!-- beautify {name}:{value} -->`. Directives let you control the behavior of the Beautifier from within your source files. Directives are placed in comments inside the file. Directives are in the format `/* beautify {name}:{value} */` in CSS and JavaScript. In HTML they are formatted as `<!-- beautify {name}:{value} -->`.
### Ignore directive ### Ignore directive
The `ignore` directive makes the beautifier completely ignore part of a file, treating it as literal text that is not parsed. The `ignore` directive makes the beautifier completely ignore part of a file, treating it as literal text that is not parsed.
The input below will remain unchanged after beautification: The input below will remain unchanged after beautification:
```js ```js
@ -361,9 +364,9 @@ var a = 1;
/* beautify ignore:end */ /* beautify ignore:end */
``` ```
### Preserve directive ### Preserve directive
NOTE: this directive only works in HTML and JavaScript, not CSS. NOTE: this directive only works in HTML and JavaScript, not CSS.
The `preserve` directive makes the Beautifier parse and then keep the existing formatting of a section of code. The `preserve` directive makes the Beautifier parse and then keep the existing formatting of a section of code.

View File

@ -16,5 +16,6 @@
"eval_code": false, "eval_code": false,
"unescape_strings": false, "unescape_strings": false,
"wrap_line_length": 0, "wrap_line_length": 0,
"indent_empty_lines": false "indent_empty_lines": false,
"templating": ["auto"]
} }

View File

@ -93,6 +93,7 @@ var path = require('path'),
"comma_first": Boolean, "comma_first": Boolean,
"operator_position": ["before-newline", "after-newline", "preserve-newline"], "operator_position": ["before-newline", "after-newline", "preserve-newline"],
"indent_empty_lines": Boolean, "indent_empty_lines": Boolean,
"templating": [String, Array],
// CSS-only // CSS-only
"selector_separator_newline": Boolean, "selector_separator_newline": Boolean,
"newline_between_rules": Boolean, "newline_between_rules": Boolean,
@ -179,6 +180,7 @@ var path = require('path'),
// no shorthand for "config" // no shorthand for "config"
// no shorthand for "editorconfig" // no shorthand for "editorconfig"
// no shorthand for "indent_empty_lines" // no shorthand for "indent_empty_lines"
// not shorthad for "templating"
}); });
function verifyExists(fullPath) { function verifyExists(fullPath) {
@ -349,6 +351,7 @@ function usage(err) {
' [first newline in file, otherwise "\\n]', ' [first newline in file, otherwise "\\n]',
' -n, --end-with-newline End output with newline', ' -n, --end-with-newline End output with newline',
' --indent-empty-lines Keep indentation on empty lines', ' --indent-empty-lines Keep indentation on empty lines',
' --templating List of templating languages (auto,none,django,erb,handlebars,php) ["auto"] auto = none in JavaScript, all in html',
' --editorconfig Use EditorConfig to set up the options' ' --editorconfig Use EditorConfig to set up the options'
]; ];

View File

@ -66,6 +66,11 @@ function Options(options, merge_child_field) {
this.wrap_line_length = this._get_number('wrap_line_length', this._get_number('max_char')); this.wrap_line_length = this._get_number('wrap_line_length', this._get_number('max_char'));
this.indent_empty_lines = this._get_boolean('indent_empty_lines'); this.indent_empty_lines = this._get_boolean('indent_empty_lines');
// valid templating languages ['django', 'erb', 'handlebars', 'php']
// For now, 'auto' = all off for javascript, all on for html (and inline javascript).
// other values ignored
this.templating = this._get_selection_list('templating', ['auto', 'none', 'django', 'erb', 'handlebars', 'php'], ['auto']);
} }
Options.prototype._get_array = function(name, default_value) { Options.prototype._get_array = function(name, default_value) {

View File

@ -80,6 +80,15 @@ TemplatablePattern.prototype.disable = function(language) {
return result; return result;
}; };
TemplatablePattern.prototype.read_options = function(options) {
var result = this._create();
for (var language in template_names) {
result._disabled[language] = options.templating.indexOf(language) === -1;
}
result._update();
return result;
};
TemplatablePattern.prototype.exclude = function(language) { TemplatablePattern.prototype.exclude = function(language) {
var result = this._create(); var result = this._create();
result._excluded[language] = true; result._excluded[language] = true;

View File

@ -32,6 +32,9 @@ var BaseOptions = require('../core/options').Options;
function Options(options) { function Options(options) {
BaseOptions.call(this, options, 'html'); BaseOptions.call(this, options, 'html');
if (this.templating.length === 1 && this.templating[0] === 'auto') {
this.templating = ['django', 'erb', 'handlebars', 'php'];
}
this.indent_inner_html = this._get_boolean('indent_inner_html'); this.indent_inner_html = this._get_boolean('indent_inner_html');
this.indent_body_inner_html = this._get_boolean('indent_body_inner_html', true); this.indent_body_inner_html = this._get_boolean('indent_body_inner_html', true);
@ -79,6 +82,7 @@ function Options(options) {
]); ]);
this.unformatted_content_delimiter = this._get_characters('unformatted_content_delimiter'); this.unformatted_content_delimiter = this._get_characters('unformatted_content_delimiter');
this.indent_scripts = this._get_selection('indent_scripts', ['normal', 'keep', 'separate']); this.indent_scripts = this._get_selection('indent_scripts', ['normal', 'keep', 'separate']);
} }
Options.prototype = new BaseOptions(); Options.prototype = new BaseOptions();

View File

@ -56,7 +56,7 @@ var Tokenizer = function(input_string, options) {
// Words end at whitespace or when a tag starts // Words end at whitespace or when a tag starts
// if we are indenting handlebars, they are considered tags // if we are indenting handlebars, they are considered tags
var templatable_reader = new TemplatablePattern(this._input); var templatable_reader = new TemplatablePattern(this._input).read_options(this._options);
var pattern_reader = new Pattern(this._input); var pattern_reader = new Pattern(this._input);
this.__patterns = { this.__patterns = {

View File

@ -108,10 +108,8 @@ var Tokenizer = function(input_string, options) {
/\u2028\u2029/.source); /\u2028\u2029/.source);
var pattern_reader = new Pattern(this._input); var pattern_reader = new Pattern(this._input);
var templatable = new TemplatablePattern(this._input); var templatable = new TemplatablePattern(this._input)
templatable = templatable.disable('handlebars'); .read_options(this._options);
templatable = templatable.disable('django');
this.__patterns = { this.__patterns = {
template: templatable, template: templatable,

View File

@ -4679,26 +4679,11 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
'// behavior of comments should be different for single statements vs block statements/expressions'); '// behavior of comments should be different for single statements vs block statements/expressions');
//============================================================
// Template Formatting
reset_options();
set_name('Template Formatting');
bt('<?=$view["name"]; ?>');
bt('a = <?= external() ?>;');
bt(
'<?php\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'?>');
bt('a = <%= external() %>;');
//============================================================ //============================================================
// minimal template handling - () // minimal template handling - ()
reset_options(); reset_options();
set_name('minimal template handling - ()'); set_name('minimal template handling - ()');
opts.templating = ['django', 'erb', 'handlebars', 'php'];
bt('var a = <?php$view["name"]; ?>;', 'var a = <?php$view["name"]; ?>;'); bt('var a = <?php$view["name"]; ?>;', 'var a = <?php$view["name"]; ?>;');
bt( bt(
'a = abc<?php\n' + 'a = abc<?php\n' +
@ -4719,10 +4704,12 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
'echo "A";\n' + 'echo "A";\n' +
'?>;\n' + '?>;\n' +
'test.method();'); 'test.method();');
bt('"<?php";if(0){}"?>";');
// minimal template handling - () // minimal template handling - ()
reset_options(); reset_options();
set_name('minimal template handling - ()'); set_name('minimal template handling - ()');
opts.templating = ['django', 'erb', 'handlebars', 'php'];
bt('var a = <?=$view["name"]; ?>;', 'var a = <?=$view["name"]; ?>;'); bt('var a = <?=$view["name"]; ?>;', 'var a = <?=$view["name"]; ?>;');
bt( bt(
'a = abc<?=\n' + 'a = abc<?=\n' +
@ -4743,10 +4730,12 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
'echo "A";\n' + 'echo "A";\n' +
'?>;\n' + '?>;\n' +
'test.method();'); 'test.method();');
bt('"<?=";if(0){}"?>";');
// minimal template handling - () // minimal template handling - ()
reset_options(); reset_options();
set_name('minimal template handling - ()'); set_name('minimal template handling - ()');
opts.templating = ['django', 'erb', 'handlebars', 'php'];
bt('var a = <%$view["name"]; %>;', 'var a = <%$view["name"]; %>;'); bt('var a = <%$view["name"]; %>;', 'var a = <%$view["name"]; %>;');
bt( bt(
'a = abc<%\n' + 'a = abc<%\n' +
@ -4767,6 +4756,393 @@ function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify,
'echo "A";\n' + 'echo "A";\n' +
'%>;\n' + '%>;\n' +
'test.method();'); 'test.method();');
bt('"<%";if(0){}"%>";');
// minimal template handling - ()
reset_options();
set_name('minimal template handling - ()');
opts.templating = ['django', 'erb', 'handlebars', 'php'];
bt('var a = <%=$view["name"]; %>;', 'var a = <%=$view["name"]; %>;');
bt(
'a = abc<%=\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'%>;');
test_fragment(
'<%= %>\n' +
'test.met<%= someValue %>hod();');
bt(
'<%= "A" %>abc<%= "D" %>;\n' +
'<%= "B" %>.test();\n' +
'" <%= "C" \'D\' %> "');
bt(
'<%=\n' +
'echo "A";\n' +
'%>;\n' +
'test.method();');
bt('"<%=";if(0){}"%>";');
// minimal template handling - ()
reset_options();
set_name('minimal template handling - ()');
opts.templating = ['django', 'erb', 'handlebars', 'php'];
bt('var a = {{$view["name"]; }};', 'var a = {{$view["name"]; }};');
bt(
'a = abc{{\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'}};');
test_fragment(
'{{ }}\n' +
'test.met{{ someValue }}hod();');
bt(
'{{ "A" }}abc{{ "D" }};\n' +
'{{ "B" }}.test();\n' +
'" {{ "C" \'D\' }} "');
bt(
'{{\n' +
'echo "A";\n' +
'}};\n' +
'test.method();');
bt('"{{";if(0){}"}}";');
// minimal template handling - ()
reset_options();
set_name('minimal template handling - ()');
opts.templating = ['django', 'erb', 'handlebars', 'php'];
bt('var a = {#$view["name"]; #};', 'var a = {#$view["name"]; #};');
bt(
'a = abc{#\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'#};');
test_fragment(
'{# #}\n' +
'test.met{# someValue #}hod();');
bt(
'{# "A" #}abc{# "D" #};\n' +
'{# "B" #}.test();\n' +
'" {# "C" \'D\' #} "');
bt(
'{#\n' +
'echo "A";\n' +
'#};\n' +
'test.method();');
bt('"{#";if(0){}"#}";');
// minimal template handling - ()
reset_options();
set_name('minimal template handling - ()');
opts.templating = ['django', 'erb', 'handlebars', 'php'];
bt('var a = {%$view["name"]; %};', 'var a = {%$view["name"]; %};');
bt(
'a = abc{%\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'%};');
test_fragment(
'{% %}\n' +
'test.met{% someValue %}hod();');
bt(
'{% "A" %}abc{% "D" %};\n' +
'{% "B" %}.test();\n' +
'" {% "C" \'D\' %} "');
bt(
'{%\n' +
'echo "A";\n' +
'%};\n' +
'test.method();');
bt('"{%";if(0){}"%}";');
// minimal template handling - ()
reset_options();
set_name('minimal template handling - ()');
opts.templating = ['django', 'erb', 'handlebars', 'php'];
bt('var a = {{$view["name"]; }};', 'var a = {{$view["name"]; }};');
bt(
'a = abc{{\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'}};');
test_fragment(
'{{ }}\n' +
'test.met{{ someValue }}hod();');
bt(
'{{ "A" }}abc{{ "D" }};\n' +
'{{ "B" }}.test();\n' +
'" {{ "C" \'D\' }} "');
bt(
'{{\n' +
'echo "A";\n' +
'}};\n' +
'test.method();');
bt('"{{";if(0){}"}}";');
// minimal template handling - ()
reset_options();
set_name('minimal template handling - ()');
opts.templating = ['django', 'erb', 'handlebars', 'php'];
bt('var a = {{#$view["name"]; }};', 'var a = {{#$view["name"]; }};');
bt(
'a = abc{{#\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'}};');
test_fragment(
'{{# }}\n' +
'test.met{{# someValue }}hod();');
bt(
'{{# "A" }}abc{{# "D" }};\n' +
'{{# "B" }}.test();\n' +
'" {{# "C" \'D\' }} "');
bt(
'{{#\n' +
'echo "A";\n' +
'}};\n' +
'test.method();');
bt('"{{#";if(0){}"}}";');
// minimal template handling - ()
reset_options();
set_name('minimal template handling - ()');
opts.templating = ['django', 'erb', 'handlebars', 'php'];
bt('var a = {{!$view["name"]; }};', 'var a = {{!$view["name"]; }};');
bt(
'a = abc{{!\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'}};');
test_fragment(
'{{! }}\n' +
'test.met{{! someValue }}hod();');
bt(
'{{! "A" }}abc{{! "D" }};\n' +
'{{! "B" }}.test();\n' +
'" {{! "C" \'D\' }} "');
bt(
'{{!\n' +
'echo "A";\n' +
'}};\n' +
'test.method();');
bt('"{{!";if(0){}"}}";');
// minimal template handling - ()
reset_options();
set_name('minimal template handling - ()');
opts.templating = ['django', 'erb', 'handlebars', 'php'];
bt('var a = {{!--$view["name"]; --}};', 'var a = {{!--$view["name"]; --}};');
bt(
'a = abc{{!--\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'--}};');
test_fragment(
'{{!-- --}}\n' +
'test.met{{!-- someValue --}}hod();');
bt(
'{{!-- "A" --}}abc{{!-- "D" --}};\n' +
'{{!-- "B" --}}.test();\n' +
'" {{!-- "C" \'D\' --}} "');
bt(
'{{!--\n' +
'echo "A";\n' +
'--}};\n' +
'test.method();');
bt('"{{!--";if(0){}"--}}";');
//============================================================
// Templating disabled - ensure formatting - ()
reset_options();
set_name('Templating disabled - ensure formatting - ()');
opts.templating = ['auto'];
bt(
'"<?php";if(0){}"?>";',
// -- output --
'"<?php";\n' +
'if (0) {}\n' +
'"?>";');
bt(
'"<?php";if(0){}',
// -- output --
'"<?php";\n' +
'if (0) {}');
// Templating disabled - ensure formatting - ()
reset_options();
set_name('Templating disabled - ensure formatting - ()');
opts.templating = ['auto'];
bt(
'"<?=";if(0){}"?>";',
// -- output --
'"<?=";\n' +
'if (0) {}\n' +
'"?>";');
bt(
'"<?=";if(0){}',
// -- output --
'"<?=";\n' +
'if (0) {}');
// Templating disabled - ensure formatting - ()
reset_options();
set_name('Templating disabled - ensure formatting - ()');
opts.templating = ['auto'];
bt(
'"<%";if(0){}"%>";',
// -- output --
'"<%";\n' +
'if (0) {}\n' +
'"%>";');
bt(
'"<%";if(0){}',
// -- output --
'"<%";\n' +
'if (0) {}');
// Templating disabled - ensure formatting - ()
reset_options();
set_name('Templating disabled - ensure formatting - ()');
opts.templating = ['auto'];
bt(
'"<%=";if(0){}"%>";',
// -- output --
'"<%=";\n' +
'if (0) {}\n' +
'"%>";');
bt(
'"<%=";if(0){}',
// -- output --
'"<%=";\n' +
'if (0) {}');
// Templating disabled - ensure formatting - ()
reset_options();
set_name('Templating disabled - ensure formatting - ()');
opts.templating = ['auto'];
bt(
'"{{";if(0){}"}}";',
// -- output --
'"{{";\n' +
'if (0) {}\n' +
'"}}";');
bt(
'"{{";if(0){}',
// -- output --
'"{{";\n' +
'if (0) {}');
// Templating disabled - ensure formatting - ()
reset_options();
set_name('Templating disabled - ensure formatting - ()');
opts.templating = ['auto'];
bt(
'"{#";if(0){}"#}";',
// -- output --
'"{#";\n' +
'if (0) {}\n' +
'"#}";');
bt(
'"{#";if(0){}',
// -- output --
'"{#";\n' +
'if (0) {}');
// Templating disabled - ensure formatting - ()
reset_options();
set_name('Templating disabled - ensure formatting - ()');
opts.templating = ['auto'];
bt(
'"{%";if(0){}"%}";',
// -- output --
'"{%";\n' +
'if (0) {}\n' +
'"%}";');
bt(
'"{%";if(0){}',
// -- output --
'"{%";\n' +
'if (0) {}');
// Templating disabled - ensure formatting - ()
reset_options();
set_name('Templating disabled - ensure formatting - ()');
opts.templating = ['auto'];
bt(
'"{{";if(0){}"}}";',
// -- output --
'"{{";\n' +
'if (0) {}\n' +
'"}}";');
bt(
'"{{";if(0){}',
// -- output --
'"{{";\n' +
'if (0) {}');
// Templating disabled - ensure formatting - ()
reset_options();
set_name('Templating disabled - ensure formatting - ()');
opts.templating = ['auto'];
bt(
'"{{#";if(0){}"}}";',
// -- output --
'"{{#";\n' +
'if (0) {}\n' +
'"}}";');
bt(
'"{{#";if(0){}',
// -- output --
'"{{#";\n' +
'if (0) {}');
// Templating disabled - ensure formatting - ()
reset_options();
set_name('Templating disabled - ensure formatting - ()');
opts.templating = ['auto'];
bt(
'"{{!";if(0){}"}}";',
// -- output --
'"{{!";\n' +
'if (0) {}\n' +
'"}}";');
bt(
'"{{!";if(0){}',
// -- output --
'"{{!";\n' +
'if (0) {}');
// Templating disabled - ensure formatting - ()
reset_options();
set_name('Templating disabled - ensure formatting - ()');
opts.templating = ['auto'];
bt(
'"{{!--";if(0){}"--}}";',
// -- output --
'"{{!--";\n' +
'if (0) {}\n' +
'"--}}";');
bt(
'"{{!--";if(0){}',
// -- output --
'"{{!--";\n' +
'if (0) {}');
//============================================================ //============================================================

View File

@ -183,6 +183,7 @@ Output options:
NOTE: Line continues until next wrap point is found. NOTE: Line continues until next wrap point is found.
-n, --end-with-newline End output with newline -n, --end-with-newline End output with newline
--indent-empty-lines Keep indentation on empty lines --indent-empty-lines Keep indentation on empty lines
--templating List of templating languages (auto,none,django,erb,handlebars,php) ["auto"] auto = none in JavaScript, all in html
--editorconfig Enable setting configuration from EditorConfig --editorconfig Enable setting configuration from EditorConfig
Rarely needed options: Rarely needed options:
@ -237,7 +238,7 @@ def main():
'brace-style=', 'indent-level=', 'unescape-strings', 'brace-style=', 'indent-level=', 'unescape-strings',
'help', 'usage', 'stdin', 'eval-code', 'indent-with-tabs', 'keep-function-indentation', 'version', 'help', 'usage', 'stdin', 'eval-code', 'indent-with-tabs', 'keep-function-indentation', 'version',
'e4x', 'end-with-newline', 'comma-first', 'operator-position=', 'wrap-line-length', 'editorconfig', 'space-after-named-function', 'e4x', 'end-with-newline', 'comma-first', 'operator-position=', 'wrap-line-length', 'editorconfig', 'space-after-named-function',
'keep-array-indentation', 'indent-empty-lines']) 'keep-array-indentation', 'indent-empty-lines', 'templating'])
except getopt.GetoptError as ex: except getopt.GetoptError as ex:
print(ex, file=sys.stderr) print(ex, file=sys.stderr)
return usage(sys.stderr) return usage(sys.stderr)
@ -299,6 +300,8 @@ def main():
js_options.wrap_line_length = int(arg) js_options.wrap_line_length = int(arg)
elif opt in ('--indent-empty-lines'): elif opt in ('--indent-empty-lines'):
js_options.indent_empty_lines = True js_options.indent_empty_lines = True
elif opt in ('--templating'):
js_options.templating = arg.split(',')
elif opt in ('--stdin', '-i'): elif opt in ('--stdin', '-i'):
# stdin is the default if no files are passed # stdin is the default if no files are passed
filepath_params = [] filepath_params = []

View File

@ -72,6 +72,14 @@ class Options:
self.indent_empty_lines = self._get_boolean('indent_empty_lines') self.indent_empty_lines = self._get_boolean('indent_empty_lines')
# valid templating languages ['django', 'erb', 'handlebars', 'php']
# For now, 'auto' = all off for javascript, all on for html (and inline javascript).
# other values ignored
self.templating = self._get_selection_list('templating',
['auto', 'none', 'django', 'erb', 'handlebars', 'php'], ['auto'])
def _get_array(self, name, default_value=[]): def _get_array(self, name, default_value=[]):
option_value = getattr(self.raw_options, name, default_value) option_value = getattr(self.raw_options, name, default_value)
result = [] result = []

View File

@ -68,6 +68,14 @@ class TemplatablePattern(Pattern):
def _update(self): def _update(self):
self.__set_templated_pattern() self.__set_templated_pattern()
def read_options(self, options):
result = self._create()
for language in ['django', 'erb', 'handlebars', 'php']:
setattr(result._disabled, language,
not (language in options.templating))
result._update()
return result
def disable(self, language): def disable(self, language):
result = self._create() result = self._create()
setattr(result._disabled, language, True) setattr(result._disabled, language, True)

View File

@ -108,7 +108,7 @@ xmlRegExp = re.compile(
r'[\s\S]*?<(\/?)([-a-zA-Z:0-9_.]+|{[\s\S]+?}|!\[CDATA\[[\s\S]*?\]\])(\s+{[\s\S]+?}|\s+[-a-zA-Z:0-9_.]+|\s+[-a-zA-Z:0-9_.]+\s*=\s*(\'[^\']*\'|"[^"]*"|{[\s\S]+?}))*\s*(/?)\s*>') r'[\s\S]*?<(\/?)([-a-zA-Z:0-9_.]+|{[\s\S]+?}|!\[CDATA\[[\s\S]*?\]\])(\s+{[\s\S]+?}|\s+[-a-zA-Z:0-9_.]+|\s+[-a-zA-Z:0-9_.]+\s*=\s*(\'[^\']*\'|"[^"]*"|{[\s\S]+?}))*\s*(/?)\s*>')
class TokenizerPatterns(BaseTokenizerPatterns): class TokenizerPatterns(BaseTokenizerPatterns):
def __init__(self, input_scanner, acorn): def __init__(self, input_scanner, acorn, options):
BaseTokenizerPatterns.__init__(self, input_scanner) BaseTokenizerPatterns.__init__(self, input_scanner)
# This is not pretty, but given how we did the version import # This is not pretty, but given how we did the version import
@ -122,9 +122,8 @@ class TokenizerPatterns(BaseTokenizerPatterns):
six.u(r'\u2028\u2029')) six.u(r'\u2028\u2029'))
pattern = Pattern(input_scanner) pattern = Pattern(input_scanner)
templatable = TemplatablePattern(input_scanner) templatable = TemplatablePattern(input_scanner) \
templatable = templatable.disable('handlebars') .read_options(options)
templatable = templatable.disable('django')
self.identifier = templatable.starting_with(acorn.identifier \ self.identifier = templatable.starting_with(acorn.identifier \
).matching(acorn.identifierMatch) ).matching(acorn.identifierMatch)
@ -162,7 +161,7 @@ class Tokenizer(BaseTokenizer):
self.in_html_comment = False self.in_html_comment = False
self.has_char_escapes = False self.has_char_escapes = False
self._patterns = TokenizerPatterns(self._input, self.acorn) self._patterns = TokenizerPatterns(self._input, self.acorn, opts)
def _reset(self): def _reset(self):

View File

@ -4423,24 +4423,10 @@ class TestJSBeautifier(unittest.TestCase):
'// behavior of comments should be different for single statements vs block statements/expressions') '// behavior of comments should be different for single statements vs block statements/expressions')
#============================================================
# Template Formatting
self.reset_options()
bt('<?=$view["name"]; ?>')
bt('a = <?= external() ?>;')
bt(
'<?php\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'?>')
bt('a = <%= external() %>;')
#============================================================ #============================================================
# minimal template handling - () # minimal template handling - ()
self.reset_options() self.reset_options()
self.options.templating = ['django', 'erb', 'handlebars', 'php']
bt('var a = <?php$view["name"]; ?>;', 'var a = <?php$view["name"]; ?>;') bt('var a = <?php$view["name"]; ?>;', 'var a = <?php$view["name"]; ?>;')
bt( bt(
'a = abc<?php\n' + 'a = abc<?php\n' +
@ -4461,9 +4447,11 @@ class TestJSBeautifier(unittest.TestCase):
'echo "A";\n' + 'echo "A";\n' +
'?>;\n' + '?>;\n' +
'test.method();') 'test.method();')
bt('"<?php";if(0){}"?>";')
# minimal template handling - () # minimal template handling - ()
self.reset_options() self.reset_options()
self.options.templating = ['django', 'erb', 'handlebars', 'php']
bt('var a = <?=$view["name"]; ?>;', 'var a = <?=$view["name"]; ?>;') bt('var a = <?=$view["name"]; ?>;', 'var a = <?=$view["name"]; ?>;')
bt( bt(
'a = abc<?=\n' + 'a = abc<?=\n' +
@ -4484,9 +4472,11 @@ class TestJSBeautifier(unittest.TestCase):
'echo "A";\n' + 'echo "A";\n' +
'?>;\n' + '?>;\n' +
'test.method();') 'test.method();')
bt('"<?=";if(0){}"?>";')
# minimal template handling - () # minimal template handling - ()
self.reset_options() self.reset_options()
self.options.templating = ['django', 'erb', 'handlebars', 'php']
bt('var a = <%$view["name"]; %>;', 'var a = <%$view["name"]; %>;') bt('var a = <%$view["name"]; %>;', 'var a = <%$view["name"]; %>;')
bt( bt(
'a = abc<%\n' + 'a = abc<%\n' +
@ -4507,6 +4497,374 @@ class TestJSBeautifier(unittest.TestCase):
'echo "A";\n' + 'echo "A";\n' +
'%>;\n' + '%>;\n' +
'test.method();') 'test.method();')
bt('"<%";if(0){}"%>";')
# minimal template handling - ()
self.reset_options()
self.options.templating = ['django', 'erb', 'handlebars', 'php']
bt('var a = <%=$view["name"]; %>;', 'var a = <%=$view["name"]; %>;')
bt(
'a = abc<%=\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'%>;')
test_fragment(
'<%= %>\n' +
'test.met<%= someValue %>hod();')
bt(
'<%= "A" %>abc<%= "D" %>;\n' +
'<%= "B" %>.test();\n' +
'" <%= "C" \'D\' %> "')
bt(
'<%=\n' +
'echo "A";\n' +
'%>;\n' +
'test.method();')
bt('"<%=";if(0){}"%>";')
# minimal template handling - ()
self.reset_options()
self.options.templating = ['django', 'erb', 'handlebars', 'php']
bt('var a = {{$view["name"]; }};', 'var a = {{$view["name"]; }};')
bt(
'a = abc{{\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'}};')
test_fragment(
'{{ }}\n' +
'test.met{{ someValue }}hod();')
bt(
'{{ "A" }}abc{{ "D" }};\n' +
'{{ "B" }}.test();\n' +
'" {{ "C" \'D\' }} "')
bt(
'{{\n' +
'echo "A";\n' +
'}};\n' +
'test.method();')
bt('"{{";if(0){}"}}";')
# minimal template handling - ()
self.reset_options()
self.options.templating = ['django', 'erb', 'handlebars', 'php']
bt('var a = {#$view["name"]; #};', 'var a = {#$view["name"]; #};')
bt(
'a = abc{#\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'#};')
test_fragment(
'{# #}\n' +
'test.met{# someValue #}hod();')
bt(
'{# "A" #}abc{# "D" #};\n' +
'{# "B" #}.test();\n' +
'" {# "C" \'D\' #} "')
bt(
'{#\n' +
'echo "A";\n' +
'#};\n' +
'test.method();')
bt('"{#";if(0){}"#}";')
# minimal template handling - ()
self.reset_options()
self.options.templating = ['django', 'erb', 'handlebars', 'php']
bt('var a = {%$view["name"]; %};', 'var a = {%$view["name"]; %};')
bt(
'a = abc{%\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'%};')
test_fragment(
'{% %}\n' +
'test.met{% someValue %}hod();')
bt(
'{% "A" %}abc{% "D" %};\n' +
'{% "B" %}.test();\n' +
'" {% "C" \'D\' %} "')
bt(
'{%\n' +
'echo "A";\n' +
'%};\n' +
'test.method();')
bt('"{%";if(0){}"%}";')
# minimal template handling - ()
self.reset_options()
self.options.templating = ['django', 'erb', 'handlebars', 'php']
bt('var a = {{$view["name"]; }};', 'var a = {{$view["name"]; }};')
bt(
'a = abc{{\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'}};')
test_fragment(
'{{ }}\n' +
'test.met{{ someValue }}hod();')
bt(
'{{ "A" }}abc{{ "D" }};\n' +
'{{ "B" }}.test();\n' +
'" {{ "C" \'D\' }} "')
bt(
'{{\n' +
'echo "A";\n' +
'}};\n' +
'test.method();')
bt('"{{";if(0){}"}}";')
# minimal template handling - ()
self.reset_options()
self.options.templating = ['django', 'erb', 'handlebars', 'php']
bt('var a = {{#$view["name"]; }};', 'var a = {{#$view["name"]; }};')
bt(
'a = abc{{#\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'}};')
test_fragment(
'{{# }}\n' +
'test.met{{# someValue }}hod();')
bt(
'{{# "A" }}abc{{# "D" }};\n' +
'{{# "B" }}.test();\n' +
'" {{# "C" \'D\' }} "')
bt(
'{{#\n' +
'echo "A";\n' +
'}};\n' +
'test.method();')
bt('"{{#";if(0){}"}}";')
# minimal template handling - ()
self.reset_options()
self.options.templating = ['django', 'erb', 'handlebars', 'php']
bt('var a = {{!$view["name"]; }};', 'var a = {{!$view["name"]; }};')
bt(
'a = abc{{!\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'}};')
test_fragment(
'{{! }}\n' +
'test.met{{! someValue }}hod();')
bt(
'{{! "A" }}abc{{! "D" }};\n' +
'{{! "B" }}.test();\n' +
'" {{! "C" \'D\' }} "')
bt(
'{{!\n' +
'echo "A";\n' +
'}};\n' +
'test.method();')
bt('"{{!";if(0){}"}}";')
# minimal template handling - ()
self.reset_options()
self.options.templating = ['django', 'erb', 'handlebars', 'php']
bt('var a = {{!--$view["name"]; --}};', 'var a = {{!--$view["name"]; --}};')
bt(
'a = abc{{!--\n' +
'for($i = 1; $i <= 100; $i++;) {\n' +
' #count to 100!\n' +
' echo($i . "</br>");\n' +
'}\n' +
'--}};')
test_fragment(
'{{!-- --}}\n' +
'test.met{{!-- someValue --}}hod();')
bt(
'{{!-- "A" --}}abc{{!-- "D" --}};\n' +
'{{!-- "B" --}}.test();\n' +
'" {{!-- "C" \'D\' --}} "')
bt(
'{{!--\n' +
'echo "A";\n' +
'--}};\n' +
'test.method();')
bt('"{{!--";if(0){}"--}}";')
#============================================================
# Templating disabled - ensure formatting - ()
self.reset_options()
self.options.templating = ['auto']
bt(
'"<?php";if(0){}"?>";',
# -- output --
'"<?php";\n' +
'if (0) {}\n' +
'"?>";')
bt(
'"<?php";if(0){}',
# -- output --
'"<?php";\n' +
'if (0) {}')
# Templating disabled - ensure formatting - ()
self.reset_options()
self.options.templating = ['auto']
bt(
'"<?=";if(0){}"?>";',
# -- output --
'"<?=";\n' +
'if (0) {}\n' +
'"?>";')
bt(
'"<?=";if(0){}',
# -- output --
'"<?=";\n' +
'if (0) {}')
# Templating disabled - ensure formatting - ()
self.reset_options()
self.options.templating = ['auto']
bt(
'"<%";if(0){}"%>";',
# -- output --
'"<%";\n' +
'if (0) {}\n' +
'"%>";')
bt(
'"<%";if(0){}',
# -- output --
'"<%";\n' +
'if (0) {}')
# Templating disabled - ensure formatting - ()
self.reset_options()
self.options.templating = ['auto']
bt(
'"<%=";if(0){}"%>";',
# -- output --
'"<%=";\n' +
'if (0) {}\n' +
'"%>";')
bt(
'"<%=";if(0){}',
# -- output --
'"<%=";\n' +
'if (0) {}')
# Templating disabled - ensure formatting - ()
self.reset_options()
self.options.templating = ['auto']
bt(
'"{{";if(0){}"}}";',
# -- output --
'"{{";\n' +
'if (0) {}\n' +
'"}}";')
bt(
'"{{";if(0){}',
# -- output --
'"{{";\n' +
'if (0) {}')
# Templating disabled - ensure formatting - ()
self.reset_options()
self.options.templating = ['auto']
bt(
'"{#";if(0){}"#}";',
# -- output --
'"{#";\n' +
'if (0) {}\n' +
'"#}";')
bt(
'"{#";if(0){}',
# -- output --
'"{#";\n' +
'if (0) {}')
# Templating disabled - ensure formatting - ()
self.reset_options()
self.options.templating = ['auto']
bt(
'"{%";if(0){}"%}";',
# -- output --
'"{%";\n' +
'if (0) {}\n' +
'"%}";')
bt(
'"{%";if(0){}',
# -- output --
'"{%";\n' +
'if (0) {}')
# Templating disabled - ensure formatting - ()
self.reset_options()
self.options.templating = ['auto']
bt(
'"{{";if(0){}"}}";',
# -- output --
'"{{";\n' +
'if (0) {}\n' +
'"}}";')
bt(
'"{{";if(0){}',
# -- output --
'"{{";\n' +
'if (0) {}')
# Templating disabled - ensure formatting - ()
self.reset_options()
self.options.templating = ['auto']
bt(
'"{{#";if(0){}"}}";',
# -- output --
'"{{#";\n' +
'if (0) {}\n' +
'"}}";')
bt(
'"{{#";if(0){}',
# -- output --
'"{{#";\n' +
'if (0) {}')
# Templating disabled - ensure formatting - ()
self.reset_options()
self.options.templating = ['auto']
bt(
'"{{!";if(0){}"}}";',
# -- output --
'"{{!";\n' +
'if (0) {}\n' +
'"}}";')
bt(
'"{{!";if(0){}',
# -- output --
'"{{!";\n' +
'if (0) {}')
# Templating disabled - ensure formatting - ()
self.reset_options()
self.options.templating = ['auto']
bt(
'"{{!--";if(0){}"--}}";',
# -- output --
'"{{!--";\n' +
'if (0) {}\n' +
'"--}}";')
bt(
'"{{!--";if(0){}',
# -- output --
'"{{!--";\n' +
'if (0) {}')
#============================================================ #============================================================

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,69 @@
var inputlib = require('./inputlib'); var inputlib = require('./inputlib');
var templating_matrix = [
// Php (<?php ... ?> and <?= ... ?>) =.
{
s: '<?php',
e: '?>'
},
{
s: '<?=',
e: '?>'
},
// erb, ejs, asp: <% ... %>
{
s: '<%',
e: '%>'
},
{
s: '<%=',
e: '%>'
},
// django {{ ... }} and {# ... #} and {% ... %}
{
s: '{{',
e: '}}'
},
{
s: '{#',
e: '#}'
},
{
s: '{%',
e: '%}'
},
// handlebars {{ ... }} and {{# ... }} and {{! ... }} and {{!-- --}}
{
// options: [
// { name: "indent_handlebars", value: "false" }
// ],
s: '{{',
e: '}}'
},
{
// options: [
// { name: "indent_handlebars", value: "false" }
// ],
s: '{{#',
e: '}}'
},
{
// options: [
// { name: "indent_handlebars", value: "false" }
// ],
s: '{{!',
e: '}}'
},
{
// options: [
// { name: "indent_handlebars", value: "false" }
// ],
s: '{{!--',
e: '--}}'
}
];
exports.test_data = { exports.test_data = {
default_options: [ default_options: [
{ name: "indent_size", value: "4" }, { name: "indent_size", value: "4" },
@ -2831,89 +2894,14 @@ exports.test_data = {
} }
] ]
}, {
name: "Template Formatting",
description: "Php (<?php ... ?>) and underscore.js templating treated as strings.",
options: [],
tests: [
{ unchanged: '<?=$view["name"]; ?>' },
{ unchanged: 'a = <?= external() ?>;' },
{
unchanged: [
'<?php',
'for($i = 1; $i <= 100; $i++;) {',
' #count to 100!',
' echo($i . "</br>");',
'}',
'?>'
]
},
{ unchanged: 'a = <%= external() %>;' }
]
}, { }, {
name: "minimal template handling", name: "minimal template handling",
description: "treated as content.", description: "treated as content.",
template: "^^^ $$$", template: "^^^ $$$",
matrix: [ options: [
{ name: "templating", value: "['django', 'erb', 'handlebars', 'php']" }
// Php (<?php ... ?> and <?= ... ?>) =.
{
s: '<?php',
e: '?>'
},
{
s: '<?=',
e: '?>'
},
// erb, ejs, asp: <% ... %>
{
s: '<%',
e: '%>'
} //,
// django {{ ... }} and {# ... #} and {% ... %}
// {
// s: '{{',
// e: '}}'
// },
// {
// s: '{#',
// e: '#}'
// },
// {
// s: '{%',
// e: '%}'
// },
// handlebars {{ ... }} and {{# ... }} and {{! ... }} and {{!-- --}}
// {
// options: [
// { name: "indent_handlebars", value: "false" }
// ],
// s: '{{',
// e: '}}'
// },
// {
// options: [
// { name: "indent_handlebars", value: "false" }
// ],
// s: '{{#',
// e: '}}'
// },
// {
// options: [
// { name: "indent_handlebars", value: "false" }
// ],
// s: '{{!',
// e: '}}'
// },
// {
// options: [
// { name: "indent_handlebars", value: "false" }
// ],
// s: '{{!--',
// e: '--}}'
// }
], ],
matrix: templating_matrix,
tests: [{ tests: [{
input: 'var a = ^^^s$$$$view["name"]; ^^^e$$$;', input: 'var a = ^^^s$$$$view["name"]; ^^^e$$$;',
output: 'var a = ^^^s$$$$view["name"]; ^^^e$$$;' output: 'var a = ^^^s$$$$view["name"]; ^^^e$$$;'
@ -2945,6 +2933,36 @@ exports.test_data = {
'^^^e$$$;', '^^^e$$$;',
'test.method();' 'test.method();'
] ]
}, {
unchanged: [
'"^^^s$$$";if(0){}"^^^e$$$";'
]
}]
}, {
name: "Templating disabled - ensure formatting",
description: "",
template: "^^^ $$$",
options: [
{ name: "templating", value: "['auto']" }
],
matrix: templating_matrix,
tests: [{
input: [
'"^^^s$$$";if(0){}"^^^e$$$";'
],
output: [
'"^^^s$$$";',
'if (0) {}',
'"^^^e$$$";'
]
}, {
input: [
'"^^^s$$$";if(0){}'
],
output: [
'"^^^s$$$";',
'if (0) {}'
]
}] }]
}, { }, {
name: "jslint and space after anon function", name: "jslint and space after anon function",