{"id":14990841,"url":"https://github.com/ije/md4w","last_synced_at":"2025-04-13T09:37:45.462Z","repository":{"id":217463161,"uuid":"743942806","full_name":"ije/md4w","owner":"ije","description":"A Markdown renderer written in Zig \u0026 C, compiled to WebAssymbly.","archived":false,"fork":false,"pushed_at":"2024-08-01T11:04:19.000Z","size":321,"stargazers_count":74,"open_issues_count":3,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-27T01:10:04.545Z","etag":null,"topics":["html","markdown","md4c","parser","renderer","streaming","wasm","webassembly","zig"],"latest_commit_sha":null,"homepage":"","language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ije.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-16T10:11:17.000Z","updated_at":"2025-03-21T04:22:42.000Z","dependencies_parsed_at":"2024-02-21T17:59:28.713Z","dependency_job_id":"bccb13c3-2098-4aeb-a14c-3037e36ee0a8","html_url":"https://github.com/ije/md4w","commit_stats":{"total_commits":105,"total_committers":1,"mean_commits":105.0,"dds":0.0,"last_synced_commit":"483ff363e2e767b440884b750ec973e185ce27f8"},"previous_names":["ije/md4w"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ije%2Fmd4w","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ije%2Fmd4w/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ije%2Fmd4w/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ije%2Fmd4w/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ije","download_url":"https://codeload.github.com/ije/md4w/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248691697,"owners_count":21146420,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["html","markdown","md4c","parser","renderer","streaming","wasm","webassembly","zig"],"created_at":"2024-09-24T14:20:57.007Z","updated_at":"2025-04-13T09:37:45.439Z","avatar_url":"https://github.com/ije.png","language":"Zig","funding_links":[],"categories":["Zig"],"sub_categories":[],"readme":"# md4w\n\nA **Markdown** renderer written in Zig \u0026 C, compiled to **WebAssymbly**.\n\n- **Compliance**: powered by [md4c](https://github.com/mity/md4c) that is fully\n  compliant to CommonMark 0.31, and partially supports GFM like task list,\n  table, etc.\n- **Fast**: written in Zig \u0026 C, compiled to WebAssembly (it's about **2.5x** faster\n  than markdown-it, see [benchmark](#benchmark)).\n- **Small**: `~28KB` gzipped.\n- **Simple**: zero dependencies, easy to use.\n- **Streaming**: supports web streaming API for reducing memory usage.\n- **Universal**: works in any JavaScript runtime (Node.js, Deno, Bun, Browsers,\n  Cloudflare Workers, etc).\n\n## Usage\n\n```js\n// npm i md4w (Node.js, Bun, Cloudflare Workers, etc.)\nimport { init, mdToHtml, mdToJSON, mdToReadableHtml } from \"md4w\";\n// or use the CDN url (Deno, Browsers)\nimport { init, mdToHtml, mdToJSON, mdToReadableHtml } from \"https://esm.sh/md4w\";\n\n// waiting for md4w.wasm...\nawait init();\n\n// markdown -\u003e HTML\nconst html = mdToHtml(\"Stay _foolish_, stay **hungry**!\");\n\n// markdown -\u003e HTML (ReadableStream)\nconst readable = mdToReadableHtml(\"Stay _foolish_, stay **hungry**!\");\nconst response = new Response(readable, {\n  headers: { \"Content-Type\": \"text/html\" },\n});\n\n// markdown -\u003e JSON\nconst tree = mdToJSON(\"Stay _foolish_, stay **hungry**!\");\n```\n\n## Wasm Mode\n\nmd4w provides two webassembly binary files:\n\n- `md4w-fast.wasm`: Faster but larger binary file. (**270KB** gzipped)\n- `md4w-small.wasm`: Tiny but slower binary file. (**28KB** gzipped)\n\nBy default, md4w uses the `md4w-fast.wasm` binary from file system, uses the `md4w-small.wasm` binary from CDN. You can also specify the wasm file by adding the `wasmMode` option.\n\n```js\nimport { init } from \"md4w\";\n\nawait init(\"fast\"); // or \"small\"\n```\n\nIf you are using a **bundler** like vite, you need to configure the `wasm` input manually.\n\n```js\nimport { init } from \"md4w\";\nimport wasmUrl from \"md4w/js/md4w-fast.wasm?url\";\n\nawait init(wasmUrl);\n```\n\n## Parse Flags\n\nBy default, md4w uses the following parse flags:\n\n- `COLLAPSE_WHITESPACE`: Collapse non-trivial whitespace into single space.\n- `PERMISSIVE_ATX_HEADERS`: Do not require space in ATX headers (`###header`).\n- `PERMISSIVE_URL_AUTO_LINKS`: Recognize URLs as links.\n- `STRIKETHROUGH`: Text enclosed in tilde marks, e.g. `~foo bar~`.\n- `TABLES`: Support GitHub-style tables.\n- `TASK_LISTS`: Support GitHub-style task lists.\n\nYou can use the `parseFlags` option to change the renderer behavior:\n\n```ts\nmdToHtml(\"Stay _foolish_, stay **hungry**!\", {\n  parseFlags: [\n    \"DEFAULT\",\n    \"NO_HTML\",\n    \"LATEX_MATH_SPANS\",\n    // ... other parse flags\n  ],\n});\n```\n\nAll available parse flags are:\n\n```ts\nexport enum ParseFlags {\n  /** Collapse non-trivial whitespace into single space. */\n  COLLAPSE_WHITESPACE,\n  /** Do not require space in ATX headers ( ###header ) */\n  PERMISSIVE_ATX_HEADERS,\n  /** Recognize URLs as links. */\n  PERMISSIVE_URL_AUTO_LINKS,\n  /** Recognize e-mails as links.*/\n  PERMISSIVE_EMAIL_AUTO_LINKS,\n  /** Disable indented code blocks. (Only fenced code works.) */\n  NO_INDENTED_CODE_BLOCKS,\n  /** Disable raw HTML blocks. */\n  NO_HTML_BLOCKS,\n  /** Disable raw HTML (inline). */\n  NO_HTML_SPANS,\n  /** Support GitHub-style tables. */\n  TABLES,\n  /** Support strike-through spans (text enclosed in tilde marks, e.g. ~foo bar~). */\n  STRIKETHROUGH,\n  /** Support WWW autolinks (without proto; just 'www.') */\n  PERMISSIVE_WWW_AUTO_LINKS,\n  /** Support GitHub-style task lists. */\n  TASKLISTS,\n  /** Support LaTeX math spans ($...$) and LaTeX display math spans ($$...$$) are supported. (Note though that the HTML renderer outputs them verbatim in a custom tag \u003cx-equation\u003e.) */\n  LATEX_MATH_SPANS,\n  /** Support wiki-style links ([[link label]] and [[target article|link label]]) are supported. (Note that the HTML renderer outputs them in a custom tag \u003cx-wikilink\u003e.) */\n  WIKI_LINKS,\n  /** Denotes an underline instead of an ordinary emphasis or strong emphasis. */\n  UNDERLINE,\n  /** Using hard line breaks. */\n  HARD_SOFT_BREAKS,\n  /** Shorthand for NO_HTML_BLOCKS | NO_HTML_SPANS */\n  NO_HTML,\n  /** Default flags COLLAPSE_WHITESPACE | PERMISSIVE_ATX_HEADERS | PERMISSIVE_URL_AUTO_LINKS | STRIKETHROUGH | TABLES | TASK_LISTS */\n  DEFAULT,\n}\n```\n\n## Code Highlighter\n\nmd4w would not add colors to the code blocks by default, however, we provide a\n`setCodeHighlighter` function to allow you to add any code highlighter you like.\n\n```js\nimport { setCodeHighlighter } from \"md4w\";\n\nsetCodeHighlighter((code, lang) =\u003e {\n  return `\u003cpre\u003e\u003ccode class=\"language-${lang}\"\u003e${hl(code)}\u003c/code\u003e\u003c/pre\u003e`;\n});\n```\n\n### Caveats\n\n- The returned code will be inserted into the html directly, without html\n  escaping. You should take care of the html escaping by yourself.\n- Although we don't send back the highlighted code to the wasm module, the\n  performance is still impacted by the code highlighter.\n\n## Web Streaming API\n\nmd4w provides the web streaming API, that is useful\nfor a http server to stream the outputed html.\n\n```js\nimport { mdToReadableHtml } from \"md4w\";\n\nconst readable = mdToReadableHtml(readFile(\"large.md\"));\n\n// write to file\nconst file = await Deno.open(\"/foo/bar.html\", { write: true, create: true });\nreadable.pipeTo(file.writable);\n\n// or send to browser\nconst response = new Response(readable, {\n  headers: { \"Content-Type\": \"text/html\" },\n});\n```\n\n### Buffer Size\n\nBy default, md4w uses a buffer size of `4KB` for streaming, you can change it by\nadding the `bufferSize` option.\n\n```js\nmdToReadableHtml(largeMarkdown, {\n  bufferSize: 16 * 1024,\n});\n```\n\n### Caveats\n\nThe streaming API currently only uses the buffer for output, you still need\nto load the whole markdown data into memory.\n\n## Rendering to JSON\n\nmd4w also provides a `mdToJSON` function to render the markdown to JSON.\n\n```js\nconst traverse = (node) =\u003e {\n  // text node\n  if (typeof node === \"string\") {\n    console.log(node);\n    return;\n  }\n\n  // element type\n  console.log(node.type);\n\n  // element attributes (may be undefined)\n  console.log(node.props);\n\n  // element children (may be undefined)\n  node.children?.forEach(traverse);\n};\n\nconst tree = mdToJSON(\"Stay _foolish_, stay **hungry**!\");\ntraverse(tree);\n```\n\n### Node Type\n\nThe node type is a number that represents the type of the node. You can import\nthe `NodeType` enum to get the human-readable node type.\n\n```ts\nimport { NodeType } from \"md4w\";\n\nconsole.log(NodeType.P); // 9\nconsole.log(NodeType.IMG); // 33\n\nif (node.type === NodeType.IMG) {\n  console.log(\"This is an image node, `src` is\", node.props.src);\n}\n```\n\n\u003e All available node types are defined in the\n\u003e [`NodeType`](./js/md4w.d.ts#L76) enum.\n\n## Development\n\nThe renderer is written in [Zig](https://ziglang.org/), ensure you have it (0.11.0)\ninstalled.\n\n```bash\nzig build \u0026\u0026 deno test -A\n```\n\n## Benchmark\n\n![screenshot](./test/benchmark-screenshot.png)\n\n```bash\nzig build \u0026\u0026 deno bench -A test/benchmark.js\n```\n\n## Prior Art\n\n- [md4c](https://github.com/mity/md4c) - C Markdown parser. Fast. SAX-like\n  interface. Compliant to CommonMark specification.\n- [markdown-wasm](https://github.com/rsms/markdown-wasm) - Very fast Markdown\n  parser and HTML generator implemented in WebAssembly, based on md4c.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fije%2Fmd4w","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fije%2Fmd4w","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fije%2Fmd4w/lists"}