@astrojs/markdown-remark 0.11.1 → 0.11.4

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.
@@ -0,0 +1,5 @@
1
+ @astrojs/markdown-remark:build: cache hit, replaying output 11f745aa911f62c3
2
+ @astrojs/markdown-remark:build: 
3
+ @astrojs/markdown-remark:build: > @astrojs/markdown-remark@0.11.4 build /home/runner/work/astro/astro/packages/markdown/remark
4
+ @astrojs/markdown-remark:build: > astro-scripts build "src/**/*.ts" && tsc -p tsconfig.json
5
+ @astrojs/markdown-remark:build: 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @astrojs/markdown-remark
2
2
 
3
+ ## 0.11.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`1cc5b7890`](https://github.com/withastro/astro/commit/1cc5b78905633608e5b07ad291f916f54e67feb1)]:
8
+ - @astrojs/prism@0.5.0
9
+
10
+ ## 0.11.3
11
+
12
+ ### Patch Changes
13
+
14
+ - [#3638](https://github.com/withastro/astro/pull/3638) [`80c71c7c`](https://github.com/withastro/astro/commit/80c71c7c56d15dc05ec0c5a848130aad222d7d51) Thanks [@tony-sull](https://github.com/tony-sull)! - Fix: HTML comments in markdown code blocks should not be wrapped in JS comments
15
+
16
+ * [#3612](https://github.com/withastro/astro/pull/3612) [`fca58cfd`](https://github.com/withastro/astro/commit/fca58cfd91b68501ec82350ab023170b208d8ce7) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix: "vpath" import error when building for netlify edge
17
+
18
+ - [#3630](https://github.com/withastro/astro/pull/3630) [`48e67fe0`](https://github.com/withastro/astro/commit/48e67fe05398dc4b1fca12db36c1b37bb341277a) Thanks [@tony-sull](https://github.com/tony-sull)! - Encodes ampersand characters in code blocks
19
+
20
+ * [#3620](https://github.com/withastro/astro/pull/3620) [`05aa7244`](https://github.com/withastro/astro/commit/05aa72442cd4512b94abdb39623e8caa2c1839b0) Thanks [@hippotastic](https://github.com/hippotastic)! - Remove extra newlines around Markdown components
21
+
22
+ ## 0.11.2
23
+
24
+ ### Patch Changes
25
+
26
+ - [#3572](https://github.com/withastro/astro/pull/3572) [`5c73f614`](https://github.com/withastro/astro/commit/5c73f614e8f579e04fe61c948b69be7bc6d81d5d) Thanks [@hippotastic](https://github.com/hippotastic)! - Fix remarkMdxish performance issue on huge sites
27
+
3
28
  ## 0.11.1
4
29
 
5
30
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -2,6 +2,5 @@ import type { MarkdownRenderingOptions, MarkdownRenderingResult } from './types'
2
2
  export * from './types.js';
3
3
  export declare const DEFAULT_REMARK_PLUGINS: string[];
4
4
  export declare const DEFAULT_REHYPE_PLUGINS: never[];
5
- export declare function slug(value: string): string;
6
5
  /** Shared utility for rendering markdown */
7
6
  export declare function renderMarkdown(content: string, opts?: MarkdownRenderingOptions): Promise<MarkdownRenderingResult>;
package/dist/index.js CHANGED
@@ -4,13 +4,13 @@ import rehypeEscape from "./rehype-escape.js";
4
4
  import rehypeExpressions from "./rehype-expressions.js";
5
5
  import rehypeIslands from "./rehype-islands.js";
6
6
  import rehypeJsx from "./rehype-jsx.js";
7
+ import remarkEscape from "./remark-escape.js";
7
8
  import remarkMarkAndUnravel from "./remark-mark-and-unravel.js";
8
9
  import remarkMdxish from "./remark-mdxish.js";
9
10
  import remarkPrism from "./remark-prism.js";
10
11
  import scopedStyles from "./remark-scoped-styles.js";
11
12
  import remarkShiki from "./remark-shiki.js";
12
13
  import remarkUnwrap from "./remark-unwrap.js";
13
- import Slugger from "github-slugger";
14
14
  import rehypeRaw from "rehype-raw";
15
15
  import rehypeStringify from "rehype-stringify";
16
16
  import markdown from "remark-parse";
@@ -20,10 +20,6 @@ import { VFile } from "vfile";
20
20
  export * from "./types.js";
21
21
  const DEFAULT_REMARK_PLUGINS = ["remark-gfm", "remark-smartypants"];
22
22
  const DEFAULT_REHYPE_PLUGINS = [];
23
- const slugger = new Slugger();
24
- function slug(value) {
25
- return slugger.slug(value);
26
- }
27
23
  async function renderMarkdown(content, opts = {}) {
28
24
  var _a;
29
25
  let {
@@ -38,15 +34,15 @@ async function renderMarkdown(content, opts = {}) {
38
34
  const scopedClassName = (_a = opts.$) == null ? void 0 : _a.scopedClassName;
39
35
  const isMDX = mode === "mdx";
40
36
  const { headers, rehypeCollectHeaders } = createCollectHeaders();
41
- let parser = unified().use(markdown).use(isMDX ? [remarkMdxish, remarkMarkAndUnravel] : []).use([remarkUnwrap]);
37
+ let parser = unified().use(markdown).use(isMDX ? [remarkMdxish, remarkMarkAndUnravel] : []).use([remarkUnwrap, remarkEscape]);
42
38
  if (remarkPlugins.length === 0 && rehypePlugins.length === 0) {
43
39
  remarkPlugins = [...DEFAULT_REMARK_PLUGINS];
44
40
  rehypePlugins = [...DEFAULT_REHYPE_PLUGINS];
45
41
  }
46
42
  const loadedRemarkPlugins = await Promise.all(loadPlugins(remarkPlugins));
47
43
  const loadedRehypePlugins = await Promise.all(loadPlugins(rehypePlugins));
48
- loadedRemarkPlugins.forEach(([plugin, opts2]) => {
49
- parser.use([[plugin, opts2]]);
44
+ loadedRemarkPlugins.forEach(([plugin, pluginOpts]) => {
45
+ parser.use([[plugin, pluginOpts]]);
50
46
  });
51
47
  if (scopedClassName) {
52
48
  parser.use([scopedStyles(scopedClassName)]);
@@ -71,8 +67,8 @@ async function renderMarkdown(content, opts = {}) {
71
67
  }
72
68
  ]
73
69
  ]);
74
- loadedRehypePlugins.forEach(([plugin, opts2]) => {
75
- parser.use([[plugin, opts2]]);
70
+ loadedRehypePlugins.forEach(([plugin, pluginOpts]) => {
71
+ parser.use([[plugin, pluginOpts]]);
76
72
  });
77
73
  parser.use(isMDX ? [rehypeJsx, rehypeExpressions] : [rehypeRaw]).use(rehypeEscape).use(rehypeIslands).use([rehypeCollectHeaders]).use(rehypeStringify, { allowDangerousHtml: true });
78
74
  let result;
@@ -109,6 +105,5 @@ ${err.message}`;
109
105
  export {
110
106
  DEFAULT_REHYPE_PLUGINS,
111
107
  DEFAULT_REMARK_PLUGINS,
112
- renderMarkdown,
113
- slug
108
+ renderMarkdown
114
109
  };
@@ -18,12 +18,12 @@ function createCollectHeaders() {
18
18
  const depth = Number.parseInt(level);
19
19
  let text = "";
20
20
  let isJSX = false;
21
- visit(node, (child, _2, parent) => {
21
+ visit(node, (child, __, parent) => {
22
22
  if (child.type === "element" || parent == null) {
23
23
  return;
24
24
  }
25
25
  if (child.type === "raw") {
26
- if (child.value.startsWith("\n<") || child.value.endsWith(">\n")) {
26
+ if (child.value.match(/^\n?<.*>\n?$/)) {
27
27
  return;
28
28
  }
29
29
  }
@@ -5,7 +5,7 @@ function rehypeEscape() {
5
5
  if (el.tagName === "code" || el.tagName === "pre") {
6
6
  el.properties["is:raw"] = true;
7
7
  visit(el, "raw", (raw) => {
8
- raw.value = raw.value.replace(/</g, "&lt;").replace(/>/g, "&gt;");
8
+ raw.value = raw.value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
9
9
  });
10
10
  }
11
11
  return el;
@@ -1,28 +1,9 @@
1
- var __defProp = Object.defineProperty;
2
- var __defProps = Object.defineProperties;
3
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
- var __spreadValues = (a, b) => {
9
- for (var prop in b || (b = {}))
10
- if (__hasOwnProp.call(b, prop))
11
- __defNormalProp(a, prop, b[prop]);
12
- if (__getOwnPropSymbols)
13
- for (var prop of __getOwnPropSymbols(b)) {
14
- if (__propIsEnum.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- }
17
- return a;
18
- };
19
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
1
  import { map } from "unist-util-map";
21
2
  function rehypeExpressions() {
22
3
  return function(node) {
23
4
  return map(node, (child) => {
24
5
  if (child.type === "text") {
25
- return __spreadProps(__spreadValues({}, child), { type: "raw" });
6
+ return { ...child, type: "raw" };
26
7
  }
27
8
  if (child.type === "mdxTextExpression") {
28
9
  return { type: "raw", value: `{${child.value}}` };
@@ -1,35 +1,17 @@
1
- var __defProp = Object.defineProperty;
2
- var __defProps = Object.defineProperties;
3
- var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
- var __spreadValues = (a, b) => {
9
- for (var prop in b || (b = {}))
10
- if (__hasOwnProp.call(b, prop))
11
- __defNormalProp(a, prop, b[prop]);
12
- if (__getOwnPropSymbols)
13
- for (var prop of __getOwnPropSymbols(b)) {
14
- if (__propIsEnum.call(b, prop))
15
- __defNormalProp(a, prop, b[prop]);
16
- }
17
- return a;
18
- };
19
- var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
1
  import { SKIP, visit as _visit } from "unist-util-visit";
21
2
  const visit = _visit;
22
3
  function rehypeIslands() {
23
4
  return function(node) {
24
5
  return visit(node, "element", (el) => {
25
- if (el.tagName == "astro-root") {
6
+ if (el.tagName == "astro-island") {
26
7
  visit(el, "text", (child, index, parent) => {
27
8
  if (child.type === "text") {
28
9
  if (parent && child.value.indexOf("<!--") > -1 && index != null) {
29
- parent.children.splice(index, 1, __spreadProps(__spreadValues({}, child), {
10
+ parent.children.splice(index, 1, {
11
+ ...child,
30
12
  type: "comment",
31
13
  value: child.value.replace("<!--", "").replace("-->", "").trim()
32
- }));
14
+ });
33
15
  return [SKIP, index];
34
16
  }
35
17
  child.value = child.value.replace(/\n+/g, "");
@@ -36,13 +36,11 @@ function rehypeJsx() {
36
36
  }
37
37
  const openingTag = {
38
38
  type: "raw",
39
- value: `
40
- <${node.name}${attrs}>`
39
+ value: `<${node.name}${attrs}>`
41
40
  };
42
41
  const closingTag = {
43
42
  type: "raw",
44
- value: `</${node.name}>
45
- `
43
+ value: `</${node.name}>`
46
44
  };
47
45
  parent.children.splice(index, 1, openingTag, ...node.children, closingTag);
48
46
  });
@@ -0,0 +1 @@
1
+ export default function remarkEscape(): (tree: any) => void;
@@ -0,0 +1,13 @@
1
+ import { visit } from "unist-util-visit";
2
+ function remarkEscape() {
3
+ return (tree) => {
4
+ visit(tree, "code", removeCommentWrapper);
5
+ visit(tree, "inlineCode", removeCommentWrapper);
6
+ };
7
+ function removeCommentWrapper(node) {
8
+ node.value = node.value.replace(/{\/\*<!--/gs, "<!--").replace(/-->\*\/}/gs, "-->");
9
+ }
10
+ }
11
+ export {
12
+ remarkEscape as default
13
+ };
@@ -1 +1 @@
1
- export default function remarkMdxish(this: any, options?: {}): void;
1
+ export default function remarkMdxish(this: any): void;
@@ -1,10 +1,13 @@
1
1
  import { mdxFromMarkdown, mdxToMarkdown } from "./mdast-util-mdxish.js";
2
2
  import { mdxjs } from "./mdxjs.js";
3
- function remarkMdxish(options = {}) {
3
+ const extMdxJs = mdxjs({});
4
+ const extMdxFromMarkdown = makeFromMarkdownLessStrict(mdxFromMarkdown());
5
+ const extMdxToMarkdown = mdxToMarkdown();
6
+ function remarkMdxish() {
4
7
  const data = this.data();
5
- add("micromarkExtensions", mdxjs(options));
6
- add("fromMarkdownExtensions", makeFromMarkdownLessStrict(mdxFromMarkdown()));
7
- add("toMarkdownExtensions", mdxToMarkdown());
8
+ add("micromarkExtensions", extMdxJs);
9
+ add("fromMarkdownExtensions", extMdxFromMarkdown);
10
+ add("toMarkdownExtensions", extMdxToMarkdown);
8
11
  function add(field, value) {
9
12
  const list = data[field] ? data[field] : data[field] = [];
10
13
  list.push(value);
@@ -9,9 +9,9 @@ function runHighlighter(lang, code) {
9
9
  if (lang == null) {
10
10
  lang = "plaintext";
11
11
  }
12
- const ensureLoaded = (lang2) => {
13
- if (lang2 && !Prism.languages[lang2]) {
14
- loadLanguages([lang2]);
12
+ const ensureLoaded = (language) => {
13
+ if (language && !Prism.languages[language]) {
14
+ loadLanguages([language]);
15
15
  }
16
16
  };
17
17
  if (languageMap.has(lang)) {
@@ -7,10 +7,10 @@ function remarkUnwrap() {
7
7
  insideAstroRoot = false;
8
8
  astroRootNodes.clear();
9
9
  visit(tree, "html", (node) => {
10
- if (node.value.indexOf("<astro-root") > -1 && !insideAstroRoot) {
10
+ if (node.value.indexOf("<astro-island") > -1 && !insideAstroRoot) {
11
11
  insideAstroRoot = true;
12
12
  }
13
- if (node.value.indexOf("</astro-root") > -1 && insideAstroRoot) {
13
+ if (node.value.indexOf("</astro-island") > -1 && insideAstroRoot) {
14
14
  insideAstroRoot = false;
15
15
  }
16
16
  astroRootNodes.add(node);
@@ -0,0 +1,2 @@
1
+ /** @see {@link "/packages/astro/vite-plugin-markdown"} */
2
+ export declare function slug(value: string): string;
@@ -0,0 +1,8 @@
1
+ import Slugger from "github-slugger";
2
+ const slugger = new Slugger();
3
+ function slug(value) {
4
+ return slugger.slug(value);
5
+ }
6
+ export {
7
+ slug
8
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/markdown-remark",
3
- "version": "0.11.1",
3
+ "version": "0.11.4",
4
4
  "type": "module",
5
5
  "author": "withastro",
6
6
  "license": "MIT",
@@ -13,16 +13,17 @@
13
13
  "homepage": "https://astro.build",
14
14
  "main": "./dist/index.js",
15
15
  "exports": {
16
- ".": "./dist/index.js"
16
+ ".": "./dist/index.js",
17
+ "./ssr-utils": "./dist/ssr-utils.js"
17
18
  },
18
19
  "dependencies": {
19
20
  "@astrojs/micromark-extension-mdx-jsx": "^1.0.3",
20
- "@astrojs/prism": "^0.4.1",
21
+ "@astrojs/prism": "^0.5.0",
21
22
  "acorn": "^8.7.1",
22
23
  "acorn-jsx": "^5.3.2",
23
24
  "assert": "^2.0.0",
24
25
  "github-slugger": "^1.4.0",
25
- "mdast-util-mdx-expression": "^1.2.0",
26
+ "mdast-util-mdx-expression": "^1.2.1",
26
27
  "mdast-util-mdx-jsx": "^1.2.0",
27
28
  "mdast-util-to-string": "^3.1.0",
28
29
  "micromark-extension-mdx-expression": "^1.0.3",
@@ -49,7 +50,7 @@
49
50
  "@types/mocha": "^9.1.1",
50
51
  "@types/prismjs": "^1.26.0",
51
52
  "@types/unist": "^2.0.6",
52
- "astro-scripts": "0.0.4",
53
+ "astro-scripts": "0.0.6",
53
54
  "chai": "^4.3.6",
54
55
  "micromark-util-types": "^1.0.2",
55
56
  "mocha": "^9.2.2"
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ import rehypeEscape from './rehype-escape.js';
6
6
  import rehypeExpressions from './rehype-expressions.js';
7
7
  import rehypeIslands from './rehype-islands.js';
8
8
  import rehypeJsx from './rehype-jsx.js';
9
+ import remarkEscape from './remark-escape.js';
9
10
  import remarkMarkAndUnravel from './remark-mark-and-unravel.js';
10
11
  import remarkMdxish from './remark-mdxish.js';
11
12
  import remarkPrism from './remark-prism.js';
@@ -13,7 +14,6 @@ import scopedStyles from './remark-scoped-styles.js';
13
14
  import remarkShiki from './remark-shiki.js';
14
15
  import remarkUnwrap from './remark-unwrap.js';
15
16
 
16
- import Slugger from 'github-slugger';
17
17
  import rehypeRaw from 'rehype-raw';
18
18
  import rehypeStringify from 'rehype-stringify';
19
19
  import markdown from 'remark-parse';
@@ -26,11 +26,6 @@ export * from './types.js';
26
26
  export const DEFAULT_REMARK_PLUGINS = ['remark-gfm', 'remark-smartypants'];
27
27
  export const DEFAULT_REHYPE_PLUGINS = [];
28
28
 
29
- const slugger = new Slugger();
30
- export function slug(value: string): string {
31
- return slugger.slug(value);
32
- }
33
-
34
29
  /** Shared utility for rendering markdown */
35
30
  export async function renderMarkdown(
36
31
  content: string,
@@ -52,7 +47,7 @@ export async function renderMarkdown(
52
47
  let parser = unified()
53
48
  .use(markdown)
54
49
  .use(isMDX ? [remarkMdxish, remarkMarkAndUnravel] : [])
55
- .use([remarkUnwrap]);
50
+ .use([remarkUnwrap, remarkEscape]);
56
51
 
57
52
  if (remarkPlugins.length === 0 && rehypePlugins.length === 0) {
58
53
  remarkPlugins = [...DEFAULT_REMARK_PLUGINS];
@@ -62,8 +57,8 @@ export async function renderMarkdown(
62
57
  const loadedRemarkPlugins = await Promise.all(loadPlugins(remarkPlugins));
63
58
  const loadedRehypePlugins = await Promise.all(loadPlugins(rehypePlugins));
64
59
 
65
- loadedRemarkPlugins.forEach(([plugin, opts]) => {
66
- parser.use([[plugin, opts]]);
60
+ loadedRemarkPlugins.forEach(([plugin, pluginOpts]) => {
61
+ parser.use([[plugin, pluginOpts]]);
67
62
  });
68
63
 
69
64
  if (scopedClassName) {
@@ -92,8 +87,8 @@ export async function renderMarkdown(
92
87
  ],
93
88
  ]);
94
89
 
95
- loadedRehypePlugins.forEach(([plugin, opts]) => {
96
- parser.use([[plugin, opts]]);
90
+ loadedRehypePlugins.forEach(([plugin, pluginOpts]) => {
91
+ parser.use([[plugin, pluginOpts]]);
97
92
  });
98
93
 
99
94
  parser
@@ -111,6 +106,7 @@ export async function renderMarkdown(
111
106
  // Ensure that the error message contains the input filename
112
107
  // to make it easier for the user to fix the issue
113
108
  err = prefixError(err, `Failed to parse Markdown file "${input.path}"`);
109
+ // eslint-disable-next-line no-console
114
110
  console.error(err);
115
111
  throw err;
116
112
  }
@@ -20,12 +20,12 @@ export default function createCollectHeaders() {
20
20
 
21
21
  let text = '';
22
22
  let isJSX = false;
23
- visit(node, (child, _, parent) => {
23
+ visit(node, (child, __, parent) => {
24
24
  if (child.type === 'element' || parent == null) {
25
25
  return;
26
26
  }
27
27
  if (child.type === 'raw') {
28
- if (child.value.startsWith('\n<') || child.value.endsWith('>\n')) {
28
+ if (child.value.match(/^\n?<.*>\n?$/)) {
29
29
  return;
30
30
  }
31
31
  }
@@ -8,7 +8,7 @@ export default function rehypeEscape(): any {
8
8
  // Visit all raw children and escape HTML tags to prevent Markdown code
9
9
  // like "This is a `<script>` tag" from actually opening a script tag
10
10
  visit(el, 'raw', (raw) => {
11
- raw.value = raw.value.replace(/</g, '&lt;').replace(/>/g, '&gt;');
11
+ raw.value = raw.value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
12
12
  });
13
13
  }
14
14
  return el;
@@ -9,14 +9,14 @@ const visit = _visit as (
9
9
  ) => any;
10
10
 
11
11
  // This fixes some confusing bugs coming from somewhere inside of our Markdown pipeline.
12
- // `unist`/`remark`/`rehype` (not sure) often generate malformed HTML inside of <astro-root>
12
+ // `unist`/`remark`/`rehype` (not sure) often generate malformed HTML inside of <astro-island>
13
13
  // For hydration to work properly, frameworks need the DOM to be the exact same on server/client.
14
14
  // This reverts some "helpful corrections" that are applied to our perfectly valid HTML!
15
15
  export default function rehypeIslands(): any {
16
16
  return function (node: any): any {
17
17
  return visit(node, 'element', (el) => {
18
- // Bugs only happen inside of <astro-root> islands
19
- if (el.tagName == 'astro-root') {
18
+ // Bugs only happen inside of <astro-island> islands
19
+ if (el.tagName == 'astro-island') {
20
20
  visit(el, 'text', (child, index, parent) => {
21
21
  if (child.type === 'text') {
22
22
  // Sometimes comments can be trapped as text, which causes them to be escaped
package/src/rehype-jsx.ts CHANGED
@@ -53,11 +53,11 @@ export default function rehypeJsx(): ReturnType<RehypePlugin> {
53
53
  // wrapped by raw opening and closing tags
54
54
  const openingTag = {
55
55
  type: 'raw',
56
- value: `\n<${node.name}${attrs}>`,
56
+ value: `<${node.name}${attrs}>`,
57
57
  };
58
58
  const closingTag = {
59
59
  type: 'raw',
60
- value: `</${node.name}>\n`,
60
+ value: `</${node.name}>`,
61
61
  };
62
62
  parent.children.splice(index, 1, openingTag, ...node.children, closingTag);
63
63
  });
@@ -0,0 +1,15 @@
1
+ import type { Literal } from 'unist';
2
+ import { visit } from 'unist-util-visit';
3
+
4
+ // In code blocks, this removes the JS comment wrapper added to
5
+ // HTML comments by vite-plugin-markdown.
6
+ export default function remarkEscape() {
7
+ return (tree: any) => {
8
+ visit(tree, 'code', removeCommentWrapper);
9
+ visit(tree, 'inlineCode', removeCommentWrapper);
10
+ };
11
+
12
+ function removeCommentWrapper(node: Literal<string>) {
13
+ node.value = node.value.replace(/{\/\*<!--/gs, '<!--').replace(/-->\*\/}/gs, '-->');
14
+ }
15
+ }
@@ -3,12 +3,17 @@ import type { Tag } from 'mdast-util-mdx-jsx';
3
3
  import { mdxFromMarkdown, mdxToMarkdown } from './mdast-util-mdxish.js';
4
4
  import { mdxjs } from './mdxjs.js';
5
5
 
6
- export default function remarkMdxish(this: any, options = {}) {
6
+ // Prepare markdown extensions once to prevent performance issues
7
+ const extMdxJs = mdxjs({});
8
+ const extMdxFromMarkdown = makeFromMarkdownLessStrict(mdxFromMarkdown());
9
+ const extMdxToMarkdown = mdxToMarkdown();
10
+
11
+ export default function remarkMdxish(this: any) {
7
12
  const data = this.data();
8
13
 
9
- add('micromarkExtensions', mdxjs(options));
10
- add('fromMarkdownExtensions', makeFromMarkdownLessStrict(mdxFromMarkdown()));
11
- add('toMarkdownExtensions', mdxToMarkdown());
14
+ add('micromarkExtensions', extMdxJs);
15
+ add('fromMarkdownExtensions', extMdxFromMarkdown);
16
+ add('toMarkdownExtensions', extMdxToMarkdown);
12
17
 
13
18
  function add(field: string, value: unknown) {
14
19
  const list = data[field] ? data[field] : (data[field] = []);
@@ -13,9 +13,9 @@ function runHighlighter(lang: string, code: string) {
13
13
  lang = 'plaintext';
14
14
  }
15
15
 
16
- const ensureLoaded = (lang: string) => {
17
- if (lang && !Prism.languages[lang]) {
18
- loadLanguages([lang]);
16
+ const ensureLoaded = (language: string) => {
17
+ if (language && !Prism.languages[language]) {
18
+ loadLanguages([language]);
19
19
  }
20
20
  };
21
21
 
@@ -30,6 +30,7 @@ function runHighlighter(lang: string, code: string) {
30
30
  }
31
31
 
32
32
  if (lang && !Prism.languages[lang]) {
33
+ // eslint-disable-next-line no-console
33
34
  console.warn(`Unable to load the language: ${lang}`);
34
35
  }
35
36
 
@@ -8,7 +8,7 @@ const visit = _visit as (
8
8
  callback?: (node: any, index: number, parent: any) => any
9
9
  ) => any;
10
10
 
11
- // Remove the wrapping paragraph for <astro-root> islands
11
+ // Remove the wrapping paragraph for <astro-island> islands
12
12
  export default function remarkUnwrap() {
13
13
  const astroRootNodes = new Set();
14
14
  let insideAstroRoot = false;
@@ -19,10 +19,10 @@ export default function remarkUnwrap() {
19
19
  astroRootNodes.clear();
20
20
 
21
21
  visit(tree, 'html', (node) => {
22
- if (node.value.indexOf('<astro-root') > -1 && !insideAstroRoot) {
22
+ if (node.value.indexOf('<astro-island') > -1 && !insideAstroRoot) {
23
23
  insideAstroRoot = true;
24
24
  }
25
- if (node.value.indexOf('</astro-root') > -1 && insideAstroRoot) {
25
+ if (node.value.indexOf('</astro-island') > -1 && insideAstroRoot) {
26
26
  insideAstroRoot = false;
27
27
  }
28
28
  astroRootNodes.add(node);
@@ -0,0 +1,8 @@
1
+ /** Utilities used in deployment-ready SSR bundles */
2
+ import Slugger from 'github-slugger';
3
+
4
+ const slugger = new Slugger();
5
+ /** @see {@link "/packages/astro/vite-plugin-markdown"} */
6
+ export function slug(value: string): string {
7
+ return slugger.slug(value);
8
+ }
@@ -49,7 +49,7 @@ describe('components', () => {
49
49
  it('should normalize children', async () => {
50
50
  const { code } = await renderMarkdown(`<Component bool={true}>Hello world!</Component>`, {});
51
51
 
52
- chai.expect(code).to.equal(`\n<Component bool={true}>Hello world!</Component>\n`);
52
+ chai.expect(code).to.equal(`<Component bool={true}>Hello world!</Component>`);
53
53
  });
54
54
 
55
55
  it('should be able to nest components', async () => {
@@ -60,7 +60,7 @@ describe('components', () => {
60
60
 
61
61
  chai
62
62
  .expect(code)
63
- .to.equal(`\n<Component bool={true}>\n<Component>Hello world!</Component>\n</Component>\n`);
63
+ .to.equal(`<Component bool={true}><Component>Hello world!</Component></Component>`);
64
64
  });
65
65
 
66
66
  it('should allow markdown without many spaces', async () => {
@@ -71,6 +71,6 @@ describe('components', () => {
71
71
  {}
72
72
  );
73
73
 
74
- chai.expect(code).to.equal(`\n<Component><h1 id="hello-world">Hello world!</h1></Component>\n`);
74
+ chai.expect(code).to.equal(`<Component><h1 id="hello-world">Hello world!</h1></Component>`);
75
75
  });
76
76
  });
@@ -1,5 +1,5 @@
1
1
  import { renderMarkdown } from '../dist/index.js';
2
- import chai from 'chai';
2
+ import chai, { expect } from 'chai';
3
3
 
4
4
  describe('expressions', () => {
5
5
  it('should be able to serialize bare expression', async () => {
@@ -11,7 +11,7 @@ describe('expressions', () => {
11
11
  it('should be able to serialize expression inside component', async () => {
12
12
  const { code } = await renderMarkdown(`<Component>{a}</Component>`, {});
13
13
 
14
- chai.expect(code).to.equal(`\n<Component>{a}</Component>\n`);
14
+ chai.expect(code).to.equal(`<Component>{a}</Component>`);
15
15
  });
16
16
 
17
17
  it('should be able to serialize expression inside markdown', async () => {
@@ -71,6 +71,29 @@ describe('expressions', () => {
71
71
  );
72
72
  });
73
73
 
74
+ it('should be able to encode ampersand characters in code blocks', async () => {
75
+ const { code } = await renderMarkdown(
76
+ 'The ampersand in `&nbsp;` must be encoded in code blocks.',
77
+ {}
78
+ );
79
+
80
+ chai
81
+ .expect(code)
82
+ .to.equal(
83
+ '<p>The ampersand in <code is:raw>&amp;nbsp;</code> must be encoded in code blocks.</p>'
84
+ );
85
+ });
86
+
87
+ it('should be able to encode ampersand characters in fenced code blocks', async () => {
88
+ const { code } = await renderMarkdown(`
89
+ \`\`\`md
90
+ The ampersand in \`&nbsp;\` must be encoded in code blocks.
91
+ \`\`\`
92
+ `);
93
+
94
+ chai.expect(code).to.match(/^<pre is:raw.*<code>.*The ampersand in `&amp;nbsp;`/);
95
+ });
96
+
74
97
  it('should be able to serialize function expression', async () => {
75
98
  const { code } = await renderMarkdown(
76
99
  `{frontmatter.list.map(item => <p id={item}>{item}</p>)}`,
@@ -79,4 +102,22 @@ describe('expressions', () => {
79
102
 
80
103
  chai.expect(code).to.equal(`{frontmatter.list.map(item => <p id={item}>{item}</p>)}`);
81
104
  });
105
+
106
+ it('should unwrap HTML comments in inline code blocks', async () => {
107
+ const { code } = await renderMarkdown(`\`{/*<!-- HTML comment -->*/}\``);
108
+
109
+ chai.expect(code).to.equal('<p><code is:raw>&lt;!-- HTML comment --&gt;</code></p>');
110
+ });
111
+
112
+ it('should unwrap HTML comments in code fences', async () => {
113
+ const { code } = await renderMarkdown(
114
+ `
115
+ \`\`\`
116
+ <!-- HTML comment -->
117
+ \`\`\`
118
+ `
119
+ );
120
+
121
+ chai.expect(code).to.match(/(?<!{\/\*)&lt;!-- HTML comment --&gt;(?!\*\/})/);
122
+ });
82
123
  });