@angular-wave/angular.ts 0.0.49 → 0.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@angular-wave/angular.ts",
3
3
  "license": "MIT",
4
- "version": "0.0.49",
4
+ "version": "0.0.50",
5
5
  "type": "module",
6
6
  "main": "dist/angular-ts.esm.js",
7
7
  "browser": "dist/angular-ts.umd.js",
@@ -6,6 +6,7 @@ import {
6
6
  valueFn,
7
7
  extend,
8
8
  } from "../../shared/utils";
9
+ import { constantWatchDelegate } from "../parser/parse";
9
10
 
10
11
  const $interpolateMinErr = minErr("$interpolate");
11
12
  $interpolateMinErr.throwNoconcat = function (text) {
@@ -112,24 +113,6 @@ export function $InterpolateProvider() {
112
113
  .replace(escapedEndRegexp, endSymbol);
113
114
  }
114
115
 
115
- // TODO: this is the same as the constantWatchDelegate in parse.js
116
- function constantWatchDelegate(
117
- scope,
118
- listener,
119
- objectEquality,
120
- constantInterp,
121
- ) {
122
- const unwatch = scope.$watch(
123
- (scope) => {
124
- unwatch();
125
- return constantInterp(scope);
126
- },
127
- listener,
128
- objectEquality,
129
- );
130
- return unwatch;
131
- }
132
-
133
116
  /**
134
117
  * @ngdoc service
135
118
  * @name $interpolate
@@ -3,15 +3,54 @@ import { isAssignable } from "./shared";
3
3
  import { ASTType } from "./ast-type";
4
4
 
5
5
  /**
6
- * @param {import('./lexer').Lexer} lexer
7
- * @param {*} options
6
+ * @typedef {Object} ASTNode
7
+ * @property {string} type - The type of the AST node.
8
+ * @property {string} [name] - The name of the identifier.
9
+ * @property {string} [kind] - The kind of the property (e.g., 'init').
10
+ * @property {*} [value] - The value of the node if it is a literal.
11
+ * @property {ASTNode[]} [elements] - The elements of an array node.
12
+ * @property {ASTNode[]} [properties] - The properties of an object node.
13
+ * @property {ASTNode} [key] - The key of an object property.
14
+ * @property {ASTNode} [value] - The value of an object property.
15
+ * @property {ASTNode} [left] - The left-hand side of a binary expression.
16
+ * @property {ASTNode} [right] - The right-hand side of a binary expression.
17
+ * @property {ASTNode} [argument] - The argument of a unary expression.
18
+ * @property {ASTNode} [test] - The test expression of a conditional expression.
19
+ * @property {ASTNode} [alternate] - The alternate expression of a conditional expression.
20
+ * @property {ASTNode} [consequent] - The consequent expression of a conditional expression.
21
+ * @property {ASTNode[]} [body] - The body of a program or block statement.
22
+ * @property {ASTNode} [expression] - The expression of an expression statement.
23
+ * @property {ASTNode} [callee] - The callee of a call expression.
24
+ * @property {ASTNode[]} [arguments] - The arguments of a call expression.
25
+ * @property {boolean} [prefix] - Indicates if a unary operator is a prefix.
26
+ * @property {ASTNode} [object] - The object of a member expression.
27
+ * @property {ASTNode} [property] - The property of a member expression.
28
+ * @property {boolean} [computed] - Indicates if a member expression is computed.
29
+ * @property {string} [operator] - The operator of a binary or logical expression.
8
30
  */
9
- export function AST(lexer, options) {
10
- this.lexer = lexer;
11
- this.options = options;
12
- }
13
31
 
14
- AST.prototype = {
32
+ /**
33
+ * @param {import('./lexer').Lexer} lexer - The lexer instance for tokenizing input
34
+ * @param {import("./parser").ParserOptions} options
35
+ */
36
+ export class AST {
37
+ constructor(lexer, options) {
38
+ /** @type {import('./lexer').Lexer} */
39
+ this.lexer = lexer;
40
+
41
+ /** @type {import("./parser").ParserOptions} */
42
+ this.options = options;
43
+ this.selfReferential = {
44
+ this: { type: ASTType.ThisExpression },
45
+ $locals: { type: ASTType.LocalsExpression },
46
+ };
47
+ }
48
+
49
+ /**
50
+ * Parses the input text and generates an AST.
51
+ * @param {string} text - The input text to parse.
52
+ * @returns {ASTNode} The root node of the AST.
53
+ */
15
54
  ast(text) {
16
55
  this.text = text;
17
56
  this.tokens = this.lexer.lex(text);
@@ -23,8 +62,12 @@ AST.prototype = {
23
62
  }
24
63
 
25
64
  return value;
26
- },
65
+ }
27
66
 
67
+ /**
68
+ * Parses a program.
69
+ * @returns {ASTNode} The program node.
70
+ */
28
71
  program() {
29
72
  const body = [];
30
73
  let hasMore = true;
@@ -36,27 +79,43 @@ AST.prototype = {
36
79
  }
37
80
  }
38
81
  return { type: ASTType.Program, body };
39
- },
82
+ }
40
83
 
