@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.
- package/CHANGELOG.md +43 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +17 -9
- 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 +22 -18
- package/src/index.ts +70 -64
- 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
package/src/load-plugins.ts
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
import * as unified from 'unified';
|
|
2
|
-
import type { Plugin
|
|
2
|
+
import type { Plugin } from './types';
|
|
3
3
|
|
|
4
|
-
async function importPlugin(p: string |
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
|
|
10
|
+
return p;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
export function loadPlugins(items: Plugin[]): Promise<[unified.Plugin
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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".
|
|
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;
|
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
|
}
|