@angular-wave/angular.ts 0.4.1 → 0.4.3

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.
Files changed (90) hide show
  1. package/dist/angular-ts.esm.js +2 -2
  2. package/dist/angular-ts.umd.js +2 -2
  3. package/package.json +7 -7
  4. package/src/angular.spec.js +1 -264
  5. package/src/animations/animate-css-driver.js +2 -2
  6. package/src/animations/animate-css.js +7 -8
  7. package/src/animations/animate-js-driver.js +1 -3
  8. package/src/animations/animate-js.js +4 -4
  9. package/src/animations/animate-queue.js +6 -6
  10. package/src/animations/animation.js +3 -3
  11. package/src/animations/shared.js +16 -14
  12. package/src/core/compile/attributes.js +2 -3
  13. package/src/core/compile/compile.js +248 -232
  14. package/src/core/compile/compile.spec.js +46 -51
  15. package/src/core/compile/compile.test.js +1 -1
  16. package/src/core/interpolate/interpolate.js +2 -2
  17. package/src/core/interval/interval.test.js +1 -1
  18. package/src/core/{parser/lexer.html → parse/ast/ast.html} +1 -1
  19. package/src/core/{parser → parse/ast}/ast.js +43 -29
  20. package/src/core/parse/ast/ast.spec.js +1462 -0
  21. package/src/core/parse/ast/ast.test.js +10 -0
  22. package/src/core/{parser → parse}/interpreter.js +10 -10
  23. package/src/core/parse/lexer/lexer.html +18 -0
  24. package/src/core/{parser → parse/lexer}/lexer.js +1 -1
  25. package/src/core/{parser → parse/lexer}/lexer.spec.js +2 -2
  26. package/src/core/parse/lexer/lexer.test.js +10 -0
  27. package/src/core/{parser → parse}/parse.html +1 -1
  28. package/src/core/{parser → parse}/parse.js +6 -6
  29. package/src/core/{parser → parse}/parse.spec.js +6 -1725
  30. package/src/core/parse/parse.test.js +10 -0
  31. package/src/core/parse/parser/parser.html +18 -0
  32. package/src/core/{parser → parse/parser}/parser.js +6 -6
  33. package/src/core/parse/parser/parser.spec.js +8 -0
  34. package/src/core/parse/parser/parser.test.js +10 -0
  35. package/src/core/sce/sce.js +1 -2
  36. package/src/core/scope/scope.js +4 -5
  37. package/src/directive/attrs/attrs.test.js +11 -0
  38. package/src/directive/attrs/boolean.html +18 -0
  39. package/src/directive/attrs/boolean.test.js +11 -0
  40. package/src/directive/attrs/element-style.html +21 -0
  41. package/src/directive/attrs/element-style.test.js +11 -0
  42. package/src/directive/bind/bing-html.spec.js +1 -1
  43. package/src/directive/class/class.js +1 -1
  44. package/src/directive/form/form.js +12 -19
  45. package/src/directive/if/if.spec.js +2 -3
  46. package/src/directive/if/if.test.js +1 -2
  47. package/src/directive/include/include.js +2 -2
  48. package/src/directive/input/input.js +1 -2
  49. package/src/directive/input/input.spec.js +187 -191
  50. package/src/directive/list/list.js +2 -2
  51. package/src/directive/model/model.js +14 -19
  52. package/src/directive/model-options/model-options.js +22 -26
  53. package/src/directive/options/options.js +1 -3
  54. package/src/directive/options/options.spec.js +3 -4
  55. package/src/directive/repeat/repeat.js +2 -2
  56. package/src/directive/repeat/repeat.spec.js +48 -57
  57. package/src/directive/select/select.spec.js +9 -10
  58. package/src/directive/switch/switch.js +1 -2
  59. package/src/directive/validators/validators.js +3 -3
  60. package/src/public.js +1 -1
  61. package/src/router/directives/state-directives.js +18 -16
  62. package/src/router/directives/view-directive.js +2 -2
  63. package/src/router/state/views.js +2 -2
  64. package/src/router/url/url-service.js +2 -8
  65. package/src/router/url/url-service.spec.js +3 -4
  66. package/src/services/http/http.js +5 -6
  67. package/src/services/http-backend/http-backend.js +19 -17
  68. package/src/shared/common.js +5 -8
  69. package/src/shared/jqlite/jqlite.js +14 -12
  70. package/src/shared/jqlite/jqlite.spec.js +2 -2
  71. package/src/shared/utils.js +15 -92
  72. package/types/animations/shared.d.ts +1 -1
  73. package/types/core/compile/compile.d.ts +1 -1
  74. package/types/core/interpolate/interpolate.d.ts +1 -1
  75. package/types/core/{parser → parse/ast}/ast.d.ts +17 -17
  76. package/types/core/{parser → parse}/interpreter.d.ts +7 -7
  77. package/types/core/{parser → parse/parser}/parser.d.ts +8 -8
  78. package/types/core/scope/scope.d.ts +3 -3
  79. package/types/directive/class/class.d.ts +3 -3
  80. package/types/directive/form/form.d.ts +1 -0
  81. package/types/directive/model/model.d.ts +6 -6
  82. package/types/directive/validators/validators.d.ts +3 -3
  83. package/types/shared/common.d.ts +0 -1
  84. package/types/shared/utils.d.ts +0 -35
  85. package/src/core/parser/parser.test.js +0 -19
  86. /package/src/core/{parser → parse}/ast-type.js +0 -0
  87. /package/src/core/{parser → parse}/parse.md +0 -0
  88. /package/types/core/{parser → parse}/ast-type.d.ts +0 -0
  89. /package/types/core/{parser → parse/lexer}/lexer.d.ts +0 -0
  90. /package/types/core/{parser → parse}/parse.d.ts +0 -0
