vasille 2.0.5 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +4 -0
  2. package/cdn/es2015.js +827 -827
  3. package/cdn/es5.js +909 -829
  4. package/flow-typed/vasille.js +2647 -835
  5. package/lib/binding/attribute.js +8 -3
  6. package/lib/binding/binding.js +5 -5
  7. package/lib/binding/class.js +4 -4
  8. package/lib/binding/style.js +2 -2
  9. package/lib/core/core.js +73 -17
  10. package/lib/core/destroyable.js +2 -2
  11. package/lib/core/ivalue.js +4 -4
  12. package/lib/functional/components.js +17 -0
  13. package/lib/functional/merge.js +41 -0
  14. package/lib/functional/models.js +26 -0
  15. package/lib/functional/options.js +1 -0
  16. package/lib/functional/reactivity.js +33 -0
  17. package/lib/functional/stack.js +127 -0
  18. package/lib/index.js +2 -7
  19. package/lib/models/array-model.js +9 -0
  20. package/lib/models/object-model.js +28 -14
  21. package/lib/node/app.js +21 -12
  22. package/lib/node/node.js +229 -573
  23. package/lib/node/watch.js +6 -14
  24. package/lib/spec/html.js +1 -0
  25. package/lib/spec/react.js +1 -0
  26. package/lib/spec/svg.js +1 -0
  27. package/lib/v/index.js +23 -0
  28. package/lib/value/expression.js +21 -18
  29. package/lib/value/mirror.js +15 -15
  30. package/lib/value/pointer.js +5 -5
  31. package/lib/value/reference.js +18 -18
  32. package/lib/views/array-view.js +6 -10
  33. package/lib/views/base-view.js +12 -23
  34. package/lib/views/map-view.js +4 -9
  35. package/lib/views/object-view.js +4 -7
  36. package/lib/views/repeat-node.js +10 -22
  37. package/lib/views/set-view.js +4 -11
  38. package/package.json +3 -1
  39. package/types/binding/attribute.d.ts +2 -2
  40. package/types/binding/binding.d.ts +1 -1
  41. package/types/core/core.d.ts +31 -43
  42. package/types/core/destroyable.d.ts +2 -2
  43. package/types/core/ivalue.d.ts +4 -4
  44. package/types/functional/components.d.ts +4 -0
  45. package/types/functional/merge.d.ts +1 -0
  46. package/types/functional/models.d.ts +10 -0
  47. package/types/functional/options.d.ts +23 -0
  48. package/types/functional/reactivity.d.ts +11 -0
  49. package/types/functional/stack.d.ts +24 -0
  50. package/types/index.d.ts +3 -7
  51. package/types/models/array-model.d.ts +1 -0
  52. package/types/models/object-model.d.ts +2 -0
  53. package/types/node/app.d.ts +19 -17
  54. package/types/node/node.d.ts +67 -388
  55. package/types/node/watch.d.ts +9 -15
  56. package/types/spec/html.d.ts +975 -0
  57. package/types/spec/react.d.ts +4 -0
  58. package/types/spec/svg.d.ts +314 -0
  59. package/types/v/index.d.ts +36 -0
  60. package/types/value/expression.d.ts +11 -24
  61. package/types/value/mirror.d.ts +6 -6
  62. package/types/value/pointer.d.ts +1 -1
  63. package/types/value/reference.d.ts +7 -7
  64. package/types/views/array-view.d.ts +3 -4
  65. package/types/views/base-view.d.ts +8 -16
  66. package/types/views/map-view.d.ts +2 -3
  67. package/types/views/object-view.d.ts +2 -3
  68. package/types/views/repeat-node.d.ts +8 -9
  69. package/types/views/set-view.d.ts +2 -3
  70. package/types/core/executor.d.ts +0 -87
  71. package/types/core/signal.d.ts +0 -35
  72. package/types/core/slot.d.ts +0 -45
  73. package/types/node/interceptor.d.ts +0 -50
  74. package/types/views/repeater.d.ts +0 -38
