@fluidframework/sequence 2.0.0-internal.6.1.0 → 2.0.0-internal.6.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 (56) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +4 -3
  3. package/dist/defaultMapInterfaces.d.ts +1 -1
  4. package/dist/defaultMapInterfaces.d.ts.map +1 -1
  5. package/dist/defaultMapInterfaces.js.map +1 -1
  6. package/dist/intervalCollection.d.ts +1 -41
  7. package/dist/intervalCollection.d.ts.map +1 -1
  8. package/dist/intervalCollection.js +1 -20
  9. package/dist/intervalCollection.js.map +1 -1
  10. package/dist/intervals/sequenceInterval.js +2 -2
  11. package/dist/intervals/sequenceInterval.js.map +1 -1
  12. package/dist/packageVersion.d.ts +1 -1
  13. package/dist/packageVersion.js +1 -1
  14. package/dist/packageVersion.js.map +1 -1
  15. package/dist/sequence.d.ts +22 -1
  16. package/dist/sequence.d.ts.map +1 -1
  17. package/dist/sequence.js +52 -6
  18. package/dist/sequence.js.map +1 -1
  19. package/dist/sharedSequence.d.ts +9 -0
  20. package/dist/sharedSequence.d.ts.map +1 -1
  21. package/dist/sharedSequence.js +6 -0
  22. package/dist/sharedSequence.js.map +1 -1
  23. package/dist/sharedString.d.ts.map +1 -1
  24. package/dist/sharedString.js +6 -6
  25. package/dist/sharedString.js.map +1 -1
  26. package/lib/defaultMapInterfaces.d.ts +1 -1
  27. package/lib/defaultMapInterfaces.d.ts.map +1 -1
  28. package/lib/defaultMapInterfaces.js.map +1 -1
  29. package/lib/intervalCollection.d.ts +1 -41
  30. package/lib/intervalCollection.d.ts.map +1 -1
  31. package/lib/intervalCollection.js +1 -20
  32. package/lib/intervalCollection.js.map +1 -1
  33. package/lib/intervals/sequenceInterval.js +1 -1
  34. package/lib/intervals/sequenceInterval.js.map +1 -1
  35. package/lib/packageVersion.d.ts +1 -1
  36. package/lib/packageVersion.js +1 -1
  37. package/lib/packageVersion.js.map +1 -1
  38. package/lib/sequence.d.ts +22 -1
  39. package/lib/sequence.d.ts.map +1 -1
  40. package/lib/sequence.js +54 -7
  41. package/lib/sequence.js.map +1 -1
  42. package/lib/sharedSequence.d.ts +9 -0
  43. package/lib/sharedSequence.d.ts.map +1 -1
  44. package/lib/sharedSequence.js +6 -0
  45. package/lib/sharedSequence.js.map +1 -1
  46. package/lib/sharedString.d.ts.map +1 -1
  47. package/lib/sharedString.js +6 -6
  48. package/lib/sharedString.js.map +1 -1
  49. package/package.json +18 -20
  50. package/src/defaultMapInterfaces.ts +1 -1
  51. package/src/intervalCollection.ts +2 -43
  52. package/src/intervals/sequenceInterval.ts +1 -1
  53. package/src/packageVersion.ts +1 -1
  54. package/src/sequence.ts +78 -8
  55. package/src/sharedSequence.ts +9 -0
  56. package/src/sharedString.ts +8 -6
