markdown_composer 0.7.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 (116) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +23 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +278 -0
  5. data/ROADMAP.md +80 -0
  6. data/docs/_md_composer_architecture.md +50 -0
  7. data/docs/_md_composer_cheatsheet.md +72 -0
  8. data/docs/_md_composer_concepts.md +64 -0
  9. data/docs/_md_composer_dev_guide.md +55 -0
  10. data/docs/_md_composer_getting_started.md +114 -0
  11. data/docs/_md_composer_readme.md +93 -0
  12. data/docs/_md_composer_user_guide.md +65 -0
  13. data/docs/ai/md_composer_ai_audit.md +35 -0
  14. data/docs/ai/md_composer_ai_canonical_docs.md +44 -0
  15. data/docs/ai/md_composer_ai_source_map.md +39 -0
  16. data/docs/compose/md_composer_compose_actions.md +338 -0
  17. data/docs/compose/md_composer_compose_anatomy.md +156 -0
  18. data/docs/compose/md_composer_compose_buffer.md +81 -0
  19. data/docs/compose/md_composer_compose_examples.md +31 -0
  20. data/docs/compose/md_composer_compose_include.md +136 -0
  21. data/docs/compose/md_composer_compose_select.md +198 -0
  22. data/docs/compose/md_composer_compose_sources.md +161 -0
  23. data/docs/compose/md_composer_compose_targets.md +194 -0
  24. data/docs/examples/md_composer_example_basic_compose.md +57 -0
  25. data/docs/examples/md_composer_example_buffer_target_actions.md +83 -0
  26. data/docs/examples/md_composer_example_fixtures.md +62 -0
  27. data/docs/examples/md_composer_example_html_output.md +50 -0
  28. data/docs/examples/md_composer_example_modify.md +77 -0
  29. data/docs/examples/md_composer_example_multi_row_compose.md +67 -0
  30. data/docs/examples/md_composer_example_ruby_plans.md +62 -0
  31. data/docs/examples/md_composer_example_structured_data.md +68 -0
  32. data/docs/examples/md_composer_example_transforms.md +68 -0
  33. data/docs/examples/md_composer_example_yaml_json_rows.md +56 -0
  34. data/docs/examples/md_composer_examples_readme.md +45 -0
  35. data/docs/examples/md_composer_runnable_examples.md +374 -0
  36. data/docs/examples/md_composer_source_ruby_dsl.md +88 -0
  37. data/docs/reference/md_composer_nested.md +170 -0
  38. data/docs/reference/md_composer_reference_api.md +71 -0
  39. data/docs/reference/md_composer_reference_capabilities.md +63 -0
  40. data/docs/reference/md_composer_reference_diagnostics.md +54 -0
  41. data/docs/reference/md_composer_reference_plan_schema.md +75 -0
  42. data/docs/reference/md_composer_reference_registries.md +63 -0
  43. data/docs/reference/md_composer_take.md +221 -0
  44. data/docs/reference/md_composer_unit_tokens.md +228 -0
  45. data/docs/reference/md_composer_where.md +227 -0
  46. data/docs/transform/md_composer_transform_anatomy.md +112 -0
  47. data/docs/transform/md_composer_transform_examples.md +30 -0
  48. data/docs/transform/md_composer_transform_modes.md +83 -0
  49. data/docs/transform/md_composer_transform_options.md +142 -0
  50. data/docs/transform/md_composer_transform_scope.md +97 -0
  51. data/docs/transform/md_composer_transform_transforms.md +99 -0
  52. data/examples/README.md +20 -0
  53. data/examples/advanced_composer.rb +207 -0
  54. data/examples/basic_compose.rb +24 -0
  55. data/examples/complex_composer.rb +235 -0
  56. data/examples/example_support.rb +18 -0
  57. data/examples/fixtures/current.md +179 -0
  58. data/examples/fixtures/faq.md +58 -0
  59. data/examples/fixtures/guide.md +62 -0
  60. data/examples/fixtures/site_intro.md +29 -0
  61. data/examples/fixtures/source.html +22 -0
  62. data/examples/html_input.rb +26 -0
  63. data/examples/output/advanced_composer.md +76 -0
  64. data/examples/output/basic_compose.md +25 -0
  65. data/examples/output/complex_composer.md +85 -0
  66. data/examples/output/html_input.md +4 -0
  67. data/examples/output/source_list_dsl.md +126 -0
  68. data/examples/output/standard_composer.md +46 -0
  69. data/examples/output/standard_sources_buffer.md +31 -0
  70. data/examples/output/yaml_plan.md +43 -0
  71. data/examples/plans/basic.yml +20 -0
  72. data/examples/source_list_dsl.rb +41 -0
  73. data/examples/standard_composer.rb +42 -0
  74. data/examples/standard_sources_buffer.rb +62 -0
  75. data/examples/yaml_plan.rb +17 -0
  76. data/lib/markdown_composer/capabilities.rb +223 -0
  77. data/lib/markdown_composer/composition_buffer.rb +378 -0
  78. data/lib/markdown_composer/data_path.rb +313 -0
  79. data/lib/markdown_composer/diagnostics.rb +63 -0
  80. data/lib/markdown_composer/document_index/html_parser.rb +84 -0
  81. data/lib/markdown_composer/document_index/markdown_parser.rb +338 -0
  82. data/lib/markdown_composer/document_index.rb +94 -0
  83. data/lib/markdown_composer/executor.rb +284 -0
  84. data/lib/markdown_composer/markdown_renderer.rb +105 -0
  85. data/lib/markdown_composer/plan.rb +436 -0
  86. data/lib/markdown_composer/plan_builder.rb +111 -0
  87. data/lib/markdown_composer/registries/action_entries.rb +26 -0
  88. data/lib/markdown_composer/registries/condition_entries.rb +58 -0
  89. data/lib/markdown_composer/registries/registry.rb +69 -0
  90. data/lib/markdown_composer/registries/source_entries.rb +18 -0
  91. data/lib/markdown_composer/registries/support_values.rb +23 -0
  92. data/lib/markdown_composer/registries/take_entries.rb +31 -0
  93. data/lib/markdown_composer/registries/take_registry.rb +18 -0
  94. data/lib/markdown_composer/registries/target_entries.rb +40 -0
  95. data/lib/markdown_composer/registries/unit_token_entries.rb +62 -0
  96. data/lib/markdown_composer/registries/where_registry.rb +84 -0
  97. data/lib/markdown_composer/registries.rb +46 -0
  98. data/lib/markdown_composer/result.rb +34 -0
  99. data/lib/markdown_composer/selection_resolver.rb +181 -0
  100. data/lib/markdown_composer/source.rb +57 -0
  101. data/lib/markdown_composer/source_list_builder.rb +47 -0
  102. data/lib/markdown_composer/take.rb +129 -0
  103. data/lib/markdown_composer/transform_options.rb +66 -0
  104. data/lib/markdown_composer/transform_runner/content_placement.rb +63 -0
  105. data/lib/markdown_composer/transform_runner/field_interpolator.rb +213 -0
  106. data/lib/markdown_composer/transform_runner/heading_numbering.rb +106 -0
  107. data/lib/markdown_composer/transform_runner/scope_resolver.rb +87 -0
  108. data/lib/markdown_composer/transform_runner.rb +264 -0
  109. data/lib/markdown_composer/transforms/default_entries.rb +31 -0
  110. data/lib/markdown_composer/transforms/registry.rb +11 -0
  111. data/lib/markdown_composer/validator.rb +378 -0
  112. data/lib/markdown_composer/value_object.rb +15 -0
  113. data/lib/markdown_composer/version.rb +5 -0
  114. data/lib/markdown_composer/where.rb +313 -0
  115. data/lib/markdown_composer.rb +114 -0
  116. metadata +260 -0
