Nine majors of marked, crossed with one line — plus TypeScript 6 and ESLint 10
plunk-it's markdown-to-email pipeline rode marked from v9 to v18 — a span that rewrote the library's renderer API twice — and our code needed exactly one line changed. Minimal API surface pays off.
Why Care?
plunk-it turns Obsidian notes into emails via the Plunk API, and marked
is the engine that converts your markdown to HTML on the way out. We were
nine major versions behind — a span in which marked rewrote its renderer
API twice (v13/v14 token objects, v17 list-token restructuring) and
dropped its CommonJS build. That's the kind of gap that eventually forces
a rushed migration at the worst moment. We crossed it deliberately, with
the release notes read first.
The punchline: because plunk-it only ever used marked's front door —
setOptions({gfm, breaks}) and one parse call — none of the renderer
carnage applied. The entire migration was one line: marked(text) becomes
marked.parse(text, { async: false }), pinning the synchronous string
return that newer versions no longer promise from the bare call.
What's New?
marked 9.1 → 18.0 — one-line adaptation, no behavior change.
TypeScript 5.8.3 → 6.0.3 (the official stop-over before the native TS 7). The compiler flagged our two deprecated tsconfig options and both are migrated properly:
moduleResolution: "node"→"bundler",baseUrl/pathsremoved. TS 6's stricter module checking also asked for an ambient*.cssdeclaration to bless the esbuild-handled side-effect CSS import — added assrc/types/css.d.ts.ESLint 9.31 → 10.7 +
@eslint/plugin-kit0.7.2, typescript-eslint 8.65, esbuild 0.25.6 → 0.28.1.dotenv 17.4.2, builtin-modules 5.3 — routine currency.
@types/nodepinned down 24 → 22 — Obsidian ships Electron 39 / Node 22; the types now match the runtime that actually executes the plugin.
Verified: tsc -noEmit clean on TS 6, esbuild production bundle at 73 KB.
Part of the family-wide dependency campaign:
content-farm/context-v/plans/Dependency-Upgrades-Across-Plugin-Family.md.