(options)
| 57 | * @param {import('#rs/index.mjs').HighlighterOptions & { highlighter: import('#rs/highlighter.mjs').SyntaxHighlighter }} options |
| 58 | */ |
| 59 | export default async function rehypeShikiji(options) { |
| 60 | const highlighter = |
| 61 | options?.highlighter ?? (await createHighlighter(options)); |
| 62 | |
| 63 | return function (tree) { |
| 64 | visit(tree, 'element', (_, index, parent) => { |
| 65 | const languages = []; |
| 66 | const displayNames = []; |
| 67 | const codeTabsChildren = []; |
| 68 | |
| 69 | let defaultTab = '0'; |
| 70 | let currentIndex = index; |
| 71 | |
| 72 | while (isCodeBlock(parent?.children[currentIndex])) { |
| 73 | const codeElement = parent?.children[currentIndex].children[0]; |
| 74 | const meta = parseMeta(codeElement.data?.meta); |
| 75 | |
| 76 | // We should get the language name from the class name |
| 77 | if (codeElement.properties.className?.length) { |
| 78 | const className = codeElement.properties.className.join(' '); |
| 79 | const matches = className.match(/language-(?<language>.*)/); |
| 80 | |
| 81 | languages.push(matches?.groups.language ?? 'text'); |
| 82 | } |
| 83 | |
| 84 | // Map the display names of each variant for the CodeTab |
| 85 | displayNames.push(meta.displayName?.replaceAll('|', '') ?? ''); |
| 86 | |
| 87 | codeTabsChildren.push(parent?.children[currentIndex]); |
| 88 | |
| 89 | // If `active="true"` is provided in a CodeBox |
| 90 | // then the default selected entry of the CodeTabs will be the desired entry |
| 91 | if (meta.active === 'true') { |
| 92 | defaultTab = String(codeTabsChildren.length - 1); |
| 93 | } |
| 94 | |
| 95 | const nextNode = parent?.children[currentIndex + 1]; |
| 96 | |
| 97 | // If the CodeBoxes are on the root tree the next Element will be |
| 98 | // an empty text element so we should skip it |
| 99 | currentIndex += nextNode && nextNode?.type === 'text' ? 2 : 1; |
| 100 | } |
| 101 | |
| 102 | if (codeTabsChildren.length >= 2) { |
| 103 | const codeTabElement = { |
| 104 | type: 'element', |
| 105 | tagName: 'CodeTabs', |
| 106 | children: codeTabsChildren, |
| 107 | properties: { |
| 108 | languages: languages.join('|'), |
| 109 | displayNames: displayNames.join('|'), |
| 110 | defaultTab, |
| 111 | }, |
| 112 | }; |
| 113 | |
| 114 | // This removes all the original Code Elements and adds a new CodeTab Element |
| 115 | // at the original start of the first Code Element |
| 116 | parent.children.splice(index, currentIndex - index, codeTabElement); |
no test coverage detected