@angular-wave/angular.ts 0.4.0 → 0.4.2

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