@handlebars/parser 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +1 -0
- package/{.eslintrc.js → .eslintrc.cjs} +5 -6
- package/.github/workflows/ci.yml +10 -9
- package/.github/workflows/plan-release.yml +93 -0
- package/.github/workflows/publish.yml +42 -0
- package/.release-plan.json +26 -0
- package/CHANGELOG.md +24 -0
- package/RELEASE.md +15 -48
- package/dist/cjs/exception.js +2 -4
- package/dist/cjs/helpers.js +44 -55
- package/dist/cjs/index.js +7 -21
- package/dist/cjs/parse.js +46 -38
- package/dist/cjs/parser.js +134 -104
- package/dist/cjs/printer.js +78 -53
- package/dist/cjs/visitor.js +8 -13
- package/dist/cjs/whitespace-control.js +66 -66
- package/dist/esm/exception.js +1 -1
- package/dist/esm/helpers.js +31 -26
- package/dist/esm/index.js +7 -7
- package/dist/esm/parse.js +41 -6
- package/dist/esm/parser.js +133 -101
- package/dist/esm/printer.js +74 -41
- package/dist/esm/visitor.js +4 -4
- package/dist/esm/whitespace-control.js +64 -59
- package/lib/helpers.js +26 -21
- package/lib/index.js +6 -6
- package/lib/parse.js +43 -6
- package/lib/printer.js +86 -54
- package/lib/visitor.js +19 -19
- package/lib/whitespace-control.js +72 -73
- package/package.json +42 -37
- package/spec/{.eslintrc.js → .eslintrc.cjs} +1 -1
- package/spec/ast.js +94 -44
- package/spec/parser.js +276 -252
- package/spec/utils.js +73 -8
- package/spec/visitor.js +36 -42
- package/src/handlebars.l +22 -4
- package/src/handlebars.yy +21 -4
- package/tsconfig.json +12 -6
package/spec/parser.js
CHANGED
|
@@ -1,386 +1,413 @@
|
|
|
1
|
-
import { parse, print } from '../dist/esm';
|
|
2
|
-
import { equals, shouldThrow } from './utils';
|
|
1
|
+
import { parse, print } from '../dist/esm/index.js';
|
|
2
|
+
import { equals, equalsAst, shouldThrow } from './utils.js';
|
|
3
3
|
|
|
4
|
-
describe('parser', function() {
|
|
4
|
+
describe('parser', function () {
|
|
5
5
|
function astFor(template) {
|
|
6
6
|
let ast = parse(template);
|
|
7
7
|
return print(ast);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
it('parses simple mustaches', function() {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
it('parses simple mustaches', function () {
|
|
11
|
+
equalsAst('{{123}}', '{{ n%123 }}');
|
|
12
|
+
equalsAst('{{"foo"}}', '{{ "foo" }}');
|
|
13
|
+
equalsAst('{{false}}', '{{ b%false }}');
|
|
14
|
+
equalsAst('{{true}}', '{{ b%true }}');
|
|
15
|
+
equalsAst('{{foo}}', '{{ p%foo }}');
|
|
16
|
+
equalsAst('{{foo?}}', '{{ p%foo? }}');
|
|
17
|
+
equalsAst('{{foo_}}', '{{ p%foo_ }}');
|
|
18
|
+
equalsAst('{{foo-}}', '{{ p%foo- }}');
|
|
19
|
+
equalsAst('{{foo:}}', '{{ p%foo: }}');
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
it('parses simple mustaches with data', function() {
|
|
23
|
-
|
|
22
|
+
it('parses simple mustaches with data', function () {
|
|
23
|
+
equalsAst('{{@foo}}', '{{ p%@foo }}');
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
it('parses simple mustaches with data paths', function() {
|
|
27
|
-
|
|
26
|
+
it('parses simple mustaches with data paths', function () {
|
|
27
|
+
equalsAst('{{@../foo}}', '{{ p%@foo }}');
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
it('parses mustaches with paths', function() {
|
|
31
|
-
|
|
30
|
+
it('parses mustaches with paths', function () {
|
|
31
|
+
equalsAst('{{foo/bar}}', '{{ p%foo/bar }}');
|
|
32
|
+
equalsAst('{{foo.bar}}', '{{ p%foo/bar }}');
|
|
33
|
+
equalsAst('{{foo.#bar}}', '{{ p%foo/#bar }}');
|
|
34
|
+
equalsAst('{{@foo.#bar}}', '{{ p%@foo/#bar }}');
|
|
35
|
+
|
|
36
|
+
equalsAst('{{this/foo}}', '{{ p%foo }}');
|
|
37
|
+
equalsAst('{{this.foo}}', '{{ p%this.foo }}');
|
|
38
|
+
equalsAst('{{this.#foo}}', '{{ p%this.#foo }}');
|
|
32
39
|
});
|
|
33
40
|
|
|
34
|
-
it('parses mustaches with
|
|
35
|
-
|
|
41
|
+
it('parses mustaches with - in a path', function () {
|
|
42
|
+
equalsAst('{{foo-bar}}', '{{ p%foo-bar }}');
|
|
36
43
|
});
|
|
37
44
|
|
|
38
|
-
it('parses mustaches with
|
|
39
|
-
|
|
45
|
+
it('parses mustaches with escaped [] in a path', function () {
|
|
46
|
+
equalsAst('{{[foo[\\]]}}', '{{ p%foo[] }}');
|
|
40
47
|
});
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
|
|
49
|
+
it('parses escaped \\\\ in path', function () {
|
|
50
|
+
equalsAst('{{[foo\\\\]}}', '{{ p%foo\\ }}');
|
|
43
51
|
});
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
|
|
53
|
+
it('parses hash literals', function () {
|
|
54
|
+
equalsAst('{{(foo=bar)}}', '{{ Hash{foo=p%bar} }}');
|
|
55
|
+
equalsAst('{{(foo=bar)}}', '{{ p%@hello }}', {
|
|
56
|
+
options: {
|
|
57
|
+
syntax: {
|
|
58
|
+
hash: (hash, loc, { yy }) => {
|
|
59
|
+
return yy.preparePath(
|
|
60
|
+
true,
|
|
61
|
+
false,
|
|
62
|
+
[{ part: yy.id('hello'), original: 'hello' }],
|
|
63
|
+
loc
|
|
64
|
+
);
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
});
|
|
46
69
|
});
|
|
47
70
|
|
|
48
|
-
it('parses
|
|
49
|
-
|
|
71
|
+
it('parses array literals', function () {
|
|
72
|
+
equalsAst('{{[foo bar]}}', '{{ Array[p%foo, p%bar] }}', {
|
|
73
|
+
options: { syntax: { square: 'node' } },
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
equalsAst('{{[foo bar].baz}}', '{{ p%[Array[p%foo, p%bar]]/baz }}', {
|
|
77
|
+
options: { syntax: { square: 'node' } },
|
|
78
|
+
});
|
|
50
79
|
});
|
|
51
80
|
|
|
52
|
-
it('parses mustaches
|
|
53
|
-
|
|
81
|
+
it('parses mustaches that are hash literals', function () {
|
|
82
|
+
equalsAst('{{foo=bar}}', '{{ Hash{foo=p%bar} }}');
|
|
83
|
+
equalsAst('{{foo=bar}}', `{{ "HASH{foo=p%bar}" }}`, {
|
|
84
|
+
options: {
|
|
85
|
+
syntax: {
|
|
86
|
+
hash: (hash, loc) => {
|
|
87
|
+
return {
|
|
88
|
+
type: 'StringLiteral',
|
|
89
|
+
original: print(hash),
|
|
90
|
+
value: print(hash),
|
|
91
|
+
loc,
|
|
92
|
+
};
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
});
|
|
54
97
|
});
|
|
55
98
|
|
|
56
|
-
it('parses mustaches with
|
|
57
|
-
|
|
99
|
+
it('parses mustaches with parameters', function () {
|
|
100
|
+
equalsAst('{{foo bar}}', '{{ p%foo [p%bar] }}');
|
|
101
|
+
equalsAst('{{this.foo bar}}', '{{ p%this.foo [p%bar] }}');
|
|
102
|
+
equalsAst('{{this.foo this.bar}}', '{{ p%this.foo [p%this.bar] }}');
|
|
103
|
+
equalsAst('{{this.#foo this.#bar}}', '{{ p%this.#foo [p%this.#bar] }}');
|
|
104
|
+
equalsAst('{{foo.#bar foo.#baz}}', '{{ p%foo/#bar [p%foo/#baz] }}');
|
|
105
|
+
equalsAst('{{@foo.#bar @foo.#baz}}', '{{ p%@foo/#bar [p%@foo/#baz] }}');
|
|
58
106
|
});
|
|
59
107
|
|
|
60
|
-
it('parses mustaches with
|
|
61
|
-
|
|
62
|
-
|
|
108
|
+
it('parses mustaches with string parameters', function () {
|
|
109
|
+
equalsAst('{{foo bar "baz" }}', '{{ p%foo [p%bar, "baz"] }}');
|
|
110
|
+
equalsAst('{{this.foo bar "baz" }}', '{{ p%this.foo [p%bar, "baz"] }}');
|
|
111
|
+
equalsAst('{{this.#foo bar "baz" }}', '{{ p%this.#foo [p%bar, "baz"] }}');
|
|
112
|
+
equalsAst('{{@item.#foo bar "baz" }}', '{{ p%@item/#foo [p%bar, "baz"] }}');
|
|
63
113
|
});
|
|
64
114
|
|
|
65
|
-
it('parses mustaches with
|
|
66
|
-
|
|
67
|
-
|
|
115
|
+
it('parses mustaches with NUMBER parameters', function () {
|
|
116
|
+
equalsAst('{{foo 1}}', '{{ p%foo [n%1] }}');
|
|
117
|
+
equalsAst('{{this.foo 1}}', '{{ p%this.foo [n%1] }}');
|
|
118
|
+
equalsAst('{{this.#foo 1}}', '{{ p%this.#foo [n%1] }}');
|
|
68
119
|
});
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
);
|
|
120
|
+
|
|
121
|
+
it('parses mustaches with BOOLEAN parameters', function () {
|
|
122
|
+
equalsAst('{{foo true}}', '{{ p%foo [b%true] }}');
|
|
123
|
+
equalsAst('{{foo false}}', '{{ p%foo [b%false] }}');
|
|
74
124
|
});
|
|
75
125
|
|
|
76
|
-
it('parses mustaches with
|
|
77
|
-
|
|
126
|
+
it('parses mustaches with undefined and null paths', function () {
|
|
127
|
+
equalsAst('{{undefined}}', '{{ UNDEFINED }}');
|
|
128
|
+
equalsAst('{{null}}', '{{ NULL }}');
|
|
78
129
|
});
|
|
79
130
|
|
|
80
|
-
it('parses mustaches with
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
equals(
|
|
84
|
-
astFor('{{foo bar=true}}'),
|
|
85
|
-
'{{ PATH:foo [] HASH{bar=BOOLEAN{true}} }}\n'
|
|
86
|
-
);
|
|
87
|
-
equals(
|
|
88
|
-
astFor('{{foo bar=false}}'),
|
|
89
|
-
'{{ PATH:foo [] HASH{bar=BOOLEAN{false}} }}\n'
|
|
90
|
-
);
|
|
91
|
-
equals(
|
|
92
|
-
astFor('{{foo bar=@baz}}'),
|
|
93
|
-
'{{ PATH:foo [] HASH{bar=@PATH:baz} }}\n'
|
|
94
|
-
);
|
|
131
|
+
it('parses mustaches with undefined and null parameters', function () {
|
|
132
|
+
equalsAst('{{foo undefined null}}', '{{ p%foo [UNDEFINED, NULL] }}');
|
|
133
|
+
});
|
|
95
134
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
135
|
+
it('parses mustaches with DATA parameters', function () {
|
|
136
|
+
equalsAst('{{foo @bar}}', '{{ p%foo [p%@bar] }}');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('parses mustaches with hash arguments', function () {
|
|
140
|
+
equalsAst('{{foo bar=baz}}', '{{ p%foo HASH{bar=p%baz} }}');
|
|
141
|
+
equalsAst('{{foo bar=1}}', '{{ p%foo HASH{bar=n%1} }}');
|
|
142
|
+
equalsAst('{{foo bar=true}}', '{{ p%foo HASH{bar=b%true} }}');
|
|
143
|
+
equalsAst('{{foo bar=false}}', '{{ p%foo HASH{bar=b%false} }}');
|
|
144
|
+
equalsAst('{{foo bar=@baz}}', '{{ p%foo HASH{bar=p%@baz} }}');
|
|
145
|
+
|
|
146
|
+
equalsAst(
|
|
147
|
+
'{{foo bar=baz bat=bam}}',
|
|
148
|
+
'{{ p%foo HASH{bar=p%baz bat=p%bam} }}'
|
|
99
149
|
);
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
'{{
|
|
150
|
+
equalsAst(
|
|
151
|
+
'{{foo bar=baz bat="bam"}}',
|
|
152
|
+
'{{ p%foo HASH{bar=p%baz bat="bam"} }}'
|
|
103
153
|
);
|
|
104
154
|
|
|
105
|
-
|
|
155
|
+
equalsAst("{{foo bat='bam'}}", '{{ p%foo HASH{bat="bam"} }}');
|
|
106
156
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
'{{
|
|
157
|
+
equalsAst(
|
|
158
|
+
'{{foo omg bar=baz bat="bam"}}',
|
|
159
|
+
'{{ p%foo [p%omg] HASH{bar=p%baz bat="bam"} }}'
|
|
110
160
|
);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
'{{
|
|
161
|
+
equalsAst(
|
|
162
|
+
'{{foo omg bar=baz bat="bam" baz=1}}',
|
|
163
|
+
'{{ p%foo [p%omg] HASH{bar=p%baz bat="bam" baz=n%1} }}'
|
|
114
164
|
);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
'{{
|
|
165
|
+
equalsAst(
|
|
166
|
+
'{{foo omg bar=baz bat="bam" baz=true}}',
|
|
167
|
+
'{{ p%foo [p%omg] HASH{bar=p%baz bat="bam" baz=b%true} }}'
|
|
118
168
|
);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
'{{
|
|
169
|
+
equalsAst(
|
|
170
|
+
'{{foo omg bar=baz bat="bam" baz=false}}',
|
|
171
|
+
'{{ p%foo [p%omg] HASH{bar=p%baz bat="bam" baz=b%false} }}'
|
|
122
172
|
);
|
|
123
173
|
});
|
|
124
174
|
|
|
125
|
-
it('parses contents followed by a mustache', function() {
|
|
126
|
-
|
|
127
|
-
astFor('foo bar {{baz}}'),
|
|
128
|
-
"CONTENT[ 'foo bar ' ]\n{{ PATH:baz [] }}\n"
|
|
129
|
-
);
|
|
175
|
+
it('parses contents followed by a mustache', function () {
|
|
176
|
+
equalsAst('foo bar {{baz}}', "CONTENT[ 'foo bar ' ]\n{{ p%baz }}");
|
|
130
177
|
});
|
|
131
178
|
|
|
132
|
-
it('parses a partial', function() {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
179
|
+
it('parses a partial', function () {
|
|
180
|
+
equalsAst('{{> foo }}', '{{> PARTIAL:foo }}');
|
|
181
|
+
equalsAst('{{> "foo" }}', '{{> PARTIAL:foo }}');
|
|
182
|
+
equalsAst('{{> 1 }}', '{{> PARTIAL:1 }}');
|
|
136
183
|
});
|
|
137
184
|
|
|
138
|
-
it('parses a partial with context', function() {
|
|
139
|
-
|
|
185
|
+
it('parses a partial with context', function () {
|
|
186
|
+
equalsAst('{{> foo bar}}', '{{> PARTIAL:foo p%bar }}');
|
|
140
187
|
});
|
|
141
188
|
|
|
142
|
-
it('parses a partial with hash', function() {
|
|
143
|
-
|
|
144
|
-
astFor('{{> foo bar=bat}}'),
|
|
145
|
-
'{{> PARTIAL:foo HASH{bar=PATH:bat} }}\n'
|
|
146
|
-
);
|
|
189
|
+
it('parses a partial with hash', function () {
|
|
190
|
+
equalsAst('{{> foo bar=bat}}', '{{> PARTIAL:foo HASH{bar=p%bat} }}');
|
|
147
191
|
});
|
|
148
192
|
|
|
149
|
-
it('parses a partial with context and hash', function() {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
'{{> PARTIAL:foo
|
|
193
|
+
it('parses a partial with context and hash', function () {
|
|
194
|
+
equalsAst(
|
|
195
|
+
'{{> foo bar bat=baz}}',
|
|
196
|
+
'{{> PARTIAL:foo p%bar HASH{bat=p%baz} }}'
|
|
153
197
|
);
|
|
154
198
|
});
|
|
155
199
|
|
|
156
|
-
it('parses a partial with a complex name', function() {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
'{{> PARTIAL:shared/partial?.bar }}
|
|
200
|
+
it('parses a partial with a complex name', function () {
|
|
201
|
+
equalsAst(
|
|
202
|
+
'{{> shared/partial?.bar}}',
|
|
203
|
+
'{{> PARTIAL:shared/partial?.bar }}'
|
|
160
204
|
);
|
|
161
205
|
});
|
|
162
206
|
|
|
163
|
-
it('parsers partial blocks', function() {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
"{{> PARTIAL BLOCK:foo PROGRAM:\n CONTENT[ 'bar' ]\n }}
|
|
207
|
+
it('parsers partial blocks', function () {
|
|
208
|
+
equalsAst(
|
|
209
|
+
'{{#> foo}}bar{{/foo}}',
|
|
210
|
+
"{{> PARTIAL BLOCK:foo PROGRAM:\n CONTENT[ 'bar' ]\n }}"
|
|
167
211
|
);
|
|
168
212
|
});
|
|
169
|
-
it('should handle parser block mismatch', function() {
|
|
213
|
+
it('should handle parser block mismatch', function () {
|
|
170
214
|
shouldThrow(
|
|
171
|
-
function() {
|
|
215
|
+
function () {
|
|
172
216
|
astFor('{{#> goodbyes}}{{/hellos}}');
|
|
173
217
|
},
|
|
174
218
|
Error,
|
|
175
219
|
/goodbyes doesn't match hellos/
|
|
176
220
|
);
|
|
177
221
|
});
|
|
178
|
-
it('parsers partial blocks with arguments', function() {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
"{{> PARTIAL BLOCK:foo
|
|
222
|
+
it('parsers partial blocks with arguments', function () {
|
|
223
|
+
equalsAst(
|
|
224
|
+
'{{#> foo context hash=value}}bar{{/foo}}',
|
|
225
|
+
"{{> PARTIAL BLOCK:foo p%context HASH{hash=p%value} PROGRAM:\n CONTENT[ 'bar' ]\n }}"
|
|
182
226
|
);
|
|
183
227
|
});
|
|
184
228
|
|
|
185
|
-
it('parses a comment', function() {
|
|
186
|
-
|
|
187
|
-
astFor('{{! this is a comment }}'),
|
|
188
|
-
"{{! ' this is a comment ' }}\n"
|
|
189
|
-
);
|
|
229
|
+
it('parses a comment', function () {
|
|
230
|
+
equalsAst('{{! this is a comment }}', "{{! ' this is a comment ' }}");
|
|
190
231
|
});
|
|
191
232
|
|
|
192
|
-
it('parses a multi-line comment', function() {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
"{{! '\nthis is a multi-line comment\n' }}
|
|
233
|
+
it('parses a multi-line comment', function () {
|
|
234
|
+
equalsAst(
|
|
235
|
+
'{{!\nthis is a multi-line comment\n}}',
|
|
236
|
+
"{{! '\nthis is a multi-line comment\n' }}"
|
|
196
237
|
);
|
|
197
238
|
});
|
|
198
239
|
|
|
199
|
-
it('parses an inverse section', function() {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
"BLOCK:\n
|
|
240
|
+
it('parses an inverse section', function () {
|
|
241
|
+
equalsAst(
|
|
242
|
+
'{{#foo}} bar {{^}} baz {{/foo}}',
|
|
243
|
+
"BLOCK:\n p%foo\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]"
|
|
203
244
|
);
|
|
204
245
|
});
|
|
205
246
|
|
|
206
|
-
it('parses an inverse (else-style) section', function() {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
"BLOCK:\n
|
|
247
|
+
it('parses an inverse (else-style) section', function () {
|
|
248
|
+
equalsAst(
|
|
249
|
+
'{{#foo}} bar {{else}} baz {{/foo}}',
|
|
250
|
+
"BLOCK:\n p%foo\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n CONTENT[ ' baz ' ]"
|
|
210
251
|
);
|
|
211
252
|
});
|
|
212
253
|
|
|
213
|
-
it('parses multiple inverse sections', function() {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
"BLOCK:\n
|
|
254
|
+
it('parses multiple inverse sections', function () {
|
|
255
|
+
equalsAst(
|
|
256
|
+
'{{#foo}} bar {{else if bar}}{{else}} baz {{/foo}}',
|
|
257
|
+
"BLOCK:\n p%foo\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}\n BLOCK:\n p%if [p%bar]\n PROGRAM:\n {{^}}\n CONTENT[ ' baz ' ]"
|
|
217
258
|
);
|
|
218
259
|
});
|
|
219
260
|
|
|
220
|
-
it('parses empty blocks', function() {
|
|
221
|
-
|
|
261
|
+
it('parses empty blocks', function () {
|
|
262
|
+
equalsAst('{{#foo}}{{/foo}}', 'BLOCK:\n p%foo\n PROGRAM:');
|
|
222
263
|
});
|
|
223
264
|
|
|
224
|
-
it('parses empty blocks with empty inverse section', function() {
|
|
225
|
-
|
|
226
|
-
astFor('{{#foo}}{{^}}{{/foo}}'),
|
|
227
|
-
'BLOCK:\n PATH:foo []\n PROGRAM:\n {{^}}\n'
|
|
228
|
-
);
|
|
265
|
+
it('parses empty blocks with empty inverse section', function () {
|
|
266
|
+
equalsAst('{{#foo}}{{^}}{{/foo}}', 'BLOCK:\n p%foo\n PROGRAM:\n {{^}}');
|
|
229
267
|
});
|
|
230
268
|
|
|
231
|
-
it('parses empty blocks with empty inverse (else-style) section', function() {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
'BLOCK:\n
|
|
269
|
+
it('parses empty blocks with empty inverse (else-style) section', function () {
|
|
270
|
+
equalsAst(
|
|
271
|
+
'{{#foo}}{{else}}{{/foo}}',
|
|
272
|
+
'BLOCK:\n p%foo\n PROGRAM:\n {{^}}'
|
|
235
273
|
);
|
|
236
274
|
});
|
|
237
275
|
|
|
238
|
-
it('parses non-empty blocks with empty inverse section', function() {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
"BLOCK:\n
|
|
276
|
+
it('parses non-empty blocks with empty inverse section', function () {
|
|
277
|
+
equalsAst(
|
|
278
|
+
'{{#foo}} bar {{^}}{{/foo}}',
|
|
279
|
+
"BLOCK:\n p%foo\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}"
|
|
242
280
|
);
|
|
243
281
|
});
|
|
244
282
|
|
|
245
|
-
it('parses non-empty blocks with empty inverse (else-style) section', function() {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
"BLOCK:\n
|
|
283
|
+
it('parses non-empty blocks with empty inverse (else-style) section', function () {
|
|
284
|
+
equalsAst(
|
|
285
|
+
'{{#foo}} bar {{else}}{{/foo}}',
|
|
286
|
+
"BLOCK:\n p%foo\n PROGRAM:\n CONTENT[ ' bar ' ]\n {{^}}"
|
|
249
287
|
);
|
|
250
288
|
});
|
|
251
289
|
|
|
252
|
-
it('parses empty blocks with non-empty inverse section', function() {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
"BLOCK:\n
|
|
290
|
+
it('parses empty blocks with non-empty inverse section', function () {
|
|
291
|
+
equalsAst(
|
|
292
|
+
'{{#foo}}{{^}} bar {{/foo}}',
|
|
293
|
+
"BLOCK:\n p%foo\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]"
|
|
256
294
|
);
|
|
257
295
|
});
|
|
258
296
|
|
|
259
|
-
it('parses empty blocks with non-empty inverse (else-style) section', function() {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
"BLOCK:\n
|
|
297
|
+
it('parses empty blocks with non-empty inverse (else-style) section', function () {
|
|
298
|
+
equalsAst(
|
|
299
|
+
'{{#foo}}{{else}} bar {{/foo}}',
|
|
300
|
+
"BLOCK:\n p%foo\n PROGRAM:\n {{^}}\n CONTENT[ ' bar ' ]"
|
|
263
301
|
);
|
|
264
302
|
});
|
|
265
303
|
|
|
266
|
-
it('parses a standalone inverse section', function() {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
"BLOCK:\n
|
|
304
|
+
it('parses a standalone inverse section', function () {
|
|
305
|
+
equalsAst(
|
|
306
|
+
'{{^foo}}bar{{/foo}}',
|
|
307
|
+
"BLOCK:\n p%foo\n {{^}}\n CONTENT[ 'bar' ]"
|
|
270
308
|
);
|
|
271
309
|
});
|
|
272
|
-
|
|
273
|
-
|
|
310
|
+
|
|
311
|
+
it('throws on old inverse section', function () {
|
|
312
|
+
shouldThrow(function () {
|
|
274
313
|
astFor('{{else foo}}bar{{/foo}}');
|
|
275
314
|
}, Error);
|
|
276
315
|
});
|
|
277
316
|
|
|
278
|
-
it('parses block with block params', function() {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
"BLOCK:\n
|
|
317
|
+
it('parses block with block params', function () {
|
|
318
|
+
equalsAst(
|
|
319
|
+
'{{#foo as |bar baz|}}content{{/foo}}',
|
|
320
|
+
"BLOCK:\n p%foo\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]"
|
|
282
321
|
);
|
|
283
322
|
});
|
|
284
323
|
|
|
285
|
-
it('parses mustaches with sub-expressions as the callable', function() {
|
|
286
|
-
|
|
287
|
-
astFor('{{(my-helper foo)}}'),
|
|
288
|
-
'{{ PATH:my-helper [PATH:foo] [] }}\n'
|
|
289
|
-
);
|
|
324
|
+
it('parses mustaches with sub-expressions as the callable', function () {
|
|
325
|
+
equalsAst('{{(my-helper foo)}}', '{{ (p%my-helper [p%foo]) }}');
|
|
290
326
|
});
|
|
291
327
|
|
|
292
|
-
it('parses mustaches with sub-expressions as the callable (with args)', function() {
|
|
293
|
-
|
|
294
|
-
astFor('{{(my-helper foo) bar}}'),
|
|
295
|
-
'{{ PATH:my-helper [PATH:foo] [PATH:bar] }}\n'
|
|
296
|
-
);
|
|
328
|
+
it('parses mustaches with sub-expressions as the callable (with args)', function () {
|
|
329
|
+
equalsAst('{{(my-helper foo) bar}}', '{{ (p%my-helper [p%foo]) [p%bar] }}');
|
|
297
330
|
});
|
|
298
331
|
|
|
299
|
-
it('parses sub-expressions with a sub-expression as the callable', function() {
|
|
300
|
-
|
|
301
|
-
astFor('{{((my-helper foo))}}'),
|
|
302
|
-
'{{ PATH:my-helper [PATH:foo] [] [] }}\n'
|
|
303
|
-
);
|
|
332
|
+
it('parses sub-expressions with a sub-expression as the callable', function () {
|
|
333
|
+
equalsAst('{{((my-helper foo))}}', '{{ ((p%my-helper [p%foo])) }}');
|
|
304
334
|
});
|
|
305
335
|
|
|
306
|
-
it('parses sub-expressions with a sub-expression as the callable (with args)', function() {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
'{{
|
|
336
|
+
it('parses sub-expressions with a sub-expression as the callable (with args)', function () {
|
|
337
|
+
equalsAst(
|
|
338
|
+
'{{((my-helper foo) bar)}}',
|
|
339
|
+
'{{ ((p%my-helper [p%foo]) [p%bar]) }}'
|
|
310
340
|
);
|
|
311
341
|
});
|
|
312
342
|
|
|
313
|
-
it('parses arguments with a sub-expression as the callable (with args)', function() {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
'{{
|
|
343
|
+
it('parses arguments with a sub-expression as the callable (with args)', function () {
|
|
344
|
+
equalsAst(
|
|
345
|
+
'{{my-helper ((foo) bar) baz=((foo bar))}}',
|
|
346
|
+
'{{ p%my-helper [((p%foo) [p%bar])] HASH{baz=((p%foo [p%bar]))} }}'
|
|
317
347
|
);
|
|
318
348
|
});
|
|
319
349
|
|
|
320
|
-
it('parses paths with sub-expressions as the root', function() {
|
|
321
|
-
|
|
322
|
-
astFor('{{(my-helper foo).bar}}'),
|
|
323
|
-
'{{ PATH:[PATH:my-helper [PATH:foo]]/bar [] }}\n'
|
|
324
|
-
);
|
|
350
|
+
it('parses paths with sub-expressions as the root', function () {
|
|
351
|
+
equalsAst('{{(my-helper foo).bar}}', '{{ p%[(p%my-helper [p%foo])]/bar }}');
|
|
325
352
|
});
|
|
326
353
|
|
|
327
|
-
it('parses paths with sub-expressions as the root as a callable', function() {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
'{{
|
|
354
|
+
it('parses paths with sub-expressions as the root as a callable', function () {
|
|
355
|
+
equalsAst(
|
|
356
|
+
'{{((my-helper foo).bar baz)}}',
|
|
357
|
+
'{{ (p%[(p%my-helper [p%foo])]/bar [p%baz]) }}'
|
|
331
358
|
);
|
|
332
359
|
});
|
|
333
360
|
|
|
334
|
-
it('parses paths with sub-expressions as the root as an argument', function() {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
'{{
|
|
361
|
+
it('parses paths with sub-expressions as the root as an argument', function () {
|
|
362
|
+
equalsAst(
|
|
363
|
+
'{{(foo (my-helper bar).baz)}}',
|
|
364
|
+
'{{ (p%foo [p%[(p%my-helper [p%bar])]/baz]) }}'
|
|
338
365
|
);
|
|
339
366
|
});
|
|
340
367
|
|
|
341
|
-
it('parses paths with sub-expressions as the root as a named argument', function() {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
'{{
|
|
368
|
+
it('parses paths with sub-expressions as the root as a named argument', function () {
|
|
369
|
+
equalsAst(
|
|
370
|
+
'{{(foo bar=(my-helper baz).qux)}}',
|
|
371
|
+
'{{ (p%foo HASH{bar=p%[(p%my-helper [p%baz])]/qux}) }}'
|
|
345
372
|
);
|
|
346
373
|
});
|
|
347
374
|
|
|
348
|
-
it('parses inverse block with block params', function() {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
"BLOCK:\n
|
|
375
|
+
it('parses inverse block with block params', function () {
|
|
376
|
+
equalsAst(
|
|
377
|
+
'{{^foo as |bar baz|}}content{{/foo}}',
|
|
378
|
+
"BLOCK:\n p%foo\n {{^}}\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]"
|
|
352
379
|
);
|
|
353
380
|
});
|
|
354
|
-
it('parses chained inverse block with block params', function() {
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
"BLOCK:\n
|
|
381
|
+
it('parses chained inverse block with block params', function () {
|
|
382
|
+
equalsAst(
|
|
383
|
+
'{{#foo}}{{else foo as |bar baz|}}content{{/foo}}',
|
|
384
|
+
"BLOCK:\n p%foo\n PROGRAM:\n {{^}}\n BLOCK:\n p%foo\n PROGRAM:\n BLOCK PARAMS: [ bar baz ]\n CONTENT[ 'content' ]"
|
|
358
385
|
);
|
|
359
386
|
});
|
|
360
|
-
it("raises if there's a Parse error", function() {
|
|
387
|
+
it("raises if there's a Parse error", function () {
|
|
361
388
|
shouldThrow(
|
|
362
|
-
function() {
|
|
389
|
+
function () {
|
|
363
390
|
astFor('foo{{^}}bar');
|
|
364
391
|
},
|
|
365
392
|
Error,
|
|
366
393
|
/Parse error on line 1/
|
|
367
394
|
);
|
|
368
395
|
shouldThrow(
|
|
369
|
-
function() {
|
|
396
|
+
function () {
|
|
370
397
|
astFor('{{foo}');
|
|
371
398
|
},
|
|
372
399
|
Error,
|
|
373
400
|
/Parse error on line 1/
|
|
374
401
|
);
|
|
375
402
|
shouldThrow(
|
|
376
|
-
function() {
|
|
403
|
+
function () {
|
|
377
404
|
astFor('{{foo &}}');
|
|
378
405
|
},
|
|
379
406
|
Error,
|
|
380
407
|
/Parse error on line 1/
|
|
381
408
|
);
|
|
382
409
|
shouldThrow(
|
|
383
|
-
function() {
|
|
410
|
+
function () {
|
|
384
411
|
astFor('{{#goodbyes}}{{/hellos}}');
|
|
385
412
|
},
|
|
386
413
|
Error,
|
|
@@ -388,7 +415,7 @@ describe('parser', function() {
|
|
|
388
415
|
);
|
|
389
416
|
|
|
390
417
|
shouldThrow(
|
|
391
|
-
function() {
|
|
418
|
+
function () {
|
|
392
419
|
astFor('{{{{goodbyes}}}} {{{{/hellos}}}}');
|
|
393
420
|
},
|
|
394
421
|
Error,
|
|
@@ -396,23 +423,23 @@ describe('parser', function() {
|
|
|
396
423
|
);
|
|
397
424
|
});
|
|
398
425
|
|
|
399
|
-
it('should handle invalid paths', function() {
|
|
426
|
+
it('should handle invalid paths', function () {
|
|
400
427
|
shouldThrow(
|
|
401
|
-
function() {
|
|
428
|
+
function () {
|
|
402
429
|
astFor('{{foo/../bar}}');
|
|
403
430
|
},
|
|
404
431
|
Error,
|
|
405
432
|
/Invalid path: foo\/\.\. - 1:2/
|
|
406
433
|
);
|
|
407
434
|
shouldThrow(
|
|
408
|
-
function() {
|
|
435
|
+
function () {
|
|
409
436
|
astFor('{{foo/./bar}}');
|
|
410
437
|
},
|
|
411
438
|
Error,
|
|
412
439
|
/Invalid path: foo\/\. - 1:2/
|
|
413
440
|
);
|
|
414
441
|
shouldThrow(
|
|
415
|
-
function() {
|
|
442
|
+
function () {
|
|
416
443
|
astFor('{{foo/this/bar}}');
|
|
417
444
|
},
|
|
418
445
|
Error,
|
|
@@ -420,16 +447,16 @@ describe('parser', function() {
|
|
|
420
447
|
);
|
|
421
448
|
});
|
|
422
449
|
|
|
423
|
-
it('knows how to report the correct line number in errors', function() {
|
|
450
|
+
it('knows how to report the correct line number in errors', function () {
|
|
424
451
|
shouldThrow(
|
|
425
|
-
function() {
|
|
452
|
+
function () {
|
|
426
453
|
astFor('hello\nmy\n{{foo}');
|
|
427
454
|
},
|
|
428
455
|
Error,
|
|
429
456
|
/Parse error on line 3/
|
|
430
457
|
);
|
|
431
458
|
shouldThrow(
|
|
432
|
-
function() {
|
|
459
|
+
function () {
|
|
433
460
|
astFor('hello\n\nmy\n\n{{foo}');
|
|
434
461
|
},
|
|
435
462
|
Error,
|
|
@@ -437,9 +464,9 @@ describe('parser', function() {
|
|
|
437
464
|
);
|
|
438
465
|
});
|
|
439
466
|
|
|
440
|
-
it('knows how to report the correct line number in errors when the first character is a newline', function() {
|
|
467
|
+
it('knows how to report the correct line number in errors when the first character is a newline', function () {
|
|
441
468
|
shouldThrow(
|
|
442
|
-
function() {
|
|
469
|
+
function () {
|
|
443
470
|
astFor('\n\nhello\n\nmy\n\n{{foo}');
|
|
444
471
|
},
|
|
445
472
|
Error,
|
|
@@ -447,31 +474,28 @@ describe('parser', function() {
|
|
|
447
474
|
);
|
|
448
475
|
});
|
|
449
476
|
|
|
450
|
-
describe('externally compiled AST', function() {
|
|
451
|
-
it('can pass through an already-compiled AST', function() {
|
|
477
|
+
describe('externally compiled AST', function () {
|
|
478
|
+
it('can pass through an already-compiled AST', function () {
|
|
452
479
|
equals(
|
|
453
480
|
astFor({
|
|
454
481
|
type: 'Program',
|
|
455
|
-
body: [{ type: 'ContentStatement', value: 'Hello' }]
|
|
482
|
+
body: [{ type: 'ContentStatement', value: 'Hello' }],
|
|
456
483
|
}),
|
|
457
484
|
"CONTENT[ 'Hello' ]\n"
|
|
458
485
|
);
|
|
459
486
|
});
|
|
460
487
|
});
|
|
461
488
|
|
|
462
|
-
describe('directives', function() {
|
|
463
|
-
it('should parse block directives', function() {
|
|
464
|
-
|
|
465
|
-
astFor('{{#* foo}}{{/foo}}'),
|
|
466
|
-
'DIRECTIVE BLOCK:\n PATH:foo []\n PROGRAM:\n'
|
|
467
|
-
);
|
|
489
|
+
describe('directives', function () {
|
|
490
|
+
it('should parse block directives', function () {
|
|
491
|
+
equalsAst('{{#* foo}}{{/foo}}', 'DIRECTIVE BLOCK:\n p%foo\n PROGRAM:');
|
|
468
492
|
});
|
|
469
|
-
it('should parse directives', function() {
|
|
470
|
-
|
|
493
|
+
it('should parse directives', function () {
|
|
494
|
+
equalsAst('{{* foo}}', '{{ DIRECTIVE p%foo }}');
|
|
471
495
|
});
|
|
472
|
-
it('should fail if directives have inverse', function() {
|
|
496
|
+
it('should fail if directives have inverse', function () {
|
|
473
497
|
shouldThrow(
|
|
474
|
-
function() {
|
|
498
|
+
function () {
|
|
475
499
|
astFor('{{#* foo}}{{^}}{{/foo}}');
|
|
476
500
|
},
|
|
477
501
|
Error,
|
|
@@ -480,7 +504,7 @@ describe('parser', function() {
|
|
|
480
504
|
});
|
|
481
505
|
});
|
|
482
506
|
|
|
483
|
-
it('GH1024 - should track program location properly', function() {
|
|
507
|
+
it('GH1024 - should track program location properly', function () {
|
|
484
508
|
let p = parse(
|
|
485
509
|
'\n' +
|
|
486
510
|
' {{#if foo}}\n' +
|
|
@@ -496,21 +520,21 @@ describe('parser', function() {
|
|
|
496
520
|
JSON.stringify(p.loc),
|
|
497
521
|
JSON.stringify({
|
|
498
522
|
start: { line: 1, column: 0 },
|
|
499
|
-
end: { line: 7, column: 4 }
|
|
523
|
+
end: { line: 7, column: 4 },
|
|
500
524
|
})
|
|
501
525
|
);
|
|
502
526
|
equals(
|
|
503
527
|
JSON.stringify(p.body[1].program.loc),
|
|
504
528
|
JSON.stringify({
|
|
505
529
|
start: { line: 2, column: 13 },
|
|
506
|
-
end: { line: 4, column: 7 }
|
|
530
|
+
end: { line: 4, column: 7 },
|
|
507
531
|
})
|
|
508
532
|
);
|
|
509
533
|
equals(
|
|
510
534
|
JSON.stringify(p.body[1].inverse.loc),
|
|
511
535
|
JSON.stringify({
|
|
512
536
|
start: { line: 4, column: 15 },
|
|
513
|
-
end: { line: 6, column: 5 }
|
|
537
|
+
end: { line: 6, column: 5 },
|
|
514
538
|
})
|
|
515
539
|
);
|
|
516
540
|
});
|