@angular-wave/angular.ts 0.0.46 → 0.0.48

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 (60) 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/angular.spec.js +1 -2
  5. package/src/animations/animate-css-driver.js +1 -1
  6. package/src/animations/animate-queue.js +3 -4
  7. package/src/animations/animation.js +1 -1
  8. package/src/animations/raf-scheduler.js +0 -1
  9. package/src/animations/shared.js +1 -1
  10. package/src/core/animate/animate.js +0 -1
  11. package/src/core/compile/compile.spec.js +1 -1
  12. package/src/core/filter/filter.js +2 -2
  13. package/src/core/location/location.js +1 -1
  14. package/src/core/location/location.spec.js +1 -1
  15. package/src/core/parser/ast-type.js +22 -0
  16. package/src/core/parser/ast.js +422 -0
  17. package/src/core/parser/compiler.js +561 -0
  18. package/src/core/parser/interpreter.js +422 -0
  19. package/src/core/parser/lexer.js +257 -0
  20. package/src/core/parser/parse.js +9 -1930
  21. package/src/core/parser/parse.spec.js +2 -2
  22. package/src/core/parser/parser.js +39 -0
  23. package/src/core/parser/shared.js +228 -0
  24. package/src/core/q/q.spec.js +0 -1
  25. package/src/core/sce/sce.js +3 -6
  26. package/src/core/scope/scope.js +19 -11
  27. package/src/core/task-tracker-factory.js +0 -1
  28. package/src/directive/attrs/attrs.js +4 -185
  29. package/src/directive/attrs/attrs.md +224 -0
  30. package/src/directive/class/class.js +0 -2
  31. package/src/directive/form/form.js +0 -3
  32. package/src/directive/include/include.js +1 -1
  33. package/src/directive/include/include.spec.js +0 -1
  34. package/src/directive/input/input.js +1 -2
  35. package/src/directive/model/model.js +1 -3
  36. package/src/directive/model/model.spec.js +0 -1
  37. package/src/directive/repeat/repeat.spec.js +0 -2
  38. package/src/exts/aria/aria.js +0 -1
  39. package/src/filters/filter.spec.js +0 -1
  40. package/src/injector.js +1 -1
  41. package/src/injector.spec.js +0 -5
  42. package/src/loader.js +0 -5
  43. package/src/services/cookie-reader.js +0 -1
  44. package/src/services/http/http.spec.js +0 -2
  45. package/src/shared/jqlite/jqlite.js +219 -140
  46. package/src/shared/utils.js +18 -7
  47. package/src/types.js +10 -0
  48. package/types/core/parser/ast-type.d.ts +20 -0
  49. package/types/core/parser/ast.d.ts +78 -0
  50. package/types/core/parser/compiler.d.ts +49 -0
  51. package/types/core/parser/interpreter.d.ts +57 -0
  52. package/types/core/parser/parse.d.ts +79 -0
  53. package/types/core/parser/parser.d.ts +22 -0
  54. package/types/core/parser/shared.d.ts +29 -0
  55. package/types/core/scope/scope.d.ts +9 -2
  56. package/types/directive/attrs/attrs.d.ts +0 -174
  57. package/types/shared/jqlite/jqlite.d.ts +33 -4
  58. package/types/shared/utils.d.ts +18 -5
  59. package/types/types.d.ts +1 -0
  60. package/types-back/index.d.ts +0 -12
@@ -4,1935 +4,18 @@ import {
4
4
  isDefined,
5
5
  isFunction,
6
6
  minErr,
7
- isString,
8
- isNumber,
9
7
  } from "../../shared/utils";
8
+ import { getValueOf, PURITY_RELATIVE } from "./shared";
9
+ import { Lexer } from "./lexer";
10
+ import { Parser } from "./parser";
10
11
 
11
- const $parseMinErr = minErr("$parse");
12
+ export const $parseMinErr = minErr("$parse");
12
13
 
