comark 0.1.2 → 0.2.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/dist/internal/parse/incremental.js +1 -2
- package/dist/internal/parse/token-processor.js +30 -45
- package/dist/internal/stringify/handlers/hr.d.ts +1 -1
- package/dist/internal/stringify/handlers/hr.js +4 -1
- package/dist/internal/stringify/handlers/html.js +1 -1
- package/dist/internal/stringify/handlers/mdc.js +2 -1
- package/dist/internal/stringify/handlers/pre.js +1 -12
- package/dist/parse.d.ts +17 -0
- package/dist/parse.js +21 -0
- package/dist/plugins/alert.d.ts +2 -2
- package/dist/plugins/alert.js +30 -31
- package/dist/plugins/emoji.d.ts +3 -2
- package/dist/plugins/emoji.js +5 -6
- package/dist/plugins/headings.d.ts +2 -2
- package/dist/plugins/headings.js +3 -2
- package/dist/plugins/highlight.d.ts +4 -5
- package/dist/plugins/highlight.js +32 -14
- package/dist/plugins/json-render.d.ts +53 -0
- package/dist/plugins/json-render.js +99 -0
- package/dist/plugins/math.d.ts +2 -2
- package/dist/plugins/math.js +7 -8
- package/dist/plugins/mermaid.d.ts +2 -2
- package/dist/plugins/mermaid.js +7 -8
- package/dist/plugins/security.d.ts +2 -3
- package/dist/plugins/security.js +3 -2
- package/dist/plugins/summary.d.ts +4 -2
- package/dist/plugins/summary.js +4 -2
- package/dist/plugins/task-list.d.ts +2 -2
- package/dist/plugins/task-list.js +5 -6
- package/dist/plugins/toc.d.ts +3 -2
- package/dist/plugins/toc.js +3 -2
- package/dist/types.d.ts +2 -1
- package/dist/utils/helpers.d.ts +12 -0
- package/dist/utils/helpers.js +23 -0
- package/dist/utils/serialized-task.d.ts +1 -0
- package/dist/utils/serialized-task.js +1 -0
- package/package.json +6 -6
|
@@ -27,8 +27,7 @@ export function extractReusableNodes(markdown, lastOutput) {
|
|
|
27
27
|
return {
|
|
28
28
|
remainingMarkdownStartLine,
|
|
29
29
|
reusedNodes: lastOutput.nodes.slice(0, lastValidNodeIndex + 1),
|
|
30
|
-
remainingMarkdown: '\n'
|
|
31
|
-
+ markdown.split('\n').slice(remainingMarkdownStartLine + 1).join('\n') || '',
|
|
30
|
+
remainingMarkdown: markdown.split('\n').slice(remainingMarkdownStartLine).join('\n') || '',
|
|
32
31
|
};
|
|
33
32
|
}
|
|
34
33
|
return {
|
|
@@ -24,16 +24,22 @@ const INLINE_TAG_MAP = {
|
|
|
24
24
|
* Convert Markdown-It tokens to a Comark tree
|
|
25
25
|
*/
|
|
26
26
|
export function marmdownItTokensToComarkTree(tokens, options = { startLine: 0, preservePositions: false }) {
|
|
27
|
+
const state = {
|
|
28
|
+
headingSlugCounts: new Map(),
|
|
29
|
+
preservePositions: options.preservePositions,
|
|
30
|
+
};
|
|
27
31
|
const nodes = [];
|
|
28
32
|
let i = 0;
|
|
29
33
|
let endLine = options.startLine;
|
|
30
34
|
while (i < tokens.length) {
|
|
31
|
-
const result = processBlockToken(tokens, i, false);
|
|
35
|
+
const result = processBlockToken(tokens, i, false, state);
|
|
32
36
|
if (result.node) {
|
|
33
37
|
if (options.preservePositions) {
|
|
34
38
|
for (let j = i; j < result.nextIndex; j++) {
|
|
35
39
|
if (tokens[j].map && tokens[j].map[1]) {
|
|
36
|
-
endLine = tokens[j].map[1]
|
|
40
|
+
endLine = tokens[j].map[1]
|
|
41
|
+
+ options.startLine
|
|
42
|
+
+ (tokens[j].type?.endsWith('_close') ? 1 : 0);
|
|
37
43
|
}
|
|
38
44
|
}
|
|
39
45
|
if (!result.node[1].$) {
|
|
@@ -207,7 +213,7 @@ function extractAttributes(tokens, startIndex, skipEmptyText = true) {
|
|
|
207
213
|
}
|
|
208
214
|
return { attrs: {}, nextIndex: startIndex };
|
|
209
215
|
}
|
|
210
|
-
function processBlockToken(tokens, startIndex, insideNestedContext = false) {
|
|
216
|
+
function processBlockToken(tokens, startIndex, insideNestedContext = false, state) {
|
|
211
217
|
const token = tokens[startIndex];
|
|
212
218
|
if (token.type === 'hr') {
|
|
213
219
|
return { node: ['hr', {}], nextIndex: startIndex + 1 };
|
|
@@ -221,7 +227,7 @@ function processBlockToken(tokens, startIndex, insideNestedContext = false) {
|
|
|
221
227
|
const inner = content.endsWith('-->') ? content.slice(4, -3) : content.slice(4);
|
|
222
228
|
return { node: [null, {}, inner], nextIndex: startIndex + 1 };
|
|
223
229
|
}
|
|
224
|
-
const children = processBlockChildren(tokens, startIndex + 1, 'html_block_close', false, false, false);
|
|
230
|
+
const children = processBlockChildren(tokens, startIndex + 1, 'html_block_close', false, false, false, state);
|
|
225
231
|
const [node1] = htmlToComarkNodes(content);
|
|
226
232
|
if (!node1) {
|
|
227
233
|
return { node: null, nextIndex: startIndex + 1 };
|
|
@@ -234,7 +240,7 @@ function processBlockToken(tokens, startIndex, insideNestedContext = false) {
|
|
|
234
240
|
const componentName = token.tag || 'component';
|
|
235
241
|
const attrs = processAttributes(token.attrs);
|
|
236
242
|
// Process children until mdc_block_close, handling slots (#slotname)
|
|
237
|
-
const children = processBlockChildrenWithSlots(tokens, startIndex + 1, 'mdc_block_close');
|
|
243
|
+
const children = processBlockChildrenWithSlots(tokens, startIndex + 1, 'mdc_block_close', state);
|
|
238
244
|
// Return the component even if it has no children (empty component like ::component\n::)
|
|
239
245
|
return { node: [componentName, attrs, ...children.nodes], nextIndex: children.nextIndex + 1 };
|
|
240
246
|
}
|
|
@@ -299,11 +305,11 @@ function processBlockToken(tokens, startIndex, insideNestedContext = false) {
|
|
|
299
305
|
const level = token.tag.replace('h', '');
|
|
300
306
|
const headingTag = `h${level}`;
|
|
301
307
|
// Process heading children with inHeading flag for Comark component handling
|
|
302
|
-
const children = processBlockChildren(tokens, startIndex + 1, 'heading_close', true, true, insideNestedContext);
|
|
308
|
+
const children = processBlockChildren(tokens, startIndex + 1, 'heading_close', true, true, insideNestedContext, state);
|
|
303
309
|
if (children.nodes.length > 0) {
|
|
304
310
|
// Always generate ID for all headings, no exceptions
|
|
305
311
|
const textContent = extractTextContent(children.nodes);
|
|
306
|
-
const headingId = slugify(textContent);
|
|
312
|
+
const headingId = uniqueSlug(slugify(textContent), state);
|
|
307
313
|
// Always attach ID to the heading element itself
|
|
308
314
|
return { node: [headingTag, { id: headingId }, ...children.nodes], nextIndex: children.nextIndex + 1 };
|
|
309
315
|
}
|
|
@@ -312,7 +318,7 @@ function processBlockToken(tokens, startIndex, insideNestedContext = false) {
|
|
|
312
318
|
// Handle list items - paragraphs should be unwrapped
|
|
313
319
|
if (token.type === 'list_item_open') {
|
|
314
320
|
const attrs = processAttributes(token.attrs, { handleBoolean: false, handleJSON: false });
|
|
315
|
-
const children = processBlockChildren(tokens, startIndex + 1, 'list_item_close', false, false, true);
|
|
321
|
+
const children = processBlockChildren(tokens, startIndex + 1, 'list_item_close', false, false, true, state);
|
|
316
322
|
// Unwrap paragraphs in list items
|
|
317
323
|
const unwrapped = [];
|
|
318
324
|
for (const child of children.nodes) {
|
|
@@ -334,46 +340,15 @@ function processBlockToken(tokens, startIndex, insideNestedContext = false) {
|
|
|
334
340
|
if (tagName) {
|
|
335
341
|
const attrs = processAttributes(token.attrs, { handleBoolean: false, handleJSON: false });
|
|
336
342
|
const closeType = token.type.replace('_open', '_close');
|
|
337
|
-
// Special handling for blockquotes
|
|
338
|
-
if (tagName === 'blockquote') {
|
|
339
|
-
// First pass: get children
|
|
340
|
-
const children = processBlockChildren(tokens, startIndex + 1, closeType, false, false, false);
|
|
341
|
-
// Rule: If a heading is the FIRST child AND there are additional children after it,
|
|
342
|
-
// then the heading should NOT have an ID. Otherwise, headings should have IDs.
|
|
343
|
-
if (children.nodes.length > 1) {
|
|
344
|
-
const firstChild = children.nodes[0];
|
|
345
|
-
// Check if first child is a heading (h1-h6)
|
|
346
|
-
const isHeading = Array.isArray(firstChild)
|
|
347
|
-
&& typeof firstChild[0] === 'string'
|
|
348
|
-
&& /^h[1-6]$/.test(firstChild[0]);
|
|
349
|
-
if (isHeading) {
|
|
350
|
-
// Heading is first child with more siblings - reprocess without IDs
|
|
351
|
-
const childrenNoIds = processBlockChildren(tokens, startIndex + 1, closeType, false, false, true);
|
|
352
|
-
if (childrenNoIds.nodes.length > 0) {
|
|
353
|
-
return { node: [tagName, attrs, ...childrenNoIds.nodes], nextIndex: childrenNoIds.nextIndex + 1 };
|
|
354
|
-
}
|
|
355
|
-
return { node: null, nextIndex: childrenNoIds.nextIndex + 1 };
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
// All other cases: use original processing (allows IDs)
|
|
359
|
-
if (children.nodes.length > 0) {
|
|
360
|
-
return { node: [tagName, attrs, ...children.nodes], nextIndex: children.nextIndex + 1 };
|
|
361
|
-
}
|
|
362
|
-
return { node: null, nextIndex: children.nextIndex + 1 };
|
|
363
|
-
}
|
|
364
|
-
// For other elements (tables, etc.)
|
|
365
343
|
const isNestedContext = ['td', 'th'].includes(tagName);
|
|
366
|
-
const children = processBlockChildren(tokens, startIndex + 1, closeType, false, false, isNestedContext);
|
|
367
|
-
|
|
368
|
-
return { node: [tagName, attrs, ...children.nodes], nextIndex: children.nextIndex + 1 };
|
|
369
|
-
}
|
|
370
|
-
return { node: null, nextIndex: children.nextIndex + 1 };
|
|
344
|
+
const children = processBlockChildren(tokens, startIndex + 1, closeType, false, false, isNestedContext, state);
|
|
345
|
+
return { node: [tagName, attrs, ...children.nodes], nextIndex: children.nextIndex + 1 };
|
|
371
346
|
}
|
|
372
347
|
const componentName = token.tag || 'component';
|
|
373
348
|
const attrs = processAttributes(token.attrs, { handleBoolean: false, handleJSON: false });
|
|
374
349
|
return { node: [componentName, attrs], nextIndex: startIndex + 1 };
|
|
375
350
|
}
|
|
376
|
-
function processBlockChildrenWithSlots(tokens, startIndex, closeType) {
|
|
351
|
+
function processBlockChildrenWithSlots(tokens, startIndex, closeType, state) {
|
|
377
352
|
const nodes = [];
|
|
378
353
|
let i = startIndex;
|
|
379
354
|
let currentSlotName = null;
|
|
@@ -420,7 +395,7 @@ function processBlockChildrenWithSlots(tokens, startIndex, closeType) {
|
|
|
420
395
|
}
|
|
421
396
|
// Process other block tokens
|
|
422
397
|
// Comark components are not nested contexts - headings inside them should get IDs
|
|
423
|
-
const result = processBlockToken(tokens, i, false);
|
|
398
|
+
const result = processBlockToken(tokens, i, false, state);
|
|
424
399
|
i = result.nextIndex;
|
|
425
400
|
if (result.node) {
|
|
426
401
|
if (currentSlotName !== null) {
|
|
@@ -439,7 +414,7 @@ function processBlockChildrenWithSlots(tokens, startIndex, closeType) {
|
|
|
439
414
|
}
|
|
440
415
|
return { nodes, nextIndex: i };
|
|
441
416
|
}
|
|
442
|
-
function processBlockChildren(tokens, startIndex, closeType, inlineOnly, inHeading = false, insideNestedContext = false) {
|
|
417
|
+
function processBlockChildren(tokens, startIndex, closeType, inlineOnly, inHeading = false, insideNestedContext = false, state) {
|
|
443
418
|
const nodes = [];
|
|
444
419
|
let i = startIndex;
|
|
445
420
|
while (i < tokens.length && tokens[i].type !== closeType) {
|
|
@@ -471,7 +446,7 @@ function processBlockChildren(tokens, startIndex, closeType, inlineOnly, inHeadi
|
|
|
471
446
|
i++;
|
|
472
447
|
}
|
|
473
448
|
else {
|
|
474
|
-
const result = processBlockToken(tokens, i, insideNestedContext);
|
|
449
|
+
const result = processBlockToken(tokens, i, insideNestedContext, state);
|
|
475
450
|
i = result.nextIndex;
|
|
476
451
|
if (result.node) {
|
|
477
452
|
nodes.push(result.node);
|
|
@@ -544,6 +519,16 @@ function slugify(text) {
|
|
|
544
519
|
}
|
|
545
520
|
return slug;
|
|
546
521
|
}
|
|
522
|
+
/**
|
|
523
|
+
* Return a unique slug by appending a numeric suffix for duplicates
|
|
524
|
+
*/
|
|
525
|
+
function uniqueSlug(slug, state) {
|
|
526
|
+
if (!state)
|
|
527
|
+
return slug;
|
|
528
|
+
const count = state.headingSlugCounts.get(slug) ?? 0;
|
|
529
|
+
state.headingSlugCounts.set(slug, count + 1);
|
|
530
|
+
return count === 0 ? slug : `${slug}-${count}`;
|
|
531
|
+
}
|
|
547
532
|
export function processInlineTokens(tokens, inHeading = false) {
|
|
548
533
|
const nodes = [];
|
|
549
534
|
let i = 0;
|
|
@@ -37,7 +37,7 @@ export async function html(node, state, parent) {
|
|
|
37
37
|
for (let i = 0; i < children.length; i++) {
|
|
38
38
|
const childContent = childrenContent[i];
|
|
39
39
|
const child = children[i];
|
|
40
|
-
const isBlock = blockTags.has(String(child?.[0])) || (!inlineTags.has(String(child?.[0])) && !hasTextSibling);
|
|
40
|
+
const isBlock = typeof child !== 'string' && (blockTags.has(String(child?.[0])) || (!inlineTags.has(String(child?.[0])) && !hasTextSibling));
|
|
41
41
|
if (i > 0 && !isPrevBlock && isBlock) {
|
|
42
42
|
content += state.context.blockSeparator;
|
|
43
43
|
}
|
|
@@ -28,7 +28,8 @@ export async function mdc(node, state, parent) {
|
|
|
28
28
|
content = content.trimEnd();
|
|
29
29
|
const attrs = attributeEntries.length > 0 ? comarkAttributes(attributes) : '';
|
|
30
30
|
if (tag === 'span') {
|
|
31
|
-
return `[${content}]${attrs}
|
|
31
|
+
return `[${content}]${attrs}`
|
|
32
|
+
+ (inline ? '' : state.context.blockSeparator);
|
|
32
33
|
}
|
|
33
34
|
const fence = ':'.repeat((state.nodeDepthInTree || 0) + 2);
|
|
34
35
|
let result = `:${tag}${content && `[${content}]`}${attrs}` + (!parent ? state.context.blockSeparator : '');
|
|
@@ -15,21 +15,10 @@ export function pre(node, state) {
|
|
|
15
15
|
? ' ' + attributes.meta
|
|
16
16
|
: '';
|
|
17
17
|
const result = '```' + language + filename + highlights + meta + '\n'
|
|
18
|
-
+ String(node[1]?.code ||
|
|
18
|
+
+ String(node[1]?.code || textContent(node)).trim()
|
|
19
19
|
+ '\n```';
|
|
20
20
|
return result + state.context.blockSeparator;
|
|
21
21
|
}
|
|
22
|
-
function extractCode(node) {
|
|
23
|
-
const codeNode = node[2];
|
|
24
|
-
if (Array.isArray(codeNode) && codeNode[0] === 'code') {
|
|
25
|
-
const spans = codeNode.slice(2);
|
|
26
|
-
const lineSpans = spans.filter(s => Array.isArray(s) && String(s[1]?.class ?? '').includes('line'));
|
|
27
|
-
if (lineSpans.length > 0) {
|
|
28
|
-
return lineSpans.map(span => textContent(span)).join('\n');
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return textContent(node);
|
|
32
|
-
}
|
|
33
22
|
function formatHighlights(highlights) {
|
|
34
23
|
if (highlights.length === 0)
|
|
35
24
|
return '';
|
package/dist/parse.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ComarkParseFn, ParseOptions, ComarkTree } from './types.ts';
|
|
2
2
|
export { parseFrontmatter } from './internal/frontmatter.ts';
|
|
3
|
+
export { defineComarkPlugin } from './utils/helpers.ts';
|
|
3
4
|
/**
|
|
4
5
|
* Creates a parser function for Comark content.
|
|
5
6
|
*
|
|
@@ -64,3 +65,19 @@ export declare function createParse(options?: ParseOptions): ComarkParseFn;
|
|
|
64
65
|
* ```
|
|
65
66
|
*/
|
|
66
67
|
export declare function parse(markdown: string, options?: ParseOptions): Promise<ComarkTree>;
|
|
68
|
+
/**
|
|
69
|
+
* Creates a serialized parser function for Comark content.
|
|
70
|
+
* This is useful for parsing large files in a streaming manner.
|
|
71
|
+
*
|
|
72
|
+
* @param options - Parser options
|
|
73
|
+
* @returns ComarkParseFn - The serialized parser function
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* import { createSerializedParse } from 'comark'
|
|
78
|
+
*
|
|
79
|
+
* const parse = createSerializedParse()
|
|
80
|
+
* const tree = await parse(content)
|
|
81
|
+
* console.log(tree.nodes)
|
|
82
|
+
*/
|
|
83
|
+
export declare function createSerializedParse(options?: ParseOptions): ComarkParseFn;
|
package/dist/parse.js
CHANGED
|
@@ -9,8 +9,11 @@ import { parseFrontmatter } from "./internal/frontmatter.js";
|
|
|
9
9
|
import { extractReusableNodes } from "./internal/parse/incremental.js";
|
|
10
10
|
import html_block from "./internal/parse/html/html_block_rule.js";
|
|
11
11
|
import html_inline from "./internal/parse/html/html_inline_rule.js";
|
|
12
|
+
import { createSerializedTask } from "./utils/helpers.js";
|
|
12
13
|
// Re-export frontmatter utilities
|
|
13
14
|
export { parseFrontmatter } from "./internal/frontmatter.js";
|
|
15
|
+
// Re-export plugin utilities
|
|
16
|
+
export { defineComarkPlugin } from "./utils/helpers.js";
|
|
14
17
|
/**
|
|
15
18
|
* Creates a parser function for Comark content.
|
|
16
19
|
*
|
|
@@ -161,3 +164,21 @@ export async function parse(markdown, options = {}) {
|
|
|
161
164
|
const parse = createParse(options);
|
|
162
165
|
return await parse(markdown);
|
|
163
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Creates a serialized parser function for Comark content.
|
|
169
|
+
* This is useful for parsing large files in a streaming manner.
|
|
170
|
+
*
|
|
171
|
+
* @param options - Parser options
|
|
172
|
+
* @returns ComarkParseFn - The serialized parser function
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* import { createSerializedParse } from 'comark'
|
|
177
|
+
*
|
|
178
|
+
* const parse = createSerializedParse()
|
|
179
|
+
* const tree = await parse(content)
|
|
180
|
+
* console.log(tree.nodes)
|
|
181
|
+
*/
|
|
182
|
+
export function createSerializedParse(options = {}) {
|
|
183
|
+
return createSerializedTask(createParse(options));
|
|
184
|
+
}
|
package/dist/plugins/alert.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export default
|
|
1
|
+
declare const _default: import("comark").ComarkPluginFactory<unknown>;
|
|
2
|
+
export default _default;
|
package/dist/plugins/alert.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { visit } from 'comark/utils';
|
|
2
|
+
import { defineComarkPlugin } from "../utils/helpers.js";
|
|
2
3
|
const markers = {
|
|
3
4
|
'!TIP': {
|
|
4
5
|
type: 'tip',
|
|
@@ -26,41 +27,39 @@ const markers = {
|
|
|
26
27
|
color: '#da3633',
|
|
27
28
|
},
|
|
28
29
|
};
|
|
29
|
-
export default
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
export default defineComarkPlugin(() => ({
|
|
31
|
+
name: 'alert',
|
|
32
|
+
post(state) {
|
|
33
|
+
visit(state.tree, node => Array.isArray(node) && node[0] === 'blockquote', (node) => {
|
|
34
|
+
const element = node;
|
|
35
|
+
if (node[2]?.[0] === 'span') {
|
|
36
|
+
const content = String(node[2][2]).toUpperCase();
|
|
37
|
+
const marker = markers[content];
|
|
38
|
+
if (marker) {
|
|
39
|
+
if (typeof node[3] === 'string') {
|
|
40
|
+
element[3] = String(element[3]).trimStart();
|
|
41
|
+
}
|
|
42
|
+
// remove span node
|
|
43
|
+
element.splice(2, 1);
|
|
44
|
+
element[1].as = marker.type;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else if (node[2]?.[0] === 'p') {
|
|
48
|
+
const paragraph = node[2];
|
|
49
|
+
if (paragraph[2]?.[0] === 'span') {
|
|
50
|
+
const content = String(paragraph[2][2]).toUpperCase();
|
|
37
51
|
const marker = markers[content];
|
|
38
52
|
if (marker) {
|
|
39
|
-
if (typeof
|
|
40
|
-
|
|
53
|
+
if (typeof paragraph[3] === 'string') {
|
|
54
|
+
paragraph[3] = String(paragraph[3]).trimStart();
|
|
41
55
|
}
|
|
42
56
|
// remove span node
|
|
43
|
-
|
|
57
|
+
paragraph.splice(2, 1);
|
|
58
|
+
// transform node
|
|
44
59
|
element[1].as = marker.type;
|
|
45
60
|
}
|
|
46
61
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const marker = markers[content];
|
|
52
|
-
if (marker) {
|
|
53
|
-
if (typeof paragraph[3] === 'string') {
|
|
54
|
-
paragraph[3] = String(paragraph[3]).trimStart();
|
|
55
|
-
}
|
|
56
|
-
// remove span node
|
|
57
|
-
paragraph.splice(2, 1);
|
|
58
|
-
// transform node
|
|
59
|
-
element[1].as = marker.type;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
}));
|
package/dist/plugins/emoji.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MarkdownItPlugin } from 'comark';
|
|
2
2
|
export declare const markdownItEmoji: MarkdownItPlugin;
|
|
3
|
-
|
|
3
|
+
declare const _default: import("comark").ComarkPluginFactory<unknown>;
|
|
4
|
+
export default _default;
|
package/dist/plugins/emoji.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defineComarkPlugin } from "../utils/helpers.js";
|
|
1
2
|
// Common emoji definitions (200+ emojis)
|
|
2
3
|
// Organized by category for easier maintenance
|
|
3
4
|
const EMOJI_MAP = new Map([
|
|
@@ -430,9 +431,7 @@ const emojiRule = (state, silent) => {
|
|
|
430
431
|
export const markdownItEmoji = (md) => {
|
|
431
432
|
md.inline.ruler.before('emphasis', 'emoji', emojiRule);
|
|
432
433
|
};
|
|
433
|
-
export default
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
};
|
|
438
|
-
}
|
|
434
|
+
export default defineComarkPlugin(() => ({
|
|
435
|
+
name: 'emoji',
|
|
436
|
+
markdownItPlugins: [markdownItEmoji],
|
|
437
|
+
}));
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ComarkPlugin } from 'comark';
|
|
2
1
|
export interface HeadingsOptions {
|
|
3
2
|
/**
|
|
4
3
|
* Tag to extract as title and set to `tree.meta.title`.
|
|
@@ -45,4 +44,5 @@ export interface HeadingsOptions {
|
|
|
45
44
|
* headings({ remove: false })
|
|
46
45
|
* ```
|
|
47
46
|
*/
|
|
48
|
-
|
|
47
|
+
declare const _default: import("comark").ComarkPluginFactory<HeadingsOptions>;
|
|
48
|
+
export default _default;
|
package/dist/plugins/headings.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defineComarkPlugin } from "../utils/helpers.js";
|
|
1
2
|
function getTag(node) {
|
|
2
3
|
if (Array.isArray(node) && node.length >= 1) {
|
|
3
4
|
return node[0];
|
|
@@ -49,7 +50,7 @@ function flattenNodeText(node) {
|
|
|
49
50
|
* headings({ remove: false })
|
|
50
51
|
* ```
|
|
51
52
|
*/
|
|
52
|
-
export default
|
|
53
|
+
export default defineComarkPlugin((options = {}) => {
|
|
53
54
|
const { titleTag = 'h1', descriptionTag = 'p', remove = false } = options;
|
|
54
55
|
return {
|
|
55
56
|
name: 'headings',
|
|
@@ -82,4 +83,4 @@ export default function headings(options = {}) {
|
|
|
82
83
|
}
|
|
83
84
|
},
|
|
84
85
|
};
|
|
85
|
-
}
|
|
86
|
+
});
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import type { LanguageRegistration } from 'shiki';
|
|
2
|
-
import type { ComarkNode, ComarkTree
|
|
3
|
-
import type { ShikiPrimitive, ThemeRegistration } from '@shikijs/primitive';
|
|
4
|
-
import type { ShikiTransformer } from '@shikijs/types';
|
|
1
|
+
import type { LanguageRegistration, ShikiTransformer, ShikiPrimitive, ThemeRegistration } from 'shiki';
|
|
2
|
+
import type { ComarkNode, ComarkTree } from 'comark';
|
|
5
3
|
export interface HighlightOptions {
|
|
6
4
|
/**
|
|
7
5
|
* Whether to use the default language definitions
|
|
@@ -68,4 +66,5 @@ export declare function highlightCodeBlocks(tree: ComarkTree, options?: Highligh
|
|
|
68
66
|
* Useful for testing or when you want to reconfigure
|
|
69
67
|
*/
|
|
70
68
|
export declare function resetHighlighter(): void;
|
|
71
|
-
|
|
69
|
+
declare const _default: import("comark").ComarkPluginFactory<HighlightOptions>;
|
|
70
|
+
export default _default;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { defineComarkPlugin } from "../utils/helpers.js";
|
|
2
|
+
import { createShikiPrimitive } from 'shiki';
|
|
2
3
|
import { createJavaScriptRegexEngine } from 'shiki/engine/javascript';
|
|
3
4
|
import { codeToHast } from 'shiki/core';
|
|
4
5
|
let highlighter = null;
|
|
@@ -23,7 +24,7 @@ export async function getHighlighter(options = {}) {
|
|
|
23
24
|
try {
|
|
24
25
|
highlighterPromise = (async () => {
|
|
25
26
|
const { themes, languages } = await registerDefaults(options);
|
|
26
|
-
const hl = createShikiPrimitive({
|
|
27
|
+
const hl = await createShikiPrimitive({
|
|
27
28
|
themes: themes,
|
|
28
29
|
langs: languages,
|
|
29
30
|
langAlias: {
|
|
@@ -51,10 +52,10 @@ async function registerDefaults(options) {
|
|
|
51
52
|
const languages = options.languages || [];
|
|
52
53
|
const promises = [];
|
|
53
54
|
if (options.registerDefaultThemes !== false) {
|
|
54
|
-
promises.push(import('
|
|
55
|
+
promises.push(import('shiki/dist/themes/material-theme-lighter.mjs').then(m => ({ type: 'theme', value: m.default })), import('shiki/dist/themes/material-theme-palenight.mjs').then(m => ({ type: 'theme', value: m.default })));
|
|
55
56
|
}
|
|
56
57
|
if (options.registerDefaultLanguages !== false) {
|
|
57
|
-
promises.push(import('
|
|
58
|
+
promises.push(import('shiki/dist/langs/vue.mjs').then(m => ({ type: 'lang', value: m.default })), import('shiki/dist/langs/tsx.mjs').then(m => ({ type: 'lang', value: m.default })), import('shiki/dist/langs/svelte.mjs').then(m => ({ type: 'lang', value: m.default })), import('shiki/dist/langs/typescript.mjs').then(m => ({ type: 'lang', value: m.default })), import('shiki/dist/langs/javascript.mjs').then(m => ({ type: 'lang', value: m.default })), import('shiki/dist/langs/mdc.mjs').then(m => ({ type: 'lang', value: m.default })), import('shiki/dist/langs/bash.mjs').then(m => ({ type: 'lang', value: m.default })), import('shiki/dist/langs/json.mjs').then(m => ({ type: 'lang', value: m.default })), import('shiki/dist/langs/yaml.mjs').then(m => ({ type: 'lang', value: m.default })), import('shiki/dist/langs/astro.mjs').then(m => ({ type: 'lang', value: m.default })));
|
|
58
59
|
}
|
|
59
60
|
const results = await Promise.all(promises);
|
|
60
61
|
for (const result of results) {
|
|
@@ -163,6 +164,7 @@ export async function highlightCodeBlocks(tree, options = {}) {
|
|
|
163
164
|
const newNodes = JSON.parse(JSON.stringify(tree.nodes));
|
|
164
165
|
for (let i = 0; i < codeBlocks.length; i++) {
|
|
165
166
|
const { node, path } = codeBlocks[i];
|
|
167
|
+
const preAttrs = node[1];
|
|
166
168
|
const result = highlightedResults[i];
|
|
167
169
|
const preNode = result.nodes[0];
|
|
168
170
|
const preNodeClasses = typeof preNode === 'string'
|
|
@@ -171,8 +173,26 @@ export async function highlightCodeBlocks(tree, options = {}) {
|
|
|
171
173
|
? preNode[1].class
|
|
172
174
|
: String(preNode[1].class).split(' '));
|
|
173
175
|
const codeChildren = preNode[2].slice(2);
|
|
174
|
-
const children = typeof preNode === 'string'
|
|
175
|
-
|
|
176
|
+
const children = typeof preNode === 'string'
|
|
177
|
+
? preNode
|
|
178
|
+
: codeChildren;
|
|
179
|
+
if (Array.isArray(children)) {
|
|
180
|
+
let line = 1;
|
|
181
|
+
for (const child of children) {
|
|
182
|
+
if (Array.isArray(child)) {
|
|
183
|
+
if (Array.isArray(preAttrs.highlights) && preAttrs.highlights.includes(line)) {
|
|
184
|
+
child[1].class = `${child[1].class ?? ''} highlight`.trim();
|
|
185
|
+
// TODO: (enforcing default style) once we unify all ecosystem styles we can remove this
|
|
186
|
+
child[1].style = 'display: inline-block';
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
// TODO: (enforcing default style) once we unify all ecosystem styles we can remove this
|
|
190
|
+
child[1].style = 'display: inline';
|
|
191
|
+
}
|
|
192
|
+
line += 1;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
176
196
|
const newPreAttrs = {
|
|
177
197
|
...preAttrs,
|
|
178
198
|
class: [...preNodeClasses, options.themes?.dark?.name ? `dark:${options.themes?.dark?.name}` : ''].filter(Boolean).join(' '),
|
|
@@ -224,11 +244,9 @@ export function resetHighlighter() {
|
|
|
224
244
|
highlighterPromise = null;
|
|
225
245
|
loadedThemes.clear();
|
|
226
246
|
}
|
|
227
|
-
export default
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
};
|
|
234
|
-
}
|
|
247
|
+
export default defineComarkPlugin((options = {}) => ({
|
|
248
|
+
name: 'highlight',
|
|
249
|
+
async post(state) {
|
|
250
|
+
state.tree = await highlightCodeBlocks(state.tree, options);
|
|
251
|
+
},
|
|
252
|
+
}));
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
interface JsonRenderConfig {
|
|
2
|
+
}
|
|
3
|
+
/**
|
|
4
|
+
* Plugin for rendering [JSON Render](https://json-render.dev/) specs as UI components.
|
|
5
|
+
*
|
|
6
|
+
* Transforms `json-render` fenced code blocks into Comark AST nodes at parse time.
|
|
7
|
+
* Supports both full specs (with `root` and `elements`) and single-element shorthand.
|
|
8
|
+
*
|
|
9
|
+
* @param config - Plugin configuration options
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { parse } from 'comark'
|
|
14
|
+
* import jsonRender from 'comark/plugins/json-render'
|
|
15
|
+
*
|
|
16
|
+
* const result = await parse(`
|
|
17
|
+
* \`\`\`json-render
|
|
18
|
+
* {
|
|
19
|
+
* "root": "card",
|
|
20
|
+
* "elements": {
|
|
21
|
+
* "card": {
|
|
22
|
+
* "type": "Card",
|
|
23
|
+
* "props": { "title": "Hello" },
|
|
24
|
+
* "children": ["text"]
|
|
25
|
+
* },
|
|
26
|
+
* "text": {
|
|
27
|
+
* "type": "Text",
|
|
28
|
+
* "props": { "content": "World" }
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
* \`\`\`
|
|
33
|
+
* `, {
|
|
34
|
+
* plugins: [jsonRender()]
|
|
35
|
+
* })
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```vue
|
|
40
|
+
* <script setup>
|
|
41
|
+
* import { Comark } from '@comark/vue'
|
|
42
|
+
* import jsonRender from '@comark/vue/plugins/json-render'
|
|
43
|
+
* </script>
|
|
44
|
+
*
|
|
45
|
+
* <template>
|
|
46
|
+
* <Suspense>
|
|
47
|
+
* <Comark :plugins="[jsonRender()]">{{ content }}</Comark>
|
|
48
|
+
* </Suspense>
|
|
49
|
+
* </template>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare const _default: import("..").ComarkPluginFactory<JsonRenderConfig>;
|
|
53
|
+
export default _default;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { defineComarkPlugin } from '../parse';
|
|
2
|
+
import { textContent, visit } from '../utils';
|
|
3
|
+
import { parseYaml } from '../internal/yaml';
|
|
4
|
+
function jsonRenderToAst(jrt) {
|
|
5
|
+
if (!jrt.root) {
|
|
6
|
+
jrt = {
|
|
7
|
+
root: 'template',
|
|
8
|
+
elements: { template: jrt },
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
const tree = jrt;
|
|
12
|
+
const root = tree.elements[tree.root];
|
|
13
|
+
return jsonRenderElementToAst(root, tree.elements);
|
|
14
|
+
}
|
|
15
|
+
function jsonRenderElementToAst(element, elements) {
|
|
16
|
+
if (element.type === 'Text') {
|
|
17
|
+
return String(element.props.content);
|
|
18
|
+
}
|
|
19
|
+
const children = element.children?.map(childName => elements[childName])
|
|
20
|
+
.filter(Boolean) || [];
|
|
21
|
+
return [
|
|
22
|
+
element.type,
|
|
23
|
+
element.props,
|
|
24
|
+
...children.map(child => jsonRenderElementToAst(child, elements)),
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Plugin for rendering [JSON Render](https://json-render.dev/) specs as UI components.
|
|
29
|
+
*
|
|
30
|
+
* Transforms `json-render` fenced code blocks into Comark AST nodes at parse time.
|
|
31
|
+
* Supports both full specs (with `root` and `elements`) and single-element shorthand.
|
|
32
|
+
*
|
|
33
|
+
* @param config - Plugin configuration options
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { parse } from 'comark'
|
|
38
|
+
* import jsonRender from 'comark/plugins/json-render'
|
|
39
|
+
*
|
|
40
|
+
* const result = await parse(`
|
|
41
|
+
* \`\`\`json-render
|
|
42
|
+
* {
|
|
43
|
+
* "root": "card",
|
|
44
|
+
* "elements": {
|
|
45
|
+
* "card": {
|
|
46
|
+
* "type": "Card",
|
|
47
|
+
* "props": { "title": "Hello" },
|
|
48
|
+
* "children": ["text"]
|
|
49
|
+
* },
|
|
50
|
+
* "text": {
|
|
51
|
+
* "type": "Text",
|
|
52
|
+
* "props": { "content": "World" }
|
|
53
|
+
* }
|
|
54
|
+
* }
|
|
55
|
+
* }
|
|
56
|
+
* \`\`\`
|
|
57
|
+
* `, {
|
|
58
|
+
* plugins: [jsonRender()]
|
|
59
|
+
* })
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```vue
|
|
64
|
+
* <script setup>
|
|
65
|
+
* import { Comark } from '@comark/vue'
|
|
66
|
+
* import jsonRender from '@comark/vue/plugins/json-render'
|
|
67
|
+
* </script>
|
|
68
|
+
*
|
|
69
|
+
* <template>
|
|
70
|
+
* <Suspense>
|
|
71
|
+
* <Comark :plugins="[jsonRender()]">{{ content }}</Comark>
|
|
72
|
+
* </Suspense>
|
|
73
|
+
* </template>
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export default defineComarkPlugin((_config = {}) => ({
|
|
77
|
+
name: 'json-render',
|
|
78
|
+
post: async (state) => {
|
|
79
|
+
visit(state.tree, node => node[0] === 'pre' && (node[1].language === 'json-render'
|
|
80
|
+
|| node[1].language === 'yaml-render'), (preNode) => {
|
|
81
|
+
const language = preNode[1].language;
|
|
82
|
+
try {
|
|
83
|
+
let spec = undefined;
|
|
84
|
+
if (language === 'json-render') {
|
|
85
|
+
spec = JSON.parse(textContent(preNode));
|
|
86
|
+
}
|
|
87
|
+
else if (language === 'yaml-render') {
|
|
88
|
+
spec = parseYaml(textContent(preNode));
|
|
89
|
+
}
|
|
90
|
+
if (spec) {
|
|
91
|
+
return jsonRenderToAst(spec);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// nothing to do
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
}));
|
package/dist/plugins/math.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ComarkPlugin } from 'comark';
|
|
2
1
|
export interface MathConfig {
|
|
3
2
|
/**
|
|
4
3
|
* Throw on parse errors or return error message
|
|
@@ -56,4 +55,5 @@ export declare function validateMath(code: string): boolean;
|
|
|
56
55
|
* })
|
|
57
56
|
* ```
|
|
58
57
|
*/
|
|
59
|
-
|
|
58
|
+
declare const _default: import("comark").ComarkPluginFactory<MathConfig>;
|
|
59
|
+
export default _default;
|
package/dist/plugins/math.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import katex from 'katex';
|
|
2
|
+
import { defineComarkPlugin } from "../utils/helpers.js";
|
|
2
3
|
/**
|
|
3
4
|
* Render LaTeX math expression to HTML using KaTeX
|
|
4
5
|
*
|
|
@@ -253,11 +254,9 @@ function markdownItMath(md, config = {}) {
|
|
|
253
254
|
* })
|
|
254
255
|
* ```
|
|
255
256
|
*/
|
|
256
|
-
export default
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
};
|
|
263
|
-
}
|
|
257
|
+
export default defineComarkPlugin((config = {}) => ({
|
|
258
|
+
name: 'math',
|
|
259
|
+
markdownItPlugins: [
|
|
260
|
+
((md) => markdownItMath(md, config)),
|
|
261
|
+
],
|
|
262
|
+
}));
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ComarkPlugin } from 'comark';
|
|
2
1
|
export type ThemeNames = 'zinc-light' | 'zinc-dark' | 'tokyo-night' | 'tokyo-night-storm' | 'tokyo-night-light' | 'catppuccin-mocha' | 'catppuccin-latte' | 'nord' | 'nord-light' | 'dracula' | 'github-light' | 'github-dark' | 'solarized-light' | 'solarized-dark' | 'one-dark';
|
|
3
2
|
export interface MermaidConfig {
|
|
4
3
|
/**
|
|
@@ -35,4 +34,5 @@ export declare function searchProps(content: string, index?: number): {
|
|
|
35
34
|
* })
|
|
36
35
|
* ```
|
|
37
36
|
*/
|
|
38
|
-
|
|
37
|
+
declare const _default: import("comark").ComarkPluginFactory<MermaidConfig>;
|
|
38
|
+
export default _default;
|
package/dist/plugins/mermaid.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defineComarkPlugin } from "../utils/helpers.js";
|
|
1
2
|
/**
|
|
2
3
|
* markdown-it plugin for mermaid diagrams
|
|
3
4
|
* This handles ```mermaid code blocks
|
|
@@ -175,11 +176,9 @@ export function searchProps(content, index = 0) {
|
|
|
175
176
|
* })
|
|
176
177
|
* ```
|
|
177
178
|
*/
|
|
178
|
-
export default
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
};
|
|
185
|
-
}
|
|
179
|
+
export default defineComarkPlugin((config = {}) => ({
|
|
180
|
+
name: 'mermaid',
|
|
181
|
+
markdownItPlugins: [
|
|
182
|
+
((md) => markdownItMermaid(md, config)),
|
|
183
|
+
],
|
|
184
|
+
}));
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ComarkPlugin } from 'comark';
|
|
2
1
|
import type { PropsValidationOptions } from '../internal/props-validation.ts';
|
|
3
2
|
interface SecurityOptions extends PropsValidationOptions {
|
|
4
3
|
/**
|
|
@@ -7,5 +6,5 @@ interface SecurityOptions extends PropsValidationOptions {
|
|
|
7
6
|
*/
|
|
8
7
|
blockedTags?: string[];
|
|
9
8
|
}
|
|
10
|
-
|
|
11
|
-
export
|
|
9
|
+
declare const _default: import("comark").ComarkPluginFactory<SecurityOptions>;
|
|
10
|
+
export default _default;
|
package/dist/plugins/security.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { defineComarkPlugin } from "../utils/helpers.js";
|
|
1
2
|
import { visit } from 'comark/utils';
|
|
2
3
|
import { validateProps } from "../internal/props-validation.js";
|
|
3
|
-
export default
|
|
4
|
+
export default defineComarkPlugin((options = {}) => {
|
|
4
5
|
const { blockedTags = [], allowedLinkPrefixes, allowedImagePrefixes, allowedProtocols, defaultOrigin, allowDataImages, } = options;
|
|
5
6
|
const dropSet = new Set(blockedTags.map(t => t.toLowerCase()));
|
|
6
7
|
const propsOptions = {
|
|
@@ -29,4 +30,4 @@ export default function security(options = {}) {
|
|
|
29
30
|
});
|
|
30
31
|
},
|
|
31
32
|
};
|
|
32
|
-
}
|
|
33
|
+
});
|
package/dist/plugins/summary.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { applyAutoUnwrap } from "../internal/parse/auto-unwrap.js";
|
|
2
2
|
import { marmdownItTokensToComarkTree } from "../internal/parse/token-processor.js";
|
|
3
|
-
|
|
3
|
+
import { defineComarkPlugin } from "../utils/helpers.js";
|
|
4
|
+
export default defineComarkPlugin((options = {}) => {
|
|
5
|
+
const { delimiter = '<!-- more -->' } = options;
|
|
4
6
|
return {
|
|
5
7
|
name: 'summary',
|
|
6
8
|
post(state) {
|
|
@@ -19,4 +21,4 @@ export default function summary(delimiter = '<!-- more -->') {
|
|
|
19
21
|
}
|
|
20
22
|
},
|
|
21
23
|
};
|
|
22
|
-
}
|
|
24
|
+
});
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* This plugin runs before inline parsing to prevent Comark from interpreting
|
|
5
5
|
* task list markers [X] and [ ] as Comark inline span syntax.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
export default
|
|
7
|
+
declare const _default: import("../types.ts").ComarkPluginFactory<unknown>;
|
|
8
|
+
export default _default;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* This plugin runs before inline parsing to prevent Comark from interpreting
|
|
5
5
|
* task list markers [X] and [ ] as Comark inline span syntax.
|
|
6
6
|
*/
|
|
7
|
+
import { defineComarkPlugin } from "../utils/helpers.js";
|
|
7
8
|
function attrSet(token, name, value) {
|
|
8
9
|
const index = token.attrIndex(name);
|
|
9
10
|
const attr = [name, value];
|
|
@@ -109,9 +110,7 @@ function markdownItTaskList(md, options) {
|
|
|
109
110
|
}
|
|
110
111
|
});
|
|
111
112
|
}
|
|
112
|
-
export default
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
};
|
|
117
|
-
}
|
|
113
|
+
export default defineComarkPlugin(() => ({
|
|
114
|
+
name: 'task-list',
|
|
115
|
+
markdownItPlugins: [markdownItTaskList],
|
|
116
|
+
}));
|
package/dist/plugins/toc.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ComarkTree } from 'comark';
|
|
2
2
|
export interface TocLink {
|
|
3
3
|
id: string;
|
|
4
4
|
text: string;
|
|
@@ -12,4 +12,5 @@ export interface Toc {
|
|
|
12
12
|
links: TocLink[];
|
|
13
13
|
}
|
|
14
14
|
export declare function generateFlatToc(body: ComarkTree, options: Toc): Toc;
|
|
15
|
-
|
|
15
|
+
declare const _default: import("comark").ComarkPluginFactory<Partial<Toc>>;
|
|
16
|
+
export default _default;
|
package/dist/plugins/toc.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defineComarkPlugin } from "../utils/helpers.js";
|
|
1
2
|
const TOC_TAGS = ['h2', 'h3', 'h4', 'h5', 'h6'];
|
|
2
3
|
const TOC_TAGS_DEPTH = TOC_TAGS.reduce((tags, tag) => {
|
|
3
4
|
tags[tag] = Number(tag.charAt(tag.length - 1));
|
|
@@ -105,7 +106,7 @@ export function generateFlatToc(body, options) {
|
|
|
105
106
|
links,
|
|
106
107
|
};
|
|
107
108
|
}
|
|
108
|
-
export default
|
|
109
|
+
export default defineComarkPlugin((options = {}) => {
|
|
109
110
|
const { title = '', depth = 2, searchDepth = 2, links = [] } = options;
|
|
110
111
|
return {
|
|
111
112
|
name: 'toc',
|
|
@@ -115,4 +116,4 @@ export default function toc(options = {}) {
|
|
|
115
116
|
state.tree.meta.toc = toc;
|
|
116
117
|
},
|
|
117
118
|
};
|
|
118
|
-
}
|
|
119
|
+
});
|
package/dist/types.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type ComarkText = string;
|
|
|
11
11
|
* @param {} - The attributes of the comment
|
|
12
12
|
* @param string - The content of the comment
|
|
13
13
|
*/
|
|
14
|
-
export type ComarkComment = [null,
|
|
14
|
+
export type ComarkComment = [null, ComarkElementAttributes, string];
|
|
15
15
|
/**
|
|
16
16
|
* The Comark element attributes
|
|
17
17
|
* @param [key: string]: unknown - The attributes of the element
|
|
@@ -190,6 +190,7 @@ export type ComarkPlugin = {
|
|
|
190
190
|
pre?: (state: ComarkParsePreState) => Promise<void> | void;
|
|
191
191
|
post?: (state: ComarkParsePostState) => Promise<void> | void;
|
|
192
192
|
};
|
|
193
|
+
export type ComarkPluginFactory<Options> = (opts?: Options) => ComarkPlugin;
|
|
193
194
|
export type ComponentManifest = (name: string) => Promise<unknown> | undefined | null;
|
|
194
195
|
export interface ComarkContextProvider {
|
|
195
196
|
components: Record<string, any>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ComarkPluginFactory } from '../types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Returns a function that invokes `fn` **strictly one at a time**: each call waits until the
|
|
4
|
+
* previous invocation has settled (resolved or rejected) before starting the next.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createSerializedTask<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => Promise<TResult>): (...args: TArgs) => Promise<TResult>;
|
|
7
|
+
/**
|
|
8
|
+
* Define a Comark plugin
|
|
9
|
+
* @param fn - The plugin factory function
|
|
10
|
+
* @returns The defined plugin
|
|
11
|
+
*/
|
|
12
|
+
export declare function defineComarkPlugin<Options>(fn: ComarkPluginFactory<Options>): ComarkPluginFactory<Options>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a function that invokes `fn` **strictly one at a time**: each call waits until the
|
|
3
|
+
* previous invocation has settled (resolved or rejected) before starting the next.
|
|
4
|
+
*/
|
|
5
|
+
export function createSerializedTask(fn) {
|
|
6
|
+
let chain = Promise.resolve(null);
|
|
7
|
+
return (...args) => {
|
|
8
|
+
chain = chain
|
|
9
|
+
.then(() => fn(...args))
|
|
10
|
+
.catch(() => null);
|
|
11
|
+
return chain;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
// #region define plugin
|
|
15
|
+
/**
|
|
16
|
+
* Define a Comark plugin
|
|
17
|
+
* @param fn - The plugin factory function
|
|
18
|
+
* @returns The defined plugin
|
|
19
|
+
*/
|
|
20
|
+
export function defineComarkPlugin(fn) {
|
|
21
|
+
return fn;
|
|
22
|
+
}
|
|
23
|
+
// #endregion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../../src/utils/serialized-task'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../../src/utils/serialized-task.ts'
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "comark",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"description": "Components in Markdown (Comark) parser with streaming support for Vue, React, Svelte and HTML",
|
|
6
6
|
"author": "",
|
|
7
7
|
"license": "MIT",
|
|
@@ -35,7 +35,6 @@
|
|
|
35
35
|
"build": "tsc",
|
|
36
36
|
"dev": "tsc --watch",
|
|
37
37
|
"test": "vitest run",
|
|
38
|
-
"benchmark": "node --import tsx benchmark.ts",
|
|
39
38
|
"prepack": "tsc",
|
|
40
39
|
"release": "release-it",
|
|
41
40
|
"release:dry": "release-it --dry-run"
|
|
@@ -43,7 +42,7 @@
|
|
|
43
42
|
"peerDependencies": {
|
|
44
43
|
"beautiful-mermaid": "^1.1.3",
|
|
45
44
|
"katex": "^0.16.33",
|
|
46
|
-
"shiki": "^
|
|
45
|
+
"shiki": "^4.0.0"
|
|
47
46
|
},
|
|
48
47
|
"peerDependenciesMeta": {
|
|
49
48
|
"shiki": {
|
|
@@ -57,21 +56,22 @@
|
|
|
57
56
|
}
|
|
58
57
|
},
|
|
59
58
|
"devDependencies": {
|
|
59
|
+
"@json-render/core": "^0.16.0",
|
|
60
60
|
"@nuxt/kit": "^4.4.2",
|
|
61
61
|
"@shikijs/primitive": "^4.0.2",
|
|
62
62
|
"@shikijs/twoslash": "^4.0.2",
|
|
63
63
|
"@types/js-yaml": "^4.0.9",
|
|
64
|
+
"@types/markdown-it": "^14.1.2",
|
|
64
65
|
"github-slugger": "^2.0.0",
|
|
65
66
|
"hast-util-to-string": "^3.0.1",
|
|
66
|
-
"markdown-it": "^14.1.1",
|
|
67
67
|
"minimark": "0.2.0",
|
|
68
68
|
"mitata": "^1.0.34",
|
|
69
69
|
"tsx": "^4.21.0",
|
|
70
70
|
"twoslash": "^0.3.6",
|
|
71
|
-
"vitest": "^4.1.
|
|
71
|
+
"vitest": "^4.1.4"
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
|
-
"@comark/markdown-it": "^0.3.
|
|
74
|
+
"@comark/markdown-it": "^0.3.3",
|
|
75
75
|
"entities": "^8.0.0",
|
|
76
76
|
"htmlparser2": "^12.0.0",
|
|
77
77
|
"js-yaml": "^4.1.1",
|