jsdoc-75lb
Version:
An API documentation generator for JavaScript.
1,184 lines (1,087 loc) • 111 kB
JavaScript
/*global js_beautify: true */
function run_javascript_tests(test_obj, Urlencoded, js_beautify, html_beautify, css_beautify)
{
var opts = {
indent_size: 4,
indent_char: ' ',
preserve_newlines: true,
jslint_happy: false,
keep_array_indentation: false,
brace_style: 'collapse',
space_before_conditional: true,
break_chained_methods: false,
selector_separator: '\n',
end_with_newline: false
};
function test_js_beautifier(input)
{
return js_beautify(input, opts);
}
function test_html_beautifier(input)
{
return html_beautify(input, opts);
}
var sanitytest;
// test the input on beautifier with the current flag settings
// does not check the indentation / surroundings as bt() does
function test_fragment(input, expected)
{
expected = expected || expected === '' ? expected : input;
sanitytest.expect(input, expected);
// if the expected is different from input, run it again
// expected output should be unchanged when run twice.
if (expected !== input) {
sanitytest.expect(expected, expected);
}
// Everywhere we do newlines, they should be replaced with opts.eol
opts.eol = '\r\\n';
expected = expected.replace(/[\n]/g, '\r\n');
sanitytest.expect(input, expected);
input = input.replace(/[\n]/g, '\r\n');
sanitytest.expect(input, expected);
opts.eol = '\n';
}
// test the input on beautifier with the current flag settings
// test both the input as well as { input } wrapping
function bt(input, expectation)
{
var wrapped_input, wrapped_expectation;
expectation = expectation || expectation === '' ? expectation : input;
sanitytest.test_function(test_js_beautifier, 'js_beautify');
test_fragment(input, expectation);
// If we set raw, input should be unchanged
opts.test_output_raw = true;
if (!opts.end_with_newline) {
test_fragment(input, input);
}
opts.test_output_raw = false;
// test also the returned indentation
// e.g if input = "asdf();"
// then test that this remains properly formatted as well:
// {
// asdf();
// indent;
// }
if (opts.indent_size === 4 && input) {
wrapped_input = '{\n' + input.replace(/^(.+)$/mg, ' $1') + '\n foo = bar;\n}';
wrapped_expectation = '{\n' + expectation.replace(/^(.+)$/mg, ' $1') + '\n foo = bar;\n}';
test_fragment(wrapped_input, wrapped_expectation);
// If we set raw, input should be unchanged
opts.test_output_raw = true;
if (!opts.end_with_newline) {
test_fragment(wrapped_input, wrapped_input);
}
opts.test_output_raw = false;
}
}
// run all tests for the given brace style ("collapse", "expand", "end-expand", or "none").
// uses various whitespace combinations before and after opening and closing braces,
// respectively, for most of the tests' inputs.
function beautify_brace_tests(brace_style) {
var ex_brace_style = opts.brace_style,
indent_on_wrap_str = ' '; // could use Array(opts.indent_size + 1).join(' '); if we wanted to replace _all_ of the hardcoded 4-space in the test and expectation strings
function permute_brace_tests(expect_open_white, expect_close_white) {
// run the tests that need permutation against a specific combination of
// pre-opening-brace and pre-closing-brace whitespace
function run_brace_permutation(test_open_white, test_close_white) {
var to = test_open_white,
tc = test_close_white,
eo = expect_open_white ? expect_open_white : to === '' ? ' ' : to,
ec = expect_close_white ? expect_close_white : tc === '' ? ' ' : tc,
i = eo === '\n' ? indent_on_wrap_str: '';
bt( '//case 1\nif (a == 1)' + to + '{}\n//case 2\nelse if (a == 2)' + to + '{}',
'//case 1\nif (a == 1)' + eo + '{}\n//case 2\nelse if (a == 2)' + eo + '{}');
bt( 'if(1)' + to + '{2}' + tc + 'else' + to + '{3}',
'if (1)' + eo + '{\n 2\n}' + ec + 'else' + eo + '{\n 3\n}');
bt( 'try' + to + '{a();}' + tc +
'catch(b)' + to + '{c();}' + tc +
'catch(d)' + to + '{}' + tc +
'finally' + to + '{e();}',
// expected
'try' + eo + '{\n a();\n}' + ec +
'catch (b)' + eo + '{\n c();\n}' + ec +
'catch (d)' + eo + '{}' + ec +
'finally' + eo + '{\n e();\n}');
bt( 'if(a)' + to + '{b();}' + tc + 'else if(c) foo();',
'if (a)' + eo + '{\n b();\n}' + ec + 'else if (c) foo();');
// if/else statement with empty body
bt( 'if (a)' + to + '{\n// comment\n}' + tc + 'else' + to + '{\n// comment\n}',
'if (a)' + eo + '{\n // comment\n}' + ec + 'else' + eo + '{\n // comment\n}');
bt( 'if (x)' + to + '{y}' + tc + 'else' + to + '{ if (x)' + to + '{y}}',
'if (x)' + eo + '{\n y\n}' + ec + 'else' + eo + '{\n if (x)' + eo + i + '{\n y\n }\n}');
bt( 'if (a)' + to + '{\nb;\n}' + tc + 'else' + to + '{\nc;\n}',
'if (a)' + eo + '{\n b;\n}' + ec + 'else' + eo + '{\n c;\n}');
test_fragment(' /*\n* xx\n*/\n// xx\nif (foo)' + to + '{\n bar();\n}',
' /*\n * xx\n */\n // xx\n if (foo)' + eo + i + '{\n bar();\n }');
bt( 'if (foo)' + to + '{}' + tc + 'else /regex/.test();',
'if (foo)' + eo + '{}' + ec + 'else /regex/.test();');
test_fragment('if (foo)' + to + '{', 'if (foo)' + eo + '{');
test_fragment('foo' + to + '{', 'foo' + eo + '{');
test_fragment('return;' + to + '{', 'return;' + eo + '{');
bt( 'function x()' + to + '{\n foo();\n}zzz', 'function x()' + eo +'{\n foo();\n}\nzzz');
bt( 'var a = new function a()' + to + '{};', 'var a = new function a()' + eo + '{};');
bt( 'var a = new function a()' + to + ' {},\n b = new function b()' + to + ' {};',
'var a = new function a()' + eo + i + '{},\n b = new function b()' + eo + i + '{};');
bt("foo(" + to + "{\n 'a': 1\n},\n10);",
"foo(" + (eo === ' ' ? '' : eo) + i + "{\n 'a': 1\n },\n 10);"); // "foo( {..." is a weird case
bt('(["foo","bar"]).each(function(i)' + to + '{return i;});',
'(["foo", "bar"]).each(function(i)' + eo + '{\n return i;\n});');
bt('(function(i)' + to + '{return i;})();', '(function(i)' + eo + '{\n return i;\n})();');
bt( "test( /*Argument 1*/" + to + "{\n" +
" 'Value1': '1'\n" +
"}, /*Argument 2\n" +
" */ {\n" +
" 'Value2': '2'\n" +
"});",
// expected
"test( /*Argument 1*/" + eo + i + "{\n" +
" 'Value1': '1'\n" +
" },\n" +
" /*Argument 2\n" +
" */\n" +
" {\n" +
" 'Value2': '2'\n" +
" });");
bt( "test( /*Argument 1*/" + to + "{\n" +
" 'Value1': '1'\n" +
"}, /*Argument 2\n" +
" */\n" +
"{\n" +
" 'Value2': '2'\n" +
"});",
// expected
"test( /*Argument 1*/" + eo + i + "{\n" +
" 'Value1': '1'\n" +
" },\n" +
" /*Argument 2\n" +
" */\n" +
" {\n" +
" 'Value2': '2'\n" +
" });");
}
run_brace_permutation('\n', '\n');
run_brace_permutation('\n', ' ');
run_brace_permutation(' ', ' ');
run_brace_permutation(' ', '\n');
run_brace_permutation('','');
// brace tests that don't make sense to permutate
test_fragment('return {'); // return needs the brace.
test_fragment('return /* inline */ {');
bt('throw {}');
bt('throw {\n foo;\n}');
bt( 'var foo = {}');
test_fragment('a: do {} while (); xxx', 'a: do {} while ();\nxxx');
bt( '{a: do {} while (); xxx}', '{\n a: do {} while ();xxx\n}');
bt( 'var a = new function() {};');
bt( 'var a = new function()\n{};', 'var a = new function() {};');
bt( "test(\n" +
"/*Argument 1*/ {\n" +
" 'Value1': '1'\n" +
"},\n" +
"/*Argument 2\n" +
" */ {\n" +
" 'Value2': '2'\n" +
"});",
// expected
"test(\n" +
" /*Argument 1*/\n" +
" {\n" +
" 'Value1': '1'\n" +
" },\n" +
" /*Argument 2\n" +
" */\n" +
" {\n" +
" 'Value2': '2'\n" +
" });");
}
opts.brace_style = brace_style;
switch(opts.brace_style) {
case 'collapse':
permute_brace_tests(' ', ' ');
break;
case 'expand':
permute_brace_tests('\n', '\n');
break;
case 'end-expand':
permute_brace_tests(' ', '\n');
break;
case 'none':
permute_brace_tests();
break;
}
opts.brace_style = ex_brace_style;
}
function unicode_char(value) {
return String.fromCharCode(value)
}
function beautifier_tests()
{
sanitytest = test_obj;
opts.indent_size = 4;
opts.indent_char = ' ';
opts.preserve_newlines = true;
opts.jslint_happy = false;
opts.keep_array_indentation = false;
opts.brace_style = 'collapse';
// Unicode Support
bt('var ' + unicode_char(3232) + '_' + unicode_char(3232) + ' = "hi";');
bt(
'var ' + unicode_char(228) + 'x = {\n' +
' ' + unicode_char(228) + 'rgerlich: true\n' +
'};');
// End With Newline - (eof = "\n")
opts.end_with_newline = true;
test_fragment('', '\n');
test_fragment(' return .5', ' return .5\n');
test_fragment(' \n\nreturn .5\n\n\n\n', ' return .5\n');
test_fragment('\n');
// End With Newline - (eof = "")
opts.end_with_newline = false;
test_fragment('');
test_fragment(' return .5');
test_fragment(' \n\nreturn .5\n\n\n\n', ' return .5');
test_fragment('\n', '');
// Comma-first option - (c0 = "\n, ", c1 = "\n , ", c2 = "\n , ", c3 = "\n , ")
opts.comma_first = true;
bt('{a:1, b:2}', '{\n a: 1\n , b: 2\n}');
bt('var a=1, b=c[d], e=6;', 'var a = 1\n , b = c[d]\n , e = 6;');
bt('for(var a=1,b=2,c=3;d<3;d++)\ne', 'for (var a = 1, b = 2, c = 3; d < 3; d++)\n e');
bt('for(var a=1,b=2,\nc=3;d<3;d++)\ne', 'for (var a = 1, b = 2\n , c = 3; d < 3; d++)\n e');
bt('function foo() {\n return [\n "one"\n , "two"\n ];\n}');
bt('a=[[1,2],[4,5],[7,8]]', 'a = [\n [1, 2]\n , [4, 5]\n , [7, 8]\n]');
bt('a=[[1,2],[4,5],[7,8],]', 'a = [\n [1, 2]\n , [4, 5]\n , [7, 8]\n, ]');
bt('a=[[1,2],[4,5],function(){},[7,8]]', 'a = [\n [1, 2]\n , [4, 5]\n , function() {}\n , [7, 8]\n]');
bt('a=[[1,2],[4,5],function(){},function(){},[7,8]]', 'a = [\n [1, 2]\n , [4, 5]\n , function() {}\n , function() {}\n , [7, 8]\n]');
bt('a=[[1,2],[4,5],function(){},[7,8]]', 'a = [\n [1, 2]\n , [4, 5]\n , function() {}\n , [7, 8]\n]');
bt('a=[b,c,function(){},function(){},d]', 'a = [b, c, function() {}, function() {}, d]');
bt('a=[b,c,\nfunction(){},function(){},d]', 'a = [b, c\n , function() {}\n , function() {}\n , d\n]');
bt('a=[a[1],b[4],c[d[7]]]', 'a = [a[1], b[4], c[d[7]]]');
bt('[1,2,[3,4,[5,6],7],8]', '[1, 2, [3, 4, [5, 6], 7], 8]');
bt('[[["1","2"],["3","4"]],[["5","6","7"],["8","9","0"]],[["1","2","3"],["4","5","6","7"],["8","9","0"]]]', '[\n [\n ["1", "2"]\n , ["3", "4"]\n ]\n , [\n ["5", "6", "7"]\n , ["8", "9", "0"]\n ]\n , [\n ["1", "2", "3"]\n , ["4", "5", "6", "7"]\n , ["8", "9", "0"]\n ]\n]');
// Comma-first option - (c0 = ",\n", c1 = ",\n ", c2 = ",\n ", c3 = ",\n ")
opts.comma_first = false;
bt('{a:1, b:2}', '{\n a: 1,\n b: 2\n}');
bt('var a=1, b=c[d], e=6;', 'var a = 1,\n b = c[d],\n e = 6;');
bt('for(var a=1,b=2,c=3;d<3;d++)\ne', 'for (var a = 1, b = 2, c = 3; d < 3; d++)\n e');
bt('for(var a=1,b=2,\nc=3;d<3;d++)\ne', 'for (var a = 1, b = 2,\n c = 3; d < 3; d++)\n e');
bt('function foo() {\n return [\n "one",\n "two"\n ];\n}');
bt('a=[[1,2],[4,5],[7,8]]', 'a = [\n [1, 2],\n [4, 5],\n [7, 8]\n]');
bt('a=[[1,2],[4,5],[7,8],]', 'a = [\n [1, 2],\n [4, 5],\n [7, 8],\n]');
bt('a=[[1,2],[4,5],function(){},[7,8]]', 'a = [\n [1, 2],\n [4, 5],\n function() {},\n [7, 8]\n]');
bt('a=[[1,2],[4,5],function(){},function(){},[7,8]]', 'a = [\n [1, 2],\n [4, 5],\n function() {},\n function() {},\n [7, 8]\n]');
bt('a=[[1,2],[4,5],function(){},[7,8]]', 'a = [\n [1, 2],\n [4, 5],\n function() {},\n [7, 8]\n]');
bt('a=[b,c,function(){},function(){},d]', 'a = [b, c, function() {}, function() {}, d]');
bt('a=[b,c,\nfunction(){},function(){},d]', 'a = [b, c,\n function() {},\n function() {},\n d\n]');
bt('a=[a[1],b[4],c[d[7]]]', 'a = [a[1], b[4], c[d[7]]]');
bt('[1,2,[3,4,[5,6],7],8]', '[1, 2, [3, 4, [5, 6], 7], 8]');
bt('[[["1","2"],["3","4"]],[["5","6","7"],["8","9","0"]],[["1","2","3"],["4","5","6","7"],["8","9","0"]]]', '[\n [\n ["1", "2"],\n ["3", "4"]\n ],\n [\n ["5", "6", "7"],\n ["8", "9", "0"]\n ],\n [\n ["1", "2", "3"],\n ["4", "5", "6", "7"],\n ["8", "9", "0"]\n ]\n]');
// New Test Suite
// Async / await tests
bt('async function foo() {}');
bt('let w = async function foo() {}');
bt('async function foo() {}\nvar x = await foo();');
// async function as an input to another function
bt('wrapper(async function foo() {})');
// await on inline anonymous function. should have a space after await
bt(
'async function() {\n var w = await(async function() {\n return await foo();\n })();\n}',
'async function() {\n var w = await (async function() {\n return await foo();\n })();\n}');
// ensure that this doesn't break anyone with the async library
bt('async.map(function(t) {})');
// e4x - Test that e4x literals passed through when e4x-option is enabled
opts.e4x = true;
bt('xml=<a b="c"><d/><e>\n foo</e>x</a>;', 'xml = <a b="c"><d/><e>\n foo</e>x</a>;');
bt('<a b=\'This is a quoted "c".\'/>');
bt('<a b="This is a quoted \'c\'."/>');
bt('<a b="A quote \' inside string."/>');
bt('<a b=\'A quote " inside string.\'/>');
bt('<a b=\'Some """ quotes "" inside string.\'/>');
// Handles inline expressions
bt('xml=<{a} b="c"><d/><e v={z}>\n foo</e>x</{a}>;', 'xml = <{a} b="c"><d/><e v={z}>\n foo</e>x</{a}>;');
bt('xml=<{a} b="c">\n <e v={z}>\n foo</e>x</{a}>;', 'xml = <{a} b="c">\n <e v={z}>\n foo</e>x</{a}>;');
// xml literals with special characters in elem names - see http://www.w3.org/TR/REC-xml/#NT-NameChar
bt('xml = <_:.valid.xml- _:.valid.xml-="123"/>;');
// Handles CDATA
bt('xml=<![CDATA[ b="c"><d/><e v={z}>\n foo</e>x/]]>;', 'xml = <![CDATA[ b="c"><d/><e v={z}>\n foo</e>x/]]>;');
bt('xml=<![CDATA[]]>;', 'xml = <![CDATA[]]>;');
bt('xml=<a b="c"><![CDATA[d/></a></{}]]></a>;', 'xml = <a b="c"><![CDATA[d/></a></{}]]></a>;');
// JSX - working jsx from http://prettydiff.com/unit_tests/beautification_javascript_jsx.txt
bt(
'var ListItem = React.createClass({\n' +
' render: function() {\n' +
' return (\n' +
' <li className="ListItem">\n' +
' <a href={ "/items/" + this.props.item.id }>\n' +
' this.props.item.name\n' +
' </a>\n' +
' </li>\n' +
' );\n' +
' }\n' +
'});');
bt(
'var List = React.createClass({\n' +
' renderList: function() {\n' +
' return this.props.items.map(function(item) {\n' +
' return <ListItem item={item} key={item.id} />;\n' +
' });\n' +
' },\n' +
'\n' +
' render: function() {\n' +
' return <ul className="List">\n' +
' this.renderList()\n' +
' </ul>\n' +
' }\n' +
'});');
bt(
'var Mist = React.createClass({\n' +
' renderList: function() {\n' +
' return this.props.items.map(function(item) {\n' +
' return <ListItem item={return <tag>{item}</tag>} key={item.id} />;\n' +
' });\n' +
' }\n' +
'});');
bt(
'// JSX\n' +
'var box = <Box>\n' +
' {shouldShowAnswer(user) ?\n' +
' <Answer value={false}>no</Answer> : <Box.Comment>\n' +
' Text Content\n' +
' </Box.Comment>}\n' +
' </Box>;\n' +
'var a = function() {\n' +
' return <tsdf>asdf</tsdf>;\n' +
'};\n' +
'\n' +
'var HelloMessage = React.createClass({\n' +
' render: function() {\n' +
' return <div>Hello {this.props.name}</div>;\n' +
' }\n' +
'});\n' +
'React.render(<HelloMessage name="John" />, mountNode);');
bt(
'var Timer = React.createClass({\n' +
' getInitialState: function() {\n' +
' return {\n' +
' secondsElapsed: 0\n' +
' };\n' +
' },\n' +
' tick: function() {\n' +
' this.setState({\n' +
' secondsElapsed: this.state.secondsElapsed + 1\n' +
' });\n' +
' },\n' +
' componentDidMount: function() {\n' +
' this.interval = setInterval(this.tick, 1000);\n' +
' },\n' +
' componentWillUnmount: function() {\n' +
' clearInterval(this.interval);\n' +
' },\n' +
' render: function() {\n' +
' return (\n' +
' <div>Seconds Elapsed: {this.state.secondsElapsed}</div>\n' +
' );\n' +
' }\n' +
'});\n' +
'React.render(<Timer />, mountNode);');
bt(
'var TodoList = React.createClass({\n' +
' render: function() {\n' +
' var createItem = function(itemText) {\n' +
' return <li>{itemText}</li>;\n' +
' };\n' +
' return <ul>{this.props.items.map(createItem)}</ul>;\n' +
' }\n' +
'});');
bt(
'var TodoApp = React.createClass({\n' +
' getInitialState: function() {\n' +
' return {\n' +
' items: [],\n' +
' text: \'\'\n' +
' };\n' +
' },\n' +
' onChange: function(e) {\n' +
' this.setState({\n' +
' text: e.target.value\n' +
' });\n' +
' },\n' +
' handleSubmit: function(e) {\n' +
' e.preventDefault();\n' +
' var nextItems = this.state.items.concat([this.state.text]);\n' +
' var nextText = \'\';\n' +
' this.setState({\n' +
' items: nextItems,\n' +
' text: nextText\n' +
' });\n' +
' },\n' +
' render: function() {\n' +
' return (\n' +
' <div>\n' +
' <h3>TODO</h3>\n' +
' <TodoList items={this.state.items} />\n' +
' <form onSubmit={this.handleSubmit}>\n' +
' <input onChange={this.onChange} value={this.state.text} />\n' +
' <button>{\'Add #\' + (this.state.items.length + 1)}</button>\n' +
' </form>\n' +
' </div>\n' +
' );\n' +
' }\n' +
'});\n' +
'React.render(<TodoApp />, mountNode);');
bt(
'var converter = new Showdown.converter();\n' +
'var MarkdownEditor = React.createClass({\n' +
' getInitialState: function() {\n' +
' return {value: \'Type some *markdown* here!\'};\n' +
' },\n' +
' handleChange: function() {\n' +
' this.setState({value: this.refs.textarea.getDOMNode().value});\n' +
' },\n' +
' render: function() {\n' +
' return (\n' +
' <div className="MarkdownEditor">\n' +
' <h3>Input</h3>\n' +
' <textarea\n' +
' onChange={this.handleChange}\n' +
' ref="textarea"\n' +
' defaultValue={this.state.value} />\n' +
' <h3>Output</h3>\n' +
' <div\n' +
' className="content"\n' +
' dangerouslySetInnerHTML=\n' +
' />\n' +
' </div>\n' +
' );\n' +
' }\n' +
'});\n' +
'React.render(<MarkdownEditor />, mountNode);',
'var converter = new Showdown.converter();\n' +
'var MarkdownEditor = React.createClass({\n' +
' getInitialState: function() {\n' +
' return {\n' +
' value: \'Type some *markdown* here!\'\n' +
' };\n' +
' },\n' +
' handleChange: function() {\n' +
' this.setState({\n' +
' value: this.refs.textarea.getDOMNode().value\n' +
' });\n' +
' },\n' +
' render: function() {\n' +
' return (\n' +
' <div className="MarkdownEditor">\n' +
' <h3>Input</h3>\n' +
' <textarea\n' +
' onChange={this.handleChange}\n' +
' ref="textarea"\n' +
' defaultValue={this.state.value} />\n' +
' <h3>Output</h3>\n' +
' <div\n' +
' className="content"\n' +
' dangerouslySetInnerHTML=\n' +
' />\n' +
' </div>\n' +
' );\n' +
' }\n' +
'});\n' +
'React.render(<MarkdownEditor />, mountNode);');
// JSX - Not quite correct jsx formatting that still works
bt(
'var content = (\n' +
' <Nav>\n' +
' {/* child comment, put {} around */}\n' +
' <Person\n' +
' /* multi\n' +
' line\n' +
' comment */\n' +
' //attr="test"\n' +
' name={window.isLoggedIn ? window.name : \'\'} // end of line comment\n' +
' />\n' +
' </Nav>\n' +
' );\n' +
'var qwer = <DropDown> A dropdown list <Menu> <MenuItem>Do Something</MenuItem> <MenuItem>Do Something Fun!</MenuItem> <MenuItem>Do Something Else</MenuItem> </Menu> </DropDown>;\n' +
'render(dropdown);',
'var content = (\n' +
' <Nav>\n' +
' {/* child comment, put {} around */}\n' +
' <Person\n' +
' /* multi\n' +
' line\n' +
' comment */\n' +
' //attr="test"\n' +
' name={window.isLoggedIn ? window.name : \'\'} // end of line comment\n' +
' />\n' +
' </Nav>\n' +
');\n' +
'var qwer = <DropDown> A dropdown list <Menu> <MenuItem>Do Something</MenuItem> <MenuItem>Do Something Fun!</MenuItem> <MenuItem>Do Something Else</MenuItem> </Menu> </DropDown>;\n' +
'render(dropdown);');
// Handles messed up tags, as long as it isn't the same name
// as the root tag. Also handles tags of same name as root tag
// as long as nesting matches.
bt(
'xml=<a x="jn"><c></b></f><a><d jnj="jnn"><f></a ></nj></a>;',
'xml = <a x="jn"><c></b></f><a><d jnj="jnn"><f></a ></nj></a>;');
// If xml is not terminated, the remainder of the file is treated
// as part of the xml-literal (passed through unaltered)
test_fragment(
'xml=<a></b>\nc<b;',
'xml = <a></b>\nc<b;');
// Issue #646 = whitespace is allowed in attribute declarations
bt(
'let a = React.createClass({\n' +
' render() {\n' +
' return (\n' +
' <p className=\'a\'>\n' +
' <span>c</span>\n' +
' </p>\n' +
' );\n' +
' }\n' +
'});');
bt(
'let a = React.createClass({\n' +
' render() {\n' +
' return (\n' +
' <p className = \'b\'>\n' +
' <span>c</span>\n' +
' </p>\n' +
' );\n' +
' }\n' +
'});');
bt(
'let a = React.createClass({\n' +
' render() {\n' +
' return (\n' +
' <p className = "c">\n' +
' <span>c</span>\n' +
' </p>\n' +
' );\n' +
' }\n' +
'});');
bt(
'let a = React.createClass({\n' +
' render() {\n' +
' return (\n' +
' <{e} className = {d}>\n' +
' <span>c</span>\n' +
' </{e}>\n' +
' );\n' +
' }\n' +
'});');
// e4x disabled
opts.e4x = false;
bt(
'xml=<a b="c"><d/><e>\n foo</e>x</a>;',
'xml = < a b = "c" > < d / > < e >\n foo < /e>x</a > ;');
// Multiple braces
bt('{{}/z/}', '{\n {}\n /z/\n}');
// Beautify preserve formatting
bt('/* beautify preserve:start */\n/* beautify preserve:end */');
bt('/* beautify preserve:start */\n var a = 1;\n/* beautify preserve:end */');
bt('var a = 1;\n/* beautify preserve:start */\n var a = 1;\n/* beautify preserve:end */');
bt('/* beautify preserve:start */ {asdklgh;y;;{}dd2d}/* beautify preserve:end */');
bt(
'var a = 1;\n/* beautify preserve:start */\n var a = 1;\n/* beautify preserve:end */',
'var a = 1;\n/* beautify preserve:start */\n var a = 1;\n/* beautify preserve:end */');
bt(
'var a = 1;\n /* beautify preserve:start */\n var a = 1;\n/* beautify preserve:end */',
'var a = 1;\n/* beautify preserve:start */\n var a = 1;\n/* beautify preserve:end */');
bt(
'var a = {\n' +
' /* beautify preserve:start */\n' +
' one : 1\n' +
' two : 2,\n' +
' three : 3,\n' +
' ten : 10\n' +
' /* beautify preserve:end */\n' +
'};');
bt(
'var a = {\n' +
'/* beautify preserve:start */\n' +
' one : 1,\n' +
' two : 2,\n' +
' three : 3,\n' +
' ten : 10\n' +
'/* beautify preserve:end */\n' +
'};',
'var a = {\n' +
' /* beautify preserve:start */\n' +
' one : 1,\n' +
' two : 2,\n' +
' three : 3,\n' +
' ten : 10\n' +
'/* beautify preserve:end */\n' +
'};');
// one space before and after required, only single spaces inside.
bt(
'var a = {\n' +
'/* beautify preserve:start */\n' +
' one : 1,\n' +
' two : 2,\n' +
' three : 3,\n' +
' ten : 10\n' +
'};',
'var a = {\n' +
' /* beautify preserve:start */\n' +
' one: 1,\n' +
' two: 2,\n' +
' three: 3,\n' +
' ten: 10\n' +
'};');
bt(
'var a = {\n' +
'/*beautify preserve:start*/\n' +
' one : 1,\n' +
' two : 2,\n' +
' three : 3,\n' +
' ten : 10\n' +
'};',
'var a = {\n' +
' /*beautify preserve:start*/\n' +
' one: 1,\n' +
' two: 2,\n' +
' three: 3,\n' +
' ten: 10\n' +
'};');
bt(
'var a = {\n' +
'/*beautify preserve:start*/\n' +
' one : 1,\n' +
' two : 2,\n' +
' three : 3,\n' +
' ten : 10\n' +
'};',
'var a = {\n' +
' /*beautify preserve:start*/\n' +
' one: 1,\n' +
' two: 2,\n' +
' three: 3,\n' +
' ten: 10\n' +
'};');
// Directive: ignore
bt('/* beautify ignore:start */\n/* beautify ignore:end */');
bt('/* beautify ignore:start */\n var a,,,{ 1;\n/* beautify ignore:end */');
bt('var a = 1;\n/* beautify ignore:start */\n var a = 1;\n/* beautify ignore:end */');
bt('/* beautify ignore:start */ {asdklgh;y;+++;dd2d}/* beautify ignore:end */');
bt(
'var a = 1;\n/* beautify ignore:start */\n var a,,,{ 1;\n/* beautify ignore:end */',
'var a = 1;\n/* beautify ignore:start */\n var a,,,{ 1;\n/* beautify ignore:end */');
bt(
'var a = 1;\n /* beautify ignore:start */\n var a,,,{ 1;\n/* beautify ignore:end */',
'var a = 1;\n/* beautify ignore:start */\n var a,,,{ 1;\n/* beautify ignore:end */');
bt(
'var a = {\n' +
' /* beautify ignore:start */\n' +
' one : 1\n' +
' two : 2,\n' +
' three : {\n' +
' ten : 10\n' +
' /* beautify ignore:end */\n' +
'};');
bt(
'var a = {\n' +
'/* beautify ignore:start */\n' +
' one : 1\n' +
' two : 2,\n' +
' three : {\n' +
' ten : 10\n' +
'/* beautify ignore:end */\n' +
'};',
'var a = {\n' +
' /* beautify ignore:start */\n' +
' one : 1\n' +
' two : 2,\n' +
' three : {\n' +
' ten : 10\n' +
'/* beautify ignore:end */\n' +
'};');
// Directives - multiple and interacting
bt(
'var a = {\n' +
'/* beautify preserve:start */\n' +
'/* beautify preserve:start */\n' +
' one : 1,\n' +
' /* beautify preserve:end */\n' +
' two : 2,\n' +
' three : 3,\n' +
'/* beautify preserve:start */\n' +
' ten : 10\n' +
'/* beautify preserve:end */\n' +
'};',
'var a = {\n' +
' /* beautify preserve:start */\n' +
'/* beautify preserve:start */\n' +
' one : 1,\n' +
' /* beautify preserve:end */\n' +
' two: 2,\n' +
' three: 3,\n' +
' /* beautify preserve:start */\n' +
' ten : 10\n' +
'/* beautify preserve:end */\n' +
'};');
bt(
'var a = {\n' +
'/* beautify ignore:start */\n' +
' one : 1\n' +
' /* beautify ignore:end */\n' +
' two : 2,\n' +
'/* beautify ignore:start */\n' +
' three : {\n' +
' ten : 10\n' +
'/* beautify ignore:end */\n' +
'};',
'var a = {\n' +
' /* beautify ignore:start */\n' +
' one : 1\n' +
' /* beautify ignore:end */\n' +
' two: 2,\n' +
' /* beautify ignore:start */\n' +
' three : {\n' +
' ten : 10\n' +
'/* beautify ignore:end */\n' +
'};');
// Starts can occur together, ignore:end must occur alone.
bt(
'var a = {\n' +
'/* beautify ignore:start */\n' +
' one : 1\n' +
' NOTE: ignore end block does not support starting other directives\n' +
' This does not match the ending the ignore...\n' +
' /* beautify ignore:end preserve:start */\n' +
' two : 2,\n' +
'/* beautify ignore:start */\n' +
' three : {\n' +
' ten : 10\n' +
' ==The next comment ends the starting ignore==\n' +
'/* beautify ignore:end */\n' +
'};',
'var a = {\n' +
' /* beautify ignore:start */\n' +
' one : 1\n' +
' NOTE: ignore end block does not support starting other directives\n' +
' This does not match the ending the ignore...\n' +
' /* beautify ignore:end preserve:start */\n' +
' two : 2,\n' +
'/* beautify ignore:start */\n' +
' three : {\n' +
' ten : 10\n' +
' ==The next comment ends the starting ignore==\n' +
'/* beautify ignore:end */\n' +
'};');
bt(
'var a = {\n' +
'/* beautify ignore:start preserve:start */\n' +
' one : {\n' +
' /* beautify ignore:end */\n' +
' two : 2,\n' +
' /* beautify ignore:start */\n' +
' three : {\n' +
'/* beautify ignore:end */\n' +
' ten : 10\n' +
' // This is all preserved\n' +
'};',
'var a = {\n' +
' /* beautify ignore:start preserve:start */\n' +
' one : {\n' +
' /* beautify ignore:end */\n' +
' two : 2,\n' +
' /* beautify ignore:start */\n' +
' three : {\n' +
'/* beautify ignore:end */\n' +
' ten : 10\n' +
' // This is all preserved\n' +
'};');
bt(
'var a = {\n' +
'/* beautify ignore:start preserve:start */\n' +
' one : {\n' +
' /* beautify ignore:end */\n' +
' two : 2,\n' +
' /* beautify ignore:start */\n' +
' three : {\n' +
'/* beautify ignore:end */\n' +
' ten : 10,\n' +
'/* beautify preserve:end */\n' +
' eleven: 11\n' +
'};',
'var a = {\n' +
' /* beautify ignore:start preserve:start */\n' +
' one : {\n' +
' /* beautify ignore:end */\n' +
' two : 2,\n' +
' /* beautify ignore:start */\n' +
' three : {\n' +
'/* beautify ignore:end */\n' +
' ten : 10,\n' +
'/* beautify preserve:end */\n' +
' eleven: 11\n' +
'};');
// 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() %>;');
// jslint and space after anon function - (f = " ", c = "")
opts.jslint_happy = true;
opts.space_after_anon_function = true;
bt(
'a=typeof(x)',
'a = typeof (x)');
bt(
'x();\n\nfunction(){}',
'x();\n\nfunction () {}');
bt(
'function () {\n var a, b, c, d, e = [],\n f;\n}');
bt(
'switch(x) {case 0: case 1: a(); break; default: break}',
'switch (x) {\ncase 0:\ncase 1:\n a();\n break;\ndefault:\n break\n}');
bt('switch(x){case -1:break;case !y:break;}', 'switch (x) {\ncase -1:\n break;\ncase !y:\n break;\n}');
// typical greasemonkey start
test_fragment('// comment 2\n(function ()');
bt(
'var a2, b2, c2, d2 = 0, c = function() {}, d = \'\';',
'var a2, b2, c2, d2 = 0,\n c = function () {},\n d = \'\';');
bt(
'var a2, b2, c2, d2 = 0, c = function() {},\nd = \'\';',
'var a2, b2, c2, d2 = 0,\n c = function () {},\n d = \'\';');
bt(
'var o2=$.extend(a);function(){alert(x);}',
'var o2 = $.extend(a);\n\nfunction () {\n alert(x);\n}');
bt('function*() {\n yield 1;\n}', 'function* () {\n yield 1;\n}');
bt('function* x() {\n yield 1;\n}');
// jslint and space after anon function - (f = " ", c = "")
opts.jslint_happy = true;
opts.space_after_anon_function = false;
bt(
'a=typeof(x)',
'a = typeof (x)');
bt(
'x();\n\nfunction(){}',
'x();\n\nfunction () {}');
bt(
'function () {\n var a, b, c, d, e = [],\n f;\n}');
bt(
'switch(x) {case 0: case 1: a(); break; default: break}',
'switch (x) {\ncase 0:\ncase 1:\n a();\n break;\ndefault:\n break\n}');
bt('switch(x){case -1:break;case !y:break;}', 'switch (x) {\ncase -1:\n break;\ncase !y:\n break;\n}');
// typical greasemonkey start
test_fragment('// comment 2\n(function ()');
bt(
'var a2, b2, c2, d2 = 0, c = function() {}, d = \'\';',
'var a2, b2, c2, d2 = 0,\n c = function () {},\n d = \'\';');
bt(
'var a2, b2, c2, d2 = 0, c = function() {},\nd = \'\';',
'var a2, b2, c2, d2 = 0,\n c = function () {},\n d = \'\';');
bt(
'var o2=$.extend(a);function(){alert(x);}',
'var o2 = $.extend(a);\n\nfunction () {\n alert(x);\n}');
bt('function*() {\n yield 1;\n}', 'function* () {\n yield 1;\n}');
bt('function* x() {\n yield 1;\n}');
// jslint and space after anon function - (f = " ", c = " ")
opts.jslint_happy = false;
opts.space_after_anon_function = true;
bt(
'a=typeof(x)',
'a = typeof (x)');
bt(
'x();\n\nfunction(){}',
'x();\n\nfunction () {}');
bt(
'function () {\n var a, b, c, d, e = [],\n f;\n}');
bt(
'switch(x) {case 0: case 1: a(); break; default: break}',
'switch (x) {\n case 0:\n case 1:\n a();\n break;\n default:\n break\n}');
bt('switch(x){case -1:break;case !y:break;}', 'switch (x) {\n case -1:\n break;\n case !y:\n break;\n}');
// typical greasemonkey start
test_fragment('// comment 2\n(function ()');
bt(
'var a2, b2, c2, d2 = 0, c = function() {}, d = \'\';',
'var a2, b2, c2, d2 = 0,\n c = function () {},\n d = \'\';');
bt(
'var a2, b2, c2, d2 = 0, c = function() {},\nd = \'\';',
'var a2, b2, c2, d2 = 0,\n c = function () {},\n d = \'\';');
bt(
'var o2=$.extend(a);function(){alert(x);}',
'var o2 = $.extend(a);\n\nfunction () {\n alert(x);\n}');
bt('function*() {\n yield 1;\n}', 'function* () {\n yield 1;\n}');
bt('function* x() {\n yield 1;\n}');
// jslint and space after anon function - (f = "", c = " ")
opts.jslint_happy = false;
opts.space_after_anon_function = false;
bt(
'a=typeof(x)',
'a = typeof(x)');
bt(
'x();\n\nfunction(){}',
'x();\n\nfunction() {}');
bt(
'function () {\n var a, b, c, d, e = [],\n f;\n}',
'function() {\n var a, b, c, d, e = [],\n f;\n}');
bt(
'switch(x) {case 0: case 1: a(); break; default: break}',
'switch (x) {\n case 0:\n case 1:\n a();\n break;\n default:\n break\n}');
bt('switch(x){case -1:break;case !y:break;}', 'switch (x) {\n case -1:\n break;\n case !y:\n break;\n}');
// typical greasemonkey start
test_fragment('// comment 2\n(function()');
bt(
'var a2, b2, c2, d2 = 0, c = function() {}, d = \'\';',
'var a2, b2, c2, d2 = 0,\n c = function() {},\n d = \'\';');
bt(
'var a2, b2, c2, d2 = 0, c = function() {},\nd = \'\';',
'var a2, b2, c2, d2 = 0,\n c = function() {},\n d = \'\';');
bt(
'var o2=$.extend(a);function(){alert(x);}',
'var o2 = $.extend(a);\n\nfunction() {\n alert(x);\n}');
bt('function*() {\n yield 1;\n}');
bt('function* x() {\n yield 1;\n}');
// Regression tests
// Issue 241
bt(
'obj\n' +
' .last({\n' +
' foo: 1,\n' +
' bar: 2\n' +
' });\n' +
'var test = 1;');
bt(
'obj\n' +
' .last(a, function() {\n' +
' var test;\n' +
' });\n' +
'var test = 1;');
bt(
'obj.first()\n' +
' .second()\n' +
' .last(function(err, response) {\n' +
' console.log(err);\n' +
' });');
// Issue 268 and 275
bt(
'obj.last(a, function() {\n' +
' var test;\n' +
'});\n' +
'var test = 1;');
bt(
'obj.last(a,\n' +
' function() {\n' +
' var test;\n' +
' });\n' +
'var test = 1;');
bt(
'(function() {if (!window.FOO) window.FOO || (window.FOO = function() {var b = {bar: "zort"};});})();',
'(function() {\n' +
' if (!window.FOO) window.FOO || (window.FOO = function() {\n' +
' var b = {\n' +
' bar: "zort"\n' +
' };\n' +
' });\n' +
'})();');
// Issue 281
bt(
'define(["dojo/_base/declare", "my/Employee", "dijit/form/Button",\n' +
' "dojo/_base/lang", "dojo/Deferred"\n' +
'], function(declare, Employee, Button, lang, Deferred) {\n' +
' return declare(Employee, {\n' +
' constructor: function() {\n' +
' new Button({\n' +
' onClick: lang.hitch(this, function() {\n' +
' new Deferred().then(lang.hitch(this, function() {\n' +
' this.salary * 0.25;\n' +
' }));\n' +
' })\n' +
' });\n' +
' }\n' +
' });\n' +
'});');
bt(
'define(["dojo/_base/declare", "my/Employee", "dijit/form/Button",\n' +
' "dojo/_base/lang", "dojo/Deferred"\n' +
' ],\n' +
' function(declare, Employee, Button, lang, Deferred) {\n' +
' return declare(Employee, {\n' +
' constructor: function() {\n' +
' new Button({\n' +
' onClick: lang.hitch(this, function() {\n' +
' new Deferred().then(lang.hitch(this, function() {\n' +
' this.salary * 0.25;\n' +
' }));\n' +
' })\n' +
' });\n' +
' }\n' +
' });\n' +
' });');
// Issue 459
bt(
'(function() {\n' +
' return {\n' +
' foo: function() {\n' +
' return "bar";\n' +
' },\n' +
' bar: ["bar"]\n' +
' };\n' +
'}());');
// Issue 505 - strings should end at newline unless continued by backslash
bt(
'var name = "a;\n' +
'name = "b";');
bt(
'var name = "a;\\\n' +
' name = b";');
// Issue 514 - some operators require spaces to distinguish them
bt('var c = "_ACTION_TO_NATIVEAPI_" + ++g++ + +new Date;');
bt('var c = "_ACTION_TO_NATIVEAPI_" - --g-- - -new Date;');
// Issue 440 - reserved words can be used as object property names
bt(
'a = {\n' +
' function: {},\n' +
' "function": {},\n' +
' throw: {},\n' +
' "throw": {},\n' +
' var: {},\n' +
' "var": {},\n' +
' set: {},\n' +
' "set": {},\n' +
' get: {},\n' +
' "get": {},\n' +
' if: {},\n' +
' "if": {},\n' +
' then: {},\n' +
' "then": {},\n' +
' else: {},\n' +
' "else": {},\n' +
' yay: {}\n' +
'};');
// Issue 331 - if-else with braces edge case
bt(
'if(x){a();}else{b();}if(y){c();}',
'if (x) {\n' +
' a();\n' +
'} else {\n' +
' b();\n' +
'}\n' +
'if (y) {\n' +
' c();\n' +
'}');
// Issue 485 - ensure function declarations behave the same in arrays as elsewhere
bt(
'var v = ["a",\n' +
' function() {\n' +
' return;\n' +
' }, {\n' +
' id: 1\n' +
' }\n' +
'];');
bt(
'var v = ["a", function() {\n' +
' return;\n' +
'}, {\n' +
' id: 1\n' +
'}];');
// Issue 382 - initial totally cursory support for es6 module export
bt(
'module "Even" {\n'