@fluidframework/merge-tree 2.0.0-dev.3.1.0.125672 → 2.0.0-dev.4.2.0.153917

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +20 -0
  3. package/dist/attributionCollection.d.ts +76 -13
  4. package/dist/attributionCollection.d.ts.map +1 -1
  5. package/dist/attributionCollection.js +173 -54
  6. package/dist/attributionCollection.js.map +1 -1
  7. package/dist/attributionPolicy.d.ts +36 -0
  8. package/dist/attributionPolicy.d.ts.map +1 -0
  9. package/dist/attributionPolicy.js +165 -0
  10. package/dist/attributionPolicy.js.map +1 -0
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +12 -3
  13. package/dist/client.js.map +1 -1
  14. package/dist/endOfTreeSegment.d.ts +4 -3
  15. package/dist/endOfTreeSegment.d.ts.map +1 -1
  16. package/dist/endOfTreeSegment.js +2 -12
  17. package/dist/endOfTreeSegment.js.map +1 -1
  18. package/dist/index.d.ts +4 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +4 -2
  21. package/dist/index.js.map +1 -1
  22. package/dist/mergeTree.d.ts +64 -9
  23. package/dist/mergeTree.d.ts.map +1 -1
  24. package/dist/mergeTree.js +127 -67
  25. package/dist/mergeTree.js.map +1 -1
  26. package/dist/mergeTreeTracking.d.ts +24 -4
  27. package/dist/mergeTreeTracking.d.ts.map +1 -1
  28. package/dist/mergeTreeTracking.js +48 -11
  29. package/dist/mergeTreeTracking.js.map +1 -1
  30. package/dist/properties.d.ts.map +1 -1
  31. package/dist/properties.js +14 -26
  32. package/dist/properties.js.map +1 -1
  33. package/dist/revertibles.d.ts +23 -9
  34. package/dist/revertibles.d.ts.map +1 -1
  35. package/dist/revertibles.js +63 -43
  36. package/dist/revertibles.js.map +1 -1
  37. package/dist/segmentPropertiesManager.d.ts +1 -0
  38. package/dist/segmentPropertiesManager.d.ts.map +1 -1
  39. package/dist/segmentPropertiesManager.js +4 -0
  40. package/dist/segmentPropertiesManager.js.map +1 -1
  41. package/dist/snapshotLoader.d.ts.map +1 -1
  42. package/dist/snapshotLoader.js +14 -4
  43. package/dist/snapshotLoader.js.map +1 -1
  44. package/dist/snapshotV1.d.ts.map +1 -1
  45. package/dist/snapshotV1.js +14 -2
  46. package/dist/snapshotV1.js.map +1 -1
  47. package/dist/snapshotlegacy.d.ts.map +1 -1
  48. package/dist/snapshotlegacy.js +8 -2
  49. package/dist/snapshotlegacy.js.map +1 -1
  50. package/dist/zamboni.js +2 -2
  51. package/dist/zamboni.js.map +1 -1
  52. package/lib/attributionCollection.d.ts +76 -13
  53. package/lib/attributionCollection.d.ts.map +1 -1
  54. package/lib/attributionCollection.js +172 -54
  55. package/lib/attributionCollection.js.map +1 -1
  56. package/lib/attributionPolicy.d.ts +36 -0
  57. package/lib/attributionPolicy.d.ts.map +1 -0
  58. package/lib/attributionPolicy.js +159 -0
  59. package/lib/attributionPolicy.js.map +1 -0
  60. package/lib/client.d.ts.map +1 -1
  61. package/lib/client.js +12 -3
  62. package/lib/client.js.map +1 -1
  63. package/lib/endOfTreeSegment.d.ts +4 -3
  64. package/lib/endOfTreeSegment.d.ts.map +1 -1
  65. package/lib/endOfTreeSegment.js +2 -12
  66. package/lib/endOfTreeSegment.js.map +1 -1
  67. package/lib/index.d.ts +4 -3
  68. package/lib/index.d.ts.map +1 -1
  69. package/lib/index.js +2 -1
  70. package/lib/index.js.map +1 -1
  71. package/lib/mergeTree.d.ts +64 -9
  72. package/lib/mergeTree.d.ts.map +1 -1
  73. package/lib/mergeTree.js +126 -67
  74. package/lib/mergeTree.js.map +1 -1
  75. package/lib/mergeTreeTracking.d.ts +24 -4
  76. package/lib/mergeTreeTracking.d.ts.map +1 -1
  77. package/lib/mergeTreeTracking.js +46 -10
  78. package/lib/mergeTreeTracking.js.map +1 -1
  79. package/lib/properties.d.ts.map +1 -1
  80. package/lib/properties.js +14 -26
  81. package/lib/properties.js.map +1 -1
  82. package/lib/revertibles.d.ts +23 -9
  83. package/lib/revertibles.d.ts.map +1 -1
  84. package/lib/revertibles.js +64 -44
  85. package/lib/revertibles.js.map +1 -1
  86. package/lib/segmentPropertiesManager.d.ts +1 -0
  87. package/lib/segmentPropertiesManager.d.ts.map +1 -1
  88. package/lib/segmentPropertiesManager.js +4 -0
  89. package/lib/segmentPropertiesManager.js.map +1 -1
  90. package/lib/snapshotLoader.d.ts.map +1 -1
  91. package/lib/snapshotLoader.js +14 -4
  92. package/lib/snapshotLoader.js.map +1 -1
  93. package/lib/snapshotV1.d.ts.map +1 -1
  94. package/lib/snapshotV1.js +14 -2
  95. package/lib/snapshotV1.js.map +1 -1
  96. package/lib/snapshotlegacy.d.ts.map +1 -1
  97. package/lib/snapshotlegacy.js +8 -2
  98. package/lib/snapshotlegacy.js.map +1 -1
  99. package/lib/zamboni.js +2 -2
  100. package/lib/zamboni.js.map +1 -1
  101. package/package.json +113 -65
  102. package/src/attributionCollection.ts +280 -71
  103. package/src/attributionPolicy.ts +250 -0
  104. package/src/client.ts +13 -2
  105. package/src/endOfTreeSegment.ts +3 -16
  106. package/src/index.ts +15 -3
  107. package/src/mergeTree.ts +205 -92
  108. package/src/mergeTreeTracking.ts +70 -17
  109. package/src/properties.ts +17 -26
  110. package/src/revertibles.ts +104 -47
  111. package/src/segmentPropertiesManager.ts +4 -0
  112. package/src/snapshotLoader.ts +18 -5
  113. package/src/snapshotV1.ts +23 -2
  114. package/src/snapshotlegacy.ts +10 -2
  115. package/src/zamboni.ts +2 -2
package/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # @fluidframework/merge-tree
2
+
3
+ ## 2.0.0-internal.4.1.0
4
+
5
+ Dependency updates only.
package/README.md CHANGED
@@ -5,6 +5,26 @@ sequence of collaboratively edited items. MergeTree is used in both SharedSequen
5
5
 