13
- const objectValueOf = {}.constructor.prototype.valueOf;
14
-
15
- /**
16
- * Converts parameter to strings property name for use as keys in an object.
17
- * Any non-string object, including a number, is typecasted into a string via the toString method.
18
- * {@link https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names}
19
- *
20
- * @param {!any} name
21
- * @returns {string}
22
- */
23
- function getStringValue(name) {
24
- return `${name}`;
25
- }
26
-
27
- const OPERATORS = Object.create(null);
28
-
29
- "+ - * / % === !== == != < > <= >= && || ! = |"
30
- .split(" ")
31
- .forEach((operator) => (OPERATORS[operator] = true));
32
-
33
- const ESCAPE = {
34
- n: "\n",
35
- f: "\f",
36
- r: "\r",
37
- t: "\t",
38
- v: "\v",
39
- "'": "'",
40
- '"': '"',
41
- };
42
-
43
- /// //////////////////////////////////////
44
-
45
- /**
46
- * @constructor
47
- */
48
- export const Lexer = function Lexer(options) {
49
- this.options = options;
50
- };
51
-
52
- Lexer.prototype = {
53
- constructor: Lexer,
54
-
55
- lex(text) {
56
- this.text = text;
57
- this.index = 0;
58
- this.tokens = [];
59
-
60
- while (this.index < this.text.length) {
61
- const ch = this.text.charAt(this.index);
62
- if (ch === '"' || ch === "'") {
63
- this.readString(ch);
64
- } else if (
65
- this.isNumber(ch) ||
66
- (ch === "." && this.isNumber(this.peek()))
67
- ) {
68
- this.readNumber();
69
- } else if (this.isIdentifierStart(this.peekMultichar())) {
70
- this.readIdent();
71
- } else if (this.is(ch, "(){}[].,;:?")) {
72
- this.tokens.push({ index: this.index, text: ch });
73
- this.index++;
74
- } else if (this.isWhitespace(ch)) {
75
- this.index++;
76
- } else {
77
- const ch2 = ch + this.peek();
78
- const ch3 = ch2 + this.peek(2);
79
- const op1 = OPERATORS[ch];
80
- const op2 = OPERATORS[ch2];
81
- const op3 = OPERATORS[ch3];
82
- if (op1 || op2 || op3) {
83
- const token = op3 ? ch3 : op2 ? ch2 : ch;
84
- this.tokens.push({ index: this.index, text: token, operator: true });
85
- this.index += token.length;
86
- } else {
87
- this.throwError(
88
- "Unexpected next character ",
89
- this.index,
90
- this.index + 1,
91
- );
92
- }
93
- }
94
- }
95
- return this.tokens;
96
- },
97
-
98
- is(ch, chars) {
99
- return chars.indexOf(ch) !== -1;
100
- },
101
-
102
- peek(i) {
103
- const num = i || 1;
104
- return this.index + num < this.text.length
105
- ? this.text.charAt(this.index + num)
106
- : false;
107
- },
108
-
109
- isNumber(ch) {
110
- return ch >= "0" && ch <= "9" && typeof ch === "string";
111
- },
112
-
113
- isWhitespace(ch) {
114
- // IE treats non-breaking space as \u00A0
115
- return (
116
- ch === " " ||
117
- ch === "\r" ||
118
- ch === "\t" ||
119
- ch === "\n" ||
120
- ch === "\v" ||
121
- ch === "\u00A0"
122
- );
123
- },
124
-
125
- isIdentifierStart(ch) {
126
- return this.options.isIdentifierStart
127
- ? this.options.isIdentifierStart(ch, this.codePointAt(ch))
128
- : this.isValidIdentifierStart(ch);
129
- },
130
-
131
- isValidIdentifierStart(ch) {
132
- return (
133
- (ch >= "a" && ch <= "z") ||
134
- (ch >= "A" && ch <= "Z") ||
135
- ch === "_" ||
136
- ch === "$"
137
- );
138
- },
139
-
140
- isIdentifierContinue(ch) {
141
- return this.options.isIdentifierContinue
142
- ? this.options.isIdentifierContinue(ch, this.codePointAt(ch))
143
- : this.isValidIdentifierContinue(ch);
144
- },
145
-
146
- isValidIdentifierContinue(ch) {
147
- return this.isValidIdentifierStart(ch) || this.isNumber(ch);
148
- },
149
-
150
- codePointAt(ch) {
151
- if (ch.length === 1) return ch.charCodeAt(0);
152
- // eslint-disable-next-line no-bitwise
153
- return (ch.charCodeAt(0) << 10) + ch.charCodeAt(1) - 0x35fdc00;
154
- },
155
-
156
- peekMultichar() {
157
- const ch = this.text.charAt(this.index);
158
- const peek = this.peek();
159
- if (!peek) {
160
- return ch;
161
- }
162
- const cp1 = ch.charCodeAt(0);
163
- const cp2 = peek.charCodeAt(0);
164
- if (cp1 >= 0xd800 && cp1 <= 0xdbff && cp2 >= 0xdc00 && cp2 <= 0xdfff) {
165
- return ch + peek;
166
- }
167
- return ch;
168
- },
169
-
170
- isExpOperator(ch) {
171
- return ch === "-" || ch === "+" || this.isNumber(ch);
172
- },
173
-
174
- throwError(error, start, end) {
175
- end = end || this.index;
176
- const colStr = isDefined(start)
177
- ? `s ${start}-${this.index} [${this.text.substring(start, end)}]`
178
- : ` ${end}`;
179
- throw $parseMinErr(
180
- "lexerr",
181
- "Lexer Error: {0} at column{1} in expression [{2}].",
182
- error,
183
- colStr,
184
- this.text,
185
- );
186
- },
187
-
188
- readNumber() {
189
- let number = "";
190
- const start = this.index;
191
- while (this.index < this.text.length) {
192
- const ch = this.text.charAt(this.index).toLowerCase();
193
- if (ch === "." || this.isNumber(ch)) {
194
- number += ch;
195
- } else {
196
- const peekCh = this.peek();
197
- if (ch === "e" && this.isExpOperator(peekCh)) {
198
- number += ch;
199
- } else if (
200
- this.isExpOperator(ch) &&
201
- peekCh &&
202
- this.isNumber(peekCh) &&
203
- number.charAt(number.length - 1) === "e"
204
- ) {
205
- number += ch;
206
- } else if (
207
- this.isExpOperator(ch) &&
208
- (!peekCh || !this.isNumber(peekCh)) &&
209
- number.charAt(number.length - 1) === "e"
210
- ) {
211
- this.throwError("Invalid exponent");
212
- } else {
213
- break;
214
- }
215
- }
216
- this.index++;
217
- }
218
- this.tokens.push({
219
- index: start,
220
- text: number,
221
- constant: true,
222
- value: Number(number),
223
- });
224
- },
225
-
226
- readIdent() {
227
- const start = this.index;
228
- this.index += this.peekMultichar().length;
229
- while (this.index < this.text.length) {
230
- const ch = this.peekMultichar();
231
- if (!this.isIdentifierContinue(ch)) {
232
- break;
233
- }
234
- this.index += ch.length;
235
- }
236
- this.tokens.push({
237
- index: start,
238
- text: this.text.slice(start, this.index),
239
- identifier: true,
240
- });
241
- },
242
-
243
- readString(quote) {
244
- const start = this.index;
245
- this.index++;
246
- let string = "";
247
- let rawString = quote;
248
- let escape = false;
249
- while (this.index < this.text.length) {
250
- const ch = this.text.charAt(this.index);
251
- rawString += ch;
252
- if (escape) {
253
- if (ch === "u") {
254
- const hex = this.text.substring(this.index + 1, this.index + 5);
255
- if (!hex.match(/[\da-f]{4}/i)) {
256
- this.throwError(`Invalid unicode escape [\\u${hex}]`);
257
- }
258
- this.index += 4;
259
- string += String.fromCharCode(parseInt(hex, 16));
260
- } else {
261
- const rep = ESCAPE[ch];
262
- string += rep || ch;
263
- }
264
- escape = false;
265
- } else if (ch === "\\") {
266
- escape = true;
267
- } else if (ch === quote) {
268
- this.index++;
269
- this.tokens.push({
270
- index: start,
271
- text: rawString,
272
- constant: true,
273
- value: string,
274
- });
275
- return;
276
- } else {
277
- string += ch;
278
- }
279
- this.index++;
280
- }
281
- this.throwError("Unterminated quote", start);
282
- },
283
- };
284
-
285
- /**
286
- * @typedef {("Program"|"ExpressionStatement"|"AssignmentExpression"|"ConditionalExpression"|"LogicalExpression"|"BinaryExpression"|"UnaryExpression"|"CallExpression"|"MemberExpression"|"Identifier"|"Literal"|"ArrayExpression"|"Property"|"ObjectExpression"|"ThisExpression"|"LocalsExpression"|"NGValueParameter")} ASTType
287
- */
288
- const ASTType = {
289
- Program: "Program",
290
- ExpressionStatement: "ExpressionStatement",
291
- AssignmentExpression: "AssignmentExpression",
292
- ConditionalExpression: "ConditionalExpression",
293
- LogicalExpression: "LogicalExpression",
294
- BinaryExpression: "BinaryExpression",
295
- UnaryExpression: "UnaryExpression",
296
- CallExpression: "CallExpression",
297
- MemberExpression: "MemberExpression",
298
- Identifier: "Identifier",
299
- Literal: "Literal",
300
- ArrayExpression: "ArrayExpression",
301
- Property: "Property",
302
- ObjectExpression: "ObjectExpression",
303
- ThisExpression: "ThisExpression",
304
- LocalsExpression: "LocalsExpression",
305
- NGValueParameter: "NGValueParameter",
306
- };
307
-
308
- export function AST(lexer, options) {
309
- this.lexer = lexer;
310
- this.options = options;
311
- }
312
-
313
- AST.prototype = {
314
- ast(text) {
315
- this.text = text;
316
- this.tokens = this.lexer.lex(text);
317
-
318
- const value = this.program();
319
-
320
- if (this.tokens.length !== 0) {
321
- this.throwError("is an unexpected token", this.tokens[0]);
322
- }
323
-
324
- return value;
325
- },
326
-
327
- program() {
328
- const body = [];
329
- let hasMore = true;
330
- while (hasMore) {
331
- if (this.tokens.length > 0 && !this.peek("}", ")", ";", "]"))
332
- body.push(this.expressionStatement());
333
- if (!this.expect(";")) {
334
- hasMore = false;
335
- }
336
- }
337
- return { type: ASTType.Program, body };
338
- },
339
-
340
- expressionStatement() {
341
- return {
342
- type: ASTType.ExpressionStatement,
343
- expression: this.filterChain(),
344
- };
345
- },
346
-
347
- filterChain() {
348
- let left = this.expression();
349
- while (this.expect("|")) {
350
- left = this.filter(left);
351
- }
352
- return left;
353
- },
354
-
355
- expression() {
356
- return this.assignment();
357
- },
358
-
359
- assignment() {
360
- let result = this.ternary();
361
- if (this.expect("=")) {
362
- if (!isAssignable(result)) {
363
- throw $parseMinErr("lval", "Trying to assign a value to a non l-value");
364
- }
365
-
366
- result = {
367
- type: ASTType.AssignmentExpression,
368
- left: result,
369
- right: this.assignment(),
370
- operator: "=",
371
- };
372
- }
373
- return result;
374
- },
375
-
376
- ternary() {
377
- const test = this.logicalOR();
378
- let alternate;
379
- let consequent;
380
- if (this.expect("?")) {
381
- alternate = this.expression();
382
- if (this.consume(":")) {
383
- consequent = this.expression();
384
- return {
385
- type: ASTType.ConditionalExpression,
386
- test,
387
- alternate,
388
- consequent,
389
- };
390
- }
391
- }
392
- return test;
393
- },
394
-
395
- logicalOR() {
396
- let left = this.logicalAND();
397
- while (this.expect("||")) {
398
- left = {
399
- type: ASTType.LogicalExpression,
400
- operator: "||",
401
- left,
402
- right: this.logicalAND(),
403
- };
404
- }
405
- return left;
406
- },
407
-
408
- logicalAND() {
409
- let left = this.equality();
410
- while (this.expect("&&")) {
411
- left = {
412
- type: ASTType.LogicalExpression,
413
- operator: "&&",
414
- left,
415
- right: this.equality(),
416
- };
417
- }
418
- return left;
419
- },
420
-
421
- equality() {
422
- let left = this.relational();
423
- let token;
424
- while ((token = this.expect("==", "!=", "===", "!=="))) {
425
- left = {
426
- type: ASTType.BinaryExpression,
427
- operator: token.text,
428
- left,
429
- right: this.relational(),
430
- };
431
- }
432
- return left;
433
- },
434
-
435
- relational() {
436
- let left = this.additive();
437
- let token;
438
- while ((token = this.expect("<", ">", "<=", ">="))) {
439
- left = {
440
- type: ASTType.BinaryExpression,
441
- operator: token.text,
442
- left,
443
- right: this.additive(),
444
- };
445
- }
446
- return left;
447
- },
448
-
449
- additive() {
450
- let left = this.multiplicative();
451
- let token;
452
- while ((token = this.expect("+", "-"))) {
453
- left = {
454
- type: ASTType.BinaryExpression,
455
- operator: token.text,
456
- left,
457
- right: this.multiplicative(),
458
- };
459
- }
460
- return left;
461
- },
462
-
463
- multiplicative() {
464
- let left = this.unary();
465
- let token;
466
- while ((token = this.expect("*", "/", "%"))) {
467
- left = {
468
- type: ASTType.BinaryExpression,
469
- operator: token.text,
470
- left,
471
- right: this.unary(),
472
- };
473
- }
474
- return left;
475
- },
476
-
477
- unary() {
478
- let token;
479
- if ((token = this.expect("+", "-", "!"))) {
480
- return {
481
- type: ASTType.UnaryExpression,
482
- operator: token.text,
483
- prefix: true,
484
- argument: this.unary(),
485
- };
486
- }
487
- return this.primary();
488
- },
489
-
490
- primary() {
491
- let primary;
492
- if (this.expect("(")) {
493
- primary = this.filterChain();
494
- this.consume(")");
495
- } else if (this.expect("[")) {
496
- primary = this.arrayDeclaration();
497
- } else if (this.expect("{")) {
498
- primary = this.object();
499
- } else if (
500
- Object.prototype.hasOwnProperty.call(
501
- this.selfReferential,
502
- this.peek().text,
503
- )
504
- ) {
505
- primary = structuredClone(this.selfReferential[this.consume().text]);
506
- } else if (
507
- Object.prototype.hasOwnProperty.call(
508
- this.options.literals,
509
- this.peek().text,
510
- )
511
- ) {
512
- primary = {
513
- type: ASTType.Literal,
514
- value: this.options.literals[this.consume().text],
515
- };
516
- } else if (this.peek().identifier) {
517
- primary = this.identifier();
518
- } else if (this.peek().constant) {
519
- primary = this.constant();
520
- } else {
521
- this.throwError("not a primary expression", this.peek());
522
- }
523
-
524
- let next;
525
- while ((next = this.expect("(", "[", "."))) {
526
- if (next.text === "(") {
527
- primary = {
528
- type: ASTType.CallExpression,
529
- callee: primary,
530
- arguments: this.parseArguments(),
531
- };
532
- this.consume(")");
533
- } else if (next.text === "[") {
534
- primary = {
535
- type: ASTType.MemberExpression,
536
- object: primary,
537
- property: this.expression(),
538
- computed: true,
539
- };
540
- this.consume("]");
541
- } else if (next.text === ".") {
542
- primary = {
543
- type: ASTType.MemberExpression,
544
- object: primary,
545
- property: this.identifier(),
546
- computed: false,
547
- };
548
- } else {
549
- this.throwError("IMPOSSIBLE");
550
- }
551
- }
552
- return primary;
553
- },
554
-
555
- filter(baseExpression) {
556
- const args = [baseExpression];
557
- const result = {
558
- type: ASTType.CallExpression,
559
- callee: this.identifier(),
560
- arguments: args,
561
- filter: true,
562
- };
563
-
564
- while (this.expect(":")) {
565
- args.push(this.expression());
566
- }
567
-
568
- return result;
569
- },
570
-
571
- parseArguments() {
572
- const args = [];
573
- if (this.peekToken().text !== ")") {
574
- do {
575
- args.push(this.filterChain());
576
- } while (this.expect(","));
577
- }
578
- return args;
579
- },
580
-
581
- identifier() {
582
- const token = this.consume();
583
- if (!token.identifier) {
584
- this.throwError("is not a valid identifier", token);
585
- }
586
- return { type: ASTType.Identifier, name: token.text };
587
- },
588
-
589
- constant() {
590
- // TODO check that it is a constant
591
- return { type: ASTType.Literal, value: this.consume().value };
592
- },
593
-
594
- arrayDeclaration() {
595
- const elements = [];
596
- if (this.peekToken().text !== "]") {
597
- do {
598
- if (this.peek("]")) {
599
- // Support trailing commas per ES5.1.
600
- break;
601
- }
602
- elements.push(this.expression());
603
- } while (this.expect(","));
604
- }
605
- this.consume("]");
606
-
607
- return { type: ASTType.ArrayExpression, elements };
608
- },
609
-
610
- object() {
611
- const properties = [];
612
- let property;
613
- if (this.peekToken().text !== "}") {
614
- do {
615
- if (this.peek("}")) {
616
- // Support trailing commas per ES5.1.
617
- break;
618
- }
619
- property = { type: ASTType.Property, kind: "init" };
620
- if (this.peek().constant) {
621
- property.key = this.constant();
622
- property.computed = false;
623
- this.consume(":");
624
- property.value = this.expression();
625
- } else if (this.peek().identifier) {
626
- property.key = this.identifier();
627
- property.computed = false;
628
- if (this.peek(":")) {
629
- this.consume(":");
630
- property.value = this.expression();
631
- } else {
632
- property.value = property.key;
633
- }
634
- } else if (this.peek("[")) {
635
- this.consume("[");
636
- property.key = this.expression();
637
- this.consume("]");
638
- property.computed = true;
639
- this.consume(":");
640
- property.value = this.expression();
641
- } else {
642
- this.throwError("invalid key", this.peek());
643
- }
644
- properties.push(property);
645
- } while (this.expect(","));
646
- }
647
- this.consume("}");
648
-
649
- return { type: ASTType.ObjectExpression, properties };
650
- },
651
-
652
- throwError(msg, token) {
653
- throw $parseMinErr(
654
- "syntax",
655
- "Syntax Error: Token '{0}' {1} at column {2} of the expression [{3}] starting at [{4}].",
656
- token.text,
657
- msg,
658
- token.index + 1,
659
- this.text,
660
- this.text.substring(token.index),
661
- );
662
- },
663
-
664
- consume(e1) {
665
- if (this.tokens.length === 0) {
666
- throw $parseMinErr(
667
- "ueoe",
668
- "Unexpected end of expression: {0}",
669
- this.text,
670
- );
671
- }
672
-
673
- const token = this.expect(e1);
674
- if (!token) {
675
- this.throwError(`is unexpected, expecting [${e1}]`, this.peek());
676
- }
677
- return token;
678
- },
679
-
680
- peekToken() {
681
- if (this.tokens.length === 0) {
682
- throw $parseMinErr(
683
- "ueoe",
684
- "Unexpected end of expression: {0}",
685
- this.text,
686
- );
687
- }
688
- return this.tokens[0];
689
- },
690
-
691
- peek(e1, e2, e3, e4) {
692
- return this.peekAhead(0, e1, e2, e3, e4);
693
- },
694
-
695
- peekAhead(i, e1, e2, e3, e4) {
696
- if (this.tokens.length > i) {
697
- const token = this.tokens[i];
698
- const t = token.text;
699
- if (
700
- t === e1 ||
701
- t === e2 ||
702
- t === e3 ||
703
- t === e4 ||
704
- (!e1 && !e2 && !e3 && !e4)
705
- ) {
706
- return token;
707
- }
708
- }
709
- return false;
710
- },
711
-
712
- expect(e1, e2, e3, e4) {
713
- const token = this.peek(e1, e2, e3, e4);
714
- if (token) {
715
- this.tokens.shift();
716
- return token;
717
- }
718
- return false;
719
- },
720
-
721
- selfReferential: {
722
- this: { type: ASTType.ThisExpression },
723
- $locals: { type: ASTType.LocalsExpression },
724
- },
725
- };
726
-
727
- function ifDefined(v, d) {
728
- return typeof v !== "undefined" ? v : d;
729
- }
730
-
731
- function plusFn(l, r) {
732
- if (typeof l === "undefined") return r;
733
- if (typeof r === "undefined") return l;
734
- return l + r;
735
- }
736
-
737
- function isStateless($filter, filterName) {
738
- const fn = $filter(filterName);
739
- return !fn.$stateful;
740
- }
741
-
742
- const PURITY_ABSOLUTE = 1;
743
- const PURITY_RELATIVE = 2;
744
-
745
- // Detect nodes which could depend on non-shallow state of objects
746
- function isPure(node, parentIsPure) {
747
- switch (node.type) {
748
- // Computed members might invoke a stateful toString()
749
- case ASTType.MemberExpression:
750
- if (node.computed) {
751
- return false;
752
- }
753
- break;
754
-
755
- // Unary always convert to primative
756
- case ASTType.UnaryExpression:
757
- return PURITY_ABSOLUTE;
758
-
759
- // The binary + operator can invoke a stateful toString().
760
- case ASTType.BinaryExpression:
761
- return node.operator !== "+" ? PURITY_ABSOLUTE : false;
762
-
763
- // Functions / filters probably read state from within objects
764
- case ASTType.CallExpression:
765
- return false;
766
- }
767
-
768
- return undefined === parentIsPure ? PURITY_RELATIVE : parentIsPure;
769
- }
770
-
771
- function findConstantAndWatchExpressions(ast, $filter, parentIsPure) {
772
- let allConstants;
773
- let argsToWatch;
774
- let isStatelessFilter;
775
-
776
- const astIsPure = (ast.isPure = isPure(ast, parentIsPure));
777
-
778
- switch (ast.type) {
779
- case ASTType.Program:
780
- allConstants = true;
781
- forEach(ast.body, (expr) => {
782
- findConstantAndWatchExpressions(expr.expression, $filter, astIsPure);
783
- allConstants = allConstants && expr.expression.constant;
784
- });
785
- ast.constant = allConstants;
786
- break;
787
- case ASTType.Literal:
788
- ast.constant = true;
789
- ast.toWatch = [];
790
- break;
791
- case ASTType.UnaryExpression:
792
- findConstantAndWatchExpressions(ast.argument, $filter, astIsPure);
793
- ast.constant = ast.argument.constant;
794
- ast.toWatch = ast.argument.toWatch;
795
- break;
796
- case ASTType.BinaryExpression:
797
- findConstantAndWatchExpressions(ast.left, $filter, astIsPure);
798
- findConstantAndWatchExpressions(ast.right, $filter, astIsPure);
799
- ast.constant = ast.left.constant && ast.right.constant;
800
- ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
801
- break;
802
- case ASTType.LogicalExpression:
803
- findConstantAndWatchExpressions(ast.left, $filter, astIsPure);
804
- findConstantAndWatchExpressions(ast.right, $filter, astIsPure);
805
- ast.constant = ast.left.constant && ast.right.constant;
806
- ast.toWatch = ast.constant ? [] : [ast];
807
- break;
808
- case ASTType.ConditionalExpression:
809
- findConstantAndWatchExpressions(ast.test, $filter, astIsPure);
810
- findConstantAndWatchExpressions(ast.alternate, $filter, astIsPure);
811
- findConstantAndWatchExpressions(ast.consequent, $filter, astIsPure);
812
- ast.constant =
813
- ast.test.constant && ast.alternate.constant && ast.consequent.constant;
814
- ast.toWatch = ast.constant ? [] : [ast];
815
- break;
816
- case ASTType.Identifier:
817
- ast.constant = false;
818
- ast.toWatch = [ast];
819
- break;
820
- case ASTType.MemberExpression:
821
- findConstantAndWatchExpressions(ast.object, $filter, astIsPure);
822
- if (ast.computed) {
823
- findConstantAndWatchExpressions(ast.property, $filter, astIsPure);
824
- }
825
- ast.constant =
826
- ast.object.constant && (!ast.computed || ast.property.constant);
827
- ast.toWatch = ast.constant ? [] : [ast];
828
- break;
829
- case ASTType.CallExpression:
830
- isStatelessFilter = ast.filter
831
- ? isStateless($filter, ast.callee.name)
832
- : false;
833
- allConstants = isStatelessFilter;
834
- argsToWatch = [];
835
- forEach(ast.arguments, (expr) => {
836
- findConstantAndWatchExpressions(expr, $filter, astIsPure);
837
- allConstants = allConstants && expr.constant;
838
- argsToWatch.push.apply(argsToWatch, expr.toWatch);
839
- });
840
- ast.constant = allConstants;
841
- ast.toWatch = isStatelessFilter ? argsToWatch : [ast];
842
- break;
843
- case ASTType.AssignmentExpression:
844
- findConstantAndWatchExpressions(ast.left, $filter, astIsPure);
845
- findConstantAndWatchExpressions(ast.right, $filter, astIsPure);
846
- ast.constant = ast.left.constant && ast.right.constant;
847
- ast.toWatch = [ast];
848
- break;
849
- case ASTType.ArrayExpression:
850
- allConstants = true;
851
- argsToWatch = [];
852
- forEach(ast.elements, (expr) => {
853
- findConstantAndWatchExpressions(expr, $filter, astIsPure);
854
- allConstants = allConstants && expr.constant;
855
- argsToWatch.push.apply(argsToWatch, expr.toWatch);
856
- });
857
- ast.constant = allConstants;
858
- ast.toWatch = argsToWatch;
859
- break;
860
- case ASTType.ObjectExpression:
861
- allConstants = true;
862
- argsToWatch = [];
863
- forEach(ast.properties, (property) => {
864
- findConstantAndWatchExpressions(property.value, $filter, astIsPure);
865
- allConstants = allConstants && property.value.constant;
866
- argsToWatch.push.apply(argsToWatch, property.value.toWatch);
867
- if (property.computed) {
868
- // `{[key]: value}` implicitly does `key.toString()` which may be non-pure
869
- findConstantAndWatchExpressions(
870
- property.key,
871
- $filter,
872
- /* parentIsPure= */ false,
873
- );
874
- allConstants = allConstants && property.key.constant;
875
- argsToWatch.push.apply(argsToWatch, property.key.toWatch);
876
- }
877
- });
878
- ast.constant = allConstants;
879
- ast.toWatch = argsToWatch;
880
- break;
881
- case ASTType.ThisExpression:
882
- ast.constant = false;
883
- ast.toWatch = [];
884
- break;
885
- case ASTType.LocalsExpression:
886
- ast.constant = false;
887
- ast.toWatch = [];
888
- break;
889
- }
890
- }
891
-
892
- function getInputs(body) {
893
- if (body.length !== 1) return;
894
- const lastExpression = body[0].expression;
895
- const candidate = lastExpression.toWatch;
896
- if (candidate.length !== 1) return candidate;
897
- return candidate[0] !== lastExpression ? candidate : undefined;
898
- }
899
-
900
- function isAssignable(ast) {
901
- return (
902
- ast.type === ASTType.Identifier || ast.type === ASTType.MemberExpression
903
- );
904
- }
905
-
906
- function assignableAST(ast) {
907
- if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
908
- return {
909
- type: ASTType.AssignmentExpression,
910
- left: ast.body[0].expression,
911
- right: { type: ASTType.NGValueParameter },
912
- operator: "=",
913
- };
914
- }
915
- }
916
-
917
- function isLiteral(ast) {
918
- return (
919
- ast.body.length === 0 ||
920
- (ast.body.length === 1 &&
921
- (ast.body[0].expression.type === ASTType.Literal ||
922
- ast.body[0].expression.type === ASTType.ArrayExpression ||
923
- ast.body[0].expression.type === ASTType.ObjectExpression))
924
- );
925
- }
926
-
927
- function isConstant(ast) {
928
- return ast.constant;
929
- }
930
-
931
- function ASTCompiler($filter) {
932
- this.$filter = $filter;
933
- }
934
-
935
- ASTCompiler.prototype = {
936
- compile(ast) {
937
- const self = this;
938
- this.state = {
939
- nextId: 0,
940
- filters: {},
941
- fn: { vars: [], body: [], own: {} },
942
- assign: { vars: [], body: [], own: {} },
943
- inputs: [],
944
- };
945
- findConstantAndWatchExpressions(ast, self.$filter);
946
- let extra = "";
947
- let assignable;
948
- this.stage = "assign";
949
- if ((assignable = assignableAST(ast))) {
950
- this.state.computing = "assign";
951
- const result = this.nextId();
952
- this.recurse(assignable, result);
953
- this.return_(result);
954
- extra = `fn.assign=${this.generateFunction("assign", "s,v,l")}`;
955
- }
956
- const toWatch = getInputs(ast.body);
957
- self.stage = "inputs";
958
- forEach(toWatch, (watch, key) => {
959
- const fnKey = `fn${key}`;
960
- self.state[fnKey] = { vars: [], body: [], own: {} };
961
- self.state.computing = fnKey;
962
- const intoId = self.nextId();
963
- self.recurse(watch, intoId);
964
- self.return_(intoId);
965
- self.state.inputs.push({ name: fnKey, isPure: watch.isPure });
966
- watch.watchId = key;
967
- });
968
- this.state.computing = "fn";
969
- this.stage = "main";
970
- this.recurse(ast);
971
- const fnString = `\n${this.filterPrefix()}let fn=${this.generateFunction(
972
- "fn",
973
- "s,l,a,i",
974
- )}${extra}${this.watchFns()}return fn;`;
975
-
976
- // eslint-disable-next-line no-new-func
977
- const fn = new Function(
978
- "$filter",
979
- "getStringValue",
980
- "ifDefined",
981
- "plus",
982
- fnString,
983
- )(this.$filter, getStringValue, ifDefined, plusFn);
984
- this.state = this.stage = undefined;
985
- return fn;
986
- },
987
-
988
- watchFns() {
989
- const result = [];
990
- const { inputs } = this.state;
991
- const self = this;
992
- forEach(inputs, (input) => {
993
- result.push(
994
- `let ${input.name}=${self.generateFunction(input.name, "s")}`,
995
- );
996
- if (input.isPure) {
997
- result.push(input.name, `.isPure=${JSON.stringify(input.isPure)};`);
998
- }
999
- });
1000
- if (inputs.length) {
1001
- result.push(`fn.inputs=[${inputs.map((i) => i.name).join(",")}];`);
1002
- }
1003
- return result.join("");
1004
- },
1005
-
1006
- generateFunction(name, params) {
1007
- return `function(${params}){${this.varsPrefix(name)}${this.body(name)}};`;
1008
- },
1009
-
1010
- filterPrefix() {
1011
- const parts = [];
1012
- const self = this;
1013
- forEach(this.state.filters, (id, filter) => {
1014
- parts.push(`${id}=$filter(${self.escape(filter)})`);
1015
- });
1016
- if (parts.length) return `let ${parts.join(",")};`;
1017
- return "";
1018
- },
1019
-
1020
- varsPrefix(section) {
1021
- return this.state[section].vars.length
1022
- ? `let ${this.state[section].vars.join(",")};`
1023
- : "";
1024
- },
1025
-
1026
- body(section) {
1027
- return this.state[section].body.join("");
1028
- },
1029
-
1030
- recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
1031
- let left;
1032
- let right;
1033
- const self = this;
1034
- let args;
1035
- let expression;
1036
- let computed;
1037
- recursionFn = recursionFn || (() => {});
1038
- if (!skipWatchIdCheck && isDefined(ast.watchId)) {
1039
- intoId = intoId || this.nextId();
1040
- this.if_(
1041
- "i",
1042
- this.lazyAssign(intoId, this.computedMember("i", ast.watchId)),
1043
- this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true),
1044
- );
1045
- return;
1046
- }
1047
- switch (ast.type) {
1048
- case ASTType.Program:
1049
- forEach(ast.body, (expression, pos) => {
1050
- self.recurse(expression.expression, undefined, undefined, (expr) => {
1051
- right = expr;
1052
- });
1053
- if (pos !== ast.body.length - 1) {
1054
- self.current().body.push(right, ";");
1055
- } else {
1056
- self.return_(right);
1057
- }
1058
- });
1059
- break;
1060
- case ASTType.Literal:
1061
- expression = this.escape(ast.value);
1062
- this.assign(intoId, expression);
1063
- recursionFn(intoId || expression);
1064
- break;
1065
- case ASTType.UnaryExpression:
1066
- this.recurse(ast.argument, undefined, undefined, (expr) => {
1067
- right = expr;
1068
- });
1069
- expression = `${ast.operator}(${this.ifDefined(right, 0)})`;
1070
- this.assign(intoId, expression);
1071
- recursionFn(expression);
1072
- break;
1073
- case ASTType.BinaryExpression:
1074
- this.recurse(ast.left, undefined, undefined, (expr) => {
1075
- left = expr;
1076
- });
1077
- this.recurse(ast.right, undefined, undefined, (expr) => {
1078
- right = expr;
1079
- });
1080
- if (ast.operator === "+") {
1081
- expression = this.plus(left, right);
1082
- } else if (ast.operator === "-") {
1083
- expression =
1084
- this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
1085
- } else {
1086
- expression = `(${left})${ast.operator}(${right})`;
1087
- }
1088
- this.assign(intoId, expression);
1089
- recursionFn(expression);
1090
- break;
1091
- case ASTType.LogicalExpression:
1092
- intoId = intoId || this.nextId();
1093
- self.recurse(ast.left, intoId);
1094
- self.if_(
1095
- ast.operator === "&&" ? intoId : self.not(intoId),
1096
- self.lazyRecurse(ast.right, intoId),
1097
- );
1098
- recursionFn(intoId);
1099
- break;
1100
- case ASTType.ConditionalExpression:
1101
- intoId = intoId || this.nextId();
1102
- self.recurse(ast.test, intoId);
1103
- self.if_(
1104
- intoId,
1105
- self.lazyRecurse(ast.alternate, intoId),
1106
- self.lazyRecurse(ast.consequent, intoId),
1107
- );
1108
- recursionFn(intoId);
1109
- break;
1110
- case ASTType.Identifier:
1111
- intoId = intoId || this.nextId();
1112
- if (nameId) {
1113
- nameId.context =
1114
- self.stage === "inputs"
1115
- ? "s"
1116
- : this.assign(
1117
- this.nextId(),
1118
- `${this.getHasOwnProperty("l", ast.name)}?l:s`,
1119
- );
1120
- nameId.computed = false;
1121
- nameId.name = ast.name;
1122
- }
1123
- self.if_(
1124
- self.stage === "inputs" ||
1125
- self.not(self.getHasOwnProperty("l", ast.name)),
1126
- () => {
1127
- self.if_(self.stage === "inputs" || "s", () => {
1128
- if (create && create !== 1) {
1129
- self.if_(
1130
- self.isNull(self.nonComputedMember("s", ast.name)),
1131
- self.lazyAssign(self.nonComputedMember("s", ast.name), "{}"),
1132
- );
1133
- }
1134
- self.assign(intoId, self.nonComputedMember("s", ast.name));
1135
- });
1136
- },
1137
- intoId &&
1138
- self.lazyAssign(intoId, self.nonComputedMember("l", ast.name)),
1139
- );
1140
- recursionFn(intoId);
1141
- break;
1142
- case ASTType.MemberExpression:
1143
- left = (nameId && (nameId.context = this.nextId())) || this.nextId();
1144
- intoId = intoId || this.nextId();
1145
- self.recurse(
1146
- ast.object,
1147
- left,
1148
- undefined,
1149
- () => {
1150
- self.if_(
1151
- self.notNull(left),
1152
- () => {
1153
- if (ast.computed) {
1154
- right = self.nextId();
1155
- self.recurse(ast.property, right);
1156
- self.getStringValue(right);
1157
- if (create && create !== 1) {
1158
- self.if_(
1159
- self.not(self.computedMember(left, right)),
1160
- self.lazyAssign(self.computedMember(left, right), "{}"),
1161
- );
1162
- }
1163
- expression = self.computedMember(left, right);
1164
- self.assign(intoId, expression);
1165
- if (nameId) {
1166
- nameId.computed = true;
1167
- nameId.name = right;
1168
- }
1169
- } else {
1170
- if (create && create !== 1) {
1171
- self.if_(
1172
- self.isNull(
1173
- self.nonComputedMember(left, ast.property.name),
1174
- ),
1175
- self.lazyAssign(
1176
- self.nonComputedMember(left, ast.property.name),
1177
- "{}",
1178
- ),
1179
- );
1180
- }
1181
- expression = self.nonComputedMember(left, ast.property.name);
1182
- self.assign(intoId, expression);
1183
- if (nameId) {
1184
- nameId.computed = false;
1185
- nameId.name = ast.property.name;
1186
- }
1187
- }
1188
- },
1189
- () => {
1190
- self.assign(intoId, "undefined");
1191
- },
1192
- );
1193
- recursionFn(intoId);
1194
- },
1195
- !!create,
1196
- );
1197
- break;
1198
- case ASTType.CallExpression:
1199
- intoId = intoId || this.nextId();
1200
- if (ast.filter) {
1201
- right = self.filter(ast.callee.name);
1202
- args = [];
1203
- forEach(ast.arguments, (expr) => {
1204
- const argument = self.nextId();
1205
- self.recurse(expr, argument);
1206
- args.push(argument);
1207
- });
1208
- expression = `${right}(${args.join(",")})`;
1209
- self.assign(intoId, expression);
1210
- recursionFn(intoId);
1211
- } else {
1212
- right = self.nextId();
1213
- left = {};
1214
- args = [];
1215
- self.recurse(ast.callee, right, left, () => {
1216
- self.if_(
1217
- self.notNull(right),
1218
- () => {
1219
- forEach(ast.arguments, (expr) => {
1220
- self.recurse(
1221
- expr,
1222
- ast.constant ? undefined : self.nextId(),
1223
- undefined,
1224
- (argument) => {
1225
- args.push(argument);
1226
- },
1227
- );
1228
- });
1229
- if (left.name) {
1230
- expression = `${self.member(
1231
- left.context,
1232
- left.name,
1233
- left.computed,
1234
- )}(${args.join(",")})`;
1235
- } else {
1236
- expression = `${right}(${args.join(",")})`;
1237
- }
1238
- self.assign(intoId, expression);
1239
- },
1240
- () => {
1241
- self.assign(intoId, "undefined");
1242
- },
1243
- );
1244
- recursionFn(intoId);
1245
- });
1246
- }
1247
- break;
1248
- case ASTType.AssignmentExpression:
1249
- right = this.nextId();
1250
- left = {};
1251
- this.recurse(
1252
- ast.left,
1253
- undefined,
1254
- left,
1255
- () => {
1256
- self.if_(self.notNull(left.context), () => {
1257
- self.recurse(ast.right, right);
1258
- expression =
1259
- self.member(left.context, left.name, left.computed) +
1260
- ast.operator +
1261
- right;
1262
- self.assign(intoId, expression);
1263
- recursionFn(intoId || expression);
1264
- });
1265
- },
1266
- 1,
1267
- );
1268
- break;
1269
- case ASTType.ArrayExpression:
1270
- args = [];
1271
- forEach(ast.elements, (expr) => {
1272
- self.recurse(
1273
- expr,
1274
- ast.constant ? undefined : self.nextId(),
1275
- undefined,
1276
- (argument) => {
1277
- args.push(argument);
1278
- },
1279
- );
1280
- });
1281
- expression = `[${args.join(",")}]`;
1282
- this.assign(intoId, expression);
1283
- recursionFn(intoId || expression);
1284
- break;
1285
- case ASTType.ObjectExpression:
1286
- args = [];
1287
- computed = false;
1288
- forEach(ast.properties, (property) => {
1289
- if (property.computed) {
1290
- computed = true;
1291
- }
1292
- });
1293
- if (computed) {
1294
- intoId = intoId || this.nextId();
1295
- this.assign(intoId, "{}");
1296
- forEach(ast.properties, (property) => {
1297
- if (property.computed) {
1298
- left = self.nextId();
1299
- self.recurse(property.key, left);
1300
- } else {
1301
- left =
1302
- property.key.type === ASTType.Identifier
1303
- ? property.key.name
1304
- : `${property.key.value}`;
1305
- }
1306
- right = self.nextId();
1307
- self.recurse(property.value, right);
1308
- self.assign(self.member(intoId, left, property.computed), right);
1309
- });
1310
- } else {
1311
- forEach(ast.properties, (property) => {
1312
- self.recurse(
1313
- property.value,
1314
- ast.constant ? undefined : self.nextId(),
1315
- undefined,
1316
- (expr) => {
1317
- args.push(
1318
- `${self.escape(
1319
- property.key.type === ASTType.Identifier
1320
- ? property.key.name
1321
- : `${property.key.value}`,
1322
- )}:${expr}`,
1323
- );
1324
- },
1325
- );
1326
- });
1327
- expression = `{${args.join(",")}}`;
1328
- this.assign(intoId, expression);
1329
- }
1330
- recursionFn(intoId || expression);
1331
- break;
1332
- case ASTType.ThisExpression:
1333
- this.assign(intoId, "s");
1334
- recursionFn(intoId || "s");
1335
- break;
1336
- case ASTType.LocalsExpression:
1337
- this.assign(intoId, "l");
1338
- recursionFn(intoId || "l");
1339
- break;
1340
- case ASTType.NGValueParameter:
1341
- this.assign(intoId, "v");
1342
- recursionFn(intoId || "v");
1343
- break;
1344
- }
1345
- },
1346
-
1347
- getHasOwnProperty(element, property) {
1348
- const key = `${element}.${property}`;
1349
- const { own } = this.current();
1350
- if (!Object.prototype.hasOwnProperty.call(own, key)) {
1351
- own[key] = this.nextId(
1352
- false,
1353
- `${element}&&(${this.escape(property)} in ${element})`,
1354
- );
1355
- }
1356
- return own[key];
1357
- },
1358
-
1359
- assign(id, value) {
1360
- if (!id) return;
1361
- this.current().body.push(id, "=", value, ";");
1362
- return id;
1363
- },
1364
-
1365
- filter(filterName) {
1366
- if (!Object.prototype.hasOwnProperty.call(this.state.filters, filterName)) {
1367
- this.state.filters[filterName] = this.nextId(true);
1368
- }
1369
- return this.state.filters[filterName];
1370
- },
1371
-
1372
- ifDefined(id, defaultValue) {
1373
- return `ifDefined(${id},${this.escape(defaultValue)})`;
1374
- },
1375
-
1376
- plus(left, right) {
1377
- return `plus(${left},${right})`;
1378
- },
1379
-
1380
- return_(id) {
1381
- this.current().body.push("return ", id, ";");
1382
- },
1383
-
1384
- if_(test, alternate, consequent) {
1385
- if (test === true) {
1386
- alternate();
1387
- } else {
1388
- const { body } = this.current();
1389
- body.push("if(", test, "){");
1390
- alternate();
1391
- body.push("}");
1392
- if (consequent) {
1393
- body.push("else{");
1394
- consequent();
1395
- body.push("}");
1396
- }
1397
- }
1398
- },
1399
-
1400
- not(expression) {
1401
- return `!(${expression})`;
1402
- },
1403
-
1404
- isNull(expression) {
1405
- return `${expression}==null`;
1406
- },
1407
-
1408
- notNull(expression) {
1409
- return `${expression}!=null`;
1410
- },
1411
-
1412
- nonComputedMember(left, right) {
1413
- const SAFE_IDENTIFIER = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/;
1414
- const UNSAFE_CHARACTERS = /[^$_a-zA-Z0-9]/g;
1415
- if (SAFE_IDENTIFIER.test(right)) {
1416
- return `${left}.${right}`;
1417
- }
1418
- return `${left}["${right.replace(
1419
- UNSAFE_CHARACTERS,
1420
- this.stringEscapeFn,
1421
- )}"]`;
1422
- },
1423
-
1424
- computedMember(left, right) {
1425
- return `${left}[${right}]`;
1426
- },
1427
-
1428
- member(left, right, computed) {
1429
- if (computed) return this.computedMember(left, right);
1430
- return this.nonComputedMember(left, right);
1431
- },
1432
-
1433
- getStringValue(item) {
1434
- this.assign(item, `getStringValue(${item})`);
1435
- },
1436
-
1437
- lazyRecurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
1438
- const self = this;
1439
- return function () {
1440
- self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
1441
- };
1442
- },
1443
-
1444
- lazyAssign(id, value) {
1445
- const self = this;
1446
- return function () {
1447
- self.assign(id, value);
1448
- };
1449
- },
1450
-
1451
- stringEscapeRegex: /[^ a-zA-Z0-9]/g,
1452
-
1453
- stringEscapeFn(c) {
1454
- return `\\u${`0000${c.charCodeAt(0).toString(16)}`.slice(-4)}`;
1455
- },
1456
-
1457
- escape(value) {
1458
- if (isString(value))
1459
- return `'${value.replace(this.stringEscapeRegex, this.stringEscapeFn)}'`;
1460
- if (isNumber(value)) return value.toString();
1461
- if (value === true) return "true";
1462
- if (value === false) return "false";
1463
- if (value === null) return "null";
1464
- if (typeof value === "undefined") return "undefined";
1465
-
1466
- throw $parseMinErr("esc", "IMPOSSIBLE");
1467
- },
1468
-
1469
- nextId(skip, init) {
1470
- const id = `v${this.state.nextId++}`;
1471
- if (!skip) {
1472
- this.current().vars.push(id + (init ? `=${init}` : ""));
1473
- }
1474
- return id;
1475
- },
1476
-
1477
- current() {
1478
- return this.state[this.state.computing];
1479
- },
1480
- };
1481
-
1482
- function ASTInterpreter($filter) {
1483
- this.$filter = $filter;
1484
- }
1485
-
1486
- ASTInterpreter.prototype = {
1487
- compile(ast) {
1488
- const self = this;
1489
- findConstantAndWatchExpressions(ast, self.$filter);
1490
- let assignable;
1491
- let assign;
1492
- if ((assignable = assignableAST(ast))) {
1493
- assign = this.recurse(assignable);
1494
- }
1495
- const toWatch = getInputs(ast.body);
1496
- let inputs;
1497
- if (toWatch) {
1498
- inputs = [];
1499
- forEach(toWatch, (watch, key) => {
1500
- const input = self.recurse(watch);
1501
- input.isPure = watch.isPure;
1502
- watch.input = input;
1503
- inputs.push(input);
1504
- watch.watchId = key;
1505
- });
1506
- }
1507
- const expressions = [];
1508
- forEach(ast.body, (expression) => {
1509
- expressions.push(self.recurse(expression.expression));
1510
- });
1511
- const fn =
1512
- ast.body.length === 0
1513
- ? () => {}
1514
- : ast.body.length === 1
1515
- ? expressions[0]
1516
- : function (scope, locals) {
1517
- let lastValue;
1518
- forEach(expressions, (exp) => {
1519
- lastValue = exp(scope, locals);
1520
- });
1521
- return lastValue;
1522
- };
1523
- if (assign) {
1524
- fn.assign = function (scope, value, locals) {
1525
- return assign(scope, locals, value);
1526
- };
1527
- }
1528
- if (inputs) {
1529
- fn.inputs = inputs;
1530
- }
1531
- return fn;
1532
- },
1533
-
1534
- recurse(ast, context, create) {
1535
- let left;
1536
- let right;
1537
- const self = this;
1538
- let args;
1539
- if (ast.input) {
1540
- return this.inputs(ast.input, ast.watchId);
1541
- }
1542
- switch (ast.type) {
1543
- case ASTType.Literal:
1544
- return this.value(ast.value, context);
1545
- case ASTType.UnaryExpression:
1546
- right = this.recurse(ast.argument);
1547
- return this[`unary${ast.operator}`](right, context);
1548
- case ASTType.BinaryExpression:
1549
- left = this.recurse(ast.left);
1550
- right = this.recurse(ast.right);
1551
- return this[`binary${ast.operator}`](left, right, context);
1552
- case ASTType.LogicalExpression:
1553
- left = this.recurse(ast.left);
1554
- right = this.recurse(ast.right);
1555
- return this[`binary${ast.operator}`](left, right, context);
1556
- case ASTType.ConditionalExpression:
1557
- return this["ternary?:"](
1558
- this.recurse(ast.test),
1559
- this.recurse(ast.alternate),
1560
- this.recurse(ast.consequent),
1561
- context,
1562
- );
1563
- case ASTType.Identifier:
1564
- return self.identifier(ast.name, context, create);
1565
- case ASTType.MemberExpression:
1566
- left = this.recurse(ast.object, false, !!create);
1567
- if (!ast.computed) {
1568
- right = ast.property.name;
1569
- }
1570
- if (ast.computed) right = this.recurse(ast.property);
1571
- return ast.computed
1572
- ? this.computedMember(left, right, context, create)
1573
- : this.nonComputedMember(left, right, context, create);
1574
- case ASTType.CallExpression:
1575
- args = [];
1576
- forEach(ast.arguments, (expr) => {
1577
- args.push(self.recurse(expr));
1578
- });
1579
- if (ast.filter) right = this.$filter(ast.callee.name);
1580
- if (!ast.filter) right = this.recurse(ast.callee, true);
1581
- return ast.filter
1582
- ? function (scope, locals, assign, inputs) {
1583
- const values = [];
1584
- for (let i = 0; i < args.length; ++i) {
1585
- values.push(args[i](scope, locals, assign, inputs));
1586
- }
1587
- const value = right.apply(undefined, values, inputs);
1588
- return context
1589
- ? { context: undefined, name: undefined, value }
1590
- : value;
1591
- }
1592
- : function (scope, locals, assign, inputs) {
1593
- const rhs = right(scope, locals, assign, inputs);
1594
- let value;
1595
- if (rhs.value != null) {
1596
- const values = [];
1597
- for (let i = 0; i < args.length; ++i) {
1598
- values.push(args[i](scope, locals, assign, inputs));
1599
- }
1600
- value = rhs.value.apply(rhs.context, values);
1601
- }
1602
- return context ? { value } : value;
1603
- };
1604
- case ASTType.AssignmentExpression:
1605
- left = this.recurse(ast.left, true, 1);
1606
- right = this.recurse(ast.right);
1607
- return function (scope, locals, assign, inputs) {
1608
- const lhs = left(scope, locals, assign, inputs);
1609
- const rhs = right(scope, locals, assign, inputs);
1610
- lhs.context[lhs.name] = rhs;
1611
- return context ? { value: rhs } : rhs;
1612
- };
1613
- case ASTType.ArrayExpression:
1614
- args = [];
1615
- forEach(ast.elements, (expr) => {
1616
- args.push(self.recurse(expr));
1617
- });
1618
- return function (scope, locals, assign, inputs) {
1619
- const value = [];
1620
- for (let i = 0; i < args.length; ++i) {
1621
- value.push(args[i](scope, locals, assign, inputs));
1622
- }
1623
- return context ? { value } : value;
1624
- };
1625
- case ASTType.ObjectExpression:
1626
- args = [];
1627
- forEach(ast.properties, (property) => {
1628
- if (property.computed) {
1629
- args.push({
1630
- key: self.recurse(property.key),
1631
- computed: true,
1632
- value: self.recurse(property.value),
1633
- });
1634
- } else {
1635
- args.push({
1636
- key:
1637
- property.key.type === ASTType.Identifier
1638
- ? property.key.name
1639
- : `${property.key.value}`,
1640
- computed: false,
1641
- value: self.recurse(property.value),
1642
- });
1643
- }
1644
- });
1645
- return function (scope, locals, assign, inputs) {
1646
- const value = {};
1647
- for (let i = 0; i < args.length; ++i) {
1648
- if (args[i].computed) {
1649
- value[args[i].key(scope, locals, assign, inputs)] = args[i].value(
1650
- scope,
1651
- locals,
1652
- assign,
1653
- inputs,
1654
- );
1655
- } else {
1656
- value[args[i].key] = args[i].value(scope, locals, assign, inputs);
1657
- }
1658
- }
1659
- return context ? { value } : value;
1660
- };
1661
- case ASTType.ThisExpression:
1662
- return function (scope) {
1663
- return context ? { value: scope } : scope;
1664
- };
1665
- case ASTType.LocalsExpression:
1666
- return function (scope, locals) {
1667
- return context ? { value: locals } : locals;
1668
- };
1669
- case ASTType.NGValueParameter:
1670
- return function (scope, locals, assign) {
1671
- return context ? { value: assign } : assign;
1672
- };
1673
- }
1674
- },
1675
-
1676
- "unary+": function (argument, context) {
1677
- return function (scope, locals, assign, inputs) {
1678
- let arg = argument(scope, locals, assign, inputs);
1679
- if (isDefined(arg)) {
1680
- arg = +arg;
1681
- } else {
1682
- arg = 0;
1683
- }
1684
- return context ? { value: arg } : arg;
1685
- };
1686
- },
1687
- "unary-": function (argument, context) {
1688
- return function (scope, locals, assign, inputs) {
1689
- let arg = argument(scope, locals, assign, inputs);
1690
- if (isDefined(arg)) {
1691
- arg = -arg;
1692
- } else {
1693
- arg = -0;
1694
- }
1695
- return context ? { value: arg } : arg;
1696
- };
1697
- },
1698
- "unary!": function (argument, context) {
1699
- return function (scope, locals, assign, inputs) {
1700
- const arg = !argument(scope, locals, assign, inputs);
1701
- return context ? { value: arg } : arg;
1702
- };
1703
- },
1704
- "binary+": function (left, right, context) {
1705
- return function (scope, locals, assign, inputs) {
1706
- const lhs = left(scope, locals, assign, inputs);
1707
- const rhs = right(scope, locals, assign, inputs);
1708
- const arg = plusFn(lhs, rhs);
1709
- return context ? { value: arg } : arg;
1710
- };
1711
- },
1712
- "binary-": function (left, right, context) {
1713
- return function (scope, locals, assign, inputs) {
1714
- const lhs = left(scope, locals, assign, inputs);
1715
- const rhs = right(scope, locals, assign, inputs);
1716
- const arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
1717
- return context ? { value: arg } : arg;
1718
- };
1719
- },
1720
- "binary*": function (left, right, context) {
1721
- return function (scope, locals, assign, inputs) {
1722
- const arg =
1723
- left(scope, locals, assign, inputs) *
1724
- right(scope, locals, assign, inputs);
1725
- return context ? { value: arg } : arg;
1726
- };
1727
- },
1728
- "binary/": function (left, right, context) {
1729
- return function (scope, locals, assign, inputs) {
1730
- const arg =
1731
- left(scope, locals, assign, inputs) /
1732
- right(scope, locals, assign, inputs);
1733
- return context ? { value: arg } : arg;
1734
- };
1735
- },
1736
- "binary%": function (left, right, context) {
1737
- return function (scope, locals, assign, inputs) {
1738
- const arg =
1739
- left(scope, locals, assign, inputs) %
1740
- right(scope, locals, assign, inputs);
1741
- return context ? { value: arg } : arg;
1742
- };
1743
- },
1744
- "binary===": function (left, right, context) {
1745
- return function (scope, locals, assign, inputs) {
1746
- const arg =
1747
- left(scope, locals, assign, inputs) ===
1748
- right(scope, locals, assign, inputs);
1749
- return context ? { value: arg } : arg;
1750
- };
1751
- },
1752
- "binary!==": function (left, right, context) {
1753
- return function (scope, locals, assign, inputs) {
1754
- const arg =
1755
- left(scope, locals, assign, inputs) !==
1756
- right(scope, locals, assign, inputs);
1757
- return context ? { value: arg } : arg;
1758
- };
1759
- },
1760
- "binary==": function (left, right, context) {
1761
- return function (scope, locals, assign, inputs) {
1762
- const arg =
1763
- left(scope, locals, assign, inputs) ==
1764
- right(scope, locals, assign, inputs);
1765
- return context ? { value: arg } : arg;
1766
- };
1767
- },
1768
- "binary!=": function (left, right, context) {
1769
- return function (scope, locals, assign, inputs) {
1770
- const arg =
1771
- left(scope, locals, assign, inputs) !=
1772
- right(scope, locals, assign, inputs);
1773
- return context ? { value: arg } : arg;
1774
- };
1775
- },
1776
- "binary<": function (left, right, context) {
1777
- return function (scope, locals, assign, inputs) {
1778
- const arg =
1779
- left(scope, locals, assign, inputs) <
1780
- right(scope, locals, assign, inputs);
1781
- return context ? { value: arg } : arg;
1782
- };
1783
- },
1784
- "binary>": function (left, right, context) {
1785
- return function (scope, locals, assign, inputs) {
1786
- const arg =
1787
- left(scope, locals, assign, inputs) >
1788
- right(scope, locals, assign, inputs);
1789
- return context ? { value: arg } : arg;
1790
- };
1791
- },
1792
- "binary<=": function (left, right, context) {
1793
- return function (scope, locals, assign, inputs) {
1794
- const arg =
1795
- left(scope, locals, assign, inputs) <=
1796
- right(scope, locals, assign, inputs);
1797
- return context ? { value: arg } : arg;
1798
- };
1799
- },
1800
- "binary>=": function (left, right, context) {
1801
- return function (scope, locals, assign, inputs) {
1802
- const arg =
1803
- left(scope, locals, assign, inputs) >=
1804
- right(scope, locals, assign, inputs);
1805
- return context ? { value: arg } : arg;
1806
- };
1807
- },
1808
- "binary&&": function (left, right, context) {
1809
- return function (scope, locals, assign, inputs) {
1810
- const arg =
1811
- left(scope, locals, assign, inputs) &&
1812
- right(scope, locals, assign, inputs);
1813
- return context ? { value: arg } : arg;
1814
- };
1815
- },
1816
- "binary||": function (left, right, context) {
1817
- return function (scope, locals, assign, inputs) {
1818
- const arg =
1819
- left(scope, locals, assign, inputs) ||
1820
- right(scope, locals, assign, inputs);
1821
- return context ? { value: arg } : arg;
1822
- };
1823
- },
1824
- "ternary?:": function (test, alternate, consequent, context) {
1825
- return function (scope, locals, assign, inputs) {
1826
- const arg = test(scope, locals, assign, inputs)
1827
- ? alternate(scope, locals, assign, inputs)
1828
- : consequent(scope, locals, assign, inputs);
1829
- return context ? { value: arg } : arg;
1830
- };
1831
- },
1832
- value(value, context) {
1833
- return function () {
1834
- return context ? { context: undefined, name: undefined, value } : value;
1835
- };
1836
- },
1837
- identifier(name, context, create) {
1838
- return function (scope, locals) {
1839
- const base = locals && name in locals ? locals : scope;
1840
- if (create && create !== 1 && base && base[name] == null) {
1841
- base[name] = {};
1842
- }
1843
- const value = base ? base[name] : undefined;
1844
- if (context) {
1845
- return { context: base, name, value };
1846
- }
1847
- return value;
1848
- };
1849
- },
1850
- computedMember(left, right, context, create) {
1851
- return function (scope, locals, assign, inputs) {
1852
- const lhs = left(scope, locals, assign, inputs);
1853
- let rhs;
1854
- let value;
1855
- if (lhs != null) {
1856
- rhs = right(scope, locals, assign, inputs);
1857
- rhs = getStringValue(rhs);
1858
- if (create && create !== 1) {
1859
- if (lhs && !lhs[rhs]) {
1860
- lhs[rhs] = {};
1861
- }
1862
- }
1863
- value = lhs[rhs];
1864
- }
1865
- if (context) {
1866
- return { context: lhs, name: rhs, value };
1867
- }
1868
- return value;
1869
- };
1870
- },
1871
- nonComputedMember(left, right, context, create) {
1872
- return function (scope, locals, assign, inputs) {
1873
- const lhs = left(scope, locals, assign, inputs);
1874
- if (create && create !== 1) {
1875
- if (lhs && lhs[right] == null) {
1876
- lhs[right] = {};
1877
- }
1878
- }
1879
- const value = lhs != null ? lhs[right] : undefined;
1880
- if (context) {
1881
- return { context: lhs, name: right, value };
1882
- }
1883
- return value;
1884
- };
1885
- },
1886
- inputs(input, watchId) {
1887
- return function (scope, value, locals, inputs) {
1888
- if (inputs) return inputs[watchId];
1889
- return input(scope, value, locals);
1890
- };
1891
- },
1892
- };
14
+ /// ////////////////////////////////
1893
15
 
