prosereflect 0.1.1 → 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 (158) 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/.github/workflows/rake.yml +4 -0
  5. data/.github/workflows/release.yml +5 -0
  6. data/.gitignore +4 -0
  7. data/.rubocop.yml +19 -1
  8. data/.rubocop_todo.yml +119 -183
  9. data/CLAUDE.md +78 -0
  10. data/Gemfile +8 -4
  11. data/README.adoc +2 -0
  12. data/Rakefile +3 -3
  13. data/docs/Gemfile +10 -0
  14. data/docs/INDEX.adoc +45 -0
  15. data/docs/_advanced/index.adoc +15 -0
  16. data/docs/_advanced/schema.adoc +112 -0
  17. data/docs/_advanced/step-map.adoc +66 -0
  18. data/docs/_advanced/steps.adoc +88 -0
  19. data/docs/_advanced/test-builder.adoc +61 -0
  20. data/docs/_advanced/transform.adoc +92 -0
  21. data/docs/_config.yml +174 -0
  22. data/docs/_features/html-input.adoc +69 -0
  23. data/docs/_features/html-output.adoc +45 -0
  24. data/docs/_features/index.adoc +15 -0
  25. data/docs/_features/marks.adoc +86 -0
  26. data/docs/_features/node-types.adoc +124 -0
  27. data/docs/_features/user-mentions.adoc +47 -0
  28. data/docs/_guides/custom-nodes.adoc +107 -0
  29. data/docs/_guides/index.adoc +13 -0
  30. data/docs/_guides/round-trip-html.adoc +91 -0
  31. data/docs/_guides/serialization.adoc +109 -0
  32. data/docs/_pages/index.adoc +67 -0
  33. data/docs/_reference/document-api.adoc +49 -0
  34. data/docs/_reference/index.adoc +14 -0
  35. data/docs/_reference/node-api.adoc +79 -0
  36. data/docs/_reference/schema-api.adoc +95 -0
  37. data/docs/_reference/transform-api.adoc +77 -0
  38. data/docs/_understanding/document-model.adoc +65 -0
  39. data/docs/_understanding/fragment.adoc +52 -0
  40. data/docs/_understanding/index.adoc +14 -0
  41. data/docs/_understanding/resolved-position.adoc +53 -0
  42. data/docs/_understanding/slice.adoc +54 -0
  43. data/docs/lychee.toml +63 -0
  44. data/lib/prosereflect/attribute/base.rb +4 -6
  45. data/lib/prosereflect/attribute/bold.rb +2 -4
  46. data/lib/prosereflect/attribute/href.rb +1 -3
  47. data/lib/prosereflect/attribute/id.rb +7 -7
  48. data/lib/prosereflect/attribute.rb +4 -7
  49. data/lib/prosereflect/blockquote.rb +19 -11
  50. data/lib/prosereflect/bullet_list.rb +36 -29
  51. data/lib/prosereflect/code_block.rb +23 -27
  52. data/lib/prosereflect/code_block_wrapper.rb +12 -13
  53. data/lib/prosereflect/document.rb +14 -22
  54. data/lib/prosereflect/fragment.rb +249 -0
  55. data/lib/prosereflect/hard_break.rb +6 -6
  56. data/lib/prosereflect/heading.rb +14 -15
  57. data/lib/prosereflect/horizontal_rule.rb +23 -14
  58. data/lib/prosereflect/image.rb +32 -23
  59. data/lib/prosereflect/input/html.rb +179 -104
  60. data/lib/prosereflect/input.rb +7 -0
  61. data/lib/prosereflect/list_item.rb +11 -12
  62. data/lib/prosereflect/mark/base.rb +9 -11
  63. data/lib/prosereflect/mark/bold.rb +1 -3
  64. data/lib/prosereflect/mark/code.rb +1 -3
  65. data/lib/prosereflect/mark/italic.rb +1 -3
  66. data/lib/prosereflect/mark/link.rb +1 -3
  67. data/lib/prosereflect/mark/strike.rb +1 -3
  68. data/lib/prosereflect/mark/subscript.rb +1 -3
  69. data/lib/prosereflect/mark/superscript.rb +1 -3
  70. data/lib/prosereflect/mark/underline.rb +1 -3
  71. data/lib/prosereflect/mark.rb +9 -5
  72. data/lib/prosereflect/node.rb +171 -33
  73. data/lib/prosereflect/ordered_list.rb +17 -14
  74. data/lib/prosereflect/output/html.rb +279 -50
  75. data/lib/prosereflect/output.rb +7 -0
  76. data/lib/prosereflect/paragraph.rb +11 -13
  77. data/lib/prosereflect/parser.rb +56 -66
  78. data/lib/prosereflect/resolved_pos.rb +256 -0
  79. data/lib/prosereflect/schema/attribute.rb +57 -0
  80. data/lib/prosereflect/schema/content_match.rb +656 -0
  81. data/lib/prosereflect/schema/fragment.rb +166 -0
  82. data/lib/prosereflect/schema/mark.rb +121 -0
  83. data/lib/prosereflect/schema/mark_type.rb +130 -0
  84. data/lib/prosereflect/schema/node.rb +236 -0
  85. data/lib/prosereflect/schema/node_type.rb +274 -0
  86. data/lib/prosereflect/schema/schema_main.rb +190 -0
  87. data/lib/prosereflect/schema/spec.rb +92 -0
  88. data/lib/prosereflect/schema.rb +39 -0
  89. data/lib/prosereflect/table.rb +12 -13
  90. data/lib/prosereflect/table_cell.rb +13 -13
  91. data/lib/prosereflect/table_header.rb +17 -17
  92. data/lib/prosereflect/table_row.rb +12 -12
  93. data/lib/prosereflect/text.rb +35 -11
  94. data/lib/prosereflect/transform/attr_step.rb +157 -0
  95. data/lib/prosereflect/transform/insert_step.rb +115 -0
  96. data/lib/prosereflect/transform/mapping.rb +82 -0
  97. data/lib/prosereflect/transform/mark_step.rb +269 -0
  98. data/lib/prosereflect/transform/replace_around_step.rb +181 -0
  99. data/lib/prosereflect/transform/replace_step.rb +157 -0
  100. data/lib/prosereflect/transform/slice.rb +91 -0
  101. data/lib/prosereflect/transform/step.rb +89 -0
  102. data/lib/prosereflect/transform/step_map.rb +126 -0
  103. data/lib/prosereflect/transform/structure.rb +120 -0
  104. data/lib/prosereflect/transform/transform.rb +341 -0
  105. data/lib/prosereflect/transform.rb +26 -0
  106. data/lib/prosereflect/user.rb +15 -15
  107. data/lib/prosereflect/version.rb +1 -1
  108. data/lib/prosereflect.rb +30 -17
  109. data/prosereflect.gemspec +17 -16
  110. data/spec/fixtures/documents/formatted_text.yaml +14 -0
  111. data/spec/fixtures/documents/heading_paragraph.yaml +16 -0
  112. data/spec/fixtures/documents/lists_doc.yaml +32 -0
  113. data/spec/fixtures/documents/mixed_content.yaml +40 -0
  114. data/spec/fixtures/documents/nested_doc.yaml +20 -0
  115. data/spec/fixtures/documents/simple_doc.yaml +6 -0
  116. data/spec/fixtures/documents/table_doc.yaml +32 -0
  117. data/spec/fixtures/documents/transform_test.yaml +14 -0
  118. data/spec/fixtures/schema/custom_schema.rb +37 -0
  119. data/spec/fixtures/schema/test_schema.rb +46 -0
  120. data/spec/fixtures/test_builder/helpers.rb +212 -0
  121. data/spec/prosereflect/document_spec.rb +332 -330
  122. data/spec/prosereflect/fragment_spec.rb +273 -0
  123. data/spec/prosereflect/hard_break_spec.rb +125 -125
  124. data/spec/prosereflect/input/html_spec.rb +718 -522
  125. data/spec/prosereflect/node_spec.rb +311 -182
  126. data/spec/prosereflect/output/html_spec.rb +105 -105
  127. data/spec/prosereflect/output/whitespace_spec.rb +248 -0
  128. data/spec/prosereflect/paragraph_spec.rb +275 -274
  129. data/spec/prosereflect/parser/round_trip_spec.rb +472 -0
  130. data/spec/prosereflect/parser_spec.rb +185 -180
  131. data/spec/prosereflect/resolved_pos_spec.rb +74 -0
  132. data/spec/prosereflect/schema/conftest.rb +68 -0
  133. data/spec/prosereflect/schema/content_match_spec.rb +237 -0
  134. data/spec/prosereflect/schema/mark_spec.rb +274 -0
  135. data/spec/prosereflect/schema/mark_type_spec.rb +86 -0
  136. data/spec/prosereflect/schema/node_type_spec.rb +142 -0
  137. data/spec/prosereflect/schema/schema_spec.rb +194 -0
  138. data/spec/prosereflect/table_cell_spec.rb +183 -183
  139. data/spec/prosereflect/table_row_spec.rb +149 -149
  140. data/spec/prosereflect/table_spec.rb +320 -318
  141. data/spec/prosereflect/test_builder/marks_spec.rb +127 -0
  142. data/spec/prosereflect/text_spec.rb +133 -132
  143. data/spec/prosereflect/transform/equivalence_spec.rb +487 -0
  144. data/spec/prosereflect/transform/mapping_spec.rb +226 -0
  145. data/spec/prosereflect/transform/replace_spec.rb +832 -0
  146. data/spec/prosereflect/transform/replace_step_spec.rb +157 -0
  147. data/spec/prosereflect/transform/slice_spec.rb +48 -0
  148. data/spec/prosereflect/transform/step_map_spec.rb +70 -0
  149. data/spec/prosereflect/transform/step_spec.rb +211 -0
  150. data/spec/prosereflect/transform/structure_spec.rb +98 -0
  151. data/spec/prosereflect/transform/transform_spec.rb +238 -0
  152. data/spec/prosereflect/user_spec.rb +31 -28
  153. data/spec/prosereflect_spec.rb +28 -26
  154. data/spec/spec_helper.rb +7 -6
  155. data/spec/support/matchers.rb +6 -6
  156. data/spec/support/shared_examples.rb +49 -49
  157. metadata +96 -5
  158. data/spec/prosereflect/version_spec.rb +0 -11
