summaryrefslogtreecommitdiff
path: root/packages/markdown/remark/src
diff options
context:
space:
mode:
authorGravatar Bjorn Lu <bjornlu.dev@gmail.com> 2023-10-12 00:07:06 +0800
committerGravatar GitHub <noreply@github.com> 2023-10-12 00:07:06 +0800
commitc4270e47681ee2453f3fea07fed7b238645fd6ea (patch)
tree46769c445a4d9f21ff2ad9d0bbcb60aa3fd79356 /packages/markdown/remark/src
parentf369fa25055a3497ebaf61c88fb0e8af56c73212 (diff)
downloadastro-c4270e47681ee2453f3fea07fed7b238645fd6ea.tar.gz
astro-c4270e47681ee2453f3fea07fed7b238645fd6ea.tar.zst
astro-c4270e47681ee2453f3fea07fed7b238645fd6ea.zip
Use shikiji (#8502)
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
Diffstat (limited to 'packages/markdown/remark/src')
-rw-r--r--packages/markdown/remark/src/remark-shiki.ts79
-rw-r--r--packages/markdown/remark/src/types.ts11
2 files changed, 52 insertions, 38 deletions
diff --git a/packages/markdown/remark/src/remark-shiki.ts b/packages/markdown/remark/src/remark-shiki.ts
index 58ed16369..bf3dd0b78 100644
--- a/packages/markdown/remark/src/remark-shiki.ts
+++ b/packages/markdown/remark/src/remark-shiki.ts
@@ -1,56 +1,52 @@
-import type * as shiki from 'shiki';
-import { getHighlighter } from 'shiki';
+import { bundledLanguages, getHighlighter, type Highlighter } from 'shikiji';
import { visit } from 'unist-util-visit';
import type { RemarkPlugin, ShikiConfig } from './types.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'
+);
+
/**
* getHighlighter() is the most expensive step of Shiki. Instead of calling it on every page,
* cache it here as much as possible. Make sure that your highlighters can be cached, state-free.
* We make this async, so that multiple calls to parse markdown still share the same highlighter.
*/
-const highlighterCacheAsync = new Map<string, Promise<shiki.Highlighter>>();
+const highlighterCacheAsync = new Map<string, Promise<Highlighter>>();
export function remarkShiki({
langs = [],
theme = 'github-dark',
wrap = false,
}: ShikiConfig = {}): ReturnType<RemarkPlugin> {
- const cacheID: string = typeof theme === 'string' ? theme : theme.name;
- let highlighterAsync = highlighterCacheAsync.get(cacheID);
+ const cacheId =
+ (typeof theme === 'string' ? theme : theme.name ?? '') +
+ langs.map((l) => l.name ?? (l as any).id).join(',');
+
+ let highlighterAsync = highlighterCacheAsync.get(cacheId);
if (!highlighterAsync) {
- highlighterAsync = getHighlighter({ theme }).then((hl) => {
- hl.setColorReplacements({
- '#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)',
- });
- return hl;
+ highlighterAsync = getHighlighter({
+ langs: langs.length ? langs : Object.keys(bundledLanguages),
+ themes: [theme],
});
- highlighterCacheAsync.set(cacheID, highlighterAsync);
+ highlighterCacheAsync.set(cacheId, highlighterAsync);
}
- let highlighter: shiki.Highlighter;
-
return async (tree: any) => {
- // Lazily assign the highlighter as async can only happen within this function,
- // and not on `remarkShiki` directly.
- if (!highlighter) {
- highlighter = await highlighterAsync!;
-
- // NOTE: There may be a performance issue here for large sites that use `lang`.
- // Since this will be called on every page load. Unclear how to fix this.
- for (const lang of langs) {
- await highlighter.loadLanguage(lang);
- }
- }
+ const highlighter = await highlighterAsync!;
visit(tree, 'code', (node) => {
let lang: string;
@@ -68,7 +64,7 @@ export function remarkShiki({
lang = 'plaintext';
}
- let html = highlighter.codeToHtml(node.value, { lang });
+ let html = highlighter.codeToHtml(node.value, { lang, theme });
// Q: Couldn't these regexes match on a user's inputted code blocks?
// A: Nope! All rendered HTML is properly escaped.
@@ -96,9 +92,22 @@ export function remarkShiki({
);
}
+ // theme.id for shiki -> shikiji compat
+ const themeName = typeof theme === 'string' ? theme : theme.name;
+ if (themeName === 'css-variables') {
+ html = html.replace(/style="(.*?)"/g, (m) => replaceCssVariables(m));
+ }
+
node.type = 'html';
node.value = html;
node.children = [];
});
};
}
+
+/**
+ * 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);
+}
diff --git a/packages/markdown/remark/src/types.ts b/packages/markdown/remark/src/types.ts
index bcab97041..4abcf578d 100644
--- a/packages/markdown/remark/src/types.ts
+++ b/packages/markdown/remark/src/types.ts
@@ -5,7 +5,12 @@ import type {
all as Handlers,
Options as RemarkRehypeOptions,
} from 'remark-rehype';
-import type { ILanguageRegistration, IThemeRegistration, Theme } from 'shiki';
+import type {
+ BuiltinTheme,
+ LanguageRegistration,
+ ThemeRegistration,
+ ThemeRegistrationRaw,
+} from 'shikiji';
import type * as unified from 'unified';
import type { VFile } from 'vfile';
@@ -35,8 +40,8 @@ export type RemarkRehype = Omit<RemarkRehypeOptions, 'handlers' | 'unknownHandle
};
export interface ShikiConfig {
- langs?: ILanguageRegistration[];
- theme?: Theme | IThemeRegistration;
+ langs?: LanguageRegistration[];
+ theme?: BuiltinTheme | ThemeRegistration | ThemeRegistrationRaw;
wrap?: boolean | null;
}