Skip to content

v0.6.1

Latest

Choose a tag to compare

@sciyoshi sciyoshi released this 21 Feb 15:42

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_between and Fragment.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_start and find_diff_end produced wrong positions for text with non-BMP characters (e.g. emoji)

DOM Parsing

  • Fix parse_slice() missing the lxmltext wrapping needed for lxml to handle text nodes (was only applied in parse())
  • Remove incorrect preserve_whitespace=True default in parse_slice() — upstream lets it inherit from context
  • Fix ruleFromNode fallback logic — when ruleFromNode returned falsy, the matchTag result was dropped instead of used as fallback

DOM Serialization

  • Handle {dom, contentDOM} dict variant in render_spec, matching the TypeScript DOMOutputSpec type
  • Coerce attribute values to string in render_spec — TypeScript's setAttribute does this implicitly
  • Cache DOMSerializer in from_schema() (upstream caches on schema.cached)

Node & Fragment

  • Fix Node.cut() not resolving default to parameter before the early-return check
  • Add text attribute to base Node class (returns None), matching Node.prototype.text = undefined in TypeScript
  • Reject negative indices in child() and maybe_child() — Python lists silently accept them, TypeScript arrays don't
  • Make Fragment.cut_by_index require both parameters to match upstream API surface

Schema & Attributes

  • Distinguish explicit None from missing in compute_attrs using a sentinel — TypeScript distinguishes null from undefined
  • Map dict and list to "object" in _validate_type to match JavaScript's typeof
  • Add else clause for unknown expression types in NFA compile (upstream throws, Python silently returned None)

Resolved Positions

  • Make ResolvedPos.index_after depth parameter optional, matching upstream

Content Matching & Replace

  • Fix check_content usage in close() to match upstream error semantics — was raising ReplaceError instead of ValueError
  • Fix infinite loop in matches_context()
  • Fix operator precedence in NodeContext.finish()
  • Fix logic inversion in ignore_fallback()

Other API Fixes

  • Change textBetween defaults to None to 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