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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f5c6ec18ecdd44c7efaba52819b0763d35c829c7af571ef7b423da2863d29caf
4
- data.tar.gz: ed3ed8a65bb95e4dbc89a0e96efe4f2dd4a2c57b0cc7210f6296c03a6b8c5d66
3
+ metadata.gz: d9f70970efc856c322c1d356262ae1492856c2432d2ed6343b7f00a4b96a97a9
4
+ data.tar.gz: 4670d12e397d85fa399ea4bd721d0eaa4d35aa24b7425c0bb7e6b61eb057a173
5
5
  SHA512:
6
- metadata.gz: f736e62b0ef5909c60daebb95b79f29c23be47b76c56edf327adeb4bdf76df1071493def7a5530209cd5a431332f1dfec3a3428453c50c5e3e336873126be238
7
- data.tar.gz: 56d78409069b3a61caf41ab36a44494f71b1f2be53e9ef15bd2290fad0eebab31cc3c7a22945b09b05f0dd0f011f65b77f0cc8045fa36230e723750b6796f118
6
+ metadata.gz: 42bb32f0114a3cb597a65498681177c93345f3ddcff24412a2ba03dd8492b1ec0da306797ada94fac95c984e0f80a63631de555fae2a836b647c8805ab73e0b6
7
+ data.tar.gz: d6b5dcf22e6d6b0c923c5b35a1dbccecea6e7103af0001428ca567ad8f2333d2f63fe7652149f087b2ea0383beff80afc69e02b09f086f93b5fd51ee7be1dca1
@@ -0,0 +1,63 @@
1
+ name: docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ paths:
7
+ - 'docs/**'
8
+ pull_request:
9
+ paths:
10
+ - 'docs/**'
11
+ repository_dispatch:
12
+ workflow_dispatch:
13
+
14
+ permissions:
15
+ contents: read
16
+ pages: write
17
+ id-token: write
18
+
19
+ concurrency:
20
+ group: ${{ github.workflow }}-${{ github.ref }}
21
+ cancel-in-progress: false
22
+
23
+ jobs:
24
+ build:
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - name: Checkout
28
+ uses: actions/checkout@v6
29
+
30
+ - name: Setup Ruby
31
+ uses: ruby/setup-ruby@v1
32
+ with:
33
+ ruby-version: '3.3'
34
+ bundler-cache: true
35
+ cache-version: 0
36
+ working-directory: docs
37
+
38
+ - name: Setup Pages
39
+ id: pages
40
+ uses: actions/configure-pages@v5
41
+
42
+ - name: Build with Jekyll
43
+ run: bundle exec jekyll build --verbose --trace --baseurl "${{ steps.pages.outputs.base_path }}"
44
+ working-directory: docs
45
+ env:
46
+ JEKYLL_ENV: production
47
+
48
+ - name: Upload artifact
49
+ uses: actions/upload-pages-artifact@v4
50
+ with:
51
+ path: docs/_site
52
+
53
+ deploy:
54
+ environment:
55
+ name: github-pages
56
+ url: ${{ steps.deployment.outputs.page_url }}
57
+ if: ${{ github.ref == 'refs/heads/main' }}
58
+ runs-on: ubuntu-latest
59
+ needs: build
60
+ steps:
61
+ - name: Deploy to GitHub Pages
62
+ id: deployment
63
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,97 @@
1
+ name: links
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ paths:
8
+ - 'docs/**'
9
+ pull_request:
10
+ paths:
11
+ - 'docs/**'
12
+
13
+ # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
14
+ permissions:
15
+ contents: read
16
+ pull-requests: write
17
+
18
+ jobs:
19
+ link_checker:
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v6
23
+
24
+ - uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: '3.4'
27
+ bundler-cache: true
28
+ working-directory: docs
29
+
30
+ - name: Build site
31
+ env:
32
+ JEKYLL_ENV: production
33
+ run: bundle exec jekyll build --trace
34
+ working-directory: docs
35
+
36
+ - name: Restore lychee cache
37
+ uses: actions/cache@v4
38
+ with:
39
+ path: .lycheecache
40
+ key: cache-lychee-${{ github.sha }}
41
+ restore-keys: cache-lychee-
42
+
43
+ - name: Check if site was built
44
+ run: |
45
+ if [ ! -d "_site" ]; then
46
+ echo "Error: _site directory not created"
47
+ exit 1
48
+ fi
49
+ echo "Site built successfully"
50
+ ls -la _site/
51
+ working-directory: docs
52
+
53
+ - name: Link Checker (Built Site)
54
+ uses: lycheeverse/lychee-action@v2
55
+ with:
56
+ args: >-
57
+ --verbose
58
+ --no-progress
59
+ --config lychee.toml
60
+ --root-dir "$(pwd)/_site"
61
+ --scheme https,http
62
+ '_site/**/*.html'
63
+ fail: true
64
+ output: link-check-results.md
65
+ format: markdown
66
+ workingDirectory: docs
67
+
68
+ - name: Upload link check results
69
+ if: always()
70
+ uses: actions/upload-artifact@v4
71
+ with:
72
+ name: link-check-results
73
+ path: |
74
+ docs/link-check-results.md
75
+ retention-days: 30
76
+
77
+ - name: Comment PR with results
78
+ if: failure() && github.event_name == 'pull_request'
79
+ uses: actions/github-script@v7
80
+ with:
81
+ script: |
82
+ const fs = require('fs');
83
+ let comment = '## Link Check Failed\n\n';
84
+
85
+ if (fs.existsSync('docs/link-check-results.md')) {
86
+ const results = fs.readFileSync('docs/link-check-results.md', 'utf8');
87
+ comment += '### Built Site Results\n\n' + results + '\n\n';
88
+ }
89
+
90
+ comment += '\n---\n\n*Please fix the broken links and push a new commit.*';
91
+
92
+ github.rest.issues.createComment({
93
+ issue_number: context.issue.number,
94
+ owner: context.repo.owner,
95
+ repo: context.repo.repo,
96
+ body: comment
97
+ });
data/.gitignore CHANGED
@@ -10,3 +10,7 @@
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
12
  Gemfile.lock
