@temelj/mdx 0.7.0 → 0.8.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/README.md +1 -1
- package/dist/compiler.d.ts +40 -0
- package/dist/compiler.js +75 -0
- package/dist/mod.d.ts +13 -0
- package/dist/mod.js +3 -0
- package/dist/plugins/heading-id/plugin.d.ts +18 -0
- package/dist/plugins/heading-id/plugin.js +22 -0
- package/dist/plugins/mod.d.ts +8 -0
- package/dist/plugins/mod.js +4 -0
- package/dist/plugins/remove-imports-exports.d.ts +11 -0
- package/dist/plugins/remove-imports-exports.js +10 -0
- package/dist/plugins/syntax-highlight/code-meta.d.ts +21 -0
- package/dist/plugins/syntax-highlight/code-meta.js +50 -0
- package/{types → dist}/plugins/syntax-highlight/plugin.d.ts +10 -9
- package/dist/plugins/syntax-highlight/plugin.js +147 -0
- package/dist/plugins/tree-processor/plugin.d.ts +20 -0
- package/dist/plugins/tree-processor/plugin.js +22 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +0 -0
- package/package.json +28 -25
- package/esm/compiler.js +0 -91
- package/esm/mod.js +0 -3
- package/esm/package.json +0 -3
- package/esm/plugins/heading-id/plugin.js +0 -19
- package/esm/plugins/mod.js +0 -4
- package/esm/plugins/remove-imports-exports.js +0 -10
- package/esm/plugins/syntax-highlight/code-meta.js +0 -50
- package/esm/plugins/syntax-highlight/plugin.js +0 -135
- package/esm/plugins/tree-processor/plugin.js +0 -19
- package/esm/types.js +0 -1
- package/types/compiler.d.ts +0 -39
- package/types/compiler.d.ts.map +0 -1
- package/types/mod.d.ts +0 -4
- package/types/mod.d.ts.map +0 -1
- package/types/plugins/heading-id/plugin.d.ts +0 -16
- package/types/plugins/heading-id/plugin.d.ts.map +0 -1
- package/types/plugins/mod.d.ts +0 -5
- package/types/plugins/mod.d.ts.map +0 -1
- package/types/plugins/remove-imports-exports.d.ts +0 -9
- package/types/plugins/remove-imports-exports.d.ts.map +0 -1
- package/types/plugins/syntax-highlight/code-meta.d.ts +0 -19
- package/types/plugins/syntax-highlight/code-meta.d.ts.map +0 -1
- package/types/plugins/syntax-highlight/plugin.d.ts.map +0 -1
- package/types/plugins/tree-processor/plugin.d.ts +0 -19
- package/types/plugins/tree-processor/plugin.d.ts.map +0 -1
- package/types/types.d.ts +0 -3
- package/types/types.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { CompileOptions } from '@mdx-js/mdx';
|
|
2
|
+
export { default as remarkFrontmatterPlugin } from 'remark-frontmatter';
|
|
3
|
+
export { default as remarkGfmPlugin } from 'remark-gfm';
|
|
4
|
+
import { Plugin } from 'unified';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { Node } from 'hast';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Represents the source content for an MDX document.
|
|
10
|
+
*/
|
|
11
|
+
type MdxSource = string | Uint8Array;
|
|
12
|
+
/**
|
|
13
|
+
* Options for compiling an MDX document.
|
|
14
|
+
*/
|
|
15
|
+
interface MdxCompileOptions {
|
|
16
|
+
frontmatterOnly?: boolean | undefined;
|
|
17
|
+
mdxOptions?: CompileOptions;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The result of compiling an MDX document.
|
|
21
|
+
* Compiled content is optional, because sometimes we only need the frontmatter.
|
|
22
|
+
*/
|
|
23
|
+
interface MdxArtifact<TFrontmatter = Record<string, unknown>> {
|
|
24
|
+
compiled?: string | undefined;
|
|
25
|
+
frontmatter: TFrontmatter;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A reusable compiler for compiling MDX.
|
|
29
|
+
*/
|
|
30
|
+
declare class MdxCompiler {
|
|
31
|
+
private readonly mdxOptions;
|
|
32
|
+
private readonly remarkPlugins;
|
|
33
|
+
private readonly rehypePlugins;
|
|
34
|
+
constructor(mdxOptions?: CompileOptions);
|
|
35
|
+
withRemarkPlugin<TOptions>(plugin: Plugin<[TOptions?], Node, Node>, options?: TOptions): MdxCompiler;
|
|
36
|
+
withRehypePlugin<TOptions>(plugin: Plugin<[TOptions?], Node, Node>, options?: TOptions): MdxCompiler;
|
|
37
|
+
compile<TFrontmatterSchema extends z.ZodSchema>(source: MdxSource, { frontmatterOnly, mdxOptions }?: MdxCompileOptions, frontmatterSchema?: TFrontmatterSchema): Promise<MdxArtifact<z.output<TFrontmatterSchema>>>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { type MdxArtifact, type MdxCompileOptions, MdxCompiler, type MdxSource };
|
package/dist/compiler.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compile as compileMdxJs
|
|
3
|
+
} from "@mdx-js/mdx";
|
|
4
|
+
import remarkFrontmatterPlugin from "remark-frontmatter";
|
|
5
|
+
import remarkGfmPlugin from "remark-gfm";
|
|
6
|
+
import { VFile } from "vfile";
|
|
7
|
+
import { matter } from "vfile-matter";
|
|
8
|
+
class MdxCompiler {
|
|
9
|
+
mdxOptions;
|
|
10
|
+
remarkPlugins;
|
|
11
|
+
rehypePlugins;
|
|
12
|
+
constructor(mdxOptions = {}) {
|
|
13
|
+
this.mdxOptions = mdxOptions;
|
|
14
|
+
this.remarkPlugins = [remarkFrontmatterPlugin, remarkGfmPlugin];
|
|
15
|
+
this.rehypePlugins = [];
|
|
16
|
+
}
|
|
17
|
+
withRemarkPlugin(plugin, options) {
|
|
18
|
+
if (options === void 0) {
|
|
19
|
+
this.remarkPlugins.push(plugin);
|
|
20
|
+
} else {
|
|
21
|
+
this.remarkPlugins.push([plugin, options]);
|
|
22
|
+
}
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
withRehypePlugin(plugin, options) {
|
|
26
|
+
if (options === void 0) {
|
|
27
|
+
this.rehypePlugins.push(plugin);
|
|
28
|
+
} else {
|
|
29
|
+
this.rehypePlugins.push([plugin, options]);
|
|
30
|
+
}
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
async compile(source, { frontmatterOnly = false, mdxOptions } = {}, frontmatterSchema) {
|
|
34
|
+
const vfile = new VFile({
|
|
35
|
+
value: source,
|
|
36
|
+
// Needed so vfile doesn't need to access fs.
|
|
37
|
+
cwd: "/",
|
|
38
|
+
path: "/",
|
|
39
|
+
message: {},
|
|
40
|
+
messages: {}
|
|
41
|
+
});
|
|
42
|
+
matter(vfile, { strip: true });
|
|
43
|
+
const remarkPlugins = [
|
|
44
|
+
...this.remarkPlugins,
|
|
45
|
+
...this.mdxOptions?.remarkPlugins ?? [],
|
|
46
|
+
...mdxOptions?.remarkPlugins ?? []
|
|
47
|
+
];
|
|
48
|
+
const rehypePlugins = [
|
|
49
|
+
...this.rehypePlugins,
|
|
50
|
+
...this.mdxOptions?.rehypePlugins ?? [],
|
|
51
|
+
...mdxOptions?.rehypePlugins ?? []
|
|
52
|
+
];
|
|
53
|
+
let compiled;
|
|
54
|
+
if (!frontmatterOnly) {
|
|
55
|
+
const compiledFile = await compileMdxJs(vfile, {
|
|
56
|
+
outputFormat: "function-body",
|
|
57
|
+
...this.mdxOptions ?? {},
|
|
58
|
+
...mdxOptions ?? {},
|
|
59
|
+
remarkPlugins,
|
|
60
|
+
rehypePlugins
|
|
61
|
+
});
|
|
62
|
+
compiled = compiledFile.value.toString();
|
|
63
|
+
}
|
|
64
|
+
const frontmatter = frontmatterSchema === void 0 ? vfile.data.matter ?? {} : frontmatterSchema.parse(vfile.data.matter ?? {});
|
|
65
|
+
return {
|
|
66
|
+
compiled,
|
|
67
|
+
frontmatter
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
MdxCompiler,
|
|
73
|
+
remarkFrontmatterPlugin,
|
|
74
|
+
remarkGfmPlugin
|
|
75
|
+
};
|
package/dist/mod.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { MdxArtifact, MdxCompileOptions, MdxCompiler, MdxSource } from './compiler.js';
|
|
2
|
+
export { HeadingIdPluginOptions, headingIdPlugin } from './plugins/heading-id/plugin.js';
|
|
3
|
+
export { SyntaxHighlightPluginOptions, syntaxHighlightPlugin } from './plugins/syntax-highlight/plugin.js';
|
|
4
|
+
export { MdxTreeProcessor, treeProcessorPlugin } from './plugins/tree-processor/plugin.js';
|
|
5
|
+
export { removeImportsExportsPlugin } from './plugins/remove-imports-exports.js';
|
|
6
|
+
export { Element as HastElement, Node as HastNode } from 'hast';
|
|
7
|
+
export { default as remarkFrontmatterPlugin } from 'remark-frontmatter';
|
|
8
|
+
export { default as remarkGfmPlugin } from 'remark-gfm';
|
|
9
|
+
import '@mdx-js/mdx';
|
|
10
|
+
import 'unified';
|
|
11
|
+
import 'zod';
|
|
12
|
+
import 'shiki';
|
|
13
|
+
import '@shikijs/transformers';
|
package/dist/mod.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Plugin } from 'unified';
|
|
2
|
+
import { Node } from 'hast';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Options for {@linkcode headingIdPlugin}.
|
|
6
|
+
*/
|
|
7
|
+
interface HeadingIdPluginOptions {
|
|
8
|
+
/** Prefix for title slugs. */
|
|
9
|
+
prefix?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A rehype plugin that adds IDs to heading tags.
|
|
13
|
+
*/
|
|
14
|
+
declare const headingIdPlugin: Plugin<[
|
|
15
|
+
HeadingIdPluginOptions?
|
|
16
|
+
], Node, Node>;
|
|
17
|
+
|
|
18
|
+
export { type HeadingIdPluginOptions, headingIdPlugin };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import GithubSlugger from "github-slugger";
|
|
2
|
+
import { toString as hastToString } from "hast-util-to-string";
|
|
3
|
+
import { visit } from "unist-util-visit";
|
|
4
|
+
const headingIdPlugin = ({ prefix } = {}) => {
|
|
5
|
+
const slugger = new GithubSlugger();
|
|
6
|
+
return (tree) => {
|
|
7
|
+
slugger.reset();
|
|
8
|
+
visit(
|
|
9
|
+
tree,
|
|
10
|
+
"element",
|
|
11
|
+
function visitor(node, index, parent) {
|
|
12
|
+
if (!parent || index === null || !node.tagName.startsWith("h")) return;
|
|
13
|
+
const id = (prefix ?? "") + slugger.slug(hastToString(node));
|
|
14
|
+
node.properties.id = id;
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
return tree;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export {
|
|
21
|
+
headingIdPlugin
|
|
22
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { HeadingIdPluginOptions, headingIdPlugin } from './heading-id/plugin.js';
|
|
2
|
+
export { SyntaxHighlightPluginOptions, syntaxHighlightPlugin } from './syntax-highlight/plugin.js';
|
|
3
|
+
export { MdxTreeProcessor, treeProcessorPlugin } from './tree-processor/plugin.js';
|
|
4
|
+
export { removeImportsExportsPlugin } from './remove-imports-exports.js';
|
|
5
|
+
import 'unified';
|
|
6
|
+
import 'hast';
|
|
7
|
+
import 'shiki';
|
|
8
|
+
import '@shikijs/transformers';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Plugin } from 'unified';
|
|
2
|
+
import { Node } from 'hast';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A remark plugin which removes all import and export statements.
|
|
6
|
+
*/
|
|
7
|
+
declare const removeImportsExportsPlugin: Plugin<[
|
|
8
|
+
unknown
|
|
9
|
+
], Node, Node>;
|
|
10
|
+
|
|
11
|
+
export { removeImportsExportsPlugin };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NumericRange } from '@temelj/iterator';
|
|
2
|
+
import { Element } from 'hast';
|
|
3
|
+
|
|
4
|
+
interface MdxCodeMeta {
|
|
5
|
+
highlight?: MdxCodeMetaHighlightLine;
|
|
6
|
+
showLineNumbers?: MdxCodeMetaLineNumbers;
|
|
7
|
+
commandLine?: MdxCodeMetaCommandLine;
|
|
8
|
+
fileName?: string;
|
|
9
|
+
}
|
|
10
|
+
type MdxCodeMetaHighlightLine = {
|
|
11
|
+
lineRange: NumericRange;
|
|
12
|
+
};
|
|
13
|
+
type MdxCodeMetaLineNumbers = {
|
|
14
|
+
lineRange: NumericRange;
|
|
15
|
+
};
|
|
16
|
+
type MdxCodeMetaCommandLine = {
|
|
17
|
+
commandRange: NumericRange;
|
|
18
|
+
};
|
|
19
|
+
declare function extractCodeMeta(node: Element): MdxCodeMeta;
|
|
20
|
+
|
|
21
|
+
export { type MdxCodeMeta, type MdxCodeMetaCommandLine, type MdxCodeMetaHighlightLine, type MdxCodeMetaLineNumbers, extractCodeMeta };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { parseNumericRange } from "@temelj/iterator";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
function extractCodeMeta(node) {
|
|
4
|
+
const meta = node?.data?.meta ?? node?.properties?.metastring ?? "";
|
|
5
|
+
return parseMetaString(meta);
|
|
6
|
+
}
|
|
7
|
+
const metaSchema = z.object({
|
|
8
|
+
highlight: z.optional(z.string()),
|
|
9
|
+
showLineNumbers: z.optional(z.union([z.boolean(), z.string()])),
|
|
10
|
+
commandLine: z.optional(z.union([z.boolean(), z.string()])),
|
|
11
|
+
fileName: z.optional(z.string())
|
|
12
|
+
});
|
|
13
|
+
function parseMetaString(meta) {
|
|
14
|
+
let raw;
|
|
15
|
+
try {
|
|
16
|
+
raw = JSON.parse(meta.trim());
|
|
17
|
+
} catch {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
const parsed = metaSchema.parse(raw);
|
|
21
|
+
const options = {};
|
|
22
|
+
if (parsed.highlight !== void 0) {
|
|
23
|
+
options.highlight = { lineRange: parseNumericRange(parsed.highlight) };
|
|
24
|
+
}
|
|
25
|
+
if (parsed.showLineNumbers !== void 0) {
|
|
26
|
+
if (typeof parsed.showLineNumbers === "string") {
|
|
27
|
+
options.showLineNumbers = {
|
|
28
|
+
lineRange: parseNumericRange(parsed.showLineNumbers)
|
|
29
|
+
};
|
|
30
|
+
} else if (parsed.showLineNumbers) {
|
|
31
|
+
options.showLineNumbers = { lineRange: [] };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (parsed.commandLine !== void 0) {
|
|
35
|
+
if (typeof parsed.commandLine === "string") {
|
|
36
|
+
options.commandLine = {
|
|
37
|
+
commandRange: parseNumericRange(parsed.commandLine)
|
|
38
|
+
};
|
|
39
|
+
} else if (parsed.commandLine) {
|
|
40
|
+
options.commandLine = { commandRange: [] };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (parsed.fileName !== void 0) {
|
|
44
|
+
options.fileName = parsed.fileName.trim();
|
|
45
|
+
}
|
|
46
|
+
return options;
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
extractCodeMeta
|
|
50
|
+
};
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import { CodeToHastOptions, BundledLanguage, BundledTheme } from 'shiki';
|
|
2
|
+
import { TransformerNotationHighlightOptions } from '@shikijs/transformers';
|
|
3
|
+
import { Plugin } from 'unified';
|
|
4
|
+
import { Node } from 'hast';
|
|
5
|
+
|
|
5
6
|
type ShikiHastOptions = Partial<CodeToHastOptions<BundledLanguage, BundledTheme>>;
|
|
6
7
|
type SyntaxDataAttribute = "source-code" | "language" | "line-count";
|
|
7
8
|
/**
|
|
8
9
|
* Options for {@linkcode syntaxHighlightPlugin}.
|
|
9
10
|
*/
|
|
10
|
-
|
|
11
|
+
interface SyntaxHighlightPluginOptions {
|
|
11
12
|
/**
|
|
12
13
|
* Include these data attributes on the `<pre>` element.
|
|
13
14
|
* These might be useful to have when building custom code components.
|
|
@@ -50,8 +51,8 @@ export interface SyntaxHighlightPluginOptions {
|
|
|
50
51
|
/**
|
|
51
52
|
* A plugin that highlights code blocks using Shiki.
|
|
52
53
|
*/
|
|
53
|
-
|
|
54
|
+
declare const syntaxHighlightPlugin: Plugin<[
|
|
54
55
|
SyntaxHighlightPluginOptions?
|
|
55
|
-
],
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
], Node, Node>;
|
|
57
|
+
|
|
58
|
+
export { type SyntaxHighlightPluginOptions, syntaxHighlightPlugin };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { toString as hastToString } from "hast-util-to-string";
|
|
2
|
+
import {
|
|
3
|
+
codeToHast,
|
|
4
|
+
ShikiError
|
|
5
|
+
} from "shiki";
|
|
6
|
+
import { visit } from "unist-util-visit";
|
|
7
|
+
import {
|
|
8
|
+
transformerNotationHighlight
|
|
9
|
+
} from "@shikijs/transformers";
|
|
10
|
+
import { numericRangeContains } from "@temelj/iterator";
|
|
11
|
+
import { extractCodeMeta } from "./code-meta";
|
|
12
|
+
const syntaxHighlightPlugin = (options = {}) => {
|
|
13
|
+
return async (tree) => {
|
|
14
|
+
const promises = [];
|
|
15
|
+
async function visitor(node, index, parent) {
|
|
16
|
+
if (!parent || index === null || node.tagName !== "pre") {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const codeNode = node.children[0];
|
|
20
|
+
if (!codeNode || codeNode.type !== "element" || codeNode.tagName !== "code" || !codeNode.properties) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const lang = getNodeLanguage(codeNode);
|
|
24
|
+
if (typeof lang !== "string") {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const meta = extractCodeMeta(codeNode);
|
|
28
|
+
const sourceCode = hastToString(codeNode).trim();
|
|
29
|
+
const hastOptions = {
|
|
30
|
+
tokenizeTimeLimit: 1e4,
|
|
31
|
+
lang,
|
|
32
|
+
themes: {
|
|
33
|
+
light: "github-light-default",
|
|
34
|
+
dark: "github-dark-default"
|
|
35
|
+
},
|
|
36
|
+
...options.shikiHastOptions ?? {}
|
|
37
|
+
};
|
|
38
|
+
if (hastOptions.transformers === void 0) {
|
|
39
|
+
hastOptions.transformers = [];
|
|
40
|
+
}
|
|
41
|
+
if (options.highlight) {
|
|
42
|
+
hastOptions.transformers.push(
|
|
43
|
+
transformerNotationHighlight({
|
|
44
|
+
...options.highlight.transformer ?? {},
|
|
45
|
+
matchAlgorithm: "v3"
|
|
46
|
+
})
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
let lineCount = 0;
|
|
50
|
+
hastOptions.transformers.push({
|
|
51
|
+
code(node2) {
|
|
52
|
+
let lineIndex = 0;
|
|
53
|
+
for (const line of node2.children.filter(
|
|
54
|
+
(node3) => node3.type === "element"
|
|
55
|
+
)) {
|
|
56
|
+
line.properties["data-line"] = lineIndex + 1;
|
|
57
|
+
if (options.highlight) {
|
|
58
|
+
if (meta.highlight && numericRangeContains(meta.highlight.lineRange, lineIndex)) {
|
|
59
|
+
this.addClassToHast(
|
|
60
|
+
line,
|
|
61
|
+
options.highlight.transformer?.classActiveLine ?? "highlighted"
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (options.lineNumbers && meta.showLineNumbers && (meta.showLineNumbers.lineRange.length === 0 || numericRangeContains(meta.showLineNumbers.lineRange, lineIndex))) {
|
|
66
|
+
this.addClassToHast(
|
|
67
|
+
line,
|
|
68
|
+
options.lineNumbers.className ?? "line-number"
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
if (options.commandLine && meta.commandLine && (meta.commandLine.commandRange.length === 0 || numericRangeContains(meta.commandLine.commandRange, lineIndex))) {
|
|
72
|
+
this.addClassToHast(
|
|
73
|
+
line,
|
|
74
|
+
options.commandLine.className ?? "line-command"
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
lineIndex++;
|
|
78
|
+
}
|
|
79
|
+
lineCount = lineIndex;
|
|
80
|
+
if (meta.showLineNumbers) {
|
|
81
|
+
if (typeof node2.properties.style !== "string") {
|
|
82
|
+
node2.properties.style = "";
|
|
83
|
+
}
|
|
84
|
+
node2.properties.style += `--${options.lineNumbers?.widthVariableName ?? "line-number-width"}:${1 + Math.floor(Math.log10(this.lines.length))}ch;`;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
try {
|
|
89
|
+
const hast = await codeToHast(sourceCode, hastOptions);
|
|
90
|
+
const hastPre = hast.children[0];
|
|
91
|
+
const properties = {
|
|
92
|
+
...hastPre.properties,
|
|
93
|
+
dataFileName: meta.fileName
|
|
94
|
+
};
|
|
95
|
+
if (options.includeDataAttributes) {
|
|
96
|
+
if (options.includeDataAttributes.includes("language")) {
|
|
97
|
+
properties.dataLanguage = lang;
|
|
98
|
+
}
|
|
99
|
+
if (options.includeDataAttributes.includes("source-code")) {
|
|
100
|
+
properties.dataSourceCode = sourceCode;
|
|
101
|
+
}
|
|
102
|
+
if (options.includeDataAttributes.includes("line-count")) {
|
|
103
|
+
properties.dataLineCount = lineCount;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
parent.children.splice(index, 1, {
|
|
107
|
+
...hastPre,
|
|
108
|
+
properties
|
|
109
|
+
});
|
|
110
|
+
} catch (error) {
|
|
111
|
+
if (error instanceof ShikiError) {
|
|
112
|
+
if (error.message.includes(
|
|
113
|
+
"Language `math` is not included in this bundle"
|
|
114
|
+
)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
visit(
|
|
122
|
+
tree,
|
|
123
|
+
"element",
|
|
124
|
+
(node, index, parent) => {
|
|
125
|
+
promises.push(visitor(node, index, parent));
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
await Promise.all(promises);
|
|
129
|
+
return tree;
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
function getNodeLanguage(node) {
|
|
133
|
+
if (!Array.isArray(node.properties.className)) {
|
|
134
|
+
return void 0;
|
|
135
|
+
}
|
|
136
|
+
const prefix = "language-";
|
|
137
|
+
const language = node.properties.className.find(
|
|
138
|
+
(name) => typeof name === "string" && name.startsWith(prefix)
|
|
139
|
+
);
|
|
140
|
+
if (typeof language === "string") {
|
|
141
|
+
return language.slice(prefix.length);
|
|
142
|
+
}
|
|
143
|
+
return language;
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
syntaxHighlightPlugin
|
|
147
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Plugin } from 'unified';
|
|
2
|
+
import { Element, Node } from 'hast';
|
|
3
|
+
|
|
4
|
+
type MdxTreeProcessor = (node: Element, index: number, parent: Element) => void | Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* Options for {@linkcode treeProcessorPlugin}.
|
|
7
|
+
*/
|
|
8
|
+
type TreeProcessorPluginOptions = {
|
|
9
|
+
/** The processor. */
|
|
10
|
+
process: MdxTreeProcessor;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* A plugin that allows to process MDX tree nodes.
|
|
14
|
+
* It can be async or sync.
|
|
15
|
+
*/
|
|
16
|
+
declare const treeProcessorPlugin: Plugin<[
|
|
17
|
+
TreeProcessorPluginOptions?
|
|
18
|
+
], Node, Node>;
|
|
19
|
+
|
|
20
|
+
export { type MdxTreeProcessor, treeProcessorPlugin };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { visit } from "unist-util-visit";
|
|
2
|
+
const treeProcessorPlugin = ({ process } = { process: () => {
|
|
3
|
+
} }) => {
|
|
4
|
+
return async (tree) => {
|
|
5
|
+
const promises = [];
|
|
6
|
+
visit(
|
|
7
|
+
tree,
|
|
8
|
+
"element",
|
|
9
|
+
function visitor(node, index, parent) {
|
|
10
|
+
const p = process(node, index, parent);
|
|
11
|
+
if (p instanceof Promise || Object.prototype.toString.call(p) === "[object Promise]") {
|
|
12
|
+
promises.push(p);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
await Promise.allSettled(promises);
|
|
17
|
+
return tree;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export {
|
|
21
|
+
treeProcessorPlugin
|
|
22
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Element as HastElement, Node as HastNode } from 'hast';
|
package/dist/types.js
ADDED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,48 +1,51 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@temelj/mdx",
|
|
3
|
-
"
|
|
4
|
-
"description": "Utilities for working with MDX.",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"mdx"
|
|
7
|
-
],
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/tinrab/temelj.git"
|
|
11
|
-
},
|
|
3
|
+
"description": "MDX processing utilities.",
|
|
12
4
|
"license": "MIT",
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
"types": "./types/mod.d.ts",
|
|
5
|
+
"version": "0.8.1",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/mod.js",
|
|
8
|
+
"types": "./dist/mod.d.ts",
|
|
18
9
|
"exports": {
|
|
19
10
|
".": {
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
"default": "./esm/mod.js"
|
|
23
|
-
}
|
|
11
|
+
"types": "./dist/mod.d.ts",
|
|
12
|
+
"import": "./dist/mod.js"
|
|
24
13
|
}
|
|
25
14
|
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
26
18
|
"dependencies": {
|
|
27
|
-
"@
|
|
28
|
-
"@
|
|
29
|
-
"@shikijs/transformers": "^3.8.0",
|
|
19
|
+
"@mdx-js/mdx": "^3.1.1",
|
|
20
|
+
"@shikijs/transformers": "^3.15.0",
|
|
30
21
|
"@types/hast": "^3.0.4",
|
|
31
22
|
"github-slugger": "^2.0.0",
|
|
32
23
|
"hast": "^1.0.0",
|
|
33
24
|
"hast-util-to-string": "^3.0.1",
|
|
34
25
|
"remark-frontmatter": "^5.0.0",
|
|
35
26
|
"remark-gfm": "^4.0.1",
|
|
36
|
-
"
|
|
27
|
+
"remark-parse": "^11.0.0",
|
|
28
|
+
"shiki": "^3.15.0",
|
|
37
29
|
"unified": "^11.0.5",
|
|
38
30
|
"unist-util-remove": "^4.0.0",
|
|
39
31
|
"unist-util-visit": "^5.0.0",
|
|
40
32
|
"vfile": "^6.0.3",
|
|
41
33
|
"vfile-matter": "^5.0.1",
|
|
42
|
-
"zod": "^4.
|
|
34
|
+
"zod": "^4.1.12",
|
|
35
|
+
"@temelj/iterator": "0.8.1"
|
|
43
36
|
},
|
|
44
37
|
"devDependencies": {
|
|
45
|
-
"@types/
|
|
38
|
+
"@types/mdast": "^4.0.4",
|
|
39
|
+
"@types/node": "24.10.1",
|
|
40
|
+
"tsup": "^8.5.1",
|
|
41
|
+
"shx": "^0.4.0",
|
|
42
|
+
"typescript": "^5.9.3",
|
|
43
|
+
"vitest": "^4.0.8"
|
|
46
44
|
},
|
|
47
|
-
"
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsup",
|
|
47
|
+
"test": "vitest run",
|
|
48
|
+
"typecheck": "tsc --noEmit",
|
|
49
|
+
"clean": "shx rm -rf dist"
|
|
50
|
+
}
|
|
48
51
|
}
|
package/esm/compiler.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { compile as compileMdxJs, } from "@mdx-js/mdx";
|
|
2
|
-
import remarkFrontmatterPlugin from "remark-frontmatter";
|
|
3
|
-
import remarkGfmPlugin from "remark-gfm";
|
|
4
|
-
import { VFile } from "vfile";
|
|
5
|
-
import { matter } from "vfile-matter";
|
|
6
|
-
export { remarkFrontmatterPlugin, remarkGfmPlugin };
|
|
7
|
-
/**
|
|
8
|
-
* A reusable compiler for compiling MDX.
|
|
9
|
-
*/
|
|
10
|
-
export class MdxCompiler {
|
|
11
|
-
constructor(mdxOptions = {}) {
|
|
12
|
-
Object.defineProperty(this, "mdxOptions", {
|
|
13
|
-
enumerable: true,
|
|
14
|
-
configurable: true,
|
|
15
|
-
writable: true,
|
|
16
|
-
value: void 0
|
|
17
|
-
});
|
|
18
|
-
Object.defineProperty(this, "remarkPlugins", {
|
|
19
|
-
enumerable: true,
|
|
20
|
-
configurable: true,
|
|
21
|
-
writable: true,
|
|
22
|
-
value: void 0
|
|
23
|
-
});
|
|
24
|
-
Object.defineProperty(this, "rehypePlugins", {
|
|
25
|
-
enumerable: true,
|
|
26
|
-
configurable: true,
|
|
27
|
-
writable: true,
|
|
28
|
-
value: void 0
|
|
29
|
-
});
|
|
30
|
-
this.mdxOptions = mdxOptions;
|
|
31
|
-
this.remarkPlugins = [remarkFrontmatterPlugin, remarkGfmPlugin];
|
|
32
|
-
this.rehypePlugins = [];
|
|
33
|
-
}
|
|
34
|
-
withRemarkPlugin(plugin, options) {
|
|
35
|
-
if (options === undefined) {
|
|
36
|
-
this.remarkPlugins.push(plugin);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
this.remarkPlugins.push([plugin, options]);
|
|
40
|
-
}
|
|
41
|
-
return this;
|
|
42
|
-
}
|
|
43
|
-
withRehypePlugin(plugin, options) {
|
|
44
|
-
if (options === undefined) {
|
|
45
|
-
this.rehypePlugins.push(plugin);
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
this.rehypePlugins.push([plugin, options]);
|
|
49
|
-
}
|
|
50
|
-
return this;
|
|
51
|
-
}
|
|
52
|
-
async compile(source, { frontmatterOnly = false, mdxOptions } = {}, frontmatterSchema) {
|
|
53
|
-
const vfile = new VFile({
|
|
54
|
-
value: source,
|
|
55
|
-
// Needed so vfile doesn't need to access fs.
|
|
56
|
-
cwd: "/",
|
|
57
|
-
path: "/",
|
|
58
|
-
message: {},
|
|
59
|
-
messages: {},
|
|
60
|
-
});
|
|
61
|
-
matter(vfile, { strip: true });
|
|
62
|
-
const remarkPlugins = [
|
|
63
|
-
...this.remarkPlugins,
|
|
64
|
-
...(this.mdxOptions?.remarkPlugins ?? []),
|
|
65
|
-
...(mdxOptions?.remarkPlugins ?? []),
|
|
66
|
-
];
|
|
67
|
-
const rehypePlugins = [
|
|
68
|
-
...this.rehypePlugins,
|
|
69
|
-
...(this.mdxOptions?.rehypePlugins ?? []),
|
|
70
|
-
...(mdxOptions?.rehypePlugins ?? []),
|
|
71
|
-
];
|
|
72
|
-
let compiled;
|
|
73
|
-
if (!frontmatterOnly) {
|
|
74
|
-
const compiledFile = await compileMdxJs(vfile, {
|
|
75
|
-
outputFormat: "function-body",
|
|
76
|
-
...(this.mdxOptions ?? {}),
|
|
77
|
-
...(mdxOptions ?? {}),
|
|
78
|
-
remarkPlugins,
|
|
79
|
-
rehypePlugins,
|
|
80
|
-
});
|
|
81
|
-
compiled = compiledFile.value.toString();
|
|
82
|
-
}
|
|
83
|
-
const frontmatter = frontmatterSchema === undefined
|
|
84
|
-
? (vfile.data.matter ?? {})
|
|
85
|
-
: frontmatterSchema.parse(vfile.data.matter ?? {});
|
|
86
|
-
return {
|
|
87
|
-
compiled,
|
|
88
|
-
frontmatter: frontmatter,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
}
|
package/esm/mod.js
DELETED
package/esm/package.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import GithubSlugger from "github-slugger";
|
|
2
|
-
import { toString as hastToString } from "hast-util-to-string";
|
|
3
|
-
import { visit } from "unist-util-visit";
|
|
4
|
-
/**
|
|
5
|
-
* A rehype plugin that adds IDs to heading tags.
|
|
6
|
-
*/
|
|
7
|
-
export const headingIdPlugin = ({ prefix } = {}) => {
|
|
8
|
-
const slugger = new GithubSlugger();
|
|
9
|
-
return (tree) => {
|
|
10
|
-
slugger.reset();
|
|
11
|
-
visit(tree, "element", function visitor(node, index, parent) {
|
|
12
|
-
if (!parent || index === null || !node.tagName.startsWith("h"))
|
|
13
|
-
return;
|
|
14
|
-
const id = (prefix ?? "") + slugger.slug(hastToString(node));
|
|
15
|
-
node.properties.id = id;
|
|
16
|
-
});
|
|
17
|
-
return tree;
|
|
18
|
-
};
|
|
19
|
-
};
|
package/esm/plugins/mod.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { parseNumericRange } from "@temelj/iterator";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
export function extractCodeMeta(node) {
|
|
4
|
-
const meta = node?.data?.meta ?? node?.properties?.metastring ?? "";
|
|
5
|
-
return parseMetaString(meta);
|
|
6
|
-
}
|
|
7
|
-
const metaSchema = z.object({
|
|
8
|
-
highlight: z.optional(z.string()),
|
|
9
|
-
showLineNumbers: z.optional(z.union([z.boolean(), z.string()])),
|
|
10
|
-
commandLine: z.optional(z.union([z.boolean(), z.string()])),
|
|
11
|
-
fileName: z.optional(z.string()),
|
|
12
|
-
});
|
|
13
|
-
function parseMetaString(meta) {
|
|
14
|
-
let raw;
|
|
15
|
-
try {
|
|
16
|
-
raw = JSON.parse(meta.trim());
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
return {};
|
|
20
|
-
}
|
|
21
|
-
const parsed = metaSchema.parse(raw);
|
|
22
|
-
const options = {};
|
|
23
|
-
if (parsed.highlight !== undefined) {
|
|
24
|
-
options.highlight = { lineRange: parseNumericRange(parsed.highlight) };
|
|
25
|
-
}
|
|
26
|
-
if (parsed.showLineNumbers !== undefined) {
|
|
27
|
-
if (typeof parsed.showLineNumbers === "string") {
|
|
28
|
-
options.showLineNumbers = {
|
|
29
|
-
lineRange: parseNumericRange(parsed.showLineNumbers),
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
else if (parsed.showLineNumbers) {
|
|
33
|
-
options.showLineNumbers = { lineRange: [] };
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
if (parsed.commandLine !== undefined) {
|
|
37
|
-
if (typeof parsed.commandLine === "string") {
|
|
38
|
-
options.commandLine = {
|
|
39
|
-
commandRange: parseNumericRange(parsed.commandLine),
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
else if (parsed.commandLine) {
|
|
43
|
-
options.commandLine = { commandRange: [] };
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
if (parsed.fileName !== undefined) {
|
|
47
|
-
options.fileName = parsed.fileName.trim();
|
|
48
|
-
}
|
|
49
|
-
return options;
|
|
50
|
-
}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { toString as hastToString } from "hast-util-to-string";
|
|
2
|
-
import { codeToHast, ShikiError, } from "shiki";
|
|
3
|
-
import { visit } from "unist-util-visit";
|
|
4
|
-
import { transformerNotationHighlight, } from "@shikijs/transformers";
|
|
5
|
-
import { numericRangeContains } from "@temelj/iterator";
|
|
6
|
-
import { extractCodeMeta } from "./code-meta.js";
|
|
7
|
-
/**
|
|
8
|
-
* A plugin that highlights code blocks using Shiki.
|
|
9
|
-
*/
|
|
10
|
-
export const syntaxHighlightPlugin = (options = {}) => {
|
|
11
|
-
return async (tree) => {
|
|
12
|
-
const promises = [];
|
|
13
|
-
async function visitor(node, index, parent) {
|
|
14
|
-
if (!parent || index === null || node.tagName !== "pre") {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
const codeNode = node.children[0];
|
|
18
|
-
if (!codeNode ||
|
|
19
|
-
codeNode.type !== "element" ||
|
|
20
|
-
codeNode.tagName !== "code" ||
|
|
21
|
-
!codeNode.properties) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
const lang = getNodeLanguage(codeNode);
|
|
25
|
-
if (typeof lang !== "string") {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const meta = extractCodeMeta(codeNode);
|
|
29
|
-
const sourceCode = hastToString(codeNode).trim();
|
|
30
|
-
const hastOptions = {
|
|
31
|
-
tokenizeTimeLimit: 10_000,
|
|
32
|
-
lang,
|
|
33
|
-
themes: {
|
|
34
|
-
light: "github-light-default",
|
|
35
|
-
dark: "github-dark-default",
|
|
36
|
-
},
|
|
37
|
-
...(options.shikiHastOptions ?? {}),
|
|
38
|
-
};
|
|
39
|
-
if (hastOptions.transformers === undefined) {
|
|
40
|
-
hastOptions.transformers = [];
|
|
41
|
-
}
|
|
42
|
-
if (options.highlight) {
|
|
43
|
-
hastOptions.transformers.push(transformerNotationHighlight({
|
|
44
|
-
...(options.highlight.transformer ?? {}),
|
|
45
|
-
matchAlgorithm: "v3",
|
|
46
|
-
}));
|
|
47
|
-
}
|
|
48
|
-
let lineCount = 0;
|
|
49
|
-
hastOptions.transformers.push({
|
|
50
|
-
code(node) {
|
|
51
|
-
let lineIndex = 0;
|
|
52
|
-
for (const line of node.children.filter((node) => node.type === "element")) {
|
|
53
|
-
line.properties["data-line"] = lineIndex + 1;
|
|
54
|
-
if (options.highlight) {
|
|
55
|
-
if (meta.highlight &&
|
|
56
|
-
numericRangeContains(meta.highlight.lineRange, lineIndex)) {
|
|
57
|
-
this.addClassToHast(line, options.highlight.transformer?.classActiveLine ??
|
|
58
|
-
"highlighted");
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (options.lineNumbers &&
|
|
62
|
-
meta.showLineNumbers &&
|
|
63
|
-
(meta.showLineNumbers.lineRange.length === 0 ||
|
|
64
|
-
numericRangeContains(meta.showLineNumbers.lineRange, lineIndex))) {
|
|
65
|
-
this.addClassToHast(line, options.lineNumbers.className ?? "line-number");
|
|
66
|
-
}
|
|
67
|
-
if (options.commandLine &&
|
|
68
|
-
meta.commandLine &&
|
|
69
|
-
(meta.commandLine.commandRange.length === 0 ||
|
|
70
|
-
numericRangeContains(meta.commandLine.commandRange, lineIndex))) {
|
|
71
|
-
this.addClassToHast(line, options.commandLine.className ?? "line-command");
|
|
72
|
-
}
|
|
73
|
-
lineIndex++;
|
|
74
|
-
}
|
|
75
|
-
lineCount = lineIndex;
|
|
76
|
-
if (meta.showLineNumbers) {
|
|
77
|
-
if (typeof node.properties.style !== "string") {
|
|
78
|
-
node.properties.style = "";
|
|
79
|
-
}
|
|
80
|
-
node.properties.style += `--${options.lineNumbers?.widthVariableName ?? "line-number-width"}:${1 + Math.floor(Math.log10(this.lines.length))}ch;`;
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
try {
|
|
85
|
-
const hast = await codeToHast(sourceCode, hastOptions);
|
|
86
|
-
// Insert highlighted code into parent
|
|
87
|
-
const hastPre = hast.children[0];
|
|
88
|
-
const properties = {
|
|
89
|
-
...hastPre.properties,
|
|
90
|
-
dataFileName: meta.fileName,
|
|
91
|
-
};
|
|
92
|
-
if (options.includeDataAttributes) {
|
|
93
|
-
if (options.includeDataAttributes.includes("language")) {
|
|
94
|
-
properties.dataLanguage = lang;
|
|
95
|
-
}
|
|
96
|
-
if (options.includeDataAttributes.includes("source-code")) {
|
|
97
|
-
properties.dataSourceCode = sourceCode;
|
|
98
|
-
}
|
|
99
|
-
if (options.includeDataAttributes.includes("line-count")) {
|
|
100
|
-
properties.dataLineCount = lineCount;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
parent.children.splice(index, 1, {
|
|
104
|
-
...hastPre,
|
|
105
|
-
properties,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
catch (error) {
|
|
109
|
-
if (error instanceof ShikiError) {
|
|
110
|
-
if (error.message.includes("Language `math` is not included in this bundle")) {
|
|
111
|
-
// Skip if the block is math block.
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
throw error;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
visit(tree, "element", (node, index, parent) => {
|
|
119
|
-
promises.push(visitor(node, index, parent));
|
|
120
|
-
});
|
|
121
|
-
await Promise.all(promises);
|
|
122
|
-
return tree;
|
|
123
|
-
};
|
|
124
|
-
};
|
|
125
|
-
function getNodeLanguage(node) {
|
|
126
|
-
if (!Array.isArray(node.properties.className)) {
|
|
127
|
-
return undefined;
|
|
128
|
-
}
|
|
129
|
-
const prefix = "language-";
|
|
130
|
-
const language = node.properties.className.find((name) => typeof name === "string" && name.startsWith(prefix));
|
|
131
|
-
if (typeof language === "string") {
|
|
132
|
-
return language.slice(prefix.length);
|
|
133
|
-
}
|
|
134
|
-
return language;
|
|
135
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { visit } from "unist-util-visit";
|
|
2
|
-
/**
|
|
3
|
-
* A plugin that allows to process MDX tree nodes.
|
|
4
|
-
* It can be async or sync.
|
|
5
|
-
*/
|
|
6
|
-
export const treeProcessorPlugin = ({ process } = { process: () => { } }) => {
|
|
7
|
-
return async (tree) => {
|
|
8
|
-
const promises = [];
|
|
9
|
-
visit(tree, "element", function visitor(node, index, parent) {
|
|
10
|
-
const p = process(node, index, parent);
|
|
11
|
-
if (p instanceof Promise ||
|
|
12
|
-
Object.prototype.toString.call(p) === "[object Promise]") {
|
|
13
|
-
promises.push(p);
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
await Promise.allSettled(promises);
|
|
17
|
-
return tree;
|
|
18
|
-
};
|
|
19
|
-
};
|
package/esm/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/types/compiler.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { type CompileOptions as MdxJsCompileOptions } from "@mdx-js/mdx";
|
|
2
|
-
import remarkFrontmatterPlugin from "remark-frontmatter";
|
|
3
|
-
import remarkGfmPlugin from "remark-gfm";
|
|
4
|
-
import type { Plugin } from "unified";
|
|
5
|
-
import type { z } from "zod";
|
|
6
|
-
import type { HastNode } from "./types.js";
|
|
7
|
-
export { remarkFrontmatterPlugin, remarkGfmPlugin };
|
|
8
|
-
/**
|
|
9
|
-
* Represents the source content for an MDX document.
|
|
10
|
-
*/
|
|
11
|
-
export type MdxSource = string | Uint8Array;
|
|
12
|
-
/**
|
|
13
|
-
* Options for compiling an MDX document.
|
|
14
|
-
*/
|
|
15
|
-
export interface MdxCompileOptions {
|
|
16
|
-
frontmatterOnly?: boolean | undefined;
|
|
17
|
-
mdxOptions?: MdxJsCompileOptions;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* The result of compiling an MDX document.
|
|
21
|
-
* Compiled content is optional, because sometimes we only need the frontmatter.
|
|
22
|
-
*/
|
|
23
|
-
export interface MdxArtifact<TFrontmatter = Record<string, unknown>> {
|
|
24
|
-
compiled?: string | undefined;
|
|
25
|
-
frontmatter: TFrontmatter;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* A reusable compiler for compiling MDX.
|
|
29
|
-
*/
|
|
30
|
-
export declare class MdxCompiler {
|
|
31
|
-
private readonly mdxOptions;
|
|
32
|
-
private readonly remarkPlugins;
|
|
33
|
-
private readonly rehypePlugins;
|
|
34
|
-
constructor(mdxOptions?: MdxJsCompileOptions);
|
|
35
|
-
withRemarkPlugin<TOptions>(plugin: Plugin<[TOptions?], HastNode, HastNode>, options?: TOptions): MdxCompiler;
|
|
36
|
-
withRehypePlugin<TOptions>(plugin: Plugin<[TOptions?], HastNode, HastNode>, options?: TOptions): MdxCompiler;
|
|
37
|
-
compile<TFrontmatterSchema extends z.ZodSchema>(source: MdxSource, { frontmatterOnly, mdxOptions }?: MdxCompileOptions, frontmatterSchema?: TFrontmatterSchema): Promise<MdxArtifact<z.output<TFrontmatterSchema>>>;
|
|
38
|
-
}
|
|
39
|
-
//# sourceMappingURL=compiler.d.ts.map
|
package/types/compiler.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,IAAI,mBAAmB,EAC3C,MAAM,aAAa,CAAC;AACrB,OAAO,uBAAuB,MAAM,oBAAoB,CAAC;AACzD,OAAO,eAAe,MAAM,YAAY,CAAC;AAGzC,OAAO,KAAK,EAA4B,MAAM,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EAAE,uBAAuB,EAAE,eAAe,EAAE,CAAC;AAEpD;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,UAAU,CAAC,EAAE,mBAAmB,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW,CAAC,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACjE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,WAAW,EAAE,YAAY,CAAC;CAC3B;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsB;IACjD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;gBAE3B,UAAU,GAAE,mBAAwB;IAMhD,gBAAgB,CAAC,QAAQ,EAC9B,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAC/C,OAAO,CAAC,EAAE,QAAQ,GACjB,WAAW;IASP,gBAAgB,CAAC,QAAQ,EAC9B,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAC/C,OAAO,CAAC,EAAE,QAAQ,GACjB,WAAW;IASD,OAAO,CAAC,kBAAkB,SAAS,CAAC,CAAC,SAAS,EACzD,MAAM,EAAE,SAAS,EACjB,EAAE,eAAuB,EAAE,UAAU,EAAE,GAAE,iBAAsB,EAC/D,iBAAiB,CAAC,EAAE,kBAAkB,GACrC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;CA2CtD"}
|
package/types/mod.d.ts
DELETED
package/types/mod.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC"}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { Plugin } from "unified";
|
|
2
|
-
import type { HastNode } from "../../types.js";
|
|
3
|
-
/**
|
|
4
|
-
* Options for {@linkcode headingIdPlugin}.
|
|
5
|
-
*/
|
|
6
|
-
export interface HeadingIdPluginOptions {
|
|
7
|
-
/** Prefix for title slugs. */
|
|
8
|
-
prefix?: string;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* A rehype plugin that adds IDs to heading tags.
|
|
12
|
-
*/
|
|
13
|
-
export declare const headingIdPlugin: Plugin<[
|
|
14
|
-
HeadingIdPluginOptions?
|
|
15
|
-
], HastNode, HastNode>;
|
|
16
|
-
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/heading-id/plugin.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAClC;IAAC,sBAAsB,CAAC;CAAC,EACzB,QAAQ,EACR,QAAQ,CAoBT,CAAC"}
|
package/types/plugins/mod.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/plugins/mod.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,6BAA6B,CAAC"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import type { Plugin } from "unified";
|
|
2
|
-
import type { HastNode } from "../types.js";
|
|
3
|
-
/**
|
|
4
|
-
* A remark plugin which removes all import and export statements.
|
|
5
|
-
*/
|
|
6
|
-
export declare const removeImportsExportsPlugin: Plugin<[
|
|
7
|
-
unknown
|
|
8
|
-
], HastNode, HastNode>;
|
|
9
|
-
//# sourceMappingURL=remove-imports-exports.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"remove-imports-exports.d.ts","sourceRoot":"","sources":["../../src/plugins/remove-imports-exports.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;GAEG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAC7C;IAAC,OAAO;CAAC,EACT,QAAQ,EACR,QAAQ,CAMT,CAAC"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { type NumericRange } from "@temelj/iterator";
|
|
2
|
-
import type { HastElement } from "../../types.js";
|
|
3
|
-
export interface MdxCodeMeta {
|
|
4
|
-
highlight?: MdxCodeMetaHighlightLine;
|
|
5
|
-
showLineNumbers?: MdxCodeMetaLineNumbers;
|
|
6
|
-
commandLine?: MdxCodeMetaCommandLine;
|
|
7
|
-
fileName?: string;
|
|
8
|
-
}
|
|
9
|
-
export type MdxCodeMetaHighlightLine = {
|
|
10
|
-
lineRange: NumericRange;
|
|
11
|
-
};
|
|
12
|
-
export type MdxCodeMetaLineNumbers = {
|
|
13
|
-
lineRange: NumericRange;
|
|
14
|
-
};
|
|
15
|
-
export type MdxCodeMetaCommandLine = {
|
|
16
|
-
commandRange: NumericRange;
|
|
17
|
-
};
|
|
18
|
-
export declare function extractCodeMeta(node: HastElement): MdxCodeMeta;
|
|
19
|
-
//# sourceMappingURL=code-meta.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"code-meta.d.ts","sourceRoot":"","sources":["../../../src/plugins/syntax-highlight/code-meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAqB,MAAM,kBAAkB,CAAC;AAGxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,wBAAwB,CAAC;IACrC,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,YAAY,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,SAAS,EAAE,YAAY,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,YAAY,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEF,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CAG9D"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/syntax-highlight/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,YAAY,EAEjB,KAAK,iBAAiB,EAEvB,MAAM,OAAO,CAAC;AAEf,OAAO,EAEL,KAAK,mCAAmC,EACzC,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGtC,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAI5D,KAAK,gBAAgB,GAAG,OAAO,CAC7B,iBAAiB,CAAC,eAAe,EAAE,YAAY,CAAC,CACjD,CAAC;AAEF,KAAK,mBAAmB,GAAG,aAAa,GAAG,UAAU,GAAG,YAAY,CAAC;AAErE;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,qBAAqB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAE9C;;OAEG;IACH,SAAS,CAAC,EAAE;QACV,WAAW,CAAC,EAAE,mCAAmC,CAAC;KACnD,CAAC;IAEF;;OAEG;IACH,WAAW,CAAC,EAAE;QACZ;;;WAGG;QACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B;;WAEG;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF;;OAEG;IACH,WAAW,CAAC,EAAE;QACZ;;WAEG;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAEF;;OAEG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,EAAE,MAAM,CACxC;IAAC,4BAA4B,CAAC;CAAC,EAC/B,QAAQ,EACR,QAAQ,CA4KT,CAAC"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { Plugin } from "unified";
|
|
2
|
-
import type { HastElement, HastNode } from "../../types.js";
|
|
3
|
-
export type MdxTreeProcessor = (node: HastElement, index: number, parent: HastElement) => void | Promise<void>;
|
|
4
|
-
/**
|
|
5
|
-
* Options for {@linkcode treeProcessorPlugin}.
|
|
6
|
-
*/
|
|
7
|
-
type TreeProcessorPluginOptions = {
|
|
8
|
-
/** The processor. */
|
|
9
|
-
process: MdxTreeProcessor;
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* A plugin that allows to process MDX tree nodes.
|
|
13
|
-
* It can be async or sync.
|
|
14
|
-
*/
|
|
15
|
-
export declare const treeProcessorPlugin: Plugin<[
|
|
16
|
-
TreeProcessorPluginOptions?
|
|
17
|
-
], HastNode, HastNode>;
|
|
18
|
-
export {};
|
|
19
|
-
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/tree-processor/plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE5D,MAAM,MAAM,gBAAgB,GAAG,CAC7B,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B;;GAEG;AACH,KAAK,0BAA0B,GAAG;IAChC,qBAAqB;IACrB,OAAO,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CACtC;IAAC,0BAA0B,CAAC;CAAC,EAC7B,QAAQ,EACR,QAAQ,CA2BT,CAAC"}
|
package/types/types.d.ts
DELETED
package/types/types.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,YAAY,EAAE,OAAO,IAAI,WAAW,EAAE,IAAI,IAAI,QAAQ,EAAE,CAAC"}
|