@angular-wave/angular.ts 0.4.3 → 0.4.4

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 (128) hide show
  1. package/dist/angular-ts.umd.js +10 -0
  2. package/index.html +74 -3
  3. package/package.json +1 -1
  4. package/src/angular.spec.js +0 -5
  5. package/src/animations/animate-css.js +5 -13
  6. package/src/animations/animate-queue.js +22 -21
  7. package/src/animations/animate-runner.js +4 -8
  8. package/src/animations/animate.md +1 -1
  9. package/src/animations/animate.spec.js +0 -21
  10. package/src/animations/animation.js +1 -1
  11. package/src/binding.spec.js +0 -1
  12. package/src/core/cache/cache.js +2 -29
  13. package/src/core/compile/compile.js +26 -27
  14. package/src/core/compile/compile.spec.js +17 -266
  15. package/src/core/compile/compile.test.js +1 -1
  16. package/src/core/controller/controller.js +2 -0
  17. package/src/core/di/injector.md +1 -1
  18. package/src/core/di/injector.spec.js +0 -2
  19. package/src/core/di/internal-injector.js +2 -1
  20. package/src/core/interpolate/interpolate.js +16 -3
  21. package/src/core/interpolate/interpolate.spec.js +70 -16
  22. package/src/core/interval/interval.test.js +1 -1
  23. package/src/core/location/location.js +0 -2
  24. package/src/core/location/location.spec.js +27 -27
  25. package/src/core/{scope/scope.html → model/model.html} +1 -1
  26. package/src/core/model/model.js +944 -0
  27. package/src/core/model/model.spec.js +3012 -0
  28. package/src/core/on.spec.js +0 -7
  29. package/src/core/parse/interpreter.js +10 -7
  30. package/src/core/parse/parse.js +26 -5
  31. package/src/core/parse/parse.spec.js +95 -91
  32. package/src/core/prop.spec.js +4 -60
  33. package/src/core/sce/sce.spec.js +0 -8
  34. package/src/core/scope/scope.js +61 -30
  35. package/src/core/scope/scope.spec.js +25 -1960
  36. package/src/directive/aria/aria.js +3 -6
  37. package/src/directive/aria/aria.spec.js +0 -87
  38. package/src/directive/attrs/attrs.spec.js +0 -5
  39. package/src/directive/attrs/boolean.spec.js +0 -15
  40. package/src/directive/attrs/element-style.spec.js +0 -8
  41. package/src/directive/attrs/src.spec.js +0 -7
  42. package/src/directive/bind/bind.spec.js +0 -33
  43. package/src/directive/bind/bing-html.spec.js +0 -3
  44. package/src/{core/q/q.html → directive/channel/channel.html} +1 -1
  45. package/src/directive/channel/channel.js +29 -0
  46. package/src/directive/channel/channel.spec.js +52 -0
  47. package/src/directive/{list/list.test.js → channel/channel.test.js} +2 -4
  48. package/src/directive/class/class.js +3 -3
  49. package/src/directive/class/class.spec.js +9 -75
  50. package/src/directive/controller/controller.spec.js +0 -13
  51. package/src/directive/events/click.spec.js +0 -3
  52. package/src/directive/events/event.spec.js +0 -6
  53. package/src/directive/form/form.js +2 -3
  54. package/src/directive/form/form.spec.js +0 -65
  55. package/src/directive/if/if.spec.js +0 -4
  56. package/src/directive/include/include.spec.js +8 -59
  57. package/src/directive/init/init.js +6 -2
  58. package/src/directive/init/init.spec.js +0 -2
  59. package/src/directive/input/input.spec.js +0 -136
  60. package/src/directive/messages/messages.spec.js +4 -35
  61. package/src/directive/model/model.js +18 -25
  62. package/src/directive/model/model.spec.js +2 -49
  63. package/src/directive/model-options/model-options.spec.js +0 -6
  64. package/src/directive/non-bindable/non-bindable.spec.js +0 -1
  65. package/src/directive/observe/observe.js +0 -1
  66. package/src/directive/observe/observe.spec.js +0 -1
  67. package/src/directive/options/options.spec.js +0 -34
  68. package/src/directive/ref/href.spec.js +0 -15
  69. package/src/directive/repeat/repeat.spec.js +8 -135
  70. package/src/directive/script/script.spec.js +0 -2
  71. package/src/directive/select/select.js +3 -3
  72. package/src/directive/select/select.spec.js +0 -96
  73. package/src/directive/show-hide/show-hide.js +2 -2
  74. package/src/directive/show-hide/show-hide.spec.js +8 -19
  75. package/src/directive/style/style.spec.js +0 -7
  76. package/src/directive/switch/switch.spec.js +5 -5
  77. package/src/directive/validators/validators.spec.js +0 -1
  78. package/src/loader.js +0 -1
  79. package/src/public.js +75 -80
  80. package/src/router/common/coreservices.js +0 -2
  81. package/src/router/directives/state-directives.js +6 -14
  82. package/src/router/directives/state-directives.spec.js +0 -83
  83. package/src/router/directives/view-directive.js +4 -13
  84. package/src/router/directives/view-directive.spec.js +25 -71
  85. package/src/router/hooks/lazy-load.js +2 -2
  86. package/src/router/hooks/views.js +3 -5
  87. package/src/router/resolve/resolvable.js +3 -6
  88. package/src/router/resolve/resolve-context.js +2 -2
  89. package/src/router/state/state-service.js +4 -4
  90. package/src/router/state/state.spec.js +2 -5
  91. package/src/router/state/views.js +7 -10
  92. package/src/router/template-factory.js +3 -6
  93. package/src/router/template-factory.spec.js +0 -4
  94. package/src/router/transition/transition-hook.js +1 -1
  95. package/src/router/transition/transition.js +1 -1
  96. package/src/router/view-hook.spec.js +2 -2
  97. package/src/router/view-scroll.js +4 -6
  98. package/src/services/http/http.js +6 -9
  99. package/src/services/http/http.spec.js +30 -31
  100. package/src/services/http/template-request.spec.js +0 -10
  101. package/src/services/http-backend/http-backend.spec.js +3 -3
  102. package/src/services/template-request.js +2 -4
  103. package/src/shared/common.js +1 -2
  104. package/src/shared/jqlite/jqlite.js +0 -3
  105. package/types/core/cache/cache.d.ts +1 -1
  106. package/types/core/model/model.d.ts +204 -0
  107. package/types/core/parse/parse.d.ts +26 -0
  108. package/types/core/scope/scope.d.ts +22 -21
  109. package/types/directive/channel/channel.d.ts +11 -0
  110. package/src/core/interval/interval-factory.js +0 -50
  111. package/src/core/interval/interval.html +0 -18
  112. package/src/core/interval/interval.js +0 -77
  113. package/src/core/interval/interval.md +0 -123
  114. package/src/core/interval/interval.spec.js +0 -280
  115. package/src/core/q/q.js +0 -472
  116. package/src/core/q/q.md +0 -211
  117. package/src/core/q/q.spec.js +0 -2748
  118. package/src/core/q/q.test.js +0 -12
  119. package/src/core/scope/scope.test.js +0 -12
  120. package/src/core/timeout/timeout.html +0 -18
  121. package/src/core/timeout/timeout.js +0 -109
  122. package/src/core/timeout/timeout.spec.js +0 -354
  123. package/src/core/timeout/timout.test.js +0 -12
  124. package/src/directive/list/list.html +0 -18
  125. package/src/directive/list/list.js +0 -46
  126. package/src/directive/list/list.md +0 -22
  127. package/src/directive/list/list.spec.js +0 -172
  128. package/types/directive/list/list.d.ts +0 -4