13
+ docs/_site/
14
+ docs/.jekyll-cache/
15
+ docs/.bundle/
16
+ docs/vendor/
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-04-13 10:04:56 UTC using RuboCop version 1.86.1.
3
+ # on 2026-04-14 23:12:52 UTC using RuboCop version 1.86.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -11,17 +11,29 @@ Gemspec/RequiredRubyVersion:
11
11
  Exclude:
12
12
  - 'prosereflect.gemspec'
13
13
 
14
- # Offense count: 5
14
+ # Offense count: 2
15
15
  # This cop supports safe autocorrection (--autocorrect).
16
- # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
17
- # SupportedHashRocketStyles: key, separator, table
18
- # SupportedColonStyles: key, separator, table
19
- # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
20
- Layout/HashAlignment:
16
+ Layout/ElseAlignment:
21
17
  Exclude:
22
- - 'spec/prosereflect/schema/conftest.rb'
18
+ - 'lib/prosereflect/schema/schema_main.rb'
23
19
 
24
- # Offense count: 80
20
+ # Offense count: 1
21
+ # This cop supports safe autocorrection (--autocorrect).
22
+ # Configuration parameters: EnforcedStyleAlignWith.
23
+ # SupportedStylesAlignWith: keyword, variable, start_of_line
24
+ Layout/EndAlignment:
25
+ Exclude:
26
+ - 'lib/prosereflect/schema/schema_main.rb'
27
+
28
+ # Offense count: 1
29
+ # This cop supports safe autocorrection (--autocorrect).
30
+ # Configuration parameters: Width, EnforcedStyleAlignWith, AllowedPatterns.
31
+ # SupportedStylesAlignWith: start_of_line, relative_to_receiver
32
+ Layout/IndentationWidth:
33
+ Exclude:
34
+ - 'lib/prosereflect/schema/schema_main.rb'
35
+
36
+ # Offense count: 264
25
37
  # This cop supports safe autocorrection (--autocorrect).
26
38
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
27
39
  # URISchemes: http, https
@@ -29,20 +41,14 @@ Layout/LineLength:
29
41
  Enabled: false
30
42
 
31
43
  # Offense count: 5
32
- # This cop supports safe autocorrection (--autocorrect).
33
- # Configuration parameters: AllowInHeredoc.
34
- Layout/TrailingWhitespace:
35
- Exclude:
36
- - 'spec/prosereflect/schema/conftest.rb'
37
-
38
- # Offense count: 4
39
44
  # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
