jashkenas--coffeescript/test/tagged_template_literals.co...

178 lines
6.9 KiB
CoffeeScript
Raw Normal View History

CS1 tagged template literals (and CS2 interpolated strings as template literals) (#4352) * Add initial support for template literals with no interpolation * Change ‘unexpected string’ error message tests to use number not identifier prefix. Identifer prefixes are now valid as tagged template literals * Test tagged template literals for non-interpolated strings and tag function. * Tagged template literals work for pure Strings. Pull tagged template definition up to Invocation level in grammar, enabling chained invocation calls. We can view a tagged template is a special form of function call. * Readying for StringWithInterpolations work. * Tweaks. * Fix style * Pass StringWithInterpolations parameter straight into Call constructor. StringWithInterpolations will be output as template literal, so already in correct form for outputting tagged template literal. * Strip down compileNode for StringWithInterpolations * Done StringLiteral case for interpolated Strings * Remove need for TemplateLiteral * Simplify code. * Small code tidy * Interpolated strings now outputting as template literals. Still needs comprehensive testing. * Move error message tests into error_messages.coffee; remove test that is testing for a Node runtime error * Split up tests that were testing multiple things per test, so that each test tests only one thing * Edge cases: tagged template literals containing interpolated strings or even internal tagged template literals * Make more concise, more idiomatic style * Pull back extreme indentation * Restore and fix commented-out tests * Edge case: tagged template literal with empty string * Only use new ES2015 interpolated string syntax if we’re inside a tagged template literal; this keeps this PR safe to merge into CoffeeScript 1.x. Remove the code from this commit to make all interpolated strings use ES2015 syntax, for CoffeeScript 2. * Compiler now _doesn’t_ use template literals. * Expand tagged template literal tests * Move ‘Unexpected string’ error message tests into tagged template literal section. ‘Unexpected string’ is not reported in these test scenarios anymore. Instead, we error that the prefixing literal is not a function. * Don’t unwrap StringWithInterpolations. Saw bug with program consisting of “#{2}” not compiling with template literals. Root cause was that Block.compileNode was unwrapping interpolated string and so didn’t use compileNode logic at StringWithInterpolations level. * No need to bracket interpolated strings any more. When interpolated string looks like `hello ${2}`, no extract brackets are needed, as the `s mark the beginning and end. * Show html templating with tagged template literals * Multiline should match multiline * Comment out unnecessary `unwrap`, which is only needed for CoffeeScript 2 all-ES2015 syntax output
2016-11-18 18:25:03 +00:00
# Tagged template literals
# ------------------------
# NOTES:
# A tagged template literal is a string that is passed to a prefixing function for
# post-processing. There's a bunch of different angles that need testing:
# - Prefixing function, which can be any form of function call:
# - function: func'Hello'
# - object property with dot notation: outerobj.obj.func'Hello'
# - object property with bracket notation: outerobj['obj']['func']'Hello'
# - String form: single quotes, double quotes and block strings
# - String is single-line or multi-line
# - String is interpolated or not
func = (text, expressions...) ->
"text: [#{text.join '|'}] expressions: [#{expressions.join '|'}]"
outerobj =
obj:
func: func
f: -> func
CS1 tagged template literals (and CS2 interpolated strings as template literals) (#4352) * Add initial support for template literals with no interpolation * Change ‘unexpected string’ error message tests to use number not identifier prefix. Identifer prefixes are now valid as tagged template literals * Test tagged template literals for non-interpolated strings and tag function. * Tagged template literals work for pure Strings. Pull tagged template definition up to Invocation level in grammar, enabling chained invocation calls. We can view a tagged template is a special form of function call. * Readying for StringWithInterpolations work. * Tweaks. * Fix style * Pass StringWithInterpolations parameter straight into Call constructor. StringWithInterpolations will be output as template literal, so already in correct form for outputting tagged template literal. * Strip down compileNode for StringWithInterpolations * Done StringLiteral case for interpolated Strings * Remove need for TemplateLiteral * Simplify code. * Small code tidy * Interpolated strings now outputting as template literals. Still needs comprehensive testing. * Move error message tests into error_messages.coffee; remove test that is testing for a Node runtime error * Split up tests that were testing multiple things per test, so that each test tests only one thing * Edge cases: tagged template literals containing interpolated strings or even internal tagged template literals * Make more concise, more idiomatic style * Pull back extreme indentation * Restore and fix commented-out tests * Edge case: tagged template literal with empty string * Only use new ES2015 interpolated string syntax if we’re inside a tagged template literal; this keeps this PR safe to merge into CoffeeScript 1.x. Remove the code from this commit to make all interpolated strings use ES2015 syntax, for CoffeeScript 2. * Compiler now _doesn’t_ use template literals. * Expand tagged template literal tests * Move ‘Unexpected string’ error message tests into tagged template literal section. ‘Unexpected string’ is not reported in these test scenarios anymore. Instead, we error that the prefixing literal is not a function. * Don’t unwrap StringWithInterpolations. Saw bug with program consisting of “#{2}” not compiling with template literals. Root cause was that Block.compileNode was unwrapping interpolated string and so didn’t use compileNode logic at StringWithInterpolations level. * No need to bracket interpolated strings any more. When interpolated string looks like `hello ${2}`, no extract brackets are needed, as the `s mark the beginning and end. * Show html templating with tagged template literals * Multiline should match multiline * Comment out unnecessary `unwrap`, which is only needed for CoffeeScript 2 all-ES2015 syntax output
2016-11-18 18:25:03 +00:00
# Example use
test "tagged template literal for html templating", ->
html = (htmlFragments, expressions...) ->
htmlFragments.reduce (fullHtml, htmlFragment, i) ->
fullHtml + "#{expressions[i - 1]}#{htmlFragment}"
state =
name: 'Greg'
adjective: 'awesome'
eq """
<p>
Hi Greg. You're looking awesome!
</p>
""",
html"""
<p>
Hi #{state.name}. You're looking #{state.adjective}!
CS1 tagged template literals (and CS2 interpolated strings as template literals) (#4352) * Add initial support for template literals with no interpolation * Change ‘unexpected string’ error message tests to use number not identifier prefix. Identifer prefixes are now valid as tagged template literals * Test tagged template literals for non-interpolated strings and tag function. * Tagged template literals work for pure Strings. Pull tagged template definition up to Invocation level in grammar, enabling chained invocation calls. We can view a tagged template is a special form of function call. * Readying for StringWithInterpolations work. * Tweaks. * Fix style * Pass StringWithInterpolations parameter straight into Call constructor. StringWithInterpolations will be output as template literal, so already in correct form for outputting tagged template literal. * Strip down compileNode for StringWithInterpolations * Done StringLiteral case for interpolated Strings * Remove need for TemplateLiteral * Simplify code. * Small code tidy * Interpolated strings now outputting as template literals. Still needs comprehensive testing. * Move error message tests into error_messages.coffee; remove test that is testing for a Node runtime error * Split up tests that were testing multiple things per test, so that each test tests only one thing * Edge cases: tagged template literals containing interpolated strings or even internal tagged template literals * Make more concise, more idiomatic style * Pull back extreme indentation * Restore and fix commented-out tests * Edge case: tagged template literal with empty string * Only use new ES2015 interpolated string syntax if we’re inside a tagged template literal; this keeps this PR safe to merge into CoffeeScript 1.x. Remove the code from this commit to make all interpolated strings use ES2015 syntax, for CoffeeScript 2. * Compiler now _doesn’t_ use template literals. * Expand tagged template literal tests * Move ‘Unexpected string’ error message tests into tagged template literal section. ‘Unexpected string’ is not reported in these test scenarios anymore. Instead, we error that the prefixing literal is not a function. * Don’t unwrap StringWithInterpolations. Saw bug with program consisting of “#{2}” not compiling with template literals. Root cause was that Block.compileNode was unwrapping interpolated string and so didn’t use compileNode logic at StringWithInterpolations level. * No need to bracket interpolated strings any more. When interpolated string looks like `hello ${2}`, no extract brackets are needed, as the `s mark the beginning and end. * Show html templating with tagged template literals * Multiline should match multiline * Comment out unnecessary `unwrap`, which is only needed for CoffeeScript 2 all-ES2015 syntax output
2016-11-18 18:25:03 +00:00
</p>
"""
# Simple, non-interpolated strings
test "tagged template literal with a single-line single-quote string", ->
eq 'text: [single-line single quotes] expressions: []',
func'single-line single quotes'
test "tagged template literal with a single-line double-quote string", ->
eq 'text: [single-line double quotes] expressions: []',
func"single-line double quotes"
test "tagged template literal with a single-line single-quote block string", ->
eq 'text: [single-line block string] expressions: []',
func'''single-line block string'''
test "tagged template literal with a single-line double-quote block string", ->
eq 'text: [single-line block string] expressions: []',
func"""single-line block string"""
test "tagged template literal with a multi-line single-quote string", ->
eq 'text: [multi-line single quotes] expressions: []',
func'multi-line
single quotes'
test "tagged template literal with a multi-line double-quote string", ->
eq 'text: [multi-line double quotes] expressions: []',
func"multi-line
double quotes"
test "tagged template literal with a multi-line single-quote block string", ->
eq 'text: [multi-line\nblock string] expressions: []',
func'''
multi-line
block string
'''
test "tagged template literal with a multi-line double-quote block string", ->
eq 'text: [multi-line\nblock string] expressions: []',
func"""
multi-line
block string
"""
# Interpolated strings with expressions
test "tagged template literal with a single-line double-quote interpolated string", ->
eq 'text: [single-line | double quotes | interpolation] expressions: [36|42]',
func"single-line #{6 * 6} double quotes #{6 * 7} interpolation"
test "tagged template literal with a single-line double-quote block interpolated string", ->
eq 'text: [single-line | block string | interpolation] expressions: [incredible|48]',
func"""single-line #{'incredible'} block string #{6 * 8} interpolation"""
test "tagged template literal with a multi-line double-quote interpolated string", ->
eq 'text: [multi-line | double quotes | interpolation] expressions: [2|awesome]',
func"multi-line #{4/2}
double quotes #{'awesome'} interpolation"
test "tagged template literal with a multi-line double-quote block interpolated string", ->
eq 'text: [multi-line |\nblock string |] expressions: [/abc/|32]',
func"""
multi-line #{/abc/}
block string #{2 * 16}
"""
# Tagged template literal must use a callable function
test "tagged template literal dot notation recognized as a callable function", ->
eq 'text: [dot notation] expressions: []',
outerobj.obj.func'dot notation'
test "tagged template literal bracket notation recognized as a callable function", ->
eq 'text: [bracket notation] expressions: []',
outerobj['obj']['func']'bracket notation'
test "tagged template literal mixed dot and bracket notation recognized as a callable function", ->
eq 'text: [mixed notation] expressions: []',
outerobj['obj'].func'mixed notation'
# Edge cases
test "tagged template literal with an empty string", ->
eq 'text: [] expressions: []',
func''
test "tagged template literal with an empty interpolated string", ->
eq 'text: [] expressions: []',
func"#{}"
test "tagged template literal as single interpolated expression", ->
eq 'text: [|] expressions: [3]',
func"#{3}"
test "tagged template literal with an interpolated string that itself contains an interpolated string", ->
eq 'text: [inner | string] expressions: [interpolated]',
func"inner #{"#{'inter'}polated"} string"
test "tagged template literal with an interpolated string that contains a tagged template literal", ->
eq 'text: [inner tagged | literal] expressions: [text: [|] expressions: [template]]',
func"inner tagged #{func"#{'template'}"} literal"
test "tagged template literal with backticks", ->
eq 'text: [ES template literals look like this: `foo bar`] expressions: []',
func"ES template literals look like this: `foo bar`"
test "tagged template literal with escaped backticks", ->
eq 'text: [ES template literals look like this: \\`foo bar\\`] expressions: []',
func"ES template literals look like this: \\`foo bar\\`"
2016-12-03 18:16:41 +00:00
test "tagged template literal with unnecessarily escaped backticks", ->
eq 'text: [ES template literals look like this: `foo bar`] expressions: []',
func"ES template literals look like this: \`foo bar\`"
test "tagged template literal with ES interpolation", ->
eq 'text: [ES template literals also look like this: `3 + 5 = ${3+5}`] expressions: []',
func"ES template literals also look like this: `3 + 5 = ${3+5}`"
test "tagged template literal with both ES and CoffeeScript interpolation", ->
eq "text: [ES template literals also look like this: `3 + 5 = ${3+5}` which equals |] expressions: [8]",
func"ES template literals also look like this: `3 + 5 = ${3+5}` which equals #{3+5}"
test "tagged template literal with escaped ES interpolation", ->
eq 'text: [ES template literals also look like this: `3 + 5 = \\${3+5}`] expressions: []',
func"ES template literals also look like this: `3 + 5 = \\${3+5}`"
2016-12-03 18:16:41 +00:00
test "tagged template literal with unnecessarily escaped ES interpolation", ->
eq 'text: [ES template literals also look like this: `3 + 5 = ${3+5}`] expressions: []',
func"ES template literals also look like this: `3 + 5 = \${3+5}`"
2016-12-03 18:16:41 +00:00
test "tagged template literal special escaping", ->
eq 'text: [` ` \\` \\` \\\\` $ { ${ ${ \\${ \\${ \\\\${ | ` ${] expressions: [1]',
func"` \` \\` \\\` \\\\` $ { ${ \${ \\${ \\\${ \\\\${ #{1} ` ${"
test '#4467: tagged template literal call recognized as a callable function', ->
eq 'text: [dot notation] expressions: []',
outerobj.obj.f()'dot notation'