document-model 6.0.0-staging.3 → 6.0.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 (281) hide show
  1. package/dist/index.d.ts +81 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +229 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/{src/core/node.d.ts → node.d.mts} +25 -23
  6. package/dist/node.d.mts.map +1 -0
  7. package/dist/node.mjs +145 -0
  8. package/dist/node.mjs.map +1 -0
  9. package/package.json +22 -18
  10. package/dist/src/core/actions.d.ts +0 -87
  11. package/dist/src/core/actions.d.ts.map +0 -1
  12. package/dist/src/core/actions.js +0 -187
  13. package/dist/src/core/actions.js.map +0 -1
  14. package/dist/src/core/crypto.d.ts +0 -8
  15. package/dist/src/core/crypto.d.ts.map +0 -1
  16. package/dist/src/core/crypto.js +0 -68
  17. package/dist/src/core/crypto.js.map +0 -1
  18. package/dist/src/core/documents.d.ts +0 -147
  19. package/dist/src/core/documents.d.ts.map +0 -1
  20. package/dist/src/core/documents.js +0 -845
  21. package/dist/src/core/documents.js.map +0 -1
  22. package/dist/src/core/errors.d.ts +0 -21
  23. package/dist/src/core/errors.d.ts.map +0 -1
  24. package/dist/src/core/errors.js +0 -46
  25. package/dist/src/core/errors.js.map +0 -1
  26. package/dist/src/core/files.d.ts +0 -27
  27. package/dist/src/core/files.d.ts.map +0 -1
  28. package/dist/src/core/files.js +0 -90
  29. package/dist/src/core/files.js.map +0 -1
  30. package/dist/src/core/header.d.ts +0 -63
  31. package/dist/src/core/header.d.ts.map +0 -1
  32. package/dist/src/core/header.js +0 -173
  33. package/dist/src/core/header.js.map +0 -1
  34. package/dist/src/core/index.d.ts +0 -15
  35. package/dist/src/core/index.d.ts.map +0 -1
  36. package/dist/src/core/index.js +0 -15
  37. package/dist/src/core/index.js.map +0 -1
  38. package/dist/src/core/logger-types.d.ts +0 -12
  39. package/dist/src/core/logger-types.d.ts.map +0 -1
  40. package/dist/src/core/logger-types.js +0 -2
  41. package/dist/src/core/logger-types.js.map +0 -1
  42. package/dist/src/core/logger.d.ts +0 -27
  43. package/dist/src/core/logger.d.ts.map +0 -1
  44. package/dist/src/core/logger.js +0 -127
  45. package/dist/src/core/logger.js.map +0 -1
  46. package/dist/src/core/node.d.ts.map +0 -1
  47. package/dist/src/core/node.js +0 -155
  48. package/dist/src/core/node.js.map +0 -1
  49. package/dist/src/core/operations.d.ts +0 -50
  50. package/dist/src/core/operations.d.ts.map +0 -1
  51. package/dist/src/core/operations.js +0 -126
  52. package/dist/src/core/operations.js.map +0 -1
  53. package/dist/src/core/ph-types.d.ts +0 -2
  54. package/dist/src/core/ph-types.d.ts.map +0 -1
  55. package/dist/src/core/ph-types.js +0 -2
  56. package/dist/src/core/ph-types.js.map +0 -1
  57. package/dist/src/core/reducer.d.ts +0 -63
  58. package/dist/src/core/reducer.d.ts.map +0 -1
  59. package/dist/src/core/reducer.js +0 -446
  60. package/dist/src/core/reducer.js.map +0 -1
  61. package/dist/src/core/schemas.d.ts +0 -75
  62. package/dist/src/core/schemas.d.ts.map +0 -1
  63. package/dist/src/core/schemas.js +0 -116
  64. package/dist/src/core/schemas.js.map +0 -1
  65. package/dist/src/core/state.d.ts +0 -26
  66. package/dist/src/core/state.d.ts.map +0 -1
  67. package/dist/src/core/state.js +0 -56
  68. package/dist/src/core/state.js.map +0 -1
  69. package/dist/src/core/types.d.ts +0 -2
  70. package/dist/src/core/types.d.ts.map +0 -1
  71. package/dist/src/core/types.js +0 -2
  72. package/dist/src/core/types.js.map +0 -1
  73. package/dist/src/core/utils.d.ts +0 -6
  74. package/dist/src/core/utils.d.ts.map +0 -1
  75. package/dist/src/core/utils.js +0 -15
  76. package/dist/src/core/utils.js.map +0 -1
  77. package/dist/src/core/validation.d.ts +0 -4
  78. package/dist/src/core/validation.d.ts.map +0 -1
  79. package/dist/src/core/validation.js +0 -27
  80. package/dist/src/core/validation.js.map +0 -1
  81. package/dist/src/document-model/actions.d.ts +0 -158
  82. package/dist/src/document-model/actions.d.ts.map +0 -1
  83. package/dist/src/document-model/actions.js +0 -111
  84. package/dist/src/document-model/actions.js.map +0 -1
  85. package/dist/src/document-model/constants.d.ts +0 -6
  86. package/dist/src/document-model/constants.d.ts.map +0 -1
  87. package/dist/src/document-model/constants.js +0 -584
  88. package/dist/src/document-model/constants.js.map +0 -1
  89. package/dist/src/document-model/document-schema.d.ts +0 -69
  90. package/dist/src/document-model/document-schema.d.ts.map +0 -1
  91. package/dist/src/document-model/document-schema.js +0 -43
  92. package/dist/src/document-model/document-schema.js.map +0 -1
  93. package/dist/src/document-model/document-type.d.ts +0 -2
  94. package/dist/src/document-model/document-type.d.ts.map +0 -1
  95. package/dist/src/document-model/document-type.js +0 -2
  96. package/dist/src/document-model/document-type.js.map +0 -1
  97. package/dist/src/document-model/files.d.ts +0 -5
  98. package/dist/src/document-model/files.d.ts.map +0 -1
  99. package/dist/src/document-model/files.js +0 -9
  100. package/dist/src/document-model/files.js.map +0 -1
  101. package/dist/src/document-model/index.d.ts +0 -11
  102. package/dist/src/document-model/index.d.ts.map +0 -1
  103. package/dist/src/document-model/index.js +0 -11
  104. package/dist/src/document-model/index.js.map +0 -1
  105. package/dist/src/document-model/module.d.ts +0 -3
  106. package/dist/src/document-model/module.d.ts.map +0 -1
  107. package/dist/src/document-model/module.js +0 -24
  108. package/dist/src/document-model/module.js.map +0 -1
  109. package/dist/src/document-model/reducers.d.ts +0 -11
  110. package/dist/src/document-model/reducers.d.ts.map +0 -1
  111. package/dist/src/document-model/reducers.js +0 -618
  112. package/dist/src/document-model/reducers.js.map +0 -1
  113. package/dist/src/document-model/schemas.d.ts +0 -189
  114. package/dist/src/document-model/schemas.d.ts.map +0 -1
  115. package/dist/src/document-model/schemas.js +0 -388
  116. package/dist/src/document-model/schemas.js.map +0 -1
  117. package/dist/src/document-model/state.d.ts +0 -15
  118. package/dist/src/document-model/state.d.ts.map +0 -1
  119. package/dist/src/document-model/state.js +0 -75
  120. package/dist/src/document-model/state.js.map +0 -1
  121. package/dist/src/document-model/types.d.ts +0 -584
  122. package/dist/src/document-model/types.d.ts.map +0 -1
  123. package/dist/src/document-model/types.js +0 -2
  124. package/dist/src/document-model/types.js.map +0 -1
  125. package/dist/src/document-model/validation.d.ts +0 -32
  126. package/dist/src/document-model/validation.d.ts.map +0 -1
  127. package/dist/src/document-model/validation.js +0 -166
  128. package/dist/src/document-model/validation.js.map +0 -1
  129. package/dist/src/index.d.ts +0 -6
  130. package/dist/src/index.d.ts.map +0 -1
  131. package/dist/src/index.js +0 -3
  132. package/dist/src/index.js.map +0 -1
  133. package/dist/test/document/crypto.test.d.ts +0 -2
  134. package/dist/test/document/crypto.test.d.ts.map +0 -1
  135. package/dist/test/document/crypto.test.js +0 -192
  136. package/dist/test/document/crypto.test.js.map +0 -1
  137. package/dist/test/document/event-vs-command.test.d.ts +0 -2
  138. package/dist/test/document/event-vs-command.test.d.ts.map +0 -1
  139. package/dist/test/document/event-vs-command.test.js +0 -202
  140. package/dist/test/document/event-vs-command.test.js.map +0 -1
  141. package/dist/test/document/local.test.d.ts +0 -2
  142. package/dist/test/document/local.test.d.ts.map +0 -1
  143. package/dist/test/document/local.test.js +0 -226
  144. package/dist/test/document/local.test.js.map +0 -1
  145. package/dist/test/document/operation-id.test.d.ts +0 -2
  146. package/dist/test/document/operation-id.test.d.ts.map +0 -1
  147. package/dist/test/document/operation-id.test.js +0 -118
  148. package/dist/test/document/operation-id.test.js.map +0 -1
  149. package/dist/test/document/prune.test.d.ts +0 -2
  150. package/dist/test/document/prune.test.d.ts.map +0 -1
  151. package/dist/test/document/prune.test.js +0 -159
  152. package/dist/test/document/prune.test.js.map +0 -1
  153. package/dist/test/document/reducer.test.d.ts +0 -2
  154. package/dist/test/document/reducer.test.d.ts.map +0 -1
  155. package/dist/test/document/reducer.test.js +0 -284
  156. package/dist/test/document/reducer.test.js.map +0 -1
  157. package/dist/test/document/skip-operations.test.d.ts +0 -2
  158. package/dist/test/document/skip-operations.test.d.ts.map +0 -1
  159. package/dist/test/document/skip-operations.test.js +0 -495
  160. package/dist/test/document/skip-operations.test.js.map +0 -1
  161. package/dist/test/document/undo-redo-v2.test.d.ts +0 -2
  162. package/dist/test/document/undo-redo-v2.test.d.ts.map +0 -1
  163. package/dist/test/document/undo-redo-v2.test.js +0 -207
  164. package/dist/test/document/undo-redo-v2.test.js.map +0 -1
  165. package/dist/test/document/undo-redo.test.d.ts +0 -2
  166. package/dist/test/document/undo-redo.test.d.ts.map +0 -1
  167. package/dist/test/document/undo-redo.test.js +0 -413
  168. package/dist/test/document/undo-redo.test.js.map +0 -1
  169. package/dist/test/document/utils.test.d.ts +0 -2
  170. package/dist/test/document/utils.test.d.ts.map +0 -1
  171. package/dist/test/document/utils.test.js +0 -172
  172. package/dist/test/document/utils.test.js.map +0 -1
  173. package/dist/test/document-helpers/addUndo.test.d.ts +0 -2
  174. package/dist/test/document-helpers/addUndo.test.d.ts.map +0 -1
  175. package/dist/test/document-helpers/addUndo.test.js +0 -120
  176. package/dist/test/document-helpers/addUndo.test.js.map +0 -1
  177. package/dist/test/document-helpers/attachBranch.test.d.ts +0 -2
  178. package/dist/test/document-helpers/attachBranch.test.d.ts.map +0 -1
  179. package/dist/test/document-helpers/attachBranch.test.js +0 -364
  180. package/dist/test/document-helpers/attachBranch.test.js.map +0 -1
  181. package/dist/test/document-helpers/checkCleanedOperationsIntegrity.test.d.ts +0 -2
  182. package/dist/test/document-helpers/checkCleanedOperationsIntegrity.test.d.ts.map +0 -1
  183. package/dist/test/document-helpers/checkCleanedOperationsIntegrity.test.js +0 -252
  184. package/dist/test/document-helpers/checkCleanedOperationsIntegrity.test.js.map +0 -1
  185. package/dist/test/document-helpers/conflictResolution.test.d.ts +0 -2
  186. package/dist/test/document-helpers/conflictResolution.test.d.ts.map +0 -1
  187. package/dist/test/document-helpers/conflictResolution.test.js +0 -109
  188. package/dist/test/document-helpers/conflictResolution.test.js.map +0 -1
  189. package/dist/test/document-helpers/filterDuplicatedOperations.test.d.ts +0 -2
  190. package/dist/test/document-helpers/filterDuplicatedOperations.test.d.ts.map +0 -1
  191. package/dist/test/document-helpers/filterDuplicatedOperations.test.js +0 -126
  192. package/dist/test/document-helpers/filterDuplicatedOperations.test.js.map +0 -1
  193. package/dist/test/document-helpers/garbageCollect.test.d.ts +0 -2
  194. package/dist/test/document-helpers/garbageCollect.test.d.ts.map +0 -1
  195. package/dist/test/document-helpers/garbageCollect.test.js +0 -136
  196. package/dist/test/document-helpers/garbageCollect.test.js.map +0 -1
  197. package/dist/test/document-helpers/groupOperationsByScope.test.d.ts +0 -2
  198. package/dist/test/document-helpers/groupOperationsByScope.test.d.ts.map +0 -1
  199. package/dist/test/document-helpers/groupOperationsByScope.test.js +0 -102
  200. package/dist/test/document-helpers/groupOperationsByScope.test.js.map +0 -1
  201. package/dist/test/document-helpers/headerRevision.test.d.ts +0 -2
  202. package/dist/test/document-helpers/headerRevision.test.d.ts.map +0 -1
  203. package/dist/test/document-helpers/headerRevision.test.js +0 -203
  204. package/dist/test/document-helpers/headerRevision.test.js.map +0 -1
  205. package/dist/test/document-helpers/merge.test.d.ts +0 -2
  206. package/dist/test/document-helpers/merge.test.d.ts.map +0 -1
  207. package/dist/test/document-helpers/merge.test.js +0 -906
  208. package/dist/test/document-helpers/merge.test.js.map +0 -1
  209. package/dist/test/document-helpers/nextSkipNumber.test.d.ts +0 -2
  210. package/dist/test/document-helpers/nextSkipNumber.test.d.ts.map +0 -1
  211. package/dist/test/document-helpers/nextSkipNumber.test.js +0 -135
  212. package/dist/test/document-helpers/nextSkipNumber.test.js.map +0 -1
  213. package/dist/test/document-helpers/prepareOperations.test.d.ts +0 -2
  214. package/dist/test/document-helpers/prepareOperations.test.d.ts.map +0 -1
  215. package/dist/test/document-helpers/prepareOperations.test.js +0 -304
  216. package/dist/test/document-helpers/prepareOperations.test.js.map +0 -1
  217. package/dist/test/document-helpers/removeExistingOperations.test.d.ts +0 -2
  218. package/dist/test/document-helpers/removeExistingOperations.test.d.ts.map +0 -1
  219. package/dist/test/document-helpers/removeExistingOperations.test.js +0 -177
  220. package/dist/test/document-helpers/removeExistingOperations.test.js.map +0 -1
  221. package/dist/test/document-helpers/reshuffleByTimestamp.test.d.ts +0 -2
  222. package/dist/test/document-helpers/reshuffleByTimestamp.test.d.ts.map +0 -1
  223. package/dist/test/document-helpers/reshuffleByTimestamp.test.js +0 -148
  224. package/dist/test/document-helpers/reshuffleByTimestamp.test.js.map +0 -1
  225. package/dist/test/document-helpers/reshuffleByTimestampAndIndex.test.d.ts +0 -2
  226. package/dist/test/document-helpers/reshuffleByTimestampAndIndex.test.d.ts.map +0 -1
  227. package/dist/test/document-helpers/reshuffleByTimestampAndIndex.test.js +0 -200
  228. package/dist/test/document-helpers/reshuffleByTimestampAndIndex.test.js.map +0 -1
  229. package/dist/test/document-helpers/skipHeaderOperations.test.d.ts +0 -2
  230. package/dist/test/document-helpers/skipHeaderOperations.test.d.ts.map +0 -1
  231. package/dist/test/document-helpers/skipHeaderOperations.test.js +0 -72
  232. package/dist/test/document-helpers/skipHeaderOperations.test.js.map +0 -1
  233. package/dist/test/document-helpers/sortOperations.test.d.ts +0 -2
  234. package/dist/test/document-helpers/sortOperations.test.d.ts.map +0 -1
  235. package/dist/test/document-helpers/sortOperations.test.js +0 -101
  236. package/dist/test/document-helpers/sortOperations.test.js.map +0 -1
  237. package/dist/test/document-helpers/split.test.d.ts +0 -2
  238. package/dist/test/document-helpers/split.test.d.ts.map +0 -1
  239. package/dist/test/document-helpers/split.test.js +0 -121
  240. package/dist/test/document-helpers/split.test.js.map +0 -1
  241. package/dist/test/document-helpers/utils.d.ts +0 -15
  242. package/dist/test/document-helpers/utils.d.ts.map +0 -1
  243. package/dist/test/document-helpers/utils.js +0 -61
  244. package/dist/test/document-helpers/utils.js.map +0 -1
  245. package/dist/test/document-model/replay.test.d.ts +0 -2
  246. package/dist/test/document-model/replay.test.d.ts.map +0 -1
  247. package/dist/test/document-model/replay.test.js +0 -139
  248. package/dist/test/document-model/replay.test.js.map +0 -1
  249. package/dist/test/document-model/skip-operations.test.d.ts +0 -2
  250. package/dist/test/document-model/skip-operations.test.d.ts.map +0 -1
  251. package/dist/test/document-model/skip-operations.test.js +0 -214
  252. package/dist/test/document-model/skip-operations.test.js.map +0 -1
  253. package/dist/test/document-model/validation.test.d.ts +0 -2
  254. package/dist/test/document-model/validation.test.d.ts.map +0 -1
  255. package/dist/test/document-model/validation.test.js +0 -451
  256. package/dist/test/document-model/validation.test.js.map +0 -1
  257. package/dist/test/document-model/versioning.test.d.ts +0 -2
  258. package/dist/test/document-model/versioning.test.d.ts.map +0 -1
  259. package/dist/test/document-model/versioning.test.js +0 -93
  260. package/dist/test/document-model/versioning.test.js.map +0 -1
  261. package/dist/test/document-model/zip.test.d.ts +0 -2
  262. package/dist/test/document-model/zip.test.d.ts.map +0 -1
  263. package/dist/test/document-model/zip.test.js +0 -79
  264. package/dist/test/document-model/zip.test.js.map +0 -1
  265. package/dist/test/helpers.d.ts +0 -79
  266. package/dist/test/helpers.d.ts.map +0 -1
  267. package/dist/test/helpers.js +0 -121
  268. package/dist/test/helpers.js.map +0 -1
  269. package/dist/test/index.d.ts +0 -4
  270. package/dist/test/index.d.ts.map +0 -1
  271. package/dist/test/index.js +0 -3
  272. package/dist/test/index.js.map +0 -1
  273. package/dist/test/types.d.ts +0 -6
  274. package/dist/test/types.d.ts.map +0 -1
  275. package/dist/test/types.js +0 -2
  276. package/dist/test/types.js.map +0 -1
  277. package/dist/tsconfig.tsbuildinfo +0 -1
  278. package/dist/vitest.config.d.ts +0 -3
  279. package/dist/vitest.config.d.ts.map +0 -1
  280. package/dist/vitest.config.js +0 -7
  281. package/dist/vitest.config.js.map +0 -1
