summaryrefslogtreecommitdiff
path: root/packages/integrations/markdoc/src
diff options
context:
space:
mode:
authorGravatar Bjorn Lu <bjornlu.dev@gmail.com> 2023-11-14 23:00:17 +0800
committerGravatar GitHub <noreply@github.com> 2023-11-14 23:00:17 +0800
commit4537ecf0d060f89cb8c000338a7fc5f4197a88c8 (patch)
tree1ef855fc2197749001d202c7e8fee133d9cbc120 /packages/integrations/markdoc/src
parent6f5de8dfba021cacc8f58140671a98bcbb0936a3 (diff)
downloadastro-4537ecf0d060f89cb8c000338a7fc5f4197a88c8.tar.gz
astro-4537ecf0d060f89cb8c000338a7fc5f4197a88c8.tar.zst
astro-4537ecf0d060f89cb8c000338a7fc5f4197a88c8.zip
Refactor shikiji syntax highlighting code (#9083)
Diffstat (limited to 'packages/integrations/markdoc/src')
-rw-r--r--packages/integrations/markdoc/src/extensions/shiki.ts105
1 files changed, 5 insertions, 100 deletions
diff --git a/packages/integrations/markdoc/src/extensions/shiki.ts b/packages/integrations/markdoc/src/extensions/shiki.ts
index 9ca894245..c70ef7f08 100644
--- a/packages/integrations/markdoc/src/extensions/shiki.ts
+++ b/packages/integrations/markdoc/src/extensions/shiki.ts
@@ -1,107 +1,19 @@
import Markdoc from '@markdoc/markdoc';
+import { createShikiHighlighter } from '@astrojs/markdown-remark';
import type { ShikiConfig } from 'astro';
import { unescapeHTML } from 'astro/runtime/server/index.js';
-import { bundledLanguages, getHighlighter, type Highlighter } from 'shikiji';
import type { AstroMarkdocConfig } from '../config.js';
-const ASTRO_COLOR_REPLACEMENTS: Record<string, string> = {
- '#000001': 'var(--astro-code-color-text)',
- '#000002': 'var(--astro-code-color-background)',
- '#000004': 'var(--astro-code-token-constant)',
- '#000005': 'var(--astro-code-token-string)',
- '#000006': 'var(--astro-code-token-comment)',
- '#000007': 'var(--astro-code-token-keyword)',
- '#000008': 'var(--astro-code-token-parameter)',
- '#000009': 'var(--astro-code-token-function)',
- '#000010': 'var(--astro-code-token-string-expression)',
- '#000011': 'var(--astro-code-token-punctuation)',
- '#000012': 'var(--astro-code-token-link)',
-};
-const COLOR_REPLACEMENT_REGEX = new RegExp(
- `(${Object.keys(ASTRO_COLOR_REPLACEMENTS).join('|')})`,
- 'g'
-);
-
-const PRE_SELECTOR = /<pre class="(.*?)shiki(.*?)"/;
-const LINE_SELECTOR = /<span class="line"><span style="(.*?)">([\+|\-])/g;
-const INLINE_STYLE_SELECTOR = /style="(.*?)"/;
-const INLINE_STYLE_SELECTOR_GLOBAL = /style="(.*?)"/g;
-
-/**
- * Note: cache only needed for dev server reloads, internal test suites, and manual calls to `Markdoc.transform` by the user.
- * Otherwise, `shiki()` is only called once per build, NOT once per page, so a cache isn't needed!
- */
-const highlighterCache = new Map<string, Highlighter>();
-
-export default async function shiki({
- langs = [],
- theme = 'github-dark',
- wrap = false,
-}: ShikiConfig = {}): Promise<AstroMarkdocConfig> {
- const cacheId = typeof theme === 'string' ? theme : theme.name || '';
- let highlighter = highlighterCache.get(cacheId)!;
- if (!highlighter) {
- highlighter = await getHighlighter({
- langs: langs.length ? langs : Object.keys(bundledLanguages),
- themes: [theme],
- });
- highlighterCache.set(cacheId, highlighter);
- }
+export default async function shiki(config?: ShikiConfig): Promise<AstroMarkdocConfig> {
+ const highlighter = await createShikiHighlighter(config);
return {
nodes: {
fence: {
attributes: Markdoc.nodes.fence.attributes!,
transform({ attributes }) {
- let lang: string;
-
- if (typeof attributes.language === 'string') {
- const langExists = highlighter
- .getLoadedLanguages()
- .includes(attributes.language as any);
- if (langExists) {
- lang = attributes.language;
- } else {
- console.warn(
- `[Shiki highlighter] The language "${attributes.language}" doesn't exist, falling back to plaintext.`
- );
- lang = 'plaintext';
- }
- } else {
- lang = 'plaintext';
- }
-
- let html = highlighter.codeToHtml(attributes.content, { lang, theme });
-
- // Q: Could these regexes match on a user's inputted code blocks?
- // A: Nope! All rendered HTML is properly escaped.
- // Ex. If a user typed `<span class="line"` into a code block,
- // It would become this before hitting our regexes:
- // &lt;span class=&quot;line&quot;
-
- html = html.replace(PRE_SELECTOR, `<pre class="$1astro-code$2"`);
- // Add "user-select: none;" for "+"/"-" diff symbols
- if (attributes.language === 'diff') {
- html = html.replace(
- LINE_SELECTOR,
- '<span class="line"><span style="$1"><span style="user-select: none;">$2</span>'
- );
- }
-
- if (wrap === false) {
- html = html.replace(INLINE_STYLE_SELECTOR, 'style="$1; overflow-x: auto;"');
- } else if (wrap === true) {
- html = html.replace(
- INLINE_STYLE_SELECTOR,
- 'style="$1; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"'
- );
- }
-
- // theme.id for shiki -> shikiji compat
- const themeName = typeof theme === 'string' ? theme : theme.name;
- if (themeName === 'css-variables') {
- html = html.replace(INLINE_STYLE_SELECTOR_GLOBAL, (m) => replaceCssVariables(m));
- }
+ const lang = typeof attributes.language === 'string' ? attributes.language : 'plaintext';
+ const html = highlighter.highlight(attributes.content, lang);
// Use `unescapeHTML` to return `HTMLString` for Astro renderer to inline as HTML
return unescapeHTML(html) as any;
@@ -110,10 +22,3 @@ export default async function shiki({
},
};
}
-
-/**
- * shiki -> shikiji compat as we need to manually replace it
- */
-function replaceCssVariables(str: string) {
- return str.replace(COLOR_REPLACEMENT_REGEX, (match) => ASTRO_COLOR_REPLACEMENTS[match] || match);
-}