Repository navigation
This release focuses on closing behavioral gaps with the upstream TypeScript ProseMirror modules. Over 25 bugs have been fixed to improve correctness and compatibility.
Upstream Compatibility
UTF-16 Semantics
- Fix UTF-16 slicing in
TextNode.text_betweenandFragment.text_between— Python string slicing uses codepoints, but ProseMirror positions are in UTF-16 code units - Fix UTF-16 character counting in
diff.py—find_diff_startandfind_diff_endproduced wrong positions for text with non-BMP characters (e.g. emoji)
DOM Parsing
- Fix
parse_slice()missing thelxmltextwrapping needed for lxml to handle text nodes (was only applied inparse()) - Remove incorrect
preserve_whitespace=Truedefault inparse_slice()— upstream lets it inherit from context - Fix
ruleFromNodefallback logic — whenruleFromNodereturned falsy, thematchTagresult was dropped instead of used as fallback
DOM Serialization
- Handle
{dom, contentDOM}dict variant inrender_spec, matching the TypeScriptDOMOutputSpectype - Coerce attribute values to string in
render_spec— TypeScript'ssetAttributedoes this implicitly - Cache
DOMSerializerinfrom_schema()(upstream caches onschema.cached)
Node & Fragment
- Fix
Node.cut()not resolving defaulttoparameter before the early-return check - Add
textattribute to baseNodeclass (returnsNone), matchingNode.prototype.text = undefinedin TypeScript - Reject negative indices in
child()andmaybe_child()— Python lists silently accept them, TypeScript arrays don't - Make
Fragment.cut_by_indexrequire both parameters to match upstream API surface
Schema & Attributes
- Distinguish explicit
Nonefrom missing incompute_attrsusing a sentinel — TypeScript distinguishesnullfromundefined - Map
dictandlistto"object"in_validate_typeto match JavaScript'stypeof - Add
elseclause for unknown expression types in NFAcompile(upstream throws, Python silently returnedNone)
Resolved Positions
- Make
ResolvedPos.index_afterdepth parameter optional, matching upstream
Content Matching & Replace
- Fix
check_contentusage inclose()to match upstream error semantics — was raisingReplaceErrorinstead ofValueError - Fix infinite loop in
matches_context() - Fix operator precedence in
NodeContext.finish() - Fix logic inversion in
ignore_fallback()
Other API Fixes
- Change
textBetweendefaults toNoneto match upstream (was defaulting to empty strings) - Add diagnostic hint to
Fragment.from_()error message about multiple versions - Add missing exports to
prosemirror.model:AttributeSpec,GenericParseRule,HTMLOutputSpec,MarkSpec,NodeSpec,ParseOptions,ParseRule,SchemaSpec,StyleParseRule,TagParseRule
Bug Fixes
- Fix memory leak in resolve cache — added weakref finalizer to clean up entries when documents are garbage collected
CI & Tooling
- Add Python 3.14 to test matrix
- Add pre-commit config for ruff, ty, and pytest