asciidoctor-mdpp 0.1.1

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.
@@ -0,0 +1,121 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, religion, or sexual identity
10
+ and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the
26
+ overall community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or
31
+ advances of any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email
35
+ address, without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our acceptable
42
+ standards of behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official e-mail address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ [INSERT CONTACT METHOD].
64
+ All complaints will be reviewed and investigated promptly and fairly.
65
+
66
+ All community leaders are obligated to respect the privacy and security of the
67
+ reporter of any incident.
68
+
69
+ ## Enforcement Guidelines
70
+
71
+ Community leaders will follow these Community Impact Guidelines in determining
72
+ the consequences for any action they deem in violation of this Code of Conduct:
73
+
74
+ ### 1. Correction
75
+
76
+ **Community Impact**: Use of inappropriate language or other behavior deemed
77
+ unprofessional or unwelcome in the community.
78
+
79
+ **Consequence**: A private, written warning from community leaders, providing
80
+ clarity around the nature of the violation and an explanation of why the
81
+ behavior was inappropriate. A public apology may be requested.
82
+
83
+ ### 2. Warning
84
+
85
+ **Community Impact**: A violation through a single incident or series
86
+ of actions.
87
+
88
+ **Consequence**: A warning with consequences for continued behavior. No
89
+ interaction with the involved people for a specified period of time, including
90
+ unsolicited interaction with those enforcing the Code of Conduct. This includes
91
+ avoiding interaction in community spaces as well as external channels like social
92
+ media. Violating these terms may lead to a temporary or permanent ban.
93
+
94
+ ### 3. Temporary Ban
95
+
96
+ **Community Impact**: A serious violation of community standards, including
97
+ sustained inappropriate behavior.
98
+
99
+ **Consequence**: A temporary ban from any sort of interaction or public
100
+ communication with the community for a specified period of time. No public or
101
+ private interaction with the involved people during this period, including
102
+ unsolicited interaction with those enforcing the Code of Conduct. Violating
103
+ these terms may lead to a permanent ban.
104
+
105
+ ### 4. Permanent Ban
106
+
107
+ **Community Impact**: Demonstrating a pattern of violation of community
108
+ standards, including sustained inappropriate behavior, harassment of an
109
+ individual, or aggression toward or disparagement of classes of individuals.
110
+
111
+ **Consequence**: A permanent ban from any sort of official interaction within
112
+ the community.
113
+
114
+ ## Attribution
115
+
116
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
117
+ version 2.1, available at
118
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
119
+
120
+ [homepage]: https://www.contributor-covenant.org
121
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,80 @@
1
+ # Contributing to Asciidoctor-MDPP
2
+
3
+ We welcome contributions to the Asciidoctor-MDPP project! By participating, you agree to abide by our [Code of Conduct](CODE_OF_CONDUCT.md).
4
+
5
+ ## How to Contribute
6
+
7
+ 1. **Fork the Repository**: Start by forking the `asciidoctor-mdpp` repository on GitHub.
8
+ 2. **Clone Your Fork**: Clone your forked repository to your local machine:
9
+ ```bash
10
+ git clone https://github.com/YOUR_USERNAME/asciidoctor-mdpp.git
11
+ cd asciidoctor-mdpp
12
+ ```
13
+ 3. **Install Dependencies**: Set up your development environment:
14
+ ```bash
15
+ bin/setup
16
+ ```
17
+ 4. **Create a New Branch**: Create a new branch for your feature or bug fix:
18
+ ```bash
19
+ git checkout -b feature/your-feature-name
20
+ ```
21
+ 5. **Implement Your Changes**:
22
+ * Follow the existing code style and conventions.
23
+ * All new features or bug fixes must be accompanied by new or updated tests.
24
+ * Ensure all tests pass before submitting your changes (`bundle exec rspec`).
25
+ * If you are adding a new conversion feature, please follow the Test-Driven Development (TDD) workflow outlined in `docs/development-guide.md` and `spec/fixtures/`.
26
+ 6. **Commit Your Changes**: Write clear, concise commit messages.
27
+ 7. **Push to Your Fork**:
28
+ ```bash
29
+ git push origin feature/your-feature-name
30
+ ```
31
+ 8. **Create a Pull Request**: Open a pull request from your fork to the `main` branch of the upstream repository. Provide a detailed description of your changes.
32
+
33
+ ## Test-Driven Development (TDD) Workflow
34
+
35
+ Our project heavily relies on TDD. When adding new conversion features:
36
+
37
+ 1. **Add Sample**: Create a new AsciiDoc sample file in `spec/fixtures/samples/`.
38
+ 2. **Define Expected Output**: Create the corresponding expected Markdown++ output in `spec/fixtures/expected/`.
39
+ 3. **Update Test Spec**: Add a new test case to `spec/converter_spec.rb` that uses your new sample and expected output.
40
+ 4. **Run Tests**: Execute `bundle exec rspec` to confirm the new test fails (as the feature is not yet implemented).
41
+ 5. **Implement Feature**: Write the necessary code in `lib/asciidoctor/converter/mdpp.rb` (or related files) to make the test pass.
42
+ 6. **Verify**: Run tests again to confirm successful conversion and that all existing tests still pass.
43
+ 7. **Commit**: Commit both the code changes and the fixture updates together.
44
+
45
+ ## Cline Workflow and Memory Bank
46
+
47
+ This project utilizes a "Cline Workflow" which is supported by a `.memory-bank` directory. This directory contains documentation files that provide context, design decisions, and progress updates for the project.
48
+
49
+ ### Memory Bank Structure
50
+
51
+ The `.memory-bank` directory contains the following core files:
52
+
53
+ * `projectbrief.md`: Defines core requirements and goals.
54
+ * `productContext.md`: Explains why the project exists, problems it solves, and user experience goals.
55
+ * `activeContext.md`: Details current work focus, recent changes, next steps, and active decisions.
56
+ * `systemPatterns.md`: Describes system architecture, key technical decisions, and design patterns.
57
+ * `techContext.md`: Outlines technologies used, development setup, and technical constraints.
58
+ * `progress.md`: Tracks what works, what's left to build, current status, and known issues.
59
+
60
+ ### How to Use the Memory Bank
61
+
62
+ * **Before Starting Work**: Always read through the `.memory-bank` files to understand the current state, context, and any ongoing discussions or decisions.
63
+ * **During Development**: Refer to `activeContext.md` for immediate next steps and `systemPatterns.md` for architectural guidance.
64
+ * **After Significant Changes**: Consider updating relevant `.memory-bank` files to reflect new patterns, design decisions, or progress. This helps maintain a shared understanding of the project's evolution.
65
+
66
+ By maintaining the `.memory-bank`, we ensure that all contributors have access to a comprehensive and up-to-date understanding of the project, facilitating smoother collaboration and onboarding.
67
+
68
+ ## Code Style
69
+
70
+ * Follow standard Ruby coding conventions.
71
+ * Use `frozen_string_literal: true` at the top of Ruby files.
72
+ * Maintain clean method boundaries and clear variable names.
73
+
74
+ ## Reporting Bugs
75
+
76
+ If you find a bug, please open an issue on our [GitHub Issues page](https://github.com/quadralay/asciidoctor-mdpp/issues). Provide as much detail as possible, including steps to reproduce the bug, expected behavior, and actual behavior.
77
+
78
+ ## Suggesting Enhancements
79
+
80
+ We welcome suggestions for new features or improvements. Please open an issue on our [GitHub Issues page](https://github.com/quadralay/asciidoctor-mdpp/issues) to discuss your ideas.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Quadralay Corporation
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,113 @@
1
+ # Asciidoctor-MDPP
2
+
3
+ Asciidoctor-MDPP is a Ruby-based Asciidoctor converter for converting AsciiDoc files to Markdown++ (MDPP) files. It provides a custom converter for transforming AsciiDoc documents into an enhanced variant of standard Markdown, extending the Asciidoctor framework with specialized conversion capabilities to handle unique Markdown++ features while preserving document structure and formatting.
4
+
5
+ ## Purpose
6
+
7
+ The primary purpose of this project is to facilitate the conversion of technical documentation from AsciiDoc format to Markdown++ format, enabling users to leverage AsciiDoc's structured authoring capabilities while targeting systems that work with Markdown++.
8
+
9
+ ## Features
10
+
11
+ * **Automated Conversion**: Seamlessly convert AsciiDoc to Markdown++.
12
+ * **Markdown++ Extensions**: Supports multiline tables, style tags, and file includes.
13
+ * **High Fidelity Output**: Preserves document structure and formatting.
14
+ * **Batch Processing**: Convert entire documentation sets with CLI tools.
15
+ * **Asciidoctor Integration**: Works with standard Asciidoctor toolchains.
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'asciidoctor-mdpp'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ ```bash
28
+ bundle install
29
+ ```
30
+
31
+ Or install it yourself as:
32
+
33
+ ```bash
34
+ gem install asciidoctor-mdpp
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### Command Line Interface (CLI)
40
+
41
+ You can convert a single AsciiDoc file to Markdown++ using the provided script:
42
+
43
+ ```bash
44
+ ./scripts/convert-mdpp-file.sh input.adoc
45
+ ```
46
+
47
+ Or using Asciidoctor directly:
48
+
49
+ ```bash
50
+ asciidoctor -r lib/asciidoctor/converter/mdpp.rb -b mdpp -o output.md input.adoc
51
+ ```
52
+
53
+ For batch conversion of all `.adoc` files in a directory:
54
+
55
+ ```bash
56
+ ./scripts/convert-mdpp.sh <SOURCE_DIR> <OUTPUT_DIR>
57
+ ```
58
+
59
+ ### Programmatic Usage
60
+
61
+ ```ruby
62
+ require 'asciidoctor/converter/mdpp'
63
+
64
+ # Option 1: Direct conversion
65
+ output = Asciidoctor.convert_file(
66
+ 'input.adoc',
67
+ backend: 'mdpp',
68
+ safe: :safe,
69
+ require: 'asciidoctor/converter/mdpp',
70
+ attributes: { 'outfilesuffix' => '.md' },
71
+ header_footer: true,
72
+ to_file: false
73
+ )
74
+
75
+ # Option 2: Two-step conversion (for source locations, recommended for complex docs)
76
+ doc = Asciidoctor.load_file(
77
+ 'input.adoc',
78
+ safe: :safe,
79
+ sourcemap: true,
80
+ require: 'asciidoctor/converter/mdpp',
81
+ backend: 'mdpp',
82
+ header_footer: true
83
+ )
84
+ output = doc.convert
85
+ ```
86
+
87
+ ## Development
88
+
89
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
90
+
91
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `lib/asciidoctor/mdpp/version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
92
+
93
+ ## Contributing
94
+
95
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/quadralay/asciidoctor-mdpp](https://github.com/quadralay/asciidoctor-mdpp). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Code of Conduct](CODE_OF_CONDUCT.md).
96
+
97
+ ## License
98
+
99
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
100
+
101
+ ## Markdown++ File Extension and Compatibility
102
+
103
+ Markdown++ files generated by Asciidoctor-MDPP use the standard `.md` file extension, not a custom `.mdpp` extension. This design choice is intentional and offers significant benefits:
104
+
105
+ * **Backward Compatibility**: Markdown++ files are fully backward compatible with standard Markdown parsers. This means you can render a Markdown++ file using any Markdown viewer or processor, and it will display as a regular Markdown document.
106
+ * **Ease of Use**: By using the `.md` extension, Markdown++ files can be seamlessly integrated into existing workflows and platforms that expect standard Markdown files, without requiring special handling or configuration for file types.
107
+ * **Enhanced Features via Comments**: Markdown++'s extended features (like multiline tables, style tags, and file includes) are implemented using Markdown-compatible syntax, often leveraging HTML comments. This ensures that while the advanced features are present and functional for Markdown++-aware processors, they gracefully degrade or are ignored by standard Markdown parsers, maintaining readability.
108
+
109
+ This approach allows you to leverage the power of Markdown++ for enhanced documentation while ensuring broad compatibility and ease of adoption.
110
+
111
+ ## About WebWorks - Quadralay Corporation
112
+
113
+ Asciidoctor-MDPP is developed by WebWorks - Quadralay Corporation as an open-source contribution to the technical documentation community.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ task default: %i[]
@@ -0,0 +1,19 @@
1
+ = Demo Document
2
+ Tony McDow
3
+ :doctype: article
4
+ :toc:
5
+
6
+ == First section
7
+
8
+ AsciiDoc is *really* easy to try.
9
+
10
+ * Bullet 1
11
+ ** Bullet 1.1
12
+ *** Bullet 1.1.1
13
+ *** Bullet 1.1.2
14
+ ** Bullet 1.2
15
+ * Bullet 2
16
+
17
+ [source,ruby]
18
+ puts "Hello, WebWorks!"
19
+
@@ -0,0 +1,14 @@
1
+ = Sample Document
2
+
3
+ This document tests nested unordered lists.
4
+
5
+ == Test Section
6
+
7
+ Here’s a top‐level introduction before the list.
8
+
9
+ * Level 1 item A
10
+ ** Level 2 item A.1
11
+ *** Level 3 item A.1.a
12
+ **** Level 4 item A.1.a.i
13
+ ** Level 2 item A.2
14
+ * Level 1 item B
@@ -0,0 +1,34 @@
1
+ = Sample Document
2
+ Author Name
3
+ :toc:
4
+
5
+ This document tests nested unordered lists.
6
+
7
+ == Test Section
8
+
9
+ Here’s a top‐level introduction before the list.
10
+
11
+ * Level 1 item A
12
+ ** Level 2 item A.1
13
+ *** Level 3 item A.1.a
14
+ **** Level 4 item A.1.a.i
15
+ ** Level 2 item A.2
16
+ * Level 1 item B
17
+
18
+ // An open block to attach a paragraph under Level 1 item C
19
+ * Level 1 item C
20
+ +
21
+ --
22
+ ** Level 2 item C.1
23
+ *** Level 3 item C.1.a
24
+ --
25
+ + This paragraph is attached to “Level 1 item C” (not to the nested list).
26
+
27
+ * Level 1 item D
28
+ ** Level 2 item D.1
29
+ + A continuation paragraph for “Level 2 item D.1”
30
+ ** Level 2 item D.2
31
+
32
+ // Another top‐level list after a blank line
33
+
34
+ * Final Level 1 item
@@ -0,0 +1,84 @@
1
+ <!-- docs/conversion-guidelines.md -->
2
+ # AsciiDoc → Markdown++ Conversion: Design Guidelines
3
+
4
+ This document captures key design decisions, assumptions, and limitations of the MDPP converter.
5
+
6
+ ## Table Conversion
7
+
8
+ - The converter supports two main table styles:
9
+ 1. **AST-based simple tables** (more than two columns): uses Asciidoctor’s AST to extract header and body rows, compute column widths, and render a padded Markdown++ table.
10
+ 2. **Grid-based multiline tables** (exactly two columns with multiline cell content): parses the raw source between `|===` fences to preserve cell grouping, then emits a two-column Markdown++ table with `multiline` style.
11
+ - A **final AST fallback** wraps the entire grid parse in a `begin…rescue` to catch inconsistent fencing, missing fences, or nil comparisons. On error, it reverts to the simple AST-based renderer to guarantee conversion succeeds.
12
+ - Challenges:
13
+ - Inconsistent AsciiDoc fencing (missing closing `|===`) caused `nil` index errors.
14
+ - Column width calculations needed nil-safe defaults.
15
+ - Preserving empty lines between logical row groups to match expected fixtures.
16
+
17
+ ## Admonition Conversion
18
+
19
+ - Two rendering modes:
20
+ 1. **Fenced blocks** (`[NOTE]` / `====…====`): convert child blocks (e.g., paragraphs, lists) recursively, then prefix each line with `> ` and prepend `<!-- style:Admonition<Type> -->` without a trailing blank line.
21
+ 2. **Short-form blocks** (`NOTE:` in a paragraph): capture the raw lines, quote them verbatim, and append a trailing blank line to separate from following content.
22
+ - Challenges:
23
+ - Distinguishing fenced vs. inline admonitions was required to control newlines correctly.
24
+ - Tests use strict equality, so extra or missing blank lines broke fixtures.
25
+
26
+ ## Image Macro Conversion
27
+
28
+ - Single converter (`convert_image`) handles both block and inline images.
29
+ - Parsing rules:
30
+ - **Alt text**: only the first positional attribute is used; if none, the `alt` is empty (`![]`).
31
+ - **Dimensions**: `width` and `height` can be numeric or percentage (e.g., `60%`), either as positional params or named attributes (`width="60%"`).
32
+ - **Style name**: built as `w<value>` and/or `h<value>` with `%` mapped to `percent` (e.g., `w60percent`).
33
+ - **Style comment**: only emitted when at least one dimension is specified: `<!-- style:w250h350 -->`.
34
+ - **pdfwidth** and other non-size attributes are ignored.
35
+ - Inline images are processed via `convert_paragraph`, which gsubs on the `image:…[...]` pattern and reuses the same style logic.
36
+ - Challenges:
37
+ - Handling mixed named and positional parameters.
38
+ - Ensuring inline and block conversions stay in sync.
39
+ - Avoiding extraneous style comments when no size is provided.
40
+
41
+ ## Strict Fixture Matching
42
+
43
+ - Because tests perform byte-for-byte comparisons, every blank line, trailing newline, and space counts.
44
+ - All converter methods (`convert_document`, `convert_admonition`, etc.) must be careful about where they append `\n`.
45
+ - For example, `convert_document` should not append an extra newline at end, to avoid unexpected blank line.
46
+ - Short-form admonitions append one trailing newline, whereas fenced admonitions do not.
47
+
48
+ ---
49
+ _These guidelines will evolve as new edge cases appear. Please document any future converter gotchas here._
50
+ ## Line Break Challenges
51
+
52
+ - Asciidoctor normalizes trailing `+` line breaks differently in paragraphs vs. list items:
53
+ - Paragraph breaks (trailing `+`) appear in `par.lines` and are handled by `convert_paragraph` by joining lines after stripping the `+`.
54
+ - List-item breaks are absorbed by the parser (AST loses the second line), so `convert_list_item` sees only the first segment.
55
+ - The only reliable way to recover list-item breaks is a minimal file-aware fallback in `convert_olist`:
56
+ 1. Call `convert(li, 'list_item')`. If it yields an empty or whitespace-only body, then
57
+ 2. Use `li.source_location` to get the file path and line number.
58
+ 3. Read that raw source line, strip the trailing `+`, emit `warn "path:lineno: inline '+' break in list item is not supported; text following the '+' has been dropped"` to `STDERR`, and use the remaining text as the list item.
59
+ - Do not attempt to preprocess or rewrite `reader.lines` for this, as it breaks nested blocks, tables, and other constructs.
60
+ - For nested list indentation, always check whether `ulist.parent.node_name == 'list_item'` instead of trusting `ulist.level`, which can vary in non-list contexts.
61
+
62
+ ## Session Summary (2025-04-30)
63
+
64
+ ### New Features
65
+ - Anchors: explicit section anchors (`[[id]]`) are rendered as `<!-- #id -->` comments only for user-defined ids (not auto-generated).
66
+ - Code and literal blocks: listing (`----`) and literal (`....`) blocks are emitted as triple-backtick fences, with language tags for `[source,lang]` blocks.
67
+ - Page breaks: AsciiDoc `<<<` directives produce blank lines to indicate page breaks.
68
+ - Thematic breaks: `'''` directives are converted to `---` horizontal rules.
69
+ - Video embeds: `video::id[youtube,width=...,height=...]` macros produce YouTube `<iframe>` embeds with specified dimensions.
70
+
71
+ ### Assumptions
72
+ - Section ids starting with the `idprefix` (default `_`) are considered auto-generated and skipped for anchor comments.
73
+ - Code fences are not applied inside `example` blocks to preserve nested blockquote formatting.
74
+ - Only YouTube provider is supported for video embeds; other providers will fall back to a TODO comment.
75
+ - The converter intentionally omits a trailing newline at the end of output to satisfy strict fixture matching.
76
+
77
+ ### Design Decisions
78
+ - In `convert_section`, detect explicit anchors by checking that `sec.id` does not start with the document’s `idprefix`.
79
+ - In `convert_listing`, handle `listing` and `source` styles with code fences, and bypass fencing when the parent node is an `example`.
80
+ - Introduce `convert_page_break` and `convert_thematic_break` to handle `<<<` and `'''` blocks as blank lines and horizontal rules, respectively.
81
+ - For video macros, implement `convert_video` to render a YouTube `<iframe>` based on `target`, `width`, and `height` attributes.
82
+ - Trim trailing newlines in expected fixtures rather than modifying spec comparisons to allow both behaviors.
83
+
84
+ _End of session summary._
@@ -0,0 +1,95 @@
1
+ <!-- docs/development-guide.md -->
2
+ # Developer Guide
3
+
4
+ This document summarizes key workflows, conventions, and architectural notes for contributors and coding agent sessions.
5
+
6
+ ## Testing and Fixtures
7
+ - All feature work is done TDD-style: start by adding or updating a sample in `spec/fixtures/samples` and its corresponding expected output in `spec/fixtures/expected`.
8
+ - Update `spec/converter_spec.rb` to include tests for new fixture files.
9
+ - Run `rspec` to verify all tests, then commit both code changes and fixture updates together.
10
+ - When writing tests that rely on node source locations (e.g., for inline-break recovery in list items), load documents with `Asciidoctor.load_file(..., sourcemap: true)` and call `doc.convert` rather than using `Asciidoctor.convert_file`. This ensures `source_location` is populated on AST nodes.
11
+
12
+ ## Converter Architecture
13
+ - The core converter is `lib/asciidoctor/converter/mdpp.rb`, implementing a `convert(node, transform)` dispatch to `convert_<node>` methods.
14
+ - Common patterns:
15
+ - `convert_paragraph`, `convert_image`, `convert_admonition`, `convert_ulist`/`convert_olist`, etc.
16
+ - For new Asciidoctor node types (e.g., tables), implement a `convert_table(node)` method.
17
+
18
+ ## Markdown++ Extensions
19
+ - Specifications for language extensions (multiline tables, custom style tags, etc.) live under `docs/mdpp-specification/`.
20
+ - Please refer to those spec files when implementing or updating features.
21
+
22
+ ## Documentation Updates
23
+ - When workflow or conventions change, update this file to reflect the new process.
24
+
25
+ ## Helpful Tips
26
+ - Use interactive inspect scripts (e.g., throwaway `inspect_*.rb`) to explore Asciidoctor AST nodes, then delete those scripts before committing.
27
+ - Keep commits small and focused: fix root causes, update only relevant files.
28
+
29
+ - Programmatically, you can invoke the converter from Ruby:
30
+ ```ruby
31
+ require 'asciidoctor/converter/mdpp'
32
+ output = Asciidoctor.convert_file(
33
+ 'input.adoc',
34
+ backend: 'mdpp',
35
+ safe: :safe,
36
+ # To enable recovery of source_location on nodes (e.g., for list-item inline-break tests),
37
+ # prefer using Asciidoctor.load_file with sourcemap: true:
38
+ # doc = Asciidoctor.load_file('input.adoc', safe: :safe, sourcemap: true,
39
+ # require: 'asciidoctor/converter/mdpp', backend: 'mdpp', header_footer: true)
40
+ # output = doc.convert
41
+ require: 'asciidoctor/converter/mdpp',
42
+ attributes: { 'outfilesuffix' => '.md' },
43
+ header_footer: true,
44
+ to_file: false
45
+ )
46
+ ```
47
+
48
+ - From the shell:
49
+ ```bash
50
+ asciidoctor -r lib/asciidoctor/converter/mdpp.rb -b mdpp -o output.md input.adoc
51
+ ```
52
+ - Byte-for-byte fixture matching: tests compare the full output (including trailing newlines). When changing newline behavior, trim or add newlines in expected fixtures (e.g., `truncate -s -1 spec/fixtures/expected/file.md`) instead of altering specs.
53
+ - Rapid ad-hoc conversion checks: use a Ruby one-liner to preview converter output, for example:
54
+ ```bash
55
+ ruby -Ilib -r asciidoctor/converter/mdpp -e "puts Asciidoctor.convert_file('spec/fixtures/samples/your.adoc', backend: 'mdpp', safe: :safe, require: 'asciidoctor/converter/mdpp', header_footer: true)"
56
+ ```
57
+ - Distinguish explicit vs. auto-generated anchors: Asciidoctor auto-prefixes IDs with the document’s `idprefix` (default `_`), so emit only user-defined anchors by checking `sec.id` against that prefix.
58
+ - Handling new block types: for each new node (e.g., `page_break`, `thematic_break`, `video`), implement a `convert_<node>` in `mdpp.rb`, add sample and expected fixtures, and update the spec.
59
+ - Logical, focused commits: group related changes into separate commits (fixtures, converter/spec updates, documentation) with clear, descriptive messages.
60
+
61
+ ## CLI Wrapper and Batch Conversion Script
62
+ - A helper script lives at `scripts/convert-mdpp.sh` to run the MDPP converter recursively over a directory tree.
63
+ - Usage: `./scripts/convert-mdpp.sh <SRC_DIR> <OUT_DIR>`
64
+ - It finds all `.adoc`/`.asciidoc` files under `SRC_DIR`, creates matching paths in `OUT_DIR`, and invokes:
65
+ ```bash
66
+ asciidoctor -r lib/asciidoctor/converter/mdpp.rb -b mdpp -o "$DST" "$SRC"
67
+ ```
68
+
69
+ ## Single-File Conversion Script
70
+ - A helper script at `scripts/convert-mdpp-file.sh` converts a single AsciiDoc file to Markdown++ side-by-side.
71
+ - Usage: `./scripts/convert-mdpp-file.sh <INPUT.adoc>`
72
+ - Verifies the file exists and has a `.adoc` or `.asciidoc` extension.
73
+ - Outputs a `.md` file alongside the source with the same basename.
74
+ - Ensures the output ends with a trailing newline for strict fixture matching.
75
+
76
+ ## Fixture Tuning and Exact Matching
77
+ - All tests perform strict string comparisons of output vs. expected fixtures.
78
+ - Blank lines, trailing newlines, and precise spacing matter for passing tests.
79
+ - When adding or modifying fixtures, use the diff in `rspec` output to identify mismatches and adjust the expected file accordingly.
80
+ - The converter updates are synchronized with fixture tweaks in each feature commit to ensure consistency.
81
+
82
+ Happy Converting!
83
+
84
+ ## CLI Wrapper and Batch Conversion Script
85
+ - A helper script resides at `scripts/convert-mdpp.sh` to invoke the MDPP converter over a directory tree.
86
+ - Usage: `./scripts/convert-mdpp.sh <SRC_DIR> <OUT_DIR>`
87
+ - It scans for `.adoc`/`.asciidoc` files under `SRC_DIR`, mirrors the directory structure in `OUT_DIR`, and runs:
88
+ ```bash
89
+ asciidoctor -r lib/asciidoctor/converter/mdpp.rb -b mdpp -o "$DST" "$SRC"
90
+ ```
91
+
92
+ ## Fixture Tuning and Exact Matching
93
+ - Tests compare outputs strictly (including blank lines, trailing newlines, and spacing).
94
+ - When creating or updating fixture files, inspect the `rspec` diff and adjust expected files to match the converter’s output exactly.
95
+ - Fixture updates should accompany code changes in the same commit to keep tests green.
@@ -0,0 +1,29 @@
1
+ ## Inline-Break Challenges and Partial Recovery
2
+
3
+ AsciiDoc hard line breaks (a trailing `+` at end of line) are handled differently depending on context:
4
+
5
+ ### Paragraph-level inline breaks
6
+ - Asciidoctor represents a trailing `+` as an inline break, but using `par.content` drops them.
7
+ - The converter now processes `par.lines`, strips any trailing `+` on each line, and joins lines with literal newlines:
8
+ ```ruby
9
+ lines = par.lines.map { |l| l.chomp("\n").chomp('+') }
10
+ text = lines.join("\n")
11
+ ```
12
+ - This restores hard breaks in normal paragraphs, image-macro paragraphs, admonitions, and most block contexts.
13
+
14
+ ### List-item inline breaks
15
+ - **AST limitation**: For `olist` items, Asciidoctor splits at the break marker and drops the continuation from the AST; only the first segment remains.
16
+ - **Fallback approach** (implemented but brittle):
17
+ 1. Enable `sourcemap: true` when loading via `Asciidoctor.load_file` so that `li.source_location` is populated.
18
+ 2. In `convert_olist`, inspect `li.source_location` to locate the raw source file and line number.
19
+ 3. Read the raw file lines, strip trailing `+`, and collect all subsequent lines until the next list-item marker or a blank line.
20
+ 4. Reconstruct the multi-line item by preserving the original numbering marker and indenting continuations.
21
+ - **Limitations**:
22
+ - `source_location` is not set when using `Asciidoctor.convert_file` (the common conversion path), so fallback rarely triggers.
23
+ - Relative paths in `loc.path` require lookup via the document’s `docfile` attribute.
24
+ - The logic is brittle and may fail for nested lists and complex items.
25
+ - The converter currently emits `<!-- TODO: inline_break -->` placeholders for list-item breaks.
26
+
27
+ ### Future work
28
+ - Consider writing an Asciidoctor extension to merge broken list-item segments before conversion.
29
+ - Improve `convert_olist` fallback or switch to a preprocessor-based approach for robust recovery.