Skip to content

Commit 4d4e10f

Browse files
sciyoshiclaude
andcommitted
fix: add missing tests and exports for prosemirror-transform
- Add test_replace_step.py with ReplaceAroundStep.map tests for wrap/unwrap - Add removeNodeMark multiple instances test - Add setBlockType function attrs test - Add changedRange tests (null, range, multiple steps, deletions) - Add liftTarget split nodes test - Export DocAttrStep from prosemirror.transform __init__.py Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent fa67048 commit 4d4e10f

File tree

4 files changed

+158
-0
lines changed

4 files changed

+158
-0
lines changed

prosemirror/transform/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .attr_step import AttrStep
2+
from .doc_attr_step import DocAttrStep
23
from .map import Mapping, MapResult, StepMap
34
from .mark_step import AddMarkStep, AddNodeMarkStep, RemoveMarkStep, RemoveNodeMarkStep
45
from .replace import (
@@ -24,6 +25,7 @@
2425
"AddMarkStep",
2526
"AddNodeMarkStep",
2627
"AttrStep",
28+
"DocAttrStep",
2729
"MapResult",
2830
"Mapping",
2931
"RemoveMarkStep",
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from prosemirror.test_builder import out
2+
from prosemirror.test_builder import test_schema as schema
3+
from prosemirror.transform import Transform, find_wrapping
4+
5+
doc = out["doc"]
6+
blockquote = out["blockquote"]
7+
p = out["p"]
8+
9+
10+
def test_replace_around_step_map_wrap_insertion():
11+
"""Wrap steps don't break on insertions at start."""
12+
d = doc(p("a"))
13+
tr_a = Transform(d)
14+
range_ = tr_a.doc.resolve(1).block_range()
15+
assert range_ is not None
16+
wrappers = find_wrapping(range_, schema.nodes["blockquote"])
17+
assert wrappers is not None
18+
tr_a.wrap(range_, wrappers)
19+
20+
tr_b = Transform(d)
21+
tr_b.insert(0, p("b"))
22+
23+
mapped_step = tr_a.steps[0].map(tr_b.mapping)
24+
assert mapped_step is not None
25+
result = Transform(tr_b.doc).step(mapped_step).doc
26+
expected = doc(p("b"), blockquote(p("a")))
27+
assert result.eq(expected)
28+
29+
30+
def test_replace_around_step_map_unwrap_insertion():
31+
"""Content inserted at start of unwrap step isn't overwritten."""
32+
d = doc(blockquote(p("a")))
33+
tr_a = Transform(d)
34+
range_ = tr_a.doc.resolve(2).block_range()
35+
assert range_ is not None
36+
tr_a.lift(range_, 0)
37+
38+
tr_b = Transform(d)
39+
tr_b.insert(2, schema.text("x"))
40+
41+
mapped_step = tr_a.steps[0].map(tr_b.mapping)
42+
assert mapped_step is not None
43+
result = Transform(tr_b.doc).step(mapped_step).doc
44+
expected = doc(p("xa"))
45+
assert result.eq(expected)

tests/prosemirror_transform/tests/test_structure.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,3 +272,39 @@ def test_replace(doc, from_, to, content, open_start, open_end, result):
272272
slice = Slice(content.content, open_start, open_end) if content else Slice.empty
273273
tr = Transform(doc).replace(from_, to, slice)
274274
assert tr.doc.eq(result)
275+
276+
277+
def test_lift_target_notices_unliftable_content():
278+
s = Schema({
279+
"nodes": {
280+
"doc": {"content": "section+"},
281+
"section": {"content": "heading? p+"},
282+
"heading": {"content": "p+"},
283+
"p": {"content": "text*"},
284+
"text": {"inline": True},
285+
},
286+
})
287+
p_node = s.node("p", None, [s.text("A")])
288+
d = s.node(
289+
"doc",
290+
None,
291+
[
292+
s.node(
293+
"section",
294+
None,
295+
[s.node("heading", None, [p_node, p_node, p_node]), p_node],
296+
),
297+
],
298+
)
299+
r1 = d.resolve(3).block_range()
300+
assert r1 is not None
301+
assert lift_target(r1) is None
302+
r2 = d.resolve(6).block_range()
303+
assert r2 is not None
304+
assert lift_target(r2) is None
305+
r3 = d.resolve(3).block_range(d.resolve(6))
306+
assert r3 is not None
307+
assert lift_target(r3) is None
308+
r4 = d.resolve(9).block_range()
309+
assert r4 is not None
310+
assert lift_target(r4) == 1

tests/prosemirror_transform/tests/test_trans.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,3 +1171,78 @@ def test_add_node_mark(doc, mark, expect, test_transform):
11711171
)
11721172
def test_remove_node_mark(doc, mark, expect, test_transform):
11731173
test_transform(Transform(doc).remove_node_mark(doc.tag["a"], mark), expect)
1174+
1175+
1176+
def test_remove_node_mark_multiple_instances(test_transform):
1177+
s = Schema({
1178+
"nodes": {
1179+
"doc": {"content": "p+", "marks": "comment"},
1180+
"p": {"content": "text*"},
1181+
"text": {},
1182+
},
1183+
"marks": {"comment": {"excludes": "", "attrs": {"id": {}}}},
1184+
})
1185+
d = s.node(
1186+
"doc",
1187+
None,
1188+
[
1189+
s.node(
1190+
"p",
1191+
None,
1192+
[s.text("abc")],
1193+
[s.mark("comment", {"id": 1}), s.mark("comment", {"id": 2})],
1194+
),
1195+
],
1196+
)
1197+
test_transform(
1198+
Transform(d).remove_node_mark(0, s.marks["comment"]),
1199+
s.node("doc", None, [s.node("p", None, [s.text("abc")])]),
1200+
)
1201+
1202+
1203+
def test_set_block_type_function_attrs(test_transform):
1204+
d = doc("<a>", h1("a"), p("b"), "<b>")
1205+
tr = Transform(d).set_block_type(
1206+
d.tag["a"],
1207+
d.tag["b"],
1208+
schema.nodes["heading"],
1209+
lambda node: {"level": (node.attrs.get("level") or 0) + 1},
1210+
)
1211+
test_transform(tr, doc(h2("a"), h1("b")))
1212+
1213+
1214+
def test_changed_range_returns_none_when_no_changes():
1215+
d = doc(p("hello"))
1216+
tr = Transform(d)
1217+
assert tr.changed_range() is None
1218+
tr.add_mark(1, 3, schema.mark("strong"))
1219+
assert tr.changed_range() is None
1220+
1221+
1222+
def test_changed_range_returns_range():
1223+
d = doc(p("ab"))
1224+
tr = Transform(d).insert(3, schema.text("c"))
1225+
ch = tr.changed_range()
1226+
assert ch is not None
1227+
assert f"{ch['from']}-{ch['to']}" == "3-4"
1228+
1229+
1230+
def test_changed_range_multiple_steps():
1231+
d = doc(p("ab"))
1232+
tr = (
1233+
Transform(d)
1234+
.insert(3, schema.text("c"))
1235+
.insert(2, schema.text("d"))
1236+
.insert(1, schema.text("e"))
1237+
)
1238+
ch = tr.changed_range()
1239+
assert ch is not None
1240+
assert f"{ch['from']}-{ch['to']}" == "1-6"
1241+
1242+
1243+
def test_changed_range_deletions_before_earlier_step():
1244+
d = doc(p("abcde"))
1245+
tr = Transform(d).insert(6, schema.text("f")).delete(1, 4)
1246+
ch = tr.changed_range()
1247+
assert ch is not None
1248+
assert f"{ch['from']}-{ch['to']}" == "1-4"

0 commit comments

Comments
 (0)