@temelj/mdx 0.1.6 → 0.1.8
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 +77 -2
- package/esm/compiler.js +11 -4
- package/esm/plugins/syntax-highlight/code-meta.js +3 -3
- package/esm/plugins/syntax-highlight/plugin.js +6 -2
- package/esm/plugins/tree-processor/plugin.js +4 -0
- package/package.json +1 -1
- package/types/compiler.d.ts +17 -2
- package/types/compiler.d.ts.map +1 -1
- package/types/plugins/syntax-highlight/plugin.d.ts +30 -2
- package/types/plugins/syntax-highlight/plugin.d.ts.map +1 -1
- package/types/plugins/tree-processor/plugin.d.ts +4 -0
- package/types/plugins/tree-processor/plugin.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<br/>
|
|
27
27
|
<br/>
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
## Installation
|
|
30
30
|
|
|
31
31
|
```sh
|
|
32
32
|
# npm
|
|
@@ -35,7 +35,82 @@ $ npm install @temelj/mdx
|
|
|
35
35
|
$ deno add jsr:@temelj/mdx # or jsr add @temelj/mdx
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
## Compile
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { assert, assertEquals } from "@std/assert";
|
|
42
|
+
import {
|
|
43
|
+
type HastElement,
|
|
44
|
+
headingIdPlugin,
|
|
45
|
+
MdxCompiler,
|
|
46
|
+
syntaxHighlightPlugin,
|
|
47
|
+
treeProcessorPlugin,
|
|
48
|
+
} from "@temelj/mdx";
|
|
49
|
+
import { z } from "zod";
|
|
50
|
+
|
|
51
|
+
const compiler = new MdxCompiler()
|
|
52
|
+
.withRehypePlugin(headingIdPlugin, {
|
|
53
|
+
prefix: "h-",
|
|
54
|
+
})
|
|
55
|
+
.withRehypePlugin(syntaxHighlightPlugin, {
|
|
56
|
+
highlight: {},
|
|
57
|
+
lineNumbers: {},
|
|
58
|
+
commandLine: {},
|
|
59
|
+
shikiHastOptions: {
|
|
60
|
+
// themes: {
|
|
61
|
+
// light: lightTheme,
|
|
62
|
+
// dark: darkTheme,
|
|
63
|
+
// },
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const source = `
|
|
68
|
+
---
|
|
69
|
+
title: Demo
|
|
70
|
+
---
|
|
71
|
+
# Hello
|
|
72
|
+
|
|
73
|
+
This will compile MDX to a render-able artifact.
|
|
74
|
+
With '@temelj/mdx-react' you can render it in an React app.
|
|
75
|
+
|
|
76
|
+
You can validate the frontmatter with a zod schema.
|
|
77
|
+
|
|
78
|
+
There are a few useful plugins:
|
|
79
|
+
- Use 'headingIdPlugin' to update heading tags (h1, h2, etc.) with IDs generated by slugging their text content.
|
|
80
|
+
This is useful for linking to headings in a page.
|
|
81
|
+
- Use 'syntaxHighlightPlugin' to highlight code blocks using [Shiki](https://github.com/shikijs/shiki).
|
|
82
|
+
You can highlight individual lines, show line numbers, or display a prompt.
|
|
83
|
+
- Use 'treeProcessorPlugin' to modify the HAST tree.
|
|
84
|
+
For example, change image URLs to point to a CDN.
|
|
85
|
+
|
|
86
|
+
\`\`\`bash {"commandLine": "0"}
|
|
87
|
+
whoamai
|
|
88
|
+
@temelj/mdx
|
|
89
|
+
\`\`\`
|
|
90
|
+
`.trim();
|
|
91
|
+
const artifact = await compiler.compile(source, {
|
|
92
|
+
frontmatterOnly: false,
|
|
93
|
+
frontmatterSchema: z.object({
|
|
94
|
+
title: z.string(),
|
|
95
|
+
}),
|
|
96
|
+
mdxOptions: {
|
|
97
|
+
rehypePlugins: [
|
|
98
|
+
[
|
|
99
|
+
treeProcessorPlugin,
|
|
100
|
+
{
|
|
101
|
+
process: (node: HastElement) => assert(typeof node.type === "string"),
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
assert(artifact.compiled !== undefined);
|
|
108
|
+
assertEquals(artifact.frontmatter, {
|
|
109
|
+
title: "Demo",
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## About
|
|
39
114
|
|
|
40
115
|
This package is part of [Temelj](https://github.com/flinect/temelj) - a big
|
|
41
116
|
standard library for TypeScript.
|
package/esm/compiler.js
CHANGED
|
@@ -4,6 +4,9 @@ import remarkGfmPlugin from "remark-gfm";
|
|
|
4
4
|
import { VFile } from "vfile";
|
|
5
5
|
import { matter } from "vfile-matter";
|
|
6
6
|
export { remarkFrontmatterPlugin, remarkGfmPlugin };
|
|
7
|
+
/**
|
|
8
|
+
* A reusable compiler for compiling MDX.
|
|
9
|
+
*/
|
|
7
10
|
export class MdxCompiler {
|
|
8
11
|
constructor(mdxOptions = {}) {
|
|
9
12
|
Object.defineProperty(this, "mdxOptions", {
|
|
@@ -46,7 +49,7 @@ export class MdxCompiler {
|
|
|
46
49
|
}
|
|
47
50
|
return this;
|
|
48
51
|
}
|
|
49
|
-
async compile(source, { frontmatterOnly = false, mdxOptions } = {}) {
|
|
52
|
+
async compile(source, { frontmatterOnly = false, frontmatterSchema, mdxOptions } = {}) {
|
|
50
53
|
const vfile = new VFile({
|
|
51
54
|
value: source,
|
|
52
55
|
// Needed so vfile doesn't need to access fs.
|
|
@@ -66,17 +69,21 @@ export class MdxCompiler {
|
|
|
66
69
|
}
|
|
67
70
|
let compiled;
|
|
68
71
|
if (!frontmatterOnly) {
|
|
69
|
-
|
|
72
|
+
const compiledFile = await compileMdxJs(vfile, {
|
|
70
73
|
outputFormat: "function-body",
|
|
71
74
|
...(this.mdxOptions ?? {}),
|
|
72
75
|
...(mdxOptions ?? {}),
|
|
73
76
|
remarkPlugins,
|
|
74
77
|
rehypePlugins,
|
|
75
78
|
});
|
|
79
|
+
compiled = compiledFile.value.toString();
|
|
76
80
|
}
|
|
81
|
+
const frontmatter = frontmatterSchema === undefined
|
|
82
|
+
? (vfile.data.matter ?? {})
|
|
83
|
+
: frontmatterSchema.parse(vfile.data.matter ?? {});
|
|
77
84
|
return {
|
|
78
|
-
compiled
|
|
79
|
-
frontmatter
|
|
85
|
+
compiled,
|
|
86
|
+
frontmatter,
|
|
80
87
|
};
|
|
81
88
|
}
|
|
82
89
|
}
|
|
@@ -6,8 +6,8 @@ export function extractCodeMeta(node) {
|
|
|
6
6
|
}
|
|
7
7
|
const metaSchema = z.object({
|
|
8
8
|
highlight: z.string().optional(),
|
|
9
|
-
showLineNumbers: z.boolean().
|
|
10
|
-
commandLine: z.string().optional(),
|
|
9
|
+
showLineNumbers: z.boolean().or(z.string()).optional(),
|
|
10
|
+
commandLine: z.boolean().or(z.string()).optional(),
|
|
11
11
|
fileName: z.string().optional(),
|
|
12
12
|
});
|
|
13
13
|
function parseMetaString(meta) {
|
|
@@ -43,7 +43,7 @@ function parseMetaString(meta) {
|
|
|
43
43
|
options.commandLine = { commandRange: [] };
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
if (
|
|
46
|
+
if (parsed.fileName !== undefined) {
|
|
47
47
|
options.fileName = parsed.fileName.trim();
|
|
48
48
|
}
|
|
49
49
|
return options;
|
|
@@ -4,6 +4,9 @@ import { visit } from "unist-util-visit";
|
|
|
4
4
|
import { transformerNotationHighlight, } from "@shikijs/transformers";
|
|
5
5
|
import { numericRangeContains } from "@temelj/iterator";
|
|
6
6
|
import { extractCodeMeta } from "./code-meta.js";
|
|
7
|
+
/**
|
|
8
|
+
* A plugin that highlights code blocks using Shiki.
|
|
9
|
+
*/
|
|
7
10
|
export function syntaxHighlightPlugin(options = {}) {
|
|
8
11
|
return async (tree) => {
|
|
9
12
|
const promises = [];
|
|
@@ -31,7 +34,7 @@ export function syntaxHighlightPlugin(options = {}) {
|
|
|
31
34
|
light: "github-light-default",
|
|
32
35
|
dark: "github-dark-default",
|
|
33
36
|
},
|
|
34
|
-
...(options.
|
|
37
|
+
...(options.shikiHastOptions ?? {}),
|
|
35
38
|
};
|
|
36
39
|
if (hastOptions.transformers === undefined) {
|
|
37
40
|
hastOptions.transformers = [];
|
|
@@ -62,7 +65,8 @@ export function syntaxHighlightPlugin(options = {}) {
|
|
|
62
65
|
}
|
|
63
66
|
if (options.commandLine &&
|
|
64
67
|
meta.commandLine &&
|
|
65
|
-
|
|
68
|
+
(meta.commandLine.commandRange.length === 0 ||
|
|
69
|
+
numericRangeContains(meta.commandLine.commandRange, lineIndex))) {
|
|
66
70
|
this.addClassToHast(line, options.commandLine.className ?? "line-command");
|
|
67
71
|
}
|
|
68
72
|
lineIndex++;
|
package/package.json
CHANGED
package/types/compiler.d.ts
CHANGED
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
import { type CompileOptions as MdxJsCompileOptions } from "@mdx-js/mdx";
|
|
2
2
|
import remarkFrontmatterPlugin from "remark-frontmatter";
|
|
3
3
|
import remarkGfmPlugin from "remark-gfm";
|
|
4
|
+
import type { z } from "zod";
|
|
4
5
|
import type { PluginFactory } from "./types.js";
|
|
5
6
|
export { remarkFrontmatterPlugin, remarkGfmPlugin };
|
|
7
|
+
/**
|
|
8
|
+
* Represents the source content for an MDX document.
|
|
9
|
+
*/
|
|
6
10
|
export type MdxSource = string | Uint8Array;
|
|
7
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Options for compiling an MDX document.
|
|
13
|
+
*/
|
|
14
|
+
export interface MdxCompileOptions<TFrontmatter extends z.ZodSchema> {
|
|
8
15
|
frontmatterOnly?: boolean | undefined;
|
|
16
|
+
frontmatterSchema?: TFrontmatter;
|
|
9
17
|
mdxOptions?: MdxJsCompileOptions;
|
|
10
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* The result of compiling an MDX document.
|
|
21
|
+
* Compiled content is optional, because sometimes we only need the frontmatter.
|
|
22
|
+
*/
|
|
11
23
|
export interface MdxArtifact<TFrontmatter = Record<string, unknown>> {
|
|
12
24
|
compiled?: string | undefined;
|
|
13
25
|
frontmatter: TFrontmatter;
|
|
14
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* A reusable compiler for compiling MDX.
|
|
29
|
+
*/
|
|
15
30
|
export declare class MdxCompiler {
|
|
16
31
|
private readonly mdxOptions;
|
|
17
32
|
private readonly remarkPlugins;
|
|
@@ -19,6 +34,6 @@ export declare class MdxCompiler {
|
|
|
19
34
|
constructor(mdxOptions?: MdxJsCompileOptions);
|
|
20
35
|
withRemarkPlugin<TOptions>(plugin: (options?: TOptions) => PluginFactory, options?: TOptions): MdxCompiler;
|
|
21
36
|
withRehypePlugin<TOptions>(plugin: (options?: TOptions) => PluginFactory, options?: TOptions): MdxCompiler;
|
|
22
|
-
compile<
|
|
37
|
+
compile<TFrontmatterSchema extends z.ZodSchema>(source: MdxSource, { frontmatterOnly, frontmatterSchema, mdxOptions }?: MdxCompileOptions<TFrontmatterSchema>): Promise<MdxArtifact<z.output<TFrontmatterSchema>>>;
|
|
23
38
|
}
|
|
24
39
|
//# sourceMappingURL=compiler.d.ts.map
|
package/types/compiler.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAIzC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,OAAO,EAAE,uBAAuB,EAAE,eAAe,EAAE,CAAC;AAEpD;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,UAAU,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAChC,YAAY,SAAS,CAAC,CAAC,SAAS;IAEhC,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAEtC,iBAAiB,CAAC,EAAE,YAAY,CAAC;IACjC,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;gBAG5C,UAAU,GAAE,mBAAwB;IAO/B,gBAAgB,CAAC,QAAQ,EAC9B,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,QAAQ,KAAK,aAAa,EAC7C,OAAO,CAAC,EAAE,QAAQ,GACjB,WAAW;IASP,gBAAgB,CAAC,QAAQ,EAC9B,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,QAAQ,KAAK,aAAa,EAC7C,OAAO,CAAC,EAAE,QAAQ,GACjB,WAAW;IASD,OAAO,CAClB,kBAAkB,SAAS,CAAC,CAAC,SAAS,EAEtC,MAAM,EAAE,SAAS,EACjB,EAAE,eAAuB,EAAE,iBAAiB,EAAE,UAAU,EAAE,GACxD,iBAAiB,CAAC,kBAAkB,CAAM,GAC3C,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;CA0CtD"}
|
|
@@ -1,24 +1,52 @@
|
|
|
1
1
|
import { type BundledLanguage, type BundledTheme, type CodeToHastOptions } from "shiki";
|
|
2
2
|
import { type TransformerNotationHighlightOptions } from "@shikijs/transformers";
|
|
3
3
|
import type { PluginFactory } from "../../types.js";
|
|
4
|
-
type
|
|
4
|
+
type ShikiHastOptions = Partial<CodeToHastOptions<BundledLanguage, BundledTheme>>;
|
|
5
5
|
/**
|
|
6
6
|
* Options for {@linkcode syntaxHighlightPlugin}.
|
|
7
7
|
*/
|
|
8
8
|
export interface SyntaxHighlightPluginOptions {
|
|
9
|
+
/**
|
|
10
|
+
* A prefix for the language class name on the code tag.
|
|
11
|
+
*/
|
|
9
12
|
languageClassNamePrefix?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Options for the highlight transformer.
|
|
15
|
+
*/
|
|
10
16
|
highlight?: {
|
|
11
17
|
transformer?: TransformerNotationHighlightOptions;
|
|
12
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* Options for line numbers.
|
|
21
|
+
*/
|
|
13
22
|
lineNumbers?: {
|
|
23
|
+
/**
|
|
24
|
+
* The name of the variable that contains the line number width.
|
|
25
|
+
* This is used for padding the line numbers so that they align.
|
|
26
|
+
*/
|
|
14
27
|
widthVariableName?: string;
|
|
28
|
+
/**
|
|
29
|
+
* A class name to be added to the line numbers.
|
|
30
|
+
*/
|
|
15
31
|
className?: string;
|
|
16
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* Options for command line.
|
|
35
|
+
*/
|
|
17
36
|
commandLine?: {
|
|
37
|
+
/**
|
|
38
|
+
* A class name to be added to the prompt line.
|
|
39
|
+
*/
|
|
18
40
|
className?: string;
|
|
19
41
|
};
|
|
20
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Extra options for the Shiki hast transformer.
|
|
44
|
+
*/
|
|
45
|
+
shikiHastOptions?: ShikiHastOptions;
|
|
21
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* A plugin that highlights code blocks using Shiki.
|
|
49
|
+
*/
|
|
22
50
|
export declare function syntaxHighlightPlugin(options?: SyntaxHighlightPluginOptions): PluginFactory;
|
|
23
51
|
export {};
|
|
24
52
|
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
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,EACvB,MAAM,OAAO,CAAC;AAEf,OAAO,EAEL,KAAK,mCAAmC,EACzC,MAAM,uBAAuB,CAAC;AAG/B,OAAO,KAAK,EAAyB,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG3E,KAAK,
|
|
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,EACvB,MAAM,OAAO,CAAC;AAEf,OAAO,EAEL,KAAK,mCAAmC,EACzC,MAAM,uBAAuB,CAAC;AAG/B,OAAO,KAAK,EAAyB,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG3E,KAAK,gBAAgB,GAAG,OAAO,CAC7B,iBAAiB,CAAC,eAAe,EAAE,YAAY,CAAC,CACjD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;OAEG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC;;OAEG;IACH,SAAS,CAAC,EAAE;QACV,WAAW,CAAC,EAAE,mCAAmC,CAAC;KACnD,CAAC;IACF;;OAEG;IACH,WAAW,CAAC,EAAE;QACZ;;;WAGG;QACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B;;WAEG;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF;;OAEG;IACH,WAAW,CAAC,EAAE;QACZ;;WAEG;QACH,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF;;OAEG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,GAAE,4BAAiC,GACzC,aAAa,CAsJf"}
|
|
@@ -7,6 +7,10 @@ type TreeProcessorPluginOptions = {
|
|
|
7
7
|
/** The processor. */
|
|
8
8
|
process: MdxTreeProcessor;
|
|
9
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* A plugin that allows to process MDX tree nodes.
|
|
12
|
+
* It can be async or sync.
|
|
13
|
+
*/
|
|
10
14
|
export declare function treeProcessorPlugin({ process }?: TreeProcessorPluginOptions): PluginFactory;
|
|
11
15
|
export {};
|
|
12
16
|
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/tree-processor/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAY,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE3E,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,wBAAgB,mBAAmB,CACjC,EAAE,OAAO,EAAE,GAAE,0BAAkD,GAC9D,aAAa,CAuBf"}
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/plugins/tree-processor/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAY,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE3E,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,wBAAgB,mBAAmB,CACjC,EAAE,OAAO,EAAE,GAAE,0BAAkD,GAC9D,aAAa,CAuBf"}
|