vasille 5.1.9 → 6.0.0-rc.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 (49) hide show
  1. package/lib/dev/components.js +2 -2
  2. package/lib/dev/node.js +4 -4
  3. package/lib/dev/runner.js +5 -8
  4. package/lib/dev/state.js +1 -0
  5. package/lib/dev/views.js +46 -26
  6. package/lib/functional/safety.js +0 -1
  7. package/lib/index.js +3 -7
  8. package/lib/models/array-model.js +320 -33
  9. package/lib/models/listener.js +20 -38
  10. package/lib/models/map-model.js +82 -17
  11. package/lib/models/set-model.js +79 -17
  12. package/lib/node/node.js +75 -73
  13. package/lib/node/watch.js +1 -1
  14. package/lib/runner/web/binding/attribute.js +4 -4
  15. package/lib/runner/web/binding/class.js +2 -2
  16. package/lib/runner/web/binding/property.js +1 -1
  17. package/lib/runner/web/binding/style.js +3 -3
  18. package/lib/runner/web/runner.js +37 -9
  19. package/package.json +1 -1
  20. package/types/dev/components.d.ts +1 -1
  21. package/types/dev/index.d.ts +1 -1
  22. package/types/dev/inspectable.d.ts +4 -0
  23. package/types/dev/models.d.ts +1 -1
  24. package/types/dev/node.d.ts +2 -2
  25. package/types/dev/runner.d.ts +2 -3
  26. package/types/dev/views.d.ts +18 -13
  27. package/types/index.d.ts +3 -8
  28. package/types/models/array-model.d.ts +50 -4
  29. package/types/models/listener.d.ts +7 -28
  30. package/types/models/map-model.d.ts +25 -4
  31. package/types/models/set-model.d.ts +25 -6
  32. package/types/node/node.d.ts +26 -30
  33. package/types/runner/web/binding/attribute.d.ts +2 -2
  34. package/types/runner/web/binding/class.d.ts +5 -5
  35. package/types/runner/web/binding/property.d.ts +2 -2
  36. package/types/runner/web/binding/style.d.ts +3 -3
  37. package/types/runner/web/runner.d.ts +6 -2
  38. package/lib/models/model.js +0 -1
  39. package/lib/views/array-view.js +0 -17
  40. package/lib/views/base-view.js +0 -38
  41. package/lib/views/map-view.js +0 -14
  42. package/lib/views/repeat-node.js +0 -54
  43. package/lib/views/set-view.js +0 -17
  44. package/types/models/model.d.ts +0 -9
  45. package/types/views/array-view.d.ts +0 -13
  46. package/types/views/base-view.d.ts +0 -27
  47. package/types/views/map-view.d.ts +0 -11
  48. package/types/views/repeat-node.d.ts +0 -23
  49. package/types/views/set-view.d.ts +0 -12
@@ -70,9 +70,9 @@ export class DevSwitchedNode extends SwitchedNode {
70
70
  time: Date.now(),
71
71
  });
72
72
  }
73
- destroy() {
73
+ destroy(keepNodes) {
74
74
  this.runner.inspector.destroy({ id: this.id, time: Date.now() });
75
- super.destroy();
75
+ super.destroy(keepNodes);
76
76
  }
77
77
  newChild(index) {
78
78
  const frag = new DevFragment(this.runner, null, null, "Case", { index });
package/lib/dev/node.js CHANGED
@@ -43,17 +43,17 @@ export class DevFragment extends Fragment {
43
43
  time: Date.now(),
44
44
  });
45
45
  }
46
- destroy() {
46
+ destroy(keepNodes) {
47
47
  this.inspector.destroy({ id: this.id, time: Date.now() });
48
- super.destroy();
48
+ super.destroy(keepNodes);
49
49
  }
50
- pushNode(node) {
50
+ push(node) {
51
51
  if ("id" in node && typeof node.id == "number") {
52
52
  this.inspector.setElementParent({
53
53
  parent: this.id,
54
54
  child: node.id,
55
55
  });
56
56
  }
57
- super.pushNode(node);
57
+ super.push(node);
58
58
  }
59
59
  }
package/lib/dev/runner.js CHANGED
@@ -25,9 +25,9 @@ export class DevTextNode extends TextNode {
25
25
  position: usage,
26
26
  });
