File: tagged_template_literals.coffee

package info (click to toggle)
coffeescript 2.7.0%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,360 kB
  • sloc: makefile: 20; xml: 9; sh: 6; javascript: 5
file content (177 lines) | stat: -rw-r--r-- 7,027 bytes parent folder | download | duplicates (2)
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'