40
45
  Lint/DuplicateBranch:
41
46
  Exclude:
42
47
  - 'lib/prosereflect/input/html.rb'
43
48
  - 'lib/prosereflect/schema/attribute.rb'
49
+ - 'lib/prosereflect/schema/content_match.rb'
44
50
  - 'lib/prosereflect/schema/mark.rb'
45
- - 'lib/prosereflect/schema/schema_class.rb'
51
+ - 'spec/fixtures/test_builder/helpers.rb'
46
52
 
47
53
  # Offense count: 1
48
54
  # This cop supports safe autocorrection (--autocorrect).
@@ -52,84 +58,60 @@ Lint/UnusedMethodArgument:
52
58
  Exclude:
53
59
  - 'lib/prosereflect/schema/node.rb'
54
60
 
55
- # Offense count: 34
61
+ # Offense count: 57
56
62
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
57
63
  Metrics/AbcSize:
58
- Exclude:
59
- - 'lib/prosereflect/input/html.rb'
60
- - 'lib/prosereflect/node.rb'
61
- - 'lib/prosereflect/output/html.rb'
62
- - 'lib/prosereflect/parser.rb'
63
- - 'lib/prosereflect/schema/fragment.rb'
64
- - 'lib/prosereflect/schema/mark_type.rb'
65
- - 'lib/prosereflect/schema/node.rb'
66
- - 'lib/prosereflect/schema/node_type.rb'
67
- - 'lib/prosereflect/schema/schema_class.rb'
68
- - 'spec/support/matchers.rb'
64
+ Enabled: false
65
+
66
+ # Offense count: 1
67
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
68
+ # AllowedMethods: refine
69
+ Metrics/BlockLength:
70
+ Max: 27
69
71
 
70
72
  # Offense count: 1
71
73
  # Configuration parameters: CountBlocks, CountModifierForms.
72
74
  Metrics/BlockNesting:
73
75
  Max: 4
74
76
 
75
- # Offense count: 30
77
+ # Offense count: 57
76
78
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
77
79
  Metrics/CyclomaticComplexity:
78
- Exclude:
79
- - 'lib/prosereflect/code_block.rb'
80
- - 'lib/prosereflect/input/html.rb'
81
- - 'lib/prosereflect/node.rb'
82
- - 'lib/prosereflect/output/html.rb'
83
- - 'lib/prosereflect/parser.rb'
84
- - 'lib/prosereflect/schema/attribute.rb'
85
- - 'lib/prosereflect/schema/fragment.rb'
86
- - 'lib/prosereflect/schema/mark_type.rb'
87
- - 'lib/prosereflect/schema/node.rb'
88
- - 'lib/prosereflect/schema/node_type.rb'
89
- - 'lib/prosereflect/schema/schema_class.rb'
90
- - 'spec/support/matchers.rb'
80
+ Enabled: false
91
81
 
92
- # Offense count: 45
82
+ # Offense count: 82
93
83
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
94
84
  Metrics/MethodLength:
95
- Max: 84
85
+ Max: 93
96
86
 
97
- # Offense count: 2
87
+ # Offense count: 9
98
88
  # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
99
89
  Metrics/ParameterLists:
100
90
  Max: 8
101
91
 
102
- # Offense count: 30
92
+ # Offense count: 52
103
93
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
104
94
  Metrics/PerceivedComplexity:
105
- Exclude:
106
- - 'lib/prosereflect/code_block.rb'
107
- - 'lib/prosereflect/input/html.rb'
108
- - 'lib/prosereflect/node.rb'
109
- - 'lib/prosereflect/output/html.rb'
110
- - 'lib/prosereflect/parser.rb'
111
- - 'lib/prosereflect/schema/fragment.rb'
112
- - 'lib/prosereflect/schema/mark_type.rb'
113
- - 'lib/prosereflect/schema/node.rb'
114
- - 'lib/prosereflect/schema/node_type.rb'
115
- - 'lib/prosereflect/schema/schema_class.rb'
116
- - 'spec/support/matchers.rb'
95
+ Enabled: false
117
96
 
118
- # Offense count: 4
97
+ # Offense count: 7
119
98
  # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
120
99
  # AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
121
100
  Naming/MethodParameterName:
122
101
  Exclude:
