remark-flexible-toc 1.2.5 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 ipikuka
3
+ Copyright (c) 2026 ipikuka
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,18 +1,11 @@
1
+ # remark-flexible-toc
2
+
1
3
  **A robust Next.js newsletter `Next.js Weekly` is sponsoring me** 💖
2
4
  [![NextjsWeekly banner](./assets/next-js-weekly.png)](https://nextjsweekly.com/)
3
5
 
4
- ### [Become a sponsor](https://github.com/sponsors/ipikuka) 🚀
5
-
6
- If you find **`remark-flexible-toc`** useful in your projects, consider supporting my work.
7
- Your sponsorship means a lot 💖
8
-
9
- My sponsors are going to be featured here and on [my sponsor wall](https://github.com/sponsors/ipikuka).
6
+ A warm thanks 🙌 to [@ErfanEbrahimnia](https://github.com/ErfanEbrahimnia), [@recepkyk](https://github.com/recepkyk), and [@LSeaburg](https://github.com/LSeaburg) for the [support](https://github.com/sponsors/ipikuka) 💖
10
7
 
11
- A warm thanks 🙌 to [@ErfanEbrahimnia](https://github.com/ErfanEbrahimnia), [@recepkyk](https://github.com/recepkyk), and [@LSeaburg](https://github.com/LSeaburg) for the support!
12
-
13
- Thank you for supporting open source! 🙌
14
-
15
- # remark-flexible-toc
8
+ ---
16
9
 
17
10
  [![npm version][badge-npm-version]][url-npm-package]
18
11
  [![npm downloads][badge-npm-download]][url-npm-package]
@@ -298,7 +291,7 @@ type TocItem = {
298
291
  ```
299
292
 
300
293
  > [!NOTE]
301
- > If there is a remark plugin before **`remark-flexible-toc`** in the plugin chain, which provides custom id for headings like **`remark-heading-id`**, that custom id takes precedence for `href`.
294
+ > If there is a remark plugin before **`remark-flexible-toc`** in the plugin chain like **`remark-heading-id`** or **`remark-custom-header-id`**, which provides custom id for headings, that custom id takes precedence for `href`.
302
295
 
303
296
  **`remark-flexible-toc`** uses **`github-slugger`** internally for producing unique links. Then, it is possible you to use [**rehype-slug**][rehype-slug] (forIDs on headings) and [**rehype-autolink-headings**][rehype-autolink-headings] (for anchors that link-to-self) because they use the same **`github-slugger`**.
304
297
 
@@ -402,6 +395,14 @@ Use of **`remark-flexible-toc`** does not involve rehype (hast) or user content
402
395
 
403
396
  I like to contribute the Unified / Remark / MDX ecosystem, so I recommend you to have a look my plugins.
404
397
 
398
+ ### Support My Work ([become a sponsor](https://github.com/sponsors/ipikuka) 🚀)
399
+
400
+ If you find **`remark-flexible-toc`** or any of my projects is useful and helpful, please consider supporting my work. Your sponsorship means a lot to me and keeps these projects alive and updated! 💖
401
+
402
+ My sponsors are going to be featured at the very top of the page and proudly displayed on my [Sponsor Wall](https://github.com/sponsors/ipikuka).
403
+
404
+ Thank you for supporting open source! 🙌
405
+
405
406
  ### My Remark Plugins
406
407
 
407
408
  - [`remark-flexible-code-titles`](https://www.npmjs.com/package/remark-flexible-code-titles)
@@ -449,6 +450,15 @@ I like to contribute the Unified / Remark / MDX ecosystem, so I recommend you to
449
450
  - [`recma-mdx-interpolate`](https://www.npmjs.com/package/recma-mdx-interpolate)
450
451
  – Recma plugin to enable interpolation of identifiers wrapped in curly braces within the `alt`, `src`, `href`, and `title` attributes of markdown link and image syntax in MDX.
451
452
 
453
+ ### My Unist Utils and Unified Plugins
454
+
455
+ I also build low-level utilities and plugins for the Unified ecosystem that can be used across Remark, Rehype, Recma, and other unist-based abstract syntax trees (ASTs).
456
+
457
+ - [`unist-util-find-between`](https://www.npmjs.com/package/unist-util-find-between)
458
+ – Unist utility to find the nodes between two nodes.
459
+ - [`unified-log-tree`](https://www.npmjs.com/package/unified-log-tree)
460
+ – Unified plugin to log abstract syntax trees (ASTs) for debugging without mutating.
461
+
452
462
  ## License
453
463
 
454
464
  [MIT License](./LICENSE) © ipikuka
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { type Plugin } from "unified";
2
- import { type Root } from "mdast";
1
+ import type { Plugin } from "unified";
2
+ import type { Root } from "mdast";
3
3
  export type Prettify<T> = {
4
4
  [K in keyof T]: T[K];
5
5
  } & {};
@@ -12,7 +12,9 @@ export type TocItem = {
12
12
  depth: HeadingDepth;
13
13
  numbering: number[];
14
14
  parent: HeadingParent;
15
- data?: Record<string, unknown>;
15
+ data?: {
16
+ [PropertyName: string]: string | number | boolean | (string | number)[] | null | undefined;
17
+ };
16
18
  };
17
19
  /**
18
20
  * tocName (default: "toc") - the key name which is attached into vfile.data
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,KAAK,IAAI,EAAoB,MAAM,OAAO,CAAC;AAKpD,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAC;AAExD,MAAM,MAAM,iBAAiB,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAExF,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,YAAY,GACZ,oBAAoB,GACpB,UAAU,GACV,WAAW,GACX,mBAAmB,CAAC;AAExB,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEjD,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,EAAE,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,SAAS,CAAC;CAC1C,CAAC;AA8DF,QAAA,MAAM,iBAAiB,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAAE,IAAI,CAiF1D,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAKlC,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAC;AAExD,MAAM,MAAM,iBAAiB,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAExF,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,YAAY,GACZ,oBAAoB,GACpB,UAAU,GACV,WAAW,GACX,mBAAmB,CAAC;AAExB,MAAM,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAEjD,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,CAAC,EAAE;QACL,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;KAC5F,CAAC;CACH,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE,MAAM,CAAC,EAAE,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,SAAS,CAAC;CAC1C,CAAC;AA4DF,QAAA,MAAM,iBAAiB,EAAE,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC,EAAE,IAAI,CAmF1D,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -78,9 +78,10 @@ const RemarkFlexibleToc = (options) => {
78
78
  return CONTINUE;
79
79
  // Other remark plugins can store custom data in node.data.hProperties
80
80
  // I omitted node.data.hName and node.data.hChildren since not related with toc
81
- const data = _node.data?.hProperties
82
- ? { ..._node.data.hProperties }
83
- : undefined;
81
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
82
+ // @ts-ignore, vscode resolves the type but tsc build raises an error awkwardly, saying "hProperties" does not exist in "HeadingData".
83
+ const hProperties = _node.data?.hProperties;
84
+ const data = hProperties ? { ...hProperties } : undefined;
84
85
  if (data?.["id"])
85
86
  href = `#${data["id"]}`;
86
87
  tocItems.push({
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Plugin } from \"unified\";\nimport { type Root, type HeadingData } from \"mdast\";\nimport { visit, CONTINUE } from \"unist-util-visit\";\nimport GithubSlugger from \"github-slugger\";\nimport { toString } from \"mdast-util-to-string\";\n\nexport type Prettify<T> = { [K in keyof T]: T[K] } & {};\n\nexport type PartiallyRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;\n\nexport type HeadingParent =\n | \"root\"\n | \"blockquote\"\n | \"footnoteDefinition\"\n | \"listItem\"\n | \"container\"\n | \"mdxJsxFlowElement\";\n\nexport type HeadingDepth = 1 | 2 | 3 | 4 | 5 | 6;\n\nexport type TocItem = {\n value: string;\n href: string;\n depth: HeadingDepth;\n numbering: number[];\n parent: HeadingParent;\n data?: Record<string, unknown>;\n};\n\n/**\n * tocName (default: \"toc\") - the key name which is attached into vfile.data\n * tocRef (default: []) — another way of exposing the tocItems\n * maxDepth (default: 6) — max heading depth to include in the table of contents; this is inclusive: when set to 3, level three headings are included\n * skipLevels (default: [1]) — disallowed heading levels, by default the article h1 is not expected to be in the TOC\n * skipParents (default: []) — disallow headings to be children of certain node types, (the \"root\" can not be skipped)\n * exclude — headings to skip, wrapped in new RegExp('^(' + value + ')$', 'i'); any heading matching this expression will not be present in the table of contents\n * prefix - the text that will be attached to headings as prefix, like \"text-prefix-\"\n * callback - It is a callback function to take the array of toc items as an argument\n */\nexport type FlexibleTocOptions = {\n tocName?: string;\n tocRef?: TocItem[];\n maxDepth?: HeadingDepth;\n skipLevels?: HeadingDepth[];\n skipParents?: Exclude<HeadingParent, \"root\">[];\n exclude?: string | string[];\n prefix?: string;\n callback?: (toc: TocItem[]) => undefined;\n};\n\ntype PartiallyRequiredFlexibleTocOptions = Prettify<\n PartiallyRequired<\n FlexibleTocOptions,\n \"tocName\" | \"tocRef\" | \"maxDepth\" | \"skipLevels\" | \"skipParents\"\n >\n>;\n\nconst DEFAULT_SETTINGS: FlexibleTocOptions = {\n tocName: \"toc\",\n tocRef: [],\n maxDepth: 6,\n skipLevels: [1],\n skipParents: [],\n};\n\ntype ExtendedHeadingData = HeadingData & { hProperties: Record<string, unknown> };\n\n/**\n * adds numberings to the TOC items.\n * why \"number[]\"? It is because up to you joining with dot or dash or slicing the first number (reserved for h1)\n *\n * [1]\n * [1,1]\n * [1,2]\n * [1,2,1]\n */\nfunction addNumbering(arr: TocItem[]) {\n for (let i = 0; i < arr.length; i++) {\n const tocItem = arr[i];\n const depth = tocItem.depth;\n\n let numbering: number[];\n\n const prevObj = i > 0 ? arr[i - 1] : undefined;\n const prevDepth = prevObj ? prevObj.depth : undefined;\n const prevNumbering = prevObj ? prevObj.numbering : undefined;\n\n if (!prevNumbering || !prevDepth) {\n numbering = Array.from({ length: depth }, () => 1);\n } else if (depth === prevDepth) {\n numbering = [...prevNumbering];\n numbering[depth - 1]++;\n } else if (depth > prevDepth) {\n numbering = [\n ...prevNumbering,\n ...(Array.from(\n { length: depth - prevDepth }, // if depth is more bigger than prevDepth, put more \"1\" inside the array\n () => 1,\n ) as HeadingDepth[]),\n ];\n } else {\n // if (depth < prevDepth)\n numbering = prevNumbering.slice(0, depth);\n numbering[depth - 1]++;\n }\n\n tocItem.numbering = numbering;\n }\n}\n\nconst RemarkFlexibleToc: Plugin<[FlexibleTocOptions?], Root> = (options) => {\n const settings = Object.assign(\n {},\n DEFAULT_SETTINGS,\n options,\n ) as PartiallyRequiredFlexibleTocOptions;\n\n const exludeRegexFilter =\n settings.exclude &&\n (Array.isArray(settings.exclude)\n ? new RegExp(\"^(\" + settings.exclude.join(\"|\") + \")$\", \"i\")\n : new RegExp(\"^(\" + settings.exclude + \")$\", \"i\"));\n\n return (tree, file) => {\n const slugger = new GithubSlugger();\n const tocItems: TocItem[] = [];\n\n visit(tree, \"heading\", (_node, _index, _parent) => {\n /* v8 ignore next -- @preserve */\n if (!_parent || typeof _index === \"undefined\") return;\n\n const depth = _node.depth;\n const value = toString(_node, { includeImageAlt: false });\n let href = `#${settings.prefix ?? \"\"}${slugger.slug(value)}`;\n const parent = _parent.type;\n\n // maxDepth check\n if (depth > settings.maxDepth) return CONTINUE;\n\n // skipLevels check\n if (settings.skipLevels.includes(depth)) return CONTINUE;\n\n // skipParents check\n if (parent !== \"root\" && settings.skipParents.includes(parent)) return CONTINUE;\n\n // exclude check\n if (exludeRegexFilter && exludeRegexFilter.test(value)) return CONTINUE;\n\n // Other remark plugins can store custom data in node.data.hProperties\n // I omitted node.data.hName and node.data.hChildren since not related with toc\n const data = (_node.data as ExtendedHeadingData)?.hProperties\n ? { ...(_node.data as ExtendedHeadingData).hProperties }\n : undefined;\n\n if (data?.[\"id\"]) href = `#${data[\"id\"]}`;\n\n tocItems.push({\n value,\n href,\n depth,\n numbering: [],\n parent,\n ...(data && { data }),\n });\n\n return CONTINUE;\n });\n\n addNumbering(tocItems);\n\n // it is allowed to modify the TOC in the callback\n settings.callback?.(tocItems);\n\n // method - 1 for exposing the data via vfile.data **************************\n\n // other plugins are not allowed to mutate the exposed TOC\n // The spreading is slower than push but need to fresh copy\n file.data[settings.tocName] = [...tocItems];\n\n // method - 2 for exposing the data via reference array *********************\n\n if (options?.tocRef) {\n // prevent dublication if the plugin is called more than once\n settings.tocRef.length = 0;\n\n tocItems.forEach((tocItem) => {\n // the tocRef is not allowed to mutate the vfile.data.toc\n settings.tocRef.push(tocItem);\n });\n }\n };\n};\n\nexport default RemarkFlexibleToc;\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Plugin } from \"unified\";\nimport type { Root } from \"mdast\";\nimport { visit, CONTINUE } from \"unist-util-visit\";\nimport GithubSlugger from \"github-slugger\";\nimport { toString } from \"mdast-util-to-string\";\n\nexport type Prettify<T> = { [K in keyof T]: T[K] } & {};\n\nexport type PartiallyRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;\n\nexport type HeadingParent =\n | \"root\"\n | \"blockquote\"\n | \"footnoteDefinition\"\n | \"listItem\"\n | \"container\"\n | \"mdxJsxFlowElement\";\n\nexport type HeadingDepth = 1 | 2 | 3 | 4 | 5 | 6;\n\nexport type TocItem = {\n value: string;\n href: string;\n depth: HeadingDepth;\n numbering: number[];\n parent: HeadingParent;\n data?: {\n [PropertyName: string]: string | number | boolean | (string | number)[] | null | undefined;\n };\n};\n\n/**\n * tocName (default: \"toc\") - the key name which is attached into vfile.data\n * tocRef (default: []) — another way of exposing the tocItems\n * maxDepth (default: 6) — max heading depth to include in the table of contents; this is inclusive: when set to 3, level three headings are included\n * skipLevels (default: [1]) — disallowed heading levels, by default the article h1 is not expected to be in the TOC\n * skipParents (default: []) — disallow headings to be children of certain node types, (the \"root\" can not be skipped)\n * exclude — headings to skip, wrapped in new RegExp('^(' + value + ')$', 'i'); any heading matching this expression will not be present in the table of contents\n * prefix - the text that will be attached to headings as prefix, like \"text-prefix-\"\n * callback - It is a callback function to take the array of toc items as an argument\n */\nexport type FlexibleTocOptions = {\n tocName?: string;\n tocRef?: TocItem[];\n maxDepth?: HeadingDepth;\n skipLevels?: HeadingDepth[];\n skipParents?: Exclude<HeadingParent, \"root\">[];\n exclude?: string | string[];\n prefix?: string;\n callback?: (toc: TocItem[]) => undefined;\n};\n\ntype PartiallyRequiredFlexibleTocOptions = Prettify<\n PartiallyRequired<\n FlexibleTocOptions,\n \"tocName\" | \"tocRef\" | \"maxDepth\" | \"skipLevels\" | \"skipParents\"\n >\n>;\n\nconst DEFAULT_SETTINGS: FlexibleTocOptions = {\n tocName: \"toc\",\n tocRef: [],\n maxDepth: 6,\n skipLevels: [1],\n skipParents: [],\n};\n\n/**\n * adds numberings to the TOC items.\n * why \"number[]\"? It is because up to you joining with dot or dash or slicing the first number (reserved for h1)\n *\n * [1]\n * [1,1]\n * [1,2]\n * [1,2,1]\n */\nfunction addNumbering(arr: TocItem[]) {\n for (let i = 0; i < arr.length; i++) {\n const tocItem = arr[i];\n const depth = tocItem.depth;\n\n let numbering: number[];\n\n const prevObj = i > 0 ? arr[i - 1] : undefined;\n const prevDepth = prevObj ? prevObj.depth : undefined;\n const prevNumbering = prevObj ? prevObj.numbering : undefined;\n\n if (!prevNumbering || !prevDepth) {\n numbering = Array.from({ length: depth }, () => 1);\n } else if (depth === prevDepth) {\n numbering = [...prevNumbering];\n numbering[depth - 1]++;\n } else if (depth > prevDepth) {\n numbering = [\n ...prevNumbering,\n ...(Array.from(\n { length: depth - prevDepth }, // if depth is more bigger than prevDepth, put more \"1\" inside the array\n () => 1,\n ) as HeadingDepth[]),\n ];\n } else {\n // if (depth < prevDepth)\n numbering = prevNumbering.slice(0, depth);\n numbering[depth - 1]++;\n }\n\n tocItem.numbering = numbering;\n }\n}\n\nconst RemarkFlexibleToc: Plugin<[FlexibleTocOptions?], Root> = (options) => {\n const settings = Object.assign(\n {},\n DEFAULT_SETTINGS,\n options,\n ) as PartiallyRequiredFlexibleTocOptions;\n\n const exludeRegexFilter =\n settings.exclude &&\n (Array.isArray(settings.exclude)\n ? new RegExp(\"^(\" + settings.exclude.join(\"|\") + \")$\", \"i\")\n : new RegExp(\"^(\" + settings.exclude + \")$\", \"i\"));\n\n return (tree, file) => {\n const slugger = new GithubSlugger();\n const tocItems: TocItem[] = [];\n\n visit(tree, \"heading\", (_node, _index, _parent) => {\n /* v8 ignore next -- @preserve */\n if (!_parent || typeof _index === \"undefined\") return;\n\n const depth = _node.depth;\n const value = toString(_node, { includeImageAlt: false });\n let href = `#${settings.prefix ?? \"\"}${slugger.slug(value)}`;\n const parent = _parent.type;\n\n // maxDepth check\n if (depth > settings.maxDepth) return CONTINUE;\n\n // skipLevels check\n if (settings.skipLevels.includes(depth)) return CONTINUE;\n\n // skipParents check\n if (parent !== \"root\" && settings.skipParents.includes(parent)) return CONTINUE;\n\n // exclude check\n if (exludeRegexFilter && exludeRegexFilter.test(value)) return CONTINUE;\n\n // Other remark plugins can store custom data in node.data.hProperties\n // I omitted node.data.hName and node.data.hChildren since not related with toc\n\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore, vscode resolves the type but tsc build raises an error awkwardly, saying \"hProperties\" does not exist in \"HeadingData\".\n const hProperties = _node.data?.hProperties;\n const data = hProperties ? { ...hProperties } : undefined;\n\n if (data?.[\"id\"]) href = `#${data[\"id\"]}`;\n\n tocItems.push({\n value,\n href,\n depth,\n numbering: [],\n parent,\n ...(data && { data }),\n });\n\n return CONTINUE;\n });\n\n addNumbering(tocItems);\n\n // it is allowed to modify the TOC in the callback\n settings.callback?.(tocItems);\n\n // method - 1 for exposing the data via vfile.data **************************\n\n // other plugins are not allowed to mutate the exposed TOC\n // The spreading is slower than push but need to fresh copy\n file.data[settings.tocName] = [...tocItems];\n\n // method - 2 for exposing the data via reference array *********************\n\n if (options?.tocRef) {\n // prevent dublication if the plugin is called more than once\n settings.tocRef.length = 0;\n\n tocItems.forEach((tocItem) => {\n // the tocRef is not allowed to mutate the vfile.data.toc\n settings.tocRef.push(tocItem);\n });\n }\n };\n};\n\nexport default RemarkFlexibleToc;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remark-flexible-toc",
3
- "version": "1.2.5",
3
+ "version": "1.2.6",
4
4
  "description": "Remark plugin to expose the table of contents via Vfile.data or via an option reference",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -13,7 +13,7 @@
13
13
  }
14
14
  },
15
15
  "scripts": {
16
- "build": "rimraf dist && tsc --build && type-coverage",
16
+ "build": "rimraf dist && tsc --build tsconfig.build.json && type-coverage",
17
17
  "format": "npm run prettier && npm run lint",
18
18
  "prettier": "prettier --write .",
19
19
  "lint": "eslint .",
@@ -54,28 +54,27 @@
54
54
  },
55
55
  "devDependencies": {
56
56
  "@eslint/js": "^10.0.1",
57
- "@types/node": "^24.10.13",
58
- "@types/remark-heading-id": "^1.0.0",
59
- "@vitest/coverage-v8": "^4.0.18",
60
- "@vitest/eslint-plugin": "^1.6.9",
61
- "dedent": "^1.7.1",
62
- "eslint": "^10.0.0",
57
+ "@types/node": "^24.12.4",
58
+ "@vitest/coverage-v8": "^4.1.7",
59
+ "@vitest/eslint-plugin": "^1.6.18",
60
+ "dedent": "^1.7.2",
61
+ "eslint": "^10.4.0",
63
62
  "eslint-config-prettier": "^10.1.8",
64
63
  "eslint-plugin-prettier": "^5.5.5",
65
- "globals": "^17.3.0",
66
- "prettier": "^3.8.1",
64
+ "globals": "^17.6.0",
65
+ "prettier": "^3.8.3",
67
66
  "rehype-format": "^5.0.1",
68
67
  "rehype-stringify": "^10.0.1",
68
+ "remark-custom-header-id": "^1.0.0",
69
69
  "remark-gfm": "^4.0.1",
70
- "remark-heading-id": "^1.0.1",
71
70
  "remark-parse": "^11.0.0",
72
71
  "remark-rehype": "^11.1.2",
73
72
  "rimraf": "^6.1.3",
74
73
  "type-coverage": "^2.29.7",
75
74
  "typescript": "^5.9.3",
76
- "typescript-eslint": "^8.56.0",
75
+ "typescript-eslint": "^8.60.0",
77
76
  "unified": "^11.0.5",
78
- "vitest": "^4.0.18"
77
+ "vitest": "^4.1.7"
79
78
  },
80
79
  "dependencies": {
81
80
  "@types/mdast": "^4.0.4",
@@ -1 +0,0 @@
1
- {"root":["../src/index.ts"],"version":"5.9.3"}