6
6
  See [GitHub](https://github.com/microsoft/FluidFramework) for more details on the Fluid Framework and packages within.
7
7
 
8
+ <!-- AUTO-GENERATED-CONTENT:START (README_DEPENDENCY_GUIDELINES_SECTION:includeHeading=TRUE) -->
9
+
10
+ <!-- prettier-ignore-start -->
11
+ <!-- NOTE: This section is automatically generated using @fluid-tools/markdown-magic. Do not update these generated contents directly. -->
12
+
13
+ ## Using Fluid Framework libraries
14
+
15
+ When taking a dependency on a Fluid Framework library, we recommend using a `^` (caret) version range, such as `^1.3.4`.
16
+ While Fluid Framework libraries may use different ranges with interdependencies between other Fluid Framework libraries,
17
+ library consumers should always prefer `^`.
18
+
19
+ Note that when depending on a library version of the form 2.0.0-internal.x.y.z, called the Fluid internal version
20
+ scheme, you must use a `>= <` dependency range. Standard `^` and `~` ranges will not work as expected. See the
21
+ [@fluid-tools/version-tools](https://github.com/microsoft/FluidFramework/blob/main/build-tools/packages/version-tools/README.md)
22
+ package for more information including tools to convert between version schemes.
23
+
24
+ <!-- prettier-ignore-end -->
25
+
26
+ <!-- AUTO-GENERATED-CONTENT:END -->
27
+
8
28
  ## Operations
9
29
 
10
30
  The three basic operations provided by MergeTree are:
@@ -4,29 +4,79 @@
4
4
  */
5
5
  import { AttributionKey } from "@fluidframework/runtime-definitions";
6
6
  import { ISegment } from "./mergeTreeNodes";
7
- export interface SerializedAttributionCollection {
7
+ /**
8
+ * @internal
9
+ */
10
+ export interface SequenceOffsets {
8
11
  /**
9
12
  * Parallel array with posBreakpoints which tracks the seq of insertion.
10
13
  * Ex: if seqs is [45, 46] and posBreakpoints is [0, 3], the section of the string
11
14
  * between offsets 0 and 3 was inserted at seq 45 and the section of the string between
12
15
  * 3 and the length of the string was inserted at seq 46.
16
+ *
17
+ * @remarks - We use null here rather than undefined as round-tripping through JSON converts
18
+ * undefineds to null anyway
13
19
  */
14
- seqs: number[];
20
+ seqs: (number | AttributionKey | null)[];
15
21
  posBreakpoints: number[];
22
+ }
23
+ /**
24
+ * @internal
25
+ */
26
+ export interface SerializedAttributionCollection extends SequenceOffsets {
27
+ channels?: {
28
+ [name: string]: SequenceOffsets;
29
+ };
16
30
  length: number;
17
31
  }
32
+ /**
33
+ * @internal
34
+ */
35
+ export interface IAttributionCollectionSpec<T> {
36
+ root: Iterable<{
37
+ offset: number;
38
+ key: T | null;
39
+ }>;
40
+ channels?: {
41
+ [name: string]: Iterable<{
42
+ offset: number;
43
+ key: T | null;
44
+ }>;
45
+ };
46
+ length: number;
47
+ }
48
+ /**
49
+ * @internal
50
+ * @sealed
51
+ */
52
+ export interface IAttributionCollectionSerializer {
53
+ /**
54
+ * @internal
55
+ */
56
+ serializeAttributionCollections(segments: Iterable<{
57
+ attribution?: IAttributionCollection<AttributionKey>;
58
+ cachedLength: number;
59
+ }>): SerializedAttributionCollection;
60
+ /**
61
+ * Populates attribution information on segments using the provided summary.
62
+ * @internal
63
+ */
64
+ populateAttributionCollections(segments: Iterable<ISegment>, summary: SerializedAttributionCollection): void;
65
+ }
18
66
  /**
19
67
  * @alpha
20
68
  */
21
69
  export interface IAttributionCollection<T> {
22
70
  /**
23
71
  * Retrieves the attribution key associated with the provided offset.
72
+ * @param channel - When specified, gets an attribution key associated with a particular channel.
24
73
  */
25
- getAtOffset(offset: number): T;
74
+ getAtOffset(offset: number, channel?: string): AttributionKey | undefined;
26
75
  /**
27
76
  * Total length of all attribution keys in this collection.
28
77
  */
29
78
  readonly length: number;
79
+ readonly channelNames: Iterable<string>;
30
80
  /**
31
81
  * Retrieve all key/offset pairs stored on this segment. Entries should be ordered by offset, such that
32
82
  * the `i`th result's attribution key applies to offsets in the open range between the `i`th offset and the
@@ -34,41 +84,54 @@ export interface IAttributionCollection<T> {
34
84
  * The last entry's key applies to the open interval from the last entry's offset to this collection's length.
35
85
  * @internal
36
86
  */
37
- getAll(): Iterable<{
38
- offset: number;
39
- key: T;
40
- }>;
87
+ getAll(): IAttributionCollectionSpec<T>;
41
88
  /** @internal */
42
89
  splitAt(pos: number): IAttributionCollection<T>;
43
90
  /** @internal */
44
91
  append(other: IAttributionCollection<T>): void;
45
92
  /** @internal */
46
93
  clone(): IAttributionCollection<T>;
94
+ /**
95
+ * Updates this collection with new attribution data.
96
+ * @param name - Name of the channel that requires an update. Undefined signifies the root channel.
97
+ * Updates apply only to the individual channel (i.e. if an attribution policy needs to update the root
98
+ * channel and 4 other channels, it should call `.update` 5 times).
99
+ * @param channel - Updated collection for that channel.
100
+ * @internal
101
+ */
102
+ update(name: string | undefined, channel: IAttributionCollection<T>): any;
47
103
  }
104
+ export declare function areEqualAttributionKeys(a: AttributionKey | null | undefined, b: AttributionKey | null | undefined): boolean;
48
105
  export declare class AttributionCollection implements IAttributionCollection<AttributionKey> {
49
106
  private _length;
50
107
  private offsets;
51
108
  private keys;
52
- constructor(baseEntry: AttributionKey, _length: number);
109
+ private channels?;
110
+ private get channelEntries();
111
+ constructor(_length: number, baseEntry?: AttributionKey | null);
112
+ get channelNames(): string[];
53
113
  getAtOffset(offset: number): AttributionKey;
114
+ getAtOffset(offset: number, channel: string): AttributionKey | undefined;
54
115
  private findIndex;
116
+ private get;
55
117
  get length(): number;
56
118
  /**
57
119
  * Splits this attribution collection into two with entries for [0, pos) and [pos, length).
58
120
  */
59
121
  splitAt(pos: number): AttributionCollection;
60
122
  append(other: AttributionCollection): void;
61
- getAll(): {
62
- offset: number;
63
- key: AttributionKey;
64
- }[];
123
+ getAll(): IAttributionCollectionSpec<AttributionKey>;
65
124
  clone(): AttributionCollection;
125
+ update(name: string | undefined, channel: AttributionCollection): void;
66
126
  /**
67
127
  * Rehydrates attribution information from its serialized form into the provided iterable of consecutive segments.
68
128
  */
69
- static populateAttributionCollections(segments: Iterable<ISegment>, summary: SerializedAttributionCollection): void;
129
+ static populateAttributionCollections(segments: ISegment[], summary: SerializedAttributionCollection): void;
70
130
  /**
71
131
  * Condenses attribution information on consecutive segments into a `SerializedAttributionCollection`
132
+ *
133
+ * Note: this operates on segments rather than attribution collections directly so that it can handle cases
134
+ * where only some segments have attribution defined.
72
135
  */
73
136
  static serializeAttributionCollections(segments: Iterable<{
74
137
  attribution?: IAttributionCollection<AttributionKey>;
@@ -1 +1 @@
1
- {"version":3,"file":"attributionCollection.d.ts","sourceRoot":"","sources":["../src/attributionCollection.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,WAAW,+BAA+B;IAC/C;;;;;OAKG;IACH,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,cAAc,EAAE,MAAM,EAAE,CAAC;IAEzB,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACxC;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC;IAE/B;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;;;;OAMG;IACH,MAAM,IAAI,QAAQ,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IAE/C,gBAAgB;IAChB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAEhD,gBAAgB;IAChB,MAAM,CAAC,KAAK,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAE/C,gBAAgB;IAChB,KAAK,IAAI,sBAAsB,CAAC,CAAC,CAAC,CAAC;CACnC;AAeD,qBAAa,qBAAsB,YAAW,sBAAsB,CAAC,cAAc,CAAC;IAIrC,OAAO,CAAC,OAAO;IAH7D,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,IAAI,CAAmB;gBAEZ,SAAS,EAAE,cAAc,EAAU,OAAO,EAAE,MAAM;IAK9D,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc;IAKlD,OAAO,CAAC,SAAS;IAWjB,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED;;OAEG;IACI,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,qBAAqB;IAgB3C,MAAM,CAAC,KAAK,EAAE,qBAAqB,GAAG,IAAI;IAW1C,MAAM,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,cAAc,CAAA;KAAE,EAAE;IAQnD,KAAK,IAAI,qBAAqB;IAOrC;;OAEG;WACW,8BAA8B,CAC3C,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC5B,OAAO,EAAE,+BAA+B,GACtC,IAAI;IAkCP;;OAEG;WACW,+BAA+B,CAC5C,QAAQ,EAAE,QAAQ,CAAC;QAClB,WAAW,CAAC,EAAE,sBAAsB,CAAC,cAAc,CAAC,CAAC;QACrD,YAAY,EAAE,MAAM,CAAC;KACrB,CAAC,GACA,+BAA+B;CAwClC"}
1
+ {"version":3,"file":"attributionCollection.d.ts","sourceRoot":"","sources":["../src/attributionCollection.ts"],"names":[],"mappings":"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"}
@@ -4,28 +4,58 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.AttributionCollection = void 0;
7
+ exports.AttributionCollection = exports.areEqualAttributionKeys = void 0;
8
8
  const common_utils_1 = require("@fluidframework/common-utils");
9
+ // note: treats null and undefined as equivalent
9
10
  function areEqualAttributionKeys(a, b) {
11
+ if (!a && !b) {
12
+ return true;
13
+ }
14
+ if (!a || !b) {
15
+ return false;
16
+ }
10
17
  if (a.type !== b.type) {
11
18
  return false;
12
19
  }
20
+ // Note: TS can't narrow the type of b inside this switch statement, hence the need for casting.
13
21
  switch (a.type) {
14
22
  case "op":
15
23
  return a.seq === b.seq;
24
+ case "detached":
25
+ return a.id === b.id;
26
+ case "local":
27
+ return true;
16
28
  default:
17
- (0, common_utils_1.unreachableCase)(a.type, "Unhandled AttributionKey type");
29
+ (0, common_utils_1.unreachableCase)(a, "Unhandled AttributionKey type");
18
30
  }
19
31
  }
32
+ exports.areEqualAttributionKeys = areEqualAttributionKeys;
20
33
  class AttributionCollection {
21
- constructor(baseEntry, _length) {
34
+ constructor(_length, baseEntry) {
22
35
  this._length = _length;
23
- this.offsets = [0];
24
- this.keys = [baseEntry];
36
+ this.offsets = [];
37
+ this.keys = [];
38
+ if (baseEntry !== undefined) {
39
+ this.offsets.push(0);
40
+ this.keys.push(baseEntry);
41
+ }
42
+ }
43
+ get channelEntries() {
44
+ var _a;
45
+ return Object.entries((_a = this.channels) !== null && _a !== void 0 ? _a : {});
25
46
  }
26
- getAtOffset(offset) {
47
+ get channelNames() {
48
+ var _a;
49
+ return Object.keys((_a = this.channels) !== null && _a !== void 0 ? _a : {});
50
+ }
51
+ getAtOffset(offset, channel) {
52
+ var _a;
53
+ if (channel !== undefined) {
54
+ const subCollection = (_a = this.channels) === null || _a === void 0 ? void 0 : _a[channel];
55
+ return subCollection === null || subCollection === void 0 ? void 0 : subCollection.getAtOffset(offset);
56
+ }
27
57
  (0, common_utils_1.assert)(offset >= 0 && offset < this._length, 0x443 /* Requested offset should be valid */);
28
- return this.keys[this.findIndex(offset)];
58
+ return this.get(this.findIndex(offset));
29
59
  }
30
60
  findIndex(offset) {
31
61
  // Note: maximum length here is 256 for text segments. Perf testing shows that linear scan beats binary search
@@ -37,6 +67,10 @@ class AttributionCollection {
37
67
  }
38
68
  return this.offsets[i] === offset ? i : i - 1;
39
69
  }
70
+ get(index) {
71
+ const key = this.keys[index];
72
+ return key !== null ? key : undefined;
73
+ }
40
74
  get length() {
41
75
  return this._length;
42
76
  }
@@ -45,12 +79,17 @@ class AttributionCollection {
45
79
  */
46
80
  splitAt(pos) {
47
81
  const splitIndex = this.findIndex(pos);
48
- const splitBaseEntry = this.keys[splitIndex];
49
- const splitCollection = new AttributionCollection(splitBaseEntry, this.length - pos);
50
- for (let i = splitIndex + 1; i < this.keys.length; i++) {
51
- splitCollection.offsets.push(this.offsets[i] - pos);
82
+ const splitCollection = new AttributionCollection(this.length - pos);
83
+ for (let i = splitIndex; i < this.keys.length; i++) {
84
+ splitCollection.offsets.push(Math.max(this.offsets[i] - pos, 0));
52
85
  splitCollection.keys.push(this.keys[i]);
53
86
  }
87
+ if (this.channels) {
88
+ splitCollection.channels = {};
89
+ for (const [key, collection] of this.channelEntries) {
90
+ splitCollection.channels[key] = collection.splitAt(pos);
91
+ }
92
+ }
54
93
  const spliceIndex = this.offsets[splitIndex] === pos ? splitIndex : splitIndex + 1;
55
94
  this.keys.splice(spliceIndex);
56
95
  this.offsets.splice(spliceIndex);
@@ -58,6 +97,8 @@ class AttributionCollection {
58
97
  return splitCollection;
59
98
  }
60
99
  append(other) {
100
+ var _a, _b, _c;
101
+ var _d;
61
102
  const lastEntry = this.keys[this.keys.length - 1];
62
103
  for (let i = 0; i < other.keys.length; i++) {
63
104
  if (i !== 0 || !areEqualAttributionKeys(lastEntry, other.keys[i])) {
@@ -65,82 +106,160 @@ class AttributionCollection {
65
106
  this.keys.push(other.keys[i]);
66
107
  }
67
108
  }
109
+ if (other.channels !== undefined || this.channels !== undefined) {
110
+ (_a = this.channels) !== null && _a !== void 0 ? _a : (this.channels = {});
111
+ for (const [key, collection] of other.channelEntries) {
112
+ const thisCollection = ((_b = (_d = this.channels)[key]) !== null && _b !== void 0 ? _b : (_d[key] = new AttributionCollection(this.length, null)));
113
+ thisCollection.append(collection);
114
+ }
115
+ for (const [key, collection] of this.channelEntries) {
116
+ if (((_c = other.channels) === null || _c === void 0 ? void 0 : _c[key]) === undefined) {
117
+ collection.append(new AttributionCollection(other.length, null));
118
+ }
119
+ }
120
+ }
68
121
  this._length += other.length;
69
122
  }
70
123
  getAll() {
71
- const results = new Array(this.keys.length);
124
+ const root = new Array(this.keys.length);
72
125
  for (let i = 0; i < this.keys.length; i++) {
73
- results[i] = { offset: this.offsets[i], key: this.keys[i] };
126
+ root[i] = { offset: this.offsets[i], key: this.keys[i] };
74
127
  }
75
- return results;
128
+ const result = {
129
+ root,
130
+ length: this.length,
131
+ };
132
+ if (this.channels !== undefined) {
133
+ result.channels = {};
134
+ for (const [key, collection] of this.channelEntries) {
135
+ result.channels[key] = collection.getAll().root;
136
+ }
137
+ }
138
+ return result;
76
139
  }
77
140
  clone() {
78
- const copy = new AttributionCollection(this.keys[0], this.length);
141
+ const copy = new AttributionCollection(this.length);
79
142
  copy.keys = this.keys.slice();
80
143
  copy.offsets = this.offsets.slice();
144
+ if (this.channels !== undefined) {
145
+ const channelsCopy = {};
146
+ for (const [key, collection] of this.channelEntries) {
147
+ channelsCopy[key] = collection.clone();
148
+ }
149
+ copy.channels = channelsCopy;
150
+ }
81
151
  return copy;
82
152
  }
153
+ update(name, channel) {
154
+ var _a;
155
+ (0, common_utils_1.assert)(channel.length === this.length, 0x5c0 /* AttributionCollection channel update should have consistent segment length */);
156
+ if (name === undefined) {
157
+ this.offsets = [...channel.offsets];
158
+ this.keys = [...channel.keys];
159
+ }
160
+ else {
161
+ (_a = this.channels) !== null && _a !== void 0 ? _a : (this.channels = {});
162
+ if (this.channels[name] !== undefined) {
163
+ this.channels[name].update(undefined, channel);
164
+ }
165
+ else {
166
+ this.channels[name] = channel;
167
+ }
168
+ }
169
+ }
83
170
  /**
84
171
  * Rehydrates attribution information from its serialized form into the provided iterable of consecutive segments.
85
172
  */
86
173
  static populateAttributionCollections(segments, summary) {
87
- const { seqs, posBreakpoints } = summary;
88
- (0, common_utils_1.assert)(seqs.length === posBreakpoints.length && seqs.length > 0, 0x445 /* Invalid attribution summary blob provided */);
89
- let curIndex = 0;
90
- let currentInfo = seqs[curIndex];
91
- let cumulativeSegPos = 0;
92
- for (const segment of segments) {
93
- const attribution = new AttributionCollection({ type: "op", seq: currentInfo }, segment.cachedLength);
94
- while (posBreakpoints[curIndex] < cumulativeSegPos + segment.cachedLength) {
95
- currentInfo = seqs[curIndex];
96
- const nextOffset = posBreakpoints[curIndex] - cumulativeSegPos;
97
- if (attribution.offsets[attribution.offsets.length - 1] !== nextOffset) {
98
- attribution.offsets.push(nextOffset);
99
- attribution.keys.push({ type: "op", seq: currentInfo });
174
+ const { channels } = summary;
175
+ (0, common_utils_1.assert)(summary.seqs.length === summary.posBreakpoints.length, 0x445 /* Invalid attribution summary blob provided */);
176
+ const extractOntoSegments = ({ seqs, posBreakpoints }, assignToSegment) => {
177
+ let curIndex = 0;
178
+ let cumulativeSegPos = 0;
179
+ for (const segment of segments) {
180
+ const attribution = new AttributionCollection(segment.cachedLength);
181
+ const pushEntry = (offset, seq) => {
182
+ attribution.offsets.push(offset);
183
+ attribution.keys.push(seq === null ? null : typeof seq === "object" ? seq : { type: "op", seq });
184
+ };
185
+ if (posBreakpoints[curIndex] > cumulativeSegPos) {
186
+ curIndex--;
187
+ }
188
+ while (posBreakpoints[curIndex] < cumulativeSegPos + segment.cachedLength) {
189
+ const nextOffset = Math.max(posBreakpoints[curIndex] - cumulativeSegPos, 0);
190
+ pushEntry(nextOffset, seqs[curIndex]);
191
+ curIndex++;
100
192
  }
101
- curIndex++;
193
+ if (attribution.offsets.length === 0) {
194
+ pushEntry(0, seqs[curIndex - 1]);
195
+ }
196
+ assignToSegment(attribution, segment);
197
+ cumulativeSegPos += segment.cachedLength;
102
198
  }
103
- if (posBreakpoints[curIndex] === cumulativeSegPos + segment.cachedLength) {
104
- currentInfo = seqs[curIndex];
199
+ };
200
+ extractOntoSegments(summary, (collection, segment) => {
201
+ segment.attribution = collection;
202
+ });
203
+ if (channels) {
204
+ for (const [name, collectionSpec] of Object.entries(channels)) {
205
+ extractOntoSegments(collectionSpec, (collection, segment) => {
206
+ var _a;
207
+ var _b;
208
+ // Cast is valid as we just assigned this field above
209
+ ((_a = (_b = segment.attribution).channels) !== null && _a !== void 0 ? _a : (_b.channels = {}))[name] =
210
+ collection;
211
+ });
105
212
  }
106
- segment.attribution = attribution;
107
- cumulativeSegPos += segment.cachedLength;
108
213
  }
109
214
  }
110
215
  /**
111
216
  * Condenses attribution information on consecutive segments into a `SerializedAttributionCollection`
217
+ *
218
+ * Note: this operates on segments rather than attribution collections directly so that it can handle cases
219
+ * where only some segments have attribution defined.
112
220
  */
113
221
  static serializeAttributionCollections(segments) {
114
- var _a, _b;
115
- const posBreakpoints = [];
116
- const seqs = [];
117
- let mostRecentAttributionKey;
118
- let cumulativePos = 0;
119
- let segmentsWithAttribution = 0;
120
- let segmentsWithoutAttribution = 0;
222
+ var _a;
223
+ const allCollectionSpecs = [];
224
+ const allChannelNames = new Set();
121
225
  for (const segment of segments) {
122
- if (segment.attribution) {
123
- segmentsWithAttribution++;
124
- for (const { offset, key } of (_b = (_a = segment.attribution) === null || _a === void 0 ? void 0 : _a.getAll()) !== null && _b !== void 0 ? _b : []) {
125
- if (!mostRecentAttributionKey ||
226
+ const collection = (_a = segment.attribution) !== null && _a !== void 0 ? _a : new AttributionCollection(segment.cachedLength, null);
227
+ const spec = collection.getAll();
228
+ allCollectionSpecs.push(spec);
229
+ if (spec.channels) {
230
+ for (const name of Object.keys(spec.channels)) {
231
+ allChannelNames.add(name);
232
+ }
233
+ }
234
+ }
235
+ const extractSequenceOffsets = (getSpecEntries) => {
236
+ const posBreakpoints = [];
237
+ const seqs = [];
238
+ let mostRecentAttributionKey;
239
+ let cumulativePos = 0;
240
+ for (const spec of allCollectionSpecs) {
241
+ for (const { offset, key } of getSpecEntries(spec)) {
242
+ (0, common_utils_1.assert)((key === null || key === void 0 ? void 0 : key.type) !== "local", 0x5c1 /* local attribution keys should never be put in summaries */);
243
+ if (mostRecentAttributionKey === undefined ||
126
244
  !areEqualAttributionKeys(key, mostRecentAttributionKey)) {
127
245
  posBreakpoints.push(offset + cumulativePos);
128
- seqs.push(key.seq);
246
+ seqs.push(!key ? null : key.type === "op" ? key.seq : key);
129
247
  }
130
248
  mostRecentAttributionKey = key;
131
249
  }
250
+ cumulativePos += spec.length;
132
251
  }
133
- else {
134
- segmentsWithoutAttribution++;
252
+ return { seqs, posBreakpoints, length: cumulativePos };
253
+ };
254
+ const blobContents = extractSequenceOffsets((spec) => spec.root);
255
+ if (allChannelNames.size > 0) {
256
+ const channels = {};
257
+ for (const name of allChannelNames) {
258
+ const { posBreakpoints, seqs } = extractSequenceOffsets((spec) => { var _a, _b; return (_b = (_a = spec.channels) === null || _a === void 0 ? void 0 : _a[name]) !== null && _b !== void 0 ? _b : [{ offset: 0, key: null }]; });
259
+ channels[name] = { posBreakpoints, seqs };
135
260
  }
136
- cumulativePos += segment.cachedLength;
261
+ blobContents.channels = channels;
137
262
  }
138
- (0, common_utils_1.assert)(segmentsWithAttribution === 0 || segmentsWithoutAttribution === 0, 0x446 /* Expected either all segments or no segments to have attribution information. */);
139
- const blobContents = {
140
- seqs,
141
- posBreakpoints,
142
- length: cumulativePos,
143
- };
144
263
  return blobContents;
145
264
  }
146
265
  }
@@ -1 +1 @@
1
- {"version":3,"file":"attributionCollection.js","sourceRoot":"","sources":["../src/attributionCollection.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+DAAuE;AAkDvE,SAAS,uBAAuB,CAAC,CAAiB,EAAE,CAAiB;IACpE,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE;QACtB,OAAO,KAAK,CAAC;KACb;IAED,QAAQ,CAAC,CAAC,IAAI,EAAE;QACf,KAAK,IAAI;YACR,OAAO,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC;QACxB;YACC,IAAA,8BAAe,EAAC,CAAC,CAAC,IAAI,EAAE,+BAA+B,CAAC,CAAC;KAC1D;AACF,CAAC;AAED,MAAa,qBAAqB;IAIjC,YAAmB,SAAyB,EAAU,OAAe;QAAf,YAAO,GAAP,OAAO,CAAQ;QACpE,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IACzB,CAAC;IAEM,WAAW,CAAC,MAAc;QAChC,IAAA,qBAAM,EAAC,MAAM,IAAI,CAAC,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC3F,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1C,CAAC;IAEO,SAAS,CAAC,MAAc;QAC/B,8GAA8G;QAC9G,8GAA8G;QAC9G,wGAAwG;QACxG,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YAC3D,CAAC,EAAE,CAAC;SACJ;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC;IAED,IAAW,MAAM;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAED;;OAEG;IACI,OAAO,CAAC,GAAW;QACzB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,eAAe,GAAG,IAAI,qBAAqB,CAAC,cAAc,EAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;QACrF,KAAK,IAAI,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YACvD,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;YACpD,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;SACxC;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC;QACnF,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC9B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;QACnB,OAAO,eAAe,CAAC;IACxB,CAAC;IAEM,MAAM,CAAC,KAA4B;QACzC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAClD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC3C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;gBAClE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;gBAClD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;aAC9B;SACD;QACD,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC;IAC9B,CAAC;IAEM,MAAM;QACZ,MAAM,OAAO,GAA8C,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC1C,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5D;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;IAEM,KAAK;QACX,MAAM,IAAI,GAAG,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAClE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,8BAA8B,CAC3C,QAA4B,EAC5B,OAAwC;QAExC,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;QACzC,IAAA,qBAAM,EACL,IAAI,CAAC,MAAM,KAAK,cAAc,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EACxD,KAAK,CAAC,+CAA+C,CACrD,CAAC;QACF,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,gBAAgB,GAAG,CAAC,CAAC;QAEzB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;YAC/B,MAAM,WAAW,GAAG,IAAI,qBAAqB,CAC5C,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,EAChC,OAAO,CAAC,YAAY,CACpB,CAAC;YACF,OAAO,cAAc,CAAC,QAAQ,CAAC,GAAG,gBAAgB,GAAG,OAAO,CAAC,YAAY,EAAE;gBAC1E,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC7B,MAAM,UAAU,GAAG,cAAc,CAAC,QAAQ,CAAC,GAAG,gBAAgB,CAAC;gBAC/D,IAAI,WAAW,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,UAAU,EAAE;oBACvE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBACrC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;iBACxD;gBACD,QAAQ,EAAE,CAAC;aACX;YAED,IAAI,cAAc,CAAC,QAAQ,CAAC,KAAK,gBAAgB,GAAG,OAAO,CAAC,YAAY,EAAE;gBACzE,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;aAC7B;YAED,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;YAClC,gBAAgB,IAAI,OAAO,CAAC,YAAY,CAAC;SACzC;IACF,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,+BAA+B,CAC5C,QAGE;;QAEF,MAAM,cAAc,GAAa,EAAE,CAAC;QACpC,MAAM,IAAI,GAAa,EAAE,CAAC;QAC1B,IAAI,wBAAoD,CAAC;QACzD,IAAI,aAAa,GAAG,CAAC,CAAC;QAEtB,IAAI,uBAAuB,GAAG,CAAC,CAAC;QAChC,IAAI,0BAA0B,GAAG,CAAC,CAAC;QACnC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;YAC/B,IAAI,OAAO,CAAC,WAAW,EAAE;gBACxB,uBAAuB,EAAE,CAAC;gBAC1B,KAAK,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,MAAA,MAAA,OAAO,CAAC,WAAW,0CAAE,MAAM,EAAE,mCAAI,EAAE,EAAE;oBAClE,IACC,CAAC,wBAAwB;wBACzB,CAAC,uBAAuB,CAAC,GAAG,EAAE,wBAAwB,CAAC,EACtD;wBACD,cAAc,CAAC,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC,CAAC;wBAC5C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;qBACnB;oBACD,wBAAwB,GAAG,GAAG,CAAC;iBAC/B;aACD;iBAAM;gBACN,0BAA0B,EAAE,CAAC;aAC7B;YAED,aAAa,IAAI,OAAO,CAAC,YAAY,CAAC;SACtC;QAED,IAAA,qBAAM,EACL,uBAAuB,KAAK,CAAC,IAAI,0BAA0B,KAAK,CAAC,EACjE,KAAK,CAAC,kFAAkF,CACxF,CAAC;QAEF,MAAM,YAAY,GAAoC;YACrD,IAAI;YACJ,cAAc;YACd,MAAM,EAAE,aAAa;SACrB,CAAC;QACF,OAAO,YAAY,CAAC;IACrB,CAAC;CACD;AAlKD,sDAkKC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert, unreachableCase } from \"@fluidframework/common-utils\";\nimport { AttributionKey } from \"@fluidframework/runtime-definitions\";\nimport { ISegment } from \"./mergeTreeNodes\";\n\nexport interface SerializedAttributionCollection {\n\t/**\n\t * Parallel array with posBreakpoints which tracks the seq of insertion.\n\t * Ex: if seqs is [45, 46] and posBreakpoints is [0, 3], the section of the string\n\t * between offsets 0 and 3 was inserted at seq 45 and the section of the string between\n\t * 3 and the length of the string was inserted at seq 46.\n\t */\n\tseqs: number[];\n\tposBreakpoints: number[];\n\t/* Total length; only necessary for validation */\n\tlength: number;\n}\n\n/**\n * @alpha\n */\nexport interface IAttributionCollection<T> {\n\t/**\n\t * Retrieves the attribution key associated with the provided offset.\n\t */\n\tgetAtOffset(offset: number): T;\n\n\t/**\n\t * Total length of all attribution keys in this collection.\n\t */\n\treadonly length: number;\n\n\t/**\n\t * Retrieve all key/offset pairs stored on this segment. Entries should be ordered by offset, such that\n\t * the `i`th result's attribution key applies to offsets in the open range between the `i`th offset and the\n\t * `i+1`th offset.\n\t * The last entry's key applies to the open interval from the last entry's offset to this collection's length.\n\t * @internal\n\t */\n\tgetAll(): Iterable<{ offset: number; key: T }>;\n\n\t/** @internal */\n\tsplitAt(pos: number): IAttributionCollection<T>;\n\n\t/** @internal */\n\tappend(other: IAttributionCollection<T>): void;\n\n\t/** @internal */\n\tclone(): IAttributionCollection<T>;\n}\n\nfunction areEqualAttributionKeys(a: AttributionKey, b: AttributionKey): boolean {\n\tif (a.type !== b.type) {\n\t\treturn false;\n\t}\n\n\tswitch (a.type) {\n\t\tcase \"op\":\n\t\t\treturn a.seq === b.seq;\n\t\tdefault:\n\t\t\tunreachableCase(a.type, \"Unhandled AttributionKey type\");\n\t}\n}\n\nexport class AttributionCollection implements IAttributionCollection<AttributionKey> {\n\tprivate offsets: number[];\n\tprivate keys: AttributionKey[];\n\n\tpublic constructor(baseEntry: AttributionKey, private _length: number) {\n\t\tthis.offsets = [0];\n\t\tthis.keys = [baseEntry];\n\t}\n\n\tpublic getAtOffset(offset: number): AttributionKey {\n\t\tassert(offset >= 0 && offset < this._length, 0x443 /* Requested offset should be valid */);\n\t\treturn this.keys[this.findIndex(offset)];\n\t}\n\n\tprivate findIndex(offset: number): number {\n\t\t// Note: maximum length here is 256 for text segments. Perf testing shows that linear scan beats binary search\n\t\t// for attribution collections with under ~64 entries, and even at maximum size (which would require a maximum\n\t\t// length segment with every offset having different attribution), getAtOffset is on the order of 100ns.\n\t\tlet i = 0;\n\t\twhile (i < this.offsets.length && offset > this.offsets[i]) {\n\t\t\ti++;\n\t\t}\n\t\treturn this.offsets[i] === offset ? i : i - 1;\n\t}\n\n\tpublic get length(): number {\n\t\treturn this._length;\n\t}\n\n\t/**\n\t * Splits this attribution collection into two with entries for [0, pos) and [pos, length).\n\t */\n\tpublic splitAt(pos: number): AttributionCollection {\n\t\tconst splitIndex = this.findIndex(pos);\n\t\tconst splitBaseEntry = this.keys[splitIndex];\n\t\tconst splitCollection = new AttributionCollection(splitBaseEntry, this.length - pos);\n\t\tfor (let i = splitIndex + 1; i < this.keys.length; i++) {\n\t\t\tsplitCollection.offsets.push(this.offsets[i] - pos);\n\t\t\tsplitCollection.keys.push(this.keys[i]);\n\t\t}\n\n\t\tconst spliceIndex = this.offsets[splitIndex] === pos ? splitIndex : splitIndex + 1;\n\t\tthis.keys.splice(spliceIndex);\n\t\tthis.offsets.splice(spliceIndex);\n\t\tthis._length = pos;\n\t\treturn splitCollection;\n\t}\n\n\tpublic append(other: AttributionCollection): void {\n\t\tconst lastEntry = this.keys[this.keys.length - 1];\n\t\tfor (let i = 0; i < other.keys.length; i++) {\n\t\t\tif (i !== 0 || !areEqualAttributionKeys(lastEntry, other.keys[i])) {\n\t\t\t\tthis.offsets.push(other.offsets[i] + this.length);\n\t\t\t\tthis.keys.push(other.keys[i]);\n\t\t\t}\n\t\t}\n\t\tthis._length += other.length;\n\t}\n\n\tpublic getAll(): { offset: number; key: AttributionKey }[] {\n\t\tconst results: { offset: number; key: AttributionKey }[] = new Array(this.keys.length);\n\t\tfor (let i = 0; i < this.keys.length; i++) {\n\t\t\tresults[i] = { offset: this.offsets[i], key: this.keys[i] };\n\t\t}\n\t\treturn results;\n\t}\n\n\tpublic clone(): AttributionCollection {\n\t\tconst copy = new AttributionCollection(this.keys[0], this.length);\n\t\tcopy.keys = this.keys.slice();\n\t\tcopy.offsets = this.offsets.slice();\n\t\treturn copy;\n\t}\n\n\t/**\n\t * Rehydrates attribution information from its serialized form into the provided iterable of consecutive segments.\n\t */\n\tpublic static populateAttributionCollections(\n\t\tsegments: Iterable<ISegment>,\n\t\tsummary: SerializedAttributionCollection,\n\t): void {\n\t\tconst { seqs, posBreakpoints } = summary;\n\t\tassert(\n\t\t\tseqs.length === posBreakpoints.length && seqs.length > 0,\n\t\t\t0x445 /* Invalid attribution summary blob provided */,\n\t\t);\n\t\tlet curIndex = 0;\n\t\tlet currentInfo = seqs[curIndex];\n\t\tlet cumulativeSegPos = 0;\n\n\t\tfor (const segment of segments) {\n\t\t\tconst attribution = new AttributionCollection(\n\t\t\t\t{ type: \"op\", seq: currentInfo },\n\t\t\t\tsegment.cachedLength,\n\t\t\t);\n\t\t\twhile (posBreakpoints[curIndex] < cumulativeSegPos + segment.cachedLength) {\n\t\t\t\tcurrentInfo = seqs[curIndex];\n\t\t\t\tconst nextOffset = posBreakpoints[curIndex] - cumulativeSegPos;\n\t\t\t\tif (attribution.offsets[attribution.offsets.length - 1] !== nextOffset) {\n\t\t\t\t\tattribution.offsets.push(nextOffset);\n\t\t\t\t\tattribution.keys.push({ type: \"op\", seq: currentInfo });\n\t\t\t\t}\n\t\t\t\tcurIndex++;\n\t\t\t}\n\n\t\t\tif (posBreakpoints[curIndex] === cumulativeSegPos + segment.cachedLength) {\n\t\t\t\tcurrentInfo = seqs[curIndex];\n\t\t\t}\n\n\t\t\tsegment.attribution = attribution;\n\t\t\tcumulativeSegPos += segment.cachedLength;\n\t\t}\n\t}\n\n\t/**\n\t * Condenses attribution information on consecutive segments into a `SerializedAttributionCollection`\n\t */\n\tpublic static serializeAttributionCollections(\n\t\tsegments: Iterable<{\n\t\t\tattribution?: IAttributionCollection<AttributionKey>;\n\t\t\tcachedLength: number;\n\t\t}>,\n\t): SerializedAttributionCollection {\n\t\tconst posBreakpoints: number[] = [];\n\t\tconst seqs: number[] = [];\n\t\tlet mostRecentAttributionKey: AttributionKey | undefined;\n\t\tlet cumulativePos = 0;\n\n\t\tlet segmentsWithAttribution = 0;\n\t\tlet segmentsWithoutAttribution = 0;\n\t\tfor (const segment of segments) {\n\t\t\tif (segment.attribution) {\n\t\t\t\tsegmentsWithAttribution++;\n\t\t\t\tfor (const { offset, key } of segment.attribution?.getAll() ?? []) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!mostRecentAttributionKey ||\n\t\t\t\t\t\t!areEqualAttributionKeys(key, mostRecentAttributionKey)\n\t\t\t\t\t) {\n\t\t\t\t\t\tposBreakpoints.push(offset + cumulativePos);\n\t\t\t\t\t\tseqs.push(key.seq);\n\t\t\t\t\t}\n\t\t\t\t\tmostRecentAttributionKey = key;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsegmentsWithoutAttribution++;\n\t\t\t}\n\n\t\t\tcumulativePos += segment.cachedLength;\n\t\t}\n\n\t\tassert(\n\t\t\tsegmentsWithAttribution === 0 || segmentsWithoutAttribution === 0,\n\t\t\t0x446 /* Expected either all segments or no segments to have attribution information. */,\n\t\t);\n\n\t\tconst blobContents: SerializedAttributionCollection = {\n\t\t\tseqs,\n\t\t\tposBreakpoints,\n\t\t\tlength: cumulativePos,\n\t\t};\n\t\treturn blobContents;\n\t}\n}\n"]}
1
+ {"version":3,"file":"attributionCollection.js","sourceRoot":"","sources":["../src/attributionCollection.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { assert, unreachableCase } from \"@fluidframework/common-utils\";\nimport {\n\tAttributionKey,\n\tOpAttributionKey,\n\tDetachedAttributionKey,\n} from \"@fluidframework/runtime-definitions\";\nimport { ISegment } from \"./mergeTreeNodes\";\n\n/**\n * @internal\n */\nexport interface SequenceOffsets {\n\t/**\n\t * Parallel array with posBreakpoints which tracks the seq of insertion.\n\t * Ex: if seqs is [45, 46] and posBreakpoints is [0, 3], the section of the string\n\t * between offsets 0 and 3 was inserted at seq 45 and the section of the string between\n\t * 3 and the length of the string was inserted at seq 46.\n\t *\n\t * @remarks - We use null here rather than undefined as round-tripping through JSON converts\n\t * undefineds to null anyway\n\t */\n\tseqs: (number | AttributionKey | null)[];\n\tposBreakpoints: number[];\n}\n\n/**\n * @internal\n */\nexport interface SerializedAttributionCollection extends SequenceOffsets {\n\tchannels?: { [name: string]: SequenceOffsets };\n\t/* Total length; only necessary for validation */\n\tlength: number;\n}\n\n/**\n * @internal\n */\nexport interface IAttributionCollectionSpec<T> {\n\troot: Iterable<{ offset: number; key: T | null }>;\n\tchannels?: { [name: string]: Iterable<{ offset: number; key: T | null }> };\n\tlength: number;\n}\n\n/**\n * @internal\n * @sealed\n */\nexport interface IAttributionCollectionSerializer {\n\t/**\n\t * @internal\n\t */\n\tserializeAttributionCollections(\n\t\tsegments: Iterable<{\n\t\t\tattribution?: IAttributionCollection<AttributionKey>;\n\t\t\tcachedLength: number;\n\t\t}>,\n\t): SerializedAttributionCollection;\n\n\t/**\n\t * Populates attribution information on segments using the provided summary.\n\t * @internal\n\t */\n\tpopulateAttributionCollections(\n\t\tsegments: Iterable<ISegment>,\n\t\tsummary: SerializedAttributionCollection,\n\t): void;\n}\n\n/**\n * @alpha\n */\nexport interface IAttributionCollection<T> {\n\t/**\n\t * Retrieves the attribution key associated with the provided offset.\n\t * @param channel - When specified, gets an attribution key associated with a particular channel.\n\t */\n\tgetAtOffset(offset: number, channel?: string): AttributionKey | undefined;\n\n\t/**\n\t * Total length of all attribution keys in this collection.\n\t */\n\treadonly length: number;\n\n\treadonly channelNames: Iterable<string>;\n\n\t/**\n\t * Retrieve all key/offset pairs stored on this segment. Entries should be ordered by offset, such that\n\t * the `i`th result's attribution key applies to offsets in the open range between the `i`th offset and the\n\t * `i+1`th offset.\n\t * The last entry's key applies to the open interval from the last entry's offset to this collection's length.\n\t * @internal\n\t */\n\tgetAll(): IAttributionCollectionSpec<T>;\n\n\t/** @internal */\n\tsplitAt(pos: number): IAttributionCollection<T>;\n\n\t/** @internal */\n\tappend(other: IAttributionCollection<T>): void;\n\n\t/** @internal */\n\tclone(): IAttributionCollection<T>;\n\n\t/**\n\t * Updates this collection with new attribution data.\n\t * @param name - Name of the channel that requires an update. Undefined signifies the root channel.\n\t * Updates apply only to the individual channel (i.e. if an attribution policy needs to update the root\n\t * channel and 4 other channels, it should call `.update` 5 times).\n\t * @param channel - Updated collection for that channel.\n\t * @internal\n\t */\n\tupdate(name: string | undefined, channel: IAttributionCollection<T>);\n}\n\n// note: treats null and undefined as equivalent\nexport function areEqualAttributionKeys(\n\ta: AttributionKey | null | undefined,\n\tb: AttributionKey | null | undefined,\n): boolean {\n\tif (!a && !b) {\n\t\treturn true;\n\t}\n\n\tif (!a || !b) {\n\t\treturn false;\n\t}\n\n\tif (a.type !== b.type) {\n\t\treturn false;\n\t}\n\n\t// Note: TS can't narrow the type of b inside this switch statement, hence the need for casting.\n\tswitch (a.type) {\n\t\tcase \"op\":\n\t\t\treturn a.seq === (b as OpAttributionKey).seq;\n\t\tcase \"detached\":\n\t\t\treturn a.id === (b as DetachedAttributionKey).id;\n\t\tcase \"local\":\n\t\t\treturn true;\n\t\tdefault:\n\t\t\tunreachableCase(a, \"Unhandled AttributionKey type\");\n\t}\n}\n\nexport class AttributionCollection implements IAttributionCollection<AttributionKey> {\n\tprivate offsets: number[] = [];\n\tprivate keys: (AttributionKey | null)[] = [];\n\n\tprivate channels?: { [name: string]: AttributionCollection };\n\n\tprivate get channelEntries(): [string, AttributionCollection][] {\n\t\treturn Object.entries(this.channels ?? {});\n\t}\n\n\tpublic constructor(private _length: number, baseEntry?: AttributionKey | null) {\n\t\tif (baseEntry !== undefined) {\n\t\t\tthis.offsets.push(0);\n\t\t\tthis.keys.push(baseEntry);\n\t\t}\n\t}\n\n\tpublic get channelNames(): string[] {\n\t\treturn Object.keys(this.channels ?? {});\n\t}\n\n\tpublic getAtOffset(offset: number): AttributionKey;\n\tpublic getAtOffset(offset: number, channel: string): AttributionKey | undefined;\n\tpublic getAtOffset(offset: number, channel?: string): AttributionKey | undefined {\n\t\tif (channel !== undefined) {\n\t\t\tconst subCollection = this.channels?.[channel];\n\t\t\treturn subCollection?.getAtOffset(offset);\n\t\t}\n\t\tassert(offset >= 0 && offset < this._length, 0x443 /* Requested offset should be valid */);\n\t\treturn this.get(this.findIndex(offset));\n\t}\n\n\tprivate findIndex(offset: number): number {\n\t\t// Note: maximum length here is 256 for text segments. Perf testing shows that linear scan beats binary search\n\t\t// for attribution collections with under ~64 entries, and even at maximum size (which would require a maximum\n\t\t// length segment with every offset having different attribution), getAtOffset is on the order of 100ns.\n\t\tlet i = 0;\n\t\twhile (i < this.offsets.length && offset > this.offsets[i]) {\n\t\t\ti++;\n\t\t}\n\t\treturn this.offsets[i] === offset ? i : i - 1;\n\t}\n\n\tprivate get(index: number): AttributionKey | undefined {\n\t\tconst key = this.keys[index];\n\t\treturn key !== null ? key : undefined;\n\t}\n\n\tpublic get length(): number {\n\t\treturn this._length;\n\t}\n\n\t/**\n\t * Splits this attribution collection into two with entries for [0, pos) and [pos, length).\n\t */\n\tpublic splitAt(pos: number): AttributionCollection {\n\t\tconst splitIndex = this.findIndex(pos);\n\t\tconst splitCollection = new AttributionCollection(this.length - pos);\n\t\tfor (let i = splitIndex; i < this.keys.length; i++) {\n\t\t\tsplitCollection.offsets.push(Math.max(this.offsets[i] - pos, 0));\n\t\t\tsplitCollection.keys.push(this.keys[i]);\n\t\t}\n\n\t\tif (this.channels) {\n\t\t\tsplitCollection.channels = {};\n\t\t\tfor (const [key, collection] of this.channelEntries) {\n\t\t\t\tsplitCollection.channels[key] = collection.splitAt(pos);\n\t\t\t}\n\t\t}\n\n\t\tconst spliceIndex = this.offsets[splitIndex] === pos ? splitIndex : splitIndex + 1;\n\t\tthis.keys.splice(spliceIndex);\n\t\tthis.offsets.splice(spliceIndex);\n\t\tthis._length = pos;\n\t\treturn splitCollection;\n\t}\n\n\tpublic append(other: AttributionCollection): void {\n\t\tconst lastEntry = this.keys[this.keys.length - 1];\n\t\tfor (let i = 0; i < other.keys.length; i++) {\n\t\t\tif (i !== 0 || !areEqualAttributionKeys(lastEntry, other.keys[i])) {\n\t\t\t\tthis.offsets.push(other.offsets[i] + this.length);\n\t\t\t\tthis.keys.push(other.keys[i]);\n\t\t\t}\n\t\t}\n\n\t\tif (other.channels !== undefined || this.channels !== undefined) {\n\t\t\tthis.channels ??= {};\n\t\t\tfor (const [key, collection] of other.channelEntries) {\n\t\t\t\tconst thisCollection = (this.channels[key] ??= new AttributionCollection(\n\t\t\t\t\tthis.length,\n\t\t\t\t\tnull,\n\t\t\t\t));\n\t\t\t\tthisCollection.append(collection);\n\t\t\t}\n\t\t\tfor (const [key, collection] of this.channelEntries) {\n\t\t\t\tif (other.channels?.[key] === undefined) {\n\t\t\t\t\tcollection.append(new AttributionCollection(other.length, null));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis._length += other.length;\n\t}\n\n\tpublic getAll(): IAttributionCollectionSpec<AttributionKey> {\n\t\tconst root: IAttributionCollectionSpec<AttributionKey>[\"root\"] = new Array(\n\t\t\tthis.keys.length,\n\t\t);\n\t\tfor (let i = 0; i < this.keys.length; i++) {\n\t\t\troot[i] = { offset: this.offsets[i], key: this.keys[i] };\n\t\t}\n\t\tconst result: IAttributionCollectionSpec<AttributionKey> = {\n\t\t\troot,\n\t\t\tlength: this.length,\n\t\t};\n\t\tif (this.channels !== undefined) {\n\t\t\tresult.channels = {};\n\t\t\tfor (const [key, collection] of this.channelEntries) {\n\t\t\t\tresult.channels[key] = collection.getAll().root;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic clone(): AttributionCollection {\n\t\tconst copy = new AttributionCollection(this.length);\n\t\tcopy.keys = this.keys.slice();\n\t\tcopy.offsets = this.offsets.slice();\n\t\tif (this.channels !== undefined) {\n\t\t\tconst channelsCopy = {};\n\t\t\tfor (const [key, collection] of this.channelEntries) {\n\t\t\t\tchannelsCopy[key] = collection.clone();\n\t\t\t}\n\t\t\tcopy.channels = channelsCopy;\n\t\t}\n\t\treturn copy;\n\t}\n\n\tpublic update(name: string | undefined, channel: AttributionCollection) {\n\t\tassert(\n\t\t\tchannel.length === this.length,\n\t\t\t0x5c0 /* AttributionCollection channel update should have consistent segment length */,\n\t\t);\n\t\tif (name === undefined) {\n\t\t\tthis.offsets = [...channel.offsets];\n\t\t\tthis.keys = [...channel.keys];\n\t\t} else {\n\t\t\tthis.channels ??= {};\n\t\t\tif (this.channels[name] !== undefined) {\n\t\t\t\tthis.channels[name].update(undefined, channel);\n\t\t\t} else {\n\t\t\t\tthis.channels[name] = channel;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Rehydrates attribution information from its serialized form into the provided iterable of consecutive segments.\n\t */\n\tpublic static populateAttributionCollections(\n\t\tsegments: ISegment[],\n\t\tsummary: SerializedAttributionCollection,\n\t): void {\n\t\tconst { channels } = summary;\n\t\tassert(\n\t\t\tsummary.seqs.length === summary.posBreakpoints.length,\n\t\t\t0x445 /* Invalid attribution summary blob provided */,\n\t\t);\n\n\t\tconst extractOntoSegments = (\n\t\t\t{ seqs, posBreakpoints }: SequenceOffsets,\n\t\t\tassignToSegment: (collection: AttributionCollection, segment: ISegment) => void,\n\t\t) => {\n\t\t\tlet curIndex = 0;\n\t\t\tlet cumulativeSegPos = 0;\n\n\t\t\tfor (const segment of segments) {\n\t\t\t\tconst attribution = new AttributionCollection(segment.cachedLength);\n\t\t\t\tconst pushEntry = (offset: number, seq: AttributionKey | number | null) => {\n\t\t\t\t\tattribution.offsets.push(offset);\n\t\t\t\t\tattribution.keys.push(\n\t\t\t\t\t\tseq === null ? null : typeof seq === \"object\" ? seq : { type: \"op\", seq },\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t\tif (posBreakpoints[curIndex] > cumulativeSegPos) {\n\t\t\t\t\tcurIndex--;\n\t\t\t\t}\n\n\t\t\t\twhile (posBreakpoints[curIndex] < cumulativeSegPos + segment.cachedLength) {\n\t\t\t\t\tconst nextOffset = Math.max(posBreakpoints[curIndex] - cumulativeSegPos, 0);\n\t\t\t\t\tpushEntry(nextOffset, seqs[curIndex]);\n\t\t\t\t\tcurIndex++;\n\t\t\t\t}\n\n\t\t\t\tif (attribution.offsets.length === 0) {\n\t\t\t\t\tpushEntry(0, seqs[curIndex - 1]);\n\t\t\t\t}\n\n\t\t\t\tassignToSegment(attribution, segment);\n\t\t\t\tcumulativeSegPos += segment.cachedLength;\n\t\t\t}\n\t\t};\n\n\t\textractOntoSegments(summary, (collection, segment) => {\n\t\t\tsegment.attribution = collection;\n\t\t});\n\t\tif (channels) {\n\t\t\tfor (const [name, collectionSpec] of Object.entries(channels)) {\n\t\t\t\textractOntoSegments(collectionSpec, (collection, segment) => {\n\t\t\t\t\t// Cast is valid as we just assigned this field above\n\t\t\t\t\t((segment.attribution as AttributionCollection).channels ??= {})[name] =\n\t\t\t\t\t\tcollection;\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Condenses attribution information on consecutive segments into a `SerializedAttributionCollection`\n\t *\n\t * Note: this operates on segments rather than attribution collections directly so that it can handle cases\n\t * where only some segments have attribution defined.\n\t */\n\tpublic static serializeAttributionCollections(\n\t\tsegments: Iterable<{\n\t\t\tattribution?: IAttributionCollection<AttributionKey>;\n\t\t\tcachedLength: number;\n\t\t}>,\n\t): SerializedAttributionCollection {\n\t\tconst allCollectionSpecs: IAttributionCollectionSpec<AttributionKey>[] = [];\n\n\t\tconst allChannelNames = new Set<string>();\n\t\tfor (const segment of segments) {\n\t\t\tconst collection =\n\t\t\t\tsegment.attribution ?? new AttributionCollection(segment.cachedLength, null);\n\t\t\tconst spec = collection.getAll();\n\t\t\tallCollectionSpecs.push(spec);\n\t\t\tif (spec.channels) {\n\t\t\t\tfor (const name of Object.keys(spec.channels)) {\n\t\t\t\t\tallChannelNames.add(name);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst extractSequenceOffsets = (\n\t\t\tgetSpecEntries: (\n\t\t\t\tspec: IAttributionCollectionSpec<AttributionKey>,\n\t\t\t) => Iterable<{ offset: number; key: AttributionKey | null }>,\n\t\t): SerializedAttributionCollection => {\n\t\t\tconst posBreakpoints: number[] = [];\n\t\t\tconst seqs: (number | AttributionKey | null)[] = [];\n\t\t\tlet mostRecentAttributionKey: AttributionKey | null | undefined;\n\t\t\tlet cumulativePos = 0;\n\n\t\t\tfor (const spec of allCollectionSpecs) {\n\t\t\t\tfor (const { offset, key } of getSpecEntries(spec)) {\n\t\t\t\t\tassert(\n\t\t\t\t\t\tkey?.type !== \"local\",\n\t\t\t\t\t\t0x5c1 /* local attribution keys should never be put in summaries */,\n\t\t\t\t\t);\n\t\t\t\t\tif (\n\t\t\t\t\t\tmostRecentAttributionKey === undefined ||\n\t\t\t\t\t\t!areEqualAttributionKeys(key, mostRecentAttributionKey)\n\t\t\t\t\t) {\n\t\t\t\t\t\tposBreakpoints.push(offset + cumulativePos);\n\t\t\t\t\t\tseqs.push(!key ? null : key.type === \"op\" ? key.seq : key);\n\t\t\t\t\t}\n\t\t\t\t\tmostRecentAttributionKey = key;\n\t\t\t\t}\n\n\t\t\t\tcumulativePos += spec.length;\n\t\t\t}\n\n\t\t\treturn { seqs, posBreakpoints, length: cumulativePos };\n\t\t};\n\n\t\tconst blobContents = extractSequenceOffsets((spec) => spec.root);\n\t\tif (allChannelNames.size > 0) {\n\t\t\tconst channels: { [name: string]: SequenceOffsets } = {};\n\t\t\tfor (const name of allChannelNames) {\n\t\t\t\tconst { posBreakpoints, seqs } = extractSequenceOffsets(\n\t\t\t\t\t(spec) => spec.channels?.[name] ?? [{ offset: 0, key: null }],\n\t\t\t\t);\n\t\t\t\tchannels[name] = { posBreakpoints, seqs };\n\t\t\t}\n\t\t\tblobContents.channels = channels;\n\t\t}\n\n\t\treturn blobContents;\n\t}\n}\n"]}
@@ -0,0 +1,36 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ import { AttributionPolicy } from "./mergeTree";
6
+ /**
7
+ * @alpha
8
+ * @returns - An {@link AttributionPolicy} which tracks only insertion of content.
9
+ */
10
+ export declare function createInsertOnlyAttributionPolicy(): AttributionPolicy;
11
+ /**
12
+ * @param propNames - List of property names for which attribution should be tracked.
13
+ * @returns - A policy which only attributes annotation of the properties specified.
14
+ * Keys for each property are stored under attribution channels of the same name--see example below.
15
+ *
16
+ * @example
17
+ *
18
+ * ```typescript
19
+ * // Use this policy when creating your merge-tree:
20
+ * const policy = createPropertyTrackingAttributionPolicyFactory("bold", "italic");
21
+ * // ... later, you can get attribution keys for the last time the "bold" and "italic"
22
+ * // properties were changed on a segment using `getAtOffset`:
23
+ * const lastBoldedAttributionKey = segment.attribution?.getAtOffset(0, "bold");
24
+ * const lastItalicizedAttributionKey = segment.attribution?.getAtOffset(0, "italic");
25
+ * ```
26
+ * @alpha
27
+ */
28
+ export declare function createPropertyTrackingAttributionPolicyFactory(...propNames: string[]): () => AttributionPolicy;
29
+ /**
30
+ * Creates an attribution policy which tracks insertion as well as annotation of certain property names.
31
+ * This combines the policies creatable using {@link createPropertyTrackingAttributionPolicyFactory} and
32
+ * {@link createInsertOnlyAttributionPolicy}: see there for more details.
33
+ * @alpha
34
+ */
35
+ export declare function createPropertyTrackingAndInsertionAttributionPolicyFactory(...propNames: string[]): () => AttributionPolicy;
36
+ //# sourceMappingURL=attributionPolicy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attributionPolicy.d.ts","sourceRoot":"","sources":["../src/attributionPolicy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAsLhD;;;GAGG;AACH,wBAAgB,iCAAiC,IAAI,iBAAiB,CAOrE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,8CAA8C,CAC7D,GAAG,SAAS,EAAE,MAAM,EAAE,GACpB,MAAM,iBAAiB,CAQzB;AAED;;;;;GAKG;AACH,wBAAgB,0DAA0D,CACzE,GAAG,SAAS,EAAE,MAAM,EAAE,GACpB,MAAM,iBAAiB,CASzB"}