@astrojs/markdown-remark 3.1.0 → 3.2.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.
@@ -3,6 +3,10 @@ import type { MarkdownAstroData } from './types.js';
3
3
  export declare class InvalidAstroDataError extends TypeError {
4
4
  }
5
5
  export declare function safelyGetAstroData(vfileData: Data): MarkdownAstroData | InvalidAstroDataError;
6
+ export declare function setVfileFrontmatter(vfile: VFile, frontmatter: Record<string, any>): void;
7
+ /**
8
+ * @deprecated Use `setVfileFrontmatter` instead
9
+ */
6
10
  export declare function toRemarkInitializeAstroData({ userFrontmatter, }: {
7
11
  userFrontmatter: Record<string, any>;
8
12
  }): () => (tree: any, vfile: VFile) => void;
@@ -19,6 +19,11 @@ function safelyGetAstroData(vfileData) {
19
19
  }
20
20
  return astro;
21
21
  }
22
+ function setVfileFrontmatter(vfile, frontmatter) {
23
+ vfile.data ??= {};
24
+ vfile.data.astro ??= {};
25
+ vfile.data.astro.frontmatter = frontmatter;
26
+ }
22
27
  function toRemarkInitializeAstroData({
23
28
  userFrontmatter
24
29
  }) {
@@ -31,5 +36,6 @@ function toRemarkInitializeAstroData({
31
36
  export {
32
37
  InvalidAstroDataError,
33
38
  safelyGetAstroData,
39
+ setVfileFrontmatter,
34
40
  toRemarkInitializeAstroData
35
41
  };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,18 @@
1
- import type { AstroMarkdownOptions, MarkdownRenderingOptions, MarkdownRenderingResult } from './types';
1
+ import type { AstroMarkdownOptions, MarkdownProcessor, MarkdownRenderingOptions, MarkdownRenderingResult } from './types.js';
2
+ export { InvalidAstroDataError, setVfileFrontmatter } from './frontmatter-injection.js';
2
3
  export { rehypeHeadingIds } from './rehype-collect-headings.js';
3
4
  export { remarkCollectImages } from './remark-collect-images.js';
4
5
  export { remarkPrism } from './remark-prism.js';
5
6
  export { remarkShiki } from './remark-shiki.js';
6
7
  export * from './types.js';
7
8
  export declare const markdownConfigDefaults: Omit<Required<AstroMarkdownOptions>, 'drafts'>;
8
- /** Shared utility for rendering markdown */
9
+ /**
10
+ * Create a markdown preprocessor to render multiple markdown files
11
+ */
12
+ export declare function createMarkdownProcessor(opts?: AstroMarkdownOptions): Promise<MarkdownProcessor>;
13
+ /**
14
+ * Shared utility for rendering markdown
15
+ *
16
+ * @deprecated Use `createMarkdownProcessor` instead for better performance
17
+ */
9
18
  export declare function renderMarkdown(content: string, opts: MarkdownRenderingOptions): Promise<MarkdownRenderingResult>;
package/dist/index.js CHANGED
@@ -1,4 +1,8 @@
1
- import { toRemarkInitializeAstroData } from "./frontmatter-injection.js";
1
+ import {
2
+ InvalidAstroDataError,
3
+ safelyGetAstroData,
4
+ setVfileFrontmatter
5
+ } from "./frontmatter-injection.js";
2
6
  import { loadPlugins } from "./load-plugins.js";
3
7
  import { rehypeHeadingIds } from "./rehype-collect-headings.js";
4
8
  import { remarkCollectImages } from "./remark-collect-images.js";
@@ -7,12 +11,13 @@ import { remarkShiki } from "./remark-shiki.js";
7
11
  import rehypeRaw from "rehype-raw";
8
12
  import rehypeStringify from "rehype-stringify";
9
13
  import remarkGfm from "remark-gfm";
10
- import markdown from "remark-parse";
11
- import markdownToHtml from "remark-rehype";
14
+ import remarkParse from "remark-parse";
15
+ import remarkRehype from "remark-rehype";
12
16
  import remarkSmartypants from "remark-smartypants";
13
17
  import { unified } from "unified";
14
18
  import { VFile } from "vfile";
15
19
  import { rehypeImages } from "./rehype-images.js";
20
+ import { InvalidAstroDataError as InvalidAstroDataError2, setVfileFrontmatter as setVfileFrontmatter2 } from "./frontmatter-injection.js";
16
21
  import { rehypeHeadingIds as rehypeHeadingIds2 } from "./rehype-collect-headings.js";
17
22
  import { remarkCollectImages as remarkCollectImages2 } from "./remark-collect-images.js";
18
23
  import { remarkPrism as remarkPrism2 } from "./remark-prism.js";
@@ -32,21 +37,20 @@ const markdownConfigDefaults = {
32
37
  smartypants: true
33
38
  };
34
39
  const isPerformanceBenchmark = Boolean(process.env.ASTRO_PERFORMANCE_BENCHMARK);
35
- async function renderMarkdown(content, opts) {
36
- let {
37
- fileURL,
40
+ async function createMarkdownProcessor(opts) {
41
+ const {
38
42
  syntaxHighlight = markdownConfigDefaults.syntaxHighlight,
39
43
  shikiConfig = markdownConfigDefaults.shikiConfig,
40
44
  remarkPlugins = markdownConfigDefaults.remarkPlugins,
41
45
  rehypePlugins = markdownConfigDefaults.rehypePlugins,
42
- remarkRehype = markdownConfigDefaults.remarkRehype,
46
+ remarkRehype: remarkRehypeOptions = markdownConfigDefaults.remarkRehype,
43
47
  gfm = markdownConfigDefaults.gfm,
44
- smartypants = markdownConfigDefaults.smartypants,
45
- frontmatter: userFrontmatter = {}
46
- } = opts;
47
- const input = new VFile({ value: content, path: fileURL });
48
- let parser = unified().use(markdown).use(toRemarkInitializeAstroData({ userFrontmatter })).use([]);
49
- if (!isPerformanceBenchmark && gfm) {
48
+ smartypants = markdownConfigDefaults.smartypants
49
+ } = opts ?? {};
50
+ const loadedRemarkPlugins = await Promise.all(loadPlugins(remarkPlugins));
51
+ const loadedRehypePlugins = await Promise.all(loadPlugins(rehypePlugins));
52
+ const parser = unified().use(remarkParse);
53
+ if (!isPerformanceBenchmark) {
50
54
  if (gfm) {
51
55
  parser.use(remarkGfm);
52
56
  }
@@ -54,11 +58,9 @@ async function renderMarkdown(content, opts) {
54
58
  parser.use(remarkSmartypants);
55
59
  }
56
60
  }
57
- const loadedRemarkPlugins = await Promise.all(loadPlugins(remarkPlugins));
58
- const loadedRehypePlugins = await Promise.all(loadPlugins(rehypePlugins));
59
- loadedRemarkPlugins.forEach(([plugin, pluginOpts]) => {
60
- parser.use([[plugin, pluginOpts]]);
61
- });
61
+ for (const [plugin, pluginOpts] of loadedRemarkPlugins) {
62
+ parser.use(plugin, pluginOpts);
63
+ }
62
64
  if (!isPerformanceBenchmark) {
63
65
  if (syntaxHighlight === "shiki") {
64
66
  parser.use(remarkShiki, shikiConfig);
@@ -67,37 +69,61 @@ async function renderMarkdown(content, opts) {
67
69
  }
68
70
  parser.use(remarkCollectImages);
69
71
  }
70
- parser.use([
71
- [
72
- markdownToHtml,
73
- {
74
- allowDangerousHtml: true,
75
- passThrough: [],
76
- ...remarkRehype
77
- }
78
- ]
79
- ]);
80
- loadedRehypePlugins.forEach(([plugin, pluginOpts]) => {
81
- parser.use([[plugin, pluginOpts]]);
72
+ parser.use(remarkRehype, {
73
+ allowDangerousHtml: true,
74
+ passThrough: [],
75
+ ...remarkRehypeOptions
82
76
  });
77
+ for (const [plugin, pluginOpts] of loadedRehypePlugins) {
78
+ parser.use(plugin, pluginOpts);
79
+ }
83
80
  parser.use(rehypeImages());
84
81
  if (!isPerformanceBenchmark) {
85
- parser.use([rehypeHeadingIds]);
82
+ parser.use(rehypeHeadingIds);
86
83
  }
87
- parser.use([rehypeRaw]).use(rehypeStringify, { allowDangerousHtml: true });
88
- let vfile;
89
- try {
90
- vfile = await parser.process(input);
91
- } catch (err) {
92
- err = prefixError(err, `Failed to parse Markdown file "${input.path}"`);
93
- console.error(err);
94
- throw err;
95
- }
96
- const headings = vfile?.data.__astroHeadings || [];
84
+ parser.use(rehypeRaw).use(rehypeStringify, { allowDangerousHtml: true });
85
+ return {
86
+ async render(content, renderOpts) {
87
+ const vfile = new VFile({ value: content, path: renderOpts?.fileURL });
88
+ setVfileFrontmatter(vfile, renderOpts?.frontmatter ?? {});
89
+ const result = await parser.process(vfile).catch((err) => {
90
+ err = prefixError(err, `Failed to parse Markdown file "${vfile.path}"`);
91
+ console.error(err);
92
+ throw err;
93
+ });
94
+ const astroData = safelyGetAstroData(result.data);
95
+ if (astroData instanceof InvalidAstroDataError) {
96
+ throw astroData;
97
+ }
98
+ return {
99
+ code: String(result.value),
100
+ metadata: {
101
+ headings: result.data.__astroHeadings ?? [],
102
+ imagePaths: result.data.imagePaths ?? /* @__PURE__ */ new Set(),
103
+ frontmatter: astroData.frontmatter ?? {}
104
+ },
105
+ // Compat for `renderMarkdown` only. Do not use!
106
+ __renderMarkdownCompat: {
107
+ result
108
+ }
109
+ };
110
+ }
111
+ };
112
+ }
113
+ async function renderMarkdown(content, opts) {
114
+ const processor = await createMarkdownProcessor(opts);
115
+ const result = await processor.render(content, {
116
+ fileURL: opts.fileURL,
117
+ frontmatter: opts.frontmatter
118
+ });
97
119
  return {
98
- metadata: { headings, source: content, html: String(vfile.value) },
99
- code: String(vfile.value),
100
- vfile
120
+ code: result.code,
121
+ metadata: {
122
+ headings: result.metadata.headings,
123
+ source: content,
124
+ html: result.code
125
+ },
126
+ vfile: result.__renderMarkdownCompat.result
101
127
  };
102
128
  }
103
129
  function prefixError(err, prefix) {
@@ -118,10 +144,13 @@ ${err.message}`;
118
144
  return wrappedError;
119
145
  }
120
146
  export {
147
+ InvalidAstroDataError2 as InvalidAstroDataError,
148
+ createMarkdownProcessor,
121
149
  markdownConfigDefaults,
122
150
  rehypeHeadingIds2 as rehypeHeadingIds,
123
151
  remarkCollectImages2 as remarkCollectImages,
124
152
  remarkPrism2 as remarkPrism,
125
153
  remarkShiki2 as remarkShiki,
126
- renderMarkdown
154
+ renderMarkdown,
155
+ setVfileFrontmatter2 as setVfileFrontmatter
127
156
  };
@@ -9,7 +9,7 @@ async function importPlugin(p) {
9
9
  return importResult2.default;
10
10
  } catch {
11
11
  }
12
- const resolved = await importMetaResolve(p, cwdUrlStr);
12
+ const resolved = importMetaResolve(p, cwdUrlStr);
13
13
  const importResult = await import(resolved);
14
14
  return importResult.default;
15
15
  }
@@ -1,2 +1,2 @@
1
- import type { MarkdownVFile } from './types';
1
+ import type { MarkdownVFile } from './types.js';
2
2
  export declare function remarkCollectImages(): (tree: any, vfile: MarkdownVFile) => void;
@@ -1,12 +1,23 @@
1
+ import { definitions } from "mdast-util-definitions";
1
2
  import { visit } from "unist-util-visit";
2
3
  function remarkCollectImages() {
3
4
  return function(tree, vfile) {
4
5
  if (typeof vfile?.path !== "string")
5
6
  return;
7
+ const definition = definitions(tree);
6
8
  const imagePaths = /* @__PURE__ */ new Set();
7
- visit(tree, "image", (node) => {
8
- if (shouldOptimizeImage(node.url))
9
- imagePaths.add(node.url);
9
+ visit(tree, ["image", "imageReference"], (node) => {
10
+ if (node.type === "image") {
11
+ if (shouldOptimizeImage(node.url))
12
+ imagePaths.add(node.url);
13
+ }
14
+ if (node.type === "imageReference") {
15
+ const imageDefinition = definition(node.identifier);
16
+ if (imageDefinition) {
17
+ if (shouldOptimizeImage(imageDefinition.url))
18
+ imagePaths.add(imageDefinition.url);
19
+ }
20
+ }
10
21
  });
11
22
  vfile.data.imagePaths = imagePaths;
12
23
  };
package/dist/types.d.ts CHANGED
@@ -37,12 +37,25 @@ export interface ImageMetadata {
37
37
  height: number;
38
38
  type: string;
39
39
  }
40
- export interface MarkdownRenderingOptions extends AstroMarkdownOptions {
40
+ export interface MarkdownProcessor {
41
+ render: (content: string, opts?: MarkdownProcessorRenderOptions) => Promise<MarkdownProcessorRenderResult>;
42
+ }
43
+ export interface MarkdownProcessorRenderOptions {
41
44
  /** @internal */
42
45
  fileURL?: URL;
43
46
  /** Used for frontmatter injection plugins */
44
47
  frontmatter?: Record<string, any>;
45
48
  }
49
+ export interface MarkdownProcessorRenderResult {
50
+ code: string;
51
+ metadata: {
52
+ headings: MarkdownHeading[];
53
+ imagePaths: Set<string>;
54
+ frontmatter: Record<string, any>;
55
+ };
56
+ }
57
+ export interface MarkdownRenderingOptions extends AstroMarkdownOptions, MarkdownProcessorRenderOptions {
58
+ }
46
59
  export interface MarkdownHeading {
47
60
  depth: number;
48
61
  slug: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/markdown-remark",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "type": "module",
5
5
  "author": "withastro",
6
6
  "license": "MIT",
@@ -20,12 +20,13 @@
20
20
  "dist"
21
21
  ],
22
22
  "peerDependencies": {
23
- "astro": "^3.0.11"
23
+ "astro": "^3.1.0"
24
24
  },
25
25
  "dependencies": {
26
26
  "@astrojs/prism": "^3.0.0",
27
27
  "github-slugger": "^2.0.0",
28
28
  "import-meta-resolve": "^3.0.0",
29
+ "mdast-util-definitions": "^6.0.0",
29
30
  "rehype-raw": "^6.1.1",
30
31
  "rehype-stringify": "^9.0.4",
31
32
  "remark-gfm": "^3.0.1",