toc.ts 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import { toc } from 'mdast-util-toc';
  2. import { remark } from 'remark';
  3. import { visit } from 'unist-util-visit';
  4. const textTypes = ['text', 'emphasis', 'strong', 'inlineCode'];
  5. function flattenNode(node: any) {
  6. const p: any[] = [];
  7. visit(node, (node) => {
  8. if (!textTypes.includes(node.type)) {
  9. return;
  10. }
  11. p.push(node.value);
  12. });
  13. return p.join('');
  14. }
  15. interface Item {
  16. title: string;
  17. url: string;
  18. items?: Item[];
  19. }
  20. interface Items {
  21. items?: Item[];
  22. }
  23. function getItems(node, current): Items {
  24. if (!node) {
  25. return {};
  26. }
  27. if (node.type === 'paragraph') {
  28. visit(node, (item) => {
  29. if (item.type === 'link') {
  30. current.url = item.url;
  31. current.title = flattenNode(node);
  32. }
  33. if (item.type === 'text') {
  34. current.title = flattenNode(node);
  35. }
  36. });
  37. return current;
  38. }
  39. if (node.type === 'list') {
  40. current.items = node.children.map((i) => getItems(i, {}));
  41. return current;
  42. } else if (node.type === 'listItem') {
  43. const heading = getItems(node.children[0], {});
  44. if (node.children.length > 1) {
  45. getItems(node.children[1], heading);
  46. }
  47. return heading;
  48. }
  49. return {};
  50. }
  51. const getToc = () => (node, file) => {
  52. const table = toc(node);
  53. file.data = getItems(table.map, {});
  54. };
  55. export type TableOfContents = Items;
  56. export async function getTableOfContents(content: string): Promise<TableOfContents> {
  57. const result = await remark().use(getToc).process(content);
  58. return result.data;
  59. }