@fluidframework/sequence 2.0.0-internal.3.0.2 → 2.0.0-internal.3.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.
Files changed (94) hide show
  1. package/.eslintrc.js +9 -12
  2. package/.mocharc.js +2 -2
  3. package/.vscode/launch.json +15 -14
  4. package/README.md +188 -179
  5. package/api-extractor.json +2 -2
  6. package/dist/defaultMap.d.ts.map +1 -1
  7. package/dist/defaultMap.js +5 -4
  8. package/dist/defaultMap.js.map +1 -1
  9. package/dist/defaultMapInterfaces.d.ts.map +1 -1
  10. package/dist/defaultMapInterfaces.js.map +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/intervalCollection.d.ts.map +1 -1
  15. package/dist/intervalCollection.js +50 -36
  16. package/dist/intervalCollection.js.map +1 -1
  17. package/dist/intervalTree.d.ts.map +1 -1
  18. package/dist/intervalTree.js.map +1 -1
  19. package/dist/localValues.d.ts.map +1 -1
  20. package/dist/localValues.js.map +1 -1
  21. package/dist/packageVersion.d.ts +1 -1
  22. package/dist/packageVersion.js +1 -1
  23. package/dist/packageVersion.js.map +1 -1
  24. package/dist/sequence.d.ts +1 -1
  25. package/dist/sequence.d.ts.map +1 -1
  26. package/dist/sequence.js +13 -17
  27. package/dist/sequence.js.map +1 -1
  28. package/dist/sequenceDeltaEvent.d.ts.map +1 -1
  29. package/dist/sequenceDeltaEvent.js.map +1 -1
  30. package/dist/sequenceFactory.d.ts.map +1 -1
  31. package/dist/sequenceFactory.js.map +1 -1
  32. package/dist/sharedIntervalCollection.d.ts.map +1 -1
  33. package/dist/sharedIntervalCollection.js.map +1 -1
  34. package/dist/sharedSequence.d.ts.map +1 -1
  35. package/dist/sharedSequence.js +3 -3
  36. package/dist/sharedSequence.js.map +1 -1
  37. package/dist/sharedString.d.ts.map +1 -1
  38. package/dist/sharedString.js +5 -4
  39. package/dist/sharedString.js.map +1 -1
  40. package/lib/defaultMap.d.ts.map +1 -1
  41. package/lib/defaultMap.js +6 -5
  42. package/lib/defaultMap.js.map +1 -1
  43. package/lib/defaultMapInterfaces.d.ts.map +1 -1
  44. package/lib/defaultMapInterfaces.js.map +1 -1
  45. package/lib/index.d.ts +2 -2
  46. package/lib/index.d.ts.map +1 -1
  47. package/lib/index.js +2 -2
  48. package/lib/index.js.map +1 -1
  49. package/lib/intervalCollection.d.ts.map +1 -1
  50. package/lib/intervalCollection.js +50 -36
  51. package/lib/intervalCollection.js.map +1 -1
  52. package/lib/intervalTree.d.ts.map +1 -1
  53. package/lib/intervalTree.js.map +1 -1
  54. package/lib/localValues.d.ts.map +1 -1
  55. package/lib/localValues.js +1 -1
  56. package/lib/localValues.js.map +1 -1
  57. package/lib/packageVersion.d.ts +1 -1
  58. package/lib/packageVersion.js +1 -1
  59. package/lib/packageVersion.js.map +1 -1
  60. package/lib/sequence.d.ts +1 -1
  61. package/lib/sequence.d.ts.map +1 -1
  62. package/lib/sequence.js +15 -19
  63. package/lib/sequence.js.map +1 -1
  64. package/lib/sequenceDeltaEvent.d.ts.map +1 -1
  65. package/lib/sequenceDeltaEvent.js.map +1 -1
  66. package/lib/sequenceFactory.d.ts.map +1 -1
  67. package/lib/sequenceFactory.js +1 -1
  68. package/lib/sequenceFactory.js.map +1 -1
  69. package/lib/sharedIntervalCollection.d.ts.map +1 -1
  70. package/lib/sharedIntervalCollection.js.map +1 -1
  71. package/lib/sharedSequence.d.ts.map +1 -1
  72. package/lib/sharedSequence.js +4 -4
  73. package/lib/sharedSequence.js.map +1 -1
  74. package/lib/sharedString.d.ts.map +1 -1
  75. package/lib/sharedString.js +5 -4
  76. package/lib/sharedString.js.map +1 -1
  77. package/package.json +55 -55
  78. package/prettier.config.cjs +1 -1
  79. package/src/defaultMap.ts +406 -405
  80. package/src/defaultMapInterfaces.ts +120 -115
  81. package/src/index.ts +27 -17
  82. package/src/intervalCollection.ts +2198 -1997
  83. package/src/intervalTree.ts +139 -139
  84. package/src/localValues.ts +64 -73
  85. package/src/packageVersion.ts +1 -1
  86. package/src/sequence.ts +739 -694
  87. package/src/sequenceDeltaEvent.ts +143 -137
  88. package/src/sequenceFactory.ts +48 -46
  89. package/src/sharedIntervalCollection.ts +150 -136
  90. package/src/sharedSequence.ts +165 -160
  91. package/src/sharedString.ts +385 -343
  92. package/tsconfig.esnext.json +6 -6
  93. package/tsconfig.json +8 -12
  94. package/.editorconfig +0 -7