@@ -0,0 +1,338 @@
1
+ ---
2
+ title: Markdown Composer Compose Actions
3
+ type: guide
4
+ status: current
5
+ updated: 2026-06-01
6
+ description: Public guide to compose actions, target rules, modify, and buffer-target actions.
7
+ ---
8
+
9
+ # Markdown Composer Compose Actions
10
+
11
+ ### References
12
+
13
+ | What | Where |
14
+ |------|-------|
15
+ | Compose anatomy | [./md_composer_compose_anatomy.md](./md_composer_compose_anatomy.md) |
16
+ | Targets | [./md_composer_compose_targets.md](./md_composer_compose_targets.md) |
17
+ | Modify example | [../examples/md_composer_example_modify.md](../examples/md_composer_example_modify.md) |
18
+
19
+ ---
20
+
21
+ ## 1. Purpose
22
+
23
+ `action` tells Markdown Composer how a compose row changes the output buffer.
24
+
25
+ ```ruby
26
+ { "select" => "heading_2_section[first:1]", "action" => "set" }
27
+ ```
28
+
29
+ If omitted, `action` defaults to `set`.
30
+
31
+ ## 2. Syntax Anatomy
32
+
33
+ An action is one field in the compose row, but it only makes sense beside `select`, `include`, and sometimes `target`.
34
+
35
+ ```text
36
+ compose_row = source + select + include + action + target
37
+
38
+ action = action_token
39
+
40
+ action_token = set
41
+ | append
42
+ | prepend
43
+ | insert_before
44
+ | insert_after
45
+ | insert_between
46
+ | replace
47
+ | copy
48
+ | move
49
+ | modify
50
+ | remove_buffer_target
51
+ | transform_buffer_target
52
+
53
+ target_selector = unit_token [take] [where condition]
54
+ ```
55
+
56
+ The target selector belongs to the `target` field, but action rules decide when it is required:
57
+
58
+ ```text
59
+ replace target = target_selector | whole output | output
60
+
61
+ insert_before target = target_selector
62
+ insert_after target = target_selector
63
+ insert_between target = between target_selector and target_selector
64
+
65
+ remove_buffer_target target = target_selector
66
+ transform_buffer_target target = target_selector
67
+
68
+ modify target = start | end | before target_selector | after target_selector
69
+ | between target_selector and target_selector | in_place
70
+ ```
71
+
72
+ Aliases are normalized before execution:
73
+
74
+ | Alias | Normal action |
75
+ |-------|---------------|
76
+ | `take` | `set` |
77
+ | `insert before` | `insert_before` |
78
+ | `insert after` | `insert_after` |
79
+ | `insert between` | `insert_between` |
80
+ | `remove` | `remove_buffer_target` when used as a buffer-target action |
81
+
82
+ ## 3. Action Decision Table
83
+
84
+ | Need | Use |
85
+ |------|-----|
86
+ | Start or replace the whole output buffer. | `set` |
87
+ | Add selected source content to the end. | `append` |
88
+ | Add selected source content to the start. | `prepend` |
89
+ | Insert selected content before a buffer match. | `insert_before` |
90
+ | Insert selected content after a buffer match. | `insert_after` |
91
+ | Insert selected content between two buffer matches. | `insert_between` |
92
+ | Replace buffer content with selected source content. | `replace` |
93
+ | Duplicate selected content near a target. | `copy` |
94
+ | Move selected buffer content near a target. | `move` |
95
+ | Transform selected source content before placing it. | `modify` |
96
+ | Remove existing buffer content by target selector. | `remove_buffer_target` |
97
+ | Transform existing buffer content by target selector. | `transform_buffer_target` |
98
+
99
+ ## 4. Actions
100
+
101
+ ### 4.1. Set
102
+
103
+ `set` replaces the whole buffer with selected and included source content. It is the default action.
104
+
105
+ ```ruby
106
+ {
107
+ "select" => "heading_2_section[first:1]",
108
+ "include" => "all",
109
+ "action" => "set"
110
+ }
111
+ ```
112
+
113
+ Use `set` for the first row of most plans. A supplied custom `target` is ignored by execution because `set` always replaces the buffer.
114
+
115
+ ### 4.2. Append
116
+
117
+ `append` adds selected content to the end of the buffer.
118
+
119
+ ```ruby
120
+ {
121
+ "select" => "heading_2_section[last:1]",
122
+ "include" => "all",
123
+ "action" => "append"
124
+ }
125
+ ```
126
+
127
+ Leave `target` blank. A supplied custom `target` is ignored because append always writes to the end.
128
+
129
+ ### 4.3. Prepend
130
+
131
+ `prepend` adds selected content to the start of the buffer.
132
+
133
+ ```ruby
134
+ {
135
+ "select" => "paragraph where text:contains(\"Summary\")",
136
+ "include" => "all",
137
+ "action" => "prepend"
138
+ }
139
+ ```
140
+
141
+ Leave `target` blank. Use `insert_before` when you need a specific anchor rather than the absolute start.
142
+
143
+ ### 4.4. Insert Before
144
+
145
+ `insert_before` places selected source content before a target selector in the current buffer.
146
+
147
+ ```ruby
148
+ {
149
+ "select" => "paragraph where text:contains(\"Important\")",
150
+ "include" => "all",
151
+ "action" => "insert_before",
152
+ "target" => "heading_2 where text:contains(\"API\")"
153
+ }
154
+ ```
155
+
156
+ The target must be a selector, not `start` or `end`. The selector uses target anatomy:
157
+
158
+ ```text
159
+ unit_token[take] where condition
160
+ ```
161
+
162
+ ### 4.5. Insert After
163
+
164
+ `insert_after` places selected source content after a target selector in the current buffer.
165
+
166
+ ```ruby
167
+ {
168
+ "select" => "code_block where language:equals(\"ruby\")",
169
+ "include" => "all",
170
+ "action" => "insert_after",
171
+ "target" => "heading_3 where text:contains(\"Example\")"
172
+ }
173
+ ```
174
+
175
+ Use it when the target anchor should remain before the inserted content.
176
+
177
+ ### 4.6. Insert Between
178
+
179
+ `insert_between` places selected source content between two buffer anchors.
180
+
181
+ ```ruby
182
+ {
183
+ "select" => "paragraph where text:contains(\"Release note\")",
184
+ "include" => "all",
185
+ "action" => "insert_between",
186
+ "target" => "between heading_2 where text:contains(\"Start\") and heading_2 where text:contains(\"End\")"
187
+ }
188
+ ```
189
+
190
+ The start anchor must resolve before the end anchor. Otherwise the target is invalid for insertion.
191
+
192
+ ### 4.7. Replace
193
+
194
+ `replace` replaces matching buffer content with selected source content.
195
+
196
+ ```ruby
197
+ {
198
+ "select" => "heading_2_section where title:equals(\"New API\")",
199
+ "include" => "all",
200
+ "action" => "replace",
201
+ "target" => "heading_2_section where title:equals(\"Old API\")"
202
+ }
203
+ ```
204
+
205
+ Use a selector target for precise replacement. Use `whole output` only when replacing the entire buffer is the intended result.
206
+
207
+ ### 4.8. Copy
208
+
209
+ `copy` duplicates selected content near a buffer target. It does not remove the source selection.
210
+
211
+ ```ruby
212
+ {
213
+ "source" => "buffer",
214
+ "select" => "heading_2_section where title:equals(\"Install\")",
215
+ "include" => "all",
216
+ "action" => "copy",
217
+ "target" => "after heading_2 where text:contains(\"Quickstart\")"
218
+ }
219
+ ```
220
+
221
+ Use `source: "buffer"` when copying content that is already in the composition buffer.
222
+
223
+ ### 4.9. Move
224
+
225
+ `move` removes selected buffer content from its original location and inserts it at the target.
226
+
227
+ ```ruby
228
+ {
229
+ "source" => "buffer",
230
+ "select" => "heading_2_section where title:equals(\"Appendix\")",
231
+ "include" => "all",
232
+ "action" => "move",
233
+ "target" => "end"
234
+ }
235
+ ```
236
+
237
+ `move` is most predictable when the selection comes from `source: "buffer"` because the action is relocating existing buffer content.
238
+
239
+ ### 4.10. Modify
240
+
241
+ `modify` transforms selected source content in a temporary fragment, then places the transformed fragment at `target`.
242
+
243
+ ```ruby
244
+ {
245
+ "select" => "heading_2_section where title:equals(\"Draft\")",
246
+ "include" => "all",
247
+ "action" => "modify",
248
+ "target" => "end",
249
+ "transforms" => [
250
+ {
251
+ "scope" => "paragraph",
252
+ "transform" => "replace_text",
253
+ "mode" => "literal",
254
+ "options" => { "from" => "Draft", "to" => "Final" }
255
+ }
256
+ ]
257
+ }
258
+ ```
259
+
260
+ Execution shape:
261
+
262
+ 1. Select source content.
263
+ 2. Apply `include`.
264
+ 3. Build a temporary fragment.
265
+ 4. Run nested transforms against that fragment.
266
+ 5. Place the transformed fragment at `target`.
267
+
268
+ No target means `end`. `modify` does not edit existing buffer content unless `target` is `in_place`.
269
+
270
+ ### 4.11. Modify In Place
271
+
272
+ `target: "in_place"` is a special `modify` target. It rewrites selected buffer content inline.
273
+
274
+ ```ruby
275
+ {
276
+ "source" => "buffer",
277
+ "select" => "paragraph where text:contains(\"Draft\")",
278
+ "include" => "all",
279
+ "action" => "modify",
280
+ "target" => "in_place",
281
+ "transforms" => [
282
+ { "transform" => "replace_text", "mode" => "literal", "options" => "from:Draft; to:Final" }
283
+ ]
284
+ }
285
+ ```
286
+
287
+ Rules:
288
+
289
+ | Rule | Meaning |
290
+ |------|---------|
291
+ | `source` must be `buffer`. | Validation checks the original source field. |
292
+ | `action` must be `modify`. | Other actions do not use `in_place`. |
293
+ | Nested transforms must be valid. | The fragment is transformed before it is written back. |
294
+
295
+ `source: "previous"` is not enough even if it resolves to the buffer; use `source: "buffer"` explicitly.
296
+
297
+ ### 4.12. Remove Buffer Target
298
+
299
+ `remove_buffer_target` removes existing buffer content matched by `target`.
300
+
301
+ ```ruby
302
+ {
303
+ "source" => "buffer",
304
+ "select" => "all",
305
+ "action" => "remove_buffer_target",
306
+ "target" => "heading_2_section where title:equals(\"Deprecated\")"
307
+ }
308
+ ```
309
+
310
+ The meaningful field is `target`, not the selected source content. The target must be a selector target, not `start`, `end`, or `whole output`.
311
+
312
+ ### 4.13. Transform Buffer Target
313
+
314
+ `transform_buffer_target` transforms existing buffer content matched by `target`.
315
+
316
+ ```ruby
317
+ {
318
+ "source" => "buffer",
319
+ "select" => "all",
320
+ "action" => "transform_buffer_target",
321
+ "target" => "heading_2_section where title:equals(\"Links\")",
322
+ "transforms" => [
323
+ { "transform" => "links", "mode" => "rewrite_url", "options" => { "from" => "http://", "to" => "https://" } }
324
+ ]
325
+ }
326
+ ```
327
+
328
+ If a nested transform omits `scope`, the action target becomes its scope. An explicit nested `scope` overrides the action target.
329
+
330
+ ## 5. Common Mistakes
331
+
332
+ | Mistake | Fix |
333
+ |---------|-----|
334
+ | Treating `modify` as the same as `transform_buffer_target`. | Use `modify` for selected source fragments; use `transform_buffer_target` for existing buffer content. |
335
+ | Using old `modify: { transforms: ... }` payloads. | Use row `"transforms" => [...]`. |
336
+ | Using `start`, `end`, or `output` with buffer-target actions. | Use a selector target. |
337
+ | Calling `take` an action. | Put take inside `select` or `include`. |
338
+ | Supplying custom targets for `set`, `append`, or `prepend`. | Leave target blank; these actions use their built-in buffer locations. |
@@ -0,0 +1,156 @@
1
+ ---
2
+ title: Markdown Composer Compose Anatomy
3
+ type: guide
4
+ status: current
5
+ updated: 2026-06-01
6
+ description: Public anatomy guide for Markdown Composer compose rows.
7
+ ---
8
+
9
+ # Markdown Composer Compose Anatomy
10
+
11
+ ### References
12
+
13
+ | What | Where |
14
+ |------|-------|
15
+ | Sources | [./md_composer_compose_sources.md](./md_composer_compose_sources.md) |
16
+ | Select | [./md_composer_compose_select.md](./md_composer_compose_select.md) |
17
+ | Include | [./md_composer_compose_include.md](./md_composer_compose_include.md) |
18
+ | Actions | [./md_composer_compose_actions.md](./md_composer_compose_actions.md) |
19
+ | Targets | [./md_composer_compose_targets.md](./md_composer_compose_targets.md) |
20
+ | Buffer | [./md_composer_compose_buffer.md](./md_composer_compose_buffer.md) |
21
+
22
+ ---
23
+
24
+ ## 1. Row Shape
25
+
26
+ A compose row builds or edits the output buffer.
27
+
28
+ ```text
29
+ Source -> Select -> Include -> Action -> Target
30
+ ```
31
+
32
+ Read it as a sentence:
33
+
34
+ ```text
35
+ From Source, select matching units, include the parts you want, then perform Action at Target.
36
+ ```
37
+
38
+ Example:
39
+
40
+ ```ruby
41
+ {
42
+ "source" => "current",
43
+ "select" => "heading_2_section where title:equals(\"API\")",
44
+ "include" => "all",
45
+ "action" => "set"
46
+ }
47
+ ```
48
+
49
+ This means: from the current source, find the H2 section titled `API`, keep the whole section, and set the buffer to that content.
50
+
51
+ ## 2. Field Responsibilities
52
+
53
+ | Field | Responsibility | Common mistake |
54
+ |-------|----------------|----------------|
55
+ | `source` | Chooses where the row reads from. | Using `buffer` before anything has created buffer content. |
56
+ | `select` | Chooses source units. | Selecting a heading node when you meant a whole section. |
57
+ | `include` | Chooses what to keep from each selected unit. | Expecting `include` to select across the whole document. It runs inside each selected unit. |
58
+ | `action` | Chooses how selected content changes the buffer. | Treating `take` as an action. Take belongs in `select` or `include`. |
59
+ | `target` | Chooses where in the buffer the action applies. | Using `start` or `end` with buffer-target actions that require selector targets. |
60
+
61
+ ## 3. Minimal Row
62
+
63
+ If you omit fields, the plan normalizes to defaults:
64
+
65
+ | Field | Default |
66
+ |-------|---------|
67
+ | `source` | `current` |
68
+ | `select` | `all` |
69
+ | `include` | `all` |
70
+ | `action` | `set` |
71
+ | `target` | action-specific default |
72
+
73
+ Minimal config:
74
+
75
+ ```ruby
76
+ config = {
77
+ "compose" => [
78
+ { "select" => "heading_2_section[first:1]" }
79
+ ]
80
+ }
81
+ ```
82
+
83
+ Because `action` defaults to `set`, this sets the buffer to the first H2 section.
84
+
85
+ ## 4. Multi-Row Composition
86
+
87
+ Rows run in order. Later rows can use earlier buffer content.
88
+
89
+ ```ruby
90
+ config = {
91
+ "compose" => [
92
+ { "select" => "heading_2_section where title:equals(\"Intro\")", "action" => "set" },
93
+ { "select" => "heading_2_section where title:equals(\"API\")", "action" => "append" },
94
+ {
95
+ "source" => "buffer",
96
+ "select" => "all",
97
+ "action" => "remove_buffer_target",
98
+ "target" => "paragraph where text:contains(\"draft\")"
99
+ }
100
+ ]
101
+ }
102
+ ```
103
+
104
+ The first row creates the buffer, the second row appends to it, and the third row removes matching content from the buffer.
105
+
106
+ ## 5. String And Hash Forms
107
+
108
+ Most author-facing fields accept compact strings or structured hashes.
109
+
110
+ ```ruby
111
+ "select" => "heading_2_section[first:1] where title:contains(\"Intro\")"
112
+ ```
113
+
114
+ Equivalent structured shape:
115
+
116
+ ```ruby
117
+ "select" => {
118
+ "type" => "heading_2_section",
119
+ "take" => { "first" => 1 },
120
+ "where" => { "field" => "title", "predicate" => "contains", "value" => "Intro" }
121
+ }
122
+ ```
123
+
124
+ Use strings for hand-written docs, spreadsheets, and examples. Use hashes for GUI builders, stored presets, and generated plans.
125
+
126
+ ## 6. Action Families
127
+
128
+ | Family | Actions | Reads selected source content? |
129
+ |--------|---------|--------------------------------|
130
+ | Buffer creation | `set` | yes |
131
+ | Buffer insertion | `append`, `prepend`, `insert_before`, `insert_after`, `insert_between` | yes |
132
+ | Buffer replacement | `replace` | yes |
133
+ | Buffer relocation | `copy`, `move` | `copy` yes; `move` should use buffer selection |
134
+ | Fragment transformation | `modify` | yes |
135
+ | Existing-buffer mutation | `remove_buffer_target`, `transform_buffer_target` | no |
136
+
137
+ `modify` is powerful because it lets one compose row select a source fragment, run nested transforms against that fragment, and place the result in the buffer.
138
+
139
+ ## 7. Validation And Diagnostics
140
+
141
+ Run validation before saving a plan:
142
+
143
+ ```ruby
144
+ validation = MarkdownComposer.validate(config: config, sources: sources)
145
+ ```
146
+
147
+ Common compose diagnostics:
148
+
149
+ | Diagnostic | Meaning |
150
+ |------------|---------|
151
+ | `source.missing` | The selected source cannot be resolved. |
152
+ | `selection.empty` | The selector matched no content. |
153
+ | `action.target_required` | The action needs a target. |
154
+ | `target.selector_required` | A buffer-target action needs a selector target. |
155
+ | `target.in_place_source_invalid` | `in_place` requires original `source: "buffer"`. |
156
+
@@ -0,0 +1,81 @@
1
+ ---
2
+ title: Markdown Composer Compose Buffer
3
+ type: guide
4
+ status: current
5
+ updated: 2026-06-01
6
+ description: Public guide to the Markdown Composer composition buffer and buffer-oriented actions.
7
+ ---
8
+
9
+ # Markdown Composer Compose Buffer
10
+
11
+ ### References
12
+
13
+ | What | Where |
14
+ |------|-------|
15
+ | Compose anatomy | [./md_composer_compose_anatomy.md](./md_composer_compose_anatomy.md) |
16
+ | Actions | [./md_composer_compose_actions.md](./md_composer_compose_actions.md) |
17
+ | Targets | [./md_composer_compose_targets.md](./md_composer_compose_targets.md) |
18
+
19
+ ---
20
+
21
+ ## 1. Purpose
22
+
23
+ The buffer is the Markdown document being built. Compose rows write to it; target matching reads from it.
24
+
25
+ ```text
26
+ row 1 -> buffer
27
+ row 2 -> buffer
28
+ row 3 -> buffer
29
+ transforms -> final output
30
+ ```
31
+
32
+ ## 2. Buffer Lifecycle
33
+
34
+ | Moment | What happens |
35
+ |--------|--------------|
36
+ | Before rows | Buffer starts empty, unless the caller passes an initial buffer. |
37
+ | `set` | Replaces buffer with selected content. |
38
+ | `append` / `prepend` | Adds content to buffer. |
39
+ | Targeted actions | Match target selectors against current buffer. |
40
+ | Top-level transforms | Run after all compose rows. |
41
+
42
+ If a plan has no compose rows and there is one current source, the source content can be used as initial output.
43
+
44
+ ## 3. Reading From The Buffer
45
+
46
+ Use `source: "buffer"` when selection should run against composed output.
47
+
48
+ ```ruby
49
+ {
50
+ "source" => "buffer",
51
+ "select" => "heading_2_section where title:contains(\"Draft\")",
52
+ "include" => "all",
53
+ "action" => "modify",
54
+ "target" => "in_place",
55
+ "transforms" => [
56
+ { "transform" => "replace_text", "mode" => "literal", "options" => "from:Draft; to:Final" }
57
+ ]
58
+ }
59
+ ```
60
+
61
+ ## 4. Buffer-Target Actions
62
+
63
+ These actions operate on existing buffer content:
64
+
65
+ | Action | Uses selected source content? | Main address |
66
+ |--------|-------------------------------|--------------|
67
+ | `remove_buffer_target` | no | `target` |
68
+ | `transform_buffer_target` | no | `target` |
69
+ | `modify` with `target: in_place` | yes, from buffer selection | `select` plus `target: in_place` |
70
+
71
+ ## 5. Stages For Debugging
72
+
73
+ When supported by caller options, stages can show how the buffer changes after each row.
74
+
75
+ ```ruby
76
+ result = MarkdownComposer.compose(sources: sources, config: config, options: { stages: true })
77
+ pp result.stages
78
+ ```
79
+
80
+ Use stages when a multi-row plan is hard to reason about.
81
+
@@ -0,0 +1,31 @@
1
+ ---
2
+ title: Markdown Composer Compose Examples
3
+ type: examples
4
+ status: current
5
+ updated: 2026-06-01
6
+ description: Compose-focused example index for Markdown Composer.
7
+ ---
8
+
9
+ # Markdown Composer Compose Examples
10
+
11
+ ### References
12
+
13
+ | What | Where |
14
+ |------|-------|
15
+ | Basic compose | [../examples/md_composer_example_basic_compose.md](../examples/md_composer_example_basic_compose.md) |
16
+ | Multi-row compose | [../examples/md_composer_example_multi_row_compose.md](../examples/md_composer_example_multi_row_compose.md) |
17
+ | Modify | [../examples/md_composer_example_modify.md](../examples/md_composer_example_modify.md) |
18
+ | Buffer actions | [../examples/md_composer_example_buffer_target_actions.md](../examples/md_composer_example_buffer_target_actions.md) |
19
+
20
+ ---
21
+
22
+ ## 1. Example Map
23
+
24
+ | Need | Example |
25
+ |------|---------|
26
+ | Select one section | [Basic compose](../examples/md_composer_example_basic_compose.md) |
27
+ | Build output from several sections | [Multi-row compose](../examples/md_composer_example_multi_row_compose.md) |
28
+ | Transform selected source content while composing | [Modify](../examples/md_composer_example_modify.md) |
29
+ | Remove or transform existing buffer content | [Buffer target actions](../examples/md_composer_example_buffer_target_actions.md) |
30
+ | Extract YAML/JSON values | [Structured data](../examples/md_composer_example_structured_data.md) |
31
+