@astrojs/markdown-remark 0.4.0 → 0.6.1-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,27 +1,28 @@
1
1
  import * as unified from 'unified';
2
- import type { Plugin, UnifiedPluginImport } from './types';
2
+ import type { Plugin } from './types';
3
3
 
4
- async function importPlugin(p: string | UnifiedPluginImport): UnifiedPluginImport {
5
- if (typeof p === 'string') {
6
- return await import(p);
7
- }
4
+ async function importPlugin(p: string | unified.Plugin): Promise<unified.Plugin> {
5
+ if (typeof p === 'string') {
6
+ const importResult = await import(p);
7
+ return importResult.default;
8
+ }
8
9
 
9
- return await p;
10
+ return p;
10
11
  }
11
12
 
12
- export function loadPlugins(items: Plugin[]): Promise<[unified.Plugin] | [unified.Plugin, any]>[] {
13
- return items.map((p) => {
14
- return new Promise((resolve, reject) => {
15
- if (Array.isArray(p)) {
16
- const [plugin, opts] = p;
17
- return importPlugin(plugin)
18
- .then((m) => resolve([m.default, opts]))
19
- .catch((e) => reject(e));
20
- }
13
+ export function loadPlugins(items: Plugin[]): Promise<[unified.Plugin, any?]>[] {
14
+ return items.map((p) => {
15
+ return new Promise((resolve, reject) => {
16
+ if (Array.isArray(p)) {
17
+ const [plugin, opts] = p;
18
+ return importPlugin(plugin)
19
+ .then((m) => resolve([m, opts]))
20
+ .catch((e) => reject(e));
21
+ }
21
22
 
22
- return importPlugin(p)
23
- .then((m) => resolve([m.default]))
24
- .catch((e) => reject(e));
25
- });
26
- });
23
+ return importPlugin(p)
24
+ .then((m) => resolve([m]))
25
+ .catch((e) => reject(e));
26
+ });
27
+ });
27
28
  }
@@ -4,35 +4,35 @@ import slugger from 'github-slugger';
4
4
 
5
5
  /** */
6
6
  export default function createCollectHeaders() {
7
- const headers: any[] = [];
7
+ const headers: any[] = [];
8
8
 
9
- function rehypeCollectHeaders() {
10
- return function (tree: Root) {
11
- visit(tree, (node) => {
12
- if (node.type !== 'element') return;
13
- const { tagName } = node;
14
- if (tagName[0] !== 'h') return;
15
- const [_, level] = tagName.match(/h([0-6])/) ?? [];
16
- if (!level) return;
17
- const depth = Number.parseInt(level);
9
+ function rehypeCollectHeaders() {
10
+ return function (tree: Root) {
11
+ visit(tree, (node) => {
12
+ if (node.type !== 'element') return;
13
+ const { tagName } = node;
14
+ if (tagName[0] !== 'h') return;
15
+ const [_, level] = tagName.match(/h([0-6])/) ?? [];
16
+ if (!level) return;
17
+ const depth = Number.parseInt(level);
18
18
 
19
- let text = '';
19
+ let text = '';
20
20
 
21
- visit(node, 'text', (child) => {
22
- text += child.value;
23
- });
21
+ visit(node, 'text', (child) => {
22
+ text += child.value;
23
+ });
24
24
 
25
- let slug = node?.properties?.id || slugger.slug(text);
25
+ let slug = node?.properties?.id || slugger.slug(text);
26
26
 
27
- node.properties = node.properties || {};
28
- node.properties.id = slug;
29
- headers.push({ depth, slug, text });
30
- });
31
- };
32
- }
27
+ node.properties = node.properties || {};
28
+ node.properties.id = slug;
29
+ headers.push({ depth, slug, text });
30
+ });
31
+ };
32
+ }
33
33
 
34
- return {
35
- headers,
36
- rehypeCollectHeaders,
37
- };
34
+ return {
35
+ headers,
36
+ rehypeCollectHeaders,
37
+ };
38
38
  }
@@ -1,12 +1,12 @@
1
1
  import { SKIP, visit } from 'unist-util-visit';
2
2
 
3
3
  export default function rehypeEscape(): any {
4
- return function (node: any): any {
5
- return visit(node, 'element', (el) => {
6
- if (el.tagName === 'code' || el.tagName === 'pre') {
7
- el.properties['data-astro-raw'] = true;
8
- }
9
- return el;
10
- });
11
- };
4
+ return function (node: any): any {
5
+ return visit(node, 'element', (el) => {
6
+ if (el.tagName === 'code' || el.tagName === 'pre') {
7
+ el.properties['data-astro-raw'] = true;
8
+ }
9
+ return el;
10
+ });
11
+ };
12
12
  }
@@ -1,12 +1,12 @@
1
1
  import { map } from 'unist-util-map';
2
2
 
3
3
  export default function rehypeExpressions(): any {
4
- return function (node: any): any {
5
- return map(node, (child) => {
6
- if (child.type === 'mdxTextExpression') {
7
- return { type: 'text', value: `{${(child as any).value}}` };
8
- }
9
- return child;
10
- });
11
- };
4
+ return function (node: any): any {
5
+ return map(node, (child) => {
6
+ if (child.type === 'mdxTextExpression') {
7
+ return { type: 'text', value: `{${(child as any).value}}` };
8
+ }
9
+ return child;
10
+ });
11
+ };
12
12
  }
@@ -1,31 +1,35 @@
1
- import { SKIP, visit } from 'unist-util-visit';
1
+ import { SKIP, visit as _visit } from 'unist-util-visit';
2
+
3
+ // This is a workaround.
4
+ // It fixes a compatibility issue between different, incompatible ASTs given by plugins to Unist
5
+ const visit = _visit as (node: any, type: string, callback?: (node: any, index: number, parent: any) => any) => any;
2
6
 
3
7
  // This fixes some confusing bugs coming from somewhere inside of our Markdown pipeline.
4
8
  // `unist`/`remark`/`rehype` (not sure) often generate malformed HTML inside of <astro-root>
5
9
  // For hydration to work properly, frameworks need the DOM to be the exact same on server/client.
6
10
  // This reverts some "helpful corrections" that are applied to our perfectly valid HTML!
7
11
  export default function rehypeIslands(): any {
8
- return function (node: any): any {
9
- return visit(node, 'element', (el) => {
10
- // Bugs only happen inside of <astro-root> islands
11
- if (el.tagName == 'astro-root') {
12
- visit(el, 'text', (child, index, parent) => {
13
- if (child.type === 'text') {
14
- // Sometimes comments can be trapped as text, which causes them to be escaped
15
- // This casts them back to real HTML comments
16
- if (parent && child.value.indexOf('<!--') > -1 && index != null) {
17
- parent.children.splice(index, 1, { ...child, type: 'comment', value: child.value.replace('<!--', '').replace('-->', '').trim() });
18
- return [SKIP, index];
19
- }
20
- // For some reason `rehype` likes to inject extra linebreaks,
21
- // but React and Vue throw hydration errors when they see these!
22
- // This removes any extra linebreaks, which is fine because
23
- // framework compilers don't preserve them anyway
24
- child.value = child.value.replace(/\n+/g, '');
25
- return child;
26
- }
27
- });
28
- }
29
- });
30
- };
12
+ return function (node: any): any {
13
+ return visit(node, 'element', (el) => {
14
+ // Bugs only happen inside of <astro-root> islands
15
+ if (el.tagName == 'astro-root') {
16
+ visit(el, 'text', (child, index, parent) => {
17
+ if (child.type === 'text') {
18
+ // Sometimes comments can be trapped as text, which causes them to be escaped
19
+ // This casts them back to real HTML comments
20
+ if (parent && child.value.indexOf('<!--') > -1 && index != null) {
21
+ parent.children.splice(index, 1, { ...child, type: 'comment', value: child.value.replace('<!--', '').replace('-->', '').trim() });
22
+ return [SKIP, index];
23
+ }
24
+ // For some reason `rehype` likes to inject extra linebreaks,
25
+ // but React and Vue throw hydration errors when they see these!
26
+ // This removes any extra linebreaks, which is fine because
27
+ // framework compilers don't preserve them anyway
28
+ child.value = child.value.replace(/\n+/g, '');
29
+ return child;
30
+ }
31
+ });
32
+ }
33
+ });
34
+ };
31
35
  }
package/src/rehype-jsx.ts CHANGED
@@ -2,28 +2,28 @@ import { map } from 'unist-util-map';
2
2
 
3
3
  const MDX_ELEMENTS = new Set(['mdxJsxFlowElement', 'mdxJsxTextElement']);
4
4
  export default function rehypeJsx(): any {
5
- return function (node: any): any {
6
- return map(node, (child: any) => {
7
- if (child.type === 'element') {
8
- return { ...child, tagName: `${child.tagName}` };
9
- }
10
- if (MDX_ELEMENTS.has(child.type)) {
11
- return {
12
- ...child,
13
- type: 'element',
14
- tagName: `${child.name}`,
15
- properties: child.attributes.reduce((acc: any[], entry: any) => {
16
- let attr = entry.value;
17
- if (attr && typeof attr === 'object') {
18
- attr = `{${attr.value}}`;
19
- } else if (attr === null) {
20
- attr = `{true}`;
21
- }
22
- return Object.assign(acc, { [entry.name]: attr });
23
- }, {}),
24
- };
25
- }
26
- return child;
27
- });
28
- };
5
+ return function (node: any): any {
6
+ return map(node, (child: any) => {
7
+ if (child.type === 'element') {
8
+ return { ...child, tagName: `${child.tagName}` };
9
+ }
10
+ if (MDX_ELEMENTS.has(child.type)) {
11
+ return {
12
+ ...child,
13
+ type: 'element',
14
+ tagName: `${child.name}`,
15
+ properties: child.attributes.reduce((acc: any[], entry: any) => {
16
+ let attr = entry.value;
17
+ if (attr && typeof attr === 'object') {
18
+ attr = `{${attr.value}}`;
19
+ } else if (attr === null) {
20
+ attr = `{true}`;
21
+ }
22
+ return Object.assign(acc, { [entry.name]: attr });
23
+ }, {}),
24
+ };
25
+ }
26
+ return child;
27
+ });
28
+ };
29
29
  }
@@ -4,28 +4,28 @@ let mdxExpressionFromMarkdown: any;
4
4
  let mdxExpressionToMarkdown: any;
5
5
 
6
6
  export function remarkExpressions(this: any, options: any) {
7
- let settings = options || {};
8
- let data = this.data();
7
+ let settings = options || {};
8
+ let data = this.data();
9
9
 
10
- add('micromarkExtensions', mdxExpression({}));
11
- add('fromMarkdownExtensions', mdxExpressionFromMarkdown);
12
- add('toMarkdownExtensions', mdxExpressionToMarkdown);
10
+ add('micromarkExtensions', mdxExpression({}));
11
+ add('fromMarkdownExtensions', mdxExpressionFromMarkdown);
12
+ add('toMarkdownExtensions', mdxExpressionToMarkdown);
13
13
 
14
- function add(field: any, value: any) {
15
- /* istanbul ignore if - other extensions. */
16
- if (data[field]) data[field].push(value);
17
- else data[field] = [value];
18
- }
14
+ function add(field: any, value: any) {
15
+ /* istanbul ignore if - other extensions. */
16
+ if (data[field]) data[field].push(value);
17
+ else data[field] = [value];
18
+ }
19
19
  }
20
20
 
21
21
  export async function loadRemarkExpressions() {
22
- if (!mdxExpression) {
23
- const micromarkMdxExpression = await import('micromark-extension-mdx-expression');
24
- mdxExpression = micromarkMdxExpression.mdxExpression;
25
- }
26
- if (!mdxExpressionFromMarkdown || !mdxExpressionToMarkdown) {
27
- const mdastUtilMdxExpression = await import('mdast-util-mdx-expression');
28
- mdxExpressionFromMarkdown = mdastUtilMdxExpression.mdxExpressionFromMarkdown;
29
- mdxExpressionToMarkdown = mdastUtilMdxExpression.mdxExpressionToMarkdown;
30
- }
22
+ if (!mdxExpression) {
23
+ const micromarkMdxExpression = await import('micromark-extension-mdx-expression');
24
+ mdxExpression = micromarkMdxExpression.mdxExpression;
25
+ }
26
+ if (!mdxExpressionFromMarkdown || !mdxExpressionToMarkdown) {
27
+ const mdastUtilMdxExpression = await import('mdast-util-mdx-expression');
28
+ mdxExpressionFromMarkdown = mdastUtilMdxExpression.mdxExpressionFromMarkdown;
29
+ mdxExpressionToMarkdown = mdastUtilMdxExpression.mdxExpressionToMarkdown;
30
+ }
31
31
  }
package/src/remark-jsx.ts CHANGED
@@ -4,28 +4,28 @@ let mdxJsxFromMarkdown: any;
4
4
  let mdxJsxToMarkdown: any;
5
5
 
6
6
  export function remarkJsx(this: any, options: any) {
7
- let settings = options || {};
8
- let data = this.data();
7
+ let settings = options || {};
8
+ let data = this.data();
9
9
 
10
- // TODO this seems to break adding slugs, no idea why add('micromarkExtensions', mdxJsx({}));
11
- add('fromMarkdownExtensions', mdxJsxFromMarkdown);
12
- add('toMarkdownExtensions', mdxJsxToMarkdown);
10
+ // TODO this seems to break adding slugs, no idea why add('micromarkExtensions', mdxJsx({}));
11
+ add('fromMarkdownExtensions', mdxJsxFromMarkdown);
12
+ add('toMarkdownExtensions', mdxJsxToMarkdown);
13
13
 
14
- function add(field: any, value: any) {
15
- /* istanbul ignore if - other extensions. */
16
- if (data[field]) data[field].push(value);
17
- else data[field] = [value];
18
- }
14
+ function add(field: any, value: any) {
15
+ /* istanbul ignore if - other extensions. */
16
+ if (data[field]) data[field].push(value);
17
+ else data[field] = [value];
18
+ }
19
19
  }
20
20
 
21
21
  export async function loadRemarkJsx() {
22
- if (!mdxJsx) {
23
- const micromarkMdxJsx = await import('micromark-extension-mdx-jsx');
24
- mdxJsx = micromarkMdxJsx.mdxJsx;
25
- }
26
- if (!mdxJsxFromMarkdown || !mdxJsxToMarkdown) {
27
- const mdastUtilMdxJsx = await import('mdast-util-mdx-jsx');
28
- mdxJsxFromMarkdown = mdastUtilMdxJsx.mdxJsxFromMarkdown;
29
- mdxJsxToMarkdown = mdastUtilMdxJsx.mdxJsxToMarkdown;
30
- }
22
+ if (!mdxJsx) {
23
+ const micromarkMdxJsx = await import('micromark-extension-mdx-jsx');
24
+ mdxJsx = micromarkMdxJsx.mdxJsx;
25
+ }
26
+ if (!mdxJsxFromMarkdown || !mdxJsxToMarkdown) {
27
+ const mdastUtilMdxJsx = await import('mdast-util-mdx-jsx');
28
+ mdxJsxFromMarkdown = mdastUtilMdxJsx.mdxJsxFromMarkdown;
29
+ mdxJsxToMarkdown = mdastUtilMdxJsx.mdxJsxToMarkdown;
30
+ }
31
31
  }
@@ -7,64 +7,64 @@ const noVisit = new Set(['root', 'html', 'text']);
7
7
  const languageMap = new Map([['ts', 'typescript']]);
8
8
 
9
9
  function runHighlighter(lang: string, code: string) {
10
- let classLanguage = `language-${lang}`;
10
+ let classLanguage = `language-${lang}`;
11
11
 
12
- if (lang == null) {
13
- lang = 'plaintext';
14
- }
12
+ if (lang == null) {
13
+ lang = 'plaintext';
14
+ }
15
15
 
16
- const ensureLoaded = (lang: string) => {
17
- if (lang && !Prism.languages[lang]) {
18
- loadLanguages([lang]);
19
- }
20
- };
16
+ const ensureLoaded = (lang: string) => {
17
+ if (lang && !Prism.languages[lang]) {
18
+ loadLanguages([lang]);
19
+ }
20
+ };
21
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
- }
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
31
 
32
- if (lang && !Prism.languages[lang]) {
33
- console.warn(`Unable to load the language: ${lang}`);
34
- }
32
+ if (lang && !Prism.languages[lang]) {
33
+ console.warn(`Unable to load the language: ${lang}`);
34
+ }
35
35
 
36
- const grammar = Prism.languages[lang];
37
- let html = code;
38
- if (grammar) {
39
- html = Prism.highlight(code, grammar, lang);
40
- }
36
+ const grammar = Prism.languages[lang];
37
+ let html = code;
38
+ if (grammar) {
39
+ html = Prism.highlight(code, grammar, lang);
40
+ }
41
41
 
42
- return { classLanguage, html };
42
+ return { classLanguage, html };
43
43
  }
44
44
 
45
45
  type MaybeString = string | null | undefined;
46
46
 
47
47
  /** */
48
48
  function transformer(className: MaybeString) {
49
- return function (tree: any) {
50
- const visitor = (node: any) => {
51
- let { lang, value } = node;
52
- node.type = 'html';
49
+ return function (tree: any) {
50
+ const visitor = (node: any) => {
51
+ let { lang, value } = node;
52
+ node.type = 'html';
53
53
 
54
- let { html, classLanguage } = runHighlighter(lang, value);
55
- let classes = [classLanguage];
56
- if (className) {
57
- classes.push(className);
58
- }
59
- node.value = `<pre class="${classes.join(' ')}"><code data-astro-raw class="${classLanguage}">${html}</code></pre>`;
60
- return node;
61
- };
62
- return visit(tree, 'code', visitor);
63
- };
54
+ let { html, classLanguage } = runHighlighter(lang, value);
55
+ let classes = [classLanguage];
56
+ if (className) {
57
+ classes.push(className);
58
+ }
59
+ node.value = `<pre class="${classes.join(' ')}"><code data-astro-raw class="${classLanguage}">${html}</code></pre>`;
60
+ return node;
61
+ };
62
+ return visit(tree, 'code', visitor);
63
+ };
64
64
  }
65
65
 
66
66
  function plugin(className: MaybeString) {
67
- return transformer.bind(null, className);
67
+ return transformer.bind(null, className);
68
68
  }
69
69
 
70
70
  export default plugin;
@@ -3,16 +3,16 @@ const noVisit = new Set(['root', 'html', 'text']);
3
3
 
4
4
  /** */
5
5
  export default function scopedStyles(className: string) {
6
- const visitor = (node: any) => {
7
- if (noVisit.has(node.type)) return;
6
+ const visitor = (node: any) => {
7
+ if (noVisit.has(node.type)) return;
8
8
 
9
- const { data } = node;
10
- let currentClassName = data?.hProperties?.class ?? '';
11
- node.data = node.data || {};
12
- node.data.hProperties = node.data.hProperties || {};
13
- node.data.hProperties.class = `${className} ${currentClassName}`.trim();
9
+ const { data } = node;
10
+ let currentClassName = data?.hProperties?.class ?? '';
11
+ node.data = node.data || {};
12
+ node.data.hProperties = node.data.hProperties || {};
13
+ node.data.hProperties.class = `${className} ${currentClassName}`.trim();
14
14
 
15
- return node;
16
- };
17
- return () => (tree: any) => visit(tree, visitor);
15
+ return node;
16
+ };
17
+ return () => (tree: any) => visit(tree, visitor);
18
18
  }
@@ -0,0 +1,62 @@
1
+ import shiki from 'shiki';
2
+ import { visit } from 'unist-util-visit';
3
+
4
+ export interface ShikiConfig {
5
+ /**
6
+ * The languages loaded to Shiki.
7
+ * Supports all languages listed here: https://github.com/shikijs/shiki/blob/main/docs/languages.md#all-languages
8
+ * Instructions for loading a custom language: https://github.com/shikijs/shiki/blob/main/docs/languages.md#supporting-your-own-languages-with-shiki
9
+ *
10
+ * @default []
11
+ */
12
+ langs?: shiki.ILanguageRegistration[];
13
+ /**
14
+ * The styling theme.
15
+ * Supports all themes listed here: https://github.com/shikijs/shiki/blob/main/docs/themes.md#all-themes
16
+ * Instructions for loading a custom theme: https://github.com/shikijs/shiki/blob/main/docs/themes.md#loading-theme
17
+ *
18
+ * @default "github-dark"
19
+ */
20
+ theme?: shiki.IThemeRegistration;
21
+ /**
22
+ * Enable word wrapping.
23
+ * - true: enabled.
24
+ * - false: enabled.
25
+ * - null: All overflow styling removed. Code will overflow the element by default.
26
+ *
27
+ * @default false
28
+ */
29
+ wrap?: boolean | null;
30
+ }
31
+
32
+ const remarkShiki = async ({ langs = [], theme = 'github-dark', wrap = false }: ShikiConfig) => {
33
+ const highlighter = await shiki.getHighlighter({ theme });
34
+
35
+ for (const lang of langs) {
36
+ await highlighter.loadLanguage(lang);
37
+ }
38
+
39
+ return () => (tree: any) => {
40
+ visit(tree, 'code', (node) => {
41
+ let html = highlighter.codeToHtml(node.value, { lang: node.lang ?? 'plaintext' });
42
+
43
+ // Replace "shiki" class naming with "astro".
44
+ html = html.replace('<pre class="shiki"', '<pre class="astro-code"');
45
+ // Replace "shiki" css variable naming with "astro".
46
+ html = html.replace(/style="(background-)?color: var\(--shiki-/g, 'style="$1color: var(--astro-code-');
47
+ // Handle code wrapping
48
+ // if wrap=null, do nothing.
49
+ if (wrap === false) {
50
+ html = html.replace(/style="(.*?)"/, 'style="$1; overflow-x: auto;"');
51
+ } else if (wrap === true) {
52
+ html = html.replace(/style="(.*?)"/, 'style="$1; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"');
53
+ }
54
+
55
+ node.type = 'html';
56
+ node.value = html;
57
+ node.children = [];
58
+ });
59
+ };
60
+ };
61
+
62
+ export default remarkShiki;
@@ -15,18 +15,18 @@ const slugs = new BananaSlug();
15
15
  * @type {import('unified').Plugin<void[], Root>}
16
16
  */
17
17
  export default function remarkSlug() {
18
- return (tree: any) => {
19
- slugs.reset();
20
- visit(tree, (node) => {
21
- console.log(node);
22
- });
23
- visit(tree, 'heading', (node) => {
24
- const data = node.data || (node.data = {});
25
- const props = /** @type {Properties} */ data.hProperties || (data.hProperties = {});
26
- let id = props.id;
27
- id = id ? slugs.slug(String(id), true) : slugs.slug(toString(node));
28
- data.id = id;
29
- props.id = id;
30
- });
31
- };
18
+ return (tree: any) => {
19
+ slugs.reset();
20
+ visit(tree, (node) => {
21
+ console.log(node);
22
+ });
23
+ visit(tree, 'heading', (node) => {
24
+ const data = node.data || (node.data = {});
25
+ const props = /** @type {Properties} */ data.hProperties || (data.hProperties = {});
26
+ let id = props.id;
27
+ id = id ? slugs.slug(String(id), true) : slugs.slug(toString(node));
28
+ data.id = id;
29
+ props.id = id;
30
+ });
31
+ };
32
32
  }