84
+ /**
85
+ * Parses an expression statement.
86
+ * @returns {ASTNode} The expression statement node.
87
+ */
41
88
  expressionStatement() {
42
89
  return {
43
90
  type: ASTType.ExpressionStatement,
44
91
  expression: this.filterChain(),
45
92
  };
46
- },
93
+ }
47
94
 
95
+ /**
96
+ * Parses a filter chain.
97
+ * @returns {ASTNode} The filter chain node.
98
+ */
48
99
  filterChain() {
49
100
  let left = this.expression();
50
101
  while (this.expect("|")) {
51
102
  left = this.filter(left);
52
103
  }
53
104
  return left;
54
- },
105
+ }
55
106
 
107
+ /**
108
+ * Parses an expression.
109
+ * @returns {ASTNode} The expression node.
110
+ */
56
111
  expression() {
57
112
  return this.assignment();
58
- },
113
+ }
59
114
 
115
+ /**
116
+ * Parses an assignment expression.
117
+ * @returns {ASTNode} The assignment expression node.
118
+ */
60
119
  assignment() {
61
120
  let result = this.ternary();
62
121
  if (this.expect("=")) {
@@ -72,8 +131,12 @@ AST.prototype = {
72
131
  };
73
132
  }
74
133
  return result;
75
- },
134
+ }
76
135
 
136
+ /**
137
+ * Parses a ternary expression.
138
+ * @returns {ASTNode} The ternary expression node.
139
+ */
77
140
  ternary() {
78
141
  const test = this.logicalOR();
79
142
  let alternate;
@@ -91,8 +154,12 @@ AST.prototype = {
91
154
  }
92
155
  }
93
156
  return test;
94
- },
157
+ }
95
158
 
159
+ /**
160
+ * Parses a logical OR expression.
161
+ * @returns {ASTNode} The logical OR expression node.
162
+ */
96
163
  logicalOR() {
97
164
  let left = this.logicalAND();
98
165
  while (this.expect("||")) {
@@ -104,8 +171,12 @@ AST.prototype = {
104
171
  };
105
172
  }
106
173
  return left;
107
- },
174
+ }
108
175
 
176
+ /**
177
+ * Parses a logical AND expression.
178
+ * @returns {ASTNode} The logical AND expression node.
179
+ */
109
180
  logicalAND() {
110
181
  let left = this.equality();
111
182
  while (this.expect("&&")) {
@@ -117,77 +188,101 @@ AST.prototype = {
117
188
  };
118
189
  }
119
190
  return left;
120
- },
191
+ }
121
192
 
193
+ /**
194
+ * Parses an equality expression.
195
+ * @returns {ASTNode} The equality expression node.
196
+ */
122
197
  equality() {
123
198
  let left = this.relational();
124
199
  let token;
125
200
  while ((token = this.expect("==", "!=", "===", "!=="))) {
126
201
  left = {
127
202
  type: ASTType.BinaryExpression,
128
- operator: token.text,
203
+ operator: /** @type {import("./lexer").Token} */ (token).text,
129
204
  left,
130
205
  right: this.relational(),
131
206
  };
132
207
  }
133
208
  return left;
134
- },
209
+ }
135
210
 
211
+ /**
212
+ * Parses a relational expression.
213
+ * @returns {ASTNode} The relational expression node.
214
+ */
136
215
  relational() {
137
216
  let left = this.additive();
138
217
  let token;
139
218
  while ((token = this.expect("<", ">", "<=", ">="))) {
140
219
  left = {
141
220
  type: ASTType.BinaryExpression,
142
- operator: token.text,
221
+ operator: /** @type {import("./lexer").Token} */ (token).text,
143
222
  left,
144
223
  right: this.additive(),
145
224
  };
146
225
  }
147
226
  return left;
148
- },
227
+ }
149
228
 
