formatferry 1.0.34 → 1.0.36
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/index.js +332 -198
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -58205,6 +58205,7 @@ var InputSanitizer = class {
|
|
|
58205
58205
|
ALLOWED_TAGS: [
|
|
58206
58206
|
"p",
|
|
58207
58207
|
"br",
|
|
58208
|
+
"hr",
|
|
58208
58209
|
"div",
|
|
58209
58210
|
"span",
|
|
58210
58211
|
"h1",
|
|
@@ -58255,6 +58256,7 @@ var InputSanitizer = class {
|
|
|
58255
58256
|
ALLOWED_TAGS: [
|
|
58256
58257
|
"p",
|
|
58257
58258
|
"br",
|
|
58259
|
+
"hr",
|
|
58258
58260
|
"div",
|
|
58259
58261
|
"span",
|
|
58260
58262
|
"h1",
|
|
@@ -58513,6 +58515,49 @@ function normalizeAtlassianHTML(html, domParser) {
|
|
|
58513
58515
|
|
|
58514
58516
|
// ../../src/shared/confluence-slack-services.ts
|
|
58515
58517
|
var import_turndown = __toESM(require_turndown_cjs(), 1);
|
|
58518
|
+
|
|
58519
|
+
// ../../src/shared/text-decoration.ts
|
|
58520
|
+
var DECLARATION = /(?:^|;)\s*text-decoration(?:-line)?\s*:([^;]*)/gi;
|
|
58521
|
+
function styleDecorations(style) {
|
|
58522
|
+
const result = { underline: false, strike: false };
|
|
58523
|
+
if (!style) return result;
|
|
58524
|
+
DECLARATION.lastIndex = 0;
|
|
58525
|
+
let match;
|
|
58526
|
+
while ((match = DECLARATION.exec(style)) !== null) {
|
|
58527
|
+
const value = match[1].toLowerCase();
|
|
58528
|
+
result.underline = /\bunderline\b/.test(value);
|
|
58529
|
+
result.strike = /\bline-through\b/.test(value);
|
|
58530
|
+
}
|
|
58531
|
+
return result;
|
|
58532
|
+
}
|
|
58533
|
+
function nodeStyle(node) {
|
|
58534
|
+
const el = node;
|
|
58535
|
+
return typeof el.getAttribute === "function" ? el.getAttribute("style") || "" : "";
|
|
58536
|
+
}
|
|
58537
|
+
function nodeDecorations(node) {
|
|
58538
|
+
const fromStyle = styleDecorations(nodeStyle(node));
|
|
58539
|
+
const name = node.nodeName;
|
|
58540
|
+
return {
|
|
58541
|
+
underline: fromStyle.underline || name === "U" || name === "INS",
|
|
58542
|
+
strike: fromStyle.strike || name === "DEL" || name === "S" || name === "STRIKE"
|
|
58543
|
+
};
|
|
58544
|
+
}
|
|
58545
|
+
function isUnderlineSpan(node) {
|
|
58546
|
+
return node.nodeName === "SPAN" && styleDecorations(nodeStyle(node)).underline;
|
|
58547
|
+
}
|
|
58548
|
+
function isStrikeSpan(node) {
|
|
58549
|
+
return node.nodeName === "SPAN" && styleDecorations(nodeStyle(node)).strike;
|
|
58550
|
+
}
|
|
58551
|
+
function decorate(content, node, syntax) {
|
|
58552
|
+
if (!content.trim()) return content;
|
|
58553
|
+
const d = nodeDecorations(node);
|
|
58554
|
+
let out = content;
|
|
58555
|
+
if (d.underline && syntax.underline) out = syntax.underline[0] + out + syntax.underline[1];
|
|
58556
|
+
if (d.strike && syntax.strike) out = syntax.strike[0] + out + syntax.strike[1];
|
|
58557
|
+
return out;
|
|
58558
|
+
}
|
|
58559
|
+
|
|
58560
|
+
// ../../src/shared/confluence-slack-services.ts
|
|
58516
58561
|
function escapeSlackEntities(text) {
|
|
58517
58562
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
58518
58563
|
}
|
|
@@ -58575,13 +58620,9 @@ function createSlackService(deps) {
|
|
|
58575
58620
|
service.addRule("slackStrikethrough", {
|
|
58576
58621
|
filter: (node) => {
|
|
58577
58622
|
if (["DEL", "S", "STRIKE"].includes(node.nodeName)) return true;
|
|
58578
|
-
|
|
58579
|
-
const style = node.getAttribute("style") || "";
|
|
58580
|
-
return style.includes("text-decoration: line-through") || style.includes("text-decoration:line-through") || style.includes("text-decoration-line: line-through") || style.includes("text-decoration-line:line-through");
|
|
58581
|
-
}
|
|
58582
|
-
return false;
|
|
58623
|
+
return isStrikeSpan(node);
|
|
58583
58624
|
},
|
|
58584
|
-
replacement: (content) => content
|
|
58625
|
+
replacement: (content, node) => decorate(content, node, { underline: null, strike: ["~", "~"] })
|
|
58585
58626
|
});
|
|
58586
58627
|
service.addRule("slackMonospaceCode", {
|
|
58587
58628
|
filter: (node) => {
|
|
@@ -58642,13 +58683,10 @@ ${escapeSlackEntities(code)}
|
|
|
58642
58683
|
service.addRule("slackUnderline", {
|
|
58643
58684
|
filter: (node) => {
|
|
58644
58685
|
if (node.nodeName === "U" || node.nodeName === "INS") return true;
|
|
58645
|
-
|
|
58646
|
-
const style = node.getAttribute("style") || "";
|
|
58647
|
-
return style.includes("text-decoration: underline") || style.includes("text-decoration:underline");
|
|
58648
|
-
}
|
|
58649
|
-
return false;
|
|
58686
|
+
return isUnderlineSpan(node);
|
|
58650
58687
|
},
|
|
58651
|
-
|
|
58688
|
+
// Slack has no underline; keep a strikethrough set on the same span
|
|
58689
|
+
replacement: (content, node) => decorate(content, node, { underline: null, strike: ["~", "~"] })
|
|
58652
58690
|
});
|
|
58653
58691
|
service.addRule("slackLink", {
|
|
58654
58692
|
filter: (node) => node.nodeName === "A" && !!node.getAttribute("href"),
|
|
@@ -58680,34 +58718,38 @@ ${plainText}
|
|
|
58680
58718
|
});
|
|
58681
58719
|
return service;
|
|
58682
58720
|
}
|
|
58683
|
-
function processConfluenceList(list, service,
|
|
58684
|
-
const
|
|
58685
|
-
const marker = (isOrdered ? "#" : "*").repeat(depth);
|
|
58721
|
+
function processConfluenceList(list, service, parentPrefix) {
|
|
58722
|
+
const prefix = parentPrefix + (list.nodeName === "OL" ? "#" : "*");
|
|
58686
58723
|
const items = Array.from(list.children).filter((c) => c.nodeName === "LI");
|
|
58687
|
-
|
|
58724
|
+
const isTop = parentPrefix === "";
|
|
58725
|
+
let result = isTop ? "\n" : "";
|
|
58688
58726
|
items.forEach((item) => {
|
|
58689
|
-
const itemContent = processConfluenceListItem(item, service,
|
|
58690
|
-
result += `${
|
|
58727
|
+
const itemContent = processConfluenceListItem(item, service, prefix);
|
|
58728
|
+
result += `${prefix} ${itemContent}
|
|
58691
58729
|
`;
|
|
58692
58730
|
});
|
|
58693
|
-
return
|
|
58731
|
+
return isTop ? result + "\n" : result;
|
|
58694
58732
|
}
|
|
58695
|
-
function processConfluenceListItem(item, service,
|
|
58696
|
-
let content = "";
|
|
58697
|
-
const TEXT_NODE = 3;
|
|
58733
|
+
function processConfluenceListItem(item, service, prefix) {
|
|
58698
58734
|
const ELEMENT_NODE2 = 1;
|
|
58735
|
+
const doc = item.ownerDocument;
|
|
58736
|
+
let content = "";
|
|
58737
|
+
let buffer = doc.createElement("div");
|
|
58738
|
+
const flush = () => {
|
|
58739
|
+
if (buffer.childNodes.length > 0) {
|
|
58740
|
+
content += service.turndown(buffer).replace(/[ \t]*\n(?:[ \t]*\n)+[ \t]*/g, " \\\\ ");
|
|
58741
|
+
}
|
|
58742
|
+
buffer = doc.createElement("div");
|
|
58743
|
+
};
|
|
58699
58744
|
Array.from(item.childNodes).forEach((child) => {
|
|
58700
|
-
if (child.nodeType ===
|
|
58701
|
-
|
|
58702
|
-
|
|
58703
|
-
|
|
58704
|
-
|
|
58705
|
-
content += "\n" + processConfluenceList(el, service, depth + 1);
|
|
58706
|
-
} else {
|
|
58707
|
-
content += service.turndown(el.outerHTML);
|
|
58708
|
-
}
|
|
58745
|
+
if (child.nodeType === ELEMENT_NODE2 && (child.nodeName === "UL" || child.nodeName === "OL")) {
|
|
58746
|
+
flush();
|
|
58747
|
+
content = content.trimEnd() + "\n" + processConfluenceList(child, service, prefix);
|
|
58748
|
+
} else {
|
|
58749
|
+
buffer.appendChild(child.cloneNode(true));
|
|
58709
58750
|
}
|
|
58710
58751
|
});
|
|
58752
|
+
flush();
|
|
58711
58753
|
return content.trim();
|
|
58712
58754
|
}
|
|
58713
58755
|
function createConfluenceService(deps) {
|
|
@@ -58783,24 +58825,16 @@ ${codeContent}
|
|
|
58783
58825
|
service.addRule("confluenceUnderline", {
|
|
58784
58826
|
filter: (node) => {
|
|
58785
58827
|
if (node.nodeName === "U" || node.nodeName === "INS") return true;
|
|
58786
|
-
|
|
58787
|
-
const style = node.getAttribute("style") || "";
|
|
58788
|
-
return style.includes("text-decoration: underline") || style.includes("text-decoration:underline");
|
|
58789
|
-
}
|
|
58790
|
-
return false;
|
|
58828
|
+
return isUnderlineSpan(node);
|
|
58791
58829
|
},
|
|
58792
|
-
replacement: (content) => content
|
|
58830
|
+
replacement: (content, node) => decorate(content, node, { underline: ["+", "+"], strike: ["-", "-"] })
|
|
58793
58831
|
});
|
|
58794
58832
|
service.addRule("confluenceStrikethrough", {
|
|
58795
58833
|
filter: (node) => {
|
|
58796
58834
|
if (["DEL", "S", "STRIKE"].includes(node.nodeName)) return true;
|
|
58797
|
-
|
|
58798
|
-
const style = node.getAttribute("style") || "";
|
|
58799
|
-
return style.includes("text-decoration: line-through") || style.includes("text-decoration:line-through") || style.includes("text-decoration-line: line-through") || style.includes("text-decoration-line:line-through");
|
|
58800
|
-
}
|
|
58801
|
-
return false;
|
|
58835
|
+
return isStrikeSpan(node);
|
|
58802
58836
|
},
|
|
58803
|
-
replacement: (content) => content
|
|
58837
|
+
replacement: (content, node) => decorate(content, node, { underline: ["+", "+"], strike: ["-", "-"] })
|
|
58804
58838
|
});
|
|
58805
58839
|
service.addRule("confluenceMonospaceCode", {
|
|
58806
58840
|
filter: (node) => {
|
|
@@ -58884,7 +58918,7 @@ h${level}. ${trimmed}
|
|
|
58884
58918
|
service.addRule("confluenceList", {
|
|
58885
58919
|
filter: ["ul", "ol"],
|
|
58886
58920
|
replacement: (_content, node) => {
|
|
58887
|
-
return processConfluenceList(node, service,
|
|
58921
|
+
return processConfluenceList(node, service, "");
|
|
58888
58922
|
}
|
|
58889
58923
|
});
|
|
58890
58924
|
service.addRule("confluenceTable", {
|
|
@@ -58898,7 +58932,7 @@ h${level}. ${trimmed}
|
|
|
58898
58932
|
const cells = Array.from(row.querySelectorAll("th, td"));
|
|
58899
58933
|
const isHeaderRow = cells.some((c) => c.nodeName === "TH");
|
|
58900
58934
|
const delim = isHeaderRow ? "||" : "|";
|
|
58901
|
-
const cellTexts = cells.map((c) => (c.textContent || "").trim());
|
|
58935
|
+
const cellTexts = cells.map((c) => (c.textContent || "").trim().replace(/\|/g, "\\|"));
|
|
58902
58936
|
result += delim + cellTexts.join(delim) + delim + "\n";
|
|
58903
58937
|
});
|
|
58904
58938
|
return result + "\n";
|
|
@@ -58981,7 +59015,7 @@ var ConversionEngine = class {
|
|
|
58981
59015
|
emDelimiter: "_"
|
|
58982
59016
|
});
|
|
58983
59017
|
this.addGoogleDocsRules(this.githubService);
|
|
58984
|
-
this.addGoogleDocsRules(this.commonmarkService);
|
|
59018
|
+
this.addGoogleDocsRules(this.commonmarkService, ["<del>", "</del>"]);
|
|
58985
59019
|
this.addGoogleDocsRules(this.customService);
|
|
58986
59020
|
this.addTableRules(this.githubService);
|
|
58987
59021
|
this.addTableRules(this.commonmarkService);
|
|
@@ -58995,6 +59029,13 @@ var ConversionEngine = class {
|
|
|
58995
59029
|
this.addSupSubMathRules(this.githubService);
|
|
58996
59030
|
this.addSupSubMathRules(this.commonmarkService);
|
|
58997
59031
|
this.addSupSubMathRules(this.customService);
|
|
59032
|
+
this.commonmarkService.addRule("commonmarkStrikethrough", {
|
|
59033
|
+
filter: (node) => {
|
|
59034
|
+
if (["DEL", "S", "STRIKE"].includes(node.nodeName)) return true;
|
|
59035
|
+
return isStrikeSpan(node);
|
|
59036
|
+
},
|
|
59037
|
+
replacement: (content, node) => decorate(content, node, { underline: ["<u>", "</u>"], strike: ["<del>", "</del>"] })
|
|
59038
|
+
});
|
|
58998
59039
|
this.addPdfPageMarkerRules(this.githubService);
|
|
58999
59040
|
this.addPdfPageMarkerRules(this.commonmarkService);
|
|
59000
59041
|
this.addPdfPageMarkerRules(this.customService);
|
|
@@ -59013,6 +59054,37 @@ var ConversionEngine = class {
|
|
|
59013
59054
|
this.confluenceService = createConfluenceService(deps);
|
|
59014
59055
|
this.addSlideMarkerRules(this.slackService);
|
|
59015
59056
|
this.addSlideMarkerRules(this.confluenceService);
|
|
59057
|
+
[
|
|
59058
|
+
this.githubService,
|
|
59059
|
+
this.commonmarkService,
|
|
59060
|
+
this.customService,
|
|
59061
|
+
this.discordService,
|
|
59062
|
+
this.redditService,
|
|
59063
|
+
this.rmarkdownService,
|
|
59064
|
+
this.slackService,
|
|
59065
|
+
this.confluenceService
|
|
59066
|
+
].forEach((service) => this.addGoogleDocsWrapperRule(service));
|
|
59067
|
+
}
|
|
59068
|
+
/**
|
|
59069
|
+
* Google Docs wraps every copied selection in
|
|
59070
|
+
* <b style="font-weight:normal" id="docs-internal-guid-...">. Treating that
|
|
59071
|
+
* as bold puts a stray pair of bold markers around the whole document, so a
|
|
59072
|
+
* <b>/<strong> whose inline style explicitly sets a non-bold weight is
|
|
59073
|
+
* rendered as its plain content.
|
|
59074
|
+
*/
|
|
59075
|
+
addGoogleDocsWrapperRule(service) {
|
|
59076
|
+
service.addRule("googleDocsNonBoldWrapper", {
|
|
59077
|
+
filter: (node) => {
|
|
59078
|
+
if (node.nodeName !== "B" && node.nodeName !== "STRONG") return false;
|
|
59079
|
+
const style = (node.getAttribute("style") || "").toLowerCase();
|
|
59080
|
+
const matches = [...style.matchAll(/font-weight\s*:\s*([a-z0-9]+)/g)];
|
|
59081
|
+
if (matches.length === 0) return false;
|
|
59082
|
+
const weight = matches[matches.length - 1][1];
|
|
59083
|
+
if (weight === "normal" || weight === "lighter") return true;
|
|
59084
|
+
return /^\d+$/.test(weight) && parseInt(weight, 10) < 600;
|
|
59085
|
+
},
|
|
59086
|
+
replacement: (content) => content
|
|
59087
|
+
});
|
|
59016
59088
|
}
|
|
59017
59089
|
/**
|
|
59018
59090
|
* Create Discord-optimized Turndown service
|
|
@@ -59034,8 +59106,10 @@ var ConversionEngine = class {
|
|
|
59034
59106
|
this.addPdfPageMarkerRules(service);
|
|
59035
59107
|
this.addSlideMarkerRules(service);
|
|
59036
59108
|
service.addRule("discordUnderline", {
|
|
59037
|
-
|
|
59038
|
-
|
|
59109
|
+
// Includes Google Docs CSS underline, which the shared rules would
|
|
59110
|
+
// otherwise emit as <u>…</u> (shown literally in Discord)
|
|
59111
|
+
filter: (node) => node.nodeName === "U" || node.nodeName === "INS" || isUnderlineSpan(node),
|
|
59112
|
+
replacement: (content, node) => decorate(content, node, { underline: ["__", "__"], strike: ["~~", "~~"] })
|
|
59039
59113
|
});
|
|
59040
59114
|
service.addRule("discordHeadingLimit", {
|
|
59041
59115
|
filter: ["h4", "h5", "h6"],
|
|
@@ -59069,7 +59143,7 @@ ${plainText}
|
|
|
59069
59143
|
},
|
|
59070
59144
|
replacement: (_content, node) => {
|
|
59071
59145
|
const checked = node.checked || node.hasAttribute("checked");
|
|
59072
|
-
return checked ? "\u2611
|
|
59146
|
+
return (checked ? "\u2611" : "\u2610") + this.checkboxSpacer(node);
|
|
59073
59147
|
}
|
|
59074
59148
|
});
|
|
59075
59149
|
return service;
|
|
@@ -59097,9 +59171,9 @@ ${plainText}
|
|
|
59097
59171
|
* Converts Unicode checkboxes to [x] and [ ]
|
|
59098
59172
|
*/
|
|
59099
59173
|
normalizeGitHubCheckboxes(markdown) {
|
|
59100
|
-
let result = markdown;
|
|
59101
|
-
result = result.replace(/^([
|
|
59102
|
-
result = result.replace(/^([
|
|
59174
|
+
let result = markdown.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)\\\[([ xX])\\\]/gm, "$1[$2]");
|
|
59175
|
+
result = result.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)[☑✓✔■⬛]/gm, "$1[x]");
|
|
59176
|
+
result = result.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)[☐✗✘□⬜]/gm, "$1[ ]");
|
|
59103
59177
|
return result;
|
|
59104
59178
|
}
|
|
59105
59179
|
/**
|
|
@@ -59107,10 +59181,10 @@ ${plainText}
|
|
|
59107
59181
|
* Converts [x], [ ], and other checkbox patterns to emoji
|
|
59108
59182
|
*/
|
|
59109
59183
|
normalizeDiscordCheckboxes(markdown) {
|
|
59110
|
-
let result = markdown.replace(/^([
|
|
59111
|
-
result = result.replace(/^([
|
|
59112
|
-
result = result.replace(/^([
|
|
59113
|
-
result = result.replace(/^([
|
|
59184
|
+
let result = markdown.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)\\?\[x\\?\]/gmi, "$1\u2611");
|
|
59185
|
+
result = result.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)[✓✔■⬛]/gm, "$1\u2611");
|
|
59186
|
+
result = result.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)\\?\[\s?\\?\]/gm, "$1\u2610");
|
|
59187
|
+
result = result.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)[✗✘□⬜]/gm, "$1\u2610");
|
|
59114
59188
|
return result;
|
|
59115
59189
|
}
|
|
59116
59190
|
/**
|
|
@@ -59118,7 +59192,6 @@ ${plainText}
|
|
|
59118
59192
|
* Converts Unicode superscript to ^text syntax
|
|
59119
59193
|
*/
|
|
59120
59194
|
normalizeRedditUnicode(markdown) {
|
|
59121
|
-
let result = markdown;
|
|
59122
59195
|
const superscriptMap = {
|
|
59123
59196
|
"\u2070": "0",
|
|
59124
59197
|
"\xB9": "1",
|
|
@@ -59133,9 +59206,6 @@ ${plainText}
|
|
|
59133
59206
|
"\u207F": "n",
|
|
59134
59207
|
"\u2071": "i"
|
|
59135
59208
|
};
|
|
59136
|
-
for (const [unicode, digit] of Object.entries(superscriptMap)) {
|
|
59137
|
-
result = result.replace(new RegExp(unicode, "g"), `^${digit}`);
|
|
59138
|
-
}
|
|
59139
59209
|
const subscriptMap = {
|
|
59140
59210
|
"\u2080": "0",
|
|
59141
59211
|
"\u2081": "1",
|
|
@@ -59148,17 +59218,13 @@ ${plainText}
|
|
|
59148
59218
|
"\u2088": "8",
|
|
59149
59219
|
"\u2089": "9"
|
|
59150
59220
|
};
|
|
59151
|
-
|
|
59152
|
-
result = result.replace(new RegExp(unicode, "g"), `[${digit}]`);
|
|
59153
|
-
}
|
|
59154
|
-
return result;
|
|
59221
|
+
return this.replaceOutsideCode(markdown, (text) => text.replace(/[⁰¹²³⁴⁵⁶⁷⁸⁹ⁿⁱ]+/g, (run) => `^(${Array.from(run).map((c) => superscriptMap[c]).join("")})`).replace(/[₀₁₂₃₄₅₆₇₈₉]+/g, (run) => `[${Array.from(run).map((c) => subscriptMap[c]).join("")}]`));
|
|
59155
59222
|
}
|
|
59156
59223
|
/**
|
|
59157
59224
|
* Normalize Unicode for R Markdown format
|
|
59158
59225
|
* Converts Unicode superscript/subscript to Pandoc syntax
|
|
59159
59226
|
*/
|
|
59160
59227
|
normalizeRMarkdownUnicode(markdown) {
|
|
59161
|
-
let result = markdown;
|
|
59162
59228
|
const superscriptMap = {
|
|
59163
59229
|
"\u2070": "0",
|
|
59164
59230
|
"\xB9": "1",
|
|
@@ -59173,9 +59239,6 @@ ${plainText}
|
|
|
59173
59239
|
"\u207F": "n",
|
|
59174
59240
|
"\u2071": "i"
|
|
59175
59241
|
};
|
|
59176
|
-
for (const [unicode, digit] of Object.entries(superscriptMap)) {
|
|
59177
|
-
result = result.replace(new RegExp(unicode, "g"), `^${digit}^`);
|
|
59178
|
-
}
|
|
59179
59242
|
const subscriptMap = {
|
|
59180
59243
|
"\u2080": "0",
|
|
59181
59244
|
"\u2081": "1",
|
|
@@ -59188,10 +59251,7 @@ ${plainText}
|
|
|
59188
59251
|
"\u2088": "8",
|
|
59189
59252
|
"\u2089": "9"
|
|
59190
59253
|
};
|
|
59191
|
-
|
|
59192
|
-
result = result.replace(new RegExp(unicode, "g"), `~${digit}~`);
|
|
59193
|
-
}
|
|
59194
|
-
return result;
|
|
59254
|
+
return this.replaceOutsideCode(markdown, (text) => text.replace(/[⁰¹²³⁴⁵⁶⁷⁸⁹ⁿⁱ]+/g, (run) => `^${Array.from(run).map((c) => superscriptMap[c]).join("")}^`).replace(/[₀₁₂₃₄₅₆₇₈₉]+/g, (run) => `~${Array.from(run).map((c) => subscriptMap[c]).join("")}~`));
|
|
59195
59255
|
}
|
|
59196
59256
|
/**
|
|
59197
59257
|
* Create Reddit-optimized Turndown service
|
|
@@ -59199,6 +59259,104 @@ ${plainText}
|
|
|
59199
59259
|
* - Subscript to bracketed text
|
|
59200
59260
|
* - Fenced code blocks (new Reddit)
|
|
59201
59261
|
*/
|
|
59262
|
+
/**
|
|
59263
|
+
* Reddit's bare ^word superscript runs to the next space, so "x^2y" would
|
|
59264
|
+
* superscript "2y". The parenthesised form ^(…) always ends where it should.
|
|
59265
|
+
*/
|
|
59266
|
+
redditSuperscript(content) {
|
|
59267
|
+
const trimmed = content.trim();
|
|
59268
|
+
return trimmed ? `^(${trimmed.replace(/\)/g, "\\)")})` : "";
|
|
59269
|
+
}
|
|
59270
|
+
/**
|
|
59271
|
+
* Pandoc ^x^ / ~x~ cannot contain bare spaces (they must be backslash-escaped),
|
|
59272
|
+
* and a bare delimiter inside the content would close the span early.
|
|
59273
|
+
*/
|
|
59274
|
+
pandocScript(content, delimiter) {
|
|
59275
|
+
const trimmed = content.trim();
|
|
59276
|
+
if (!trimmed) return "";
|
|
59277
|
+
const escaped = trimmed.replace(delimiter === "^" ? /(?<!\\)\^/g : /(?<!\\)~/g, `\\${delimiter}`).replace(/ /g, "\\ ");
|
|
59278
|
+
return `${delimiter}${escaped}${delimiter}`;
|
|
59279
|
+
}
|
|
59280
|
+
/**
|
|
59281
|
+
* Apply a text transform everywhere except fenced code blocks and inline code spans.
|
|
59282
|
+
*
|
|
59283
|
+
* Fences may use ``` or ~~~ of any length (3+) and may sit behind list
|
|
59284
|
+
* indentation or blockquote markers; a fence closes only on a run of the same
|
|
59285
|
+
* character at least as long as the opener. Inline code spans close on a
|
|
59286
|
+
* backtick run of exactly the opening length (CommonMark), so `` a`b `` is
|
|
59287
|
+
* protected whole.
|
|
59288
|
+
*/
|
|
59289
|
+
replaceOutsideCode(markdown, transform) {
|
|
59290
|
+
const fenceOpen = /^((?:[ \t]*>)*[ \t]*(?:(?:[-*+]|\d+[.)])[ \t]+)?[ \t]*)(`{3,}|~{3,})/;
|
|
59291
|
+
const lines = markdown.split(/(?<=\n)/);
|
|
59292
|
+
const segments = [];
|
|
59293
|
+
const push = (text, code) => {
|
|
59294
|
+
const last = segments[segments.length - 1];
|
|
59295
|
+
if (last && last.code === code) last.text += text;
|
|
59296
|
+
else segments.push({ text, code });
|
|
59297
|
+
};
|
|
59298
|
+
let fence = null;
|
|
59299
|
+
for (const line of lines) {
|
|
59300
|
+
if (fence) {
|
|
59301
|
+
push(line, true);
|
|
59302
|
+
const body = line.replace(/^(?:[ \t]*>)*[ \t]*/, "");
|
|
59303
|
+
const close = body.match(/^(`{3,}|~{3,})[ \t]*\r?\n?$/);
|
|
59304
|
+
if (close && close[1][0] === fence.char && close[1].length >= fence.len) fence = null;
|
|
59305
|
+
continue;
|
|
59306
|
+
}
|
|
59307
|
+
const open = line.match(fenceOpen);
|
|
59308
|
+
if (open && !(open[2][0] === "`" && line.slice(open[0].length).includes("`"))) {
|
|
59309
|
+
fence = { char: open[2][0], len: open[2].length };
|
|
59310
|
+
push(line, true);
|
|
59311
|
+
continue;
|
|
59312
|
+
}
|
|
59313
|
+
push(line, false);
|
|
59314
|
+
}
|
|
59315
|
+
const out = [];
|
|
59316
|
+
for (const seg of segments) {
|
|
59317
|
+
if (seg.code) {
|
|
59318
|
+
out.push(seg.text);
|
|
59319
|
+
continue;
|
|
59320
|
+
}
|
|
59321
|
+
const text = seg.text;
|
|
59322
|
+
let plainStart = 0;
|
|
59323
|
+
let i = 0;
|
|
59324
|
+
while (i < text.length) {
|
|
59325
|
+
if (text[i] !== "`") {
|
|
59326
|
+
i++;
|
|
59327
|
+
continue;
|
|
59328
|
+
}
|
|
59329
|
+
let j = i;
|
|
59330
|
+
while (j < text.length && text[j] === "`") j++;
|
|
59331
|
+
const runLen = j - i;
|
|
59332
|
+
let k = j;
|
|
59333
|
+
let closeAt = -1;
|
|
59334
|
+
while (k < text.length) {
|
|
59335
|
+
if (text[k] !== "`") {
|
|
59336
|
+
k++;
|
|
59337
|
+
continue;
|
|
59338
|
+
}
|
|
59339
|
+
let m = k;
|
|
59340
|
+
while (m < text.length && text[m] === "`") m++;
|
|
59341
|
+
if (m - k === runLen) {
|
|
59342
|
+
closeAt = m;
|
|
59343
|
+
break;
|
|
59344
|
+
}
|
|
59345
|
+
k = m;
|
|
59346
|
+
}
|
|
59347
|
+
if (closeAt === -1) {
|
|
59348
|
+
i = j;
|
|
59349
|
+
continue;
|
|
59350
|
+
}
|
|
59351
|
+
out.push(transform(text.slice(plainStart, i)));
|
|
59352
|
+
out.push(text.slice(i, closeAt));
|
|
59353
|
+
plainStart = closeAt;
|
|
59354
|
+
i = closeAt;
|
|
59355
|
+
}
|
|
59356
|
+
out.push(transform(text.slice(plainStart)));
|
|
59357
|
+
}
|
|
59358
|
+
return out.join("");
|
|
59359
|
+
}
|
|
59202
59360
|
createRedditService() {
|
|
59203
59361
|
const service = new import_turndown2.default({
|
|
59204
59362
|
headingStyle: "atx",
|
|
@@ -59212,13 +59370,15 @@ ${plainText}
|
|
|
59212
59370
|
this.addListRules(service);
|
|
59213
59371
|
this.addPdfPageMarkerRules(service);
|
|
59214
59372
|
this.addSlideMarkerRules(service);
|
|
59373
|
+
service.addRule("redditUnderline", {
|
|
59374
|
+
filter: (node) => node.nodeName === "U" || node.nodeName === "INS" || isUnderlineSpan(node),
|
|
59375
|
+
// Keep a strikethrough set on the same span
|
|
59376
|
+
replacement: (content, node) => decorate(content, node, { underline: null, strike: ["~~", "~~"] })
|
|
59377
|
+
});
|
|
59378
|
+
this.addTaskListRules(service);
|
|
59215
59379
|
service.addRule("redditSuperscript", {
|
|
59216
59380
|
filter: (node) => node.nodeName === "SUP",
|
|
59217
|
-
replacement: (content) =>
|
|
59218
|
-
const trimmed = content.trim();
|
|
59219
|
-
if (!trimmed) return "";
|
|
59220
|
-
return trimmed.includes(" ") ? `^(${trimmed})` : `^${trimmed}`;
|
|
59221
|
-
}
|
|
59381
|
+
replacement: (content) => this.redditSuperscript(content)
|
|
59222
59382
|
});
|
|
59223
59383
|
service.addRule("redditSuperscriptStyle", {
|
|
59224
59384
|
filter: (node) => {
|
|
@@ -59226,11 +59386,7 @@ ${plainText}
|
|
|
59226
59386
|
const style = node.getAttribute("style") || "";
|
|
59227
59387
|
return style.includes("vertical-align: super") || style.includes("vertical-align:super");
|
|
59228
59388
|
},
|
|
59229
|
-
replacement: (content) =>
|
|
59230
|
-
const trimmed = content.trim();
|
|
59231
|
-
if (!trimmed) return "";
|
|
59232
|
-
return trimmed.includes(" ") ? `^(${trimmed})` : `^${trimmed}`;
|
|
59233
|
-
}
|
|
59389
|
+
replacement: (content) => this.redditSuperscript(content)
|
|
59234
59390
|
});
|
|
59235
59391
|
service.addRule("redditSubscript", {
|
|
59236
59392
|
filter: (node) => node.nodeName === "SUB",
|
|
@@ -59271,12 +59427,10 @@ ${plainText}
|
|
|
59271
59427
|
this.addListRules(service);
|
|
59272
59428
|
this.addPdfPageMarkerRules(service);
|
|
59273
59429
|
this.addSlideMarkerRules(service);
|
|
59430
|
+
this.addTaskListRules(service);
|
|
59274
59431
|
service.addRule("rmdSuperscript", {
|
|
59275
59432
|
filter: (node) => node.nodeName === "SUP",
|
|
59276
|
-
replacement: (content) =>
|
|
59277
|
-
const trimmed = content.trim();
|
|
59278
|
-
return trimmed ? `^${trimmed}^` : "";
|
|
59279
|
-
}
|
|
59433
|
+
replacement: (content) => this.pandocScript(content, "^")
|
|
59280
59434
|
});
|
|
59281
59435
|
service.addRule("rmdSuperscriptStyle", {
|
|
59282
59436
|
filter: (node) => {
|
|
@@ -59284,17 +59438,11 @@ ${plainText}
|
|
|
59284
59438
|
const style = node.getAttribute("style") || "";
|
|
59285
59439
|
return style.includes("vertical-align: super") || style.includes("vertical-align:super");
|
|
59286
59440
|
},
|
|
59287
|
-
replacement: (content) =>
|
|
59288
|
-
const trimmed = content.trim();
|
|
59289
|
-
return trimmed ? `^${trimmed}^` : "";
|
|
59290
|
-
}
|
|
59441
|
+
replacement: (content) => this.pandocScript(content, "^")
|
|
59291
59442
|
});
|
|
59292
59443
|
service.addRule("rmdSubscript", {
|
|
59293
59444
|
filter: (node) => node.nodeName === "SUB",
|
|
59294
|
-
replacement: (content) =>
|
|
59295
|
-
const trimmed = content.trim();
|
|
59296
|
-
return trimmed ? `~${trimmed}~` : "";
|
|
59297
|
-
}
|
|
59445
|
+
replacement: (content) => this.pandocScript(content, "~")
|
|
59298
59446
|
});
|
|
59299
59447
|
service.addRule("rmdSubscriptStyle", {
|
|
59300
59448
|
filter: (node) => {
|
|
@@ -59302,10 +59450,7 @@ ${plainText}
|
|
|
59302
59450
|
const style = node.getAttribute("style") || "";
|
|
59303
59451
|
return style.includes("vertical-align: sub") || style.includes("vertical-align:sub");
|
|
59304
59452
|
},
|
|
59305
|
-
replacement: (content) =>
|
|
59306
|
-
const trimmed = content.trim();
|
|
59307
|
-
return trimmed ? `~${trimmed}~` : "";
|
|
59308
|
-
}
|
|
59453
|
+
replacement: (content) => this.pandocScript(content, "~")
|
|
59309
59454
|
});
|
|
59310
59455
|
service.addRule("rmdMath", {
|
|
59311
59456
|
filter: (node) => {
|
|
@@ -59365,7 +59510,7 @@ ${plainText}
|
|
|
59365
59510
|
});
|
|
59366
59511
|
return doc.body.firstElementChild?.innerHTML ?? html;
|
|
59367
59512
|
}
|
|
59368
|
-
addGoogleDocsRules(service) {
|
|
59513
|
+
addGoogleDocsRules(service, strike = ["~~", "~~"]) {
|
|
59369
59514
|
service.addRule("googleDocsBold", {
|
|
59370
59515
|
filter: (node) => {
|
|
59371
59516
|
if (node.nodeName !== "SPAN") return false;
|
|
@@ -59435,16 +59580,9 @@ ${plainText}
|
|
|
59435
59580
|
}
|
|
59436
59581
|
});
|
|
59437
59582
|
service.addRule("googleDocsUnderline", {
|
|
59438
|
-
filter: (node) =>
|
|
59439
|
-
|
|
59440
|
-
|
|
59441
|
-
return style.includes("text-decoration: underline") || style.includes("text-decoration:underline");
|
|
59442
|
-
}
|
|
59443
|
-
return false;
|
|
59444
|
-
},
|
|
59445
|
-
replacement: (content) => {
|
|
59446
|
-
return content.trim() ? `<u>${content}</u>` : content;
|
|
59447
|
-
}
|
|
59583
|
+
filter: (node) => isUnderlineSpan(node),
|
|
59584
|
+
// Also applies a line-through set on the same span
|
|
59585
|
+
replacement: (content, node) => decorate(content, node, { underline: ["<u>", "</u>"], strike })
|
|
59448
59586
|
});
|
|
59449
59587
|
service.addRule("strikethroughTags", {
|
|
59450
59588
|
filter: ["del", "s"],
|
|
@@ -59459,14 +59597,9 @@ ${plainText}
|
|
|
59459
59597
|
}
|
|
59460
59598
|
});
|
|
59461
59599
|
service.addRule("strikethroughStyle", {
|
|
59462
|
-
filter: (node) =>
|
|
59463
|
-
|
|
59464
|
-
|
|
59465
|
-
return style.includes("text-decoration: line-through") || style.includes("text-decoration:line-through") || style.includes("text-decoration-line: line-through") || style.includes("text-decoration-line:line-through");
|
|
59466
|
-
},
|
|
59467
|
-
replacement: (content) => {
|
|
59468
|
-
return content.trim() ? `~~${content}~~` : content;
|
|
59469
|
-
}
|
|
59600
|
+
filter: (node) => isStrikeSpan(node),
|
|
59601
|
+
// Also applies an underline set on the same span
|
|
59602
|
+
replacement: (content, node) => decorate(content, node, { underline: ["<u>", "</u>"], strike })
|
|
59470
59603
|
});
|
|
59471
59604
|
service.addRule("monospaceCode", {
|
|
59472
59605
|
filter: (node) => {
|
|
@@ -59580,6 +59713,11 @@ ${plainText}
|
|
|
59580
59713
|
escapeTableCell(content) {
|
|
59581
59714
|
return content.replace(/\|/g, "\\|").replace(/\s*<br>\s*/g, "<br>").trim();
|
|
59582
59715
|
}
|
|
59716
|
+
/** A space after a checkbox marker unless the label text already starts with one. */
|
|
59717
|
+
checkboxSpacer(node) {
|
|
59718
|
+
const next = node.nextSibling;
|
|
59719
|
+
return next && /^\s/.test(next.textContent || "") ? "" : " ";
|
|
59720
|
+
}
|
|
59583
59721
|
addTaskListRules(service) {
|
|
59584
59722
|
service.addRule("gfmTaskListCheckbox", {
|
|
59585
59723
|
filter: (node) => {
|
|
@@ -59587,53 +59725,31 @@ ${plainText}
|
|
|
59587
59725
|
},
|
|
59588
59726
|
replacement: (_content, node) => {
|
|
59589
59727
|
const checked = node.checked || node.hasAttribute("checked");
|
|
59590
|
-
return checked ? "[x]
|
|
59728
|
+
return (checked ? "[x]" : "[ ]") + this.checkboxSpacer(node);
|
|
59591
59729
|
}
|
|
59592
59730
|
});
|
|
59593
59731
|
}
|
|
59594
59732
|
/**
|
|
59595
|
-
* FF-IMP-004:
|
|
59596
|
-
* github/commonmark flavours.
|
|
59597
|
-
*
|
|
59598
|
-
*
|
|
59733
|
+
* FF-IMP-004: Superscript, subscript and math span rules for the
|
|
59734
|
+
* github/commonmark/gdocs flavours. Neither GFM nor CommonMark has
|
|
59735
|
+
* superscript/subscript syntax: Pandoc-style ^x^ shows literally, and GitHub
|
|
59736
|
+
* renders ~x~ as strikethrough. Both allow inline HTML and GitHub keeps
|
|
59737
|
+
* <sup>/<sub>, so those are emitted instead.
|
|
59599
59738
|
*/
|
|
59600
59739
|
addSupSubMathRules(service) {
|
|
59601
|
-
|
|
59602
|
-
|
|
59603
|
-
|
|
59604
|
-
|
|
59605
|
-
|
|
59606
|
-
|
|
59607
|
-
|
|
59608
|
-
|
|
59609
|
-
|
|
59610
|
-
|
|
59611
|
-
|
|
59612
|
-
|
|
59613
|
-
|
|
59614
|
-
replacement: (content) => {
|
|
59615
|
-
const trimmed = content.trim();
|
|
59616
|
-
return trimmed ? `^${trimmed}^` : "";
|
|
59617
|
-
}
|
|
59618
|
-
});
|
|
59619
|
-
service.addRule("githubSubscript", {
|
|
59620
|
-
filter: (node) => node.nodeName === "SUB",
|
|
59621
|
-
replacement: (content) => {
|
|
59622
|
-
const trimmed = content.trim();
|
|
59623
|
-
return trimmed ? `~${trimmed}~` : "";
|
|
59624
|
-
}
|
|
59625
|
-
});
|
|
59626
|
-
service.addRule("githubSubscriptStyle", {
|
|
59627
|
-
filter: (node) => {
|
|
59628
|
-
if (node.nodeName !== "SPAN") return false;
|
|
59629
|
-
const style = node.getAttribute("style") || "";
|
|
59630
|
-
return style.includes("vertical-align: sub") || style.includes("vertical-align:sub");
|
|
59631
|
-
},
|
|
59632
|
-
replacement: (content) => {
|
|
59633
|
-
const trimmed = content.trim();
|
|
59634
|
-
return trimmed ? `~${trimmed}~` : "";
|
|
59635
|
-
}
|
|
59636
|
-
});
|
|
59740
|
+
const isStyle = (node, value) => {
|
|
59741
|
+
if (node.nodeName !== "SPAN") return false;
|
|
59742
|
+
const style = node.getAttribute("style") || "";
|
|
59743
|
+
return style.includes(`vertical-align: ${value}`) || style.includes(`vertical-align:${value}`);
|
|
59744
|
+
};
|
|
59745
|
+
const wrap = (tag) => (content) => {
|
|
59746
|
+
const trimmed = content.trim();
|
|
59747
|
+
return trimmed ? `<${tag}>${trimmed}</${tag}>` : "";
|
|
59748
|
+
};
|
|
59749
|
+
service.addRule("githubSuperscript", { filter: (node) => node.nodeName === "SUP", replacement: wrap("sup") });
|
|
59750
|
+
service.addRule("githubSuperscriptStyle", { filter: (node) => isStyle(node, "super"), replacement: wrap("sup") });
|
|
59751
|
+
service.addRule("githubSubscript", { filter: (node) => node.nodeName === "SUB", replacement: wrap("sub") });
|
|
59752
|
+
service.addRule("githubSubscriptStyle", { filter: (node) => isStyle(node, "sub"), replacement: wrap("sub") });
|
|
59637
59753
|
service.addRule("githubMath", {
|
|
59638
59754
|
filter: (node) => {
|
|
59639
59755
|
if (node.nodeName !== "SPAN") return false;
|
|
@@ -59653,60 +59769,78 @@ ${plainText}
|
|
|
59653
59769
|
service.addRule("enhancedList", {
|
|
59654
59770
|
filter: ["ul", "ol"],
|
|
59655
59771
|
replacement: (content, node) => {
|
|
59656
|
-
const listType = node?.nodeName.toLowerCase();
|
|
59657
59772
|
const items = Array.from(node.children).filter(
|
|
59658
59773
|
(child) => child.nodeName.toLowerCase() === "li"
|
|
59659
59774
|
);
|
|
59660
59775
|
if (items.length === 0) return content;
|
|
59661
|
-
|
|
59662
|
-
const isOrdered = listType === "ol";
|
|
59663
|
-
const marker = isOrdered ? "1." : service.options.bulletListMarker || "-";
|
|
59664
|
-
items.forEach((item, index) => {
|
|
59665
|
-
const itemContent = this.processListItem(item, service);
|
|
59666
|
-
const actualMarker = isOrdered ? `${index + 1}.` : marker;
|
|
59667
|
-
markdown += `${actualMarker} ${itemContent}
|
|
59668
|
-
`;
|
|
59669
|
-
});
|
|
59670
|
-
return markdown + "\n";
|
|
59671
|
-
}
|
|
59672
|
-
});
|
|
59673
|
-
}
|
|
59674
|
-
processListItem(item, service, depth = 0) {
|
|
59675
|
-
let content = "";
|
|
59676
|
-
const TEXT_NODE = 3;
|
|
59677
|
-
const ELEMENT_NODE2 = 1;
|
|
59678
|
-
Array.from(item.childNodes).forEach((child) => {
|
|
59679
|
-
if (child.nodeType === TEXT_NODE) {
|
|
59680
|
-
content += child.textContent || "";
|
|
59681
|
-
} else if (child.nodeType === ELEMENT_NODE2) {
|
|
59682
|
-
const element = child;
|
|
59683
|
-
if (element.nodeName.toLowerCase() === "ul" || element.nodeName.toLowerCase() === "ol") {
|
|
59684
|
-
const nestedContent = this.processNestedList(element, service, depth + 1);
|
|
59685
|
-
content += "\n" + nestedContent;
|
|
59686
|
-
} else {
|
|
59687
|
-
content += service.turndown(element.outerHTML);
|
|
59688
|
-
}
|
|
59776
|
+
return "\n" + this.renderList(node, service) + "\n";
|
|
59689
59777
|
}
|
|
59690
59778
|
});
|
|
59691
|
-
return content.trim();
|
|
59692
59779
|
}
|
|
59693
|
-
|
|
59780
|
+
/**
|
|
59781
|
+
* Render a list with markers at column 0. Continuation lines of each item
|
|
59782
|
+
* (extra paragraphs, nested lists) are indented to the item's content
|
|
59783
|
+
* column (marker width + 1), which is what CommonMark/GFM require for them
|
|
59784
|
+
* to stay inside the item: 2 spaces under "- ", 3 under "1. ", 4 under "10. ".
|
|
59785
|
+
*/
|
|
59786
|
+
renderList(list, service) {
|
|
59694
59787
|
const items = Array.from(list.children).filter(
|
|
59695
59788
|
(child) => child.nodeName.toLowerCase() === "li"
|
|
59696
59789
|
);
|
|
59697
|
-
if (items.length === 0) return "";
|
|
59698
|
-
let markdown = "";
|
|
59699
59790
|
const isOrdered = list.nodeName.toLowerCase() === "ol";
|
|
59700
|
-
const
|
|
59701
|
-
|
|
59791
|
+
const bullet = service.options.bulletListMarker || "-";
|
|
59792
|
+
let markdown = "";
|
|
59702
59793
|
items.forEach((item, index) => {
|
|
59703
|
-
const
|
|
59704
|
-
const
|
|
59705
|
-
|
|
59794
|
+
const marker = isOrdered ? `${index + 1}.` : bullet;
|
|
59795
|
+
const indent = " ".repeat(marker.length + 1);
|
|
59796
|
+
const body = this.processListItem(item, service);
|
|
59797
|
+
const lines = body.split("\n");
|
|
59798
|
+
const indented = lines.map((line, i) => i === 0 || line === "" ? line : indent + line).join("\n");
|
|
59799
|
+
markdown += `${marker} ${indented}
|
|
59706
59800
|
`;
|
|
59707
59801
|
});
|
|
59708
59802
|
return markdown;
|
|
59709
59803
|
}
|
|
59804
|
+
/**
|
|
59805
|
+
* Render one list item's content relative to its own content column.
|
|
59806
|
+
* Inline runs and block children are converted together, so whitespace
|
|
59807
|
+
* between sibling spans survives (Google Docs emits one span per run) and
|
|
59808
|
+
* multiple paragraphs stay separated.
|
|
59809
|
+
*/
|
|
59810
|
+
processListItem(item, service) {
|
|
59811
|
+
const parts = [];
|
|
59812
|
+
const ELEMENT_NODE2 = 1;
|
|
59813
|
+
const doc = item.ownerDocument;
|
|
59814
|
+
let buffer = doc.createElement("div");
|
|
59815
|
+
const flush = () => {
|
|
59816
|
+
if (buffer.childNodes.length > 0) {
|
|
59817
|
+
const md = service.turndown(buffer).trim();
|
|
59818
|
+
if (md) parts.push(md);
|
|
59819
|
+
}
|
|
59820
|
+
buffer = doc.createElement("div");
|
|
59821
|
+
};
|
|
59822
|
+
Array.from(item.childNodes).forEach((child) => {
|
|
59823
|
+
const name = child.nodeType === ELEMENT_NODE2 ? child.nodeName.toLowerCase() : "";
|
|
59824
|
+
if (name === "ul" || name === "ol") {
|
|
59825
|
+
flush();
|
|
59826
|
+
const nested = this.renderList(child, service).replace(/\n+$/, "");
|
|
59827
|
+
if (nested) parts.push(nested);
|
|
59828
|
+
} else {
|
|
59829
|
+
buffer.appendChild(child.cloneNode(true));
|
|
59830
|
+
}
|
|
59831
|
+
});
|
|
59832
|
+
flush();
|
|
59833
|
+
let content = "";
|
|
59834
|
+
parts.forEach((part, i) => {
|
|
59835
|
+
if (i === 0) {
|
|
59836
|
+
content = part;
|
|
59837
|
+
return;
|
|
59838
|
+
}
|
|
59839
|
+
const isList = /^(?:[-*+]|\d+\.) /.test(part);
|
|
59840
|
+
content += (isList ? "\n" : "\n\n") + part;
|
|
59841
|
+
});
|
|
59842
|
+
return content;
|
|
59843
|
+
}
|
|
59710
59844
|
addSlideMarkerRules(service) {
|
|
59711
59845
|
service.addRule("pptxSlideMarker", {
|
|
59712
59846
|
filter: (node) => node.nodeName === "DIV" && node.hasAttribute("data-slide-marker"),
|
|
@@ -64775,8 +64909,8 @@ import { readFileSync as readFileSync5 } from "fs";
|
|
|
64775
64909
|
import { resolve, dirname as dirname3 } from "path";
|
|
64776
64910
|
import { fileURLToPath } from "url";
|
|
64777
64911
|
var getVersion = () => {
|
|
64778
|
-
if ("1.0.
|
|
64779
|
-
return "1.0.
|
|
64912
|
+
if ("1.0.36") {
|
|
64913
|
+
return "1.0.36";
|
|
64780
64914
|
}
|
|
64781
64915
|
try {
|
|
64782
64916
|
const __dirname2 = dirname3(fileURLToPath(import.meta.url));
|