{"id":18041629,"url":"https://github.com/katyo/marklit","last_synced_at":"2025-08-04T21:33:08.698Z","repository":{"id":57291336,"uuid":"144376724","full_name":"katyo/marklit","owner":"katyo","description":"Modern markdown parser in TypeScript","archived":false,"fork":false,"pushed_at":"2018-12-04T07:21:32.000Z","size":208,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-09T05:03:04.649Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","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/katyo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-08-11T10:36:19.000Z","updated_at":"2019-09-13T22:23:11.000Z","dependencies_parsed_at":"2022-08-27T12:20:14.201Z","dependency_job_id":null,"html_url":"https://github.com/katyo/marklit","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/katyo/marklit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/katyo%2Fmarklit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/katyo%2Fmarklit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/katyo%2Fmarklit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/katyo%2Fmarklit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/katyo","download_url":"https://codeload.github.com/katyo/marklit/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/katyo%2Fmarklit/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268779108,"owners_count":24306039,"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","status":"online","status_checked_at":"2025-08-04T02:00:09.867Z","response_time":79,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-10-30T16:11:07.266Z","updated_at":"2025-08-04T21:33:08.643Z","avatar_url":"https://github.com/katyo.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Marklit modern markdown parser in TypeScript\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)\n[![npm version](https://badge.fury.io/js/marklit.svg)](https://badge.fury.io/js/marklit)\n[![npm downloads](https://img.shields.io/npm/dm/marklit.svg)](https://www.npmjs.com/package/marklit)\n[![Build Status](https://travis-ci.org/katyo/marklit.svg?branch=master)](https://travis-ci.org/katyo/marklit)\n\n**WARNING**: Ready for use with exceptions (missing HTML parsing rules)\n\nOriginally this project is deeply re-engineered fork of __[marked]__ with conceptual differences.\n\n## Design goals\n\n* Deep customizability\n* Compile-time configuration\n* Compact code size\n\n## Key features\n\n* Parsing result is abstract document tree what allows advanced intermediate processing and non-string rendering\n* Extensible architecture which allows adding new parsing rules and document tree element types\n* Strictly typed design which allows to use full power of typescript to avoid runtime errors\n* Progressive parser core implementation what gives maximum possible parsing speed\n\n### HTML support\n\nThe HTML doesn't supported at the moment, but it will be added in future.\n\n## Usage tips\n\n### Basic setup\n\nBasically you need to do several things to get type-safe markdown parser and renderer.\n\n#### Define types\n\nFirst, you need define some types:\n\n* Meta-data type\n* Block token types map\n* Inline token types map\n* Context mapping type\n\nSee example below:\n\n```typescript\nimport {\n  MetaData,\n  InlineTokenMap,\n  BlockTokenMap,\n  ContextMap,\n} from 'marklit';\n\ninterface InlineToken extends InlineTokenMap\u003cInlineToken\u003e { }\n\ninterface BlockToken extends BlockTokenMap\u003cBlockToken, InlineToken\u003e { }\n\ninterface Context extends ContextMap\u003cBlockToken, InlineToken, MetaData\u003e { }\n```\n\n#### Init parser\n\nNext, you can initialize parser:\n\n```typescript\nimport {\n  BlockNormal,\n  InlineNormal,\n  init,\n  parse\n} from 'marklit';\n\n// initialize parser using normal parsing rules\nconst parser = init\u003cContext\u003e(...BlockNormal, ...InlineNormal);\n\n// parse markdown to get abstract document tree\nconst adt = parse(parser, \"markdown source string\");\n```\n\n...and renderer:\n\n```typescript\nimport {\n  BlockHtml,\n  InlineHtml,\n  initRenderHtml,\n  render\n} from 'marklit';\n\n// initialize renderer using basic HTML render rules\nconst renderer = initRenderHtml\u003cContext\u003e(...BlockHtml, ...InlineHtml);\n\n// render abstract document tree to get HTML string\nconst html = render(renderer, adt);\n```\n\n#### All together\n\nThe example below shows complete configuration:\n\n```typescript\nimport {\n  MetaData,\n  InlineTokenMap,\n  BlockTokenMap,\n  ContextMap,\n  \n  BlockNormal,\n  InlineNormal,\n  init,\n  parse,\n  \n  BlockHtml,\n  InlineHtml,\n  initRenderHtml,\n  render\n} from 'marklit';\n\ninterface InlineToken extends InlineTokenMap\u003cInlineToken\u003e { }\n\ninterface BlockToken extends BlockTokenMap\u003cBlockToken, InlineToken\u003e { }\n\ninterface Context extends ContextMap\u003cBlockToken, InlineToken, MetaData\u003e { }\n\n// initialize parser using normal parsing rules\nconst parser = init\u003cContext\u003e(...BlockNormal, ...InlineNormal);\n\n// initialize renderer using basic HTML render rules\nconst renderer = initRenderHtml\u003cContext\u003e(...BlockHtml, ...InlineHtml);\n\n// parse markdown to get abstract document tree\nconst adt = parse(parser, \"markdown source string\");\n\n// render abstract document tree to get HTML string\nconst html = render(renderer, adt);\n```\n\n#### Github-flavored markdown\n\nThe next example shows configuration which uses GFM rules instead of normal:\n\n```typescript\nimport {\n  MetaData,\n  InlineTokenMap,\n  BlockTokenMap,\n  ContextMap,\n  \n  BlockGfm,\n  InlineGfm,\n  init,\n  parse,\n  \n  BlockTablesHtml,\n  InlineGfmHtml,\n  initRenderHtml,\n  render\n} from 'marklit';\n\ninterface InlineToken extends InlineTokenMap\u003cInlineToken\u003e { }\n\ninterface BlockToken extends BlockTokenMap\u003cBlockToken, InlineToken\u003e { }\n\ninterface Context extends ContextMap\u003cBlockToken, InlineToken, MetaData\u003e { }\n\n// initialize parser using normal parsing rules\nconst parser = init\u003cContext\u003e(...BlockGfm, ...InlineGfm);\n\n// initialize renderer using basic HTML render rules\nconst renderer = initRenderHtml\u003cContext\u003e(...BlockTablesHtml, ...InlineGfmHtml);\n\n// parse markdown to get abstract document tree\nconst adt = parse(parser, \"markdown source string\");\n\n// render abstract document tree to get HTML string\nconst html = render(renderer, adt);\n```\n\n### Using extensions\n\nThe programming design of __marklit__ allows to modify the behavior of any rules in order to extend parser and renderer.\n\nAn extensions includes rules and rule modifiers which allows deep customization.\n\n#### Writing rulesets\n\nYou can override existing rules in rulesets like `BlockNormal`, `InlineNormal`, `BlockGfm` by appending modified rules.\nOr you can create your own rulesets using existing or new rules.\n\nThe topics below shows how to customize behavior by using extensions:\n\n#### GFM breaks\n\nYou can extend normal text rule to _GFM_ or _GFM with breaks_:\n\n```typescript\nimport {\n  TextSpan,\n  gfmText,\n  gfmBreaks,\n} from 'marklit';\n\nconst GfmTextSpan = gfmText(TextSpan);\nconst GfmBreaksTextSpan = gfmBreaks(gfmText(TextSpan));\n```\n\nOr simply use existing GFM text rules:\n\n```typescriot\nimport {\n  GfmTextSpan,\n  GfmBreaksTextSpan\n} from 'marklit';\n```\n\n#### SmartyPants\n\nYou can add [smartypants] support to any text rule like this:\n\n```typescript\nimport {\n  BlockNormal,\n  InlineNormal,\n  \n  BlockGfmTables,\n  InlineGfm,\n\n  TextSpan,\n  GfmTextSpan,\n  smartypantsText,\n  \n  init\n} from 'marklit';\n\nconst SmartypantsTextSpan = smartypantsText(TextSpan);\nconst SmartypantsGfmTextSpan = smartypantsText(GfmTextSpan);\n\n// Custom SmartypantsTextSpan rule overrides default TextSpan rule which comes from InlineNormal ruleset\nconst parser = init\u003cContext\u003e(...BlockNormal, ...InlineNormal, ...SmartypantsTextSpan);\n\n// Custom SmartypantsGfmTextSpan rule overrides default GfmTextSpan rule which comes from InlineGfm ruleset\nconst parser = init\u003cContext\u003e(...BlockGfmTables, ...InlineGfm, ...SmartypantsGfmTextSpan);\n```\n\n#### Math extension\n\nThe mathematic extension includes two rules:\n\n1. Inline math enclosed by `$` signs like an inline code (`MathSpan`)\n2. Block math enclosed by series of `$` signs like a fenced code blocks (`MathBlock`)\n\nYou can use one of this rules or both together.\n\n```typescript\nimport {\n  InlineTokenMap,\n  BlockTokenMap,\n  ContextMap,\n  \n  BlockMath,\n  InlineMath,\n  \n  BlockNormal,\n  InlineNormal,\n  \n  MathBlock,\n  MathSpan,\n  \n  init,\n  parse,\n  \n  BlockHtml,\n  InlineHtml,\n  MathBlockHtml,\n  MathSpanHtml,\n  \n  initHtmlRender,\n  render\n} from 'marklit';\n\n// inline token with math\ninterface InlineToken extends InlineTokenMap\u003cInlineToken\u003e, InlineMath { }\n\n// block token with math\ninterface BlockToken extends BlockTokenMap\u003cBlockToken, InlineToken\u003e, BlockMath { }\n\n// inline context with math\ninterface InlineContext extends ContextMap\u003cBlockToken, InlineToken, NoMeta\u003e { }\n\n// append math rules to normal rules\nconst parser = init\u003cContext\u003e(...BlockNormal, MathBlock, ...InlineNormal, MathSpan);\n\n// append math rules to normal rules\nconst renderer = initRenderHtml\u003cContext\u003e(...BlockHtml, MathBlockHtml, InlineHtml, MathSpanHtml);\n\nconst adt = parse(parser, `\nInline formula $E = mc^2$\n\nBlock equation:\n\n$$$.dot\ngraph {\n    a -- b;\n    b -- c;\n    a -- c;\n}\n$$$\n`);\n\nconst html = render(renderer, adt);\n```\n\n#### Abbreviations\n\nThe abbrevs extension consists of three parts:\n\n1. Block rule (`AbbrevBlock`)\n2. Text rule modifier (`abbrevText`)\n3. Inline rule (`Abbrev`)\n\nUsually you need first two rules to get automatic abbreviations.\nThe third rule adds extra forced abbreviations into inline context.\n\n```typescript\nimport {\n  InlineTokenMap,\n  BlockTokenMap,\n  ContextMap,\n  \n  InlineAbbrev,\n  \n  BlockNormal,\n  InlineNormal,\n  AbbrevBlock,\n  Abbrev,\n  TextSpan,\n  abbrevText,\n  \n  init,\n  parse,\n  \n  BlockHtml,\n  InlineHtml,\n  AbbrevHtml,\n  \n  initHtmlRender,\n  render\n} from 'marklit';\n\n// inline token with abbrev\ninterface InlineToken extends InlineTokenMap\u003cInlineToken\u003e, InlineAbbrev { }\n\n// normal block token\ninterface BlockToken extends BlockTokenMap\u003cBlockToken, InlineToken\u003e { }\n\n// inline context with abbrev\ninterface InlineContext extends ContextMap\u003cBlockToken, InlineToken, NoMeta\u003e { }\n\n// append abbrev rules to normal rules\nconst parser = init\u003cContext\u003e(...BlockNormal, AbbrevBlock, ...InlineNormal, Abbrev, abbrevText(TextSpan));\n\n// append abbrev rules to normal rules\nconst renderer = initRenderHtml\u003cContext\u003e(...BlockHtml, InlineHtml, AbbrevHtml);\n\nconst adt = parse(parser, `The HTML specification\nis maintained by the W3C.\n\n*[HTML]: Hyper Text Markup Language\n*[W3C]:  World Wide Web Consortium\n`);\n\nconst html = render(renderer, adt);\n```\n\n#### Footnotes\n\nThe footnotes extension includes two rules:\n\n1. Inline footnote reference rule (`Footnote`)\n2. Block footnotes block rule (`FootnotesBlock`)\n\nYou need use both rules to get working footnotes:\n\n```typescript\nimport {\n  InlineTokenMap,\n  BlockTokenMap,\n  ContextMap,\n  \n  InlineFootnote,\n  BlockFootnotes,\n  \n  BlockNormal,\n  InlineNormal,\n  FootnotesBlock,\n  Footnote,\n  \n  init,\n  parse,\n  \n  BlockHtml,\n  InlineHtml,\n  FootnoteHtml,\n  FootnotesBlockHtml,\n  \n  initHtmlRender,\n  render\n} from 'marklit';\n\n// inline token with footnote refs\ninterface InlineToken extends InlineTokenMap\u003cInlineToken\u003e, InlineFootnote { }\n\n// block token with footnotes list\ninterface BlockToken extends BlockTokenMap\u003cBlockToken, InlineToken\u003e, BlockFootnotes { }\n\n// inline context with footnotes\ninterface InlineContext extends ContextMap\u003cBlockToken, InlineToken, NoMeta\u003e { }\n\n// append footnote rules to normal rules\nconst parser = init\u003cContext\u003e(...BlockNormal, FootnotesBlock, ...InlineNormal, Footnote);\n\n// append footnote rules to normal rules\nconst renderer = initRenderHtml\u003cContext\u003e(...BlockHtml, FootnotesBlockHtml, InlineHtml, FootnoteHtml);\n\nconst adt = parse(parser, `Footnotes[^1] have a label[^@#$%] and the footnote's content.\n\n[^1]: This is a footnote content.\n[^@#$%]: A footnote on the label: \"@#$%\".`);\n\nconst html = render(renderer, adt);\n```\n\n#### Inline footnotes\n\n*TODO*:\n\n#### Table of contents\n\n*TODO*:\n\n## Basic ideas\n\n### Abstract document tree\n\nTraditionally markdown parsers generates HTML as result.\nThis is simple but not so useful in most advanced usecases.\nBy example, when you need intermediate processing or direct rendering to DOM tree, the ADT is much more conveniently.\n\nThe **marklit** ADT is a JSON tree of _block_ and _inline_ elements called **tokens**.\nEach token is a simple object with `$` field as tag, optional `_` field with list of sub-tokens, and optionally several other token type specific fields which called properties.\n\n__TODO__: Document tree examples.\n\n### Extensibility\n\nThe architecture of **marked** does not allows you to add new rules. You may only modify regexps of existing rules and write your own string-based renderer.\n\nThe **[marked-ast]** partially solves the problem of renderer but still doesn't allows add new rules.\n\nThe **[simple-markdown]** from Khan academy have good extensibility but it is not so fast parser as marked.\n\nBecause one of important goal of this project is parsing speed it required solution, which gives extensibility without worsening of speed.\n\n### Type-safety\n\nAs conceived the abstract document tree must be is strictly typed itself.\nBut because __TypeScript__ doesn't yet support circular type referencing, the token type infering cannot be implemented now.\nSo you need a little bit of handwork with types here.\n\n### Speedup parsing\n\nThe __marked__ iterates over matching regexps for each rules until first match occured. It's not so fast as it can be because JS engine does multiple matching for multiple regexps.\n\nThe __marklit__ constructs single regexp using all rules to do matching for all rules at once. This technique moves workload from JS side to embedded RegExp engine.\n\n#### Benchmarking\n\nBecause the operation flow of marklit includes ADT stage it is too differs from other md-to-html parsers so the benchmarking won't give comparable results.\n\n[markdown]: https://www.markdownguide.org/\n[marked]: https://marked.js.org/\n[marked-ast]: https://github.com/pdubroy/marked-ast\n[simple-markdown]: https://github.com/Khan/simple-markdown\n[smartypants]: https://daringfireball.net/projects/smartypants\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkatyo%2Fmarklit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkatyo%2Fmarklit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkatyo%2Fmarklit/lists"}