@astrojs/markdown-remark 6.1.0 → 6.2.1

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.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { AstroMarkdownOptions, MarkdownProcessor } from './types.js';
1
+ import type { AstroMarkdownOptions, AstroMarkdownProcessorOptions, MarkdownProcessor } from './types.js';
2
2
  export { rehypeHeadingIds } from './rehype-collect-headings.js';
3
3
  export { remarkCollectImages } from './remark-collect-images.js';
4
4
  export { rehypePrism } from './rehype-prism.js';
@@ -10,4 +10,4 @@ export declare const markdownConfigDefaults: Required<AstroMarkdownOptions>;
10
10
  /**
11
11
  * Create a markdown preprocessor to render multiple markdown files
12
12
  */
13
- export declare function createMarkdownProcessor(opts?: AstroMarkdownOptions): Promise<MarkdownProcessor>;
13
+ export declare function createMarkdownProcessor(opts?: AstroMarkdownProcessorOptions): Promise<MarkdownProcessor>;
package/dist/index.js CHANGED
@@ -67,7 +67,7 @@ async function createMarkdownProcessor(opts) {
67
67
  parser.use(plugin, pluginOpts);
68
68
  }
69
69
  if (!isPerformanceBenchmark) {
70
- parser.use(remarkCollectImages);
70
+ parser.use(remarkCollectImages, opts?.image);
71
71
  }
