@fluidframework/merge-tree 0.58.0-55561 → 0.58.0-55983

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 (72) hide show
  1. package/dist/base.js.map +1 -1
  2. package/dist/client.d.ts +3 -3
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +6 -7
  5. package/dist/client.js.map +1 -1
  6. package/dist/collections.d.ts +1 -1
  7. package/dist/collections.js +2 -2
  8. package/dist/collections.js.map +1 -1
  9. package/dist/mergeTree.d.ts +0 -4
  10. package/dist/mergeTree.d.ts.map +1 -1
  11. package/dist/mergeTree.js +2 -50
  12. package/dist/mergeTree.js.map +1 -1
  13. package/dist/mergeTreeDeltaCallback.d.ts.map +1 -1
  14. package/dist/mergeTreeDeltaCallback.js.map +1 -1
  15. package/dist/partialLengths.js +14 -17
  16. package/dist/partialLengths.js.map +1 -1
  17. package/dist/segmentPropertiesManager.js +1 -5
  18. package/dist/segmentPropertiesManager.js.map +1 -1
  19. package/dist/snapshotChunks.js +3 -3
  20. package/dist/snapshotChunks.js.map +1 -1
  21. package/dist/snapshotV1.d.ts +2 -1
  22. package/dist/snapshotV1.d.ts.map +1 -1
  23. package/dist/snapshotV1.js +4 -4
  24. package/dist/snapshotV1.js.map +1 -1
  25. package/dist/sortedSegmentSet.d.ts +3 -3
  26. package/dist/sortedSegmentSet.d.ts.map +1 -1
  27. package/dist/sortedSegmentSet.js +12 -12
  28. package/dist/sortedSegmentSet.js.map +1 -1
  29. package/dist/textSegment.js +3 -3
  30. package/dist/textSegment.js.map +1 -1
  31. package/lib/base.js.map +1 -1
  32. package/lib/client.d.ts +3 -3
  33. package/lib/client.d.ts.map +1 -1
  34. package/lib/client.js +6 -7
  35. package/lib/client.js.map +1 -1
  36. package/lib/collections.d.ts +1 -1
  37. package/lib/collections.js +2 -2
  38. package/lib/collections.js.map +1 -1
  39. package/lib/mergeTree.d.ts +0 -4
  40. package/lib/mergeTree.d.ts.map +1 -1
  41. package/lib/mergeTree.js +1 -48
  42. package/lib/mergeTree.js.map +1 -1
  43. package/lib/mergeTreeDeltaCallback.d.ts.map +1 -1
  44. package/lib/mergeTreeDeltaCallback.js.map +1 -1
  45. package/lib/partialLengths.js +14 -17
  46. package/lib/partialLengths.js.map +1 -1
  47. package/lib/segmentPropertiesManager.js +1 -5
  48. package/lib/segmentPropertiesManager.js.map +1 -1
  49. package/lib/snapshotChunks.js +3 -3
  50. package/lib/snapshotChunks.js.map +1 -1
  51. package/lib/snapshotV1.d.ts +2 -1
  52. package/lib/snapshotV1.d.ts.map +1 -1
  53. package/lib/snapshotV1.js +4 -4
  54. package/lib/snapshotV1.js.map +1 -1
  55. package/lib/sortedSegmentSet.d.ts +3 -3
  56. package/lib/sortedSegmentSet.d.ts.map +1 -1
  57. package/lib/sortedSegmentSet.js +12 -12
  58. package/lib/sortedSegmentSet.js.map +1 -1
  59. package/lib/textSegment.js +3 -3
  60. package/lib/textSegment.js.map +1 -1
  61. package/package.json +10 -10
  62. package/src/base.ts +2 -2
  63. package/src/client.ts +6 -7
  64. package/src/collections.ts +2 -2
  65. package/src/mergeTree.ts +1 -51
  66. package/src/mergeTreeDeltaCallback.ts +0 -1
  67. package/src/partialLengths.ts +17 -17
  68. package/src/segmentPropertiesManager.ts +5 -5
  69. package/src/snapshotChunks.ts +3 -3
  70. package/src/snapshotV1.ts +3 -3
  71. package/src/sortedSegmentSet.ts +12 -12
  72. package/src/textSegment.ts +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotV1.js","sourceRoot":"","sources":["../src/snapshotV1.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 { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport { IFluidSerializer } from \"@fluidframework/shared-object-base\";\nimport { assert, bufferToString } from \"@fluidframework/common-utils\";\nimport { ChildLogger } from \"@fluidframework/telemetry-utils\";\nimport { IChannelStorageService } from \"@fluidframework/datastore-definitions\";\nimport { ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\nimport { SummaryTreeBuilder } from \"@fluidframework/runtime-utils\";\nimport { UnassignedSequenceNumber } from \"./constants\";\nimport {\n ISegment,\n MergeTree,\n} from \"./mergeTree\";\nimport {\n matchProperties,\n PropertySet,\n} from \"./properties\";\nimport {\n IJSONSegmentWithMergeInfo,\n JsonSegmentSpecs,\n MergeTreeHeaderMetadata,\n MergeTreeChunkV1,\n toLatestVersion,\n serializeAsMaxSupportedVersion,\n} from \"./snapshotChunks\";\nimport { SnapshotLegacy } from \"./snapshotlegacy\";\n\nexport class SnapshotV1 {\n // Split snapshot into two entries - headers (small) and body (overflow) for faster loading initial content\n // Please note that this number has no direct relationship to anything other than size of raw text (characters).\n // As we produce json for the blob (and then send over the wire compressed), this number\n // is really hard to correlate with any actual metric that matters (like bytes over the wire).\n // For test with small number of chunks it would be closer to blob size,\n // for very chunky text, blob size can easily be 4x-8x of that number.\n public static readonly chunkSize: number = 10000;\n\n private readonly header: MergeTreeHeaderMetadata;\n private readonly segments: JsonSegmentSpecs[];\n private readonly segmentLengths: number[];\n private readonly logger: ITelemetryLogger;\n private readonly chunkSize: number;\n\n constructor(\n public mergeTree: MergeTree,\n logger: ITelemetryLogger,\n public filename?: string,\n public onCompletion?: () => void,\n ) {\n this.logger = ChildLogger.create(logger, \"Snapshot\");\n this.chunkSize = mergeTree?.options?.mergeTreeSnapshotChunkSize ?? SnapshotV1.chunkSize;\n\n const { currentSeq, minSeq } = mergeTree.getCollabWindow();\n this.header = {\n minSequenceNumber: minSeq,\n sequenceNumber: currentSeq,\n orderedChunkMetadata: [],\n totalLength: 0,\n totalSegmentCount: 0,\n };\n\n this.segments = [];\n this.segmentLengths = [];\n }\n\n private getSeqLengthSegs(\n allSegments: JsonSegmentSpecs[],\n allLengths: number[],\n approxSequenceLength: number,\n startIndex = 0): MergeTreeChunkV1 {\n const segments: JsonSegmentSpecs[] = [];\n let length = 0;\n let segmentCount = 0;\n while ((length < approxSequenceLength) && ((startIndex + segmentCount) < allSegments.length)) {\n const pseg = allSegments[startIndex + segmentCount];\n segments.push(pseg);\n length += allLengths[startIndex + segmentCount];\n segmentCount++;\n }\n return {\n version: \"1\",\n segmentCount,\n length,\n segments,\n startIndex,\n headerMetadata: undefined,\n };\n }\n\n /**\n * Emits the snapshot to an ISummarizeResult. If provided the optional IFluidSerializer will be used when\n * serializing the summary data rather than JSON.stringify.\n */\n emit(\n serializer: IFluidSerializer,\n bind: IFluidHandle,\n ): ISummaryTreeWithStats {\n const chunks: MergeTreeChunkV1[] = [];\n this.header.totalSegmentCount = 0;\n this.header.totalLength = 0;\n do {\n const chunk = this.getSeqLengthSegs(\n this.segments,\n this.segmentLengths,\n this.chunkSize,\n this.header.totalSegmentCount);\n chunks.push(chunk);\n this.header.totalSegmentCount += chunk.segmentCount;\n this.header.totalLength += chunk.length;\n } while (this.header.totalSegmentCount < this.segments.length);\n\n // The do while loop should have added at least one chunk\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const headerChunk = chunks.shift()!;\n headerChunk.headerMetadata = this.header;\n headerChunk.headerMetadata.orderedChunkMetadata = [{ id: SnapshotLegacy.header }];\n const blobs: [key: string, content: string][] = [];\n chunks.forEach((chunk, index) => {\n const id = `${SnapshotLegacy.body}_${index}`;\n this.header.orderedChunkMetadata.push({ id });\n blobs.push([id, serializeAsMaxSupportedVersion(\n id,\n chunk,\n this.logger,\n this.mergeTree.options,\n serializer,\n bind)]);\n });\n\n const builder = new SummaryTreeBuilder();\n builder.addBlob(SnapshotLegacy.header, serializeAsMaxSupportedVersion(\n SnapshotLegacy.header,\n headerChunk,\n this.logger,\n this.mergeTree.options,\n serializer,\n bind));\n blobs.forEach((value) => {\n builder.addBlob(value[0], value[1]);\n });\n\n return builder.getSummaryTree();\n }\n\n extractSync() {\n const mergeTree = this.mergeTree;\n const minSeq = this.header.minSequenceNumber;\n\n // Helper to add the given `MergeTreeChunkV0SegmentSpec` to the snapshot.\n const pushSegRaw = (json: JsonSegmentSpecs, length: number) => {\n this.segments.push(json);\n this.segmentLengths.push(length);\n };\n\n // Helper to serialize the given `segment` and add it to the snapshot (if a segment is provided).\n const pushSeg = (segment?: ISegment) => {\n if (segment) { pushSegRaw(segment.toJSONObject(), segment.cachedLength); }\n };\n\n let prev: ISegment | undefined;\n const extractSegment = (segment: ISegment) => {\n // Elide segments that do not need to be included in the snapshot. A segment may be elided if\n // either condition is true:\n // a) The segment has not yet been ACKed. We do not need to snapshot unACKed segments because\n // there is a pending insert op that will deliver the segment on reconnection.\n // b) The segment was removed at or below the MSN. Pending ops can no longer reference this\n // segment, and therefore we can discard it.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n if (segment.seq === UnassignedSequenceNumber || segment.removedSeq! <= minSeq) {\n return true;\n }\n\n // Next determine if the snapshot needs to preserve information required for merging the segment\n // (seq, client, etc.) This information is only needed if the segment is above the MSN (and doesn't\n // have a pending remove.)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n if ((segment.seq! <= minSeq) // Segment is below the MSN, and...\n && (segment.removedSeq === undefined // .. Segment has not been removed, or...\n || segment.removedSeq === UnassignedSequenceNumber) // .. Removal op to be delivered on reconnect\n ) {\n // This segment is below the MSN, which means that future ops will not reference it. Attempt to\n // coalesce the new segment with the previous (if any).\n if (!prev) {\n // We do not have a previous candidate for coalescing. Make the current segment the new candidate.\n prev = segment;\n } else if (prev.canAppend(segment) && matchProperties(prev.properties, segment.properties)) {\n // We have a compatible pair. Replace `prev` with the coalesced segment. Clone to avoid\n // modifying the segment instances currently in the MergeTree.\n prev = prev.clone();\n prev.append(segment.clone());\n } else {\n // The segment pair could not be coalesced. Record the `prev` segment in the snapshot\n // and make the current segment the new candidate for coalescing.\n pushSeg(prev);\n prev = segment;\n }\n } else {\n // This segment needs to preserve it's metadata as it may be referenced by future ops. It's ineligible\n // for coalescing, so emit the 'prev' segment now (if any).\n pushSeg(prev);\n prev = undefined;\n\n const raw: IJSONSegmentWithMergeInfo = { json: segment.toJSONObject() };\n // If the segment insertion is above the MSN, record the insertion merge info.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n if (segment.seq! > minSeq) {\n raw.seq = segment.seq;\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n raw.client = mergeTree.getLongClientId!(segment.clientId);\n }\n // We have already dispensed with removed segments below the MSN and removed segments with unassigned\n // sequence numbers. Any remaining removal info should be preserved.\n if (segment.removedSeq !== undefined) {\n assert(segment.removedSeq !== UnassignedSequenceNumber && segment.removedSeq > minSeq,\n 0x065 /* \"On removal info preservation, segment has invalid removed sequence number!\" */);\n raw.removedSeq = segment.removedSeq;\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n raw.removedClient = mergeTree.getLongClientId!(segment.removedClientId!);\n }\n\n // Sanity check that we are preserving either the seq < minSeq or a removed segment's info.\n assert(raw.seq !== undefined && raw.client !== undefined\n || raw.removedSeq !== undefined && raw.removedClient !== undefined,\n 0x066 /* \"Corrupted preservation of segment metadata!\" */);\n\n // Record the segment with it's required metadata.\n pushSegRaw(raw, segment.cachedLength);\n }\n return true;\n };\n\n mergeTree.walkAllSegments(mergeTree.root, extractSegment, this);\n\n // If the last segment in the walk was coalescable, push it now.\n pushSeg(prev);\n\n return this.segments;\n }\n\n public static async loadChunk(\n storage: IChannelStorageService,\n path: string,\n logger: ITelemetryLogger,\n options: PropertySet | undefined,\n serializer?: IFluidSerializer,\n ): Promise<MergeTreeChunkV1> {\n const blob = await storage.readBlob(path);\n const chunkAsString = bufferToString(blob, \"utf8\");\n return SnapshotV1.processChunk(path, chunkAsString, logger, options, serializer);\n }\n\n public static processChunk(\n path: string,\n chunk: string,\n logger: ITelemetryLogger,\n options: PropertySet | undefined,\n serializer?: IFluidSerializer,\n ): MergeTreeChunkV1 {\n const chunkObj = serializer ? serializer.parse(chunk) : JSON.parse(chunk);\n return toLatestVersion(path, chunkObj, logger, options);\n }\n}\n"]}
