@fluidframework/sequence 2.0.0-internal.4.1.2 → 2.0.0-internal.4.2.0
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/dist/intervalCollection.d.ts +65 -23
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +128 -110
- package/dist/intervalCollection.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/lib/intervalCollection.d.ts +65 -23
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +127 -108
- package/lib/intervalCollection.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/package.json +18 -15
- package/src/intervalCollection.ts +188 -129
- package/src/packageVersion.ts +1 -1
package/lib/packageVersion.d.ts
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export declare const pkgName = "@fluidframework/sequence";
|
|
8
|
-
export declare const pkgVersion = "2.0.0-internal.4.
|
|
8
|
+
export declare const pkgVersion = "2.0.0-internal.4.2.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.d.ts.map
|
package/lib/packageVersion.js
CHANGED
|
@@ -5,5 +5,5 @@
|
|
|
5
5
|
* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
|
|
6
6
|
*/
|
|
7
7
|
export const pkgName = "@fluidframework/sequence";
|
|
8
|
-
export const pkgVersion = "2.0.0-internal.4.
|
|
8
|
+
export const pkgVersion = "2.0.0-internal.4.2.0";
|
|
9
9
|
//# sourceMappingURL=packageVersion.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,0BAA0B,CAAC;AAClD,MAAM,CAAC,MAAM,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/sequence\";\nexport const pkgVersion = \"2.0.0-internal.4.
|
|
1
|
+
{"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,0BAA0B,CAAC;AAClD,MAAM,CAAC,MAAM,UAAU,GAAG,sBAAsB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/sequence\";\nexport const pkgVersion = \"2.0.0-internal.4.2.0\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/sequence",
|
|
3
|
-
"version": "2.0.0-internal.4.
|
|
3
|
+
"version": "2.0.0-internal.4.2.0",
|
|
4
4
|
"description": "Distributed sequence",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -37,30 +37,30 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@fluidframework/common-definitions": "^0.20.1",
|
|
39
39
|
"@fluidframework/common-utils": "^1.1.1",
|
|
40
|
-
"@fluidframework/container-utils": ">=2.0.0-internal.4.
|
|
41
|
-
"@fluidframework/core-interfaces": ">=2.0.0-internal.4.
|
|
42
|
-
"@fluidframework/datastore-definitions": ">=2.0.0-internal.4.
|
|
43
|
-
"@fluidframework/merge-tree": ">=2.0.0-internal.4.
|
|
40
|
+
"@fluidframework/container-utils": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
41
|
+
"@fluidframework/core-interfaces": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
42
|
+
"@fluidframework/datastore-definitions": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
43
|
+
"@fluidframework/merge-tree": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
44
44
|
"@fluidframework/protocol-definitions": "^1.1.0",
|
|
45
|
-
"@fluidframework/runtime-definitions": ">=2.0.0-internal.4.
|
|
46
|
-
"@fluidframework/runtime-utils": ">=2.0.0-internal.4.
|
|
47
|
-
"@fluidframework/shared-object-base": ">=2.0.0-internal.4.
|
|
48
|
-
"@fluidframework/telemetry-utils": ">=2.0.0-internal.4.
|
|
45
|
+
"@fluidframework/runtime-definitions": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
46
|
+
"@fluidframework/runtime-utils": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
47
|
+
"@fluidframework/shared-object-base": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
48
|
+
"@fluidframework/telemetry-utils": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
49
49
|
"uuid": "^8.3.1"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@fluid-internal/stochastic-test-utils": ">=2.0.0-internal.4.
|
|
53
|
-
"@fluid-internal/test-dds-utils": ">=2.0.0-internal.4.
|
|
52
|
+
"@fluid-internal/stochastic-test-utils": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
53
|
+
"@fluid-internal/test-dds-utils": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
54
54
|
"@fluid-tools/benchmark": "^0.47.0",
|
|
55
|
-
"@fluid-tools/build-cli": "^0.
|
|
55
|
+
"@fluid-tools/build-cli": "^0.17.0",
|
|
56
56
|
"@fluidframework/build-common": "^1.1.0",
|
|
57
|
-
"@fluidframework/build-tools": "^0.
|
|
57
|
+
"@fluidframework/build-tools": "^0.17.0",
|
|
58
58
|
"@fluidframework/eslint-config-fluid": "^2.0.0",
|
|
59
59
|
"@fluidframework/gitresources": "^0.1039.1000",
|
|
60
|
-
"@fluidframework/mocha-test-setup": ">=2.0.0-internal.4.
|
|
60
|
+
"@fluidframework/mocha-test-setup": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
61
61
|
"@fluidframework/sequence-previous": "npm:@fluidframework/sequence@2.0.0-internal.4.1.0",
|
|
62
62
|
"@fluidframework/server-services-client": "^0.1039.1000",
|
|
63
|
-
"@fluidframework/test-runtime-utils": ">=2.0.0-internal.4.
|
|
63
|
+
"@fluidframework/test-runtime-utils": ">=2.0.0-internal.4.2.0 <2.0.0-internal.4.3.0",
|
|
64
64
|
"@microsoft/api-extractor": "^7.34.4",
|
|
65
65
|
"@types/diff": "^3.5.1",
|
|
66
66
|
"@types/mocha": "^9.1.1",
|
|
@@ -101,9 +101,12 @@
|
|
|
101
101
|
"format": "npm run prettier:fix",
|
|
102
102
|
"lint": "npm run prettier && npm run eslint",
|
|
103
103
|
"lint:fix": "npm run prettier:fix && npm run eslint:fix",
|
|
104
|
+
"perf": "cross-env FLUID_TEST_VERBOSE=1 mocha \"dist/**/*.spec.js\" --node-option unhandled-rejections=strict,expose-gc --exit -r node_modules/@fluidframework/mocha-test-setup --perfMode --fgrep @Benchmark --reporter @fluid-tools/benchmark/dist/MochaReporter.js --timeout 30000",
|
|
105
|
+
"perf:measure": "npm run perf -- --fgrep @Measurement",
|
|
104
106
|
"prettier": "prettier --check . --ignore-path ../../../.prettierignore",
|
|
105
107
|
"prettier:fix": "prettier --write . --ignore-path ../../../.prettierignore",
|
|
106
108
|
"test": "npm run test:mocha",
|
|
109
|
+
"test:benchmark:report": "mocha \"dist/test/*.perf.spec.js\" --node-option unhandled-rejections=strict,expose-gc --exit --perfMode --fgrep @Benchmark -r @fluidframework/mocha-test-setup --reporter @fluid-tools/benchmark/dist/MochaReporter.js --timeout 60000",
|
|
107
110
|
"test:coverage": "nyc npm test -- --reporter xunit --reporter-option output=nyc/junit-report.xml",
|
|
108
111
|
"test:memory": "mocha --config src/test/memory/.mocharc.js",
|
|
109
112
|
"test:memory-profiling:report": "mocha --config src/test/memory/.mocharc.js",
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
addProperties,
|
|
13
13
|
Client,
|
|
14
14
|
compareReferencePositions,
|
|
15
|
-
ConflictAction,
|
|
16
15
|
createMap,
|
|
17
16
|
ICombiningOp,
|
|
18
17
|
ISegment,
|
|
@@ -791,97 +790,54 @@ export function createSequenceInterval(
|
|
|
791
790
|
return ival;
|
|
792
791
|
}
|
|
793
792
|
|
|
794
|
-
export function
|
|
795
|
-
a.addPropertySet(b.properties);
|
|
796
|
-
return a;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
export function createIntervalIndex(conflict?: IntervalConflictResolver<Interval>) {
|
|
793
|
+
export function createIntervalIndex() {
|
|
800
794
|
const helpers: IIntervalHelpers<Interval> = {
|
|
801
795
|
compareEnds: compareIntervalEnds,
|
|
802
796
|
create: createInterval,
|
|
803
797
|
};
|
|
804
798
|
const lc = new LocalIntervalCollection<Interval>(undefined as any as Client, "", helpers);
|
|
805
|
-
if (conflict) {
|
|
806
|
-
lc.addConflictResolver(conflict);
|
|
807
|
-
} else {
|
|
808
|
-
lc.addConflictResolver(defaultIntervalConflictResolver);
|
|
809
|
-
}
|
|
810
799
|
return lc;
|
|
811
800
|
}
|
|
812
801
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
802
|
+
/**
|
|
803
|
+
* Collection of intervals.
|
|
804
|
+
*
|
|
805
|
+
* Implementers of this interface will typically implement additional APIs to support efficiently querying a collection
|
|
806
|
+
* of intervals in some manner, for example:
|
|
807
|
+
* - "find all intervals with start endpoint between these two points"
|
|
808
|
+
* - "find all intervals which overlap this range"
|
|
809
|
+
* etc.
|
|
810
|
+
*/
|
|
811
|
+
export interface IntervalIndex<TInterval extends ISerializableInterval> {
|
|
812
|
+
/**
|
|
813
|
+
* Adds an interval to the index.
|
|
814
|
+
* @remarks - Application code should never need to invoke this method on their index for production scenarios:
|
|
815
|
+
* Fluid handles adding and removing intervals from an index in response to sequence or interval changes.
|
|
816
|
+
*/
|
|
817
|
+
add(interval: TInterval): void;
|
|
819
818
|
|
|
820
|
-
|
|
819
|
+
/**
|
|
820
|
+
* Removes an interval from the index.
|
|
821
|
+
* @remarks - Application code should never need to invoke this method on their index for production scenarios:
|
|
822
|
+
* Fluid handles adding and removing intervals from an index in response to sequence or interval changes.
|
|
823
|
+
*/
|
|
824
|
+
remove(interval: TInterval): void;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
class OverlappingIntervalsIndex<TInterval extends ISerializableInterval>
|
|
828
|
+
implements IntervalIndex<TInterval>
|
|
829
|
+
{
|
|
830
|
+
private readonly intervalTree = new IntervalTree<TInterval>();
|
|
821
831
|
|
|
822
832
|
constructor(
|
|
823
833
|
private readonly client: Client,
|
|
824
|
-
private readonly label: string,
|
|
825
834
|
private readonly helpers: IIntervalHelpers<TInterval>,
|
|
826
|
-
|
|
827
|
-
private readonly onPositionChange?: (
|
|
828
|
-
interval: TInterval,
|
|
829
|
-
previousInterval: TInterval,
|
|
830
|
-
) => void,
|
|
831
|
-
) {
|
|
832
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
833
|
-
this.endIntervalTree = new RedBlackTree<TInterval, TInterval>(helpers.compareEnds);
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
public addConflictResolver(conflictResolver: IntervalConflictResolver<TInterval>) {
|
|
837
|
-
this.conflictResolver = conflictResolver;
|
|
838
|
-
this.endConflictResolver = (key: TInterval, currentKey: TInterval) => {
|
|
839
|
-
const ival = conflictResolver(key, currentKey);
|
|
840
|
-
return {
|
|
841
|
-
data: ival,
|
|
842
|
-
key: ival,
|
|
843
|
-
};
|
|
844
|
-
};
|
|
845
|
-
}
|
|
835
|
+
) {}
|
|
846
836
|
|
|
847
837
|
public map(fn: (interval: TInterval) => void) {
|
|
848
838
|
this.intervalTree.map(fn);
|
|
849
839
|
}
|
|
850
840
|
|
|
851
|
-
public createLegacyId(start: number, end: number): string {
|
|
852
|
-
// Create a non-unique ID based on start and end to be used on intervals that come from legacy clients
|
|
853
|
-
// without ID's.
|
|
854
|
-
return `${LocalIntervalCollection.legacyIdPrefix}${start}-${end}`;
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
/**
|
|
858
|
-
* Validates that a serialized interval has the ID property. Creates an ID
|
|
859
|
-
* if one does not already exist
|
|
860
|
-
*
|
|
861
|
-
* @param serializedInterval - The interval to be checked
|
|
862
|
-
* @returns The interval's existing or newly created id
|
|
863
|
-
*/
|
|
864
|
-
public ensureSerializedId(serializedInterval: ISerializedInterval): string {
|
|
865
|
-
let id: string | undefined = serializedInterval.properties?.[reservedIntervalIdKey];
|
|
866
|
-
if (id === undefined) {
|
|
867
|
-
// An interval came over the wire without an ID, so create a non-unique one based on start/end.
|
|
868
|
-
// This will allow all clients to refer to this interval consistently.
|
|
869
|
-
id = this.createLegacyId(serializedInterval.start, serializedInterval.end);
|
|
870
|
-
const newProps = {
|
|
871
|
-
[reservedIntervalIdKey]: id,
|
|
872
|
-
};
|
|
873
|
-
serializedInterval.properties = addProperties(serializedInterval.properties, newProps);
|
|
874
|
-
}
|
|
875
|
-
// Make the ID immutable for safety's sake.
|
|
876
|
-
Object.defineProperty(serializedInterval.properties, reservedIntervalIdKey, {
|
|
877
|
-
configurable: false,
|
|
878
|
-
enumerable: true,
|
|
879
|
-
writable: false,
|
|
880
|
-
});
|
|
881
|
-
|
|
882
|
-
return id;
|
|
883
|
-
}
|
|
884
|
-
|
|
885
841
|
public mapUntil(fn: (interval: TInterval) => boolean) {
|
|
886
842
|
this.intervalTree.mapUntil(fn);
|
|
887
843
|
}
|
|
@@ -988,6 +944,61 @@ export class LocalIntervalCollection<TInterval extends ISerializableInterval> {
|
|
|
988
944
|
return overlappingIntervalNodes.map((node) => node.key);
|
|
989
945
|
}
|
|
990
946
|
|
|
947
|
+
public remove(interval: TInterval) {
|
|
948
|
+
this.intervalTree.removeExisting(interval);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
public add(interval: TInterval) {
|
|
952
|
+
this.intervalTree.put(interval);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
class IdIntervalIndex<TInterval extends ISerializableInterval>
|
|
957
|
+
implements IntervalIndex<TInterval>, Iterable<TInterval>
|
|
958
|
+
{
|
|
959
|
+
private readonly intervalIdMap: Map<string, TInterval> = new Map();
|
|
960
|
+
|
|
961
|
+
public add(interval: TInterval) {
|
|
962
|
+
const id = interval.getIntervalId();
|
|
963
|
+
assert(
|
|
964
|
+
id !== undefined,
|
|
965
|
+
0x2c0 /* "ID must be created before adding interval to collection" */,
|
|
966
|
+
);
|
|
967
|
+
// Make the ID immutable.
|
|
968
|
+
Object.defineProperty(interval.properties, reservedIntervalIdKey, {
|
|
969
|
+
configurable: false,
|
|
970
|
+
enumerable: true,
|
|
971
|
+
writable: false,
|
|
972
|
+
});
|
|
973
|
+
this.intervalIdMap.set(id, interval);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
public remove(interval: TInterval) {
|
|
977
|
+
const id = interval.getIntervalId();
|
|
978
|
+
assert(id !== undefined, 0x311 /* expected id to exist on interval */);
|
|
979
|
+
this.intervalIdMap.delete(id);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
public getIntervalById(id: string) {
|
|
983
|
+
return this.intervalIdMap.get(id);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
public [Symbol.iterator]() {
|
|
987
|
+
return this.intervalIdMap.values();
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
class EndpointIndex<TInterval extends ISerializableInterval> implements IntervalIndex<TInterval> {
|
|
992
|
+
private readonly endIntervalTree: RedBlackTree<TInterval, TInterval>;
|
|
993
|
+
|
|
994
|
+
constructor(
|
|
995
|
+
private readonly client: Client,
|
|
996
|
+
private readonly helpers: IIntervalHelpers<TInterval>,
|
|
997
|
+
) {
|
|
998
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
999
|
+
this.endIntervalTree = new RedBlackTree<TInterval, TInterval>(helpers.compareEnds);
|
|
1000
|
+
}
|
|
1001
|
+
|
|
991
1002
|
public previousInterval(pos: number) {
|
|
992
1003
|
const transientInterval = this.helpers.create(
|
|
993
1004
|
"transient",
|
|
@@ -1016,32 +1027,85 @@ export class LocalIntervalCollection<TInterval extends ISerializableInterval> {
|
|
|
1016
1027
|
}
|
|
1017
1028
|
}
|
|
1018
1029
|
|
|
1019
|
-
public
|
|
1020
|
-
|
|
1021
|
-
"transient",
|
|
1022
|
-
startPosition,
|
|
1023
|
-
endPosition,
|
|
1024
|
-
this.client,
|
|
1025
|
-
IntervalType.Transient,
|
|
1026
|
-
);
|
|
1027
|
-
this.intervalTree.remove(transientInterval);
|
|
1028
|
-
this.endIntervalTree.remove(transientInterval);
|
|
1029
|
-
return transientInterval;
|
|
1030
|
+
public add(interval: TInterval): void {
|
|
1031
|
+
this.endIntervalTree.put(interval, interval);
|
|
1030
1032
|
}
|
|
1031
1033
|
|
|
1032
|
-
|
|
1033
|
-
this.intervalTree.removeExisting(interval);
|
|
1034
|
+
public remove(interval: TInterval): void {
|
|
1034
1035
|
this.endIntervalTree.remove(interval);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1035
1038
|
|
|
1036
|
-
|
|
1039
|
+
export class LocalIntervalCollection<TInterval extends ISerializableInterval> {
|
|
1040
|
+
private static readonly legacyIdPrefix = "legacy";
|
|
1041
|
+
public readonly overlappingIntervalsIndex: OverlappingIntervalsIndex<TInterval>;
|
|
1042
|
+
public readonly idIntervalIndex: IdIntervalIndex<TInterval>;
|
|
1043
|
+
public readonly endIntervalIndex: EndpointIndex<TInterval>;
|
|
1044
|
+
private readonly indexes: IntervalIndex<TInterval>[];
|
|
1037
1045
|
|
|
1038
|
-
|
|
1046
|
+
constructor(
|
|
1047
|
+
private readonly client: Client,
|
|
1048
|
+
private readonly label: string,
|
|
1049
|
+
private readonly helpers: IIntervalHelpers<TInterval>,
|
|
1050
|
+
/** Callback invoked each time one of the endpoints of an interval slides. */
|
|
1051
|
+
private readonly onPositionChange?: (
|
|
1052
|
+
interval: TInterval,
|
|
1053
|
+
previousInterval: TInterval,
|
|
1054
|
+
) => void,
|
|
1055
|
+
) {
|
|
1056
|
+
this.overlappingIntervalsIndex = new OverlappingIntervalsIndex(client, helpers);
|
|
1057
|
+
this.idIntervalIndex = new IdIntervalIndex();
|
|
1058
|
+
this.endIntervalIndex = new EndpointIndex(client, helpers);
|
|
1059
|
+
this.indexes = [
|
|
1060
|
+
this.overlappingIntervalsIndex,
|
|
1061
|
+
this.idIntervalIndex,
|
|
1062
|
+
this.endIntervalIndex,
|
|
1063
|
+
];
|
|
1064
|
+
}
|
|
1039
1065
|
|
|
1040
|
-
|
|
1066
|
+
public createLegacyId(start: number, end: number): string {
|
|
1067
|
+
// Create a non-unique ID based on start and end to be used on intervals that come from legacy clients
|
|
1068
|
+
// without ID's.
|
|
1069
|
+
return `${LocalIntervalCollection.legacyIdPrefix}${start}-${end}`;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* Validates that a serialized interval has the ID property. Creates an ID
|
|
1074
|
+
* if one does not already exist
|
|
1075
|
+
*
|
|
1076
|
+
* @param serializedInterval - The interval to be checked
|
|
1077
|
+
* @returns The interval's existing or newly created id
|
|
1078
|
+
*/
|
|
1079
|
+
public ensureSerializedId(serializedInterval: ISerializedInterval): string {
|
|
1080
|
+
let id: string | undefined = serializedInterval.properties?.[reservedIntervalIdKey];
|
|
1081
|
+
if (id === undefined) {
|
|
1082
|
+
// Back-compat: 0.39 and earlier did not have IDs on intervals. If an interval from such a client
|
|
1083
|
+
// comes over the wire, create a non-unique one based on start/end.
|
|
1084
|
+
// This will allow all clients to refer to this interval consistently.
|
|
1085
|
+
id = this.createLegacyId(serializedInterval.start, serializedInterval.end);
|
|
1086
|
+
const newProps = {
|
|
1087
|
+
[reservedIntervalIdKey]: id,
|
|
1088
|
+
};
|
|
1089
|
+
serializedInterval.properties = addProperties(serializedInterval.properties, newProps);
|
|
1090
|
+
}
|
|
1091
|
+
// Make the ID immutable for safety's sake.
|
|
1092
|
+
Object.defineProperty(serializedInterval.properties, reservedIntervalIdKey, {
|
|
1093
|
+
configurable: false,
|
|
1094
|
+
enumerable: true,
|
|
1095
|
+
writable: false,
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
return id;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
private removeIntervalFromIndexes(interval: TInterval) {
|
|
1102
|
+
for (const index of this.indexes) {
|
|
1103
|
+
index.remove(interval);
|
|
1104
|
+
}
|
|
1041
1105
|
}
|
|
1042
1106
|
|
|
1043
1107
|
public removeExistingInterval(interval: TInterval) {
|
|
1044
|
-
this.
|
|
1108
|
+
this.removeIntervalFromIndexes(interval);
|
|
1045
1109
|
this.removeIntervalListeners(interval);
|
|
1046
1110
|
}
|
|
1047
1111
|
|
|
@@ -1083,33 +1147,18 @@ export class LocalIntervalCollection<TInterval extends ISerializableInterval> {
|
|
|
1083
1147
|
}
|
|
1084
1148
|
}
|
|
1085
1149
|
|
|
1086
|
-
private
|
|
1087
|
-
const
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
0x2c0 /* "ID must be created before adding interval to collection" */,
|
|
1091
|
-
);
|
|
1092
|
-
// Make the ID immutable.
|
|
1093
|
-
Object.defineProperty(interval.properties, reservedIntervalIdKey, {
|
|
1094
|
-
configurable: false,
|
|
1095
|
-
enumerable: true,
|
|
1096
|
-
writable: false,
|
|
1097
|
-
});
|
|
1098
|
-
this.intervalTree.put(interval, this.conflictResolver);
|
|
1099
|
-
this.endIntervalTree.put(interval, interval, this.endConflictResolver);
|
|
1100
|
-
this.intervalIdMap.set(id, interval);
|
|
1150
|
+
private addIntervalToIndexes(interval: TInterval) {
|
|
1151
|
+
for (const index of this.indexes) {
|
|
1152
|
+
index.add(interval);
|
|
1153
|
+
}
|
|
1101
1154
|
}
|
|
1102
1155
|
|
|
1103
1156
|
public add(interval: TInterval): void {
|
|
1104
1157
|
this.linkEndpointsToInterval(interval);
|
|
1105
|
-
this.
|
|
1158
|
+
this.addIntervalToIndexes(interval);
|
|
1106
1159
|
this.addIntervalListeners(interval);
|
|
1107
1160
|
}
|
|
1108
1161
|
|
|
1109
|
-
public getIntervalById(id: string) {
|
|
1110
|
-
return this.intervalIdMap.get(id);
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
1162
|
public changeInterval(
|
|
1114
1163
|
interval: TInterval,
|
|
1115
1164
|
start: number | undefined,
|
|
@@ -1128,10 +1177,11 @@ export class LocalIntervalCollection<TInterval extends ISerializableInterval> {
|
|
|
1128
1177
|
}
|
|
1129
1178
|
|
|
1130
1179
|
public serialize(): ISerializedIntervalCollectionV2 {
|
|
1131
|
-
const intervals = this.intervalTree.intervals.keys();
|
|
1132
1180
|
return {
|
|
1133
1181
|
label: this.label,
|
|
1134
|
-
intervals:
|
|
1182
|
+
intervals: Array.from(this.idIntervalIndex, (interval) =>
|
|
1183
|
+
compressInterval(interval.serialize()),
|
|
1184
|
+
),
|
|
1135
1185
|
version: 2,
|
|
1136
1186
|
};
|
|
1137
1187
|
}
|
|
@@ -1164,7 +1214,7 @@ export class LocalIntervalCollection<TInterval extends ISerializableInterval> {
|
|
|
1164
1214
|
previousInterval = interval.clone() as TInterval & SequenceInterval;
|
|
1165
1215
|
previousInterval.start = cloneRef(previousInterval.start);
|
|
1166
1216
|
previousInterval.end = cloneRef(previousInterval.end);
|
|
1167
|
-
this.
|
|
1217
|
+
this.removeIntervalFromIndexes(interval);
|
|
1168
1218
|
}
|
|
1169
1219
|
},
|
|
1170
1220
|
() => {
|
|
@@ -1174,7 +1224,7 @@ export class LocalIntervalCollection<TInterval extends ISerializableInterval> {
|
|
|
1174
1224
|
);
|
|
1175
1225
|
pendingChanges--;
|
|
1176
1226
|
if (pendingChanges === 0) {
|
|
1177
|
-
this.
|
|
1227
|
+
this.addIntervalToIndexes(interval);
|
|
1178
1228
|
this.onPositionChange?.(interval, previousInterval);
|
|
1179
1229
|
previousInterval = undefined;
|
|
1180
1230
|
}
|
|
@@ -1646,7 +1696,7 @@ export class IntervalCollection<TInterval extends ISerializableInterval> extends
|
|
|
1646
1696
|
if (!this.localCollection) {
|
|
1647
1697
|
throw new LoggingError("attach must be called before accessing intervals");
|
|
1648
1698
|
}
|
|
1649
|
-
return this.localCollection.getIntervalById(id);
|
|
1699
|
+
return this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
1650
1700
|
}
|
|
1651
1701
|
|
|
1652
1702
|
/**
|
|
@@ -1734,7 +1784,7 @@ export class IntervalCollection<TInterval extends ISerializableInterval> extends
|
|
|
1734
1784
|
if (!this.localCollection) {
|
|
1735
1785
|
throw new LoggingError("Attach must be called before accessing intervals");
|
|
1736
1786
|
}
|
|
1737
|
-
const interval = this.localCollection.getIntervalById(id);
|
|
1787
|
+
const interval = this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
1738
1788
|
if (interval) {
|
|
1739
1789
|
this.deleteExistingInterval(interval, true, undefined);
|
|
1740
1790
|
}
|
|
@@ -1965,11 +2015,10 @@ export class IntervalCollection<TInterval extends ISerializableInterval> extends
|
|
|
1965
2015
|
*
|
|
1966
2016
|
* As such, the conflict resolver is never invoked and unnecessary. This API will be removed in an upcoming release.
|
|
1967
2017
|
*/
|
|
1968
|
-
public addConflictResolver(
|
|
2018
|
+
public addConflictResolver(_: IntervalConflictResolver<TInterval>): void {
|
|
1969
2019
|
if (!this.localCollection) {
|
|
1970
2020
|
throw new LoggingError("attachSequence must be called");
|
|
1971
2021
|
}
|
|
1972
|
-
this.localCollection.addConflictResolver(conflictResolver);
|
|
1973
2022
|
}
|
|
1974
2023
|
|
|
1975
2024
|
public attachDeserializer(onDeserialize: DeserializeCallback): void {
|
|
@@ -1982,9 +2031,9 @@ export class IntervalCollection<TInterval extends ISerializableInterval> extends
|
|
|
1982
2031
|
this.onDeserialize = onDeserialize;
|
|
1983
2032
|
|
|
1984
2033
|
// Trigger the async prepare work across all values in the collection
|
|
1985
|
-
this.
|
|
1986
|
-
onDeserialize
|
|
1987
|
-
}
|
|
2034
|
+
if (this.attached) {
|
|
2035
|
+
this.map(onDeserialize);
|
|
2036
|
+
}
|
|
1988
2037
|
}
|
|
1989
2038
|
|
|
1990
2039
|
/**
|
|
@@ -2013,7 +2062,7 @@ export class IntervalCollection<TInterval extends ISerializableInterval> extends
|
|
|
2013
2062
|
this.localSeqToRebasedInterval.get(localSeq) ?? this.computeRebasedPositions(localSeq);
|
|
2014
2063
|
|
|
2015
2064
|
const intervalId = properties?.[reservedIntervalIdKey];
|
|
2016
|
-
const localInterval = this.localCollection?.getIntervalById(intervalId);
|
|
2065
|
+
const localInterval = this.localCollection?.idIntervalIndex.getIntervalById(intervalId);
|
|
2017
2066
|
|
|
2018
2067
|
const rebased: SerializedIntervalDelta = {
|
|
2019
2068
|
start: startRebased,
|
|
@@ -2235,7 +2284,7 @@ export class IntervalCollection<TInterval extends ISerializableInterval> extends
|
|
|
2235
2284
|
}
|
|
2236
2285
|
|
|
2237
2286
|
const id = this.localCollection.ensureSerializedId(serializedInterval);
|
|
2238
|
-
const interval = this.localCollection.getIntervalById(id);
|
|
2287
|
+
const interval = this.localCollection.idIntervalIndex.getIntervalById(id);
|
|
2239
2288
|
if (interval) {
|
|
2240
2289
|
this.deleteExistingInterval(interval, local, op);
|
|
2241
2290
|
}
|
|
@@ -2328,7 +2377,12 @@ export class IntervalCollection<TInterval extends ISerializableInterval> extends
|
|
|
2328
2377
|
return;
|
|
2329
2378
|
}
|
|
2330
2379
|
|
|
2331
|
-
this.localCollection.gatherIterationResults(
|
|
2380
|
+
this.localCollection.overlappingIntervalsIndex.gatherIterationResults(
|
|
2381
|
+
results,
|
|
2382
|
+
iteratesForward,
|
|
2383
|
+
start,
|
|
2384
|
+
end,
|
|
2385
|
+
);
|
|
2332
2386
|
}
|
|
2333
2387
|
|
|
2334
2388
|
/**
|
|
@@ -2340,7 +2394,10 @@ export class IntervalCollection<TInterval extends ISerializableInterval> extends
|
|
|
2340
2394
|
throw new LoggingError("attachSequence must be called");
|
|
2341
2395
|
}
|
|
2342
2396
|
|
|
2343
|
-
return this.localCollection.findOverlappingIntervals(
|
|
2397
|
+
return this.localCollection.overlappingIntervalsIndex.findOverlappingIntervals(
|
|
2398
|
+
startPosition,
|
|
2399
|
+
endPosition,
|
|
2400
|
+
);
|
|
2344
2401
|
}
|
|
2345
2402
|
|
|
2346
2403
|
/**
|
|
@@ -2351,7 +2408,9 @@ export class IntervalCollection<TInterval extends ISerializableInterval> extends
|
|
|
2351
2408
|
throw new LoggingError("attachSequence must be called");
|
|
2352
2409
|
}
|
|
2353
2410
|
|
|
2354
|
-
this.localCollection.
|
|
2411
|
+
for (const interval of this.localCollection.idIntervalIndex) {
|
|
2412
|
+
fn(interval);
|
|
2413
|
+
}
|
|
2355
2414
|
}
|
|
2356
2415
|
|
|
2357
2416
|
public previousInterval(pos: number): TInterval | undefined {
|
|
@@ -2359,7 +2418,7 @@ export class IntervalCollection<TInterval extends ISerializableInterval> extends
|
|
|
2359
2418
|
throw new LoggingError("attachSequence must be called");
|
|
2360
2419
|
}
|
|
2361
2420
|
|
|
2362
|
-
return this.localCollection.previousInterval(pos);
|
|
2421
|
+
return this.localCollection.endIntervalIndex.previousInterval(pos);
|
|
2363
2422
|
}
|
|
2364
2423
|
|
|
2365
2424
|
public nextInterval(pos: number): TInterval | undefined {
|
|
@@ -2367,7 +2426,7 @@ export class IntervalCollection<TInterval extends ISerializableInterval> extends
|
|
|
2367
2426
|
throw new LoggingError("attachSequence must be called");
|
|
2368
2427
|
}
|
|
2369
2428
|
|
|
2370
|
-
return this.localCollection.nextInterval(pos);
|
|
2429
|
+
return this.localCollection.endIntervalIndex.nextInterval(pos);
|
|
2371
2430
|
}
|
|
2372
2431
|
}
|
|
2373
2432
|
|
package/src/packageVersion.ts
CHANGED