102
+ - 'lib/prosereflect/schema/content_match.rb'
123
103
  - 'lib/prosereflect/schema/fragment.rb'
104
+ - 'lib/prosereflect/schema/mark.rb'
124
105
  - 'lib/prosereflect/schema/node.rb'
125
106
 
126
- # Offense count: 6
107
+ # Offense count: 8
127
108
  # Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
128
109
  # AllowedMethods: call
129
110
  # WaywardPredicates: infinite?, nonzero?
130
111
  Naming/PredicateMethod:
131
112
  Exclude:
132
113
  - 'lib/prosereflect/schema/attribute.rb'
114
+ - 'lib/prosereflect/schema/content_match.rb'
133
115
  - 'lib/prosereflect/schema/node.rb'
134
116
 
135
117
  # Offense count: 12
@@ -160,12 +142,12 @@ RSpec/ContextWording:
160
142
  - 'spec/prosereflect/schema/conftest.rb'
161
143
  - 'spec/support/shared_examples.rb'
162
144
 
163
- # Offense count: 142
145
+ # Offense count: 254
164
146
  # Configuration parameters: CountAsOne.
165
147
  RSpec/ExampleLength:
166
148
  Max: 134
167
149
 
168
- # Offense count: 73
150
+ # Offense count: 158
169
151
  RSpec/MultipleExpectations:
170
152
  Max: 8
171
153
 
@@ -174,24 +156,28 @@ RSpec/MultipleExpectations:
174
156
  RSpec/NestedGroups:
175
157
  Max: 4
176
158
 
159
+ # Offense count: 1
160
+ # Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector.
161
+ # SupportedInflectors: default, active_support
162
+ RSpec/SpecFilePathFormat:
163
+ Exclude:
164
+ - 'spec/prosereflect/schema/schema_spec.rb'
165
+
177
166
  # Offense count: 2
178
167
  # This cop supports unsafe autocorrection (--autocorrect-all).
179
168
  Style/IdenticalConditionalBranches:
180
169
  Exclude:
181
170
  - 'lib/prosereflect/schema/mark.rb'
182
171
 
183
- # Offense count: 2
184
- # This cop supports safe autocorrection (--autocorrect).
185
- # Configuration parameters: EnforcedStyleForMultiline.
186
- # SupportedStylesForMultiline: comma, consistent_comma, diff_comma, no_comma
187
- Style/TrailingCommaInArguments:
172
+ # Offense count: 1
173
+ # Configuration parameters: EnforcedStyle.
174
+ # SupportedStyles: allow_single_line, disallow
175
+ Style/NumberedParameters:
188
176
  Exclude:
189
- - 'spec/prosereflect/schema/conftest.rb'
177
+ - 'lib/prosereflect/schema/content_match.rb'
190
178
 
191
- # Offense count: 4
192
- # This cop supports safe autocorrection (--autocorrect).
193
- # Configuration parameters: EnforcedStyleForMultiline.
194
- # SupportedStylesForMultiline: comma, consistent_comma, diff_comma, no_comma
195
- Style/TrailingCommaInHashLiteral:
179
+ # Offense count: 1
180
+ # Configuration parameters: AllowedClasses.
181
+ Style/OneClassPerFile:
196
182
  Exclude:
197
- - 'spec/prosereflect/schema/conftest.rb'
183
+ - 'lib/prosereflect/schema.rb'
data/README.adoc CHANGED
@@ -14,6 +14,8 @@ accessing the hierarchical document tree structure represented in ProseMirror's
14
14
  JSON/YAML format. This allows for convenient traversal and extraction of content
15
15
  from rich text documents.
16
16
 
17
+ https://metanorma.org/prosereflect/[Full documentation] is available on the docs site.
18
+
17
19
 
18
20
  == Installation
19
21
 
