markdown-codec 1.1.3 → 1.1.5
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.
- package/README.md +12 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ graph TD
|
|
|
14
14
|
pdfcodec("pdf-codec")
|
|
15
15
|
mdcodec("markdown-codec")
|
|
16
16
|
documents("documents.js")
|
|
17
|
+
mcp("document-mcp")
|
|
17
18
|
cli("document-cli")
|
|
18
19
|
|
|
19
20
|
schema --> ooxml
|
|
@@ -25,8 +26,11 @@ graph TD
|
|
|
25
26
|
odf --> documents
|
|
26
27
|
pdfcodec --> documents
|
|
27
28
|
mdcodec --> documents
|
|
29
|
+
documents --> mcp
|
|
30
|
+
pdfcodec --> mcp
|
|
28
31
|
documents --> cli
|
|
29
32
|
odf --> cli
|
|
33
|
+
pdfcodec --> cli
|
|
30
34
|
|
|
31
35
|
click schema "https://github.com/ExaDev/document-schema.js" "document-schema.js"
|
|
32
36
|
click ooxml "https://github.com/ExaDev/ooxml.js" "ooxml.js"
|
|
@@ -34,6 +38,7 @@ graph TD
|
|
|
34
38
|
click pdfcodec "https://github.com/ExaDev/pdf-codec" "pdf-codec"
|
|
35
39
|
click mdcodec "https://github.com/ExaDev/markdown-codec" "markdown-codec"
|
|
36
40
|
click documents "https://github.com/ExaDev/documents.js" "documents.js"
|
|
41
|
+
click mcp "https://github.com/ExaDev/document-mcp" "document-mcp"
|
|
37
42
|
click cli "https://github.com/ExaDev/document-cli" "document-cli"
|
|
38
43
|
|
|
39
44
|
style mdcodec fill:#f9a825,stroke:#333,stroke-width:3px
|
|
@@ -61,7 +66,7 @@ pnpm add markdown-codec
|
|
|
61
66
|
npm install markdown-codec
|
|
62
67
|
```
|
|
63
68
|
|
|
64
|
-
This package is
|
|
69
|
+
This package is published to [npmjs.org](https://www.npmjs.com/package/markdown-codec) via npm's OIDC trusted publishing — see [Release and publishing](#release-and-publishing) below for the full pipeline. [`documents.js`](https://github.com/ExaDev/documents.js) now consumes it via an ordinary semver range rather than the pinned git commit (`markdown-codec@github:ExaDev/markdown-codec#<commit>`) it depended on before this package's own trusted-publisher setup existed. `dist/` remains committed to the repository rather than gitignored — a holdover from that pre-publish period, when a git-tarball install needed a working build with no install-time compile step: pnpm's own git-dependency preparation sandbox proved unreliable at running a `tsdown` build reliably in CI (two independent, environment-specific failures surfaced while chasing this — a Node.js ESM-loader bug in tsdown's default config loader, then dts generation silently producing zero output under the same sandbox even after routing around the first bug), so shipping the build output directly sidestepped the whole class of problem rather than chasing a third variant of it. Now that a real npm release exists and every known consumer installs from the registry, `dist/` tracking no longer serves that original purpose and is a known cleanup rather than a load-bearing requirement.
|
|
65
70
|
|
|
66
71
|
## Usage
|
|
67
72
|
|
|
@@ -82,7 +87,7 @@ const markdown = writeMarkdown(document, {
|
|
|
82
87
|
});
|
|
83
88
|
```
|
|
84
89
|
|
|
85
|
-
Both accept an optional `signal` (`AbortSignal`) and `sink` (a `MarkdownDiagnosticSink`, called once per construct either side cannot represent losslessly — see [Gotchas](#gotchas-and-quirks) for the full list, one entry per
|
|
90
|
+
Both accept an optional `signal` (`AbortSignal`) and `sink` (a `MarkdownDiagnosticSink`, called once per recoverable read-side issue — a spec-legal-but-almost-certainly-a-typo construct such as an unclosed fence, in addition to a construct either side cannot represent losslessly — see [Gotchas](#gotchas-and-quirks) for the full construct-mapping list, one entry per lowering/emission `MarkdownDiagnosticCodes` code). `writeMarkdown` throws `MarkdownUnsupportedDocumentKindError` for a non-`'wordprocessing'` `ContentDocument` — markdown has no presentation/spreadsheet/drawing equivalent to render.
|
|
86
91
|
|
|
87
92
|
The same round trip is also available as a schema-validated [`z.codec()`](https://zod.dev) pair, mirroring `pdf-codec`'s own `pdfCodec` convention:
|
|
88
93
|
|
|
@@ -102,7 +107,7 @@ Every construct-mapping gap either side cannot represent losslessly reports thro
|
|
|
102
107
|
|
|
103
108
|
Modelled on `pdf-codec`'s own layering (generic primitives outward to the two conversion directions), aimed at CommonMark+GFM instead of PDF:
|
|
104
109
|
|
|
105
|
-
- **`src/diagnostics/`** — the read-side diagnostic sink, matching `pdf-codec`'s own three-tier `PdfDiagnosticSink` policy: throw (`MarkdownParseError` and its subclasses — invalid UTF-8, input-too-large, nesting-limit-exceeded) for input this package cannot meaningfully process at all; recover-with-diagnostic for markdown that is spec-legal but almost certainly a typo (an unclosed fence, a table cell-count mismatch, a duplicate link reference, a list marker-type conflict); degrade-with-diagnostic for an individual construct `src/lower`'s or `src/emit`'s own `ContentDocument` mapping cannot represent, while the rest of the document still reads. `MarkdownDiagnosticCodes` names every code either tier can produce; `src/diagnostics/diagnostics.test.ts` asserts the whole table is reachable from real input.
|
|
110
|
+
- **`src/diagnostics/`** — the read-side diagnostic sink, matching `pdf-codec`'s own three-tier `PdfDiagnosticSink` policy: throw (`MarkdownParseError` and its subclasses — invalid UTF-8, input-too-large, nesting-limit-exceeded) for input this package cannot meaningfully process at all; recover-with-diagnostic for markdown that is spec-legal but almost certainly a typo (an unclosed fence, an unterminated HTML block, a table cell-count mismatch, a duplicate link reference, a list marker-type conflict); degrade-with-diagnostic for an individual construct `src/lower`'s or `src/emit`'s own `ContentDocument` mapping cannot represent, while the rest of the document still reads. `MarkdownDiagnosticCodes` names every code either tier can produce; `src/diagnostics/diagnostics.test.ts` asserts the whole table is reachable from real input.
|
|
106
111
|
- **`src/ast/`** — this package's own markdown AST node types (document/block/inline discriminated union), Zod-first like every other model in this family: every node type inferred from its schema, never hand-written.
|
|
107
112
|
- **`src/options/`** / **`src/defaults/`** — `readMarkdown`/`writeMarkdown`'s own options (GFM extension toggles, a diagnostic sink, an `AbortSignal`, `writeMarkdown`'s own style choices — heading/bullet/ordered-delimiter/emphasis/code-fence/thematic-break characters, line ending, front matter emission) and their default values.
|
|
108
113
|
- **`src/scan/`** — the hand-written CommonMark line/character scanner feeding block parsing, plus `entity-table.ts` (auto-generated by `scripts/generate-entity-table.mjs` from `assets/html-entities/entities.json`, committed to the repository so this package never needs a filesystem read of the vendored asset at runtime).
|
|
@@ -110,7 +115,7 @@ Modelled on `pdf-codec`'s own layering (generic primitives outward to the two co
|
|
|
110
115
|
- **`src/inline/`** — inline-level parsing within a block's own content: emphasis, code spans, links, autolinks, raw inline HTML, GFM strikethrough, line breaks.
|
|
111
116
|
- **`src/html/`** — raw block/inline HTML recognition (CommonMark's own bounded seven-condition block-HTML rules and inline tag syntax — not a general HTML parser) plus `render.ts`, the real CommonMark-HTML conformance oracle `src/conformance.test.ts`/`src/gfm-conformance.test.ts` render parsed documents through — internal plumbing, never re-exported from `src/index.ts`.
|
|
112
117
|
- **`src/image/`** — a hand-written PNG/JPEG dimension reader plus an isomorphic base64 codec, shared by `src/lower/image.ts`'s data: URI decoding and `src/emit/image.ts`'s re-encoding.
|
|
113
|
-
- **`src/shared/`** — string-shape conventions `src/lower` (mint/read) and `src/emit` (read/write) must agree on exactly: `style-constants.ts` (heading/quote/code-block/rule/HTML-preformatted styleIds, the monospace font family, the blockquote per-level indent unit, the GFM task-checkbox glyph pair) and `list-id.ts` (the opaque `numId` grammar a list's own type/task/tightness is packed into, since `ContentListMembership` itself carries only `{numId, level}`).
|
|
118
|
+
- **`src/shared/`** — string-shape conventions `src/lower` (mint/read) and `src/emit` (read/write) must agree on exactly: `style-constants.ts` (heading/quote/code-block/rule/HTML-preformatted styleIds, the monospace font family, the blockquote per-level indent unit, the GFM task-checkbox glyph pair) and `list-id.ts` (the opaque `numId` grammar a list's own type/task/tightness is packed into, since `ContentListMembership` itself carries only `{numId, level}`). Most of this module's own surface (`headingStyleId`/`parseHeadingStyleId`/`MAX_HEADING_STYLE_LEVEL`/`QUOTE_STYLE_ID`/`CODE_BLOCK_STYLE_ID`/`HORIZONTAL_RULE_STYLE_ID`/`HTML_PREFORMATTED_STYLE_ID`/`MONOSPACE_FONT_FAMILY`/`QUOTE_INDENT_PT` from `style-constants.ts`, and `createNumIdMintState`/`mintListNumId`/`parseListNumId`/`mintedListType` plus the `ListNumIdInfo`/`ListNumIdMintOptions`/`NumIdMintState` types from `list-id.ts`) is re-exported from `src/index.ts`, not kept internal — so a sibling package building its own editor over a `ContentDocument` (`documents.js`'s `MarkdownEditor`) can mint and parse the identical styleId/numId strings this package's own lower/emit pair uses, rather than duplicating the grammar. `style-constants.ts`'s `TASK_CHECKBOX_UNCHECKED`/`TASK_CHECKBOX_CHECKED` glyphs stay unexported, since a checkbox glyph pair embedded in run text has no identity a caller could round-trip against the way a styleId or numId does.
|
|
114
119
|
- **`src/lower/`** — the AST → `ContentDocument` lowering stage: the markdown-side counterpart to `ooxml.js`'s `readDocx`/`readPptx` and `odf.js`'s `readOdt`/`readOdp` — a thin adapter from a format-specific parse result onto the shared pivot, not a second parser. `lower.ts`'s own top-of-file table maps every construct (headings, emphasis/links/breaks via `inline.ts`, code blocks, blockquotes, lists via `src/shared/list-id.ts`, GFM tables via `table.ts`, images via `image.ts`'s `MarkdownImageResolver` port, raw HTML, front matter via `front-matter.ts`) onto its own `MarkdownDiagnosticCodes` gap.
|
|
115
120
|
- **`src/emit/`** — the `ContentDocument` → markdown text emission stage (`writeMarkdown`'s build-side half), the structural inverse of `src/lower/` construct for construct — `emit.ts`'s own top-of-file table mirrors `lower.ts`'s.
|
|
116
121
|
- **`src/read.ts`** / **`src/write.ts`** / **`src/codec.ts`** — the public `readMarkdown`/`writeMarkdown` entry points and their `z.codec()` pair (`markdownCodec`), matching `pdf-codec`'s own `pdfCodec` convention. `readMarkdown` operates on `document-schema.js`'s full `ContentDocument` envelope directly (`kind`/`formatVersion`/`metadata`/`sections`), not a bare `{metadata, sections}` shape a caller would need to wrap — see `src/read.ts`'s own top-of-file comment for the recorded reconciliation decision, reasoned from `ooxml.js`'s `readXlsxContent`/`buildXlsxPackage` precedent (the more recent design choice in this family, and the structurally closer fit: markdown has no PDF-pivot layout stage of its own, the same position xlsx⇄ods's bridge is in).
|
|
@@ -132,7 +137,7 @@ pnpm lint # eslint . --max-warnings 0
|
|
|
132
137
|
pnpm test # vitest run --project unit (includes the CommonMark/GFM conformance suites)
|
|
133
138
|
pnpm test:watch # vitest --project unit
|
|
134
139
|
pnpm test:coverage # vitest run --project unit --coverage
|
|
135
|
-
pnpm test:smoke # rebuilds dist/, then verifies ESM/CJS parity and a real readMarkdown/writeMarkdown round trip
|
|
140
|
+
pnpm test:smoke # rebuilds dist/, then verifies ESM/CJS export parity and runs a real readMarkdown/writeMarkdown/markdownCodec round trip against each built bundle independently
|
|
136
141
|
pnpm test:corpus # optional, gitignored real-world CommonMark/GFM sanity check -- see Fidelity below
|
|
137
142
|
```
|
|
138
143
|
|
|
@@ -189,7 +194,7 @@ This is also why `pdf-codec`'s own permanent "no round-trip-losslessness claim"
|
|
|
189
194
|
|
|
190
195
|
`.github/workflows/ci.yml` runs commitlint, lint, typecheck, the unit suite (including the conformance suites), and the smoke test on every push and pull request. On a push to `main` where those all pass, `release.config.ts` drives [semantic-release](https://semantic-release.gitbook.io/semantic-release): commit history since the last tag decides the version bump, `CHANGELOG.md` and `package.json` are committed back to `main`, a GitHub Release is cut, and the package publishes to [npmjs.org](https://www.npmjs.com/package/markdown-codec) via npm's OIDC trusted publishing, so no `NPM_TOKEN` exists anywhere in the pipeline.
|
|
191
196
|
|
|
192
|
-
Whether that release actually published a new version is detected by diffing `package.json`'s version before and after the release step, not by trusting a third-party action's own detection.
|
|
197
|
+
Whether that release actually published a new version is detected by diffing `package.json`'s version before and after the release step, not by trusting a third-party action's own detection. Four further jobs gate on that: one dispatches a `sibling-released` `repository_dispatch` event to `documents.js`, so that repo's own dependency-bump PR opens within seconds rather than waiting on Dependabot's next daily scan; one republishes the same build under the scoped `@exadev/markdown-codec` alias to GitHub Packages (which has no OIDC exchange of its own, so it authenticates with `GITHUB_TOKEN` instead); one republishes under the `mrkdwn.js` alias to npmjs.org via the identical OIDC exchange; and one packs the release into its own directory, generates an SPDX SBOM (`pnpm sbom`), and signs both an SBOM and a build-provenance attestation against that exact tarball — verifiable independently of the registry, and still present if the package is later unpublished.
|
|
193
198
|
|
|
194
199
|
## Contributing
|
|
195
200
|
|
|
@@ -199,7 +204,7 @@ Commits follow Conventional Commits (`feat:`, `fix:`, `test:`, `chore:`, …), e
|
|
|
199
204
|
|
|
200
205
|
- [document-schema.js](https://github.com/ExaDev/document-schema.js) — the sibling package that owns the shared `ContentDocument` pivot this package reads and writes.
|
|
201
206
|
- [pdf-codec](https://github.com/ExaDev/pdf-codec) — the sibling package this project's own scaffold, tooling, and "hand-write the format" philosophy are modelled on.
|
|
202
|
-
- [documents.js](https://github.com/ExaDev/documents.js) — the consumer package
|
|
207
|
+
- [documents.js](https://github.com/ExaDev/documents.js) — the consumer package that bridges markdown to docx/odt/PDF via this package's `ContentDocument` output: `markdownToPdf`/`pdfToMarkdown` through the shared wordprocessing layout engine docx/odt already use, and `markdownToDocx`/`docxToMarkdown`, `markdownToOdt`/`odtToMarkdown` as direct `ContentDocument`-to-`ContentDocument` bridges bypassing the PDF pivot entirely, the same way it already bridges odt⇄docx and odp⇄pptx. Markdown has no presentation/spreadsheet/drawing `ContentDocument` variant of its own, so pptx/odp/ods/odg are out of reach structurally, not merely unimplemented.
|
|
203
208
|
- [CommonMark Spec](https://spec.commonmark.org/) — the base specification this package's scanner/block/inline parsers target.
|
|
204
209
|
- [GitHub Flavored Markdown Spec](https://github.github.com/gfm/) — the GFM extensions layered on top of CommonMark.
|
|
205
210
|
- [WHATWG HTML Standard § named character references](https://html.spec.whatwg.org/multipage/named-characters.html) — the entity table `assets/html-entities/` vendors.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markdown-codec",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "Hand-written CommonMark+GFM <-> ContentDocument codec, built on document-schema.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"license": "MIT",
|
|
70
70
|
"packageManager": "pnpm@11.6.0",
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"document-schema.js": "^2.3.
|
|
72
|
+
"document-schema.js": "^2.3.2",
|
|
73
73
|
"zod": "^4.4.3"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|