prosereflect 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/docs.yml +63 -0
  3. data/.github/workflows/links.yml +97 -0
  4. data/.gitignore +4 -0
  5. data/.rubocop_todo.yml +61 -75
  6. data/README.adoc +2 -0
  7. data/docs/Gemfile +10 -0
  8. data/docs/INDEX.adoc +45 -0
  9. data/docs/_advanced/index.adoc +15 -0
  10. data/docs/_advanced/schema.adoc +112 -0
  11. data/docs/_advanced/step-map.adoc +66 -0
  12. data/docs/_advanced/steps.adoc +88 -0
  13. data/docs/_advanced/test-builder.adoc +61 -0
  14. data/docs/_advanced/transform.adoc +92 -0
  15. data/docs/_config.yml +174 -0
  16. data/docs/_features/html-input.adoc +69 -0
  17. data/docs/_features/html-output.adoc +45 -0
  18. data/docs/_features/index.adoc +15 -0
  19. data/docs/_features/marks.adoc +86 -0
  20. data/docs/_features/node-types.adoc +124 -0
  21. data/docs/_features/user-mentions.adoc +47 -0
  22. data/docs/_guides/custom-nodes.adoc +107 -0
  23. data/docs/_guides/index.adoc +13 -0
  24. data/docs/_guides/round-trip-html.adoc +91 -0
  25. data/docs/_guides/serialization.adoc +109 -0
  26. data/docs/_pages/index.adoc +67 -0
  27. data/docs/_reference/document-api.adoc +49 -0
  28. data/docs/_reference/index.adoc +14 -0
  29. data/docs/_reference/node-api.adoc +79 -0
  30. data/docs/_reference/schema-api.adoc +95 -0
  31. data/docs/_reference/transform-api.adoc +77 -0
  32. data/docs/_understanding/document-model.adoc +65 -0
  33. data/docs/_understanding/fragment.adoc +52 -0
  34. data/docs/_understanding/index.adoc +14 -0
  35. data/docs/_understanding/resolved-position.adoc +53 -0
  36. data/docs/_understanding/slice.adoc +54 -0
  37. data/docs/lychee.toml +63 -0
  38. data/lib/prosereflect/blockquote.rb +9 -0
  39. data/lib/prosereflect/bullet_list.rb +25 -19
  40. data/lib/prosereflect/code_block.rb +1 -5
  41. data/lib/prosereflect/fragment.rb +249 -0
  42. data/lib/prosereflect/horizontal_rule.rb +9 -0
  43. data/lib/prosereflect/image.rb +9 -0
  44. data/lib/prosereflect/input/html.rb +96 -0
  45. data/lib/prosereflect/node.rb +141 -3
  46. data/lib/prosereflect/ordered_list.rb +2 -0
  47. data/lib/prosereflect/output/html.rb +227 -0
  48. data/lib/prosereflect/parser.rb +9 -0
  49. data/lib/prosereflect/resolved_pos.rb +256 -0
  50. data/lib/prosereflect/schema/attribute.rb +57 -0
  51. data/lib/prosereflect/schema/content_match.rb +656 -0
  52. data/lib/prosereflect/schema/fragment.rb +166 -0
  53. data/lib/prosereflect/schema/mark.rb +121 -0
  54. data/lib/prosereflect/schema/mark_type.rb +130 -0
  55. data/lib/prosereflect/schema/node.rb +236 -0
  56. data/lib/prosereflect/schema/node_type.rb +274 -0
  57. data/lib/prosereflect/schema/schema_main.rb +190 -0
  58. data/lib/prosereflect/schema/spec.rb +92 -0
  59. data/lib/prosereflect/schema.rb +39 -0
  60. data/lib/prosereflect/text.rb +24 -0
  61. data/lib/prosereflect/transform/attr_step.rb +157 -0
  62. data/lib/prosereflect/transform/insert_step.rb +115 -0
  63. data/lib/prosereflect/transform/mapping.rb +82 -0
  64. data/lib/prosereflect/transform/mark_step.rb +269 -0
  65. data/lib/prosereflect/transform/replace_around_step.rb +181 -0
  66. data/lib/prosereflect/transform/replace_step.rb +157 -0
  67. data/lib/prosereflect/transform/slice.rb +91 -0
  68. data/lib/prosereflect/transform/step.rb +89 -0
  69. data/lib/prosereflect/transform/step_map.rb +126 -0
  70. data/lib/prosereflect/transform/structure.rb +120 -0
  71. data/lib/prosereflect/transform/transform.rb +341 -0
  72. data/lib/prosereflect/transform.rb +26 -0
  73. data/lib/prosereflect/version.rb +1 -1
  74. data/lib/prosereflect.rb +3 -0
  75. data/spec/fixtures/documents/formatted_text.yaml +14 -0
  76. data/spec/fixtures/documents/heading_paragraph.yaml +16 -0
  77. data/spec/fixtures/documents/lists_doc.yaml +32 -0
  78. data/spec/fixtures/documents/mixed_content.yaml +40 -0
  79. data/spec/fixtures/documents/nested_doc.yaml +20 -0
  80. data/spec/fixtures/documents/simple_doc.yaml +6 -0
  81. data/spec/fixtures/documents/table_doc.yaml +32 -0
  82. data/spec/fixtures/documents/transform_test.yaml +14 -0
  83. data/spec/fixtures/schema/custom_schema.rb +37 -0
  84. data/spec/fixtures/schema/test_schema.rb +46 -0
  85. data/spec/fixtures/test_builder/helpers.rb +212 -0
  86. data/spec/prosereflect/document_spec.rb +1 -1
  87. data/spec/prosereflect/fragment_spec.rb +273 -0
  88. data/spec/prosereflect/input/html_spec.rb +197 -1
  89. data/spec/prosereflect/node_spec.rb +128 -0
  90. data/spec/prosereflect/output/whitespace_spec.rb +248 -0
  91. data/spec/prosereflect/parser/round_trip_spec.rb +472 -0
  92. data/spec/prosereflect/resolved_pos_spec.rb +74 -0
  93. data/spec/prosereflect/schema/conftest.rb +68 -0
  94. data/spec/prosereflect/schema/content_match_spec.rb +237 -0
  95. data/spec/prosereflect/schema/mark_spec.rb +274 -0
  96. data/spec/prosereflect/schema/mark_type_spec.rb +86 -0
  97. data/spec/prosereflect/schema/node_type_spec.rb +142 -0
  98. data/spec/prosereflect/schema/schema_spec.rb +194 -0
  99. data/spec/prosereflect/test_builder/marks_spec.rb +127 -0
  100. data/spec/prosereflect/transform/equivalence_spec.rb +487 -0
  101. data/spec/prosereflect/transform/mapping_spec.rb +226 -0
  102. data/spec/prosereflect/transform/replace_spec.rb +832 -0
  103. data/spec/prosereflect/transform/replace_step_spec.rb +157 -0
  104. data/spec/prosereflect/transform/slice_spec.rb +48 -0
  105. data/spec/prosereflect/transform/step_map_spec.rb +70 -0
  106. data/spec/prosereflect/transform/step_spec.rb +211 -0
  107. data/spec/prosereflect/transform/structure_spec.rb +98 -0
  108. data/spec/prosereflect/transform/transform_spec.rb +238 -0
  109. data/spec/spec_helper.rb +1 -0
  110. metadata +90 -2
