fix: prevent documentToMarkdown from mutating source document (#1184)
* fix: prevent documentToMarkdown from mutating source document convertNodes() was calling pageNode(children: nodes) which triggered Node's constructor to unlink() each child from its original parent, orphaning nested list items in the source document. Fix by deep-copying nodes before passing them to pageNode(). Fixes https://github.com/AppFlowy-IO/AppFlowy/issues/8486 * chore: add regression test for issue #8486 Verifies that documentToMarkdown() does not orphan children of nested list items in the source document after conversion.
This commit is contained in:
parent
955db55b8a
commit
301d0fa579
2 changed files with 35 additions and 1 deletions
|
|
@ -34,7 +34,9 @@ class DocumentMarkdownEncoder extends Converter<Document, String> {
|
||||||
List<Node> nodes, {
|
List<Node> nodes, {
|
||||||
bool withIndent = false,
|
bool withIndent = false,
|
||||||
}) {
|
}) {
|
||||||
final result = convert(Document(root: pageNode(children: nodes)));
|
final result = convert(
|
||||||
|
Document(root: pageNode(children: nodes.map((n) => n.deepCopy()))),
|
||||||
|
);
|
||||||
if (result.isNotEmpty && withIndent) {
|
if (result.isNotEmpty && withIndent) {
|
||||||
return result
|
return result
|
||||||
.split('\n')
|
.split('\n')
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,38 @@ void main() {
|
||||||
expect(nodes[0].delta?.toPlainText(), 'This is the first line');
|
expect(nodes[0].delta?.toPlainText(), 'This is the first line');
|
||||||
expect(nodes[1].attributes['url'], 'https://example.com/image.png');
|
expect(nodes[1].attributes['url'], 'https://example.com/image.png');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Regression test for https://github.com/AppFlowy-IO/AppFlowy/issues/8486
|
||||||
|
// documentToMarkdown() must not mutate the source document when processing
|
||||||
|
// nested (indented) list items.
|
||||||
|
test('documentToMarkdown does not orphan children of nested list items',
|
||||||
|
() {
|
||||||
|
final childNode = bulletedListNode(text: 'Child item');
|
||||||
|
final parentNode = bulletedListNode(
|
||||||
|
text: 'Parent item',
|
||||||
|
children: [childNode],
|
||||||
|
);
|
||||||
|
final document = Document(root: pageNode(children: [parentNode]));
|
||||||
|
|
||||||
|
// Verify initial structure: parent has 1 child.
|
||||||
|
expect(document.root.children.length, 1);
|
||||||
|
expect(document.root.children.first.children.length, 1);
|
||||||
|
|
||||||
|
final markdown = documentToMarkdown(document);
|
||||||
|
|
||||||
|
// The markdown output should be correct.
|
||||||
|
expect(markdown, '* Parent item\n\t* Child item\n');
|
||||||
|
|
||||||
|
// After conversion, the source document must be unchanged.
|
||||||
|
// Before the fix, convertNodes() called pageNode(children: nodes) which
|
||||||
|
// invoked unlink() on each child, removing them from their original parent.
|
||||||
|
expect(
|
||||||
|
document.root.children.first.children.length,
|
||||||
|
1,
|
||||||
|
reason:
|
||||||
|
'documentToMarkdown() must not remove children from the source document',
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue