Leading content replaced by TOC if I don't have a heading before it
dereckmezquita opened this issue · comments
Initial checklist
- I read the support docs
- I read the contributing guide
- I agree to follow the code of conduct
- I searched issues and couldn’t find anything (or linked relevant results below)
Affected packages and versions
^10.1.0
Link to runnable example
No response
Steps to reproduce
If I have my markdown with a TOC insertion point and content directly below it without a header then any content until the next header is removed and replaced with the TOC:
---
title: "Hierarchy in art"
published: true
---
## Table of contents
Here is some content that will get removed.
## test
Some more content.
However, if I do this then my content doesn't get removed:
---
title: "Hierarchy in art"
published: true
---
## Table of contents
## some header any header here even an empty one protects content
Here is some content that will get removed.
## test
Some more content.
Is there a way I can avoid losing that content there? I have my h1 generated from the yaml in my markdown and only want to insert the TOC for any lower level headers h2 etc.
I don't necessarily need my leading content to have a header as this is my de facto introduction etc.
You can consult my source code here; note this is a work in progress: https://github.com/dereckmezquita/derecksnotes.com/tree/v3-nextjs-refactor/client-next
Expected behavior
If I place a TOC header and no following headers then the content should not be removed instead a TOC should be inserted.
Actual behavior
If there is not header after a TOC insertion point and there is content directly after, then any content before the next header gets removed.
Runtime
Node v16
Package manager
npm 8
OS
macOS
Build and bundle tools
Next.js
Duplicate of #18
Hi! This was closed. Team: If this was fixed, please add phase/solved
. Otherwise, please add one of the no/*
labels.
Hi! Thanks for taking the time to contribute!
Because we treat issues as our backlog, we close duplicates to focus our work and not have to touch the same chunk of code for the same reason multiple times. This is also why we may mark something as duplicate that isn’t an exact duplicate but is closely related.
Thanks,
— bb
I posted this a while ago because I was not happy with remarkToc
; I was not happy with the rigidity - unfortunately, we can't have more options.
I created my own remark plugin using the underlying dependency mdast-util-toc
; sharing for others to use:
import { toc, Options as TocOptions } from 'mdast-util-toc';
import { Root } from 'mdast';
import { Node } from 'mdast-util-toc/lib'
import { Plugin } from 'unified';
interface RemarkTocCollapseOptions extends TocOptions {
heading?: string;
}
/**
* Plugin to generate a Table of Contents (TOC); does not remove leading paragraphs without headers.
*/
const remarkToc: Plugin<[(RemarkTocOptions | undefined)?], Root> = (options = {}) => {
return (node: Node) => {
const result = toc(
node as Root,
Object.assign({}, options, {
heading: options.heading || 'toc|table[ -]of[ -]contents?',
tight: true,
maxDepth: 10
})
);
if (
result.endIndex === null ||
result.index === null ||
result.index === -1 ||
!result.map
) {
return;
}
// I don't want remarkToc to remove leading paragraphs with no headers
if ('children' in node) {
node.children = [
...node.children.slice(0, result.index),
result.map,
...node.children.slice(result.index)
];
}
};
};
export default remarkToc;
That algorithm unfortunately doesn’t support repeated calls: it would keep on adding tables of contents repeatedly.