229
+ /**
230
+ * Parses an additive expression.
231
+ * @returns {ASTNode} The additive expression node.
232
+ */
150
233
  additive() {
151
234
  let left = this.multiplicative();
152
235
  let token;
153
236
  while ((token = this.expect("+", "-"))) {
154
237
  left = {
155
238
  type: ASTType.BinaryExpression,
156
- operator: token.text,
239
+ operator: /** @type {import("./lexer").Token} */ (token).text,
157
240
  left,
158
241
  right: this.multiplicative(),
159
242
  };
160
243
  }
161
244
  return left;
162
- },
245
+ }
163
246
 
247
+ /**
248
+ * Parses a multiplicative expression.
249
+ * @returns {ASTNode} The multiplicative expression node.
250
+ */
164
251
  multiplicative() {
165
252
  let left = this.unary();
166
253
  let token;
167
254
  while ((token = this.expect("*", "/", "%"))) {
168
255
  left = {
169
256
  type: ASTType.BinaryExpression,
170
- operator: token.text,
257
+ operator: /** @type {import("./lexer").Token} */ (token).text,
171
258
  left,
172
259
  right: this.unary(),
173
260
  };
174
261
  }
175
262
  return left;
176
- },
263
+ }
177
264
 
265
+ /**
266
+ * Parses a unary expression.
267
+ * @returns {ASTNode} The unary expression node.
268
+ */
178
269
  unary() {
179
270
  let token;
180
271
  if ((token = this.expect("+", "-", "!"))) {
181
272
  return {
182
273
  type: ASTType.UnaryExpression,
183
- operator: token.text,
274
+ operator: /** @type {import("./lexer").Token} */ (token).text,
184
275
  prefix: true,
185
276
  argument: this.unary(),
186
277
  };
187
278
  }
188
279
  return this.primary();
189
- },
280
+ }
190
281
 
