@astrojs/markdown-remark 4.2.1 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import type { VFileData as Data, VFile } from 'vfile';
1
+ import type { VFile, VFileData as Data } from 'vfile';
2
2
  import type { MarkdownAstroData } from './types.js';
3
3
  export declare class InvalidAstroDataError extends TypeError {
4
4
  }
@@ -0,0 +1,13 @@
1
+ import type { Root } from 'hast';
2
+ type Highlighter = (code: string, language: string) => string;
3
+ /**
4
+ * A hast utility to syntax highlight code blocks with a given syntax highlighter.
5
+ *
6
+ * @param tree
7
+ * The hast tree in which to syntax highlight code blocks.
8
+ * @param highlighter
9
+ * A fnction which receives the code and language, and returns the HTML of a syntax
10
+ * highlighted `<pre>` element.
11
+ */
12
+ export declare function highlightCodeBlocks(tree: Root, highlighter: Highlighter): void;
13
+ export {};
@@ -0,0 +1,44 @@
1
+ import { fromHtml } from "hast-util-from-html";
2
+ import { toText } from "hast-util-to-text";
3
+ import { removePosition } from "unist-util-remove-position";
4
+ import { visitParents } from "unist-util-visit-parents";
5
+ const languagePattern = /\blanguage-(\S+)\b/;
6
+ function highlightCodeBlocks(tree, highlighter) {
7
+ visitParents(tree, { type: "element", tagName: "code" }, (node, ancestors) => {
8
+ const parent = ancestors.at(-1);
9
+ if (parent?.type !== "element" || parent.tagName !== "pre") {
10
+ return;
11
+ }
12
+ if (parent.children.length !== 1) {
13
+ return;
14
+ }
15
+ let languageMatch;
16
+ let { className } = node.properties;
17
+ if (typeof className === "string") {
18
+ languageMatch = className.match(languagePattern);
19
+ } else if (Array.isArray(className)) {
20
+ for (const cls of className) {
21
+ if (typeof cls !== "string") {
22
+ continue;
23
+ }
24
+ languageMatch = cls.match(languagePattern);
25
+ if (languageMatch) {
26
+ break;
27
+ }
28
+ }
29
+ }
30
+ if (languageMatch?.[1] === "math") {
31
+ return;
32
+ }
33
+ const code = toText(node, { whitespace: "pre" });
34
+ const html = highlighter(code, languageMatch?.[1] || "plaintext");
35
+ const replacement = fromHtml(html, { fragment: true }).children[0];
36
+ removePosition(replacement);
37
+ const grandParent = ancestors.at(-2);
38
+ const index = grandParent.children.indexOf(parent);
39
+ grandParent.children[index] = replacement;
40
+ });
41
+ }
42
+ export {
43
+ highlightCodeBlocks
44
+ };
@@ -1,6 +1,6 @@
1
- import { resolve as importMetaResolve } from "import-meta-resolve";
2
1
  import path from "node:path";
3
2
  import { pathToFileURL } from "node:url";
3
+ import { resolve as importMetaResolve } from "import-meta-resolve";
4
4
  let cwdUrlStr;
