From aa9a1cc7cef935a78b8f4005669e41ff53cb8b7a Mon Sep 17 00:00:00 2001 From: Chris Maas Date: Tue, 10 Sep 2024 16:46:09 +0200 Subject: [PATCH] 0.8.0 - Added function getTokensText similar to how it's done in markdown-it-anchor to support other ways of text extraction (fixes #61) --- CHANGELOG.md | 7 ++++++- README.md | 27 +++++++++++++++------------ index.js | 18 ++++++++++++++---- package.json | 2 +- test/modules/test.js | 13 +++++++++++++ 5 files changed, 49 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 773cd34..650eacd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,12 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -– +## [0.8.0] - 2024-09-10 + +* **Added:** Option `getTokensText` to override how text is extracted from tokens to build headlines and slugs (fixes #61), similar to the function in markdown-it-anchor. + +*** ## [0.7.0] - 2024-09-09 * **Added:** Override the container element * ⚠️ **BREAKING CHANGE:** The plugin moved from *inline mode* to *block mode* (fixes #62) +* **Changed:** Updated tests, readme etc. * **Removed:** Old forceFullToc attribute *** diff --git a/README.md b/README.md index f125bc0..58ffa63 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # markdown-it-table-of-contents -A table of contents plugin for Markdown-it. Simple, customizable and with a default slugifier that matches that of https://www.npmjs.com/package/markdown-it-anchor (>5.0.0). +A table of contents plugin for Markdown-it. Simple, customizable and with a default slugifier that matches that of [markdown-it-anchor](https://www.npmjs.com/package/markdown-it-anchor) (>5.0.0). ## Usage @@ -64,17 +64,18 @@ These options are available: Name | Description | Default -----------------------|-------------------------------------------------------------------------------------|------------------------------------ -"includeLevel" | Headings levels to use (2 for h2:s etc) | [1, 2] -"containerClass" | The class for the container DIV | "table-of-contents" -"slugify" | A custom slugification function | `encodeURIComponent(String(s).trim().toLowerCase().replace(/\s+/g, '-'))` -"markerPattern" | Regex pattern of the marker to be replaced with TOC | `/^\[\[toc\]\]/im` -"listType" | Type of list (`ul` for unordered, `ol` for ordered) | `ul` -"format" | A function for formatting headings (see below) | `md.renderInline(content)` -"containerHeaderHtml" | Optional HTML string for container header | `undefined` -"containerFooterHtml" | Optional HTML string for container footer | `undefined` -"transformLink" | A function for transforming the TOC links | `undefined` -"transformContainerOpen"| A function for transforming the container opening tag | (see source code) -"transformContainerClose"| A function for transforming the container closing tag | (see source code) +`includeLevel` | Headings levels to use (2 for h2:s etc) | [1, 2] +`containerClass` | The class for the container DIV | "table-of-contents" +`slugify` | A custom slugification function | `encodeURIComponent(String(s).trim().toLowerCase().replace(/\s+/g, '-'))` +`markerPattern` | Regex pattern of the marker to be replaced with TOC | `/^\[\[toc\]\]/im` +`listType` | Type of list (`ul` for unordered, `ol` for ordered) | `ul` +`format` | A function for formatting headings (see below) | `md.renderInline(content)` +`containerHeaderHtml` | Optional HTML string for container header | `undefined` +`containerFooterHtml` | Optional HTML string for container footer | `undefined` +`transformLink` | A function for transforming the TOC links | `undefined` +`transformContainerOpen`| A function for transforming the container opening tag | (see source code) +`transformContainerClose`| A function for transforming the container closing tag | (see source code) +`getTokensText` | A function for extracting text from tokens for titles | (see source code) `format` is an optional function for changing how the headings are displayed in the TOC. @@ -112,6 +113,8 @@ md.use(markdownItTOC, { }); ``` +`getTokensText` is a function that can be used to change how text is extracted from tokens to support more ways how headlines are build. See source code for more information or the equivalent function in [markdown-it-anchor](https://www.npmjs.com/package/markdown-it-anchor). + ## Recommended plugins By default, markdown-it-table-of-contents collects all headings and renders a nested list. It uses the `slugify()` function to create anchor targets for the links in the list. However, the headlines in your markdown document are not touched by markdown-it-table-of-contents. You'd have a nice table of contents, but the links don't link to anything. That's why you need another plugin to generate ids (anchor link targets) for all of your headlines. There are two recommended plugins to achieve this: diff --git a/index.js b/index.js index b109595..0e041c6 100644 --- a/index.js +++ b/index.js @@ -43,7 +43,8 @@ const defaultOptions = { containerFooterHtml: undefined, transformLink: undefined, transformContainerOpen: transformContainerOpen, - transformContainerClose: transformContainerClose + transformContainerClose: transformContainerClose, + getTokensText: getTokensText }; /** @@ -62,6 +63,17 @@ const defaultOptions = { * @property {TocItem} parent Parent this item belongs to */ +/** + * Helper to extract text from tokens, same function as in markdown-it-anchor + * @returns {string} + */ +function getTokensText(tokens) { + return tokens + .filter(t => ['text', 'code_inline'].includes(t.type)) + .map(t => t.content) + .join(''); +} + /** * Finds all headline items for the defined levels in a Markdown document. * @param {Array} levels includeLevels like `[1, 2, 3]` @@ -86,9 +98,7 @@ function findHeadlineElements(levels, tokens, options) { } } else if (currentHeading && token.type === 'inline') { - const textContent = token.children - .filter((childToken) => childToken.type === 'text' || childToken.type === 'code_inline') - .reduce((acc, t) => acc + t.content, ''); + const textContent = options.getTokensText(token.children); currentHeading.text = textContent; if (!currentHeading.anchor) { currentHeading.anchor = options.slugify(textContent, token.content); diff --git a/package.json b/package.json index 0d381a7..3a834b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "license": "MIT", - "version": "0.7.0", + "version": "0.8.0", "name": "markdown-it-table-of-contents", "main": "index.js", "scripts": { diff --git a/test/modules/test.js b/test/modules/test.js index 1dd2ed3..f8f7bce 100644 --- a/test/modules/test.js +++ b/test/modules/test.js @@ -304,4 +304,17 @@ describe('Testing Markdown rendering', function () { assert.equal(adjustEOL(md.render(basicMarkdown)), basicHTML); done(); }); + + it('getTokensText', function (done) { + const md = new MarkdownIt(); + md.use(markdownItTOC, { + getTokensText: tokens => tokens.filter(t => ['text', 'image'].includes(t.type)).map(t => t.content).join('') + }); + assert.equal( + md.render('# H1 ![image](link) `code` _em_' + '\n' + '[[toc]]'), + '

H1 image code em

\n' + + '\n' + ); + done(); + }); });