@@ -4,19 +4,19 @@
4
4
  */
5
5
 
6
6
  import {
7
- ICombiningOp,
8
- IMergeTreeInsertMsg,
9
- IMergeTreeRemoveMsg,
10
- IMergeTreeTextHelper,
11
- IRelativePosition,
12
- ISegment,
13
- ISegmentAction,
14
- Marker,
15
- PropertySet,
16
- ReferencePosition,
17
- ReferenceType,
18
- refHasTileLabel,
19
- TextSegment,
7
+ ICombiningOp,
8
+ IMergeTreeInsertMsg,
9
+ IMergeTreeRemoveMsg,
10
+ IMergeTreeTextHelper,
11
+ IRelativePosition,
12
+ ISegment,
13
+ ISegmentAction,
14
+ Marker,
15
+ PropertySet,
16
+ ReferencePosition,
17
+ ReferenceType,
18
+ refHasTileLabel,
19
+ TextSegment,
20
20
  } from "@fluidframework/merge-tree";
21
21
  import { IFluidDataStoreRuntime, IChannelAttributes } from "@fluidframework/datastore-definitions";
22
22
  import { SharedSegmentSequence } from "./sequence";
@@ -26,26 +26,30 @@ import { SharedStringFactory } from "./sequenceFactory";
26
26
  * Fluid object interface describing access methods on a SharedString
27
27
  */
28
28
  export interface ISharedString extends SharedSegmentSequence<SharedStringSegment> {
29
- /**
30
- * Inserts the text at the position.
31
- * @param pos - The position to insert the text at
32
- * @param text - The text to insert
33
- * @param props - The properties of the text
34
- */
35
- insertText(pos: number, text: string, props?: PropertySet): void;
36
-
37
- /**
38
- * Inserts a marker at the position.
39
- * @param pos - The position to insert the marker at
40
- * @param refType - The reference type of the marker
41
- * @param props - The properties of the marker
42
- */
43
- insertMarker(pos: number, refType: ReferenceType, props?: PropertySet): IMergeTreeInsertMsg | undefined;
44
-
45
- /**
46
- * {@inheritDoc SharedSegmentSequence.posFromRelativePos}
47
- */
48
- posFromRelativePos(relativePos: IRelativePosition): number;
29
+ /**
30
+ * Inserts the text at the position.
31
+ * @param pos - The position to insert the text at
32
+ * @param text - The text to insert
33
+ * @param props - The properties of the text
34
+ */
35
+ insertText(pos: number, text: string, props?: PropertySet): void;
36
+
37
+ /**
38
+ * Inserts a marker at the position.
39
+ * @param pos - The position to insert the marker at
40
+ * @param refType - The reference type of the marker
41
+ * @param props - The properties of the marker
42
+ */
43
+ insertMarker(
44
+ pos: number,
45
+ refType: ReferenceType,
46
+ props?: PropertySet,
47
+ ): IMergeTreeInsertMsg | undefined;
48
+
49
+ /**
50
+ * {@inheritDoc SharedSegmentSequence.posFromRelativePos}
51
+ */
52
+ posFromRelativePos(relativePos: IRelativePosition): number;
49
53
  }
