├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── bb.yml │ └── main.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .remarkignore ├── index.d.ts ├── index.js ├── lib └── index.js ├── license ├── package.json ├── readme.md ├── test ├── fixtures │ ├── blockquote │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── code │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── entities-named │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── entities-numerical │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── escape-commonmark │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── escape │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── html-sanitize │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── html │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── images │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── links │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── list │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── references │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ ├── rule │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md │ └── self-closing │ │ ├── config.json │ │ ├── input.md │ │ ├── output.html │ │ └── output.md ├── index.js └── integrations │ ├── footnotes │ ├── input.md │ └── output.html │ ├── frontmatter │ ├── input.md │ └── output.html │ ├── gfm │ ├── input.md │ └── output.html │ ├── github │ ├── input.md │ └── output.html │ └── toc │ ├── input.md │ └── output.html └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # https://github.com/github/linguist/blob/HEAD/docs/overrides.md 2 | test/**/*.html linguist-vendored 3 | -------------------------------------------------------------------------------- /.github/workflows/bb.yml: -------------------------------------------------------------------------------- 1 | name: bb 2 | on: 3 | issues: 4 | types: [opened, reopened, edited, closed, labeled, unlabeled] 5 | pull_request_target: 6 | types: [opened, reopened, edited, closed, labeled, unlabeled] 7 | jobs: 8 | main: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: unifiedjs/beep-boop-beta@main 12 | with: 13 | repo-token: ${{secrets.GITHUB_TOKEN}} 14 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: main 2 | on: 3 | - pull_request 4 | - push 5 | jobs: 6 | main: 7 | name: ${{matrix.node}} 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - uses: actions/setup-node@v3 12 | with: 13 | node-version: ${{matrix.node}} 14 | - run: npm install 15 | - run: npm test 16 | - uses: codecov/codecov-action@v3 17 | strategy: 18 | matrix: 19 | node: 20 | - lts/gallium 21 | - node 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | node_modules/ 3 | .DS_Store 4 | *.d.ts 5 | *.log 6 | yarn.lock 7 | !/index.d.ts 8 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | ignore-scripts=true 2 | package-lock=false 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | *.html 3 | *.md 4 | -------------------------------------------------------------------------------- /.remarkignore: -------------------------------------------------------------------------------- 1 | /test/ 2 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import type {Root} from 'mdast' 2 | import type {Plugin} from 'unified' 3 | import type {Options} from './lib/index.js' 4 | 5 | export type {Options} from './lib/index.js' 6 | 7 | /** 8 | * Add support for serializing to HTML. 9 | * 10 | * @this 11 | * Unified processor. 12 | * @param 13 | * Configuration (optional). 14 | * @returns 15 | * Nothing. 16 | */ 17 | declare const remarkHtml: Plugin< 18 | [(Readonly | null | undefined)?], 19 | Root, 20 | string 21 | > 22 | export default remarkHtml 23 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Note: types exposed from `index.d.ts`. 2 | export {default} from './lib/index.js' 3 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {import('hast-util-sanitize').Schema} Schema 3 | * @typedef {import('hast-util-to-html').Options} ToHtmlOptions 4 | * @typedef {import('mdast').Root} Root 5 | * @typedef {import('mdast-util-to-hast').Handlers} Handlers 6 | * @typedef {import('unified').Compiler} Compiler 7 | * @typedef {import('unified').Processor} Processor 8 | */ 9 | 10 | /** 11 | * @typedef ExtraOptionsFields 12 | * Extra fields. 13 | * @property {Readonly | null | undefined} [handlers] 14 | * How to turn mdast nodes into hast nodes (optional); 15 | * passed to `mdast-util-to-hast`. 16 | * @property {Readonly | boolean | null | undefined} [sanitize] 17 | * Sanitize the output, and how (default: `true`). 18 | * 19 | * @typedef {ToHtmlOptions & ExtraOptionsFields} Options 20 | * Configuration. 21 | */ 22 | 23 | import {sanitize} from 'hast-util-sanitize' 24 | import {toHast} from 'mdast-util-to-hast' 25 | import {toHtml} from 'hast-util-to-html' 26 | 27 | /** @type {Readonly} */ 28 | const emptyOptions = {} 29 | 30 | /** 31 | * Serialize markdown as HTML. 32 | * 33 | * ###### Notes 34 | * 35 | * Passing `sanitize: false` is dangerous. 36 | * It allows arbitrary HTML and does not sanitize elements. 37 | * 38 | * @param {Readonly | null | undefined} [options] 39 | * Configuration (optional). 40 | * @returns {undefined} 41 | * Nothing. 42 | */ 43 | export default function remarkHtml(options) { 44 | /** @type {Processor} */ 45 | // @ts-expect-error: TS in JSDoc generates wrong types if `this` is typed regularly. 46 | // eslint-disable-next-line unicorn/no-this-assignment 47 | const self = this 48 | const {handlers, sanitize: clean, ...toHtmlOptions} = options || emptyOptions 49 | let allowDangerousHtml = false 50 | /** @type {Readonly | undefined} */ 51 | let schema 52 | 53 | if (typeof clean === 'boolean') { 54 | allowDangerousHtml = !clean 55 | } else if (clean) { 56 | schema = clean 57 | } 58 | 59 | self.compiler = compiler 60 | 61 | /** 62 | * @type {Compiler} 63 | */ 64 | function compiler(tree, file) { 65 | const hast = toHast(tree, {handlers, allowDangerousHtml}) 66 | const safeHast = allowDangerousHtml ? hast : sanitize(hast, schema) 67 | const result = toHtml(safeHast, {...toHtmlOptions, allowDangerousHtml}) 68 | 69 | if (file.extname) { 70 | file.extname = '.html' 71 | } 72 | 73 | // Add an eof eol. 74 | return tree && 75 | tree.type === 'root' && 76 | result && 77 | /[^\r\n]/.test(result.charAt(result.length - 1)) 78 | ? result + '\n' 79 | : result 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2015 Titus Wormer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remark-html", 3 | "version": "16.0.1", 4 | "description": "remark plugin to compile Markdown to HTML", 5 | "license": "MIT", 6 | "keywords": [ 7 | "compile", 8 | "html", 9 | "markdown", 10 | "mdast", 11 | "plugin", 12 | "remark", 13 | "remark-plugin", 14 | "stringify", 15 | "unified" 16 | ], 17 | "repository": "remarkjs/remark-html", 18 | "bugs": "https://github.com/remarkjs/remark-html/issues", 19 | "funding": { 20 | "type": "opencollective", 21 | "url": "https://opencollective.com/unified" 22 | }, 23 | "author": "Titus Wormer (https://wooorm.com)", 24 | "contributors": [ 25 | "Titus Wormer (https://wooorm.com)", 26 | "Ben Briggs ", 27 | "Seth Vincent ", 28 | "Junyoung Choi ", 29 | "Jonathan Soeder " 30 | ], 31 | "sideEffects": false, 32 | "type": "module", 33 | "exports": "./index.js", 34 | "files": [ 35 | "lib/", 36 | "index.d.ts", 37 | "index.js" 38 | ], 39 | "dependencies": { 40 | "@types/mdast": "^4.0.0", 41 | "hast-util-sanitize": "^5.0.0", 42 | "mdast-util-to-hast": "^13.0.0", 43 | "hast-util-to-html": "^9.0.0", 44 | "unified": "^11.0.0" 45 | }, 46 | "devDependencies": { 47 | "@types/hast": "^3.0.0", 48 | "@types/node": "^20.0.0", 49 | "c8": "^8.0.0", 50 | "commonmark.json": "^0.30.0", 51 | "hast-util-from-html": "^2.0.0", 52 | "prettier": "^3.0.0", 53 | "remark-cli": "^11.0.0", 54 | "remark-frontmatter": "^5.0.0", 55 | "remark-gfm": "^4.0.0", 56 | "remark-github": "^12.0.0", 57 | "remark-parse": "^11.0.0", 58 | "remark-preset-wooorm": "^9.0.0", 59 | "remark-slug": "^7.0.0", 60 | "remark-toc": "^9.0.0", 61 | "type-coverage": "^2.0.0", 62 | "typescript": "^5.0.0", 63 | "vfile": "^6.0.0", 64 | "xo": "^0.56.0" 65 | }, 66 | "scripts": { 67 | "build": "tsc --build --clean && tsc --build && type-coverage", 68 | "format": "remark . --frail --output --quiet && prettier . --log-level warn --write && xo --fix", 69 | "prepack": "npm run build && npm run format", 70 | "test": "npm run build && npm run format && npm run test-coverage", 71 | "test-api": "node --conditions development test/index.js", 72 | "test-coverage": "c8 --100 --reporter lcov npm run test-api" 73 | }, 74 | "prettier": { 75 | "bracketSpacing": false, 76 | "singleQuote": true, 77 | "semi": false, 78 | "tabWidth": 2, 79 | "trailingComma": "none", 80 | "useTabs": false 81 | }, 82 | "remarkConfig": { 83 | "plugins": [ 84 | "remark-preset-wooorm" 85 | ] 86 | }, 87 | "typeCoverage": { 88 | "atLeast": 100, 89 | "detail": true, 90 | "ignoreCatch": true, 91 | "strict": true 92 | }, 93 | "xo": { 94 | "overrides": [ 95 | { 96 | "files": [ 97 | "**/*.ts" 98 | ], 99 | "rules": { 100 | "@typescript-eslint/ban-types": "off" 101 | } 102 | }, 103 | { 104 | "files": [ 105 | "test/**/*.js" 106 | ], 107 | "rules": { 108 | "no-await-in-loop": "off" 109 | } 110 | } 111 | ], 112 | "prettier": true, 113 | "rules": { 114 | "unicorn/prefer-at": "off" 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # remark-html 2 | 3 | [![Build][build-badge]][build] 4 | [![Coverage][coverage-badge]][coverage] 5 | [![Downloads][downloads-badge]][downloads] 6 | [![Size][size-badge]][size] 7 | [![Sponsors][sponsors-badge]][collective] 8 | [![Backers][backers-badge]][collective] 9 | [![Chat][chat-badge]][chat] 10 | 11 | **[remark][]** plugin to add support for serializing HTML. 12 | 13 | ## Contents 14 | 15 | * [What is this?](#what-is-this) 16 | * [When should I use this?](#when-should-i-use-this) 17 | * [Install](#install) 18 | * [Use](#use) 19 | * [API](#api) 20 | * [`unified().use(remarkHtml[, options])`](#unifieduseremarkhtml-options) 21 | * [`Options`](#options) 22 | * [Types](#types) 23 | * [Compatibility](#compatibility) 24 | * [Security](#security) 25 | * [Related](#related) 26 | * [Contribute](#contribute) 27 | * [License](#license) 28 | 29 | ## What is this? 30 | 31 | This package is a [unified][] ([remark][]) plugin that compiles markdown to 32 | HTML. 33 | 34 | ## When should I use this? 35 | 36 | This plugin is useful when you want to turn markdown into HTML. 37 | It’s a shortcut for 38 | `.use(remarkRehype).use(rehypeSanitize).use(rehypeStringify)`. 39 | 40 | The reason that there are different ecosystems for markdown and HTML is that 41 | turning markdown into HTML is, while frequently needed, not the only purpose of 42 | markdown. 43 | Checking (linting) and formatting markdown are also common use cases for 44 | remark and markdown. 45 | There are several aspects of markdown that do not translate 1-to-1 to HTML. 46 | In some cases markdown contains more information than HTML: for example, there 47 | are several ways to add a link in markdown (as in, autolinks: ``, 48 | resource links: `[label](url)`, and reference links with definitions: 49 | `[label][id]` and `[id]: url`). 50 | In other cases HTML contains more information than markdown: there are many 51 | tags, which add new meaning (semantics), available in HTML that aren’t available 52 | in markdown. 53 | If there was just one AST, it would be quite hard to perform the tasks that 54 | several remark and rehype plugins currently do. 55 | 56 | This plugin is useful when you want to quickly turn markdown into HTML. 57 | In most cases though, it’s recommended to use [`remark-rehype`][remark-rehype] 58 | instead and finally use [`rehype-stringify`][rehype-stringify] to serialize 59 | HTML. 60 | The reason using both ecosystems instead of this plugin is recommended, is that 61 | there are many useful rehype plugins that you can then use. 62 | For example, you can [minify HTML][rehype-minify], [format HTML][rehype-format], 63 | [highlight code][rehype-highlight], [add metadata][rehype-meta], and a lot more. 64 | 65 | ## Install 66 | 67 | This package is [ESM only][esm]. 68 | In Node.js (version 16+), install with [npm][]: 69 | 70 | ```sh 71 | npm install remark-html 72 | ``` 73 | 74 | In Deno with [`esm.sh`][esmsh]: 75 | 76 | ```js 77 | import remarkHtml from 'https://esm.sh/remark-html@16' 78 | ``` 79 | 80 | In browsers with [`esm.sh`][esmsh]: 81 | 82 | ```html 83 | 86 | ``` 87 | 88 | ## Use 89 | 90 | Say we have the following file `example.md`: 91 | 92 | ```markdown 93 | # Pluto 94 | 95 | **Pluto** (minor-planet designation: **134340 Pluto**) is a 96 | [dwarf planet](https://en.wikipedia.org/wiki/Dwarf_planet) in the 97 | [Kuiper belt](https://en.wikipedia.org/wiki/Kuiper_belt). 98 | ``` 99 | 100 | …and a module `example.js`: 101 | 102 | ```js 103 | import remarkHtml from 'remark-html' 104 | import remarkParse from 'remark-parse' 105 | import {read} from 'to-vfile' 106 | import {unified} from 'unified' 107 | 108 | const file = await unified() 109 | .use(remarkParse) 110 | .use(remarkHtml) 111 | .process(await read('example.md')) 112 | 113 | console.log(String(file)) 114 | ``` 115 | 116 | …then running `node example.js` yields: 117 | 118 | ```html 119 |