1894
16
  /**
1895
- * @constructor
17
+ * @typedef {function(string|function(import('../scope/scope').Scope):any, function(any, Scope, any):any=, boolean=): import('../../types').CompiledExpression} ParseService
1896
18
  */
1897
- class Parser {
1898
- constructor(lexer, $filter, options) {
1899
- this.ast = new AST(lexer, options);
1900
- this.astCompiler = options.csp
1901
- ? new ASTInterpreter($filter)
1902
- : new ASTCompiler($filter);
1903
- }
1904
-
1905
- parse(text) {
1906
- const { ast, oneTime } = this.getAst(text);
1907
- const fn = this.astCompiler.compile(ast);
1908
- fn.literal = isLiteral(ast);
1909
- fn.constant = isConstant(ast);
1910
- fn.oneTime = oneTime;
1911
- return fn;
1912
- }
1913
-
1914
- getAst(exp) {
1915
- let oneTime = false;
1916
- exp = exp.trim();
1917
-
1918
- if (exp.startsWith("::")) {
1919
- oneTime = true;
1920
- exp = exp.substring(2);
1921
- }
1922
- return {
1923
- ast: this.ast.ast(exp),
1924
- oneTime,
1925
- };
1926
- }
1927
- }
1928
-
1929
- function getValueOf(value) {
1930
- return isFunction(value.valueOf)
1931
- ? value.valueOf()
1932
- : objectValueOf.call(value);
1933
- }
1934
-
1935
- /// ////////////////////////////////
1936
19
 