1
+ {"version":3,"file":"snapshotV1.js","sourceRoot":"","sources":["../src/snapshotV1.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 { ITelemetryLogger } from \"@fluidframework/common-definitions\";\nimport { IFluidHandle } from \"@fluidframework/core-interfaces\";\nimport { IFluidSerializer } from \"@fluidframework/shared-object-base\";\nimport { assert, bufferToString } from \"@fluidframework/common-utils\";\nimport { ChildLogger } from \"@fluidframework/telemetry-utils\";\nimport { IChannelStorageService } from \"@fluidframework/datastore-definitions\";\nimport { ISummaryTreeWithStats } from \"@fluidframework/runtime-definitions\";\nimport { SummaryTreeBuilder } from \"@fluidframework/runtime-utils\";\nimport { UnassignedSequenceNumber } from \"./constants\";\nimport {\n ISegment,\n MergeTree,\n} from \"./mergeTree\";\nimport {\n matchProperties,\n PropertySet,\n} from \"./properties\";\nimport {\n IJSONSegmentWithMergeInfo,\n JsonSegmentSpecs,\n MergeTreeHeaderMetadata,\n MergeTreeChunkV1,\n toLatestVersion,\n serializeAsMaxSupportedVersion,\n} from \"./snapshotChunks\";\nimport { SnapshotLegacy } from \"./snapshotlegacy\";\n\nexport class SnapshotV1 {\n // Split snapshot into two entries - headers (small) and body (overflow) for faster loading initial content\n // Please note that this number has no direct relationship to anything other than size of raw text (characters).\n // As we produce json for the blob (and then send over the wire compressed), this number\n // is really hard to correlate with any actual metric that matters (like bytes over the wire).\n // For test with small number of chunks it would be closer to blob size,\n // for very chunky text, blob size can easily be 4x-8x of that number.\n public static readonly chunkSize: number = 10000;\n\n private readonly header: MergeTreeHeaderMetadata;\n private readonly segments: JsonSegmentSpecs[];\n private readonly segmentLengths: number[];\n private readonly logger: ITelemetryLogger;\n private readonly chunkSize: number;\n\n constructor(\n public mergeTree: MergeTree,\n logger: ITelemetryLogger,\n private readonly getLongClientId: (id: number) => string,\n public filename?: string,\n public onCompletion?: () => void,\n ) {\n this.logger = ChildLogger.create(logger, \"Snapshot\");\n this.chunkSize = mergeTree?.options?.mergeTreeSnapshotChunkSize ?? SnapshotV1.chunkSize;\n\n const { currentSeq, minSeq } = mergeTree.getCollabWindow();\n this.header = {\n minSequenceNumber: minSeq,\n sequenceNumber: currentSeq,\n orderedChunkMetadata: [],\n totalLength: 0,\n totalSegmentCount: 0,\n };\n\n this.segments = [];\n this.segmentLengths = [];\n }\n\n private getSeqLengthSegs(\n allSegments: JsonSegmentSpecs[],\n allLengths: number[],\n approxSequenceLength: number,\n startIndex = 0): MergeTreeChunkV1 {\n const segments: JsonSegmentSpecs[] = [];\n let length = 0;\n let segmentCount = 0;\n while ((length < approxSequenceLength) && ((startIndex + segmentCount) < allSegments.length)) {\n const pseg = allSegments[startIndex + segmentCount];\n segments.push(pseg);\n length += allLengths[startIndex + segmentCount];\n segmentCount++;\n }\n return {\n version: \"1\",\n segmentCount,\n length,\n segments,\n startIndex,\n headerMetadata: undefined,\n };\n }\n\n /**\n * Emits the snapshot to an ISummarizeResult. If provided the optional IFluidSerializer will be used when\n * serializing the summary data rather than JSON.stringify.\n */\n emit(\n serializer: IFluidSerializer,\n bind: IFluidHandle,\n ): ISummaryTreeWithStats {\n const chunks: MergeTreeChunkV1[] = [];\n this.header.totalSegmentCount = 0;\n this.header.totalLength = 0;\n do {\n const chunk = this.getSeqLengthSegs(\n this.segments,\n this.segmentLengths,\n this.chunkSize,\n this.header.totalSegmentCount);\n chunks.push(chunk);\n this.header.totalSegmentCount += chunk.segmentCount;\n this.header.totalLength += chunk.length;\n } while (this.header.totalSegmentCount < this.segments.length);\n\n // The do while loop should have added at least one chunk\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const headerChunk = chunks.shift()!;\n headerChunk.headerMetadata = this.header;\n headerChunk.headerMetadata.orderedChunkMetadata = [{ id: SnapshotLegacy.header }];\n const blobs: [key: string, content: string][] = [];\n chunks.forEach((chunk, index) => {\n const id = `${SnapshotLegacy.body}_${index}`;\n this.header.orderedChunkMetadata.push({ id });\n blobs.push([id, serializeAsMaxSupportedVersion(\n id,\n chunk,\n this.logger,\n this.mergeTree.options,\n serializer,\n bind)]);\n });\n\n const builder = new SummaryTreeBuilder();\n builder.addBlob(SnapshotLegacy.header, serializeAsMaxSupportedVersion(\n SnapshotLegacy.header,\n headerChunk,\n this.logger,\n this.mergeTree.options,\n serializer,\n bind));\n blobs.forEach((value) => {\n builder.addBlob(value[0], value[1]);\n });\n\n return builder.getSummaryTree();\n }\n\n extractSync() {\n const mergeTree = this.mergeTree;\n const minSeq = this.header.minSequenceNumber;\n\n // Helper to add the given `MergeTreeChunkV0SegmentSpec` to the snapshot.\n const pushSegRaw = (json: JsonSegmentSpecs, length: number) => {\n this.segments.push(json);\n this.segmentLengths.push(length);\n };\n\n // Helper to serialize the given `segment` and add it to the snapshot (if a segment is provided).\n const pushSeg = (segment?: ISegment) => {\n if (segment) { pushSegRaw(segment.toJSONObject(), segment.cachedLength); }\n };\n\n let prev: ISegment | undefined;\n const extractSegment = (segment: ISegment) => {\n // Elide segments that do not need to be included in the snapshot. A segment may be elided if\n // either condition is true:\n // a) The segment has not yet been ACKed. We do not need to snapshot unACKed segments because\n // there is a pending insert op that will deliver the segment on reconnection.\n // b) The segment was removed at or below the MSN. Pending ops can no longer reference this\n // segment, and therefore we can discard it.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n if (segment.seq === UnassignedSequenceNumber || segment.removedSeq! <= minSeq) {\n return true;\n }\n\n // Next determine if the snapshot needs to preserve information required for merging the segment\n // (seq, client, etc.) This information is only needed if the segment is above the MSN (and doesn't\n // have a pending remove.)\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n if ((segment.seq! <= minSeq) // Segment is below the MSN, and...\n && (segment.removedSeq === undefined // .. Segment has not been removed, or...\n || segment.removedSeq === UnassignedSequenceNumber) // .. Removal op to be delivered on reconnect\n ) {\n // This segment is below the MSN, which means that future ops will not reference it. Attempt to\n // coalesce the new segment with the previous (if any).\n if (!prev) {\n // We do not have a previous candidate for coalescing. Make the current segment the new candidate.\n prev = segment;\n } else if (prev.canAppend(segment) && matchProperties(prev.properties, segment.properties)) {\n // We have a compatible pair. Replace `prev` with the coalesced segment. Clone to avoid\n // modifying the segment instances currently in the MergeTree.\n prev = prev.clone();\n prev.append(segment.clone());\n } else {\n // The segment pair could not be coalesced. Record the `prev` segment in the snapshot\n // and make the current segment the new candidate for coalescing.\n pushSeg(prev);\n prev = segment;\n }\n } else {\n // This segment needs to preserve it's metadata as it may be referenced by future ops. It's ineligible\n // for coalescing, so emit the 'prev' segment now (if any).\n pushSeg(prev);\n prev = undefined;\n\n const raw: IJSONSegmentWithMergeInfo = { json: segment.toJSONObject() };\n // If the segment insertion is above the MSN, record the insertion merge info.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n if (segment.seq! > minSeq) {\n raw.seq = segment.seq;\n raw.client = this.getLongClientId(segment.clientId);\n }\n // We have already dispensed with removed segments below the MSN and removed segments with unassigned\n // sequence numbers. Any remaining removal info should be preserved.\n if (segment.removedSeq !== undefined) {\n assert(segment.removedSeq !== UnassignedSequenceNumber && segment.removedSeq > minSeq,\n 0x065 /* \"On removal info preservation, segment has invalid removed sequence number!\" */);\n raw.removedSeq = segment.removedSeq;\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n raw.removedClient = this.getLongClientId(segment.removedClientId!);\n }\n\n // Sanity check that we are preserving either the seq < minSeq or a removed segment's info.\n assert(raw.seq !== undefined && raw.client !== undefined\n || raw.removedSeq !== undefined && raw.removedClient !== undefined,\n 0x066 /* \"Corrupted preservation of segment metadata!\" */);\n\n // Record the segment with it's required metadata.\n pushSegRaw(raw, segment.cachedLength);\n }\n return true;\n };\n\n mergeTree.walkAllSegments(mergeTree.root, extractSegment, this);\n\n // If the last segment in the walk was coalescable, push it now.\n pushSeg(prev);\n\n return this.segments;\n }\n\n public static async loadChunk(\n storage: IChannelStorageService,\n path: string,\n logger: ITelemetryLogger,\n options: PropertySet | undefined,\n serializer?: IFluidSerializer,\n ): Promise<MergeTreeChunkV1> {\n const blob = await storage.readBlob(path);\n const chunkAsString = bufferToString(blob, \"utf8\");\n return SnapshotV1.processChunk(path, chunkAsString, logger, options, serializer);\n }\n\n public static processChunk(\n path: string,\n chunk: string,\n logger: ITelemetryLogger,\n options: PropertySet | undefined,\n serializer?: IFluidSerializer,\n ): MergeTreeChunkV1 {\n const chunkObj = serializer ? serializer.parse(chunk) : JSON.parse(chunk);\n return toLatestVersion(path, chunkObj, logger, options);\n }\n}\n"]}
@@ -8,15 +8,15 @@ import { ISegment } from "./mergeTree";
8
8
  *
