From 66300a90c3f23d707ddc983bbe14c4b340fdea5a Mon Sep 17 00:00:00 2001 From: Alex Good Date: Tue, 27 Jun 2023 14:57:17 +0100 Subject: [PATCH] update to 2.1.0-alpha.7 and add a test --- .gitignore | 1 + package.json | 2 +- src/PatchSemaphore.ts | 14 +------------- test/DocHandle.ts | 17 ++++++++++++----- test/Editor.cy.tsx | 31 +++++++++++++++++++++++++++---- test/Editor.tsx | 3 ++- yarn.lock | 18 +++++++++--------- 7 files changed, 53 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 6248e16..c672490 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules yarn-error.log dist/ +cypress/videos diff --git a/package.json b/package.json index 25960ed..81365d7 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "dist/**/*.js" ], "dependencies": { - "@automerge/automerge": "^2.1.0-alpha.5", + "@automerge/automerge": "^2.1.0-alpha.7", "@codemirror/state": "^6.2.1", "@codemirror/view": "^6.13.2", "automerge-repo": "^0.1.0", diff --git a/src/PatchSemaphore.ts b/src/PatchSemaphore.ts index 36c4f1f..7a478c9 100644 --- a/src/PatchSemaphore.ts +++ b/src/PatchSemaphore.ts @@ -38,9 +38,7 @@ export class PatchSemaphore { this._inReconcile = true const path = getPath(view.state, this._field) - const remoteHeads = automerge.getHeads(doc) const oldHeads = getLastHeads(view.state, this._field) - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion let selection = view.state.selection const transactions = view.state @@ -59,16 +57,12 @@ export class PatchSemaphore { } // now apply the unreconciled transactions to the document - let newHeads = codeMirrorToAm( + const newHeads = codeMirrorToAm( this._field, change, transactions, view.state ) - if (headsEqual(oldHeads, newHeads)) { - // No changes were made, so we're just applying remote changes - newHeads = remoteHeads - } // now get the diff between the updated state of the document and the heads // and apply that to the codemirror doc @@ -84,9 +78,3 @@ export class PatchSemaphore { } } } - -function headsEqual(a: Heads, b: Heads): boolean { - return ( - a.length == b.length && a.every(head => b.some(other => head === other)) - ) -} diff --git a/test/DocHandle.ts b/test/DocHandle.ts index ba5913b..33c8424 100644 --- a/test/DocHandle.ts +++ b/test/DocHandle.ts @@ -3,7 +3,8 @@ import { unstable as automerge, getHeads, Heads } from "@automerge/automerge" export type PatchListener = ( // eslint-disable-next-line @typescript-eslint/no-explicit-any doc: automerge.Doc, - patches: Array + patches: Array, + source: string ) => void type Listener = { heads: automerge.Heads @@ -27,17 +28,23 @@ export class DocHandle { fn: (doc: automerge.Doc) => void ): Heads => { this.doc = automerge.changeAt(this.doc, atHeads, fn) - this._notifyListeners() + this._notifyListeners("changeAt") return getHeads(this.doc) } // eslint-disable-next-line @typescript-eslint/no-explicit-any change = (fn: (doc: automerge.Doc) => void): Heads => { this.doc = automerge.change(this.doc, fn) - this._notifyListeners() + this._notifyListeners("change") return getHeads(this.doc) } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + merge = (other: automerge.Doc) => { + this.doc = automerge.merge(this.doc, other) + this._notifyListeners("merge") + } + addListener = (listener: PatchListener) => { const heads = automerge.getHeads(this.doc) this.listeners.push({ heads, callback: listener }) @@ -47,13 +54,13 @@ export class DocHandle { this.listeners = [] } - _notifyListeners = () => { + _notifyListeners = (source: string) => { const newHeads = automerge.getHeads(this.doc) for (const listener of this.listeners) { if (listener.heads !== newHeads) { const diff = automerge.diff(this.doc, listener.heads, newHeads) if (diff.length > 0) { - listener.callback(this.doc, diff) + listener.callback(this.doc, diff, source) } listener.heads = newHeads } diff --git a/test/Editor.cy.tsx b/test/Editor.cy.tsx index 75a3a0b..53b4ba9 100644 --- a/test/Editor.cy.tsx +++ b/test/Editor.cy.tsx @@ -80,25 +80,48 @@ describe("", () => { const doc = automerge.from({ text: "Hello World!" }) const handle = new DocHandle(doc) mount() + + // Create a local change + cy.get("div.cm-content") + .type("!") + .then(() => { + cy.get("div.cm-content").should( + "have.html", + expectedHtml(["Hello World!!"]) + ) + }) + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let branch: automerge.Doc + // create a remote change then merge it in cy.wait(100) .then(() => { - handle.change(d => { + branch = automerge.clone(handle.doc) + branch = automerge.change(branch, d => { automerge.splice(d, ["text"], 5, 0, " Happy") }) + handle.merge(branch) }) + .wait(100) .then(() => { cy.get("div.cm-content").should( "have.html", - expectedHtml(["Hello Happy World!"]) + expectedHtml(["Hello Happy World!!"]) ) }) + + // Now create another remote change and receive that + cy.wait(100) .then(() => { - cy.get("div.cm-content").type("!") + branch = automerge.change(branch, d => { + automerge.splice(d, ["text"], 5, 0, " hello") + }) + handle.merge(branch) }) .then(() => { cy.get("div.cm-content").should( "have.html", - expectedHtml(["Hello Happy World!!"]) + expectedHtml(["Hello hello Happy World!!"]) ) }) }) diff --git a/test/Editor.tsx b/test/Editor.tsx index 4a0ff71..43666ab 100644 --- a/test/Editor.tsx +++ b/test/Editor.tsx @@ -29,7 +29,8 @@ export function Editor({ handle, path }: EditorProps) { parent: containerRef.current, })) - handle.addListener((doc, _patches) => { + handle.addListener((doc, _patches, source) => { + console.log("patch from ", source) semaphore.reconcile(doc, handle.changeAt, view) }) diff --git a/yarn.lock b/yarn.lock index c4696bb..8f2ecd6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,17 +10,17 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@automerge/automerge-wasm@^0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@automerge/automerge-wasm/-/automerge-wasm-0.2.4.tgz#ed6070c9477c8f3ea1b2520776e84c1dd9a9d77b" - integrity sha512-qbXpBbdMb/t+ufWCvn5ZLFkDpWhO2eko+dgv1NCfS9Z9DMLI9cvr+foxZ6ekTc6iDEVtgftbhZJiDcN1LPkDcw== +"@automerge/automerge-wasm@^0.2.6": + version "0.2.6" + resolved "https://registry.yarnpkg.com/@automerge/automerge-wasm/-/automerge-wasm-0.2.6.tgz#0e8ab9a0516cce3cf1a27ddc98ef978c768986df" + integrity sha512-pbH2ETAq891BDNb4VgeAem9EGkhm9uuetRiRcBvNA0BaW8lqheAu2Ll4E32+RRQL7WXCM172FLQdu/de/kkUBg== -"@automerge/automerge@^2.1.0-alpha.5": - version "2.1.0-alpha.5" - resolved "https://registry.yarnpkg.com/@automerge/automerge/-/automerge-2.1.0-alpha.5.tgz#789fb80fd80783eaeee83a172b37ae236cb47bdb" - integrity sha512-b9GKSja7cBbBpY1ydI5vT2ibm/9iLp+KD+1VoTEIVRCrrSFosmD7h6e27++LSYHQoZx5fTS411vcDUW9uvHZaQ== +"@automerge/automerge@^2.1.0-alpha.7": + version "2.1.0-alpha.7" + resolved "https://registry.yarnpkg.com/@automerge/automerge/-/automerge-2.1.0-alpha.7.tgz#0553f7035e9fa88e6a9716b65a322e9ebd73e81e" + integrity sha512-pPJFOeeuX0vsuXQRs+w6uQtU7Ocvon86r7fk5vuaCbW145iLIkfzlfU7PionJdkOmTkVOq+5vAr1ApEBP7PXsQ== dependencies: - "@automerge/automerge-wasm" "^0.2.4" + "@automerge/automerge-wasm" "^0.2.6" uuid "^9.0.0" "@babel/code-frame@^7.22.5":