5
5
  async function importPlugin(p) {
6
6
  try {
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ import type { AstroMarkdownOptions, MarkdownProcessor } from './types.js';
2
2
  export { InvalidAstroDataError, setVfileFrontmatter } from './frontmatter-injection.js';
3
3
  export { rehypeHeadingIds } from './rehype-collect-headings.js';
4
4
  export { remarkCollectImages } from './remark-collect-images.js';
5
+ export { rehypePrism } from './rehype-prism.js';
6
+ export { rehypeShiki } from './rehype-shiki.js';
5
7
  export { remarkPrism } from './remark-prism.js';
6
8
  export { remarkShiki } from './remark-shiki.js';
7
9
  export { createShikiHighlighter, replaceCssVariables, type ShikiHighlighter } from './shiki.js';
package/dist/index.js CHANGED
@@ -5,9 +5,9 @@ import {
5
5
  } from "./frontmatter-injection.js";
6
6
  import { loadPlugins } from "./load-plugins.js";
7
7
  import { rehypeHeadingIds } from "./rehype-collect-headings.js";
8
+ import { rehypePrism } from "./rehype-prism.js";
9
+ import { rehypeShiki } from "./rehype-shiki.js";
8
10
  import { remarkCollectImages } from "./remark-collect-images.js";
9
- import { remarkPrism } from "./remark-prism.js";
10
- import { remarkShiki } from "./remark-shiki.js";
11
11
  import rehypeRaw from "rehype-raw";
12
12
  import rehypeStringify from "rehype-stringify";
13
13
  import remarkGfm from "remark-gfm";
@@ -20,8 +20,10 @@ import { rehypeImages } from "./rehype-images.js";
20
20
  import { InvalidAstroDataError as InvalidAstroDataError2, setVfileFrontmatter as setVfileFrontmatter2 } from "./frontmatter-injection.js";
21
21
  import { rehypeHeadingIds as rehypeHeadingIds2 } from "./rehype-collect-headings.js";
22
22
  import { remarkCollectImages as remarkCollectImages2 } from "./remark-collect-images.js";
23
- import { remarkPrism as remarkPrism2 } from "./remark-prism.js";
24
- import { remarkShiki as remarkShiki2 } from "./remark-shiki.js";
23
+ import { rehypePrism as rehypePrism2 } from "./rehype-prism.js";
24
+ import { rehypeShiki as rehypeShiki2 } from "./rehype-shiki.js";
25
+ import { remarkPrism } from "./remark-prism.js";
26
+ import { remarkShiki } from "./remark-shiki.js";
25
27
  import { createShikiHighlighter, replaceCssVariables } from "./shiki.js";
26
28
  export * from "./types.js";
27
29
  const markdownConfigDefaults = {
@@ -29,7 +31,7 @@ const markdownConfigDefaults = {
29
31
  shikiConfig: {
30
32
  langs: [],
31
33
  theme: "github-dark",
32
- experimentalThemes: {},
34
+ themes: {},
33
35
  wrap: false,
34
36
  transformers: []
35
37
  },
@@ -65,11 +67,6 @@ async function createMarkdownProcessor(opts) {
65
67
  parser.use(plugin, pluginOpts);
66
68
  }
67
69
  if (!isPerformanceBenchmark) {
68
- if (syntaxHighlight === "shiki") {
69
- parser.use(remarkShiki, shikiConfig);
70
- } else if (syntaxHighlight === "prism") {
71
- parser.use(remarkPrism);
72
- }
73
70
  parser.use(remarkCollectImages);
74
71
  }
75
72
  parser.use(remarkRehype, {
@@ -77,6 +74,13 @@ async function createMarkdownProcessor(opts) {
77
74
  passThrough: [],
78
75
  ...remarkRehypeOptions
79
76
  });
77
+ if (!isPerformanceBenchmark) {
78
+ if (syntaxHighlight === "shiki") {
79
+ parser.use(rehypeShiki, shikiConfig);
80
+ } else if (syntaxHighlight === "prism") {
81
+ parser.use(rehypePrism);
82
+ }
83
+ }
80
84
  for (const [plugin, pluginOpts] of loadedRehypePlugins) {
81
85
  parser.use(plugin, pluginOpts);
82
86
  }
@@ -132,9 +136,11 @@ export {
132
136
  createShikiHighlighter,
133
137
  markdownConfigDefaults,
134
138
  rehypeHeadingIds2 as rehypeHeadingIds,
139
+ rehypePrism2 as rehypePrism,
140
+ rehypeShiki2 as rehypeShiki,
135
141
  remarkCollectImages2 as remarkCollectImages,
136
- remarkPrism2 as remarkPrism,
137
- remarkShiki2 as remarkShiki,
142
+ remarkPrism,
143
+ remarkShiki,
138
144
  replaceCssVariables,
139
145
  setVfileFrontmatter2 as setVfileFrontmatter
140
146
  };
@@ -0,0 +1,3 @@
1
+ import type { Root } from 'hast';
2
+ import type { Plugin } from 'unified';
3
+ export declare const rehypePrism: Plugin<[], Root>;
@@ -0,0 +1,11 @@
1
+ import { runHighlighterWithAstro } from "@astrojs/prism/dist/highlighter";
2
+ import { highlightCodeBlocks } from "./highlight.js";
3
+ const rehypePrism = () => (tree) => {
4
+ highlightCodeBlocks(tree, (code, language) => {
5
+ let { html, classLanguage } = runHighlighterWithAstro(language, code);
6
+ return `<pre class="${classLanguage}"><code is:raw class="${classLanguage}">${html}</code></pre>`;
7
+ });
8
+ };
9
+ export {
10
+ rehypePrism
11
+ };
@@ -0,0 +1,4 @@
1
+ import type { Root } from 'hast';
2
+ import type { Plugin } from 'unified';
3
+ import type { ShikiConfig } from './types.js';
4
+ export declare const rehypeShiki: Plugin<[ShikiConfig?], Root>;
@@ -0,0 +1,13 @@
1
+ import { highlightCodeBlocks } from "./highlight.js";
2
+ import { createShikiHighlighter } from "./shiki.js";
3
+ const rehypeShiki = (config) => {
4
+ let highlighterAsync;
5
+ return async (tree) => {
6
+ highlighterAsync ??= createShikiHighlighter(config);
7
+ const highlighter = await highlighterAsync;
8
+ highlightCodeBlocks(tree, highlighter.highlight);
9
+ };
10
+ };
11
+ export {
12
+ rehypeShiki
13
+ };
@@ -1,2 +1,5 @@
1
1
  import type { RemarkPlugin } from './types.js';
2
+ /**
3
+ * @deprecated Use `rehypePrism` instead
4
+ */
2
5
  export declare function remarkPrism(): ReturnType<RemarkPlugin>;
@@ -1,2 +1,5 @@
1
1
  import type { RemarkPlugin, ShikiConfig } from './types.js';
2
+ /**
3
+ * @deprecated Use `rehypeShiki` instead
4
+ */
2
5
  export declare function remarkShiki(config?: ShikiConfig): ReturnType<RemarkPlugin>;
package/dist/shiki.d.ts CHANGED
@@ -2,6 +2,7 @@ import type { ShikiConfig } from './types.js';
2
2
  export interface ShikiHighlighter {
3
3
  highlight(code: string, lang?: string, options?: {
4
4
  inline?: boolean;
5
+ attributes?: Record<string, string>;
5
6
  }): string;
6
7
  }
7
- export declare function createShikiHighlighter({ langs, theme, experimentalThemes, wrap, transformers, }?: ShikiConfig): Promise<ShikiHighlighter>;
8
+ export declare function createShikiHighlighter({ langs, theme, themes, wrap, transformers, }?: ShikiConfig): Promise<ShikiHighlighter>;
package/dist/shiki.js CHANGED
@@ -1,11 +1,11 @@
1
- import { bundledLanguages, createCssVariablesTheme, getHighlighter } from "shikiji";
1
+ import { bundledLanguages, createCssVariablesTheme, getHighlighter } from "shiki";
2
2
  import { visit } from "unist-util-visit";
3
3
  const ASTRO_COLOR_REPLACEMENTS = {
4
4
  "--astro-code-foreground": "--astro-code-color-text",
5
5
  "--astro-code-background": "--astro-code-color-background"
6
6
  };
7
7
  const COLOR_REPLACEMENT_REGEX = new RegExp(
8
- `(${Object.keys(ASTRO_COLOR_REPLACEMENTS).join("|")})`,
8
+ `${Object.keys(ASTRO_COLOR_REPLACEMENTS).join("|")}`,
9
9
  "g"
10
10
  );
11
11
  let _cssVariablesTheme;
@@ -13,11 +13,10 @@ const cssVariablesTheme = () => _cssVariablesTheme ?? (_cssVariablesTheme = crea
13
13
  async function createShikiHighlighter({
14
14
  langs = [],
15
15
  theme = "github-dark",
16
- experimentalThemes = {},
16
+ themes = {},
17
17
  wrap = false,
18
18
  transformers = []
19
19
  } = {}) {
20
- const themes = experimentalThemes;
21
20
  theme = theme === "css-variables" ? cssVariablesTheme() : theme;
22
21
  const highlighter = await getHighlighter({
23
22
  langs: langs.length ? langs : Object.keys(bundledLanguages),
@@ -41,8 +40,14 @@ async function createShikiHighlighter({
41
40
  if (inline) {
42
41
  node.tagName = "code";
43
42
  }
44
- const classValue = normalizePropAsString(node.properties.class) ?? "";
45
- const styleValue = normalizePropAsString(node.properties.style) ?? "";
43
+ const {
44
+ class: attributesClass,
45
+ style: attributesStyle,
46
+ ...rest
47
+ } = options?.attributes ?? {};
48
+ Object.assign(node.properties, rest);
49
+ const classValue = (normalizePropAsString(node.properties.class) ?? "") + (attributesClass ? ` ${attributesClass}` : "");
50
+ const styleValue = (normalizePropAsString(node.properties.style) ?? "") + (attributesStyle ? `; ${attributesStyle}` : "");
46
51
  node.properties.class = classValue.replace(/shiki/g, "astro-code");
47
52
  if (wrap === false) {
48
53
  node.properties.style = styleValue + "; overflow-x: auto;";
@@ -74,7 +79,7 @@ async function createShikiHighlighter({
74
79
  }
75
80
  },
76
81
  root(node) {
77
- if (Object.values(experimentalThemes).length) {
82
+ if (Object.values(themes).length) {
78
83
  return;
79
84
  }
80
85
  const themeName = typeof theme === "string" ? theme : theme.name;
package/dist/types.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type * as hast from 'hast';
2
2
  import type * as mdast from 'mdast';
3
3
  import type { Options as RemarkRehypeOptions } from 'remark-rehype';
4
- import type { BuiltinTheme, LanguageRegistration, ShikijiTransformer, ThemeRegistration, ThemeRegistrationRaw } from 'shikiji';
4
+ import type { BuiltinTheme, LanguageRegistration, ShikiTransformer, ThemeRegistration, ThemeRegistrationRaw } from 'shiki';
5
5
  import type * as unified from 'unified';
6
6
  import type { VFile } from 'vfile';
7
7
  export type { Node } from 'unist';
@@ -17,9 +17,9 @@ export type ThemePresets = BuiltinTheme | 'css-variables';
17
17
  export interface ShikiConfig {
18
18
  langs?: LanguageRegistration[];
19
19
  theme?: ThemePresets | ThemeRegistration | ThemeRegistrationRaw;
20
- experimentalThemes?: Record<string, ThemePresets | ThemeRegistration | ThemeRegistrationRaw>;
20
+ themes?: Record<string, ThemePresets | ThemeRegistration | ThemeRegistrationRaw>;
21
21
  wrap?: boolean | null;
22
- transformers?: ShikijiTransformer[];
22
+ transformers?: ShikiTransformer[];
23
23
  }
24
24
  export interface AstroMarkdownOptions {
25
25
  syntaxHighlight?: 'shiki' | 'prism' | false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/markdown-remark",
3
- "version": "4.2.1",
3
+ "version": "4.3.0",
4
4
  "type": "module",
5
5
  "author": "withastro",
6
6
  "license": "MIT",
@@ -28,6 +28,8 @@
28
28
  "dependencies": {
29
29
  "@astrojs/prism": "^3.0.0",
30
30
  "github-slugger": "^2.0.0",
31
+ "hast-util-from-html": "^2.0.0",
32
+ "hast-util-to-text": "^4.0.0",
31
33
  "import-meta-resolve": "^4.0.0",
32
34
  "mdast-util-definitions": "^6.0.0",
33
35
  "rehype-raw": "^7.0.0",
@@ -36,9 +38,11 @@
36
38
  "remark-parse": "^11.0.0",
37
39
  "remark-rehype": "^11.0.0",
38
40
  "remark-smartypants": "^2.0.0",
39
- "shikiji": "^0.9.18",
41
+ "shiki": "^1.1.2",
40
42
  "unified": "^11.0.4",
43
+ "unist-util-remove-position": "^5.0.0",
41
44
  "unist-util-visit": "^5.0.0",
45
+ "unist-util-visit-parents": "^6.0.0",
42
46
  "vfile": "^6.0.1"
43
47
  },
44
48
  "devDependencies": {
@@ -48,10 +52,8 @@
48
52
  "@types/mdast": "^4.0.3",
49
53
  "@types/mocha": "^10.0.4",
50
54
  "@types/unist": "^3.0.2",
51
- "chai": "^4.3.7",
52
55
  "esbuild": "^0.19.6",
53
56
  "mdast-util-mdx-expression": "^2.0.0",
54
- "mocha": "^10.2.0",
55
57
  "astro-scripts": "0.0.14"
56
58
  },
57
59
  "publishConfig": {
@@ -63,6 +65,6 @@
63
65
  "build:ci": "astro-scripts build \"src/**/*.ts\"",
64
66
  "postbuild": "astro-scripts copy \"src/**/*.js\"",
65
67
  "dev": "astro-scripts dev \"src/**/*.ts\"",
66
- "test": "mocha --exit --timeout 20000"
68
+ "test": "astro-scripts test \"test/**/*.test.js\""
67
69
  }
68
70
  }