@@ -1,207 +0,0 @@
1
- import { baseCreateDocument, processUndoRedo, undo } from "document-model/core";
2
- import { countReducer, createCountDocumentState, increment, testCreateBaseState, } from "document-model/test";
3
- import { beforeEach, describe, expect, it } from "vitest";
4
- describe("UNDO/REDO with protocolVersion: 2", () => {
5
- let document;
6
- beforeEach(() => {
7
- const initialState = testCreateBaseState({ count: 0 }, { name: "" });
8
- document = baseCreateDocument(createCountDocumentState, initialState);
9
- document = countReducer(document, increment());
10
- document = countReducer(document, increment());
11
- document = countReducer(document, increment());
12
- });
13
- describe("processUndoRedo with protocolVersion: 2", () => {
14
- it("should return reuseLastOperationIndex: false", () => {
15
- const undoAction = undo();
16
- const result = processUndoRedo(document, undoAction, 0, 2);
17
- expect(result.reuseLastOperationIndex).toBe(false);
18
- });
19
- it("should always return skip=1 for v2", () => {
20
- const undoAction = undo();
21
- const result = processUndoRedo(document, undoAction, 0, 2);
22
- expect(result.skip).toBe(1);
23
- expect(result.action.type).toBe("NOOP");
24
- });
25
- it("should always return reuseLastOperationIndex: false even after NOOP", () => {
26
- document = countReducer(document, undo());
27
- const undoAction = undo();
28
- const result = processUndoRedo(document, undoAction, 0, 2);
29
- expect(result.reuseLastOperationIndex).toBe(false);
30
- });
31
- });
32
- describe("comparison: protocolVersion 1 vs 2", () => {
33
- it("protocolVersion 1 allows index reuse after NOOP", () => {
34
- document = countReducer(document, undo());
35
- const undoAction = undo();
36
- const resultV1 = processUndoRedo(document, undoAction, 0, 1);
37
- expect(resultV1.reuseLastOperationIndex).toBe(true);
38
- });
39
- it("protocolVersion 2 never allows index reuse", () => {
40
- document = countReducer(document, undo());
41
- const undoAction = undo();
42
- const resultV2 = processUndoRedo(document, undoAction, 0, 2);
43
- expect(resultV2.reuseLastOperationIndex).toBe(false);
44
- });
45
- });
46
- describe("end-to-end with protocolVersion: 2 in reducer", () => {
47
- it("should create NOOP operations with correct skip value", () => {
48
- document = countReducer(document, undo(), undefined, {
49
- protocolVersion: 2,
50
- });
51
- const ops = document.operations.global;
52
- const lastOp = ops[ops.length - 1];
53
- expect(lastOp.action.type).toBe("NOOP");
54
- expect(lastOp.skip).toBe(1);
55
- expect(lastOp.index).toBe(3);
56
- });
57
- it("protocolVersion 2 always creates NOOPs with skip=1", () => {
58
- document = countReducer(document, undo(), undefined, {
59
- protocolVersion: 2,
60
- });
61
- const ops = document.operations.global;
62
- const noopOp = ops.find((op) => op.action.type === "NOOP");
63
- expect(noopOp).toBeDefined();
64
- expect(noopOp.skip).toBe(1);
65
- });
66
- it("should correctly undo state with protocolVersion 2", () => {
67
- expect(document.state.global.count).toBe(3);
68
- document = countReducer(document, undo(), undefined, {
69
- protocolVersion: 2,
70
- });
71
- expect(document.state.global.count).toBe(2);
72
- });
73
- it("consecutive undos should all have skip=1 and incrementing indices", () => {
74
- // First undo
75
- document = countReducer(document, undo(), undefined, {
76
- protocolVersion: 2,
77
- });
78
- const ops1 = document.operations.global;
79
- const noop1 = ops1[ops1.length - 1];
80
- expect(noop1.action.type).toBe("NOOP");
81
- expect(noop1.skip).toBe(1);
82
- expect(noop1.index).toBe(3);
83
- expect(document.state.global.count).toBe(2);
84
- // Second undo
85
- document = countReducer(document, undo(), undefined, {
86
- protocolVersion: 2,
87
- });
88
- const ops2 = document.operations.global;
89
- const noop2 = ops2[ops2.length - 1];
90
- expect(noop2.action.type).toBe("NOOP");
91
- expect(noop2.skip).toBe(1);
92
- expect(noop2.index).toBe(4); // Should increment, not reuse
93
- expect(document.state.global.count).toBe(1);
94
- // Third undo
95
- document = countReducer(document, undo(), undefined, {
96
- protocolVersion: 2,
97
- });
98
- const ops3 = document.operations.global;
99
- const noop3 = ops3[ops3.length - 1];
100
- expect(noop3.action.type).toBe("NOOP");
101
- expect(noop3.skip).toBe(1);
102
- expect(noop3.index).toBe(5); // Should increment, not reuse
103
- expect(document.state.global.count).toBe(0);
104
- });
105
- it("should throw when trying to undo more than available", () => {
106
- // Undo all 3 increments
107
- document = countReducer(document, undo(), undefined, {
108
- protocolVersion: 2,
109
- });
110
- document = countReducer(document, undo(), undefined, {
111
- protocolVersion: 2,
112
- });
113
- document = countReducer(document, undo(), undefined, {
114
- protocolVersion: 2,
115
- });
116
- expect(document.state.global.count).toBe(0);
117
- // Try to undo when there's nothing left
118
- expect(() => countReducer(document, undo(), undefined, {
119
- protocolVersion: 2,
120
- })).toThrow("Cannot undo: no more operations to undo in scope history");
121
- });
122
- it("operations list should preserve all operations including NOOPs", () => {
123
- document = countReducer(document, undo(), undefined, {
124
- protocolVersion: 2,
125
- });
126
- document = countReducer(document, undo(), undefined, {
127
- protocolVersion: 2,
128
- });
129
- const ops = document.operations.global;
130
- // Should have: 3 increments + 2 NOOPs = 5 operations
131
- expect(ops.length).toBe(5);
132
- expect(ops.map((op) => op.action.type)).toEqual([
133
- "INCREMENT",
134
- "INCREMENT",
135
- "INCREMENT",
136
- "NOOP",
137
- "NOOP",
138
- ]);
139
- expect(ops.map((op) => op.index)).toEqual([0, 1, 2, 3, 4]);
140
- });
141
- it("should handle undo after new operations added following undos (gapped indices)", () => {
142
- // This test reproduces the bug where undo fails after:
143
- // 1. Multiple undos create NOOPs
144
- // 2. New operations are added after the undos
145
- // 3. Undo is triggered again
146
- //
147
- // The issue is that garbageCollectV2 creates a set of effective operations
148
- // with gaps in indices (e.g., [0, 5, 6] instead of [0, 1, 2, 3, 4, 5, 6])
149
- // and the state rebuild fails due to index validation.
150
- // Initial state: count = 3 with operations [0: INC, 1: INC, 2: INC]
151
- expect(document.state.global.count).toBe(3);
152
- // Undo twice: count = 1
153
- // Operations: [0: INC, 1: INC, 2: INC, 3: NOOP(skip=1), 4: NOOP(skip=1)]
154
- document = countReducer(document, undo(), undefined, {
155
- protocolVersion: 2,
156
- });
157
- document = countReducer(document, undo(), undefined, {
158
- protocolVersion: 2,
159
- });
160
- expect(document.state.global.count).toBe(1);
161
- // Add new operations after undos: count = 3
162
- // Operations: [0: INC, 1: INC, 2: INC, 3: NOOP, 4: NOOP, 5: INC, 6: INC]
163
- document = countReducer(document, increment(), undefined, {
164
- protocolVersion: 2,
165
- });
166
- document = countReducer(document, increment(), undefined, {
167
- protocolVersion: 2,
168
- });
169
- expect(document.state.global.count).toBe(3);
170
- const opsBeforeUndo = document.operations.global;
171
- expect(opsBeforeUndo.map((op) => op.action.type)).toEqual([
172
- "INCREMENT",
173
- "INCREMENT",
174
- "INCREMENT",
175
- "NOOP",
176
- "NOOP",
177
- "INCREMENT",
178
- "INCREMENT",
179
- ]);
180
- expect(opsBeforeUndo.map((op) => op.index)).toEqual([
181
- 0, 1, 2, 3, 4, 5, 6,
182
- ]);
183
- // Now undo - this is where the bug occurs
184
- // garbageCollectV2 will return effective operations with gapped indices
185
- // (operations 1, 2 are "undone" by NOOPs at 3, 4)
186
- // Effective non-NOOP ops: indices [0, 5, 6] - there's a gap!
187
- document = countReducer(document, undo(), undefined, {
188
- protocolVersion: 2,
189
- });
190
- // Should have undone the last increment
191
- expect(document.state.global.count).toBe(2);
192
- const opsAfterUndo = document.operations.global;
193
- expect(opsAfterUndo.length).toBe(8);
194
- expect(opsAfterUndo.map((op) => op.action.type)).toEqual([
195
- "INCREMENT",
196
- "INCREMENT",
197
- "INCREMENT",
198
- "NOOP",
199
- "NOOP",
200
- "INCREMENT",
201
- "INCREMENT",
202
- "NOOP",
203
- ]);
204
- });
205
- });
206
- });
207
- //# sourceMappingURL=undo-redo-v2.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"undo-redo-v2.test.js","sourceRoot":"","sources":["../../../test/document/undo-redo-v2.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=undo-redo.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"undo-redo.test.d.ts","sourceRoot":"","sources":["../../../test/document/undo-redo.test.ts"],"names":[],"mappings":""}
@@ -1,413 +0,0 @@
1
- import { baseCreateDocument, deriveOperationId, noop, processUndoRedo, redo, undo, } from "document-model/core";
2
- import { countReducer, createCountDocumentState, increment, testCreateBaseState, } from "document-model/test";
3
- import { beforeEach, describe, expect, it } from "vitest";
4
- describe("UNDO/REDO", () => {
5
- let document;
6
- beforeEach(() => {
7
- const initialState = testCreateBaseState({ count: 0 }, { name: "" });
8
- document = baseCreateDocument(createCountDocumentState, initialState);
9
- document = countReducer(document, increment());
10
- document = countReducer(document, increment());
11
- document = countReducer(document, increment());
12
- document = countReducer(document, increment());
13
- document = countReducer(document, increment());
14
- });
15
- describe("processUndoRedo -> UNDO", () => {
16
- it("should return a NOOP action when an UNDO action is dispatched", () => {
17
- const skip = 0;
18
- const undoAction = undo();
19
- const result = processUndoRedo(document, undoAction, skip);
20
- expect(result.action.type).toBe("NOOP");
21
- });
22
- it("should return skip = undo value if there's no skip value passed to the reducer", () => {
23
- const skip = 0;
24
- const undoAction = undo();
25
- const result = processUndoRedo(document, undoAction, skip);
26
- expect(result.skip).toBe(1);
27
- expect(result.action.type).toBe("NOOP");
28
- });
29
- it("should return skip = undo value + previous NOOP skip value, when latest action is NOOP with skip > 0", () => {
30
- const skip = 0;
31
- const undoAction = undo();
32
- document = countReducer(document, noop(), undefined, {
33
- skip: 3,
34
- ignoreSkipOperations: true,
35
- });
36
- const result = processUndoRedo(document, undoAction, skip);
37
- expect(result.skip).toBe(4);
38
- expect(result.action.type).toBe("NOOP");
39
- });
40
- it("should NOT remove latest operation if !== NOOP", () => {
41
- const skip = 0;
42
- const undoAction = undo();
43
- const result = processUndoRedo(document, undoAction, skip);
44
- expect(result.skip).toBe(1);
45
- expect(result.document.operations.global.length).toBe(5);
46
- expect(result.document.operations.global[4].action.type).toBe("INCREMENT");
47
- });
48
- it("should NOT remove latest operation if is a NOOP with skip = 0", () => {
49
- const skip = 0;
50
- const undoAction = undo();
51
- document = countReducer(document, noop(), undefined, {
52
- skip: 0,
53
- ignoreSkipOperations: true,
54
- });
55
- const result = processUndoRedo(document, undoAction, skip);
56
- expect(result.skip).toBe(1);
57
- expect(result.document.operations.global.length).toBe(6);
58
- expect(result.document.operations.global[5].action.type).toBe("NOOP");
59
- });
60
- it("should throw an error if you try to undone more operations than the ones available", () => {
61
- const initialState = testCreateBaseState({ count: 0 }, { name: "" });
62
- document = baseCreateDocument(createCountDocumentState, initialState);
63
- const skip = 0;
64
- const undoAction = undo();
65
- const throwErrorFunc = () => processUndoRedo(document, undoAction, skip);
66
- expect(throwErrorFunc).toThrow("Cannot undo: you can't undo more operations than the ones in the scope history");
67
- });
68
- });
69
- describe("processUndoRedo -> REDO", () => {
70
- it("should throw an error when there's no operation to redo in the clipboard", () => {
71
- const initialState = testCreateBaseState({ count: 0 }, { name: "" });
72
- document = baseCreateDocument(createCountDocumentState, initialState);
73
- const skip = 0;
74
- const redoAction = redo();
75
- const throwErrorFunc = () => processUndoRedo(document, redoAction, skip);
76
- expect(throwErrorFunc).toThrow("Cannot redo: no operations in the clipboard");
77
- });
78
- it("should throw an error if you try to redo more than 1 operation", () => {
79
- const skip = 0;
80
- const redoAction = redo(2);
81
- const throwErrorFunc = () => processUndoRedo(document, redoAction, skip);
82
- expect(throwErrorFunc).toThrow("Cannot redo: you can only redo one operation at a time");
83
- });
84
- it("should throw an error if you try to redo with an skip value", () => {
85
- const skip = 1;
86
- const redoAction = redo(1);
87
- const throwErrorFunc = () => processUndoRedo(document, redoAction, skip);
88
- expect(throwErrorFunc).toThrow("Cannot redo: skip value from reducer cannot be used with REDO action");
89
- });
90
- it("should throw an error if there's no operations for the scope in the clipboard", () => {
91
- const skip = 0;
92
- const redoAction = redo(1, "local");
93
- document = countReducer(document, undo(1));
94
- const throwErrorFunc = () => processUndoRedo(document, redoAction, skip);
95
- expect(throwErrorFunc).toThrow('Cannot redo: no operations in clipboard for scope "local"');
96
- });
97
- it("should transform REDO action into the latest valid action stored in the clipboard", () => {
98
- const skip = 0;
99
- const redoAction = redo(1);
100
- document = countReducer(document, undo(1));
101
- const result = processUndoRedo(document, redoAction, skip);
102
- expect(result.action.type).toBe("INCREMENT");
103
- expect(result.action.scope).toBe("global");
104
- expect(result.action.input).toStrictEqual({});
105
- });
106
- it("should remove the latest valid action from the clipboard", () => {
107
- const skip = 0;
108
- const redoAction = redo(1);
109
- document = countReducer(document, undo(1));
110
- expect(document.clipboard.length).toBe(1);
111
- const result = processUndoRedo(document, redoAction, skip);
112
- expect(result.document.clipboard.length).toBe(0);
113
- });
114
- });
115
- describe("UNDO", () => {
116
- it("should undo operations", () => {
117
- document = countReducer(document, undo(1));
118
- expect(document.header.revision.global).toBe(6);
119
- expect(document.state.global.count).toBe(4);
120
- expect(document.clipboard.length).toBe(1);
121
- expect(document.clipboard[0].action.type).toBe("INCREMENT");
122
- expect(document.clipboard[0].index).toBe(4);
123
- expect(document.operations.global.length).toBe(5);
124
- expect(document.operations.global[4]).toMatchObject({
125
- type: "NOOP",
126
- index: 5,
127
- skip: 1,
128
- });
129
- expect(document.operations.global[3]).toMatchObject({
130
- type: "INCREMENT",
131
- index: 3,
132
- skip: 0,
133
- });
134
- expect(document.operations.global[2]).toMatchObject({
135
- type: "INCREMENT",
136
- index: 2,
137
- skip: 0,
138
- });
139
- });
140
- it("should increase skip value of a previous undo Operation", () => {
141
- document = countReducer(document, undo());
142
- document = countReducer(document, undo());
143
- document = countReducer(document, undo());
144
- expect(document.header.revision.global).toBe(6);
145
- expect(document.state.global.count).toBe(2);
146
- expect(document.clipboard.length).toBe(3);
147
- expect(document.clipboard[0].action.type).toBe("INCREMENT");
148
- expect(document.clipboard[0].index).toBe(4);
149
- expect(document.clipboard[1].action.type).toBe("INCREMENT");
150
- expect(document.clipboard[1].index).toBe(3);
151
- expect(document.clipboard[2].action.type).toBe("INCREMENT");
152
- expect(document.clipboard[2].index).toBe(2);
153
- expect(document.operations.global.length).toBe(3);
154
- expect(document.operations.global[2]).toMatchObject({
155
- type: "NOOP",
156
- index: 5,
157
- skip: 3,
158
- });
159
- expect(document.operations.global[1]).toMatchObject({
160
- type: "INCREMENT",
161
- index: 1,
162
- skip: 0,
163
- });
164
- expect(document.operations.global[0]).toMatchObject({
165
- type: "INCREMENT",
166
- index: 0,
167
- skip: 0,
168
- });
169
- });
170
- it("should undo the latest valid operation if undo overlaps with a previous undo operation", () => {
171
- document = countReducer(document, undo());
172
- document = countReducer(document, undo());
173
- document = countReducer(document, undo());
174
- document = countReducer(document, increment());
175
- document = countReducer(document, increment());
176
- document = countReducer(document, undo());
177
- document = countReducer(document, undo());
178
- document = countReducer(document, undo());
179
- expect(document.header.revision.global).toBe(9);
180
- expect(document.state.global.count).toBe(1);
181
- expect(document.clipboard.length).toBe(3);
182
- expect(document.clipboard[0].action.type).toBe("INCREMENT");
183
- expect(document.clipboard[0].index).toBe(7);
184
- expect(document.clipboard[1].action.type).toBe("INCREMENT");
185
- expect(document.clipboard[1].index).toBe(6);
186
- expect(document.clipboard[2].action.type).toBe("INCREMENT");
187
- expect(document.clipboard[2].index).toBe(1);
188
- expect(document.operations.global.length).toBe(2);
189
- expect(document.operations.global).toMatchObject([
190
- {
191
- type: "INCREMENT",
192
- index: 0,
193
- skip: 0,
194
- },
195
- {
196
- type: "NOOP",
197
- index: 8,
198
- skip: 7,
199
- },
200
- ]);
201
- });
202
- it("should undo the latest valid operation if undo overlaps with 2 previous undo operations", () => {
203
- document = countReducer(document, undo());
204
- document = countReducer(document, increment());
205
- document = countReducer(document, undo());
206
- document = countReducer(document, undo());
207
- document = countReducer(document, increment());
208
- document = countReducer(document, undo());
209
- document = countReducer(document, undo());
210
- expect(document.header.revision.global).toBe(10);
211
- expect(document.state.global.count).toBe(2);
212
- expect(document.clipboard.length).toBe(2);
213
- expect(document.clipboard[0].action.type).toBe("INCREMENT");
214
- expect(document.clipboard[0].index).toBe(8);
215
- expect(document.clipboard[1].action.type).toBe("INCREMENT");
216
- expect(document.clipboard[1].index).toBe(2);
217
- expect(document.operations.global.length).toBe(3);
218
- expect(document.operations.global).toMatchObject([
219
- {
220
- type: "INCREMENT",
221
- index: 0,
222
- skip: 0,
223
- },
224
- {
225
- type: "INCREMENT",
226
- index: 1,
227
- skip: 0,
228
- },
229
- {
230
- type: "NOOP",
231
- index: 9,
232
- skip: 7,
233
- },
234
- ]);
235
- });
236
- });
237
- describe("REDO", () => {
238
- it("should redo the latest operation", () => {
239
- document = countReducer(document, undo());
240
- document = countReducer(document, undo());
241
- document = countReducer(document, redo());
242
- expect(document.header.revision.global).toBe(7);
243
- expect(document.state.global.count).toBe(4);
244
- expect(document.operations.global.length).toBe(5);
245
- expect(document.clipboard.length).toBe(1);
246
- expect(document.operations.global[4]).toMatchObject({
247
- type: "INCREMENT",
248
- index: 6,
249
- });
250
- });
251
- it("should revert document state to the latest state before applying an undo", () => {
252
- document = countReducer(document, undo());
253
- document = countReducer(document, undo());
254
- document = countReducer(document, redo());
255
- document = countReducer(document, redo());
256
- expect(document.header.revision.global).toBe(8);
257
- expect(document.state.global.count).toBe(5);
258
- expect(document.operations.global.length).toBe(6);
259
- expect(document.clipboard.length).toBe(0);
260
- expect(document.operations.global[5]).toMatchObject({
261
- type: "INCREMENT",
262
- index: 7,
263
- skip: 0,
264
- });
265
- expect(document.operations.global[4]).toMatchObject({
266
- type: "INCREMENT",
267
- index: 6,
268
- skip: 0,
269
- });
270
- expect(document.operations.global[3]).toMatchObject({
271
- type: "NOOP",
272
- index: 5,
273
- skip: 2,
274
- });
275
- expect(document.operations.global[2]).toMatchObject({
276
- type: "INCREMENT",
277
- index: 2,
278
- skip: 0,
279
- });
280
- expect(document.operations.global[1]).toMatchObject({
281
- type: "INCREMENT",
282
- index: 1,
283
- skip: 0,
284
- });
285
- expect(document.operations.global[0]).toMatchObject({
286
- type: "INCREMENT",
287
- index: 0,
288
- skip: 0,
289
- });
290
- });
291
- it("should clean clipboard after applying an action that's not UNDO/REDO", () => {
292
- document = countReducer(document, undo());
293
- document = countReducer(document, undo());
294
- document = countReducer(document, increment());
295
- expect(document.header.revision.global).toBe(7);
296
- expect(document.state.global.count).toBe(4);
297
- expect(document.operations.global.length).toBe(5);
298
- expect(document.clipboard.length).toBe(0);
299
- });
300
- });
301
- describe("NOOP operations", () => {
302
- it("should apply NOOP operations", () => {
303
- const op = {
304
- // using a fixed id, even though Action ids and Operation ids are different
305
- id: "noop-1",
306
- timestampUtcMs: new Date().toISOString(),
307
- input: {},
308
- type: "NOOP",
309
- skip: 1,
310
- index: 5,
311
- scope: "global",
312
- hash: "Ki38EB6gkUcnU3ceRsc88njPo3U=",
313
- };
314
- document = countReducer(document, op, undefined, {
315
- skip: 1,
316
- });
317
- expect(document.header.revision.global).toBe(6);
318
- expect(document.state.global.count).toBe(4);
319
- expect(document.operations.global.length).toBe(5);
320
- expect(document.operations.global[4]).toMatchObject({
321
- type: "NOOP",
322
- index: 5,
323
- skip: 1,
324
- });
325
- });
326
- it("should replace previous noop operation and update skip number when a new noop is dispatched after another one", () => {
327
- const baseAction = {
328
- id: "noop-2",
329
- timestampUtcMs: new Date().toISOString(),
330
- input: {},
331
- type: "NOOP",
332
- scope: "global",
333
- };
334
- const baseOperation = {
335
- id: undefined,
336
- skip: 0,
337
- index: 5,
338
- hash: "Ki38EB6gkUcnU3ceRsc88njPo3U=",
339
- timestampUtcMs: new Date().toISOString(),
340
- action: baseAction,
341
- };
342
- const action1 = { ...baseAction, id: "noop-1" };
343
- const action2 = { ...baseAction, id: "noop-2" };
344
- const action3 = { ...baseAction, id: "noop-3" };
345
- const op1 = {
346
- ...baseOperation,
347
- id: deriveOperationId(document.header.id, "global", "main", action1.id),
348
- skip: 1,
349
- action: action1,
350
- };
351
- const op2 = {
352
- ...baseOperation,
353
- id: deriveOperationId(document.header.id, "global", "main", action2.id),
354
- skip: 2,
355
- action: action2,
356
- };
357
- const op3 = {
358
- ...baseOperation,
359
- id: deriveOperationId(document.header.id, "global", "main", action3.id),
360
- skip: 3,
361
- action: action3,
362
- };
363
- document = countReducer(document, action1, undefined, {
364
- pruneOnSkip: true,
365
- skip: 1,
366
- replayOptions: {
367
- operation: op1,
368
- },
369
- });
370
- document = countReducer(document, action2, undefined, {
371
- pruneOnSkip: true,
372
- skip: 2,
373
- replayOptions: {
374
- operation: op2,
375
- },
376
- });
377
- document = countReducer(document, action3, undefined, {
378
- pruneOnSkip: true,
379
- skip: 3,
380
- replayOptions: {
381
- operation: op3,
382
- },
383
- });
384
- expect(document.header.revision.global).toBe(6);
385
- expect(document.state.global.count).toBe(2);
386
- expect(document.operations.global.length).toBe(3);
387
- expect(document.operations.global[2]).toMatchObject({
388
- index: 5,
389
- skip: 3,
390
- });
391
- expect(document.operations.global[2].action).toMatchObject({
392
- type: "NOOP",
393
- });
394
- });
395
- it("NOOP operation should not add skipped operation to the clipboard", () => {
396
- const op = {
397
- id: "noop-3",
398
- input: {},
399
- type: "NOOP",
400
- skip: 1,
401
- index: 5,
402
- scope: "global",
403
- hash: "Ki38EB6gkUcnU3ceRsc88njPo3U=",
404
- timestampUtcMs: new Date().toISOString(),
405
- };
406
- document = countReducer(document, op, undefined, {
407
- skip: 1,
408
- });
409
- expect(document.clipboard.length).toBe(0);
410
- });
411
- });
412
- });
413
- //# sourceMappingURL=undo-redo.test.js.map