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,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown Composer Compose Include
|
|
3
|
+
type: guide
|
|
4
|
+
status: current
|
|
5
|
+
updated: 2026-06-01
|
|
6
|
+
description: Public guide to Include syntax and examples in Markdown Composer compose rows.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Markdown Composer Compose Include
|
|
10
|
+
|
|
11
|
+
### References
|
|
12
|
+
|
|
13
|
+
| What | Where |
|
|
14
|
+
|------|-------|
|
|
15
|
+
| Compose anatomy | [./md_composer_compose_anatomy.md](./md_composer_compose_anatomy.md) |
|
|
16
|
+
| Select | [./md_composer_compose_select.md](./md_composer_compose_select.md) |
|
|
17
|
+
| Unit tokens | [../reference/md_composer_unit_tokens.md](../reference/md_composer_unit_tokens.md) |
|
|
18
|
+
| Take modifiers | [../reference/md_composer_take.md](../reference/md_composer_take.md) |
|
|
19
|
+
| Where conditions | [../reference/md_composer_where.md](../reference/md_composer_where.md) |
|
|
20
|
+
| Nested syntax | [../reference/md_composer_nested.md](../reference/md_composer_nested.md) |
|
|
21
|
+
| Structured data example | [../examples/md_composer_example_structured_data.md](../examples/md_composer_example_structured_data.md) |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 1. Purpose
|
|
26
|
+
|
|
27
|
+
`include` chooses what to keep from each selected unit.
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
{
|
|
31
|
+
"select" => "heading_2_section",
|
|
32
|
+
"include" => "heading_title, paragraph[first:1]"
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If omitted, `include` defaults to `all`.
|
|
37
|
+
|
|
38
|
+
## 2. Syntax Anatomy
|
|
39
|
+
|
|
40
|
+
`include` is an include expression. It runs inside each selected unit.
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
include = all | content | include_list
|
|
44
|
+
|
|
45
|
+
include_list = include_item, include_item, ...
|
|
46
|
+
|
|
47
|
+
include_item = include_unit [take] [where condition] [except exclude_unit]
|
|
48
|
+
| data_path("path.expression")
|
|
49
|
+
| nested_include
|
|
50
|
+
|
|
51
|
+
nested_include = unit_token { include_item; include_item; ... }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
For every include-capable token and alias, see [Unit Tokens](../reference/md_composer_unit_tokens.md).
|
|
55
|
+
For shared bracketed take syntax inside include items, see [Take Modifiers](../reference/md_composer_take.md).
|
|
56
|
+
For shared `where` syntax inside include items, see [Where Conditions](../reference/md_composer_where.md).
|
|
57
|
+
For nested include projection, recursion, and separators, see [Nested Syntax](../reference/md_composer_nested.md).
|
|
58
|
+
|
|
59
|
+
Include parts:
|
|
60
|
+
|
|
61
|
+
| Part | Example | Meaning |
|
|
62
|
+
|------|---------|---------|
|
|
63
|
+
| `all` | `all` | Keep the whole selected unit. |
|
|
64
|
+
| `content` | `content` | Keep the selected unit body without its heading/title wrapper. |
|
|
65
|
+
| `include_unit` | `paragraph`, `heading_title`, `code_block` | Keep only matching child units. |
|
|
66
|
+
| `[take]` | `paragraph[first:2]` | Keep positions inside each selected unit. |
|
|
67
|
+
| `where condition` | `paragraph where text:contains("Note")` | Filter child units. |
|
|
68
|
+
| `except` | `paragraph except link` | Keep the include unit while excluding nested matches. |
|
|
69
|
+
| `data_path(...)` | `data_path("metadata.title")` | Extract structured YAML/JSON values from `data_block`. |
|
|
70
|
+
|
|
71
|
+
Examples:
|
|
72
|
+
|
|
73
|
+
| Goal | Include |
|
|
74
|
+
|------|---------|
|
|
75
|
+
| Whole selected unit | `all` |
|
|
76
|
+
| Body without section heading | `content` |
|
|
77
|
+
| Only heading title | `heading_title` |
|
|
78
|
+
| First paragraph inside each selected section | `paragraph[first:1]` |
|
|
79
|
+
| Keep paragraphs except links | `paragraph except link` |
|
|
80
|
+
| Extract data value | `data_path("title")` |
|
|
81
|
+
|
|
82
|
+
## 3. Include Runs Per Selected Unit
|
|
83
|
+
|
|
84
|
+
This row selects two H2 sections and keeps the first paragraph from each section:
|
|
85
|
+
|
|
86
|
+
```ruby
|
|
87
|
+
{
|
|
88
|
+
"select" => "heading_2_section[position:1,2]",
|
|
89
|
+
"include" => "paragraph[first:1]",
|
|
90
|
+
"action" => "set"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
It does not keep the first paragraph across the whole document. It keeps the first paragraph inside each selected section.
|
|
95
|
+
|
|
96
|
+
## 4. Nested Include
|
|
97
|
+
|
|
98
|
+
Nested include is useful when a selection should keep a specific shape.
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
{
|
|
102
|
+
"select" => "heading_2_section { heading_title; paragraph[first:1] }",
|
|
103
|
+
"action" => "set"
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The nested include after `{ ... }` is part of the selector string and is normalized as include rules for each selected section.
|
|
108
|
+
|
|
109
|
+
## 5. Data Path Include
|
|
110
|
+
|
|
111
|
+
`data_path(...)` is only valid when the selected unit is `data_block`.
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
{
|
|
115
|
+
"select" => "data_block where format:equals(\"yaml\")",
|
|
116
|
+
"include" => "data_path(\"metadata.title\")",
|
|
117
|
+
"action" => "set"
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`data_path(...)` creates derived nodes:
|
|
122
|
+
|
|
123
|
+
| Derived type | Produced when |
|
|
124
|
+
|--------------|---------------|
|
|
125
|
+
| `data_record` | The extracted value is an object/hash. |
|
|
126
|
+
| `data_value` | The extracted value is a scalar or array value. |
|
|
127
|
+
|
|
128
|
+
These derived node types matter for metadata and future structured-output targeting. In normal Markdown output, they are serialized back into Markdown text.
|
|
129
|
+
|
|
130
|
+
## 6. Common Mistakes
|
|
131
|
+
|
|
132
|
+
| Mistake | Fix |
|
|
133
|
+
|---------|-----|
|
|
134
|
+
| Using `data_path(...)` outside `data_block`. | Select `data_block` first. |
|
|
135
|
+
| Expecting `include` to choose source sections. | Use `select` for source units; use `include` for parts inside those units. |
|
|
136
|
+
| Forgetting `heading_title` when rebuilding summaries. | Include it explicitly with body parts. |
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown Composer Compose Select
|
|
3
|
+
type: guide
|
|
4
|
+
status: current
|
|
5
|
+
updated: 2026-06-01
|
|
6
|
+
description: Public guide to Select syntax, unit tokens, take operators, and where conditions.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Markdown Composer Compose Select
|
|
10
|
+
|
|
11
|
+
### References
|
|
12
|
+
|
|
13
|
+
| What | Where |
|
|
14
|
+
|------|-------|
|
|
15
|
+
| Compose anatomy | [./md_composer_compose_anatomy.md](./md_composer_compose_anatomy.md) |
|
|
16
|
+
| Include | [./md_composer_compose_include.md](./md_composer_compose_include.md) |
|
|
17
|
+
| Targets | [./md_composer_compose_targets.md](./md_composer_compose_targets.md) |
|
|
18
|
+
| Unit tokens | [../reference/md_composer_unit_tokens.md](../reference/md_composer_unit_tokens.md) |
|
|
19
|
+
| Take modifiers | [../reference/md_composer_take.md](../reference/md_composer_take.md) |
|
|
20
|
+
| Where conditions | [../reference/md_composer_where.md](../reference/md_composer_where.md) |
|
|
21
|
+
| Nested syntax | [../reference/md_composer_nested.md](../reference/md_composer_nested.md) |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 1. Purpose
|
|
26
|
+
|
|
27
|
+
`select` chooses source units before `include` decides what to keep from each unit.
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
{ "select" => "heading_2_section[first:1]" }
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If omitted, `select` defaults to `all`.
|
|
34
|
+
|
|
35
|
+
## 2. Syntax Anatomy
|
|
36
|
+
|
|
37
|
+
`select` is a selector expression. It can be plain, filtered, narrowed by take, or paired with a nested include block.
|
|
38
|
+
|
|
39
|
+
Readable shape:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
heading_2_section[position:2,3] where title:contains("API") { heading_title; paragraph[first:1] }
|
|
43
|
+
| | | | | | |
|
|
44
|
+
| | | | | └── nested include rules
|
|
45
|
+
| | | | └──── include block for each selected unit
|
|
46
|
+
| | | └────────────────────────── where condition
|
|
47
|
+
| | └──────────────────────────────── take modifier
|
|
48
|
+
└─────────────────────────────────────────────────────────────── unit token
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Read it as:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
Select H2 sections, keep positions 2 and 3 after filtering, require the title to contain "API", then keep only the heading title and first paragraph from each selected section.
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Simple selectors can stop at any earlier part:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
paragraph
|
|
61
|
+
| |
|
|
62
|
+
└───────└── unit token only
|
|
63
|
+
|
|
64
|
+
paragraph[first:2]
|
|
65
|
+
| | |
|
|
66
|
+
| └───────└── take modifier
|
|
67
|
+
└────────────────── unit token
|
|
68
|
+
|
|
69
|
+
paragraph where text:contains("warning")
|
|
70
|
+
| | |
|
|
71
|
+
| | └── where condition
|
|
72
|
+
| └──────── where keyword
|
|
73
|
+
└────────────────── unit token
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 2.1. Formal Grammar
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
select = all | selector
|
|
80
|
+
|
|
81
|
+
selector = unit_token [take] [where condition] [nested_include]
|
|
82
|
+
|
|
83
|
+
unit_token = heading_2_section | paragraph | table | code_block | ...
|
|
84
|
+
|
|
85
|
+
take = [first:n] | [last:n] | [position:n,n] | [range:n..n] | [odd] | [even] | [every:n]
|
|
86
|
+
|
|
87
|
+
nested_include = { include_item; include_item; ... }
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
For every supported unit token and alias, see [Unit Tokens](../reference/md_composer_unit_tokens.md).
|
|
91
|
+
For every take operator, see [Take Modifiers](../reference/md_composer_take.md).
|
|
92
|
+
For every where field, predicate, and group, see [Where Conditions](../reference/md_composer_where.md).
|
|
93
|
+
For nested include projection, see [Nested Syntax](../reference/md_composer_nested.md).
|
|
94
|
+
|
|
95
|
+
The order matters:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
unit token first, take second, where third, nested include last
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 2.2. Selector Parts
|
|
102
|
+
|
|
103
|
+
| Part | Example | Purpose |
|
|
104
|
+
|------|---------|---------|
|
|
105
|
+
| [`unit_token`](../reference/md_composer_unit_tokens.md) | `heading_2_section` | Chooses the kind of source unit. |
|
|
106
|
+
| [`[take]`](../reference/md_composer_take.md) | `[position:2,3]` | Narrows by position after unit matching. |
|
|
107
|
+
| [`where condition`](../reference/md_composer_where.md) | `where title:contains("API")` | Filters matches by metadata or text. |
|
|
108
|
+
| [`{ nested include }`](../reference/md_composer_nested.md) | `{ heading_title; paragraph[first:1] }` | Keeps a shaped subset from each selected unit. |
|
|
109
|
+
|
|
110
|
+
### 2.3. Examples
|
|
111
|
+
|
|
112
|
+
| Goal | Select | Anatomy used |
|
|
113
|
+
|------|--------|--------------|
|
|
114
|
+
| All content | `all` | special selector |
|
|
115
|
+
| All paragraphs | `paragraph` | unit token |
|
|
116
|
+
| First H2 section | `heading_2_section[first:1]` | unit token + take |
|
|
117
|
+
| H2 section with title | `heading_2_section where title:equals("API")` | unit token + where |
|
|
118
|
+
| Paragraphs containing text | `paragraph where text:contains("warning")` | unit token + where |
|
|
119
|
+
| H2 sections 2 through 4 | `heading_2_section[range:2..4]` | unit token + take |
|
|
120
|
+
| H2 sections with nested include | `heading_2_section { heading_title; paragraph[first:1] }` | unit token + nested include |
|
|
121
|
+
| H2 sections with take, where, and include | `heading_2_section[position:2,3] where title:contains("API") { heading_title; paragraph[first:1] }` | full selector |
|
|
122
|
+
|
|
123
|
+
## 3. Section Versus Node Tokens
|
|
124
|
+
|
|
125
|
+
| Token | Selects |
|
|
126
|
+
|-------|---------|
|
|
127
|
+
| `heading_2` / `h2` | Only H2 heading nodes. |
|
|
128
|
+
| `heading_2_section` / `h2_section` | H2 heading plus content until the next H2 or higher heading. |
|
|
129
|
+
| `paragraph` / `p` | Paragraph nodes. |
|
|
130
|
+
| `section` | Heading-defined sections at any level. |
|
|
131
|
+
| `heading` | Heading nodes at any level. |
|
|
132
|
+
|
|
133
|
+
If you want a heading and its body, use a section token.
|
|
134
|
+
|
|
135
|
+
## 4. Take Operators
|
|
136
|
+
|
|
137
|
+
Take operators live inside brackets.
|
|
138
|
+
|
|
139
|
+
For full syntax anatomy, advanced operators, target/scope take, and field-take, see [Take Modifiers](../reference/md_composer_take.md).
|
|
140
|
+
|
|
141
|
+
| Goal | Select |
|
|
142
|
+
|------|--------|
|
|
143
|
+
| First two matches | `paragraph[first:2]` |
|
|
144
|
+
| Last match | `heading_2_section[last:1]` |
|
|
145
|
+
| Positions | `heading_2_section[position:2,3]` |
|
|
146
|
+
| Range | `heading_2_section[range:2..4]` |
|
|
147
|
+
| Odd positions | `list_item[odd]` |
|
|
148
|
+
| Every third paragraph | `paragraph[every:3]` |
|
|
149
|
+
| Exclude positions | `heading_2_section[except:1,3]` |
|
|
150
|
+
|
|
151
|
+
Positions are 1-based. Negative positions count from the end in structured take values.
|
|
152
|
+
|
|
153
|
+
## 5. Where Conditions
|
|
154
|
+
|
|
155
|
+
Where conditions are shared selector syntax. They work in `select`, `include`, `target`, and transform `scope`.
|
|
156
|
+
|
|
157
|
+
In `select`, where conditions filter matches after the unit token is selected and before take is applied.
|
|
158
|
+
|
|
159
|
+
```ruby
|
|
160
|
+
"heading_2_section where title:contains(\"Install\")"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
For the full syntax anatomy, field list, predicates, groups, field-take, and diagnostics, see [Where Conditions](../reference/md_composer_where.md).
|
|
164
|
+
|
|
165
|
+
Common fields:
|
|
166
|
+
|
|
167
|
+
| Field | Example |
|
|
168
|
+
|-------|---------|
|
|
169
|
+
| `title` | `heading_2_section where title:equals("API")` |
|
|
170
|
+
| `text` | `paragraph where text:contains("warning")` |
|
|
171
|
+
| `position` | `section where position:range(2..4)` |
|
|
172
|
+
| `language` | `code_block where language:equals("ruby")` |
|
|
173
|
+
| `links` | `section where links:exists` |
|
|
174
|
+
| `empty` | `paragraph where empty:equals(false)` |
|
|
175
|
+
|
|
176
|
+
Groups combine conditions:
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
"heading_2_section where any(title:contains(\"API\"); title:contains(\"CLI\"))"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## 6. Data Blocks
|
|
183
|
+
|
|
184
|
+
Markdown Composer can select structured YAML or JSON blocks:
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
"data_block where format:equals(\"json\")"
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Use `include: 'data_path("...")'` to extract values from selected data blocks. `data_record` and `data_value` are produced by `data_path(...)`; they are not normal `select` tokens.
|
|
191
|
+
|
|
192
|
+
## 7. Common Mistakes
|
|
193
|
+
|
|
194
|
+
| Mistake | Fix |
|
|
195
|
+
|---------|-----|
|
|
196
|
+
| Using `h2` when you want body content. | Use `h2_section`. |
|
|
197
|
+
| Putting `where` before take. | Use `unit[take] where condition`. |
|
|
198
|
+
| Treating `data_value` as a normal selector. | Select `data_block`, then include `data_path(...)`. |
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown Composer Compose Sources
|
|
3
|
+
type: guide
|
|
4
|
+
status: current
|
|
5
|
+
updated: 2026-06-01
|
|
6
|
+
description: Public guide to Source values in Markdown Composer compose rows.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Markdown Composer Compose Sources
|
|
10
|
+
|
|
11
|
+
### References
|
|
12
|
+
|
|
13
|
+
| What | Where |
|
|
14
|
+
|------|-------|
|
|
15
|
+
| Compose anatomy | [./md_composer_compose_anatomy.md](./md_composer_compose_anatomy.md) |
|
|
16
|
+
| Source examples | [../examples/md_composer_example_multi_row_compose.md](../examples/md_composer_example_multi_row_compose.md) |
|
|
17
|
+
| Capabilities | [../reference/md_composer_reference_capabilities.md](../reference/md_composer_reference_capabilities.md) |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Purpose
|
|
22
|
+
|
|
23
|
+
`source` tells a compose row where to read content from.
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
{ "source" => "current", "select" => "heading_2_section[first:1]" }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
If omitted, `source` defaults to `current`.
|
|
30
|
+
|
|
31
|
+
## 2. Syntax Anatomy
|
|
32
|
+
|
|
33
|
+
`source` can be omitted, a source token string, a structured source reference, or an inline source object.
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
source = omitted
|
|
37
|
+
| source_token
|
|
38
|
+
| source_reference
|
|
39
|
+
| inline_source
|
|
40
|
+
|
|
41
|
+
source_token = current | explicit | inherited | previous | buffer | inline
|
|
42
|
+
|
|
43
|
+
source_reference = {
|
|
44
|
+
type: source_token,
|
|
45
|
+
key: source_key
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
inline_source = {
|
|
49
|
+
type: inline,
|
|
50
|
+
key: source_key,
|
|
51
|
+
markdown: markdown_text
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Common forms:
|
|
56
|
+
|
|
57
|
+
| Form | Example | Meaning |
|
|
58
|
+
|------|---------|---------|
|
|
59
|
+
| omitted | no `source` field | Use `current`. |
|
|
60
|
+
| string token | `"source" => "buffer"` | Use a named source behavior. |
|
|
61
|
+
| structured reference | `"source" => { "type" => "explicit", "key" => "guide" }` | Resolve a keyed source. |
|
|
62
|
+
| inline object | `"source" => { "type" => "inline", "markdown" => "..." }` | Embed small source content in the plan. |
|
|
63
|
+
|
|
64
|
+
## 3. Source Tokens
|
|
65
|
+
|
|
66
|
+
| Source | Meaning | When to use |
|
|
67
|
+
|--------|---------|-------------|
|
|
68
|
+
| `current` | The main source supplied by the caller. | Most one-document recipes. |
|
|
69
|
+
| `explicit` | A keyed source selected by the plan or caller. | Multi-source composition. |
|
|
70
|
+
| `inherited` | A caller-resolved inherited source. | Applications that provide inheritance. |
|
|
71
|
+
| `previous` | The effective source from the previous row. | Repeating the same source without restating it. |
|
|
72
|
+
| `buffer` | The current composition buffer. | Moving, modifying, removing, or transforming content already composed. |
|
|
73
|
+
| `inline` | Content embedded in the config. | Small generated snippets or tests. |
|
|
74
|
+
|
|
75
|
+
## 4. Current Source
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
sources = [
|
|
79
|
+
{ "key" => "current", "type" => "current", "markdown" => "# Guide\n\n## Intro\n\nHello.\n" }
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
config = {
|
|
83
|
+
"compose" => [
|
|
84
|
+
{ "source" => "current", "select" => "heading_2_section[first:1]", "action" => "set" }
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If there is exactly one current source, you can omit `source`.
|
|
90
|
+
|
|
91
|
+
## 5. Explicit Source
|
|
92
|
+
|
|
93
|
+
Use explicit source references when a plan reads from more than one input.
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
sources = [
|
|
97
|
+
{ "key" => "guide", "type" => "explicit", "markdown" => "# Guide\n\n## API\n\nUse it.\n" },
|
|
98
|
+
{ "key" => "faq", "type" => "explicit", "markdown" => "# FAQ\n\n## Install\n\nBundle it.\n" }
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
config = {
|
|
102
|
+
"compose" => [
|
|
103
|
+
{ "source" => { "type" => "explicit", "key" => "guide" }, "select" => "heading_2_section", "action" => "set" },
|
|
104
|
+
{ "source" => { "type" => "explicit", "key" => "faq" }, "select" => "heading_2_section", "action" => "append" }
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 6. Previous Source
|
|
110
|
+
|
|
111
|
+
`previous` uses the effective source reference from the prior row. On the first row, it falls back to `current`.
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
{
|
|
115
|
+
"compose" => [
|
|
116
|
+
{ "source" => "current", "select" => "heading_2_section[first:1]", "action" => "set" },
|
|
117
|
+
{ "source" => "previous", "select" => "heading_2_section[last:1]", "action" => "append" }
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## 7. Buffer Source
|
|
123
|
+
|
|
124
|
+
Use `buffer` when the row should read from composed output rather than the original source.
|
|
125
|
+
|
|
126
|
+
```ruby
|
|
127
|
+
{
|
|
128
|
+
"source" => "buffer",
|
|
129
|
+
"select" => "heading_2_section where title:contains(\"Draft\")",
|
|
130
|
+
"action" => "remove_buffer_target",
|
|
131
|
+
"target" => "heading_2_section where title:contains(\"Draft\")"
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`buffer` is only useful after a previous row has created buffer content, unless the caller passes an initial buffer option.
|
|
136
|
+
|
|
137
|
+
## 8. Inline Source
|
|
138
|
+
|
|
139
|
+
Inline source embeds content directly in the plan.
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
{
|
|
143
|
+
"source" => {
|
|
144
|
+
"type" => "inline",
|
|
145
|
+
"key" => "notice",
|
|
146
|
+
"markdown" => "## Notice\n\nGenerated content.\n"
|
|
147
|
+
},
|
|
148
|
+
"select" => "heading_2_section",
|
|
149
|
+
"action" => "append"
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Use inline sources for small generated snippets, not large documents.
|
|
154
|
+
|
|
155
|
+
## 9. Common Mistakes
|
|
156
|
+
|
|
157
|
+
| Mistake | Fix |
|
|
158
|
+
|---------|-----|
|
|
159
|
+
| Using `buffer` in the first row. | Use `current`, or provide `initial_buffer`. |
|
|
160
|
+
| Using `previous` when the prior row used `buffer`. | Be explicit if the distinction matters. |
|
|
161
|
+
| Forgetting a key for multi-source explicit plans. | Pass `key`, `id`, or `slug` in the source reference. |
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown Composer Compose Targets
|
|
3
|
+
type: guide
|
|
4
|
+
status: current
|
|
5
|
+
updated: 2026-06-01
|
|
6
|
+
description: Public guide to target syntax, placement, selector targets, and structured-output target caveats.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Markdown Composer Compose Targets
|
|
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
|
+
| Buffer | [./md_composer_compose_buffer.md](./md_composer_compose_buffer.md) |
|
|
18
|
+
| Unit tokens | [../reference/md_composer_unit_tokens.md](../reference/md_composer_unit_tokens.md) |
|
|
19
|
+
| Take modifiers | [../reference/md_composer_take.md](../reference/md_composer_take.md) |
|
|
20
|
+
| Where conditions | [../reference/md_composer_where.md](../reference/md_composer_where.md) |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 1. Purpose
|
|
25
|
+
|
|
26
|
+
`target` addresses the current composition buffer. It does not address the original source unless the row explicitly uses `source: "buffer"`.
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
{
|
|
30
|
+
"action" => "replace",
|
|
31
|
+
"target" => "heading_2_section where title:equals(\"Old\")"
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 2. Syntax Anatomy
|
|
36
|
+
|
|
37
|
+
`target` has three layers: a special buffer position, a selector that matches the current buffer, or a placement expression built from selectors.
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
target = special_target | target_selector | placement_target
|
|
41
|
+
|
|
42
|
+
special_target = whole output | output | start | end | in_place
|
|
43
|
+
|
|
44
|
+
target_selector = unit_token [take] [where condition]
|
|
45
|
+
|
|
46
|
+
placement_target = before target_selector
|
|
47
|
+
| after target_selector
|
|
48
|
+
| between target_selector and target_selector
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For every target-capable token and alias, see [Unit Tokens](../reference/md_composer_unit_tokens.md).
|
|
52
|
+
For shared target-selector take syntax, see [Take Modifiers](../reference/md_composer_take.md).
|
|
53
|
+
For shared target-selector `where` syntax, see [Where Conditions](../reference/md_composer_where.md).
|
|
54
|
+
|
|
55
|
+
| Layer | Example | Meaning |
|
|
56
|
+
|-------|---------|---------|
|
|
57
|
+
| `special_target` | `end` | A built-in buffer location or whole-buffer operation. |
|
|
58
|
+
| `target_selector` | `heading_2_section[first:1]` | A selector matched against the current composition buffer. |
|
|
59
|
+
| `placement_target` | `before heading_2 where text:contains("API")` | A placement instruction anchored to one or two buffer selectors. |
|
|
60
|
+
|
|
61
|
+
Target selector anatomy:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
unit_token[take] where condition
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
| Part | Example | Notes |
|
|
68
|
+
|------|---------|-------|
|
|
69
|
+
| `unit_token` | `heading_2_section`, `paragraph`, `table` | Uses the same token registry as `select` and transform `scope`. |
|
|
70
|
+
| `[take]` | `[first:1]`, `[position:2,3]`, `[range:2..4]` | Optional. Positions are 1-based. |
|
|
71
|
+
| `where condition` | `where title:equals("API")` | Optional. Filters buffer matches. |
|
|
72
|
+
|
|
73
|
+
Common target forms:
|
|
74
|
+
|
|
75
|
+
| Form | Example | Common actions |
|
|
76
|
+
|------|---------|----------------|
|
|
77
|
+
| `whole output` | `target: "whole output"` | `set`, `replace`, `modify` |
|
|
78
|
+
| `start` | `target: "start"` | `copy`, `move`, `modify` |
|
|
79
|
+
| `end` | `target: "end"` | `copy`, `move`, `modify` |
|
|
80
|
+
| selector | `target: "heading_2_section[first:1]"` | `replace`, `remove_buffer_target`, `transform_buffer_target` |
|
|
81
|
+
| before | `target: "before heading_2 where text:contains(\"API\")"` | `insert_before`, `copy`, `move`, `modify` |
|
|
82
|
+
| after | `target: "after heading_2 where text:contains(\"API\")"` | `insert_after`, `copy`, `move`, `modify` |
|
|
83
|
+
| between | `target: "between heading_2[first:1] and heading_2[last:1]"` | `insert_between`, `modify` |
|
|
84
|
+
| `in_place` | `target: "in_place"` | `modify` with `source: "buffer"` only |
|
|
85
|
+
|
|
86
|
+
## 3. Selector Targets
|
|
87
|
+
|
|
88
|
+
Selector targets reuse select syntax, but they match against the current buffer.
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
{
|
|
92
|
+
"action" => "replace",
|
|
93
|
+
"target" => "paragraph where text:contains(\"TODO\")"
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The target can use take and where:
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
"heading_2_section[position:2] where title:contains(\"Draft\")"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
That means this row replaces the first matching section already in the buffer, not the first matching section in the original source:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
{
|
|
107
|
+
"select" => "heading_2_section where title:equals(\"New API\")",
|
|
108
|
+
"action" => "replace",
|
|
109
|
+
"target" => "heading_2_section where title:equals(\"Old API\")"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## 4. Between Targets
|
|
114
|
+
|
|
115
|
+
Between targets need a start anchor and an end anchor.
|
|
116
|
+
|
|
117
|
+
```ruby
|
|
118
|
+
{
|
|
119
|
+
"action" => "insert_between",
|
|
120
|
+
"target" => "between heading_2 where text:contains(\"Start\") and heading_2 where text:contains(\"End\")"
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The start anchor must resolve before the end anchor. Otherwise validation/execution reports `target.order_invalid`.
|
|
125
|
+
|
|
126
|
+
## 5. In Place Target
|
|
127
|
+
|
|
128
|
+
`in_place` rewrites selected buffer content inline.
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
{
|
|
132
|
+
"source" => "buffer",
|
|
133
|
+
"select" => "paragraph where text:contains(\"Draft\")",
|
|
134
|
+
"action" => "modify",
|
|
135
|
+
"target" => "in_place",
|
|
136
|
+
"transforms" => [
|
|
137
|
+
{ "transform" => "replace_text", "mode" => "literal", "options" => "from:Draft; to:Final" }
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Rules:
|
|
143
|
+
|
|
144
|
+
| Rule | Meaning |
|
|
145
|
+
|------|---------|
|
|
146
|
+
| Source must be `buffer`. | The row must select from the existing buffer. |
|
|
147
|
+
| Action must be `modify`. | Other actions reject `in_place`. |
|
|
148
|
+
| Selected content must be line-addressable. | Markdown Composer maps transformed fragments back to original buffer line ranges. |
|
|
149
|
+
|
|
150
|
+
## 6. Target-Supported Unit Tokens
|
|
151
|
+
|
|
152
|
+
Capabilities mark some unit tokens as valid for target matching. The common practical target tokens are the same node/section tokens used by selection:
|
|
153
|
+
|
|
154
|
+
| Token family | Example target |
|
|
155
|
+
|--------------|----------------|
|
|
156
|
+
| Sections | `heading_2_section where title:equals("API")` |
|
|
157
|
+
| Headings | `heading_2 where text:contains("API")` |
|
|
158
|
+
| Paragraphs | `paragraph where text:contains("TODO")` |
|
|
159
|
+
| Lists | `list`, `list_item`, `ordered_list`, `unordered_list` |
|
|
160
|
+
| Tables | `table`, `table_row`, `table_cell` |
|
|
161
|
+
| Code and diagrams | `code_block`, `mermaid`, `math_block` |
|
|
162
|
+
| Data blocks | `data_block where format:equals("yaml")` |
|
|
163
|
+
|
|
164
|
+
`data_record` and `data_value` are different. Capabilities mark them as advanced targets and output-only scopes because they are derived structured-output node types produced by `data_path(...)`. In the standalone Markdown buffer, `data_path(...)` values are serialized back to Markdown text, and normal target matching reparses that Markdown. Treat `data_record` and `data_value` as metadata/deferred structured-output target tokens unless a host adapter preserves them as matchable buffer nodes.
|
|
165
|
+
|
|
166
|
+
Practical structured-data recipe:
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
{
|
|
170
|
+
"select" => "data_block where format:equals(\"yaml\")",
|
|
171
|
+
"include" => "data_path(\"fields[type=dropdown].label\")",
|
|
172
|
+
"action" => "set"
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Then target the serialized Markdown text if needed:
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
{
|
|
180
|
+
"source" => "buffer",
|
|
181
|
+
"select" => "all",
|
|
182
|
+
"action" => "remove_buffer_target",
|
|
183
|
+
"target" => "paragraph where text:contains(\"Old label\")"
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## 7. Common Mistakes
|
|
188
|
+
|
|
189
|
+
| Mistake | Fix |
|
|
190
|
+
|---------|-----|
|
|
191
|
+
| Expecting target to match the original source. | Target matches the current buffer. |
|
|
192
|
+
| Using `data_record` directly as a normal target in standalone Markdown output. | Select `data_block`, include `data_path(...)`, then target the serialized output or use a host adapter that preserves structured nodes. |
|
|
193
|
+
| Using `start` or `end` with `remove_buffer_target`. | Use a selector target. |
|
|
194
|
+
| Using `in_place` without `source: "buffer"`. | Select from the buffer explicitly. |
|