@@ -0,0 +1,226 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Prosereflect::Transform::Mapping do
6
+ let(:step_map) { Prosereflect::Transform::StepMap.new([[0, 5, 0, 5]]) }
7
+
8
+ describe "creation" do
9
+ it "creates empty mapping" do
10
+ mapping = described_class.new
11
+ expect(mapping.to_a).to eq([])
12
+ end
13
+
14
+ it "creates mapping with step maps" do
15
+ mapping = described_class.new(maps: [step_map])
16
+ expect(mapping.to_a.length).to eq(1)
17
+ end
18
+ end
19
+
20
+ describe "add_map" do
21
+ it "adds step map to end" do
22
+ mapping = described_class.new
23
+ mapping.add_map(step_map)
24
+ expect(mapping.to_a.length).to eq(1)
25
+ end
26
+
27
+ it "adds step map at specific index" do
28
+ mapping = described_class.new(maps: [step_map])
29
+ new_map = Prosereflect::Transform::StepMap.new([[10, 15, 10, 15]])
30
+ mapping.add_map(new_map, 0)
31
+ expect(mapping.to_a.length).to eq(2)
32
+ end
33
+ end
34
+
35
+ describe "map" do
36
+ it "maps position through empty mapping returns same position" do
37
+ mapping = described_class.new
38
+ expect(mapping.map(5)).to eq(5)
39
+ end
40
+
41
+ it "maps position through single step map" do
42
+ # StepMap [[0, 5, 0, 5]] means: old 0-5 maps to new 0-5 (no change)
43
+ step_map = Prosereflect::Transform::StepMap.new([[0, 5, 0, 5]])
44
+ mapping = described_class.new(maps: [step_map])
45
+ expect(mapping.map(3)).to eq(3)
46
+ end
47
+
48
+ it "maps position through multiple step maps" do
49
+ # First step: positions 0-5 stay at 0-5
50
+ # Second step: positions 5-10 stay at 5-5 (5 chars inserted)
51
+ map1 = Prosereflect::Transform::StepMap.new([[0, 5, 0, 5]])
52
+ map2 = Prosereflect::Transform::StepMap.new([[5, 10, 5, 5]])
53
+ mapping = described_class.new(maps: [map1, map2])
54
+ expect(mapping.map(3)).to eq(3)
55
+ end
56
+
57
+ it "handles deletion step map" do
58
+ # StepMap [[0, 3, 0, 0]] means: old 0-3 maps to new 0-0 (3 deleted)
59
+ step_map = Prosereflect::Transform::StepMap.new([[0, 3, 0, 0]])
60
+ mapping = described_class.new(maps: [step_map])
61
+ # Position 5 (after deletion) should be offset by -3
62
+ expect(mapping.map(5)).to eq(2)
63
+ end
64
+ end
65
+
66
+ describe "map_result" do
67
+ it "returns pos and deleted status for position not deleted" do
68
+ # StepMap [[0, 2, 0, 2]] deletes 0-1, position 5 is after range
69
+ step_map = Prosereflect::Transform::StepMap.new([[0, 2, 0, 2]])
70
+ mapping = described_class.new(maps: [step_map])
71
+ result = mapping.map_result(5)
72
+ expect(result[:pos]).to eq(5)
73
+ expect(result[:deleted]).to be false
74
+ end
75
+
76
+ it "returns deleted true for position in deleted range" do
77
+ # StepMap [[0, 3, 0, 0]] means: old 0-3 maps to new 0-0 (3 deleted)
78
+ step_map = Prosereflect::Transform::StepMap.new([[0, 3, 0, 0]])
79
+ mapping = described_class.new(maps: [step_map])
80
+ result = mapping.map_result(1)
81
+ expect(result[:deleted]).to be true
82
+ end
83
+ end
84
+
85
+ describe "map_deletes" do
86
+ it "returns false when position not deleted" do
87
+ mapping = described_class.new(maps: [step_map])
88
+ expect(mapping.map_deletes(10)).to be false
89
+ end
90
+
91
+ it "returns true when position deleted" do
92
+ # StepMap [[0, 5, 0, 0]] is a deletion of 0-5
93
+ step_map = Prosereflect::Transform::StepMap.new([[0, 5, 0, 0]])
94
+ mapping = described_class.new(maps: [step_map])
95
+ expect(mapping.map_deletes(2)).to be true
96
+ end
97
+
98
+ it "returns false for position after deleted range" do
99
+ # StepMap [[0, 3, 0, 0]] deletes 0-3
100
+ step_map = Prosereflect::Transform::StepMap.new([[0, 3, 0, 0]])
101
+ mapping = described_class.new(maps: [step_map])
102
+ # Position 5 is after the deleted range
103
+ expect(mapping.map_deletes(5)).to be false
104
+ end
105
+ end
106
+
107
+ describe "to_a" do
108
+ it "returns array of step maps" do
109
+ mapping = described_class.new(maps: [step_map])
110
+ expect(mapping.to_a).to eq([step_map])
111
+ end
112
+ end
113
+
114
+ describe "from_step_map" do
115
+ it "creates mapping from single step map" do
116
+ mapping = described_class.from_step_map(step_map)
117
+ expect(mapping.to_a).to eq([step_map])
118
+ end
119
+ end
120
+
121
+ context "with StepMap" do
122
+ describe "creation" do
123
+ it "creates empty step map" do
124
+ step_map = Prosereflect::Transform::StepMap.new
125
+ expect(step_map.ranges).to eq([])
126
+ end
127
+
128
+ it "creates step map with ranges" do
129
+ step_map = Prosereflect::Transform::StepMap.new([[0, 5, 0, 5]])
130
+ expect(step_map.ranges).to eq([[0, 5, 0, 5]])
131
+ end
132
+ end
133
+
134
+ describe ".empty" do
135
+ it "returns empty step map" do
136
+ step_map = Prosereflect::Transform::StepMap.empty
137
+ expect(step_map.ranges).to eq([])
138
+ end
139
+ end
140
+
141
+ describe ".delete" do
142
+ it "creates step map for deletion" do
143
+ step_map = Prosereflect::Transform::StepMap.delete(2, 5)
144
+ # [[2, 5, 2, 2]] - from 2 to 5 deleted, maps to position 2
145
+ expect(step_map.ranges).to eq([[2, 5, 2, 2]])
146
+ end
147
+ end
148
+
149
+ describe ".replace" do
150
+ it "creates step map for replacement" do
151
+ step_map = Prosereflect::Transform::StepMap.replace(0, 3, 0, 5)
152
+ # [[0, 3, 0, 5]] - old 0-3 replaced with new 0-5
153
+ expect(step_map.ranges).to eq([[0, 3, 0, 5]])
154
+ end
155
+ end
156
+
157
+ describe "map" do
158
+ it "maps position before any range unchanged" do
159
+ step_map = Prosereflect::Transform::StepMap.new([[5, 10, 5, 10]])
160
+ expect(step_map.map(3)).to eq(3)
161
+ end
162
+
163
+ it "maps position within range" do
164
+ step_map = Prosereflect::Transform::StepMap.new([[2, 5, 2, 8]])
165
+ # Position 3 within old 2-5 maps to 2 + (3-2) = 3
166
+ expect(step_map.map(3)).to eq(3)
167
+ end
168
+
169
+ it "maps position after range with offset" do
170
+ step_map = Prosereflect::Transform::StepMap.new([[0, 3, 0, 0]])
171
+ # Position 5 is after deleted range 0-3
172
+ # offset = (0 - 3) = -3
173
+ expect(step_map.map(5)).to eq(2)
174
+ end
175
+ end
176
+
177
+ describe "map_result" do
178
+ it "returns result with deleted false when not deleted" do
179
+ # StepMap [[0, 2, 0, 2]] deletes 0-1, position 5 is not in range
180
+ step_map = Prosereflect::Transform::StepMap.new([[0, 2, 0, 2]])
181
+ result = step_map.map_result(5)
182
+ expect(result.deleted).to be false
183
+ expect(result.pos).to eq(5)
184
+ end
185
+
186
+ it "returns result with deleted true when in range" do
187
+ step_map = Prosereflect::Transform::StepMap.new([[0, 5, 0, 0]])
188
+ result = step_map.map_result(2)
189
+ expect(result.deleted).to be true
190
+ end
191
+ end
192
+
193
+ describe "deleted?" do
194
+ it "returns true for position in deleted range" do
195
+ step_map = Prosereflect::Transform::StepMap.new([[0, 5, 0, 0]])
196
+ expect(step_map.deleted?(2)).to be true
197
+ end
198
+
199
+ it "returns false for position after range" do
200
+ step_map = Prosereflect::Transform::StepMap.new([[0, 5, 0, 0]])
201
+ expect(step_map.deleted?(10)).to be false
202
+ end
203
+
204
+ it "returns false for position before range" do
205
+ step_map = Prosereflect::Transform::StepMap.new([[5, 10, 5, 10]])
206
+ expect(step_map.deleted?(2)).to be false
207
+ end
208
+ end
209
+
210
+ describe "add_map" do
211
+ it "returns other map when self is empty" do
212
+ empty = Prosereflect::Transform::StepMap.new
213
+ other = Prosereflect::Transform::StepMap.new([[0, 5, 0, 5]])
214
+ result = empty.add_map(other)
215
+ expect(result.ranges).to eq([[0, 5, 0, 5]])
216
+ end
217
+
218
+ it "returns self when other is empty" do
219
+ map = Prosereflect::Transform::StepMap.new([[0, 5, 0, 5]])
220
+ empty = Prosereflect::Transform::StepMap.new
221
+ result = map.add_map(empty)
222
+ expect(result.ranges).to eq([[0, 5, 0, 5]])
223
+ end
224
+ end
225
+ end
226
+ end