diff --git a/.agency/do.md b/.agency/do.md index bec84165e..dc83375c6 100644 --- a/.agency/do.md +++ b/.agency/do.md @@ -19,6 +19,8 @@ Ignore Github Actions (slow) unless user asks for it. ## Documentation Keep `README.md`, `docs/` (user documentation), and `CHANGELOG.md` (under the `Unreleased` section) in sync with user-facing changes. +New or fixed **Markdown-syntax features** should be demonstrated in [`docs/guide/markdown.md`](../docs/guide/markdown.md) so the live example serves as both reference and regression check. A working `
` block, a new callout type, a new wiki-link form — each goes there as a real rendered sample, not just a CHANGELOG note. + ## PR evidence When the change has visible UI impact (theme, layout, rendering, navigation), post a `## Evidence` PR comment with screenshots. Use judgment — backend-only diffs (parser, link resolver, model) sometimes ripple into rendering and warrant a shot anyway. diff --git a/docs/guide/markdown.md b/docs/guide/markdown.md index b6632abd7..95ff43c17 100644 --- a/docs/guide/markdown.md +++ b/docs/guide/markdown.md @@ -160,6 +160,19 @@ See [[callout]] for details. > Lorem **ipsum** dolor sit *amet*, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +## Raw HTML + +Block-level HTML is passed through verbatim. When an opening tag and its matching closing tag each sit on their own line with blank lines on either side, the markdown between them is parsed as the element's children. This is how `
` renders as a working disclosure widget with rich content inside: + +
+ +This paragraph is a child of the `
` element. Regular **markdown** still works inside — _emphasis_, [example links](https://example.com), `code spans`, and Emanote extensions like [[neuron|wiki links]] all parse normally. + +
+ +Without the blank lines, the `
...
` is treated as one opaque HTML block — markdown inside is not parsed. _For an Emanote-native foldable variant that doesn't require raw HTML at all, see the `+` / `-` callout suffix in [[callout]]._ + + {#hanchor} ## Heading anchors diff --git a/emanote/CHANGELOG.md b/emanote/CHANGELOG.md index 10ebed31c..dab860ced 100644 --- a/emanote/CHANGELOG.md +++ b/emanote/CHANGELOG.md @@ -26,6 +26,7 @@ - Markdown links to a static `.xml` asset (e.g. `[Test](./test.xml)`) now resolve to the file. Previously a `.xml` URL was always interpreted as the Atom feed of a same-named note, leaving asset links broken when no such feed-enabled note existed. The missing-link page now also tailors its "you may create…" hint to the URL extension instead of always suggesting `.md` / `.org` (closes [#547](https://github.com/srid/emanote/issues/547)) - Resolve relative URLs inside `/index.md` against `/` instead of its parent ([#651](https://github.com/srid/emanote/pull/651), closes [#608](https://github.com/srid/emanote/issues/608)) - Raw HTML blocks containing a literal `` no longer crash the renderer with `div cannot contain text looking like its end tag` (closes [#119](https://github.com/srid/emanote/issues/119)). Fixed upstream in [srid/heist-extra#13](https://github.com/srid/heist-extra/pull/13) by switching the raw-HTML wrapper to a unique `` element with `display: contents`. +- Raw HTML blocks separated by blank lines (CommonMark "type 6", e.g. `
` … markdown … `
`) now nest the markdown content as a real DOM child of the surrounding element instead of leaving the open and close tags trapped inside their own `` wrappers. Fixed upstream by the new `groupRawHtmlBlocks` AST pass in heist-extra (closes [#433](https://github.com/srid/emanote/issues/433)). - A malformed `*.yaml` file (e.g. a non-string mapping key like `[]: foo`) no longer takes the live server down with `BadInput "NonStringKey []"`. The parse error is folded into `SData` itself and surfaced as a banner on the notes whose meta cascade actually depends on the bad file — a broken `subfolder/index.yaml` shows up under `/subfolder/*`, not on every page (closes [#285](https://github.com/srid/emanote/issues/285)). - TOC sidebar: tightened entry padding and styled the overflow scrollbar (Firefox `scrollbar-width: thin` + WebKit pseudo-element) so long tables of contents no longer surface the chunky OS-default bar (closes [#668](https://github.com/srid/emanote/issues/668)). - Markdown tables now honour Pandoc's column alignment, column widths, cell `rowspan` / `colspan`, row & cell attributes, and table footers — previously every field beyond "rows of cells" was discarded (closes [#27](https://github.com/srid/emanote/issues/27); fixed upstream in [srid/heist-extra#15](https://github.com/srid/heist-extra/pull/15)). diff --git a/flake.lock b/flake.lock index 6c46e49b5..746d5d9d1 100644 --- a/flake.lock +++ b/flake.lock @@ -169,11 +169,11 @@ "heist-extra": { "flake": false, "locked": { - "lastModified": 1777251633, - "narHash": "sha256-r1KTm9OIvwVeU6K6rZrGL/IrhGeCZ/9EqmK0e7FqDFk=", + "lastModified": 1777488739, + "narHash": "sha256-4N50ZxRC0kMKxfylHjdjwGhC+Od7WdAdVPo6wp07NSU=", "owner": "srid", "repo": "heist-extra", - "rev": "4857e8b265968f6c8f8c0d4d0075455bf99eeddb", + "rev": "f496d0c8210d4b17c97d85dde589363823d45aea", "type": "github" }, "original": { diff --git a/tests/features/smoke.feature b/tests/features/smoke.feature index 9d4882010..4e6f26559 100644 --- a/tests/features/smoke.feature +++ b/tests/features/smoke.feature @@ -44,6 +44,10 @@ Feature: Smoke When I open "/rawhtml.html" Then the page contains an element with data-marker "RAWHTML_DIV_OK" + Scenario: Markdown between blank-line-separated raw-HTML tags nests inside (#433) + When I open "/rawhtml-details.html" + Then the emitted HTML for "/rawhtml-details.html" wraps no around its
tags + Scenario: A feed-enabled note whose query matches no notes does not crash the build (regression: #490) When I fetch "/empty-feed.xml" Then the response is a valid Atom feed diff --git a/tests/fixtures/notebook/rawhtml-details.md b/tests/fixtures/notebook/rawhtml-details.md new file mode 100644 index 000000000..ee56782be --- /dev/null +++ b/tests/fixtures/notebook/rawhtml-details.md @@ -0,0 +1,19 @@ +--- +slug: rawhtml-details +--- + +# Raw HTML group (issue #433) + +CommonMark "type 6" HTML blocks (e.g. `
`) end at the next blank +line, so Pandoc emits the open tag, the markdown content, and the close +tag as three separate AST blocks. Without grouping, the markdown +paragraph escapes the surrounding element and ends up as its sibling. +The marker on the inner paragraph is what the e2e step asserts on: +the marker must have a `
` ancestor. + +
+ +This paragraph **must** render as a child of the `
` element. +marker + +
diff --git a/tests/step_definitions/smoke_steps.ts b/tests/step_definitions/smoke_steps.ts index ddd8602a1..26620d21e 100644 --- a/tests/step_definitions/smoke_steps.ts +++ b/tests/step_definitions/smoke_steps.ts @@ -28,6 +28,29 @@ Then( }, ); +// #433: orphan opener/closer raw-HTML tags around markdown content used to +// produce two stranded `` wrappers immediately adjacent to the +// `
` opener and closer. Browsers' lenient HTML5 parser recovers +// the broken stream into a DOM that nests the marker under
, so a +// DOM-level `closest("details")` check passes on master too. Catching the +// regression requires inspecting the *emitted* HTML directly. The +// load-bearing structural difference is the `
` +// adjacency on master vs. a bare `
` on the fix. +Then( + "the emitted HTML for {string} wraps no around its
tags", + async function (this: EmanoteWorld, route: string) { + const response = await this.page.request.get(route); + assert.ok(response.ok(), `Failed to fetch ${route}: ${response.status()}`); + const html = await response.text(); + const wrappedOpener = /]*>\s*)/.test(html); + const wrappedCloser = /]*>\s*<\/details>/.test(html); + assert.ok( + !wrappedOpener && !wrappedCloser, + `Expected ${route} to emit a bare
...
with no surrounding wrappers. Got wrappedOpener=${wrappedOpener}, wrappedCloser=${wrappedCloser}. The orphan-RawHtml grouping pass (heist-extra: groupRawHtmlBlocks) likely regressed.`, + ); + }, +); + // #285 — two complementary checks. The "no Ema exception" assertion // guards the *crash* (the original bug surface); the banner assertion // guards the *visibility* of the error so a parse failure can't fail