27
27
  }
28
- destroy() {
28
+ destroy(keepNodes) {
29
29
  this.runner.inspector.destroy({ id: this.id, time: Date.now() });
30
- super.destroy();
30
+ super.destroy(keepNodes);
31
31
  }
32
32
  compose() {
33
33
  super.compose();
@@ -110,16 +110,13 @@ export class DevTag extends Tag {
110
110
  }
111
111
  super.applyOptions(options);
112
112
  }
113
- getNode() {
114
- return this.node;
115
- }
116
- destroy() {
113
+ destroy(keepNodes) {
117
114
  this.runner.inspector.destroy({ id: this.id, time: Date.now() });
118
- super.destroy();
115
+ super.destroy(keepNodes);
119
116
  }
120
117
  compose() {
121
118
  super.compose();
122
- Object.defineProperty(this.element, "vasille", { value: this.id, configurable: false, enumerable: false });
119
+ Object.defineProperty(this.node, "vasille", { value: this.id, configurable: false, enumerable: false });
123
120
  }
124
121
  }
125
122
  export class DevRunner extends Runner {
package/lib/dev/state.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { IValue } from "../core/ivalue.js";
2
+ import { reportError } from "../functional/safety.js";
2
3
  import { errorToString, provideId, toDevValue, } from "./inspectable.js";
3
4
  export class DevIValue extends IValue {
4
5
  }
package/lib/dev/views.js CHANGED
@@ -1,62 +1,82 @@
1
- import { ArrayView } from "../views/array-view.js";
2
- import { MapView } from "../views/map-view.js";
3
- import { SetView } from "../views/set-view.js";
1
+ import { ArrayView, SinglePassArrayView } from "../models/array-model.js";
2
+ import { MapView } from "../models/map-model.js";
3
+ import { SetView } from "../models/set-model.js";
4
+ import { Reference } from "../value/reference.js";
4
5
  import { provideId, toDevObject } from "./inspectable.js";
5
6
  import { DevFragment } from "./node.js";
7
+ import { DevReference } from "./state.js";
8
+ function createDevFragment(runner, host) {
9
+ const frag = new DevFragment(runner, null, null, "Fragment", {});
10
+ runner.inspector.setElementParent({ parent: host.id, child: frag.id });
11
+ return frag;
12
+ }
6
13
  export class DevArrayView extends ArrayView {
7
14
  id;
8
- constructor(input, runner, usage) {
9
- super(input, runner);
15
+ constructor(runner, model, slot, usage, indexDeclaration) {
16
+ super(runner, model, slot, v => (indexDeclaration ? new DevReference(v, indexDeclaration, runner.inspector) : new Reference(v)), runner => createDevFragment(runner, this));
10
17
  this.id = provideId();
11
18
  runner.inspector.createComponent({
12
19
  id: this.id,
13
20
  name: "ArrayView",
14
- props: toDevObject(input),
21
+ props: toDevObject({ model }),
22
+ usage: usage,
23
+ time: Date.now(),
24
+ });
25
+ }
26
+ }
27
+ export class DevSinglePassArrayView extends SinglePassArrayView {
28
+ id;
29
+ constructor(runner, model, key, slot, usage, valueDeclaration, indexDeclaration) {
30
+ super(runner, model, key, slot, v => new DevReference(v, valueDeclaration, runner.inspector), v => new DevReference(v, indexDeclaration, runner.inspector), runner => createDevFragment(runner, this));
31
+ this.id = provideId();
32
+ runner.inspector.createComponent({
33
+ id: this.id,
34
+ name: "SinglePassArrayView",
35
+ props: toDevObject({ model }),
15
36
  usage: usage,
16
37
  time: Date.now(),
17
38
  });
18
39
  }
19
- newChild(id, item) {
20
- const frag = new DevFragment(this.runner, null, null, "ArrayViewItem", { item });
21
- this.runner.inspector?.setElementParent({ parent: this.id, child: frag.id });
22
- return frag;
40
+ }
41
+ export class DevMultiPassArrayView extends SinglePassArrayView {
42
+ id;
43
+ constructor(runner, model, key, slot, usage, valueDeclaration, indexDeclaration) {
44
+ super(runner, model, key, slot, v => new DevReference(v, valueDeclaration, runner.inspector), v => new DevReference(v, indexDeclaration, runner.inspector), runner => createDevFragment(runner, this));
45
+ this.id = provideId();
46
+ runner.inspector.createComponent({
47
+ id: this.id,
48
+ name: "MultiPassArrayView",
49
+ props: toDevObject({ model }),
50
+ usage: usage,
51
+ time: Date.now(),
52
+ });
23
53
  }
24
54
  }
25
55
  export class DevSetView extends SetView {
26
56
  id;
27
- constructor(input, runner, usage) {
28
- super(input, runner);
57
+ constructor(runner, model, slot, usage) {
58
+ super(runner, model, slot, runner => createDevFragment(runner, this));
29
59
  this.id = provideId();
30
60
  runner.inspector.createComponent({
31
61
  id: this.id,
32
62
  name: "SetView",
33
- props: toDevObject(input),
63
+ props: toDevObject({ model }),
34
64
  usage: usage,
35
65
  time: Date.now(),
36
66
  });
37
67
  }
38
- newChild(_id, item) {
39
- const frag = new DevFragment(this.runner, null, null, "SetViewItem", { item });
40
- this.runner.inspector.setElementParent({ parent: this.id, child: frag.id });
41
- return frag;
42
- }
43
68
  }
44
69
  export class DevMapView extends MapView {
45
70
  id;
46
- constructor(input, runner, usage) {
47
- super(input, runner);
71
+ constructor(runner, model, slot, usage, valueDeclaration) {
72
+ super(runner, model, slot, v => (valueDeclaration ? new DevReference(v, valueDeclaration, runner.inspector) : new Reference(v)), runner => createDevFragment(runner, this));
48
73
  this.id = provideId();
49
74
  runner.inspector.createComponent({
50
75
  id: this.id,
51
76
  name: "MapView",
52
- props: toDevObject(input),
77
+ props: toDevObject({ model }),
53
78
  usage: usage,
54
79
  time: Date.now(),
55
80
  });
56
81
  }
57
- newChild(key, value) {
58
- const frag = new DevFragment(this.runner, null, null, "MapViewItem", { key, value });
59
- this.runner.inspector.setElementParent({ parent: this.id, child: frag.id });
60
- return frag;
61
- }
62
82
  }
@@ -1,6 +1,5 @@
1
1
  export let reportError = (e) => {
2
2
  console.error(e);
3
- console.log("Docs Link https://github.com/vasille-js/vasille-js/blob/v4/doc/V4-API.md");
4
3
  };
5
4
  export function setErrorHandler(handler) {
6
5
  reportError = handler;
package/lib/index.js CHANGED
@@ -1,17 +1,13 @@
1
1
  export { Reactive } from "./core/core.js";
2
2
  export { IValue } from "./core/ivalue.js";
3
3
  export { reportError, setErrorHandler, safe } from "./functional/safety.js";
4
- export { ArrayModel } from "./models/array-model.js";
4
+ export { ArrayModel, SinglePassArrayView, ArrayView } from "./models/array-model.js";
5
5
  export { Listener } from "./models/listener.js";
6
- export { MapModel } from "./models/map-model.js";
7
- export { SetModel } from "./models/set-model.js";
6
+ export { MapModel, MapView } from "./models/map-model.js";
7
+ export { SetModel, SetView } from "./models/set-model.js";
8
8
  export { App, Portal } from "./node/app.js";
9
9
  export { Fragment, Tag, TextNode, SwitchedNode } from "./node/node.js";
10
10
  export { Expression } from "./value/expression.js";
11
11
  export { Reference } from "./value/reference.js";
12
- export { ArrayView } from "./views/array-view.js";
13
- export { BaseView } from "./views/base-view.js";
14
- export { MapView } from "./views/map-view.js";
15
- export { SetView } from "./views/set-view.js";
16
12
  export { userError } from "./core/errors.js";
17
13
  export { Watch } from "./node/watch.js";
@@ -1,3 +1,4 @@
1
+ import { Fragment } from "../node/node.js";
1
2
  import { Listener } from "./listener.js";
2
3
  /**
3
4
  * Model based on Array class
@@ -11,12 +12,10 @@ export class ArrayModel extends Array {
11
12
  * @param ctx lifetime context of model
12
13
  */
13
14
  constructor(data, ctx) {
14
- super();
15
+ super(typeof data === "number" ? data : 0);
15
16
  this.listener = new Listener();
16
17
  if (data instanceof Array) {
17
- for (let i = 0; i < data.length; i++) {
18
- super.push(data[i]);
19
- }
18
+ super.push(...data);
20
19
  }
21
20
  ctx?.bind(this);
22
21
  }
@@ -37,10 +36,9 @@ export class ArrayModel extends Array {
37
36
  end = this.length;
38
37
  }
39
38
  for (let i = start; i < end; i++) {
40
- this.listener.emitRemoved(this[i], this[i]);
41
39
  this[i] = value;
42
- this.listener.emitAdded(value, value);
43
40
  }
41
+ this.listener.emit(0, this.length, this);
44
42
  return this;
45
43
  }
46
44
  /**
@@ -50,9 +48,8 @@ export class ArrayModel extends Array {
50
48
  pop() {
51
49
  /* istanbul ignore else */
52
50
  if (this.length > 0) {
53
- const v = super.pop();
54
- this.listener.emitRemoved(v, v);
55
- return v;
51
+ this.listener.emit(this.length - 1, 1);
52
+ return super.pop();
56
53
  }
57
54
  }
58
55
  /**
@@ -61,10 +58,8 @@ export class ArrayModel extends Array {
61
58
  * @return {number} new length of the array
62
59
  */
63
60
  push(...items) {
64
- items.forEach(item => {
65
- this.listener.emitAdded(item, item);
66
- super.push(item);
67
- });
61
+ this.listener.emit(this.length, 0, items);
62
+ super.push(...items);
68
63
  return this.length;
69
64
  }
70
65
  /**
@@ -74,9 +69,8 @@ export class ArrayModel extends Array {
74
69
  shift() {
75
70
  /* istanbul ignore else */
76
71
  if (this.length > 0) {
77
- const v = super.shift();
78
- this.listener.emitRemoved(v, v);
79
- return v;
72
+ this.listener.emit(0, 1);
73
+ return super.shift();
80
74
  }
81
75
  }
82
76
  /**
@@ -89,18 +83,8 @@ export class ArrayModel extends Array {
89
83
  splice(start, deleteCount, ...items) {
90
84
  start = Math.min(start, this.length);
91
85
  deleteCount = typeof deleteCount === "number" ? deleteCount : this.length - start;
92
- const before = this[start + deleteCount];
93
- for (let i = 0; i < deleteCount; i++) {
94
- const index = start + deleteCount - i - 1;
95
- /* istanbul ignore else */
96
- if (this[index] !== undefined) {
97
- this.listener.emitRemoved(this[index], this[index]);
98
- }
99
- }
100
- for (let i = 0; i < items.length; i++) {
101
- this.listener.emitAdded(before, items[i]);
102
- }
103
- return new ArrayModel(super.splice(start, deleteCount, ...items));
86
+ this.listener.emit(start, deleteCount, items);
87
+ return super.splice(start, deleteCount, ...items);
104
88
  }
105
89
  /**
106
90
  * Calls Array.unshift and notify about changed
@@ -108,14 +92,11 @@ export class ArrayModel extends Array {
108
92
  * @return {number} the length after prepending
109
93
  */
110
94
  unshift(...items) {
111
- for (let i = 0; i < items.length; i++) {
112
- this.listener.emitAdded(this[i], items[i]);
113
- }
95
+ this.listener.emit(0, 0, items);
114
96
  return super.unshift(...items);
115
97
  }
116
98
  replace(at, with_) {
117
- this.listener.emitAdded(this[at], with_);
118
- this.listener.emitRemoved(this[at], this[at]);
99
+ this.listener.emit(at, 1, [with_]);
119
100
  this[at] = with_;
120
101
  return this;
121
102
  }
@@ -123,3 +104,309 @@ export class ArrayModel extends Array {
123
104
  this.splice(0);
124
105
  }
125
106
  }
107
+ class BaseArrayView extends Fragment {
108
+ cache = [];
109
+ unmount(keepStructure) {
110
+ super.unmount(keepStructure);
111
+ this.cache.forEach(item => item.frag.unmount(true));
112
+ }
113
+ remount() {
114
+ for (let i = this.cache.length - 1; i >= 0; i--) {
115
+ this.cache[i].frag.remount();
116
+ }
117
+ }
118
+ destroy(keepNodes) {
119
+ for (let i = this.cache.length - 1; i >= 0; i--) {
120
+ this.cache[i]?.frag.destroy(keepNodes);
121
+ }
122
+ super.destroy(keepNodes);
123
+ }
124
+ }
125
+ export class ArrayView extends BaseArrayView {
126
+ model;
127
+ slot;
128
+ ref;
129
+ frag;
130
+ apply;
131
+ constructor(runner, model, slot, ref, frag) {
132
+ super(runner);
133
+ this.model = model;
134
+ this.slot = slot;
135
+ this.ref = ref;
136
+ this.frag = frag;
137
+ }
138
+ compose() {
139
+ const view = this;
140
+ function apply(index, remove, values) {
141
+ const children = view.cache;
142
+ const toInsert = [];
143
+ const prev = children[index - 1]?.frag;
144
+ const next = children[index + remove]?.frag;
145
+ const length = values?.length || 0;
146
+ const lastIndex = length - 1;
147
+ // create new fragments
148
+ for (let i = 0; i < length; i++) {
149
+ toInsert[i] = {
150
+ frag: view.frag(view.runner),
151
+ index: view.ref(i + index),
152
+ };
153
+ }
154
+ // locate new fragments
155
+ for (let i = 0; i < length; i++) {
156
+ toInsert[i].frag.link(view, i === 0 ? prev : toInsert[i - 1].frag, i === lastIndex ? next : toInsert[i + 1].frag);
157
+ }
158
+ // destroy removed nodes
159
+ for (let i = 0; i < remove; i++) {
160
+ children[index + i]?.frag.destroy();
161
+ }
162
+ // modify the cache
163
+ children.splice(index, remove, ...toInsert);
164
+ // update indexes of affected items in the cache
165
+ for (let i = index + length; i < children.length; i++) {
166
+ children[i].index.V = i;
167
+ }
168
+ // render new fragments content in reverse order
169
+ for (let i = lastIndex; i >= 0; i--) {
170
+ view.slot(toInsert[i].frag, values[i], toInsert[i].index);
171
+ }
172
+ }
173
+ apply(0, 0, this.model);
174
+ this.model.listener.on(apply);
175
+ this.apply = apply;
176
+ }
177
+ destroy(keepNodes) {
178
+ /* istanbul ignore else */
179
+ if (this.apply) {
180
+ this.model.listener.off(this.apply);
181
+ }
182
+ super.destroy(keepNodes);
183
+ }
184
+ }
185
+ export class DiffingArrayView extends BaseArrayView {
186
+ model;
187
+ key;
188
+ slot;
189
+ vRef;
190
+ iRef;
191
+ frag;
192
+ match;
193
+ constructor(runner, model, key, slot, vRef, iRef, frag) {
194
+ super(runner);
195
+ this.model = model;
196
+ this.key = key;
197
+ this.slot = slot;
198
+ this.vRef = vRef;
199
+ this.iRef = iRef;
200
+ this.frag = frag;
201
+ }
202
+ addChild(newCache, key, modelItem, prev, next) {
203
+ const frag = this.frag(this.runner);
204
+ const index = this.iRef(newCache.length);
205
+ const value = this.vRef(modelItem);
206
+ const cache = {
207
+ frag: frag,
208
+ key: key,
209
+ value: value,
210
+ moved: false,
211
+ unmounted: false,
212
+ index,
213
+ };
214
+ frag.link(this, prev, next);
215
+ this.slot(frag, value, index);
216
+ newCache.push(cache);
217
+ return cache;
218
+ }
219
+ destroy(keepNodes) {
220
+ /* istanbul ignore else */
221
+ if (this.match) {
222
+ this.model.off(this.match);
223
+ }
224
+ super.destroy(keepNodes);
225
+ }
226
+ }
227
+ export class SinglePassArrayView extends DiffingArrayView {
228
+ existing = new Map();
229
+ compose() {
230
+ const view = this;
231
+ const { existing } = this;
232
+ function match(model) {
233
+ const children = view.cache;
234
+ const newCache = [];
235
+ const unmounted = new Set();
236
+ const modelLength = model.length;
237
+ const cacheLength = children.length;
238
+ let modelIndex = 0;
239
+ let cacheIndex = 0;
240
+ while (modelIndex <= modelLength &&
241
+ cacheIndex <= cacheLength &&
242
+ !(modelIndex == modelLength && cacheIndex == cacheLength)) {
243
+ const modelItem = model[modelIndex];
244
+ const cacheItem = children[cacheIndex];
245
+ const key = modelItem ? view.key(modelItem) : null;
246
+ const prev = newCache[modelIndex - 1];
247
+ let present;
248
+ // ideal case, a match
249
+ if (key === cacheItem?.key) {
250
+ cacheItem.value.V = modelItem;
251
+ cacheItem.index.V = modelIndex;
252
+ newCache.push(cacheItem);
253
+ modelIndex++;
254
+ cacheIndex++;
255
+ continue;
256
+ }
257
+ // skip already unmounted items
258
+ if (cacheItem?.moved || !modelItem) {
259
+ cacheIndex++;
260
+ /* istanbul ignore else */
261
+ if (cacheItem) {
262
+ if (cacheItem.moved) {
263
+ cacheItem.moved = false;
264
+ }
265
+ else {
266
+ cacheItem.frag.unlink();
267
+ unmounted.add(cacheItem);
268
+ cacheItem.unmounted = true;
269
+ }
270
+ }
271
+ }
272
+ // the item is present in another position, move it
273
+ else if ((present = existing.get(key))) {
274
+ const frag = present.frag;
275
+ const presentIndex = present.index;
276
+ const presentValue = present.value;
277
+ const indexDiff = presentIndex.V - cacheIndex;
278
+ const removeLimit = modelLength < cacheLength ? cacheLength - modelLength + 2 : 4;
279
+ // remove items between if less than 5
280
+ if (indexDiff <= removeLimit && indexDiff > 0) {
281
+ while (cacheIndex < presentIndex.V) {
282
+ const item = children[cacheIndex];
283
+ item.frag.unmount(false);
284
+ item.unmounted = true;
285
+ unmounted.add(item);
286
+ cacheIndex++;
287
+ }
288
+ }
289
+ else {
290
+ if (!present.unmounted) {
291
+ frag.unmount(false);
292
+ }
293
+ frag.link(view, prev?.frag, cacheItem?.frag);
294
+ frag.remount();
295
+ presentIndex.V = modelIndex;
296
+ presentValue.V = modelItem;
297
+ present.moved = indexDiff > 0;
298
+ newCache.push(present);
299
+ modelIndex++;
300
+ // if was unmounted, remove it from the unmounted set
301
+ if (present.unmounted) {
302
+ unmounted.delete(present);
303
+ present.unmounted = false;
304
+ }
305
+ }
306
+ }
307
+ // add missing items
308
+ else {
309
+ /* istanbul ignore else */
310
+ if (key !== null && modelItem) {
311
+ existing.set(key, view.addChild(newCache, key, modelItem, prev?.frag, cacheItem?.frag));
312
+ modelIndex++;
313
+ }
314
+ }
315
+ }
316
+ // destroy removed nodes
317
+ unmounted.forEach(item => {
318
+ existing.delete(item.key);
319
+ item.frag.destroy();
320
+ });
321
+ view.cache = newCache;
322
+ }
323
+ match(this.model.V);
324
+ this.model.on(match);
325
+ this.match = match;
326
+ }
327
+ }
328
+ // export class MultiPassArrayView<
329
+ // T,
330
+ // Node,
331
+ // Element,
332
+ // TagOptions extends object,
333
+ // Runner extends IRunner<Node, Element, TagOptions>,
334
+ // > extends DiffingArrayView<T, Node, Element, TagOptions, Runner> {
335
+ // public override compose() {
336
+ // const view = this;
337
+ //
338
+ // function match(model: T[]) {
339
+ // const children = view.cache;
340
+ // const newCache: KeyedCacheItem<T, Node, Element, TagOptions, Runner>[] = [];
341
+ // const modelKeys = new Set<number | string>();
342
+ // const modelData: { item: T; key: number | string }[] = [];
343
+ //
344
+ // // pass 1, transform model data to keyed data
345
+ // for (let i = 0; i < model.length; i++) {
346
+ // const modelItem = model[i] as T;
347
+ // const key = view.key(modelItem);
348
+ // modelKeys.add(key);
349
+ // modelData.push({ item: modelItem, key });
350
+ // }
351
+ //
352
+ // let gt = 0,
353
+ // lt = 0;
354
+ //
355
+ // // pass 2, destroy unexisting items
356
+ // for (let i = 0; i < children.length; i++) {
357
+ // const cacheItem = children[i]!;
358
+ // const key = cacheItem.key;
359
+ //
360
+ // if (!modelKeys.has(key)) {
361
+ // const { next, prev } = cacheItem.frag;
362
+ //
363
+ // if (prev) {
364
+ // prev.next = next;
365
+ // }
366
+ // if (next) {
367
+ // next.prev = prev;
368
+ // }
369
+ //
370
+ // cacheItem.unmounted = true;
371
+ // cacheItem.frag.destroy();
372
+ // }
373
+ // }
374
+ //
375
+ // const modelLength = model.length;
376
+ // const cacheLength = children.length;
377
+ // let modelIndex = 0;
378
+ // let cacheIndex = 0;
379
+ //
380
+ // // pass 3, create new items
381
+ // while (modelIndex < modelLength && cacheIndex <= cacheLength) {
382
+ // const modelItem = modelData[modelIndex]!;
383
+ // const cacheItem = children[cacheIndex];
384
+ // const key = modelItem.key;
385
+ //
386
+ // // ideal case, a match
387
+ // if (key === cacheItem?.key) {
388
+ // cacheItem.value.V = modelItem.item;
389
+ // cacheItem.index.V = modelIndex;
390
+ // newCache.push(cacheItem);
391
+ // modelIndex++;
392
+ // cacheIndex++;
393
+ // }
394
+ // // skip unmounted items in step 2
395
+ // else if (cacheItem?.unmounted) {
396
+ // cacheIndex++;
397
+ // }
398
+ // // add missing items
399
+ // else {
400
+ // view.addChild(newCache, key, modelItem.item, newCache[modelIndex - 1]?.frag, cacheItem?.frag);
401
+ // modelIndex++;
402
+ // }
403
+ // }
404
+ //
405
+ // view.cache = newCache;
406
+ // }
407
+ //
408
+ // match(this.model.V);
409
+ // this.model.on(match);
410
+ // this.match = match;
411
+ // }
412
+ // }