diff --git a/src/markdown/plain/adf-to-plain-markdown.test.ts b/src/markdown/plain/adf-to-plain-markdown.test.ts index 28db1b7..d634fe0 100644 --- a/src/markdown/plain/adf-to-plain-markdown.test.ts +++ b/src/markdown/plain/adf-to-plain-markdown.test.ts @@ -344,3 +344,9 @@ test('writes what the editor-normal form of the document writes', () => { assert.equal(plain({ content: [], text: 'hi', type: 'futureInline' }), 'hi\n') assert.equal(plain(paragraph({ marks: [{ attrs: {}, type: 'code' }], text: 'a', type: 'text' }, { marks: [{ type: 'code' }], text: '|b', type: 'text' })), '`a|b`\n') }) + +test('writes a text node holding content the same in either order beside its neighbour', () => { + const holding: AdfNode = { content: [text('inner')], text: 'a', type: 'text' } + assert.equal(plain(paragraph(holding, text('b'))), 'ab\n') + assert.equal(plain(paragraph(text('b'), holding)), 'ba\n') +}) diff --git a/src/markdown/plain/editor-normal.test.ts b/src/markdown/plain/editor-normal.test.ts index 3eb32e7..851c660 100644 --- a/src/markdown/plain/editor-normal.test.ts +++ b/src/markdown/plain/editor-normal.test.ts @@ -50,7 +50,7 @@ test('reads negative zero as zero, as JSON does', () => { ) }) -test('reads an empty attrs object, marks array or content array as the absent key, but on doc', () => { +test('reads an empty attrs object, marks array or content array as the absent key, except on doc', () => { const paragraph: AdfNode = { attrs: {}, content: [{ attrs: {}, marks: [], text: 'a', type: 'text' }, { marks: [{ attrs: {}, type: 'em' }], text: 'b', type: 'text' }], marks: [], type: 'paragraph' } assert.deepEqual(toEditorNormal({ content: [paragraph, { content: [], type: 'rule' }], type: 'doc', version: 1 }), { content: [{ content: [{ text: 'a', type: 'text' }, { marks: [{ type: 'em' }], text: 'b', type: 'text' }], type: 'paragraph' }, { type: 'rule' }], @@ -77,7 +77,9 @@ test('normalizes blocks and mark attributes nesting far past the levels a recurs assert.deepEqual(merged.content?.[0]?.content?.map((text) => text.text), ['ab']) }) -test('joins a text node holding content to its neighbour, as editor-normal forms hold no content to part them', () => { - const paragraph: AdfNode = { content: [{ content: [{ text: 'lost', type: 'text' }], text: 'a', type: 'text' }, { text: 'b', type: 'text' }], type: 'paragraph' } - assert.deepEqual(toEditorNormal({ content: [paragraph], type: 'doc', version: 1 }).content, [{ content: [{ content: [{ text: 'lost', type: 'text' }], text: 'ab', type: 'text' }], type: 'paragraph' }]) +test('joins a text node holding content to no neighbour, so its content is kept', () => { + const holding: AdfNode = { content: [{ text: 'kept', type: 'text' }], text: 'a', type: 'text' } + for (const content of [[holding, { text: 'b', type: 'text' }], [{ text: 'b', type: 'text' }, holding]]) { + assert.deepEqual(toEditorNormal({ content: [{ content, type: 'paragraph' }], type: 'doc', version: 1 }).content, [{ content, type: 'paragraph' }]) + } }) diff --git a/src/markdown/plain/editor-normal.ts b/src/markdown/plain/editor-normal.ts index 74b3a74..3877967 100644 --- a/src/markdown/plain/editor-normal.ts +++ b/src/markdown/plain/editor-normal.ts @@ -7,8 +7,9 @@ type JsonContainer = JsonValue[] | { [key: string]: JsonValue } type NodeHolder = { content?: AdfNode[] } -// The editor's rule is the reader's over the pair's editor-normal forms, which hold no content: a text node's content never parts it. +// The editor's rule is the reader's over the pair's editor-normal forms; a text node holding content never joins, so its content is kept. export function joinsWhenEditorNormal(previous: AdfNode, node: AdfNode): boolean { + if (previous.type !== 'text' || node.type !== 'text' || nodeContent(previous).length > 0 || nodeContent(node).length > 0) return false return joinsWhenRead(normalNode(previous), normalNode(node)) }