Skip to content

[fm-var] Convert references to vanilla Markdown #130

Description

@DandyLyons

Problem / outcome

Provide one command that converts a document containing active RFC 001 Rev 3 fm-var syntax into ordinary, portable Markdown:

md-utils fm-var to-markdown document.md

to-md is an exact alias for to-markdown.

The result contains no active <fm-var>, <fm-list>, or <fm-format> elements. Cached presentation values are inlined. When a reference has no cached value, the command resolves and evaluates its live value and inlines that result. fm-var-owned HTML and entity escaping are converted into vanilla Markdown while preserving the rendered meaning as closely as possible.

This is an export/conversion workflow, not synchronization: the output deliberately discards the dynamic fm-var declarations.

Epic: #111. This issue is related to, but semantically distinct from, cache synchronization in #113.

Command surface

Canonical command and alias:

md-utils fm-var to-markdown document.md
md-utils fm-var to-md document.md

Expected output modes:

  • Default to converted Markdown on stdout without modifying the source.
  • Support --output <file> for one input file.
  • Require explicit --write for in-place replacement.
  • Follow existing GlobalOptions conventions for file/tree selection, recursion, exclusions, hidden files, deterministic ordering, diagnostics, and styling.
  • Reject ambiguous combinations such as multiple inputs with a single --output file.

Conversion semantics

For every active element recognized by the lossless fm-var parser:

  1. <fm-var>

    • If the element has a non-empty cache, use that cache without fetching or refreshing the live value.
    • If the cache is empty or absent, run the normal source-resolution, YAML projection, JSONPath, fallback, coercion, formatting, and escaping pipeline and use the resulting value.
    • Replace the complete element, including opening and closing tags, with vanilla Markdown representing the selected presentation value.
  2. <fm-list>

    • Apply the same cache-first/live-when-empty rule atomically to the complete list.
    • Convert canonical <ul>/<ol>/<li> success caches into Markdown unordered/ordered lists with valid indentation and the document's line-ending convention.
    • Convert inline list formats and literal fallbacks to safe Markdown text.
    • Preserve item order and duplicates.
  3. <fm-format>

    • Remove the declaration and its fm-var-only syntax from the output.
    • Avoid leaving unnecessary blank lines where a top-level declaration was removed.
  4. Entities and literal text

    • Decode fm-var cache entities such as &amp;, &lt;, and numeric character references.
    • Re-serialize decoded text as safe Markdown when necessary so decoding does not accidentally change its rendered meaning or create markup injection. For example, an encoded literal Markdown delimiter may need a Markdown backslash escape rather than becoming active emphasis.
    • Normalize only fm-var-owned cache serialization. Unrelated authored Markdown/HTML remains unchanged.

Only active syntax recognized by FMVarParser is converted. Tag-like examples inside code spans, fenced/indented code, escaped text, comments, raw-code contexts, or other parser exclusion regions remain literal source text.

Failure and atomicity

  • Never silently discard an unresolved reference.
  • If an empty/absent cache cannot be resolved to a valid presentation value, report a precise diagnostic and do not emit or write a misleading partially stripped version of that file.
  • Plan and validate every complete-element replacement before producing a successful file result.
  • For --write, revision-check and atomically replace each changed file; skip byte-identical files.
  • Define deterministic multi-file partial-success and exit-status behavior consistent with other fm-var workflows.
  • Treat cached child content as untrusted input and prevent HTML/Markdown/custom-element injection during conversion.

Architecture direction

Acceptance criteria

  • md-utils fm-var to-markdown exists and md-utils fm-var to-md is an exact alias.
  • Default execution writes converted Markdown to stdout and never mutates the input.
  • A cached <fm-var> becomes vanilla Markdown without live source access.
  • An empty/absent scalar cache is resolved live and converted when policy permits.
  • Cached and live <fm-list> results become Markdown lists or safe inline Markdown as appropriate.
  • All active <fm-var>, <fm-list>, and <fm-format> syntax is absent from successful output.
  • fm-var-owned HTML list wrappers are removed and entity-escaped cache text is decoded/re-escaped safely for Markdown.
  • Unrelated Markdown, frontmatter spelling, whitespace, attributes outside replaced elements, Unicode, and LF/CRLF bytes remain unchanged wherever conversion does not require an edit.
  • Literal tag-like text in parser exclusion contexts remains unchanged.
  • An unresolved empty cache fails visibly rather than dropping content or emitting a partially stripped file.
  • --output and explicit --write behavior are documented, tested, and safe against concurrent changes.
  • Human-readable and structured diagnostics identify the document, source range, element, cache/live decision, and failure reason.

Test requirements

  • Golden tests for cached scalar, empty-cache live scalar, zero/null fallbacks, cached/live inline lists, ordered/unordered lists, and <fm-format> removal.
  • Entity cases for named and numeric references, Unicode, Markdown delimiters, angle brackets, ampersands, quotes, and closing-tag/injection attempts.
  • Preservation tests for frontmatter spelling, unrelated Markdown/HTML, inline/fenced/indented code, comments, escaped tags, whitespace, LF, and CRLF.
  • Failure tests for denied/unreadable sources, invalid queries, unresolved zero/null results, bad value shapes, invalid cache markup, and output-path conflicts.
  • Process tests proving stdout is non-mutating, to-md matches to-markdown, --output writes only the destination, and --write uses revision-checked atomic replacement.
  • Directory tests for deterministic ordering, exclusions, partial failure, no-op files, and exit statuses.

Documentation / CLI-help impact

  • Document the cache-first/live-when-empty rule prominently.
  • Explain that the operation is intentionally destructive to fm-var declarations and differs from synchronization.
  • Include stdout, --output, --write, single-file, and directory examples.
  • Document the boundary between fm-var-owned HTML/entity conversion and unrelated authored HTML, which remains unchanged.
  • Update README, DocC, CLI help, common-use-case references, and both synchronized copies of the bundled Markdown Utilities skill.

Explicitly deferred

  • Refreshing non-empty caches before conversion; use synchronization for that workflow.
  • Converting arbitrary unrelated HTML throughout the document.
  • Updating authoritative YAML/frontmatter.
  • Recursive/transitive evaluation of referenced documents.
  • General-purpose templating or conversion of non-fm-var custom elements.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions