{"id":16828087,"url":"https://github.com/bevacqua/megamark","last_synced_at":"2025-10-04T00:13:05.318Z","repository":{"id":27555031,"uuid":"31036852","full_name":"bevacqua/megamark","owner":"bevacqua","description":":heart_eyes_cat: Markdown with easy tokenization, a fast highlighter, and a lean HTML sanitizer","archived":false,"fork":false,"pushed_at":"2021-02-18T18:44:05.000Z","size":2391,"stargazers_count":106,"open_issues_count":1,"forks_count":7,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-02-26T12:04:38.758Z","etag":null,"topics":["markdown","tokenizer"],"latest_commit_sha":null,"homepage":"https://ponyfoo.com","language":"JavaScript","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/bevacqua.png","metadata":{"files":{"readme":"readme.markdown","changelog":"changelog.markdown","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":"2015-02-19T21:05:10.000Z","updated_at":"2025-01-21T12:12:41.000Z","dependencies_parsed_at":"2022-09-09T13:22:10.821Z","dependency_job_id":null,"html_url":"https://github.com/bevacqua/megamark","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bevacqua%2Fmegamark","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bevacqua%2Fmegamark/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bevacqua%2Fmegamark/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bevacqua%2Fmegamark/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bevacqua","download_url":"https://codeload.github.com/bevacqua/megamark/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243841223,"owners_count":20356446,"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":["markdown","tokenizer"],"created_at":"2024-10-13T11:24:36.866Z","updated_at":"2025-10-04T00:13:00.271Z","avatar_url":"https://github.com/bevacqua.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# megamark\n\n\u003e [markdown-it][1] with easy tokenization, a fast highlighter, and a lean HTML sanitizer\n\nMegamark is [markdown-it][1] plus a few reasonable factory defaults.\n\n- Markdown parsing via [markdown-it][1]\n- HTML is sanitized via [insane][2], and _that's configurable_\n- Code is highlighted with [highlight.js][3] _(on a [diet in the client-side][4]!)_\n- Tokenization made easy: **turn those `@` mentions into links in no-time!**\n- Text gets prettified just like you're used to from [marked's `smartypants`][5]\n- You can highlight interesting content using `\u003cmark\u003e` tags, _even inside code blocks_\n- Headings get unique `id`, helping you implement navigation in your Markdown documents\n- Still manages to produce a small footprint\n\n# Install\n\n```shell\nnpm install megamark --save\n```\n\n```shell\nbower install megamark --save\n```\n\n# `megamark(markdown, options?)`\n\nThe `markdown` input will be parsed via `markdown-it`. Megamark configures `markdown-it` for syntax highlighting, prefixing classes with `md-`. Output is sanitized via [insane][2], and you can configure the whitelisting process too.\n\n### `options.tokenizers`\n\nTokenizers can help you transform bits of text like `@bevacqua` into links. This is often a very useful feature for your users, but hardly ever implemented by developers because how convoluted it is. With `megamark`, it becomes a pretty easy thing to do.\n\n```js\nmegamark('Who is this @bevacqua person?', {\n  tokenizers: [{\n    token: /(^|\\s)@([A-z]+)\\b/g,\n    transform: function (all, separator, username) {\n      return separator + '\u003ca href=\"/' + username + '\"\u003e' + all + '\u003c/a\u003e';\n    }\n  }]\n});\n// \u003c- '\u003cp\u003eWho is this \u003ca href='/bevacqua'\u003e@bevacqua\u003c/a\u003e person?\u003c/p\u003e\\n'\n```\n\nThe `transform` method will get all of the arguments of `text.match(token)`, so the first argument will be `text`, followed by any capturing groups. In our case, the `/(^|\\s)@([A-z]+)\\b/` can be decomposed as follows.\n\n- First off we have `(?:^|\\s)`\n  - The parenthesis delimit a capturing group\n  - It'll be passed to transform as the second argument\n  - `^|\\s` means that we are looking to match either the start of input or a space character\n  - We can't use `\\b` instead of this expression because `@` is not a word character\n- Then there's the `@` literal\n- Another capturing group, `([A-z]+)`\n  - It'll be passed to transform as the third argument\n  - Matches one or more alphabet characters\n- Finally, `\\b` means that we want to match everything up to a word boundary\n\nYou can use any regular expression you want, but make sure to use the `g` modifier if you want to match multiples of any given token.\n\n### `options.linkifiers`\n\nLinkifiers are a simpler kind of tokenizer, but they're also more limited. Instead of asking you for a token expression, linkifiers will run on every single user-provided link _(that's in plain text, such as `ponyfoo.com`, note that actual links such as `[ponyfoo](http://ponyfoo.com)` won't be affected by this)_. If an HTML string is returned from your linkifier, then that'll be used. If none of your linkifiers return an HTML string, then the original functionality of converting the link text into an HTML link will be used.\n\nLinkifiers are run one by one. The first linkifier to return a string will stop the rest of the linkifiers from ever running. Each linkifier receives an `href` argument and a `text` argument, containing the actual link and the text that should go in the link. These are just hints, you can return arbitrary HTML from your linkifier method, even something other than anchor links.\n\n###### Example\n\nReturn `''` when you want to completely ignore a link. Maybe use a condition where you whitelist links from origins you're happy with.\n\n```js\nmegamark('ponyfoo.com', {\n  linkifiers: [function (href, text) {\n    return '';\n  }]\n});\n// \u003c- '\u003cp\u003e\u003c/p\u003e\\n'\n```\n\n###### Example\n\nA real use case for this type of tokenizer is prettifying the text on the link. This is particularly useful for links on your own domain. The example below converts links that would be turned into `\u003ca href='http://localhost:9000/bevacqua/stompflow/issues/28'\u003ehttp://localhost:9000/bevacqua/stompflow/issues/28\u003c/a\u003e` into `\u003ca href='http://localhost:9000/bevacqua/stompflow/issues/28' class='issue-id'\u003e#28\u003c/a\u003e` instead.\n\n```js\nmegamark('http://localhost:9000/bevacqua/stompflow/issues/28', {\n  linkifiers: [function (href, text) {\n    return \"\u003ca href='\" + href + \"' class='issue-id'\u003e#\" + href.split('/').pop() + \"\u003c/a\u003e\";\n  }]\n});\n// \u003c- '\u003cp\u003e\u003ca href='http://localhost:9000/bevacqua/stompflow/issues/28' class='issue-id'\u003e#28\u003c/a\u003e\u003c/p\u003e\\n'\n```\n\n### `options.sanitizer`\n\nThese configuration options will be passed to [insane][2]. The defaults from [insane][2] are used by default.\n\n### `options.markers`\n\n_Advanced option._ Setting markers to an array such as `[[0, 'START'], [10, 'END']]` will place each of those markers in the output, based on the input index you want to track. This feature is necessary because there is no other reliable way of tracking a text cursor position before and after a piece of Markdown is converted to HTML.\n\nThe following example shows how markers could be used to preserve a text selection across Markdown-into-HTML parsing, by providing markers for each cursor. When the output from `megamark` comes back, all you need to do is find your markers, remove them, and place the text selection at their indices. The [`woofmark`][6] Markdown/HTML/WYSIWYG editor module leverages this functionality to do exactly that.\n\n```js\nmegamark('**foo**', {\n  markers: [[1, '[START]'], [4, '[END]']]\n});\n// \u003c- '\u003cstrong\u003e[START]fo[END]o\u003c/strong\u003e'\n```\n\n\u003csub\u003eAlso note that, as shown in the example above, when a marker can't be placed in the output exactly where you asked for, it'll be cleanly placed nearby. In the above example, the `[START]` marker would've been placed _\"somewhere inside\"_ the opening `\u003cstrong\u003e` tag, but right after the opening tag finishes was preferred.\u003c/sub\u003e\n\n# License\n\nMIT\n\n[1]: https://github.com/markdown-it/markdown-it\n[2]: https://github.com/bevacqua/insane\n[3]: https://github.com/isagalaev/highlight.js\n[4]: https://github.com/bevacqua/highlight-redux\n[5]: https://github.com/chjj/marked#smartypants\n[6]: https://github.com/bevacqua/woofmark\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbevacqua%2Fmegamark","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbevacqua%2Fmegamark","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbevacqua%2Fmegamark/lists"}