Utils.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // @ts-check
  2. const _ = require('lodash')
  3. /**
  4. * @import { CommentOp, DeleteOp, InsertOp, Op, TrackedChange } from './types'
  5. */
  6. /**
  7. * Returns true if the op is an insert
  8. *
  9. * @param {Op} op
  10. * @returns {op is InsertOp}
  11. */
  12. function isInsert(op) {
  13. return 'i' in op && op.i != null
  14. }
  15. /**
  16. * Returns true if the op is an insert
  17. *
  18. * @param {Op} op
  19. * @returns {op is DeleteOp}
  20. */
  21. function isDelete(op) {
  22. return 'd' in op && op.d != null
  23. }
  24. /**
  25. * Returns true if the op is a comment
  26. *
  27. * @param {Op} op
  28. * @returns {op is CommentOp}
  29. */
  30. function isComment(op) {
  31. return 'c' in op && op.c != null
  32. }
  33. /**
  34. * Get the length of a document from its lines
  35. *
  36. * @param {string[]} lines
  37. * @returns {number}
  38. */
  39. function getDocLength(lines) {
  40. let docLength = _.reduce(lines, (chars, line) => chars + line.length, 0)
  41. // Add newline characters. Lines are joined by newlines, but the last line
  42. // doesn't include a newline. We must make a special case for an empty list
  43. // so that it doesn't report a doc length of -1.
  44. docLength += Math.max(lines.length - 1, 0)
  45. return docLength
  46. }
  47. /**
  48. * Adds given tracked deletes to the given content.
  49. *
  50. * The history system includes tracked deletes in the document content.
  51. *
  52. * @param {string} content
  53. * @param {TrackedChange[]} trackedChanges
  54. * @return {string} content for the history service
  55. */
  56. function addTrackedDeletesToContent(content, trackedChanges) {
  57. let cursor = 0
  58. let result = ''
  59. for (const change of trackedChanges) {
  60. if (isDelete(change.op)) {
  61. // Add the content before the tracked delete
  62. result += content.slice(cursor, change.op.p)
  63. cursor = change.op.p
  64. // Add the content of the tracked delete
  65. result += change.op.d
  66. }
  67. }
  68. // Add the content after all tracked deletes
  69. result += content.slice(cursor)
  70. return result
  71. }
  72. /**
  73. * checks if the given originOrSource should be treated as a source or origin
  74. * TODO: remove this hack and remove all "source" references
  75. */
  76. function extractOriginOrSource(originOrSource) {
  77. let source = null
  78. let origin = null
  79. if (typeof originOrSource === 'string') {
  80. source = originOrSource
  81. } else if (originOrSource && typeof originOrSource === 'object') {
  82. origin = originOrSource
  83. }
  84. return { source, origin }
  85. }
  86. module.exports = {
  87. isInsert,
  88. isDelete,
  89. isComment,
  90. addTrackedDeletesToContent,
  91. getDocLength,
  92. extractOriginOrSource,
  93. }