@@ -0,0 +1,944 @@
1
+ import {
2
+ isUndefined,
3
+ nextUid,
4
+ isObject,
5
+ concat,
6
+ isFunction,
7
+ assert,
8
+ isString,
9
+ } from "../../shared/utils.js";
10
+ import { ASTType } from "../parse/ast-type.js";
11
+
12
+ /**
13
+ * @type {import('../parse/parse.js').ParseService}
14
+ */
15
+ let $parse;
16
+
17
+ /**@type {import('../exception-handler').ErrorHandler} */
18
+ let $exceptionHandler;
19
+
20
+ /**
21
+ * @typedef {Object} AsyncQueueTask
22
+ * @property {Model} handler
23
+ * @property {Function} fn
24
+ * @property {Object} locals
25
+ */
26
+
27
+ export const $postUpdateQueue = [];
28
+
29
+ /**
30
+ * @type {Function[]}
31
+ */
32
+ export const $$applyAsyncQueue = [];
33
+
34
+ export class RootModelProvider {
35
+ constructor() {
36
+ this.rootModel = createModel();
37
+ }
38
+
39
+ $get = [
40
+ "$exceptionHandler",
41
+ "$parse",
42
+ "$browser",
43
+ /**
44
+ * @param {import('../exception-handler').ErrorHandler} exceptionHandler
45
+ * @param {import('../parse/parse.js').ParseService} parse
46
+ */
47
+ (exceptionHandler, parse) => {
48
+ $exceptionHandler = exceptionHandler;
49
+ $parse = parse;
50
+ return this.rootModel;
51
+ },
52
+ ];
53
+ }
54
+
55
+ /**
56
+ * Creates a deep proxy for the target object, intercepting property changes
57
+ * and recursively applying proxies to nested objects.
58
+ *
59
+ * @param {Object} target - The object to be wrapped in a proxy.
60
+ * @param {Model} [context] - The context for the handler, used to track listeners.
61
+ * @returns {ProxyHandler<Object>} - A proxy that intercepts operations on the target object,
62
+ * or the original value if the target is not an object.
63
+ */
64
+ export function createModel(target = {}, context) {
65
+ if (typeof target === "object" && target !== null) {
66
+ for (const key in target) {
67
+ if (Object.prototype.hasOwnProperty.call(target, key)) {
68
+ target[key] = createModel(target[key], new Model(target, context));
69
+ }
70
+ }
71
+ return new Proxy(target, new Model(target, context));
72
+ } else {
73
+ return target;
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Listener function definition.
79
+ * @typedef {Object} Listener
80
+ * @property {Object} originalTarget - The original target object.
81
+ * @property {ListenerFunction} listenerFn - The function invoked when changes are detected.
82
+ * @property {import("../parse/parse.js").CompiledExpression} watchFn
83
+ * @property {number} id
84
+ * @property {boolean} oneTime
85
+ * @property {string} property
86
+ * @property {Object} [context] - The optional context in which a property exists
87
+ * @property {Proxy} [foreignListener]
88
+ */
89
+
90
+ /**
91
+ * Listener function type.
92
+ * @callback ListenerFunction
93
+ * @param {*} newValue - The new value of the changed property.
94
+ * @param {*} oldValue - The old value of the changed property.
95
+ * @param {Object} originalTarget - The original target object.
96
+ */
97
+
98
+ export const isProxySymbol = Symbol("isProxy");
99
+
100
+ /**
101
+ * @enum {number}
102
+ */
103
+ export const ModelPhase = {
104
+ NONE: 0,
105
+ WATCH: 1,
106
+ DIGEST: 2,
107
+ };
108
+
109
+ /**
110
+ * Model class for the Proxy. It intercepts operations like property access (get)
111
+ * and property setting (set), and adds support for deep change tracking and
112
+ * observer-like behavior.
113
+ */
114
+ class Model {
115
+ /**
116
+ * Initializes the handler with the target object and a context.
117
+ *
118
+ * @param {Object} target - The target object being proxied.
119
+ * @param {Model} [context] - The context containing listeners.
120
+ */
121
+ constructor(target, context) {
122
+ /** @type {Object} */
123
+ this.$target = target;
124
+
125
+ this.context = context
126
+ ? context.context
127
+ ? context.context
128
+ : context
129
+ : undefined;
130
+
131
+ /** @type {Map<string, Array<Listener>>} Watch listeners */
132
+ this.listeners = context ? context.listeners : new Map();
133
+
134
+ /** @type {Map<string, Array<Listener>>} Watch listeners from other proxies */
135
+ this.foreignListeners = context ? context.foreignListeners : new Map();
136
+
137
+ /** @type {WeakMap<Object, Array<string>>} */
138
+ this.objectListeners = context ? context.objectListeners : new WeakMap();
139
+
140
+ /** @type {Map<Function, {oldValue: any, fn: Function}>} */
141
+ this.functionListeners = context ? context.functionListeners : new Map();
142
+
143
+ /** @type {?number} */
144
+ this.listenerCache = null;
145
+
146
+ /** @type {Proxy} */
147
+ this.proxy = null;
148
+
149
+ /**
150
+ * @type {Proxy[]}
151
+ */
152
+ this.children = [];
153
+
154
+ /**
155
+ * @type {number} Unique model ID (monotonically increasing) useful for debugging.
156
+ */
157
+ this.id = nextUid();
158
+
159
+ /**
160
+ * @type {Model}
161
+ */
162
+ this.$root = context ? context.$root : this;
163
+
164
+ this.$parent = this.$root === this ? null : context;
165
+
166
+ /** @type {number} */
167
+ this.$$watchersCount = 0;
168
+
169
+ /** @type {AsyncQueueTask[]} */
170
+ this.$$asyncQueue = [];
171
+
172
+ /** @type {Map<String, Function[]>} Event listeners */
173
+ this.$$listeners = new Map();
174
+
175
+ this.filters = [];
176
+
177
+ /** @type {ModelPhase} */
178
+ this.state = ModelPhase.NONE;
179
+ }
180
+
181
+ /**
182
+ * Intercepts and handles property assignments on the target object. If a new value is
183
+ * an object, it will be recursively proxied.
184
+ *
185
+ * @param {Object} target - The target object.
186
+ * @param {string} property - The name of the property being set.
187
+ * @param {*} value - The new value being assigned to the property.
188
+ * @returns {boolean} - Returns true to indicate success of the operation.
189
+ */
190
+ set(target, property, value, proxy) {
191
+ this.proxy = proxy;
192
+ const oldValue = target[property];
193
+ if (oldValue && oldValue[isProxySymbol]) {
194
+ if (Array.isArray(value)) {
195
+ if (oldValue !== value) {
196
+ const listeners = this.listeners.get(property);
197
+
198
+ if (listeners) {
199
+ this.scheduleListener(listeners, oldValue);
200
+ }
201
+
202
+ const foreignListeners = this.foreignListeners.get(property);
203
+
204
+ if (foreignListeners) {
205
+ this.scheduleListener(foreignListeners, oldValue);
206
+ }
207
+ }
208
+ target[property] = value;
209
+ return true;
210
+ }
211
+ if (isObject(value)) {
212
+ if (Object.prototype.hasOwnProperty.call(target, property)) {
213
+ Object.keys(oldValue)
214
+ .filter((x) => !value[x])
215
+ .forEach((k) => {
216
+ delete oldValue[k];
217
+ });
218
+ }
219
+
220
+ if (oldValue !== value) {
221
+ const listeners = this.listeners.get(property);
222
+
223
+ if (listeners) {
224
+ this.scheduleListener(listeners, oldValue);
225
+ }
226
+
227
+ const foreignListeners = this.foreignListeners.get(property);
228
+
229
+ if (foreignListeners) {
230
+ this.scheduleListener(foreignListeners, oldValue);
231
+ }
232
+ }
233
+ target[property] = createModel({}, this);
234
+ setDeepValue(target[property], value);
235
+ return true;
236
+ }
237
+
238
+ if (isUndefined(value)) {
239
+ Object.keys(oldValue.$target).forEach((k) => {
240
+ delete oldValue[k];
241
+ });
242
+ target[property] = undefined;
243
+ const listeners = this.listeners.get(property);
244
+
245
+ if (listeners) {
246
+ this.scheduleListener(listeners, oldValue);
247
+ }
248
+ return true;
249
+ }
250
+ return true;
251
+ } else {
252
+ if (
253
+ oldValue !== undefined &&
254
+ Number.isNaN(oldValue) &&
255
+ Number.isNaN(value)
256
+ ) {
257
+ return true;
258
+ }
259
+
260
+ target[property] = createModel(value, this);
261
+
262
+ if (oldValue !== value) {
263
+ const listeners = this.listeners.get(property);
264
+
265
+ if (listeners) {
266
+ assert(listeners.length !== 0);
267
+ // primitive only
268
+
269
+ let isValue =
270
+ Number.isNaN(value) ||
271
+ listeners[0].watchFn(this.context?.$target) == value ||
272
+ (() => {
273
+ const res = listeners[0].watchFn(this.$target);
274
+ if (res && res[isProxySymbol]) {
275
+ return res.$target == value;
276
+ } else {
277
+ return res == value;
278
+ }
279
+ })();
280
+
281
+ if (isValue) {
282
+ this.scheduleListener(listeners, oldValue);
283
+ }
284
+ }
285
+
286
+ const foreignListeners = this.foreignListeners.get(property);
287
+
288
+ if (foreignListeners) {
289
+ assert(foreignListeners.length !== 0);
290
+ // primitive only
291
+
292
+ // let isValue =
293
+ // Number.isNaN(value) ||
294
+ // foreignListeners[0].watchFn(this.context?.$target) == value ||
295
+ // (() => {
296
+ // const res = foreignListeners[0].watchFn(this.$target);
297
+ // if (res && res[isProxySymbol]) {
298
+ // return res.$target == value;
299
+ // } else {
300
+ // return res == value;
301
+ // }
302
+ // })();
303
+
304
+ // if (isValue) {
305
+ this.scheduleListener(foreignListeners, oldValue);
306
+ //}
307
+ }
308
+ }
309
+
310
+ // Right now this is only for Arrays
311
+ if (this.objectListeners.has(target) && property !== "length") {
312
+ let keys = this.objectListeners.get(target);
313
+ keys.forEach((key) => {
314
+ const listeners = this.listeners.get(key);
315
+ if (listeners) {
316
+ this.scheduleListener(listeners, oldValue);
317
+ }
318
+ });
319
+ }
320
+
321
+ return true;
322
+ }
323
+ }
324
+
325
+ /**
326
+ * Intercepts property access on the target object. It checks for specific
327
+ * properties (`watch` and `sync`) and binds their methods. For other properties,
328
+ * it returns the value directly.
329
+ *
330
+ * @param {Object} target - The target object.
331
+ * @param {string|number|symbol} property - The name of the property being accessed.
332
+ * @param {Proxy} proxy - The proxy object being invoked
333
+ * @returns {*} - The value of the property or a method if accessing `watch` or `sync`.
334
+ */
335
+ get(target, property, proxy) {
336
+ this.proxy = proxy;
337
+
338
+ if (property === isProxySymbol) return true;
339
+ const propertyMap = {
340
+ $watch: this.$watch.bind(this),
341
+ $watchGroup: this.$watchGroup.bind(this),
342
+ $watchCollection: this.$watchCollection.bind(this),
343
+ $new: this.$new.bind(this),
344
+ $destroy: this.$destroy.bind(this),
345
+ $eval: this.$eval.bind(this),
346
+ $apply: this.$apply.bind(this),
347
+ $evalAsync: this.$evalAsync.bind(this),
348
+ $postUpdate: this.$postUpdate.bind(this),
349
+ $isRoot: this.isRoot.bind(this),
350
+ $target: this.$target,
351
+ $digest: this.$digest.bind(this),
352
+ $on: this.$on.bind(this),
353
+ $emit: this.$emit.bind(this),
354
+ $broadcast: this.$broadcast.bind(this),
355
+ $transcluded: this.$transcluded.bind(this),
356
+ $handler: this,
357
+ $parent: this.$parent,
358
+ $root: this.$root,
359
+ $$watchersCount: this.$$watchersCount,
360
+ $children: this.children,
361
+ id: this.id,
362
+ state: this.state,
363
+ registerForeignKey: this.registerForeignKey.bind(this),
364
+ notifyListener: this.notifyListener.bind(this),
365
+ };
366
+
367
+ return Object.prototype.hasOwnProperty.call(propertyMap, property)
368
+ ? propertyMap[property]
369
+ : target[property];
370
+ }
371
+
372
+ /**
373
+ * @private
374
+ * @param {Listener[]} listeners
375
+ * @param {*} oldValue
376
+ */
377
+ scheduleListener(listeners, oldValue) {
378
+ Promise.resolve().then(() => {
379
+ let index = 0;
380
+ while (index < listeners.length) {
381
+ const listener = listeners[index];
382
+ if (listener.foreignListener) {
383
+ listener.foreignListener.notifyListener(
384
+ listener,
385
+ oldValue,
386
+ this.$target,
387
+ );
388
+ } else {
389
+ this.notifyListener(listener, oldValue, this.$target);
390
+ }
391
+
392
+ if (
393
+ listener.oneTime &&
394
+ this.deregisterKey(listener.property, listener.id)
395
+ ) {
396
+ this.incrementWatchersCount(-1);
397
+ }
398
+ index++;
399
+ }
400
+ });
401
+ }
402
+
403
+ deleteProperty(target, property) {
404
+ // Currently deletes $model
405
+ if (target[property] && target[property][isProxySymbol]) {
406
+ delete target[property];
407
+ return true;
408
+ }
409
+
410
+ var oldValue = structuredClone(target);
411
+ delete target[property];
412
+ if (this.objectListeners.has(target)) {
413
+ let keys = this.objectListeners.get(target);
414
+ keys.forEach((key) => {
415
+ const listeners = this.listeners.get(key);
416
+ if (listeners) {
417
+ this.scheduleListener(listeners, oldValue);
418
+ }
419
+ });
420
+ } else {
421
+ const listeners = this.listeners.get(property);
422
+ if (listeners) {
423
+ this.scheduleListener(listeners, target[property]);
424
+ }
425
+ }
426
+
427
+ return true;
428
+ }
429
+
430
+ /**
431
+ * Registers a watcher for a property along with a listener function. The listener
432
+ * function is invoked when changes to that property are detected.
433
+ *
434
+ * @param {string} watchProp - An expression to be watched in the context of this model.
435
+ * @param {ListenerFunction} [listenerFn] - A function to execute when changes are detected on watched context.
436
+ */
437
+ $watch(watchProp, listenerFn) {
438
+ assert(isString(watchProp), "Watched property required");
439
+ this.state = ModelPhase.WATCH;
440
+
441
+ const get = $parse(watchProp);
442
+
443
+ // Constant are immediately passed to listener function
444
+ if (get.constant) {
445
+ if (listenerFn) {
446
+ Promise.resolve().then(() => {
447
+ let res = get();
448
+ while (isFunction(res)) {
449
+ res = res();
450
+ }
451
+ listenerFn(res, undefined, this.$target);
452
+ });
453
+ }
454
+ return () => {};
455
+ }
456
+
457
+ /** @type {Listener} */
458
+ const listener = {
459
+ originalTarget: this.$target,
460
+ listenerFn: listenerFn,
461
+ watchFn: get,
462
+ id: nextUid(),
463
+ oneTime: get.oneTime,
464
+ property: undefined,
465
+ };
466
+
467
+ // simplest case
468
+ let key = get.decoratedNode.body[0].expression.name;
469
+
470
+ let type = get.decoratedNode.body[0].expression.type;
471
+ switch (type) {
472
+ // 1
473
+ case ASTType.Program: {
474
+ throw new Error("Unsupported type " + type);
475
+ }
476
+
477
+ // 2
478
+ case ASTType.ExpressionStatement: {
479
+ throw new Error("Unsupported type " + type);
480
+ }
481
+ // 3
482
+ case ASTType.AssignmentExpression:
483
+ // assignment calls without listener functions
484
+ if (!listenerFn) {
485
+ let res = get(this.$target);
486
+ while (isFunction(res)) {
487
+ res = res(this.$target);
488
+ }
489
+ Promise.resolve().then(res);
490
+ return () => {};
491
+ }
492
+ break;
493
+ // 4
494
+ case ASTType.ConditionalExpression: {
495
+ throw new Error("Unsupported type " + type);
496
+ }
497
+ // 5
498
+ case ASTType.LogicalExpression: {
499
+ throw new Error("Unsupported type " + type);
500
+ }
501
+ // 6
502
+ case ASTType.BinaryExpression: {
503
+ throw new Error("Unsupported type " + type);
504
+ }
505
+
506
+ // 7
507
+ case ASTType.UnaryExpression: {
508
+ throw new Error("Unsupported type " + type);
509
+ }
510
+
511
+ // function
512
+ case ASTType.CallExpression: {
513
+ listener.property = get.decoratedNode.body[0].callee.name;
514
+ break;
515
+ }
516
+
517
+ case ASTType.MemberExpression: {
518
+ listener.property = get.decoratedNode.body[0].expression.property.name;
519
+ const name = extractTarget(get.decoratedNode.body[0].expression.object);
520
+ if (this.$target[name]) {
521
+ listener.context = () => {
522
+ return this.$target[name].$target;
523
+ };
524
+ }
525
+ break;
526
+ }
527
+
528
+ // 10
529
+ case ASTType.Identifier: {
530
+ listener.property = get.decoratedNode.body[0].expression.name;
531
+ break;
532
+ }
533
+
534
+ // 11
535
+ case ASTType.Literal: {
536
+ throw new Error("Unsupported type " + type);
537
+ }
538
+
539
+ // 12
540
+ case ASTType.ArrayExpression: {
541
+ throw new Error("Unsupported type " + type);
542
+ }
543
+
544
+ // 13
545
+ case ASTType.Property: {
546
+ throw new Error("Unsupported type " + type);
547
+ }
548
+
549
+ // 14
550
+ case ASTType.ObjectExpression: {
551
+ throw new Error("Unsupported type " + type);
552
+ }
553
+
554
+ // 15
555
+ case ASTType.ThisExpression: {
556
+ throw new Error("Unsupported type " + type);
557
+ }
558
+
559
+ // 16
560
+ case ASTType.LocalsExpression: {
561
+ throw new Error("Unsupported type " + type);
562
+ }
563
+
564
+ // 17
565
+ case ASTType.NGValueParameter: {
566
+ throw new Error("Unsupported type " + type);
567
+ }
568
+ }
569
+
570
+ if (listener.context && listener.context()[isProxySymbol]) {
571
+ listener.foreignListener = this.proxy;
572
+ key = get.decoratedNode.body[0].expression.property.name;
573
+ listener.context().$handler.registerForeignKey(key, listener);
574
+ } else {
575
+ this.registerKey(key, listener);
576
+ }
577
+
578
+ let watchedValue = get(this.$target);
579
+ const value =
580
+ watchedValue && watchedValue[isProxySymbol]
581
+ ? watchedValue.$target
582
+ : watchedValue;
583
+
584
+ const isArray = Array.isArray(value);
585
+ const isObject =
586
+ Object.prototype.toString.call(value) === "[object Object]";
587
+ if (isArray || isObject) {
588
+ if (this.objectListeners.has(value)) {
589
+ this.objectListeners.get(value).push(key);
590
+ } else {
591
+ this.objectListeners.set(value, [key]);
592
+ }
593
+ }
594
+
595
+ this.incrementWatchersCount(1);
596
+ this.state = ModelPhase.NONE;
597
+ return () => {
598
+ const res = this.deregisterKey(key, listener.id);
599
+ if (res) {
600
+ this.incrementWatchersCount(-1);
601
+ }
602
+ };
603
+ }
604
+
605
+ $watchGroup(watchArray, listenerFn) {
606
+ watchArray.forEach((x) => this.$watch(x, listenerFn));
607
+ }
608
+
609
+ $watchCollection(watchProp, listenerFn) {
610
+ return this.$watch(watchProp, listenerFn);
611
+ }
612
+
613
+ $new(childInstance) {
614
+ let child;
615
+ if (childInstance) {
616
+ if (Object.getPrototypeOf(childInstance) === Object.prototype) {
617
+ Object.setPrototypeOf(childInstance, this.$target);
618
+ } else {
619
+ Object.setPrototypeOf(
620
+ Object.getPrototypeOf(childInstance),
621
+ this.$target,
622
+ );
623
+ }
624
+
625
+ child = childInstance;
626
+ } else {
627
+ child = Object.create(this.$target);
628
+ child.$$watchersCount = 0;
629
+ child.$parent = this.$parent;
630
+ }
631
+
632
+ const proxy = new Proxy(child, new Model(child, this));
633
+ this.children.push(proxy);
634
+ return proxy;
635
+ }
636
+
637
+ $transcluded(parentInstance) {
638
+ let child = Object.create(this.$target);
639
+ child.$$watchersCount = 0;
640
+ child.$parent = parentInstance;
641
+ const proxy = new Proxy(child, new Model(child, this));
642
+ this.children.push(proxy);
643
+ return proxy;
644
+ }
645
+
646
+ registerKey(key, listener) {
647
+ if (this.listeners.has(key)) {
648
+ this.listeners.get(key).push(listener);
649
+ } else {
650
+ this.listeners.set(key, [listener]);
651
+ }
652
+ }
653
+
654
+ registerForeignKey(key, listener) {
655
+ if (this.foreignListeners.has(key)) {
656
+ this.foreignListeners.get(key).push(listener);
657
+ } else {
658
+ this.foreignListeners.set(key, [listener]);
659
+ }
660
+ }
661
+
662
+ deregisterKey(key, id) {
663
+ const listenerList = this.listeners.get(key);
664
+ if (!listenerList) return false;
665
+
666
+ const index = listenerList.findIndex((x) => x.id === id);
667
+ if (index === -1) return false;
668
+
669
+ listenerList.splice(index, 1);
670
+ if (listenerList.length) {
671
+ this.listeners.set(key, listenerList);
672
+ } else {
673
+ this.listeners.delete(key);
674
+ }
675
+ return true;
676
+ }
677
+
678
+ deregisterForeignKey(key, id) {
679
+ const listenerList = this.foreignListeners.get(key);
680
+ if (!listenerList) return false;
681
+
682
+ const index = listenerList.findIndex((x) => x.id === id);
683
+ if (index === -1) return false;
684
+
685
+ listenerList.splice(index, 1);
686
+ if (listenerList.length) {
687
+ this.foreignListeners.set(key, listenerList);
688
+ } else {
689
+ this.foreignListeners.delete(key);
690
+ }
691
+ return true;
692
+ }
693
+
694
+ /**
695
+ * @deprecated
696
+ */
697
+ $digest() {
698
+ throw new Error("$Digest is deprecated");
699
+ }
700
+
701
+ $eval(expr, locals) {
702
+ const fn = $parse(expr);
703
+ const res = fn(this.$target, locals);
704
+
705
+ if (isUndefined(res) || res === null) {
706
+ return res;
707
+ }
708
+
709
+ if (res["name"] === Object.hasOwnProperty["name"]) {
710
+ return res;
711
+ }
712
+ if (isFunction(res)) {
713
+ return res();
714
+ }
715
+
716
+ if (Number.isNaN(res)) {
717
+ return 0;
718
+ }
719
+
720
+ return res;
721
+ }
722
+
723
+ async $evalAsync(expr, locals) {
724
+ return this.$eval(expr, locals);
725
+ }
726
+
727
+ $apply(expr) {
728
+ try {
729
+ return $parse(expr)(this.proxy);
730
+ } catch (e) {
731
+ $exceptionHandler(e);
732
+ }
733
+ }
734
+
735
+ $on(name, listener) {
736
+ let namedListeners = this.$$listeners.get(name);
737
+ if (!namedListeners) {
738
+ namedListeners = [];
739
+ this.$$listeners.set(name, namedListeners);
740
+ }
741
+ namedListeners.push(listener);
742
+
743
+ return () => {
744
+ const indexOfListener = namedListeners.indexOf(listener);
745
+ if (indexOfListener !== -1) {
746
+ namedListeners.splice(indexOfListener, 1);
747
+ if (namedListeners.length == 0) {
748
+ this.$$listeners.delete(name);
749
+ }
750
+ }
751
+ };
752
+ }
753
+
754
+ /**
755
+ * @param {string} name
756
+ * @param {...any} args
757
+ * @returns
758
+ */
759
+ $emit(name, ...args) {
760
+ return this.eventHelper(
761
+ { name: name, event: undefined, broadcast: false },
762
+ ...args,
763
+ );
764
+ }
765
+
766
+ /**
767
+ * @param {string} name
768
+ * @param {...any} args
769
+ * @returns
770
+ */
771
+ $broadcast(name, ...args) {
772
+ return this.eventHelper(
773
+ { name: name, event: undefined, broadcast: true },
774
+ ...args,
775
+ );
776
+ }
777
+
778
+ eventHelper({ name, event, broadcast }, ...args) {
779
+ if (!broadcast) {
780
+ if (!this.$$listeners.has(name)) {
781
+ return;
782
+ }
783
+ }
784
+ if (event) {
785
+ event.currentScope = this.$target;
786
+ } else {
787
+ event = event || {
788
+ name,
789
+ targetScope: this.$target,
790
+ currentScope: this.$target,
791
+ stopped: false,
792
+ stopPropagation() {
793
+ event.stopped = true;
794
+ },
795
+ preventDefault() {
796
+ event.defaultPrevented = true;
797
+ },
798
+ defaultPrevented: false,
799
+ };
800
+ }
801
+
802
+ const listenerArgs = concat([event], [event].concat(args), 1);
803
+ let listeners = this.$$listeners.get(name);
804
+ if (listeners) {
805
+ let length = listeners.length;
806
+ for (let i = 0; i < length; i++) {
807
+ try {
808
+ let cb = listeners[i];
809
+ cb.apply(null, listenerArgs);
810
+ if (listeners.length !== length) {
811
+ if (listeners.length < length) {
812
+ i--;
813
+ }
814
+ length = listeners.length;
815
+ }
816
+ } catch (e) {
817
+ $exceptionHandler(e);
818
+ }
819
+ }
820
+ }
821
+
822
+ event.currentScope = null;
823
+
824
+ if (event.stopped) {
825
+ return event;
826
+ }
827
+
828
+ if (broadcast) {
829
+ if (this.children.length > 0) {
830
+ this.children.forEach((child) => {
831
+ event = child["$handler"].eventHelper(
832
+ { name: name, event: event, broadcast: broadcast },
833
+ ...args,
834
+ );
835
+ });
836
+ }
837
+ return event;
838
+ } else {
839
+ if (this.$parent) {
840
+ return this.$parent?.eventHelper(
841
+ { name: name, event: event, broadcast: broadcast },
842
+ ...args,
843
+ );
844
+ } else {
845
+ return event;
846
+ }
847
+ }
848
+ }
849
+
850
+ /**
851
+ * @private
852
+ * @returns {boolean}
853
+ */
854
+ isRoot() {
855
+ return this.$root == this;
856
+ }
857
+
858
+ async $applyAsync(expr) {
859
+ try {
860
+ const result = $parse(expr)(this.proxy);
861
+ return result;
862
+ } catch (error) {
863
+ $exceptionHandler(error);
864
+ throw error;
865
+ }
866
+ }
867
+
868
+ $postUpdate(fn) {
869
+ $postUpdateQueue.push(fn);
870
+ }
871
+
872
+ $destroy() {
873
+ this.incrementWatchersCount(-this.$$watchersCount);
874
+ }
875
+
876
+ /**
877
+ * @param {number} count
878
+ */
879
+ incrementWatchersCount(count) {
880
+ this.$$watchersCount += count;
881
+ if (this.$parent) {
882
+ this.$parent.incrementWatchersCount(count);
883
+ }
884
+ }
885
+
886
+ /**
887
+ * Invokes the registered listener function with watched property changes.
888
+ *
889
+ * @param {Listener} listener - The property path that was changed.
890
+ * @param {*} oldValue - The old value of the property.
891
+ */
892
+ notifyListener(listener, oldValue, target) {
893
+ const { originalTarget, listenerFn, watchFn } = listener;
894
+ try {
895
+ const newVal = watchFn(target || listener.originalTarget);
896
+ //const res = watchFn(listener.originalTarget.$target).$target
897
+ listenerFn(newVal, oldValue, originalTarget);
898
+ // if (oneTime) {
899
+ // this.deregisterKey(property, id)
900
+ // }
901
+
902
+ this.$$asyncQueue.forEach((x) => {
903
+ if (x.handler.id == this.id) {
904
+ Promise.resolve().then(x.fn(x.handler, x.locals));
905
+ }
906
+ });
907
+
908
+ while ($postUpdateQueue.length) {
909
+ $postUpdateQueue.shift()();
910
+ }
911
+ } catch (e) {
912
+ $exceptionHandler(e);
913
+ }
914
+ }
915
+ }
916
+
917
+ function setDeepValue(model, obj) {
918
+ for (const key in obj) {
919
+ if (isObject(obj[key]) && !Array.isArray(obj[key])) {
920
+ if (!isObject(model[key])) {
921
+ model[key] = {};
922
+ }
923
+ setDeepValue(model[key], obj[key]);
924
+ } else {
925
+ model[key] = obj[key];
926
+ }
927
+ }
928
+ }
929
+
930
+ function extractTarget(object) {
931
+ if (!object.name) {
932
+ return extractTarget(object.object);
933
+ } else {
934
+ return object.name;
935
+ }
936
+ }
937
+
938
+ // function deProxy(maybeProxy) {
939
+ // if (maybeProxy[isProxySymbol]) {
940
+ // return deProxy(maybeProxy);
941
+ // } else {
942
+ // return maybeProxy.$target;
943
+ // }
944
+ // }