@astrojs/markdown-remark 0.11.7 → 0.14.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,5 +1,5 @@
1
- @astrojs/markdown-remark:build: cache hit, replaying output b4050b97e1fd3558
2
- @astrojs/markdown-remark:build: 
3
- @astrojs/markdown-remark:build: > @astrojs/markdown-remark@0.11.7 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: 
1
+ @astrojs/markdown-remark:build: cache hit, replaying output 6f4b2d3bfc1168f3
2
+ @astrojs/markdown-remark:build: 
3
+ @astrojs/markdown-remark:build: > @astrojs/markdown-remark@0.14.0 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,54 @@
1
1
  # @astrojs/markdown-remark
2
2
 
3
+ ## 0.14.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#4114](https://github.com/withastro/astro/pull/4114) [`64432bcb8`](https://github.com/withastro/astro/commit/64432bcb873efd0e4297c00fc9583a1fe516dfe7) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Refactor `@astrojs/mdx` and `@astrojs/markdown-remark` to use `@astrojs/prism` instead of duplicating the code
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`64432bcb8`](https://github.com/withastro/astro/commit/64432bcb873efd0e4297c00fc9583a1fe516dfe7)]:
12
+ - @astrojs/prism@0.7.0
13
+
14
+ ## 0.13.0
15
+
16
+ ### Minor Changes
17
+
18
+ - [`ba11b3399`](https://github.com/withastro/astro/commit/ba11b33996d79c32da947986edb0f32dbcc04aaf) Thanks [@RafidMuhymin](https://github.com/RafidMuhymin)! - fixed generated slugs in markdown that ends with a dash
19
+
20
+ * [#4016](https://github.com/withastro/astro/pull/4016) [`00fab4ce1`](https://github.com/withastro/astro/commit/00fab4ce135eb799cac69140403d7724686733d6) Thanks [@bholmesdev](https://github.com/bholmesdev)! - The use of components and JSX expressions in Markdown are no longer supported by default.
21
+
22
+ For long term support, migrate to the `@astrojs/mdx` integration for MDX support (including `.mdx` pages!).
23
+
24
+ Not ready to migrate to MDX? Add the legacy flag to your Astro config to re-enable the previous Markdown support.
25
+
26
+ ```js
27
+ // https://astro.build/config
28
+ export default defineConfig({
29
+ legacy: {
30
+ astroFlavoredMarkdown: true,
31
+ },
32
+ });
33
+ ```
34
+
35
+ - [#4031](https://github.com/withastro/astro/pull/4031) [`6e27a5fdc`](https://github.com/withastro/astro/commit/6e27a5fdc21276cad26cd50e16a2709a40a7cbac) Thanks [@natemoo-re](https://github.com/natemoo-re)! - **BREAKING** Renamed Markdown utility function `getHeaders()` to `getHeadings()`.
36
+
37
+ ### Patch Changes
38
+
39
+ - [#4008](https://github.com/withastro/astro/pull/4008) [`399d7e269`](https://github.com/withastro/astro/commit/399d7e269834d11c046b390705a9a53d3738f3cf) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Avoid parsing JSX, components, and Astro islands when using "plain" md mode. This brings `markdown.mode: 'md'` in-line with our docs description.
40
+
41
+ ## 0.12.0
42
+
43
+ ### Minor Changes
44
+
45
+ - [#3924](https://github.com/withastro/astro/pull/3924) [`07fb544da`](https://github.com/withastro/astro/commit/07fb544dab142a3d4bb9d0d878aab34eaea447b2) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Remove unused ssr-utils file
46
+
47
+ ### Patch Changes
48
+
49
+ - Updated dependencies [[`31f9c0bf0`](https://github.com/withastro/astro/commit/31f9c0bf029ffa4b470e620f2c32e1370643e81e)]:
50
+ - @astrojs/prism@0.6.1
51
+
3
52
  ## 0.11.7
4
53
 
5
54
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -3,4 +3,4 @@ export * from './types.js';
3
3
  export declare const DEFAULT_REMARK_PLUGINS: string[];
4
4
  export declare const DEFAULT_REHYPE_PLUGINS: never[];
5
5
  /** Shared utility for rendering markdown */
6
- export declare function renderMarkdown(content: string, opts?: MarkdownRenderingOptions): Promise<MarkdownRenderingResult>;
6
+ export declare function renderMarkdown(content: string, opts: MarkdownRenderingOptions): Promise<MarkdownRenderingResult>;
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { loadPlugins } from "./load-plugins.js";
2
- import createCollectHeaders from "./rehype-collect-headers.js";
2
+ import createCollectHeadings from "./rehype-collect-headings.js";
3
3
  import rehypeEscape from "./rehype-escape.js";
4
4
  import rehypeExpressions from "./rehype-expressions.js";
5
5
  import rehypeIslands from "./rehype-islands.js";
@@ -20,21 +20,20 @@ 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
- async function renderMarkdown(content, opts = {}) {
23
+ async function renderMarkdown(content, opts) {
24
24
  var _a;
25
25
  let {
26
26
  fileURL,
27
- mode = "mdx",
28
27
  syntaxHighlight = "shiki",
29
28
  shikiConfig = {},
30
29
  remarkPlugins = [],
31
- rehypePlugins = []
30
+ rehypePlugins = [],
31
+ isAstroFlavoredMd = false
32
32
  } = opts;
33
33
  const input = new VFile({ value: content, path: fileURL });
34
34
  const scopedClassName = (_a = opts.$) == null ? void 0 : _a.scopedClassName;
35
- const isMDX = mode === "mdx";
36
- const { headers, rehypeCollectHeaders } = createCollectHeaders();
37
- let parser = unified().use(markdown).use(isMDX ? [remarkMdxish, remarkMarkAndUnravel] : []).use([remarkUnwrap, remarkEscape]);
35
+ const { headings, rehypeCollectHeadings } = createCollectHeadings();
36
+ let parser = unified().use(markdown).use(isAstroFlavoredMd ? [remarkMdxish, remarkMarkAndUnravel, remarkUnwrap, remarkEscape] : []);
38
37
  if (remarkPlugins.length === 0 && rehypePlugins.length === 0) {
39
38
  remarkPlugins = [...DEFAULT_REMARK_PLUGINS];
40
39
  rehypePlugins = [...DEFAULT_REHYPE_PLUGINS];
@@ -57,20 +56,22 @@ async function renderMarkdown(content, opts = {}) {
57
56
  markdownToHtml,
58
57
  {
59
58
  allowDangerousHtml: true,
60
- passThrough: [
59
+ passThrough: isAstroFlavoredMd ? [
61
60
  "raw",
62
61
  "mdxFlowExpression",
63
62
  "mdxJsxFlowElement",
64
63
  "mdxJsxTextElement",
65
64
  "mdxTextExpression"
66
- ]
65
+ ] : []
67
66
  }
68
67
  ]
69
68
  ]);
70
69
  loadedRehypePlugins.forEach(([plugin, pluginOpts]) => {
71
70
  parser.use([[plugin, pluginOpts]]);
72
71
  });
73
- parser.use(isMDX ? [rehypeJsx, rehypeExpressions] : [rehypeRaw]).use(rehypeEscape).use(rehypeIslands).use([rehypeCollectHeaders]).use(rehypeStringify, { allowDangerousHtml: true });
72
+ parser.use(
73
+ isAstroFlavoredMd ? [rehypeJsx, rehypeExpressions, rehypeEscape, rehypeIslands, rehypeCollectHeadings] : [rehypeCollectHeadings, rehypeRaw]
74
+ ).use(rehypeStringify, { allowDangerousHtml: true });
74
75
  let result;
75
76
  try {
76
77
  const vfile = await parser.process(input);
@@ -81,7 +82,7 @@ async function renderMarkdown(content, opts = {}) {
81
82
  throw err;
82
83
  }
83
84
  return {
84
- metadata: { headers, source: content, html: result.toString() },
85
+ metadata: { headings, source: content, html: result.toString() },
85
86
  code: result.toString()
86
87
  };
87
88
  }
package/dist/mdxjs.js CHANGED
@@ -5,11 +5,14 @@ import { mdxExpression } from "micromark-extension-mdx-expression";
5
5
  import { mdxMd } from "micromark-extension-mdx-md";
6
6
  import { combineExtensions } from "micromark-util-combine-extensions";
7
7
  function mdxjs(options) {
8
- const settings = Object.assign({
9
- acorn: Parser.extend(acornJsx()),
10
- acornOptions: { ecmaVersion: 2020, sourceType: "module" },
11
- addResult: true
12
- }, options);
8
+ const settings = Object.assign(
9
+ {
10
+ acorn: Parser.extend(acornJsx()),
11
+ acornOptions: { ecmaVersion: 2020, sourceType: "module" },
12
+ addResult: true
13
+ },
14
+ options
15
+ );
13
16
  return combineExtensions([mdxExpression(settings), mdxJsx(settings), mdxMd]);
14
17
  }
15
18
  export {
@@ -0,0 +1,5 @@
1
+ import type { MarkdownHeading, RehypePlugin } from './types.js';
2
+ export default function createCollectHeadings(): {
3
+ headings: MarkdownHeading[];
4
+ rehypeCollectHeadings: () => ReturnType<RehypePlugin>;
5
+ };
@@ -1,10 +1,10 @@
1
1
  import Slugger from "github-slugger";
2
2
  import { toHtml } from "hast-util-to-html";
3
3
  import { visit } from "unist-util-visit";
4
- function createCollectHeaders() {
5
- const headers = [];
4
+ function createCollectHeadings() {
5
+ const headings = [];
6
6
  const slugger = new Slugger();
7
- function rehypeCollectHeaders() {
7
+ function rehypeCollectHeadings() {
8
8
  return function(tree) {
9
9
  visit(tree, (node) => {
10
10
  if (node.type !== "element")
@@ -44,18 +44,21 @@ function createCollectHeaders() {
44
44
  node.type = "raw";
45
45
  node.value = `<${node.tagName} id={${node.properties.id}}>${raw}</${node.tagName}>`;
46
46
  } else {
47
- node.properties.id = slugger.slug(text);
47
+ let slug = slugger.slug(text);
48
+ if (slug.endsWith("-"))
49
+ slug = slug.slice(0, -1);
50
+ node.properties.id = slug;
48
51
  }
49
52
  }
50
- headers.push({ depth, slug: node.properties.id, text });
53
+ headings.push({ depth, slug: node.properties.id, text });
51
54
  });
52
55
  };
53
56
  }
54
57
  return {
55
- headers,
56
- rehypeCollectHeaders
58
+ headings,
59
+ rehypeCollectHeadings
57
60
  };
58
61
  }
59
62
  export {
60
- createCollectHeaders as default
63
+ createCollectHeadings as default
61
64
  };
@@ -1 +1,2 @@
1
+ export declare function escapeEntities(value: string): string;
1
2
  export default function rehypeEscape(): any;
@@ -1,11 +1,14 @@
1
1
  import { visit } from "unist-util-visit";
2
+ function escapeEntities(value) {
3
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
4
+ }
2
5
  function rehypeEscape() {
3
6
  return function(node) {
4
7
  return visit(node, "element", (el) => {
5
8
  if (el.tagName === "code" || el.tagName === "pre") {
6
9
  el.properties["is:raw"] = true;
7
10
  visit(el, "raw", (raw) => {
8
- raw.value = raw.value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
11
+ raw.value = escapeEntities(raw.value);
9
12
  });
10
13
  }
11
14
  return el;
@@ -13,5 +16,6 @@ function rehypeEscape() {
13
16
  };
14
17
  }
15
18
  export {
16
- rehypeEscape as default
19
+ rehypeEscape as default,
20
+ escapeEntities
17
21
  };
@@ -1,49 +1,19 @@
1
- import { addAstro } from "@astrojs/prism/internal";
2
- import Prism from "prismjs";
3
- import loadLanguages from "prismjs/components/index.js";
1
+ import { runHighlighterWithAstro } from "@astrojs/prism/dist/highlighter";
4
2
  import { visit } from "unist-util-visit";
5
3
  const noVisit = /* @__PURE__ */ new Set(["root", "html", "text"]);
6
- const languageMap = /* @__PURE__ */ new Map([["ts", "typescript"]]);
7
- function runHighlighter(lang, code) {
8
- let classLanguage = `language-${lang}`;
9
- if (lang == null) {
10
- lang = "plaintext";
11
- }
12
- const ensureLoaded = (language) => {
13
- if (language && !Prism.languages[language]) {
14
- loadLanguages([language]);
15
- }
16
- };
17
- if (languageMap.has(lang)) {
18
- ensureLoaded(languageMap.get(lang));
19
- } else if (lang === "astro") {
20
- ensureLoaded("typescript");
21
- addAstro(Prism);
22
- } else {
23
- ensureLoaded("markup-templating");
24
- ensureLoaded(lang);
25
- }
26
- if (lang && !Prism.languages[lang]) {
27
- console.warn(`Unable to load the language: ${lang}`);
28
- }
29
- const grammar = Prism.languages[lang];
30
- let html = code;
31
- if (grammar) {
32
- html = Prism.highlight(code, grammar, lang);
33
- }
34
- return { classLanguage, html };
35
- }
36
4
  function transformer(className) {
37
5
  return function(tree) {
38
6
  const visitor = (node) => {
39
7
  let { lang, value } = node;
40
8
  node.type = "html";
41
- let { html, classLanguage } = runHighlighter(lang, value);
9
+ let { html, classLanguage } = runHighlighterWithAstro(lang, value);
42
10
  let classes = [classLanguage];
43
11
  if (className) {
44
12
  classes.push(className);
45
13
  }
46
- node.value = `<pre class="${classes.join(" ")}"><code is:raw class="${classLanguage}">${html}</code></pre>`;
14
+ node.value = `<pre class="${classes.join(
15
+ " "
16
+ )}"><code is:raw class="${classLanguage}">${html}</code></pre>`;
47
17
  return node;
48
18
  };
49
19
  return visit(tree, "code", visitor);
@@ -27,15 +27,27 @@ const remarkShiki = async ({ langs = [], theme = "github-dark", wrap = false },
27
27
  lang = "plaintext";
28
28
  }
29
29
  let html = highlighter.codeToHtml(node.value, { lang });
30
- html = html.replace('<pre class="shiki"', `<pre is:raw class="astro-code${scopedClassName ? " " + scopedClassName : ""}"`);
31
- html = html.replace(/style="(background-)?color: var\(--shiki-/g, 'style="$1color: var(--astro-code-');
30
+ html = html.replace(
31
+ '<pre class="shiki"',
32
+ `<pre is:raw class="astro-code${scopedClassName ? " " + scopedClassName : ""}"`
33
+ );
34
+ html = html.replace(
35
+ /style="(background-)?color: var\(--shiki-/g,
36
+ 'style="$1color: var(--astro-code-'
37
+ );
32
38
  if (node.lang === "diff") {
33
- html = html.replace(/<span class="line"><span style="(.*?)">([\+|\-])/g, '<span class="line"><span style="$1"><span style="user-select: none;">$2</span>');
39
+ html = html.replace(
40
+ /<span class="line"><span style="(.*?)">([\+|\-])/g,
41
+ '<span class="line"><span style="$1"><span style="user-select: none;">$2</span>'
42
+ );
34
43
  }
35
44
  if (wrap === false) {
36
45
  html = html.replace(/style="(.*?)"/, 'style="$1; overflow-x: auto;"');
37
46
  } else if (wrap === true) {
38
- html = html.replace(/style="(.*?)"/, 'style="$1; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"');
47
+ html = html.replace(
48
+ /style="(.*?)"/,
49
+ 'style="$1; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"'
50
+ );
39
51
  }
40
52
  if (scopedClassName) {
41
53
  html = html.replace(/\<span class="line"\>/g, `<span class="line ${scopedClassName}"`);
package/dist/types.d.ts CHANGED
@@ -27,14 +27,15 @@ export interface MarkdownRenderingOptions extends AstroMarkdownOptions {
27
27
  $?: {
28
28
  scopedClassName: string | null;
29
29
  };
30
+ isAstroFlavoredMd?: boolean;
30
31
  }
31
- export interface MarkdownHeader {
32
+ export interface MarkdownHeading {
32
33
  depth: number;
33
34
  slug: string;
34
35
  text: string;
35
36
  }
36
37
  export interface MarkdownMetadata {
37
- headers: MarkdownHeader[];
38
+ headings: MarkdownHeading[];
38
39
  source: string;
39
40
  html: string;
40
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/markdown-remark",
3
- "version": "0.11.7",
3
+ "version": "0.14.0",
4
4
  "type": "module",
5
5
  "author": "withastro",
6
6
  "license": "MIT",
@@ -13,23 +13,19 @@
13
13
  "homepage": "https://astro.build",
14
14
  "main": "./dist/index.js",
15
15
  "exports": {
16
- ".": "./dist/index.js",
17
- "./ssr-utils": "./dist/ssr-utils.js"
16
+ ".": "./dist/index.js"
18
17
  },
19
18
  "dependencies": {
20
19
  "@astrojs/micromark-extension-mdx-jsx": "^1.0.3",
21
- "@astrojs/prism": "^0.6.0",
20
+ "@astrojs/prism": "^0.7.0",
22
21
  "acorn": "^8.7.1",
23
22
  "acorn-jsx": "^5.3.2",
24
- "assert": "^2.0.0",
25
23
  "github-slugger": "^1.4.0",
26
24
  "mdast-util-mdx-expression": "^1.2.1",
27
25
  "mdast-util-mdx-jsx": "^1.2.0",
28
- "mdast-util-to-string": "^3.1.0",
29
26
  "micromark-extension-mdx-expression": "^1.0.3",
30
27
  "micromark-extension-mdx-md": "^1.0.0",
31
28
  "micromark-util-combine-extensions": "^1.0.0",
32
- "prismjs": "^1.28.0",
33
29
  "rehype-raw": "^6.1.1",
34
30
  "rehype-stringify": "^9.0.3",
35
31
  "remark-gfm": "^3.0.1",
@@ -48,7 +44,6 @@
48
44
  "@types/hast": "^2.3.4",
49
45
  "@types/mdast": "^3.0.10",
50
46
  "@types/mocha": "^9.1.1",
51
- "@types/prismjs": "^1.26.0",
52
47
  "@types/unist": "^2.0.6",
53
48
  "astro-scripts": "0.0.6",
54
49
  "chai": "^4.3.6",
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { MarkdownRenderingOptions, MarkdownRenderingResult } from './types';
2
2
 
3
3
  import { loadPlugins } from './load-plugins.js';
4
- import createCollectHeaders from './rehype-collect-headers.js';
4
+ import createCollectHeadings from './rehype-collect-headings.js';
5
5
  import rehypeEscape from './rehype-escape.js';
6
6
  import rehypeExpressions from './rehype-expressions.js';
7
7
  import rehypeIslands from './rehype-islands.js';
@@ -29,25 +29,23 @@ export const DEFAULT_REHYPE_PLUGINS = [];
29
29
  /** Shared utility for rendering markdown */
30
30
  export async function renderMarkdown(
31
31
  content: string,
32
- opts: MarkdownRenderingOptions = {}
32
+ opts: MarkdownRenderingOptions
33
33
  ): Promise<MarkdownRenderingResult> {
34
34
  let {
35
35
  fileURL,
36
- mode = 'mdx',
37
36
  syntaxHighlight = 'shiki',
38
37
  shikiConfig = {},
39
38
  remarkPlugins = [],
40
39
  rehypePlugins = [],
40
+ isAstroFlavoredMd = false,
41
41
  } = opts;
42
42
  const input = new VFile({ value: content, path: fileURL });
43
43
  const scopedClassName = opts.$?.scopedClassName;
44
- const isMDX = mode === 'mdx';
45
- const { headers, rehypeCollectHeaders } = createCollectHeaders();
44
+ const { headings, rehypeCollectHeadings } = createCollectHeadings();
46
45
 
47
46
  let parser = unified()
48
47
  .use(markdown)
49
- .use(isMDX ? [remarkMdxish, remarkMarkAndUnravel] : [])
50
- .use([remarkUnwrap, remarkEscape]);
48
+ .use(isAstroFlavoredMd ? [remarkMdxish, remarkMarkAndUnravel, remarkUnwrap, remarkEscape] : []);
51
49
 
52
50
  if (remarkPlugins.length === 0 && rehypePlugins.length === 0) {
53
51
  remarkPlugins = [...DEFAULT_REMARK_PLUGINS];
@@ -76,13 +74,15 @@ export async function renderMarkdown(
76
74
  markdownToHtml as any,
77
75
  {
78
76
  allowDangerousHtml: true,
79
- passThrough: [
80
- 'raw',
81
- 'mdxFlowExpression',
82
- 'mdxJsxFlowElement',
83
- 'mdxJsxTextElement',
84
- 'mdxTextExpression',
85
- ],
77
+ passThrough: isAstroFlavoredMd
78
+ ? [
79
+ 'raw',
80
+ 'mdxFlowExpression',
81
+ 'mdxJsxFlowElement',
82
+ 'mdxJsxTextElement',
83
+ 'mdxTextExpression',
84
+ ]
85
+ : [],
86
86
  },
87
87
  ],
88
88
  ]);
@@ -92,10 +92,11 @@ export async function renderMarkdown(
92
92
  });
93
93
 
94
94
  parser
95
- .use(isMDX ? [rehypeJsx, rehypeExpressions] : [rehypeRaw])
96
- .use(rehypeEscape)
97
- .use(rehypeIslands)
98
- .use([rehypeCollectHeaders])
95
+ .use(
96
+ isAstroFlavoredMd
97
+ ? [rehypeJsx, rehypeExpressions, rehypeEscape, rehypeIslands, rehypeCollectHeadings]
98
+ : [rehypeCollectHeadings, rehypeRaw]
99
+ )
99
100
  .use(rehypeStringify, { allowDangerousHtml: true });
100
101
 
101
102
  let result: string;
@@ -112,7 +113,7 @@ export async function renderMarkdown(
112
113
  }
113
114
 
114
115
  return {
115
- metadata: { headers, source: content, html: result.toString() },
116
+ metadata: { headings, source: content, html: result.toString() },
116
117
  code: result.toString(),
117
118
  };
118
119
  }
@@ -2,13 +2,13 @@ import Slugger from 'github-slugger';
2
2
  import { toHtml } from 'hast-util-to-html';
3
3
  import { visit } from 'unist-util-visit';
4
4
 
5
- import type { MarkdownHeader, RehypePlugin } from './types.js';
5
+ import type { MarkdownHeading, RehypePlugin } from './types.js';
6
6
 
7
- export default function createCollectHeaders() {
8
- const headers: MarkdownHeader[] = [];
7
+ export default function createCollectHeadings() {
8
+ const headings: MarkdownHeading[] = [];
9
9
  const slugger = new Slugger();
10
10
 
11
- function rehypeCollectHeaders(): ReturnType<RehypePlugin> {
11
+ function rehypeCollectHeadings(): ReturnType<RehypePlugin> {
12
12
  return function (tree) {
13
13
  visit(tree, (node) => {
14
14
  if (node.type !== 'element') return;
@@ -53,17 +53,21 @@ export default function createCollectHeaders() {
53
53
  node as any
54
54
  ).value = `<${node.tagName} id={${node.properties.id}}>${raw}</${node.tagName}>`;
55
55
  } else {
56
- node.properties.id = slugger.slug(text);
56
+ let slug = slugger.slug(text);
57
+
58
+ if (slug.endsWith('-')) slug = slug.slice(0, -1);
59
+
60
+ node.properties.id = slug;
57
61
  }
58
62
  }
59
63
 
60
- headers.push({ depth, slug: node.properties.id, text });
64
+ headings.push({ depth, slug: node.properties.id, text });
61
65
  });
62
66
  };
63
67
  }
64
68
 
65
69
  return {
66
- headers,
67
- rehypeCollectHeaders,
70
+ headings,
71
+ rehypeCollectHeadings,
68
72
  };
69
73
  }
@@ -1,5 +1,9 @@
1
1
  import { visit } from 'unist-util-visit';
2
2
 
3
+ export function escapeEntities(value: string): string {
4
+ return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
5
+ }
6
+
3
7
  export default function rehypeEscape(): any {
4
8
  return function (node: any): any {
5
9
  return visit(node, 'element', (el) => {
@@ -8,7 +12,7 @@ export default function rehypeEscape(): any {
8
12
  // Visit all raw children and escape HTML tags to prevent Markdown code
9
13
  // like "This is a `<script>` tag" from actually opening a script tag
10
14
  visit(el, 'raw', (raw) => {
11
- raw.value = raw.value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
15
+ raw.value = escapeEntities(raw.value);
12
16
  });
13
17
  }
14
18
  return el;
@@ -1,48 +1,7 @@
1
- import { addAstro } from '@astrojs/prism/internal';
2
- import Prism from 'prismjs';
3
- import loadLanguages from 'prismjs/components/index.js';
1
+ import { runHighlighterWithAstro } from '@astrojs/prism/dist/highlighter';
4
2
  import { visit } from 'unist-util-visit';
5
3
  const noVisit = new Set(['root', 'html', 'text']);
6
4
 
7
- const languageMap = new Map([['ts', 'typescript']]);
8
-
9
- function runHighlighter(lang: string, code: string) {
10
- let classLanguage = `language-${lang}`;
11
-
12
- if (lang == null) {
13
- lang = 'plaintext';
14
- }
15
-
16
- const ensureLoaded = (language: string) => {
17
- if (language && !Prism.languages[language]) {
18
- loadLanguages([language]);
19
- }
20
- };
21
-
22
- if (languageMap.has(lang)) {
23
- ensureLoaded(languageMap.get(lang)!);
24
- } else if (lang === 'astro') {
25
- ensureLoaded('typescript');
26
- addAstro(Prism);
27
- } else {
28
- ensureLoaded('markup-templating'); // Prism expects this to exist for a number of other langs
29
- ensureLoaded(lang);
30
- }
31
-
32
- if (lang && !Prism.languages[lang]) {
33
- // eslint-disable-next-line no-console
34
- console.warn(`Unable to load the language: ${lang}`);
35
- }
36
-
37
- const grammar = Prism.languages[lang];
38
- let html = code;
39
- if (grammar) {
40
- html = Prism.highlight(code, grammar, lang);
41
- }
42
-
43
- return { classLanguage, html };
44
- }
45
-
46
5
  type MaybeString = string | null | undefined;
47
6
 
48
7
  /** */
@@ -52,7 +11,7 @@ function transformer(className: MaybeString) {
52
11
  let { lang, value } = node;
53
12
  node.type = 'html';
54
13
 
55
- let { html, classLanguage } = runHighlighter(lang, value);
14
+ let { html, classLanguage } = runHighlighterWithAstro(lang, value);
56
15
  let classes = [classLanguage];
57
16
  if (className) {
58
17
  classes.push(className);
@@ -37,6 +37,7 @@ const remarkShiki = async (
37
37
  if (langExists) {
38
38
  lang = node.lang;
39
39
  } else {
40
+ // eslint-disable-next-line no-console
40
41
  console.warn(`The language "${node.lang}" doesn't exist, falling back to plaintext.`);
41
42
  lang = 'plaintext';
42
43
  }
package/src/types.ts CHANGED
@@ -41,16 +41,17 @@ export interface MarkdownRenderingOptions extends AstroMarkdownOptions {
41
41
  $?: {
42
42
  scopedClassName: string | null;
43
43
  };
44
+ isAstroFlavoredMd?: boolean;
44
45
  }
45
46
 
46
- export interface MarkdownHeader {
47
+ export interface MarkdownHeading {
47
48
  depth: number;
48
49
  slug: string;
49
50
  text: string;
50
51
  }
51
52
 
52
53
  export interface MarkdownMetadata {
53
- headers: MarkdownHeader[];
54
+ headings: MarkdownHeading[];
54
55
  source: string;
55
56
  html: string;
56
57
  }
@@ -2,91 +2,107 @@ import { renderMarkdown } from '../dist/index.js';
2
2
  import chai from 'chai';
3
3
 
4
4
  describe('autolinking', () => {
5
- it('autolinks URLs starting with a protocol in plain text', async () => {
6
- const { code } = await renderMarkdown(`See https://example.com for more.`, {});
5
+ describe('plain md', () => {
6
+ it('autolinks URLs starting with a protocol in plain text', async () => {
7
+ const { code } = await renderMarkdown(`See https://example.com for more.`, {});
7
8
 
8
- chai
9
- .expect(code.replace(/\n/g, ''))
10
- .to.equal(`<p>See <a href="https://example.com">https://example.com</a> for more.</p>`);
11
- });
9
+ chai
10
+ .expect(code.replace(/\n/g, ''))
11
+ .to.equal(`<p>See <a href="https://example.com">https://example.com</a> for more.</p>`);
12
+ });
12
13
 
13
- it('autolinks URLs starting with "www." in plain text', async () => {
14
- const { code } = await renderMarkdown(`See www.example.com for more.`, {});
14
+ it('autolinks URLs starting with "www." in plain text', async () => {
15
+ const { code } = await renderMarkdown(`See www.example.com for more.`, {});
15
16
 
16
- chai
17
- .expect(code.trim())
18
- .to.equal(`<p>See <a href="http://www.example.com">www.example.com</a> for more.</p>`);
19
- });
17
+ chai
18
+ .expect(code.trim())
19
+ .to.equal(`<p>See <a href="http://www.example.com">www.example.com</a> for more.</p>`);
20
+ });
20
21
 
21
- it('does not autolink URLs in code blocks', async () => {
22
- const { code } = await renderMarkdown(
23
- 'See `https://example.com` or `www.example.com` for more.',
24
- {}
25
- );
26
-
27
- chai
28
- .expect(code.trim())
29
- .to.equal(
30
- `<p>See <code is:raw>https://example.com</code> or ` +
31
- `<code is:raw>www.example.com</code> for more.</p>`
22
+ it('does not autolink URLs in code blocks', async () => {
23
+ const { code } = await renderMarkdown(
24
+ 'See `https://example.com` or `www.example.com` for more.',
25
+ {}
32
26
  );
27
+
28
+ chai
29
+ .expect(code.trim())
30
+ .to.equal(
31
+ `<p>See <code>https://example.com</code> or ` +
32
+ `<code>www.example.com</code> for more.</p>`
33
+ );
34
+ });
33
35
  });
34
36
 
35
- it('does not autolink URLs in fenced code blocks', async () => {
36
- const { code } = await renderMarkdown(
37
- 'Example:\n```\nGo to https://example.com or www.example.com now.\n```',
38
- {}
39
- );
37
+ describe('astro-flavored md', () => {
38
+ const renderAstroMd = (text) => renderMarkdown(text, { isAstroFlavoredMd: true });
40
39
 
41
- chai
42
- .expect(code)
43
- .to.contain(`<pre is:raw`)
44
- .to.contain(`Go to https://example.com or www.example.com now.`);
45
- });
40
+ it('does not autolink URLs in code blocks', async () => {
41
+ const { code } = await renderAstroMd(
42
+ 'See `https://example.com` or `www.example.com` for more.',
43
+ {}
44
+ );
45
+
46
+ chai
47
+ .expect(code.trim())
48
+ .to.equal(
49
+ `<p>See <code is:raw>https://example.com</code> or ` +
50
+ `<code is:raw>www.example.com</code> for more.</p>`
51
+ );
52
+ });
46
53
 
47
- it('does not autolink URLs starting with a protocol when nested inside links', async () => {
48
- const { code } = await renderMarkdown(
49
- `See [http://example.com](http://example.com) or ` +
50
- `<a test href="https://example.com">https://example.com</a>`,
51
- {}
52
- );
53
-
54
- chai
55
- .expect(code.replace(/\n/g, ''))
56
- .to.equal(
57
- `<p>See <a href="http://example.com">http://example.com</a> or ` +
58
- `<a test href="https://example.com">https://example.com</a></p>`
54
+ it('does not autolink URLs in fenced code blocks', async () => {
55
+ const { code } = await renderAstroMd(
56
+ 'Example:\n```\nGo to https://example.com or www.example.com now.\n```'
59
57
  );
60
- });
61
58
 
62
- it('does not autolink URLs starting with "www." when nested inside links', async () => {
63
- const { code } = await renderMarkdown(
64
- `See [www.example.com](https://www.example.com) or ` +
65
- `<a test href="https://www.example.com">www.example.com</a>`,
66
- {}
67
- );
68
-
69
- chai
70
- .expect(code.replace(/\n/g, ''))
71
- .to.equal(
72
- `<p>See <a href="https://www.example.com">www.example.com</a> or ` +
73
- `<a test href="https://www.example.com">www.example.com</a></p>`
59
+ chai
60
+ .expect(code)
61
+ .to.contain(`<pre is:raw`)
62
+ .to.contain(`Go to https://example.com or www.example.com now.`);
63
+ });
64
+
65
+ it('does not autolink URLs starting with a protocol when nested inside links', async () => {
66
+ const { code } = await renderAstroMd(
67
+ `See [http://example.com](http://example.com) or ` +
68
+ `<a test href="https://example.com">https://example.com</a>`
74
69
  );
75
- });
76
70
 
77
- it('does not autolink URLs when nested several layers deep inside links', async () => {
78
- const { code } = await renderMarkdown(
79
- `<a href="https://www.example.com">**Visit _our www.example.com or ` +
80
- `http://localhost pages_ for more!**</a>`,
81
- {}
82
- );
83
-
84
- chai
85
- .expect(code.replace(/\n/g, ''))
86
- .to.equal(
87
- `<a href="https://www.example.com"><strong>` +
88
- `Visit <em>our www.example.com or http://localhost pages</em> for more!` +
89
- `</strong></a>`
71
+ chai
72
+ .expect(code.replace(/\n/g, ''))
73
+ .to.equal(
74
+ `<p>See <a href="http://example.com">http://example.com</a> or ` +
75
+ `<a test href="https://example.com">https://example.com</a></p>`
76
+ );
77
+ });
78
+
79
+ it('does not autolink URLs starting with "www." when nested inside links', async () => {
80
+ const { code } = await renderAstroMd(
81
+ `See [www.example.com](https://www.example.com) or ` +
82
+ `<a test href="https://www.example.com">www.example.com</a>`
90
83
  );
84
+
85
+ chai
86
+ .expect(code.replace(/\n/g, ''))
87
+ .to.equal(
88
+ `<p>See <a href="https://www.example.com">www.example.com</a> or ` +
89
+ `<a test href="https://www.example.com">www.example.com</a></p>`
90
+ );
91
+ });
92
+
93
+ it('does not autolink URLs when nested several layers deep inside links', async () => {
94
+ const { code } = await renderAstroMd(
95
+ `<a href="https://www.example.com">**Visit _our www.example.com or ` +
96
+ `http://localhost pages_ for more!**</a>`
97
+ );
98
+
99
+ chai
100
+ .expect(code.replace(/\n/g, ''))
101
+ .to.equal(
102
+ `<a href="https://www.example.com"><strong>` +
103
+ `Visit <em>our www.example.com or http://localhost pages</em> for more!` +
104
+ `</strong></a>`
105
+ );
106
+ });
91
107
  });
92
108
  });
@@ -2,32 +2,34 @@ import { renderMarkdown } from '../dist/index.js';
2
2
  import chai from 'chai';
3
3
 
4
4
  describe('components', () => {
5
+ const renderAstroMd = (text) => renderMarkdown(text, { isAstroFlavoredMd: true });
6
+
5
7
  it('should be able to serialize string', async () => {
6
- const { code } = await renderMarkdown(`<Component str="cool!" />`, {});
8
+ const { code } = await renderAstroMd(`<Component str="cool!" />`);
7
9
 
8
10
  chai.expect(code).to.equal(`<Component str="cool!" />`);
9
11
  });
10
12
 
11
13
  it('should be able to serialize boolean attribute', async () => {
12
- const { code } = await renderMarkdown(`<Component bool={true} />`, {});
14
+ const { code } = await renderAstroMd(`<Component bool={true} />`);
13
15
 
14
16
  chai.expect(code).to.equal(`<Component bool={true} />`);
15
17
  });
16
18
 
17
19
  it('should be able to serialize array', async () => {
18
- const { code } = await renderMarkdown(`<Component prop={["a", "b", "c"]} />`, {});
20
+ const { code } = await renderAstroMd(`<Component prop={["a", "b", "c"]} />`);
19
21
 
20
22
  chai.expect(code).to.equal(`<Component prop={["a", "b", "c"]} />`);
21
23
  });
22
24
 
23
25
  it('should be able to serialize object', async () => {
24
- const { code } = await renderMarkdown(`<Component prop={{ a: 0, b: 1, c: 2 }} />`, {});
26
+ const { code } = await renderAstroMd(`<Component prop={{ a: 0, b: 1, c: 2 }} />`);
25
27
 
26
28
  chai.expect(code).to.equal(`<Component prop={{ a: 0, b: 1, c: 2 }} />`);
27
29
  });
28
30
 
29
31
  it('should be able to serialize empty attribute', async () => {
30
- const { code } = await renderMarkdown(`<Component empty />`, {});
32
+ const { code } = await renderAstroMd(`<Component empty />`);
31
33
 
32
34
  chai.expect(code).to.equal(`<Component empty />`);
33
35
  });
@@ -35,25 +37,25 @@ describe('components', () => {
35
37
  // Notable omission: shorthand attribute
36
38
 
37
39
  it('should be able to serialize spread attribute', async () => {
38
- const { code } = await renderMarkdown(`<Component {...spread} />`, {});
40
+ const { code } = await renderAstroMd(`<Component {...spread} />`);
39
41
 
40
42
  chai.expect(code).to.equal(`<Component {...spread} />`);
41
43
  });
42
44
 
43
45
  it('should allow client:* directives', async () => {
44
- const { code } = await renderMarkdown(`<Component client:load />`, {});
46
+ const { code } = await renderAstroMd(`<Component client:load />`);
45
47
 
46
48
  chai.expect(code).to.equal(`<Component client:load />`);
47
49
  });
48
50
 
49
51
  it('should normalize children', async () => {
50
- const { code } = await renderMarkdown(`<Component bool={true}>Hello world!</Component>`, {});
52
+ const { code } = await renderAstroMd(`<Component bool={true}>Hello world!</Component>`);
51
53
 
52
54
  chai.expect(code).to.equal(`<Component bool={true}>Hello world!</Component>`);
53
55
  });
54
56
 
55
57
  it('should be able to nest components', async () => {
56
- const { code } = await renderMarkdown(
58
+ const { code } = await renderAstroMd(
57
59
  `<Component bool={true}><Component>Hello world!</Component></Component>`,
58
60
  {}
59
61
  );
@@ -64,7 +66,7 @@ describe('components', () => {
64
66
  });
65
67
 
66
68
  it('should allow markdown without many spaces', async () => {
67
- const { code } = await renderMarkdown(
69
+ const { code } = await renderAstroMd(
68
70
  `<Component>
69
71
  # Hello world!
70
72
  </Component>`,
@@ -0,0 +1,12 @@
1
+ import { renderMarkdown } from '../dist/index.js';
2
+ import { expect } from 'chai';
3
+
4
+ describe('entities', () => {
5
+ const renderAstroMd = (text) => renderMarkdown(text, { isAstroFlavoredMd: false });
6
+
7
+ it('should not unescape entities', async () => {
8
+ const { code } = await renderAstroMd(`&lt;i&gt;This should NOT be italic&lt;/i&gt;`);
9
+
10
+ expect(code).to.equal(`<p>&#x3C;i>This should NOT be italic&#x3C;/i></p>`);
11
+ });
12
+ });
@@ -1,21 +1,23 @@
1
1
  import { renderMarkdown } from '../dist/index.js';
2
- import chai, { expect } from 'chai';
2
+ import chai from 'chai';
3
3
 
4
4
  describe('expressions', () => {
5
+ const renderAstroMd = (text, opts) => renderMarkdown(text, { isAstroFlavoredMd: true, ...opts });
6
+
5
7
  it('should be able to serialize bare expression', async () => {
6
- const { code } = await renderMarkdown(`{a}`, {});
8
+ const { code } = await renderAstroMd(`{a}`, {});
7
9
 
8
10
  chai.expect(code).to.equal(`{a}`);
9
11
  });
10
12
 
11
13
  it('should be able to serialize expression inside component', async () => {
12
- const { code } = await renderMarkdown(`<Component>{a}</Component>`, {});
14
+ const { code } = await renderAstroMd(`<Component>{a}</Component>`, {});
13
15
 
14
16
  chai.expect(code).to.equal(`<Component>{a}</Component>`);
15
17
  });
16
18
 
17
19
  it('should be able to serialize expression inside markdown', async () => {
18
- const { code } = await renderMarkdown(`# {frontmatter.title}`, {});
20
+ const { code } = await renderAstroMd(`# {frontmatter.title}`, {});
19
21
 
20
22
  chai
21
23
  .expect(code)
@@ -23,7 +25,7 @@ describe('expressions', () => {
23
25
  });
24
26
 
25
27
  it('should be able to serialize complex expression inside markdown', async () => {
26
- const { code } = await renderMarkdown(`# Hello {frontmatter.name}`, {});
28
+ const { code } = await renderAstroMd(`# Hello {frontmatter.name}`, {});
27
29
 
28
30
  chai
29
31
  .expect(code)
@@ -31,7 +33,7 @@ describe('expressions', () => {
31
33
  });
32
34
 
33
35
  it('should be able to serialize complex expression with markup inside markdown', async () => {
34
- const { code } = await renderMarkdown(`# Hello <span>{frontmatter.name}</span>`, {});
36
+ const { code } = await renderAstroMd(`# Hello <span>{frontmatter.name}</span>`, {});
35
37
 
36
38
  chai
37
39
  .expect(code)
@@ -41,7 +43,7 @@ describe('expressions', () => {
41
43
  });
42
44
 
43
45
  it('should be able to avoid evaluating JSX-like expressions in an inline code & generate a slug for id', async () => {
44
- const { code } = await renderMarkdown(`# \`{frontmatter.title}\``, {});
46
+ const { code } = await renderAstroMd(`# \`{frontmatter.title}\``, {});
45
47
 
46
48
  chai
47
49
  .expect(code)
@@ -49,17 +51,17 @@ describe('expressions', () => {
49
51
  });
50
52
 
51
53
  it('should be able to avoid evaluating JSX-like expressions in inline codes', async () => {
52
- const { code } = await renderMarkdown(`# \`{ foo }\` is a shorthand for \`{ foo: foo }\``, {});
54
+ const { code } = await renderAstroMd(`# \`{ foo }\` is a shorthand for \`{ foo: foo }\``, {});
53
55
 
54
56
  chai
55
57
  .expect(code)
56
58
  .to.equal(
57
- '<h1 id="-foo--is-a-shorthand-for--foo-foo-"><code is:raw>{ foo }</code> is a shorthand for <code is:raw>{ foo: foo }</code></h1>'
59
+ '<h1 id="-foo--is-a-shorthand-for--foo-foo"><code is:raw>{ foo }</code> is a shorthand for <code is:raw>{ foo: foo }</code></h1>'
58
60
  );
59
61
  });
60
62
 
61
63
  it('should be able to avoid evaluating JSX-like expressions & escape HTML tag characters in inline codes', async () => {
62
- const { code } = await renderMarkdown(
64
+ const { code } = await renderAstroMd(
63
65
  `###### \`{}\` is equivalent to \`Record<never, never>\` <small>(at TypeScript v{frontmatter.version})</small>`,
64
66
  {}
65
67
  );
@@ -72,7 +74,7 @@ describe('expressions', () => {
72
74
  });
73
75
 
74
76
  it('should be able to encode ampersand characters in code blocks', async () => {
75
- const { code } = await renderMarkdown(
77
+ const { code } = await renderAstroMd(
76
78
  'The ampersand in `&nbsp;` must be encoded in code blocks.',
77
79
  {}
78
80
  );
@@ -85,7 +87,7 @@ describe('expressions', () => {
85
87
  });
86
88
 
87
89
  it('should be able to encode ampersand characters in fenced code blocks', async () => {
88
- const { code } = await renderMarkdown(`
90
+ const { code } = await renderAstroMd(`
89
91
  \`\`\`md
90
92
  The ampersand in \`&nbsp;\` must be encoded in code blocks.
91
93
  \`\`\`
@@ -95,7 +97,7 @@ describe('expressions', () => {
95
97
  });
96
98
 
97
99
  it('should be able to serialize function expression', async () => {
98
- const { code } = await renderMarkdown(
100
+ const { code } = await renderAstroMd(
99
101
  `{frontmatter.list.map(item => <p id={item}>{item}</p>)}`,
100
102
  {}
101
103
  );
@@ -104,13 +106,13 @@ describe('expressions', () => {
104
106
  });
105
107
 
106
108
  it('should unwrap HTML comments in inline code blocks', async () => {
107
- const { code } = await renderMarkdown(`\`{/*<!-- HTML comment -->*/}\``);
109
+ const { code } = await renderAstroMd(`\`{/*<!-- HTML comment -->*/}\``);
108
110
 
109
111
  chai.expect(code).to.equal('<p><code is:raw>&lt;!-- HTML comment --&gt;</code></p>');
110
112
  });
111
113
 
112
114
  it('should unwrap HTML comments in code fences', async () => {
113
- const { code } = await renderMarkdown(
115
+ const { code } = await renderAstroMd(
114
116
  `
115
117
  \`\`\`
116
118
  <!-- HTML comment -->
@@ -1,9 +1,11 @@
1
1
  import { renderMarkdown } from '../dist/index.js';
2
2
  import chai from 'chai';
3
3
 
4
- describe('strictness', () => {
4
+ describe('strictness in Astro-flavored markdown', () => {
5
+ const renderAstroMd = (text, opts) => renderMarkdown(text, { isAstroFlavoredMd: true, ...opts });
6
+
5
7
  it('should allow self-closing HTML tags (void elements)', async () => {
6
- const { code } = await renderMarkdown(
8
+ const { code } = await renderAstroMd(
7
9
  `Use self-closing void elements<br>like word<wbr>break and images: <img src="hi.jpg">`,
8
10
  {}
9
11
  );
@@ -17,25 +19,25 @@ describe('strictness', () => {
17
19
  });
18
20
 
19
21
  it('should allow attribute names starting with ":" after element names', async () => {
20
- const { code } = await renderMarkdown(`<div :class="open ? '' : 'hidden'">Test</div>`, {});
22
+ const { code } = await renderAstroMd(`<div :class="open ? '' : 'hidden'">Test</div>`, {});
21
23
 
22
24
  chai.expect(code.trim()).to.equal(`<div :class="open ? '' : 'hidden'">Test</div>`);
23
25
  });
24
26
 
25
27
  it('should allow attribute names starting with ":" after local element names', async () => {
26
- const { code } = await renderMarkdown(`<div.abc :class="open ? '' : 'hidden'">x</div.abc>`, {});
28
+ const { code } = await renderAstroMd(`<div.abc :class="open ? '' : 'hidden'">x</div.abc>`, {});
27
29
 
28
30
  chai.expect(code.trim()).to.equal(`<div.abc :class="open ? '' : 'hidden'">x</div.abc>`);
29
31
  });
30
32
 
31
33
  it('should allow attribute names starting with ":" after attribute names', async () => {
32
- const { code } = await renderMarkdown(`<input type="text" disabled :placeholder="hi">`, {});
34
+ const { code } = await renderAstroMd(`<input type="text" disabled :placeholder="hi">`, {});
33
35
 
34
36
  chai.expect(code.trim()).to.equal(`<input type="text" disabled :placeholder="hi" />`);
35
37
  });
36
38
 
37
39
  it('should allow attribute names starting with ":" after local attribute names', async () => {
38
- const { code } = await renderMarkdown(
40
+ const { code } = await renderAstroMd(
39
41
  `<input type="text" x-test:disabled :placeholder="hi">`,
40
42
  {}
41
43
  );
@@ -44,19 +46,19 @@ describe('strictness', () => {
44
46
  });
45
47
 
46
48
  it('should allow attribute names starting with ":" after attribute values', async () => {
47
- const { code } = await renderMarkdown(`<input type="text" :placeholder="placeholder">`, {});
49
+ const { code } = await renderAstroMd(`<input type="text" :placeholder="placeholder">`, {});
48
50
 
49
51
  chai.expect(code.trim()).to.equal(`<input type="text" :placeholder="placeholder" />`);
50
52
  });
51
53
 
52
54
  it('should allow attribute names starting with "@" after element names', async () => {
53
- const { code } = await renderMarkdown(`<button @click="handleClick">Test</button>`, {});
55
+ const { code } = await renderAstroMd(`<button @click="handleClick">Test</button>`, {});
54
56
 
55
57
  chai.expect(code.trim()).to.equal(`<button @click="handleClick">Test</button>`);
56
58
  });
57
59
 
58
60
  it('should allow attribute names starting with "@" after local element names', async () => {
59
- const { code } = await renderMarkdown(
61
+ const { code } = await renderAstroMd(
60
62
  `<button.local @click="handleClick">Test</button.local>`,
61
63
  {}
62
64
  );
@@ -65,16 +67,13 @@ describe('strictness', () => {
65
67
  });
66
68
 
67
69
  it('should allow attribute names starting with "@" after attribute names', async () => {
68
- const { code } = await renderMarkdown(
69
- `<button disabled @click="handleClick">Test</button>`,
70
- {}
71
- );
70
+ const { code } = await renderAstroMd(`<button disabled @click="handleClick">Test</button>`, {});
72
71
 
73
72
  chai.expect(code.trim()).to.equal(`<button disabled @click="handleClick">Test</button>`);
74
73
  });
75
74
 
76
75
  it('should allow attribute names starting with "@" after local attribute names', async () => {
77
- const { code } = await renderMarkdown(
76
+ const { code } = await renderAstroMd(
78
77
  `<button x-test:disabled @click="handleClick">Test</button>`,
79
78
  {}
80
79
  );
@@ -83,7 +82,7 @@ describe('strictness', () => {
83
82
  });
84
83
 
85
84
  it('should allow attribute names starting with "@" after attribute values', async () => {
86
- const { code } = await renderMarkdown(
85
+ const { code } = await renderAstroMd(
87
86
  `<button type="submit" @click="handleClick">Test</button>`,
88
87
  {}
89
88
  );
@@ -92,7 +91,7 @@ describe('strictness', () => {
92
91
  });
93
92
 
94
93
  it('should allow attribute names containing dots', async () => {
95
- const { code } = await renderMarkdown(`<input x-on:input.debounce.500ms="fetchResults">`, {});
94
+ const { code } = await renderAstroMd(`<input x-on:input.debounce.500ms="fetchResults">`, {});
96
95
 
97
96
  chai.expect(code.trim()).to.equal(`<input x-on:input.debounce.500ms="fetchResults" />`);
98
97
  });
@@ -1,5 +0,0 @@
1
- import type { MarkdownHeader, RehypePlugin } from './types.js';
2
- export default function createCollectHeaders(): {
3
- headers: MarkdownHeader[];
4
- rehypeCollectHeaders: () => ReturnType<RehypePlugin>;
5
- };
@@ -1,2 +0,0 @@
1
- /** @see {@link "/packages/astro/vite-plugin-markdown"} */
2
- export declare function slug(value: string): string;
package/dist/ssr-utils.js DELETED
@@ -1,8 +0,0 @@
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/src/ssr-utils.ts DELETED
@@ -1,8 +0,0 @@
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
- }