282
+ /**
283
+ * Parses a primary expression.
284
+ * @returns {ASTNode} The primary expression node.
285
+ */
191
286
  primary() {
192
287
  let primary;
193
288
  if (this.expect("(")) {
@@ -200,38 +295,43 @@ AST.prototype = {
200
295
  } else if (
201
296
  Object.prototype.hasOwnProperty.call(
202
297
  this.selfReferential,
203
- this.peek().text,
298
+ /** @type {import("./lexer").Token} */ (this.peek()).text,
204
299
  )
205
300
  ) {
206
301
  primary = structuredClone(this.selfReferential[this.consume().text]);
207
302
  } else if (
208
303
  Object.prototype.hasOwnProperty.call(
209
304
  this.options.literals,
210
- this.peek().text,
305
+ /** @type {import("./lexer").Token} */ (this.peek()).text,
211
306
  )
212
307
  ) {
213
308
  primary = {
214
309
  type: ASTType.Literal,
215
310
  value: this.options.literals[this.consume().text],
216
311
  };
217
- } else if (this.peek().identifier) {
312
+ } else if (
313
+ /** @type {import("./lexer").Token} */ (this.peek()).identifier
314
+ ) {
218
315
  primary = this.identifier();
219
- } else if (this.peek().constant) {
316
+ } else if (/** @type {import("./lexer").Token} */ (this.peek()).constant) {
220
317
  primary = this.constant();
221
318
  } else {
222
- this.throwError("not a primary expression", this.peek());
319
+ this.throwError(
320
+ "not a primary expression",
321
+ /** @type {import("./lexer").Token} */ (this.peek()),
322
+ );
223
323
  }
224
324
 
225
325
  let next;
226
326
  while ((next = this.expect("(", "[", "."))) {
227
- if (next.text === "(") {
327
+ if (/** @type {import("./lexer").Token} */ (next).text === "(") {
228
328
  primary = {
229
329
  type: ASTType.CallExpression,
230
330
  callee: primary,
231
331
  arguments: this.parseArguments(),
232
332
  };
233
333
  this.consume(")");
234
- } else if (next.text === "[") {
334
+ } else if (/** @type {import("./lexer").Token} */ (next).text === "[") {
235
335
  primary = {
236
336
  type: ASTType.MemberExpression,
237
337
  object: primary,
@@ -239,7 +339,7 @@ AST.prototype = {
239
339
  computed: true,
240
340
  };
241
341
  this.consume("]");
242
- } else if (next.text === ".") {
342
+ } else if (/** @type {import("./lexer").Token} */ (next).text === ".") {
243
343
  primary = {
244
344
  type: ASTType.MemberExpression,
245
345
  object: primary,
@@ -251,9 +351,15 @@ AST.prototype = {
251
351
  }
252
352
  }
253
353
  return primary;
254
- },
354
+ }
255
355
 
356
+ /**
357
+ * Parses a filter.
358
+ * @param {ASTNode} baseExpression - The base expression to apply the filter to.
359
+ * @returns {ASTNode} The filter node.
360
+ */
256
361
  filter(baseExpression) {
362
+ /** @type {ASTNode[]} */
257
363
  const args = [baseExpression];
258
364
  const result = {
259
365
  type: ASTType.CallExpression,
@@ -267,9 +373,14 @@ AST.prototype = {
267
373
  }
268
374
 
269
375
  return result;
270
- },
376
+ }
271
377
 
378
+ /**
379
+ * Parses function arguments.
380
+ * @returns {ASTNode[]} The arguments array.
381
+ */
272
382
  parseArguments() {
383
+ /** @type {ASTNode[]} */
273
384
  const args = [];
274
385
  if (this.peekToken().text !== ")") {
275
386
  do {
@@ -277,22 +388,35 @@ AST.prototype = {
277
388
  } while (this.expect(","));
278
389
  }
279
390
  return args;
280
- },
391
+ }
281
392
 
393
+ /**
394
+ * Parses an identifier.
395
+ * @returns {ASTNode} The identifier node.
396
+ */
282
397
  identifier() {
283
398
  const token = this.consume();
284
399
  if (!token.identifier) {
285
400
  this.throwError("is not a valid identifier", token);
286
401
  }
287
402
  return { type: ASTType.Identifier, name: token.text };
288
- },
403
+ }
289
404
 
405
+ /**
406
+ * Parses a constant.
407
+ * @returns {ASTNode} The constant node.
408
+ */
290
409
  constant() {
291
410
  // TODO check that it is a constant
292
411
  return { type: ASTType.Literal, value: this.consume().value };
293
- },
412
+ }
294
413
 
414
+ /**
415
+ * Parses an array declaration.
416
+ * @returns {ASTNode} The array declaration node.
417
+ */
295
418
  arrayDeclaration() {
419
+ /** @type {ASTNode[]} */
296
420
  const elements = [];
297
421
  if (this.peekToken().text !== "]") {
298
422
  do {
@@ -306,10 +430,16 @@ AST.prototype = {
306
430
  this.consume("]");
307
431
 
308
432
  return { type: ASTType.ArrayExpression, elements };
309
- },
433
+ }
310
434
 
435
+ /**
436
+ * Parses an object.
437
+ * @returns {ASTNode} The object node.
438
+ */
311
439
  object() {
440
+ /** @type {ASTNode[]} */
312
441
  const properties = [];
442
+ /** @type {ASTNode} */
313
443
  let property;
314
444
  if (this.peekToken().text !== "}") {
315
445
  do {
@@ -318,12 +448,14 @@ AST.prototype = {
318
448
  break;
319
449
  }
320
450
  property = { type: ASTType.Property, kind: "init" };
321
- if (this.peek().constant) {
451
+ if (/** @type {import("./lexer").Token} */ (this.peek()).constant) {
322
452
  property.key = this.constant();
323
453
  property.computed = false;
324
454
  this.consume(":");
325
455
  property.value = this.expression();
326
- } else if (this.peek().identifier) {
456
+ } else if (
457
+ /** @type {import("./lexer").Token} */ (this.peek()).identifier
458
+ ) {
327
459
  property.key = this.identifier();
328
460
  property.computed = false;
329
461
  if (this.peek(":")) {
@@ -340,7 +472,10 @@ AST.prototype = {
340
472
  this.consume(":");
341
473
  property.value = this.expression();
342
474
  } else {
343
- this.throwError("invalid key", this.peek());
475
+ this.throwError(
476
+ "invalid key",
477
+ /** @type {import("./lexer").Token} */ (this.peek()),
478
+ );
344
479
  }
345
480
  properties.push(property);
346
481
  } while (this.expect(","));
@@ -348,8 +483,13 @@ AST.prototype = {
348
483
  this.consume("}");
349
484
 
350
485
  return { type: ASTType.ObjectExpression, properties };
351
- },
486
+ }
352
487
 
488
+ /**
489
+ * Throws a syntax error.
490
+ * @param {string} msg - The error message.
491
+ * @param {import("./lexer").Token} [token] - The token that caused the error.
492
+ */
353
493
  throwError(msg, token) {
354
494
  throw $parseMinErr(
355
495
  "syntax",
@@ -360,8 +500,13 @@ AST.prototype = {
360
500
  this.text,
361
501
  this.text.substring(token.index),
362
502
  );
363
- },
503
+ }
364
504
 
505
+ /**
506
+ * Consumes a token if it matches the expected type.
507
+ * @param {string} [e1] - The expected token type.
508
+ * @returns {import("./lexer").Token} The consumed token.
509
+ */
365
510
  consume(e1) {
366
511
  if (this.tokens.length === 0) {
367
512
  throw $parseMinErr(
@@ -373,11 +518,19 @@ AST.prototype = {
373
518
 
374
519
  const token = this.expect(e1);
375
520
  if (!token) {
376
- this.throwError(`is unexpected, expecting [${e1}]`, this.peek());
521
+ this.throwError(
522
+ `is unexpected, expecting [${e1}]`,
523
+ /** @type {import("./lexer").Token} */ (this.peek()),
524
+ );
525
+ } else {
526
+ return /** @type {import("./lexer").Token} */ (token);
377
527
  }
378
- return token;
379
- },
528
+ }
380
529
 
530
+ /**
531
+ * Returns the next token without consuming it.
532
+ * @returns {import("./lexer").Token} The next token.
533
+ */
381
534
  peekToken() {
382
535
  if (this.tokens.length === 0) {
383
536
  throw $parseMinErr(
@@ -387,40 +540,48 @@ AST.prototype = {
387
540
  );
388
541
  }
389
542
  return this.tokens[0];
390
- },
391
-
392
- peek(e1, e2, e3, e4) {
393
- return this.peekAhead(0, e1, e2, e3, e4);
394
- },
395
-
396
- peekAhead(i, e1, e2, e3, e4) {
543
+ }
544
+
545
+ /**
546
+ * Checks if the next token matches any of the expected types.
547
+ * @param {...string} [expected] - The expected token types.
548
+ * @returns {import('./lexer').Token|boolean} The next token if it matches, otherwise false.
549
+ */
550
+ peek(...expected) {
551
+ return this.peekAhead(0, ...expected);
552
+ }
553
+
554
+ /**
555
+ * Checks if the token at the specified index matches any of the expected types.
556
+ * @param {number} i - The index to check.
557
+ * @param {...string} [expected] - The expected token types.
558
+ * @returns {import("./lexer").Token|boolean} The token at the specified index if it matches, otherwise false.
559
+ */
560
+ peekAhead(i, ...expected) {
397
561
  if (this.tokens.length > i) {
398
562
  const token = this.tokens[i];
399
563
  const t = token.text;
400
564
  if (
401
- t === e1 ||
402
- t === e2 ||
403
- t === e3 ||
404
- t === e4 ||
405
- (!e1 && !e2 && !e3 && !e4)
565
+ expected.includes(t) ||
566
+ (!expected[0] && !expected[1] && !expected[2] && !expected[3])
406
567
  ) {
407
568
  return token;
408
569
  }
409
570
  }
410
571
  return false;
411
- },
412
-
413
- expect(e1, e2, e3, e4) {
414
- const token = this.peek(e1, e2, e3, e4);
572
+ }
573
+
574
+ /**
575
+ * Consumes the next token if it matches any of the expected types.
576
+ * @param {...string} [expected] - The expected token types.
577
+ * @returns {import("./lexer").Token|boolean} The consumed token if it matches, otherwise false.
578
+ */
579
+ expect(...expected) {
580
+ const token = this.peek(...expected);
415
581
  if (token) {
416
582
  this.tokens.shift();
417
583
  return token;
418
584
  }
419
585
  return false;
420
- },
421
-
422
- selfReferential: {
423
- this: { type: ASTType.ThisExpression },
424
- $locals: { type: ASTType.LocalsExpression },
425
- },
426
- };
586
+ }
587
+ }