diff --git a/.changeset/cuddly-trees-sniff.md b/.changeset/cuddly-trees-sniff.md new file mode 100644 index 000000000000..eea217d8b060 --- /dev/null +++ b/.changeset/cuddly-trees-sniff.md @@ -0,0 +1,5 @@ +--- +'@astrojs/markdown-remark': patch +--- + +Removed `rehype-slug` in favor of our own implementation. The behavior of the slugging should remain the same diff --git a/.changeset/silly-yaks-happen.md b/.changeset/silly-yaks-happen.md new file mode 100644 index 000000000000..88728b310b0d --- /dev/null +++ b/.changeset/silly-yaks-happen.md @@ -0,0 +1,6 @@ +--- +'astro': patch +'@astrojs/markdown-remark': patch +--- + +Moved some type from `astro` to `@astrojs/markdown-remark` diff --git a/examples/with-markdown-plugins/astro.config.mjs b/examples/with-markdown-plugins/astro.config.mjs index 4872caac782e..af2d96e75c89 100644 --- a/examples/with-markdown-plugins/astro.config.mjs +++ b/examples/with-markdown-plugins/astro.config.mjs @@ -7,10 +7,10 @@ export default defineConfig({ markdown: { remarkPlugins: ['remark-code-titles'], rehypePlugins: [ + 'rehype-slug', ['rehype-autolink-headings', { behavior: 'prepend' }], ['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }], - 'rehype-slug', ], }, }); diff --git a/packages/astro/package.json b/packages/astro/package.json index 69f017271471..114010ab51cf 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -116,7 +116,6 @@ "prismjs": "^1.28.0", "prompts": "^2.4.2", "recast": "^0.20.5", - "rehype-slug": "^5.0.1", "resolve": "^1.22.0", "rollup": "^2.70.2", "semver": "^7.3.7", diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index f2c5577de0ca..f0d7e73115db 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -2,7 +2,14 @@ import type { AddressInfo } from 'net'; import type * as babel from '@babel/core'; import type * as vite from 'vite'; import { z } from 'zod'; -import type { ShikiConfig, RemarkPlugins, RehypePlugins } from '@astrojs/markdown-remark'; +import type { + ShikiConfig, + RemarkPlugins, + RehypePlugins, + MarkdownHeader, + MarkdownMetadata, + MarkdownRenderingResult, +} from '@astrojs/markdown-remark'; import type { AstroConfigSchema } from '../core/config'; import type { AstroComponentFactory, Metadata } from '../runtime/server'; import type { ViteConfigWithSSR } from '../core/create-vite'; @@ -530,7 +537,7 @@ export interface AstroUserConfig { * @description * Pass a custom [Remark](https://github.com/remarkjs/remark) plugin to customize how your Markdown is built. * - * **Note:** Enabling custom `remarkPlugins` or `rehypePlugins` removes Astro's built-in support for [GitHub-flavored Markdown](https://github.github.com/gfm/) support, [Footnotes](https://github.com/remarkjs/remark-footnotes) syntax, [Smartypants](https://github.com/silvenon/remark-smartypants). You must explicitly add these plugins to your `astro.config.mjs` file, if desired. + * **Note:** Enabling custom `remarkPlugins` or `rehypePlugins` removes Astro's built-in support for [GitHub-flavored Markdown](https://github.github.com/gfm/) support and [Smartypants](https://github.com/silvenon/remark-smartypants). You must explicitly add these plugins to your `astro.config.mjs` file, if desired. * * ```js * { @@ -549,13 +556,13 @@ export interface AstroUserConfig { * @description * Pass a custom [Rehype](https://github.com/remarkjs/remark-rehype) plugin to customize how your Markdown is built. * - * **Note:** Enabling custom `remarkPlugins` or `rehypePlugins` removes Astro's built-in support for [GitHub-flavored Markdown](https://github.github.com/gfm/) support, [Footnotes](https://github.com/remarkjs/remark-footnotes) syntax, [Smartypants](https://github.com/silvenon/remark-smartypants). You must explicitly add these plugins to your `astro.config.mjs` file, if desired. + * **Note:** Enabling custom `remarkPlugins` or `rehypePlugins` removes Astro's built-in support for [GitHub-flavored Markdown](https://github.github.com/gfm/) support and [Smartypants](https://github.com/silvenon/remark-smartypants). You must explicitly add these plugins to your `astro.config.mjs` file, if desired. * * ```js * { * markdown: { * // Example: The default set of rehype plugins used by Astro - * rehypePlugins: [['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }], 'rehype-slug'], + * rehypePlugins: ['rehype-slug', ['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }]], * }, * }; * ``` @@ -774,24 +781,10 @@ export interface ManifestData { routes: RouteData[]; } -export interface MarkdownHeader { - depth: number; - slug: string; - text: string; -} - -export interface MarkdownMetadata { - headers: MarkdownHeader[]; - source: string; - html: string; -} - -export interface MarkdownParserResponse { +export interface MarkdownParserResponse extends MarkdownRenderingResult { frontmatter: { [key: string]: any; }; - metadata: MarkdownMetadata; - code: string; } /** diff --git a/packages/astro/test/astro-markdown-plugins.test.js b/packages/astro/test/astro-markdown-plugins.test.js index 30e0d7f743b9..350997c66438 100644 --- a/packages/astro/test/astro-markdown-plugins.test.js +++ b/packages/astro/test/astro-markdown-plugins.test.js @@ -15,9 +15,9 @@ describe('Astro Markdown plugins', () => { ['rehype-autolink-headings', { behavior: 'prepend' }], ], rehypePlugins: [ + 'rehype-slug', ['rehype-toc', { headings: ['h2', 'h3'] }], [addClasses, { 'h1,h2,h3': 'title' }], - 'rehype-slug', ], }, }); diff --git a/packages/astro/test/fixtures/astro-markdown-plugins/package.json b/packages/astro/test/fixtures/astro-markdown-plugins/package.json index d6f815c19241..3335ff4ab690 100644 --- a/packages/astro/test/fixtures/astro-markdown-plugins/package.json +++ b/packages/astro/test/fixtures/astro-markdown-plugins/package.json @@ -5,6 +5,7 @@ "dependencies": { "@astrojs/preact": "workspace:*", "astro": "workspace:*", - "hast-util-select": "^5.0.1" + "hast-util-select": "^5.0.1", + "rehype-slug": "^5.0.1" } } diff --git a/packages/markdown/remark/package.json b/packages/markdown/remark/package.json index 9fed8fa7f1dd..0086d3b1a73f 100644 --- a/packages/markdown/remark/package.json +++ b/packages/markdown/remark/package.json @@ -32,7 +32,6 @@ "micromark-extension-mdx-jsx": "^1.0.3", "prismjs": "^1.28.0", "rehype-raw": "^6.1.1", - "rehype-slug": "^5.0.1", "rehype-stringify": "^9.0.3", "remark-gfm": "^3.0.1", "remark-parse": "^10.0.1", diff --git a/packages/markdown/remark/src/index.ts b/packages/markdown/remark/src/index.ts index 2dfb81d234b7..bf660a508553 100644 --- a/packages/markdown/remark/src/index.ts +++ b/packages/markdown/remark/src/index.ts @@ -1,4 +1,4 @@ -import type { MarkdownRenderingOptions } from './types'; +import type { MarkdownRenderingOptions, MarkdownRenderingResult } from './types'; import createCollectHeaders from './rehype-collect-headers.js'; import scopedStyles from './remark-scoped-styles.js'; @@ -22,11 +22,13 @@ import rehypeRaw from 'rehype-raw'; export * from './types.js'; export const DEFAULT_REMARK_PLUGINS = ['remark-gfm', 'remark-smartypants']; - -export const DEFAULT_REHYPE_PLUGINS = ['rehype-slug']; +export const DEFAULT_REHYPE_PLUGINS = []; /** Shared utility for rendering markdown */ -export async function renderMarkdown(content: string, opts: MarkdownRenderingOptions) { +export async function renderMarkdown( + content: string, + opts: MarkdownRenderingOptions +): Promise { let { mode, syntaxHighlight, shikiConfig, remarkPlugins, rehypePlugins } = opts; const scopedClassName = opts.$?.scopedClassName; const isMDX = mode === 'mdx'; diff --git a/packages/markdown/remark/src/rehype-collect-headers.ts b/packages/markdown/remark/src/rehype-collect-headers.ts index 93b34b0aea28..927f965906a5 100644 --- a/packages/markdown/remark/src/rehype-collect-headers.ts +++ b/packages/markdown/remark/src/rehype-collect-headers.ts @@ -1,12 +1,14 @@ import { visit } from 'unist-util-visit'; -import slugger from 'github-slugger'; +import Slugger from 'github-slugger'; + +import type { MarkdownHeader, RehypePlugin } from './types.js'; -/** */ export default function createCollectHeaders() { - const headers: any[] = []; + const headers: MarkdownHeader[] = []; + const slugger = new Slugger(); - function rehypeCollectHeaders() { - return function (tree: any) { + function rehypeCollectHeaders(): ReturnType { + return function (tree) { visit(tree, (node) => { if (node.type !== 'element') return; const { tagName } = node; @@ -21,11 +23,12 @@ export default function createCollectHeaders() { text += child.value; }); - let slug = node?.properties?.id || slugger.slug(text); - node.properties = node.properties || {}; - node.properties.id = slug; - headers.push({ depth, slug, text }); + if (typeof node.properties.id !== 'string') { + node.properties.id = slugger.slug(text); + } + + headers.push({ depth, slug: node.properties.id, text }); }); }; } diff --git a/packages/markdown/remark/src/remark-slug.ts b/packages/markdown/remark/src/remark-slug.ts deleted file mode 100644 index 6d8ddcf2db85..000000000000 --- a/packages/markdown/remark/src/remark-slug.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @typedef {import('mdast').Root} Root - * @typedef {import('hast').Properties} Properties - */ - -import { toString } from 'mdast-util-to-string'; -import { visit } from 'unist-util-visit'; -import BananaSlug from 'github-slugger'; - -const slugs = new BananaSlug(); - -/** - * Plugin to add anchors headings using GitHub’s algorithm. - * - * @type {import('unified').Plugin} - */ -export default function remarkSlug() { - return (tree: any) => { - slugs.reset(); - visit(tree, (node) => { - console.log(node); - }); - visit(tree, 'heading', (node) => { - const data = node.data || (node.data = {}); - const props = /** @type {Properties} */ data.hProperties || (data.hProperties = {}); - let id = props.id; - id = id ? slugs.slug(String(id), true) : slugs.slug(toString(node)); - data.id = id; - props.id = id; - }); - }; -} diff --git a/packages/markdown/remark/src/types.ts b/packages/markdown/remark/src/types.ts index bba486921010..3aef317107fa 100644 --- a/packages/markdown/remark/src/types.ts +++ b/packages/markdown/remark/src/types.ts @@ -40,3 +40,20 @@ export interface MarkdownRenderingOptions extends AstroMarkdownOptions { scopedClassName: string | null; }; } + +export interface MarkdownHeader { + depth: number; + slug: string; + text: string; +} + +export interface MarkdownMetadata { + headers: MarkdownHeader[]; + source: string; + html: string; +} + +export interface MarkdownRenderingResult { + metadata: MarkdownMetadata; + code: string; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ab95ed58305..cbdc463e35c2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -523,7 +523,6 @@ importers: prismjs: ^1.28.0 prompts: ^2.4.2 recast: ^0.20.5 - rehype-slug: ^5.0.1 resolve: ^1.22.0 rollup: ^2.70.2 sass: ^1.50.1 @@ -584,7 +583,6 @@ importers: prismjs: 1.28.0 prompts: 2.4.2 recast: 0.20.5 - rehype-slug: 5.0.1 resolve: 1.22.0 rollup: 2.70.2 semver: 7.3.7 @@ -823,10 +821,12 @@ importers: '@astrojs/preact': workspace:* astro: workspace:* hast-util-select: ^5.0.1 + rehype-slug: ^5.0.1 dependencies: '@astrojs/preact': link:../../../../integrations/preact astro: link:../../.. hast-util-select: 5.0.1 + rehype-slug: 5.0.1 packages/astro/test/fixtures/astro-markdown-shiki/langs: specifiers: @@ -1485,7 +1485,6 @@ importers: micromark-extension-mdx-jsx: ^1.0.3 prismjs: ^1.28.0 rehype-raw: ^6.1.1 - rehype-slug: ^5.0.1 rehype-stringify: ^9.0.3 remark-gfm: ^3.0.1 remark-parse: ^10.0.1 @@ -1505,7 +1504,6 @@ importers: micromark-extension-mdx-jsx: 1.0.3 prismjs: 1.28.0 rehype-raw: 6.1.1 - rehype-slug: 5.0.1 rehype-stringify: 9.0.3 remark-gfm: 3.0.1 remark-parse: 10.0.1