@microsoft/fast-element 1.10.2 → 2.0.0-beta.3
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/.eslintrc.json +1 -12
- package/CHANGELOG.json +387 -1
- package/CHANGELOG.md +74 -2
- package/README.md +2 -2
- package/dist/dts/components/attributes.d.ts +4 -1
- package/dist/dts/components/controller.d.ts +12 -11
- package/dist/dts/components/fast-definitions.d.ts +10 -2
- package/dist/dts/components/fast-element.d.ts +12 -5
- package/dist/dts/context.d.ts +157 -0
- package/dist/dts/debug.d.ts +1 -0
- package/dist/dts/hooks.d.ts +20 -0
- package/dist/dts/index.d.ts +16 -15
- package/dist/dts/index.debug.d.ts +2 -0
- package/dist/dts/index.rollup.d.ts +2 -0
- package/dist/dts/index.rollup.debug.d.ts +3 -0
- package/dist/dts/interfaces.d.ts +145 -0
- package/dist/dts/metadata.d.ts +25 -0
- package/dist/dts/observation/arrays.d.ts +207 -0
- package/dist/dts/observation/behavior.d.ts +4 -4
- package/dist/dts/observation/notifier.d.ts +18 -18
- package/dist/dts/observation/observable.d.ts +56 -18
- package/dist/dts/observation/splice-strategies.d.ts +13 -0
- package/dist/dts/observation/update-queue.d.ts +40 -0
- package/dist/dts/platform.d.ts +18 -67
- package/dist/dts/polyfills.d.ts +8 -0
- package/dist/dts/styles/css-directive.d.ts +43 -5
- package/dist/dts/styles/css.d.ts +19 -3
- package/dist/dts/styles/element-styles.d.ts +42 -62
- package/dist/dts/templating/binding-signal.d.ts +38 -0
- package/dist/dts/templating/binding-two-way.d.ts +56 -0
- package/dist/dts/templating/binding.d.ts +233 -65
- package/dist/dts/templating/children.d.ts +18 -15
- package/dist/dts/templating/compiler.d.ts +46 -28
- package/dist/dts/templating/dom.d.ts +41 -0
- package/dist/dts/templating/html-directive.d.ts +181 -43
- package/dist/dts/templating/markup.d.ts +48 -0
- package/dist/dts/templating/node-observation.d.ts +45 -29
- package/dist/dts/templating/ref.d.ts +6 -12
- package/dist/dts/templating/repeat.d.ts +26 -14
- package/dist/dts/templating/slotted.d.ts +13 -14
- package/dist/dts/templating/template.d.ts +27 -21
- package/dist/dts/templating/view.d.ts +15 -22
- package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +1 -1
- package/dist/dts/utilities.d.ts +40 -0
- package/dist/esm/components/attributes.js +25 -24
- package/dist/esm/components/controller.js +77 -57
- package/dist/esm/components/fast-definitions.js +16 -22
- package/dist/esm/components/fast-element.js +10 -2
- package/dist/esm/context.js +159 -0
- package/dist/esm/debug.js +30 -0
- package/dist/esm/hooks.js +32 -0
- package/dist/esm/index.debug.js +2 -0
- package/dist/esm/index.js +19 -14
- package/dist/esm/index.rollup.debug.js +3 -0
- package/dist/esm/index.rollup.js +2 -0
- package/dist/esm/interfaces.js +8 -1
- package/dist/esm/metadata.js +60 -0
- package/dist/esm/observation/arrays.js +269 -0
- package/dist/esm/observation/notifier.js +27 -35
- package/dist/esm/observation/observable.js +93 -68
- package/dist/esm/observation/{array-change-records.js → splice-strategies.js} +136 -62
- package/dist/esm/observation/update-queue.js +67 -0
- package/dist/esm/platform.js +36 -42
- package/dist/esm/polyfills.js +85 -0
- package/dist/esm/styles/css-directive.js +29 -13
- package/dist/esm/styles/css.js +27 -40
- package/dist/esm/styles/element-styles.js +65 -104
- package/dist/esm/templating/binding-signal.js +84 -0
- package/dist/esm/templating/binding-two-way.js +82 -0
- package/dist/esm/templating/binding.js +306 -153
- package/dist/esm/templating/children.js +33 -23
- package/dist/esm/templating/compiler.js +236 -152
- package/dist/esm/templating/dom.js +49 -0
- package/dist/esm/templating/html-directive.js +128 -40
- package/dist/esm/templating/markup.js +75 -0
- package/dist/esm/templating/node-observation.js +50 -45
- package/dist/esm/templating/ref.js +7 -16
- package/dist/esm/templating/repeat.js +39 -36
- package/dist/esm/templating/slotted.js +23 -20
- package/dist/esm/templating/template.js +51 -95
- package/dist/esm/templating/view.js +44 -43
- package/dist/esm/templating/when.js +2 -1
- package/dist/esm/utilities.js +139 -0
- package/dist/fast-element.api.json +11789 -5377
- package/dist/fast-element.d.ts +1178 -530
- package/dist/fast-element.debug.js +3722 -0
- package/dist/fast-element.debug.min.js +1 -0
- package/dist/fast-element.js +3484 -4033
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +2699 -0
- package/docs/api-report.md +472 -219
- package/docs/fast-element-2-changes.md +15 -0
- package/docs/guide/declaring-templates.md +4 -4
- package/docs/guide/defining-elements.md +2 -2
- package/docs/guide/next-steps.md +2 -2
- package/docs/guide/observables-and-state.md +1 -1
- package/docs/guide/using-directives.md +1 -1
- package/karma.conf.cjs +6 -17
- package/package.json +63 -15
- package/dist/dts/dom.d.ts +0 -112
- package/dist/dts/observation/array-change-records.d.ts +0 -48
- package/dist/dts/observation/array-observer.d.ts +0 -9
- package/dist/esm/dom.js +0 -207
- package/dist/esm/observation/array-observer.js +0 -177
|
@@ -1,28 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isFunction, isString, } from "../interfaces.js";
|
|
2
2
|
import { FAST } from "../platform.js";
|
|
3
|
+
import { Updates } from "./update-queue.js";
|
|
3
4
|
import { PropertyChangeNotifier, SubscriberSet } from "./notifier.js";
|
|
4
5
|
/**
|
|
5
6
|
* Common Observable APIs.
|
|
6
7
|
* @public
|
|
7
8
|
*/
|
|
8
|
-
export const Observable = FAST.getById(2 /* observable */, () => {
|
|
9
|
+
export const Observable = FAST.getById(2 /* KernelServiceId.observable */, () => {
|
|
10
|
+
const queueUpdate = Updates.enqueue;
|
|
9
11
|
const volatileRegex = /(:|&&|\|\||if)/;
|
|
10
12
|
const notifierLookup = new WeakMap();
|
|
11
13
|
const accessorLookup = new WeakMap();
|
|
12
|
-
const queueUpdate = DOM.queueUpdate;
|
|
13
14
|
let watcher = void 0;
|
|
14
15
|
let createArrayObserver = (array) => {
|
|
15
|
-
throw
|
|
16
|
+
throw FAST.error(1101 /* Message.needsArrayObservation */);
|
|
16
17
|
};
|
|
17
18
|
function getNotifier(source) {
|
|
18
|
-
|
|
19
|
+
var _a;
|
|
20
|
+
let found = (_a = source.$fastController) !== null && _a !== void 0 ? _a : notifierLookup.get(source);
|
|
19
21
|
if (found === void 0) {
|
|
20
|
-
|
|
21
|
-
found = createArrayObserver(source)
|
|
22
|
-
|
|
23
|
-
else {
|
|
24
|
-
notifierLookup.set(source, (found = new PropertyChangeNotifier(source)));
|
|
25
|
-
}
|
|
22
|
+
Array.isArray(source)
|
|
23
|
+
? (found = createArrayObserver(source))
|
|
24
|
+
: notifierLookup.set(source, (found = new PropertyChangeNotifier(source)));
|
|
26
25
|
}
|
|
27
26
|
return found;
|
|
28
27
|
}
|
|
@@ -34,12 +33,7 @@ export const Observable = FAST.getById(2 /* observable */, () => {
|
|
|
34
33
|
accessors = accessorLookup.get(currentTarget);
|
|
35
34
|
currentTarget = Reflect.getPrototypeOf(currentTarget);
|
|
36
35
|
}
|
|
37
|
-
|
|
38
|
-
accessors = [];
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
accessors = accessors.slice(0);
|
|
42
|
-
}
|
|
36
|
+
accessors = accessors === void 0 ? [] : accessors.slice(0);
|
|
43
37
|
accessorLookup.set(target, accessors);
|
|
44
38
|
}
|
|
45
39
|
return accessors;
|
|
@@ -62,7 +56,7 @@ export const Observable = FAST.getById(2 /* observable */, () => {
|
|
|
62
56
|
if (oldValue !== newValue) {
|
|
63
57
|
source[field] = newValue;
|
|
64
58
|
const callback = source[this.callback];
|
|
65
|
-
if (
|
|
59
|
+
if (isFunction(callback)) {
|
|
66
60
|
callback.call(source, oldValue, newValue);
|
|
67
61
|
}
|
|
68
62
|
getNotifier(source).notify(this.name);
|
|
@@ -76,6 +70,7 @@ export const Observable = FAST.getById(2 /* observable */, () => {
|
|
|
76
70
|
this.isVolatileBinding = isVolatileBinding;
|
|
77
71
|
this.needsRefresh = true;
|
|
78
72
|
this.needsQueue = true;
|
|
73
|
+
this.isAsync = true;
|
|
79
74
|
this.first = this;
|
|
80
75
|
this.last = null;
|
|
81
76
|
this.propertySource = void 0;
|
|
@@ -83,18 +78,21 @@ export const Observable = FAST.getById(2 /* observable */, () => {
|
|
|
83
78
|
this.notifier = void 0;
|
|
84
79
|
this.next = void 0;
|
|
85
80
|
}
|
|
81
|
+
setMode(isAsync) {
|
|
82
|
+
this.isAsync = this.needsQueue = isAsync;
|
|
83
|
+
}
|
|
86
84
|
observe(source, context) {
|
|
87
85
|
if (this.needsRefresh && this.last !== null) {
|
|
88
|
-
this.
|
|
86
|
+
this.dispose();
|
|
89
87
|
}
|
|
90
88
|
const previousWatcher = watcher;
|
|
91
89
|
watcher = this.needsRefresh ? this : void 0;
|
|
92
90
|
this.needsRefresh = this.isVolatileBinding;
|
|
93
|
-
const result = this.binding(source, context);
|
|
91
|
+
const result = this.binding(source, context !== null && context !== void 0 ? context : ExecutionContext.default);
|
|
94
92
|
watcher = previousWatcher;
|
|
95
93
|
return result;
|
|
96
94
|
}
|
|
97
|
-
|
|
95
|
+
dispose() {
|
|
98
96
|
if (this.last !== null) {
|
|
99
97
|
let current = this.first;
|
|
100
98
|
while (current !== void 0) {
|
|
@@ -102,7 +100,7 @@ export const Observable = FAST.getById(2 /* observable */, () => {
|
|
|
102
100
|
current = current.next;
|
|
103
101
|
}
|
|
104
102
|
this.last = null;
|
|
105
|
-
this.needsRefresh = this.needsQueue =
|
|
103
|
+
this.needsRefresh = this.needsQueue = this.isAsync;
|
|
106
104
|
}
|
|
107
105
|
}
|
|
108
106
|
watch(propertySource, propertyName) {
|
|
@@ -122,7 +120,7 @@ export const Observable = FAST.getById(2 /* observable */, () => {
|
|
|
122
120
|
watcher = void 0;
|
|
123
121
|
/* eslint-disable-next-line */
|
|
124
122
|
prevValue = prev.propertySource[prev.propertyName];
|
|
125
|
-
/* eslint-disable-next-line
|
|
123
|
+
/* eslint-disable-next-line */
|
|
126
124
|
watcher = this;
|
|
127
125
|
if (propertySource === prevValue) {
|
|
128
126
|
this.needsRefresh = true;
|
|
@@ -137,33 +135,22 @@ export const Observable = FAST.getById(2 /* observable */, () => {
|
|
|
137
135
|
this.needsQueue = false;
|
|
138
136
|
queueUpdate(this);
|
|
139
137
|
}
|
|
138
|
+
else if (!this.isAsync) {
|
|
139
|
+
this.call();
|
|
140
|
+
}
|
|
140
141
|
}
|
|
141
142
|
call() {
|
|
142
143
|
if (this.last !== null) {
|
|
143
|
-
this.needsQueue =
|
|
144
|
+
this.needsQueue = this.isAsync;
|
|
144
145
|
this.notify(this);
|
|
145
146
|
}
|
|
146
147
|
}
|
|
147
|
-
records() {
|
|
148
|
+
*records() {
|
|
148
149
|
let next = this.first;
|
|
149
|
-
|
|
150
|
-
next
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
return { value: void 0, done: true };
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
next = next.next;
|
|
157
|
-
return {
|
|
158
|
-
value: current,
|
|
159
|
-
done: false,
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
[Symbol.iterator]: function () {
|
|
164
|
-
return this;
|
|
165
|
-
},
|
|
166
|
-
};
|
|
150
|
+
while (next !== void 0) {
|
|
151
|
+
yield next;
|
|
152
|
+
next = next.next;
|
|
153
|
+
}
|
|
167
154
|
}
|
|
168
155
|
}
|
|
169
156
|
return Object.freeze({
|
|
@@ -185,18 +172,14 @@ export const Observable = FAST.getById(2 /* observable */, () => {
|
|
|
185
172
|
* @param propertyName - The property to track as changed.
|
|
186
173
|
*/
|
|
187
174
|
track(source, propertyName) {
|
|
188
|
-
|
|
189
|
-
watcher.watch(source, propertyName);
|
|
190
|
-
}
|
|
175
|
+
watcher && watcher.watch(source, propertyName);
|
|
191
176
|
},
|
|
192
177
|
/**
|
|
193
178
|
* Notifies watchers that the currently executing property getter or function is volatile
|
|
194
179
|
* with respect to its observable dependencies.
|
|
195
180
|
*/
|
|
196
181
|
trackVolatile() {
|
|
197
|
-
|
|
198
|
-
watcher.needsRefresh = true;
|
|
199
|
-
}
|
|
182
|
+
watcher && (watcher.needsRefresh = true);
|
|
200
183
|
},
|
|
201
184
|
/**
|
|
202
185
|
* Notifies subscribers of a source object of changes.
|
|
@@ -204,6 +187,7 @@ export const Observable = FAST.getById(2 /* observable */, () => {
|
|
|
204
187
|
* @param args - The change args to pass to subscribers.
|
|
205
188
|
*/
|
|
206
189
|
notify(source, args) {
|
|
190
|
+
/* eslint-disable-next-line @typescript-eslint/no-use-before-define */
|
|
207
191
|
getNotifier(source).notify(args);
|
|
208
192
|
},
|
|
209
193
|
/**
|
|
@@ -213,16 +197,16 @@ export const Observable = FAST.getById(2 /* observable */, () => {
|
|
|
213
197
|
* or a custom accessor that specifies the property name and accessor implementation.
|
|
214
198
|
*/
|
|
215
199
|
defineProperty(target, nameOrAccessor) {
|
|
216
|
-
if (
|
|
200
|
+
if (isString(nameOrAccessor)) {
|
|
217
201
|
nameOrAccessor = new DefaultObservableAccessor(nameOrAccessor);
|
|
218
202
|
}
|
|
219
203
|
getAccessors(target).push(nameOrAccessor);
|
|
220
204
|
Reflect.defineProperty(target, nameOrAccessor.name, {
|
|
221
205
|
enumerable: true,
|
|
222
|
-
get
|
|
206
|
+
get() {
|
|
223
207
|
return nameOrAccessor.getValue(this);
|
|
224
208
|
},
|
|
225
|
-
set
|
|
209
|
+
set(newValue) {
|
|
226
210
|
nameOrAccessor.setValue(this, newValue);
|
|
227
211
|
},
|
|
228
212
|
});
|
|
@@ -271,13 +255,13 @@ export function observable(target, nameOrAccessor) {
|
|
|
271
255
|
*/
|
|
272
256
|
export function volatile(target, name, descriptor) {
|
|
273
257
|
return Object.assign({}, descriptor, {
|
|
274
|
-
get
|
|
258
|
+
get() {
|
|
275
259
|
Observable.trackVolatile();
|
|
276
260
|
return descriptor.get.apply(this);
|
|
277
261
|
},
|
|
278
262
|
});
|
|
279
263
|
}
|
|
280
|
-
const contextEvent = FAST.getById(3 /* contextEvent */, () => {
|
|
264
|
+
const contextEvent = FAST.getById(3 /* KernelServiceId.contextEvent */, () => {
|
|
281
265
|
let current = null;
|
|
282
266
|
return {
|
|
283
267
|
get() {
|
|
@@ -293,7 +277,7 @@ const contextEvent = FAST.getById(3 /* contextEvent */, () => {
|
|
|
293
277
|
* @public
|
|
294
278
|
*/
|
|
295
279
|
export class ExecutionContext {
|
|
296
|
-
constructor() {
|
|
280
|
+
constructor(parentSource = null, parentContext = null) {
|
|
297
281
|
/**
|
|
298
282
|
* The index of the current item within a repeat context.
|
|
299
283
|
*/
|
|
@@ -302,14 +286,8 @@ export class ExecutionContext {
|
|
|
302
286
|
* The length of the current collection within a repeat context.
|
|
303
287
|
*/
|
|
304
288
|
this.length = 0;
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
*/
|
|
308
|
-
this.parent = null;
|
|
309
|
-
/**
|
|
310
|
-
* The parent execution context when in nested context scenarios.
|
|
311
|
-
*/
|
|
312
|
-
this.parentContext = null;
|
|
289
|
+
this.parent = parentSource;
|
|
290
|
+
this.parentContext = parentContext;
|
|
313
291
|
}
|
|
314
292
|
/**
|
|
315
293
|
* The current event within an event handler.
|
|
@@ -352,6 +330,47 @@ export class ExecutionContext {
|
|
|
352
330
|
get isLast() {
|
|
353
331
|
return this.index === this.length - 1;
|
|
354
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* Returns the typed event detail of a custom event.
|
|
335
|
+
*/
|
|
336
|
+
eventDetail() {
|
|
337
|
+
return this.event.detail;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Returns the typed event target of the event.
|
|
341
|
+
*/
|
|
342
|
+
eventTarget() {
|
|
343
|
+
return this.event.target;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Updates the position/size on a context associated with a list item.
|
|
347
|
+
* @param index - The new index of the item.
|
|
348
|
+
* @param length - The new length of the list.
|
|
349
|
+
*/
|
|
350
|
+
updatePosition(index, length) {
|
|
351
|
+
this.index = index;
|
|
352
|
+
this.length = length;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Creates a new execution context descendent from the current context.
|
|
356
|
+
* @param source - The source for the context if different than the parent.
|
|
357
|
+
* @returns A child execution context.
|
|
358
|
+
*/
|
|
359
|
+
createChildContext(parentSource) {
|
|
360
|
+
return new ExecutionContext(parentSource, this);
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Creates a new execution context descent suitable for use in list rendering.
|
|
364
|
+
* @param item - The list item to serve as the source.
|
|
365
|
+
* @param index - The index of the item in the list.
|
|
366
|
+
* @param length - The length of the list.
|
|
367
|
+
*/
|
|
368
|
+
createItemContext(index, length) {
|
|
369
|
+
const childContext = Object.create(this);
|
|
370
|
+
childContext.index = index;
|
|
371
|
+
childContext.length = length;
|
|
372
|
+
return childContext;
|
|
373
|
+
}
|
|
355
374
|
/**
|
|
356
375
|
* Sets the event for the current execution context.
|
|
357
376
|
* @param event - The event to set.
|
|
@@ -360,11 +379,17 @@ export class ExecutionContext {
|
|
|
360
379
|
static setEvent(event) {
|
|
361
380
|
contextEvent.set(event);
|
|
362
381
|
}
|
|
382
|
+
/**
|
|
383
|
+
* Creates a new root execution context.
|
|
384
|
+
* @returns A new execution context.
|
|
385
|
+
*/
|
|
386
|
+
static create() {
|
|
387
|
+
return new ExecutionContext();
|
|
388
|
+
}
|
|
363
389
|
}
|
|
364
|
-
Observable.defineProperty(ExecutionContext.prototype, "index");
|
|
365
|
-
Observable.defineProperty(ExecutionContext.prototype, "length");
|
|
366
390
|
/**
|
|
367
|
-
* The default execution context
|
|
368
|
-
* @public
|
|
391
|
+
* The default execution context.
|
|
369
392
|
*/
|
|
370
|
-
|
|
393
|
+
ExecutionContext.default = new ExecutionContext();
|
|
394
|
+
Observable.defineProperty(ExecutionContext.prototype, "index");
|
|
395
|
+
Observable.defineProperty(ExecutionContext.prototype, "length");
|
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
import { emptyArray } from "../platform.js";
|
|
2
|
-
|
|
3
|
-
export function newSplice(index, removed, addedCount) {
|
|
4
|
-
return {
|
|
5
|
-
index: index,
|
|
6
|
-
removed: removed,
|
|
7
|
-
addedCount: addedCount,
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
const EDIT_LEAVE = 0;
|
|
11
|
-
const EDIT_UPDATE = 1;
|
|
12
|
-
const EDIT_ADD = 2;
|
|
13
|
-
const EDIT_DELETE = 3;
|
|
2
|
+
import { Splice, SpliceStrategy, SpliceStrategySupport, } from "./arrays.js";
|
|
14
3
|
// Note: This function is *based* on the computation of the Levenshtein
|
|
15
4
|
// "edit" distance. The one change is that "updates" are treated as two
|
|
16
5
|
// edits - not one. With Array splices, an update is really a delete
|
|
17
6
|
// followed by an add. By retaining this, we optimize for "keeping" the
|
|
18
7
|
// maximum array items in the original array. For example:
|
|
19
8
|
//
|
|
20
|
-
// 'xxxx123'
|
|
9
|
+
// 'xxxx123' to '123yyyy'
|
|
21
10
|
//
|
|
22
11
|
// With 1-edit updates, the shortest path would be just to update all seven
|
|
23
12
|
// characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
|
|
@@ -62,12 +51,12 @@ function spliceOperationsFromEditDistances(distances) {
|
|
|
62
51
|
const edits = [];
|
|
63
52
|
while (i > 0 || j > 0) {
|
|
64
53
|
if (i === 0) {
|
|
65
|
-
edits.push(
|
|
54
|
+
edits.push(2 /* Edit.add */);
|
|
66
55
|
j--;
|
|
67
56
|
continue;
|
|
68
57
|
}
|
|
69
58
|
if (j === 0) {
|
|
70
|
-
edits.push(
|
|
59
|
+
edits.push(3 /* Edit.delete */);
|
|
71
60
|
i--;
|
|
72
61
|
continue;
|
|
73
62
|
}
|
|
@@ -83,28 +72,27 @@ function spliceOperationsFromEditDistances(distances) {
|
|
|
83
72
|
}
|
|
84
73
|
if (min === northWest) {
|
|
85
74
|
if (northWest === current) {
|
|
86
|
-
edits.push(
|
|
75
|
+
edits.push(0 /* Edit.leave */);
|
|
87
76
|
}
|
|
88
77
|
else {
|
|
89
|
-
edits.push(
|
|
78
|
+
edits.push(1 /* Edit.update */);
|
|
90
79
|
current = northWest;
|
|
91
80
|
}
|
|
92
81
|
i--;
|
|
93
82
|
j--;
|
|
94
83
|
}
|
|
95
84
|
else if (min === west) {
|
|
96
|
-
edits.push(
|
|
85
|
+
edits.push(3 /* Edit.delete */);
|
|
97
86
|
i--;
|
|
98
87
|
current = west;
|
|
99
88
|
}
|
|
100
89
|
else {
|
|
101
|
-
edits.push(
|
|
90
|
+
edits.push(2 /* Edit.add */);
|
|
102
91
|
j--;
|
|
103
92
|
current = north;
|
|
104
93
|
}
|
|
105
94
|
}
|
|
106
|
-
edits.reverse();
|
|
107
|
-
return edits;
|
|
95
|
+
return edits.reverse();
|
|
108
96
|
}
|
|
109
97
|
function sharedPrefix(current, old, searchLength) {
|
|
110
98
|
for (let i = 0; i < searchLength; ++i) {
|
|
@@ -146,20 +134,6 @@ function intersect(start1, end1, start2, end2) {
|
|
|
146
134
|
return end1 - start1; // Contained
|
|
147
135
|
}
|
|
148
136
|
/**
|
|
149
|
-
* Splice Projection functions:
|
|
150
|
-
*
|
|
151
|
-
* A splice map is a representation of how a previous array of items
|
|
152
|
-
* was transformed into a new array of items. Conceptually it is a list of
|
|
153
|
-
* tuples of
|
|
154
|
-
*
|
|
155
|
-
* <index, removed, addedCount>
|
|
156
|
-
*
|
|
157
|
-
* which are kept in ascending index order of. The tuple represents that at
|
|
158
|
-
* the |index|, |removed| sequence of items were removed, and counting forward
|
|
159
|
-
* from |index|, |addedCount| items were added.
|
|
160
|
-
*/
|
|
161
|
-
/**
|
|
162
|
-
* @internal
|
|
163
137
|
* @remarks
|
|
164
138
|
* Lacking individual splice mutation information, the minimal set of
|
|
165
139
|
* splices can be synthesized given the previous state and final state of an
|
|
@@ -170,7 +144,7 @@ function intersect(start1, end1, start2, end2) {
|
|
|
170
144
|
* l: The length of the current array
|
|
171
145
|
* p: The length of the old array
|
|
172
146
|
*/
|
|
173
|
-
|
|
147
|
+
function calc(current, currentStart, currentEnd, old, oldStart, oldEnd) {
|
|
174
148
|
let prefixCount = 0;
|
|
175
149
|
let suffixCount = 0;
|
|
176
150
|
const minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
|
|
@@ -188,14 +162,14 @@ export function calcSplices(current, currentStart, currentEnd, old, oldStart, ol
|
|
|
188
162
|
return emptyArray;
|
|
189
163
|
}
|
|
190
164
|
if (currentStart === currentEnd) {
|
|
191
|
-
const splice =
|
|
165
|
+
const splice = new Splice(currentStart, [], 0);
|
|
192
166
|
while (oldStart < oldEnd) {
|
|
193
167
|
splice.removed.push(old[oldStart++]);
|
|
194
168
|
}
|
|
195
169
|
return [splice];
|
|
196
170
|
}
|
|
197
171
|
else if (oldStart === oldEnd) {
|
|
198
|
-
return [
|
|
172
|
+
return [new Splice(currentStart, [], currentEnd - currentStart)];
|
|
199
173
|
}
|
|
200
174
|
const ops = spliceOperationsFromEditDistances(calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
|
|
201
175
|
const splices = [];
|
|
@@ -204,7 +178,7 @@ export function calcSplices(current, currentStart, currentEnd, old, oldStart, ol
|
|
|
204
178
|
let oldIndex = oldStart;
|
|
205
179
|
for (let i = 0; i < ops.length; ++i) {
|
|
206
180
|
switch (ops[i]) {
|
|
207
|
-
case
|
|
181
|
+
case 0 /* Edit.leave */:
|
|
208
182
|
if (splice !== void 0) {
|
|
209
183
|
splices.push(splice);
|
|
210
184
|
splice = void 0;
|
|
@@ -212,25 +186,25 @@ export function calcSplices(current, currentStart, currentEnd, old, oldStart, ol
|
|
|
212
186
|
index++;
|
|
213
187
|
oldIndex++;
|
|
214
188
|
break;
|
|
215
|
-
case
|
|
189
|
+
case 1 /* Edit.update */:
|
|
216
190
|
if (splice === void 0) {
|
|
217
|
-
splice =
|
|
191
|
+
splice = new Splice(index, [], 0);
|
|
218
192
|
}
|
|
219
193
|
splice.addedCount++;
|
|
220
194
|
index++;
|
|
221
195
|
splice.removed.push(old[oldIndex]);
|
|
222
196
|
oldIndex++;
|
|
223
197
|
break;
|
|
224
|
-
case
|
|
198
|
+
case 2 /* Edit.add */:
|
|
225
199
|
if (splice === void 0) {
|
|
226
|
-
splice =
|
|
200
|
+
splice = new Splice(index, [], 0);
|
|
227
201
|
}
|
|
228
202
|
splice.addedCount++;
|
|
229
203
|
index++;
|
|
230
204
|
break;
|
|
231
|
-
case
|
|
205
|
+
case 3 /* Edit.delete */:
|
|
232
206
|
if (splice === void 0) {
|
|
233
|
-
splice =
|
|
207
|
+
splice = new Splice(index, [], 0);
|
|
234
208
|
}
|
|
235
209
|
splice.removed.push(old[oldIndex]);
|
|
236
210
|
oldIndex++;
|
|
@@ -243,9 +217,7 @@ export function calcSplices(current, currentStart, currentEnd, old, oldStart, ol
|
|
|
243
217
|
}
|
|
244
218
|
return splices;
|
|
245
219
|
}
|
|
246
|
-
|
|
247
|
-
function mergeSplice(splices, index, removed, addedCount) {
|
|
248
|
-
const splice = newSplice(index, removed, addedCount);
|
|
220
|
+
function merge(splice, splices) {
|
|
249
221
|
let inserted = false;
|
|
250
222
|
let insertionOffset = 0;
|
|
251
223
|
for (let i = 0; i < splices.length; i++) {
|
|
@@ -271,14 +243,14 @@ function mergeSplice(splices, index, removed, addedCount) {
|
|
|
271
243
|
if (splice.index < current.index) {
|
|
272
244
|
// some prefix of splice.removed is prepended to current.removed.
|
|
273
245
|
const prepend = splice.removed.slice(0, current.index - splice.index);
|
|
274
|
-
|
|
246
|
+
prepend.push(...currentRemoved);
|
|
275
247
|
currentRemoved = prepend;
|
|
276
248
|
}
|
|
277
249
|
if (splice.index + splice.removed.length >
|
|
278
250
|
current.index + current.addedCount) {
|
|
279
251
|
// some suffix of splice.removed is appended to current.removed.
|
|
280
252
|
const append = splice.removed.slice(current.index + current.addedCount - splice.index);
|
|
281
|
-
|
|
253
|
+
currentRemoved.push(...append);
|
|
282
254
|
}
|
|
283
255
|
splice.removed = currentRemoved;
|
|
284
256
|
if (current.index < splice.index) {
|
|
@@ -300,18 +272,12 @@ function mergeSplice(splices, index, removed, addedCount) {
|
|
|
300
272
|
splices.push(splice);
|
|
301
273
|
}
|
|
302
274
|
}
|
|
303
|
-
function
|
|
304
|
-
const splices = [];
|
|
305
|
-
for (let i = 0, ii = changeRecords.length; i < ii; i++) {
|
|
306
|
-
const record = changeRecords[i];
|
|
307
|
-
mergeSplice(splices, record.index, record.removed, record.addedCount);
|
|
308
|
-
}
|
|
309
|
-
return splices;
|
|
310
|
-
}
|
|
311
|
-
/** @internal */
|
|
312
|
-
export function projectArraySplices(array, changeRecords) {
|
|
275
|
+
function project(array, changes) {
|
|
313
276
|
let splices = [];
|
|
314
|
-
const initialSplices =
|
|
277
|
+
const initialSplices = [];
|
|
278
|
+
for (let i = 0, ii = changes.length; i < ii; i++) {
|
|
279
|
+
merge(changes[i], initialSplices);
|
|
280
|
+
}
|
|
315
281
|
for (let i = 0, ii = initialSplices.length; i < ii; ++i) {
|
|
316
282
|
const splice = initialSplices[i];
|
|
317
283
|
if (splice.addedCount === 1 && splice.removed.length === 1) {
|
|
@@ -320,7 +286,115 @@ export function projectArraySplices(array, changeRecords) {
|
|
|
320
286
|
}
|
|
321
287
|
continue;
|
|
322
288
|
}
|
|
323
|
-
splices = splices.concat(
|
|
289
|
+
splices = splices.concat(calc(array, splice.index, splice.index + splice.addedCount, splice.removed, 0, splice.removed.length));
|
|
324
290
|
}
|
|
325
291
|
return splices;
|
|
326
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* A SpliceStrategy that attempts to merge all splices into the minimal set of
|
|
295
|
+
* splices needed to represent the change from the old array to the new array.
|
|
296
|
+
* @public
|
|
297
|
+
*/
|
|
298
|
+
export const mergeSpliceStrategy = Object.freeze({
|
|
299
|
+
support: SpliceStrategySupport.optimized,
|
|
300
|
+
normalize(previous, current, changes) {
|
|
301
|
+
if (previous === void 0) {
|
|
302
|
+
if (changes === void 0) {
|
|
303
|
+
return emptyArray;
|
|
304
|
+
}
|
|
305
|
+
return changes.length > 1 ? project(current, changes) : changes;
|
|
306
|
+
}
|
|
307
|
+
return calc(current, 0, current.length, previous, 0, previous.length);
|
|
308
|
+
},
|
|
309
|
+
pop(array, observer, pop, args) {
|
|
310
|
+
const notEmpty = array.length > 0;
|
|
311
|
+
const result = pop.apply(array, args);
|
|
312
|
+
if (notEmpty) {
|
|
313
|
+
observer.addSplice(new Splice(array.length, [result], 0));
|
|
314
|
+
}
|
|
315
|
+
return result;
|
|
316
|
+
},
|
|
317
|
+
push(array, observer, push, args) {
|
|
318
|
+
const result = push.apply(array, args);
|
|
319
|
+
observer.addSplice(new Splice(array.length - args.length, [], args.length).adjustTo(array));
|
|
320
|
+
return result;
|
|
321
|
+
},
|
|
322
|
+
reverse(array, observer, reverse, args) {
|
|
323
|
+
observer.flush();
|
|
324
|
+
const oldArray = array.slice();
|
|
325
|
+
const result = reverse.apply(array, args);
|
|
326
|
+
observer.reset(oldArray);
|
|
327
|
+
return result;
|
|
328
|
+
},
|
|
329
|
+
shift(array, observer, shift, args) {
|
|
330
|
+
const notEmpty = array.length > 0;
|
|
331
|
+
const result = shift.apply(array, args);
|
|
332
|
+
if (notEmpty) {
|
|
333
|
+
observer.addSplice(new Splice(0, [result], 0));
|
|
334
|
+
}
|
|
335
|
+
return result;
|
|
336
|
+
},
|
|
337
|
+
sort(array, observer, sort, args) {
|
|
338
|
+
observer.flush();
|
|
339
|
+
const oldArray = array.slice();
|
|
340
|
+
const result = sort.apply(array, args);
|
|
341
|
+
observer.reset(oldArray);
|
|
342
|
+
return result;
|
|
343
|
+
},
|
|
344
|
+
splice(array, observer, splice, args) {
|
|
345
|
+
const result = splice.apply(array, args);
|
|
346
|
+
observer.addSplice(new Splice(+args[0], result, args.length > 2 ? args.length - 2 : 0).adjustTo(array));
|
|
347
|
+
return result;
|
|
348
|
+
},
|
|
349
|
+
unshift(array, observer, unshift, args) {
|
|
350
|
+
const result = unshift.apply(array, args);
|
|
351
|
+
observer.addSplice(new Splice(0, [], args.length).adjustTo(array));
|
|
352
|
+
return result;
|
|
353
|
+
},
|
|
354
|
+
});
|
|
355
|
+
/**
|
|
356
|
+
* A splice strategy that doesn't create splices, but instead
|
|
357
|
+
* tracks every change as a full array reset.
|
|
358
|
+
* @public
|
|
359
|
+
*/
|
|
360
|
+
export const resetSpliceStrategy = Object.freeze({
|
|
361
|
+
support: SpliceStrategySupport.reset,
|
|
362
|
+
normalize(previous, current, changes) {
|
|
363
|
+
return SpliceStrategy.reset;
|
|
364
|
+
},
|
|
365
|
+
pop(array, observer, pop, args) {
|
|
366
|
+
const result = pop.apply(array, args);
|
|
367
|
+
observer.reset(array);
|
|
368
|
+
return result;
|
|
369
|
+
},
|
|
370
|
+
push(array, observer, push, args) {
|
|
371
|
+
const result = push.apply(array, args);
|
|
372
|
+
observer.reset(array);
|
|
373
|
+
return result;
|
|
374
|
+
},
|
|
375
|
+
reverse(array, observer, reverse, args) {
|
|
376
|
+
const result = reverse.apply(array, args);
|
|
377
|
+
observer.reset(array);
|
|
378
|
+
return result;
|
|
379
|
+
},
|
|
380
|
+
shift(array, observer, shift, args) {
|
|
381
|
+
const result = shift.apply(array, args);
|
|
382
|
+
observer.reset(array);
|
|
383
|
+
return result;
|
|
384
|
+
},
|
|
385
|
+
sort(array, observer, sort, args) {
|
|
386
|
+
const result = sort.apply(array, args);
|
|
387
|
+
observer.reset(array);
|
|
388
|
+
return result;
|
|
389
|
+
},
|
|
390
|
+
splice(array, observer, splice, args) {
|
|
391
|
+
const result = splice.apply(array, args);
|
|
392
|
+
observer.reset(array);
|
|
393
|
+
return result;
|
|
394
|
+
},
|
|
395
|
+
unshift(array, observer, unshift, args) {
|
|
396
|
+
const result = unshift.apply(array, args);
|
|
397
|
+
observer.reset(array);
|
|
398
|
+
return result;
|
|
399
|
+
},
|
|
400
|
+
});
|