@@ -0,0 +1,1462 @@
1
+ import { AST } from "./ast.js";
2
+ import { Lexer } from "../lexer/lexer.js";
3
+ import { createInjector } from "../../di/injector";
4
+ import { ASTType } from "../ast-type";
5
+ import { Angular } from "../../../loader";
6
+
7
+ describe("ast", () => {
8
+ let $rootScope;
9
+ let $parse;
10
+ let logs = [];
11
+
12
+ beforeEach(() => {
13
+ window.angular = new Angular();
14
+ window.angular
15
+ .module("myModule", ["ng"])
16
+ .decorator("$exceptionHandler", function () {
17
+ return (exception, cause) => {
18
+ logs.push(exception);
19
+ console.error(exception, cause);
20
+ };
21
+ });
22
+ let injector = createInjector(["myModule"]);
23
+ $parse = injector.get("$parse");
24
+ $rootScope = injector.get("$rootScope");
25
+ });
26
+
27
+ let createAst;
28
+
29
+ beforeEach(() => {
30
+ /* global AST: false */
31
+ createAst = function () {
32
+ const lexer = new Lexer({});
33
+ const ast = new AST(lexer, {
34
+ csp: false,
35
+ literals: {
36
+ true: true,
37
+ false: false,
38
+ undefined: undefined,
39
+ null: null,
40
+ },
41
+ });
42
+ return ast.ast.apply(ast, arguments);
43
+ };
44
+ });
45
+
46
+ it("should handle an empty list of tokens", () => {
47
+ expect(createAst("")).toEqual({ type: ASTType.Program, body: [] });
48
+ });
49
+
50
+ it("should understand identifiers", () => {
51
+ expect(createAst("foo")).toEqual({
52
+ type: ASTType.Program,
53
+ body: [
54
+ {
55
+ type: ASTType.ExpressionStatement,
56
+ expression: { type: ASTType.Identifier, name: "foo" },
57
+ },
58
+ ],
59
+ });
60
+ });
61
+
62
+ it("should understand non-computed member expressions", () => {
63
+ expect(createAst("foo.bar")).toEqual({
64
+ type: ASTType.Program,
65
+ body: [
66
+ {
67
+ type: ASTType.ExpressionStatement,
68
+ expression: {
69
+ type: ASTType.MemberExpression,
70
+ object: { type: ASTType.Identifier, name: "foo" },
71
+ property: { type: ASTType.Identifier, name: "bar" },
72
+ computed: false,
73
+ },
74
+ },
75
+ ],
76
+ });
77
+ });
78
+
79
+ it("should associate non-computed member expressions left-to-right", () => {
80
+ expect(createAst("foo.bar.baz")).toEqual({
81
+ type: ASTType.Program,
82
+ body: [
83
+ {
84
+ type: ASTType.ExpressionStatement,
85
+ expression: {
86
+ type: ASTType.MemberExpression,
87
+ object: {
88
+ type: ASTType.MemberExpression,
89
+ object: { type: ASTType.Identifier, name: "foo" },
90
+ property: { type: ASTType.Identifier, name: "bar" },
91
+ computed: false,
92
+ },
93
+ property: { type: ASTType.Identifier, name: "baz" },
94
+ computed: false,
95
+ },
96
+ },
97
+ ],
98
+ });
99
+ });
100
+
101
+ it("should understand computed member expressions", () => {
102
+ expect(createAst("foo[bar]")).toEqual({
103
+ type: ASTType.Program,
104
+ body: [
105
+ {
106
+ type: ASTType.ExpressionStatement,
107
+ expression: {
108
+ type: ASTType.MemberExpression,
109
+ object: { type: ASTType.Identifier, name: "foo" },
110
+ property: { type: ASTType.Identifier, name: "bar" },
111
+ computed: true,
112
+ },
113
+ },
114
+ ],
115
+ });
116
+ });
117
+
118
+ it("should associate computed member expressions left-to-right", () => {
119
+ expect(createAst("foo[bar][baz]")).toEqual({
120
+ type: ASTType.Program,
121
+ body: [
122
+ {
123
+ type: ASTType.ExpressionStatement,
124
+ expression: {
125
+ type: ASTType.MemberExpression,
126
+ object: {
127
+ type: ASTType.MemberExpression,
128
+ object: { type: ASTType.Identifier, name: "foo" },
129
+ property: { type: ASTType.Identifier, name: "bar" },
130
+ computed: true,
131
+ },
132
+ property: { type: ASTType.Identifier, name: "baz" },
133
+ computed: true,
134
+ },
135
+ },
136
+ ],
137
+ });
138
+ });
139
+
140
+ it("should understand call expressions", () => {
141
+ expect(createAst("foo()")).toEqual({
142
+ type: ASTType.Program,
143
+ body: [
144
+ {
145
+ type: ASTType.ExpressionStatement,
146
+ expression: {
147
+ type: ASTType.CallExpression,
148
+ callee: { type: ASTType.Identifier, name: "foo" },
149
+ arguments: [],
150
+ },
151
+ },
152
+ ],
153
+ });
154
+ });
155
+
156
+ it("should parse call expression arguments", () => {
157
+ expect(createAst("foo(bar, baz)")).toEqual({
158
+ type: ASTType.Program,
159
+ body: [
160
+ {
161
+ type: ASTType.ExpressionStatement,
162
+ expression: {
163
+ type: ASTType.CallExpression,
164
+ callee: { type: ASTType.Identifier, name: "foo" },
165
+ arguments: [
166
+ { type: ASTType.Identifier, name: "bar" },
167
+ { type: ASTType.Identifier, name: "baz" },
168
+ ],
169
+ },
170
+ },
171
+ ],
172
+ });
173
+ });
174
+
175
+ it("should parse call expression left-to-right", () => {
176
+ expect(createAst("foo(bar, baz)(man, shell)")).toEqual({
177
+ type: ASTType.Program,
178
+ body: [
179
+ {
180
+ type: ASTType.ExpressionStatement,
181
+ expression: {
182
+ type: ASTType.CallExpression,
183
+ callee: {
184
+ type: ASTType.CallExpression,
185
+ callee: { type: ASTType.Identifier, name: "foo" },
186
+ arguments: [
187
+ { type: ASTType.Identifier, name: "bar" },
188
+ { type: ASTType.Identifier, name: "baz" },
189
+ ],
190
+ },
191
+ arguments: [
192
+ { type: ASTType.Identifier, name: "man" },
193
+ { type: ASTType.Identifier, name: "shell" },
194
+ ],
195
+ },
196
+ },
197
+ ],
198
+ });
199
+ });
200
+
201
+ it("should keep the context when having superfluous parenthesis", () => {
202
+ expect(createAst("(foo)(bar, baz)")).toEqual({
203
+ type: ASTType.Program,
204
+ body: [
205
+ {
206
+ type: ASTType.ExpressionStatement,
207
+ expression: {
208
+ type: ASTType.CallExpression,
209
+ callee: { type: ASTType.Identifier, name: "foo" },
210
+ arguments: [
211
+ { type: ASTType.Identifier, name: "bar" },
212
+ { type: ASTType.Identifier, name: "baz" },
213
+ ],
214
+ },
215
+ },
216
+ ],
217
+ });
218
+ });
219
+
220
+ it("should treat member expressions and call expression with the same precedence", () => {
221
+ expect(createAst("foo.bar[baz]()")).toEqual({
222
+ type: ASTType.Program,
223
+ body: [
224
+ {
225
+ type: ASTType.ExpressionStatement,
226
+ expression: {
227
+ type: ASTType.CallExpression,
228
+ callee: {
229
+ type: ASTType.MemberExpression,
230
+ object: {
231
+ type: ASTType.MemberExpression,
232
+ object: { type: ASTType.Identifier, name: "foo" },
233
+ property: { type: ASTType.Identifier, name: "bar" },
234
+ computed: false,
235
+ },
236
+ property: { type: ASTType.Identifier, name: "baz" },
237
+ computed: true,
238
+ },
239
+ arguments: [],
240
+ },
241
+ },
242
+ ],
243
+ });
244
+ expect(createAst("foo[bar]().baz")).toEqual({
245
+ type: ASTType.Program,
246
+ body: [
247
+ {
248
+ type: ASTType.ExpressionStatement,
249
+ expression: {
250
+ type: ASTType.MemberExpression,
251
+ object: {
252
+ type: ASTType.CallExpression,
253
+ callee: {
254
+ type: ASTType.MemberExpression,
255
+ object: { type: ASTType.Identifier, name: "foo" },
256
+ property: { type: ASTType.Identifier, name: "bar" },
257
+ computed: true,
258
+ },
259
+ arguments: [],
260
+ },
261
+ property: { type: ASTType.Identifier, name: "baz" },
262
+ computed: false,
263
+ },
264
+ },
265
+ ],
266
+ });
267
+ expect(createAst("foo().bar[baz]")).toEqual({
268
+ type: ASTType.Program,
269
+ body: [
270
+ {
271
+ type: ASTType.ExpressionStatement,
272
+ expression: {
273
+ type: ASTType.MemberExpression,
274
+ object: {
275
+ type: ASTType.MemberExpression,
276
+ object: {
277
+ type: ASTType.CallExpression,
278
+ callee: { type: ASTType.Identifier, name: "foo" },
279
+ arguments: [],
280
+ },
281
+ property: { type: ASTType.Identifier, name: "bar" },
282
+ computed: false,
283
+ },
284
+ property: { type: ASTType.Identifier, name: "baz" },
285
+ computed: true,
286
+ },
287
+ },
288
+ ],
289
+ });
290
+ });
291
+
292
+ it("should understand literals", () => {
293
+ // In a strict sense, `undefined` is not a literal but an identifier
294
+ Object.entries({
295
+ 123: 123,
296
+ '"123"': "123",
297
+ true: true,
298
+ false: false,
299
+ null: null,
300
+ undefined: undefined,
301
+ }).forEach(([expression, value]) => {
302
+ expect(createAst(expression)).toEqual({
303
+ type: ASTType.Program,
304
+ body: [
305
+ {
306
+ type: ASTType.ExpressionStatement,
307
+ expression: { type: ASTType.Literal, value },
308
+ },
309
+ ],
310
+ });
311
+ });
312
+ });
313
+
314
+ it("should understand the `this` expression", () => {
315
+ expect(createAst("this")).toEqual({
316
+ type: ASTType.Program,
317
+ body: [
318
+ {
319
+ type: ASTType.ExpressionStatement,
320
+ expression: { type: ASTType.ThisExpression },
321
+ },
322
+ ],
323
+ });
324
+ });
325
+
326
+ it("should understand the `$locals` expression", () => {
327
+ expect(createAst("$locals")).toEqual({
328
+ type: ASTType.Program,
329
+ body: [
330
+ {
331
+ type: ASTType.ExpressionStatement,
332
+ expression: { type: ASTType.LocalsExpression },
333
+ },
334
+ ],
335
+ });
336
+ });
337
+
338
+ it("should not confuse `this`, `$locals`, `undefined`, `true`, `false`, `null` when used as identifiers", () => {
339
+ ["this", "$locals", "undefined", "true", "false", "null"].forEach(
340
+ (identifier) => {
341
+ expect(createAst(`foo.${identifier}`)).toEqual({
342
+ type: ASTType.Program,
343
+ body: [
344
+ {
345
+ type: ASTType.ExpressionStatement,
346
+ expression: {
347
+ type: ASTType.MemberExpression,
348
+ object: { type: ASTType.Identifier, name: "foo" },
349
+ property: { type: ASTType.Identifier, name: identifier },
350
+ computed: false,
351
+ },
352
+ },
353
+ ],
354
+ });
355
+ },
356
+ );
357
+ });
358
+
359
+ it("should throw when trying to use non-identifiers as identifiers", () => {
360
+ expect(() => {
361
+ createAst("foo.)");
362
+ }).toThrowError(/syntax/);
363
+ });
364
+
365
+ it("should throw when all tokens are not consumed", () => {
366
+ expect(() => {
367
+ createAst("foo bar");
368
+ }).toThrowError(/syntax/);
369
+ });
370
+
371
+ it("should understand the unary operators `-`, `+` and `!`", () => {
372
+ ["-", "+", "!"].forEach((operator) => {
373
+ expect(createAst(`${operator}foo`)).toEqual({
374
+ type: ASTType.Program,
375
+ body: [
376
+ {
377
+ type: ASTType.ExpressionStatement,
378
+ expression: {
379
+ type: ASTType.UnaryExpression,
380
+ operator,
381
+ prefix: true,
382
+ argument: { type: ASTType.Identifier, name: "foo" },
383
+ },
384
+ },
385
+ ],
386
+ });
387
+ });
388
+ });
389
+
390
+ it("should handle all unary operators with the same precedence", () => {
391
+ [
392
+ ["+", "-", "!"],
393
+ ["-", "!", "+"],
394
+ ["!", "+", "-"],
395
+ ].forEach((operators) => {
396
+ expect(createAst(`${operators.join("")}foo`)).toEqual({
397
+ type: ASTType.Program,
398
+ body: [
399
+ {
400
+ type: ASTType.ExpressionStatement,
401
+ expression: {
402
+ type: ASTType.UnaryExpression,
403
+ operator: operators[0],
404
+ prefix: true,
405
+ argument: {
406
+ type: ASTType.UnaryExpression,
407
+ operator: operators[1],
408
+ prefix: true,
409
+ argument: {
410
+ type: ASTType.UnaryExpression,
411
+ operator: operators[2],
412
+ prefix: true,
413
+ argument: { type: ASTType.Identifier, name: "foo" },
414
+ },
415
+ },
416
+ },
417
+ },
418
+ ],
419
+ });
420
+ });
421
+ });
422
+
423
+ it("should be able to understand binary operators", () => {
424
+ [
425
+ "*",
426
+ "/",
427
+ "%",
428
+ "+",
429
+ "-",
430
+ "<",
431
+ ">",
432
+ "<=",
433
+ ">=",
434
+ "==",
435
+ "!=",
436
+ "===",
437
+ "!==",
438
+ ].forEach((operator) => {
439
+ expect(createAst(`foo${operator}bar`)).toEqual({
440
+ type: ASTType.Program,
441
+ body: [
442
+ {
443
+ type: ASTType.ExpressionStatement,
444
+ expression: {
445
+ type: ASTType.BinaryExpression,
446
+ operator,
447
+ left: { type: ASTType.Identifier, name: "foo" },
448
+ right: { type: ASTType.Identifier, name: "bar" },
449
+ },
450
+ },
451
+ ],
452
+ });
453
+ });
454
+ });
455
+
456
+ it("should associate binary operators with the same precedence left-to-right", () => {
457
+ const operatorsByPrecedence = [
458
+ ["*", "/", "%"],
459
+ ["+", "-"],
460
+ ["<", ">", "<=", ">="],
461
+ ["==", "!=", "===", "!=="],
462
+ ];
463
+ operatorsByPrecedence.forEach((operators) => {
464
+ operators.forEach((op1) => {
465
+ operators.forEach((op2) => {
466
+ expect(createAst(`foo${op1}bar${op2}baz`)).toEqual({
467
+ type: ASTType.Program,
468
+ body: [
469
+ {
470
+ type: ASTType.ExpressionStatement,
471
+ expression: {
472
+ type: ASTType.BinaryExpression,
473
+ operator: op2,
474
+ left: {
475
+ type: ASTType.BinaryExpression,
476
+ operator: op1,
477
+ left: { type: ASTType.Identifier, name: "foo" },
478
+ right: { type: ASTType.Identifier, name: "bar" },
479
+ },
480
+ right: { type: ASTType.Identifier, name: "baz" },
481
+ },
482
+ },
483
+ ],
484
+ });
485
+ });
486
+ });
487
+ });
488
+ });
489
+
490
+ it("should give higher precedence to member calls than to unary expressions", () => {
491
+ ["!", "+", "-"].forEach((operator) => {
492
+ expect(createAst(`${operator}foo()`)).toEqual({
493
+ type: ASTType.Program,
494
+ body: [
495
+ {
496
+ type: ASTType.ExpressionStatement,
497
+ expression: {
498
+ type: ASTType.UnaryExpression,
499
+ operator,
500
+ prefix: true,
501
+ argument: {
502
+ type: ASTType.CallExpression,
503
+ callee: { type: ASTType.Identifier, name: "foo" },
504
+ arguments: [],
505
+ },
506
+ },
507
+ },
508
+ ],
509
+ });
510
+ expect(createAst(`${operator}foo.bar`)).toEqual({
511
+ type: ASTType.Program,
512
+ body: [
513
+ {
514
+ type: ASTType.ExpressionStatement,
515
+ expression: {
516
+ type: ASTType.UnaryExpression,
517
+ operator,
518
+ prefix: true,
519
+ argument: {
520
+ type: ASTType.MemberExpression,
521
+ object: { type: ASTType.Identifier, name: "foo" },
522
+ property: { type: ASTType.Identifier, name: "bar" },
523
+ computed: false,
524
+ },
525
+ },
526
+ },
527
+ ],
528
+ });
529
+ expect(createAst(`${operator}foo[bar]`)).toEqual({
530
+ type: ASTType.Program,
531
+ body: [
532
+ {
533
+ type: ASTType.ExpressionStatement,
534
+ expression: {
535
+ type: ASTType.UnaryExpression,
536
+ operator,
537
+ prefix: true,
538
+ argument: {
539
+ type: ASTType.MemberExpression,
540
+ object: { type: ASTType.Identifier, name: "foo" },
541
+ property: { type: ASTType.Identifier, name: "bar" },
542
+ computed: true,
543
+ },
544
+ },
545
+ },
546
+ ],
547
+ });
548
+ });
549
+ });
550
+
551
+ it("should give higher precedence to unary operators over multiplicative operators", () => {
552
+ ["!", "+", "-"].forEach((op1) => {
553
+ ["*", "/", "%"].forEach((op2) => {
554
+ expect(createAst(`${op1}foo${op2}${op1}bar`)).toEqual({
555
+ type: ASTType.Program,
556
+ body: [
557
+ {
558
+ type: ASTType.ExpressionStatement,
559
+ expression: {
560
+ type: ASTType.BinaryExpression,
561
+ operator: op2,
562
+ left: {
563
+ type: ASTType.UnaryExpression,
564
+ operator: op1,
565
+ prefix: true,
566
+ argument: { type: ASTType.Identifier, name: "foo" },
567
+ },
568
+ right: {
569
+ type: ASTType.UnaryExpression,
570
+ operator: op1,
571
+ prefix: true,
572
+ argument: { type: ASTType.Identifier, name: "bar" },
573
+ },
574
+ },
575
+ },
576
+ ],
577
+ });
578
+ });
579
+ });
580
+ });
581
+
582
+ it("should give binary operators their right precedence", () => {
583
+ const operatorsByPrecedence = [
584
+ ["*", "/", "%"],
585
+ ["+", "-"],
586
+ ["<", ">", "<=", ">="],
587
+ ["==", "!=", "===", "!=="],
588
+ ];
589
+ for (let i = 0; i < operatorsByPrecedence.length - 1; ++i) {
590
+ operatorsByPrecedence[i].forEach((op1) => {
591
+ operatorsByPrecedence[i + 1].forEach((op2) => {
592
+ expect(createAst(`foo${op1}bar${op2}baz${op1}man`)).toEqual({
593
+ type: ASTType.Program,
594
+ body: [
595
+ {
596
+ type: ASTType.ExpressionStatement,
597
+ expression: {
598
+ type: ASTType.BinaryExpression,
599
+ operator: op2,
600
+ left: {
601
+ type: ASTType.BinaryExpression,
602
+ operator: op1,
603
+ left: { type: ASTType.Identifier, name: "foo" },
604
+ right: { type: ASTType.Identifier, name: "bar" },
605
+ },
606
+ right: {
607
+ type: ASTType.BinaryExpression,
608
+ operator: op1,
609
+ left: { type: ASTType.Identifier, name: "baz" },
610
+ right: { type: ASTType.Identifier, name: "man" },
611
+ },
612
+ },
613
+ },
614
+ ],
615
+ });
616
+ });
617
+ });
618
+ }
619
+ });
620
+
621
+ it("should understand logical operators", () => {
622
+ ["||", "&&"].forEach((operator) => {
623
+ expect(createAst(`foo${operator}bar`)).toEqual({
624
+ type: ASTType.Program,
625
+ body: [
626
+ {
627
+ type: ASTType.ExpressionStatement,
628
+ expression: {
629
+ type: ASTType.LogicalExpression,
630
+ operator,
631
+ left: { type: ASTType.Identifier, name: "foo" },
632
+ right: { type: ASTType.Identifier, name: "bar" },
633
+ },
634
+ },
635
+ ],
636
+ });
637
+ });
638
+ });
639
+
640
+ it("should associate logical operators left-to-right", () => {
641
+ ["||", "&&"].forEach((op) => {
642
+ expect(createAst(`foo${op}bar${op}baz`)).toEqual({
643
+ type: ASTType.Program,
644
+ body: [
645
+ {
646
+ type: ASTType.ExpressionStatement,
647
+ expression: {
648
+ type: ASTType.LogicalExpression,
649
+ operator: op,
650
+ left: {
651
+ type: ASTType.LogicalExpression,
652
+ operator: op,
653
+ left: { type: ASTType.Identifier, name: "foo" },
654
+ right: { type: ASTType.Identifier, name: "bar" },
655
+ },
656
+ right: { type: ASTType.Identifier, name: "baz" },
657
+ },
658
+ },
659
+ ],
660
+ });
661
+ });
662
+ });
663
+
664
+ it("should understand ternary operators", () => {
665
+ expect(createAst("foo?bar:baz")).toEqual({
666
+ type: ASTType.Program,
667
+ body: [
668
+ {
669
+ type: ASTType.ExpressionStatement,
670
+ expression: {
671
+ type: ASTType.ConditionalExpression,
672
+ test: { type: ASTType.Identifier, name: "foo" },
673
+ alternate: { type: ASTType.Identifier, name: "bar" },
674
+ consequent: { type: ASTType.Identifier, name: "baz" },
675
+ },
676
+ },
677
+ ],
678
+ });
679
+ });
680
+
681
+ it("should associate the conditional operator right-to-left", () => {
682
+ expect(createAst("foo0?foo1:foo2?bar0?bar1:bar2:man0?man1:man2")).toEqual({
683
+ type: ASTType.Program,
684
+ body: [
685
+ {
686
+ type: ASTType.ExpressionStatement,
687
+ expression: {
688
+ type: ASTType.ConditionalExpression,
689
+ test: { type: ASTType.Identifier, name: "foo0" },
690
+ alternate: { type: ASTType.Identifier, name: "foo1" },
691
+ consequent: {
692
+ type: ASTType.ConditionalExpression,
693
+ test: { type: ASTType.Identifier, name: "foo2" },
694
+ alternate: {
695
+ type: ASTType.ConditionalExpression,
696
+ test: { type: ASTType.Identifier, name: "bar0" },
697
+ alternate: { type: ASTType.Identifier, name: "bar1" },
698
+ consequent: { type: ASTType.Identifier, name: "bar2" },
699
+ },
700
+ consequent: {
701
+ type: ASTType.ConditionalExpression,
702
+ test: { type: ASTType.Identifier, name: "man0" },
703
+ alternate: { type: ASTType.Identifier, name: "man1" },
704
+ consequent: { type: ASTType.Identifier, name: "man2" },
705
+ },
706
+ },
707
+ },
708
+ },
709
+ ],
710
+ });
711
+ });
712
+
713
+ it("should understand assignment operator", () => {
714
+ // Currently, only `=` is supported
715
+ expect(createAst("foo=bar")).toEqual({
716
+ type: ASTType.Program,
717
+ body: [
718
+ {
719
+ type: ASTType.ExpressionStatement,
720
+ expression: {
721
+ type: ASTType.AssignmentExpression,
722
+ left: { type: ASTType.Identifier, name: "foo" },
723
+ right: { type: ASTType.Identifier, name: "bar" },
724
+ operator: "=",
725
+ },
726
+ },
727
+ ],
728
+ });
729
+ });
730
+
731
+ it("should associate assignments right-to-left", () => {
732
+ // Currently, only `=` is supported
733
+ expect(createAst("foo=bar=man")).toEqual({
734
+ type: ASTType.Program,
735
+ body: [
736
+ {
737
+ type: ASTType.ExpressionStatement,
738
+ expression: {
739
+ type: ASTType.AssignmentExpression,
740
+ left: { type: ASTType.Identifier, name: "foo" },
741
+ right: {
742
+ type: ASTType.AssignmentExpression,
743
+ left: { type: ASTType.Identifier, name: "bar" },
744
+ right: { type: ASTType.Identifier, name: "man" },
745
+ operator: "=",
746
+ },
747
+ operator: "=",
748
+ },
749
+ },
750
+ ],
751
+ });
752
+ });
753
+
754
+ it("should give higher precedence to equality than to the logical `and` operator", () => {
755
+ ["==", "!=", "===", "!=="].forEach((operator) => {
756
+ expect(createAst(`foo${operator}bar && man${operator}shell`)).toEqual({
757
+ type: ASTType.Program,
758
+ body: [
759
+ {
760
+ type: ASTType.ExpressionStatement,
761
+ expression: {
762
+ type: ASTType.LogicalExpression,
763
+ operator: "&&",
764
+ left: {
765
+ type: ASTType.BinaryExpression,
766
+ operator,
767
+ left: { type: ASTType.Identifier, name: "foo" },
768
+ right: { type: ASTType.Identifier, name: "bar" },
769
+ },
770
+ right: {
771
+ type: ASTType.BinaryExpression,
772
+ operator,
773
+ left: { type: ASTType.Identifier, name: "man" },
774
+ right: { type: ASTType.Identifier, name: "shell" },
775
+ },
776
+ },
777
+ },
778
+ ],
779
+ });
780
+ });
781
+ });
782
+
783
+ it("should give higher precedence to logical `and` than to logical `or`", () => {
784
+ expect(createAst("foo&&bar||man&&shell")).toEqual({
785
+ type: ASTType.Program,
786
+ body: [
787
+ {
788
+ type: ASTType.ExpressionStatement,
789
+ expression: {
790
+ type: ASTType.LogicalExpression,
791
+ operator: "||",
792
+ left: {
793
+ type: ASTType.LogicalExpression,
794
+ operator: "&&",
795
+ left: { type: ASTType.Identifier, name: "foo" },
796
+ right: { type: ASTType.Identifier, name: "bar" },
797
+ },
798
+ right: {
799
+ type: ASTType.LogicalExpression,
800
+ operator: "&&",
801
+ left: { type: ASTType.Identifier, name: "man" },
802
+ right: { type: ASTType.Identifier, name: "shell" },
803
+ },
804
+ },
805
+ },
806
+ ],
807
+ });
808
+ });
809
+
810
+ it("should give higher precedence to the logical `or` than to the conditional operator", () => {
811
+ expect(createAst("foo||bar?man:shell")).toEqual({
812
+ type: ASTType.Program,
813
+ body: [
814
+ {
815
+ type: ASTType.ExpressionStatement,
816
+ expression: {
817
+ type: ASTType.ConditionalExpression,
818
+ test: {
819
+ type: ASTType.LogicalExpression,
820
+ operator: "||",
821
+ left: { type: ASTType.Identifier, name: "foo" },
822
+ right: { type: ASTType.Identifier, name: "bar" },
823
+ },
824
+ alternate: { type: ASTType.Identifier, name: "man" },
825
+ consequent: { type: ASTType.Identifier, name: "shell" },
826
+ },
827
+ },
828
+ ],
829
+ });
830
+ });
831
+
832
+ it("should give higher precedence to the conditional operator than to assignment operators", () => {
833
+ expect(createAst("foo=bar?man:shell")).toEqual({
834
+ type: ASTType.Program,
835
+ body: [
836
+ {
837
+ type: ASTType.ExpressionStatement,
838
+ expression: {
839
+ type: ASTType.AssignmentExpression,
840
+ left: { type: ASTType.Identifier, name: "foo" },
841
+ right: {
842
+ type: ASTType.ConditionalExpression,
843
+ test: { type: ASTType.Identifier, name: "bar" },
844
+ alternate: { type: ASTType.Identifier, name: "man" },
845
+ consequent: { type: ASTType.Identifier, name: "shell" },
846
+ },
847
+ operator: "=",
848
+ },
849
+ },
850
+ ],
851
+ });
852
+ });
853
+
854
+ it("should understand array literals", () => {
855
+ expect(createAst("[]")).toEqual({
856
+ type: ASTType.Program,
857
+ body: [
858
+ {
859
+ type: ASTType.ExpressionStatement,
860
+ expression: {
861
+ type: ASTType.ArrayExpression,
862
+ elements: [],
863
+ },
864
+ },
865
+ ],
866
+ });
867
+ expect(createAst("[foo]")).toEqual({
868
+ type: ASTType.Program,
869
+ body: [
870
+ {
871
+ type: ASTType.ExpressionStatement,
872
+ expression: {
873
+ type: ASTType.ArrayExpression,
874
+ elements: [{ type: ASTType.Identifier, name: "foo" }],
875
+ },
876
+ },
877
+ ],
878
+ });
879
+ expect(createAst("[foo,]")).toEqual({
880
+ type: ASTType.Program,
881
+ body: [
882
+ {
883
+ type: ASTType.ExpressionStatement,
884
+ expression: {
885
+ type: ASTType.ArrayExpression,
886
+ elements: [{ type: ASTType.Identifier, name: "foo" }],
887
+ },
888
+ },
889
+ ],
890
+ });
891
+ expect(createAst("[foo,bar,man,shell]")).toEqual({
892
+ type: ASTType.Program,
893
+ body: [
894
+ {
895
+ type: ASTType.ExpressionStatement,
896
+ expression: {
897
+ type: ASTType.ArrayExpression,
898
+ elements: [
899
+ { type: ASTType.Identifier, name: "foo" },
900
+ { type: ASTType.Identifier, name: "bar" },
901
+ { type: ASTType.Identifier, name: "man" },
902
+ { type: ASTType.Identifier, name: "shell" },
903
+ ],
904
+ },
905
+ },
906
+ ],
907
+ });
908
+ expect(createAst("[foo,bar,man,shell,]")).toEqual({
909
+ type: ASTType.Program,
910
+ body: [
911
+ {
912
+ type: ASTType.ExpressionStatement,
913
+ expression: {
914
+ type: ASTType.ArrayExpression,
915
+ elements: [
916
+ { type: ASTType.Identifier, name: "foo" },
917
+ { type: ASTType.Identifier, name: "bar" },
918
+ { type: ASTType.Identifier, name: "man" },
919
+ { type: ASTType.Identifier, name: "shell" },
920
+ ],
921
+ },
922
+ },
923
+ ],
924
+ });
925
+ });
926
+
927
+ it("should understand objects", () => {
928
+ expect(createAst("{}")).toEqual({
929
+ type: ASTType.Program,
930
+ body: [
931
+ {
932
+ type: ASTType.ExpressionStatement,
933
+ expression: {
934
+ type: ASTType.ObjectExpression,
935
+ properties: [],
936
+ },
937
+ },
938
+ ],
939
+ });
940
+ expect(createAst("{foo: bar}")).toEqual({
941
+ type: ASTType.Program,
942
+ body: [
943
+ {
944
+ type: ASTType.ExpressionStatement,
945
+ expression: {
946
+ type: ASTType.ObjectExpression,
947
+ properties: [
948
+ {
949
+ type: ASTType.Property,
950
+ kind: "init",
951
+ key: { type: ASTType.Identifier, name: "foo" },
952
+ computed: false,
953
+ value: { type: ASTType.Identifier, name: "bar" },
954
+ },
955
+ ],
956
+ },
957
+ },
958
+ ],
959
+ });
960
+ expect(createAst("{foo: bar,}")).toEqual({
961
+ type: ASTType.Program,
962
+ body: [
963
+ {
964
+ type: ASTType.ExpressionStatement,
965
+ expression: {
966
+ type: ASTType.ObjectExpression,
967
+ properties: [
968
+ {
969
+ type: ASTType.Property,
970
+ kind: "init",
971
+ key: { type: ASTType.Identifier, name: "foo" },
972
+ computed: false,
973
+ value: { type: ASTType.Identifier, name: "bar" },
974
+ },
975
+ ],
976
+ },
977
+ },
978
+ ],
979
+ });
980
+ expect(createAst('{foo: bar, "man": "shell", 42: 23}')).toEqual({
981
+ type: ASTType.Program,
982
+ body: [
983
+ {
984
+ type: ASTType.ExpressionStatement,
985
+ expression: {
986
+ type: ASTType.ObjectExpression,
987
+ properties: [
988
+ {
989
+ type: ASTType.Property,
990
+ kind: "init",
991
+ key: { type: ASTType.Identifier, name: "foo" },
992
+ computed: false,
993
+ value: { type: ASTType.Identifier, name: "bar" },
994
+ },
995
+ {
996
+ type: ASTType.Property,
997
+ kind: "init",
998
+ key: { type: ASTType.Literal, value: "man" },
999
+ computed: false,
1000
+ value: { type: ASTType.Literal, value: "shell" },
1001
+ },
1002
+ {
1003
+ type: ASTType.Property,
1004
+ kind: "init",
1005
+ key: { type: ASTType.Literal, value: 42 },
1006
+ computed: false,
1007
+ value: { type: ASTType.Literal, value: 23 },
1008
+ },
1009
+ ],
1010
+ },
1011
+ },
1012
+ ],
1013
+ });
1014
+ expect(createAst('{foo: bar, "man": "shell", 42: 23,}')).toEqual({
1015
+ type: ASTType.Program,
1016
+ body: [
1017
+ {
1018
+ type: ASTType.ExpressionStatement,
1019
+ expression: {
1020
+ type: ASTType.ObjectExpression,
1021
+ properties: [
1022
+ {
1023
+ type: ASTType.Property,
1024
+ kind: "init",
1025
+ key: { type: ASTType.Identifier, name: "foo" },
1026
+ computed: false,
1027
+ value: { type: ASTType.Identifier, name: "bar" },
1028
+ },
1029
+ {
1030
+ type: ASTType.Property,
1031
+ kind: "init",
1032
+ key: { type: ASTType.Literal, value: "man" },
1033
+ computed: false,
1034
+ value: { type: ASTType.Literal, value: "shell" },
1035
+ },
1036
+ {
1037
+ type: ASTType.Property,
1038
+ kind: "init",
1039
+ key: { type: ASTType.Literal, value: 42 },
1040
+ computed: false,
1041
+ value: { type: ASTType.Literal, value: 23 },
1042
+ },
1043
+ ],
1044
+ },
1045
+ },
1046
+ ],
1047
+ });
1048
+ });
1049
+
1050
+ it("should understand ES6 object initializer", () => {
1051
+ // Shorthand properties definitions.
1052
+ expect(createAst("{x, y, z}")).toEqual({
1053
+ type: ASTType.Program,
1054
+ body: [
1055
+ {
1056
+ type: ASTType.ExpressionStatement,
1057
+ expression: {
1058
+ type: ASTType.ObjectExpression,
1059
+ properties: [
1060
+ {
1061
+ type: ASTType.Property,
1062
+ kind: "init",
1063
+ key: { type: ASTType.Identifier, name: "x" },
1064
+ computed: false,
1065
+ value: { type: ASTType.Identifier, name: "x" },
1066
+ },
1067
+ {
1068
+ type: ASTType.Property,
1069
+ kind: "init",
1070
+ key: { type: ASTType.Identifier, name: "y" },
1071
+ computed: false,
1072
+ value: { type: ASTType.Identifier, name: "y" },
1073
+ },
1074
+ {
1075
+ type: ASTType.Property,
1076
+ kind: "init",
1077
+ key: { type: ASTType.Identifier, name: "z" },
1078
+ computed: false,
1079
+ value: { type: ASTType.Identifier, name: "z" },
1080
+ },
1081
+ ],
1082
+ },
1083
+ },
1084
+ ],
1085
+ });
1086
+ expect(() => {
1087
+ createAst('{"foo"}');
1088
+ }).toThrow();
1089
+
1090
+ // Computed properties
1091
+ expect(createAst("{[x]: x}")).toEqual({
1092
+ type: ASTType.Program,
1093
+ body: [
1094
+ {
1095
+ type: ASTType.ExpressionStatement,
1096
+ expression: {
1097
+ type: ASTType.ObjectExpression,
1098
+ properties: [
1099
+ {
1100
+ type: ASTType.Property,
1101
+ kind: "init",
1102
+ key: { type: ASTType.Identifier, name: "x" },
1103
+ computed: true,
1104
+ value: { type: ASTType.Identifier, name: "x" },
1105
+ },
1106
+ ],
1107
+ },
1108
+ },
1109
+ ],
1110
+ });
1111
+ expect(createAst("{[x + 1]: x}")).toEqual({
1112
+ type: ASTType.Program,
1113
+ body: [
1114
+ {
1115
+ type: ASTType.ExpressionStatement,
1116
+ expression: {
1117
+ type: ASTType.ObjectExpression,
1118
+ properties: [
1119
+ {
1120
+ type: ASTType.Property,
1121
+ kind: "init",
1122
+ key: {
1123
+ type: ASTType.BinaryExpression,
1124
+ operator: "+",
1125
+ left: { type: ASTType.Identifier, name: "x" },
1126
+ right: { type: ASTType.Literal, value: 1 },
1127
+ },
1128
+ computed: true,
1129
+ value: { type: ASTType.Identifier, name: "x" },
1130
+ },
1131
+ ],
1132
+ },
1133
+ },
1134
+ ],
1135
+ });
1136
+ });
1137
+
1138
+ it("should understand multiple expressions", () => {
1139
+ expect(createAst("foo = bar; man = shell")).toEqual({
1140
+ type: ASTType.Program,
1141
+ body: [
1142
+ {
1143
+ type: ASTType.ExpressionStatement,
1144
+ expression: {
1145
+ type: ASTType.AssignmentExpression,
1146
+ left: { type: ASTType.Identifier, name: "foo" },
1147
+ right: { type: ASTType.Identifier, name: "bar" },
1148
+ operator: "=",
1149
+ },
1150
+ },
1151
+ {
1152
+ type: ASTType.ExpressionStatement,
1153
+ expression: {
1154
+ type: ASTType.AssignmentExpression,
1155
+ left: { type: ASTType.Identifier, name: "man" },
1156
+ right: { type: ASTType.Identifier, name: "shell" },
1157
+ operator: "=",
1158
+ },
1159
+ },
1160
+ ],
1161
+ });
1162
+ });
1163
+
1164
+ // This is non-standard syntax
1165
+ it("should understand filters", () => {
1166
+ expect(createAst("foo | bar")).toEqual({
1167
+ type: ASTType.Program,
1168
+ body: [
1169
+ {
1170
+ type: ASTType.ExpressionStatement,
1171
+ expression: {
1172
+ type: ASTType.CallExpression,
1173
+ callee: { type: ASTType.Identifier, name: "bar" },
1174
+ arguments: [{ type: ASTType.Identifier, name: "foo" }],
1175
+ filter: true,
1176
+ },
1177
+ },
1178
+ ],
1179
+ });
1180
+ });
1181
+
1182
+ it("should understand filters with extra parameters", () => {
1183
+ expect(createAst("foo | bar:baz")).toEqual({
1184
+ type: ASTType.Program,
1185
+ body: [
1186
+ {
1187
+ type: ASTType.ExpressionStatement,
1188
+ expression: {
1189
+ type: ASTType.CallExpression,
1190
+ callee: { type: ASTType.Identifier, name: "bar" },
1191
+ arguments: [
1192
+ { type: ASTType.Identifier, name: "foo" },
1193
+ { type: ASTType.Identifier, name: "baz" },
1194
+ ],
1195
+ filter: true,
1196
+ },
1197
+ },
1198
+ ],
1199
+ });
1200
+ });
1201
+
1202
+ it("should associate filters right-to-left", () => {
1203
+ expect(createAst("foo | bar:man | shell")).toEqual({
1204
+ type: ASTType.Program,
1205
+ body: [
1206
+ {
1207
+ type: ASTType.ExpressionStatement,
1208
+ expression: {
1209
+ type: ASTType.CallExpression,
1210
+ callee: { type: ASTType.Identifier, name: "shell" },
1211
+ arguments: [
1212
+ {
1213
+ type: ASTType.CallExpression,
1214
+ callee: { type: ASTType.Identifier, name: "bar" },
1215
+ arguments: [
1216
+ { type: ASTType.Identifier, name: "foo" },
1217
+ { type: ASTType.Identifier, name: "man" },
1218
+ ],
1219
+ filter: true,
1220
+ },
1221
+ ],
1222
+ filter: true,
1223
+ },
1224
+ },
1225
+ ],
1226
+ });
1227
+ });
1228
+
1229
+ it("should give higher precedence to assignments over filters", () => {
1230
+ expect(createAst("foo=bar | man")).toEqual({
1231
+ type: ASTType.Program,
1232
+ body: [
1233
+ {
1234
+ type: ASTType.ExpressionStatement,
1235
+ expression: {
1236
+ type: ASTType.CallExpression,
1237
+ callee: { type: ASTType.Identifier, name: "man" },
1238
+ arguments: [
1239
+ {
1240
+ type: ASTType.AssignmentExpression,
1241
+ left: { type: ASTType.Identifier, name: "foo" },
1242
+ right: { type: ASTType.Identifier, name: "bar" },
1243
+ operator: "=",
1244
+ },
1245
+ ],
1246
+ filter: true,
1247
+ },
1248
+ },
1249
+ ],
1250
+ });
1251
+ });
1252
+
1253
+ it("should accept expression as filters parameters", () => {
1254
+ expect(createAst("foo | bar:baz=man")).toEqual({
1255
+ type: ASTType.Program,
1256
+ body: [
1257
+ {
1258
+ type: ASTType.ExpressionStatement,
1259
+ expression: {
1260
+ type: ASTType.CallExpression,
1261
+ callee: { type: ASTType.Identifier, name: "bar" },
1262
+ arguments: [
1263
+ { type: ASTType.Identifier, name: "foo" },
1264
+ {
1265
+ type: ASTType.AssignmentExpression,
1266
+ left: { type: ASTType.Identifier, name: "baz" },
1267
+ right: { type: ASTType.Identifier, name: "man" },
1268
+ operator: "=",
1269
+ },
1270
+ ],
1271
+ filter: true,
1272
+ },
1273
+ },
1274
+ ],
1275
+ });
1276
+ });
1277
+
1278
+ it("should accept expression as computer members", () => {
1279
+ expect(createAst("foo[a = 1]")).toEqual({
1280
+ type: ASTType.Program,
1281
+ body: [
1282
+ {
1283
+ type: ASTType.ExpressionStatement,
1284
+ expression: {
1285
+ type: ASTType.MemberExpression,
1286
+ object: { type: ASTType.Identifier, name: "foo" },
1287
+ property: {
1288
+ type: ASTType.AssignmentExpression,
1289
+ left: { type: ASTType.Identifier, name: "a" },
1290
+ right: { type: ASTType.Literal, value: 1 },
1291
+ operator: "=",
1292
+ },
1293
+ computed: true,
1294
+ },
1295
+ },
1296
+ ],
1297
+ });
1298
+ });
1299
+
1300
+ it("should accept expression in function arguments", () => {
1301
+ expect(createAst("foo(a = 1)")).toEqual({
1302
+ type: ASTType.Program,
1303
+ body: [
1304
+ {
1305
+ type: ASTType.ExpressionStatement,
1306
+ expression: {
1307
+ type: ASTType.CallExpression,
1308
+ callee: { type: ASTType.Identifier, name: "foo" },
1309
+ arguments: [
1310
+ {
1311
+ type: ASTType.AssignmentExpression,
1312
+ left: { type: ASTType.Identifier, name: "a" },
1313
+ right: { type: ASTType.Literal, value: 1 },
1314
+ operator: "=",
1315
+ },
1316
+ ],
1317
+ },
1318
+ },
1319
+ ],
1320
+ });
1321
+ });
1322
+
1323
+ it("should accept expression as part of ternary operators", () => {
1324
+ expect(createAst("foo || bar ? man = 1 : shell = 1")).toEqual({
1325
+ type: ASTType.Program,
1326
+ body: [
1327
+ {
1328
+ type: ASTType.ExpressionStatement,
1329
+ expression: {
1330
+ type: ASTType.ConditionalExpression,
1331
+ test: {
1332
+ type: ASTType.LogicalExpression,
1333
+ operator: "||",
1334
+ left: { type: ASTType.Identifier, name: "foo" },
1335
+ right: { type: ASTType.Identifier, name: "bar" },
1336
+ },
1337
+ alternate: {
1338
+ type: ASTType.AssignmentExpression,
1339
+ left: { type: ASTType.Identifier, name: "man" },
1340
+ right: { type: ASTType.Literal, value: 1 },
1341
+ operator: "=",
1342
+ },
1343
+ consequent: {
1344
+ type: ASTType.AssignmentExpression,
1345
+ left: { type: ASTType.Identifier, name: "shell" },
1346
+ right: { type: ASTType.Literal, value: 1 },
1347
+ operator: "=",
1348
+ },
1349
+ },
1350
+ },
1351
+ ],
1352
+ });
1353
+ });
1354
+
1355
+ it("should accept expression as part of array literals", () => {
1356
+ expect(createAst("[foo = 1]")).toEqual({
1357
+ type: ASTType.Program,
1358
+ body: [
1359
+ {
1360
+ type: ASTType.ExpressionStatement,
1361
+ expression: {
1362
+ type: ASTType.ArrayExpression,
1363
+ elements: [
1364
+ {
1365
+ type: ASTType.AssignmentExpression,
1366
+ left: { type: ASTType.Identifier, name: "foo" },
1367
+ right: { type: ASTType.Literal, value: 1 },
1368
+ operator: "=",
1369
+ },
1370
+ ],
1371
+ },
1372
+ },
1373
+ ],
1374
+ });
1375
+ });
1376
+
1377
+ it("should accept expression as part of object literals", () => {
1378
+ expect(createAst("{foo: bar = 1}")).toEqual({
1379
+ type: ASTType.Program,
1380
+ body: [
1381
+ {
1382
+ type: ASTType.ExpressionStatement,
1383
+ expression: {
1384
+ type: ASTType.ObjectExpression,
1385
+ properties: [
1386
+ {
1387
+ type: ASTType.Property,
1388
+ kind: "init",
1389
+ key: { type: ASTType.Identifier, name: "foo" },
1390
+ computed: false,
1391
+ value: {
1392
+ type: ASTType.AssignmentExpression,
1393
+ left: { type: ASTType.Identifier, name: "bar" },
1394
+ right: { type: ASTType.Literal, value: 1 },
1395
+ operator: "=",
1396
+ },
1397
+ },
1398
+ ],
1399
+ },
1400
+ },
1401
+ ],
1402
+ });
1403
+ });
1404
+
1405
+ it("should be possible to use parenthesis to indicate precedence", () => {
1406
+ expect(createAst("(foo + bar).man")).toEqual({
1407
+ type: ASTType.Program,
1408
+ body: [
1409
+ {
1410
+ type: ASTType.ExpressionStatement,
1411
+ expression: {
1412
+ type: ASTType.MemberExpression,
1413
+ object: {
1414
+ type: ASTType.BinaryExpression,
1415
+ operator: "+",
1416
+ left: { type: ASTType.Identifier, name: "foo" },
1417
+ right: { type: ASTType.Identifier, name: "bar" },
1418
+ },
1419
+ property: { type: ASTType.Identifier, name: "man" },
1420
+ computed: false,
1421
+ },
1422
+ },
1423
+ ],
1424
+ });
1425
+ });
1426
+
1427
+ it("should skip empty expressions", () => {
1428
+ expect(createAst("foo;;;;bar")).toEqual({
1429
+ type: ASTType.Program,
1430
+ body: [
1431
+ {
1432
+ type: ASTType.ExpressionStatement,
1433
+ expression: { type: ASTType.Identifier, name: "foo" },
1434
+ },
1435
+ {
1436
+ type: ASTType.ExpressionStatement,
1437
+ expression: { type: ASTType.Identifier, name: "bar" },
1438
+ },
1439
+ ],
1440
+ });
1441
+ expect(createAst(";foo")).toEqual({
1442
+ type: ASTType.Program,
1443
+ body: [
1444
+ {
1445
+ type: ASTType.ExpressionStatement,
1446
+ expression: { type: ASTType.Identifier, name: "foo" },
1447
+ },
1448
+ ],
1449
+ });
1450
+ expect(createAst("foo;")).toEqual({
1451
+ type: ASTType.Program,
1452
+ body: [
1453
+ {
1454
+ type: ASTType.ExpressionStatement,
1455
+ expression: { type: ASTType.Identifier, name: "foo" },
1456
+ },
1457
+ ],
1458
+ });
1459
+ expect(createAst(";;;;")).toEqual({ type: ASTType.Program, body: [] });
1460
+ expect(createAst("")).toEqual({ type: ASTType.Program, body: [] });
1461
+ });
1462
+ });