diff options
Diffstat (limited to 'packages/markdown-support/src')
-rw-r--r-- | packages/markdown-support/src/codeblock.ts | 44 | ||||
-rw-r--r-- | packages/markdown-support/src/index.ts | 84 | ||||
-rw-r--r-- | packages/markdown-support/src/load-plugins.ts | 27 | ||||
-rw-r--r-- | packages/markdown-support/src/rehype-collect-headers.ts | 39 | ||||
-rw-r--r-- | packages/markdown-support/src/rehype-expressions.ts | 12 | ||||
-rw-r--r-- | packages/markdown-support/src/remark-expressions.ts | 19 | ||||
-rw-r--r-- | packages/markdown-support/src/remark-scoped-styles.ts | 18 | ||||
-rw-r--r-- | packages/markdown-support/src/types.ts | 20 |
8 files changed, 0 insertions, 263 deletions
diff --git a/packages/markdown-support/src/codeblock.ts b/packages/markdown-support/src/codeblock.ts deleted file mode 100644 index 3f0c2894d..000000000 --- a/packages/markdown-support/src/codeblock.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { visit } from 'unist-util-visit'; -import type { Element, Root as HastRoot, Properties } from 'hast'; -import type { Root as MdastRoot } from 'mdast'; - -/** */ -export function remarkCodeBlock() { - return function (tree: MdastRoot) { - visit(tree, 'code', (node) => { - const { data, meta } = node; - let lang = node.lang || 'html'; // default to html to match GFM behavior. - - let currentClassName = (data?.hProperties as Properties)?.class ?? ''; - node.data = node.data || {}; - node.data.hProperties = node.data.hProperties || {}; - node.data.hProperties = { ...(node.data.hProperties as Properties), class: `language-${lang} ${currentClassName}`.trim(), lang, meta }; - }); - }; -} - -/** */ -export function rehypeCodeBlock() { - return function (tree: HastRoot) { - const escapeCode = (code: Element): void => { - code.children = code.children.map((child) => { - if (child.type === 'text') { - return { ...child, value: child.value.replace(/\{/g, 'ASTRO_ESCAPED_LEFT_CURLY_BRACKET\0') }; - } - return child; - }); - }; - visit(tree, 'element', (node) => { - if (node.tagName === 'code') { - escapeCode(node); - return; - } - - if (node.tagName !== 'pre') return; - if (!node.children[0]) return; - const code = node.children[0]; - if (code.type !== 'element' || code.tagName !== 'code') return; - node.properties = { ...code.properties }; - }); - }; -} diff --git a/packages/markdown-support/src/index.ts b/packages/markdown-support/src/index.ts deleted file mode 100644 index 4973da7f9..000000000 --- a/packages/markdown-support/src/index.ts +++ /dev/null @@ -1,84 +0,0 @@ -import type { AstroMarkdownOptions, MarkdownRenderingOptions } from './types'; - -import createCollectHeaders from './rehype-collect-headers.js'; -import scopedStyles from './remark-scoped-styles.js'; -import remarkExpressions from './remark-expressions.js'; -import rehypeExpressions from './rehype-expressions.js'; -import { remarkCodeBlock, rehypeCodeBlock } from './codeblock.js'; -import { loadPlugins } from './load-plugins.js'; -import raw from 'rehype-raw'; - -import { unified } from 'unified'; -import markdown from 'remark-parse'; -import markdownToHtml from 'remark-rehype'; -import rehypeStringify from 'rehype-stringify'; -import remarkSlug from 'remark-slug'; - -export { AstroMarkdownOptions, MarkdownRenderingOptions }; - -/** Internal utility for rendering a full markdown file and extracting Frontmatter data */ -export async function renderMarkdownWithFrontmatter(contents: string, opts?: MarkdownRenderingOptions | null) { - // Dynamic import to ensure that "gray-matter" isn't built by Snowpack - const { default: matter } = await import('gray-matter'); - const { data: frontmatter, content } = matter(contents); - const value = await renderMarkdown(content, opts); - return { ...value, frontmatter }; -} - -/** Shared utility for rendering markdown */ -export async function renderMarkdown(content: string, opts?: MarkdownRenderingOptions | null) { - const { $: { scopedClassName = null } = {}, footnotes: useFootnotes = true, gfm: useGfm = true, remarkPlugins = [], rehypePlugins = [] } = opts ?? {}; - const { headers, rehypeCollectHeaders } = createCollectHeaders(); - let parser = unified() - .use(markdown) - .use(remarkSlug) - .use([remarkExpressions, { addResult: true }]); - - if (remarkPlugins.length === 0) { - if (useGfm) { - remarkPlugins.push('remark-gfm'); - } - - if (useFootnotes) { - remarkPlugins.push('remark-footnotes'); - } - - remarkPlugins.push('@silvenon/remark-smartypants'); - } - const loadedRemarkPlugins = await Promise.all(loadPlugins(remarkPlugins)); - const loadedRehypePlugins = await Promise.all(loadPlugins(rehypePlugins)); - - loadedRemarkPlugins.forEach(([plugin, opts]) => { - parser.use(plugin, opts); - }); - - if (scopedClassName) { - parser.use(scopedStyles(scopedClassName)); - } - - parser.use(remarkCodeBlock); - parser.use(markdownToHtml, { allowDangerousHtml: true, passThrough: ['raw', 'mdxTextExpression'] }); - parser.use(rehypeExpressions); - - loadedRehypePlugins.forEach(([plugin, opts]) => { - parser.use(plugin, opts); - }); - - let result: string; - try { - const vfile = await parser - .use(raw) - .use(rehypeCollectHeaders) - .use(rehypeCodeBlock) - .use(rehypeStringify, { entities: { useNamedReferences: true } }) - .process(content); - result = vfile.toString(); - } catch (err) { - throw err; - } - - return { - astro: { headers, source: content, html: result.toString() }, - content: result.toString(), - }; -} diff --git a/packages/markdown-support/src/load-plugins.ts b/packages/markdown-support/src/load-plugins.ts deleted file mode 100644 index 6d30e8361..000000000 --- a/packages/markdown-support/src/load-plugins.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as unified from 'unified'; -import type { Plugin, UnifiedPluginImport } from './types'; - -async function importPlugin(p: string | UnifiedPluginImport): UnifiedPluginImport { - if (typeof p === 'string') { - return await import(p); - } - - return await p; -} - -export function loadPlugins(items: Plugin[]): Promise<[unified.Plugin] | [unified.Plugin, any]>[] { - return items.map((p) => { - return new Promise((resolve, reject) => { - if (Array.isArray(p)) { - const [plugin, opts] = p; - return importPlugin(plugin) - .then((m) => resolve([m.default, opts])) - .catch((e) => reject(e)); - } - - return importPlugin(p) - .then((m) => resolve([m.default])) - .catch((e) => reject(e)); - }); - }); -} diff --git a/packages/markdown-support/src/rehype-collect-headers.ts b/packages/markdown-support/src/rehype-collect-headers.ts deleted file mode 100644 index 211b7177c..000000000 --- a/packages/markdown-support/src/rehype-collect-headers.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { visit } from 'unist-util-visit'; -import type { Root, Properties } from 'hast'; -import slugger from 'github-slugger'; - -/** */ -export default function createCollectHeaders() { - const headers: any[] = []; - - function rehypeCollectHeaders() { - return function (tree: Root) { - visit(tree, (node) => { - if (node.type !== 'element') return; - const { tagName } = node; - if (tagName[0] !== 'h') return; - const [_, level] = tagName.match(/h([0-6])/) ?? []; - if (!level) return; - const depth = Number.parseInt(level); - - let text = ''; - - visit(node, 'text', (child) => { - text += child.value; - }); - - let slug = node?.data?.id || slugger.slug(text); - - node.data = node.data || {}; - node.data.properties = node.data.properties || {}; - node.data.properties = { ...(node.data.properties as Properties), slug }; - headers.push({ depth, slug, text }); - }); - }; - } - - return { - headers, - rehypeCollectHeaders, - }; -} diff --git a/packages/markdown-support/src/rehype-expressions.ts b/packages/markdown-support/src/rehype-expressions.ts deleted file mode 100644 index d296c2afe..000000000 --- a/packages/markdown-support/src/rehype-expressions.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { map } from 'unist-util-map'; - -export default function rehypeExpressions(): any { - return function (node: any): any { - return map(node, (child) => { - if (child.type === 'mdxTextExpression') { - return { type: 'text', value: `{${(child as any).value}}` }; - } - return child; - }); - }; -} diff --git a/packages/markdown-support/src/remark-expressions.ts b/packages/markdown-support/src/remark-expressions.ts deleted file mode 100644 index a38c5f3bf..000000000 --- a/packages/markdown-support/src/remark-expressions.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { mdxExpression } from 'micromark-extension-mdx-expression'; -import { mdxExpressionFromMarkdown, mdxExpressionToMarkdown } from 'mdast-util-mdx-expression'; - -function remarkExpressions(this: any, options: any) { - let settings = options || {}; - let data = this.data(); - - add('micromarkExtensions', mdxExpression({})); - add('fromMarkdownExtensions', mdxExpressionFromMarkdown); - add('toMarkdownExtensions', mdxExpressionToMarkdown); - - function add(field: any, value: any) { - /* istanbul ignore if - other extensions. */ - if (data[field]) data[field].push(value); - else data[field] = [value]; - } -} - -export default remarkExpressions; diff --git a/packages/markdown-support/src/remark-scoped-styles.ts b/packages/markdown-support/src/remark-scoped-styles.ts deleted file mode 100644 index 9ca70c029..000000000 --- a/packages/markdown-support/src/remark-scoped-styles.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { visit } from 'unist-util-visit'; -const noVisit = new Set(['root', 'html', 'text']); - -/** */ -export default function scopedStyles(className: string) { - const visitor = (node: any) => { - if (noVisit.has(node.type)) return; - - const { data } = node; - let currentClassName = data?.hProperties?.class ?? ''; - node.data = node.data || {}; - node.data.hProperties = node.data.hProperties || {}; - node.data.hProperties.class = `${className} ${currentClassName}`.trim(); - - return node; - }; - return () => (tree: any) => visit(tree, visitor); -} diff --git a/packages/markdown-support/src/types.ts b/packages/markdown-support/src/types.ts deleted file mode 100644 index be73db6a5..000000000 --- a/packages/markdown-support/src/types.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as unified from 'unified'; - -export type UnifiedPluginImport = Promise<{ default: unified.Plugin }>; -export type Plugin = string | [string, any] | UnifiedPluginImport | [UnifiedPluginImport, any]; - -export interface AstroMarkdownOptions { - /** Enable or disable footnotes syntax extension */ - footnotes: boolean; - /** Enable or disable GitHub-flavored Markdown syntax extension */ - gfm: boolean; - remarkPlugins: Plugin[]; - rehypePlugins: Plugin[]; -} - -export interface MarkdownRenderingOptions extends Partial<AstroMarkdownOptions> { - /** @internal */ - $?: { - scopedClassName: string | null; - }; -} |