9
9
  * This differs from a normal sorted set in that the keys are not fixed.
10
10
  * The segments are sorted via their ordinals which can change as the merge tree is modified.
11
- * Eventhough the values of the ordinals can change their ordering and uniqueness cannot, so the order of a set of
11
+ * Even though the values of the ordinals can change their ordering and uniqueness cannot, so the order of a set of
12
12
  * segments ordered by their ordinals will always have the same order even if the ordinal values on
13
- * the segments changes. This invarient allows ensure the segments stay ordered and unique, and that new segments
13
+ * the segments changes. This invariant allows ensure the segments stay ordered and unique, and that new segments
14
14
  * can be inserted into that order.
15
15
  */
16
16
  export declare class SortedSegmentSet<T extends ISegment | {
17
17
  readonly segment: ISegment;
18
18
  } = ISegment> {
19
- private readonly oridinalSortedItems;
19
+ private readonly ordinalSortedItems;
20
20
  get size(): number;
21
21
  get items(): readonly T[];
22
22
  addOrUpdate(newItem: T, update?: (existingItem: T, newItem: T) => T): void;
@@ -1 +1 @@
1
- {"version":3,"file":"sortedSegmentSet.d.ts","sourceRoot":"","sources":["../src/sortedSegmentSet.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC;;;;;;;;;GASG;AACH,qBAAa,gBAAgB,CAAC,CAAC,SAAS,QAAQ,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAAG,QAAQ;IACxF,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAW;IAE/C,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,IAAW,KAAK,IAAI,SAAS,CAAC,EAAE,CAE/B;IAEM,WAAW,CAAC,OAAO,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC;IAWnE,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO;IASxB,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO;IAK5B,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,mBAAmB;CAqB9B"}
1
+ {"version":3,"file":"sortedSegmentSet.d.ts","sourceRoot":"","sources":["../src/sortedSegmentSet.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC;;;;;;;;;GASG;AACH,qBAAa,gBAAgB,CAAC,CAAC,SAAS,QAAQ,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAA;CAAE,GAAG,QAAQ;IACxF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAW;IAE9C,IAAW,IAAI,IAAI,MAAM,CAExB;IAED,IAAW,KAAK,IAAI,SAAS,CAAC,EAAE,CAE/B;IAEM,WAAW,CAAC,OAAO,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC;IAWnE,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO;IASxB,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO;IAK5B,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,mBAAmB;CAqB9B"}
@@ -7,36 +7,36 @@
7
7
  *
8
8
  * This differs from a normal sorted set in that the keys are not fixed.
9
9
  * The segments are sorted via their ordinals which can change as the merge tree is modified.
10
- * Eventhough the values of the ordinals can change their ordering and uniqueness cannot, so the order of a set of
10
+ * Even though the values of the ordinals can change their ordering and uniqueness cannot, so the order of a set of
11
11
  * segments ordered by their ordinals will always have the same order even if the ordinal values on
12
- * the segments changes. This invarient allows ensure the segments stay ordered and unique, and that new segments
12
+ * the segments changes. This invariant allows ensure the segments stay ordered and unique, and that new segments
13
13
  * can be inserted into that order.
14
14
  */
15
15
  export class SortedSegmentSet {
16
16
  constructor() {
17
- this.oridinalSortedItems = [];
17
+ this.ordinalSortedItems = [];
18
18
  }
19
19
  get size() {
20
- return this.oridinalSortedItems.length;
20
+ return this.ordinalSortedItems.length;
21
21
  }
22
22
  get items() {
23
- return this.oridinalSortedItems;
23
+ return this.ordinalSortedItems;
24
24
  }
25
25
  addOrUpdate(newItem, update) {
26
26
  const position = this.findOrdinalPosition(this.getOrdinal(newItem));
27
27
  if (position.exists) {
28
28
  if (update) {
29
- update(this.oridinalSortedItems[position.index], newItem);
29
+ update(this.ordinalSortedItems[position.index], newItem);
30
30
  }
31
31
  }
32
32
  else {
33
- this.oridinalSortedItems.splice(position.index, 0, newItem);
33
+ this.ordinalSortedItems.splice(position.index, 0, newItem);
34
34
  }
35
35
  }
36
36
  remove(item) {
37
37
  const position = this.findOrdinalPosition(this.getOrdinal(item));
38
38
  if (position.exists) {
39
- this.oridinalSortedItems.splice(position.index, 1);
39
+ this.ordinalSortedItems.splice(position.index, 1);
40
40
  return true;
41
41
  }
42
42
  return false;
@@ -54,20 +54,20 @@ export class SortedSegmentSet {
54
54
  return maybeSegment.ordinal;
55
55
  }
56
56
  findOrdinalPosition(ordinal, start, end) {
57
- if (this.oridinalSortedItems.length === 0) {
57
+ if (this.ordinalSortedItems.length === 0) {
58
58
  return { exists: false, index: 0 };
59
59
  }
60
60
  if (start === undefined || end === undefined) {
61
- return this.findOrdinalPosition(ordinal, 0, this.oridinalSortedItems.length - 1);
61
+ return this.findOrdinalPosition(ordinal, 0, this.ordinalSortedItems.length - 1);
62
62
  }
63
63
  const index = start + Math.floor((end - start) / 2);
64
- if (this.getOrdinal(this.oridinalSortedItems[index]) > ordinal) {
64
+ if (this.getOrdinal(this.ordinalSortedItems[index]) > ordinal) {
65
65
  if (start === index) {
66
66
  return { exists: false, index };
67
67
  }
68
68
  return this.findOrdinalPosition(ordinal, start, index - 1);
69
69
  }
70
- else if (this.getOrdinal(this.oridinalSortedItems[index]) < ordinal) {
70
+ else if (this.getOrdinal(this.ordinalSortedItems[index]) < ordinal) {
71
71
  if (index === end) {
72
72
  return { exists: false, index: index + 1 };
73
73
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sortedSegmentSet.js","sourceRoot":"","sources":["../src/sortedSegmentSet.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 { ISegment } from \"./mergeTree\";\n\n/**\n * Stores a unique and sorted set of segments, or objects with segments\n *\n * This differs from a normal sorted set in that the keys are not fixed.\n * The segments are sorted via their ordinals which can change as the merge tree is modified.\n * Eventhough the values of the ordinals can change their ordering and uniqueness cannot, so the order of a set of\n * segments ordered by their ordinals will always have the same order even if the ordinal values on\n * the segments changes. This invarient allows ensure the segments stay ordered and unique, and that new segments\n * can be inserted into that order.\n */\nexport class SortedSegmentSet<T extends ISegment | { readonly segment: ISegment } = ISegment> {\n private readonly oridinalSortedItems: T[] = [];\n\n public get size(): number {\n return this.oridinalSortedItems.length;\n }\n\n public get items(): readonly T[] {\n return this.oridinalSortedItems;\n }\n\n public addOrUpdate(newItem: T, update?: (existingItem: T, newItem: T) => T) {\n const position = this.findOrdinalPosition(this.getOrdinal(newItem));\n if (position.exists) {\n if (update) {\n update(this.oridinalSortedItems[position.index], newItem);\n }\n } else {\n this.oridinalSortedItems.splice(position.index, 0, newItem);\n }\n }\n\n public remove(item: T): boolean {\n const position = this.findOrdinalPosition(this.getOrdinal(item));\n if (position.exists) {\n this.oridinalSortedItems.splice(position.index, 1);\n return true;\n }\n return false;\n }\n\n public has(item: T): boolean {\n const position = this.findOrdinalPosition(this.getOrdinal(item));\n return position.exists;\n }\n\n private getOrdinal(item: T): string {\n const maybeObject = item as { readonly segment: ISegment };\n if (maybeObject && maybeObject.segment) {\n return maybeObject.segment.ordinal;\n }\n\n const maybeSegment = item as ISegment;\n return maybeSegment.ordinal;\n }\n\n private findOrdinalPosition(ordinal: string, start?: number, end?: number): { exists: boolean, index: number } {\n if (this.oridinalSortedItems.length === 0) {\n return { exists: false, index: 0 };\n }\n if (start === undefined || end === undefined) {\n return this.findOrdinalPosition(ordinal, 0, this.oridinalSortedItems.length - 1);\n }\n const index = start + Math.floor((end - start) / 2);\n if (this.getOrdinal(this.oridinalSortedItems[index]) > ordinal) {\n if (start === index) {\n return { exists: false, index };\n }\n return this.findOrdinalPosition(ordinal, start, index - 1);\n } else if (this.getOrdinal(this.oridinalSortedItems[index]) < ordinal) {\n if (index === end) {\n return { exists: false, index: index + 1 };\n }\n return this.findOrdinalPosition(ordinal, index + 1, end);\n }\n return { exists: true, index };\n }\n}\n"]}
1
+ {"version":3,"file":"sortedSegmentSet.js","sourceRoot":"","sources":["../src/sortedSegmentSet.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 { ISegment } from \"./mergeTree\";\n\n/**\n * Stores a unique and sorted set of segments, or objects with segments\n *\n * This differs from a normal sorted set in that the keys are not fixed.\n * The segments are sorted via their ordinals which can change as the merge tree is modified.\n * Even though the values of the ordinals can change their ordering and uniqueness cannot, so the order of a set of\n * segments ordered by their ordinals will always have the same order even if the ordinal values on\n * the segments changes. This invariant allows ensure the segments stay ordered and unique, and that new segments\n * can be inserted into that order.\n */\nexport class SortedSegmentSet<T extends ISegment | { readonly segment: ISegment } = ISegment> {\n private readonly ordinalSortedItems: T[] = [];\n\n public get size(): number {\n return this.ordinalSortedItems.length;\n }\n\n public get items(): readonly T[] {\n return this.ordinalSortedItems;\n }\n\n public addOrUpdate(newItem: T, update?: (existingItem: T, newItem: T) => T) {\n const position = this.findOrdinalPosition(this.getOrdinal(newItem));\n if (position.exists) {\n if (update) {\n update(this.ordinalSortedItems[position.index], newItem);\n }\n } else {\n this.ordinalSortedItems.splice(position.index, 0, newItem);\n }\n }\n\n public remove(item: T): boolean {\n const position = this.findOrdinalPosition(this.getOrdinal(item));\n if (position.exists) {\n this.ordinalSortedItems.splice(position.index, 1);\n return true;\n }\n return false;\n }\n\n public has(item: T): boolean {\n const position = this.findOrdinalPosition(this.getOrdinal(item));\n return position.exists;\n }\n\n private getOrdinal(item: T): string {\n const maybeObject = item as { readonly segment: ISegment };\n if (maybeObject && maybeObject.segment) {\n return maybeObject.segment.ordinal;\n }\n\n const maybeSegment = item as ISegment;\n return maybeSegment.ordinal;\n }\n\n private findOrdinalPosition(ordinal: string, start?: number, end?: number): { exists: boolean, index: number } {\n if (this.ordinalSortedItems.length === 0) {\n return { exists: false, index: 0 };\n }\n if (start === undefined || end === undefined) {\n return this.findOrdinalPosition(ordinal, 0, this.ordinalSortedItems.length - 1);\n }\n const index = start + Math.floor((end - start) / 2);\n if (this.getOrdinal(this.ordinalSortedItems[index]) > ordinal) {\n if (start === index) {\n return { exists: false, index };\n }\n return this.findOrdinalPosition(ordinal, start, index - 1);\n } else if (this.getOrdinal(this.ordinalSortedItems[index]) < ordinal) {\n if (index === end) {\n return { exists: false, index: index + 1 };\n }\n return this.findOrdinalPosition(ordinal, index + 1, end);\n }\n return { exists: true, index };\n }\n}\n"]}
@@ -24,11 +24,11 @@ export class TextSegment extends BaseSegment {
24
24
  return segment.type === TextSegment.type;
25
25
  }
26
26
  static make(text, props) {
27
- const tseg = new TextSegment(text);
27
+ const seg = new TextSegment(text);
28
28
  if (props) {
29
- tseg.addProperties(props);
29
+ seg.addProperties(props);
30
30
  }
31
- return tseg;
31
+ return seg;
32
32
  }
33
33
  static fromJSONObject(spec) {
34
34
  if (typeof spec === "string") {
@@ -1 +1 @@
1
- {"version":3,"file":"textSegment.js","sourceRoot":"","sources":["../src/textSegment.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 { IIntegerRange } from \"./base\";\nimport { BaseSegment, ISegment, Marker, MergeTree } from \"./mergeTree\";\nimport { IJSONSegment } from \"./ops\";\nimport { PropertySet } from \"./properties\";\nimport { LocalReferenceCollection } from \"./localReference\";\n\n// Maximum length of text segment to be considered to be merged with other segment.\n// Maximum segment length is at least 2x of it (not taking into account initial segment creation).\n// The bigger it is, the more expensive it is to break segment into sub-segments (on edits)\n// The smaller it is, the more segments we have in snapshots (and in memory) - it's more expensive to load snapshots.\n// Small number also makes ReplayTool produce false positives (\"same\" snapshots have slightly different binary\n// representations). More measurements needs to be done, but it's very likely the right spot is somewhere between\n// 1K-2K mark. That said, we also break segments on newline and there are very few segments that are longer than 256\n// because of it. Must be an even number\nconst TextSegmentGranularity = 256;\n\nexport interface IJSONTextSegment extends IJSONSegment {\n text: string;\n}\n\nexport class TextSegment extends BaseSegment {\n public static readonly type = \"TextSegment\";\n\n public static is(segment: ISegment): segment is TextSegment {\n return segment.type === TextSegment.type;\n }\n\n public static make(text: string, props?: PropertySet) {\n const tseg = new TextSegment(text);\n if (props) {\n tseg.addProperties(props);\n }\n return tseg;\n }\n\n public static fromJSONObject(spec: any) {\n if (typeof spec === \"string\") {\n return new TextSegment(spec);\n } else if (spec && typeof spec === \"object\" && \"text\" in spec) {\n const textSpec = spec as IJSONTextSegment;\n return TextSegment.make(textSpec.text, textSpec.props as PropertySet);\n }\n return undefined;\n }\n\n public readonly type = TextSegment.type;\n\n constructor(public text: string) {\n super();\n this.cachedLength = text.length;\n }\n\n public toJSONObject() {\n // To reduce snapshot/ops size, we serialize a TextSegment as a plain 'string' if it is\n // not annotated.\n return this.properties\n ? { text: this.text, props: this.properties }\n : this.text;\n }\n\n public clone(start = 0, end?: number) {\n const text = this.text.substring(start, end);\n const b = TextSegment.make(text, this.properties);\n this.cloneInto(b);\n return b;\n }\n\n public canAppend(segment: ISegment): boolean {\n return !this.text.endsWith(\"\\n\")\n && TextSegment.is(segment)\n && (this.cachedLength <= TextSegmentGranularity ||\n segment.cachedLength <= TextSegmentGranularity);\n }\n\n public toString() {\n return this.text;\n }\n\n public append(segment: ISegment) {\n if (TextSegment.is(segment)) {\n // Note: Must call 'appendLocalRefs' before modifying this segment's length as\n // 'this.cachedLength' is used to adjust the offsets of the local refs.\n LocalReferenceCollection.append(this, segment);\n\n this.text += segment.text;\n this.cachedLength = this.text.length;\n } else {\n throw new Error(\"can only append text segment\");\n }\n }\n\n // TODO: retain removed text for undo\n // returns true if entire string removed\n public removeRange(start: number, end: number) {\n let remnantString = \"\";\n const len = this.text.length;\n if (start > 0) {\n remnantString += this.text.substring(0, start);\n }\n if (end < len) {\n remnantString += this.text.substring(end);\n }\n this.text = remnantString;\n this.cachedLength = remnantString.length;\n return (remnantString.length === 0);\n }\n\n protected createSplitSegmentAt(pos: number) {\n if (pos > 0) {\n const remainingText = this.text.substring(pos);\n this.text = this.text.substring(0, pos);\n this.cachedLength = this.text.length;\n const leafSegment = new TextSegment(remainingText);\n return leafSegment;\n }\n }\n}\n\ninterface ITextAccumulator {\n textSegment: TextSegment;\n placeholder?: string;\n parallelArrays?: boolean;\n}\n\ninterface ITextAndMarkerAccumulator extends ITextAccumulator {\n parallelArrays: true;\n parallelText: string[];\n parallelMarkers: Marker[];\n parallelMarkerLabel: string;\n tagsInProgress: string[];\n}\n\nfunction isTextAndMarkerAccumulator(accum: ITextAccumulator): accum is ITextAndMarkerAccumulator {\n return accum.parallelArrays === true;\n}\n\ntype ITextAccumulatorType = ITextAccumulator | ITextAndMarkerAccumulator;\nexport class MergeTreeTextHelper {\n constructor(private readonly mergeTree: MergeTree) { }\n\n public getTextAndMarkers(refSeq: number, clientId: number, label: string, start?: number, end?: number) {\n const range = this.getValidRange(start, end, refSeq, clientId);\n const accum: ITextAndMarkerAccumulator = {\n parallelArrays: true,\n parallelMarkerLabel: label,\n parallelMarkers: [],\n parallelText: [],\n tagsInProgress: [],\n textSegment: new TextSegment(\"\"),\n };\n\n this.mergeTree.mapRange<ITextAndMarkerAccumulator>(\n { leaf: this.gatherText },\n refSeq,\n clientId,\n accum,\n range.start,\n range.end);\n\n return { parallelText: accum.parallelText, parallelMarkers: accum.parallelMarkers };\n }\n\n public getText(refSeq: number, clientId: number, placeholder = \"\", start?: number, end?: number) {\n const range = this.getValidRange(start, end, refSeq, clientId);\n\n const accum: ITextAccumulator = { textSegment: new TextSegment(\"\"), placeholder };\n\n this.mergeTree.mapRange<ITextAccumulator>(\n { leaf: this.gatherText },\n refSeq,\n clientId,\n accum,\n range.start,\n range.end);\n return accum.textSegment.text;\n }\n\n private getValidRange(\n start: number | undefined,\n end: number | undefined,\n refSeq: number,\n clientId: number,\n ): IIntegerRange {\n const range: IIntegerRange = {\n end: end ?? this.mergeTree.getLength(refSeq, clientId),\n start: start ?? 0,\n };\n return range;\n }\n\n private readonly gatherText = (segment: ISegment, pos: number, refSeq: number, clientId: number, start: number,\n end: number, accumText: ITextAccumulatorType) => {\n let _start = start;\n if (TextSegment.is(segment)) {\n\n let beginTags = \"\";\n let endTags = \"\";\n if (isTextAndMarkerAccumulator(accumText)) {\n // TODO: let clients pass in function to get tag\n const tags = [] as string[];\n const initTags = [] as string[];\n\n if (segment.properties && (segment.properties[\"font-weight\"])) {\n tags.push(\"b\");\n }\n if (segment.properties && (segment.properties[\"text-decoration\"])) {\n tags.push(\"u\");\n }\n const remTags = [] as string[];\n if (tags.length > 0) {\n for (const tag of tags) {\n if (!accumText.tagsInProgress.includes(tag)) {\n beginTags += `<${tag}>`;\n initTags.push(tag);\n }\n }\n for (const accumTag of accumText.tagsInProgress) {\n if (!tags.includes(accumTag)) {\n endTags += `</${accumTag}>`;\n remTags.push(accumTag);\n }\n }\n for (const initTag of initTags.reverse()) {\n accumText.tagsInProgress.push(initTag);\n }\n } else {\n for (const accumTag of accumText.tagsInProgress) {\n endTags += `</${accumTag}>`;\n remTags.push(accumTag);\n }\n }\n for (const remTag of remTags) {\n const remdex = accumText.tagsInProgress.indexOf(remTag);\n if (remdex >= 0) {\n accumText.tagsInProgress.splice(remdex, 1);\n }\n }\n }\n accumText.textSegment.text += endTags;\n accumText.textSegment.text += beginTags;\n if ((_start <= 0) && (end >= segment.text.length)) {\n accumText.textSegment.text += segment.text;\n } else {\n if (_start < 0) {\n _start = 0;\n }\n if (end >= segment.text.length) {\n accumText.textSegment.text += segment.text.substring(_start);\n } else {\n accumText.textSegment.text += segment.text.substring(_start, end);\n }\n }\n } else {\n if (accumText.placeholder && (accumText.placeholder.length > 0)) {\n if (accumText.placeholder === \"*\") {\n const marker = segment as Marker;\n accumText.textSegment.text += `\\n${marker.toString()}`;\n } else {\n for (let i = 0; i < segment.cachedLength; i++) {\n accumText.textSegment.text += accumText.placeholder;\n }\n }\n } else if (isTextAndMarkerAccumulator(accumText)) {\n const marker = segment as Marker;\n if (marker.hasTileLabel(accumText.parallelMarkerLabel)) {\n accumText.parallelMarkers.push(marker);\n accumText.parallelText.push(accumText.textSegment.text);\n accumText.textSegment.text = \"\";\n }\n }\n }\n\n return true;\n };\n}\n"]}
1
+ {"version":3,"file":"textSegment.js","sourceRoot":"","sources":["../src/textSegment.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 { IIntegerRange } from \"./base\";\nimport { BaseSegment, ISegment, Marker, MergeTree } from \"./mergeTree\";\nimport { IJSONSegment } from \"./ops\";\nimport { PropertySet } from \"./properties\";\nimport { LocalReferenceCollection } from \"./localReference\";\n\n// Maximum length of text segment to be considered to be merged with other segment.\n// Maximum segment length is at least 2x of it (not taking into account initial segment creation).\n// The bigger it is, the more expensive it is to break segment into sub-segments (on edits)\n// The smaller it is, the more segments we have in snapshots (and in memory) - it's more expensive to load snapshots.\n// Small number also makes ReplayTool produce false positives (\"same\" snapshots have slightly different binary\n// representations). More measurements needs to be done, but it's very likely the right spot is somewhere between\n// 1K-2K mark. That said, we also break segments on newline and there are very few segments that are longer than 256\n// because of it. Must be an even number\nconst TextSegmentGranularity = 256;\n\nexport interface IJSONTextSegment extends IJSONSegment {\n text: string;\n}\n\nexport class TextSegment extends BaseSegment {\n public static readonly type = \"TextSegment\";\n\n public static is(segment: ISegment): segment is TextSegment {\n return segment.type === TextSegment.type;\n }\n\n public static make(text: string, props?: PropertySet) {\n const seg = new TextSegment(text);\n if (props) {\n seg.addProperties(props);\n }\n return seg;\n }\n\n public static fromJSONObject(spec: any) {\n if (typeof spec === \"string\") {\n return new TextSegment(spec);\n } else if (spec && typeof spec === \"object\" && \"text\" in spec) {\n const textSpec = spec as IJSONTextSegment;\n return TextSegment.make(textSpec.text, textSpec.props as PropertySet);\n }\n return undefined;\n }\n\n public readonly type = TextSegment.type;\n\n constructor(public text: string) {\n super();\n this.cachedLength = text.length;\n }\n\n public toJSONObject() {\n // To reduce snapshot/ops size, we serialize a TextSegment as a plain 'string' if it is\n // not annotated.\n return this.properties\n ? { text: this.text, props: this.properties }\n : this.text;\n }\n\n public clone(start = 0, end?: number) {\n const text = this.text.substring(start, end);\n const b = TextSegment.make(text, this.properties);\n this.cloneInto(b);\n return b;\n }\n\n public canAppend(segment: ISegment): boolean {\n return !this.text.endsWith(\"\\n\")\n && TextSegment.is(segment)\n && (this.cachedLength <= TextSegmentGranularity ||\n segment.cachedLength <= TextSegmentGranularity);\n }\n\n public toString() {\n return this.text;\n }\n\n public append(segment: ISegment) {\n if (TextSegment.is(segment)) {\n // Note: Must call 'appendLocalRefs' before modifying this segment's length as\n // 'this.cachedLength' is used to adjust the offsets of the local refs.\n LocalReferenceCollection.append(this, segment);\n\n this.text += segment.text;\n this.cachedLength = this.text.length;\n } else {\n throw new Error(\"can only append text segment\");\n }\n }\n\n // TODO: retain removed text for undo\n // returns true if entire string removed\n public removeRange(start: number, end: number) {\n let remnantString = \"\";\n const len = this.text.length;\n if (start > 0) {\n remnantString += this.text.substring(0, start);\n }\n if (end < len) {\n remnantString += this.text.substring(end);\n }\n this.text = remnantString;\n this.cachedLength = remnantString.length;\n return (remnantString.length === 0);\n }\n\n protected createSplitSegmentAt(pos: number) {\n if (pos > 0) {\n const remainingText = this.text.substring(pos);\n this.text = this.text.substring(0, pos);\n this.cachedLength = this.text.length;\n const leafSegment = new TextSegment(remainingText);\n return leafSegment;\n }\n }\n}\n\ninterface ITextAccumulator {\n textSegment: TextSegment;\n placeholder?: string;\n parallelArrays?: boolean;\n}\n\ninterface ITextAndMarkerAccumulator extends ITextAccumulator {\n parallelArrays: true;\n parallelText: string[];\n parallelMarkers: Marker[];\n parallelMarkerLabel: string;\n tagsInProgress: string[];\n}\n\nfunction isTextAndMarkerAccumulator(accum: ITextAccumulator): accum is ITextAndMarkerAccumulator {\n return accum.parallelArrays === true;\n}\n\ntype ITextAccumulatorType = ITextAccumulator | ITextAndMarkerAccumulator;\nexport class MergeTreeTextHelper {\n constructor(private readonly mergeTree: MergeTree) { }\n\n public getTextAndMarkers(refSeq: number, clientId: number, label: string, start?: number, end?: number) {\n const range = this.getValidRange(start, end, refSeq, clientId);\n const accum: ITextAndMarkerAccumulator = {\n parallelArrays: true,\n parallelMarkerLabel: label,\n parallelMarkers: [],\n parallelText: [],\n tagsInProgress: [],\n textSegment: new TextSegment(\"\"),\n };\n\n this.mergeTree.mapRange<ITextAndMarkerAccumulator>(\n { leaf: this.gatherText },\n refSeq,\n clientId,\n accum,\n range.start,\n range.end);\n\n return { parallelText: accum.parallelText, parallelMarkers: accum.parallelMarkers };\n }\n\n public getText(refSeq: number, clientId: number, placeholder = \"\", start?: number, end?: number) {\n const range = this.getValidRange(start, end, refSeq, clientId);\n\n const accum: ITextAccumulator = { textSegment: new TextSegment(\"\"), placeholder };\n\n this.mergeTree.mapRange<ITextAccumulator>(\n { leaf: this.gatherText },\n refSeq,\n clientId,\n accum,\n range.start,\n range.end);\n return accum.textSegment.text;\n }\n\n private getValidRange(\n start: number | undefined,\n end: number | undefined,\n refSeq: number,\n clientId: number,\n ): IIntegerRange {\n const range: IIntegerRange = {\n end: end ?? this.mergeTree.getLength(refSeq, clientId),\n start: start ?? 0,\n };\n return range;\n }\n\n private readonly gatherText = (segment: ISegment, pos: number, refSeq: number, clientId: number, start: number,\n end: number, accumText: ITextAccumulatorType) => {\n let _start = start;\n if (TextSegment.is(segment)) {\n\n let beginTags = \"\";\n let endTags = \"\";\n if (isTextAndMarkerAccumulator(accumText)) {\n // TODO: let clients pass in function to get tag\n const tags = [] as string[];\n const initTags = [] as string[];\n\n if (segment.properties && (segment.properties[\"font-weight\"])) {\n tags.push(\"b\");\n }\n if (segment.properties && (segment.properties[\"text-decoration\"])) {\n tags.push(\"u\");\n }\n const remTags = [] as string[];\n if (tags.length > 0) {\n for (const tag of tags) {\n if (!accumText.tagsInProgress.includes(tag)) {\n beginTags += `<${tag}>`;\n initTags.push(tag);\n }\n }\n for (const accumTag of accumText.tagsInProgress) {\n if (!tags.includes(accumTag)) {\n endTags += `</${accumTag}>`;\n remTags.push(accumTag);\n }\n }\n for (const initTag of initTags.reverse()) {\n accumText.tagsInProgress.push(initTag);\n }\n } else {\n for (const accumTag of accumText.tagsInProgress) {\n endTags += `</${accumTag}>`;\n remTags.push(accumTag);\n }\n }\n for (const remTag of remTags) {\n const remdex = accumText.tagsInProgress.indexOf(remTag);\n if (remdex >= 0) {\n accumText.tagsInProgress.splice(remdex, 1);\n }\n }\n }\n accumText.textSegment.text += endTags;\n accumText.textSegment.text += beginTags;\n if ((_start <= 0) && (end >= segment.text.length)) {\n accumText.textSegment.text += segment.text;\n } else {\n if (_start < 0) {\n _start = 0;\n }\n if (end >= segment.text.length) {\n accumText.textSegment.text += segment.text.substring(_start);\n } else {\n accumText.textSegment.text += segment.text.substring(_start, end);\n }\n }\n } else {\n if (accumText.placeholder && (accumText.placeholder.length > 0)) {\n if (accumText.placeholder === \"*\") {\n const marker = segment as Marker;\n accumText.textSegment.text += `\\n${marker.toString()}`;\n } else {\n for (let i = 0; i < segment.cachedLength; i++) {\n accumText.textSegment.text += accumText.placeholder;\n }\n }\n } else if (isTextAndMarkerAccumulator(accumText)) {\n const marker = segment as Marker;\n if (marker.hasTileLabel(accumText.parallelMarkerLabel)) {\n accumText.parallelMarkers.push(marker);\n accumText.parallelText.push(accumText.textSegment.text);\n accumText.textSegment.text = \"\";\n }\n }\n }\n\n return true;\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/merge-tree",
3
- "version": "0.58.0-55561",
3
+ "version": "0.58.0-55983",
4
4
  "description": "Merge tree",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": "https://github.com/microsoft/FluidFramework",
@@ -56,20 +56,20 @@
56
56
  "dependencies": {
57
57
  "@fluidframework/common-definitions": "^0.20.1",
58
58
  "@fluidframework/common-utils": "^0.32.1",
59
- "@fluidframework/container-definitions": "^0.46.0-0",
59
+ "@fluidframework/container-definitions": "^0.47.0-0",
60
60
  "@fluidframework/core-interfaces": "^0.42.0",
61
- "@fluidframework/datastore-definitions": "0.58.0-55561",
62
- "@fluidframework/protocol-definitions": "^0.1026.0",
63
- "@fluidframework/runtime-definitions": "0.58.0-55561",
64
- "@fluidframework/runtime-utils": "0.58.0-55561",
65
- "@fluidframework/shared-object-base": "0.58.0-55561",
66
- "@fluidframework/telemetry-utils": "0.58.0-55561"
61
+ "@fluidframework/datastore-definitions": "0.58.0-55983",
62
+ "@fluidframework/protocol-definitions": "^0.1027.0-0",
63
+ "@fluidframework/runtime-definitions": "0.58.0-55983",
64
+ "@fluidframework/runtime-utils": "0.58.0-55983",
65
+ "@fluidframework/shared-object-base": "0.58.0-55983",
66
+ "@fluidframework/telemetry-utils": "0.58.0-55983"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@fluidframework/build-common": "^0.23.0",
70
70
  "@fluidframework/eslint-config-fluid": "^0.26.0-0",
71
- "@fluidframework/mocha-test-setup": "0.58.0-55561",
72
- "@fluidframework/test-runtime-utils": "0.58.0-55561",
71
+ "@fluidframework/mocha-test-setup": "0.58.0-55983",
72
+ "@fluidframework/test-runtime-utils": "0.58.0-55983",
73
73
  "@microsoft/api-extractor": "^7.16.1",
74
74
  "@rushstack/eslint-config": "^2.5.1",
75
75
  "@types/diff": "^3.5.1",
package/src/base.ts CHANGED
@@ -14,7 +14,7 @@ export interface QProperty<TKey, TData> {
14
14
  }
15
15
 
16
16
  export interface PropertyAction<TKey, TData> {
17
- // eslint-disable-next-line @typescript-eslint/prefer-function-type
17
+
18
18
  <TAccum>(p: Property<TKey, TData>, accum?: TAccum): boolean;
19
19
  }
20
20
 
@@ -35,7 +35,7 @@ export interface SortedDictionary<TKey, TData> extends Dictionary<TKey, TData> {
35
35
  }
36
36
 
37
37
  export interface KeyComparer<TKey> {
38
- // eslint-disable-next-line @typescript-eslint/prefer-function-type
38
+
39
39
  (a: TKey, b: TKey): number;
40
40
  }
41
41
  /**
package/src/client.ts CHANGED
@@ -101,7 +101,6 @@ export class Client {
101
101
  options?: PropertySet,
102
102
  ) {
103
103
  this.mergeTree = new MergeTree(options);
104
- this.mergeTree.getLongClientId = (id) => this.getLongClientId(id);
105
104
  }
106
105
 
107
106
  /**
@@ -126,7 +125,7 @@ export class Client {
126
125
  }
127
126
 
128
127
  /**
129
- * Annotate a maker and call the callback on concensus.
128
+ * Annotate a marker and call the callback on consensus.
130
129
  * @param marker - The marker to annotate
131
130
  * @param props - The properties to annotate the marker with
132
131
  * @param consensusCallback - The callback called when consensus is reached
@@ -285,7 +284,7 @@ export class Client {
285
284
  }
286
285
 
287
286
  /**
288
- * Serializes the data required for garbage collection. The IFluidHandles stored in all segements that haven't
287
+ * Serializes the data required for garbage collection. The IFluidHandles stored in all segments that haven't
289
288
  * been removed represent routes to other objects. We serialize the data in these segments using the passed in
290
289
  * serializer which keeps track of all serialized handles.
291
290
  */
@@ -647,7 +646,7 @@ export class Client {
647
646
  * @param segment - The segment to find the position for
648
647
  * @param localSeq - The localSeq to find the position of the segment at
649
648
  */
650
- public findReconnectionPostition(segment: ISegment, localSeq: number) {
649
+ protected findReconnectionPosition(segment: ISegment, localSeq: number) {
651
650
  assert(localSeq <= this.mergeTree.collabWindow.localSeq, 0x032 /* "localSeq greater than collab window" */);
652
651
  let segmentPosition = 0;
653
652
  /*
@@ -694,12 +693,12 @@ export class Client {
694
693
  // The reason they need them sorted, as they have the same local sequence number and which means
695
694
  // farther segments will take into account nearer segments when calculating their position.
696
695
  // By sorting we ensure the nearer segment will be applied and sequenced before the father segments
697
- // so their recalulated positions will be correct.
696
+ // so their recalculated positions will be correct.
698
697
  for (const segment of segmentGroup.segments.sort((a, b) => a.ordinal < b.ordinal ? -1 : 1)) {
699
698
  const segmentSegGroup = segment.segmentGroups.dequeue();
700
699
  assert(segmentGroup === segmentSegGroup,
701
700
  0x035 /* "Segment group not at head of segment pending queue" */);
702
- const segmentPosition = this.findReconnectionPostition(segment, segmentGroup.localSeq);
701
+ const segmentPosition = this.findReconnectionPosition(segment, segmentGroup.localSeq);
703
702
  let newOp: IMergeTreeDeltaOp | undefined;
704
703
  switch (resetOp.type) {
705
704
  case MergeTreeDeltaType.ANNOTATE:
@@ -889,7 +888,7 @@ export class Client {
889
888
  assert(
890
889
  catchUpMsgs === undefined || catchUpMsgs.length === 0,
891
890
  0x03f /* "New format should not emit catchup ops" */);
892
- const snap = new SnapshotV1(this.mergeTree, this.logger);
891
+ const snap = new SnapshotV1(this.mergeTree, this.logger, (id)=>this.getLongClientId(id));
893
892
  snap.extractSync();
894
893
  return snap.emit(serializer, handle);
895
894
  } else {
@@ -180,7 +180,7 @@ export class Heap<T> {
180
180
  const x = this.L[1];
181
181
  this.L[1] = this.L[this.count()];
182
182
  this.L.pop();
183
- this.fixdown(1);
183
+ this.fixDown(1);
184
184
  return x;
185
185
  }
186
186
 
@@ -199,7 +199,7 @@ export class Heap<T> {
199
199
  }
200
200
  }
201
201
 
202
- private fixdown(k: number) {
202
+ private fixDown(k: number) {
203
203
  let _k = k;
204
204
  while ((_k << 1) <= (this.count())) {
205
205
  let j = _k << 1;
package/src/mergeTree.ts CHANGED
@@ -912,14 +912,6 @@ const LRUSegmentComparer: Comparer<LRUSegment> = {
912
912
  compare: (a, b) => a.maxSeq - b.maxSeq,
913
913
  };
914
914
 
915
- export function glc(mergeTree: MergeTree, id: number) {
916
- if (mergeTree.getLongClientId) {
917
- return mergeTree.getLongClientId(id);
918
- } else {
919
- return id.toString();
920
- }
921
- }
922
-
923
915
  export interface SegmentAccumulator {
924
916
  segments: ISegment[];
925
917
  }
@@ -1059,8 +1051,6 @@ export class MergeTree {
1059
1051
  // if we need to have pointers to non-markers, we can change to point at local refs
1060
1052
  private readonly idToSegment = new Map<string, ISegment>();
1061
1053
  private minSeqListeners: Heap<MinListener> | undefined;
1062
- // For diagnostics
1063
- public getLongClientId?: (id: number) => string;
1064
1054
  public mergeTreeDeltaCallback?: MergeTreeDeltaCallback;
1065
1055
  public mergeTreeMaintenanceCallback?: MergeTreeMaintenanceCallback;
1066
1056
 
@@ -2113,7 +2103,7 @@ export class MergeTree {
2113
2103
  if (pos === 0) {
2114
2104
  // normalize the seq numbers
2115
2105
  // if the new seg is local (UnassignedSequenceNumber) give it the highest possible
2116
- // seq for comparision, as it will get a seq higher than any other seq once sequences
2106
+ // seq for comparison, as it will get a seq higher than any other seq once sequences
2117
2107
  // if the current seg is local (UnassignedSequenceNumber) give it the second highest
2118
2108
  // possible seq, as the highest is reserved for the previous.
2119
2109
  const newSeq = seq === UnassignedSequenceNumber ? Number.MAX_SAFE_INTEGER : seq;
@@ -2607,46 +2597,6 @@ export class MergeTree {
2607
2597
  this.nodeMap(this.root, actions, 0, refSeq, clientId, accum, start, end);
2608
2598
  }
2609
2599
 
2610
- public nodeToString(block: IMergeBlock, strbuf: string, indentCount = 0) {
2611
- let _strbuf = strbuf;
2612
- _strbuf += internedSpaces(indentCount);
2613
- // eslint-disable-next-line max-len
2614
- _strbuf += `Node (len ${block.cachedLength}) p len (${block.parent ? block.parent.cachedLength : 0}) ord ${ordinalToArray(block.ordinal)} with ${block.childCount} segs:\n`;
2615
- if (MergeTree.blockUpdateMarkers) {
2616
- _strbuf += internedSpaces(indentCount);
2617
- _strbuf += (<IHierBlock>block).hierToString(indentCount);
2618
- }
2619
- if (this.collabWindow.collaborating) {
2620
- _strbuf += internedSpaces(indentCount);
2621
- _strbuf += `${block.partialLengths!.toString((id) => glc(this, id), indentCount)}\n`;
2622
- }
2623
- const children = block.children;
2624
- for (let childIndex = 0; childIndex < block.childCount; childIndex++) {
2625
- const child = children[childIndex];
2626
- if (!child.isLeaf()) {
2627
- _strbuf = this.nodeToString(child, _strbuf, indentCount + 4);
2628
- } else {
2629
- const segment = child;
2630
- _strbuf += internedSpaces(indentCount + 4);
2631
- // eslint-disable-next-line max-len
2632
- _strbuf += `cli: ${glc(this, segment.clientId)} seq: ${segment.seq} ord: ${ordinalToArray(segment.ordinal)}`;
2633
- const removalInfo: IRemovalInfo = segment;
2634
- if (removalInfo.removedSeq !== undefined) {
2635
- _strbuf += ` rcli: ${glc(this, removalInfo.removedClientId!)} rseq: ${removalInfo.removedSeq}`;
2636
- }
2637
- _strbuf += "\n";
2638
- _strbuf += internedSpaces(indentCount + 4);
2639
- _strbuf += segment.toString();
2640
- _strbuf += "\n";
2641
- }
2642
- }
2643
- return _strbuf;
2644
- }
2645
-
2646
- public toString() {
2647
- return this.nodeToString(this.root, "", 0);
2648
- }
2649
-
2650
2600
  public incrementalBlockMap<TContext>(stateStack: Stack<IncrementalMapState<TContext>>) {
2651
2601
  while (!stateStack.empty()) {
2652
2602
  // We already check the stack is not empty
@@ -75,7 +75,6 @@ export interface IMergeTreeClientSequenceArgs {
75
75
  export type MergeTreeDeltaCallback =
76
76
  (opArgs: IMergeTreeDeltaOpArgs, deltaArgs: IMergeTreeDeltaCallbackArgs) => void;
77
77
 
78
- // eslint-disable-next-line @typescript-eslint/no-empty-interface
79
78
  export interface IMergeTreeMaintenanceCallbackArgs extends IMergeTreeDeltaCallbackArgs<MergeTreeMaintenanceType> { }
80
79
 
81
80
  export type MergeTreeMaintenanceCallback =