Skip to content

Commit 88c3d1a

Browse files
authored
fix: remove marks from breaks that are the last node inside that mark (#101)
1 parent efaa359 commit 88c3d1a

File tree

5 files changed

+41
-10
lines changed

5 files changed

+41
-10
lines changed

src/core/markdown/Markdown.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {MarkdownParser} from './MarkdownParser';
1111
import {MarkdownSerializer} from './MarkdownSerializer';
1212

1313
const {schema} = builder;
14+
schema.nodes['hard_break'].spec.isBreak = true;
1415
const parser: Parser = new MarkdownParser(schema, new MarkdownIt('commonmark'), {
1516
paragraph: {type: 'block', name: 'paragraph'},
1617
heading: {
@@ -160,6 +161,9 @@ describe('markdown', () => {
160161

161162
it('drops trailing hard breaks', () => serialize(doc(p('a', br(), br())), 'a'));
162163

164+
it('should remove marks from edge break', () =>
165+
serialize(doc(p(strong('text', br()), 'text2')), '**text**\\\ntext2'));
166+
163167
it('expels enclosing whitespace from inside emphasis', () =>
164168
serialize(
165169
doc(

src/core/markdown/MarkdownSerializer.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,10 @@ export class MarkdownSerializerState {
189189
const progress = (node, _, index) => {
190190
let marks = node ? node.marks : [];
191191

192-
// Remove marks from `hard_break` that are the last node inside
192+
// Remove marks from breaks (hard_break or soft_break) that are the last node inside
193193
// that mark to prevent parser edge cases with new lines just
194194
// before closing marks.
195-
// (FIXME it'd be nice if we had a schema-agnostic way to
196-
// identify nodes that serialize as hard breaks)
197-
if (node && node.type.name === 'hard_break') {
195+
if (node && node.type.spec.isBreak) {
198196
marks = marks.filter(m => {
199197
if (index + 1 == parent.childCount) return false;
200198
const next = parent.child(index + 1);

src/core/types/serializer.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,10 @@ export interface SerializerMarkToken {
3030
escape?: boolean;
3131
expelEnclosingWhitespace?: boolean;
3232
}
33+
34+
declare module 'prosemirror-model' {
35+
interface NodeSpec {
36+
/** Default false */
37+
isBreak?: boolean;
38+
}
39+
}

src/extensions/markdown/Breaks/Breaks.test.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,38 @@
11
import {builders} from 'prosemirror-test-builder';
22
import {parseDOM} from '../../../../tests/parse-dom';
3+
import {createMarkupChecker} from '../../../../tests/sameMarkup';
34
import {ExtensionsManager} from '../../../core';
45
import {BaseNode, BaseSpecsPreset} from '../../base/specs';
6+
import {BoldSpecs, boldMarkName} from '../../markdown/Bold/BoldSpecs';
57
import {BreakNodeName, BreaksSpecs} from './BreaksSpecs';
68

7-
const {schema} = new ExtensionsManager({
8-
extensions: (builder) => builder.use(BaseSpecsPreset, {}).use(BreaksSpecs, {}),
9+
const {schema, parser, serializer} = new ExtensionsManager({
10+
extensions: (builder) => builder.use(BaseSpecsPreset, {}).use(BreaksSpecs, {}).use(BoldSpecs),
911
}).buildDeps();
1012

11-
const {doc, p, hb} = builders(schema, {
13+
const {doc, p, hb, sb, bold} = builders(schema, {
1214
doc: {nodeType: BaseNode.Doc},
1315
p: {nodeType: BaseNode.Paragraph},
1416
hb: {nodeType: BreakNodeName.HardBreak},
15-
}) as PMTestBuilderResult<'doc' | 'p' | 'hb'>;
17+
sb: {nodeType: BreakNodeName.SoftBreak},
18+
bold: {markType: boldMarkName},
19+
}) as PMTestBuilderResult<'doc' | 'p' | 'hb' | 'sb', 'bold'>;
20+
21+
const {serialize} = createMarkupChecker({parser, serializer});
1622

1723
describe('Breaks extension', () => {
24+
it('should serialize hard break', () =>
25+
serialize(
26+
doc(p('Lorem ', bold('ipsum', hb()), 'dolor sit amet')),
27+
'Lorem **ipsum**\\\ndolor sit amet',
28+
));
29+
30+
it('should serialize soft break', () =>
31+
serialize(
32+
doc(p('Lorem ', bold('ipsum', sb()), 'dolor sit amet')),
33+
'Lorem **ipsum**\ndolor sit amet',
34+
));
35+
1836
it('should parse html - br tag', () => {
1937
parseDOM(schema, '<div>hello<br>world!</div>', doc(p('hello', hb(), 'world!')));
2038
});

src/extensions/markdown/Breaks/BreaksSpecs/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ export const BreaksSpecs: ExtensionAuto = (builder) => {
1313
builder.addNode(BreakNodeName.HardBreak, () => ({
1414
spec: {
1515
inline: true,
16-
group: 'inline',
16+
group: 'inline break',
17+
marks: '',
18+
isBreak: true,
1719
selectable: false,
1820
parseDOM: [{tag: 'br'}],
1921
toDOM() {
@@ -38,7 +40,9 @@ export const BreaksSpecs: ExtensionAuto = (builder) => {
3840
builder.addNode(BreakNodeName.SoftBreak, () => ({
3941
spec: {
4042
inline: true,
41-
group: 'inline',
43+
group: 'inline break',
44+
marks: '',
45+
isBreak: true,
4246
selectable: false,
4347
toDOM() {
4448
return ['br'];

0 commit comments

Comments
 (0)