From 624f3a1cdbbe38fa6ec8afed0df322dd0a92d38c Mon Sep 17 00:00:00 2001 From: Alexander Onnikov Date: Mon, 3 Feb 2025 17:36:47 +0400 Subject: [PATCH] UBERF-9353 Fix markup to ydoc conversion (#7884) --- .vscode/launch.json | 1 + packages/text-ydoc/src/__tests__/ydoc.test.ts | 13 ++++++++++- packages/text-ydoc/src/ydoc.ts | 23 +++++++++++-------- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index a42da33928..cf5c4226f5 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -257,6 +257,7 @@ "MINIO_SECRET_KEY": "minioadmin", "MINIO_ENDPOINT": "localhost" }, + "runtimeVersion": "20", "runtimeArgs": ["--nolazy", "-r", "ts-node/register"], "sourceMaps": true, "cwd": "${workspaceRoot}/pods/collaborator", diff --git a/packages/text-ydoc/src/__tests__/ydoc.test.ts b/packages/text-ydoc/src/__tests__/ydoc.test.ts index 6894635f07..132ccafb1d 100644 --- a/packages/text-ydoc/src/__tests__/ydoc.test.ts +++ b/packages/text-ydoc/src/__tests__/ydoc.test.ts @@ -14,7 +14,8 @@ // import { Markup } from '@hcengineering/core' -import { markupToYDoc, markupToYDocNoSchema, yDocToMarkup } from '../ydoc' +import { markupToJSON } from '@hcengineering/text' +import { jsonToYDocNoSchema, markupToYDoc, markupToYDocNoSchema, yDocToMarkup } from '../ydoc' describe('ydoc', () => { const markups: Markup[] = [ @@ -60,4 +61,14 @@ describe('ydoc', () => { expect(JSON.parse(back)).toEqual(JSON.parse(markup)) }) }) + + describe.each(markups)('jsonToYDocNoSchema', (markup) => { + it('converts json to ydoc', () => { + const json = markupToJSON(markup) + const ydoc1 = jsonToYDocNoSchema(json, 'test') + const ydoc2 = markupToYDoc(markup, 'test') + + expect(ydoc1.getXmlFragment('test').toJSON()).toEqual(ydoc2.getXmlFragment('test').toJSON()) + }) + }) }) diff --git a/packages/text-ydoc/src/ydoc.ts b/packages/text-ydoc/src/ydoc.ts index 1fb83c3a83..a517662099 100644 --- a/packages/text-ydoc/src/ydoc.ts +++ b/packages/text-ydoc/src/ydoc.ts @@ -17,7 +17,14 @@ import { generateId, Markup } from '@hcengineering/core' import { Extensions, getSchema } from '@tiptap/core' import { Node, Schema } from '@tiptap/pm/model' import { prosemirrorJSONToYDoc, prosemirrorToYDoc, yDocToProsemirrorJSON } from 'y-prosemirror' -import { Doc as YDoc, applyUpdate, encodeStateAsUpdate, XmlElement as YXmlElement, XmlText as YXmlText } from 'yjs' +import { + Doc as YDoc, + XmlElement as YXmlElement, + XmlFragment as YXmlFragment, + XmlText as YXmlText, + applyUpdate, + encodeStateAsUpdate +} from 'yjs' import { defaultExtensions, jsonToMarkup, markupToJSON, markupToPmNode, type MarkupNode } from '@hcengineering/text' const defaultSchema = getSchema(defaultExtensions) @@ -45,13 +52,11 @@ export function markupToYDocNoSchema (markup: Markup, field: string): YDoc { * @public */ export function jsonToYDocNoSchema (json: MarkupNode, field: string): YDoc { - const nodes = json.type === 'doc' ? json.content ?? [] : [json] - const content = nodes.map(nodeToYXmlElement) - const ydoc = new YDoc({ guid: generateId() }) - const fragment = ydoc.getXmlFragment(field) - fragment.push(content) + + const nodes = json.type === 'doc' ? json.content ?? [] : [json] + nodes.map((p) => nodeToYXmlElement(fragment, p)) return ydoc } @@ -59,13 +64,13 @@ export function jsonToYDocNoSchema (json: MarkupNode, field: string): YDoc { /** * Convert ProseMirror JSON Node representation to YXmlElement * */ -function nodeToYXmlElement (node: MarkupNode): YXmlElement | YXmlText { +function nodeToYXmlElement (parent: YXmlFragment, node: MarkupNode): YXmlElement | YXmlText { const elem = node.type === 'text' ? new YXmlText() : new YXmlElement(node.type) + parent.push([elem]) if (elem instanceof YXmlElement) { if (node.content !== undefined && node.content.length > 0) { - const content = node.content.map(nodeToYXmlElement) - elem.push(content) + node.content.map((p) => nodeToYXmlElement(elem, p)) } } else { // https://github.com/yjs/y-prosemirror/blob/master/src/plugins/sync-plugin.js#L777