data/docs/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "jekyll", "~> 4.3"
4
+ gem "jekyll-asciidoc"
5
+ gem "just-the-docs"
6
+
7
+ group :jekyll_plugins do
8
+ gem "jekyll-seo-tag"
9
+ gem "jekyll-sitemap"
10
+ end
data/docs/INDEX.adoc ADDED
@@ -0,0 +1,45 @@
1
+ ---
2
+ layout: default
3
+ title: Home
4
+ nav_order: 1
5
+ ---
6
+
7
+ = Prosereflect Documentation
8
+
9
+ `prosereflect` is a Ruby gem for working with the document structure used by the https://prosemirror.net/[ProseMirror rich text editor].
10
+
11
+ It provides a set of models and utilities for parsing, manipulating, and accessing the hierarchical document tree structure represented in ProseMirror's JSON/YAML format.
12
+
13
+ == Quick Start
14
+
15
+ Install the gem:
16
+
17
+ [source,sh]
18
+ ----
19
+ gem install prosereflect
20
+ ----
21
+
22
+ Parse a document:
23
+
24
+ [source,ruby]
25
+ ----
26
+ require 'prosereflect'
27
+
28
+ doc = Prosereflect::Parser.parse_document({
29
+ "type" => "doc",
30
+ "content" => [
31
+ { "type" => "paragraph", "content" => [{ "type" => "text", "text" => "Hello world" }] }
32
+ ]
33
+ })
34
+ ----
35
+
36
+ == Documentation Sections
37
+
38
+ * x:features:node-types[Node Types] -- All available node types and their attributes
39
+ * x:features:marks[Marks] -- Text formatting marks (bold, italic, links, etc.)
40
+ * x:understanding:document-model[Document Model] -- Node hierarchy and content model
41
+ * x:understanding:fragment[Fragment] -- Flat content collections
42
+ * x:understanding:resolved-position[Resolved Positions] -- Position resolution in the document tree
43
+ * x:advanced:transform[Transforms] -- Document transformations and step-based editing
44
+ * x:advanced:schema[Schema] -- Schema definition and validation
45
+ * x:guides:round-trip-html[HTML Round-Trip] -- Convert between HTML and ProseMirror documents
@@ -0,0 +1,15 @@
1
+ ---
2
+ layout: default
3
+ title: Advanced
4
+ nav_order: 5
5
+ has_children: true
6
+ ---
7
+ = Advanced
8
+
9
+ This section covers advanced topics for power users.
10
+
11
+ * x:transform[Transforms] -- Step-based document transformations
12
+ * x:steps[Step Types] -- Individual step types and their behavior
13
+ * x:step-map[Step Maps and Mappings] -- Position tracking through transforms
14
+ * x:schema[Schema] -- Schema definition and content validation
15
+ * x:test-builder[Test Builder] -- DSL for building test documents
@@ -0,0 +1,112 @@
1
+ ---
2
+ layout: default
3
+ title: Schema
4
+ parent: Advanced
5
+ nav_order: 4
6
+ ---
7
+ = Schema
8
+
9
+ `Prosereflect::Schema` defines the structure of valid documents: which node types exist, what content they can contain, and which marks are allowed.
10
+
11
+ == Creating a Schema
12
+
13
+ [source,ruby]
14
+ ----
15
+ schema = Prosereflect::Schema.new(
16
+ nodes_spec: {
17
+ "doc" => { content: "block+" },
18
+ "paragraph" => { content: "inline*", group: "block" },
19
+ "heading" => { content: "inline*", group: "block", attrs: { "level" => { "default" => 1 } } },
20
+ "text" => { group: "inline" }
21
+ },
22
+ marks_spec: {
23
+ "bold" => {},
24
+ "italic" => {},
25
+ "link" => { attrs: { "href" => {} } }
26
+ }
27
+ )
28
+ ----
29
+
30
+ == Requirements
31
+
32
+ Every schema must define:
33
+
34
+ * A `"doc"` node type (the top-level container)
35
+ * A `"text"` node type (inline text)
36
+ * At least one block node type in the doc's content expression
37
+
38
+ == Content Expressions
39
+
40
+ Content expressions define what children a node can have. Supported syntax:
41
+
42
+ * `"block+"` -- one or more block nodes
43
+ * `"inline*"` -- zero or more inline nodes
44
+ * `"paragraph heading"` -- a paragraph followed by a heading
45
+ * `"(paragraph | heading)"` -- either paragraph or heading
46
+ * `"block{2,4}"` -- between 2 and 4 block nodes
47
+ * `"block?"` -- optional block node
48
+
49
+ == NodeType
50
+
51
+ Access and use node types from a schema:
52
+
53
+ [source,ruby]
54
+ ----
55
+ para_type = schema.node_type("paragraph")
56
+ para_type.name # => "paragraph"
57
+ para_type.is_block? # => true
58
+ para_type.is_inline? # => false
59
+ para_type.is_textblock? # => true
60
+ para_type.is_leaf? # => false
61
+ para_type.is_atom? # => false
62
+ ----
63
+
64
+ Creating validated nodes:
65
+
66
+ [source,ruby]
67
+ ----
68
+ # Create with validation
69
+ node = para_type.create_checked(nil, [text_node])
70
+
71
+ # Create with defaults
72
+ node = para_type.create_and_fill
73
+
74
+ # Check content validity
75
+ para_type.valid_content?(fragment)
76
+ ----
77
+
78
+ == MarkType
79
+
80
+ Access and use mark types:
81
+
82
+ [source,ruby]
83
+ ----
84
+ bold_type = schema.mark_type("bold")
85
+ mark = bold_type.create # Schema::Mark instance
86
+ mark.attrs # => {}
87
+
88
+ link_type = schema.mark_type("link")
89
+ link = link_type.create("href" => "https://example.com")
90
+ link.attrs # => {"href" => "https://example.com"}
91
+ ----
92
+
93
+ == ContentMatch
94
+
95
+ `ContentMatch` is the engine that validates content expressions. It uses an NFA/DFA approach to parse and match content expressions:
96
+
97
+ * `match_type(node_type)` -- try to match a node type, returns next match state or nil
98
+ * `match_fragment(fragment)` -- match a full fragment
99
+ * `valid_end` -- whether this state is a valid end state
100
+ * `fill_before(after:, to_end:)` -- compute filler content
101
+ * `find_wrapping(target_type)` -- find wrapping nodes for content
102
+ * `inline_content?` -- whether this match accepts inline content
103
+ * `default_type` -- the default node type for this match
104
+
105
+ == Validation Errors
106
+
107
+ The schema raises `Prosereflect::SchemaErrors::ValidationError` for:
108
+
109
+ * Missing required node types (doc, text)
110
+ * Name collisions between nodes and marks
111
+ * Invalid content in created nodes
112
+ * Missing required attributes
@@ -0,0 +1,66 @@
1
+ ---
2
+ layout: default
3
+ title: Step Maps and Mappings
4
+ parent: Advanced
5
+ nav_order: 3
6
+ ---
7
+ = Step Maps and Mappings
8
+
9
+ When steps are applied to a document, positions in the original document may no longer correspond to the same locations. Step maps and mappings track these changes.
10
+
11
+ == StepMap
12
+
13
+ `Prosereflect::Transform::StepMap` maps positions through a single step. It stores an array of ranges `[old_start, old_end, new_start, new_end]`.
14
+
15
+ [source,ruby]
16
+ ----
17
+ # Create a step map
18
+ map = Prosereflect::Transform::StepMap.new([[0, 5, 0, 8]])
19
+
20
+ # Map a position
21
+ map.map(3) # => new position after the step
22
+
23
+ # Check if a position was deleted
24
+ map.deleted?(3) # => true/false
25
+
26
+ # Map with deletion info
27
+ result = map.map_result(3)
28
+ result.pos # => new position
29
+ result.deleted # => whether the position was deleted
30
+ result.transformed # => whether the position changed
31
+ ----
32
+
33
+ === Factory Methods
34
+
35
+ * `StepMap.empty` -- identity map (no changes)
36
+ * `StepMap.delete(from, to)` -- map for a deletion
37
+ * `StepMap.replace(from, to, target_from, target_to)` -- map for a replacement
38
+
39
+ == Mapping
40
+
41
+ `Prosereflect::Transform::Mapping` composes multiple step maps to track positions through a full transform chain.
42
+
43
+ [source,ruby]
44
+ ----
45
+ mapping = Prosereflect::Transform::Mapping.new
46
+ mapping.add_map(step_map_1)
47
+ mapping.add_map(step_map_2)
48
+
49
+ # Map a position through all steps
50
+ mapping.map(5) # => final position
51
+
52
+ # Map with deletion tracking
53
+ result = mapping.map_result(5)
54
+ result[:pos] # => final position
55
+ result[:deleted] # => whether deleted by any step
56
+
57
+ # Map backwards
58
+ mapping.map_reverse(8) # => original position
59
+ ----
60
+
61
+ === Checking Deletions
62
+
63
+ [source,ruby]
64
+ ----
65
+ mapping.map_deletes(5) # => whether position 5 was deleted by any step
66
+ ----