github-markdown-adf 0.0.0-semantic-release
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/LICENSE +24 -0
- package/README.md +158 -0
- package/dist/browser/index.iife.js +48 -0
- package/dist/browser/index.js +48 -0
- package/dist/index.cjs +658 -0
- package/dist/index.d.cts +413 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +413 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +634 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +90 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
+
get: ((k) => from[k]).bind(null, key),
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
//#endregion
|
|
24
|
+
let unified = require("unified");
|
|
25
|
+
let remark_parse = require("remark-parse");
|
|
26
|
+
remark_parse = __toESM(remark_parse);
|
|
27
|
+
let remark_gfm = require("remark-gfm");
|
|
28
|
+
remark_gfm = __toESM(remark_gfm);
|
|
29
|
+
//#region src/md-to-adf/parser.ts
|
|
30
|
+
function parseMarkdown(markdown) {
|
|
31
|
+
return (0, unified.unified)().use(remark_parse.default).use(remark_gfm.default).parse(markdown);
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/utils/language.ts
|
|
35
|
+
const LANGUAGE_ALIASES = {
|
|
36
|
+
ts: "typescript",
|
|
37
|
+
js: "javascript",
|
|
38
|
+
jsx: "javascript",
|
|
39
|
+
tsx: "typescript",
|
|
40
|
+
py: "python",
|
|
41
|
+
rb: "ruby",
|
|
42
|
+
sh: "bash",
|
|
43
|
+
zsh: "bash",
|
|
44
|
+
shell: "bash",
|
|
45
|
+
yml: "yaml",
|
|
46
|
+
md: "markdown",
|
|
47
|
+
rs: "rust",
|
|
48
|
+
kt: "kotlin",
|
|
49
|
+
tf: "hcl",
|
|
50
|
+
dockerfile: "docker"
|
|
51
|
+
};
|
|
52
|
+
function normalizeLanguage(lang) {
|
|
53
|
+
if (!lang) return void 0;
|
|
54
|
+
const lower = lang.toLowerCase().trim();
|
|
55
|
+
if (!lower) return void 0;
|
|
56
|
+
return LANGUAGE_ALIASES[lower] ?? lower;
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/md-to-adf/transform/marks.ts
|
|
60
|
+
const OPEN_HTML_TAG = /^<(ins|sub|sup)>$/i;
|
|
61
|
+
const CLOSE_HTML_TAG = /^<\/(ins|sub|sup)>$/i;
|
|
62
|
+
function htmlTagToMark(tag) {
|
|
63
|
+
const t = tag.toLowerCase();
|
|
64
|
+
if (t === "ins") return { type: "underline" };
|
|
65
|
+
if (t === "sub") return {
|
|
66
|
+
type: "subsup",
|
|
67
|
+
attrs: { type: "sub" }
|
|
68
|
+
};
|
|
69
|
+
if (t === "sup") return {
|
|
70
|
+
type: "subsup",
|
|
71
|
+
attrs: { type: "sup" }
|
|
72
|
+
};
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
function phrasingToInlineNodes(nodes) {
|
|
76
|
+
const markStack = [];
|
|
77
|
+
const result = [];
|
|
78
|
+
for (const node of nodes) {
|
|
79
|
+
if (node.type === "html") {
|
|
80
|
+
const openMatch = OPEN_HTML_TAG.exec(node.value);
|
|
81
|
+
if (openMatch) {
|
|
82
|
+
const mark = htmlTagToMark(openMatch[1] ?? "");
|
|
83
|
+
if (mark) markStack.push(mark);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (CLOSE_HTML_TAG.exec(node.value)) {
|
|
87
|
+
markStack.pop();
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
result.push(...phrasingToInline(node, markStack.slice()));
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
function phrasingToInline(node, inheritedMarks) {
|
|
96
|
+
switch (node.type) {
|
|
97
|
+
case "text":
|
|
98
|
+
if (!node.value) return [];
|
|
99
|
+
return [makeText(node.value, inheritedMarks)];
|
|
100
|
+
case "inlineCode": {
|
|
101
|
+
const marks = [...inheritedMarks.filter((m) => m.type === "link"), { type: "code" }];
|
|
102
|
+
return [makeText(node.value, marks)];
|
|
103
|
+
}
|
|
104
|
+
case "strong": return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, { type: "strong" }]));
|
|
105
|
+
case "emphasis": return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, { type: "em" }]));
|
|
106
|
+
case "delete": return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, { type: "strike" }]));
|
|
107
|
+
case "link": {
|
|
108
|
+
const linkMark = {
|
|
109
|
+
type: "link",
|
|
110
|
+
attrs: {
|
|
111
|
+
href: node.url,
|
|
112
|
+
...node.title ? { title: node.title } : {}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
return node.children.flatMap((c) => phrasingToInline(c, [...inheritedMarks, linkMark]));
|
|
116
|
+
}
|
|
117
|
+
case "image": return [{
|
|
118
|
+
type: "inlineCard",
|
|
119
|
+
attrs: { url: node.url }
|
|
120
|
+
}];
|
|
121
|
+
case "break": return [{ type: "hardBreak" }];
|
|
122
|
+
case "html": return parseHtmlInline(node.value, inheritedMarks);
|
|
123
|
+
case "linkReference":
|
|
124
|
+
case "imageReference": return [];
|
|
125
|
+
default: return [];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function makeText(value, marks) {
|
|
129
|
+
const node = {
|
|
130
|
+
type: "text",
|
|
131
|
+
text: value
|
|
132
|
+
};
|
|
133
|
+
if (marks.length > 0) node.marks = marks;
|
|
134
|
+
return node;
|
|
135
|
+
}
|
|
136
|
+
function parseHtmlInline(html, inheritedMarks) {
|
|
137
|
+
const stripped = html.replace(/<[^>]+>/g, "");
|
|
138
|
+
if (stripped) return [makeText(stripped, inheritedMarks)];
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region src/md-to-adf/transform/blocks.ts
|
|
143
|
+
function transformHeading(node) {
|
|
144
|
+
return {
|
|
145
|
+
type: "heading",
|
|
146
|
+
attrs: { level: node.depth },
|
|
147
|
+
content: phrasingToInlineNodes(node.children)
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function transformParagraph(node) {
|
|
151
|
+
return {
|
|
152
|
+
type: "paragraph",
|
|
153
|
+
content: phrasingToInlineNodes(node.children)
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function transformCode(node) {
|
|
157
|
+
const result = { type: "codeBlock" };
|
|
158
|
+
const lang = normalizeLanguage(node.lang);
|
|
159
|
+
if (lang) result.attrs = { language: lang };
|
|
160
|
+
if (node.value) result.content = [{
|
|
161
|
+
type: "text",
|
|
162
|
+
text: node.value
|
|
163
|
+
}];
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
function transformThematicBreak(_node) {
|
|
167
|
+
return { type: "rule" };
|
|
168
|
+
}
|
|
169
|
+
const ALERT_PATTERN = /^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s*/i;
|
|
170
|
+
const ALERT_TO_PANEL = {
|
|
171
|
+
NOTE: "note",
|
|
172
|
+
TIP: "info",
|
|
173
|
+
IMPORTANT: "warning",
|
|
174
|
+
WARNING: "warning",
|
|
175
|
+
CAUTION: "error"
|
|
176
|
+
};
|
|
177
|
+
function transformBlockquote(node, transformChildren) {
|
|
178
|
+
const firstChild = node.children[0];
|
|
179
|
+
if (firstChild?.type === "paragraph") {
|
|
180
|
+
const firstText = firstChild.children[0];
|
|
181
|
+
if (firstText?.type === "text") {
|
|
182
|
+
const match = ALERT_PATTERN.exec(firstText.value);
|
|
183
|
+
if (match) {
|
|
184
|
+
const panelType = ALERT_TO_PANEL[(match[1] ?? "NOTE").toUpperCase()] ?? "info";
|
|
185
|
+
const remainingFirstParagraphText = firstText.value.replace(ALERT_PATTERN, "").trim();
|
|
186
|
+
const remainingChildren = [...firstChild.children.slice(1)];
|
|
187
|
+
const contentNodes = [];
|
|
188
|
+
if (remainingFirstParagraphText || remainingChildren.length > 0) {
|
|
189
|
+
const newParagraph = {
|
|
190
|
+
type: "paragraph",
|
|
191
|
+
children: [...remainingFirstParagraphText ? [{
|
|
192
|
+
type: "text",
|
|
193
|
+
value: remainingFirstParagraphText
|
|
194
|
+
}] : [], ...remainingChildren]
|
|
195
|
+
};
|
|
196
|
+
if (newParagraph.children.length > 0) contentNodes.push(transformParagraph(newParagraph));
|
|
197
|
+
}
|
|
198
|
+
const restChildren = node.children.slice(1);
|
|
199
|
+
contentNodes.push(...transformChildren(restChildren));
|
|
200
|
+
if (contentNodes.length === 0) contentNodes.push({
|
|
201
|
+
type: "paragraph",
|
|
202
|
+
content: []
|
|
203
|
+
});
|
|
204
|
+
return {
|
|
205
|
+
type: "panel",
|
|
206
|
+
attrs: { panelType },
|
|
207
|
+
content: contentNodes
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const content = transformChildren(node.children);
|
|
213
|
+
return {
|
|
214
|
+
type: "blockquote",
|
|
215
|
+
content: content.length > 0 ? content : [{
|
|
216
|
+
type: "paragraph",
|
|
217
|
+
content: []
|
|
218
|
+
}]
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
//#endregion
|
|
222
|
+
//#region src/md-to-adf/transform/inlines.ts
|
|
223
|
+
function transformHtmlBlock(node) {
|
|
224
|
+
const detailsMatch = /<details[^>]*>\s*<summary[^>]*>(.*?)<\/summary>([\s\S]*?)<\/details>/i.exec(node.value);
|
|
225
|
+
if (detailsMatch) return {
|
|
226
|
+
type: "paragraph",
|
|
227
|
+
content: [{
|
|
228
|
+
type: "text",
|
|
229
|
+
text: (detailsMatch[1] ?? "").trim()
|
|
230
|
+
}]
|
|
231
|
+
};
|
|
232
|
+
const stripped = node.value.replace(/<[^>]+>/g, "").trim();
|
|
233
|
+
if (!stripped) return null;
|
|
234
|
+
return {
|
|
235
|
+
type: "paragraph",
|
|
236
|
+
content: [{
|
|
237
|
+
type: "text",
|
|
238
|
+
text: stripped
|
|
239
|
+
}]
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
//#endregion
|
|
243
|
+
//#region src/utils/id.ts
|
|
244
|
+
function generateId() {
|
|
245
|
+
return crypto.randomUUID();
|
|
246
|
+
}
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region src/md-to-adf/transform/lists.ts
|
|
249
|
+
function transformList(node, transformBlock) {
|
|
250
|
+
if (node.children.some((item) => item.checked !== null && item.checked !== void 0)) return transformTaskList(node);
|
|
251
|
+
if (node.ordered) return transformOrderedList(node, transformBlock);
|
|
252
|
+
return transformBulletList(node, transformBlock);
|
|
253
|
+
}
|
|
254
|
+
function transformBulletList(node, transformBlock) {
|
|
255
|
+
return {
|
|
256
|
+
type: "bulletList",
|
|
257
|
+
content: node.children.map((item) => transformListItem(item, transformBlock))
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
function transformOrderedList(node, transformBlock) {
|
|
261
|
+
const result = {
|
|
262
|
+
type: "orderedList",
|
|
263
|
+
content: node.children.map((item) => transformListItem(item, transformBlock))
|
|
264
|
+
};
|
|
265
|
+
if (node.start !== null && node.start !== void 0 && node.start !== 1) result.attrs = { order: node.start };
|
|
266
|
+
return result;
|
|
267
|
+
}
|
|
268
|
+
function transformListItem(node, transformBlock) {
|
|
269
|
+
const content = [];
|
|
270
|
+
for (const child of node.children) if (child.type === "paragraph") content.push({
|
|
271
|
+
type: "paragraph",
|
|
272
|
+
content: phrasingToInlineNodes(child.children)
|
|
273
|
+
});
|
|
274
|
+
else if (child.type === "list") {
|
|
275
|
+
const nestedList = transformList(child, transformBlock);
|
|
276
|
+
if (nestedList.type === "taskList") {
|
|
277
|
+
const para = {
|
|
278
|
+
type: "paragraph",
|
|
279
|
+
content: []
|
|
280
|
+
};
|
|
281
|
+
if (content.length === 0) content.push(para);
|
|
282
|
+
} else {
|
|
283
|
+
if (content.length === 0) content.push({
|
|
284
|
+
type: "paragraph",
|
|
285
|
+
content: []
|
|
286
|
+
});
|
|
287
|
+
content.push(nestedList);
|
|
288
|
+
}
|
|
289
|
+
} else if (child.type === "code") content.push({
|
|
290
|
+
type: "codeBlock",
|
|
291
|
+
content: [{
|
|
292
|
+
type: "text",
|
|
293
|
+
text: child.value
|
|
294
|
+
}],
|
|
295
|
+
...child.lang ? { attrs: { language: child.lang } } : {}
|
|
296
|
+
});
|
|
297
|
+
else {
|
|
298
|
+
const transformed = transformBlock(child);
|
|
299
|
+
if (transformed) {
|
|
300
|
+
if (transformed.type === "paragraph") content.push(transformed);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
if (content.length === 0) content.push({
|
|
304
|
+
type: "paragraph",
|
|
305
|
+
content: []
|
|
306
|
+
});
|
|
307
|
+
return {
|
|
308
|
+
type: "listItem",
|
|
309
|
+
content
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
function transformTaskList(node) {
|
|
313
|
+
const listId = generateId();
|
|
314
|
+
const items = node.children.map((listItem) => {
|
|
315
|
+
const state = listItem.checked === true ? "DONE" : "TODO";
|
|
316
|
+
const inlineContent = listItem.children.filter((c) => c.type === "paragraph").flatMap((c) => phrasingToInlineNodes(c.children));
|
|
317
|
+
const taskItem = {
|
|
318
|
+
type: "taskItem",
|
|
319
|
+
attrs: {
|
|
320
|
+
localId: generateId(),
|
|
321
|
+
state
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
if (inlineContent.length > 0) taskItem.content = inlineContent;
|
|
325
|
+
return taskItem;
|
|
326
|
+
});
|
|
327
|
+
return {
|
|
328
|
+
type: "taskList",
|
|
329
|
+
attrs: { localId: listId },
|
|
330
|
+
content: items
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region src/md-to-adf/transform/tables.ts
|
|
335
|
+
function transformTable(node) {
|
|
336
|
+
const rows = node.children;
|
|
337
|
+
if (rows.length === 0) return {
|
|
338
|
+
type: "table",
|
|
339
|
+
content: []
|
|
340
|
+
};
|
|
341
|
+
const headerRow = rows[0];
|
|
342
|
+
const bodyRows = rows.slice(1);
|
|
343
|
+
const adfRows = [];
|
|
344
|
+
if (headerRow) adfRows.push({
|
|
345
|
+
type: "tableRow",
|
|
346
|
+
content: headerRow.children.map((cell) => transformTableHeader(cell))
|
|
347
|
+
});
|
|
348
|
+
for (const row of bodyRows) adfRows.push({
|
|
349
|
+
type: "tableRow",
|
|
350
|
+
content: row.children.map((cell) => transformTableCell(cell))
|
|
351
|
+
});
|
|
352
|
+
return {
|
|
353
|
+
type: "table",
|
|
354
|
+
content: adfRows
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function transformTableHeader(cell) {
|
|
358
|
+
const inlines = phrasingToInlineNodes(cell.children);
|
|
359
|
+
return {
|
|
360
|
+
type: "tableHeader",
|
|
361
|
+
attrs: {},
|
|
362
|
+
content: [{
|
|
363
|
+
type: "paragraph",
|
|
364
|
+
content: inlines.length > 0 ? inlines : []
|
|
365
|
+
}]
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function transformTableCell(cell) {
|
|
369
|
+
const inlines = phrasingToInlineNodes(cell.children);
|
|
370
|
+
return {
|
|
371
|
+
type: "tableCell",
|
|
372
|
+
attrs: {},
|
|
373
|
+
content: [{
|
|
374
|
+
type: "paragraph",
|
|
375
|
+
content: inlines.length > 0 ? inlines : []
|
|
376
|
+
}]
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
//#endregion
|
|
380
|
+
//#region src/md-to-adf/transform/index.ts
|
|
381
|
+
function transformRoot(root) {
|
|
382
|
+
return {
|
|
383
|
+
version: 1,
|
|
384
|
+
type: "doc",
|
|
385
|
+
content: root.children.flatMap((node) => {
|
|
386
|
+
const result = transformBlock(node);
|
|
387
|
+
return result ? [result] : [];
|
|
388
|
+
})
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
function transformBlock(node) {
|
|
392
|
+
switch (node.type) {
|
|
393
|
+
case "heading": return transformHeading(node);
|
|
394
|
+
case "paragraph": return transformParagraph(node);
|
|
395
|
+
case "code": return transformCode(node);
|
|
396
|
+
case "thematicBreak": return transformThematicBreak(node);
|
|
397
|
+
case "blockquote": return transformBlockquote(node, (children) => children.flatMap((c) => {
|
|
398
|
+
const r = transformBlock(c);
|
|
399
|
+
return r ? [r] : [];
|
|
400
|
+
}));
|
|
401
|
+
case "list": return transformList(node, transformBlock);
|
|
402
|
+
case "table": return transformTable(node);
|
|
403
|
+
case "html": return transformHtmlBlock(node);
|
|
404
|
+
default: return null;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
//#endregion
|
|
408
|
+
//#region src/utils/sanitize.ts
|
|
409
|
+
function stripNullBytes(text) {
|
|
410
|
+
return text.replace(/\0/g, "");
|
|
411
|
+
}
|
|
412
|
+
function normalizeNewlines(text) {
|
|
413
|
+
return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
414
|
+
}
|
|
415
|
+
function trimTrailingWhitespace(text) {
|
|
416
|
+
return text.replace(/[^\S\n]+$/gm, "");
|
|
417
|
+
}
|
|
418
|
+
function collapseBlankLines(text) {
|
|
419
|
+
return text.replace(/\n{3,}/g, "\n\n");
|
|
420
|
+
}
|
|
421
|
+
function sanitizeMarkdown(text) {
|
|
422
|
+
return collapseBlankLines(trimTrailingWhitespace(normalizeNewlines(stripNullBytes(text))));
|
|
423
|
+
}
|
|
424
|
+
function sanitizeText(text) {
|
|
425
|
+
return stripNullBytes(normalizeNewlines(text));
|
|
426
|
+
}
|
|
427
|
+
//#endregion
|
|
428
|
+
//#region src/md-to-adf/index.ts
|
|
429
|
+
function mdToAdf(markdown) {
|
|
430
|
+
return transformRoot(parseMarkdown(sanitizeText(markdown)));
|
|
431
|
+
}
|
|
432
|
+
//#endregion
|
|
433
|
+
//#region src/utils/escape.ts
|
|
434
|
+
const INLINE_ESCAPE = /([\\`*_[\]~|<])/g;
|
|
435
|
+
function escapeMarkdown(text) {
|
|
436
|
+
let result = text.replace(INLINE_ESCAPE, "\\$1");
|
|
437
|
+
result = result.replace(/^(#{1,6} )/m, "\\$1");
|
|
438
|
+
result = result.replace(/^([-+]) /m, "\\$1 ");
|
|
439
|
+
result = result.replace(/^> /m, "\\> ");
|
|
440
|
+
result = result.replace(/^(\d+)\./m, "$1\\.");
|
|
441
|
+
return result;
|
|
442
|
+
}
|
|
443
|
+
//#endregion
|
|
444
|
+
//#region src/adf-to-md/serialize/marks.ts
|
|
445
|
+
function applyMarks(text, marks) {
|
|
446
|
+
if (!marks || marks.length === 0) return text;
|
|
447
|
+
let result = text;
|
|
448
|
+
if (marks.some((m) => m.type === "code")) {
|
|
449
|
+
const linkMark = marks.find((m) => m.type === "link");
|
|
450
|
+
result = `\`${result}\``;
|
|
451
|
+
if (linkMark) result = `[${result}](${linkMark.attrs.href})`;
|
|
452
|
+
return result;
|
|
453
|
+
}
|
|
454
|
+
for (const mark of marks) switch (mark.type) {
|
|
455
|
+
case "strong":
|
|
456
|
+
result = `**${result}**`;
|
|
457
|
+
break;
|
|
458
|
+
case "em":
|
|
459
|
+
result = `*${result}*`;
|
|
460
|
+
break;
|
|
461
|
+
case "strike":
|
|
462
|
+
result = `~~${result}~~`;
|
|
463
|
+
break;
|
|
464
|
+
case "underline":
|
|
465
|
+
result = `<ins>${result}</ins>`;
|
|
466
|
+
break;
|
|
467
|
+
case "subsup":
|
|
468
|
+
result = mark.attrs.type === "sub" ? `<sub>${result}</sub>` : `<sup>${result}</sup>`;
|
|
469
|
+
break;
|
|
470
|
+
case "link":
|
|
471
|
+
result = `[${result}](${mark.attrs.href}${mark.attrs.title ? ` "${mark.attrs.title}"` : ""})`;
|
|
472
|
+
break;
|
|
473
|
+
case "textColor":
|
|
474
|
+
case "backgroundColor":
|
|
475
|
+
case "alignment":
|
|
476
|
+
case "indentation":
|
|
477
|
+
case "breakout":
|
|
478
|
+
case "border":
|
|
479
|
+
case "annotation":
|
|
480
|
+
case "dataConsumer":
|
|
481
|
+
case "fragment": break;
|
|
482
|
+
}
|
|
483
|
+
return result;
|
|
484
|
+
}
|
|
485
|
+
//#endregion
|
|
486
|
+
//#region src/adf-to-md/serialize/inlines.ts
|
|
487
|
+
function serializeInlineNodes(nodes) {
|
|
488
|
+
if (!nodes || nodes.length === 0) return "";
|
|
489
|
+
return nodes.map(serializeInline).join("");
|
|
490
|
+
}
|
|
491
|
+
function serializeInline(node) {
|
|
492
|
+
switch (node.type) {
|
|
493
|
+
case "text": return applyMarks(escapeMarkdown(node.text), node.marks);
|
|
494
|
+
case "hardBreak": return "\\\n";
|
|
495
|
+
case "mention": return node.attrs.text ?? `@${node.attrs.id}`;
|
|
496
|
+
case "emoji": return node.attrs.text ?? `:${node.attrs.shortName}:`;
|
|
497
|
+
case "date": return node.attrs.timestamp;
|
|
498
|
+
case "status": return `\`[${node.attrs.text}]\``;
|
|
499
|
+
case "inlineCard": return node.attrs.url ? `<${node.attrs.url}>` : "";
|
|
500
|
+
case "mediaInline": return "";
|
|
501
|
+
default: return "";
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
//#endregion
|
|
505
|
+
//#region src/adf-to-md/serialize/blocks.ts
|
|
506
|
+
function serializeHeading(node) {
|
|
507
|
+
return `${"#".repeat(node.attrs.level)} ${serializeInlineNodes(node.content)}`;
|
|
508
|
+
}
|
|
509
|
+
function serializeParagraph(node) {
|
|
510
|
+
return serializeInlineNodes(node.content);
|
|
511
|
+
}
|
|
512
|
+
function serializeCodeBlock(node) {
|
|
513
|
+
return `\`\`\`${node.attrs?.language ?? ""}\n${node.content?.map((t) => t.text).join("") ?? ""}\n\`\`\``;
|
|
514
|
+
}
|
|
515
|
+
function serializeRule(_node) {
|
|
516
|
+
return "---";
|
|
517
|
+
}
|
|
518
|
+
function serializeBlockquote(node, serializeBlock) {
|
|
519
|
+
return node.content.map((child) => serializeBlock(child)).join("\n\n").split("\n").map((line) => `> ${line}`).join("\n");
|
|
520
|
+
}
|
|
521
|
+
//#endregion
|
|
522
|
+
//#region src/adf-to-md/serialize/lists.ts
|
|
523
|
+
function serializeBulletList(node, depth = 0) {
|
|
524
|
+
return node.content.map((item) => serializeListItem(item, "-", depth)).join("\n");
|
|
525
|
+
}
|
|
526
|
+
function serializeOrderedList(node, depth = 0) {
|
|
527
|
+
const start = node.attrs?.order ?? 1;
|
|
528
|
+
return node.content.map((item, i) => serializeListItem(item, `${start + i}.`, depth)).join("\n");
|
|
529
|
+
}
|
|
530
|
+
function serializeTaskList(node, depth = 0) {
|
|
531
|
+
return node.content.map((item) => {
|
|
532
|
+
return `${" ".repeat(depth)}- ${item.attrs.state === "DONE" ? "[x]" : "[ ]"} ${serializeInlineNodes(item.content)}`;
|
|
533
|
+
}).join("\n");
|
|
534
|
+
}
|
|
535
|
+
function serializeDecisionList(node, depth = 0) {
|
|
536
|
+
return node.content.map((item) => {
|
|
537
|
+
return `${" ".repeat(depth)}- [x] ${serializeInlineNodes(item.content)}`;
|
|
538
|
+
}).join("\n");
|
|
539
|
+
}
|
|
540
|
+
function serializeListItem(node, bullet, depth) {
|
|
541
|
+
const indent = " ".repeat(depth);
|
|
542
|
+
const parts = [];
|
|
543
|
+
for (const child of node.content) if (child.type === "paragraph") parts.push(serializeInlineNodes(child.content));
|
|
544
|
+
else if (child.type === "bulletList") parts.push("\n" + serializeBulletList(child, depth + 1));
|
|
545
|
+
else if (child.type === "orderedList") parts.push("\n" + serializeOrderedList(child, depth + 1));
|
|
546
|
+
else if (child.type === "codeBlock") {
|
|
547
|
+
const lang = child.attrs?.language ?? "";
|
|
548
|
+
const code = child.content?.map((t) => t.text).join("") ?? "";
|
|
549
|
+
parts.push(`\n\`\`\`${lang}\n${code}\n\`\`\``);
|
|
550
|
+
}
|
|
551
|
+
return `${indent}${bullet} ${parts.join("")}`;
|
|
552
|
+
}
|
|
553
|
+
//#endregion
|
|
554
|
+
//#region src/adf-to-md/serialize/panels.ts
|
|
555
|
+
const PANEL_TO_ALERT = {
|
|
556
|
+
note: "NOTE",
|
|
557
|
+
info: "TIP",
|
|
558
|
+
tip: "TIP",
|
|
559
|
+
warning: "WARNING",
|
|
560
|
+
success: "NOTE",
|
|
561
|
+
error: "CAUTION",
|
|
562
|
+
custom: "NOTE"
|
|
563
|
+
};
|
|
564
|
+
function serializePanel(node, serializeBlock) {
|
|
565
|
+
const alertType = PANEL_TO_ALERT[node.attrs.panelType] ?? "NOTE";
|
|
566
|
+
const contentLines = node.content.map((child) => serializeBlock(child)).join("\n\n");
|
|
567
|
+
return [`> [!${alertType}]`, ...contentLines.split("\n").map((l) => `> ${l}`)].join("\n");
|
|
568
|
+
}
|
|
569
|
+
function serializeExpand(node, serializeBlock) {
|
|
570
|
+
return `<details>\n<summary>${node.attrs.title ?? ""}</summary>\n\n${node.content.map((child) => serializeBlock(child)).join("\n\n")}\n</details>`;
|
|
571
|
+
}
|
|
572
|
+
function serializeMediaSingle(node) {
|
|
573
|
+
const media = node.content[0];
|
|
574
|
+
if (!media) return "";
|
|
575
|
+
const alt = media.attrs.alt ?? "image";
|
|
576
|
+
if (media.attrs.type === "link") {
|
|
577
|
+
const url = media.attrs.url;
|
|
578
|
+
if (url) return ``;
|
|
579
|
+
}
|
|
580
|
+
return `[media: ${media.attrs.id}]`;
|
|
581
|
+
}
|
|
582
|
+
function serializeBlockCard(node) {
|
|
583
|
+
const url = node.attrs.url;
|
|
584
|
+
if (!url) return "";
|
|
585
|
+
return `[${url}](${url})`;
|
|
586
|
+
}
|
|
587
|
+
function serializeEmbedCard(node) {
|
|
588
|
+
return `[${node.attrs.url}](${node.attrs.url})`;
|
|
589
|
+
}
|
|
590
|
+
//#endregion
|
|
591
|
+
//#region src/adf-to-md/serialize/tables.ts
|
|
592
|
+
function serializeTable(node) {
|
|
593
|
+
const rows = node.content;
|
|
594
|
+
if (rows.length === 0) return "";
|
|
595
|
+
const firstRow = rows[0];
|
|
596
|
+
if (!firstRow) return "";
|
|
597
|
+
const isHeaderRow = firstRow.content.some((c) => c.type === "tableHeader");
|
|
598
|
+
const serializeCell = (cell) => {
|
|
599
|
+
const para = cell.content.find((c) => c.type === "paragraph");
|
|
600
|
+
if (!para) return " ";
|
|
601
|
+
return serializeInlineNodes(para.content).trim() || " ";
|
|
602
|
+
};
|
|
603
|
+
const lines = [];
|
|
604
|
+
if (isHeaderRow) {
|
|
605
|
+
const headerCells = firstRow.content.map(serializeCell);
|
|
606
|
+
lines.push(`| ${headerCells.join(" | ")} |`);
|
|
607
|
+
lines.push(`| ${headerCells.map(() => "---").join(" | ")} |`);
|
|
608
|
+
for (const row of rows.slice(1)) {
|
|
609
|
+
const cells = row.content.map(serializeCell);
|
|
610
|
+
lines.push(`| ${cells.join(" | ")} |`);
|
|
611
|
+
}
|
|
612
|
+
} else {
|
|
613
|
+
const colCount = firstRow.content.length;
|
|
614
|
+
const headerPlaceholders = Array(colCount).fill(" ");
|
|
615
|
+
lines.push(`| ${headerPlaceholders.join(" | ")} |`);
|
|
616
|
+
lines.push(`| ${headerPlaceholders.map(() => "---").join(" | ")} |`);
|
|
617
|
+
for (const row of rows) {
|
|
618
|
+
const cells = row.content.map(serializeCell);
|
|
619
|
+
lines.push(`| ${cells.join(" | ")} |`);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
return lines.join("\n");
|
|
623
|
+
}
|
|
624
|
+
//#endregion
|
|
625
|
+
//#region src/adf-to-md/serialize/index.ts
|
|
626
|
+
function serializeBlock(node) {
|
|
627
|
+
switch (node.type) {
|
|
628
|
+
case "paragraph": return serializeParagraph(node);
|
|
629
|
+
case "heading": return serializeHeading(node);
|
|
630
|
+
case "codeBlock": return serializeCodeBlock(node);
|
|
631
|
+
case "rule": return serializeRule(node);
|
|
632
|
+
case "blockquote": return serializeBlockquote(node, serializeBlock);
|
|
633
|
+
case "bulletList": return serializeBulletList(node);
|
|
634
|
+
case "orderedList": return serializeOrderedList(node);
|
|
635
|
+
case "taskList": return serializeTaskList(node);
|
|
636
|
+
case "decisionList": return serializeDecisionList(node);
|
|
637
|
+
case "table": return serializeTable(node);
|
|
638
|
+
case "panel": return serializePanel(node, serializeBlock);
|
|
639
|
+
case "expand": return serializeExpand(node, serializeBlock);
|
|
640
|
+
case "nestedExpand": return serializeExpand(node, serializeBlock);
|
|
641
|
+
case "mediaSingle": return serializeMediaSingle(node);
|
|
642
|
+
case "blockCard": return serializeBlockCard(node);
|
|
643
|
+
case "embedCard": return serializeEmbedCard(node);
|
|
644
|
+
case "layoutSection": return serializeLayoutSection(node);
|
|
645
|
+
default: return "";
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
function serializeLayoutSection(node) {
|
|
649
|
+
return node.content.map((col) => col.content.map((child) => serializeBlock(child)).join("\n\n")).join("\n\n---\n\n");
|
|
650
|
+
}
|
|
651
|
+
//#endregion
|
|
652
|
+
//#region src/adf-to-md/index.ts
|
|
653
|
+
function adfToMd(adf) {
|
|
654
|
+
return sanitizeMarkdown(adf.content.map((node) => serializeBlock(node)).filter((p) => p.length > 0).join("\n\n"));
|
|
655
|
+
}
|
|
656
|
+
//#endregion
|
|
657
|
+
exports.adfToMd = adfToMd;
|
|
658
|
+
exports.mdToAdf = mdToAdf;
|