formatferry 1.0.34 → 1.0.35
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 +105 -49
- 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",
|
|
@@ -59013,6 +59015,37 @@ var ConversionEngine = class {
|
|
|
59013
59015
|
this.confluenceService = createConfluenceService(deps);
|
|
59014
59016
|
this.addSlideMarkerRules(this.slackService);
|
|
59015
59017
|
this.addSlideMarkerRules(this.confluenceService);
|
|
59018
|
+
[
|
|
59019
|
+
this.githubService,
|
|
59020
|
+
this.commonmarkService,
|
|
59021
|
+
this.customService,
|
|
59022
|
+
this.discordService,
|
|
59023
|
+
this.redditService,
|
|
59024
|
+
this.rmarkdownService,
|
|
59025
|
+
this.slackService,
|
|
59026
|
+
this.confluenceService
|
|
59027
|
+
].forEach((service) => this.addGoogleDocsWrapperRule(service));
|
|
59028
|
+
}
|
|
59029
|
+
/**
|
|
59030
|
+
* Google Docs wraps every copied selection in
|
|
59031
|
+
* <b style="font-weight:normal" id="docs-internal-guid-...">. Treating that
|
|
59032
|
+
* as bold puts a stray pair of bold markers around the whole document, so a
|
|
59033
|
+
* <b>/<strong> whose inline style explicitly sets a non-bold weight is
|
|
59034
|
+
* rendered as its plain content.
|
|
59035
|
+
*/
|
|
59036
|
+
addGoogleDocsWrapperRule(service) {
|
|
59037
|
+
service.addRule("googleDocsNonBoldWrapper", {
|
|
59038
|
+
filter: (node) => {
|
|
59039
|
+
if (node.nodeName !== "B" && node.nodeName !== "STRONG") return false;
|
|
59040
|
+
const style = (node.getAttribute("style") || "").toLowerCase();
|
|
59041
|
+
const matches = [...style.matchAll(/font-weight\s*:\s*([a-z0-9]+)/g)];
|
|
59042
|
+
if (matches.length === 0) return false;
|
|
59043
|
+
const weight = matches[matches.length - 1][1];
|
|
59044
|
+
if (weight === "normal" || weight === "lighter") return true;
|
|
59045
|
+
return /^\d+$/.test(weight) && parseInt(weight, 10) < 600;
|
|
59046
|
+
},
|
|
59047
|
+
replacement: (content) => content
|
|
59048
|
+
});
|
|
59016
59049
|
}
|
|
59017
59050
|
/**
|
|
59018
59051
|
* Create Discord-optimized Turndown service
|
|
@@ -59069,7 +59102,7 @@ ${plainText}
|
|
|
59069
59102
|
},
|
|
59070
59103
|
replacement: (_content, node) => {
|
|
59071
59104
|
const checked = node.checked || node.hasAttribute("checked");
|
|
59072
|
-
return checked ? "\u2611
|
|
59105
|
+
return (checked ? "\u2611" : "\u2610") + this.checkboxSpacer(node);
|
|
59073
59106
|
}
|
|
59074
59107
|
});
|
|
59075
59108
|
return service;
|
|
@@ -59097,9 +59130,9 @@ ${plainText}
|
|
|
59097
59130
|
* Converts Unicode checkboxes to [x] and [ ]
|
|
59098
59131
|
*/
|
|
59099
59132
|
normalizeGitHubCheckboxes(markdown) {
|
|
59100
|
-
let result = markdown;
|
|
59101
|
-
result = result.replace(/^([
|
|
59102
|
-
result = result.replace(/^([
|
|
59133
|
+
let result = markdown.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)\\\[([ xX])\\\]/gm, "$1[$2]");
|
|
59134
|
+
result = result.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)[☑✓✔■⬛]/gm, "$1[x]");
|
|
59135
|
+
result = result.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)[☐✗✘□⬜]/gm, "$1[ ]");
|
|
59103
59136
|
return result;
|
|
59104
59137
|
}
|
|
59105
59138
|
/**
|
|
@@ -59107,10 +59140,10 @@ ${plainText}
|
|
|
59107
59140
|
* Converts [x], [ ], and other checkbox patterns to emoji
|
|
59108
59141
|
*/
|
|
59109
59142
|
normalizeDiscordCheckboxes(markdown) {
|
|
59110
|
-
let result = markdown.replace(/^([
|
|
59111
|
-
result = result.replace(/^([
|
|
59112
|
-
result = result.replace(/^([
|
|
59113
|
-
result = result.replace(/^([
|
|
59143
|
+
let result = markdown.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)\\?\[x\\?\]/gmi, "$1\u2611");
|
|
59144
|
+
result = result.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)[✓✔■⬛]/gm, "$1\u2611");
|
|
59145
|
+
result = result.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)\\?\[\s?\\?\]/gm, "$1\u2610");
|
|
59146
|
+
result = result.replace(/^([ \t]*(?:[-*+]|\d+[.)])[ \t]+)[✗✘□⬜]/gm, "$1\u2610");
|
|
59114
59147
|
return result;
|
|
59115
59148
|
}
|
|
59116
59149
|
/**
|
|
@@ -59580,6 +59613,11 @@ ${plainText}
|
|
|
59580
59613
|
escapeTableCell(content) {
|
|
59581
59614
|
return content.replace(/\|/g, "\\|").replace(/\s*<br>\s*/g, "<br>").trim();
|
|
59582
59615
|
}
|
|
59616
|
+
/** A space after a checkbox marker unless the label text already starts with one. */
|
|
59617
|
+
checkboxSpacer(node) {
|
|
59618
|
+
const next = node.nextSibling;
|
|
59619
|
+
return next && /^\s/.test(next.textContent || "") ? "" : " ";
|
|
59620
|
+
}
|
|
59583
59621
|
addTaskListRules(service) {
|
|
59584
59622
|
service.addRule("gfmTaskListCheckbox", {
|
|
59585
59623
|
filter: (node) => {
|
|
@@ -59587,7 +59625,7 @@ ${plainText}
|
|
|
59587
59625
|
},
|
|
59588
59626
|
replacement: (_content, node) => {
|
|
59589
59627
|
const checked = node.checked || node.hasAttribute("checked");
|
|
59590
|
-
return checked ? "[x]
|
|
59628
|
+
return (checked ? "[x]" : "[ ]") + this.checkboxSpacer(node);
|
|
59591
59629
|
}
|
|
59592
59630
|
});
|
|
59593
59631
|
}
|
|
@@ -59653,60 +59691,78 @@ ${plainText}
|
|
|
59653
59691
|
service.addRule("enhancedList", {
|
|
59654
59692
|
filter: ["ul", "ol"],
|
|
59655
59693
|
replacement: (content, node) => {
|
|
59656
|
-
const listType = node?.nodeName.toLowerCase();
|
|
59657
59694
|
const items = Array.from(node.children).filter(
|
|
59658
59695
|
(child) => child.nodeName.toLowerCase() === "li"
|
|
59659
59696
|
);
|
|
59660
59697
|
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";
|
|
59698
|
+
return "\n" + this.renderList(node, service) + "\n";
|
|
59671
59699
|
}
|
|
59672
59700
|
});
|
|
59673
59701
|
}
|
|
59674
|
-
|
|
59675
|
-
|
|
59676
|
-
|
|
59677
|
-
|
|
59678
|
-
|
|
59679
|
-
|
|
59680
|
-
|
|
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
|
-
}
|
|
59689
|
-
}
|
|
59690
|
-
});
|
|
59691
|
-
return content.trim();
|
|
59692
|
-
}
|
|
59693
|
-
processNestedList(list, service, depth) {
|
|
59702
|
+
/**
|
|
59703
|
+
* Render a list with markers at column 0. Continuation lines of each item
|
|
59704
|
+
* (extra paragraphs, nested lists) are indented to the item's content
|
|
59705
|
+
* column (marker width + 1), which is what CommonMark/GFM require for them
|
|
59706
|
+
* to stay inside the item: 2 spaces under "- ", 3 under "1. ", 4 under "10. ".
|
|
59707
|
+
*/
|
|
59708
|
+
renderList(list, service) {
|
|
59694
59709
|
const items = Array.from(list.children).filter(
|
|
59695
59710
|
(child) => child.nodeName.toLowerCase() === "li"
|
|
59696
59711
|
);
|
|
59697
|
-
if (items.length === 0) return "";
|
|
59698
|
-
let markdown = "";
|
|
59699
59712
|
const isOrdered = list.nodeName.toLowerCase() === "ol";
|
|
59700
|
-
const
|
|
59701
|
-
|
|
59713
|
+
const bullet = service.options.bulletListMarker || "-";
|
|
59714
|
+
let markdown = "";
|
|
59702
59715
|
items.forEach((item, index) => {
|
|
59703
|
-
const
|
|
59704
|
-
const
|
|
59705
|
-
|
|
59716
|
+
const marker = isOrdered ? `${index + 1}.` : bullet;
|
|
59717
|
+
const indent = " ".repeat(marker.length + 1);
|
|
59718
|
+
const body = this.processListItem(item, service);
|
|
59719
|
+
const lines = body.split("\n");
|
|
59720
|
+
const indented = lines.map((line, i) => i === 0 || line === "" ? line : indent + line).join("\n");
|
|
59721
|
+
markdown += `${marker} ${indented}
|
|
59706
59722
|
`;
|
|
59707
59723
|
});
|
|
59708
59724
|
return markdown;
|
|
59709
59725
|
}
|
|
59726
|
+
/**
|
|
59727
|
+
* Render one list item's content relative to its own content column.
|
|
59728
|
+
* Inline runs and block children are converted together, so whitespace
|
|
59729
|
+
* between sibling spans survives (Google Docs emits one span per run) and
|
|
59730
|
+
* multiple paragraphs stay separated.
|
|
59731
|
+
*/
|
|
59732
|
+
processListItem(item, service) {
|
|
59733
|
+
const parts = [];
|
|
59734
|
+
const ELEMENT_NODE2 = 1;
|
|
59735
|
+
const doc = item.ownerDocument;
|
|
59736
|
+
let buffer = doc.createElement("div");
|
|
59737
|
+
const flush = () => {
|
|
59738
|
+
if (buffer.childNodes.length > 0) {
|
|
59739
|
+
const md = service.turndown(buffer).trim();
|
|
59740
|
+
if (md) parts.push(md);
|
|
59741
|
+
}
|
|
59742
|
+
buffer = doc.createElement("div");
|
|
59743
|
+
};
|
|
59744
|
+
Array.from(item.childNodes).forEach((child) => {
|
|
59745
|
+
const name = child.nodeType === ELEMENT_NODE2 ? child.nodeName.toLowerCase() : "";
|
|
59746
|
+
if (name === "ul" || name === "ol") {
|
|
59747
|
+
flush();
|
|
59748
|
+
const nested = this.renderList(child, service).replace(/\n+$/, "");
|
|
59749
|
+
if (nested) parts.push(nested);
|
|
59750
|
+
} else {
|
|
59751
|
+
buffer.appendChild(child.cloneNode(true));
|
|
59752
|
+
}
|
|
59753
|
+
});
|
|
59754
|
+
flush();
|
|
59755
|
+
let content = "";
|
|
59756
|
+
parts.forEach((part, i) => {
|
|
59757
|
+
if (i === 0) {
|
|
59758
|
+
content = part;
|
|
59759
|
+
return;
|
|
59760
|
+
}
|
|
59761
|
+
const isList = /^(?:[-*+]|\d+\.) /.test(part);
|
|
59762
|
+
content += (isList ? "\n" : "\n\n") + part;
|
|
59763
|
+
});
|
|
59764
|
+
return content;
|
|
59765
|
+
}
|
|
59710
59766
|
addSlideMarkerRules(service) {
|
|
59711
59767
|
service.addRule("pptxSlideMarker", {
|
|
59712
59768
|
filter: (node) => node.nodeName === "DIV" && node.hasAttribute("data-slide-marker"),
|
|
@@ -64775,8 +64831,8 @@ import { readFileSync as readFileSync5 } from "fs";
|
|
|
64775
64831
|
import { resolve, dirname as dirname3 } from "path";
|
|
64776
64832
|
import { fileURLToPath } from "url";
|
|
64777
64833
|
var getVersion = () => {
|
|
64778
|
-
if ("1.0.
|
|
64779
|
-
return "1.0.
|
|
64834
|
+
if ("1.0.35") {
|
|
64835
|
+
return "1.0.35";
|
|
64780
64836
|
}
|
|
64781
64837
|
try {
|
|
64782
64838
|
const __dirname2 = dirname3(fileURLToPath(import.meta.url));
|