Utils.js 2.1 KB

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