50
54
 
51
55
  export type SharedStringSegment = TextSegment | Marker;
@@ -60,230 +64,261 @@ export type SharedStringSegment = TextSegment | Marker;
60
64
  * image or Fluid object that should be rendered with the text.
61
65
  *
62
66
  */
63
- export class SharedString extends SharedSegmentSequence<SharedStringSegment> implements ISharedString {
64
- /**
65
- * Create a new shared string.
66
- * @param runtime - data store runtime the new shared string belongs to
67
- * @param id - optional name of the shared string
68
- * @returns newly create shared string (but not attached yet)
69
- */
70
- public static create(runtime: IFluidDataStoreRuntime, id?: string) {
71
- return runtime.createChannel(id, SharedStringFactory.Type) as SharedString;
72
- }
73
-
74
- /**
75
- * Get a factory for SharedString to register with the data store.
76
- * @returns a factory that creates and load SharedString
77
- */
78
- public static getFactory() {
79
- return new SharedStringFactory();
80
- }
81
-
82
- public get ISharedString(): ISharedString {
83
- return this;
84
- }
85
-
86
- private readonly mergeTreeTextHelper: IMergeTreeTextHelper;
87
-
88
- constructor(document: IFluidDataStoreRuntime, public id: string, attributes: IChannelAttributes) {
89
- super(document, id, attributes, SharedStringFactory.segmentFromSpec as any);
90
- this.mergeTreeTextHelper = this.client.createTextHelper();
91
- }
92
-
93
- /**
94
- * Inserts a marker at a relative position.
95
- * @param relativePos1 - The relative position to insert the marker at
96
- * @param refType - The reference type of the marker
97
- * @param props - The properties of the marker
98
- */
99
- public insertMarkerRelative(
100
- relativePos1: IRelativePosition,
101
- refType: ReferenceType,
102
- props?: PropertySet) {
103
- const segment = new Marker(refType);
104
- if (props) {
105
- segment.addProperties(props);
106
- }
107
-
108
- const pos = this.posFromRelativePos(relativePos1);
109
- const insertOp = this.client.insertSegmentLocal(pos, segment);
110
- if (insertOp) {
111
- this.submitSequenceMessage(insertOp);
112
- }
113
- }
114
-
115
- /**
116
- * {@inheritDoc ISharedString.insertMarker}
117
- */
118
- public insertMarker(
119
- pos: number,
120
- refType: ReferenceType,
121
- props?: PropertySet): IMergeTreeInsertMsg | undefined {
122
- const segment = new Marker(refType);
123
- if (props) {
124
- segment.addProperties(props);
125
- }
126
-
127
- const insertOp = this.client.insertSegmentLocal(pos, segment);
128
- if (insertOp) {
129
- this.submitSequenceMessage(insertOp);
130
- }
131
- return insertOp;
132
- }
133
-
134
- /**
135
- * Inserts the text at the position.
136
- * @param relativePos1 - The relative position to insert the text at
137
- * @param text - The text to insert
138
- * @param props - The properties of text
139
- */
140
- public insertTextRelative(relativePos1: IRelativePosition, text: string, props?: PropertySet) {
141
- const segment = new TextSegment(text);
142
- if (props) {
143
- segment.addProperties(props);
144
- }
145
-
146
- const pos = this.posFromRelativePos(relativePos1);
147
- const insertOp = this.client.insertSegmentLocal(pos, segment);
148
- if (insertOp) {
149
- this.submitSequenceMessage(insertOp);
150
- }
151
- }
152
-
153
- /**
154
- * {@inheritDoc ISharedString.insertText}
155
- */
156
- public insertText(pos: number, text: string, props?: PropertySet) {
157
- const segment = new TextSegment(text);
158
- if (props) {
159
- segment.addProperties(props);
160
- }
161
-
162
- const insertOp = this.client.insertSegmentLocal(pos, segment);
163
- if (insertOp) {
164
- this.submitSequenceMessage(insertOp);
165
- }
166
- }
167
-
168
- /**
169
- * Replaces a range with the provided text.
170
- * @param start - The inclusive start of the range to replace
171
- * @param end - The exclusive end of the range to replace
172
- * @param text - The text to replace the range with
173
- * @param props - Optional. The properties of the replacement text
174
- */
175
- public replaceText(start: number, end: number, text: string, props?: PropertySet) {
176
- this.replaceRange(start, end, TextSegment.make(text, props));
177
- }
178
-
179
- /**
180
- * Removes the text in the given range.
181
- * @param start - The inclusive start of the range to remove
182
- * @param end - The exclusive end of the range to replace
183
- * @returns the message sent.
184
- */
185
- public removeText(start: number, end: number): IMergeTreeRemoveMsg {
186
- return this.removeRange(start, end);
187
- }
188
-
189
- /**
190
- * Annotates the marker with the provided properties and calls the callback on consensus.
191
- * @param marker - The marker to annotate
192
- * @param props - The properties to annotate the marker with
193
- * @param consensusCallback - The callback called when consensus is reached
194
- */
195
- public annotateMarkerNotifyConsensus(
196
- marker: Marker,
197
- props: PropertySet,
198
- callback: (m: Marker) => void) {
199
- const annotateOp = this.client.annotateMarkerNotifyConsensus(marker, props, callback);
200
- if (annotateOp) {
201
- this.submitSequenceMessage(annotateOp);
202
- }
203
- }
204
-
205
- /**
206
- * Annotates the marker with the provided properties.
207
- * @param marker - The marker to annotate
208
- * @param props - The properties to annotate the marker with
209
- * @param combiningOp - Optional. Specifies how to combine values for the property, such as "incr" for increment.
210
- */
211
- public annotateMarker(
212
- marker: Marker,
213
- props: PropertySet,
214
- combiningOp?: ICombiningOp) {
215
- const annotateOp = this.client.annotateMarker(marker, props, combiningOp);
216
- if (annotateOp) {
217
- this.submitSequenceMessage(annotateOp);
218
- }
219
- }
220
-
221
- /**
222
- * Finds the nearest reference with ReferenceType.Tile to `startPos` in the direction dictated by `tilePrecedesPos`.
223
- * Note that Markers receive `ReferenceType.Tile` by default.
224
- * @param startPos - Position at which to start the search
225
- * @param clientId - clientId dictating the perspective to search from
226
- * @param tileLabel - Label of the tile to search for
227
- * @param preceding - Whether the desired tile comes before (true) or after (false) `startPos`
228
- */
229
- public findTile(startPos: number | undefined, tileLabel: string, preceding = true): {
230
- tile: ReferencePosition;
231
- pos: number;
232
- } | undefined {
233
- return this.client.findTile(startPos ?? 0, tileLabel, preceding);
234
- }
235
-
236
- /**
237
- * Retrieve text from the SharedString in string format.
238
- * @param start - The starting index of the text to retrieve, or 0 if omitted.
239
- * @param end - The ending index of the text to retrieve, or the end of the string if omitted
240
- * @returns The requested text content as a string.
241
- */
242
- public getText(start?: number, end?: number) {
243
- const segmentWindow = this.client.getCollabWindow();
244
- return this.mergeTreeTextHelper.getText(segmentWindow.currentSeq, segmentWindow.clientId, "", start, end);
245
- }
246
-
247
- /**
248
- * Adds spaces for markers and handles, so that position calculations account for them.
249
- */
250
- public getTextWithPlaceholders(start?: number, end?: number) {
251
- const segmentWindow = this.client.getCollabWindow();
252
- return this.mergeTreeTextHelper.getText(segmentWindow.currentSeq, segmentWindow.clientId, " ", start, end);
253
- }
254
-
255
- public getTextRangeWithMarkers(start: number, end: number) {
256
- const segmentWindow = this.client.getCollabWindow();
257
- return this.mergeTreeTextHelper.getText(segmentWindow.currentSeq, segmentWindow.clientId, "*", start, end);
258
- }
259
-
260
- /**
261
- * Looks up and returns a `Marker` using its id. Returns `undefined` if there is no marker with the provided
262
- * id in this `SharedString`.
263
- */
264
- public getMarkerFromId(id: string): ISegment | undefined {
265
- return this.client.getMarkerFromId(id);
266
- }
267
-
268
- /**
269
- * Revert an op
270
- */
271
- protected rollback(content: any, localOpMetadata: unknown): void {
272
- if (this.client.rollback !== undefined) {
273
- this.client.rollback(content, localOpMetadata);
274
- } else {
275
- super.rollback(content, localOpMetadata);
276
- }
277
- }
67
+ export class SharedString
68
+ extends SharedSegmentSequence<SharedStringSegment>
69
+ implements ISharedString
70
+ {
71
+ /**
72
+ * Create a new shared string.
73
+ * @param runtime - data store runtime the new shared string belongs to
74
+ * @param id - optional name of the shared string
75
+ * @returns newly create shared string (but not attached yet)
76
+ */
77
+ public static create(runtime: IFluidDataStoreRuntime, id?: string) {
78
+ return runtime.createChannel(id, SharedStringFactory.Type) as SharedString;
79
+ }
80
+
81
+ /**
82
+ * Get a factory for SharedString to register with the data store.
83
+ * @returns a factory that creates and load SharedString
84
+ */
85
+ public static getFactory() {
86
+ return new SharedStringFactory();
87
+ }
88
+
89
+ public get ISharedString(): ISharedString {
90
+ return this;
91
+ }
92
+
93
+ private readonly mergeTreeTextHelper: IMergeTreeTextHelper;
94
+
95
+ constructor(
96
+ document: IFluidDataStoreRuntime,
97
+ public id: string,
98
+ attributes: IChannelAttributes,
99
+ ) {
100
+ super(document, id, attributes, SharedStringFactory.segmentFromSpec as any);
101
+ this.mergeTreeTextHelper = this.client.createTextHelper();
102
+ }
103
+
104
+ /**
105
+ * Inserts a marker at a relative position.
106
+ * @param relativePos1 - The relative position to insert the marker at
107
+ * @param refType - The reference type of the marker
108
+ * @param props - The properties of the marker
109
+ */
110
+ public insertMarkerRelative(
111
+ relativePos1: IRelativePosition,
112
+ refType: ReferenceType,
113
+ props?: PropertySet,
114
+ ) {
115
+ const segment = new Marker(refType);
116
+ if (props) {
117
+ segment.addProperties(props);
118
+ }
119
+
120
+ const pos = this.posFromRelativePos(relativePos1);
121
+ const insertOp = this.client.insertSegmentLocal(pos, segment);
122
+ if (insertOp) {
123
+ this.submitSequenceMessage(insertOp);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * {@inheritDoc ISharedString.insertMarker}
129
+ */
130
+ public insertMarker(
131
+ pos: number,
132
+ refType: ReferenceType,
133
+ props?: PropertySet,
134
+ ): IMergeTreeInsertMsg | undefined {
135
+ const segment = new Marker(refType);
136
+ if (props) {
137
+ segment.addProperties(props);
138
+ }
139
+
140
+ const insertOp = this.client.insertSegmentLocal(pos, segment);
141
+ if (insertOp) {
142
+ this.submitSequenceMessage(insertOp);
143
+ }
144
+ return insertOp;
145
+ }
146
+
147
+ /**
148
+ * Inserts the text at the position.
149
+ * @param relativePos1 - The relative position to insert the text at
150
+ * @param text - The text to insert
151
+ * @param props - The properties of text
152
+ */
153
+ public insertTextRelative(relativePos1: IRelativePosition, text: string, props?: PropertySet) {
154
+ const segment = new TextSegment(text);
155
+ if (props) {
156
+ segment.addProperties(props);
157
+ }
158
+
159
+ const pos = this.posFromRelativePos(relativePos1);
160
+ const insertOp = this.client.insertSegmentLocal(pos, segment);
161
+ if (insertOp) {
162
+ this.submitSequenceMessage(insertOp);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * {@inheritDoc ISharedString.insertText}
168
+ */
169
+ public insertText(pos: number, text: string, props?: PropertySet) {
170
+ const segment = new TextSegment(text);
171
+ if (props) {
172
+ segment.addProperties(props);
173
+ }
174
+
175
+ const insertOp = this.client.insertSegmentLocal(pos, segment);
176
+ if (insertOp) {
177
+ this.submitSequenceMessage(insertOp);
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Replaces a range with the provided text.
183
+ * @param start - The inclusive start of the range to replace
184
+ * @param end - The exclusive end of the range to replace
185
+ * @param text - The text to replace the range with
186
+ * @param props - Optional. The properties of the replacement text
187
+ */
188
+ public replaceText(start: number, end: number, text: string, props?: PropertySet) {
189
+ this.replaceRange(start, end, TextSegment.make(text, props));
190
+ }
191
+
192
+ /**
193
+ * Removes the text in the given range.
194
+ * @param start - The inclusive start of the range to remove
195
+ * @param end - The exclusive end of the range to replace
196
+ * @returns the message sent.
197
+ */
198
+ public removeText(start: number, end: number): IMergeTreeRemoveMsg {
199
+ return this.removeRange(start, end);
200
+ }
201
+
202
+ /**
203
+ * Annotates the marker with the provided properties and calls the callback on consensus.
204
+ * @param marker - The marker to annotate
205
+ * @param props - The properties to annotate the marker with
206
+ * @param consensusCallback - The callback called when consensus is reached
207
+ */
208
+ public annotateMarkerNotifyConsensus(
209
+ marker: Marker,
210
+ props: PropertySet,
211
+ callback: (m: Marker) => void,
212
+ ) {
213
+ const annotateOp = this.client.annotateMarkerNotifyConsensus(marker, props, callback);
214
+ if (annotateOp) {
215
+ this.submitSequenceMessage(annotateOp);
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Annotates the marker with the provided properties.
221
+ * @param marker - The marker to annotate
222
+ * @param props - The properties to annotate the marker with
223
+ * @param combiningOp - Optional. Specifies how to combine values for the property, such as "incr" for increment.
224
+ */
225
+ public annotateMarker(marker: Marker, props: PropertySet, combiningOp?: ICombiningOp) {
226
+ const annotateOp = this.client.annotateMarker(marker, props, combiningOp);
227
+ if (annotateOp) {
228
+ this.submitSequenceMessage(annotateOp);
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Finds the nearest reference with ReferenceType.Tile to `startPos` in the direction dictated by `tilePrecedesPos`.
234
+ * Note that Markers receive `ReferenceType.Tile` by default.
235
+ * @param startPos - Position at which to start the search
236
+ * @param clientId - clientId dictating the perspective to search from
237
+ * @param tileLabel - Label of the tile to search for
238
+ * @param preceding - Whether the desired tile comes before (true) or after (false) `startPos`
239
+ */
240
+ public findTile(
241
+ startPos: number | undefined,
242
+ tileLabel: string,
243
+ preceding = true,
244
+ ):
245
+ | {
246
+ tile: ReferencePosition;
247
+ pos: number;
248
+ }
249
+ | undefined {
250
+ return this.client.findTile(startPos ?? 0, tileLabel, preceding);
251
+ }
252
+
253
+ /**
254
+ * Retrieve text from the SharedString in string format.
255
+ * @param start - The starting index of the text to retrieve, or 0 if omitted.
256
+ * @param end - The ending index of the text to retrieve, or the end of the string if omitted
257
+ * @returns The requested text content as a string.
258
+ */
259
+ public getText(start?: number, end?: number) {
260
+ const segmentWindow = this.client.getCollabWindow();
261
+ return this.mergeTreeTextHelper.getText(
262
+ segmentWindow.currentSeq,
263
+ segmentWindow.clientId,
264
+ "",
265
+ start,
266
+ end,
267
+ );
268
+ }
269
+
270
+ /**
271
+ * Adds spaces for markers and handles, so that position calculations account for them.
272
+ */
273
+ public getTextWithPlaceholders(start?: number, end?: number) {
274
+ const segmentWindow = this.client.getCollabWindow();
275
+ return this.mergeTreeTextHelper.getText(
276
+ segmentWindow.currentSeq,
277
+ segmentWindow.clientId,
278
+ " ",
279
+ start,
280
+ end,
281
+ );
282
+ }
283
+
284
+ public getTextRangeWithMarkers(start: number, end: number) {
285
+ const segmentWindow = this.client.getCollabWindow();
286
+ return this.mergeTreeTextHelper.getText(
287
+ segmentWindow.currentSeq,
288
+ segmentWindow.clientId,
289
+ "*",
290
+ start,
291
+ end,
292
+ );
293
+ }
294
+
295
+ /**
296
+ * Looks up and returns a `Marker` using its id. Returns `undefined` if there is no marker with the provided
297
+ * id in this `SharedString`.
298
+ */
299
+ public getMarkerFromId(id: string): ISegment | undefined {
300
+ return this.client.getMarkerFromId(id);
301
+ }
302
+
303
+ /**
304
+ * Revert an op
305
+ */
306
+ protected rollback(content: any, localOpMetadata: unknown): void {
307
+ if (this.client.rollback !== undefined) {
308
+ this.client.rollback(content, localOpMetadata);
309
+ } else {
310
+ super.rollback(content, localOpMetadata);
311
+ }
312
+ }
278
313
  }
279
314
 
280
315
  interface ITextAndMarkerAccumulator {
281
- parallelText: string[];
282
- parallelMarkers: Marker[];
283
- parallelMarkerLabel: string;
284
- placeholder?: string;
285
- tagsInProgress: string[];
286
- textSegment: TextSegment;
316
+ parallelText: string[];
317
+ parallelMarkers: Marker[];
318
+ parallelMarkerLabel: string;
319
+ placeholder?: string;
320
+ tagsInProgress: string[];
321
+ textSegment: TextSegment;
287
322
  }
288
323
 
289
324
  /**
@@ -301,98 +336,105 @@ interface ITextAndMarkerAccumulator {
301
336
  * // Note parallelText does not include "missing".
302
337
  * ```
303
338
  */
304
- export function getTextAndMarkers(sharedString: SharedString, label: string, start?: number, end?: number): {
305
- parallelText: string[];
306
- parallelMarkers: Marker[];
339
+ export function getTextAndMarkers(
340
+ sharedString: SharedString,
341
+ label: string,
342
+ start?: number,
343
+ end?: number,
344
+ ): {
345
+ parallelText: string[];
346
+ parallelMarkers: Marker[];
307
347
  } {
308
- const accum: ITextAndMarkerAccumulator = {
309
- parallelMarkerLabel: label,
310
- parallelMarkers: [],
311
- parallelText: [],
312
- tagsInProgress: [],
313
- textSegment: new TextSegment(""),
314
- };
315
-
316
- sharedString.walkSegments(gatherTextAndMarkers, start, end, accum);
317
- return { parallelText: accum.parallelText, parallelMarkers: accum.parallelMarkers };
348
+ const accum: ITextAndMarkerAccumulator = {
349
+ parallelMarkerLabel: label,
350
+ parallelMarkers: [],
351
+ parallelText: [],
352
+ tagsInProgress: [],
353
+ textSegment: new TextSegment(""),
354
+ };
355
+
356
+ sharedString.walkSegments(gatherTextAndMarkers, start, end, accum);
357
+ return { parallelText: accum.parallelText, parallelMarkers: accum.parallelMarkers };
318
358
  }
319
359
 
320
360
  const gatherTextAndMarkers: ISegmentAction<ITextAndMarkerAccumulator> = (
321
- segment: ISegment,
322
- pos: number,
323
- refSeq: number,
324
- clientId: number,
325
- start: number,
326
- end: number,
327
- accumText: ITextAndMarkerAccumulator,
361
+ segment: ISegment,
362
+ pos: number,
363
+ refSeq: number,
364
+ clientId: number,
365
+ start: number,
366
+ end: number,
367
+ accumText: ITextAndMarkerAccumulator,
328
368
  ) => {
329
- const { placeholder, tagsInProgress, textSegment } = accumText;
330
- if (TextSegment.is(segment)) {
331
- let beginTags = "";
332
- let endTags = "";
333
- // TODO: let clients pass in function to get tag
334
- const tags = [] as string[];
335
- const initTags = [] as string[];
336
-
337
- if (segment.properties?.["font-weight"]) {
338
- tags.push("b");
339
- }
340
- if (segment.properties?.["text-decoration"]) {
341
- tags.push("u");
342
- }
343
- const remTags = [] as string[];
344
- if (tags.length > 0) {
345
- for (const tag of tags) {
346
- if (!tagsInProgress.includes(tag)) {
347
- beginTags += `<${tag}>`;
348
- initTags.push(tag);
349
- }
350
- }
351
- for (const accumTag of tagsInProgress) {
352
- if (!tags.includes(accumTag)) {
353
- endTags += `</${accumTag}>`;
354
- remTags.push(accumTag);
355
- }
356
- }
357
- for (const initTag of initTags.reverse()) {
358
- tagsInProgress.push(initTag);
359
- }
360
- } else {
361
- for (const accumTag of tagsInProgress) {
362
- endTags += `</${accumTag}>`;
363
- remTags.push(accumTag);
364
- }
365
- }
366
- for (const remTag of remTags) {
367
- const remdex = tagsInProgress.indexOf(remTag);
368
- if (remdex >= 0) {
369
- tagsInProgress.splice(remdex, 1);
370
- }
371
- }
372
- textSegment.text += endTags;
373
- textSegment.text += beginTags;
374
- if ((start <= 0) && (end >= segment.text.length)) {
375
- textSegment.text += segment.text;
376
- } else {
377
- const seglen = segment.text.length;
378
- const _start = start < 0 ? 0 : start;
379
- const _end = end >= seglen ? undefined : end;
380
- textSegment.text += segment.text.substring(_start, _end);
381
- }
382
- } else {
383
- if (placeholder && (placeholder.length > 0)) {
384
- const placeholderText = placeholder === "*" ?
385
- `\n${segment.toString()}` : placeholder.repeat(segment.cachedLength);
386
- textSegment.text += placeholderText;
387
- } else {
388
- const marker = segment as Marker;
389
- if (refHasTileLabel(marker, accumText.parallelMarkerLabel)) {
390
- accumText.parallelMarkers.push(marker);
391
- accumText.parallelText.push(textSegment.text);
392
- textSegment.text = "";
393
- }
394
- }
395
- }
396
-
397
- return true;
369
+ const { placeholder, tagsInProgress, textSegment } = accumText;
370
+ if (TextSegment.is(segment)) {
371
+ let beginTags = "";
372
+ let endTags = "";
373
+ // TODO: let clients pass in function to get tag
374
+ const tags = [] as string[];
375
+ const initTags = [] as string[];
376
+
377
+ if (segment.properties?.["font-weight"]) {
378
+ tags.push("b");
379
+ }
380
+ if (segment.properties?.["text-decoration"]) {
381
+ tags.push("u");
382
+ }
383
+ const remTags = [] as string[];
384
+ if (tags.length > 0) {
385
+ for (const tag of tags) {
386
+ if (!tagsInProgress.includes(tag)) {
387
+ beginTags += `<${tag}>`;
388
+ initTags.push(tag);
389
+ }
390
+ }
391
+ for (const accumTag of tagsInProgress) {
392
+ if (!tags.includes(accumTag)) {
393
+ endTags += `</${accumTag}>`;
394
+ remTags.push(accumTag);
395
+ }
396
+ }
397
+ for (const initTag of initTags.reverse()) {
398
+ tagsInProgress.push(initTag);
399
+ }
400
+ } else {
401
+ for (const accumTag of tagsInProgress) {
402
+ endTags += `</${accumTag}>`;
403
+ remTags.push(accumTag);
404
+ }
405
+ }
406
+ for (const remTag of remTags) {
407
+ const remdex = tagsInProgress.indexOf(remTag);
408
+ if (remdex >= 0) {
409
+ tagsInProgress.splice(remdex, 1);
410
+ }
411
+ }
412
+ textSegment.text += endTags;
413
+ textSegment.text += beginTags;
414
+ if (start <= 0 && end >= segment.text.length) {
415
+ textSegment.text += segment.text;
416
+ } else {
417
+ const seglen = segment.text.length;
418
+ const _start = start < 0 ? 0 : start;
419
+ const _end = end >= seglen ? undefined : end;
420
+ textSegment.text += segment.text.substring(_start, _end);
421
+ }
422
+ } else {
423
+ if (placeholder && placeholder.length > 0) {
424
+ const placeholderText =
425
+ placeholder === "*"
426
+ ? `\n${segment.toString()}`
427
+ : placeholder.repeat(segment.cachedLength);
428
+ textSegment.text += placeholderText;
429
+ } else {
430
+ const marker = segment as Marker;
431
+ if (refHasTileLabel(marker, accumText.parallelMarkerLabel)) {
432
+ accumText.parallelMarkers.push(marker);
433
+ accumText.parallelText.push(textSegment.text);
434
+ textSegment.text = "";
435
+ }
436
+ }
437
+ }
438
+
439
+ return true;
398
440
  };