Pluto

120 |

Pluto (minor-planet designation: 134340 Pluto) is a 121 | dwarf planet in the 122 | Kuiper belt.

123 | ``` 124 | 125 | ## API 126 | 127 | This package exports no identifiers. 128 | The default export is [`remarkHtml`][api-remark-html]. 129 | 130 | ### `unified().use(remarkHtml[, options])` 131 | 132 | Serialize markdown as HTML. 133 | 134 | ###### Parameters 135 | 136 | * `options` ([`Options`][api-options], optional) 137 | — configuration 138 | 139 | ###### Returns 140 | 141 | Transform ([`Transformer`][unified-transformer]). 142 | 143 | ###### Notes 144 | 145 | Passing `sanitize: false` is dangerous. 146 | It allows arbitrary HTML and does not sanitize elements. 147 | 148 | ### `Options` 149 | 150 | Configuration (TypeScript type). 151 | 152 | ###### Fields 153 | 154 | * `handlers` ([`Handlers` from 155 | `mdast-util-to-hast`][mdast-util-to-hast-handlers], optional) 156 | — how to turn mdast nodes into hast nodes 157 | * `sanitize` ([`Schema` from 158 | `hast-util-sanitize`][hast-util-sanitize-schema] or `boolean`, default: 159 | `true`) 160 | — sanitize the output, and how 161 | * `...toHtmlOptions` ([`Options` from 162 | `hast-util-to-html`][hast-util-to-html-options], optional) 163 | — other options are passed to `hast-util-to-html` 164 | 165 | ## Types 166 | 167 | This package is fully typed with [TypeScript][]. 168 | It exports the additional type [`Options`][api-options]. 169 | 170 | ## Compatibility 171 | 172 | Projects maintained by the unified collective are compatible with maintained 173 | versions of Node.js. 174 | 175 | When we cut a new major release, we drop support for unmaintained versions of 176 | Node. 177 | This means we try to keep the current release line, `remark-html@^16`, 178 | compatible with Node.js 16. 179 | 180 | This plugin works with `unified` version 6+ and `remark` version 15+. 181 | 182 | ## Security 183 | 184 | Use of `remark-html` is safe by default. 185 | Passing `sanitize: false` is unsafe and opens you up to 186 | [cross-site scripting (XSS)][wiki-xss] attacks. 187 | A safe schema is used by default, but passing an unsafe schema is unsafe. 188 | 189 | ## Related 190 | 191 | * [`remark-rehype`](https://github.com/remarkjs/remark-rehype) 192 | — turn markdown into HTML to support rehype 193 | * [`rehype-sanitize`](https://github.com/rehypejs/rehype-sanitize) 194 | — sanitize HTML 195 | 196 | ## Contribute 197 | 198 | See [`contributing.md`][contributing] in [`remarkjs/.github`][health] for ways 199 | to get started. 200 | See [`support.md`][support] for ways to get help. 201 | 202 | This project has a [code of conduct][coc]. 203 | By interacting with this repository, organization, or community you agree to 204 | abide by its terms. 205 | 206 | ## License 207 | 208 | [MIT][license] © [Titus Wormer][author] 209 | 210 | 211 | 212 | [build-badge]: https://github.com/remarkjs/remark-html/workflows/main/badge.svg 213 | 214 | [build]: https://github.com/remarkjs/remark-html/actions 215 | 216 | [coverage-badge]: https://img.shields.io/codecov/c/github/remarkjs/remark-html.svg 217 | 218 | [coverage]: https://codecov.io/github/remarkjs/remark-html 219 | 220 | [downloads-badge]: https://img.shields.io/npm/dm/remark-html.svg 221 | 222 | [downloads]: https://www.npmjs.com/package/remark-html 223 | 224 | [size-badge]: https://img.shields.io/bundlejs/size/remark-html 225 | 226 | [size]: https://bundlejs.com/?q=remark-html 227 | 228 | [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg 229 | 230 | [backers-badge]: https://opencollective.com/unified/backers/badge.svg 231 | 232 | [collective]: https://opencollective.com/unified 233 | 234 | [chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg 235 | 236 | [chat]: https://github.com/remarkjs/remark/discussions 237 | 238 | [npm]: https://docs.npmjs.com/cli/install 239 | 240 | [esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c 241 | 242 | [esmsh]: https://esm.sh 243 | 244 | [health]: https://github.com/remarkjs/.github 245 | 246 | [contributing]: https://github.com/remarkjs/.github/blob/main/contributing.md 247 | 248 | [support]: https://github.com/remarkjs/.github/blob/main/support.md 249 | 250 | [coc]: https://github.com/remarkjs/.github/blob/main/code-of-conduct.md 251 | 252 | [license]: license 253 | 254 | [author]: https://wooorm.com 255 | 256 | [hast-util-sanitize-schema]: https://github.com/syntax-tree/hast-util-sanitize#schema 257 | 258 | [hast-util-to-html-options]: https://github.com/syntax-tree/hast-util-to-html#options 259 | 260 | [mdast-util-to-hast-handlers]: https://github.com/syntax-tree/mdast-util-to-hast#handlers 261 | 262 | [rehype-format]: https://github.com/rehypejs/rehype-format 263 | 264 | [rehype-highlight]: https://github.com/rehypejs/rehype-highlight 265 | 266 | [rehype-meta]: https://github.com/rehypejs/rehype-meta 267 | 268 | [rehype-minify]: https://github.com/rehypejs/rehype-minify 269 | 270 | [rehype-stringify]: https://github.com/rehypejs/rehype/tree/main/packages/rehype-stringify 271 | 272 | [remark]: https://github.com/remarkjs/remark 273 | 274 | [remark-rehype]: https://github.com/remarkjs/remark-rehype 275 | 276 | [typescript]: https://www.typescriptlang.org 277 | 278 | [unified]: https://github.com/unifiedjs/unified 279 | 280 | [unified-transformer]: https://github.com/unifiedjs/unified#transformer 281 | 282 | [wiki-xss]: https://en.wikipedia.org/wiki/Cross-site_scripting 283 | 284 | [api-options]: #options 285 | 286 | [api-remark-html]: #unifieduseremarkhtml-options 287 | -------------------------------------------------------------------------------- /test/fixtures/blockquote/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/blockquote/input.md: -------------------------------------------------------------------------------- 1 | # Block Quote 2 | 3 | > * code.in.a.list(); 4 | > 5 | > * Paragraph. 6 | > 7 | > * Normal list 8 | > 9 | > Paragraph. 10 | -------------------------------------------------------------------------------- /test/fixtures/blockquote/output.html: -------------------------------------------------------------------------------- 1 |

Block Quote

2 |
3 |
    4 |
  • 5 |
    code.in.a.list();
     6 | 
    7 |
  • 8 |
  • 9 |

    Paragraph.

    10 |
  • 11 |
  • 12 |

    Normal list

    13 |
  • 14 |
15 |

Paragraph.

16 |
17 | -------------------------------------------------------------------------------- /test/fixtures/blockquote/output.md: -------------------------------------------------------------------------------- 1 |

Block Quote

2 |
3 |
    4 |
  • 5 |
    code.in.a.list();
     6 | 
    7 |
  • 8 |
  • 9 |

    Paragraph.

    10 |
  • 11 |
  • 12 |

    Normal list

    13 |
  • 14 |
15 |

Paragraph.

16 |
17 | -------------------------------------------------------------------------------- /test/fixtures/code/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/code/input.md: -------------------------------------------------------------------------------- 1 | # Code 2 | 3 | ```js 4 | alert('some JavaScript code.'); 5 | ``` 6 | 7 | ``` 8 | foo bar baz 9 | ``` 10 | 11 | alpha bravo charlie 12 | 13 | ```empty 14 | ``` 15 | 16 | ```tabs 17 | two spaces 18 | one 19 | two 20 | one 21 | mixed. 22 | ``` 23 | -------------------------------------------------------------------------------- /test/fixtures/code/output.html: -------------------------------------------------------------------------------- 1 |

Code

2 |
alert('some JavaScript code.');
 3 | 
4 |
foo bar baz
 5 | 
6 |
alpha bravo charlie
 7 | 
8 |
9 |
  two spaces
10 | 	one
11 | 		two
12 | 	one
13 | 	  mixed.
14 | 
15 | -------------------------------------------------------------------------------- /test/fixtures/code/output.md: -------------------------------------------------------------------------------- 1 |

Code

2 |
alert('some JavaScript code.');
 3 | 
4 |
foo bar baz
 5 | 
6 |
alpha bravo charlie
 7 | 
8 |
9 |
  two spaces
10 | 	one
11 | 		two
12 | 	one
13 | 	  mixed.
14 | 
15 | -------------------------------------------------------------------------------- /test/fixtures/entities-named/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false, 3 | "characterReferences": { 4 | "useNamedReferences": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/entities-named/input.md: -------------------------------------------------------------------------------- 1 | # Entities 2 | 3 | Plain text: 4 | 5 | AT&T with entity, AT&T with numeric entity, AT&T without entity. 6 | 7 | Fenced code language flags: 8 | 9 | ```AT&T 10 | Something in the AT&T language 11 | ``` 12 | 13 | ```AT&T 14 | Something in the AT&T language 15 | ``` 16 | 17 | ```AT&T 18 | Something in the AT&T language 19 | ``` 20 | 21 | Automatic links: 22 | 23 | , , and . 24 | 25 | Link `href`: 26 | 27 | [With entity](http://at&t.com), [numeric entity](http://at&t.com), [without entity](http://at&t.com). 28 | 29 | Link `title`: 30 | 31 | [With entity](http://att.com "AT&T"), [numeric entity](http://att.com "AT&T"), [without entity](http://example.com "AT&T"). 32 | 33 | Image `src`: 34 | 35 | ![With entity](http://at&t.com/fav.ico), ![numeric entity](http://at&t.com/fav.ico), ![without entity](http://at&t.com/fav.ico). 36 | 37 | Image `alt`: 38 | 39 | ![AT&T with entity](http://att.com/fav.ico), ![AT&T with numeric entity](http://att.com/fav.ico), ![AT&T without entity](http://att.com/fav.ico). 40 | 41 | Image `title`: 42 | 43 | ![With entity](http://att.com/fav.ico "AT&T"), ![numeric entity](http://att.com/fav.ico "AT&T"), ![without entity](http://att.com/fav.ico "AT&T"). 44 | 45 | Reference `link`: 46 | 47 | [Entity][entity], [Numeric entity][numeric-entity], [Literal][literal]. 48 | 49 | ![Entity][entity], ![Numeric entity][numeric-entity], ![Literal][literal]. 50 | 51 | Reference `title`: 52 | 53 | [Entity][title-entity], [Numeric entity][title-numeric-entity], [Literal][title-literal]. 54 | 55 | ![Entity][title-entity], ![Numeric entity][title-numeric-entity], ![Literal][title-literal]. 56 | 57 | Image Reference `alt`: 58 | 59 | ![AT&T with entity][reference], ![AT&T with numeric entity][reference], ![AT&T without entity][reference]. 60 | 61 | Definitions: 62 | 63 | [reference]: http://at&t.com/fav.ico "AT&T favicon" 64 | 65 | [entity]: http://at&t.com/fav.ico "ATT favicon" 66 | [numeric-entity]: http://at&t.com/fav.ico "ATT favicon" 67 | [literal]: http://at&t.com/fav.ico "ATT favicon" 68 | 69 | [title-entity]: http://at&t.com/fav.ico "AT&T favicon" 70 | [title-numeric-entity]: http://at&t.com/fav.ico "AT&T favicon" 71 | [title-literal]: http://at&t.com/fav.ico "AT&T favicon" 72 | -------------------------------------------------------------------------------- /test/fixtures/entities-named/output.html: -------------------------------------------------------------------------------- 1 |

Entities

2 |

Plain text:

3 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

4 |

Fenced code language flags:

5 |
Something in the AT&amp;T language
 6 | 
7 |
Something in the AT&#x26;T language
 8 | 
9 |
Something in the AT&T language
10 | 
11 |

Automatic links:

12 |

http://at&amp;t.com, http://at&#x26;t.com, and http://at&t.com.

13 |

Link href:

14 |

With entity, numeric entity, without entity.

15 |

Link title:

16 |

With entity, numeric entity, without entity.

17 |

Image src:

18 |

With entity, numeric entity, without entity.

19 |

Image alt:

20 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

21 |

Image title:

22 |

With entity, numeric entity, without entity.

23 |

Reference link:

24 |

Entity, Numeric entity, Literal.

25 |

Entity, Numeric entity, Literal.

26 |

Reference title:

27 |

Entity, Numeric entity, Literal.

28 |

Entity, Numeric entity, Literal.

29 |

Image Reference alt:

30 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

31 |

Definitions:

32 | -------------------------------------------------------------------------------- /test/fixtures/entities-named/output.md: -------------------------------------------------------------------------------- 1 |

Entities

2 |

Plain text:

3 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

4 |

Fenced code language flags:

5 |
Something in the AT&amp;T language
 6 | 
7 |
Something in the AT&#x26;T language
 8 | 
9 |
Something in the AT&T language
10 | 
11 |

Automatic links:

12 |

http://at&amp;t.com, http://at&#x26;t.com, and http://at&t.com.

13 |

Link href:

14 |

With entity, numeric entity, without entity.

15 |

Link title:

16 |

With entity, numeric entity, without entity.

17 |

Image src:

18 |

With entity, numeric entity, without entity.

19 |

Image alt:

20 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

21 |

Image title:

22 |

With entity, numeric entity, without entity.

23 |

Reference link:

24 |

Entity, Numeric entity, Literal.

25 |

Entity, Numeric entity, Literal.

26 |

Reference title:

27 |

Entity, Numeric entity, Literal.

28 |

Entity, Numeric entity, Literal.

29 |

Image Reference alt:

30 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

31 |

Definitions:

32 | -------------------------------------------------------------------------------- /test/fixtures/entities-numerical/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/entities-numerical/input.md: -------------------------------------------------------------------------------- 1 | # Entities 2 | 3 | Plain text: 4 | 5 | AT&T with entity, AT&T with numeric entity, AT&T without entity. 6 | 7 | Fenced code language flags: 8 | 9 | ```AT&T 10 | Something in the AT&T language 11 | ``` 12 | 13 | ```AT&T 14 | Something in the AT&T language 15 | ``` 16 | 17 | ```AT&T 18 | Something in the AT&T language 19 | ``` 20 | 21 | Automatic links: 22 | 23 | , , and . 24 | 25 | Link `href`: 26 | 27 | [With entity](http://at&t.com), [numeric entity](http://at&t.com), [without entity](http://at&t.com). 28 | 29 | Link `title`: 30 | 31 | [With entity](http://att.com "AT&T"), [numeric entity](http://att.com "AT&T"), [without entity](http://example.com "AT&T"). 32 | 33 | Image `src`: 34 | 35 | ![With entity](http://at&t.com/fav.ico), ![numeric entity](http://at&t.com/fav.ico), ![without entity](http://at&t.com/fav.ico). 36 | 37 | Image `alt`: 38 | 39 | ![AT&T with entity](http://att.com/fav.ico), ![AT&T with numeric entity](http://att.com/fav.ico), ![AT&T without entity](http://att.com/fav.ico). 40 | 41 | Image `title`: 42 | 43 | ![With entity](http://att.com/fav.ico "AT&T"), ![numeric entity](http://att.com/fav.ico "AT&T"), ![without entity](http://att.com/fav.ico "AT&T"). 44 | 45 | Reference `link`: 46 | 47 | [Entity][entity], [Numeric entity][numeric-entity], [Literal][literal]. 48 | 49 | ![Entity][entity], ![Numeric entity][numeric-entity], ![Literal][literal]. 50 | 51 | Reference `title`: 52 | 53 | [Entity][title-entity], [Numeric entity][title-numeric-entity], [Literal][title-literal]. 54 | 55 | ![Entity][title-entity], ![Numeric entity][title-numeric-entity], ![Literal][title-literal]. 56 | 57 | Image Reference `alt`: 58 | 59 | ![AT&T with entity][reference], ![AT&T with numeric entity][reference], ![AT&T without entity][reference]. 60 | 61 | Definitions: 62 | 63 | [reference]: http://at&t.com/fav.ico "AT&T favicon" 64 | 65 | [entity]: http://at&t.com/fav.ico "ATT favicon" 66 | [numeric-entity]: http://at&t.com/fav.ico "ATT favicon" 67 | [literal]: http://at&t.com/fav.ico "ATT favicon" 68 | 69 | [title-entity]: http://at&t.com/fav.ico "AT&T favicon" 70 | [title-numeric-entity]: http://at&t.com/fav.ico "AT&T favicon" 71 | [title-literal]: http://at&t.com/fav.ico "AT&T favicon" 72 | -------------------------------------------------------------------------------- /test/fixtures/entities-numerical/output.html: -------------------------------------------------------------------------------- 1 |

Entities

2 |

Plain text:

3 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

4 |

Fenced code language flags:

5 |
Something in the AT&amp;T language
 6 | 
7 |
Something in the AT&#x26;T language
 8 | 
9 |
Something in the AT&T language
10 | 
11 |

Automatic links:

12 |

http://at&amp;t.com, http://at&#x26;t.com, and http://at&t.com.

13 |

Link href:

14 |

With entity, numeric entity, without entity.

15 |

Link title:

16 |

With entity, numeric entity, without entity.

17 |

Image src:

18 |

With entity, numeric entity, without entity.

19 |

Image alt:

20 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

21 |

Image title:

22 |

With entity, numeric entity, without entity.

23 |

Reference link:

24 |

Entity, Numeric entity, Literal.

25 |

Entity, Numeric entity, Literal.

26 |

Reference title:

27 |

Entity, Numeric entity, Literal.

28 |

Entity, Numeric entity, Literal.

29 |

Image Reference alt:

30 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

31 |

Definitions:

32 | -------------------------------------------------------------------------------- /test/fixtures/entities-numerical/output.md: -------------------------------------------------------------------------------- 1 |

Entities

2 |

Plain text:

3 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

4 |

Fenced code language flags:

5 |
Something in the AT&amp;T language
 6 | 
7 |
Something in the AT&#x26;T language
 8 | 
9 |
Something in the AT&T language
10 | 
11 |

Automatic links:

12 |

http://at&amp;t.com, http://at&#x26;t.com, and http://at&t.com.

13 |

Link href:

14 |

With entity, numeric entity, without entity.

15 |

Link title:

16 |

With entity, numeric entity, without entity.

17 |

Image src:

18 |

With entity, numeric entity, without entity.

19 |

Image alt:

20 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

21 |

Image title:

22 |

With entity, numeric entity, without entity.

23 |

Reference link:

24 |

Entity, Numeric entity, Literal.

25 |

Entity, Numeric entity, Literal.

26 |

Reference title:

27 |

Entity, Numeric entity, Literal.

28 |

Entity, Numeric entity, Literal.

29 |

Image Reference alt:

30 |

AT&T with entity, AT&T with numeric entity, AT&T without entity.

31 |

Definitions:

32 | -------------------------------------------------------------------------------- /test/fixtures/escape-commonmark/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false, 3 | "commonmark": true 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/escape-commonmark/input.md: -------------------------------------------------------------------------------- 1 | These should all get escaped: 2 | 3 | Backslash: \\ 4 | 5 | Backtick: \` 6 | 7 | Asterisk: \* 8 | 9 | Underscore: \_ 10 | 11 | Left brace: \{ 12 | 13 | Right brace: \} 14 | 15 | Left bracket: \[ 16 | 17 | Right bracket: \] 18 | 19 | Left paren: \( 20 | 21 | Right paren: \) 22 | 23 | Greater-than: \> 24 | 25 | Hash: \# 26 | 27 | Period: \. 28 | 29 | Bang: \! 30 | 31 | Plus: \+ 32 | 33 | Minus: \- 34 | 35 | **GFM:** 36 | 37 | Pipe: \| 38 | 39 | Tilde: \~ 40 | 41 | **Commonmark:** 42 | 43 | Quote: \" 44 | 45 | Dollar: \$ 46 | 47 | Percentage: \% 48 | 49 | Ampersand: \& 50 | 51 | Single quote: \' 52 | 53 | Comma: \, 54 | 55 | Forward slash: \/ 56 | 57 | Colon: \: 58 | 59 | Semicolon: \; 60 | 61 | Less-than: \< 62 | 63 | Equals: \= 64 | 65 | Question mark: \? 66 | 67 | At-sign: \@ 68 | 69 | Caret: \^ 70 | 71 | New line: \ 72 | only works in paragraphs. 73 | 74 | Two spaces: 75 | only works in paragraphs. 76 | -------------------------------------------------------------------------------- /test/fixtures/escape-commonmark/output.html: -------------------------------------------------------------------------------- 1 |

These should all get escaped:

2 |

Backslash: \

3 |

Backtick: `