@@ -1 +1 @@
1
- {"version":3,"file":"sharedString.js","sourceRoot":"","sources":["../src/sharedString.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAQN,MAAM,EAIN,eAAe,EACf,WAAW,GACX,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAkCxD;;;;;;;;;GASG;AACH,MAAM,OAAO,YACZ,SAAQ,qBAA0C;IA2BlD,YACC,QAAgC,EACzB,EAAU,EACjB,UAA8B;QAE9B,KAAK,CAAC,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,mBAAmB,CAAC,eAAsB,CAAC,CAAC;QAHrE,OAAE,GAAF,EAAE,CAAQ;QAIjB,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;IAC3D,CAAC;IA/BD;;;;;OAKG;IACI,MAAM,CAAC,MAAM,CAAC,OAA+B,EAAE,EAAW;QAChE,OAAO,OAAO,CAAC,aAAa,CAAC,EAAE,EAAE,mBAAmB,CAAC,IAAI,CAAiB,CAAC;IAC5E,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,UAAU;QACvB,OAAO,IAAI,mBAAmB,EAAE,CAAC;IAClC,CAAC;IAED,IAAW,aAAa;QACvB,OAAO,IAAI,CAAC;IACb,CAAC;IAaD;;;;;OAKG;IACI,oBAAoB,CAC1B,YAA+B,EAC/B,OAAsB,EACtB,KAAmB;QAEnB,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,KAAK,EAAE;YACV,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;SAC7B;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED;;OAEG;IACI,YAAY,CAClB,GAAW,EACX,OAAsB,EACtB,KAAmB;QAEnB,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;QACpC,IAAI,KAAK,EAAE;YACV,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;SAC7B;QAED,OAAO,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IAED;;;;;OAKG;IACI,kBAAkB,CAAC,YAA+B,EAAE,IAAY,EAAE,KAAmB;QAC3F,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,KAAK,EAAE;YACV,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;SAC7B;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED;;OAEG;IACI,UAAU,CAAC,GAAW,EAAE,IAAY,EAAE,KAAmB;QAC/D,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,KAAK,EAAE;YACV,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;SAC7B;QAED,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;OAMG;IACI,WAAW,CAAC,KAAa,EAAE,GAAW,EAAE,IAAY,EAAE,KAAmB;QAC/E,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED;;;;;OAKG;IACI,UAAU,CAAC,KAAa,EAAE,GAAW;QAC3C,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IACrC,CAAC;IAED;;;;;OAKG;IACI,6BAA6B,CACnC,MAAc,EACd,KAAkB,EAClB,QAA6B;QAE7B,IAAI,CAAC,MAAM,CAAC,6BAA6B,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IACpE,CAAC;IAED;;;;;OAKG;IACI,cAAc,CAAC,MAAc,EAAE,KAAkB,EAAE,WAA0B;QACnF,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;;OAOG;IACI,QAAQ,CACd,QAA4B,EAC5B,SAAiB,EACjB,SAAS,GAAG,IAAI;QAOhB,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,IAAI,CAAC,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAClE,CAAC;IAED;;;;;OAKG;IACI,OAAO,CAAC,KAAc,EAAE,GAAY;QAC1C,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC,mBAAmB,CAAC,OAAO,CACtC,aAAa,CAAC,UAAU,EACxB,aAAa,CAAC,QAAQ,EACtB,EAAE,EACF,KAAK,EACL,GAAG,CACH,CAAC;IACH,CAAC;IAED;;OAEG;IACI,uBAAuB,CAAC,KAAc,EAAE,GAAY;QAC1D,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC,mBAAmB,CAAC,OAAO,CACtC,aAAa,CAAC,UAAU,EACxB,aAAa,CAAC,QAAQ,EACtB,GAAG,EACH,KAAK,EACL,GAAG,CACH,CAAC;IACH,CAAC;IAEM,uBAAuB,CAAC,KAAa,EAAE,GAAW;QACxD,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC,mBAAmB,CAAC,OAAO,CACtC,aAAa,CAAC,UAAU,EACxB,aAAa,CAAC,QAAQ,EACtB,GAAG,EACH,KAAK,EACL,GAAG,CACH,CAAC;IACH,CAAC;IAED;;;OAGG;IACI,eAAe,CAAC,EAAU;QAChC,OAAO,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC;IAED;;OAEG;IACO,QAAQ,CAAC,OAAY,EAAE,eAAwB;QACxD,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE;YACvC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;SAC/C;aAAM;YACN,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;SACzC;IACF,CAAC;CACD;AAWD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB,CAChC,YAA0B,EAC1B,KAAa,EACb,KAAc,EACd,GAAY;IAKZ,MAAM,KAAK,GAA8B;QACxC,mBAAmB,EAAE,KAAK;QAC1B,eAAe,EAAE,EAAE;QACnB,YAAY,EAAE,EAAE;QAChB,cAAc,EAAE,EAAE;QAClB,WAAW,EAAE,IAAI,WAAW,CAAC,EAAE,CAAC;KAChC,CAAC;IAEF,YAAY,CAAC,YAAY,CAAC,oBAAoB,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACnE,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,eAAe,EAAE,KAAK,CAAC,eAAe,EAAE,CAAC;AACrF,CAAC;AAED,MAAM,oBAAoB,GAA8C,CACvE,OAAiB,EACjB,GAAW,EACX,MAAc,EACd,QAAgB,EAChB,KAAa,EACb,GAAW,EACX,SAAoC,EACnC,EAAE;IACH,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IAC/D,IAAI,WAAW,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE;QAC5B,IAAI,SAAS,GAAG,EAAE,CAAC;QACnB,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,gDAAgD;QAChD,MAAM,IAAI,GAAG,EAAc,CAAC;QAC5B,MAAM,QAAQ,GAAG,EAAc,CAAC;QAEhC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,aAAa,CAAC,EAAE;YACxC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SACf;QACD,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC,iBAAiB,CAAC,EAAE;YAC5C,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SACf;QACD,MAAM,OAAO,GAAG,EAAc,CAAC;QAC/B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;YACpB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;gBACvB,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;oBAClC,SAAS,IAAI,IAAI,GAAG,GAAG,CAAC;oBACxB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;iBACnB;aACD;YACD,KAAK,MAAM,QAAQ,IAAI,cAAc,EAAE;gBACtC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;oBAC7B,OAAO,IAAI,KAAK,QAAQ,GAAG,CAAC;oBAC5B,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;iBACvB;aACD;YACD,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE;gBACzC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;aAC7B;SACD;aAAM;YACN,KAAK,MAAM,QAAQ,IAAI,cAAc,EAAE;gBACtC,OAAO,IAAI,KAAK,QAAQ,GAAG,CAAC;gBAC5B,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;aACvB;SACD;QACD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;YAC7B,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC9C,IAAI,MAAM,IAAI,CAAC,EAAE;gBAChB,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;aACjC;SACD;QACD,WAAW,CAAC,IAAI,IAAI,OAAO,CAAC;QAC5B,WAAW,CAAC,IAAI,IAAI,SAAS,CAAC;QAC9B,IAAI,KAAK,IAAI,CAAC,IAAI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE;YAC7C,WAAW,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;SACjC;aAAM;YACN,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;YACnC,MAAM,MAAM,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YACrC,MAAM,IAAI,GAAG,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC;YAC7C,WAAW,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;SACzD;KACD;SAAM;QACN,IAAI,WAAW,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE;YAC1C,MAAM,eAAe,GACpB,WAAW,KAAK,GAAG;gBAClB,CAAC,CAAC,KAAK,OAAO,CAAC,QAAQ,EAAE,EAAE;gBAC3B,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YAC7C,WAAW,CAAC,IAAI,IAAI,eAAe,CAAC;SACpC;aAAM;YACN,MAAM,MAAM,GAAG,OAAiB,CAAC;YACjC,IAAI,eAAe,CAAC,MAAM,EAAE,SAAS,CAAC,mBAAmB,CAAC,EAAE;gBAC3D,SAAS,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACvC,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;gBAC9C,WAAW,CAAC,IAAI,GAAG,EAAE,CAAC;aACtB;SACD;KACD;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tICombiningOp,\n\tIMergeTreeInsertMsg,\n\tIMergeTreeRemoveMsg,\n\tIMergeTreeTextHelper,\n\tIRelativePosition,\n\tISegment,\n\tISegmentAction,\n\tMarker,\n\tPropertySet,\n\tReferencePosition,\n\tReferenceType,\n\trefHasTileLabel,\n\tTextSegment,\n} from \"@fluidframework/merge-tree\";\nimport { IFluidDataStoreRuntime, IChannelAttributes } from \"@fluidframework/datastore-definitions\";\nimport { SharedSegmentSequence } from \"./sequence\";\nimport { SharedStringFactory } from \"./sequenceFactory\";\n\n/**\n * Fluid object interface describing access methods on a SharedString\n */\nexport interface ISharedString extends SharedSegmentSequence<SharedStringSegment> {\n\t/**\n\t * Inserts the text at the position.\n\t * @param pos - The position to insert the text at\n\t * @param text - The text to insert\n\t * @param props - The properties of the text\n\t */\n\tinsertText(pos: number, text: string, props?: PropertySet): void;\n\n\t/**\n\t * Inserts a marker at the position.\n\t * @param pos - The position to insert the marker at\n\t * @param refType - The reference type of the marker\n\t * @param props - The properties of the marker\n\t */\n\tinsertMarker(\n\t\tpos: number,\n\t\trefType: ReferenceType,\n\t\tprops?: PropertySet,\n\t): IMergeTreeInsertMsg | undefined;\n\n\t/**\n\t * {@inheritDoc SharedSegmentSequence.posFromRelativePos}\n\t */\n\tposFromRelativePos(relativePos: IRelativePosition): number;\n}\n\nexport type SharedStringSegment = TextSegment | Marker;\n\n/**\n * The Shared String is a specialized data structure for handling collaborative\n * text. It is based on a more general Sequence data structure but has\n * additional features that make working with text easier.\n *\n * In addition to text, a Shared String can also contain markers. Markers can be\n * used to store metadata at positions within the text, like the details of an\n * image or Fluid object that should be rendered with the text.\n *\n */\nexport class SharedString\n\textends SharedSegmentSequence<SharedStringSegment>\n\timplements ISharedString\n{\n\t/**\n\t * Create a new shared string.\n\t * @param runtime - data store runtime the new shared string belongs to\n\t * @param id - optional name of the shared string\n\t * @returns newly create shared string (but not attached yet)\n\t */\n\tpublic static create(runtime: IFluidDataStoreRuntime, id?: string) {\n\t\treturn runtime.createChannel(id, SharedStringFactory.Type) as SharedString;\n\t}\n\n\t/**\n\t * Get a factory for SharedString to register with the data store.\n\t * @returns a factory that creates and load SharedString\n\t */\n\tpublic static getFactory() {\n\t\treturn new SharedStringFactory();\n\t}\n\n\tpublic get ISharedString(): ISharedString {\n\t\treturn this;\n\t}\n\n\tprivate readonly mergeTreeTextHelper: IMergeTreeTextHelper;\n\n\tconstructor(\n\t\tdocument: IFluidDataStoreRuntime,\n\t\tpublic id: string,\n\t\tattributes: IChannelAttributes,\n\t) {\n\t\tsuper(document, id, attributes, SharedStringFactory.segmentFromSpec as any);\n\t\tthis.mergeTreeTextHelper = this.client.createTextHelper();\n\t}\n\n\t/**\n\t * Inserts a marker at a relative position.\n\t * @param relativePos1 - The relative position to insert the marker at\n\t * @param refType - The reference type of the marker\n\t * @param props - The properties of the marker\n\t */\n\tpublic insertMarkerRelative(\n\t\trelativePos1: IRelativePosition,\n\t\trefType: ReferenceType,\n\t\tprops?: PropertySet,\n\t) {\n\t\tconst segment = new Marker(refType);\n\t\tif (props) {\n\t\t\tsegment.addProperties(props);\n\t\t}\n\n\t\tconst pos = this.posFromRelativePos(relativePos1);\n\t\tthis.client.insertSegmentLocal(pos, segment);\n\t}\n\n\t/**\n\t * {@inheritDoc ISharedString.insertMarker}\n\t */\n\tpublic insertMarker(\n\t\tpos: number,\n\t\trefType: ReferenceType,\n\t\tprops?: PropertySet,\n\t): IMergeTreeInsertMsg | undefined {\n\t\tconst segment = new Marker(refType);\n\t\tif (props) {\n\t\t\tsegment.addProperties(props);\n\t\t}\n\n\t\treturn this.client.insertSegmentLocal(pos, segment);\n\t}\n\n\t/**\n\t * Inserts the text at the position.\n\t * @param relativePos1 - The relative position to insert the text at\n\t * @param text - The text to insert\n\t * @param props - The properties of text\n\t */\n\tpublic insertTextRelative(relativePos1: IRelativePosition, text: string, props?: PropertySet) {\n\t\tconst segment = new TextSegment(text);\n\t\tif (props) {\n\t\t\tsegment.addProperties(props);\n\t\t}\n\n\t\tconst pos = this.posFromRelativePos(relativePos1);\n\t\tthis.client.insertSegmentLocal(pos, segment);\n\t}\n\n\t/**\n\t * {@inheritDoc ISharedString.insertText}\n\t */\n\tpublic insertText(pos: number, text: string, props?: PropertySet) {\n\t\tconst segment = new TextSegment(text);\n\t\tif (props) {\n\t\t\tsegment.addProperties(props);\n\t\t}\n\n\t\tthis.client.insertSegmentLocal(pos, segment);\n\t}\n\n\t/**\n\t * Replaces a range with the provided text.\n\t * @param start - The inclusive start of the range to replace\n\t * @param end - The exclusive end of the range to replace\n\t * @param text - The text to replace the range with\n\t * @param props - Optional. The properties of the replacement text\n\t */\n\tpublic replaceText(start: number, end: number, text: string, props?: PropertySet) {\n\t\tthis.replaceRange(start, end, TextSegment.make(text, props));\n\t}\n\n\t/**\n\t * Removes the text in the given range.\n\t * @param start - The inclusive start of the range to remove\n\t * @param end - The exclusive end of the range to replace\n\t * @returns the message sent.\n\t */\n\tpublic removeText(start: number, end: number): IMergeTreeRemoveMsg {\n\t\treturn this.removeRange(start, end);\n\t}\n\n\t/**\n\t * Annotates the marker with the provided properties and calls the callback on consensus.\n\t * @param marker - The marker to annotate\n\t * @param props - The properties to annotate the marker with\n\t * @param consensusCallback - The callback called when consensus is reached\n\t */\n\tpublic annotateMarkerNotifyConsensus(\n\t\tmarker: Marker,\n\t\tprops: PropertySet,\n\t\tcallback: (m: Marker) => void,\n\t) {\n\t\tthis.client.annotateMarkerNotifyConsensus(marker, props, callback);\n\t}\n\n\t/**\n\t * Annotates the marker with the provided properties.\n\t * @param marker - The marker to annotate\n\t * @param props - The properties to annotate the marker with\n\t * @param combiningOp - Optional. Specifies how to combine values for the property, such as \"incr\" for increment.\n\t */\n\tpublic annotateMarker(marker: Marker, props: PropertySet, combiningOp?: ICombiningOp) {\n\t\tthis.client.annotateMarker(marker, props, combiningOp);\n\t}\n\n\t/**\n\t * Finds the nearest reference with ReferenceType.Tile to `startPos` in the direction dictated by `tilePrecedesPos`.\n\t * Note that Markers receive `ReferenceType.Tile` by default.\n\t * @param startPos - Position at which to start the search\n\t * @param clientId - clientId dictating the perspective to search from\n\t * @param tileLabel - Label of the tile to search for\n\t * @param preceding - Whether the desired tile comes before (true) or after (false) `startPos`\n\t */\n\tpublic findTile(\n\t\tstartPos: number | undefined,\n\t\ttileLabel: string,\n\t\tpreceding = true,\n\t):\n\t\t| {\n\t\t\t\ttile: ReferencePosition;\n\t\t\t\tpos: number;\n\t\t }\n\t\t| undefined {\n\t\treturn this.client.findTile(startPos ?? 0, tileLabel, preceding);\n\t}\n\n\t/**\n\t * Retrieve text from the SharedString in string format.\n\t * @param start - The starting index of the text to retrieve, or 0 if omitted.\n\t * @param end - The ending index of the text to retrieve, or the end of the string if omitted\n\t * @returns The requested text content as a string.\n\t */\n\tpublic getText(start?: number, end?: number) {\n\t\tconst segmentWindow = this.client.getCollabWindow();\n\t\treturn this.mergeTreeTextHelper.getText(\n\t\t\tsegmentWindow.currentSeq,\n\t\t\tsegmentWindow.clientId,\n\t\t\t\"\",\n\t\t\tstart,\n\t\t\tend,\n\t\t);\n\t}\n\n\t/**\n\t * Adds spaces for markers and handles, so that position calculations account for them.\n\t */\n\tpublic getTextWithPlaceholders(start?: number, end?: number) {\n\t\tconst segmentWindow = this.client.getCollabWindow();\n\t\treturn this.mergeTreeTextHelper.getText(\n\t\t\tsegmentWindow.currentSeq,\n\t\t\tsegmentWindow.clientId,\n\t\t\t\" \",\n\t\t\tstart,\n\t\t\tend,\n\t\t);\n\t}\n\n\tpublic getTextRangeWithMarkers(start: number, end: number) {\n\t\tconst segmentWindow = this.client.getCollabWindow();\n\t\treturn this.mergeTreeTextHelper.getText(\n\t\t\tsegmentWindow.currentSeq,\n\t\t\tsegmentWindow.clientId,\n\t\t\t\"*\",\n\t\t\tstart,\n\t\t\tend,\n\t\t);\n\t}\n\n\t/**\n\t * Looks up and returns a `Marker` using its id. Returns `undefined` if there is no marker with the provided\n\t * id in this `SharedString`.\n\t */\n\tpublic getMarkerFromId(id: string): ISegment | undefined {\n\t\treturn this.client.getMarkerFromId(id);\n\t}\n\n\t/**\n\t * Revert an op\n\t */\n\tprotected rollback(content: any, localOpMetadata: unknown): void {\n\t\tif (this.client.rollback !== undefined) {\n\t\t\tthis.client.rollback(content, localOpMetadata);\n\t\t} else {\n\t\t\tsuper.rollback(content, localOpMetadata);\n\t\t}\n\t}\n}\n\ninterface ITextAndMarkerAccumulator {\n\tparallelText: string[];\n\tparallelMarkers: Marker[];\n\tparallelMarkerLabel: string;\n\tplaceholder?: string;\n\ttagsInProgress: string[];\n\ttextSegment: TextSegment;\n}\n\n/**\n * Splits the text into regions ending with markers with the given `label`.\n * @param sharedString - String to retrieve text and markers from\n * @param label - label to split on\n * @returns Two parallel lists of text and markers, split by markers with the provided `label`.\n *\n * For example:\n * ```typescript\n * // Say sharedstring has contents \"hello<paragraph marker 1>world<paragraph marker 2>missing\".\n * const { parallelText, parallelMarkers } = getTextAndMarkers(sharedString, \"paragraph\");\n * // parallelText === [\"hello\", \"world\"]\n * // parallelMarkers === [<paragraph marker 1 object>, <paragraph marker 2 object>]\n * // Note parallelText does not include \"missing\".\n * ```\n */\nexport function getTextAndMarkers(\n\tsharedString: SharedString,\n\tlabel: string,\n\tstart?: number,\n\tend?: number,\n): {\n\tparallelText: string[];\n\tparallelMarkers: Marker[];\n} {\n\tconst accum: ITextAndMarkerAccumulator = {\n\t\tparallelMarkerLabel: label,\n\t\tparallelMarkers: [],\n\t\tparallelText: [],\n\t\ttagsInProgress: [],\n\t\ttextSegment: new TextSegment(\"\"),\n\t};\n\n\tsharedString.walkSegments(gatherTextAndMarkers, start, end, accum);\n\treturn { parallelText: accum.parallelText, parallelMarkers: accum.parallelMarkers };\n}\n\nconst gatherTextAndMarkers: ISegmentAction<ITextAndMarkerAccumulator> = (\n\tsegment: ISegment,\n\tpos: number,\n\trefSeq: number,\n\tclientId: number,\n\tstart: number,\n\tend: number,\n\taccumText: ITextAndMarkerAccumulator,\n) => {\n\tconst { placeholder, tagsInProgress, textSegment } = accumText;\n\tif (TextSegment.is(segment)) {\n\t\tlet beginTags = \"\";\n\t\tlet endTags = \"\";\n\t\t// TODO: let clients pass in function to get tag\n\t\tconst tags = [] as string[];\n\t\tconst initTags = [] as string[];\n\n\t\tif (segment.properties?.[\"font-weight\"]) {\n\t\t\ttags.push(\"b\");\n\t\t}\n\t\tif (segment.properties?.[\"text-decoration\"]) {\n\t\t\ttags.push(\"u\");\n\t\t}\n\t\tconst remTags = [] as string[];\n\t\tif (tags.length > 0) {\n\t\t\tfor (const tag of tags) {\n\t\t\t\tif (!tagsInProgress.includes(tag)) {\n\t\t\t\t\tbeginTags += `<${tag}>`;\n\t\t\t\t\tinitTags.push(tag);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const accumTag of tagsInProgress) {\n\t\t\t\tif (!tags.includes(accumTag)) {\n\t\t\t\t\tendTags += `</${accumTag}>`;\n\t\t\t\t\tremTags.push(accumTag);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const initTag of initTags.reverse()) {\n\t\t\t\ttagsInProgress.push(initTag);\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const accumTag of tagsInProgress) {\n\t\t\t\tendTags += `</${accumTag}>`;\n\t\t\t\tremTags.push(accumTag);\n\t\t\t}\n\t\t}\n\t\tfor (const remTag of remTags) {\n\t\t\tconst remdex = tagsInProgress.indexOf(remTag);\n\t\t\tif (remdex >= 0) {\n\t\t\t\ttagsInProgress.splice(remdex, 1);\n\t\t\t}\n\t\t}\n\t\ttextSegment.text += endTags;\n\t\ttextSegment.text += beginTags;\n\t\tif (start <= 0 && end >= segment.text.length) {\n\t\t\ttextSegment.text += segment.text;\n\t\t} else {\n\t\t\tconst seglen = segment.text.length;\n\t\t\tconst _start = start < 0 ? 0 : start;\n\t\t\tconst _end = end >= seglen ? undefined : end;\n\t\t\ttextSegment.text += segment.text.substring(_start, _end);\n\t\t}\n\t} else {\n\t\tif (placeholder && placeholder.length > 0) {\n\t\t\tconst placeholderText =\n\t\t\t\tplaceholder === \"*\"\n\t\t\t\t\t? `\\n${segment.toString()}`\n\t\t\t\t\t: placeholder.repeat(segment.cachedLength);\n\t\t\ttextSegment.text += placeholderText;\n\t\t} else {\n\t\t\tconst marker = segment as Marker;\n\t\t\tif (refHasTileLabel(marker, accumText.parallelMarkerLabel)) {\n\t\t\t\taccumText.parallelMarkers.push(marker);\n\t\t\t\taccumText.parallelText.push(textSegment.text);\n\t\t\t\ttextSegment.text = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true;\n};\n"]}
1
+ {"version":3,"file":"sharedString.js","sourceRoot":"","sources":["../src/sharedString.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 {\n\tICombiningOp,\n\tIMergeTreeInsertMsg,\n\tIMergeTreeRemoveMsg,\n\tIMergeTreeTextHelper,\n\tIRelativePosition,\n\tISegment,\n\tISegmentAction,\n\tMarker,\n\tPropertySet,\n\tReferencePosition,\n\tReferenceType,\n\trefHasTileLabel,\n\tTextSegment,\n} from \"@fluidframework/merge-tree\";\nimport { IFluidDataStoreRuntime, IChannelAttributes } from \"@fluidframework/datastore-definitions\";\nimport { SharedSegmentSequence } from \"./sequence\";\nimport { SharedStringFactory } from \"./sequenceFactory\";\n\n/**\n * Fluid object interface describing access methods on a SharedString\n */\nexport interface ISharedString extends SharedSegmentSequence<SharedStringSegment> {\n\t/**\n\t * Inserts the text at the position.\n\t * @param pos - The position to insert the text at\n\t * @param text - The text to insert\n\t * @param props - The properties of the text\n\t */\n\tinsertText(pos: number, text: string, props?: PropertySet): void;\n\n\t/**\n\t * Inserts a marker at the position.\n\t * @param pos - The position to insert the marker at\n\t * @param refType - The reference type of the marker\n\t * @param props - The properties of the marker\n\t */\n\tinsertMarker(\n\t\tpos: number,\n\t\trefType: ReferenceType,\n\t\tprops?: PropertySet,\n\t): IMergeTreeInsertMsg | undefined;\n\n\t/**\n\t * {@inheritDoc SharedSegmentSequence.posFromRelativePos}\n\t */\n\tposFromRelativePos(relativePos: IRelativePosition): number;\n}\n\nexport type SharedStringSegment = TextSegment | Marker;\n\n/**\n * The Shared String is a specialized data structure for handling collaborative\n * text. It is based on a more general Sequence data structure but has\n * additional features that make working with text easier.\n *\n * In addition to text, a Shared String can also contain markers. Markers can be\n * used to store metadata at positions within the text, like the details of an\n * image or Fluid object that should be rendered with the text.\n *\n */\nexport class SharedString\n\textends SharedSegmentSequence<SharedStringSegment>\n\timplements ISharedString\n{\n\t/**\n\t * Create a new shared string.\n\t * @param runtime - data store runtime the new shared string belongs to\n\t * @param id - optional name of the shared string\n\t * @returns newly create shared string (but not attached yet)\n\t */\n\tpublic static create(runtime: IFluidDataStoreRuntime, id?: string) {\n\t\treturn runtime.createChannel(id, SharedStringFactory.Type) as SharedString;\n\t}\n\n\t/**\n\t * Get a factory for SharedString to register with the data store.\n\t * @returns a factory that creates and load SharedString\n\t */\n\tpublic static getFactory() {\n\t\treturn new SharedStringFactory();\n\t}\n\n\tpublic get ISharedString(): ISharedString {\n\t\treturn this;\n\t}\n\n\tprivate readonly mergeTreeTextHelper: IMergeTreeTextHelper;\n\n\tconstructor(\n\t\tdocument: IFluidDataStoreRuntime,\n\t\tpublic id: string,\n\t\tattributes: IChannelAttributes,\n\t) {\n\t\tsuper(document, id, attributes, SharedStringFactory.segmentFromSpec as any);\n\t\tthis.mergeTreeTextHelper = this.client.createTextHelper();\n\t}\n\n\t/**\n\t * Inserts a marker at a relative position.\n\t * @param relativePos1 - The relative position to insert the marker at\n\t * @param refType - The reference type of the marker\n\t * @param props - The properties of the marker\n\t */\n\tpublic insertMarkerRelative(\n\t\trelativePos1: IRelativePosition,\n\t\trefType: ReferenceType,\n\t\tprops?: PropertySet,\n\t) {\n\t\tconst segment = new Marker(refType);\n\t\tif (props) {\n\t\t\tsegment.addProperties(props);\n\t\t}\n\n\t\tconst pos = this.posFromRelativePos(relativePos1);\n\t\tthis.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));\n\t}\n\n\t/**\n\t * {@inheritDoc ISharedString.insertMarker}\n\t */\n\tpublic insertMarker(\n\t\tpos: number,\n\t\trefType: ReferenceType,\n\t\tprops?: PropertySet,\n\t): IMergeTreeInsertMsg | undefined {\n\t\tconst segment = new Marker(refType);\n\t\tif (props) {\n\t\t\tsegment.addProperties(props);\n\t\t}\n\n\t\treturn this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));\n\t}\n\n\t/**\n\t * Inserts the text at the position.\n\t * @param relativePos1 - The relative position to insert the text at\n\t * @param text - The text to insert\n\t * @param props - The properties of text\n\t */\n\tpublic insertTextRelative(relativePos1: IRelativePosition, text: string, props?: PropertySet) {\n\t\tconst segment = new TextSegment(text);\n\t\tif (props) {\n\t\t\tsegment.addProperties(props);\n\t\t}\n\n\t\tconst pos = this.posFromRelativePos(relativePos1);\n\t\tthis.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));\n\t}\n\n\t/**\n\t * {@inheritDoc ISharedString.insertText}\n\t */\n\tpublic insertText(pos: number, text: string, props?: PropertySet) {\n\t\tconst segment = new TextSegment(text);\n\t\tif (props) {\n\t\t\tsegment.addProperties(props);\n\t\t}\n\n\t\tthis.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));\n\t}\n\n\t/**\n\t * Replaces a range with the provided text.\n\t * @param start - The inclusive start of the range to replace\n\t * @param end - The exclusive end of the range to replace\n\t * @param text - The text to replace the range with\n\t * @param props - Optional. The properties of the replacement text\n\t */\n\tpublic replaceText(start: number, end: number, text: string, props?: PropertySet) {\n\t\tthis.replaceRange(start, end, TextSegment.make(text, props));\n\t}\n\n\t/**\n\t * Removes the text in the given range.\n\t * @param start - The inclusive start of the range to remove\n\t * @param end - The exclusive end of the range to replace\n\t * @returns the message sent.\n\t */\n\tpublic removeText(start: number, end: number): IMergeTreeRemoveMsg {\n\t\treturn this.removeRange(start, end);\n\t}\n\n\t/**\n\t * Annotates the marker with the provided properties and calls the callback on consensus.\n\t * @param marker - The marker to annotate\n\t * @param props - The properties to annotate the marker with\n\t * @param consensusCallback - The callback called when consensus is reached\n\t */\n\tpublic annotateMarkerNotifyConsensus(\n\t\tmarker: Marker,\n\t\tprops: PropertySet,\n\t\tcallback: (m: Marker) => void,\n\t) {\n\t\tthis.guardReentrancy(() =>\n\t\t\tthis.client.annotateMarkerNotifyConsensus(marker, props, callback),\n\t\t);\n\t}\n\n\t/**\n\t * Annotates the marker with the provided properties.\n\t * @param marker - The marker to annotate\n\t * @param props - The properties to annotate the marker with\n\t * @param combiningOp - Optional. Specifies how to combine values for the property, such as \"incr\" for increment.\n\t */\n\tpublic annotateMarker(marker: Marker, props: PropertySet, combiningOp?: ICombiningOp) {\n\t\tthis.guardReentrancy(() => this.client.annotateMarker(marker, props, combiningOp));\n\t}\n\n\t/**\n\t * Finds the nearest reference with ReferenceType.Tile to `startPos` in the direction dictated by `tilePrecedesPos`.\n\t * Note that Markers receive `ReferenceType.Tile` by default.\n\t * @param startPos - Position at which to start the search\n\t * @param clientId - clientId dictating the perspective to search from\n\t * @param tileLabel - Label of the tile to search for\n\t * @param preceding - Whether the desired tile comes before (true) or after (false) `startPos`\n\t */\n\tpublic findTile(\n\t\tstartPos: number | undefined,\n\t\ttileLabel: string,\n\t\tpreceding = true,\n\t):\n\t\t| {\n\t\t\t\ttile: ReferencePosition;\n\t\t\t\tpos: number;\n\t\t }\n\t\t| undefined {\n\t\treturn this.client.findTile(startPos ?? 0, tileLabel, preceding);\n\t}\n\n\t/**\n\t * Retrieve text from the SharedString in string format.\n\t * @param start - The starting index of the text to retrieve, or 0 if omitted.\n\t * @param end - The ending index of the text to retrieve, or the end of the string if omitted\n\t * @returns The requested text content as a string.\n\t */\n\tpublic getText(start?: number, end?: number) {\n\t\tconst segmentWindow = this.client.getCollabWindow();\n\t\treturn this.mergeTreeTextHelper.getText(\n\t\t\tsegmentWindow.currentSeq,\n\t\t\tsegmentWindow.clientId,\n\t\t\t\"\",\n\t\t\tstart,\n\t\t\tend,\n\t\t);\n\t}\n\n\t/**\n\t * Adds spaces for markers and handles, so that position calculations account for them.\n\t */\n\tpublic getTextWithPlaceholders(start?: number, end?: number) {\n\t\tconst segmentWindow = this.client.getCollabWindow();\n\t\treturn this.mergeTreeTextHelper.getText(\n\t\t\tsegmentWindow.currentSeq,\n\t\t\tsegmentWindow.clientId,\n\t\t\t\" \",\n\t\t\tstart,\n\t\t\tend,\n\t\t);\n\t}\n\n\tpublic getTextRangeWithMarkers(start: number, end: number) {\n\t\tconst segmentWindow = this.client.getCollabWindow();\n\t\treturn this.mergeTreeTextHelper.getText(\n\t\t\tsegmentWindow.currentSeq,\n\t\t\tsegmentWindow.clientId,\n\t\t\t\"*\",\n\t\t\tstart,\n\t\t\tend,\n\t\t);\n\t}\n\n\t/**\n\t * Looks up and returns a `Marker` using its id. Returns `undefined` if there is no marker with the provided\n\t * id in this `SharedString`.\n\t */\n\tpublic getMarkerFromId(id: string): ISegment | undefined {\n\t\treturn this.client.getMarkerFromId(id);\n\t}\n\n\t/**\n\t * Revert an op\n\t */\n\tprotected rollback(content: any, localOpMetadata: unknown): void {\n\t\tif (this.client.rollback !== undefined) {\n\t\t\tthis.client.rollback(content, localOpMetadata);\n\t\t} else {\n\t\t\tsuper.rollback(content, localOpMetadata);\n\t\t}\n\t}\n}\n\ninterface ITextAndMarkerAccumulator {\n\tparallelText: string[];\n\tparallelMarkers: Marker[];\n\tparallelMarkerLabel: string;\n\tplaceholder?: string;\n\ttagsInProgress: string[];\n\ttextSegment: TextSegment;\n}\n\n/**\n * Splits the text into regions ending with markers with the given `label`.\n * @param sharedString - String to retrieve text and markers from\n * @param label - label to split on\n * @returns Two parallel lists of text and markers, split by markers with the provided `label`.\n *\n * For example:\n * ```typescript\n * // Say sharedstring has contents \"hello<paragraph marker 1>world<paragraph marker 2>missing\".\n * const { parallelText, parallelMarkers } = getTextAndMarkers(sharedString, \"paragraph\");\n * // parallelText === [\"hello\", \"world\"]\n * // parallelMarkers === [<paragraph marker 1 object>, <paragraph marker 2 object>]\n * // Note parallelText does not include \"missing\".\n * ```\n */\nexport function getTextAndMarkers(\n\tsharedString: SharedString,\n\tlabel: string,\n\tstart?: number,\n\tend?: number,\n): {\n\tparallelText: string[];\n\tparallelMarkers: Marker[];\n} {\n\tconst accum: ITextAndMarkerAccumulator = {\n\t\tparallelMarkerLabel: label,\n\t\tparallelMarkers: [],\n\t\tparallelText: [],\n\t\ttagsInProgress: [],\n\t\ttextSegment: new TextSegment(\"\"),\n\t};\n\n\tsharedString.walkSegments(gatherTextAndMarkers, start, end, accum);\n\treturn { parallelText: accum.parallelText, parallelMarkers: accum.parallelMarkers };\n}\n\nconst gatherTextAndMarkers: ISegmentAction<ITextAndMarkerAccumulator> = (\n\tsegment: ISegment,\n\tpos: number,\n\trefSeq: number,\n\tclientId: number,\n\tstart: number,\n\tend: number,\n\taccumText: ITextAndMarkerAccumulator,\n) => {\n\tconst { placeholder, tagsInProgress, textSegment } = accumText;\n\tif (TextSegment.is(segment)) {\n\t\tlet beginTags = \"\";\n\t\tlet endTags = \"\";\n\t\t// TODO: let clients pass in function to get tag\n\t\tconst tags = [] as string[];\n\t\tconst initTags = [] as string[];\n\n\t\tif (segment.properties?.[\"font-weight\"]) {\n\t\t\ttags.push(\"b\");\n\t\t}\n\t\tif (segment.properties?.[\"text-decoration\"]) {\n\t\t\ttags.push(\"u\");\n\t\t}\n\t\tconst remTags = [] as string[];\n\t\tif (tags.length > 0) {\n\t\t\tfor (const tag of tags) {\n\t\t\t\tif (!tagsInProgress.includes(tag)) {\n\t\t\t\t\tbeginTags += `<${tag}>`;\n\t\t\t\t\tinitTags.push(tag);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const accumTag of tagsInProgress) {\n\t\t\t\tif (!tags.includes(accumTag)) {\n\t\t\t\t\tendTags += `</${accumTag}>`;\n\t\t\t\t\tremTags.push(accumTag);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const initTag of initTags.reverse()) {\n\t\t\t\ttagsInProgress.push(initTag);\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const accumTag of tagsInProgress) {\n\t\t\t\tendTags += `</${accumTag}>`;\n\t\t\t\tremTags.push(accumTag);\n\t\t\t}\n\t\t}\n\t\tfor (const remTag of remTags) {\n\t\t\tconst remdex = tagsInProgress.indexOf(remTag);\n\t\t\tif (remdex >= 0) {\n\t\t\t\ttagsInProgress.splice(remdex, 1);\n\t\t\t}\n\t\t}\n\t\ttextSegment.text += endTags;\n\t\ttextSegment.text += beginTags;\n\t\tif (start <= 0 && end >= segment.text.length) {\n\t\t\ttextSegment.text += segment.text;\n\t\t} else {\n\t\t\tconst seglen = segment.text.length;\n\t\t\tconst _start = start < 0 ? 0 : start;\n\t\t\tconst _end = end >= seglen ? undefined : end;\n\t\t\ttextSegment.text += segment.text.substring(_start, _end);\n\t\t}\n\t} else {\n\t\tif (placeholder && placeholder.length > 0) {\n\t\t\tconst placeholderText =\n\t\t\t\tplaceholder === \"*\"\n\t\t\t\t\t? `\\n${segment.toString()}`\n\t\t\t\t\t: placeholder.repeat(segment.cachedLength);\n\t\t\ttextSegment.text += placeholderText;\n\t\t} else {\n\t\t\tconst marker = segment as Marker;\n\t\t\tif (refHasTileLabel(marker, accumText.parallelMarkerLabel)) {\n\t\t\t\taccumText.parallelMarkers.push(marker);\n\t\t\t\taccumText.parallelText.push(textSegment.text);\n\t\t\t\ttextSegment.text = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true;\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/sequence",
3
- "version": "2.0.0-internal.6.1.0",
3
+ "version": "2.0.0-internal.6.2.0",
4
4
  "description": "Distributed sequence",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -35,32 +35,30 @@
35
35
  "temp-directory": "nyc/.nyc_output"
36
36
  },
37
37
  "dependencies": {
38
- "@fluidframework/common-definitions": "^0.20.1",
39
38
  "@fluidframework/common-utils": "^1.1.1",
40
- "@fluidframework/container-utils": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
41
- "@fluidframework/core-interfaces": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
42
- "@fluidframework/datastore-definitions": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
43
- "@fluidframework/merge-tree": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
39
+ "@fluidframework/core-interfaces": ">=2.0.0-internal.6.2.0 <2.0.0-internal.6.3.0",
40
+ "@fluidframework/datastore-definitions": ">=2.0.0-internal.6.2.0 <2.0.0-internal.6.3.0",
41
+ "@fluidframework/merge-tree": ">=2.0.0-internal.6.2.0 <2.0.0-internal.6.3.0",
44
42
  "@fluidframework/protocol-definitions": "^1.1.0",
45
- "@fluidframework/runtime-definitions": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
46
- "@fluidframework/runtime-utils": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
47
- "@fluidframework/shared-object-base": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
48
- "@fluidframework/telemetry-utils": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
49
- "uuid": "^8.3.1"
43
+ "@fluidframework/runtime-definitions": ">=2.0.0-internal.6.2.0 <2.0.0-internal.6.3.0",
44
+ "@fluidframework/runtime-utils": ">=2.0.0-internal.6.2.0 <2.0.0-internal.6.3.0",
45
+ "@fluidframework/shared-object-base": ">=2.0.0-internal.6.2.0 <2.0.0-internal.6.3.0",
46
+ "@fluidframework/telemetry-utils": ">=2.0.0-internal.6.2.0 <2.0.0-internal.6.3.0",
47
+ "uuid": "^9.0.0"
50
48
  },
51
49
  "devDependencies": {
52
- "@fluid-internal/stochastic-test-utils": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
53
- "@fluid-internal/test-dds-utils": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
50
+ "@fluid-internal/stochastic-test-utils": ">=2.0.0-internal.6.2.0 <2.0.0-internal.6.3.0",
51
+ "@fluid-internal/test-dds-utils": ">=2.0.0-internal.6.2.0 <2.0.0-internal.6.3.0",
54
52
  "@fluid-tools/benchmark": "^0.48.0",
55
- "@fluid-tools/build-cli": "^0.22.0",
53
+ "@fluid-tools/build-cli": "^0.23.0",
56
54
  "@fluidframework/build-common": "^2.0.0",
57
- "@fluidframework/build-tools": "^0.22.0",
58
- "@fluidframework/eslint-config-fluid": "^2.0.0",
55
+ "@fluidframework/build-tools": "^0.23.0",
56
+ "@fluidframework/eslint-config-fluid": "^2.1.0",
59
57
  "@fluidframework/gitresources": "^1.0.0",
60
- "@fluidframework/mocha-test-setup": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
61
- "@fluidframework/sequence-previous": "npm:@fluidframework/sequence@2.0.0-internal.6.0.0",
58
+ "@fluidframework/mocha-test-setup": ">=2.0.0-internal.6.2.0 <2.0.0-internal.6.3.0",
59
+ "@fluidframework/sequence-previous": "npm:@fluidframework/sequence@2.0.0-internal.6.1.1",
62
60
  "@fluidframework/server-services-client": "^1.0.0",
63
- "@fluidframework/test-runtime-utils": ">=2.0.0-internal.6.1.0 <2.0.0-internal.6.2.0",
61
+ "@fluidframework/test-runtime-utils": ">=2.0.0-internal.6.2.0 <2.0.0-internal.6.3.0",
64
62
  "@microsoft/api-extractor": "^7.34.4",
65
63
  "@types/diff": "^3.5.1",
66
64
  "@types/mocha": "^9.1.1",
@@ -117,7 +115,7 @@
117
115
  "test:memory": "mocha --config src/test/memory/.mocharc.js",
118
116
  "test:memory-profiling:report": "mocha --config src/test/memory/.mocharc.js",
119
117
  "test:mocha": "mocha --ignore 'dist/test/memory/**/*' --recursive 'dist/test/**/*.spec.js' -r node_modules/@fluidframework/mocha-test-setup --unhandled-rejections=strict",
120
- "test:mocha:multireport": "cross-env FLUID_TEST_MULTIREPORT=1 npm run test:mocha",
118
+ "test:mocha:multireport": "npm run test:mocha",
121
119
  "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
122
120
  "test:newsnapfiles": "node dist/test/createSnapshotFiles.js",
123
121
  "test:stress": "cross-env FUZZ_TEST_COUNT=100 FUZZ_STRESS_RUN=true mocha --ignore 'dist/test/memory/**/*' --recursive 'dist/test/**/*.fuzz.spec.js' -r @fluidframework/mocha-test-setup --unhandled-rejections=strict",
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
7
7
  import { ISharedObjectEvents } from "@fluidframework/shared-object-base";
8
- import { IEventThisPlaceHolder } from "@fluidframework/common-definitions";
8
+ import { IEventThisPlaceHolder } from "@fluidframework/core-interfaces";
9
9
 
10
10
  /**
11
11
  * Type of "valueChanged" event parameter.
@@ -6,8 +6,7 @@
6
6
  /* eslint-disable no-bitwise */
7
7
 
8
8
  import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
9
- import { IEvent } from "@fluidframework/common-definitions";
10
- import { UsageError } from "@fluidframework/container-utils";
9
+ import { IEvent } from "@fluidframework/core-interfaces";
11
10
  import {
12
11
  addProperties,
13
12
  Client,
@@ -24,7 +23,7 @@ import {
24
23
  DetachedReferencePosition,
25
24
  } from "@fluidframework/merge-tree";
26
25
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
27
- import { LoggingError } from "@fluidframework/telemetry-utils";
26
+ import { LoggingError, UsageError } from "@fluidframework/telemetry-utils";
28
27
  import { v4 as uuid } from "uuid";
29
28
  import {
30
29
  IMapMessageLocalMetadata,
@@ -677,29 +676,21 @@ export interface IIntervalCollection<TInterval extends ISerializableInterval>
677
676
 
678
677
  /**
679
678
  * @returns a forward iterator over all intervals in this collection with start point equal to `startPosition`.
680
- *
681
- * @deprecated - The sequence order of collection order will not be supported
682
679
  */
683
680
  CreateForwardIteratorWithStartPosition(startPosition: number): Iterator<TInterval>;
684
681
 
685
682
  /**
686
683
  * @returns a backward iterator over all intervals in this collection with start point equal to `startPosition`.
687
- *
688
- * @deprecated - The sequence order of collection order will not be supported
689
684
  */
690
685
  CreateBackwardIteratorWithStartPosition(startPosition: number): Iterator<TInterval>;
691
686
 
692
687
  /**
693
688
  * @returns a forward iterator over all intervals in this collection with end point equal to `endPosition`.
694
- *
695
- * @deprecated - The sequence order of collection order will not be supported
696
689
  */
697
690
  CreateForwardIteratorWithEndPosition(endPosition: number): Iterator<TInterval>;
698
691
 
699
692
  /**
700
693
  * @returns a backward iterator over all intervals in this collection with end point equal to `endPosition`.
701
- *
702
- * @deprecated - The sequence order of collection order will not be supported
703
694
  */
704
695
  CreateBackwardIteratorWithEndPosition(endPosition: number): Iterator<TInterval>;
705
696
 
@@ -710,9 +701,6 @@ export interface IIntervalCollection<TInterval extends ISerializableInterval>
710
701
  * @param iteratesForward - whether or not iteration should be in the forward direction
711
702
  * @param start - If provided, only match intervals whose start point is equal to `start`.
712
703
  * @param end - If provided, only match intervals whose end point is equal to `end`.
713
- *
714
- * @deprecated - This API will be deprecated as its functionality will be moved to the `OverlappingIntervalsIndex`.
715
- * We would like the user to attach the index to the collection on their own.
716
704
  */
717
705
  gatherIterationResults(
718
706
  results: TInterval[],
@@ -724,9 +712,6 @@ export interface IIntervalCollection<TInterval extends ISerializableInterval>
724
712
  /**
725
713
  * @returns an array of all intervals in this collection that overlap with the interval
726
714
  * `[startPosition, endPosition]`.
727
- *
728
- * @deprecated - This API will be deprecated as its functionality will be moved to the `OverlappingIntervalsIndex`.
729
- * We would like the user to attach the index to the collection on their own.
730
715
  */
731
716
  findOverlappingIntervals(startPosition: number, endPosition: number): TInterval[];
732
717
 
@@ -735,16 +720,8 @@ export interface IIntervalCollection<TInterval extends ISerializableInterval>
735
720
  */
736
721
  map(fn: (interval: TInterval) => void): void;
737
722
 
738
- /**
739
- * @deprecated - This API will be deprecated as its functionality will be moved to the `EndpointIndex`.
740
- * We would like the user to attach the index to the collection on their own.
741
- */
742
723
  previousInterval(pos: number): TInterval | undefined;
743
724
 
744
- /**
745
- * @deprecated - This API will be deprecated as its functionality will be moved to the `EndpointIndex`.
746
- * We would like the user to attach the index to the collection on their own.
747
- */
748
725
  nextInterval(pos: number): TInterval | undefined;
749
726
  }
750
727
 
@@ -1594,8 +1571,6 @@ export class IntervalCollection<TInterval extends ISerializableInterval>
1594
1571
 
1595
1572
  /**
1596
1573
  * {@inheritdoc IIntervalCollection.CreateForwardIteratorWithStartPosition}
1597
- *
1598
- * @deprecated - The sequence order of collection order will not be supported
1599
1574
  */
1600
1575
  public CreateForwardIteratorWithStartPosition(
1601
1576
  startPosition: number,
@@ -1606,8 +1581,6 @@ export class IntervalCollection<TInterval extends ISerializableInterval>
1606
1581
 
1607
1582
  /**
1608
1583
  * {@inheritdoc IIntervalCollection.CreateBackwardIteratorWithStartPosition}
1609
- *
1610
- * @deprecated - The sequence order of collection order will not be supported
1611
1584
  */
1612
1585
  public CreateBackwardIteratorWithStartPosition(
1613
1586
  startPosition: number,
@@ -1618,8 +1591,6 @@ export class IntervalCollection<TInterval extends ISerializableInterval>
1618
1591
 
1619
1592
  /**
1620
1593
  * {@inheritdoc IIntervalCollection.CreateForwardIteratorWithEndPosition}
1621
- *
1622
- * @deprecated - The sequence order of collection order will not be supported
1623
1594
  */
1624
1595
  public CreateForwardIteratorWithEndPosition(
1625
1596
  endPosition: number,
@@ -1635,8 +1606,6 @@ export class IntervalCollection<TInterval extends ISerializableInterval>
1635
1606
 
1636
1607
  /**
1637
1608
  * {@inheritdoc IIntervalCollection.CreateBackwardIteratorWithEndPosition}
1638
- *
1639
- * @deprecated - The sequence order of collection order will not be supported
1640
1609
  */
1641
1610
  public CreateBackwardIteratorWithEndPosition(
1642
1611
  endPosition: number,
@@ -1652,8 +1621,6 @@ export class IntervalCollection<TInterval extends ISerializableInterval>
1652
1621
 
1653
1622
  /**
1654
1623
  * {@inheritdoc IIntervalCollection.gatherIterationResults}
1655
- * @deprecated - This API will be deprecated as its functionality will be moved to the `OverlappingIntervalsIndex`.
1656
- * We would like the user to attach the index to the collection on their own.
1657
1624
  */
1658
1625
  public gatherIterationResults(
1659
1626
  results: TInterval[],
@@ -1675,8 +1642,6 @@ export class IntervalCollection<TInterval extends ISerializableInterval>
1675
1642
 
1676
1643
  /**
1677
1644
  * {@inheritdoc IIntervalCollection.findOverlappingIntervals}
1678
- * @deprecated - This API will be deprecated as its functionality will be moved to the `OverlappingIntervalsIndex`.
1679
- * We would like the user to attach the index to the collection on their own.
1680
1645
  */
1681
1646
  public findOverlappingIntervals(startPosition: number, endPosition: number): TInterval[] {
1682
1647
  if (!this.localCollection) {
@@ -1704,9 +1669,6 @@ export class IntervalCollection<TInterval extends ISerializableInterval>
1704
1669
 
1705
1670
  /**
1706
1671
  * {@inheritdoc IIntervalCollection.previousInterval}
1707
- *
1708
- * @deprecated - This API will be deprecated as its functionality will be moved to the `EndpointIndex`.
1709
- * We would like the user to attach the index to the collection on their own.
1710
1672
  */
1711
1673
  public previousInterval(pos: number): TInterval | undefined {
1712
1674
  if (!this.localCollection) {
@@ -1718,9 +1680,6 @@ export class IntervalCollection<TInterval extends ISerializableInterval>
1718
1680
 
1719
1681
  /**
1720
1682
  * {@inheritdoc IIntervalCollection.nextInterval}
1721
- *
1722
- * @deprecated - This API will be deprecated as its functionality will be moved to the `EndpointIndex`.
1723
- * We would like the user to attach the index to the collection on their own.
1724
1683
  */
1725
1684
  public nextInterval(pos: number): TInterval | undefined {
1726
1685
  if (!this.localCollection) {
@@ -25,7 +25,7 @@ import {
25
25
  } from "@fluidframework/merge-tree";
26
26
  import { assert } from "@fluidframework/common-utils";
27
27
  import { ISequencedDocumentMessage } from "@fluidframework/protocol-definitions";
28
- import { UsageError } from "@fluidframework/container-utils";
28
+ import { UsageError } from "@fluidframework/telemetry-utils";
29
29
  import {
30
30
  IIntervalHelpers,
31
31
  ISerializableInterval,
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/sequence";
9
- export const pkgVersion = "2.0.0-internal.6.1.0";
9
+ export const pkgVersion = "2.0.0-internal.6.2.0";
package/src/sequence.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { Deferred, bufferToString, assert } from "@fluidframework/common-utils";
6
- import { createChildLogger } from "@fluidframework/telemetry-utils";
6
+ import { LoggingError, createChildLogger } from "@fluidframework/telemetry-utils";
7
7
  import { ISequencedDocumentMessage, MessageType } from "@fluidframework/protocol-definitions";
8
8
  import {
9
9
  IChannelAttributes,
@@ -13,6 +13,7 @@ import {
13
13
  import {
14
14
  Client,
15
15
  createAnnotateRangeOp,
16
+ // eslint-disable-next-line import/no-deprecated
16
17
  createGroupOp,
17
18
  createInsertOp,
18
19
  createRemoveRangeOp,
@@ -46,9 +47,8 @@ import {
46
47
  ISharedObjectEvents,
47
48
  SummarySerializer,
48
49
  } from "@fluidframework/shared-object-base";
49
- import { IEventThisPlaceHolder } from "@fluidframework/common-definitions";
50
+ import { IEventThisPlaceHolder } from "@fluidframework/core-interfaces";
50
51
  import { ISummaryTreeWithStats, ITelemetryContext } from "@fluidframework/runtime-definitions";
51
-
52
52
  import { DefaultMap, IMapOperation } from "./defaultMap";
53
53
  import { IMapMessageLocalMetadata, IValueChanged } from "./defaultMapInterfaces";
54
54
  import { SequenceInterval } from "./intervals";
@@ -119,6 +119,21 @@ export abstract class SharedSegmentSequence<T extends ISegment>
119
119
  return this.loadedDeferred.promise;
120
120
  }
121
121
 
122
+ /**
123
+ * This is a safeguard to avoid problematic reentrancy of local ops. This type of scenario occurs if the user of SharedString subscribes
124
+ * to the `sequenceDelta` event and uses the callback for a local op to submit further local ops.
125
+ * Historically (before 2.0.0-internal.6.1.0), doing so would result in eventual consistency issues or a corrupted document.
126
+ * These issues were fixed in #16815 which makes such reentrancy no different from applying the ops in order but not from within the change events,
127
+ * but there is still little test coverage for reentrant scenarios.
128
+ * Additionally, applications submitting ops from inside change events need to take extreme care that their data models also support reentrancy.
129
+ * Since this is likely not the case, by default SharedString throws when encountering reentrant ops.
130
+ *
131
+ * An application using SharedString which explicitly wants to opt in to allowing reentrancy anyway can set `sharedStringPreventReentrancy`
132
+ * on the data store options to `false`.
133
+ * @internal
134
+ */
135
+ protected guardReentrancy: <TRet>(callback: () => TRet) => TRet;
136
+
122
137
  private static createOpsFromDelta(event: SequenceDeltaEvent): IMergeTreeDeltaOp[] {
123
138
  const ops: IMergeTreeDeltaOp[] = [];
124
139
  for (const r of event.ranges) {
@@ -194,6 +209,19 @@ export abstract class SharedSegmentSequence<T extends ISegment>
194
209
  ) {
195
210
  super(id, dataStoreRuntime, attributes, "fluid_sequence_");
196
211
 
212
+ this.guardReentrancy =
213
+ dataStoreRuntime.options.sharedStringPreventReentrancy ?? true
214
+ ? ensureNoReentrancy
215
+ : createReentrancyDetector((depth) => {
216
+ if (totalReentrancyLogs > 0) {
217
+ totalReentrancyLogs--;
218
+ this.logger.sendTelemetryEvent(
219
+ { eventName: "LocalOpReentry", depth },
220
+ new LoggingError(reentrancyErrorMessage),
221
+ );
222
+ }
223
+ });
224
+
197
225
  this.loadedDeferred.promise.catch((error) => {
198
226
  this.logger.sendErrorEvent({ eventName: "SequenceLoadFailed" }, error);
199
227
  });
@@ -233,14 +261,14 @@ export abstract class SharedSegmentSequence<T extends ISegment>
233
261
  * @param end - The exclusive end of the range to remove
234
262
  */
235
263
  public removeRange(start: number, end: number): IMergeTreeRemoveMsg {
236
- return this.client.removeRangeLocal(start, end);
264
+ return this.guardReentrancy(() => this.client.removeRangeLocal(start, end));
237
265
  }
238
266
 
239
267
  /**
240
268
  * @deprecated - The ability to create group ops will be removed in an upcoming release, as group ops are redundant with the native batching capabilities of the runtime
241
269
  */
242
270
  public groupOperation(groupOp: IMergeTreeGroupMsg) {
243
- this.client.localTransaction(groupOp);
271
+ this.guardReentrancy(() => this.client.localTransaction(groupOp));
244
272
  }
245
273
 
246
274
  /**
@@ -286,7 +314,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
286
314
  props: PropertySet,
287
315
  combiningOp?: ICombiningOp,
288
316
  ) {
289
- this.client.annotateRangeLocal(start, end, props, combiningOp);
317
+ this.guardReentrancy(() => this.client.annotateRangeLocal(start, end, props, combiningOp));
290
318
  }
291
319
 
292
320
  public getPropertiesAtPosition(pos: number) {
@@ -415,6 +443,9 @@ export abstract class SharedSegmentSequence<T extends ISegment>
415
443
  this.client.walkSegments(handler, start, end, accum as TClientData, splitRange);
416
444
  }
417
445
 
446
+ /**
447
+ * @deprecated - this functionality is no longer supported and will be removed
448
+ */
418
449
  public getStackContext(startPos: number, rangeLabels: string[]): RangeStackMap {
419
450
  return this.client.getStackContext(startPos, rangeLabels);
420
451
  }
@@ -433,7 +464,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
433
464
  * @param segment - The segment to insert
434
465
  */
435
466
  public insertAtReferencePosition(pos: ReferencePosition, segment: T) {
436
- this.client.insertAtReferencePositionLocal(pos, segment);
467
+ this.guardReentrancy(() => this.client.insertAtReferencePositionLocal(pos, segment));
437
468
  }
438
469
  /**
439
470
  * Inserts a segment
@@ -442,7 +473,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
442
473
  */
443
474
  public insertFromSpec(pos: number, spec: IJSONSegment) {
444
475
  const segment = this.segmentFromSpec(spec);
445
- this.client.insertSegmentLocal(pos, segment);
476
+ this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));
446
477
  }
447
478
 
448
479
  /**
@@ -722,6 +753,7 @@ export abstract class SharedSegmentSequence<T extends ISegment>
722
753
  stashMessage = {
723
754
  ...message,
724
755
  referenceSequenceNumber: stashMessage.sequenceNumber - 1,
756
+ // eslint-disable-next-line import/no-deprecated
725
757
  contents: ops.length !== 1 ? createGroupOp(...ops) : ops[0],
726
758
  };
727
759
  }
@@ -803,3 +835,41 @@ export abstract class SharedSegmentSequence<T extends ISegment>
803
835
  }
804
836
  }
805
837
  }
838
+
839
+ function createReentrancyDetector(
840
+ onReentrancy: (depth: number) => void,
841
+ ): <T>(callback: () => T) => T {
842
+ let depth = 0;
843
+ function detectReentrancy<T>(callback: () => T): T {
844
+ if (depth > 0) {
845
+ onReentrancy(depth);
846
+ }
847
+ depth++;
848
+ try {
849
+ return callback();
850
+ } finally {
851
+ depth--;
852
+ }
853
+ }
854
+
855
+ return detectReentrancy;
856
+ }
857
+
858
+ /**
859
+ * Apps which generate reentrant behavior may do so at a high frequency.
860
+ * Logging even per-SharedSegmentSequence instance might be too noisy, and having a few logs from a session
861
+ * is likely enough.
862
+ */
863
+ let totalReentrancyLogs = 3;
864
+
865
+ /**
866
+ * Resets the reentrancy log counter. Test-only API.
867
+ */
868
+ export function resetReentrancyLogCounter() {
869
+ totalReentrancyLogs = 3;
870
+ }
871
+
872
+ const reentrancyErrorMessage = "Reentrancy detected in sequence local ops";
873
+ const ensureNoReentrancy = createReentrancyDetector(() => {
874
+ throw new LoggingError(reentrancyErrorMessage);
875
+ });
@@ -14,10 +14,16 @@ import { SharedSegmentSequence } from "./sequence";
14
14
 
15
15
  const MaxRun = 128;
16
16
 
17
+ /**
18
+ * @deprecated - IJSONRunSegment will be removed in a upcoming release. It has been moved to the fluid-experimental/sequence-deprecated package
19
+ */
17
20
  export interface IJSONRunSegment<T> extends IJSONSegment {
18
21
  items: Serializable<T>[];
19
22
  }
20
23
 
24
+ /**
25
+ * @deprecated - SubSequence will be removed in a upcoming release. It has been moved to the fluid-experimental/sequence-deprecated package
26
+ */
21
27
  export class SubSequence<T> extends BaseSegment {
22
28
  public static readonly typeString: string = "SubSequence";
23
29
  public static is(segment: ISegment): segment is SubSequence<any> {
@@ -98,6 +104,9 @@ export class SubSequence<T> extends BaseSegment {
98
104
  }
99
105
  }
100
106
 
107
+ /**
108
+ * @deprecated - SharedSequence will be removed in a upcoming release. It has been moved to the fluid-experimental/sequence-deprecated package
109
+ */
101
110
  export class SharedSequence<T> extends SharedSegmentSequence<SubSequence<T>> {
102
111
  constructor(
103
112
  document: IFluidDataStoreRuntime,
@@ -118,7 +118,7 @@ export class SharedString
118
118
  }
119
119
 
120
120
  const pos = this.posFromRelativePos(relativePos1);
121
- this.client.insertSegmentLocal(pos, segment);
121
+ this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));
122
122
  }
123
123
 
124
124
  /**
@@ -134,7 +134,7 @@ export class SharedString
134
134
  segment.addProperties(props);
135
135
  }
136
136
 
137
- return this.client.insertSegmentLocal(pos, segment);
137
+ return this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));
138
138
  }
139
139
 
140
140
  /**
@@ -150,7 +150,7 @@ export class SharedString
150
150
  }
151
151
 
152
152
  const pos = this.posFromRelativePos(relativePos1);
153
- this.client.insertSegmentLocal(pos, segment);
153
+ this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));
154
154
  }
155
155
 
156
156
  /**
@@ -162,7 +162,7 @@ export class SharedString
162
162
  segment.addProperties(props);
163
163
  }
164
164
 
165
- this.client.insertSegmentLocal(pos, segment);
165
+ this.guardReentrancy(() => this.client.insertSegmentLocal(pos, segment));
166
166
  }
167
167
 
168
168
  /**
@@ -197,7 +197,9 @@ export class SharedString
197
197
  props: PropertySet,
198
198
  callback: (m: Marker) => void,
199
199
  ) {
200
- this.client.annotateMarkerNotifyConsensus(marker, props, callback);
200
+ this.guardReentrancy(() =>
201
+ this.client.annotateMarkerNotifyConsensus(marker, props, callback),
202
+ );
201
203
  }
202
204
 
203
205
  /**
@@ -207,7 +209,7 @@ export class SharedString
207
209
  * @param combiningOp - Optional. Specifies how to combine values for the property, such as "incr" for increment.
208
210
  */
209
211
  public annotateMarker(marker: Marker, props: PropertySet, combiningOp?: ICombiningOp) {
210
- this.client.annotateMarker(marker, props, combiningOp);
212
+ this.guardReentrancy(() => this.client.annotateMarker(marker, props, combiningOp));
211
213
  }
212
214
 
213
215
  /**