@@ -15,12 +15,17 @@ export class AttributeBinding extends Binding {
15
15
  super(value);
16
16
  this.init((value) => {
17
17
  if (value) {
18
- node.app.run.setAttribute(node.node, name, value);
18
+ if (typeof value === 'boolean') {
19
+ node.node.setAttribute(name, "");
20
+ }
21
+ else {
22
+ node.node.setAttribute(name, `${value}`);
23
+ }
19
24
  }
20
25
  else {
21
- node.app.run.removeAttribute(node.node, name);
26
+ node.node.removeAttribute(name);
22
27
  }
23
28
  });
24
- this.seal();
29
+ this.$seal();
25
30
  }
26
31
  }
@@ -12,18 +12,18 @@ export class Binding extends Destroyable {
12
12
  constructor(value) {
13
13
  super();
14
14
  this.binding = value;
15
- this.seal();
15
+ this.$seal();
16
16
  }
17
17
  init(bounded) {
18
18
  this.func = bounded;
19
- this.binding.on(this.func);
19
+ this.binding.$on(this.func);
20
20
  this.func(this.binding.$);
21
21
  }
22
22
  /**
23
23
  * Just clear bindings
24
24
  */
25
- destroy() {
26
- this.binding.off(this.func);
27
- super.destroy();
25
+ $destroy() {
26
+ this.binding.$off(this.func);
27
+ super.$destroy();
28
28
  }
29
29
  }
@@ -1,9 +1,9 @@
1
1
  import { Binding } from "./binding";
2
2
  function addClass(node, cl) {
3
- node.app.run.addClass(node.node, cl);
3
+ node.node.classList.add(cl);
4
4
  }
5
5
  function removeClass(node, cl) {
6
- node.app.run.removeClass(node.node, cl);
6
+ node.node.classList.remove(cl);
7
7
  }
8
8
  export class StaticClassBinding extends Binding {
9
9
  constructor(node, name, value) {
@@ -20,7 +20,7 @@ export class StaticClassBinding extends Binding {
20
20
  this.current = value;
21
21
  }
22
22
  });
23
- this.seal();
23
+ this.$seal();
24
24
  }
25
25
  }
26
26
  export class DynamicalClassBinding extends Binding {
@@ -38,6 +38,6 @@ export class DynamicalClassBinding extends Binding {
38
38
  this.current = value;
39
39
  }
40
40
  });
41
- this.seal();
41
+ this.$seal();
42
42
  }
43
43
  }
@@ -15,9 +15,9 @@ export class StyleBinding extends Binding {
15
15
  super(value);
16
16
  this.init((value) => {
17
17
  if (node.node instanceof HTMLElement) {
18
- node.app.run.setStyle(node.node, name, value);
18
+ node.node.style.setProperty(name, value);
19
19
  }
20
20
  });
21
- this.seal();
21
+ this.$seal();
22
22
  }
23
23
  }
package/lib/core/core.js CHANGED
@@ -4,6 +4,15 @@ import { Expression } from "../value/expression";
4
4
  import { Reference } from "../value/reference";
5
5
  import { Pointer } from "../value/pointer";
6
6
  import { Mirror } from "../value/mirror";
7
+ export let current = null;
8
+ const currentStack = [];
9
+ function stack(node) {
10
+ currentStack.push(current);
11
+ current = node;
12
+ }
13
+ function unstack() {
14
+ current = currentStack.pop();
15
+ }
7
16
  /**
8
17
  * Private stuff of a reactive object
9
18
  * @class ReactivePrivate
@@ -36,18 +45,18 @@ export class ReactivePrivate extends Destroyable {
36
45
  * @type {boolean}
37
46
  */
38
47
  this.frozen = false;
39
- this.seal();
48
+ this.$seal();
40
49
  }
