Skip to content

feat(wrap): interpolate any --meta-json key (generic frontmatter hook) - #127

Merged
drawmeanelephant merged 1 commit into
mainfrom
feat/wrap-generic-hook
Aug 27, 2026
Merged

drawmeanelephant merged 1 commit into
mainfrom
feat/wrap-generic-hook

Conversation

@drawmeanelephant

Copy link
Copy Markdown
Owner

Generic frontmatter hook for oliver wrap

rotkeeper issue #269 asks for reusable Oliver hooks: injecting a new frontmatter field should not require a struct field, fieldVal entry, rebuild, and pin move every time. This PR makes the wrap dialect generic.

What changes

wrap now parses --meta-json twice — the typed v1/v2 struct (unchanged semantics) plus a dynamic object map — and any key present in the map becomes an interpolatable token:

  • string values substitute html-escaped, like every metadata token
  • null → empty (and $if$ gates off)
  • integers / floats / booleans stringify ($count$ with "count": 77)
  • objects / arrays render as compact JSON (escaped on substitution)
  • $if(name)$ gating extends to every present key
  • keys absent from meta-json still pass through verbatim

The typed fieldVal lookup runs first, so the 13 known tokens keep their exact behavior; extras are purely additive. This is the "reusable hooks" ask from rotkeeper #269 — no upstream change needed to add a frontmatter field, the adapter just merges it into meta-json.

Tests

466 tests green, including new v3 coverage: generic substitution, html-escaped extras, scalar stringification (int/bool/object), $if$ gating on generic keys, null-gating, and verbatim passthrough for absent keys.

rotkeeper #269 asks for reusable Oliver hooks: injecting a new frontmatter
field should not require a struct field, fieldVal entry, rebuild, and pin
move each time. wrap now parses the meta JSON twice — the typed v1/v2
struct (unchanged semantics) plus a dynamic object map — and any key
present in the map becomes an interpolatable token:

  - string values substitute html-escaped, like every metadata token
  - null → empty (and $if$ gates off)
  - integers/floats/booleans stringify
  - objects/arrays render as compact JSON (escaped on substitution)
  - $if(name)$ gating extends to every present key
  - keys absent from meta-json still pass through verbatim

The typed fieldVal lookup stays first, so the 13 known tokens keep their
exact behavior; extras are purely additive. 466 tests green, including
new v3 coverage for substitution, escaping, stringification, gating,
null gating, and verbatim passthrough.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
@drawmeanelephant
drawmeanelephant merged commit 3f05bac into main Aug 27, 2026
3 checks passed
@drawmeanelephant
drawmeanelephant deleted the feat/wrap-generic-hook branch August 27, 2026 22:32
@itoqa

itoqa Bot commented Aug 27, 2026

Copy link
Copy Markdown

Ito QA test results
Commit: 84d0d6d: 11 test cases ran, 11 passed ✅.

Summary

Coverage spans normal template rendering, conditional content inclusion and removal, metadata substitution and HTML escaping, preservation of trusted and unknown values, typed-value precedence, and malformed or invalid metadata handling. It also exercises ordering and edge-case behavior where conditional markers or metadata are absent, null, nested-looking, or conflicting.

Safe to merge — all exercised behaviors passed, including normal flows, security-relevant escaping, validation failures, and edge cases, with no PR-attributable regressions or unresolved failures. There are no merge blockers identified in this run.

Tests run by Ito

View full run

Result Severity Type Description
General The conditional article kept its content and replaced both values with the same escaped text as the control template. Each value appeared once, so the two rendering phases did not change the result.
General The template kept the outer section content, preserved the inner-looking marker, and left the sentinel text and extra closing marker in the correct order.
General A typed page type value controls both the conditional block and the value shown inside it. When the typed value is null, the block and the token outside it are both empty, so a generic value cannot replace it.
Conditional A template with a non-empty slug kept its conditional text and replaced the slug with hello. The conditional markers were removed from the final output.
Conditional When the note value is null, the complete conditional block is removed. The output is exactly Before After, with no hidden text or template markers.
Conditional When the metadata does not contain the requested name, the complete conditional text stays unchanged. The command finished successfully and returned the exact expected output.
Metadata The wrap command rendered strings, numbers, booleans, arrays, and objects from the metadata JSON. It escaped HTML-sensitive text and rendered the null value as empty text.
Metadata The wrap command rejected an unterminated metadata string and did not render the template. It returned an error with exit code 1, as expected.
Metadata The wrap command rejected a valid JSON array instead of trying to render it. It returned the expected parse error, exit code 1, and no output.
Wrap The wrap command escaped the metadata value, kept the body and asset path unchanged, and preserved the unknown placeholder.
Wrap The wrap command converted every special character in the metadata value to its HTML entity, so the output contained no raw delimiters.

Tip

Reply with @itoqa to send us feedback on this test run.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant