From da768d0f96c613506b487c674dedfaf29c85a3e0 Mon Sep 17 00:00:00 2001 From: avivkeller Date: Wed, 28 May 2025 18:18:59 -0400 Subject: [PATCH 1/7] chore(shiki): add languages used in core --- packages/rehype-shiki/src/languages.mjs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/rehype-shiki/src/languages.mjs b/packages/rehype-shiki/src/languages.mjs index d9764697ff335..187a806307405 100644 --- a/packages/rehype-shiki/src/languages.mjs +++ b/packages/rehype-shiki/src/languages.mjs @@ -1,7 +1,11 @@ 'use strict'; +import cLanguage from 'shiki/langs/c.mjs'; +import coffeeScriptLanguage from 'shiki/langs/coffeescript.mjs'; +import cPlusPlusLanguage from 'shiki/langs/cpp.mjs'; import diffLanguage from 'shiki/langs/diff.mjs'; import dockerLanguage from 'shiki/langs/docker.mjs'; +import httpLanguage from 'shiki/langs/http.mjs'; import iniLanguage from 'shiki/langs/ini.mjs'; import javaScriptLanguage from 'shiki/langs/javascript.mjs'; import jsonLanguage from 'shiki/langs/json.mjs'; @@ -33,6 +37,10 @@ export const LANGUAGES = [ ...dockerLanguage, ...diffLanguage, ...yamlLanguage, + ...cLanguage, + ...cPlusPlusLanguage, + ...httpLanguage, + ...coffeeScriptLanguage, ]; // This is the default theme we use for our Shiki Syntax Highlighter From 4bc363697b0c99ebd75e7d589658f274e311b096 Mon Sep 17 00:00:00 2001 From: avivkeller Date: Sat, 31 May 2025 10:13:15 -0400 Subject: [PATCH 2/7] chore(shiki): only send required langs to client --- .../Downloads/Release/ReleaseCodeBox.tsx | 2 +- apps/site/next.mdx.plugins.mjs | 2 +- packages/rehype-shiki/package.json | 6 +- packages/rehype-shiki/src/highlighter.mjs | 97 +++++++++++-------- packages/rehype-shiki/src/index.mjs | 46 ++++++++- packages/rehype-shiki/src/languages.mjs | 68 ------------- packages/rehype-shiki/src/minimal.mjs | 11 +++ packages/rehype-shiki/src/plugin.mjs | 4 +- 8 files changed, 119 insertions(+), 117 deletions(-) delete mode 100644 packages/rehype-shiki/src/languages.mjs create mode 100644 packages/rehype-shiki/src/minimal.mjs diff --git a/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx b/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx index 0497ca0d234a9..7e18a7bea4b9b 100644 --- a/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx +++ b/apps/site/components/Downloads/Release/ReleaseCodeBox.tsx @@ -1,6 +1,6 @@ 'use client'; -import { highlightToHtml } from '@node-core/rehype-shiki'; +import { highlightToHtml } from '@node-core/rehype-shiki/minimal'; import AlertBox from '@node-core/ui-components/Common/AlertBox'; import Skeleton from '@node-core/ui-components/Common/Skeleton'; import { useTranslations } from 'next-intl'; diff --git a/apps/site/next.mdx.plugins.mjs b/apps/site/next.mdx.plugins.mjs index 016407b360422..a857a298de193 100644 --- a/apps/site/next.mdx.plugins.mjs +++ b/apps/site/next.mdx.plugins.mjs @@ -1,6 +1,6 @@ 'use strict'; -import rehypeShikiji from '@node-core/rehype-shiki'; +import rehypeShikiji from '@node-core/rehype-shiki/plugin'; import remarkHeadings from '@vcarl/remark-headings'; import rehypeAutolinkHeadings from 'rehype-autolink-headings'; import rehypeSlug from 'rehype-slug'; diff --git a/packages/rehype-shiki/package.json b/packages/rehype-shiki/package.json index ed32e84e52e9e..ab27b26ba010d 100644 --- a/packages/rehype-shiki/package.json +++ b/packages/rehype-shiki/package.json @@ -1,8 +1,10 @@ { "name": "@node-core/rehype-shiki", "type": "module", - "main": "./src/index.mjs", - "module": "./src/index.mjs", + "exports": { + ".": "./src/index.mjs", + "./*": "./src/*.mjs" + }, "scripts": { "lint:js": "eslint \"**/*.mjs\"", "test": "node --test" diff --git a/packages/rehype-shiki/src/highlighter.mjs b/packages/rehype-shiki/src/highlighter.mjs index a31fda8da7300..759e0378876fc 100644 --- a/packages/rehype-shiki/src/highlighter.mjs +++ b/packages/rehype-shiki/src/highlighter.mjs @@ -1,47 +1,66 @@ import { createHighlighterCoreSync } from '@shikijs/core'; import { createJavaScriptRegexEngine } from '@shikijs/engine-javascript'; +import shikiNordTheme from 'shiki/themes/nord.mjs'; -import { LANGUAGES, DEFAULT_THEME } from './languages.mjs'; - -let _shiki; - -/** - * Lazy-load and memoize the minimal Shikiji Syntax Highlighter - * @returns {import('@shikijs/core').HighlighterCore} - */ -export const getShiki = () => { - if (!_shiki) { - _shiki = createHighlighterCoreSync({ - themes: [DEFAULT_THEME], - langs: LANGUAGES, - // Let's use Shiki's new Experimental JavaScript-based regex engine! - engine: createJavaScriptRegexEngine(), - }); - } - return _shiki; +const DEFAULT_THEME = { + // We updating this color because the background color and comment text color + // in the Codebox component do not comply with accessibility standards + // @see https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html + colorReplacements: { '#616e88': '#707e99' }, + ...shikiNordTheme, }; /** - * Highlights code and returns the inner HTML inside the tag - * - * @param {string} code - The code to highlight - * @param {string} language - The programming language to use for highlighting - * @returns {string} The inner HTML of the highlighted code + * Creates a syntax highlighter with utility functions + * @param {import('@shikijs/core').HighlighterCoreOptions} options - Configuration options for the highlighter */ -export const highlightToHtml = (code, language) => - getShiki() - .codeToHtml(code, { lang: language, theme: DEFAULT_THEME }) - // Shiki will always return the Highlighted code encapsulated in a
 and  tag
-    // since our own CodeBox component handles the  tag, we just want to extract
-    // the inner highlighted code to the CodeBox
-    .match(/(.+?)<\/code>/s)[1];
+export const createHighlighter = options => {
+  const shiki = createHighlighterCoreSync({
+    themes: [DEFAULT_THEME],
+    langs: [],
+    engine: createJavaScriptRegexEngine(),
+    ...options,
+  });
+  const theme = options.themes?.[0] ?? DEFAULT_THEME;
 
-/**
- * Highlights code and returns a HAST tree
- *
- * @param {string} code - The code to highlight
- * @param {string} language - The programming language to use for highlighting
- * @returns {import('hast').Element} The HAST representation of the highlighted code
- */
-export const highlightToHast = (code, language) =>
-  getShiki().codeToHast(code, { lang: language, theme: DEFAULT_THEME });
+  const getLanguageDisplayName = language => {
+    const languageByIdOrAlias = options.langs.find(
+      ({ name, aliases }) =>
+        name.toLowerCase() === language.toLowerCase() ||
+        (aliases !== undefined && aliases.includes(language.toLowerCase()))
+    );
+
+    return languageByIdOrAlias?.displayName ?? language;
+  };
+
+  /**
+   * Highlights code and returns the inner HTML inside the  tag
+   *
+   * @param {string} code - The code to highlight
+   * @param {string} language - The programming language to use for highlighting
+   * @returns {string} The inner HTML of the highlighted code
+   */
+  const highlightToHtml = (code, language) =>
+    shiki
+      .codeToHtml(code, { lang: language, theme })
+      // Shiki will always return the Highlighted code encapsulated in a 
 and  tag
+      // since our own CodeBox component handles the  tag, we just want to extract
+      // the inner highlighted code to the CodeBox
+      .match(/(.+?)<\/code>/s)[1];
+
+  /**
+   * Highlights code and returns a HAST tree
+   *
+   * @param {string} code - The code to highlight
+   * @param {string} language - The programming language to use for highlighting
+   */
+  const highlightToHast = (code, language) =>
+    shiki.codeToHast(code, { lang: language, theme });
+
+  return {
+    shiki,
+    getLanguageDisplayName,
+    highlightToHtml,
+    highlightToHast,
+  };
+};
diff --git a/packages/rehype-shiki/src/index.mjs b/packages/rehype-shiki/src/index.mjs
index 68cfc211ea64c..1a7e144a46719 100644
--- a/packages/rehype-shiki/src/index.mjs
+++ b/packages/rehype-shiki/src/index.mjs
@@ -1,5 +1,43 @@
-import { rehypeShikiji } from './plugin.mjs';
-export * from './highlighter.mjs';
-export * from './languages.mjs';
+import cLanguage from 'shiki/langs/c.mjs';
+import coffeeScriptLanguage from 'shiki/langs/coffeescript.mjs';
+import cPlusPlusLanguage from 'shiki/langs/cpp.mjs';
+import diffLanguage from 'shiki/langs/diff.mjs';
+import dockerLanguage from 'shiki/langs/docker.mjs';
+import httpLanguage from 'shiki/langs/http.mjs';
+import iniLanguage from 'shiki/langs/ini.mjs';
+import javaScriptLanguage from 'shiki/langs/javascript.mjs';
+import jsonLanguage from 'shiki/langs/json.mjs';
+import powershellLanguage from 'shiki/langs/powershell.mjs';
+import shellScriptLanguage from 'shiki/langs/shellscript.mjs';
+import shellSessionLanguage from 'shiki/langs/shellsession.mjs';
+import typeScriptLanguage from 'shiki/langs/typescript.mjs';
+import yamlLanguage from 'shiki/langs/yaml.mjs';
 
