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,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown Composer Transform Anatomy
|
|
3
|
+
type: guide
|
|
4
|
+
status: current
|
|
5
|
+
updated: 2026-06-01
|
|
6
|
+
description: Public anatomy guide for Markdown Composer transform rows.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Markdown Composer Transform Anatomy
|
|
10
|
+
|
|
11
|
+
### References
|
|
12
|
+
|
|
13
|
+
| What | Where |
|
|
14
|
+
|------|-------|
|
|
15
|
+
| Scope | [./md_composer_transform_scope.md](./md_composer_transform_scope.md) |
|
|
16
|
+
| Transforms | [./md_composer_transform_transforms.md](./md_composer_transform_transforms.md) |
|
|
17
|
+
| Modes | [./md_composer_transform_modes.md](./md_composer_transform_modes.md) |
|
|
18
|
+
| Options | [./md_composer_transform_options.md](./md_composer_transform_options.md) |
|
|
19
|
+
| Transform examples | [./md_composer_transform_examples.md](./md_composer_transform_examples.md) |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Row Shape
|
|
24
|
+
|
|
25
|
+
A transform row reshapes composed output.
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
Scope -> Transform -> Mode -> Options
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Full row anatomy:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
transform_row = {
|
|
35
|
+
scope: scope_selector | output,
|
|
36
|
+
transform: transform_family,
|
|
37
|
+
mode: family_mode,
|
|
38
|
+
options: option_hash | option_string
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Read it as a sentence:
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
Inside this Scope, run this Transform in this Mode with these Options.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Example:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
{
|
|
52
|
+
"scope" => "output",
|
|
53
|
+
"transform" => "replace_text",
|
|
54
|
+
"mode" => "literal",
|
|
55
|
+
"options" => { "from" => "Draft", "to" => "Final" }
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 2. Top-Level Transforms
|
|
60
|
+
|
|
61
|
+
Top-level transforms run after all compose rows have finished building the buffer.
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
config = {
|
|
65
|
+
"compose" => [
|
|
66
|
+
{ "select" => "heading_2_section", "action" => "set" }
|
|
67
|
+
],
|
|
68
|
+
"transform" => [
|
|
69
|
+
{ "scope" => "output", "transform" => "heading_numbers", "mode" => "rebuild", "options" => { "levels" => [2] } }
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
If `scope` is omitted, it defaults to `output`.
|
|
75
|
+
|
|
76
|
+
## 3. Row-Level Transforms
|
|
77
|
+
|
|
78
|
+
Row-level transforms are used by actions that explicitly support nested transforms:
|
|
79
|
+
|
|
80
|
+
| Action | What nested transforms affect |
|
|
81
|
+
|--------|-------------------------------|
|
|
82
|
+
| `modify` | A temporary fragment made from selected source content. |
|
|
83
|
+
| `transform_buffer_target` | Existing buffer content matched by the action target, unless an explicit nested scope is supplied. |
|
|
84
|
+
|
|
85
|
+
Row-level transforms are not a separate global pipeline. They belong to the compose row that declares them.
|
|
86
|
+
|
|
87
|
+
## 4. Field Responsibilities
|
|
88
|
+
|
|
89
|
+
| Field | Responsibility | Common mistake |
|
|
90
|
+
|-------|----------------|----------------|
|
|
91
|
+
| `scope` | Chooses which buffer units the transform changes. | Forgetting that top-level scope matches composed output, not original source. |
|
|
92
|
+
| `transform` | Chooses the transform family. | Picking a transform without checking its modes. |
|
|
93
|
+
| `mode` | Chooses behavior inside the transform family. | Assuming modes share the same required options. |
|
|
94
|
+
| `options` | Provides transform-specific settings. | Treating options as JSON only; hashes and semicolon strings both work. |
|
|
95
|
+
|
|
96
|
+
## 5. Validation
|
|
97
|
+
|
|
98
|
+
Validation checks transform tokens, modes, required options, unknown option keys, option value types, and policy-gated transforms.
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
validation = MarkdownComposer.validate(config: config, sources: sources)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Missing options produce `transform.option_missing`. Unknown options produce `transform.option_unknown`.
|
|
105
|
+
|
|
106
|
+
## 6. Important Caveats
|
|
107
|
+
|
|
108
|
+
| Caveat | Meaning |
|
|
109
|
+
|--------|---------|
|
|
110
|
+
| Optional options are validation metadata. | Some accepted optional keys are ahead of standalone runner behavior. |
|
|
111
|
+
| HTML link attribute modes are special. | `links/nofollow` and `links/target_blank` apply during final HTML rendering for top-level transforms. |
|
|
112
|
+
| Policy-gated modes are not ordinary features. | `adapter`, `sanitise`, and `order/target_order` need host policy or are deferred. |
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown Composer Transform Examples
|
|
3
|
+
type: examples
|
|
4
|
+
status: current
|
|
5
|
+
updated: 2026-06-01
|
|
6
|
+
description: Transform-focused example index for Markdown Composer.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Markdown Composer Transform Examples
|
|
10
|
+
|
|
11
|
+
### References
|
|
12
|
+
|
|
13
|
+
| What | Where |
|
|
14
|
+
|------|-------|
|
|
15
|
+
| Transform anatomy | [./md_composer_transform_anatomy.md](./md_composer_transform_anatomy.md) |
|
|
16
|
+
| Transform examples | [../examples/md_composer_example_transforms.md](../examples/md_composer_example_transforms.md) |
|
|
17
|
+
| HTML output | [../examples/md_composer_example_html_output.md](../examples/md_composer_example_html_output.md) |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Example Map
|
|
22
|
+
|
|
23
|
+
| Need | Example |
|
|
24
|
+
|------|---------|
|
|
25
|
+
| Replace text after composing | [Transform examples](../examples/md_composer_example_transforms.md) |
|
|
26
|
+
| Use transform options | [Transform options](./md_composer_transform_options.md) |
|
|
27
|
+
| Add HTML link attributes | [HTML output](../examples/md_composer_example_html_output.md) |
|
|
28
|
+
| Transform during `modify` | [Modify](../examples/md_composer_example_modify.md) |
|
|
29
|
+
| Transform an existing buffer target | [Buffer target actions](../examples/md_composer_example_buffer_target_actions.md) |
|
|
30
|
+
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown Composer Transform Modes
|
|
3
|
+
type: guide
|
|
4
|
+
status: current
|
|
5
|
+
updated: 2026-06-01
|
|
6
|
+
description: Public guide to transform modes and mode-specific behavior.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Markdown Composer Transform Modes
|
|
10
|
+
|
|
11
|
+
### References
|
|
12
|
+
|
|
13
|
+
| What | Where |
|
|
14
|
+
|------|-------|
|
|
15
|
+
| Transform families | [./md_composer_transform_transforms.md](./md_composer_transform_transforms.md) |
|
|
16
|
+
| Options | [./md_composer_transform_options.md](./md_composer_transform_options.md) |
|
|
17
|
+
| Capabilities | [../reference/md_composer_reference_capabilities.md](../reference/md_composer_reference_capabilities.md) |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Purpose
|
|
22
|
+
|
|
23
|
+
`mode` selects behavior inside a transform family.
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
{ "transform" => "heading_numbers", "mode" => "rebuild", "options" => { "levels" => [2] } }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Modes are transform-specific. Do not assume options from one mode work in another mode.
|
|
30
|
+
|
|
31
|
+
## 2. Syntax Anatomy
|
|
32
|
+
|
|
33
|
+
`mode` is not global. It is resolved inside the selected transform family.
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
mode_key = transform_family "/" mode
|
|
37
|
+
|
|
38
|
+
heading_numbers/rebuild
|
|
39
|
+
replace_text/literal
|
|
40
|
+
links/rewrite_url
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The mode key controls:
|
|
44
|
+
|
|
45
|
+
| Control | Example |
|
|
46
|
+
|---------|---------|
|
|
47
|
+
| Required options | `replace_text/literal` requires `from` and `to`. |
|
|
48
|
+
| Optional options | `heading_numbers/rebuild` accepts `start`, `format`, and related keys. |
|
|
49
|
+
| Output constraints | `links/nofollow` and `links/target_blank` are meaningful with HTML output. |
|
|
50
|
+
| Policy gates | `order/target_order` is not a normal ready-to-use mode. |
|
|
51
|
+
|
|
52
|
+
## 3. Mode Matrix
|
|
53
|
+
|
|
54
|
+
| Transform | Modes |
|
|
55
|
+
|-----------|-------|
|
|
56
|
+
| `heading_numbers` | `keep`, `strip`, `add`, `rebuild` |
|
|
57
|
+
| `replace_text` | `literal`, `word`, `regex` |
|
|
58
|
+
| `links` | `keep`, `unwrap`, `remove`, `rewrite_url`, `nofollow`, `target_blank` |
|
|
59
|
+
| `heading_levels` | `promote`, `demote`, `normalise` |
|
|
60
|
+
| `remove_empty` | `remove` |
|
|
61
|
+
| `insert_before`, `insert_after`, `prepend_content`, `append_content` | `insert` |
|
|
62
|
+
| `replace_content` | `replace` |
|
|
63
|
+
| `remove_content` | `remove` |
|
|
64
|
+
| `dedupe` | `source_node_id`, `normalised_text` |
|
|
65
|
+
| `order` | `action_order`, `source_order`, `target_order` |
|
|
66
|
+
| `sanitise` | `block_safe`, `text_only`, `links_unwrapped`, `strict` |
|
|
67
|
+
|
|
68
|
+
## 4. GUI Filtering Rule
|
|
69
|
+
|
|
70
|
+
If you build a UI, filter by mode-level `enabled`, not only transform-level `enabled`.
|
|
71
|
+
|
|
72
|
+
Example: `order` can be visible while `order/target_order` is gated. The mode metadata is the source of truth for whether a mode should be offered.
|
|
73
|
+
|
|
74
|
+
## 5. HTML Link Attribute Modes
|
|
75
|
+
|
|
76
|
+
`links/nofollow` and `links/target_blank` are special:
|
|
77
|
+
|
|
78
|
+
| Rule | Meaning |
|
|
79
|
+
|------|---------|
|
|
80
|
+
| Require HTML output metadata | They are useful with `output: "html"`. |
|
|
81
|
+
| Top-level post-processing | Final HTML link attributes are applied after Markdown rendering. |
|
|
82
|
+
| Global external-link behavior | The renderer walks rendered links; it skips empty links and `#anchor` links. |
|
|
83
|
+
| Row-level caveat | Row-level link attribute transforms do not update final HTML attributes. |
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown Composer Transform Options
|
|
3
|
+
type: guide
|
|
4
|
+
status: current
|
|
5
|
+
updated: 2026-06-01
|
|
6
|
+
description: Public guide to transform options, hash syntax, semicolon syntax, required keys, and validation errors.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Markdown Composer Transform Options
|
|
10
|
+
|
|
11
|
+
### References
|
|
12
|
+
|
|
13
|
+
| What | Where |
|
|
14
|
+
|------|-------|
|
|
15
|
+
| Transform anatomy | [./md_composer_transform_anatomy.md](./md_composer_transform_anatomy.md) |
|
|
16
|
+
| Modes | [./md_composer_transform_modes.md](./md_composer_transform_modes.md) |
|
|
17
|
+
| Diagnostics | [../reference/md_composer_reference_diagnostics.md](../reference/md_composer_reference_diagnostics.md) |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Purpose
|
|
22
|
+
|
|
23
|
+
`options` provides settings for a transform mode.
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
{ "transform" => "replace_text", "mode" => "literal", "options" => { "from" => "Draft", "to" => "Final" } }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The field label in capabilities says `Options JSON`, but public authors can use either structured hashes or semicolon option strings.
|
|
30
|
+
|
|
31
|
+
## 2. Syntax Anatomy
|
|
32
|
+
|
|
33
|
+
`options` can be a structured hash/object or a compact semicolon string. Both forms normalize into the same option map before validation.
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
options = option_hash | option_string
|
|
37
|
+
|
|
38
|
+
option_hash = { key => value, key => value }
|
|
39
|
+
|
|
40
|
+
option_string = key:value; key:value; key:value
|
|
41
|
+
|
|
42
|
+
value = string | number | boolean | nil | unit_token | unit_list | target_selector
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Option names and required keys depend on the selected transform/mode pair:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
transform + mode -> allowed option keys
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Some option values have their own mini-grammar:
|
|
52
|
+
|
|
53
|
+
| Option kind | Example | Notes |
|
|
54
|
+
|-------------|---------|-------|
|
|
55
|
+
| Text value | `from:"Draft"` | Quote values that contain punctuation or semicolons. |
|
|
56
|
+
| Boolean | `case_sensitive:false` | Normalizes to `false`. |
|
|
57
|
+
| Unit token | `unit:p` | Aliases normalize, for example `p` to `paragraph`. |
|
|
58
|
+
| Unit list | `levels:h2,h3` | Comma-separated aliases normalize where supported. |
|
|
59
|
+
| Target selector | `target:"heading_2_section[first:1]"` | Used by target-order style metadata and gated/deferred modes. |
|
|
60
|
+
|
|
61
|
+
## 3. Hash Syntax
|
|
62
|
+
|
|
63
|
+
Use hashes for Ruby code, JSON configs, generated plans, and GUI builders.
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
"options" => {
|
|
67
|
+
"from" => "Draft",
|
|
68
|
+
"to" => "Final",
|
|
69
|
+
"case_sensitive" => false
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## 4. Semicolon String Syntax
|
|
74
|
+
|
|
75
|
+
Use semicolon strings for compact authoring.
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
"options" => "from:\"Draft\"; to:\"Final\"; case_sensitive:false"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The parser splits only at top-level semicolons, so quoted semicolons and nested expressions can survive.
|
|
82
|
+
|
|
83
|
+
Values support:
|
|
84
|
+
|
|
85
|
+
| Value form | Example |
|
|
86
|
+
|------------|---------|
|
|
87
|
+
| String | `from:"Draft"` |
|
|
88
|
+
| Boolean | `case_sensitive:false` |
|
|
89
|
+
| Nil | `target:nil` |
|
|
90
|
+
| Integer | `limit:2` |
|
|
91
|
+
| Unit aliases | `unit:p`, `as:paragraph`, `levels:h2,h3` |
|
|
92
|
+
|
|
93
|
+
Option values normalize through unit token aliases where appropriate.
|
|
94
|
+
|
|
95
|
+
## 5. Required Options
|
|
96
|
+
|
|
97
|
+
| Transform / mode | Required |
|
|
98
|
+
|------------------|----------|
|
|
99
|
+
| `replace_text/literal` | `from`, `to` |
|
|
100
|
+
| `replace_text/word` | `from`, `to` |
|
|
101
|
+
| `replace_text/regex` | `from`, `to` |
|
|
102
|
+
| `links/rewrite_url` | `from`, `to` |
|
|
103
|
+
| `heading_numbers/add` | `levels` |
|
|
104
|
+
| `heading_numbers/rebuild` | `levels` |
|
|
105
|
+
| `heading_levels/promote` | `by` |
|
|
106
|
+
| `heading_levels/demote` | `by` |
|
|
107
|
+
| `heading_levels/normalise` | `to` |
|
|
108
|
+
| `remove_empty/remove` | `unit` |
|
|
109
|
+
| content insertion/replacement | `content`, `as` |
|
|
110
|
+
| `order/target_order` | `target` |
|
|
111
|
+
|
|
112
|
+
## 6. Optional Options
|
|
113
|
+
|
|
114
|
+
Examples:
|
|
115
|
+
|
|
116
|
+
| Transform / mode | Optional |
|
|
117
|
+
|------------------|----------|
|
|
118
|
+
| `heading_numbers/rebuild` | `start`, `format`, `exclude`, `restart_at` |
|
|
119
|
+
| `replace_text/literal` | `case_sensitive`, `limit`, `whole_node` |
|
|
120
|
+
| `links/rewrite_url` | `match`, `case_sensitive` |
|
|
121
|
+
| `heading_levels/promote` | `min_level`, `max_level` |
|
|
122
|
+
| `remove_empty/remove` | `trim`, `ignore_nbsp`, `ignore_comments` |
|
|
123
|
+
| `insert_before/insert` | `dedupe`, `parse_as` |
|
|
124
|
+
|
|
125
|
+
Some optional keys are validation metadata ahead of standalone runner behavior. Validate and test advanced options before promising them in a host UI.
|
|
126
|
+
|
|
127
|
+
## 7. Validation Errors
|
|
128
|
+
|
|
129
|
+
| Diagnostic | Meaning |
|
|
130
|
+
|------------|---------|
|
|
131
|
+
| `transform.option_missing` | A required option is absent. |
|
|
132
|
+
| `transform.option_unknown` | The option key is not accepted for that transform/mode. |
|
|
133
|
+
| `transform.options_syntax` | The options value is not a readable string or object. |
|
|
134
|
+
| `transform.policy_required` | The transform requires host policy. |
|
|
135
|
+
|
|
136
|
+
## 8. Common Mistakes
|
|
137
|
+
|
|
138
|
+
| Mistake | Fix |
|
|
139
|
+
|---------|-----|
|
|
140
|
+
| Treating options as JSON only. | Use either hashes or semicolon strings. |
|
|
141
|
+
| Copying options between modes. | Check the selected transform/mode pair. |
|
|
142
|
+
| Passing `levels:2,3` and expecting raw integers only. | Levels may normalize aliases like `h2,h3` to canonical tokens. |
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown Composer Transform Scope
|
|
3
|
+
type: guide
|
|
4
|
+
status: current
|
|
5
|
+
updated: 2026-06-01
|
|
6
|
+
description: Public guide to transform scope syntax and behavior.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Markdown Composer Transform Scope
|
|
10
|
+
|
|
11
|
+
### References
|
|
12
|
+
|
|
13
|
+
| What | Where |
|
|
14
|
+
|------|-------|
|
|
15
|
+
| Transform anatomy | [./md_composer_transform_anatomy.md](./md_composer_transform_anatomy.md) |
|
|
16
|
+
| Compose targets | [../compose/md_composer_compose_targets.md](../compose/md_composer_compose_targets.md) |
|
|
17
|
+
| Select syntax | [../compose/md_composer_compose_select.md](../compose/md_composer_compose_select.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
|
+
`scope` chooses which units in the composed buffer a transform should affect.
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
{ "scope" => "heading_2_section[first:1]", "transform" => "replace_text", "mode" => "literal", "options" => "from:Draft; to:Final" }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If omitted, scope defaults to `output`.
|
|
33
|
+
|
|
34
|
+
## 2. Syntax Anatomy
|
|
35
|
+
|
|
36
|
+
Scope reuses selector syntax:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
scope = output | scope_selector
|
|
40
|
+
|
|
41
|
+
scope_selector = unit_token [take] [where condition]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
For every scope-capable token and alias, see [Unit Tokens](../reference/md_composer_unit_tokens.md).
|
|
45
|
+
For shared scope-selector take syntax, see [Take Modifiers](../reference/md_composer_take.md).
|
|
46
|
+
For shared scope-selector `where` syntax, see [Where Conditions](../reference/md_composer_where.md).
|
|
47
|
+
|
|
48
|
+
Scope selector parts:
|
|
49
|
+
|
|
50
|
+
| Part | Example | Meaning |
|
|
51
|
+
|------|---------|---------|
|
|
52
|
+
| `output` | `output` | The whole composed buffer or row fragment. |
|
|
53
|
+
| `unit_token` | `heading_2_section`, `paragraph`, `link` | A unit matched inside the current transform input. |
|
|
54
|
+
| `[take]` | `[first:1]`, `[position:2]` | Optional positional narrowing. |
|
|
55
|
+
| `where condition` | `where text:contains("Draft")` | Optional filtering. |
|
|
56
|
+
|
|
57
|
+
Examples:
|
|
58
|
+
|
|
59
|
+
| Goal | Scope |
|
|
60
|
+
|------|-------|
|
|
61
|
+
| Whole composed output | `output` |
|
|
62
|
+
| First H2 section in buffer | `heading_2_section[first:1]` |
|
|
63
|
+
| Paragraphs with text | `paragraph where text:contains("Draft")` |
|
|
64
|
+
| Code blocks | `code_block` |
|
|
65
|
+
| Data blocks | `data_block where format:equals("yaml")` |
|
|
66
|
+
|
|
67
|
+
## 3. Top-Level Scope
|
|
68
|
+
|
|
69
|
+
Top-level transform scope matches the composed buffer after all compose rows have run. It does not search the original sources.
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
{
|
|
73
|
+
"transform" => [
|
|
74
|
+
{ "scope" => "output", "transform" => "replace_text", "mode" => "literal", "options" => "from:Draft; to:Final" }
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 4. Row-Level Scope
|
|
80
|
+
|
|
81
|
+
For `modify`, omitted nested scope means the temporary fragment output.
|
|
82
|
+
|
|
83
|
+
For `transform_buffer_target`, omitted nested scope means the action `target`. An explicit nested scope overrides the action target.
|
|
84
|
+
|
|
85
|
+
## 5. Data Record And Data Value Scope
|
|
86
|
+
|
|
87
|
+
Capabilities mark `data_record` and `data_value` as output-only scopes. In the standalone Markdown buffer, they are transient derived nodes produced by `data_path(...)` and then serialized back to Markdown. Do not rely on `scope: "data_record"` or `scope: "data_value"` after ordinary composition unless a host adapter preserves structured nodes.
|
|
88
|
+
|
|
89
|
+
Use `data_block` scope for source-like structured blocks, or target the serialized Markdown text after extraction.
|
|
90
|
+
|
|
91
|
+
## 6. Common Mistakes
|
|
92
|
+
|
|
93
|
+
| Mistake | Fix |
|
|
94
|
+
|---------|-----|
|
|
95
|
+
| Expecting scope to search source documents. | Scope searches the composed buffer or row fragment. |
|
|
96
|
+
| Omitting scope without understanding defaults. | Top-level transforms default to `output`; row-level defaults depend on action. |
|
|
97
|
+
| Using `data_value` as a reliable standalone scope. | Treat it as transient structured-output metadata unless preserved by a host. |
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown Composer Transform Families
|
|
3
|
+
type: guide
|
|
4
|
+
status: current
|
|
5
|
+
updated: 2026-06-01
|
|
6
|
+
description: Public guide to Markdown Composer transform families.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Markdown Composer Transform Families
|
|
10
|
+
|
|
11
|
+
### References
|
|
12
|
+
|
|
13
|
+
| What | Where |
|
|
14
|
+
|------|-------|
|
|
15
|
+
| Transform anatomy | [./md_composer_transform_anatomy.md](./md_composer_transform_anatomy.md) |
|
|
16
|
+
| Modes | [./md_composer_transform_modes.md](./md_composer_transform_modes.md) |
|
|
17
|
+
| Options | [./md_composer_transform_options.md](./md_composer_transform_options.md) |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. Purpose
|
|
22
|
+
|
|
23
|
+
`transform` chooses the family of operation to run. `mode` chooses the behavior inside that family.
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
{ "transform" => "replace_text", "mode" => "literal", "options" => { "from" => "Draft", "to" => "Final" } }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 2. Syntax Anatomy
|
|
30
|
+
|
|
31
|
+
The `transform` field is only the family token. It is paired with `mode` and `options` to form an executable transform row.
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
transform_row = scope + transform_family + mode + options
|
|
35
|
+
|
|
36
|
+
transform_family = heading_numbers
|
|
37
|
+
| replace_text
|
|
38
|
+
| links
|
|
39
|
+
| heading_levels
|
|
40
|
+
| remove_empty
|
|
41
|
+
| insert_before
|
|
42
|
+
| insert_after
|
|
43
|
+
| prepend_content
|
|
44
|
+
| append_content
|
|
45
|
+
| replace_content
|
|
46
|
+
| remove_content
|
|
47
|
+
| dedupe
|
|
48
|
+
| order
|
|
49
|
+
| sanitise
|
|
50
|
+
| adapter
|
|
51
|
+
|
|
52
|
+
mode = one mode supported by that family
|
|
53
|
+
|
|
54
|
+
options = required and optional keys for that family/mode pair
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Example anatomy:
|
|
58
|
+
|
|
59
|
+
| Field | Value | Meaning |
|
|
60
|
+
|-------|-------|---------|
|
|
61
|
+
| `scope` | `paragraph where text:contains("Draft")` | Match paragraphs in the composed buffer. |
|
|
62
|
+
| `transform` | `replace_text` | Use the text replacement family. |
|
|
63
|
+
| `mode` | `literal` | Use literal text replacement. |
|
|
64
|
+
| `options` | `from:"Draft"; to:"Final"` | Provide required replacement values. |
|
|
65
|
+
|
|
66
|
+
## 3. Transform Families
|
|
67
|
+
|
|
68
|
+
| Transform | Use for |
|
|
69
|
+
|-----------|---------|
|
|
70
|
+
| `heading_numbers` | Keep, strip, add, or rebuild heading numbering. |
|
|
71
|
+
| `replace_text` | Replace literal text, whole words, or regex matches. |
|
|
72
|
+
| `links` | Keep, unwrap, remove, rewrite URLs, or add HTML link attributes. |
|
|
73
|
+
| `heading_levels` | Promote, demote, or normalize heading levels. |
|
|
74
|
+
| `remove_empty` | Remove empty units. |
|
|
75
|
+
| `insert_before` / `insert_after` | Insert content near scoped units. |
|
|
76
|
+
| `prepend_content` / `append_content` | Add content inside or near scoped units. |
|
|
77
|
+
| `replace_content` | Replace scoped content. |
|
|
78
|
+
| `remove_content` | Remove scoped content. |
|
|
79
|
+
| `dedupe` | Remove duplicates by source node id or normalized text. |
|
|
80
|
+
| `order` | Preserve action/source order; target order is gated/deferred. |
|
|
81
|
+
| `sanitise` | Host-policy sanitizing profiles. |
|
|
82
|
+
| `adapter` | Host-provided transform behavior. |
|
|
83
|
+
|
|
84
|
+
## 4. Common Choices
|
|
85
|
+
|
|
86
|
+
| Need | Transform / mode |
|
|
87
|
+
|------|------------------|
|
|
88
|
+
| Rename a term | `replace_text/literal` |
|
|
89
|
+
| Renumber headings | `heading_numbers/rebuild` |
|
|
90
|
+
| Promote headings | `heading_levels/promote` |
|
|
91
|
+
| Insert a warning before sections | `insert_before/insert` |
|
|
92
|
+
| Remove empty paragraphs | `remove_empty/remove` |
|
|
93
|
+
| Rewrite links | `links/rewrite_url` |
|
|
94
|
+
|
|
95
|
+
## 5. Policy-Gated Families
|
|
96
|
+
|
|
97
|
+
`sanitise` and `adapter` are policy-gated. A host must explicitly enable and implement policy behavior before exposing them as ordinary user controls.
|
|
98
|
+
|
|
99
|
+
`order/target_order` is also gated/deferred in capabilities. Public docs should not present it as a normal ready-to-use transform.
|
data/examples/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Markdown Composer Examples
|
|
2
|
+
|
|
3
|
+
These examples are runnable Ruby scripts for learning the gem from a normal Ruby project.
|
|
4
|
+
|
|
5
|
+
Run them from the gem root:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
ruby examples/basic_compose.rb
|
|
9
|
+
ruby examples/source_list_dsl.rb
|
|
10
|
+
ruby examples/yaml_plan.rb
|
|
11
|
+
ruby examples/html_input.rb
|
|
12
|
+
ruby examples/standard_composer.rb
|
|
13
|
+
ruby examples/standard_sources_buffer.rb
|
|
14
|
+
ruby examples/advanced_composer.rb
|
|
15
|
+
ruby examples/complex_composer.rb
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Each script prints Markdown and writes the same result to `examples/output/*.md`.
|
|
19
|
+
|
|
20
|
+
The examples use small Markdown and HTML fixtures in `examples/fixtures/`. They are user-facing sample inputs, separate from `test/fixtures/`, which are larger test-only fixtures used by the automated suite.
|