@microsoft/fast-element 1.10.5 → 2.0.0-beta.10
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 +629 -6
- package/CHANGELOG.md +152 -5
- package/dist/dts/components/attributes.d.ts +14 -1
- package/dist/dts/components/{controller.d.ts → element-controller.d.ts} +32 -32
- package/dist/dts/components/fast-definitions.d.ts +51 -11
- package/dist/dts/components/fast-element.d.ts +18 -23
- package/dist/dts/context.d.ts +157 -0
- package/dist/{esm/observation/behavior.js → dts/debug.d.ts} +0 -0
- package/dist/dts/di/di.d.ts +899 -0
- package/dist/dts/index.d.ts +17 -16
- 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 +176 -0
- package/dist/dts/metadata.d.ts +25 -0
- package/dist/dts/observation/arrays.d.ts +207 -0
- package/dist/dts/observation/notifier.d.ts +18 -18
- package/dist/dts/observation/observable.d.ts +117 -34
- package/dist/dts/observation/update-queue.d.ts +40 -0
- package/dist/dts/pending-task.d.ts +20 -0
- package/dist/dts/platform.d.ts +23 -66
- package/dist/dts/polyfills.d.ts +8 -0
- package/dist/dts/state/exports.d.ts +3 -0
- package/dist/dts/state/reactive.d.ts +8 -0
- package/dist/dts/state/state.d.ts +141 -0
- package/dist/dts/state/visitor.d.ts +6 -0
- package/dist/dts/state/watch.d.ts +10 -0
- package/dist/dts/styles/css-directive.d.ts +44 -6
- package/dist/dts/styles/css.d.ts +19 -3
- package/dist/dts/styles/element-styles.d.ts +49 -63
- package/dist/dts/styles/host.d.ts +68 -0
- package/dist/dts/templating/binding-signal.d.ts +21 -0
- package/dist/dts/templating/binding-two-way.d.ts +39 -0
- package/dist/dts/templating/binding.d.ts +101 -70
- 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 +239 -45
- package/dist/dts/templating/markup.d.ts +48 -0
- package/dist/dts/templating/node-observation.d.ts +45 -30
- package/dist/dts/templating/ref.d.ts +6 -20
- package/dist/dts/templating/render.d.ts +272 -0
- package/dist/dts/templating/repeat.d.ts +36 -33
- package/dist/dts/templating/slotted.d.ts +13 -14
- package/dist/dts/templating/template.d.ts +28 -22
- package/dist/dts/templating/view.d.ts +82 -24
- package/dist/dts/templating/when.d.ts +3 -3
- package/dist/dts/testing/exports.d.ts +3 -0
- package/dist/dts/testing/fakes.d.ts +4 -0
- package/dist/dts/testing/fixture.d.ts +84 -0
- package/dist/dts/testing/timeout.d.ts +7 -0
- package/dist/{tsdoc-metadata.json → dts/tsdoc-metadata.json} +1 -1
- package/dist/dts/utilities.d.ts +22 -0
- package/dist/esm/components/attributes.js +38 -28
- package/dist/esm/components/{controller.js → element-controller.js} +150 -140
- package/dist/esm/components/fast-definitions.js +48 -46
- package/dist/esm/components/fast-element.js +31 -12
- package/dist/esm/context.js +163 -0
- package/dist/esm/debug.js +61 -0
- package/dist/esm/di/di.js +1435 -0
- package/dist/esm/index.debug.js +2 -0
- package/dist/esm/index.js +20 -14
- package/dist/esm/index.rollup.debug.js +3 -0
- package/dist/esm/index.rollup.js +2 -0
- package/dist/esm/interfaces.js +12 -1
- package/dist/esm/metadata.js +60 -0
- package/dist/esm/observation/arrays.js +570 -0
- package/dist/esm/observation/notifier.js +27 -35
- package/dist/esm/observation/observable.js +116 -149
- package/dist/esm/observation/update-queue.js +67 -0
- package/dist/esm/pending-task.js +16 -0
- package/dist/esm/platform.js +60 -42
- package/dist/esm/polyfills.js +85 -0
- package/dist/esm/state/exports.js +3 -0
- package/dist/esm/state/reactive.js +34 -0
- package/dist/esm/state/state.js +148 -0
- package/dist/esm/state/visitor.js +28 -0
- package/dist/esm/state/watch.js +36 -0
- package/dist/esm/styles/css-directive.js +29 -13
- package/dist/esm/styles/css.js +29 -42
- package/dist/esm/styles/element-styles.js +79 -104
- package/dist/esm/styles/host.js +1 -0
- package/dist/esm/templating/binding-signal.js +83 -0
- package/dist/esm/templating/binding-two-way.js +103 -0
- package/dist/esm/templating/binding.js +189 -159
- package/dist/esm/templating/children.js +33 -23
- package/dist/esm/templating/compiler.js +258 -152
- package/dist/esm/templating/dom.js +49 -0
- package/dist/esm/templating/html-directive.js +193 -36
- package/dist/esm/templating/markup.js +75 -0
- package/dist/esm/templating/node-observation.js +51 -45
- package/dist/esm/templating/ref.js +8 -25
- package/dist/esm/templating/render.js +391 -0
- package/dist/esm/templating/repeat.js +83 -79
- package/dist/esm/templating/slotted.js +23 -20
- package/dist/esm/templating/template.js +51 -93
- package/dist/esm/templating/view.js +125 -46
- package/dist/esm/templating/when.js +6 -4
- package/dist/esm/testing/exports.js +3 -0
- package/dist/esm/testing/fakes.js +76 -0
- package/dist/esm/testing/fixture.js +86 -0
- package/dist/esm/testing/timeout.js +24 -0
- package/dist/esm/utilities.js +44 -0
- package/dist/fast-element.api.json +12153 -5373
- package/dist/fast-element.d.ts +1448 -696
- package/dist/fast-element.debug.js +4107 -0
- package/dist/fast-element.debug.min.js +1 -0
- package/dist/fast-element.js +3817 -4029
- package/dist/fast-element.min.js +1 -1
- package/dist/fast-element.untrimmed.d.ts +2814 -0
- package/docs/api-report.md +567 -254
- package/docs/fast-element-2-changes.md +15 -0
- package/karma.conf.cjs +6 -17
- package/package.json +76 -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/dts/observation/behavior.d.ts +0 -19
- package/dist/esm/dom.js +0 -207
- package/dist/esm/observation/array-change-records.js +0 -326
- package/dist/esm/observation/array-observer.js +0 -177
package/dist/esm/index.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
export * from "./platform.js";
|
|
2
|
-
|
|
3
|
-
export * from "./components/fast-element.js";
|
|
4
|
-
export { FASTElementDefinition, } from "./components/fast-definitions.js";
|
|
5
|
-
export * from "./components/attributes.js";
|
|
6
|
-
export * from "./components/controller.js";
|
|
7
|
-
export * from "./templating/compiler.js";
|
|
8
|
-
export { ElementStyles, } from "./styles/element-styles.js";
|
|
9
|
-
export { css, cssPartial } from "./styles/css.js";
|
|
10
|
-
export { CSSDirective } from "./styles/css-directive.js";
|
|
11
|
-
export * from "./templating/view.js";
|
|
2
|
+
// Observation
|
|
12
3
|
export * from "./observation/observable.js";
|
|
13
4
|
export * from "./observation/notifier.js";
|
|
14
|
-
export
|
|
15
|
-
export
|
|
16
|
-
|
|
5
|
+
export * from "./observation/arrays.js";
|
|
6
|
+
export * from "./observation/update-queue.js";
|
|
7
|
+
// Styles
|
|
8
|
+
export * from "./styles/element-styles.js";
|
|
9
|
+
export * from "./styles/css.js";
|
|
10
|
+
export * from "./styles/css-directive.js";
|
|
11
|
+
export * from "./styles/host.js";
|
|
12
|
+
// Templating
|
|
13
|
+
export * from "./templating/dom.js";
|
|
14
|
+
export * from "./templating/template.js";
|
|
15
|
+
export * from "./templating/compiler.js";
|
|
16
|
+
export { Markup, Parser } from "./templating/markup.js";
|
|
17
17
|
export * from "./templating/binding.js";
|
|
18
18
|
export * from "./templating/html-directive.js";
|
|
19
19
|
export * from "./templating/ref.js";
|
|
@@ -21,4 +21,10 @@ export * from "./templating/when.js";
|
|
|
21
21
|
export * from "./templating/repeat.js";
|
|
22
22
|
export * from "./templating/slotted.js";
|
|
23
23
|
export * from "./templating/children.js";
|
|
24
|
-
export
|
|
24
|
+
export * from "./templating/view.js";
|
|
25
|
+
export * from "./templating/node-observation.js";
|
|
26
|
+
// Components
|
|
27
|
+
export * from "./components/fast-element.js";
|
|
28
|
+
export * from "./components/fast-definitions.js";
|
|
29
|
+
export * from "./components/attributes.js";
|
|
30
|
+
export * from "./components/element-controller.js";
|
package/dist/esm/interfaces.js
CHANGED
|
@@ -1 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @internal
|
|
3
|
+
*/
|
|
4
|
+
export const isFunction = (object) => typeof object === "function";
|
|
5
|
+
/**
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export const isString = (object) => typeof object === "string";
|
|
9
|
+
/**
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export const noop = () => void 0;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { emptyArray } from "./platform.js";
|
|
2
|
+
// Tiny polyfill for TypeScript's Reflect metadata API.
|
|
3
|
+
const metadataByTarget = new Map();
|
|
4
|
+
if (!("metadata" in Reflect)) {
|
|
5
|
+
Reflect.metadata = function (key, value) {
|
|
6
|
+
return function (target) {
|
|
7
|
+
Reflect.defineMetadata(key, value, target);
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
Reflect.defineMetadata = function (key, value, target) {
|
|
11
|
+
let metadata = metadataByTarget.get(target);
|
|
12
|
+
if (metadata === void 0) {
|
|
13
|
+
metadataByTarget.set(target, (metadata = new Map()));
|
|
14
|
+
}
|
|
15
|
+
metadata.set(key, value);
|
|
16
|
+
};
|
|
17
|
+
Reflect.getOwnMetadata = function (key, target) {
|
|
18
|
+
const metadata = metadataByTarget.get(target);
|
|
19
|
+
if (metadata !== void 0) {
|
|
20
|
+
return metadata.get(key);
|
|
21
|
+
}
|
|
22
|
+
return void 0;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Provides basic metadata capabilities used by Context and Dependency Injection.
|
|
27
|
+
*/
|
|
28
|
+
export const Metadata = Object.freeze({
|
|
29
|
+
/**
|
|
30
|
+
* Gets the "design:paramtypes" metadata for the specified type.
|
|
31
|
+
* @param Type - The type to get the metadata for.
|
|
32
|
+
* @returns The metadata array or a frozen empty array if no metadata is found.
|
|
33
|
+
*/
|
|
34
|
+
getDesignParamTypes: Type => {
|
|
35
|
+
var _a;
|
|
36
|
+
return (_a = Reflect.getOwnMetadata("design:paramtypes", Type)) !== null && _a !== void 0 ? _a : emptyArray;
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* Gets the "annotation:paramtypes" metadata for the specified type.
|
|
40
|
+
* @param Type - The type to get the metadata for.
|
|
41
|
+
* @returns The metadata array or a frozen empty array if no metadata is found.
|
|
42
|
+
*/
|
|
43
|
+
getAnnotationParamTypes: Type => {
|
|
44
|
+
var _a;
|
|
45
|
+
return (_a = Reflect.getOwnMetadata("annotation:paramtypes", Type)) !== null && _a !== void 0 ? _a : emptyArray;
|
|
46
|
+
},
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
* @param Type - Gets the "annotation:paramtypes" metadata for the specified type. If none is found,
|
|
50
|
+
* an empty, mutable metadata array is created and added.
|
|
51
|
+
* @returns The metadata array.
|
|
52
|
+
*/
|
|
53
|
+
getOrCreateAnnotationParamTypes(Type) {
|
|
54
|
+
let types = this.getAnnotationParamTypes(Type);
|
|
55
|
+
if (types === emptyArray) {
|
|
56
|
+
Reflect.defineMetadata("annotation:paramtypes", (types = []), Type);
|
|
57
|
+
}
|
|
58
|
+
return types;
|
|
59
|
+
},
|
|
60
|
+
});
|
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
import { emptyArray } from "../platform.js";
|
|
2
|
+
import { SubscriberSet } from "./notifier.js";
|
|
3
|
+
import { Observable } from "./observable.js";
|
|
4
|
+
import { Updates } from "./update-queue.js";
|
|
5
|
+
/**
|
|
6
|
+
* A splice map is a representation of how a previous array of items
|
|
7
|
+
* was transformed into a new array of items. Conceptually it is a list of
|
|
8
|
+
* tuples of
|
|
9
|
+
*
|
|
10
|
+
* (index, removed, addedCount)
|
|
11
|
+
*
|
|
12
|
+
* which are kept in ascending index order of. The tuple represents that at
|
|
13
|
+
* the |index|, |removed| sequence of items were removed, and counting forward
|
|
14
|
+
* from |index|, |addedCount| items were added.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export class Splice {
|
|
18
|
+
/**
|
|
19
|
+
* Creates a splice.
|
|
20
|
+
* @param index - The index that the splice occurs at.
|
|
21
|
+
* @param removed - The items that were removed.
|
|
22
|
+
* @param addedCount - The number of items that were added.
|
|
23
|
+
*/
|
|
24
|
+
constructor(index, removed, addedCount) {
|
|
25
|
+
this.index = index;
|
|
26
|
+
this.removed = removed;
|
|
27
|
+
this.addedCount = addedCount;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Adjusts the splice index based on the provided array.
|
|
31
|
+
* @param array - The array to adjust to.
|
|
32
|
+
* @returns The same splice, mutated based on the reference array.
|
|
33
|
+
*/
|
|
34
|
+
adjustTo(array) {
|
|
35
|
+
let index = this.index;
|
|
36
|
+
const arrayLength = array.length;
|
|
37
|
+
if (index > arrayLength) {
|
|
38
|
+
index = arrayLength - this.addedCount;
|
|
39
|
+
}
|
|
40
|
+
else if (index < 0) {
|
|
41
|
+
index = arrayLength + this.removed.length + index - this.addedCount;
|
|
42
|
+
}
|
|
43
|
+
this.index = index < 0 ? 0 : index;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Indicates what level of feature support the splice
|
|
49
|
+
* strategy provides.
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
export const SpliceStrategySupport = Object.freeze({
|
|
53
|
+
/**
|
|
54
|
+
* Only supports resets.
|
|
55
|
+
*/
|
|
56
|
+
reset: 1,
|
|
57
|
+
/**
|
|
58
|
+
* Supports tracking splices and resets.
|
|
59
|
+
*/
|
|
60
|
+
splice: 2,
|
|
61
|
+
/**
|
|
62
|
+
* Supports tracking splices and resets, while applying some form
|
|
63
|
+
* of optimization, such as merging, to the splices.
|
|
64
|
+
*/
|
|
65
|
+
optimized: 3,
|
|
66
|
+
});
|
|
67
|
+
const reset = new Splice(0, emptyArray, 0);
|
|
68
|
+
reset.reset = true;
|
|
69
|
+
const resetSplices = [reset];
|
|
70
|
+
// Note: This function is *based* on the computation of the Levenshtein
|
|
71
|
+
// "edit" distance. The one change is that "updates" are treated as two
|
|
72
|
+
// edits - not one. With Array splices, an update is really a delete
|
|
73
|
+
// followed by an add. By retaining this, we optimize for "keeping" the
|
|
74
|
+
// maximum array items in the original array. For example:
|
|
75
|
+
//
|
|
76
|
+
// 'xxxx123' to '123yyyy'
|
|
77
|
+
//
|
|
78
|
+
// With 1-edit updates, the shortest path would be just to update all seven
|
|
79
|
+
// characters. With 2-edit updates, we delete 4, leave 3, and add 4. This
|
|
80
|
+
// leaves the substring '123' intact.
|
|
81
|
+
function calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd) {
|
|
82
|
+
// "Deletion" columns
|
|
83
|
+
const rowCount = oldEnd - oldStart + 1;
|
|
84
|
+
const columnCount = currentEnd - currentStart + 1;
|
|
85
|
+
const distances = new Array(rowCount);
|
|
86
|
+
let north;
|
|
87
|
+
let west;
|
|
88
|
+
// "Addition" rows. Initialize null column.
|
|
89
|
+
for (let i = 0; i < rowCount; ++i) {
|
|
90
|
+
distances[i] = new Array(columnCount);
|
|
91
|
+
distances[i][0] = i;
|
|
92
|
+
}
|
|
93
|
+
// Initialize null row
|
|
94
|
+
for (let j = 0; j < columnCount; ++j) {
|
|
95
|
+
distances[0][j] = j;
|
|
96
|
+
}
|
|
97
|
+
for (let i = 1; i < rowCount; ++i) {
|
|
98
|
+
for (let j = 1; j < columnCount; ++j) {
|
|
99
|
+
if (current[currentStart + j - 1] === old[oldStart + i - 1]) {
|
|
100
|
+
distances[i][j] = distances[i - 1][j - 1];
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
north = distances[i - 1][j] + 1;
|
|
104
|
+
west = distances[i][j - 1] + 1;
|
|
105
|
+
distances[i][j] = north < west ? north : west;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return distances;
|
|
110
|
+
}
|
|
111
|
+
// This starts at the final weight, and walks "backward" by finding
|
|
112
|
+
// the minimum previous weight recursively until the origin of the weight
|
|
113
|
+
// matrix.
|
|
114
|
+
function spliceOperationsFromEditDistances(distances) {
|
|
115
|
+
let i = distances.length - 1;
|
|
116
|
+
let j = distances[0].length - 1;
|
|
117
|
+
let current = distances[i][j];
|
|
118
|
+
const edits = [];
|
|
119
|
+
while (i > 0 || j > 0) {
|
|
120
|
+
if (i === 0) {
|
|
121
|
+
edits.push(2 /* Edit.add */);
|
|
122
|
+
j--;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (j === 0) {
|
|
126
|
+
edits.push(3 /* Edit.delete */);
|
|
127
|
+
i--;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const northWest = distances[i - 1][j - 1];
|
|
131
|
+
const west = distances[i - 1][j];
|
|
132
|
+
const north = distances[i][j - 1];
|
|
133
|
+
let min;
|
|
134
|
+
if (west < north) {
|
|
135
|
+
min = west < northWest ? west : northWest;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
min = north < northWest ? north : northWest;
|
|
139
|
+
}
|
|
140
|
+
if (min === northWest) {
|
|
141
|
+
if (northWest === current) {
|
|
142
|
+
edits.push(0 /* Edit.leave */);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
edits.push(1 /* Edit.update */);
|
|
146
|
+
current = northWest;
|
|
147
|
+
}
|
|
148
|
+
i--;
|
|
149
|
+
j--;
|
|
150
|
+
}
|
|
151
|
+
else if (min === west) {
|
|
152
|
+
edits.push(3 /* Edit.delete */);
|
|
153
|
+
i--;
|
|
154
|
+
current = west;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
edits.push(2 /* Edit.add */);
|
|
158
|
+
j--;
|
|
159
|
+
current = north;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return edits.reverse();
|
|
163
|
+
}
|
|
164
|
+
function sharedPrefix(current, old, searchLength) {
|
|
165
|
+
for (let i = 0; i < searchLength; ++i) {
|
|
166
|
+
if (current[i] !== old[i]) {
|
|
167
|
+
return i;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return searchLength;
|
|
171
|
+
}
|
|
172
|
+
function sharedSuffix(current, old, searchLength) {
|
|
173
|
+
let index1 = current.length;
|
|
174
|
+
let index2 = old.length;
|
|
175
|
+
let count = 0;
|
|
176
|
+
while (count < searchLength && current[--index1] === old[--index2]) {
|
|
177
|
+
count++;
|
|
178
|
+
}
|
|
179
|
+
return count;
|
|
180
|
+
}
|
|
181
|
+
function intersect(start1, end1, start2, end2) {
|
|
182
|
+
// Disjoint
|
|
183
|
+
if (end1 < start2 || end2 < start1) {
|
|
184
|
+
return -1;
|
|
185
|
+
}
|
|
186
|
+
// Adjacent
|
|
187
|
+
if (end1 === start2 || end2 === start1) {
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
// Non-zero intersect, span1 first
|
|
191
|
+
if (start1 < start2) {
|
|
192
|
+
if (end1 < end2) {
|
|
193
|
+
return end1 - start2; // Overlap
|
|
194
|
+
}
|
|
195
|
+
return end2 - start2; // Contained
|
|
196
|
+
}
|
|
197
|
+
// Non-zero intersect, span2 first
|
|
198
|
+
if (end2 < end1) {
|
|
199
|
+
return end2 - start1; // Overlap
|
|
200
|
+
}
|
|
201
|
+
return end1 - start1; // Contained
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* @remarks
|
|
205
|
+
* Lacking individual splice mutation information, the minimal set of
|
|
206
|
+
* splices can be synthesized given the previous state and final state of an
|
|
207
|
+
* array. The basic approach is to calculate the edit distance matrix and
|
|
208
|
+
* choose the shortest path through it.
|
|
209
|
+
*
|
|
210
|
+
* Complexity: O(l * p)
|
|
211
|
+
* l: The length of the current array
|
|
212
|
+
* p: The length of the old array
|
|
213
|
+
*/
|
|
214
|
+
function calc(current, currentStart, currentEnd, old, oldStart, oldEnd) {
|
|
215
|
+
let prefixCount = 0;
|
|
216
|
+
let suffixCount = 0;
|
|
217
|
+
const minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);
|
|
218
|
+
if (currentStart === 0 && oldStart === 0) {
|
|
219
|
+
prefixCount = sharedPrefix(current, old, minLength);
|
|
220
|
+
}
|
|
221
|
+
if (currentEnd === current.length && oldEnd === old.length) {
|
|
222
|
+
suffixCount = sharedSuffix(current, old, minLength - prefixCount);
|
|
223
|
+
}
|
|
224
|
+
currentStart += prefixCount;
|
|
225
|
+
oldStart += prefixCount;
|
|
226
|
+
currentEnd -= suffixCount;
|
|
227
|
+
oldEnd -= suffixCount;
|
|
228
|
+
if (currentEnd - currentStart === 0 && oldEnd - oldStart === 0) {
|
|
229
|
+
return emptyArray;
|
|
230
|
+
}
|
|
231
|
+
if (currentStart === currentEnd) {
|
|
232
|
+
const splice = new Splice(currentStart, [], 0);
|
|
233
|
+
while (oldStart < oldEnd) {
|
|
234
|
+
splice.removed.push(old[oldStart++]);
|
|
235
|
+
}
|
|
236
|
+
return [splice];
|
|
237
|
+
}
|
|
238
|
+
else if (oldStart === oldEnd) {
|
|
239
|
+
return [new Splice(currentStart, [], currentEnd - currentStart)];
|
|
240
|
+
}
|
|
241
|
+
const ops = spliceOperationsFromEditDistances(calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));
|
|
242
|
+
const splices = [];
|
|
243
|
+
let splice = void 0;
|
|
244
|
+
let index = currentStart;
|
|
245
|
+
let oldIndex = oldStart;
|
|
246
|
+
for (let i = 0; i < ops.length; ++i) {
|
|
247
|
+
switch (ops[i]) {
|
|
248
|
+
case 0 /* Edit.leave */:
|
|
249
|
+
if (splice !== void 0) {
|
|
250
|
+
splices.push(splice);
|
|
251
|
+
splice = void 0;
|
|
252
|
+
}
|
|
253
|
+
index++;
|
|
254
|
+
oldIndex++;
|
|
255
|
+
break;
|
|
256
|
+
case 1 /* Edit.update */:
|
|
257
|
+
if (splice === void 0) {
|
|
258
|
+
splice = new Splice(index, [], 0);
|
|
259
|
+
}
|
|
260
|
+
splice.addedCount++;
|
|
261
|
+
index++;
|
|
262
|
+
splice.removed.push(old[oldIndex]);
|
|
263
|
+
oldIndex++;
|
|
264
|
+
break;
|
|
265
|
+
case 2 /* Edit.add */:
|
|
266
|
+
if (splice === void 0) {
|
|
267
|
+
splice = new Splice(index, [], 0);
|
|
268
|
+
}
|
|
269
|
+
splice.addedCount++;
|
|
270
|
+
index++;
|
|
271
|
+
break;
|
|
272
|
+
case 3 /* Edit.delete */:
|
|
273
|
+
if (splice === void 0) {
|
|
274
|
+
splice = new Splice(index, [], 0);
|
|
275
|
+
}
|
|
276
|
+
splice.removed.push(old[oldIndex]);
|
|
277
|
+
oldIndex++;
|
|
278
|
+
break;
|
|
279
|
+
// no default
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (splice !== void 0) {
|
|
283
|
+
splices.push(splice);
|
|
284
|
+
}
|
|
285
|
+
return splices;
|
|
286
|
+
}
|
|
287
|
+
function merge(splice, splices) {
|
|
288
|
+
let inserted = false;
|
|
289
|
+
let insertionOffset = 0;
|
|
290
|
+
for (let i = 0; i < splices.length; i++) {
|
|
291
|
+
const current = splices[i];
|
|
292
|
+
current.index += insertionOffset;
|
|
293
|
+
if (inserted) {
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
const intersectCount = intersect(splice.index, splice.index + splice.removed.length, current.index, current.index + current.addedCount);
|
|
297
|
+
if (intersectCount >= 0) {
|
|
298
|
+
// Merge the two splices
|
|
299
|
+
splices.splice(i, 1);
|
|
300
|
+
i--;
|
|
301
|
+
insertionOffset -= current.addedCount - current.removed.length;
|
|
302
|
+
splice.addedCount += current.addedCount - intersectCount;
|
|
303
|
+
const deleteCount = splice.removed.length + current.removed.length - intersectCount;
|
|
304
|
+
if (!splice.addedCount && !deleteCount) {
|
|
305
|
+
// merged splice is a noop. discard.
|
|
306
|
+
inserted = true;
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
let currentRemoved = current.removed;
|
|
310
|
+
if (splice.index < current.index) {
|
|
311
|
+
// some prefix of splice.removed is prepended to current.removed.
|
|
312
|
+
const prepend = splice.removed.slice(0, current.index - splice.index);
|
|
313
|
+
prepend.push(...currentRemoved);
|
|
314
|
+
currentRemoved = prepend;
|
|
315
|
+
}
|
|
316
|
+
if (splice.index + splice.removed.length >
|
|
317
|
+
current.index + current.addedCount) {
|
|
318
|
+
// some suffix of splice.removed is appended to current.removed.
|
|
319
|
+
const append = splice.removed.slice(current.index + current.addedCount - splice.index);
|
|
320
|
+
currentRemoved.push(...append);
|
|
321
|
+
}
|
|
322
|
+
splice.removed = currentRemoved;
|
|
323
|
+
if (current.index < splice.index) {
|
|
324
|
+
splice.index = current.index;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
else if (splice.index < current.index) {
|
|
329
|
+
// Insert splice here.
|
|
330
|
+
inserted = true;
|
|
331
|
+
splices.splice(i, 0, splice);
|
|
332
|
+
i++;
|
|
333
|
+
const offset = splice.addedCount - splice.removed.length;
|
|
334
|
+
current.index += offset;
|
|
335
|
+
insertionOffset += offset;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (!inserted) {
|
|
339
|
+
splices.push(splice);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
function project(array, changes) {
|
|
343
|
+
let splices = [];
|
|
344
|
+
const initialSplices = [];
|
|
345
|
+
for (let i = 0, ii = changes.length; i < ii; i++) {
|
|
346
|
+
merge(changes[i], initialSplices);
|
|
347
|
+
}
|
|
348
|
+
for (let i = 0, ii = initialSplices.length; i < ii; ++i) {
|
|
349
|
+
const splice = initialSplices[i];
|
|
350
|
+
if (splice.addedCount === 1 && splice.removed.length === 1) {
|
|
351
|
+
if (splice.removed[0] !== array[splice.index]) {
|
|
352
|
+
splices.push(splice);
|
|
353
|
+
}
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
splices = splices.concat(calc(array, splice.index, splice.index + splice.addedCount, splice.removed, 0, splice.removed.length));
|
|
357
|
+
}
|
|
358
|
+
return splices;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* A SpliceStrategy that attempts to merge all splices into the minimal set of
|
|
362
|
+
* splices needed to represent the change from the old array to the new array.
|
|
363
|
+
* @public
|
|
364
|
+
*/
|
|
365
|
+
let defaultSpliceStrategy = Object.freeze({
|
|
366
|
+
support: SpliceStrategySupport.optimized,
|
|
367
|
+
normalize(previous, current, changes) {
|
|
368
|
+
if (previous === void 0) {
|
|
369
|
+
if (changes === void 0) {
|
|
370
|
+
return emptyArray;
|
|
371
|
+
}
|
|
372
|
+
return changes.length > 1 ? project(current, changes) : changes;
|
|
373
|
+
}
|
|
374
|
+
return resetSplices;
|
|
375
|
+
},
|
|
376
|
+
pop(array, observer, pop, args) {
|
|
377
|
+
const notEmpty = array.length > 0;
|
|
378
|
+
const result = pop.apply(array, args);
|
|
379
|
+
if (notEmpty) {
|
|
380
|
+
observer.addSplice(new Splice(array.length, [result], 0));
|
|
381
|
+
}
|
|
382
|
+
return result;
|
|
383
|
+
},
|
|
384
|
+
push(array, observer, push, args) {
|
|
385
|
+
const result = push.apply(array, args);
|
|
386
|
+
observer.addSplice(new Splice(array.length - args.length, [], args.length).adjustTo(array));
|
|
387
|
+
return result;
|
|
388
|
+
},
|
|
389
|
+
reverse(array, observer, reverse, args) {
|
|
390
|
+
const result = reverse.apply(array, args);
|
|
391
|
+
observer.reset(array);
|
|
392
|
+
return result;
|
|
393
|
+
},
|
|
394
|
+
shift(array, observer, shift, args) {
|
|
395
|
+
const notEmpty = array.length > 0;
|
|
396
|
+
const result = shift.apply(array, args);
|
|
397
|
+
if (notEmpty) {
|
|
398
|
+
observer.addSplice(new Splice(0, [result], 0));
|
|
399
|
+
}
|
|
400
|
+
return result;
|
|
401
|
+
},
|
|
402
|
+
sort(array, observer, sort, args) {
|
|
403
|
+
const result = sort.apply(array, args);
|
|
404
|
+
observer.reset(array);
|
|
405
|
+
return result;
|
|
406
|
+
},
|
|
407
|
+
splice(array, observer, splice, args) {
|
|
408
|
+
const result = splice.apply(array, args);
|
|
409
|
+
observer.addSplice(new Splice(+args[0], result, args.length > 2 ? args.length - 2 : 0).adjustTo(array));
|
|
410
|
+
return result;
|
|
411
|
+
},
|
|
412
|
+
unshift(array, observer, unshift, args) {
|
|
413
|
+
const result = unshift.apply(array, args);
|
|
414
|
+
observer.addSplice(new Splice(0, [], args.length).adjustTo(array));
|
|
415
|
+
return result;
|
|
416
|
+
},
|
|
417
|
+
});
|
|
418
|
+
/**
|
|
419
|
+
* Functionality related to tracking changes in arrays.
|
|
420
|
+
* @public
|
|
421
|
+
*/
|
|
422
|
+
export const SpliceStrategy = Object.freeze({
|
|
423
|
+
/**
|
|
424
|
+
* A set of changes that represent a full array reset.
|
|
425
|
+
*/
|
|
426
|
+
reset: resetSplices,
|
|
427
|
+
/**
|
|
428
|
+
* Sets the default strategy to use for array observers.
|
|
429
|
+
* @param strategy - The splice strategy to use.
|
|
430
|
+
*/
|
|
431
|
+
setDefaultStrategy(strategy) {
|
|
432
|
+
defaultSpliceStrategy = strategy;
|
|
433
|
+
},
|
|
434
|
+
});
|
|
435
|
+
function setNonEnumerable(target, property, value) {
|
|
436
|
+
Reflect.defineProperty(target, property, {
|
|
437
|
+
value,
|
|
438
|
+
enumerable: false,
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
class DefaultArrayObserver extends SubscriberSet {
|
|
442
|
+
constructor(subject) {
|
|
443
|
+
super(subject);
|
|
444
|
+
this.oldCollection = void 0;
|
|
445
|
+
this.splices = void 0;
|
|
446
|
+
this.needsQueue = true;
|
|
447
|
+
this._strategy = null;
|
|
448
|
+
this._lengthObserver = void 0;
|
|
449
|
+
this.call = this.flush;
|
|
450
|
+
setNonEnumerable(subject, "$fastController", this);
|
|
451
|
+
}
|
|
452
|
+
get strategy() {
|
|
453
|
+
return this._strategy;
|
|
454
|
+
}
|
|
455
|
+
set strategy(value) {
|
|
456
|
+
this._strategy = value;
|
|
457
|
+
}
|
|
458
|
+
get lengthObserver() {
|
|
459
|
+
let observer = this._lengthObserver;
|
|
460
|
+
if (observer === void 0) {
|
|
461
|
+
const array = this.subject;
|
|
462
|
+
this._lengthObserver = observer = {
|
|
463
|
+
length: array.length,
|
|
464
|
+
handleChange() {
|
|
465
|
+
if (this.length !== array.length) {
|
|
466
|
+
this.length = array.length;
|
|
467
|
+
Observable.notify(observer, "length");
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
};
|
|
471
|
+
this.subscribe(observer);
|
|
472
|
+
}
|
|
473
|
+
return observer;
|
|
474
|
+
}
|
|
475
|
+
subscribe(subscriber) {
|
|
476
|
+
this.flush();
|
|
477
|
+
super.subscribe(subscriber);
|
|
478
|
+
}
|
|
479
|
+
addSplice(splice) {
|
|
480
|
+
if (this.splices === void 0) {
|
|
481
|
+
this.splices = [splice];
|
|
482
|
+
}
|
|
483
|
+
else {
|
|
484
|
+
this.splices.push(splice);
|
|
485
|
+
}
|
|
486
|
+
this.enqueue();
|
|
487
|
+
}
|
|
488
|
+
reset(oldCollection) {
|
|
489
|
+
this.oldCollection = oldCollection;
|
|
490
|
+
this.enqueue();
|
|
491
|
+
}
|
|
492
|
+
flush() {
|
|
493
|
+
var _a;
|
|
494
|
+
const splices = this.splices;
|
|
495
|
+
const oldCollection = this.oldCollection;
|
|
496
|
+
if (splices === void 0 && oldCollection === void 0) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
this.needsQueue = true;
|
|
500
|
+
this.splices = void 0;
|
|
501
|
+
this.oldCollection = void 0;
|
|
502
|
+
this.notify(((_a = this._strategy) !== null && _a !== void 0 ? _a : defaultSpliceStrategy).normalize(oldCollection, this.subject, splices));
|
|
503
|
+
}
|
|
504
|
+
enqueue() {
|
|
505
|
+
if (this.needsQueue) {
|
|
506
|
+
this.needsQueue = false;
|
|
507
|
+
Updates.enqueue(this);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
let enabled = false;
|
|
512
|
+
/**
|
|
513
|
+
* An observer for arrays.
|
|
514
|
+
* @public
|
|
515
|
+
*/
|
|
516
|
+
export const ArrayObserver = Object.freeze({
|
|
517
|
+
/**
|
|
518
|
+
* Enables the array observation mechanism.
|
|
519
|
+
* @remarks
|
|
520
|
+
* Array observation is enabled automatically when using the
|
|
521
|
+
* {@link RepeatDirective}, so calling this API manually is
|
|
522
|
+
* not typically necessary.
|
|
523
|
+
*/
|
|
524
|
+
enable() {
|
|
525
|
+
if (enabled) {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
enabled = true;
|
|
529
|
+
Observable.setArrayObserverFactory((collection) => new DefaultArrayObserver(collection));
|
|
530
|
+
const proto = Array.prototype;
|
|
531
|
+
if (!proto.$fastPatch) {
|
|
532
|
+
setNonEnumerable(proto, "$fastPatch", 1);
|
|
533
|
+
[
|
|
534
|
+
proto.pop,
|
|
535
|
+
proto.push,
|
|
536
|
+
proto.reverse,
|
|
537
|
+
proto.shift,
|
|
538
|
+
proto.sort,
|
|
539
|
+
proto.splice,
|
|
540
|
+
proto.unshift,
|
|
541
|
+
].forEach(method => {
|
|
542
|
+
proto[method.name] = function (...args) {
|
|
543
|
+
var _a;
|
|
544
|
+
const o = this.$fastController;
|
|
545
|
+
return o === void 0
|
|
546
|
+
? method.apply(this, args)
|
|
547
|
+
: ((_a = o.strategy) !== null && _a !== void 0 ? _a : defaultSpliceStrategy)[method.name](this, o, method, args);
|
|
548
|
+
};
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
},
|
|
552
|
+
});
|
|
553
|
+
/**
|
|
554
|
+
* Enables observing the length of an array.
|
|
555
|
+
* @param array - The array to observe the length of.
|
|
556
|
+
* @returns The length of the array.
|
|
557
|
+
* @public
|
|
558
|
+
*/
|
|
559
|
+
export function lengthOf(array) {
|
|
560
|
+
if (!array) {
|
|
561
|
+
return 0;
|
|
562
|
+
}
|
|
563
|
+
let arrayObserver = array.$fastController;
|
|
564
|
+
if (arrayObserver === void 0) {
|
|
565
|
+
ArrayObserver.enable();
|
|
566
|
+
arrayObserver = Observable.getNotifier(array);
|
|
567
|
+
}
|
|
568
|
+
Observable.track(arrayObserver.lengthObserver, "length");
|
|
569
|
+
return array.length;
|
|
570
|
+
}
|