-export default rehypeShikiji;
+import { createHighlighter } from './highlighter.mjs';
+
+const { shiki, getLanguageDisplayName, highlightToHast, highlightToHtml } =
+  createHighlighter({
+    langs: [
+      ...cLanguage,
+      ...coffeeScriptLanguage,
+      ...cPlusPlusLanguage,
+      ...diffLanguage,
+      ...dockerLanguage,
+      ...httpLanguage,
+      ...iniLanguage,
+      {
+        ...javaScriptLanguage[0],
+        // We patch the JavaScript language to include the CommonJS and ES Module aliases
+        // that are commonly used (non-standard aliases) within our API docs and Blog posts
+        aliases: javaScriptLanguage[0].aliases.concat('cjs', 'mjs'),
+      },
+      ...jsonLanguage,
+      ...powershellLanguage,
+      ...shellScriptLanguage,
+      ...shellSessionLanguage,
+      ...typeScriptLanguage,
+      ...yamlLanguage,
+    ],
+  });
+
+export { shiki, getLanguageDisplayName, highlightToHast, highlightToHtml };
diff --git a/packages/rehype-shiki/src/languages.mjs b/packages/rehype-shiki/src/languages.mjs
deleted file mode 100644
index 187a806307405..0000000000000
--- a/packages/rehype-shiki/src/languages.mjs
+++ /dev/null
@@ -1,68 +0,0 @@
-'use strict';
-
-import cLanguage from 'shiki/langs/c.mjs';
-import coffeeScriptLanguage from 'shiki/langs/coffeescript.mjs';
-import cPlusPlusLanguage from 'shiki/langs/cpp.mjs';
-import diffLanguage from 'shiki/langs/diff.mjs';
-import dockerLanguage from 'shiki/langs/docker.mjs';
-import httpLanguage from 'shiki/langs/http.mjs';
-import iniLanguage from 'shiki/langs/ini.mjs';
-import javaScriptLanguage from 'shiki/langs/javascript.mjs';
-import jsonLanguage from 'shiki/langs/json.mjs';
-import powershellLanguage from 'shiki/langs/powershell.mjs';
-import shellScriptLanguage from 'shiki/langs/shellscript.mjs';
-import shellSessionLanguage from 'shiki/langs/shellsession.mjs';
-import typeScriptLanguage from 'shiki/langs/typescript.mjs';
-import yamlLanguage from 'shiki/langs/yaml.mjs';
-import shikiNordTheme from 'shiki/themes/nord.mjs';
-
-/**
- * All languages needed within the Node.js website for syntax highlighting.
- *
- * @type {Array}
- */
-export const LANGUAGES = [
-  {
-    ...javaScriptLanguage[0],
-    // We path the JavaScript language to include the CommonJS and ES Module aliases
-    // that are commonly used (non-standard aliases) within our API docs and Blog posts
-    aliases: javaScriptLanguage[0].aliases.concat('cjs', 'mjs'),
-  },
-  ...iniLanguage,
-  ...jsonLanguage,
-  ...typeScriptLanguage,
-  ...shellScriptLanguage,
-  ...powershellLanguage,
-  ...shellSessionLanguage,
-  ...dockerLanguage,
-  ...diffLanguage,
-  ...yamlLanguage,
-  ...cLanguage,
-  ...cPlusPlusLanguage,
-  ...httpLanguage,
-  ...coffeeScriptLanguage,
-];
-
-// This is the default theme we use for our Shiki Syntax Highlighter
-export const DEFAULT_THEME = {
-  // We updating this color because the background color and comment text color
-  // in the Codebox component do not comply with accessibility standards
-  // @see https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html
-  colorReplacements: { '#616e88': '#707e99' },
-  ...shikiNordTheme,
-};
-
-/**
- * Get the display name of a given language
- * @param {string} language The language ID
- * @returns {string} The display name of the language, or the input as a fallback
- */
-export const getLanguageDisplayName = language => {
-  const languageByIdOrAlias = LANGUAGES.find(
-    ({ name, aliases }) =>
-      name.toLowerCase() === language.toLowerCase() ||
-      (aliases !== undefined && aliases.includes(language.toLowerCase()))
-  );
-
-  return languageByIdOrAlias?.displayName ?? language;
-};
diff --git a/packages/rehype-shiki/src/minimal.mjs b/packages/rehype-shiki/src/minimal.mjs
new file mode 100644
index 0000000000000..cdbb5c8f2ca9c
--- /dev/null
+++ b/packages/rehype-shiki/src/minimal.mjs
@@ -0,0 +1,11 @@
+import powershellLanguage from 'shiki/langs/powershell.mjs';
+import shellScriptLanguage from 'shiki/langs/shellscript.mjs';
+
+import { createHighlighter } from './highlighter.mjs';
+
+const { shiki, getLanguageDisplayName, highlightToHast, highlightToHtml } =
+  createHighlighter({
+    langs: [...powershellLanguage, ...shellScriptLanguage],
+  });
+
+export { shiki, getLanguageDisplayName, highlightToHast, highlightToHtml };
diff --git a/packages/rehype-shiki/src/plugin.mjs b/packages/rehype-shiki/src/plugin.mjs
index d486615296c40..2931b0be9f36d 100644
--- a/packages/rehype-shiki/src/plugin.mjs
+++ b/packages/rehype-shiki/src/plugin.mjs
@@ -4,7 +4,7 @@ import classNames from 'classnames';
 import { toString } from 'hast-util-to-string';
 import { SKIP, visit } from 'unist-util-visit';
 