1937
20
  /**
1938
21
  * @ngdoc service
@@ -2116,7 +199,7 @@ export function $ParseProvider() {
2116
199
  }
2117
200
 
2118
201
  //Primitive or NaN
2119
- // eslint-disable-next-line no-self-compare
202
+
2120
203
  return (
2121
204
  newValue === oldValueOfValue ||
2122
205
  (newValue !== newValue && oldValueOfValue !== oldValueOfValue)
@@ -2393,7 +476,7 @@ export function inputsWatchDelegate(
2393
476
 
2394
477
  if (inputExpressions.length === 1) {
2395
478
  let oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
2396
- // eslint-disable-next-line prefer-destructuring
479
+
2397
480
  inputExpressions = inputExpressions[0];
2398
481
  return scope.$watch(
2399
482
  ($scope) => {
@@ -2428,12 +511,10 @@ export function inputsWatchDelegate(
2428
511
  (scope) => {
2429
512
  let changed = false;
2430
513
 
2431
- // eslint-disable-next-line no-plusplus
2432
514
  for (let i = 0, ii = inputExpressions.length; i < ii; i++) {
2433
515
  const newInputValue = inputExpressions[i](scope);
2434
516
  if (
2435
517
  changed ||
2436
- // eslint-disable-next-line no-cond-assign
2437
518
  (changed = !expressionInputDirtyCheck(
2438
519
  newInputValue,
2439
520
  oldInputValueOfValues[i],
@@ -2541,15 +622,13 @@ export function expressionInputDirtyCheck(
2541
622
  }
2542
623
 
2543
624
  // Primitive or NaN
2544
- // eslint-disable-next-line no-self-compare
625
+
2545
626
  return (
2546
627
  newValue === oldValueOfValue ||
2547
- // eslint-disable-next-line no-self-compare
2548
628
  (newValue !== newValue && oldValueOfValue !== oldValueOfValue)
2549
629
  );
2550
630
  }
2551
631
 
2552
- // eslint-disable-next-line class-methods-use-this
2553
632
  export function isAllDefined(value) {
2554
633
  let allDefined = true;
2555
634
  forEach(value, (val) => {