1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
# 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
# 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}!
</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\\`"
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}`"
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}`"
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'
|