├── .editorconfig ├── .github └── workflows │ ├── bb.yml │ └── main.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .remarkignore ├── index.js ├── lib └── index.js ├── license ├── package.json ├── readme.md ├── test ├── fixtures │ ├── contents │ │ ├── input.md │ │ └── output.md │ ├── custom-heading │ │ ├── config.json │ │ ├── input.md │ │ └── output.md │ ├── empty-headings │ │ ├── input.md │ │ └── output.md │ ├── image-in-link-in-heading │ │ ├── input.md │ │ └── output.md │ ├── loose │ │ ├── config.json │ │ ├── input.md │ │ └── output.md │ ├── maximum-depth-1 │ │ ├── config.json │ │ ├── input.md │ │ └── output.md │ ├── maximum-depth-3 │ │ ├── config.json │ │ ├── input.md │ │ └── output.md │ ├── maximum-depth-6 │ │ ├── config.json │ │ ├── input.md │ │ └── output.md │ ├── missing-content │ │ ├── input.md │ │ └── output.md │ ├── missing-heading │ │ ├── input.md │ │ └── output.md │ ├── normal-content │ │ ├── input.md │ │ └── output.md │ ├── normal-dashes │ │ ├── input.md │ │ └── output.md │ ├── normal-literal-dashes │ │ ├── input.md │ │ └── output.md │ ├── normal-more-content │ │ ├── input.md │ │ └── output.md │ ├── normal-nesting-inverted │ │ ├── input.md │ │ └── output.md │ ├── normal-singular │ │ ├── input.md │ │ └── output.md │ ├── normal-toc │ │ ├── input.md │ │ └── output.md │ ├── normal │ │ ├── input.md │ │ └── output.md │ ├── skip │ │ ├── config.json │ │ ├── input.md │ │ └── output.md │ ├── slug-for-images-and-links │ │ ├── input.md │ │ └── output.md │ ├── tight │ │ ├── config.json │ │ ├── input.md │ │ └── output.md │ └── unicode │ │ ├── input.md │ │ └── output.md └── index.js └── 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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | ignore-scripts=true 2 | package-lock=false 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | *.md 3 | -------------------------------------------------------------------------------- /.remarkignore: -------------------------------------------------------------------------------- 1 | test/fixtures/ 2 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {import('./lib/index.js').Options} Options 3 | */ 4 | 5 | export {default} from './lib/index.js' 6 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {import('mdast').Root} Root 3 | * @typedef {import('mdast-util-toc').Options} Options 4 | */ 5 | 6 | import {toc} from 'mdast-util-toc' 7 | 8 | /** 9 | * Generate a table of contents (TOC). 10 | * 11 | * Looks for the first heading matching `options.heading` (case insensitive), 12 | * removes everything between it and an equal or higher next heading, and 13 | * replaces that with a list representing the rest of the document structure, 14 | * linking to all further headings. 15 | * 16 | * @param {Readonly | null | undefined} [options] 17 | * Configuration (optional). 18 | * @returns 19 | * Transform. 20 | */ 21 | export default function remarkToc(options) { 22 | const settings = { 23 | ...options, 24 | heading: (options && options.heading) || '(table[ -]of[ -])?contents?|toc', 25 | tight: options && typeof options.tight === 'boolean' ? options.tight : true 26 | } 27 | 28 | /** 29 | * Transform. 30 | * 31 | * @param {Root} tree 32 | * Tree. 33 | * @returns {undefined} 34 | * Nothing. 35 | */ 36 | return function (tree) { 37 | const result = toc(tree, settings) 38 | 39 | if ( 40 | result.endIndex === undefined || 41 | result.endIndex === -1 || 42 | result.index === undefined || 43 | result.index === -1 || 44 | !result.map 45 | ) { 46 | return 47 | } 48 | 49 | tree.children = [ 50 | ...tree.children.slice(0, result.index), 51 | result.map, 52 | ...tree.children.slice(result.endIndex) 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /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 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remark-toc", 3 | "version": "9.0.0", 4 | "description": "remark plugin to generate a table of contents (TOC)", 5 | "license": "MIT", 6 | "keywords": [ 7 | "content", 8 | "contents", 9 | "generation", 10 | "markdown", 11 | "mdast", 12 | "plugin", 13 | "remark", 14 | "remark-plugin", 15 | "table", 16 | "toc", 17 | "unified" 18 | ], 19 | "repository": "remarkjs/remark-toc", 20 | "bugs": "https://github.com/remarkjs/remark-toc/issues", 21 | "funding": { 22 | "type": "opencollective", 23 | "url": "https://opencollective.com/unified" 24 | }, 25 | "author": "Titus Wormer (https://wooorm.com)", 26 | "contributors": [ 27 | "Titus Wormer (https://wooorm.com)", 28 | "Gary Katsevman ", 29 | "Jonathan Haines ", 30 | "Robin Millette " 31 | ], 32 | "sideEffects": false, 33 | "type": "module", 34 | "exports": "./index.js", 35 | "files": [ 36 | "lib/", 37 | "index.d.ts", 38 | "index.js" 39 | ], 40 | "dependencies": { 41 | "@types/mdast": "^4.0.0", 42 | "mdast-util-toc": "^7.0.0" 43 | }, 44 | "devDependencies": { 45 | "@types/node": "^20.0.0", 46 | "c8": "^8.0.0", 47 | "is-hidden": "^2.0.0", 48 | "prettier": "^3.0.0", 49 | "remark": "^15.0.0", 50 | "remark-cli": "^11.0.0", 51 | "remark-preset-wooorm": "^9.0.0", 52 | "type-coverage": "^2.0.0", 53 | "typescript": "^5.0.0", 54 | "xo": "^0.56.0" 55 | }, 56 | "scripts": { 57 | "build": "tsc --build --clean && tsc --build && type-coverage", 58 | "format": "remark . --frail --output --quiet && prettier . --log-level warn --write && xo --fix", 59 | "prepack": "npm run build && npm run format", 60 | "test": "npm run build && npm run format && npm run test-coverage", 61 | "test-api": "node --conditions development test/index.js", 62 | "test-coverage": "c8 --100 --reporter lcov npm run test-api" 63 | }, 64 | "prettier": { 65 | "bracketSpacing": false, 66 | "singleQuote": true, 67 | "semi": false, 68 | "tabWidth": 2, 69 | "trailingComma": "none", 70 | "useTabs": false 71 | }, 72 | "remarkConfig": { 73 | "plugins": [ 74 | "remark-preset-wooorm" 75 | ] 76 | }, 77 | "typeCoverage": { 78 | "atLeast": 100, 79 | "detail": true, 80 | "ignoreCatch": true, 81 | "strict": true 82 | }, 83 | "xo": { 84 | "overrides": [ 85 | { 86 | "files": [ 87 | "test/**/*.js" 88 | ], 89 | "rules": { 90 | "no-await-in-loop": "off" 91 | } 92 | } 93 | ], 94 | "prettier": true 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # remark-toc 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 generate a table of contents. 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(remarkToc[, options])`](#unifieduseremarktoc-options) 21 | * [`Options`](#options) 22 | * [Examples](#examples) 23 | * [Example: a different heading](#example-a-different-heading) 24 | * [Example: ordered, loose list](#example-ordered-loose-list) 25 | * [Example: including and excluding headings](#example-including-and-excluding-headings) 26 | * [Example: adding a prefix](#example-adding-a-prefix) 27 | * [Types](#types) 28 | * [Compatibility](#compatibility) 29 | * [Security](#security) 30 | * [Related](#related) 31 | * [Contribute](#contribute) 32 | * [License](#license) 33 | 34 | ## What is this? 35 | 36 | This package is a [unified][] ([remark][]) plugin to generate a table of 37 | contents of the document such as the one above. 38 | 39 | ## When should I use this? 40 | 41 | This project is useful when authors are writing docs in markdown that are 42 | sometimes quite long and so would benefit from automated overviews inside them. 43 | It is assumed that headings define the structure of documents and that they can 44 | be linked to. 45 | When this plugin is used, authors can add a certain heading (say, `## Contents`) 46 | to documents and this plugin will populate those sections with lists that link 47 | to all following sections. 48 | 49 | GitHub and similar services automatically add IDs (and anchors that 50 | link-to-self) to headings. 51 | You can add similar features when combining remark with [rehype][] through 52 | [`remark-rehype`][remark-rehype] after this plugin. 53 | Then it’s possible to use the rehype plugins [`rehype-slug`][rehype-slug] (for 54 | IDs on headings) and [`rehype-autolink-headings`][rehype-autolink-headings] (for 55 | anchors that link-to-self). 56 | 57 | This plugin does not generate a table of contents for the *whole* document or 58 | expose it to other plugins. 59 | You can use the underlying mdast utility [`mdast-util-toc`][mdast-util-toc] and 60 | [create a plugin][unified-create-a-plugin] yourself to do that and more. 61 | 62 | ## Install 63 | 64 | This package is [ESM only][esm]. 65 | In Node.js (version 16+), install with [npm][]: 66 | 67 | ```sh 68 | npm install remark-toc 69 | ``` 70 | 71 | In Deno with [`esm.sh`][esmsh]: 72 | 73 | ```js 74 | import remarkToc from 'https://esm.sh/remark-toc@9' 75 | ``` 76 | 77 | In browsers with [`esm.sh`][esmsh]: 78 | 79 | ```html 80 | 83 | ``` 84 | 85 | ## Use 86 | 87 | Say we have the following file `example.md`: 88 | 89 | ```markdown 90 | # Pluto 91 | 92 | Pluto is a dwarf planet in the Kuiper belt. 93 | 94 | ## Contents 95 | 96 | ## History 97 | 98 | ### Discovery 99 | 100 | In the 1840s, Urbain Le Verrier used Newtonian mechanics to predict the 101 | position of… 102 | 103 | ### Name and symbol 104 | 105 | The name Pluto is for the Roman god of the underworld, from a Greek epithet for 106 | Hades… 107 | 108 | ### Planet X disproved 109 | 110 | Once Pluto was found, its faintness and lack of a viewable disc cast doubt… 111 | 112 | ## Orbit 113 | 114 | Pluto’s orbital period is about 248 years… 115 | ``` 116 | 117 | …and a module `example.js`: 118 | 119 | ```js 120 | import {remark} from 'remark' 121 | import remarkToc from 'remark-toc' 122 | import {read} from 'to-vfile' 123 | 124 | const file = await remark() 125 | .use(remarkToc) 126 | .process(await read('example.md')) 127 | 128 | console.error(String(file)) 129 | ``` 130 | 131 | …then running `node example.js` yields: 132 | 133 | ```markdown 134 | # Pluto 135 | 136 | Pluto is a dwarf planet in the Kuiper belt. 137 | 138 | ## Contents 139 | 140 | * [History](#history) 141 | * [Discovery](#discovery) 142 | * [Name and symbol](#name-and-symbol) 143 | * [Planet X disproved](#planet-x-disproved) 144 | * [Orbit](#orbit) 145 | 146 | ## History 147 | 148 | ### Discovery 149 | 150 | In the 1840s, Urbain Le Verrier used Newtonian mechanics to predict the 151 | position of… 152 | 153 | ### Name and symbol 154 | 155 | The name Pluto is for the Roman god of the underworld, from a Greek epithet for 156 | Hades… 157 | 158 | ### Planet X disproved 159 | 160 | Once Pluto was found, its faintness and lack of a viewable disc cast doubt… 161 | 162 | ## Orbit 163 | 164 | Pluto’s orbital period is about 248 years… 165 | ``` 166 | 167 | ## API 168 | 169 | This package exports no identifiers. 170 | The default export is [`remarkToc`][api-remark-toc]. 171 | 172 | ### `unified().use(remarkToc[, options])` 173 | 174 | Generate a table of contents (TOC). 175 | 176 | Looks for the first heading matching `options.heading` (case insensitive), 177 | removes everything between it and an equal or higher next heading, and replaces 178 | that with a list representing the rest of the document structure, linking to 179 | all further headings. 180 | 181 | ###### Parameters 182 | 183 | * `options` ([`Options`][api-options], optional) 184 | — configuration 185 | 186 | ###### Returns 187 | 188 | Transform ([`Transformer`][unified-transformer]). 189 | 190 | ### `Options` 191 | 192 | Configuration (TypeScript type). 193 | 194 | ###### Fields 195 | 196 | * `heading` (`string`, default: `'(table[ -]of[ -])?contents?|toc'`) 197 | — heading to look for, wrapped in `new RegExp('^(' + value + ')$', 'i')` 198 | * `maxDepth` (`number`, default: `6`) 199 | — max heading depth to include in the table of contents; this is inclusive: 200 | when set to `3`, level three headings are included (those with three hashes, 201 | `###`) 202 | * `skip` (`string`, optional) 203 | — headings to skip, wrapped in `new RegExp('^(' + value + ')$', 'i')`; 204 | any heading matching this expression will not be present in the table of 205 | contents 206 | * `parents` ([`Test` from `unist-util-is`][unist-util-is-test], default: 207 | `tree`) 208 | — allow headings to be children of certain node types 209 | * `tight` (`boolean`, default: `true`) 210 | — whether to compile list items tightly, otherwise space is added around 211 | items 212 | * `ordered` (`boolean`, default: `false`) 213 | — whether to compile list items as an ordered list, otherwise they are 214 | unordered 215 | * `prefix` (`string`, optional, example: `'user-content-'`) 216 | — add a prefix to links to headings in the table of contents; 217 | useful for example when later going from markdown to HTML and sanitizing 218 | with [`rehype-sanitize`][rehype-sanitize] 219 | 220 | ## Examples 221 | 222 | ### Example: a different heading 223 | 224 | The option `heading` can be set to search for a different heading. 225 | The example from before can be changed to search for different headings like so: 226 | 227 | ```diff 228 | @@ -3,7 +3,7 @@ import remarkToc from 'remark-toc' 229 | import {read} from 'to-vfile' 230 | 231 | const file = await remark() 232 | - .use(remarkToc) 233 | + .use(remarkToc, {heading: 'structure'}) 234 | .process(await read('example.md')) 235 | 236 | console.error(String(file)) 237 | ``` 238 | 239 | …that would search for `structure` (case-insensitive) headings. 240 | 241 | ### Example: ordered, loose list 242 | 243 | The options `ordered` and `tight` can be toggled to change the list. 244 | The example from before can be changed to generate a tight, ordered list like 245 | so: 246 | 247 | ```diff 248 | @@ -3,7 +3,7 @@ import remarkToc from 'remark-toc' 249 | import {read} from 'to-vfile' 250 | 251 | const file = await remark() 252 | - .use(remarkToc) 253 | + .use(remarkToc, {ordered: true, tight: false}) 254 | .process(await read('example.md')) 255 | 256 | console.error(String(file)) 257 | ``` 258 | 259 | …that would generate the following list: 260 | 261 | ```markdown 262 | 1. [History](#history) 263 | 264 | 1. [Discovery](#discovery) 265 | 2. [Name and symbol](#name-and-symbol) 266 | 3. [Planet X disproved](#planet-x-disproved) 267 | 268 | 2. [Orbit](#orbit) 269 | ``` 270 | 271 | ### Example: including and excluding headings 272 | 273 | The options `maxDepth`, `parents`, and `skip` can be used to include and 274 | exclude certain headings from list. 275 | The example from before can be changed to only include level 1, 2, and 3 276 | headings, to include headings directly in list items, and to exclude headings 277 | with the text `delta` (case-insensitive, full match): 278 | 279 | ```diff 280 | @@ -3,7 +3,7 @@ import remarkToc from 'remark-toc' 281 | import {read} from 'to-vfile' 282 | 283 | const file = await remark() 284 | - .use(remarkToc) 285 | + .use(remarkToc, {maxDepth: 3, parents: ['listItem', 'root'], skip: 'delta'}) 286 | .process(await read('example.md')) 287 | 288 | console.error(String(file)) 289 | ``` 290 | 291 | ### Example: adding a prefix 292 | 293 | The `prefix` option can set to prepend a string to all links to headings in the 294 | generated list: 295 | 296 | ```diff 297 | @@ -3,7 +3,7 @@ import remarkToc from 'remark-toc' 298 | import {read} from 'to-vfile' 299 | 300 | const file = await remark() 301 | - .use(remarkToc) 302 | + .use(remarkToc, {prefix: 'user-content-'}) 303 | .process(await read('example.md')) 304 | 305 | console.error(String(file)) 306 | ``` 307 | 308 | …that would generate the following list: 309 | 310 | ```markdown 311 | * [History](#user-content-history) 312 | * [Discovery](#user-content-discovery) 313 | * [Name and symbol](#user-content-name-and-symbol) 314 | * [Planet X disproved](#user-content-planet-x-disproved) 315 | * [Orbit](#user-content-orbit) 316 | ``` 317 | 318 | ## Types 319 | 320 | This package is fully typed with [TypeScript][]. 321 | It exports the additional type [`Options`][api-options]. 322 | 323 | ## Compatibility 324 | 325 | Projects maintained by the unified collective are compatible with maintained 326 | versions of Node.js. 327 | 328 | When we cut a new major release, we drop support for unmaintained versions of 329 | Node. 330 | This means we try to keep the current release line, `remark-toc@^9`, compatible 331 | with Node.js 16. 332 | 333 | This plugin works with `unified` version 3+ and `remark` version 4+. 334 | 335 | ## Security 336 | 337 | Use of `remark-toc` involves user content and changes the tree, so it can open 338 | you up for a [cross-site scripting (XSS)][wiki-xss] attack. 339 | 340 | Existing nodes are copied into the table of contents. 341 | The following example shows how an existing script is copied into the table of 342 | contents. 343 | 344 | The following markdown: 345 | 346 | ```markdown 347 | # Contents 348 | 349 | ## Bravo 350 | 351 | ## Charlie 352 | ``` 353 | 354 | Yields: 355 | 356 | ```markdown 357 | # Contents 358 | 359 | - [Bravo](#bravoscriptalert1script) 360 | - [Charlie](#charlie) 361 | 362 | ## Bravo 363 | 364 | ## Charlie 365 | ``` 366 | 367 | This may become a problem if the markdown is later transformed to 368 | **[rehype][]** (**[hast][]**) or opened in an unsafe markdown viewer. 369 | 370 | ## Related 371 | 372 | * [`remark-normalize-headings`](https://github.com/remarkjs/remark-normalize-headings) 373 | — make sure that there is only one top-level heading by normalizing heading 374 | ranks 375 | * [`remark-collapse`](https://github.com/Rokt33r/remark-collapse) 376 | – make some sections collapsible 377 | * [`remark-contributors`](https://github.com/remarkjs/remark-contributors) 378 | – generate a contributors section 379 | * [`remark-license`](https://github.com/remarkjs/remark-license) 380 | – generate a license section 381 | * [`remark-package-dependencies`](https://github.com/unlight/remark-package-dependencies) 382 | – generate a dependencies section 383 | * [`remark-usage`](https://github.com/remarkjs/remark-usage) 384 | – generate a usage section 385 | 386 | ## Contribute 387 | 388 | See [`contributing.md`][contributing] in [`remarkjs/.github`][health] for ways 389 | to get started. 390 | See [`support.md`][support] for ways to get help. 391 | 392 | This project has a [code of conduct][coc]. 393 | By interacting with this repository, organization, or community you agree to 394 | abide by its terms. 395 | 396 | ## License 397 | 398 | [MIT][license] © [Titus Wormer][author] 399 | 400 | 401 | 402 | [build-badge]: https://github.com/remarkjs/remark-toc/workflows/main/badge.svg 403 | 404 | [build]: https://github.com/remarkjs/remark-toc/actions 405 | 406 | [coverage-badge]: https://img.shields.io/codecov/c/github/remarkjs/remark-toc.svg 407 | 408 | [coverage]: https://codecov.io/github/remarkjs/remark-toc 409 | 410 | [downloads-badge]: https://img.shields.io/npm/dm/remark-toc.svg 411 | 412 | [downloads]: https://www.npmjs.com/package/remark-toc 413 | 414 | [size-badge]: https://img.shields.io/bundlejs/size/remark-toc 415 | 416 | [size]: https://bundlejs.com/?q=remark-toc 417 | 418 | [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg 419 | 420 | [backers-badge]: https://opencollective.com/unified/backers/badge.svg 421 | 422 | [collective]: https://opencollective.com/unified 423 | 424 | [chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg 425 | 426 | [chat]: https://github.com/remarkjs/remark/discussions 427 | 428 | [npm]: https://docs.npmjs.com/cli/install 429 | 430 | [esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c 431 | 432 | [esmsh]: https://esm.sh 433 | 434 | [health]: https://github.com/remarkjs/.github 435 | 436 | [contributing]: https://github.com/remarkjs/.github/blob/main/contributing.md 437 | 438 | [support]: https://github.com/remarkjs/.github/blob/main/support.md 439 | 440 | [coc]: https://github.com/remarkjs/.github/blob/main/code-of-conduct.md 441 | 442 | [license]: license 443 | 444 | [author]: https://wooorm.com 445 | 446 | [hast]: https://github.com/syntax-tree/hast 447 | 448 | [mdast-util-toc]: https://github.com/syntax-tree/mdast-util-toc 449 | 450 | [rehype]: https://github.com/rehypejs/rehype 451 | 452 | [rehype-autolink-headings]: https://github.com/rehypejs/rehype-autolink-headings 453 | 454 | [rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize 455 | 456 | [rehype-slug]: https://github.com/rehypejs/rehype-slug 457 | 458 | [remark]: https://github.com/remarkjs/remark 459 | 460 | [remark-rehype]: https://github.com/remarkjs/remark-rehype 461 | 462 | [typescript]: https://www.typescriptlang.org 463 | 464 | [unified]: https://github.com/unifiedjs/unified 465 | 466 | [unified-transformer]: https://github.com/unifiedjs/unified#transformer 467 | 468 | [unified-create-a-plugin]: https://unifiedjs.com/learn/guide/create-a-plugin/ 469 | 470 | [unist-util-is-test]: https://github.com/syntax-tree/unist-util-is#test 471 | 472 | [wiki-xss]: https://en.wikipedia.org/wiki/Cross-site_scripting 473 | 474 | [api-options]: #options 475 | 476 | [api-remark-toc]: #unifieduseremarktoc-options 477 | -------------------------------------------------------------------------------- /test/fixtures/contents/input.md: -------------------------------------------------------------------------------- 1 | # Alpha 2 | 3 | ## Contents 4 | 5 | # Bravo 6 | -------------------------------------------------------------------------------- /test/fixtures/contents/output.md: -------------------------------------------------------------------------------- 1 | # Alpha 2 | 3 | ## Contents 4 | 5 | * [Bravo](#bravo) 6 | 7 | # Bravo 8 | -------------------------------------------------------------------------------- /test/fixtures/custom-heading/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "heading": "fo+" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/custom-heading/input.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Fooooo 4 | 5 | # Something if 6 | 7 | ## Something else 8 | 9 | Text. 10 | 11 | ## Something elsefi 12 | 13 | # Something iffi 14 | -------------------------------------------------------------------------------- /test/fixtures/custom-heading/output.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Fooooo 4 | 5 | * [Something if](#something-if) 6 | * [Something else](#something-else) 7 | * [Something elsefi](#something-elsefi) 8 | * [Something iffi](#something-iffi) 9 | 10 | # Something if 11 | 12 | ## Something else 13 | 14 | Text. 15 | 16 | ## Something elsefi 17 | 18 | # Something iffi 19 | -------------------------------------------------------------------------------- /test/fixtures/empty-headings/input.md: -------------------------------------------------------------------------------- 1 | # Empty headings 2 | 3 | ## Table of Contents 4 | 5 | ## 6 | 7 | ## ![](an-image.svg) 8 | -------------------------------------------------------------------------------- /test/fixtures/empty-headings/output.md: -------------------------------------------------------------------------------- 1 | # Empty headings 2 | 3 | ## Table of Contents 4 | 5 | * [](#) 6 | * [![](an-image.svg)](#-1) 7 | 8 | ## 9 | 10 | ## ![](an-image.svg) 11 | -------------------------------------------------------------------------------- /test/fixtures/image-in-link-in-heading/input.md: -------------------------------------------------------------------------------- 1 | # Image in link in heading 2 | 3 | ## [![](./some-table.png "Table of Contents")](some-link.com) 4 | 5 | # Something if 6 | 7 | ## Something else 8 | 9 | Text. 10 | 11 | ## Something elsefi 12 | 13 | # Something iffi 14 | -------------------------------------------------------------------------------- /test/fixtures/image-in-link-in-heading/output.md: -------------------------------------------------------------------------------- 1 | # Image in link in heading 2 | 3 | ## [![](./some-table.png "Table of Contents")](some-link.com) 4 | 5 | # Something if 6 | 7 | ## Something else 8 | 9 | Text. 10 | 11 | ## Something elsefi 12 | 13 | # Something iffi 14 | -------------------------------------------------------------------------------- /test/fixtures/loose/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "tight": false 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/loose/input.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | # Something if 6 | 7 | ## Something else 8 | 9 | Text. 10 | 11 | ## Something elsefi 12 | 13 | ### Yet Another Thing 14 | 15 | ### And another thing 16 | 17 | # Something iffi 18 | -------------------------------------------------------------------------------- /test/fixtures/loose/output.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | * [Something if](#something-if) 6 | 7 | * [Something else](#something-else) 8 | 9 | * [Something elsefi](#something-elsefi) 10 | 11 | * [Yet Another Thing](#yet-another-thing) 12 | * [And another thing](#and-another-thing) 13 | 14 | * [Something iffi](#something-iffi) 15 | 16 | # Something if 17 | 18 | ## Something else 19 | 20 | Text. 21 | 22 | ## Something elsefi 23 | 24 | ### Yet Another Thing 25 | 26 | ### And another thing 27 | 28 | # Something iffi 29 | -------------------------------------------------------------------------------- /test/fixtures/maximum-depth-1/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "maxDepth": 1 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/maximum-depth-1/input.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | # Table of Contents 4 | 5 | # Alpha 6 | 7 | ## Bravo 8 | 9 | ### Charlie 10 | 11 | #### Delta 12 | 13 | ##### Echo 14 | 15 | ###### Foxtrot 16 | -------------------------------------------------------------------------------- /test/fixtures/maximum-depth-1/output.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | # Table of Contents 4 | 5 | * [Alpha](#alpha) 6 | 7 | # Alpha 8 | 9 | ## Bravo 10 | 11 | ### Charlie 12 | 13 | #### Delta 14 | 15 | ##### Echo 16 | 17 | ###### Foxtrot 18 | -------------------------------------------------------------------------------- /test/fixtures/maximum-depth-3/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "maxDepth": 3 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/maximum-depth-3/input.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | # Table of Contents 4 | 5 | # Alpha 6 | 7 | ## Bravo 8 | 9 | ### Charlie 10 | 11 | #### Delta 12 | 13 | ##### Echo 14 | 15 | ###### Foxtrot 16 | -------------------------------------------------------------------------------- /test/fixtures/maximum-depth-3/output.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | # Table of Contents 4 | 5 | * [Alpha](#alpha) 6 | * [Bravo](#bravo) 7 | * [Charlie](#charlie) 8 | 9 | # Alpha 10 | 11 | ## Bravo 12 | 13 | ### Charlie 14 | 15 | #### Delta 16 | 17 | ##### Echo 18 | 19 | ###### Foxtrot 20 | -------------------------------------------------------------------------------- /test/fixtures/maximum-depth-6/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "maxDepth": 6 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/maximum-depth-6/input.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | # Table of Contents 4 | 5 | # Alpha 6 | 7 | ## Bravo 8 | 9 | ### Charlie 10 | 11 | #### Delta 12 | 13 | ##### Echo 14 | 15 | ###### Foxtrot 16 | -------------------------------------------------------------------------------- /test/fixtures/maximum-depth-6/output.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | # Table of Contents 4 | 5 | * [Alpha](#alpha) 6 | * [Bravo](#bravo) 7 | * [Charlie](#charlie) 8 | * [Delta](#delta) 9 | * [Echo](#echo) 10 | * [Foxtrot](#foxtrot) 11 | 12 | # Alpha 13 | 14 | ## Bravo 15 | 16 | ### Charlie 17 | 18 | #### Delta 19 | 20 | ##### Echo 21 | 22 | ###### Foxtrot 23 | -------------------------------------------------------------------------------- /test/fixtures/missing-content/input.md: -------------------------------------------------------------------------------- 1 | # Missing content 2 | 3 | ## Table of Contents 4 | 5 | --- 6 | -------------------------------------------------------------------------------- /test/fixtures/missing-content/output.md: -------------------------------------------------------------------------------- 1 | # Missing content 2 | 3 | ## Table of Contents 4 | 5 | *** 6 | -------------------------------------------------------------------------------- /test/fixtures/missing-heading/input.md: -------------------------------------------------------------------------------- 1 | # Missing heading 2 | 3 | # Something if 4 | 5 | ## Something else 6 | 7 | Text. 8 | 9 | ## Something elsefi 10 | 11 | # Something iffi 12 | -------------------------------------------------------------------------------- /test/fixtures/missing-heading/output.md: -------------------------------------------------------------------------------- 1 | # Missing heading 2 | 3 | # Something if 4 | 5 | ## Something else 6 | 7 | Text. 8 | 9 | ## Something elsefi 10 | 11 | # Something iffi 12 | -------------------------------------------------------------------------------- /test/fixtures/normal-content/input.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | Here’s some content. 6 | 7 | # Something if 8 | 9 | ## Something else 10 | 11 | Text. 12 | 13 | ## Something elsefi 14 | 15 | # Something iffi 16 | -------------------------------------------------------------------------------- /test/fixtures/normal-content/output.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | * [Something if](#something-if) 6 | * [Something else](#something-else) 7 | * [Something elsefi](#something-elsefi) 8 | * [Something iffi](#something-iffi) 9 | 10 | # Something if 11 | 12 | ## Something else 13 | 14 | Text. 15 | 16 | ## Something elsefi 17 | 18 | # Something iffi 19 | -------------------------------------------------------------------------------- /test/fixtures/normal-dashes/input.md: -------------------------------------------------------------------------------- 1 | # Normal Dashes 2 | 3 | ## Table-of-contents 4 | 5 | # Something if 6 | 7 | ## Something else 8 | 9 | Text. 10 | 11 | ## Something elsefi 12 | 13 | # Something iffi 14 | -------------------------------------------------------------------------------- /test/fixtures/normal-dashes/output.md: -------------------------------------------------------------------------------- 1 | # Normal Dashes 2 | 3 | ## Table-of-contents 4 | 5 | * [Something if](#something-if) 6 | * [Something else](#something-else) 7 | * [Something elsefi](#something-elsefi) 8 | * [Something iffi](#something-iffi) 9 | 10 | # Something if 11 | 12 | ## Something else 13 | 14 | Text. 15 | 16 | ## Something elsefi 17 | 18 | # Something iffi 19 | -------------------------------------------------------------------------------- /test/fixtures/normal-literal-dashes/input.md: -------------------------------------------------------------------------------- 1 | # Normal Dashes 2 | 3 | ## Table-of-contents 4 | 5 | ## Rules 6 | 7 | ### Foo-bar-baz 8 | 9 | ## Alpha-bravo-charlie 10 | -------------------------------------------------------------------------------- /test/fixtures/normal-literal-dashes/output.md: -------------------------------------------------------------------------------- 1 | # Normal Dashes 2 | 3 | ## Table-of-contents 4 | 5 | * [Rules](#rules) 6 | * [Foo-bar-baz](#foo-bar-baz) 7 | * [Alpha-bravo-charlie](#alpha-bravo-charlie) 8 | 9 | ## Rules 10 | 11 | ### Foo-bar-baz 12 | 13 | ## Alpha-bravo-charlie 14 | -------------------------------------------------------------------------------- /test/fixtures/normal-more-content/input.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | Here’s some content. 6 | 7 | Here’s some more content. 8 | 9 | # Something if 10 | 11 | ## Something else 12 | 13 | Text. 14 | 15 | ## Something elsefi 16 | 17 | # Something iffi 18 | -------------------------------------------------------------------------------- /test/fixtures/normal-more-content/output.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | * [Something if](#something-if) 6 | * [Something else](#something-else) 7 | * [Something elsefi](#something-elsefi) 8 | * [Something iffi](#something-iffi) 9 | 10 | # Something if 11 | 12 | ## Something else 13 | 14 | Text. 15 | 16 | ## Something elsefi 17 | 18 | # Something iffi 19 | -------------------------------------------------------------------------------- /test/fixtures/normal-nesting-inverted/input.md: -------------------------------------------------------------------------------- 1 | # Normal with inverted nesting 2 | 3 | ## Table of Contents 4 | 5 | ## Something if 6 | 7 | # Something else 8 | 9 | Text. 10 | 11 | ## Something elsefi 12 | 13 | # Something iffi 14 | -------------------------------------------------------------------------------- /test/fixtures/normal-nesting-inverted/output.md: -------------------------------------------------------------------------------- 1 | # Normal with inverted nesting 2 | 3 | ## Table of Contents 4 | 5 | * * [Something if](#something-if) 6 | * [Something else](#something-else) 7 | * [Something elsefi](#something-elsefi) 8 | * [Something iffi](#something-iffi) 9 | 10 | ## Something if 11 | 12 | # Something else 13 | 14 | Text. 15 | 16 | ## Something elsefi 17 | 18 | # Something iffi 19 | -------------------------------------------------------------------------------- /test/fixtures/normal-singular/input.md: -------------------------------------------------------------------------------- 1 | # Normal with TOC 2 | 3 | ## Table of Content 4 | 5 | # Something if 6 | 7 | ## Something else 8 | 9 | Text. 10 | 11 | ## Something elsefi 12 | 13 | # Something iffi 14 | -------------------------------------------------------------------------------- /test/fixtures/normal-singular/output.md: -------------------------------------------------------------------------------- 1 | # Normal with TOC 2 | 3 | ## Table of Content 4 | 5 | * [Something if](#something-if) 6 | * [Something else](#something-else) 7 | * [Something elsefi](#something-elsefi) 8 | * [Something iffi](#something-iffi) 9 | 10 | # Something if 11 | 12 | ## Something else 13 | 14 | Text. 15 | 16 | ## Something elsefi 17 | 18 | # Something iffi 19 | -------------------------------------------------------------------------------- /test/fixtures/normal-toc/input.md: -------------------------------------------------------------------------------- 1 | # Normal with TOC 2 | 3 | ## TOC 4 | 5 | # Something if 6 | 7 | ## Something else 8 | 9 | Text. 10 | 11 | ## Something elsefi 12 | 13 | # Something iffi 14 | -------------------------------------------------------------------------------- /test/fixtures/normal-toc/output.md: -------------------------------------------------------------------------------- 1 | # Normal with TOC 2 | 3 | ## TOC 4 | 5 | * [Something if](#something-if) 6 | * [Something else](#something-else) 7 | * [Something elsefi](#something-elsefi) 8 | * [Something iffi](#something-iffi) 9 | 10 | # Something if 11 | 12 | ## Something else 13 | 14 | Text. 15 | 16 | ## Something elsefi 17 | 18 | # Something iffi 19 | -------------------------------------------------------------------------------- /test/fixtures/normal/input.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | # Something if 6 | 7 | ## Something else 8 | 9 | Text. 10 | 11 | ## Something elsefi 12 | 13 | # Something iffi 14 | -------------------------------------------------------------------------------- /test/fixtures/normal/output.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | * [Something if](#something-if) 6 | * [Something else](#something-else) 7 | * [Something elsefi](#something-elsefi) 8 | * [Something iffi](#something-iffi) 9 | 10 | # Something if 11 | 12 | ## Something else 13 | 14 | Text. 15 | 16 | ## Something elsefi 17 | 18 | # Something iffi 19 | -------------------------------------------------------------------------------- /test/fixtures/skip/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "skip": "example|notes?" 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/skip/input.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | ## Alpha 6 | 7 | ## Bravo 8 | 9 | ### Example 10 | 11 | ### Note 12 | 13 | ## Charlie 14 | 15 | ### Note 16 | 17 | ## Delta 18 | 19 | ### Examples 20 | 21 | ## Echo 22 | 23 | ### Notes 24 | 25 | ## Foxtrot 26 | 27 | ## Example 28 | -------------------------------------------------------------------------------- /test/fixtures/skip/output.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | * [Alpha](#alpha) 6 | * [Bravo](#bravo) 7 | * [Charlie](#charlie) 8 | * [Delta](#delta) 9 | * [Examples](#examples) 10 | * [Echo](#echo) 11 | * [Foxtrot](#foxtrot) 12 | 13 | ## Alpha 14 | 15 | ## Bravo 16 | 17 | ### Example 18 | 19 | ### Note 20 | 21 | ## Charlie 22 | 23 | ### Note 24 | 25 | ## Delta 26 | 27 | ### Examples 28 | 29 | ## Echo 30 | 31 | ### Notes 32 | 33 | ## Foxtrot 34 | 35 | ## Example 36 | -------------------------------------------------------------------------------- /test/fixtures/slug-for-images-and-links/input.md: -------------------------------------------------------------------------------- 1 | # Slugs for images and links 2 | 3 | ## Table of Contents 4 | 5 | # [Something if](http://a-link.com) 6 | 7 | ## ![Something else](an-image.svg) 8 | 9 | Text. 10 | 11 | ## ![](an-alt.jpeg "Something elsefi") 12 | 13 | # [![Something iffi](a-link.png "a title")](http://a-link.com "another title") 14 | -------------------------------------------------------------------------------- /test/fixtures/slug-for-images-and-links/output.md: -------------------------------------------------------------------------------- 1 | # Slugs for images and links 2 | 3 | ## Table of Contents 4 | 5 | * [Something if](#something-if) 6 | * [![Something else](an-image.svg)](#) 7 | * [![](an-alt.jpeg "Something elsefi")](#-1) 8 | * [![Something iffi](a-link.png "a title")](#-2) 9 | 10 | # [Something if](http://a-link.com) 11 | 12 | ## ![Something else](an-image.svg) 13 | 14 | Text. 15 | 16 | ## ![](an-alt.jpeg "Something elsefi") 17 | 18 | # [![Something iffi](a-link.png "a title")](http://a-link.com "another title") 19 | -------------------------------------------------------------------------------- /test/fixtures/tight/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "tight": true 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/tight/input.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | # Something if 6 | 7 | ## Something else 8 | 9 | Text. 10 | 11 | ## Something elsefi 12 | 13 | ### Yet Another Thing 14 | 15 | ### And another thing 16 | 17 | # Something iffi 18 | -------------------------------------------------------------------------------- /test/fixtures/tight/output.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | * [Something if](#something-if) 6 | * [Something else](#something-else) 7 | * [Something elsefi](#something-elsefi) 8 | * [Yet Another Thing](#yet-another-thing) 9 | * [And another thing](#and-another-thing) 10 | * [Something iffi](#something-iffi) 11 | 12 | # Something if 13 | 14 | ## Something else 15 | 16 | Text. 17 | 18 | ## Something elsefi 19 | 20 | ### Yet Another Thing 21 | 22 | ### And another thing 23 | 24 | # Something iffi 25 | -------------------------------------------------------------------------------- /test/fixtures/unicode/input.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | # I ♥ unicode. 6 | -------------------------------------------------------------------------------- /test/fixtures/unicode/output.md: -------------------------------------------------------------------------------- 1 | # Normal 2 | 3 | ## Table of Contents 4 | 5 | * [I ♥ unicode.](#i--unicode) 6 | 7 | # I ♥ unicode. 8 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {import('remark-toc').Options} Options 3 | */ 4 | 5 | import assert from 'node:assert/strict' 6 | import fs from 'node:fs/promises' 7 | import process from 'node:process' 8 | import test from 'node:test' 9 | import {isHidden} from 'is-hidden' 10 | import {remark} from 'remark' 11 | import remarkToc from 'remark-toc' 12 | 13 | test('remarkToc', async function (t) { 14 | await t.test('should expose the public api', async function () { 15 | assert.deepEqual(Object.keys(await import('remark-toc')).sort(), [ 16 | 'default' 17 | ]) 18 | }) 19 | }) 20 | 21 | test('fixtures', async function (t) { 22 | const base = new URL('fixtures/', import.meta.url) 23 | const folders = await fs.readdir(base) 24 | 25 | let index = -1 26 | 27 | while (++index < folders.length) { 28 | const folder = folders[index] 29 | 30 | if (isHidden(folder)) continue 31 | 32 | await t.test(folder, async function () { 33 | const folderUrl = new URL(folder + '/', base) 34 | const inputUrl = new URL('input.md', folderUrl) 35 | const outputUrl = new URL('output.md', folderUrl) 36 | const configUrl = new URL('config.json', folderUrl) 37 | 38 | const input = String(await fs.readFile(inputUrl)) 39 | 40 | /** @type {Options | undefined} */ 41 | let config 42 | /** @type {string} */ 43 | let output 44 | 45 | try { 46 | config = JSON.parse(String(await fs.readFile(configUrl))) 47 | } catch {} 48 | 49 | const proc = remark().use(remarkToc, config) 50 | 51 | const actual = String(await proc.process(input)) 52 | 53 | try { 54 | if ('UPDATE' in process.env) { 55 | throw new Error('Updating…') 56 | } 57 | 58 | output = String(await fs.readFile(outputUrl)) 59 | } catch { 60 | output = actual 61 | await fs.writeFile(outputUrl, actual) 62 | } 63 | 64 | assert.equal(actual, String(output)) 65 | }) 66 | } 67 | }) 68 | -------------------------------------------------------------------------------- /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"] 15 | } 16 | --------------------------------------------------------------------------------