41
- destroy() {
42
- var _a;
43
- this.watch.forEach(value => value.destroy());
50
+ $destroy() {
51
+ this.watch.forEach(value => value.$destroy());
44
52
  this.watch.clear();
45
- this.bindings.forEach(binding => binding.destroy());
53
+ this.bindings.forEach(binding => binding.$destroy());
46
54
  this.bindings.clear();
47
55
  this.models.forEach(model => model.disableReactivity());
48
56
  this.models.clear();
49
- (_a = this.freezeExpr) === null || _a === void 0 ? void 0 : _a.destroy();
50
- super.destroy();
57
+ this.freezeExpr && this.freezeExpr.$destroy();
58
+ this.onDestroy && this.onDestroy();
59
+ super.$destroy();
51
60
  }
52
61
  }
53
62
  /**
@@ -56,9 +65,17 @@ export class ReactivePrivate extends Destroyable {
56
65
  * @extends Destroyable
57
66
  */
58
67
  export class Reactive extends Destroyable {
59
- constructor($) {
68
+ constructor(input, $) {
60
69
  super();
70
+ this.input = input;
61
71
  this.$ = $ || new ReactivePrivate;
72
+ this.$seal();
73
+ }
74
+ /**
75
+ * Get parent node
76
+ */
77
+ get parent() {
78
+ return this.$.parent;
62
79
  }
63
80
  /**
64
81
  * Create a reference
@@ -107,12 +124,23 @@ export class Reactive extends Destroyable {
107
124
  this.$.models.add(model);
108
125
  return model;
109
126
  }
110
- watch(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
127
+ /**
128
+ * Creates a watcher
129
+ * @param func {function} function to run on any argument change
130
+ * @param values
131
+ */
132
+ watch(func, ...values) {
111
133
  const $ = this.$;
112
- $.watch.add(new Expression(func, !this.$.frozen, v1, v2, v3, v4, v5, v6, v7, v8, v9));
134
+ $.watch.add(new Expression(func, !this.$.frozen, ...values));
113
135
  }
114
- bind(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
115
- const res = new Expression(func, !this.$.frozen, v1, v2, v3, v4, v5, v6, v7, v8, v9);
136
+ /**
137
+ * Creates a computed value
138
+ * @param func {function} function to run on any argument change
139
+ * @param values
140
+ * @return {IValue} the created ivalue
141
+ */
142
+ expr(func, ...values) {
143
+ const res = new Expression(func, !this.$.frozen, ...values);
116
144
  const $ = this.$;
117
145
  $.watch.add(res);
118
146
  return res;
@@ -124,7 +152,7 @@ export class Reactive extends Destroyable {
124
152
  const $ = this.$;
125
153
  if (!$.enabled) {
126
154
  $.watch.forEach(watcher => {
127
- watcher.enable();
155
+ watcher.$enable();
128
156
  });
129
157
  $.models.forEach(model => {
130
158
  model.enableReactivity();
@@ -139,7 +167,7 @@ export class Reactive extends Destroyable {
139
167
  const $ = this.$;
140
168
  if ($.enabled) {
141
169
  $.watch.forEach(watcher => {
142
- watcher.disable();
170
+ watcher.$disable();
143
171
  });
144
172
  $.models.forEach(model => {
145
173
  model.disableReactivity();
@@ -174,9 +202,37 @@ export class Reactive extends Destroyable {
174
202
  }, true, cond);
175
203
  return this;
176
204
  }
177
- destroy() {
178
- super.destroy();
179
- this.$.destroy();
205
+ init() {
206
+ this.applyOptions(this.input);
207
+ this.compose(this.input);
208
+ }
209
+ applyOptions(input) {
210
+ // empty
211
+ }
212
+ applyOptionsNow() {
213
+ this.applyOptions(this.input);
214
+ }
215
+ compose(input) {
216
+ // empty
217
+ }
218
+ composeNow() {
219
+ this.compose(this.input);
220
+ }
221
+ runFunctional(f, ...args) {
222
+ stack(this);
223
+ // yet another ts bug
224
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
225
+ // @ts-ignore
226
+ const result = f(...args);
227
+ unstack();
228
+ return result;
229
+ }
230
+ runOnDestroy(func) {
231
+ this.$.onDestroy = func;
232
+ }
233
+ $destroy() {
234
+ super.$destroy();
235
+ this.$.$destroy();
180
236
  this.$ = null;
181
237
  }
182
238
  }
@@ -7,7 +7,7 @@ export class Destroyable {
7
7
  * Make object fields non configurable
8
8
  * @protected
9
9
  */
10
- seal() {
10
+ $seal() {
11
11
  const $ = this;
12
12
  Object.keys($).forEach(i => {
13
13
  // eslint-disable-next-line no-prototype-builtins
@@ -39,7 +39,7 @@ export class Destroyable {
39
39
  /**
40
40
  * Garbage collector method
41
41
  */
42
- destroy() {
42
+ $destroy() {
43
43
  // nothing here
44
44
  }
45
45
  }
@@ -4,13 +4,13 @@ export class Switchable extends Destroyable {
4
4
  /**
5
5
  * Enable update handlers triggering
6
6
  */
7
- enable() {
7
+ $enable() {
8
8
  throw notOverwritten();
9
9
  }
10
10
  /**
11
11
  * disable update handlers triggering
12
12
  */
13
- disable() {
13
+ $disable() {
14
14
  throw notOverwritten();
15
15
  }
16
16
  }
@@ -45,14 +45,14 @@ export class IValue extends Switchable {
45
45
  * Add a new handler to value change
46
46
  * @param handler {function(value : *)} the handler to add
47
47
  */
48
- on(handler) {
48
+ $on(handler) {
49
49
  throw notOverwritten();
50
50
  }
51
51
  /**
52
52
  * Removes a handler of value change
53
53
  * @param handler {function(value : *)} the handler to remove
54
54
  */
55
- off(handler) {
55
+ $off(handler) {
56
56
  throw notOverwritten();
57
57
  }
58
58
  }
@@ -0,0 +1,17 @@
1
+ import { Fragment } from "../node/node";
2
+ import { current } from "../core/core";
3
+ import { userError } from "../core/errors";
4
+ export function text(text) {
5
+ if (!(current instanceof Fragment))
6
+ throw userError('missing parent node', 'out-of-context');
7
+ ;
8
+ current.text(text);
9
+ }
10
+ export function debug(text) {
11
+ if (!(current instanceof Fragment))
12
+ throw userError('missing parent node', 'out-of-context');
13
+ current.debug(text);
14
+ }
15
+ export function predefine(slot, predefined) {
16
+ return slot || predefined;
17
+ }
@@ -0,0 +1,41 @@
1
+ import { IValue } from "../core/ivalue";
2
+ export function merge(main, ...targets) {
3
+ function refactorClass(obj) {
4
+ if (Array.isArray(obj.class)) {
5
+ const out = {
6
+ $: []
7
+ };
8
+ obj.class.forEach(item => {
9
+ if (item instanceof IValue) {
10
+ out.$.push(item);
11
+ }
12
+ else if (typeof item === 'string') {
13
+ out[item] = true;
14
+ }
15
+ else if (typeof item === 'object') {
16
+ Object.assign(out, item);
17
+ }
18
+ });
19
+ obj.class = out;
20
+ }
21
+ }
22
+ refactorClass(main);
23
+ targets.forEach(target => {
24
+ Reflect.ownKeys(target).forEach((prop) => {
25
+ if (!Reflect.has(main, prop)) {
26
+ main[prop] = target[prop];
27
+ }
28
+ else if (typeof main[prop] === 'object' && typeof target[prop] === 'object') {
29
+ if (prop === 'class') {
30
+ refactorClass(target);
31
+ }
32
+ if (prop === '$' && Array.isArray(main[prop]) && Array.isArray(target[prop])) {
33
+ main.$.push(...target.$);
34
+ }
35
+ else {
36
+ merge(main[prop], target[prop]);
37
+ }
38
+ }
39
+ });
40
+ });
41
+ }
@@ -0,0 +1,26 @@
1
+ import { ArrayModel } from "../models/array-model";
2
+ import { MapModel } from "../models/map-model";
3
+ import { SetModel } from "../models/set-model";
4
+ import { ObjectModel } from "../models/object-model";
5
+ import { current } from "../core/core";
6
+ import { userError } from "../core/errors";
7
+ export function arrayModel(arr = []) {
8
+ if (!current)
9
+ throw userError('missing parent node', 'out-of-context');
10
+ return current.register(new ArrayModel(arr)).proxy();
11
+ }
12
+ export function mapModel(map = []) {
13
+ if (!current)
14
+ throw userError('missing parent node', 'out-of-context');
15
+ return current.register(new MapModel(map));
16
+ }
17
+ export function setModel(arr = []) {
18
+ if (!current)
19
+ throw userError('missing parent node', 'out-of-context');
20
+ return current.register(new SetModel(arr));
21
+ }
22
+ export function objectModel(obj = {}) {
23
+ if (!current)
24
+ throw userError('missing parent node', 'out-of-context');
25
+ return current.register(new ObjectModel(obj));
26
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,33 @@
1
+ import { IValue } from "../core/ivalue";
2
+ import { Pointer } from "../value/pointer";
3
+ import { current } from "../core/core";
4
+ export function ref(value) {
5
+ const ref = current.ref(value);
6
+ return [ref, (value) => ref.$ = value];
7
+ }
8
+ export function mirror(value) {
9
+ return current.mirror(value);
10
+ }
11
+ export function forward(value) {
12
+ return current.forward(value);
13
+ }
14
+ export function point(value) {
15
+ return current.point(value);
16
+ }
17
+ export function expr(func, ...values) {
18
+ return current.expr(func, ...values);
19
+ }
20
+ export function watch(func, ...values) {
21
+ current.watch(func, ...values);
22
+ }
23
+ export function valueOf(value) {
24
+ return value.$;
25
+ }
26
+ export function setValue(ref, value) {
27
+ if (ref instanceof Pointer && value instanceof IValue) {
28
+ ref.$$ = value;
29
+ }
30
+ else {
31
+ ref.$ = value instanceof IValue ? value.$ : value;
32
+ }
33
+ }
@@ -0,0 +1,127 @@
1
+ import { Component, Extension, Fragment } from "../node/node";
2
+ import { App } from "../node/app";
3
+ import { current } from "../core/core";
4
+ import { ArrayModel } from "../models/array-model";
5
+ import { ArrayView } from "../views/array-view";
6
+ import { MapModel } from "../models/map-model";
7
+ import { MapView } from "../views/map-view";
8
+ import { SetModel } from "../models/set-model";
9
+ import { SetView } from "../views/set-view";
10
+ import { ObjectModel } from "../models/object-model";
11
+ import { ObjectView } from "../views/object-view";
12
+ import { Watch } from "../node/watch";
13
+ import { userError } from "../core/errors";
14
+ export function app(renderer) {
15
+ return (node, opts) => {
16
+ return new App(node, opts).runFunctional(renderer, opts);
17
+ };
18
+ }
19
+ export function component(renderer) {
20
+ return (opts, callback) => {
21
+ const component = new Component(opts);
22
+ if (!(current instanceof Fragment))
23
+ throw userError('missing parent node', 'out-of-context');
24
+ let ret;
25
+ if (callback)
26
+ opts.slot = callback;
27
+ current.create(component, node => {
28
+ ret = node.runFunctional(renderer, opts);
29
+ });
30
+ return ret;
31
+ };
32
+ }
33
+ export function fragment(renderer) {
34
+ return (opts, callback) => {
35
+ const frag = new Fragment(opts);
36
+ if (!(current instanceof Fragment))
37
+ throw userError('missing parent node', 'out-of-context');
38
+ if (callback)
39
+ opts.slot = callback;
40
+ current.create(frag);
41
+ return frag.runFunctional(renderer, opts);
42
+ };
43
+ }
44
+ export function extension(renderer) {
45
+ return (opts, callback) => {
46
+ const ext = new Extension(opts);
47
+ if (!(current instanceof Fragment))
48
+ throw userError('missing parent node', 'out-of-context');
49
+ if (callback)
50
+ opts.slot = callback;
51
+ current.create(ext);
52
+ return ext.runFunctional(renderer, opts);
53
+ };
54
+ }
55
+ export function tag(name, opts, callback) {
56
+ if (!(current instanceof Fragment))
57
+ throw userError('missing parent node', 'out-of-context');
58
+ return {
59
+ node: current.tag(name, opts, (node) => {
60
+ callback && node.runFunctional(callback);
61
+ })
62
+ };
63
+ }
64
+ export function create(node, callback) {
65
+ if (!(current instanceof Fragment))
66
+ throw userError('missing current node', 'out-of-context');
67
+ current.create(node, (node, ...args) => {
68
+ callback && node.runFunctional(callback, ...args);
69
+ });
70
+ return node;
71
+ }
72
+ export const vx = {
73
+ if(condition, callback) {
74
+ if (current instanceof Fragment) {
75
+ current.if(condition, node => node.runFunctional(callback));
76
+ }
77
+ else {
78
+ throw userError("wrong use of `v.if` function", "logic-error");
79
+ }
80
+ },
81
+ else(callback) {
82
+ if (current instanceof Fragment) {
83
+ current.else(node => node.runFunctional(callback));
84
+ }
85
+ else {
86
+ throw userError("wrong use of `v.else` function", "logic-error");
87
+ }
88
+ },
89
+ elif(condition, callback) {
90
+ if (current instanceof Fragment) {
91
+ current.elif(condition, node => node.runFunctional(callback));
92
+ }
93
+ else {
94
+ throw userError("wrong use of `v.elif` function", "logic-error");
95
+ }
96
+ },
97
+ for(model, callback) {
98
+ if (model instanceof ArrayModel) {
99
+ // for arrays T & K are the same type
100
+ create(new ArrayView({ model }), callback);
101
+ }
102
+ else if (model instanceof MapModel) {
103
+ create(new MapView({ model }), callback);
104
+ }
105
+ else if (model instanceof SetModel) {
106
+ // for sets T & K are the same type
107
+ create(new SetView({ model }), callback);
108
+ }
109
+ else if (model instanceof ObjectModel) {
110
+ // for objects K is always string
111
+ create(new ObjectView({ model }), callback);
112
+ }
113
+ else {
114
+ throw userError("wrong use of `v.for` function", 'wrong-model');
115
+ }
116
+ },
117
+ watch(model, callback) {
118
+ const opts = { model };
119
+ create(new Watch(opts), callback);
120
+ },
121
+ nextTick(callback) {
122
+ const node = current;
123
+ window.setTimeout(() => {
124
+ node.runFunctional(callback);
125
+ }, 0);
126
+ }
127
+ };
package/lib/index.js CHANGED
@@ -1,16 +1,12 @@
1
1
  import { Destroyable } from "./core/destroyable";
2
- import { Executor, InstantExecutor, TimeoutExecutor } from "./core/executor";
3
2
  import { Reactive } from "./core/core";
4
3
  import { IValue } from "./core/ivalue";
5
- import { Signal } from "./core/signal";
6
- import { Slot } from "./core/slot";
7
4
  import { ArrayModel } from "./models/array-model";
8
5
  import { Listener } from "./models/listener";
9
6
  import { MapModel } from "./models/map-model";
10
7
  import { ObjectModel } from "./models/object-model";
11
8
  import { SetModel } from "./models/set-model";
12
9
  import { App, AppNode } from "./node/app";
13
- import { Interceptor, InterceptorNode } from "./node/interceptor";
14
10
  import { Component, Extension, Fragment, INode, Tag } from "./node/node";
15
11
  import { Expression } from "./value/expression";
16
12
  import { Mirror } from "./value/mirror";
@@ -20,8 +16,7 @@ import { ArrayView } from "./views/array-view";
20
16
  import { BaseView } from "./views/base-view";
21
17
  import { MapView } from "./views/map-view";
22
18
  import { ObjectView } from "./views/object-view";
23
- import { RepeatNode } from "./views/repeat-node";
24
- import { Repeater } from "./views/repeater";
25
19
  import { SetView } from "./views/set-view";
26
20
  import { Binding } from "./binding/binding";
27
- export { Destroyable, IValue, Reference, Mirror, Pointer, ArrayModel, MapModel, ObjectModel, SetModel, RepeatNode, Repeater, BaseView, Listener, ArrayView, MapView, ObjectView, SetView, Fragment, INode, Tag, Component, Extension, AppNode, App, Executor, InstantExecutor, TimeoutExecutor, Signal, Slot, Interceptor, InterceptorNode, Expression, Binding, Reactive, };
21
+ import * as libV from "./v/index";
22
+ export { Destroyable, IValue, Reference, Mirror, Pointer, ArrayModel, MapModel, ObjectModel, SetModel, BaseView, Listener, ArrayView, MapView, ObjectView, SetView, Fragment, INode, Tag, Component, Extension, AppNode, App, Expression, Binding, Reactive, libV };
@@ -19,6 +19,15 @@ export class ArrayModel extends Array {
19
19
  super.push(data[i]);
20
20
  }
21
21
  }
22
+ // proxy
23
+ proxy() {
24
+ return new Proxy(this, {
25
+ set(target, p, value) {
26
+ target.splice(parseInt(p), 1, value);
27
+ return true;
28
+ }
29
+ });
30
+ }
22
31
  /* Array members */
23
32
  /**
24
33
  * Gets the last item of array
@@ -10,13 +10,14 @@ export class ObjectModel extends Object {
10
10
  */
11
11
  constructor(obj = {}) {
12
12
  super();
13
+ this.container = Object.create(null);
13
14
  Object.defineProperty(this, 'listener', {
14
15
  value: new Listener,
15
16
  writable: false,
16
17
  configurable: false
17
18
  });
18
19
  for (const i in obj) {
19
- Object.defineProperty(this, i, {
20
+ Object.defineProperty(this.container, i, {
20
21
  value: obj[i],
21
22
  configurable: true,
22
23
  writable: true,
@@ -31,8 +32,7 @@ export class ObjectModel extends Object {
31
32
  * @return {*}
32
33
  */
33
34
  get(key) {
34
- const ts = this;
35
- return ts[key];
35
+ return this.container[key];
36
36
  }
37
37
  /**
38
38
  * Sets an object property value
@@ -41,21 +41,19 @@ export class ObjectModel extends Object {
41
41
  * @return {ObjectModel} a pointer to this
42
42
  */
43
43
  set(key, v) {
44
- const ts = this;
45
- // eslint-disable-next-line no-prototype-builtins
46
- if (ts.hasOwnProperty(key)) {
47
- this.listener.emitRemoved(key, ts[key]);
48
- ts[key] = v;
44
+ if (Reflect.has(this.container, key)) {
45
+ this.listener.emitRemoved(key, this.container[key]);
46
+ this.container[key] = v;
49
47
  }
50
48
  else {
51
- Object.defineProperty(ts, key, {
49
+ Object.defineProperty(this.container, key, {
52
50
  value: v,
53
51
  configurable: true,
54
52
  writable: true,
55
53
  enumerable: true
56
54
  });
57
55
  }
58
- this.listener.emitAdded(key, ts[key]);
56
+ this.listener.emitAdded(key, this.container[key]);
59
57
  return this;
60
58
  }
61
59
  /**
@@ -63,12 +61,28 @@ export class ObjectModel extends Object {
63
61
  * @param key {string} property name
64
62
  */
65
63
  delete(key) {
66
- const ts = this;
67
- if (ts[key]) {
68
- this.listener.emitRemoved(key, ts[key]);
69
- delete ts[key];
64
+ if (this.container[key]) {
65
+ this.listener.emitRemoved(key, this.container[key]);
66
+ delete this.container[key];
70
67
  }
71
68
  }
69
+ proxy() {
70
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
71
+ const ts = this;
72
+ return new Proxy(this.container, {
73
+ get(target, p) {
74
+ return ts.get(p);
75
+ },
76
+ set(target, p, value) {
77
+ ts.set(p, value);
78
+ return true;
79
+ },
80
+ deleteProperty(target, p) {
81
+ ts.delete(p);
82
+ return true;
83
+ }
84
+ });
85
+ }
72
86
  enableReactivity() {
73
87
  this.listener.enableReactivity();
74
88
  }