@handlebars/parser 2.0.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 +32 -0
- package/RELEASE.md +15 -48
- package/dist/cjs/exception.js +2 -4
- package/dist/cjs/helpers.js +60 -50
- package/dist/cjs/index.js +7 -21
- package/dist/cjs/parse.js +46 -38
- package/dist/cjs/parser.js +130 -97
- package/dist/cjs/printer.js +77 -44
- 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 +49 -23
- package/dist/esm/index.js +7 -7
- package/dist/esm/parse.js +41 -6
- package/dist/esm/parser.js +129 -94
- package/dist/esm/printer.js +75 -34
- package/dist/esm/visitor.js +4 -4
- package/dist/esm/whitespace-control.js +64 -59
- package/lib/helpers.js +44 -26
- package/lib/index.js +6 -6
- package/lib/parse.js +43 -6
- package/lib/printer.js +87 -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 +284 -232
- package/spec/utils.js +73 -8
- package/spec/visitor.js +36 -42
- package/src/handlebars.l +22 -4
- package/src/handlebars.yy +23 -5
- package/tsconfig.json +12 -6
- package/types/ast.d.ts +3 -1
package/spec/parser.js
CHANGED
|
@@ -1,358 +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
|
-
|
|
288
|
-
|
|
324
|
+
it('parses mustaches with sub-expressions as the callable', function () {
|
|
325
|
+
equalsAst('{{(my-helper foo)}}', '{{ (p%my-helper [p%foo]) }}');
|
|
326
|
+
});
|
|
327
|
+
|
|
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] }}');
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('parses sub-expressions with a sub-expression as the callable', function () {
|
|
333
|
+
equalsAst('{{((my-helper foo))}}', '{{ ((p%my-helper [p%foo])) }}');
|
|
334
|
+
});
|
|
335
|
+
|
|
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]) }}'
|
|
289
340
|
);
|
|
290
341
|
});
|
|
291
342
|
|
|
292
|
-
it('parses
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
'{{
|
|
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]))} }}'
|
|
296
347
|
);
|
|
297
348
|
});
|
|
298
349
|
|
|
299
|
-
it('parses
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
350
|
+
it('parses paths with sub-expressions as the root', function () {
|
|
351
|
+
equalsAst('{{(my-helper foo).bar}}', '{{ p%[(p%my-helper [p%foo])]/bar }}');
|
|
352
|
+
});
|
|
353
|
+
|
|
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]) }}'
|
|
303
358
|
);
|
|
304
359
|
});
|
|
305
360
|
|
|
306
|
-
it('parses
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
'{{
|
|
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]) }}'
|
|
310
365
|
);
|
|
311
366
|
});
|
|
312
367
|
|
|
313
|
-
it('parses
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
'{{
|
|
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}) }}'
|
|
317
372
|
);
|
|
318
373
|
});
|
|
319
374
|
|
|
320
|
-
it('parses inverse block with block params', function() {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
"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' ]"
|
|
324
379
|
);
|
|
325
380
|
});
|
|
326
|
-
it('parses chained inverse block with block params', function() {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
"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' ]"
|
|
330
385
|
);
|
|
331
386
|
});
|
|
332
|
-
it("raises if there's a Parse error", function() {
|
|
387
|
+
it("raises if there's a Parse error", function () {
|
|
333
388
|
shouldThrow(
|
|
334
|
-
function() {
|
|
389
|
+
function () {
|
|
335
390
|
astFor('foo{{^}}bar');
|
|
336
391
|
},
|
|
337
392
|
Error,
|
|
338
393
|
/Parse error on line 1/
|
|
339
394
|
);
|
|
340
395
|
shouldThrow(
|
|
341
|
-
function() {
|
|
396
|
+
function () {
|
|
342
397
|
astFor('{{foo}');
|
|
343
398
|
},
|
|
344
399
|
Error,
|
|
345
400
|
/Parse error on line 1/
|
|
346
401
|
);
|
|
347
402
|
shouldThrow(
|
|
348
|
-
function() {
|
|
403
|
+
function () {
|
|
349
404
|
astFor('{{foo &}}');
|
|
350
405
|
},
|
|
351
406
|
Error,
|
|
352
407
|
/Parse error on line 1/
|
|
353
408
|
);
|
|
354
409
|
shouldThrow(
|
|
355
|
-
function() {
|
|
410
|
+
function () {
|
|
356
411
|
astFor('{{#goodbyes}}{{/hellos}}');
|
|
357
412
|
},
|
|
358
413
|
Error,
|
|
@@ -360,7 +415,7 @@ describe('parser', function() {
|
|
|
360
415
|
);
|
|
361
416
|
|
|
362
417
|
shouldThrow(
|
|
363
|
-
function() {
|
|
418
|
+
function () {
|
|
364
419
|
astFor('{{{{goodbyes}}}} {{{{/hellos}}}}');
|
|
365
420
|
},
|
|
366
421
|
Error,
|
|
@@ -368,23 +423,23 @@ describe('parser', function() {
|
|
|
368
423
|
);
|
|
369
424
|
});
|
|
370
425
|
|
|
371
|
-
it('should handle invalid paths', function() {
|
|
426
|
+
it('should handle invalid paths', function () {
|
|
372
427
|
shouldThrow(
|
|
373
|
-
function() {
|
|
428
|
+
function () {
|
|
374
429
|
astFor('{{foo/../bar}}');
|
|
375
430
|
},
|
|
376
431
|
Error,
|
|
377
432
|
/Invalid path: foo\/\.\. - 1:2/
|
|
378
433
|
);
|
|
379
434
|
shouldThrow(
|
|
380
|
-
function() {
|
|
435
|
+
function () {
|
|
381
436
|
astFor('{{foo/./bar}}');
|
|
382
437
|
},
|
|
383
438
|
Error,
|
|
384
439
|
/Invalid path: foo\/\. - 1:2/
|
|
385
440
|
);
|
|
386
441
|
shouldThrow(
|
|
387
|
-
function() {
|
|
442
|
+
function () {
|
|
388
443
|
astFor('{{foo/this/bar}}');
|
|
389
444
|
},
|
|
390
445
|
Error,
|
|
@@ -392,16 +447,16 @@ describe('parser', function() {
|
|
|
392
447
|
);
|
|
393
448
|
});
|
|
394
449
|
|
|
395
|
-
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 () {
|
|
396
451
|
shouldThrow(
|
|
397
|
-
function() {
|
|
452
|
+
function () {
|
|
398
453
|
astFor('hello\nmy\n{{foo}');
|
|
399
454
|
},
|
|
400
455
|
Error,
|
|
401
456
|
/Parse error on line 3/
|
|
402
457
|
);
|
|
403
458
|
shouldThrow(
|
|
404
|
-
function() {
|
|
459
|
+
function () {
|
|
405
460
|
astFor('hello\n\nmy\n\n{{foo}');
|
|
406
461
|
},
|
|
407
462
|
Error,
|
|
@@ -409,9 +464,9 @@ describe('parser', function() {
|
|
|
409
464
|
);
|
|
410
465
|
});
|
|
411
466
|
|
|
412
|
-
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 () {
|
|
413
468
|
shouldThrow(
|
|
414
|
-
function() {
|
|
469
|
+
function () {
|
|
415
470
|
astFor('\n\nhello\n\nmy\n\n{{foo}');
|
|
416
471
|
},
|
|
417
472
|
Error,
|
|
@@ -419,31 +474,28 @@ describe('parser', function() {
|
|
|
419
474
|
);
|
|
420
475
|
});
|
|
421
476
|
|
|
422
|
-
describe('externally compiled AST', function() {
|
|
423
|
-
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 () {
|
|
424
479
|
equals(
|
|
425
480
|
astFor({
|
|
426
481
|
type: 'Program',
|
|
427
|
-
body: [{ type: 'ContentStatement', value: 'Hello' }]
|
|
482
|
+
body: [{ type: 'ContentStatement', value: 'Hello' }],
|
|
428
483
|
}),
|
|
429
484
|
"CONTENT[ 'Hello' ]\n"
|
|
430
485
|
);
|
|
431
486
|
});
|
|
432
487
|
});
|
|
433
488
|
|
|
434
|
-
describe('directives', function() {
|
|
435
|
-
it('should parse block directives', function() {
|
|
436
|
-
|
|
437
|
-
astFor('{{#* foo}}{{/foo}}'),
|
|
438
|
-
'DIRECTIVE BLOCK:\n PATH:foo []\n PROGRAM:\n'
|
|
439
|
-
);
|
|
489
|
+
describe('directives', function () {
|
|
490
|
+
it('should parse block directives', function () {
|
|
491
|
+
equalsAst('{{#* foo}}{{/foo}}', 'DIRECTIVE BLOCK:\n p%foo\n PROGRAM:');
|
|
440
492
|
});
|
|
441
|
-
it('should parse directives', function() {
|
|
442
|
-
|
|
493
|
+
it('should parse directives', function () {
|
|
494
|
+
equalsAst('{{* foo}}', '{{ DIRECTIVE p%foo }}');
|
|
443
495
|
});
|
|
444
|
-
it('should fail if directives have inverse', function() {
|
|
496
|
+
it('should fail if directives have inverse', function () {
|
|
445
497
|
shouldThrow(
|
|
446
|
-
function() {
|
|
498
|
+
function () {
|
|
447
499
|
astFor('{{#* foo}}{{^}}{{/foo}}');
|
|
448
500
|
},
|
|
449
501
|
Error,
|
|
@@ -452,7 +504,7 @@ describe('parser', function() {
|
|
|
452
504
|
});
|
|
453
505
|
});
|
|
454
506
|
|
|
455
|
-
it('GH1024 - should track program location properly', function() {
|
|
507
|
+
it('GH1024 - should track program location properly', function () {
|
|
456
508
|
let p = parse(
|
|
457
509
|
'\n' +
|
|
458
510
|
' {{#if foo}}\n' +
|
|
@@ -468,21 +520,21 @@ describe('parser', function() {
|
|
|
468
520
|
JSON.stringify(p.loc),
|
|
469
521
|
JSON.stringify({
|
|
470
522
|
start: { line: 1, column: 0 },
|
|
471
|
-
end: { line: 7, column: 4 }
|
|
523
|
+
end: { line: 7, column: 4 },
|
|
472
524
|
})
|
|
473
525
|
);
|
|
474
526
|
equals(
|
|
475
527
|
JSON.stringify(p.body[1].program.loc),
|
|
476
528
|
JSON.stringify({
|
|
477
529
|
start: { line: 2, column: 13 },
|
|
478
|
-
end: { line: 4, column: 7 }
|
|
530
|
+
end: { line: 4, column: 7 },
|
|
479
531
|
})
|
|
480
532
|
);
|
|
481
533
|
equals(
|
|
482
534
|
JSON.stringify(p.body[1].inverse.loc),
|
|
483
535
|
JSON.stringify({
|
|
484
536
|
start: { line: 4, column: 15 },
|
|
485
|
-
end: { line: 6, column: 5 }
|
|
537
|
+
end: { line: 6, column: 5 },
|
|
486
538
|
})
|
|
487
539
|
);
|
|
488
540
|
});
|