Skip to content

Commit 069a324

Browse files
committed
release: 7.7.0
Round 8 rich-text fidelity and dialect capability typing. Added: `==text==` highlight round-trip; inline link/image title preservation; `fallbackToHtml.itemLineBreaks`; syntax-typed dialect capabilities (`admonitions: 'blockquote'|'fence'|'fence-attribute'`, `strikethrough: 'tilde'`, new `highlight: 'equals'`, etc., each with `'none'`). Deprecated: boolean dialect toggles and admonition flavour names (coerced, removed next major). Fixed: nested lists no longer flatten on the round trip (and generate spec-valid HTML); per-column GFM table alignment; inline monospace -> `<code>`; single-line code-with-language -> `<pre><code>`; plain `<blockquote>` export; `<br>` hard break; single-line `$$...$$` block math. Syncs CHANGELOG, README, the config spec, and the visualizer; bumps to 7.7.0.
1 parent 3316861 commit 069a324

6 files changed

Lines changed: 49 additions & 20 deletions

File tree

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,26 @@ All notable changes to `officeParser` are documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [7.7.0] - 2026-08-17
8+
### Added
9+
- **`==text==` highlight round-trips through Markdown.** In a dialect that defines it (Obsidian/extended), a highlighted run now emits as `==text==` and `==text==` parses back to a highlight; other dialects keep the HTML `<mark>`/`<span>` fallback and leave `==` literal on parse. Import is purely additive; export of the default-yellow highlight becomes `==` under the `extended` dialect.
10+
- **Inline link and image titles are preserved in both directions.** `[text](url "Title")` and `![alt](img.png "Title")` now parse their title into `TextMetadata.title` / `ImageMetadata.title` - previously an *inline* destination swallowed `url "Title"` as one URL (reference-style links already parsed the title correctly) - and the generators emit it back as a Markdown title and an HTML `title=` attribute.
11+
- **`MdGeneratorConfig.fallbackToHtml.itemLineBreaks`** (default on): multi-paragraph list-item content (an HTML `<li>` with several `<p>` children) is joined onto the item's single Markdown line with `<br>` instead of a space, mirroring `cellLineBreaks` for table cells.
12+
- **Markdown dialect capabilities are typed by the syntax they select.** `mdConfig.dialect` now names each capability's syntax: `admonitions: 'blockquote' | 'fence' | 'fence-attribute' | 'none'`, and `strikethrough`/`definitionLists`/`footnotes`/`citations`/`wikilinks`/`attributeLists` as `'<marker>' | 'none'` (e.g. `strikethrough: 'tilde'`, `wikilinks: 'double-bracket'`). A new `highlight: 'equals' | 'none'` capability is added. `'none'` is the explicit off switch; an omitted field still inherits from `extends`. Naming each capability for its syntax (rather than a product flavour or a bare boolean) lets a shared convention be one value and lets a second syntax be added later without a breaking change.
13+
14+
### Deprecated
15+
- **Boolean values for dialect capability fields, and the admonition flavour names.** `strikethrough: true`/`false` (and the same for `definitionLists`, `footnotes`, `citations`, `wikilinks`, `attributeLists`) and `admonitions: 'github' | 'gitlab' | 'pandoc'` still work - they coerce to the new syntax values (`true` to the marker, `false` to `'none'`; the flavour names to `'blockquote'`/`'fence'`/`'fence-attribute'`) - but are deprecated and will be removed in the next major. Output is byte-identical for existing configs.
16+
17+
### Fixed
18+
- **Nested lists flattened on an HTML round trip.** An HTML list item wrapping its text in a block element (`<li><p>a</p><ul>…`, the shape rich-text editors built on ProseMirror/Tiptap emit) exported to Markdown as `- a\n\n\n - a1`: the paragraph's trailing blank line split the list into separate blocks and the child's indent was then stripped on reparse, so `a` and `a1` came back as flat siblings in one list. List items are now emitted as a single tight line (via `itemLineBreaks` above), a conservative parser pass re-joins a blank-line-split indented child back into its list, and `HtmlGenerator` places a nested list inside its parent's still-open `<li>` (spec-valid `<li>a<ul>…</ul></li>` instead of the invalid sibling `<li>a</li><ul>…`), which also makes generated EPUB XHTML valid. A bare-text `<li>` (no `<p>`) was never affected. **Behaviour change** to the shape of generated nested-list HTML.
19+
- **GFM table column alignment was lost on import, non-standard on Markdown export, and dropped through HTML.** Import ignored the `:---`/`:---:`/`---:` separator markers; Markdown export emitted `| --- |` with a trailing non-standard table-level `{align=…}` rather than per-column markers; and the HTML generator emitted no cell alignment at all, so a table lost its alignment whenever it passed through HTML (the editor import path `md → HTML → editor`). Alignment now lives on per-column `CellMetadata.align`: the Markdown generator regenerates the standard `:---`/`:---:`/`---:` markers, and the HTML generator emits `style="text-align: …"` on each `<th>`/`<td>` which `HtmlParser` reads back (alongside the existing table-level `<table data-align>`), so alignment survives `md → HTML → md` losslessly. A uniform-alignment table additionally carries `data-align` on the `<table>` for editors that model one alignment per table. Unaligned tables are byte-identical. **Behaviour change** to generated table separators (Markdown) and cell styles (HTML).
20+
- **Inline monospace text was emitted as a styled `<span>` in HTML.** Inline code (a monospace text node) rendered as a `font-family: monospace` `<span>` rather than `<code>`, so it did not round-trip as inline code through HTML. It is now a `<code>` element (with bold/italic wrapping it), which the parser reads back to a monospace run.
21+
- **A single-line code block carrying a language rendered inline in HTML.** `HtmlGenerator` chose `<pre><code>` vs an inline `<span>` purely by whether the code contained a newline, so a one-line code node with a language (`const x = 1;` tagged `js`, or a one-line mermaid diagram) rendered inline and lost its block-ness. A code node carrying a language now always renders as `<pre><code>`.
22+
- **A plain `<blockquote>` was dropped on HTML → Markdown export.** Only the admonition `> [!NOTE]` path emitted a blockquote; a plain `<blockquote>` silently lost its `>` marker. It now round-trips as a `> quoted` blockquote.
23+
- **An HTML `<br>` was read back as a soft wrapping break.** `HtmlParser` mapped `<br>` to a `textWrapping` break, which the Markdown generator emitted as a bare `\n` in a paragraph - reimporting as a space, so `<p>line1<br>line2</p>` collapsed to one line. `<br>` is now a `carriageReturn` hard line break, symmetric with the generator, so it survives the round trip in paragraphs as well as cells.
24+
- **A single-line `$$…$$` imported as inline math with stray `$`.** A `$$\int_a^b$$` on its own line fell through to the inline `$…$` tokenizer, which matched the inner `$\int_a^b$` and leaked the outer pair as two literal `$`. An own-line `$$…$$` is now block math, matching the multi-line `$$` form. (`$$` inside a line of other text is left as-is.)
25+
- **`npm test` failed on a cold run, and a CLI timeout masqueraded as a content mismatch.** The CLI parity test shells out to OCR the sample PDF (~27-30s, more on a cold cache), but the harness capped every CLI call at 30s and coerced `spawnSync`'s SIGTERM kill (`status: null`) to exit `0`. So a cold run clipped the PDF at the limit and then read the killed process as a clean exit with empty output, reporting `0.0% similarity ... Got: 0 words` - a phantom parser regression rather than the timeout it was. The OCR parity call now gets a 120s budget, and a timed-out CLI run is surfaced as a distinct non-zero status with a clear message. Test tooling only; the published package is unchanged. (#111)
26+
727
## [7.6.2] - 2026-08-15
828
### Fixed
929
- **A generated table's header was invalid HTML and did not round-trip.** `generate('html')` emitted the header row's cells directly under `<thead>` (`<thead><th>…`) with no wrapping `<tr>`, which is invalid and which `HtmlParser` could not read back as a table - so a `md -> HTML -> md` round trip through officeParser alone lost the header (its cells came back empty). The header row is now wrapped in `<tr>` (`<thead><tr><th>…`), which is valid and self-idempotent.

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,8 @@ idempotent and `.md → AST → HTML → AST → .md` survives unchanged.
780780
| Attribute lists | `![alt](img.png){width=50% .centered}` | `ImageMetadata.width` / `.align`, `TableMetadata.align` |
781781
| Citations | `[@smith2024]` | `TextMetadata.citationKey` |
782782
| Wikilinks | `[[Page]]` / `[[Page\|Alias]]` | `TextMetadata.wikilink`, `.link`, `.linkType` |
783+
| Highlight | `==text==` | `TextMetadata.backgroundColor` |
784+
| Link/image titles | `[text](url "Title")` / `![alt](img.png "Title")` | `TextMetadata.title` / `ImageMetadata.title` |
783785
| Inline/block math | `$E=mc^2$` / `` $$...$$ `` | `type: 'code'`, `CodeMetadata.math` (`'inline' \| 'block'`) |
784786
| Frontmatter arrays | `tags: [a, b]` or `tags: ["a","b"]` | Real array in `metadata.customProperties`/`nativeProperties` |
785787
| MDX components (import-only) | `<Component prop="x">...</Component>` | Stripped; inner Markdown is kept. Never generated back. |
@@ -795,7 +797,8 @@ save→reload cycle:
795797
| HTML attribute | AST field | Notes |
796798
|---|---|---|
797799
| `data-width` / `data-align` / inline `style="width:…"` on `<img>` | `ImageMetadata.width` / `.align` | |
798-
| `data-align` on `<table>` | `TableMetadata.align` | |
800+
| `data-align` on `<table>` | `TableMetadata.align` | Emitted/parsed as per-column GFM markers (`:---`, `:---:`, `---:`); alignment rides `CellMetadata.align` |
801+
| `title` on `<a>` / `<img>` | `TextMetadata.title` / `ImageMetadata.title` | Survives both directions (`[text](url "Title")` in Markdown) |
799802
| `colspan` / `rowspan` on `<td>`/`<th>` | `CellMetadata.colSpan` / `.rowSpan` | Previously dropped on HTML import — merged cells now survive a save→reload cycle |
800803
| `<div data-youtube-video="ID">` / `<iframe src="...youtube.com...">` | `type: 'embed'` | |
801804
| `<ul data-type="taskList">` / `<li data-checked>` | `ListMetadata.isTask` / `.checked` | |
@@ -1146,7 +1149,8 @@ Pass as `mdConfig` inside `GeneratorConfig`.
11461149
11471150
| Option | Type | Default | Description |
11481151
|--------|------|---------|-------------|
1149-
| `fallbackToHtml` | `boolean \| FallbackToHtmlConfig` | `true` | Use HTML tags for features Markdown cannot represent (underlines, merged table cells, embeds, etc.). Pass an object for per-feature control. `inlineFormatting` (default `false`, opt-in even when the boolean is `true`) additionally round-trips inline color/highlight/font-size as `<span style="...">` runs. |
1152+
| `fallbackToHtml` | `boolean \| FallbackToHtmlConfig` | `true` | Use HTML tags for features Markdown cannot represent (underlines, merged table cells, embeds, etc.). Pass an object for per-feature control. `cellLineBreaks`/`itemLineBreaks` (default on) join multi-line table-cell / multi-paragraph list-item content with `<br>` instead of a space. `inlineFormatting` (default `false`, opt-in even when the boolean is `true`) additionally round-trips inline color/highlight/font-size as `<span style="...">` runs. |
1153+
| `dialect` | `MarkdownDialectPreset \| MarkdownDialectConfig` | `'extended'` | Which native syntax to emit for constructs that differ across targets (GitHub/GitLab/Obsidian/Pandoc/CommonMark). Each capability is typed by the syntax it selects (e.g. `strikethrough: 'tilde'`, `highlight: 'equals'`, `admonitions: 'blockquote'`), with `'none'` to turn it off. See [Markdown Dialect Support](#markdown-dialect-support). The old `boolean` toggles and admonition flavour names (`'github'`/`'gitlab'`/`'pandoc'`) still work but are deprecated. |
11501154
11511155
### PdfGeneratorConfig
11521156

0 commit comments

Comments
 (0)