72
72
  parser.use(remarkRehype, {
73
73
  allowDangerousHtml: true,
@@ -84,7 +84,7 @@ async function createMarkdownProcessor(opts) {
84
84
  for (const [plugin, pluginOpts] of loadedRehypePlugins) {
85
85
  parser.use(plugin, pluginOpts);
86
86
  }
87
- parser.use(rehypeImages());
87
+ parser.use(rehypeImages);
88
88
  if (!isPerformanceBenchmark) {
89
89
  parser.use(rehypeHeadingIds);
90
90
  }
@@ -109,7 +109,8 @@ async function createMarkdownProcessor(opts) {
109
109
  code: String(result.value),
110
110
  metadata: {
111
111
  headings: result.data.astro?.headings ?? [],
112
- imagePaths: result.data.astro?.imagePaths ?? [],
112
+ localImagePaths: result.data.astro?.localImagePaths ?? [],
113
+ remoteImagePaths: result.data.astro?.remoteImagePaths ?? [],
113
114
  frontmatter: result.data.astro?.frontmatter ?? {}
114
115
  }
115
116
  };
@@ -1,2 +1,3 @@
1
+ import type { Root } from 'hast';
1
2
  import type { VFile } from 'vfile';
2
- export declare function rehypeImages(): () => (tree: any, file: VFile) => void;
3
+ export declare function rehypeImages(): (tree: Root, file: VFile) => void;
@@ -1,22 +1,30 @@
1
1
  import { visit } from "unist-util-visit";
2
2
  function rehypeImages() {
3
- return () => function(tree, file) {
3
+ return function(tree, file) {
4
+ if (!file.data.astro?.localImagePaths?.length && !file.data.astro?.remoteImagePaths?.length) {
5
+ return;
6
+ }
4
7
  const imageOccurrenceMap = /* @__PURE__ */ new Map();
5
- visit(tree, (node) => {
6
- if (node.type !== "element") return;
8
+ visit(tree, "element", (node) => {
7
9
  if (node.tagName !== "img") return;
8
- if (node.properties?.src) {
9
- node.properties.src = decodeURI(node.properties.src);
10
- if (file.data.astro?.imagePaths?.includes(node.properties.src)) {
11
- const { ...props } = node.properties;
12
- const index = imageOccurrenceMap.get(node.properties.src) || 0;
13
- imageOccurrenceMap.set(node.properties.src, index + 1);
14
- node.properties["__ASTRO_IMAGE_"] = JSON.stringify({ ...props, index });
15
- Object.keys(props).forEach((prop) => {
16
- delete node.properties[prop];
17
- });
18
- }
10
+ if (typeof node.properties?.src !== "string") return;
11
+ const src = decodeURI(node.properties.src);
12
+ let newProperties;
13
+ if (file.data.astro?.localImagePaths?.includes(src)) {
14
+ newProperties = { ...node.properties, src };
15
+ } else if (file.data.astro?.remoteImagePaths?.includes(src)) {
16
+ newProperties = {
17
+ // By default, markdown images won't have width and height set. However, just in case another user plugin does set these, we should respect them.
18
+ inferSize: "width" in node.properties && "height" in node.properties ? void 0 : true,
19
+ ...node.properties,
20
+ src
21
+ };
22
+ } else {
23
+ return;
19
24
  }
25
+ const index = imageOccurrenceMap.get(node.properties.src) || 0;
26
+ imageOccurrenceMap.set(node.properties.src, index + 1);
27
+ node.properties = { __ASTRO_IMAGE_: JSON.stringify({ ...newProperties, index }) };
20
28
  });
21
29
  };
22
30
  }
@@ -1,2 +1,4 @@
1
+ import type { Root } from 'mdast';
1
2
  import type { VFile } from 'vfile';
2
- export declare function remarkCollectImages(): (tree: any, vfile: VFile) => void;
3
+ import type { AstroMarkdownProcessorOptions } from './types.js';
4
+ export declare function remarkCollectImages(opts: AstroMarkdownProcessorOptions['image']): (tree: Root, vfile: VFile) => void;
@@ -1,37 +1,38 @@
1
+ import { isRemoteAllowed } from "@astrojs/internal-helpers/remote";
1
2
  import { definitions } from "mdast-util-definitions";
2
3
  import { visit } from "unist-util-visit";
3
- function remarkCollectImages() {
4
+ function remarkCollectImages(opts) {
5
+ const domains = opts?.domains ?? [];
6
+ const remotePatterns = opts?.remotePatterns ?? [];
4
7
  return function(tree, vfile) {
5
8
  if (typeof vfile?.path !== "string") return;
6
9
  const definition = definitions(tree);
7
- const imagePaths = /* @__PURE__ */ new Set();
8
- visit(tree, ["image", "imageReference"], (node) => {
10
+ const localImagePaths = /* @__PURE__ */ new Set();
11
+ const remoteImagePaths = /* @__PURE__ */ new Set();
12
+ visit(tree, (node) => {
13
+ let url;
9
14
  if (node.type === "image") {
10
- if (shouldOptimizeImage(node.url)) imagePaths.add(decodeURI(node.url));
11
- }
12
- if (node.type === "imageReference") {
15
+ url = decodeURI(node.url);
16
+ } else if (node.type === "imageReference") {
13
17
  const imageDefinition = definition(node.identifier);
14
18
  if (imageDefinition) {
15
- if (shouldOptimizeImage(imageDefinition.url))
16
- imagePaths.add(decodeURI(imageDefinition.url));
19
+ url = decodeURI(imageDefinition.url);
20
+ }
21
+ }
22
+ if (!url) return;
23
+ if (URL.canParse(url)) {
24
+ if (isRemoteAllowed(url, { domains, remotePatterns })) {
25
+ remoteImagePaths.add(url);
17
26
  }
27
+ } else if (!url.startsWith("/")) {
28
+ localImagePaths.add(url);
18
29
  }
19
30
  });
20
31
  vfile.data.astro ??= {};
21
- vfile.data.astro.imagePaths = Array.from(imagePaths);
32
+ vfile.data.astro.localImagePaths = Array.from(localImagePaths);
33
+ vfile.data.astro.remoteImagePaths = Array.from(remoteImagePaths);
22
34
  };
23
35
  }
24
- function shouldOptimizeImage(src) {
25
- return !isValidUrl(src) && !src.startsWith("/");
26
- }
27
- function isValidUrl(str) {
28
- try {
29
- new URL(str);
30
- return true;
31
- } catch {
32
- return false;
33
- }
34
- }
35
36
  export {
36
37
  remarkCollectImages
37
38
  };
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { RemotePattern } from '@astrojs/internal-helpers/remote';
1
2
  import type * as hast from 'hast';
2
3
  import type * as mdast from 'mdast';
3
4
  import type { Options as RemarkRehypeOptions } from 'remark-rehype';
@@ -9,7 +10,8 @@ declare module 'vfile' {
9
10
  interface DataMap {
10
11
  astro: {
11
12
  headings?: MarkdownHeading[];
12
- imagePaths?: string[];
13
+ localImagePaths?: string[];
14
+ remoteImagePaths?: string[];
13
15
  frontmatter?: Record<string, any>;
14
16
  };
15
17
  }
@@ -22,6 +24,9 @@ export type RemarkRehype = RemarkRehypeOptions;
22
24
  export type ThemePresets = BuiltinTheme | 'css-variables';
23
25
  export interface ShikiConfig extends Pick<CreateShikiHighlighterOptions, 'langs' | 'theme' | 'themes' | 'langAlias'>, Pick<ShikiHighlighterHighlightOptions, 'defaultColor' | 'wrap' | 'transformers'> {
24
26
  }
27
+ /**
28
+ * Configuration options that end up in the markdown section of AstroConfig
29
+ */
25
30
  export interface AstroMarkdownOptions {
26
31
  syntaxHighlight?: 'shiki' | 'prism' | false;
27
32
  shikiConfig?: ShikiConfig;
@@ -31,6 +36,15 @@ export interface AstroMarkdownOptions {
31
36
  gfm?: boolean;
32
37
  smartypants?: boolean;
33
38
  }
39
+ /**
40
+ * Extra configuration options from other parts of AstroConfig that get injected into this plugin
41
+ */
42
+ export interface AstroMarkdownProcessorOptions extends AstroMarkdownOptions {
43
+ image?: {
44
+ domains?: string[];
45
+ remotePatterns?: RemotePattern[];
46
+ };
47
+ }
34
48
  export interface MarkdownProcessor {
35
49
  render: (content: string, opts?: MarkdownProcessorRenderOptions) => Promise<MarkdownProcessorRenderResult>;
36
50
  }
@@ -42,7 +56,8 @@ export interface MarkdownProcessorRenderResult {
42
56
  code: string;
43
57
  metadata: {
44
58
  headings: MarkdownHeading[];
45
- imagePaths: string[];
59
+ localImagePaths: string[];
60
+ remoteImagePaths: string[];
46
61
  frontmatter: Record<string, any>;
47
62
  };
48
63
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/markdown-remark",
3
- "version": "6.1.0",
3
+ "version": "6.2.1",
4
4
  "type": "module",
5
5
  "author": "withastro",
6
6
  "license": "MIT",
@@ -33,17 +33,18 @@
33
33
  "mdast-util-definitions": "^6.0.0",
34
34
  "rehype-raw": "^7.0.0",
35
35
  "rehype-stringify": "^10.0.1",
36
- "remark-gfm": "^4.0.0",
36
+ "remark-gfm": "^4.0.1",
37
37
  "remark-parse": "^11.0.0",
38
38
  "remark-rehype": "^11.1.1",
39
39
  "remark-smartypants": "^3.0.2",
40
- "shiki": "^1.29.1",
40
+ "shiki": "^1.29.2",
41
41
  "smol-toml": "^1.3.1",
42
42
  "unified": "^11.0.5",
43
43
  "unist-util-remove-position": "^5.0.0",
44
44
  "unist-util-visit": "^5.0.0",
45
45
  "unist-util-visit-parents": "^6.0.1",
46
46
  "vfile": "^6.0.3",
47
+ "@astrojs/internal-helpers": "0.6.1",
47
48
  "@astrojs/prism": "3.2.0"
48
49
  },
49
50
  "devDependencies": {