github-markdown-adf 1.1.0 → 1.3.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 +29 -4
- package/dist/browser/index.iife.js +17 -32
- package/dist/browser/index.js +17 -32
- package/dist/index.cjs +107 -81
- package/dist/index.d.cts +24 -7
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +24 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +108 -57
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -7
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import { fromMarkdown } from "mdast-util-from-markdown";
|
|
2
|
+
import { gfmFromMarkdown } from "mdast-util-gfm";
|
|
3
|
+
import { gfm } from "micromark-extension-gfm";
|
|
4
4
|
//#region src/md-to-adf/parser.ts
|
|
5
|
-
const
|
|
5
|
+
const markdownParseOptions = {
|
|
6
|
+
extensions: [gfm()],
|
|
7
|
+
mdastExtensions: [gfmFromMarkdown()]
|
|
8
|
+
};
|
|
6
9
|
function parseMarkdown(markdown) {
|
|
7
|
-
return
|
|
10
|
+
return fromMarkdown(markdown, markdownParseOptions);
|
|
8
11
|
}
|
|
9
12
|
//#endregion
|
|
10
13
|
//#region src/utils/language.ts
|
|
@@ -35,6 +38,7 @@ function normalizeLanguage(lang) {
|
|
|
35
38
|
//#region src/md-to-adf/transform/marks.ts
|
|
36
39
|
const OPEN_HTML_TAG = /^<(ins|sub|sup)>$/i;
|
|
37
40
|
const CLOSE_HTML_TAG = /^<\/(ins|sub|sup)>$/i;
|
|
41
|
+
const MENTION_PATTERN = /(^|[^A-Za-z0-9_@])@([A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?)(?=$|[^A-Za-z0-9._@-])/g;
|
|
38
42
|
function htmlTagToMark(tag) {
|
|
39
43
|
const t = tag.toLowerCase();
|
|
40
44
|
if (t === "ins") return { type: "underline" };
|
|
@@ -48,7 +52,7 @@ function htmlTagToMark(tag) {
|
|
|
48
52
|
};
|
|
49
53
|
return null;
|
|
50
54
|
}
|
|
51
|
-
function phrasingToInlineNodes(nodes) {
|
|
55
|
+
function phrasingToInlineNodes(nodes, options) {
|
|
52
56
|
const markStack = [];
|
|
53
57
|
const result = [];
|
|
54
58
|
for (const node of nodes) {
|
|
@@ -64,22 +68,22 @@ function phrasingToInlineNodes(nodes) {
|
|
|
64
68
|
continue;
|
|
65
69
|
}
|
|
66
70
|
}
|
|
67
|
-
result.push(...phrasingToInline(node, markStack.slice()));
|
|
71
|
+
result.push(...phrasingToInline(node, markStack.slice(), options));
|
|
68
72
|
}
|
|
69
73
|
return result;
|
|
70
74
|
}
|
|
71
|
-
function phrasingToInline(node, inheritedMarks) {
|
|
75
|
+
function phrasingToInline(node, inheritedMarks, options) {
|
|
72
76
|
switch (node.type) {
|
|
73
77
|
case "text":
|
|
74
78
|
if (!node.value) return [];
|
|
75
|
-
return
|
|
79
|
+
return textToInlineNodes(node.value, inheritedMarks, options);
|
|
76
80
|
case "inlineCode": {
|
|
77
81
|
const marks = [...inheritedMarks.filter((m) => m.type === "link"), { type: "code" }];
|
|
78
82
|
return [makeText(node.value, marks)];
|
|
79
83
|
}
|
|
80
|
-
case "strong": return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, { type: "strong" }]));
|
|
81
|
-
case "emphasis": return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, { type: "em" }]));
|
|
82
|
-
case "delete": return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, { type: "strike" }]));
|
|
84
|
+
case "strong": return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, { type: "strong" }], options));
|
|
85
|
+
case "emphasis": return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, { type: "em" }], options));
|
|
86
|
+
case "delete": return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, { type: "strike" }], options));
|
|
83
87
|
case "link": {
|
|
84
88
|
const linkMark = {
|
|
85
89
|
type: "link",
|
|
@@ -88,7 +92,7 @@ function phrasingToInline(node, inheritedMarks) {
|
|
|
88
92
|
...node.title ? { title: node.title } : {}
|
|
89
93
|
}
|
|
90
94
|
};
|
|
91
|
-
return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, linkMark]));
|
|
95
|
+
return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, linkMark], options));
|
|
92
96
|
}
|
|
93
97
|
case "image": return [{
|
|
94
98
|
type: "inlineCard",
|
|
@@ -101,6 +105,27 @@ function phrasingToInline(node, inheritedMarks) {
|
|
|
101
105
|
default: return [];
|
|
102
106
|
}
|
|
103
107
|
}
|
|
108
|
+
function textToInlineNodes(value, marks, options) {
|
|
109
|
+
if (!options?.mentions || marks.length > 0) return [makeText(value, marks)];
|
|
110
|
+
const result = [];
|
|
111
|
+
let lastIndex = 0;
|
|
112
|
+
for (const match of value.matchAll(MENTION_PATTERN)) {
|
|
113
|
+
const matchIndex = match.index ?? 0;
|
|
114
|
+
const prefix = match[1] ?? "";
|
|
115
|
+
const username = match[2];
|
|
116
|
+
if (!username) continue;
|
|
117
|
+
const mentionStart = matchIndex + prefix.length;
|
|
118
|
+
const mentionEnd = matchIndex + match[0].length;
|
|
119
|
+
appendTextNode(result, value.slice(lastIndex, mentionStart), marks);
|
|
120
|
+
const mentionNode = makeMentionNode(username, options.mentions);
|
|
121
|
+
if (mentionNode) result.push(mentionNode);
|
|
122
|
+
else appendTextNode(result, value.slice(mentionStart, mentionEnd), marks);
|
|
123
|
+
lastIndex = mentionEnd;
|
|
124
|
+
}
|
|
125
|
+
if (result.length === 0) return [makeText(value, marks)];
|
|
126
|
+
appendTextNode(result, value.slice(lastIndex), marks);
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
104
129
|
function makeText(value, marks) {
|
|
105
130
|
const node = {
|
|
106
131
|
type: "text",
|
|
@@ -109,6 +134,31 @@ function makeText(value, marks) {
|
|
|
109
134
|
if (marks.length > 0) node.marks = marks;
|
|
110
135
|
return node;
|
|
111
136
|
}
|
|
137
|
+
function appendTextNode(result, value, marks) {
|
|
138
|
+
if (!value) return;
|
|
139
|
+
const previousNode = result[result.length - 1];
|
|
140
|
+
if (previousNode?.type === "text" && sameMarks(previousNode.marks, marks)) {
|
|
141
|
+
previousNode.text += value;
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
result.push(makeText(value, marks));
|
|
145
|
+
}
|
|
146
|
+
function makeMentionNode(username, mentions) {
|
|
147
|
+
const attrs = typeof mentions === "function" ? mentions(username) : {
|
|
148
|
+
id: username,
|
|
149
|
+
text: `@${username}`
|
|
150
|
+
};
|
|
151
|
+
if (!attrs) return null;
|
|
152
|
+
return {
|
|
153
|
+
type: "mention",
|
|
154
|
+
attrs
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function sameMarks(leftMarks, rightMarks) {
|
|
158
|
+
const normalizedLeft = leftMarks ?? [];
|
|
159
|
+
if (normalizedLeft.length !== rightMarks.length) return false;
|
|
160
|
+
return normalizedLeft.every((mark, index) => JSON.stringify(mark) === JSON.stringify(rightMarks[index]));
|
|
161
|
+
}
|
|
112
162
|
function parseHtmlInline(html, inheritedMarks) {
|
|
113
163
|
const stripped = html.replace(/<[^>]+>/g, "");
|
|
114
164
|
if (stripped) return [makeText(stripped, inheritedMarks)];
|
|
@@ -116,17 +166,17 @@ function parseHtmlInline(html, inheritedMarks) {
|
|
|
116
166
|
}
|
|
117
167
|
//#endregion
|
|
118
168
|
//#region src/md-to-adf/transform/blocks.ts
|
|
119
|
-
function transformHeading(node) {
|
|
169
|
+
function transformHeading(node, options) {
|
|
120
170
|
return {
|
|
121
171
|
type: "heading",
|
|
122
172
|
attrs: { level: node.depth },
|
|
123
|
-
content: phrasingToInlineNodes(node.children)
|
|
173
|
+
content: phrasingToInlineNodes(node.children, options)
|
|
124
174
|
};
|
|
125
175
|
}
|
|
126
|
-
function transformParagraph(node) {
|
|
176
|
+
function transformParagraph(node, options) {
|
|
127
177
|
return {
|
|
128
178
|
type: "paragraph",
|
|
129
|
-
content: phrasingToInlineNodes(node.children)
|
|
179
|
+
content: phrasingToInlineNodes(node.children, options)
|
|
130
180
|
};
|
|
131
181
|
}
|
|
132
182
|
function transformCode(node) {
|
|
@@ -150,7 +200,7 @@ const ALERT_TO_PANEL = {
|
|
|
150
200
|
WARNING: "warning",
|
|
151
201
|
CAUTION: "error"
|
|
152
202
|
};
|
|
153
|
-
function buildPanelContent(firstChild, restChildren, transformChildren) {
|
|
203
|
+
function buildPanelContent(firstChild, restChildren, transformChildren, options) {
|
|
154
204
|
const remainingText = firstChild.children[0].value.replace(ALERT_PATTERN, "").trim();
|
|
155
205
|
const remainingInlines = firstChild.children.slice(1);
|
|
156
206
|
const contentNodes = [];
|
|
@@ -162,7 +212,7 @@ function buildPanelContent(firstChild, restChildren, transformChildren) {
|
|
|
162
212
|
value: remainingText
|
|
163
213
|
}] : [], ...remainingInlines]
|
|
164
214
|
};
|
|
165
|
-
if (paragraph.children.length > 0) contentNodes.push(transformParagraph(paragraph));
|
|
215
|
+
if (paragraph.children.length > 0) contentNodes.push(transformParagraph(paragraph, options));
|
|
166
216
|
}
|
|
167
217
|
contentNodes.push(...transformChildren(restChildren));
|
|
168
218
|
if (contentNodes.length === 0) contentNodes.push({
|
|
@@ -171,7 +221,7 @@ function buildPanelContent(firstChild, restChildren, transformChildren) {
|
|
|
171
221
|
});
|
|
172
222
|
return contentNodes;
|
|
173
223
|
}
|
|
174
|
-
function tryTransformAlert(node, transformChildren) {
|
|
224
|
+
function tryTransformAlert(node, transformChildren, options) {
|
|
175
225
|
const firstChild = node.children[0];
|
|
176
226
|
if (firstChild?.type !== "paragraph") return null;
|
|
177
227
|
const firstText = firstChild.children[0];
|
|
@@ -179,15 +229,15 @@ function tryTransformAlert(node, transformChildren) {
|
|
|
179
229
|
const match = ALERT_PATTERN.exec(firstText.value);
|
|
180
230
|
if (!match) return null;
|
|
181
231
|
const panelType = ALERT_TO_PANEL[(match[1] ?? "NOTE").toUpperCase()] ?? "info";
|
|
182
|
-
const content = buildPanelContent(firstChild, node.children.slice(1), transformChildren);
|
|
232
|
+
const content = buildPanelContent(firstChild, node.children.slice(1), transformChildren, options);
|
|
183
233
|
return {
|
|
184
234
|
type: "panel",
|
|
185
235
|
attrs: { panelType },
|
|
186
236
|
content
|
|
187
237
|
};
|
|
188
238
|
}
|
|
189
|
-
function transformBlockquote(node, transformChildren) {
|
|
190
|
-
const panel = tryTransformAlert(node, transformChildren);
|
|
239
|
+
function transformBlockquote(node, transformChildren, options) {
|
|
240
|
+
const panel = tryTransformAlert(node, transformChildren, options);
|
|
191
241
|
if (panel) return panel;
|
|
192
242
|
const content = transformChildren(node.children);
|
|
193
243
|
return {
|
|
@@ -351,33 +401,33 @@ function generateId() {
|
|
|
351
401
|
}
|
|
352
402
|
//#endregion
|
|
353
403
|
//#region src/md-to-adf/transform/lists.ts
|
|
354
|
-
function transformList(node, transformBlock) {
|
|
355
|
-
if (node.children.some((item) => item.checked !== null && item.checked !== void 0)) return transformTaskList(node);
|
|
356
|
-
if (node.ordered) return transformOrderedList(node, transformBlock);
|
|
357
|
-
return transformBulletList(node, transformBlock);
|
|
404
|
+
function transformList(node, transformBlock, options) {
|
|
405
|
+
if (node.children.some((item) => item.checked !== null && item.checked !== void 0)) return transformTaskList(node, options);
|
|
406
|
+
if (node.ordered) return transformOrderedList(node, transformBlock, options);
|
|
407
|
+
return transformBulletList(node, transformBlock, options);
|
|
358
408
|
}
|
|
359
|
-
function transformBulletList(node, transformBlock) {
|
|
409
|
+
function transformBulletList(node, transformBlock, options) {
|
|
360
410
|
return {
|
|
361
411
|
type: "bulletList",
|
|
362
|
-
content: node.children.map((item) => transformListItem(item, transformBlock))
|
|
412
|
+
content: node.children.map((item) => transformListItem(item, transformBlock, options))
|
|
363
413
|
};
|
|
364
414
|
}
|
|
365
|
-
function transformOrderedList(node, transformBlock) {
|
|
415
|
+
function transformOrderedList(node, transformBlock, options) {
|
|
366
416
|
const result = {
|
|
367
417
|
type: "orderedList",
|
|
368
|
-
content: node.children.map((item) => transformListItem(item, transformBlock))
|
|
418
|
+
content: node.children.map((item) => transformListItem(item, transformBlock, options))
|
|
369
419
|
};
|
|
370
420
|
if (node.start !== null && node.start !== void 0 && node.start !== 1) result.attrs = { order: node.start };
|
|
371
421
|
return result;
|
|
372
422
|
}
|
|
373
|
-
function transformListItem(node, transformBlock) {
|
|
423
|
+
function transformListItem(node, transformBlock, options) {
|
|
374
424
|
const content = [];
|
|
375
425
|
for (const child of node.children) if (child.type === "paragraph") content.push({
|
|
376
426
|
type: "paragraph",
|
|
377
|
-
content: phrasingToInlineNodes(child.children)
|
|
427
|
+
content: phrasingToInlineNodes(child.children, options)
|
|
378
428
|
});
|
|
379
429
|
else if (child.type === "list") {
|
|
380
|
-
const nestedList = transformList(child, transformBlock);
|
|
430
|
+
const nestedList = transformList(child, transformBlock, options);
|
|
381
431
|
if (nestedList.type === "taskList") {
|
|
382
432
|
const para = {
|
|
383
433
|
type: "paragraph",
|
|
@@ -414,11 +464,11 @@ function transformListItem(node, transformBlock) {
|
|
|
414
464
|
content
|
|
415
465
|
};
|
|
416
466
|
}
|
|
417
|
-
function transformTaskList(node) {
|
|
467
|
+
function transformTaskList(node, options) {
|
|
418
468
|
const listId = generateId();
|
|
419
469
|
const items = node.children.map((listItem) => {
|
|
420
470
|
const state = listItem.checked === true ? "DONE" : "TODO";
|
|
421
|
-
const inlineContent = listItem.children.filter((c) => c.type === "paragraph").flatMap((c) => phrasingToInlineNodes(c.children));
|
|
471
|
+
const inlineContent = listItem.children.filter((c) => c.type === "paragraph").flatMap((c) => phrasingToInlineNodes(c.children, options));
|
|
422
472
|
const taskItem = {
|
|
423
473
|
type: "taskItem",
|
|
424
474
|
attrs: {
|
|
@@ -437,7 +487,7 @@ function transformTaskList(node) {
|
|
|
437
487
|
}
|
|
438
488
|
//#endregion
|
|
439
489
|
//#region src/md-to-adf/transform/tables.ts
|
|
440
|
-
function transformTable(node) {
|
|
490
|
+
function transformTable(node, options) {
|
|
441
491
|
const rows = node.children;
|
|
442
492
|
if (rows.length === 0) return {
|
|
443
493
|
type: "table",
|
|
@@ -448,19 +498,19 @@ function transformTable(node) {
|
|
|
448
498
|
const adfRows = [];
|
|
449
499
|
if (headerRow) adfRows.push({
|
|
450
500
|
type: "tableRow",
|
|
451
|
-
content: headerRow.children.map((cell) => transformTableHeader(cell))
|
|
501
|
+
content: headerRow.children.map((cell) => transformTableHeader(cell, options))
|
|
452
502
|
});
|
|
453
503
|
for (const row of bodyRows) adfRows.push({
|
|
454
504
|
type: "tableRow",
|
|
455
|
-
content: row.children.map((cell) => transformTableCell(cell))
|
|
505
|
+
content: row.children.map((cell) => transformTableCell(cell, options))
|
|
456
506
|
});
|
|
457
507
|
return {
|
|
458
508
|
type: "table",
|
|
459
509
|
content: adfRows
|
|
460
510
|
};
|
|
461
511
|
}
|
|
462
|
-
function transformTableHeader(cell) {
|
|
463
|
-
const inlines = phrasingToInlineNodes(cell.children);
|
|
512
|
+
function transformTableHeader(cell, options) {
|
|
513
|
+
const inlines = phrasingToInlineNodes(cell.children, options);
|
|
464
514
|
return {
|
|
465
515
|
type: "tableHeader",
|
|
466
516
|
attrs: {},
|
|
@@ -470,8 +520,8 @@ function transformTableHeader(cell) {
|
|
|
470
520
|
}]
|
|
471
521
|
};
|
|
472
522
|
}
|
|
473
|
-
function transformTableCell(cell) {
|
|
474
|
-
const inlines = phrasingToInlineNodes(cell.children);
|
|
523
|
+
function transformTableCell(cell, options) {
|
|
524
|
+
const inlines = phrasingToInlineNodes(cell.children, options);
|
|
475
525
|
return {
|
|
476
526
|
type: "tableCell",
|
|
477
527
|
attrs: {},
|
|
@@ -483,42 +533,42 @@ function transformTableCell(cell) {
|
|
|
483
533
|
}
|
|
484
534
|
//#endregion
|
|
485
535
|
//#region src/md-to-adf/transform/index.ts
|
|
486
|
-
function transformRoot(root) {
|
|
536
|
+
function transformRoot(root, options) {
|
|
487
537
|
return {
|
|
488
538
|
version: 1,
|
|
489
539
|
type: "doc",
|
|
490
|
-
content: transformNodes(root.children)
|
|
540
|
+
content: transformNodes(root.children, options)
|
|
491
541
|
};
|
|
492
542
|
}
|
|
493
|
-
function transformNodes(nodes) {
|
|
543
|
+
function transformNodes(nodes, options) {
|
|
494
544
|
const result = [];
|
|
495
545
|
const detailsPairs = buildDetailsPairs(nodes);
|
|
496
546
|
let i = 0;
|
|
497
547
|
while (i < nodes.length) {
|
|
498
|
-
const expand = tryTransformExpand(nodes, i, detailsPairs, transformBlock);
|
|
548
|
+
const expand = tryTransformExpand(nodes, i, detailsPairs, (node) => transformBlock(node, options));
|
|
499
549
|
if (expand) {
|
|
500
550
|
result.push(expand.node);
|
|
501
551
|
i = expand.next;
|
|
502
552
|
continue;
|
|
503
553
|
}
|
|
504
|
-
const transformed = transformBlock(nodes[i]);
|
|
554
|
+
const transformed = transformBlock(nodes[i], options);
|
|
505
555
|
if (transformed) result.push(transformed);
|
|
506
556
|
i++;
|
|
507
557
|
}
|
|
508
558
|
return result;
|
|
509
559
|
}
|
|
510
|
-
function transformBlock(node) {
|
|
560
|
+
function transformBlock(node, options) {
|
|
511
561
|
switch (node.type) {
|
|
512
|
-
case "heading": return transformHeading(node);
|
|
513
|
-
case "paragraph": return transformParagraph(node);
|
|
562
|
+
case "heading": return transformHeading(node, options);
|
|
563
|
+
case "paragraph": return transformParagraph(node, options);
|
|
514
564
|
case "code": return transformCode(node);
|
|
515
565
|
case "thematicBreak": return transformThematicBreak(node);
|
|
516
566
|
case "blockquote": return transformBlockquote(node, (children) => children.flatMap((c) => {
|
|
517
|
-
const r = transformBlock(c);
|
|
567
|
+
const r = transformBlock(c, options);
|
|
518
568
|
return r ? [r] : [];
|
|
519
|
-
}));
|
|
520
|
-
case "list": return transformList(node, transformBlock);
|
|
521
|
-
case "table": return transformTable(node);
|
|
569
|
+
}), options);
|
|
570
|
+
case "list": return transformList(node, (blockNode) => transformBlock(blockNode, options), options);
|
|
571
|
+
case "table": return transformTable(node, options);
|
|
522
572
|
case "html": return transformHtmlBlock(node);
|
|
523
573
|
default: return null;
|
|
524
574
|
}
|
|
@@ -545,8 +595,8 @@ function sanitizeText(text) {
|
|
|
545
595
|
}
|
|
546
596
|
//#endregion
|
|
547
597
|
//#region src/md-to-adf/index.ts
|
|
548
|
-
function mdToAdf(markdown) {
|
|
549
|
-
return transformRoot(parseMarkdown(sanitizeText(markdown)));
|
|
598
|
+
function mdToAdf(markdown, options) {
|
|
599
|
+
return transformRoot(parseMarkdown(sanitizeText(markdown)), options);
|
|
550
600
|
}
|
|
551
601
|
//#endregion
|
|
552
602
|
//#region src/utils/escape.ts
|
|
@@ -613,6 +663,7 @@ function serializeInline(node, options) {
|
|
|
613
663
|
case "hardBreak": return "\\\n";
|
|
614
664
|
case "mention":
|
|
615
665
|
if (options?.mentions === false) return node.attrs.text ?? node.attrs.id;
|
|
666
|
+
if (typeof options?.mentions === "function") return options.mentions(node.attrs);
|
|
616
667
|
return node.attrs.text ?? `@${node.attrs.id}`;
|
|
617
668
|
case "emoji": return node.attrs.text ?? `:${node.attrs.shortName}:`;
|
|
618
669
|
case "date": return node.attrs.timestamp;
|