@@ -0,0 +1,124 @@
1
+ ---
2
+ layout: default
3
+ title: Node Types
4
+ parent: Features
5
+ nav_order: 1
6
+ ---
7
+ = Node Types
8
+
9
+ prosereflect provides node classes for all standard ProseMirror node types. Each inherits from `Prosereflect::Node` and defines a `PM_TYPE` constant.
10
+
11
+ == Block Nodes
12
+
13
+ === Document
14
+
15
+ Top-level container. Create with `Document.create`:
16
+
17
+ [source,ruby]
18
+ ----
19
+ doc = Prosereflect::Document.create
20
+ doc.add_paragraph("Hello world")
21
+ ----
22
+
23
+ Convenience methods: `tables`, `paragraphs`, `find_first`, `find_all`, `find_children`, `add_paragraph`, `add_heading`, `add_table`, `add_image`, `add_bullet_list`, `add_ordered_list`, `add_blockquote`, `add_horizontal_rule`, `add_code_block_wrapper`, `add_user`.
24
+
25
+ === Paragraph
26
+
27
+ Represents a paragraph of text.
28
+
29
+ [source,ruby]
30
+ ----
31
+ para = Prosereflect::Paragraph.new
32
+ para.add_text("Hello")
33
+ para.text_content # => "Hello"
34
+ ----
35
+
36
+ === Heading
37
+
38
+ Heading with level attribute (1-6):
39
+
40
+ [source,ruby]
41
+ ----
42
+ heading = Prosereflect::Heading.new
43
+ heading.level = 2
44
+ heading.add_text("Title")
45
+ ----
46
+
47
+ === Table, TableRow, TableCell, TableHeader
48
+
49
+ Table structures with convenience methods:
50
+
51
+ [source,ruby]
52
+ ----
53
+ table = doc.add_table
54
+ row = table.add_row
55
+ cell = row.add_cell
56
+ cell.add_paragraph("Data")
57
+ ----
58
+
59
+ Table methods: `header_row`, `data_rows`, `cell_at(row, col)`, `rows`.
60
+
61
+ === Lists
62
+
63
+ `BulletList` and `OrderedList` contain `ListItem` children:
64
+
65
+ [source,ruby]
66
+ ----
67
+ list = doc.add_bullet_list
68
+ item = list.add_item
69
+ item.add_paragraph("First item")
70
+ ----
71
+
72
+ `OrderedList` supports a `start` attribute for numbering.
73
+
74
+ === Blockquote
75
+
76
+ Contains block-level children:
77
+
78
+ [source,ruby]
79
+ ----
80
+ quote = doc.add_blockquote
81
+ quote.add_paragraph("To be or not to be")
82
+ ----
83
+
84
+ === CodeBlockWrapper and CodeBlock
85
+
86
+ Code blocks with syntax highlighting:
87
+
88
+ [source,ruby]
89
+ ----
90
+ wrapper = doc.add_code_block_wrapper
91
+ block = wrapper.add_code_block("puts 'hello'", language: "ruby")
92
+ ----
93
+
94
+ === Image
95
+
96
+ Inline image node with `src`, `alt`, `title`, `width`, `height` attributes.
97
+
98
+ === HorizontalRule
99
+
100
+ Horizontal rule element with `style`, `width`, `thickness` attributes.
101
+
102
+ === HardBreak
103
+
104
+ Inline break element within paragraphs.
105
+
106
+ == Text Nodes
107
+
108
+ `Prosereflect::Text` represents a text node with `text` attribute and optional marks. `node_size` returns `text.length + 1`.
109
+
110
+ == Common Methods
111
+
112
+ All node types inherit from `Node`:
113
+
114
+ * `node_size` -- size in the document position space
115
+ * `text?` -- whether this is a text node
116
+ * `cut(from, to)` -- return a copy with content restricted to range
117
+ * `copy(content)` -- return a copy with different content
118
+ * `find_first(type)`, `find_all(type)`, `find_children(klass)` -- node traversal
119
+ * `add_child(node)` -- append a child
120
+ * `text_content` -- combined text of all descendant text nodes
121
+ * `to_h` -- serialize to ProseMirror JSON hash
122
+ * `resolve(pos)` -- resolve a position to a `ResolvedPos`
123
+ * `nodes_between(from, to)` -- iterate nodes in a range
124
+ * `descendants` -- iterate all descendant nodes
@@ -0,0 +1,47 @@
1
+ ---
2
+ layout: default
3
+ title: User Mentions
4
+ parent: Features
5
+ nav_order: 5
6
+ ---
7
+ = User Mentions
8
+
9
+ prosereflect supports user @mentions as a special inline node type.
10
+
11
+ == Creating Mentions
12
+
13
+ [source,ruby]
14
+ ----
15
+ doc = Prosereflect::Document.create
16
+ para = doc.add_paragraph("Hello ")
17
+ user = Prosereflect::User.new
18
+ user.id = "123"
19
+ para.add_child(user)
20
+ para.add_text("!")
21
+ ----
22
+
23
+ == HTML Representation
24
+
25
+ User mentions are represented as `<user-mention>` elements in HTML:
26
+
27
+ [source,ruby]
28
+ ----
29
+ html = Prosereflect::Output::Html.convert(doc)
30
+ # includes: <user-mention data-id="123"></user-mention>
31
+ ----
32
+
33
+ == Parsing from HTML
34
+
35
+ [source,ruby]
36
+ ----
37
+ html = '<p>Hello <user-mention data-id="123"></user-mention>!</p>'
38
+ doc = Prosereflect::Input::Html.parse(html)
39
+ users = doc.find_all('user')
40
+ users.first.id # => "123"
41
+ ----
42
+
43
+ == Use Cases
44
+
45
+ * Mentioning users in comments or messages
46
+ * Tagging users in collaborative documents
47
+ * Tracking user references in content
@@ -0,0 +1,107 @@
1
+ ---
2
+ layout: default
3
+ title: Custom Nodes
4
+ parent: Guides
5
+ nav_order: 2
6
+ ---
7
+ = Custom Nodes
8
+
9
+ This guide explains how to define custom node types that integrate with prosereflect's serialization and HTML conversion systems.
10
+
11
+ == Defining a Custom Node
12
+
13
+ Create a new class that inherits from `Prosereflect::Node`:
14
+
15
+ [source,ruby]
16
+ ----
17
+ class Callout < Prosereflect::Node
18
+ PM_TYPE = "callout"
19
+
20
+ # Define custom attributes
21
+ attribute :variant, :string
22
+
23
+ # Define serialization mapping
24
+ key_value do
25
+ map "type", to: :type, render_default: true
26
+ map "attrs", to: :attrs
27
+ map "content", to: :content
28
+ end
29
+ end
30
+ ----
31
+
32
+ == Key Concepts
33
+
34
+ === PM_TYPE
35
+
36
+ The `PM_TYPE` constant must match the ProseMirror type string used in JSON serialization. This is how the parser maps JSON data to your Ruby class.
37
+
38
+ === Attributes
39
+
40
+ Use `lutaml-model`'s `attribute` DSL to define custom attributes:
41
+
42
+ [source,ruby]
43
+ ----
44
+ attribute :variant, :string # string attribute
45
+ attribute :count, :integer # integer attribute
46
+ ----
47
+
48
+ Attributes are automatically included in `to_h` output when present in the `attrs` hash.
49
+
50
+ === key_value Block
51
+
52
+ The `key_value` block defines how Ruby attributes map to JSON keys:
53
+
54
+ [source,ruby]
55
+ ----
56
+ key_value do
57
+ map "type", to: :type, render_default: true
58
+ map "attrs", to: :attrs
59
+ map "content", to: :content
60
+ end
61
+ ----
62
+
63
+ === Convenience Methods
64
+
65
+ Add helper methods for construction:
66
+
67
+ [source,ruby]
68
+ ----
69
+ class Callout < Prosereflect::Node
70
+ PM_TYPE = "callout"
71
+
72
+ def self.create(variant: "info", text: nil)
73
+ node = new(type: PM_TYPE, attrs: { "variant" => variant })
74
+ node.add_text(text) if text
75
+ node
76
+ end
77
+ end
78
+ ----
79
+
80
+ == Serialization Round-Trip
81
+
82
+ Ensure `to_h` and `Parser` are compatible:
83
+
84
+ [source,ruby]
85
+ ----
86
+ # Serialize
87
+ callout = Callout.create(variant: "warning", text: "Be careful!")
88
+ hash = callout.to_h
89
+ # => {"type" => "callout", "attrs" => {"variant" => "warning"},
90
+ # "content" => [{"type" => "text", "text" => "Be careful!"}]}
91
+
92
+ # Deserialize (if registered with Parser)
93
+ doc = Prosereflect::Parser.parse_document({
94
+ "type" => "doc",
95
+ "content" => [hash]
96
+ })
97
+ ----
98
+
99
+ == Node Naming Pattern
100
+
101
+ prosereflect maps PM_TYPE strings to classes by convention:
102
+
103
+ * `"paragraph"` -> `Prosereflect::Paragraph`
104
+ * `"heading"` -> `Prosereflect::Heading`
105
+ * `"table"` -> `Prosereflect::Table`
106
+
107
+ Custom types follow the same pattern -- the parser uses `PM_TYPE` to find the matching class.
@@ -0,0 +1,13 @@
1
+ ---
2
+ layout: default
3
+ title: Guides
4
+ nav_order: 6
5
+ has_children: true
6
+ ---
7
+ = Guides
8
+
9
+ Task-oriented tutorials for common prosereflect workflows.
10
+
11
+ * x:round-trip-html[HTML Round-Trip] -- Convert between HTML and ProseMirror
12
+ * x:custom-nodes[Custom Nodes] -- Define custom node types
13
+ * x:serialization[Serialization] -- JSON/YAML round-trips
@@ -0,0 +1,91 @@
1
+ ---
2
+ layout: default
3
+ title: HTML Round-Trip
4
+ parent: Guides
5
+ nav_order: 1
6
+ ---
7
+ = HTML Round-Trip
8
+
9
+ This guide shows how to parse HTML into a ProseMirror document model, modify it, and convert back to HTML.
10
+
11
+ == Parse HTML
12
+
13
+ [source,ruby]
14
+ ----
15
+ require 'prosereflect'
16
+
17
+ html = '<p>This is <strong>bold</strong> and <em>italic</em> text.</p>'
18
+ doc = Prosereflect::Input::Html.parse(html)
19
+ ----
20
+
21
+ == Navigate and Modify
22
+
23
+ [source,ruby]
24
+ ----
25
+ # Access the first paragraph
26
+ para = doc.paragraphs.first
27
+ para.text_content # => "This is bold and italic text."
28
+
29
+ # Append text
30
+ para.add_text(" More content.")
31
+
32
+ # Add a new paragraph
33
+ doc.add_paragraph("Second paragraph.")
34
+ ----
35
+
36
+ == Convert Back to HTML
37
+
38
+ [source,ruby]
39
+ ----
40
+ modified_html = Prosereflect::Output::Html.convert(doc)
41
+ ----
42
+
43
+ == Working with Tables
44
+
45
+ [source,ruby]
46
+ ----
47
+ html = '<table><tr><th>Header</th></tr><tr><td>Data</td></tr></table>'
48
+ doc = Prosereflect::Input::Html.parse(html)
49
+
50
+ tables = doc.tables
51
+ first_table = tables.first
52
+ first_table.header_row # => row with TableHeader cells
53
+ first_table.data_rows # => rows with TableCell cells
54
+ ----
55
+
56
+ == Round-Trip with Marks
57
+
58
+ [source,ruby]
59
+ ----
60
+ html = '<p><a href="https://example.com">click here</a></p>'
61
+ doc = Prosereflect::Input::Html.parse(html)
62
+
63
+ # The link mark is preserved
64
+ para = doc.paragraphs.first
65
+
66
+ # Convert back - links are rendered as <a> tags
67
+ output = Prosereflect::Output::Html.convert(doc)
68
+ ----
69
+
70
+ == Common Patterns
71
+
72
+ === Extract Plain Text
73
+
74
+ [source,ruby]
75
+ ----
76
+ doc = Prosereflect::Input::Html.parse(html_content)
77
+ plain_text = doc.text_content
78
+ ----
79
+
80
+ === Find and Replace Text
81
+
82
+ [source,ruby]
83
+ ----
84
+ doc = Prosereflect::Input::Html.parse(html_content)
85
+
86
+ doc.paragraphs.each do |para|
87
+ # Access text content
88
+ text = para.text_content
89
+ # Modify via transforms
90
+ end
91
+ ----
@@ -0,0 +1,109 @@
1
+ ---
2
+ layout: default
3
+ title: Serialization
4
+ parent: Guides
5
+ nav_order: 3
6
+ ---
7
+ = Serialization
8
+
9
+ prosereflect supports round-trip serialization through ProseMirror's JSON/YAML format using the `to_h` / `Parser.parse_document` methods.
10
+
11
+ == to_h (Serialize)
12
+
13
+ Every node can be serialized to a Ruby hash matching ProseMirror's JSON format:
14
+
15
+ [source,ruby]
16
+ ----
17
+ doc = Prosereflect::Document.create
18
+ para = doc.add_paragraph("Hello")
19
+ para.add_text(" bold", [Prosereflect::Mark::Bold.new])
20
+
21
+ hash = doc.to_h
22
+ # => {
23
+ # "type" => "doc",
24
+ # "content" => [
25
+ # {
26
+ # "type" => "paragraph",
27
+ # "content" => [
28
+ # { "type" => "text", "text" => "Hello" },
29
+ # { "type" => "text", "text" => " bold", "marks" => [{"type" => "bold"}] }
30
+ # ]
31
+ # }
32
+ # ]
33
+ # }
34
+ ----
35
+
36
+ == parse_document (Deserialize)
37
+
38
+ Convert a ProseMirror hash back to node objects:
39
+
40
+ [source,ruby]
41
+ ----
42
+ doc = Prosereflect::Parser.parse_document(hash)
43
+ doc.paragraphs.first.text_content # => "Hello bold"
44
+ ----
45
+
46
+ Works with YAML and JSON strings too:
47
+
48
+ [source,ruby]
49
+ ----
50
+ # From YAML
51
+ doc = Prosereflect::Parser.parse_document(YAML.safe_load(yaml_string))
52
+
53
+ # From JSON
54
+ doc = Prosereflect::Parser.parse_document(JSON.parse(json_string))
55
+ ----
56
+
57
+ == YAML Round-Trip
58
+
59
+ [source,ruby]
60
+ ----
61
+ # Serialize to YAML
62
+ yaml = doc.to_yaml
63
+
64
+ # Deserialize from YAML
65
+ data = YAML.safe_load(yaml)
66
+ doc = Prosereflect::Parser.parse_document(data)
67
+
68
+ # Verify round-trip
69
+ doc.to_h == original_doc.to_h # => true
70
+ ----
71
+
72
+ == JSON Round-Trip
73
+
74
+ [source,ruby]
75
+ ----
76
+ require 'json'
77
+
78
+ # Serialize to JSON
79
+ json = JSON.pretty_generate(doc.to_h)
80
+
81
+ # Deserialize from JSON
82
+ data = JSON.parse(json)
83
+ doc = Prosereflect::Parser.parse_document(data)
84
+ ----
85
+
86
+ == Step Serialization
87
+
88
+ Transform steps can be serialized to JSON:
89
+
90
+ [source,ruby]
91
+ ----
92
+ step = Prosereflect::Transform::ReplaceStep.new(2, 5, slice)
93
+ json = step.to_json
94
+ # => {"stepType" => "replace", "from" => 2, "to" => 5, "slice" => [...]}
95
+
96
+ # Deserialize
97
+ step = Prosereflect::Transform::ReplaceStep.from_json(schema, json)
98
+ ----
99
+
100
+ == to_h Behavior
101
+
102
+ The `to_h` method includes:
103
+
104
+ * `type` -- always included
105
+ * `attrs` -- only if non-empty
106
+ * `marks` -- only if non-empty
107
+ * `content` -- only if non-empty
108
+
109
+ This matches ProseMirror's JSON serialization format where omitted fields use defaults.
@@ -0,0 +1,67 @@
1
+ ---
2
+ layout: default
3
+ title: Getting Started
4
+ nav_order: 2
5
+ ---
6
+ = Getting Started
7
+
8
+ == What is prosereflect?
9
+
10
+ `prosereflect` is a Ruby gem for working with the document structure used by the https://prosemirror.net/[ProseMirror rich text editor].
11
+
12
+ It provides a complete Ruby object model for ProseMirror documents, including:
13
+
14
+ * Parsing and serialization (JSON, YAML, HTML)
15
+ * A rich node hierarchy with type-safe accessors
16
+ * A full Transform system for step-based document manipulation
17
+ * Schema definition and content validation
18
+ * Position resolution and mapping
19
+ * HTML input and output with whitespace handling
20
+ * A test builder DSL for constructing test documents
21
+
22
+ == Installation
23
+
24
+ Add to your Gemfile:
25
+
26
+ [source,ruby]
27
+ ----
28
+ gem 'prosereflect'
29
+ ----
30
+
31
+ Or install directly:
32
+
33
+ [source,sh]
34
+ ----
35
+ gem install prosereflect
36
+ ----
37
+
38
+ == Quick Example
39
+
40
+ [source,ruby]
41
+ ----
42
+ require 'prosereflect'
43
+
44
+ # Create a document
45
+ doc = Prosereflect::Document.create
46
+ doc.add_paragraph("Hello world")
47
+
48
+ # Parse from JSON hash
49
+ doc = Prosereflect::Parser.parse_document({
50
+ "type" => "doc",
51
+ "content" => [
52
+ { "type" => "paragraph", "content" => [{ "type" => "text", "text" => "Hello" }] }
53
+ ]
54
+ })
55
+
56
+ # Parse from HTML
57
+ doc = Prosereflect::Input::Html.parse('<p>Hello <strong>world</strong></p>')
58
+
59
+ # Convert to HTML
60
+ html = Prosereflect::Output::Html.convert(doc)
61
+ ----
62
+
63
+ == Next Steps
64
+
65
+ * x:features:node-types[Node Types] -- all available node types
66
+ * x:understanding:document-model[Document Model] -- how the document tree works
67
+ * x:guides:round-trip-html[HTML Round-Trip] -- convert between HTML and ProseMirror
@@ -0,0 +1,49 @@
1
+ ---
2
+ layout: default
3
+ title: Document API
4
+ parent: Reference
5
+ nav_order: 2
6
+ ---
7
+ = Document API
8
+
9
+ == Prosereflect::Document
10
+
11
+ Top-level document container. Inherits from Node with PM_TYPE "doc".
12
+
13
+ === Class Methods
14
+
15
+ [cols="1,3"]
16
+ |===
17
+ | Method | Description
18
+
19
+ | `Document.create(attrs)` | Create an empty document
20
+ |===
21
+
22
+ === Query Methods
23
+
24
+ [cols="1,3"]
25
+ |===
26
+ | Method | Description
27
+
28
+ | `tables` | Find all direct child Table nodes
29
+ | `paragraphs` | Find all direct child Paragraph nodes
30
+ | `text_content` | Plain text from all nodes, joined by newlines
31
+ |===
32
+
33
+ === Builder Methods
34
+
35
+ [cols="1,3"]
36
+ |===
37
+ | Method | Description
38
+
39
+ | `add_paragraph(text, attrs)` | Add a paragraph, optionally with text
40
+ | `add_heading(level)` | Add a heading with the given level
41
+ | `add_table(attrs)` | Add a table
42
+ | `add_image(src, alt)` | Add an image
43
+ | `add_bullet_list(attrs)` | Add a bullet list
44
+ | `add_ordered_list(attrs)` | Add an ordered list
45
+ | `add_blockquote(attrs)` | Add a blockquote
46
+ | `add_horizontal_rule(attrs)` | Add a horizontal rule
47
+ | `add_code_block_wrapper(attrs)` | Add a code block wrapper
48
+ | `add_user(id)` | Add a user mention node
49
+ |===
@@ -0,0 +1,14 @@
1
+ ---
2
+ layout: default
3
+ title: Reference
4
+ nav_order: 7
5
+ has_children: true
6
+ ---
7
+ = Reference
8
+
9
+ API reference documentation organized by module.
10
+
11
+ * x:node-api[Node API] -- Node base class and Document
12
+ * x:document-api[Document API] -- Document convenience methods
13
+ * x:transform-api[Transform API] -- Transform and Step classes
14
+ * x:schema-api[Schema API] -- Schema, NodeType, MarkType, ContentMatch
@@ -0,0 +1,79 @@
1
+ ---
2
+ layout: default
3
+ title: Node API
4
+ parent: Reference
5
+ nav_order: 1
6
+ ---
7
+ = Node API
8
+
9
+ == Prosereflect::Node
10
+
11
+ Base class for all document elements.
12
+
13
+ === Attributes
14
+
15
+ * `type` (String) -- The node type (e.g. "doc", "paragraph", "text")
16
+ * `attrs` (Hash) -- Node-specific attributes
17
+ * `marks` (Array) -- Formatting marks applied to this node
18
+ * `content` (Array) -- Child nodes
19
+
20
+ === Class Methods
21
+
22
+ [cols="1,3"]
23
+ |===
24
+ | Method | Description
25
+
26
+ | `Node.create(type, attrs)` | Create a new node with the given type and attrs
27
+ | `Node.from_json(schema, json)` | Deserialize from JSON (requires schema)
28
+ |===
29
+
30
+ === Instance Methods
31
+
32
+ [cols="1,3"]
33
+ |===
34
+ | Method | Description
35
+
36
+ | `node_size` | Size in document position space
37
+ | `text?` | Whether this is a text node
38
+ | `text_content` | Combined text of all descendant text nodes
39
+ | `cut(from, to)` | Return a copy restricted to position range
40
+ | `copy(content)` | Return a copy with different content
41
+ | `add_child(node)` | Append a child node
42
+ | `find_first(type)` | Find first descendant of type
43
+ | `find_all(type)` | Find all descendants of type
44
+ | `find_children(klass)` | Find direct children of class
45
+ | `resolve(pos)` | Resolve position to ResolvedPos
46
+ | `nodes_between(from, to, &block)` | Iterate nodes in position range
47
+ | `descendants(&block)` | Iterate all descendant nodes
48
+ | `eq?(other)` | Structural equality
49
+ | `to_h` | Serialize to ProseMirror hash
50
+ | `to_yaml` | Serialize to YAML
51
+ |===
52
+
53
+ == Prosereflect::Text
54
+
55
+ Text node (PM_TYPE: "text").
56
+
57
+ [cols="1,3"]
58
+ |===
59
+ | Method | Description
60
+
61
+ | `text` | The text string
62
+ | `node_size` | `text.length + 1`
63
+ | `text?` | Always `true`
64
+ |===
65
+
66
+ == Prosereflect::Mark::Base
67
+
68
+ Base class for all marks.
69
+
70
+ [cols="1,3"]
71
+ |===
72
+ | Method | Description
73
+
74
+ | `type` | The mark type string
75
+ | `attrs` | Mark attributes (e.g. href for links)
76
+ | `to_h` | Serialize to hash
77
+ |===
78
+
79
+ Mark subclasses: `Bold`, `Italic`, `Code`, `Link`, `Strike`, `Subscript`, `Superscript`, `Underline`.