safe-mdx 1.7.0 → 1.9.0
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 +56 -0
- package/dist/esm-parser.test.js +5 -0
- package/dist/esm-parser.test.js.map +1 -1
- package/dist/html/html-and-md.test.js +14 -41
- package/dist/html/html-and-md.test.js.map +1 -1
- package/dist/html/html-to-mdx-ast.d.ts +26 -1
- package/dist/html/html-to-mdx-ast.d.ts.map +1 -1
- package/dist/html/html-to-mdx-ast.js +40 -0
- package/dist/html/html-to-mdx-ast.js.map +1 -1
- package/dist/incremental-parse.d.ts +41 -0
- package/dist/incremental-parse.d.ts.map +1 -0
- package/dist/incremental-parse.js +139 -0
- package/dist/incremental-parse.js.map +1 -0
- package/dist/incremental-parse.test.d.ts +2 -0
- package/dist/incremental-parse.test.d.ts.map +1 -0
- package/dist/incremental-parse.test.js +299 -0
- package/dist/incremental-parse.test.js.map +1 -0
- package/dist/markdown-html.test.d.ts +2 -0
- package/dist/markdown-html.test.d.ts.map +1 -0
- package/dist/markdown-html.test.js +129 -0
- package/dist/markdown-html.test.js.map +1 -0
- package/dist/markdown.d.ts +3 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +4 -0
- package/dist/markdown.js.map +1 -0
- package/dist/parse.d.ts +9 -2
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +34 -20
- package/dist/parse.js.map +1 -1
- package/dist/safe-mdx.d.ts.map +1 -1
- package/dist/safe-mdx.js +6 -24
- package/dist/safe-mdx.js.map +1 -1
- package/package.json +9 -1
- package/src/esm-parser.test.ts +7 -1
- package/src/html/html-and-md.test.ts +15 -47
- package/src/html/html-to-mdx-ast.ts +53 -1
- package/src/incremental-parse.test.ts +315 -0
- package/src/incremental-parse.ts +219 -0
- package/src/markdown-html.test.tsx +144 -0
- package/src/markdown.ts +4 -0
- package/src/parse.ts +46 -20
- package/src/safe-mdx.test.tsx +2 -0
- package/src/safe-mdx.tsx +6 -26
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
// Verifies segment-cached parsing for streaming MDX without tying the API to React rendering.
|
|
2
|
+
import { describe, expect, test } from 'vitest';
|
|
3
|
+
import { mdxParse } from "./parse.js";
|
|
4
|
+
import { createMdxProcessor, parseMarkdownIncremental } from "./incremental-parse.js";
|
|
5
|
+
function nodeSummary(ast) {
|
|
6
|
+
return ast.children.map((node) => ({
|
|
7
|
+
type: node.type,
|
|
8
|
+
value: node.value,
|
|
9
|
+
name: node.name,
|
|
10
|
+
start: node.position?.start,
|
|
11
|
+
end: node.position?.end,
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
describe('parseMarkdownIncremental', () => {
|
|
15
|
+
test('parses MDX into an mdast root and reports no errors', () => {
|
|
16
|
+
const cache = new Map();
|
|
17
|
+
const result = parseMarkdownIncremental({
|
|
18
|
+
markdown: '# Hello\n\n<Alert>streaming</Alert>\n\nTail',
|
|
19
|
+
cache,
|
|
20
|
+
trailingNodes: 1,
|
|
21
|
+
});
|
|
22
|
+
expect(result.errors).toMatchInlineSnapshot(`[]`);
|
|
23
|
+
expect(nodeSummary(result.mdast)).toMatchInlineSnapshot(`
|
|
24
|
+
[
|
|
25
|
+
{
|
|
26
|
+
"end": {
|
|
27
|
+
"column": 8,
|
|
28
|
+
"line": 1,
|
|
29
|
+
"offset": 7,
|
|
30
|
+
},
|
|
31
|
+
"name": undefined,
|
|
32
|
+
"start": {
|
|
33
|
+
"column": 1,
|
|
34
|
+
"line": 1,
|
|
35
|
+
"offset": 0,
|
|
36
|
+
},
|
|
37
|
+
"type": "heading",
|
|
38
|
+
"value": undefined,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"end": {
|
|
42
|
+
"column": 25,
|
|
43
|
+
"line": 3,
|
|
44
|
+
"offset": 33,
|
|
45
|
+
},
|
|
46
|
+
"name": "Alert",
|
|
47
|
+
"start": {
|
|
48
|
+
"column": 1,
|
|
49
|
+
"line": 3,
|
|
50
|
+
"offset": 9,
|
|
51
|
+
},
|
|
52
|
+
"type": "mdxJsxFlowElement",
|
|
53
|
+
"value": undefined,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"end": {
|
|
57
|
+
"column": 5,
|
|
58
|
+
"line": 5,
|
|
59
|
+
"offset": 39,
|
|
60
|
+
},
|
|
61
|
+
"name": undefined,
|
|
62
|
+
"start": {
|
|
63
|
+
"column": 1,
|
|
64
|
+
"line": 5,
|
|
65
|
+
"offset": 35,
|
|
66
|
+
},
|
|
67
|
+
"type": "paragraph",
|
|
68
|
+
"value": undefined,
|
|
69
|
+
},
|
|
70
|
+
]
|
|
71
|
+
`);
|
|
72
|
+
expect(Array.from(cache.keys())).toMatchInlineSnapshot(`
|
|
73
|
+
[
|
|
74
|
+
0,
|
|
75
|
+
7,
|
|
76
|
+
]
|
|
77
|
+
`);
|
|
78
|
+
});
|
|
79
|
+
test('reuses cached stable segments', () => {
|
|
80
|
+
const cache = new Map();
|
|
81
|
+
let parseCalls = 0;
|
|
82
|
+
const parse = (markdown) => {
|
|
83
|
+
parseCalls++;
|
|
84
|
+
return mdxParse(markdown);
|
|
85
|
+
};
|
|
86
|
+
parseMarkdownIncremental({
|
|
87
|
+
markdown: '# Title\n\nFirst paragraph\n\nSecond paragraph',
|
|
88
|
+
cache,
|
|
89
|
+
trailingNodes: 0,
|
|
90
|
+
parse,
|
|
91
|
+
});
|
|
92
|
+
parseMarkdownIncremental({
|
|
93
|
+
markdown: '# Title\n\nFirst paragraph\n\nSecond paragraph',
|
|
94
|
+
cache,
|
|
95
|
+
trailingNodes: 0,
|
|
96
|
+
parse,
|
|
97
|
+
});
|
|
98
|
+
expect(parseCalls).toMatchInlineSnapshot(`1`);
|
|
99
|
+
expect(Array.from(cache.entries()).map(([start, entry]) => ({ start, end: entry.end }))).toMatchInlineSnapshot(`
|
|
100
|
+
[
|
|
101
|
+
{
|
|
102
|
+
"end": 7,
|
|
103
|
+
"start": 0,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"end": 24,
|
|
107
|
+
"start": 7,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"end": 42,
|
|
111
|
+
"start": 24,
|
|
112
|
+
},
|
|
113
|
+
]
|
|
114
|
+
`);
|
|
115
|
+
});
|
|
116
|
+
test('keeps positions correct after cached prefixes', () => {
|
|
117
|
+
const cache = new Map();
|
|
118
|
+
parseMarkdownIncremental({
|
|
119
|
+
markdown: '# Title\n\nFirst paragraph\n\nLive',
|
|
120
|
+
cache,
|
|
121
|
+
trailingNodes: 1,
|
|
122
|
+
});
|
|
123
|
+
const result = parseMarkdownIncremental({
|
|
124
|
+
markdown: '# Title\n\nFirst paragraph\n\nLive tail\n\nNew paragraph',
|
|
125
|
+
cache,
|
|
126
|
+
trailingNodes: 1,
|
|
127
|
+
});
|
|
128
|
+
expect(result.errors).toMatchInlineSnapshot(`[]`);
|
|
129
|
+
expect(nodeSummary(result.mdast)).toMatchInlineSnapshot(`
|
|
130
|
+
[
|
|
131
|
+
{
|
|
132
|
+
"end": {
|
|
133
|
+
"column": 8,
|
|
134
|
+
"line": 1,
|
|
135
|
+
"offset": 7,
|
|
136
|
+
},
|
|
137
|
+
"name": undefined,
|
|
138
|
+
"start": {
|
|
139
|
+
"column": 1,
|
|
140
|
+
"line": 1,
|
|
141
|
+
"offset": 0,
|
|
142
|
+
},
|
|
143
|
+
"type": "heading",
|
|
144
|
+
"value": undefined,
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
"end": {
|
|
148
|
+
"column": 16,
|
|
149
|
+
"line": 3,
|
|
150
|
+
"offset": 24,
|
|
151
|
+
},
|
|
152
|
+
"name": undefined,
|
|
153
|
+
"start": {
|
|
154
|
+
"column": 1,
|
|
155
|
+
"line": 3,
|
|
156
|
+
"offset": 9,
|
|
157
|
+
},
|
|
158
|
+
"type": "paragraph",
|
|
159
|
+
"value": undefined,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"end": {
|
|
163
|
+
"column": 10,
|
|
164
|
+
"line": 5,
|
|
165
|
+
"offset": 35,
|
|
166
|
+
},
|
|
167
|
+
"name": undefined,
|
|
168
|
+
"start": {
|
|
169
|
+
"column": 1,
|
|
170
|
+
"line": 5,
|
|
171
|
+
"offset": 26,
|
|
172
|
+
},
|
|
173
|
+
"type": "paragraph",
|
|
174
|
+
"value": undefined,
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"end": {
|
|
178
|
+
"column": 14,
|
|
179
|
+
"line": 7,
|
|
180
|
+
"offset": 50,
|
|
181
|
+
},
|
|
182
|
+
"name": undefined,
|
|
183
|
+
"start": {
|
|
184
|
+
"column": 1,
|
|
185
|
+
"line": 7,
|
|
186
|
+
"offset": 37,
|
|
187
|
+
},
|
|
188
|
+
"type": "paragraph",
|
|
189
|
+
"value": undefined,
|
|
190
|
+
},
|
|
191
|
+
]
|
|
192
|
+
`);
|
|
193
|
+
});
|
|
194
|
+
test('returns partial cached AST instead of throwing on invalid live tail', () => {
|
|
195
|
+
const cache = new Map();
|
|
196
|
+
parseMarkdownIncremental({
|
|
197
|
+
markdown: '# Stable\n\nDone\n\nTail',
|
|
198
|
+
cache,
|
|
199
|
+
trailingNodes: 1,
|
|
200
|
+
});
|
|
201
|
+
const result = parseMarkdownIncremental({
|
|
202
|
+
markdown: '# Stable\n\nDone\n\n<Card',
|
|
203
|
+
cache,
|
|
204
|
+
trailingNodes: 1,
|
|
205
|
+
});
|
|
206
|
+
expect(result.errors.map((error) => ({
|
|
207
|
+
message: error.message,
|
|
208
|
+
line: error.line,
|
|
209
|
+
column: error.column,
|
|
210
|
+
offset: error.offset,
|
|
211
|
+
}))).toMatchInlineSnapshot(`
|
|
212
|
+
[
|
|
213
|
+
{
|
|
214
|
+
"column": 6,
|
|
215
|
+
"line": 5,
|
|
216
|
+
"message": "Unexpected end of file in name, expected a name character such as letters, digits, \`$\`, or \`_\`; whitespace before attributes; or the end of the tag",
|
|
217
|
+
"offset": 21,
|
|
218
|
+
},
|
|
219
|
+
]
|
|
220
|
+
`);
|
|
221
|
+
expect(nodeSummary(result.mdast)).toMatchInlineSnapshot(`
|
|
222
|
+
[
|
|
223
|
+
{
|
|
224
|
+
"end": {
|
|
225
|
+
"column": 9,
|
|
226
|
+
"line": 1,
|
|
227
|
+
"offset": 8,
|
|
228
|
+
},
|
|
229
|
+
"name": undefined,
|
|
230
|
+
"start": {
|
|
231
|
+
"column": 1,
|
|
232
|
+
"line": 1,
|
|
233
|
+
"offset": 0,
|
|
234
|
+
},
|
|
235
|
+
"type": "heading",
|
|
236
|
+
"value": undefined,
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"end": {
|
|
240
|
+
"column": 5,
|
|
241
|
+
"line": 3,
|
|
242
|
+
"offset": 14,
|
|
243
|
+
},
|
|
244
|
+
"name": undefined,
|
|
245
|
+
"start": {
|
|
246
|
+
"column": 1,
|
|
247
|
+
"line": 3,
|
|
248
|
+
"offset": 10,
|
|
249
|
+
},
|
|
250
|
+
"type": "paragraph",
|
|
251
|
+
"value": undefined,
|
|
252
|
+
},
|
|
253
|
+
]
|
|
254
|
+
`);
|
|
255
|
+
});
|
|
256
|
+
test('uses custom processor plugins', () => {
|
|
257
|
+
const cache = new Map();
|
|
258
|
+
const processor = createMdxProcessor({
|
|
259
|
+
remarkPlugins: [remarkUppercaseText],
|
|
260
|
+
});
|
|
261
|
+
const result = parseMarkdownIncremental({
|
|
262
|
+
markdown: 'hello **world**',
|
|
263
|
+
cache,
|
|
264
|
+
processor,
|
|
265
|
+
});
|
|
266
|
+
expect(result.errors).toMatchInlineSnapshot(`[]`);
|
|
267
|
+
expect(textValues(result.mdast)).toMatchInlineSnapshot(`
|
|
268
|
+
[
|
|
269
|
+
"HELLO ",
|
|
270
|
+
"WORLD",
|
|
271
|
+
]
|
|
272
|
+
`);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
function remarkUppercaseText() {
|
|
276
|
+
return (tree) => {
|
|
277
|
+
walk(tree, (node) => {
|
|
278
|
+
if (node.type === 'text') {
|
|
279
|
+
node.value = node.value.toUpperCase();
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
function textValues(node) {
|
|
285
|
+
const values = [];
|
|
286
|
+
walk(node, (child) => {
|
|
287
|
+
if (child.type === 'text')
|
|
288
|
+
values.push(child.value);
|
|
289
|
+
});
|
|
290
|
+
return values;
|
|
291
|
+
}
|
|
292
|
+
function walk(node, visit) {
|
|
293
|
+
visit(node);
|
|
294
|
+
if (Array.isArray(node.children)) {
|
|
295
|
+
for (const child of node.children)
|
|
296
|
+
walk(child, visit);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
//# sourceMappingURL=incremental-parse.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"incremental-parse.test.js","sourceRoot":"","sources":["../src/incremental-parse.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-html.test.d.ts","sourceRoot":"","sources":["../src/markdown-html.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// Tests for rendering markdown (not MDX) that contains raw HTML blocks.
|
|
2
|
+
// The remarkHtmlToMdx plugin is used as a pre-processing step to convert
|
|
3
|
+
// `html` AST nodes (produced by plain remark) into mdxJsx nodes before
|
|
4
|
+
// MdastToJsx ever sees them. This way linkedom stays out of the main bundle.
|
|
5
|
+
import dedent from 'dedent';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
8
|
+
import { remark } from 'remark';
|
|
9
|
+
import remarkGfm from 'remark-gfm';
|
|
10
|
+
import { expect, test, describe } from 'vitest';
|
|
11
|
+
import { MdastToJsx } from "./safe-mdx.js";
|
|
12
|
+
import { remarkHtmlToMdx } from "./markdown.js";
|
|
13
|
+
import { validHtmlElements } from "./html/valid-html-elements.js";
|
|
14
|
+
const components = {
|
|
15
|
+
Heading({ children, ...props }) {
|
|
16
|
+
return React.createElement('h1', props, children);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
// convertTagName that only keeps standard HTML elements, drops everything else.
|
|
20
|
+
// This mirrors what the old case 'html' did inside MdastToJsx.
|
|
21
|
+
const onlyValidHtml = ({ tagName }) => validHtmlElements.has(tagName.toLowerCase()) ? tagName.toLowerCase() : '';
|
|
22
|
+
// Parse with plain remark + remarkHtmlToMdx pre-processor, then render via MdastToJsx.
|
|
23
|
+
// No html nodes remain by the time MdastToJsx sees the AST.
|
|
24
|
+
function render(markdown) {
|
|
25
|
+
const processor = remark()
|
|
26
|
+
.use(remarkGfm)
|
|
27
|
+
.use(remarkHtmlToMdx, { convertTagName: onlyValidHtml });
|
|
28
|
+
const mdast = processor.parse(markdown);
|
|
29
|
+
processor.runSync(mdast);
|
|
30
|
+
const visitor = new MdastToJsx({ markdown, mdast, components });
|
|
31
|
+
const result = visitor.run();
|
|
32
|
+
const html = renderToStaticMarkup(result);
|
|
33
|
+
return { errors: visitor.errors || [], html };
|
|
34
|
+
}
|
|
35
|
+
describe('remarkHtmlToMdx pre-processor with plain remark', () => {
|
|
36
|
+
test('renders a block-level HTML div', () => {
|
|
37
|
+
const { html, errors } = render(dedent `
|
|
38
|
+
# Title
|
|
39
|
+
|
|
40
|
+
<div class="box">hello world</div>
|
|
41
|
+
|
|
42
|
+
Some paragraph after.
|
|
43
|
+
`);
|
|
44
|
+
expect(errors).toMatchInlineSnapshot(`[]`);
|
|
45
|
+
expect(html).toMatchInlineSnapshot(`"<h1>Title</h1><div class="box">hello world</div><p>Some paragraph after.</p>"`);
|
|
46
|
+
});
|
|
47
|
+
test('inline HTML in a paragraph is split by remark into per-tag html nodes (known limitation)', () => {
|
|
48
|
+
// remark parses inline HTML at tag boundaries, so <strong>bold</strong> becomes:
|
|
49
|
+
// html("<strong>") → empty element, text("bold"), html("</strong>") → dropped
|
|
50
|
+
// Block-level HTML (own line + blank lines) is the only reliably handled case.
|
|
51
|
+
const { html, errors } = render('Some text with <strong>bold</strong> and <em>italic</em> inline.');
|
|
52
|
+
expect(errors).toMatchInlineSnapshot(`[]`);
|
|
53
|
+
expect(html).toMatchInlineSnapshot(`"<p>Some text with <strong></strong>bold and <em></em>italic inline.</p>"`);
|
|
54
|
+
});
|
|
55
|
+
test('strips unknown custom elements but keeps their text children', () => {
|
|
56
|
+
// <callout> is not in validHtmlElements, so the tag wrapper is dropped
|
|
57
|
+
const { html, errors } = render(dedent `
|
|
58
|
+
<callout icon="💡">
|
|
59
|
+
Important note
|
|
60
|
+
</callout>
|
|
61
|
+
`);
|
|
62
|
+
expect(errors).toMatchInlineSnapshot(`[]`);
|
|
63
|
+
expect(html).toMatchInlineSnapshot(`"Important note"`);
|
|
64
|
+
});
|
|
65
|
+
test('renders self-closing void element hr', () => {
|
|
66
|
+
const { html, errors } = render(dedent `
|
|
67
|
+
Before
|
|
68
|
+
|
|
69
|
+
<hr>
|
|
70
|
+
|
|
71
|
+
After
|
|
72
|
+
`);
|
|
73
|
+
expect(errors).toMatchInlineSnapshot(`[]`);
|
|
74
|
+
expect(html).toMatchInlineSnapshot(`"<p>Before</p><hr/><p>After</p>"`);
|
|
75
|
+
});
|
|
76
|
+
test('renders HTML anchor with name attribute', () => {
|
|
77
|
+
const { html, errors } = render(dedent `
|
|
78
|
+
<a name="section-one"></a>
|
|
79
|
+
|
|
80
|
+
## Section One
|
|
81
|
+
`);
|
|
82
|
+
expect(errors).toMatchInlineSnapshot(`[]`);
|
|
83
|
+
expect(html).toMatchInlineSnapshot(`"<p><a name="section-one"></a></p><h2>Section One</h2>"`);
|
|
84
|
+
});
|
|
85
|
+
test('converts class attribute to className', () => {
|
|
86
|
+
// Note: span without blank-line separation is treated as inline HTML by remark —
|
|
87
|
+
// the opening tag and text content become separate nodes (see inline limitation above).
|
|
88
|
+
const { html, errors } = render(dedent `
|
|
89
|
+
<span class="highlight">highlighted text</span>
|
|
90
|
+
`);
|
|
91
|
+
expect(errors).toMatchInlineSnapshot(`[]`);
|
|
92
|
+
expect(html).toMatchInlineSnapshot(`"<p><span class="highlight"></span>highlighted text</p>"`);
|
|
93
|
+
});
|
|
94
|
+
test('renders a table from raw HTML', () => {
|
|
95
|
+
const { html, errors } = render(dedent `
|
|
96
|
+
<table>
|
|
97
|
+
<tr><th>Name</th><th>Value</th></tr>
|
|
98
|
+
<tr><td>foo</td><td>bar</td></tr>
|
|
99
|
+
</table>
|
|
100
|
+
`);
|
|
101
|
+
expect(errors).toMatchInlineSnapshot(`[]`);
|
|
102
|
+
expect(html).toMatchInlineSnapshot(`"<table><tr><th>Name</th><th>Value</th></tr><tr><td>foo</td><td>bar</td></tr></table>"`);
|
|
103
|
+
});
|
|
104
|
+
test('mixed markdown and HTML block', () => {
|
|
105
|
+
const { html, errors } = render(dedent `
|
|
106
|
+
## My Section
|
|
107
|
+
|
|
108
|
+
<div class="card">
|
|
109
|
+
Card content here
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
Back to **markdown**.
|
|
113
|
+
`);
|
|
114
|
+
expect(errors).toMatchInlineSnapshot(`[]`);
|
|
115
|
+
expect(html).toMatchInlineSnapshot(`"<h2>My Section</h2><div class="card">Card content here</div><p>Back to <strong>markdown</strong>.</p>"`);
|
|
116
|
+
});
|
|
117
|
+
test('without the plugin, html nodes are silently skipped by MdastToJsx', () => {
|
|
118
|
+
// Verify the old case 'html' path is gone — without the plugin, html nodes are dropped
|
|
119
|
+
const processor = remark().use(remarkGfm); // no remarkHtmlToMdx
|
|
120
|
+
const mdast = processor.parse(dedent `
|
|
121
|
+
<div class="box">hello world</div>
|
|
122
|
+
`);
|
|
123
|
+
const visitor = new MdastToJsx({ markdown: '', mdast, components });
|
|
124
|
+
const result = visitor.run();
|
|
125
|
+
const html = renderToStaticMarkup(result);
|
|
126
|
+
expect(html).toMatchInlineSnapshot(`""`);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=markdown-html.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-html.test.js","sourceRoot":"","sources":["../src/markdown-html.test.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAC9E,YAAY,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAA"}
|
package/dist/markdown.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Pre-processing utilities for rendering plain markdown (not MDX) that contains raw HTML.
|
|
2
|
+
// Import from 'safe-mdx/markdown' to keep linkedom out of the main bundle.
|
|
3
|
+
export { remarkHtmlToMdx, parseHtmlToMdxAst } from "./html/html-to-mdx-ast.js";
|
|
4
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,2EAA2E;AAC3E,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA"}
|
package/dist/parse.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Root } from 'mdast';
|
|
2
|
-
import {
|
|
3
|
-
export {
|
|
2
|
+
import { remarkMdxJsxNormalize } from './html/remark-mdx-jsx-normalize.ts';
|
|
3
|
+
export { remarkMdxJsxNormalize };
|
|
4
4
|
export type MdxImportSpecifier = {
|
|
5
5
|
/** Name used in MDX (e.g. `Card`, `MyButton`, `Utils`) */
|
|
6
6
|
local: string;
|
|
@@ -19,6 +19,12 @@ export type MdxImport = {
|
|
|
19
19
|
*/
|
|
20
20
|
export declare function extractImports(ast: Root): MdxImport[];
|
|
21
21
|
export declare function mdxParse(code: string): Root;
|
|
22
|
+
export type MdxProcessorOptions = {
|
|
23
|
+
/** Extra remark plugins appended after safe-mdx's default MDX, frontmatter, and GFM parsers. */
|
|
24
|
+
remarkPlugins?: any[];
|
|
25
|
+
};
|
|
26
|
+
export declare function createMdxProcessor({ remarkPlugins, }?: MdxProcessorOptions): import("unified").Processor<Root, undefined, undefined, Root, string>;
|
|
27
|
+
export type MdxProcessor = ReturnType<typeof createMdxProcessor>;
|
|
22
28
|
/**
|
|
23
29
|
* https://github.com/mdx-js/mdx/blob/b3351fadcb6f78833a72757b7135dcfb8ab646fe/packages/mdx/lib/plugin/remark-mark-and-unravel.js
|
|
24
30
|
* A tiny plugin that unravels `<p><h1>x</h1></p>` but also
|
|
@@ -56,4 +62,5 @@ export declare function resolveModules({ glob, mdast, baseUrl, }: {
|
|
|
56
62
|
mdast: Root;
|
|
57
63
|
baseUrl: string;
|
|
58
64
|
}): Promise<EagerModules>;
|
|
65
|
+
export declare const mdxProcessor: import("unified").Processor<Root, undefined, undefined, Root, string>;
|
|
59
66
|
//# sourceMappingURL=parse.d.ts.map
|
package/dist/parse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAe,MAAM,OAAO,CAAA;AAIzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAe,MAAM,OAAO,CAAA;AAIzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAA;AAE1E,OAAO,EAAE,qBAAqB,EAAE,CAAA;AAIhC,MAAM,MAAM,kBAAkB,GAAG;IAC7B,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAA;IACb,uGAAuG;IACvG,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,WAAW,CAAA;CAC1C,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACpB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,kBAAkB,EAAE,CAAA;CACnC,CAAA;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,IAAI,GAAG,SAAS,EAAE,CAkCrD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAET,IAAI,CAC/B;AAED,MAAM,MAAM,mBAAmB,GAAG;IAC9B,gGAAgG;IAChG,aAAa,CAAC,EAAE,GAAG,EAAE,CAAA;CACxB,CAAA;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,aAAkB,GACrB,GAAE,mBAAwB,yEAqB1B;AAED,MAAM,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAEhE;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,KACf,MAAM,IAAI,UAuE9B;AAUD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAAE,GACrB,MAAM,GAAG,SAAS,CAwBpB;AA0BD,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;AACzE,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;AAE9D;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAAC,EACjC,IAAI,EACJ,KAAK,EACL,OAAO,GACV,EAAE;IACC,IAAI,EAAE,QAAQ,CAAA;IACd,KAAK,EAAE,IAAI,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;CAClB,GAAG,OAAO,CAAC,YAAY,CAAC,CAkBxB;AAED,eAAO,MAAM,YAAY,uEAAuB,CAAA"}
|
package/dist/parse.js
CHANGED
|
@@ -4,8 +4,8 @@ import { visit } from 'unist-util-visit';
|
|
|
4
4
|
import { remark } from 'remark';
|
|
5
5
|
import remarkGfm from 'remark-gfm';
|
|
6
6
|
import remarkMdx from 'remark-mdx';
|
|
7
|
-
import {
|
|
8
|
-
export {
|
|
7
|
+
import { remarkMdxJsxNormalize } from "./html/remark-mdx-jsx-normalize.js";
|
|
8
|
+
export { remarkMdxJsxNormalize };
|
|
9
9
|
/**
|
|
10
10
|
* Extract all import declarations from a parsed mdast tree.
|
|
11
11
|
* Unlike `parseEsmImports`, this accepts ANY source (not just HTTPS URLs).
|
|
@@ -50,6 +50,27 @@ export function mdxParse(code) {
|
|
|
50
50
|
const file = mdxProcessor.processSync(code);
|
|
51
51
|
return file.data.ast;
|
|
52
52
|
}
|
|
53
|
+
export function createMdxProcessor({ remarkPlugins = [], } = {}) {
|
|
54
|
+
const processor = remark()
|
|
55
|
+
.use(remarkMdx)
|
|
56
|
+
.use(remarkFrontmatter, ['yaml', 'toml'])
|
|
57
|
+
.use(remarkGfm);
|
|
58
|
+
for (const plugin of remarkPlugins) {
|
|
59
|
+
if (Array.isArray(plugin)) {
|
|
60
|
+
processor.use(plugin[0], ...plugin.slice(1));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
processor.use(plugin);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return processor
|
|
67
|
+
.use(remarkMarkAndUnravel)
|
|
68
|
+
.use(() => {
|
|
69
|
+
return (tree, file) => {
|
|
70
|
+
file.data.ast = tree;
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
}
|
|
53
74
|
/**
|
|
54
75
|
* https://github.com/mdx-js/mdx/blob/b3351fadcb6f78833a72757b7135dcfb8ab646fe/packages/mdx/lib/plugin/remark-mark-and-unravel.js
|
|
55
76
|
* A tiny plugin that unravels `<p><h1>x</h1></p>` but also
|
|
@@ -141,8 +162,6 @@ export function resolveModulePath(source, baseUrl, moduleKeys) {
|
|
|
141
162
|
else if (source.startsWith('./') || source.startsWith('../')) {
|
|
142
163
|
// Relative import: resolve from baseUrl
|
|
143
164
|
const joined = joinPaths(baseUrl, source);
|
|
144
|
-
if (!joined)
|
|
145
|
-
return undefined; // .. escaped above root
|
|
146
165
|
normalized = joined;
|
|
147
166
|
}
|
|
148
167
|
else {
|
|
@@ -159,23 +178,27 @@ export function resolveModulePath(source, baseUrl, moduleKeys) {
|
|
|
159
178
|
return undefined;
|
|
160
179
|
}
|
|
161
180
|
/** Simple path join that normalizes `./a/b/../c` segments.
|
|
162
|
-
*
|
|
163
|
-
*
|
|
181
|
+
* Outputs inside-root paths with `./` prefix and outside-root paths with
|
|
182
|
+
* leading `../` segments, matching Vite glob keys from explicit imports. */
|
|
164
183
|
function joinPaths(base, relative) {
|
|
165
184
|
// Strip ./ prefix and trailing /
|
|
166
185
|
const baseParts = base.replace(/^\.\//, '').replace(/\/$/, '').split('/').filter(Boolean);
|
|
167
186
|
const relParts = relative.replace(/^\.\//, '').split('/').filter(Boolean);
|
|
168
187
|
for (const part of relParts) {
|
|
169
188
|
if (part === '..') {
|
|
170
|
-
if (baseParts.length
|
|
171
|
-
|
|
172
|
-
|
|
189
|
+
if (baseParts.length > 0 && baseParts[baseParts.length - 1] !== '..') {
|
|
190
|
+
baseParts.pop();
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
baseParts.push('..');
|
|
194
|
+
}
|
|
173
195
|
}
|
|
174
196
|
else if (part !== '.') {
|
|
175
197
|
baseParts.push(part);
|
|
176
198
|
}
|
|
177
199
|
}
|
|
178
|
-
|
|
200
|
+
const joined = baseParts.join('/');
|
|
201
|
+
return joined.startsWith('../') ? joined : './' + joined;
|
|
179
202
|
}
|
|
180
203
|
/**
|
|
181
204
|
* Given a lazy Vite glob and a parsed mdast, resolve only the imported
|
|
@@ -206,14 +229,5 @@ export async function resolveModules({ glob, mdast, baseUrl, }) {
|
|
|
206
229
|
}));
|
|
207
230
|
return result;
|
|
208
231
|
}
|
|
209
|
-
const mdxProcessor =
|
|
210
|
-
.use(remarkMdx)
|
|
211
|
-
.use(remarkFrontmatter, ['yaml', 'toml'])
|
|
212
|
-
.use(remarkGfm)
|
|
213
|
-
.use(remarkMarkAndUnravel)
|
|
214
|
-
.use(() => {
|
|
215
|
-
return (tree, file) => {
|
|
216
|
-
file.data.ast = tree;
|
|
217
|
-
};
|
|
218
|
-
});
|
|
232
|
+
export const mdxProcessor = createMdxProcessor();
|
|
219
233
|
//# sourceMappingURL=parse.js.map
|
package/dist/parse.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAExC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,SAAS,MAAM,YAAY,CAAA;AAClC,OAAO,SAAS,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA,OAAO,iBAAiB,MAAM,oBAAoB,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAExC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,SAAS,MAAM,YAAY,CAAA;AAClC,OAAO,SAAS,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAA;AAE1E,OAAO,EAAE,qBAAqB,EAAE,CAAA;AAkBhC;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,GAAS;IACpC,MAAM,OAAO,GAAgB,EAAE,CAAA;IAE/B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU;YAAE,SAAQ;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,MAAM,CAAA;QAChC,IAAI,CAAC,MAAM;YAAE,SAAQ;QAErB,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAClC,IAAI,SAAS,CAAC,IAAI,KAAK,mBAAmB;gBAAE,SAAQ;YACpD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAA;YACtC,IAAI,OAAO,MAAM,KAAK,QAAQ;gBAAE,SAAQ;YAExC,MAAM,UAAU,GAAyB,EAAE,CAAA;YAC3C,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;gBAC5C,IAAI,IAAI,CAAC,IAAI,KAAK,wBAAwB,EAAE,CAAC;oBACzC,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAA;gBACrF,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;oBACzC,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;wBACpD,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI;wBACpB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;oBACjC,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;gBACtF,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,0BAA0B,EAAE,CAAC;oBAClD,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAA;gBACjF,CAAC;YACL,CAAC;YAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAA;YACxC,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY;IACjC,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,GAAW,CAAA;AAChC,CAAC;AAOD,MAAM,UAAU,kBAAkB,CAAC,EAC/B,aAAa,GAAG,EAAE,MACG,EAAE;IACvB,MAAM,SAAS,GAAG,MAAM,EAAE;SACrB,GAAG,CAAC,SAAS,CAAC;SACd,GAAG,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;SACxC,GAAG,CAAC,SAAS,CAAC,CAAA;IAEnB,KAAK,MAAM,MAAM,IAAI,aAAa,EAAE,CAAC;QACjC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QAChD,CAAC;aAAM,CAAC;YACJ,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACzB,CAAC;IACL,CAAC;IAED,OAAO,SAAS;SACX,GAAG,CAAC,oBAAoB,CAAC;SACzB,GAAG,CAAC,GAAG,EAAE;QACN,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;YAClB,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAA;QACxB,CAAC,CAAA;IACL,CAAC,CAAC,CAAA;AACV,CAAC;AAID;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB;IAChC,OAAO,UAAU,IAAU;QACvB,KAAK,CAAC,IAAI,EAAE,UAAU,IAAI,EAAE,KAAK,EAAE,MAAM;YACrC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAA;YACf,IAAI,GAAG,GAAG,IAAI,CAAA;YACd,IAAI,SAAS,GAAG,KAAK,CAAA;YAErB,IACI,MAAM;gBACN,OAAO,KAAK,KAAK,QAAQ;gBACzB,IAAI,CAAC,IAAI,KAAK,WAAW,EAC3B,CAAC;gBACC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;gBAE9B,OAAO,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;oBAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;oBAC9B,IAAI,CAAC,KAAK;wBAAE,SAAQ;oBAEpB,IACI,KAAK,CAAC,IAAI,KAAK,mBAAmB;wBAClC,KAAK,CAAC,IAAI,KAAK,mBAAmB,EACpC,CAAC;wBACC,SAAS,GAAG,IAAI,CAAA;oBACpB,CAAC;yBAAM,IACH,KAAK,CAAC,IAAI,KAAK,MAAM;wBACrB,kBAAkB,CAAC,KAAK,CAAC,KAAK,EAAE;4BAC5B,KAAK,EAAE,MAAM;4BACb,IAAI,EAAE,IAAI;yBACb,CAAC,KAAK,EAAE,EACX,CAAC;wBACC,SAAS;oBACb,CAAC;yBAAM,CAAC;wBACJ,GAAG,GAAG,KAAK,CAAA;wBACX,MAAK;oBACT,CAAC;gBACL,CAAC;gBAED,IAAI,GAAG,IAAI,SAAS,EAAE,CAAC;oBACnB,MAAM,GAAG,CAAC,CAAC,CAAA;oBAEX,MAAM,WAAW,GAAkB,EAAE,CAAA;oBAErC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;wBAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;wBAC9B,IAAI,CAAC,KAAK;4BAAE,SAAQ;wBAEpB,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;4BACrC,wEAAwE;4BACxE,KAAK,CAAC,IAAI,GAAG,mBAAmB,CAAA;wBACpC,CAAC;wBAED,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;4BACrC,wEAAwE;4BACxE,KAAK,CAAC,IAAI,GAAG,mBAAmB,CAAA;wBACpC,CAAC;wBAED,IACI,KAAK,CAAC,IAAI,KAAK,MAAM;4BACrB,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAC1C,CAAC;4BACC,SAAS;wBACb,CAAC;6BAAM,CAAC;4BACJ,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;wBAC3B,CAAC;oBACL,CAAC;oBAED,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,WAAW,CAAC,CAAA;oBAChD,OAAO,KAAK,CAAA;gBAChB,CAAC;YACL,CAAC;QACL,CAAC,CAAC,CAAA;IACN,CAAC,CAAA;AACL,CAAC;AAED,4EAA4E;AAE5E,sEAAsE;AACtE,MAAM,kBAAkB,GAAG;IACvB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK;IAC/C,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW;CACvD,CAAA;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC7B,MAAc,EACd,OAAe,EACf,UAAoB;IAEpB,IAAI,UAAkB,CAAA;IAEtB,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACzB,sEAAsE;QACtE,UAAU,GAAG,GAAG,GAAG,MAAM,CAAA;IAC7B,CAAC;SAAM,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7D,wCAAwC;QACxC,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QACzC,UAAU,GAAG,MAAM,CAAA;IACvB,CAAC;SAAM,CAAC;QACJ,+DAA+D;QAC/D,OAAO,SAAS,CAAA;IACpB,CAAC;IAED,qBAAqB;IACrB,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;QACnC,MAAM,SAAS,GAAG,UAAU,GAAG,GAAG,CAAA;QAClC,IAAI,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACjC,OAAO,SAAS,CAAA;QACpB,CAAC;IACL,CAAC;IAED,OAAO,SAAS,CAAA;AACpB,CAAC;AAED;;6EAE6E;AAC7E,SAAS,SAAS,CAAC,IAAY,EAAE,QAAgB;IAC7C,iCAAiC;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IACzF,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAEzE,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC1B,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAChB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBACnE,SAAS,CAAC,GAAG,EAAE,CAAA;YACnB,CAAC;iBAAM,CAAC;gBACJ,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACxB,CAAC;QACL,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACtB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACxB,CAAC;IACL,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAClC,OAAO,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,MAAM,CAAA;AAC5D,CAAC;AAKD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EACjC,IAAI,EACJ,KAAK,EACL,OAAO,GAKV;IACG,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,CAAA;IACrC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IAEnC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9B,MAAM,MAAM,GAAiB,EAAE,CAAA;IAE/B,MAAM,OAAO,CAAC,GAAG,CACb,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACtB,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;QAC7D,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAM;QACxC,sCAAsC;QACtC,IAAI,MAAM,CAAC,QAAQ,CAAC;YAAE,OAAM;QAC5B,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAA;IAC7C,CAAC,CAAC,CACL,CAAA;IAED,OAAO,MAAM,CAAA;AACjB,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,kBAAkB,EAAE,CAAA"}
|