diff --git a/app/packages/rehype-momiji/buildHTML.ts b/app/packages/rehype-momiji/buildCodeBlock.ts similarity index 97% rename from app/packages/rehype-momiji/buildHTML.ts rename to app/packages/rehype-momiji/buildCodeBlock.ts index fc358a0..5752dbd 100644 --- a/app/packages/rehype-momiji/buildHTML.ts +++ b/app/packages/rehype-momiji/buildCodeBlock.ts @@ -7,7 +7,7 @@ import { visit } from "unist-util-visit"; const defaultHighlighter = await getHighlighter({ themes: bundledThemes, langs: bundledLanguages }); -const buildHTML = ( +const buildCodeBlock = ( rawCode: string, lang: string, theme: BundledTheme, @@ -21,11 +21,11 @@ const buildHTML = ( }); const filenameColorStyle = `background-color: ${filenameBGColor ?? COLOR_HAI}; color: ${filenameTextColor ?? COLOR_SHIRONERI};`; - // Add filename to the code block if it exists if (filename === "") { return toHtml(hast); } + // Add filename to the code block if it exists visit(hast, "element", (node: Element) => { if ( node.tagName === "pre" && @@ -58,4 +58,4 @@ const buildHTML = ( return toHtml(hast); }; -export { buildHTML }; +export { buildCodeBlock }; diff --git a/app/packages/rehype-momiji/rehypeMomiji.ts b/app/packages/rehype-momiji/rehypeMomiji.ts index 4326bbf..0b94c54 100644 --- a/app/packages/rehype-momiji/rehypeMomiji.ts +++ b/app/packages/rehype-momiji/rehypeMomiji.ts @@ -1,23 +1,25 @@ import { bundledLanguages, bundledThemes, type BundledLanguage, type BundledTheme } from "shiki"; +import type { Node } from "unist"; import type { Plugin } from "unified"; -import type { Text, Element, Root } from "hast"; +import type { Text, Element } from "hast"; import { visit } from "unist-util-visit"; import { getHighlighter } from "./highlighter"; import { parser } from "./parser"; -import { buildHTML } from "./buildHTML"; +import { buildCodeBlock } from "./buildCodeBlock"; -type Options = { +interface Option { theme?: BundledTheme; fallbackLang?: BundledLanguage; + excludeLangs?: string[]; filenameBGColor?: string; filenameTextColor?: string; -}; +} const defaultHighlighter = await getHighlighter({ themes: bundledThemes, langs: bundledLanguages }); -const rehypeMomiji: Plugin = (options: Options = {}) => { +const rehypeMomiji: Plugin = (options) => { const langs = defaultHighlighter.getLoadedLanguages(); - const { theme = "github-dark-default", fallbackLang = "c", filenameBGColor, filenameTextColor } = options; + const { theme = "github-dark-default", fallbackLang = "c", excludeLangs, filenameBGColor, filenameTextColor } = options; const parseLanguage = (classNames: string[]): string | undefined => { for (const className of classNames) { @@ -28,12 +30,12 @@ const rehypeMomiji: Plugin = (options: Options = {}) => { return; }; - const checkSupportedLanguage = (lang?: string): string | undefined => { + const checkSupportedLanguage = (lang: string): string => { if (lang && langs.includes(lang)) return lang; return fallbackLang; }; - return (node) => { + return (node: Node) => { visit(node, "element", (node: Element) => { // Check if the node is a pre tag with a single child if (!(node.tagName === "pre" && Array.isArray(node.children) && node.children.length === 1)) { @@ -68,18 +70,24 @@ const rehypeMomiji: Plugin = (options: Options = {}) => { // Parse the language from the class names and check if it is supported const lang = parseLanguage(classNames); - const supportedLang = checkSupportedLanguage(lang); - if (!supportedLang) { + if (!lang) { return; } + // Check if the language should be excluded + if(excludeLangs?.includes(lang)) { + return; + } + + const supportedLang = checkSupportedLanguage(lang); + const filename = (codeElem.properties["data-remark-code-filename"] as string) ?? ""; - const highlightCode = buildHTML(rawCode, supportedLang, theme, filename, filenameBGColor, filenameTextColor); + const codeBlock = buildCodeBlock(rawCode, supportedLang, theme, filename, filenameBGColor, filenameTextColor); const container = ` - ${highlightCode} + ${codeBlock} `; diff --git a/package.json b/package.json index 41838e1..ef6dfb2 100644 --- a/package.json +++ b/package.json @@ -32,12 +32,12 @@ "husky": "^9.1.1", "lint-staged": "^15.2.7", "mdast": "^3.0.0", - "rehype-parse": "^9.0.0", + "rehype-parse": "^9.0.1", "remark-breaks": "^4.0.0", "remark-frontmatter": "^5.0.0", "remark-gfm": "^4.0.0", "remark-mdx-frontmatter": "^5.0.0", - "shiki": "^1.16.2", + "shiki": "^1.23.0", "unified": "^11.0.5", "unist": "^0.0.1", "unist-util-visit": "^5.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dac04b8..096b5ee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,8 +58,8 @@ importers: specifier: ^3.0.0 version: 3.0.0 rehype-parse: - specifier: ^9.0.0 - version: 9.0.0 + specifier: ^9.0.1 + version: 9.0.1 remark-breaks: specifier: ^4.0.0 version: 4.0.0 @@ -73,8 +73,8 @@ importers: specifier: ^5.0.0 version: 5.0.0 shiki: - specifier: ^1.16.2 - version: 1.16.2 + specifier: ^1.23.0 + version: 1.23.0 unified: specifier: ^11.0.5 version: 11.0.5 @@ -698,11 +698,20 @@ packages: cpu: [x64] os: [win32] - '@shikijs/core@1.16.2': - resolution: {integrity: sha512-XSVH5OZCvE4WLMgdoBqfPMYmGHGmCC3OgZhw0S7KcSi2XKZ+5oHGe71GFnTljgdOxvxx5WrRks6QoTLKrl1eAA==} + '@shikijs/core@1.23.0': + resolution: {integrity: sha512-J4Fo22oBlfRHAXec+1AEzcowv+Qdf4ZQkuP/X/UHYH9+KA9LvyFXSXyS+HxuBRFfon+u7bsmKdRBjoZlbDVRkQ==} - '@shikijs/vscode-textmate@9.2.0': - resolution: {integrity: sha512-5FinaOp6Vdh/dl4/yaOTh0ZeKch+rYS8DUb38V3GMKYVkdqzxw53lViRKUYkVILRiVQT7dcPC7VvAKOR73zVtQ==} + '@shikijs/engine-javascript@1.23.0': + resolution: {integrity: sha512-CcrppseWShG+8Efp1iil9divltuXVdCaU4iu+CKvzTGZO5RmXyAiSx668M7VbX8+s/vt1ZKu75Vn/jWi8O3G/Q==} + + '@shikijs/engine-oniguruma@1.23.0': + resolution: {integrity: sha512-gS8bZLqVvmZXX+E5JUMJICsBp+kx6gj79MH/UEpKHKIqnUzppgbmEn6zLa6mB5D+sHse2gFei3YYJxQe1EzZXQ==} + + '@shikijs/types@1.23.0': + resolution: {integrity: sha512-HiwzsihRao+IbPk7FER/EQT/D0dEEK3n5LAtHDzL5iRT+JMblA7y9uitUnjEnHeLkKigNM+ZplrP7MuEyyc5kA==} + + '@shikijs/vscode-textmate@9.3.0': + resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==} '@types/acorn@4.0.6': resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} @@ -991,6 +1000,9 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + emoji-regex-xs@1.0.0: + resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} + emoji-regex@10.3.0: resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} @@ -1171,6 +1183,9 @@ packages: hast-util-to-html@9.0.2: resolution: {integrity: sha512-RP5wNpj5nm1Z8cloDv4Sl4RS8jH5HYa0v93YB6Wb4poEzgMo/dAAL0KcT4974dCjcNG5pkLqTImeFHHCwwfY3g==} + hast-util-to-html@9.0.3: + resolution: {integrity: sha512-M17uBDzMJ9RPCqLMO92gNNUDuBSq10a25SDBI08iCCxmorf4Yy6sYHK57n9WAbRAAaU+DuR4W6GN9K4DFZesYg==} + hast-util-to-jsx-runtime@2.3.0: resolution: {integrity: sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==} @@ -1572,6 +1587,9 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} + oniguruma-to-es@0.1.2: + resolution: {integrity: sha512-sBYKVJlIMB0WPO+tSu/NNB1ytSFeHyyJZ3Ayxfx3f/QUuXu0lvZk0VB4K7npmdlHSC0ldqanzh/sUSlAbgCTfw==} + parse-entities@4.0.1: resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==} @@ -1645,8 +1663,17 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - rehype-parse@9.0.0: - resolution: {integrity: sha512-WG7nfvmWWkCR++KEkZevZb/uw41E8TsH4DsY9UxsTbIXCVGbAs4S+r8FrQ+OtH5EEQAs+5UxKC42VinkmpA1Yw==} + regex-recursion@4.2.1: + resolution: {integrity: sha512-QHNZyZAeKdndD1G3bKAbBEKOSSK4KOHQrAJ01N1LJeb0SoH4DJIeFhp0uUpETgONifS4+P3sOgoA1dhzgrQvhA==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@4.4.0: + resolution: {integrity: sha512-uCUSuobNVeqUupowbdZub6ggI5/JZkYyJdDogddJr60L764oxC2pMZov1fQ3wM9bdyzUILDG+Sqx6NAKAz9rKQ==} + + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} remark-breaks@4.0.0: resolution: {integrity: sha512-IjEjJOkH4FuJvHZVIW0QCDWxcG96kCq7An/KVH2NfJe6rKZU2AsHeB3OEjPNRxi4QC34Xdx7I2KGYn6IpT7gxQ==} @@ -1726,8 +1753,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@1.16.2: - resolution: {integrity: sha512-gSym0hZf5a1U0iDPsdoOAZbvoi+e0c6c3NKAi03FoSLTm7oG20tum29+gk0wzzivOasn3loxfGUPT+jZXIUbWg==} + shiki@1.23.0: + resolution: {integrity: sha512-xfdu9DqPkIpExH29cmiTlgo0/jBki5la1Tkfhsv+Wu5TT3APLNHslR1acxuKJOCWqVdSc+pIbs/2ozjVRGppdg==} signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} @@ -2405,12 +2432,32 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.20.0': optional: true - '@shikijs/core@1.16.2': + '@shikijs/core@1.23.0': dependencies: - '@shikijs/vscode-textmate': 9.2.0 + '@shikijs/engine-javascript': 1.23.0 + '@shikijs/engine-oniguruma': 1.23.0 + '@shikijs/types': 1.23.0 + '@shikijs/vscode-textmate': 9.3.0 '@types/hast': 3.0.4 + hast-util-to-html: 9.0.3 - '@shikijs/vscode-textmate@9.2.0': {} + '@shikijs/engine-javascript@1.23.0': + dependencies: + '@shikijs/types': 1.23.0 + '@shikijs/vscode-textmate': 9.3.0 + oniguruma-to-es: 0.1.2 + + '@shikijs/engine-oniguruma@1.23.0': + dependencies: + '@shikijs/types': 1.23.0 + '@shikijs/vscode-textmate': 9.3.0 + + '@shikijs/types@1.23.0': + dependencies: + '@shikijs/vscode-textmate': 9.3.0 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@9.3.0': {} '@types/acorn@4.0.6': dependencies: @@ -2710,6 +2757,8 @@ snapshots: dependencies: path-type: 4.0.0 + emoji-regex-xs@1.0.0: {} + emoji-regex@10.3.0: {} entities@4.5.0: {} @@ -2970,6 +3019,20 @@ snapshots: stringify-entities: 4.0.4 zwitch: 2.0.4 + hast-util-to-html@9.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + property-information: 6.5.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + hast-util-to-jsx-runtime@2.3.0: dependencies: '@types/estree': 1.0.5 @@ -3679,6 +3742,12 @@ snapshots: dependencies: mimic-function: 5.0.1 + oniguruma-to-es@0.1.2: + dependencies: + emoji-regex-xs: 1.0.0 + regex: 4.4.0 + regex-recursion: 4.2.1 + parse-entities@4.0.1: dependencies: '@types/unist': 2.0.11 @@ -3763,7 +3832,15 @@ snapshots: dependencies: picomatch: 2.3.1 - rehype-parse@9.0.0: + regex-recursion@4.2.1: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@4.4.0: {} + + rehype-parse@9.0.1: dependencies: '@types/hast': 3.0.4 hast-util-from-html: 2.0.2 @@ -3904,10 +3981,13 @@ snapshots: shebang-regex@3.0.0: {} - shiki@1.16.2: + shiki@1.23.0: dependencies: - '@shikijs/core': 1.16.2 - '@shikijs/vscode-textmate': 9.2.0 + '@shikijs/core': 1.23.0 + '@shikijs/engine-javascript': 1.23.0 + '@shikijs/engine-oniguruma': 1.23.0 + '@shikijs/types': 1.23.0 + '@shikijs/vscode-textmate': 9.3.0 '@types/hast': 3.0.4 signal-exit@4.1.0: {} diff --git a/vite.config.ts b/vite.config.ts index 166b19a..604481e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -23,7 +23,7 @@ export default defineConfig(() => { mdx({ jsxImportSource: 'hono/jsx', remarkPlugins: [remarkGfm, remarkBreaks, remarkFrontmatter, remarkMdxFrontmatter, remarkMomijiCodeFilename], - rehypePlugins: [rehypeMomiji] + rehypePlugins: [[rehypeMomiji, {}]], }) ], }