4 |

Asterisk: *

5 |

Underscore: _

6 |

Left brace: {

7 |

Right brace: }

8 |

Left bracket: [

9 |

Right bracket: ]

10 |

Left paren: (

11 |

Right paren: )

12 |

Greater-than: >

13 |

Hash: #

14 |

Period: .

15 |

Bang: !

16 |

Plus: +

17 |

Minus: -

18 |

GFM:

19 |

Pipe: |

20 |

Tilde: ~

21 |

Commonmark:

22 |

Quote: "

23 |

Dollar: $

24 |

Percentage: %

25 |

Ampersand: &

26 |

Single quote: '

27 |

Comma: ,

28 |

Forward slash: /

29 |

Colon: :

30 |

Semicolon: ;

31 |

Less-than: <

32 |

Equals: =

33 |

Question mark: ?

34 |

At-sign: @

35 |

Caret: ^

36 |

New line:
37 | only works in paragraphs.

38 |

Two spaces:
39 | only works in paragraphs.

40 | -------------------------------------------------------------------------------- /test/fixtures/escape-commonmark/output.md: -------------------------------------------------------------------------------- 1 |

These should all get escaped:

2 |

Backslash: \

3 |

Backtick: `

4 |

Asterisk: *

5 |

Underscore: _

6 |

Left brace: {

7 |

Right brace: }

8 |

Left bracket: [

9 |

Right bracket: ]

10 |

Left paren: (

11 |

Right paren: )

12 |

Greater-than: >

13 |

Hash: #

14 |

Period: .

15 |

Bang: !

16 |

Plus: +

17 |

Minus: -

18 |

GFM:

19 |

Pipe: |

20 |

Tilde: ~

21 |

Commonmark:

22 |

Quote: "

23 |

Dollar: $

24 |

Percentage: %

25 |

Ampersand: &

26 |

Single quote: '

27 |

Comma: ,

28 |

Forward slash: /

29 |

Colon: :

30 |

Semicolon: ;

31 |

Less-than: <

32 |

Equals: =

33 |

Question mark: ?

34 |

At-sign: @

35 |

Caret: ^

36 |

New line:
37 | only works in paragraphs.

38 |

Two spaces:
39 | only works in paragraphs.

40 | -------------------------------------------------------------------------------- /test/fixtures/escape/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/escape/input.md: -------------------------------------------------------------------------------- 1 | These should all get escaped: 2 | 3 | Backslash: \\ 4 | 5 | Backtick: \` 6 | 7 | Asterisk: \* 8 | 9 | Underscore: \_ 10 | 11 | Left brace: \{ 12 | 13 | Right brace: \} 14 | 15 | Left bracket: \[ 16 | 17 | Right bracket: \] 18 | 19 | Left paren: \( 20 | 21 | Right paren: \) 22 | 23 | Greater-than: \> 24 | 25 | Hash: \# 26 | 27 | Period: \. 28 | 29 | Bang: \! 30 | 31 | Plus: \+ 32 | 33 | Minus: \- 34 | 35 | **GFM:** 36 | 37 | Pipe: \| 38 | 39 | Tilde: \~ 40 | 41 | **Commonmark:** 42 | 43 | Quote: \" 44 | 45 | Dollar: \$ 46 | 47 | Percentage: \% 48 | 49 | Ampersand: \& 50 | 51 | Single quote: \' 52 | 53 | Comma: \, 54 | 55 | Forward slash: \/ 56 | 57 | Colon: \: 58 | 59 | Semicolon: \; 60 | 61 | Less-than: \< 62 | 63 | Equals: \= 64 | 65 | Question mark: \? 66 | 67 | At-sign: \@ 68 | 69 | Caret: \^ 70 | 71 | New line: \ 72 | only works in paragraphs. 73 | 74 | Two spaces: 75 | only works in paragraphs. 76 | -------------------------------------------------------------------------------- /test/fixtures/escape/output.html: -------------------------------------------------------------------------------- 1 |

These should all get escaped:

2 |

Backslash: \

3 |

Backtick: `

