@astrojs/markdown-remark 0.5.0 → 0.6.1-next.2
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.
- package/CHANGELOG.md +37 -4
- package/dist/index.js +10 -3
- package/dist/load-plugins.d.ts +1 -1
- package/dist/load-plugins.js +6 -5
- package/dist/rehype-collect-headers.js +1 -1
- package/dist/rehype-escape.js +1 -1
- package/dist/rehype-expressions.js +1 -1
- package/dist/rehype-islands.js +3 -2
- package/dist/rehype-jsx.js +1 -1
- package/dist/remark-expressions.js +1 -1
- package/dist/remark-jsx.js +1 -1
- package/dist/remark-prism.js +1 -1
- package/dist/remark-scoped-styles.js +1 -1
- package/dist/remark-shiki.d.ts +30 -0
- package/dist/remark-shiki.js +29 -0
- package/dist/remark-slug.js +1 -1
- package/dist/remark-unwrap.js +3 -2
- package/dist/types.d.ts +5 -5
- package/package.json +9 -4
- package/src/index.ts +68 -60
- package/src/load-plugins.ts +21 -20
- package/src/rehype-collect-headers.ts +25 -25
- package/src/rehype-escape.ts +8 -8
- package/src/rehype-expressions.ts +8 -8
- package/src/rehype-islands.ts +28 -24
- package/src/rehype-jsx.ts +24 -24
- package/src/remark-expressions.ts +19 -19
- package/src/remark-jsx.ts +19 -19
- package/src/remark-prism.ts +42 -42
- package/src/remark-scoped-styles.ts +10 -10
- package/src/remark-shiki.ts +62 -0
- package/src/remark-slug.ts +14 -14
- package/src/remark-unwrap.ts +30 -26
- package/src/types.ts +12 -10
- package/tsconfig.json +1 -1
|
@@ -4,35 +4,35 @@ import slugger from 'github-slugger';
|
|
|
4
4
|
|
|
5
5
|
/** */
|
|
6
6
|
export default function createCollectHeaders() {
|
|
7
|
-
|
|
7
|
+
const headers: any[] = [];
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
19
|
+
let text = '';
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
visit(node, 'text', (child) => {
|
|
22
|
+
text += child.value;
|
|
23
|
+
});
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
let slug = node?.properties?.id || slugger.slug(text);
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
return {
|
|
35
|
+
headers,
|
|
36
|
+
rehypeCollectHeaders,
|
|
37
|
+
};
|
|
38
38
|
}
|
package/src/rehype-escape.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { SKIP, visit } from 'unist-util-visit';
|
|
2
2
|
|
|
3
3
|
export default function rehypeEscape(): any {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
}
|
package/src/rehype-islands.ts
CHANGED
|
@@ -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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
8
|
-
|
|
7
|
+
let settings = options || {};
|
|
8
|
+
let data = this.data();
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
add('micromarkExtensions', mdxExpression({}));
|
|
11
|
+
add('fromMarkdownExtensions', mdxExpressionFromMarkdown);
|
|
12
|
+
add('toMarkdownExtensions', mdxExpressionToMarkdown);
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
8
|
-
|
|
7
|
+
let settings = options || {};
|
|
8
|
+
let data = this.data();
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
}
|
package/src/remark-prism.ts
CHANGED
|
@@ -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
|
-
|
|
10
|
+
let classLanguage = `language-${lang}`;
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
if (lang == null) {
|
|
13
|
+
lang = 'plaintext';
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
const ensureLoaded = (lang: string) => {
|
|
17
|
+
if (lang && !Prism.languages[lang]) {
|
|
18
|
+
loadLanguages([lang]);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
if (lang && !Prism.languages[lang]) {
|
|
33
|
+
console.warn(`Unable to load the language: ${lang}`);
|
|
34
|
+
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
return function (tree: any) {
|
|
50
|
+
const visitor = (node: any) => {
|
|
51
|
+
let { lang, value } = node;
|
|
52
|
+
node.type = 'html';
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7
|
-
|
|
6
|
+
const visitor = (node: any) => {
|
|
7
|
+
if (noVisit.has(node.type)) return;
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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" and add "data-astro-raw".
|
|
44
|
+
html = html.replace('<pre class="shiki"', '<pre data-astro-raw 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;
|
package/src/remark-slug.ts
CHANGED
|
@@ -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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
}
|
package/src/remark-unwrap.ts
CHANGED
|
@@ -1,34 +1,38 @@
|
|
|
1
|
-
import { visit, SKIP } from 'unist-util-visit';
|
|
1
|
+
import { visit as _visit, SKIP } 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
|
// Remove the wrapping paragraph for <astro-root> islands
|
|
4
8
|
export default function remarkUnwrap() {
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
const astroRootNodes = new Set();
|
|
10
|
+
let insideAstroRoot = false;
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
return (tree: any) => {
|
|
13
|
+
// reset state
|
|
14
|
+
insideAstroRoot = false;
|
|
15
|
+
astroRootNodes.clear();
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
visit(tree, 'html', (node) => {
|
|
18
|
+
if (node.value.indexOf('<astro-root') > -1 && !insideAstroRoot) {
|
|
19
|
+
insideAstroRoot = true;
|
|
20
|
+
}
|
|
21
|
+
if (node.value.indexOf('</astro-root') > -1 && insideAstroRoot) {
|
|
22
|
+
insideAstroRoot = false;
|
|
23
|
+
}
|
|
24
|
+
astroRootNodes.add(node);
|
|
25
|
+
});
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
visit(tree, 'paragraph', (node, index, parent) => {
|
|
28
|
+
if (parent && typeof index === 'number' && containsAstroRootNode(node)) {
|
|
29
|
+
parent.children.splice(index, 1, ...node.children);
|
|
30
|
+
return [SKIP, index];
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
};
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
function containsAstroRootNode(node: any) {
|
|
36
|
+
return node.children.map((child: any) => astroRootNodes.has(child)).reduce((all: boolean, v: boolean) => (all ? all : v), false);
|
|
37
|
+
}
|
|
34
38
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import * as unified from 'unified';
|
|
1
|
+
import type * as unified from 'unified';
|
|
2
|
+
import type { ShikiConfig } from './remark-shiki';
|
|
2
3
|
|
|
3
|
-
export type
|
|
4
|
-
export type Plugin = string | [string, any] | UnifiedPluginImport | [UnifiedPluginImport, any];
|
|
4
|
+
export type Plugin = string | [string, any] | unified.Plugin | [unified.Plugin, any];
|
|
5
5
|
|
|
6
6
|
export interface AstroMarkdownOptions {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
mode?: 'md' | 'mdx';
|
|
8
|
+
syntaxHighlight?: 'prism' | 'shiki' | false;
|
|
9
|
+
shikiConfig?: ShikiConfig;
|
|
10
|
+
remarkPlugins?: Plugin[];
|
|
11
|
+
rehypePlugins?: Plugin[];
|
|
10
12
|
}
|
|
11
13
|
|
|
12
14
|
export interface MarkdownRenderingOptions extends Partial<AstroMarkdownOptions> {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
/** @internal */
|
|
16
|
+
$?: {
|
|
17
|
+
scopedClassName: string | null;
|
|
18
|
+
};
|
|
17
19
|
}
|