-import { highlightToHast } from './highlighter.mjs';
+import { highlightToHast } from '.';
 
 // This is what Remark will use as prefix within a 
 className
 // to attribute the current language of the 
 element
@@ -53,7 +53,7 @@ function isCodeBlock(node) {
   );
 }
 
-export function rehypeShikiji() {
+export default function rehypeShikiji() {
   return function (tree) {
     visit(tree, 'element', (_, index, parent) => {
       const languages = [];

From 199ff6ef13fe7a33803d526c2724ca2537df5122 Mon Sep 17 00:00:00 2001
From: avivkeller 
Date: Sat, 31 May 2025 10:19:22 -0400
Subject: [PATCH 3/7] fixup! chore(shiki): only send required langs to client

---
 packages/rehype-shiki/src/highlighter.mjs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/rehype-shiki/src/highlighter.mjs b/packages/rehype-shiki/src/highlighter.mjs
index 759e0378876fc..3863adfd837ef 100644
--- a/packages/rehype-shiki/src/highlighter.mjs
+++ b/packages/rehype-shiki/src/highlighter.mjs
@@ -17,14 +17,14 @@ const DEFAULT_THEME = {
 export const createHighlighter = options => {
   const shiki = createHighlighterCoreSync({
     themes: [DEFAULT_THEME],
-    langs: [],
     engine: createJavaScriptRegexEngine(),
     ...options,
   });
   const theme = options.themes?.[0] ?? DEFAULT_THEME;
+  const langs = options.langs ?? [];
 
   const getLanguageDisplayName = language => {
-    const languageByIdOrAlias = options.langs.find(
+    const languageByIdOrAlias = langs.find(
       ({ name, aliases }) =>
         name.toLowerCase() === language.toLowerCase() ||
         (aliases !== undefined && aliases.includes(language.toLowerCase()))

From c7a9aa48b1b9fbe115ff22abb1f679f03b0aaaca Mon Sep 17 00:00:00 2001
From: avivkeller 
Date: Sat, 31 May 2025 10:39:01 -0400
Subject: [PATCH 4/7] fix unit tests

---
 packages/rehype-shiki/package.json            |  3 +-
 .../src/__tests__/highlighter.test.mjs        | 75 +++++++++++++++++++
 .../src/__tests__/languages.test.mjs          | 27 -------
 .../src/__tests__/plugin.test.mjs             | 67 +++++++++++++++++
 packages/rehype-shiki/src/plugin.mjs          |  2 +-
 packages/rehype-shiki/turbo.json              |  2 +-
 6 files changed, 146 insertions(+), 30 deletions(-)
 create mode 100644 packages/rehype-shiki/src/__tests__/highlighter.test.mjs
 delete mode 100644 packages/rehype-shiki/src/__tests__/languages.test.mjs
 create mode 100644 packages/rehype-shiki/src/__tests__/plugin.test.mjs

diff --git a/packages/rehype-shiki/package.json b/packages/rehype-shiki/package.json
index ab27b26ba010d..72037c0eaee0f 100644
--- a/packages/rehype-shiki/package.json
+++ b/packages/rehype-shiki/package.json
@@ -7,7 +7,8 @@
   },
   "scripts": {
     "lint:js": "eslint \"**/*.mjs\"",
-    "test": "node --test"
+    "test": "turbo test:unit",
+    "test:unit": "node --experimental-test-module-mocks --test \"**/*.test.mjs\""
   },
   "dependencies": {
     "@shikijs/core": "^3.3.0",
diff --git a/packages/rehype-shiki/src/__tests__/highlighter.test.mjs b/packages/rehype-shiki/src/__tests__/highlighter.test.mjs
new file mode 100644
index 0000000000000..7ab0fcaa6e1b0
--- /dev/null
+++ b/packages/rehype-shiki/src/__tests__/highlighter.test.mjs
@@ -0,0 +1,75 @@
+import assert from 'node:assert/strict';
+import { describe, it, mock } from 'node:test';
+
+// Mock dependencies
+const mockShiki = {
+  codeToHtml: mock.fn(() => '
highlighted code
'), + codeToHast: mock.fn(() => ({ type: 'element', tagName: 'pre' })), +}; + +mock.module('@shikijs/core', { + namedExports: { createHighlighterCoreSync: () => mockShiki }, +}); + +mock.module('@shikijs/engine-javascript', { + namedExports: { createJavaScriptRegexEngine: () => ({}) }, +}); + +mock.module('shiki/themes/nord.mjs', { + defaultExport: { name: 'nord', colors: { 'editor.background': '#2e3440' } }, +}); + +describe('createHighlighter', async () => { + const { createHighlighter } = await import('../highlighter.mjs'); + + describe('getLanguageDisplayName', () => { + it('returns display name for known languages', () => { + const langs = [ + { name: 'javascript', displayName: 'JavaScript', aliases: ['js'] }, + ]; + const highlighter = createHighlighter({ langs }); + + assert.strictEqual( + highlighter.getLanguageDisplayName('javascript'), + 'JavaScript' + ); + assert.strictEqual( + highlighter.getLanguageDisplayName('js'), + 'JavaScript' + ); + }); + + it('returns original name for unknown languages', () => { + const highlighter = createHighlighter({ langs: [] }); + assert.strictEqual( + highlighter.getLanguageDisplayName('unknown'), + 'unknown' + ); + }); + }); + + describe('highlightToHtml', () => { + it('extracts inner HTML from code tag', () => { + mockShiki.codeToHtml.mock.mockImplementationOnce( + () => '
const x = 1;
' + ); + + const highlighter = createHighlighter({}); + const result = highlighter.highlightToHtml('const x = 1;', 'javascript'); + + assert.strictEqual(result, 'const x = 1;'); + }); + }); + + describe('highlightToHast', () => { + it('returns HAST tree from shiki', () => { + const expectedHast = { type: 'element', tagName: 'pre' }; + mockShiki.codeToHast.mock.mockImplementationOnce(() => expectedHast); + + const highlighter = createHighlighter({}); + const result = highlighter.highlightToHast('code', 'javascript'); + + assert.deepStrictEqual(result, expectedHast); + }); + }); +}); diff --git a/packages/rehype-shiki/src/__tests__/languages.test.mjs b/packages/rehype-shiki/src/__tests__/languages.test.mjs deleted file mode 100644 index 0900f25ff365b..0000000000000 --- a/packages/rehype-shiki/src/__tests__/languages.test.mjs +++ /dev/null @@ -1,27 +0,0 @@ -import assert from 'node:assert/strict'; -import { it, describe } from 'node:test'; - -import { getLanguageDisplayName, LANGUAGES } from '../languages.mjs'; - -LANGUAGES.splice( - 0, - LANGUAGES.length, - { name: 'javascript', aliases: ['js'], displayName: 'JavaScript' }, - { name: 'typescript', aliases: ['ts'], displayName: 'TypeScript' } -); - -describe('getLanguageDisplayName', async () => { - it('should return the display name for a known language', () => { - assert.equal(getLanguageDisplayName('javascript'), 'JavaScript'); - assert.equal(getLanguageDisplayName('js'), 'JavaScript'); - }); - - it('should return the display name for another known language', () => { - assert.equal(getLanguageDisplayName('typescript'), 'TypeScript'); - assert.equal(getLanguageDisplayName('ts'), 'TypeScript'); - }); - - it('should return the input language if it is not known', () => { - assert.equal(getLanguageDisplayName('unknown'), 'unknown'); - }); -}); diff --git a/packages/rehype-shiki/src/__tests__/plugin.test.mjs b/packages/rehype-shiki/src/__tests__/plugin.test.mjs new file mode 100644 index 0000000000000..11f545ad28ba3 --- /dev/null +++ b/packages/rehype-shiki/src/__tests__/plugin.test.mjs @@ -0,0 +1,67 @@ +import assert from 'node:assert/strict'; +import { describe, it, mock } from 'node:test'; + +// Simplified mocks - only mock what's actually needed +mock.module('../index.mjs', { + namedExports: { highlightToHast: mock.fn(() => ({ children: [] })) }, +}); + +mock.module('classnames', { + defaultExport: (...args) => args.filter(Boolean).join(' '), +}); + +mock.module('hast-util-to-string', { + namedExports: { toString: () => 'code' }, +}); + +const mockVisit = mock.fn(); +mock.module('unist-util-visit', { + namedExports: { visit: mockVisit, SKIP: Symbol() }, +}); + +describe('rehypeShikiji', async () => { + const { default: rehypeShikiji } = await import('../plugin.mjs'); + const mockTree = { type: 'root', children: [] }; + + it('calls visit twice', () => { + mockVisit.mock.resetCalls(); + rehypeShikiji()(mockTree); + assert.strictEqual(mockVisit.mock.calls.length, 2); + }); + + it('creates CodeTabs for multiple code blocks', () => { + const parent = { + children: [ + { + tagName: 'pre', + children: [ + { + tagName: 'code', + data: { meta: 'displayName="JS"' }, + properties: { className: ['language-js'] }, + }, + ], + }, + { + tagName: 'pre', + children: [ + { + tagName: 'code', + data: { meta: 'displayName="TS"' }, + properties: { className: ['language-ts'] }, + }, + ], + }, + ], + }; + + mockVisit.mock.mockImplementation((tree, selector, visitor) => { + if (selector === 'element') { + visitor(parent.children[0], 0, parent); + } + }); + + rehypeShikiji()(mockTree); + assert.ok(parent.children.some(child => child.tagName === 'CodeTabs')); + }); +}); diff --git a/packages/rehype-shiki/src/plugin.mjs b/packages/rehype-shiki/src/plugin.mjs index 2931b0be9f36d..c07416a4db326 100644 --- a/packages/rehype-shiki/src/plugin.mjs +++ b/packages/rehype-shiki/src/plugin.mjs @@ -4,7 +4,7 @@ import classNames from 'classnames'; import { toString } from 'hast-util-to-string'; import { SKIP, visit } from 'unist-util-visit'; -import { highlightToHast } from '.'; +import { highlightToHast } from './index.mjs'; // This is what Remark will use as prefix within a
 className
 // to attribute the current language of the 
 element
diff --git a/packages/rehype-shiki/turbo.json b/packages/rehype-shiki/turbo.json
index aa0ce04f53ac8..1dd6dce7da26a 100644
--- a/packages/rehype-shiki/turbo.json
+++ b/packages/rehype-shiki/turbo.json
@@ -6,7 +6,7 @@
     "lint:js": {
       "inputs": ["src/**/*.mjs"]
     },
-    "test": {
+    "test:unit": {
       "inputs": ["src/**/*.mjs"]
     }
   }

From 056fc43e8768b91939d384f896631fceb8e1b08f Mon Sep 17 00:00:00 2001
From: avivkeller 
Date: Sat, 31 May 2025 10:43:41 -0400
Subject: [PATCH 5/7] fixup! fix unit tests

---
 packages/rehype-shiki/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/rehype-shiki/package.json b/packages/rehype-shiki/package.json
index 72037c0eaee0f..09a03b003e373 100644
--- a/packages/rehype-shiki/package.json
+++ b/packages/rehype-shiki/package.json
@@ -8,7 +8,7 @@
   "scripts": {
     "lint:js": "eslint \"**/*.mjs\"",
     "test": "turbo test:unit",
-    "test:unit": "node --experimental-test-module-mocks --test \"**/*.test.mjs\""
+    "test:unit": "node --experimental-test-coverage --experimental-test-module-mocks --test \"**/*.test.mjs\""
   },
   "dependencies": {
     "@shikijs/core": "^3.3.0",

From cb04de45d49adbfd6bd513945047a864da447fb3 Mon Sep 17 00:00:00 2001
From: Aviv Keller 
Date: Sat, 31 May 2025 10:49:20 -0400
Subject: [PATCH 6/7] Update packages/rehype-shiki/src/highlighter.mjs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Aviv Keller 
---
 packages/rehype-shiki/src/highlighter.mjs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/packages/rehype-shiki/src/highlighter.mjs b/packages/rehype-shiki/src/highlighter.mjs
index 3863adfd837ef..ffaecbd2c4224 100644
--- a/packages/rehype-shiki/src/highlighter.mjs
+++ b/packages/rehype-shiki/src/highlighter.mjs
@@ -3,7 +3,7 @@ import { createJavaScriptRegexEngine } from '@shikijs/engine-javascript';
 import shikiNordTheme from 'shiki/themes/nord.mjs';
 
 const DEFAULT_THEME = {
-  // We updating this color because the background color and comment text color
+  // We are updating this color because the background color and comment text color
   // in the Codebox component do not comply with accessibility standards
   // @see https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html
   colorReplacements: { '#616e88': '#707e99' },

From ca998e8b2bc431610e1992a08f7603035c100b22 Mon Sep 17 00:00:00 2001
From: Aviv Keller 
Date: Sat, 31 May 2025 11:06:17 -0400
Subject: [PATCH 7/7] Update packages/rehype-shiki/src/highlighter.mjs

Co-authored-by: Claudio W. 
Signed-off-by: Aviv Keller 
---
 packages/rehype-shiki/src/highlighter.mjs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/packages/rehype-shiki/src/highlighter.mjs b/packages/rehype-shiki/src/highlighter.mjs
index ffaecbd2c4224..9f37e26ae179e 100644
--- a/packages/rehype-shiki/src/highlighter.mjs
+++ b/packages/rehype-shiki/src/highlighter.mjs
@@ -20,6 +20,7 @@ export const createHighlighter = options => {
     engine: createJavaScriptRegexEngine(),
     ...options,
   });
+
   const theme = options.themes?.[0] ?? DEFAULT_THEME;
   const langs = options.langs ?? [];