* Fixes #1147: template strings not obeying -b ascii_only true * Allow evaluation of template expressions by adding optimizers and walkers * Make sure tagged templates are never changed * Remove template tokenizer in parser, add template tokenizer in tokenizer. It is using a brace counter to track brace position of templates * Add tokens `template_head` and `template_substitution` but parsing tokens stays mostly the same * Do not output strings anymore in AST_TemplateString, instead use AST_TemplateSegment * Fix parsing tagged templates, allowing multiple templates behind as spec allows this These changes don't influence tagged templates because raw content may influence code execution, however they are safe to do in normal templates: * Allow basic string concatenation of templates where possible * Allow custom character escape style similar to strings, except in tagged templates Note that expressions are still compressed in tagged templates. Optional things that may be improved later: * Custom quote style for templates if it doesn't have expressions. Making it obey the quote_style option if this is the case.
332 lines
7.7 KiB
JavaScript
332 lines
7.7 KiB
JavaScript
template_strings: {
|
|
beautify = {
|
|
quote_style: 3
|
|
}
|
|
input: {
|
|
``;
|
|
`xx\`x`;
|
|
`${ foo + 2 }`;
|
|
` foo ${ bar + `baz ${ qux }` }`;
|
|
}
|
|
expect_exact: "``;`xx\\`x`;`${foo+2}`;` foo ${bar+`baz ${qux}`}`;";
|
|
}
|
|
|
|
template_string_prefixes: {
|
|
beautify = {
|
|
quote_style: 3
|
|
}
|
|
input: {
|
|
String.raw`foo`;
|
|
foo `bar`;
|
|
}
|
|
expect_exact: "String.raw`foo`;foo`bar`;";
|
|
}
|
|
|
|
template_strings_ascii_only: {
|
|
beautify = {
|
|
ascii_only: true,
|
|
quote_style: 3
|
|
}
|
|
input: {
|
|
var foo = `foo
|
|
bar
|
|
ↂωↂ`;
|
|
var bar = `\``;
|
|
}
|
|
expect_exact: "var foo=`foo\\n bar\\n \\u2182\\u03c9\\u2182`;var bar=`\\``;"
|
|
}
|
|
|
|
template_strings_without_ascii_only: {
|
|
beautify = {
|
|
quote_style: 3
|
|
}
|
|
input: {
|
|
var foo = `foo
|
|
bar
|
|
ↂωↂ`
|
|
}
|
|
expect_exact: "var foo=`foo\n bar\n ↂωↂ`;"
|
|
}
|
|
|
|
template_string_with_constant_expression: {
|
|
options = {
|
|
evaluate: true
|
|
}
|
|
beautify = {
|
|
quote_style: 3
|
|
}
|
|
input: {
|
|
var foo = `${4 + 4} equals 4 + 4`;
|
|
}
|
|
expect: {
|
|
var foo = `8 equals 4 + 4`;
|
|
}
|
|
}
|
|
|
|
template_string_with_predefined_constants: {
|
|
options = {
|
|
evaluate: true
|
|
}
|
|
beautify = {
|
|
quote_style: 3
|
|
}
|
|
input: {
|
|
var foo = `This is ${undefined}`;
|
|
var bar = `This is ${NaN}`;
|
|
var baz = `This is ${null}`;
|
|
var foofoo = `This is ${Infinity}`;
|
|
var foobar = "This is ${1/0}";
|
|
var foobaz = 'This is ${1/0}';
|
|
var barfoo = "This is ${NaN}";
|
|
var bazfoo = "This is ${null}";
|
|
var bazbaz = `This is ${1/0}`;
|
|
var barbar = `This is ${0/0}`;
|
|
var barbar = "This is ${0/0}";
|
|
var barber = 'This is ${0/0}';
|
|
|
|
var a = `${4**11}`; // 8 in template vs 7 chars - 4194304
|
|
var b = `${4**12}`; // 8 in template vs 8 chars - 16777216
|
|
var c = `${4**14}`; // 8 in template vs 9 chars - 268435456
|
|
}
|
|
expect: {
|
|
var foo = `This is undefined`;
|
|
var bar = `This is NaN`;
|
|
var baz = `This is null`;
|
|
var foofoo = `This is ${1/0}`;
|
|
var foobar = "This is ${1/0}";
|
|
var foobaz = 'This is ${1/0}';
|
|
var barfoo = "This is ${NaN}";
|
|
var bazfoo = "This is ${null}";
|
|
var bazbaz = `This is ${1/0}`;
|
|
var barbar = `This is NaN`;
|
|
var barbar = "This is ${0/0}";
|
|
var barber = 'This is ${0/0}';
|
|
|
|
var a = `4194304`;
|
|
var b = `16777216`; // Potential for further concatentation
|
|
var c = `${4**14}`; // Not worth converting
|
|
}
|
|
}
|
|
|
|
template_string_evaluate_with_many_segments: {
|
|
options = {
|
|
evaluate: true
|
|
}
|
|
beautify = {
|
|
quote_style: 3
|
|
}
|
|
input: {
|
|
var foo = `Hello ${guest()}, welcome to ${location()}${"."}`;
|
|
var bar = `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
|
|
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
|
|
var buzz = `${1}${foobar()}${2}${foobar()}${3}${foobar()}`;
|
|
}
|
|
expect: {
|
|
var foo = `Hello ${guest()}, welcome to ${location()}.`;
|
|
var bar = `1234567890`;
|
|
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
|
|
var buzz = `1${foobar()}2${foobar()}3${foobar()}`;
|
|
}
|
|
}
|
|
|
|
template_string_with_many_segments: {
|
|
beautify = {
|
|
quote_style: 3
|
|
}
|
|
input: {
|
|
var foo = `Hello ${guest()}, welcome to ${location()}${"."}`;
|
|
var bar = `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
|
|
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
|
|
var buzz = `${1}${foobar()}${2}${foobar()}${3}${foobar()}`;
|
|
}
|
|
expect: {
|
|
var foo = `Hello ${guest()}, welcome to ${location()}${"."}`;
|
|
var bar = `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
|
|
var baz = `${foobar()}${foobar()}${foobar()}${foobar()}`;
|
|
var buzz = `${1}${foobar()}${2}${foobar()}${3}${foobar()}`;
|
|
}
|
|
}
|
|
|
|
template_string_to_normal_string: {
|
|
options = {
|
|
evaluate: true
|
|
}
|
|
beautify = {
|
|
quote_style: 0
|
|
}
|
|
input: {
|
|
var foo = `This is ${undefined}`;
|
|
var bar = "Decimals " + `${1}${2}${3}${4}${5}${6}${7}${8}${9}${0}`;
|
|
}
|
|
expect: {
|
|
var foo = `This is undefined`;
|
|
var bar = "Decimals 1234567890";
|
|
}
|
|
}
|
|
|
|
template_concattenating_string: {
|
|
options = {
|
|
evaluate: true
|
|
}
|
|
beautify = {
|
|
quote_style: 3 // Yes, keep quotes
|
|
}
|
|
input: {
|
|
var foo = "Have a nice " + `day. ${`day. ` + `day.`}`;
|
|
var bar = "Have a nice " + `${day()}`;
|
|
}
|
|
expect: {
|
|
var foo = "Have a nice day. day. day.";
|
|
var bar = "Have a nice " + `${day()}`;
|
|
}
|
|
}
|
|
|
|
evaluate_nested_templates: {
|
|
options = {
|
|
evaluate: true
|
|
}
|
|
beautify = {
|
|
quote_style: 0
|
|
}
|
|
input: {
|
|
var baz = `${`${`${`foo`}`}`}`;
|
|
}
|
|
expect: {
|
|
var baz = `foo`;
|
|
}
|
|
}
|
|
|
|
enforce_double_quotes: {
|
|
beautify = {
|
|
quote_style: 1
|
|
}
|
|
input: {
|
|
var foo = `Hello world`;
|
|
var bar = `Hello ${'world'}`;
|
|
var baz = `Hello ${world()}`;
|
|
}
|
|
expect: {
|
|
var foo = `Hello world`;
|
|
var bar = `Hello ${"world"}`;
|
|
var baz = `Hello ${world()}`;
|
|
}
|
|
}
|
|
|
|
enforce_single_quotes: {
|
|
beautify = {
|
|
quote_style: 2
|
|
}
|
|
input: {
|
|
var foo = `Hello world`;
|
|
var bar = `Hello ${"world"}`;
|
|
var baz = `Hello ${world()}`;
|
|
}
|
|
expect: {
|
|
var foo = `Hello world`;
|
|
var bar = `Hello ${'world'}`;
|
|
var baz = `Hello ${world()}`;
|
|
}
|
|
}
|
|
|
|
enforce_double_quotes_and_evaluate: {
|
|
beautify = {
|
|
quote_style: 1
|
|
}
|
|
options = {
|
|
evaluate: true
|
|
}
|
|
input: {
|
|
var foo = `Hello world`;
|
|
var bar = `Hello ${'world'}`;
|
|
var baz = `Hello ${world()}`;
|
|
}
|
|
expect: {
|
|
var foo = `Hello world`;
|
|
var bar = `Hello world`;
|
|
var baz = `Hello ${world()}`;
|
|
}
|
|
}
|
|
|
|
enforce_single_quotes_and_evaluate: {
|
|
beautify = {
|
|
quote_style: 2
|
|
}
|
|
options = {
|
|
evaluate: true
|
|
}
|
|
input: {
|
|
var foo = `Hello world`;
|
|
var bar = `Hello ${"world"}`;
|
|
var baz = `Hello ${world()}`;
|
|
}
|
|
expect: {
|
|
var foo = `Hello world`;
|
|
var bar = `Hello world`;
|
|
var baz = `Hello ${world()}`;
|
|
}
|
|
}
|
|
|
|
respect_inline_script: {
|
|
beautify = {
|
|
inline_script: true,
|
|
quote_style: 3
|
|
}
|
|
input: {
|
|
var foo = `</script>${content}`;
|
|
var bar = `<!--`;
|
|
var baz = `-->`;
|
|
}
|
|
expect_exact: "var foo=`<\\/script>${content}`;var bar=`\\x3c!--`;var baz=`--\\x3e`;";
|
|
}
|
|
|
|
do_not_optimize_tagged_template_1: {
|
|
beautify = {
|
|
quote_style: 0
|
|
}
|
|
options = {
|
|
evaluate: true
|
|
}
|
|
input: {
|
|
var foo = tag`Shall not be optimized. ${"But " + "this " + "is " + "fine."}`;
|
|
var bar = tag`Don't even mind changing my quotes!`;
|
|
}
|
|
expect_exact:
|
|
'var foo=tag`Shall not be optimized. ${"But this is fine."}`;var bar=tag`Don\'t even mind changing my quotes!`;';
|
|
}
|
|
|
|
do_not_optimize_tagged_template_2: {
|
|
options = {
|
|
evaluate: true
|
|
}
|
|
input: {
|
|
var foo = tag`test` + " something out";
|
|
}
|
|
expect_exact: 'var foo=tag`test`+" something out";';
|
|
}
|
|
|
|
keep_raw_content_in_tagged_template: {
|
|
options = {
|
|
evaluate: true
|
|
}
|
|
input: {
|
|
var foo = tag`\u0020\u{20}\u{00020}\x20\40\040 `;
|
|
}
|
|
expect_exact: "var foo=tag`\\u0020\\u{20}\\u{00020}\\x20\\40\\040 `;";
|
|
}
|
|
|
|
allow_chained_templates: {
|
|
input: {
|
|
var foo = tag`a``b``c``d`;
|
|
}
|
|
expect: {
|
|
var foo = tag`a``b``c``d`;
|
|
}
|
|
}
|
|
|
|
check_escaped_chars: {
|
|
input: {
|
|
var foo = `\u0020\u{20}\u{00020}\x20\40\040 `;
|
|
}
|
|
expect_exact: "var foo=` `;";
|
|
}
|