diff --git a/src/json-crdt-extensions/peritext/block/Fragment.ts b/src/json-crdt-extensions/peritext/block/Fragment.ts index 7c7fb875a1..be021219b3 100644 --- a/src/json-crdt-extensions/peritext/block/Fragment.ts +++ b/src/json-crdt-extensions/peritext/block/Fragment.ts @@ -33,7 +33,9 @@ export class Fragment extends Range implements Printable, Stateful { // ------------------------------------------------------------------- export public toJson(): PeritextMlElement { - return this.root.toJson(); + const node = this.root.toJson(); + node[0] = ''; + return node; } // ---------------------------------------------------------------- Printable diff --git a/src/json-crdt-extensions/peritext/block/__tests__/Fragment-export.spec.ts b/src/json-crdt-extensions/peritext/block/__tests__/Fragment-export.spec.ts index 750329e85a..6a36dd9b07 100644 --- a/src/json-crdt-extensions/peritext/block/__tests__/Fragment-export.spec.ts +++ b/src/json-crdt-extensions/peritext/block/__tests__/Fragment-export.spec.ts @@ -1,7 +1,5 @@ -import { - type Kit, - setupAlphabetKit, -} from '../../__tests__/setup'; +import {type Kit, runAlphabetKitTestSuite} from '../../__tests__/setup'; +import {toJsonMl} from '../../export/toJsonMl'; import {CommonSliceType} from '../../slice'; const runTests = (setup: () => Kit) => { @@ -12,30 +10,44 @@ const runTests = (setup: () => Kit) => { peritext.refresh(); const fragment = peritext.fragment(peritext.rangeAt(4, 10)); fragment.refresh(); - expect(fragment.toJsonMl()).toEqual([ - 'div', - {}, - ['p', {}, 'efghij'], - ['p', {}, 'klm'], + const html = toJsonMl(fragment.toJson()); + expect(html).toEqual([ + '', + null, + ['p', null, 'efghij'], + ['p', null, 'klm'], ]); - expect(fragment.toHtml()).toBe('

efghij

klm

'); }); -}; -describe('Fragment.toJsonMl()', () => { - describe('basic alphabet', () => { - runTests(setupAlphabetKit); + test('can export two paragraphs with inline formatting', () => { + const {editor, peritext} = setup(); + editor.cursor.setAt(10); + editor.saved.insMarker(CommonSliceType.p); + editor.cursor.setAt(6, 2); + editor.saved.insOverwrite(CommonSliceType.b); + editor.cursor.setAt(7, 2); + editor.saved.insOverwrite(CommonSliceType.i); + peritext.refresh(); + const fragment = peritext.fragment(peritext.rangeAt(4, 10)); + fragment.refresh(); + const html = toJsonMl(fragment.toJson()); + expect(html).toEqual([ + '', + null, + ['p', null, + 'ef', + ['b', null, 'g'], + ['i', null, + ['b', null, 'h'], + ], + ['i', null, 'i'], + 'j', + ], + ['p', null, 'klm'], + ]); }); +}; - // describe('alphabet with two chunks', () => { - // runTests(setupAlphabetWithTwoChunksKit); - // }); - - // describe('alphabet with chunk split', () => { - // runTests(setupAlphabetChunkSplitKit); - // }); - - // describe('alphabet with deletes', () => { - // runTests(setupAlphabetWithDeletesKit); - // }); +describe('Fragment.toJson()', () => { + runAlphabetKitTestSuite(runTests); }); diff --git a/src/json-crdt-extensions/peritext/export/toJsonMl.ts b/src/json-crdt-extensions/peritext/export/toJsonMl.ts new file mode 100644 index 0000000000..bfc5acd664 --- /dev/null +++ b/src/json-crdt-extensions/peritext/export/toJsonMl.ts @@ -0,0 +1,15 @@ +import {SliceTypeName} from "../slice"; +import type {JsonMlNode} from "../../../json-ml"; +import type {PeritextMlNode} from "../block/types"; + +export const toJsonMl = (json: PeritextMlNode): JsonMlNode => { + if (typeof json === 'string') return json; + const [tag, attr, ...children] = json; + const namedTag = tag === '' ? tag : SliceTypeName[tag as any]; + const htmlTag = namedTag ?? (attr?.inline ? 'span' : 'div'); + const htmlAttr = attr && (attr.data !== void 0) ? {'data-attr': JSON.stringify(attr.data)} : null; + const htmlNode: JsonMlNode = [htmlTag, htmlAttr]; + const length = children.length; + for (let i = 0; i < length; i++) htmlNode.push(toJsonMl(children[i])); + return htmlNode; +}; diff --git a/src/json-crdt-extensions/peritext/slice/index.ts b/src/json-crdt-extensions/peritext/slice/index.ts index 915c95da00..6a22d47d74 100644 --- a/src/json-crdt-extensions/peritext/slice/index.ts +++ b/src/json-crdt-extensions/peritext/slice/index.ts @@ -1,2 +1,2 @@ export type * from './types'; -export {CursorAnchor, SliceTypeName as CommonSliceType} from './constants'; +export {CursorAnchor, SliceTypeName, SliceTypeName as CommonSliceType} from './constants';