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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +23 -0
- data/LICENSE.txt +21 -0
- data/README.md +278 -0
- data/ROADMAP.md +80 -0
- data/docs/_md_composer_architecture.md +50 -0
- data/docs/_md_composer_cheatsheet.md +72 -0
- data/docs/_md_composer_concepts.md +64 -0
- data/docs/_md_composer_dev_guide.md +55 -0
- data/docs/_md_composer_getting_started.md +114 -0
- data/docs/_md_composer_readme.md +93 -0
- data/docs/_md_composer_user_guide.md +65 -0
- data/docs/ai/md_composer_ai_audit.md +35 -0
- data/docs/ai/md_composer_ai_canonical_docs.md +44 -0
- data/docs/ai/md_composer_ai_source_map.md +39 -0
- data/docs/compose/md_composer_compose_actions.md +338 -0
- data/docs/compose/md_composer_compose_anatomy.md +156 -0
- data/docs/compose/md_composer_compose_buffer.md +81 -0
- data/docs/compose/md_composer_compose_examples.md +31 -0
- data/docs/compose/md_composer_compose_include.md +136 -0
- data/docs/compose/md_composer_compose_select.md +198 -0
- data/docs/compose/md_composer_compose_sources.md +161 -0
- data/docs/compose/md_composer_compose_targets.md +194 -0
- data/docs/examples/md_composer_example_basic_compose.md +57 -0
- data/docs/examples/md_composer_example_buffer_target_actions.md +83 -0
- data/docs/examples/md_composer_example_fixtures.md +62 -0
- data/docs/examples/md_composer_example_html_output.md +50 -0
- data/docs/examples/md_composer_example_modify.md +77 -0
- data/docs/examples/md_composer_example_multi_row_compose.md +67 -0
- data/docs/examples/md_composer_example_ruby_plans.md +62 -0
- data/docs/examples/md_composer_example_structured_data.md +68 -0
- data/docs/examples/md_composer_example_transforms.md +68 -0
- data/docs/examples/md_composer_example_yaml_json_rows.md +56 -0
- data/docs/examples/md_composer_examples_readme.md +45 -0
- data/docs/examples/md_composer_runnable_examples.md +374 -0
- data/docs/examples/md_composer_source_ruby_dsl.md +88 -0
- data/docs/reference/md_composer_nested.md +170 -0
- data/docs/reference/md_composer_reference_api.md +71 -0
- data/docs/reference/md_composer_reference_capabilities.md +63 -0
- data/docs/reference/md_composer_reference_diagnostics.md +54 -0
- data/docs/reference/md_composer_reference_plan_schema.md +75 -0
- data/docs/reference/md_composer_reference_registries.md +63 -0
- data/docs/reference/md_composer_take.md +221 -0
- data/docs/reference/md_composer_unit_tokens.md +228 -0
- data/docs/reference/md_composer_where.md +227 -0
- data/docs/transform/md_composer_transform_anatomy.md +112 -0
- data/docs/transform/md_composer_transform_examples.md +30 -0
- data/docs/transform/md_composer_transform_modes.md +83 -0
- data/docs/transform/md_composer_transform_options.md +142 -0
- data/docs/transform/md_composer_transform_scope.md +97 -0
- data/docs/transform/md_composer_transform_transforms.md +99 -0
- data/examples/README.md +20 -0
- data/examples/advanced_composer.rb +207 -0
- data/examples/basic_compose.rb +24 -0
- data/examples/complex_composer.rb +235 -0
- data/examples/example_support.rb +18 -0
- data/examples/fixtures/current.md +179 -0
- data/examples/fixtures/faq.md +58 -0
- data/examples/fixtures/guide.md +62 -0
- data/examples/fixtures/site_intro.md +29 -0
- data/examples/fixtures/source.html +22 -0
- data/examples/html_input.rb +26 -0
- data/examples/output/advanced_composer.md +76 -0
- data/examples/output/basic_compose.md +25 -0
- data/examples/output/complex_composer.md +85 -0
- data/examples/output/html_input.md +4 -0
- data/examples/output/source_list_dsl.md +126 -0
- data/examples/output/standard_composer.md +46 -0
- data/examples/output/standard_sources_buffer.md +31 -0
- data/examples/output/yaml_plan.md +43 -0
- data/examples/plans/basic.yml +20 -0
- data/examples/source_list_dsl.rb +41 -0
- data/examples/standard_composer.rb +42 -0
- data/examples/standard_sources_buffer.rb +62 -0
- data/examples/yaml_plan.rb +17 -0
- data/lib/markdown_composer/capabilities.rb +223 -0
- data/lib/markdown_composer/composition_buffer.rb +378 -0
- data/lib/markdown_composer/data_path.rb +313 -0
- data/lib/markdown_composer/diagnostics.rb +63 -0
- data/lib/markdown_composer/document_index/html_parser.rb +84 -0
- data/lib/markdown_composer/document_index/markdown_parser.rb +338 -0
- data/lib/markdown_composer/document_index.rb +94 -0
- data/lib/markdown_composer/executor.rb +284 -0
- data/lib/markdown_composer/markdown_renderer.rb +105 -0
- data/lib/markdown_composer/plan.rb +436 -0
- data/lib/markdown_composer/plan_builder.rb +111 -0
- data/lib/markdown_composer/registries/action_entries.rb +26 -0
- data/lib/markdown_composer/registries/condition_entries.rb +58 -0
- data/lib/markdown_composer/registries/registry.rb +69 -0
- data/lib/markdown_composer/registries/source_entries.rb +18 -0
- data/lib/markdown_composer/registries/support_values.rb +23 -0
- data/lib/markdown_composer/registries/take_entries.rb +31 -0
- data/lib/markdown_composer/registries/take_registry.rb +18 -0
- data/lib/markdown_composer/registries/target_entries.rb +40 -0
- data/lib/markdown_composer/registries/unit_token_entries.rb +62 -0
- data/lib/markdown_composer/registries/where_registry.rb +84 -0
- data/lib/markdown_composer/registries.rb +46 -0
- data/lib/markdown_composer/result.rb +34 -0
- data/lib/markdown_composer/selection_resolver.rb +181 -0
- data/lib/markdown_composer/source.rb +57 -0
- data/lib/markdown_composer/source_list_builder.rb +47 -0
- data/lib/markdown_composer/take.rb +129 -0
- data/lib/markdown_composer/transform_options.rb +66 -0
- data/lib/markdown_composer/transform_runner/content_placement.rb +63 -0
- data/lib/markdown_composer/transform_runner/field_interpolator.rb +213 -0
- data/lib/markdown_composer/transform_runner/heading_numbering.rb +106 -0
- data/lib/markdown_composer/transform_runner/scope_resolver.rb +87 -0
- data/lib/markdown_composer/transform_runner.rb +264 -0
- data/lib/markdown_composer/transforms/default_entries.rb +31 -0
- data/lib/markdown_composer/transforms/registry.rb +11 -0
- data/lib/markdown_composer/validator.rb +378 -0
- data/lib/markdown_composer/value_object.rb +15 -0
- data/lib/markdown_composer/version.rb +5 -0
- data/lib/markdown_composer/where.rb +313 -0
- data/lib/markdown_composer.rb +114 -0
- 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
|
+
|