4 |

Asterisk: *

5 |

Underscore: _

6 |

Left brace: {

7 |

Right brace: }

8 |

Left bracket: [

9 |

Right bracket: ]

10 |

Left paren: (

11 |

Right paren: )

12 |

Greater-than: >

13 |

Hash: #

14 |

Period: .

15 |

Bang: !

16 |

Plus: +

17 |

Minus: -

18 |

GFM:

19 |

Pipe: |

20 |

Tilde: ~

21 |

Commonmark:

22 |

Quote: "

23 |

Dollar: $

24 |

Percentage: %

25 |

Ampersand: &

26 |

Single quote: '

27 |

Comma: ,

28 |

Forward slash: /

29 |

Colon: :

30 |

Semicolon: ;

31 |

Less-than: <

32 |

Equals: =

33 |

Question mark: ?

34 |

At-sign: @

35 |

Caret: ^

36 |

New line:
37 | only works in paragraphs.

38 |

Two spaces:
39 | only works in paragraphs.

40 | -------------------------------------------------------------------------------- /test/fixtures/escape/output.md: -------------------------------------------------------------------------------- 1 |

These should all get escaped:

2 |

Backslash: \

3 |

Backtick: `

4 |

Asterisk: *

5 |

Underscore: _

6 |

Left brace: {

7 |

Right brace: }

8 |

Left bracket: [

9 |

Right bracket: ]

10 |

Left paren: (

11 |

Right paren: )

12 |

Greater-than: >

13 |

Hash: #

14 |

Period: .

15 |

Bang: !

16 |

Plus: +

17 |

Minus: -

18 |

GFM:

19 |

Pipe: |

20 |

Tilde: ~

21 |

Commonmark:

22 |

Quote: "

23 |

Dollar: $

24 |

Percentage: %

25 |

Ampersand: &

26 |

Single quote: '

27 |

Comma: ,

28 |

Forward slash: /

29 |

Colon: :

30 |

Semicolon: ;

31 |

Less-than: <

32 |

Equals: =

33 |

Question mark: ?

34 |

At-sign: @

35 |

Caret: ^

36 |

New line:
37 | only works in paragraphs.

38 |

Two spaces:
39 | only works in paragraphs.

40 | -------------------------------------------------------------------------------- /test/fixtures/html-sanitize/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": true 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/html-sanitize/input.md: -------------------------------------------------------------------------------- 1 |

Alpha

2 | 3 | Foo bar baz qux. 4 | 5 | # heading 6 | 7 | Alpha [bravo](javascript:alert(1)) charlie. 8 | -------------------------------------------------------------------------------- /test/fixtures/html-sanitize/output.html: -------------------------------------------------------------------------------- 1 |

Foo bar baz qux.

2 |

heading

3 |

Alpha bravo charlie.

4 | -------------------------------------------------------------------------------- /test/fixtures/html-sanitize/output.md: -------------------------------------------------------------------------------- 1 |

Foo bar baz qux.

2 |

heading

3 |

Alpha bravo charlie.

4 | -------------------------------------------------------------------------------- /test/fixtures/html/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/html/input.md: -------------------------------------------------------------------------------- 1 |

Alpha

2 | 3 | Foo bar baz qux. 4 | -------------------------------------------------------------------------------- /test/fixtures/html/output.html: -------------------------------------------------------------------------------- 1 |

Alpha

2 |

Foo bar baz qux.

3 | -------------------------------------------------------------------------------- /test/fixtures/html/output.md: -------------------------------------------------------------------------------- 1 |

Alpha

2 |

Foo bar baz qux.

3 | -------------------------------------------------------------------------------- /test/fixtures/images/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/images/input.md: -------------------------------------------------------------------------------- 1 | ![Example](http://example.com/favicon.ico "Example Image") 2 | 3 | ![Example](http://example.com/favicon.ico) 4 | 5 | ![](http://example.com/favicon.ico) 6 | 7 | ![](<> "Example Image") 8 | 9 | ![](<>) 10 | 11 | ![]() 12 | -------------------------------------------------------------------------------- /test/fixtures/images/output.html: -------------------------------------------------------------------------------- 1 |

Example

2 |

Example

3 |

4 |

5 |

6 |

7 | -------------------------------------------------------------------------------- /test/fixtures/images/output.md: -------------------------------------------------------------------------------- 1 |

Example

2 |

Example

3 |

4 |

5 |

6 |

7 | -------------------------------------------------------------------------------- /test/fixtures/links/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/links/input.md: -------------------------------------------------------------------------------- 1 | [Example](http://example.com "Example Link") 2 | 3 | [Example](http://example.com) 4 | 5 | [](http://example.com) 6 | 7 | [](<> "Example Link") 8 | 9 | [](<>) 10 | 11 | []() 12 | -------------------------------------------------------------------------------- /test/fixtures/links/output.html: -------------------------------------------------------------------------------- 1 |

Example

2 |

Example

3 |

4 |

5 |

6 |

7 | -------------------------------------------------------------------------------- /test/fixtures/links/output.md: -------------------------------------------------------------------------------- 1 |

Example

2 |

Example

3 |

4 |

5 |

6 |

7 | -------------------------------------------------------------------------------- /test/fixtures/list/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/list/input.md: -------------------------------------------------------------------------------- 1 | # List 2 | 3 | * **One**; 4 | * _Two_; 5 | * ~~Three~~. 6 | 7 | 1. One; 8 | 2. Two; 9 | 10 | 11 | 12 | 4. Four. 13 | 5. Five. 14 | 15 | * Loose: 16 | 17 | - Alpha; 18 | - Bravo; 19 | - Charlie. 20 | 21 | * Loose 2: 22 | 23 | + Delta; 24 | + Echo; 25 | + Foxtrot. 26 | 27 | * *** 28 | 29 | And a rule. 30 | -------------------------------------------------------------------------------- /test/fixtures/list/output.html: -------------------------------------------------------------------------------- 1 |

List

2 |
    3 |
  • One;
  • 4 |
  • Two;
  • 5 |
  • ~~Three~~.
  • 6 |
7 |
    8 |
  1. One;
  2. 9 |
  3. Two;
  4. 10 |
11 | 12 |
    13 |
  1. Four.
  2. 14 |
  3. Five.
  4. 15 |
16 |
    17 |
  • 18 |

    Loose:

    19 |
      20 |
    • Alpha;
    • 21 |
    • Bravo;
    • 22 |
    • Charlie.
    • 23 |
    24 |
  • 25 |
  • 26 |

    Loose 2:

    27 |
      28 |
    • Delta;
    • 29 |
    • Echo;
    • 30 |
    • Foxtrot.
    • 31 |
    32 |
  • 33 |
34 |
35 |
And a rule.
36 | 
37 | -------------------------------------------------------------------------------- /test/fixtures/list/output.md: -------------------------------------------------------------------------------- 1 |

List

2 |
    3 |
  • One;
  • 4 |
  • Two;
  • 5 |
  • ~~Three~~.
  • 6 |
7 |
    8 |
  1. One;
  2. 9 |
  3. Two;
  4. 10 |
11 | 12 |
    13 |
  1. Four.
  2. 14 |
  3. Five.
  4. 15 |
16 |
    17 |
  • 18 |

    Loose:

    19 |
      20 |
    • Alpha;
    • 21 |
    • Bravo;
    • 22 |
    • Charlie.
    • 23 |
    24 |
  • 25 |
  • 26 |

    Loose 2:

    27 |
      28 |
    • Delta;
    • 29 |
    • Echo;
    • 30 |
    • Foxtrot.
    • 31 |
    32 |
  • 33 |
34 |
35 |
And a rule.
36 | 
37 | -------------------------------------------------------------------------------- /test/fixtures/references/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/references/input.md: -------------------------------------------------------------------------------- 1 | # References 2 | 3 | Entities contains some serious entity tests relating to titles and links 4 | in definitions. 5 | 6 | However, the [missing], [missing][], and [missing][missing] are omitted. 7 | 8 | However, the ![missing], ![missing][], and ![missing][missing] are omitted. 9 | 10 | Same goes for [][empty] and ![][empty]. 11 | 12 | [foo]: http://example.com "Example Domain" 13 | -------------------------------------------------------------------------------- /test/fixtures/references/output.html: -------------------------------------------------------------------------------- 1 |

References

2 |

Entities contains some serious entity tests relating to titles and links 3 | in definitions.

4 |

However, the [missing], [missing][], and [missing][missing] are omitted.

5 |

However, the ![missing], ![missing][], and ![missing][missing] are omitted.

6 |

Same goes for [][empty] and ![][empty].

7 | -------------------------------------------------------------------------------- /test/fixtures/references/output.md: -------------------------------------------------------------------------------- 1 |

References

2 |

Entities contains some serious entity tests relating to titles and links 3 | in definitions.

4 |

However, the [missing], [missing][], and [missing][missing] are omitted.

5 |

However, the ![missing], ![missing][], and ![missing][missing] are omitted.

6 |

Same goes for [][empty] and ![][empty].

7 | -------------------------------------------------------------------------------- /test/fixtures/rule/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "sanitize": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/rule/input.md: -------------------------------------------------------------------------------- 1 | # Horizontal Rules 2 | 3 | * * * 4 | 5 | --- 6 | 7 | __________ 8 | -------------------------------------------------------------------------------- /test/fixtures/rule/output.html: -------------------------------------------------------------------------------- 1 |

Horizontal Rules

2 |
3 |
4 |
5 | -------------------------------------------------------------------------------- /test/fixtures/rule/output.md: -------------------------------------------------------------------------------- 1 |

Horizontal Rules

2 |
3 |
4 |
5 | -------------------------------------------------------------------------------- /test/fixtures/self-closing/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "closeSelfClosing": true 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/self-closing/input.md: -------------------------------------------------------------------------------- 1 | Hello 2 | world 3 | 4 | *** 5 | 6 | ![Favicon](http://exaple.com/fav.ico "Example Favicon") 7 | -------------------------------------------------------------------------------- /test/fixtures/self-closing/output.html: -------------------------------------------------------------------------------- 1 |

Hello
2 | world

3 |
4 |

Favicon

5 | -------------------------------------------------------------------------------- /test/fixtures/self-closing/output.md: -------------------------------------------------------------------------------- 1 |

Hello
2 | world

3 |
4 |

Favicon

5 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {import('hast').Element} Element 3 | * @typedef {import('mdast').Paragraph} Paragraph 4 | * @typedef {import('mdast').Root} Root 5 | * @typedef {import('remark-html').Options} Options 6 | * @typedef {import('unified').Pluggable} Pluggable 7 | */ 8 | 9 | import assert from 'node:assert/strict' 10 | import fs from 'node:fs/promises' 11 | import process from 'node:process' 12 | import test from 'node:test' 13 | import {commonmark} from 'commonmark.json' 14 | import {fromHtml} from 'hast-util-from-html' 15 | import {toHtml} from 'hast-util-to-html' 16 | import remarkFrontmatter from 'remark-frontmatter' 17 | import remarkGfm from 'remark-gfm' 18 | import remarkGithub from 'remark-github' 19 | import remarkHtml from 'remark-html' 20 | import remarkParse from 'remark-parse' 21 | import remarkSlug from 'remark-slug' 22 | import remarkToc from 'remark-toc' 23 | import {unified} from 'unified' 24 | import {VFile} from 'vfile' 25 | 26 | test('remarkHtml', async function (t) { 27 | await t.test('should expose the public api', async function () { 28 | assert.deepEqual(Object.keys(await import('remark-html')).sort(), [ 29 | 'default' 30 | ]) 31 | }) 32 | 33 | await t.test('should stringify unknown void nodes', async function () { 34 | assert.equal( 35 | unified() 36 | .use(remarkParse) 37 | .use(remarkHtml) 38 | // @ts-expect-error: check how an unknown node is handled. 39 | .stringify({type: 'alpha'}), 40 | '
' 41 | ) 42 | }) 43 | 44 | await t.test('should stringify unknown nodes w/ children', async function () { 45 | assert.equal( 46 | unified() 47 | .use(remarkParse) 48 | .use(remarkHtml) 49 | .stringify({ 50 | // @ts-expect-error: check how an unknown node is handled. 51 | type: 'alpha', 52 | children: [ 53 | {type: 'strong', children: [{type: 'text', value: 'bravo'}]} 54 | ] 55 | }), 56 | '
bravo
' 57 | ) 58 | }) 59 | 60 | await t.test( 61 | 'should stringify unknown nodes w/ data fields', 62 | async function () { 63 | assert.equal( 64 | unified() 65 | .use(remarkParse) 66 | .use(remarkHtml, {sanitize: false}) 67 | .stringify({ 68 | // @ts-expect-error: check how an unknown node is handled. 69 | type: 'alpha', 70 | children: [{type: 'text', value: 'bravo'}], 71 | data: { 72 | hName: 'i', 73 | hProperties: {className: 'charlie'}, 74 | hChildren: [{type: 'text', value: 'delta'}] 75 | } 76 | }), 77 | 'delta' 78 | ) 79 | } 80 | ) 81 | 82 | await t.test('should support handlers', async function () { 83 | assert.equal( 84 | String( 85 | await unified() 86 | .use(remarkParse) 87 | .use(remarkHtml, { 88 | handlers: { 89 | /** @param {Paragraph} node */ 90 | paragraph(state, node) { 91 | const head = node.children[0] 92 | 93 | if (head.type === 'text') { 94 | head.value = 'changed' 95 | } 96 | 97 | /** @type {Element} */ 98 | const result = { 99 | type: 'element', 100 | tagName: 'p', 101 | properties: {}, 102 | children: state.all(node) 103 | } 104 | state.patch(node, result) 105 | return state.applyData(node, result) 106 | } 107 | } 108 | }) 109 | .process('paragraph text') 110 | ), 111 | '

changed

\n' 112 | ) 113 | }) 114 | 115 | await t.test('should patch and merge attributes', async function () { 116 | assert.equal( 117 | String( 118 | await unified() 119 | .use(remarkParse) 120 | .use(function () { 121 | /** 122 | * @param {Root} tree 123 | * Tree. 124 | * @returns {undefined} 125 | * Nothing. 126 | */ 127 | return function (tree) { 128 | const paragraph = tree.children[0] 129 | assert(paragraph.type === 'paragraph') 130 | const image = paragraph.children[0] 131 | assert(image.type === 'image') 132 | image.data = { 133 | hProperties: {title: 'overwrite'} 134 | } 135 | } 136 | }) 137 | .use(remarkHtml) 138 | .process('![hello](example.jpg "overwritten")') 139 | ), 140 | '

hello

\n' 141 | ) 142 | }) 143 | 144 | await t.test('should overwrite a tag name', async function () { 145 | assert.equal( 146 | String( 147 | await unified() 148 | .use(remarkParse) 149 | .use(function () { 150 | /** 151 | * @param {Root} tree 152 | * Tree. 153 | * @returns {undefined} 154 | * Nothing. 155 | */ 156 | return function (tree) { 157 | const paragraph = tree.children[0] 158 | assert(paragraph.type === 'paragraph') 159 | const strong = paragraph.children[0] 160 | assert(strong.type === 'strong') 161 | strong.data = {hName: 'b'} 162 | } 163 | }) 164 | .use(remarkHtml) 165 | .process('**Bold!**') 166 | ), 167 | '

Bold!

\n' 168 | ) 169 | }) 170 | 171 | await t.test('should overwrite content', async function () { 172 | assert.equal( 173 | String( 174 | await unified() 175 | .use(remarkParse) 176 | .use(function () { 177 | /** 178 | * @param {Root} tree 179 | * Tree. 180 | * @returns {undefined} 181 | * Nothing. 182 | */ 183 | return function (tree) { 184 | const paragraph = tree.children[0] 185 | assert(paragraph.type === 'paragraph') 186 | const inlineCode = paragraph.children[0] 187 | assert(inlineCode.type === 'inlineCode') 188 | inlineCode.data = { 189 | hChildren: [ 190 | { 191 | type: 'element', 192 | tagName: 'span', 193 | properties: {className: ['token']}, 194 | children: [{type: 'text', value: inlineCode.value}] 195 | } 196 | ] 197 | } 198 | } 199 | }) 200 | .use(remarkHtml, {sanitize: false}) 201 | .process('`var`') 202 | ), 203 | '

var

\n' 204 | ) 205 | }) 206 | 207 | await t.test('should sanitize overwriten content', async function () { 208 | assert.equal( 209 | String( 210 | await unified() 211 | .use(remarkParse) 212 | .use(function () { 213 | /** 214 | * @param {Root} tree 215 | * Tree. 216 | * @returns {undefined} 217 | * Nothing. 218 | */ 219 | return function (tree) { 220 | const paragraph = tree.children[0] 221 | assert(paragraph.type === 'paragraph') 222 | const inlineCode = paragraph.children[0] 223 | assert(inlineCode.type === 'inlineCode') 224 | inlineCode.data = { 225 | hChildren: [ 226 | { 227 | type: 'element', 228 | tagName: 'span', 229 | properties: {className: ['token']}, 230 | children: [{type: 'text', value: inlineCode.value}] 231 | } 232 | ] 233 | } 234 | } 235 | }) 236 | .use(remarkHtml, {sanitize: true}) 237 | .process('`var`') 238 | ), 239 | '

var

\n' 240 | ) 241 | }) 242 | 243 | await t.test('should overwrite classes on code', async function () { 244 | assert.equal( 245 | String( 246 | await unified() 247 | .use(remarkParse) 248 | .use(function () { 249 | /** 250 | * @param {Root} tree 251 | * Tree. 252 | * @returns {undefined} 253 | * Nothing. 254 | */ 255 | return function (tree) { 256 | const code = tree.children[0] 257 | assert(code.type === 'code') 258 | code.data = {hProperties: {className: 'foo'}} 259 | } 260 | }) 261 | .use(remarkHtml, {sanitize: false}) 262 | .process('```js\nvar\n```\n') 263 | ), 264 | '
var\n
\n' 265 | ) 266 | }) 267 | 268 | await t.test('should be `sanitize: true` by default', async function () { 269 | assert.equal( 270 | String( 271 | await unified() 272 | .use(remarkParse) 273 | .use(remarkHtml) 274 | .process('## Hello world') 275 | ), 276 | '

Hello world

\n' 277 | ) 278 | }) 279 | 280 | await t.test('should support `sanitize: true`', async function () { 281 | assert.equal( 282 | String( 283 | await unified() 284 | .use(remarkParse) 285 | .use(remarkHtml, {sanitize: true}) 286 | .process('## Hello world') 287 | ), 288 | '

Hello world

\n' 289 | ) 290 | }) 291 | 292 | await t.test('should support `sanitize: null`', async function () { 293 | assert.equal( 294 | String( 295 | await unified() 296 | .use(remarkParse) 297 | .use(remarkHtml, {sanitize: null}) 298 | .process('## Hello world') 299 | ), 300 | '

Hello world

\n' 301 | ) 302 | }) 303 | 304 | await t.test('should support `sanitize: false`', async function () { 305 | assert.equal( 306 | String( 307 | await unified() 308 | .use(remarkParse) 309 | .use(remarkHtml, {sanitize: false}) 310 | .process('## Hello world') 311 | ), 312 | '

Hello world

\n' 313 | ) 314 | }) 315 | 316 | await t.test('should support sanitize schemas', async function () { 317 | assert.equal( 318 | String( 319 | await unified() 320 | .use(remarkParse) 321 | .use(remarkHtml, {sanitize: {tagNames: []}}) 322 | .process('## Hello world') 323 | ), 324 | 'Hello world\n' 325 | ) 326 | }) 327 | }) 328 | 329 | test('CommonMark', async function (t) { 330 | /** @type {Set} */ 331 | const skip = new Set() 332 | let start = 0 333 | let index = -1 334 | /** @type {string | undefined} */ 335 | let section 336 | 337 | while (++index < commonmark.length) { 338 | const example = commonmark[index] 339 | 340 | if (skip.has(index)) { 341 | console.log('To do: `commonmark` test %d', index) 342 | continue 343 | } 344 | 345 | await t.test( 346 | index + ': ' + example.section + ' (' + (index - start + 1) + ')', 347 | async function () { 348 | if (section !== example.section) { 349 | section = example.section 350 | start = index 351 | } 352 | 353 | const actual = String( 354 | await unified() 355 | .use(remarkParse) 356 | .use(remarkHtml, {sanitize: false}) 357 | .process(example.markdown) 358 | ) 359 | 360 | // Normalize meaningless stuff, like character references, `
` is `
`, 361 | // etc. 362 | assert.equal( 363 | String(toHtml(fromHtml(actual))), 364 | String(toHtml(fromHtml(actual))) 365 | ) 366 | } 367 | ) 368 | } 369 | }) 370 | 371 | test('fixtures', async function (t) { 372 | const base = new URL('fixtures/', import.meta.url) 373 | const files = await fs.readdir(base) 374 | let index = -1 375 | 376 | while (++index < files.length) { 377 | const folder = files[index] 378 | 379 | if (folder.startsWith('.')) continue 380 | 381 | await t.test(folder, async function () { 382 | const folderUrl = new URL(folder + '/', base) 383 | const inputUrl = new URL('input.md', folderUrl) 384 | const outputUrl = new URL('output.html', folderUrl) 385 | const configUrl = new URL('config.json', folderUrl) 386 | const input = String(await fs.readFile(inputUrl)) 387 | /** @type {Options | undefined} */ 388 | let config 389 | /** @type {string} */ 390 | let output 391 | 392 | try { 393 | config = JSON.parse(String(await fs.readFile(configUrl))) 394 | } catch {} 395 | 396 | const actual = String( 397 | await unified().use(remarkParse).use(remarkHtml, config).process(input) 398 | ) 399 | 400 | try { 401 | if ('UPDATE' in process.env) { 402 | throw new Error('Updating…') 403 | } 404 | 405 | output = String(await fs.readFile(outputUrl)) 406 | } catch { 407 | output = actual 408 | await fs.writeFile(outputUrl, actual) 409 | } 410 | 411 | assert.equal(actual, String(output)) 412 | }) 413 | } 414 | }) 415 | 416 | test('integrations', async function (t) { 417 | /** @type {Record} */ 418 | const integrationMap = { 419 | footnotes: remarkGfm, 420 | frontmatter: remarkFrontmatter, 421 | gfm: remarkGfm, 422 | github: remarkGithub, 423 | toc: [ 424 | // @ts-expect-error: legacy; to do: remove? 425 | remarkSlug, 426 | remarkToc 427 | ] 428 | } 429 | const base = new URL('integrations/', import.meta.url) 430 | const files = await fs.readdir(base) 431 | let index = -1 432 | 433 | while (++index < files.length) { 434 | const folder = files[index] 435 | 436 | if (folder.startsWith('.')) continue 437 | 438 | await t.test('should integrate w/ `' + folder + '`', async function () { 439 | const folderUrl = new URL(folder + '/', base) 440 | const inputUrl = new URL('input.md', folderUrl) 441 | const outputUrl = new URL('output.html', folderUrl) 442 | const input = String(await fs.readFile(inputUrl)) 443 | 444 | const actual = String( 445 | await unified() 446 | .use(remarkParse) 447 | // @ts-expect-error: fine. 448 | .use(integrationMap[folder]) 449 | .use(remarkHtml, {sanitize: false}) 450 | .process(new VFile({path: folder + '.md', value: input})) 451 | ) 452 | 453 | /** @type {string} */ 454 | let output 455 | 456 | try { 457 | if ('UPDATE' in process.env) { 458 | throw new Error('Updating…') 459 | } 460 | 461 | output = String(await fs.readFile(outputUrl)) 462 | } catch { 463 | output = actual 464 | await fs.writeFile(outputUrl, actual) 465 | } 466 | 467 | assert.equal(actual, String(output)) 468 | }) 469 | } 470 | }) 471 | -------------------------------------------------------------------------------- /test/integrations/footnotes/input.md: -------------------------------------------------------------------------------- 1 | Here is a footnote reference,[^1] 2 | another,[^longnote], 3 | and optionally there are inline 4 | notes.^[you can type them inline, which may be easier, since you don’t 5 | have to pick an identifier and move down to type the note.] 6 | 7 | [^1]: Here is the footnote. 8 | 9 | [^longnote]: Here’s one with multiple blocks. 10 | 11 | Subsequent paragraphs are indented to show that they 12 | belong to the previous footnote. 13 | 14 | { some.code } 15 | 16 | The whole paragraph can be indented, or just the first 17 | line. In this way, multi-paragraph footnotes work like 18 | multi-paragraph list items. 19 | 20 | This paragraph won’t be part of the note, because it 21 | isn’t indented. 22 | -------------------------------------------------------------------------------- /test/integrations/footnotes/output.html: -------------------------------------------------------------------------------- 1 |

Here is a footnote reference,1 2 | another,2, 3 | and optionally there are inline 4 | notes.^[you can type them inline, which may be easier, since you don’t 5 | have to pick an identifier and move down to type the note.]

6 |

This paragraph won’t be part of the note, because it 7 | isn’t indented.

8 |

Footnotes

9 |
    10 |
  1. 11 |

    Here is the footnote.

    12 |
  2. 13 |
  3. 14 |

    Here’s one with multiple blocks.

    15 |

    Subsequent paragraphs are indented to show that they 16 | belong to the previous footnote.

    17 |
    { some.code }
    18 | 
    19 |

    The whole paragraph can be indented, or just the first 20 | line. In this way, multi-paragraph footnotes work like 21 | multi-paragraph list items.

    22 |
  4. 23 |
24 |
25 | -------------------------------------------------------------------------------- /test/integrations/frontmatter/input.md: -------------------------------------------------------------------------------- 1 | --- 2 | title = "New Website" 3 | --- 4 | 5 | # Other markdown 6 | -------------------------------------------------------------------------------- /test/integrations/frontmatter/output.html: -------------------------------------------------------------------------------- 1 |

Other markdown

2 | -------------------------------------------------------------------------------- /test/integrations/gfm/input.md: -------------------------------------------------------------------------------- 1 | # GFM 2 | 3 | ## Autolink literals 4 | 5 | www.example.com, https://example.com, and contact@example.com. 6 | 7 | ## Strikethrough 8 | 9 | ~one~ or ~~two~~ tildes. 10 | 11 | ## Table 12 | 13 | | a | b | c | d | 14 | | - | :- | -: | :-: | 15 | 16 | ## Tasklist 17 | 18 | * [ ] to do 19 | * [x] done 20 | -------------------------------------------------------------------------------- /test/integrations/gfm/output.html: -------------------------------------------------------------------------------- 1 |

GFM

2 |

Autolink literals

3 |

www.example.com, https://example.com, and contact@example.com.

4 |

Strikethrough

5 |

one or two tildes.

6 |

Table

7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
abcd
17 |

Tasklist

18 |
    19 |
  • to do
  • 20 |
  • done
  • 21 |
22 | -------------------------------------------------------------------------------- /test/integrations/github/input.md: -------------------------------------------------------------------------------- 1 | * SHA: a5c3785; 2 | * SHA: a5c3785ed8d6a35868bc169f07e40e889087fd2e; 3 | * User@SHA: jlord@a5c3785ed8d6a35868bc169f07e40e889087fd2e; 4 | * User/Repository@SHA: jlord/sheetsee.js@a5c3785e; 5 | * #Num: #26; 6 | * GH-Num: GH-26; 7 | * User#Num: jlord#26; 8 | * User/Repository#Num: jlord/sheetsee.js#26; 9 | * @mention; 10 | * And @mentioning someone else; 11 | * And nothing. 12 | -------------------------------------------------------------------------------- /test/integrations/github/output.html: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /test/integrations/toc/input.md: -------------------------------------------------------------------------------- 1 | # Hello 2 | 3 | ## Table of Contents 4 | 5 | ## Foo 6 | 7 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 8 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 9 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 10 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 11 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat 12 | non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 13 | 14 | ## Bar 15 | 16 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 17 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 18 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 19 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 20 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat 21 | non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 22 | 23 | ## Baz 24 | 25 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 26 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 27 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 28 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 29 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat 30 | non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 31 | -------------------------------------------------------------------------------- /test/integrations/toc/output.html: -------------------------------------------------------------------------------- 1 |

Hello

2 |

Table of Contents

3 | 8 |

Foo

9 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 10 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 11 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 12 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 13 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat 14 | non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

15 |

Bar

16 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 17 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 18 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 19 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 20 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat 21 | non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

22 |

Baz

23 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 24 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 25 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo 26 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse 27 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat 28 | non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

29 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "checkJs": true, 4 | "customConditions": ["development"], 5 | "declaration": true, 6 | "emitDeclarationOnly": true, 7 | "exactOptionalPropertyTypes": true, 8 | "lib": ["es2022"], 9 | "module": "node16", 10 | "strict": true, 11 | "target": "es2022" 12 | }, 13 | "exclude": ["coverage/", "node_modules/"], 14 | "include": ["**/*.js", "index.d.ts"] 15 | } 16 | --------------------------------------------------------------------------------