formatferry 1.0.6 → 1.0.9
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 +409 -406
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -17256,8 +17256,8 @@ var require_turndown_cjs = __commonJS({
|
|
|
17256
17256
|
[/_/g, "\\_"],
|
|
17257
17257
|
[/^(\d+)\. /g, "$1\\. "]
|
|
17258
17258
|
];
|
|
17259
|
-
function
|
|
17260
|
-
if (!(this instanceof
|
|
17259
|
+
function TurndownService3(options) {
|
|
17260
|
+
if (!(this instanceof TurndownService3)) return new TurndownService3(options);
|
|
17261
17261
|
var defaults = {
|
|
17262
17262
|
rules,
|
|
17263
17263
|
headingStyle: "setext",
|
|
@@ -17284,7 +17284,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
17284
17284
|
this.options = extend({}, defaults, options);
|
|
17285
17285
|
this.rules = new Rules(this.options);
|
|
17286
17286
|
}
|
|
17287
|
-
|
|
17287
|
+
TurndownService3.prototype = {
|
|
17288
17288
|
/**
|
|
17289
17289
|
* The entry point for converting a string or DOM node to Markdown
|
|
17290
17290
|
* @public
|
|
@@ -17405,7 +17405,7 @@ var require_turndown_cjs = __commonJS({
|
|
|
17405
17405
|
function canConvert(input) {
|
|
17406
17406
|
return input != null && (typeof input === "string" || input.nodeType && (input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11));
|
|
17407
17407
|
}
|
|
17408
|
-
module.exports =
|
|
17408
|
+
module.exports = TurndownService3;
|
|
17409
17409
|
}
|
|
17410
17410
|
});
|
|
17411
17411
|
|
|
@@ -19490,7 +19490,7 @@ import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "
|
|
|
19490
19490
|
import { extname } from "path";
|
|
19491
19491
|
|
|
19492
19492
|
// ../../src/shared/conversion-engine.ts
|
|
19493
|
-
var
|
|
19493
|
+
var import_turndown2 = __toESM(require_turndown_cjs(), 1);
|
|
19494
19494
|
|
|
19495
19495
|
// ../../src/shared/input-sanitizer.ts
|
|
19496
19496
|
import DOMPurifyImport from "dompurify";
|
|
@@ -19978,6 +19978,357 @@ function normalizeAtlassianHTML(html, domParser) {
|
|
|
19978
19978
|
return doc.body.innerHTML;
|
|
19979
19979
|
}
|
|
19980
19980
|
|
|
19981
|
+
// ../../src/shared/confluence-slack-services.ts
|
|
19982
|
+
var import_turndown = __toESM(require_turndown_cjs(), 1);
|
|
19983
|
+
function createSlackService(deps) {
|
|
19984
|
+
const service = new import_turndown.default({
|
|
19985
|
+
headingStyle: "atx",
|
|
19986
|
+
hr: "---",
|
|
19987
|
+
bulletListMarker: "-",
|
|
19988
|
+
codeBlockStyle: "fenced",
|
|
19989
|
+
fence: "```",
|
|
19990
|
+
emDelimiter: "_"
|
|
19991
|
+
});
|
|
19992
|
+
deps.addListRules(service);
|
|
19993
|
+
deps.addPdfPageMarkerRules(service);
|
|
19994
|
+
service.addRule("slackBold", {
|
|
19995
|
+
filter: (node) => {
|
|
19996
|
+
if (node.nodeName === "STRONG" || node.nodeName === "B") return true;
|
|
19997
|
+
if (node.nodeName === "SPAN") {
|
|
19998
|
+
const style = node.getAttribute("style") || "";
|
|
19999
|
+
if (style.includes("font-weight: bold") || style.includes("font-weight:bold")) return true;
|
|
20000
|
+
const fwMatch = style.match(/font-weight:\s*(\d+)/);
|
|
20001
|
+
if (fwMatch && parseInt(fwMatch[1]) >= 600) return true;
|
|
20002
|
+
const ffMatch = style.match(/font-family:\s*['"]*([^'"]+)['"]*[;]?/);
|
|
20003
|
+
if (ffMatch && ffMatch[1].toLowerCase().includes("bold")) return true;
|
|
20004
|
+
}
|
|
20005
|
+
return false;
|
|
20006
|
+
},
|
|
20007
|
+
replacement: (content) => content.trim() ? `*${content}*` : content
|
|
20008
|
+
});
|
|
20009
|
+
service.addRule("slackItalic", {
|
|
20010
|
+
filter: (node) => {
|
|
20011
|
+
if (node.nodeName === "EM" || node.nodeName === "I") return true;
|
|
20012
|
+
if (node.nodeName === "SPAN") {
|
|
20013
|
+
const style = node.getAttribute("style") || "";
|
|
20014
|
+
if (style.includes("font-style: italic") || style.includes("font-style:italic")) return true;
|
|
20015
|
+
const ffMatch = style.match(/font-family:\s*['"]*([^'"]+)['"]*[;]?/);
|
|
20016
|
+
if (ffMatch && ffMatch[1].toLowerCase().includes("italic")) return true;
|
|
20017
|
+
}
|
|
20018
|
+
return false;
|
|
20019
|
+
},
|
|
20020
|
+
replacement: (content) => content.trim() ? `_${content}_` : content
|
|
20021
|
+
});
|
|
20022
|
+
service.addRule("slackStrikethrough", {
|
|
20023
|
+
filter: (node) => {
|
|
20024
|
+
if (["DEL", "S", "STRIKE"].includes(node.nodeName)) return true;
|
|
20025
|
+
if (node.nodeName === "SPAN") {
|
|
20026
|
+
const style = node.getAttribute("style") || "";
|
|
20027
|
+
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");
|
|
20028
|
+
}
|
|
20029
|
+
return false;
|
|
20030
|
+
},
|
|
20031
|
+
replacement: (content) => content.trim() ? `~${content}~` : content
|
|
20032
|
+
});
|
|
20033
|
+
service.addRule("slackMonospaceCode", {
|
|
20034
|
+
filter: (node) => {
|
|
20035
|
+
if (node.nodeName !== "SPAN") return false;
|
|
20036
|
+
const style = node.getAttribute("style") || "";
|
|
20037
|
+
const fontFamily = style.toLowerCase();
|
|
20038
|
+
return fontFamily.includes("monospace") || fontFamily.includes("courier") || fontFamily.includes("consolas") || fontFamily.includes("monaco") || fontFamily.includes("menlo") || fontFamily.includes("source code") || fontFamily.includes("fira code") || fontFamily.includes("roboto mono") || fontFamily.includes("ubuntu mono");
|
|
20039
|
+
},
|
|
20040
|
+
replacement: (content) => {
|
|
20041
|
+
const trimmed = content.trim();
|
|
20042
|
+
if (!trimmed) return content;
|
|
20043
|
+
return trimmed.includes("`") ? `\`\` ${trimmed} \`\`` : `\`${trimmed}\``;
|
|
20044
|
+
}
|
|
20045
|
+
});
|
|
20046
|
+
service.addRule("slackHeading", {
|
|
20047
|
+
filter: ["h1", "h2", "h3", "h4", "h5", "h6"],
|
|
20048
|
+
replacement: (content) => content.trim() ? `*${content.trim()}*
|
|
20049
|
+
|
|
20050
|
+
` : content
|
|
20051
|
+
});
|
|
20052
|
+
service.addRule("slackGoogleDocsHeadings", {
|
|
20053
|
+
filter: (node) => {
|
|
20054
|
+
if (node.nodeName !== "P" && node.nodeName !== "DIV") return false;
|
|
20055
|
+
const style = node.getAttribute("style") || "";
|
|
20056
|
+
const fontSizeMatch = style.match(/font-size:\s*(\d+(?:\.\d+)?)px/);
|
|
20057
|
+
if (fontSizeMatch && parseFloat(fontSizeMatch[1]) > 16) return true;
|
|
20058
|
+
if (style.includes("font-weight: bold") || style.includes("font-weight:bold")) {
|
|
20059
|
+
const textContent = node.textContent || "";
|
|
20060
|
+
return textContent.length < 100 && textContent.trim().length > 0;
|
|
20061
|
+
}
|
|
20062
|
+
return false;
|
|
20063
|
+
},
|
|
20064
|
+
replacement: (content) => content.trim() ? `*${content.trim()}*
|
|
20065
|
+
|
|
20066
|
+
` : content
|
|
20067
|
+
});
|
|
20068
|
+
service.addRule("slackUnderline", {
|
|
20069
|
+
filter: (node) => {
|
|
20070
|
+
if (node.nodeName === "U" || node.nodeName === "INS") return true;
|
|
20071
|
+
if (node.nodeName === "SPAN") {
|
|
20072
|
+
const style = node.getAttribute("style") || "";
|
|
20073
|
+
return style.includes("text-decoration: underline") || style.includes("text-decoration:underline");
|
|
20074
|
+
}
|
|
20075
|
+
return false;
|
|
20076
|
+
},
|
|
20077
|
+
replacement: (content) => content
|
|
20078
|
+
});
|
|
20079
|
+
service.addRule("slackLink", {
|
|
20080
|
+
filter: (node) => node.nodeName === "A" && !!node.getAttribute("href"),
|
|
20081
|
+
replacement: (content, node) => {
|
|
20082
|
+
const href = node.getAttribute("href") || "";
|
|
20083
|
+
const text = content.trim().replace(/\|/g, " ");
|
|
20084
|
+
if (!text || text === href) return `<${href}>`;
|
|
20085
|
+
return `<${href}|${text}>`;
|
|
20086
|
+
}
|
|
20087
|
+
});
|
|
20088
|
+
service.addRule("slackImage", {
|
|
20089
|
+
filter: "img",
|
|
20090
|
+
replacement: (_content, node) => {
|
|
20091
|
+
const src = node.getAttribute("src") || "";
|
|
20092
|
+
const alt = (node.getAttribute("alt") || "image").replace(/\|/g, " ");
|
|
20093
|
+
return `<${src}|${alt}>`;
|
|
20094
|
+
}
|
|
20095
|
+
});
|
|
20096
|
+
service.addRule("slackTable", {
|
|
20097
|
+
filter: "table",
|
|
20098
|
+
replacement: (_content, node) => {
|
|
20099
|
+
const plainText = deps.tableToPlainText(node);
|
|
20100
|
+
return `\`\`\`
|
|
20101
|
+
${plainText}
|
|
20102
|
+
\`\`\`
|
|
20103
|
+
|
|
20104
|
+
`;
|
|
20105
|
+
}
|
|
20106
|
+
});
|
|
20107
|
+
return service;
|
|
20108
|
+
}
|
|
20109
|
+
function processConfluenceList(list, service, depth) {
|
|
20110
|
+
const isOrdered = list.nodeName === "OL";
|
|
20111
|
+
const marker = (isOrdered ? "#" : "*").repeat(depth);
|
|
20112
|
+
const items = Array.from(list.children).filter((c) => c.nodeName === "LI");
|
|
20113
|
+
let result = depth === 1 ? "\n" : "";
|
|
20114
|
+
items.forEach((item) => {
|
|
20115
|
+
const itemContent = processConfluenceListItem(item, service, depth);
|
|
20116
|
+
result += `${marker} ${itemContent}
|
|
20117
|
+
`;
|
|
20118
|
+
});
|
|
20119
|
+
return depth === 1 ? result + "\n" : result;
|
|
20120
|
+
}
|
|
20121
|
+
function processConfluenceListItem(item, service, depth) {
|
|
20122
|
+
let content = "";
|
|
20123
|
+
const TEXT_NODE = 3;
|
|
20124
|
+
const ELEMENT_NODE = 1;
|
|
20125
|
+
Array.from(item.childNodes).forEach((child) => {
|
|
20126
|
+
if (child.nodeType === TEXT_NODE) {
|
|
20127
|
+
content += child.textContent || "";
|
|
20128
|
+
} else if (child.nodeType === ELEMENT_NODE) {
|
|
20129
|
+
const el = child;
|
|
20130
|
+
if (el.nodeName === "UL" || el.nodeName === "OL") {
|
|
20131
|
+
content += "\n" + processConfluenceList(el, service, depth + 1);
|
|
20132
|
+
} else {
|
|
20133
|
+
content += service.turndown(el.outerHTML);
|
|
20134
|
+
}
|
|
20135
|
+
}
|
|
20136
|
+
});
|
|
20137
|
+
return content.trim();
|
|
20138
|
+
}
|
|
20139
|
+
function createConfluenceService(deps) {
|
|
20140
|
+
const service = new import_turndown.default({
|
|
20141
|
+
headingStyle: "atx",
|
|
20142
|
+
hr: "---",
|
|
20143
|
+
bulletListMarker: "-",
|
|
20144
|
+
codeBlockStyle: "fenced",
|
|
20145
|
+
emDelimiter: "_"
|
|
20146
|
+
});
|
|
20147
|
+
deps.addPdfPageMarkerRules(service);
|
|
20148
|
+
service.addRule("confluenceHeading", {
|
|
20149
|
+
filter: ["h1", "h2", "h3", "h4", "h5", "h6"],
|
|
20150
|
+
replacement: (content, node) => {
|
|
20151
|
+
const level = parseInt(node.nodeName[1], 10);
|
|
20152
|
+
return `
|
|
20153
|
+
|
|
20154
|
+
h${level}. ${content.trim()}
|
|
20155
|
+
|
|
20156
|
+
`;
|
|
20157
|
+
}
|
|
20158
|
+
});
|
|
20159
|
+
service.addRule("confluenceCodeBlock", {
|
|
20160
|
+
filter: "pre",
|
|
20161
|
+
replacement: (_content, node) => {
|
|
20162
|
+
const codeEl = node.querySelector("code");
|
|
20163
|
+
const langMatch = codeEl?.className?.match(/language-(\w+)/);
|
|
20164
|
+
const lang = langMatch ? langMatch[1] : "";
|
|
20165
|
+
const codeContent = codeEl?.textContent || node.textContent || "";
|
|
20166
|
+
const langAttr = lang ? `:language=${lang}` : "";
|
|
20167
|
+
return `
|
|
20168
|
+
|
|
20169
|
+
{code${langAttr}}
|
|
20170
|
+
${codeContent}
|
|
20171
|
+
{code}
|
|
20172
|
+
|
|
20173
|
+
`;
|
|
20174
|
+
}
|
|
20175
|
+
});
|
|
20176
|
+
service.addRule("confluenceInlineCode", {
|
|
20177
|
+
filter: (node) => node.nodeName === "CODE" && node.parentNode?.nodeName !== "PRE",
|
|
20178
|
+
replacement: (content) => content ? `{{${content.replace(/}+/g, (m) => m.split("").join(" "))}}}` : ""
|
|
20179
|
+
});
|
|
20180
|
+
service.addRule("confluenceBold", {
|
|
20181
|
+
filter: (node) => {
|
|
20182
|
+
if (node.nodeName === "STRONG" || node.nodeName === "B") return true;
|
|
20183
|
+
if (node.nodeName === "SPAN") {
|
|
20184
|
+
const style = node.getAttribute("style") || "";
|
|
20185
|
+
if (style.includes("font-weight: bold") || style.includes("font-weight:bold")) return true;
|
|
20186
|
+
const fwMatch = style.match(/font-weight:\s*(\d+)/);
|
|
20187
|
+
if (fwMatch && parseInt(fwMatch[1]) >= 600) return true;
|
|
20188
|
+
const ffMatch = style.match(/font-family:\s*['"]*([^'"]+)['"]*[;]?/);
|
|
20189
|
+
if (ffMatch && ffMatch[1].toLowerCase().includes("bold")) return true;
|
|
20190
|
+
}
|
|
20191
|
+
return false;
|
|
20192
|
+
},
|
|
20193
|
+
replacement: (content) => content.trim() ? `*${content}*` : content
|
|
20194
|
+
});
|
|
20195
|
+
service.addRule("confluenceItalic", {
|
|
20196
|
+
filter: (node) => {
|
|
20197
|
+
if (node.nodeName === "EM" || node.nodeName === "I") return true;
|
|
20198
|
+
if (node.nodeName === "SPAN") {
|
|
20199
|
+
const style = node.getAttribute("style") || "";
|
|
20200
|
+
if (style.includes("font-style: italic") || style.includes("font-style:italic")) return true;
|
|
20201
|
+
const ffMatch = style.match(/font-family:\s*['"]*([^'"]+)['"]*[;]?/);
|
|
20202
|
+
if (ffMatch && ffMatch[1].toLowerCase().includes("italic")) return true;
|
|
20203
|
+
}
|
|
20204
|
+
return false;
|
|
20205
|
+
},
|
|
20206
|
+
replacement: (content) => content.trim() ? `_${content}_` : content
|
|
20207
|
+
});
|
|
20208
|
+
service.addRule("confluenceUnderline", {
|
|
20209
|
+
filter: (node) => {
|
|
20210
|
+
if (node.nodeName === "U" || node.nodeName === "INS") return true;
|
|
20211
|
+
if (node.nodeName === "SPAN") {
|
|
20212
|
+
const style = node.getAttribute("style") || "";
|
|
20213
|
+
return style.includes("text-decoration: underline") || style.includes("text-decoration:underline");
|
|
20214
|
+
}
|
|
20215
|
+
return false;
|
|
20216
|
+
},
|
|
20217
|
+
replacement: (content) => content.trim() ? `+${content}+` : content
|
|
20218
|
+
});
|
|
20219
|
+
service.addRule("confluenceStrikethrough", {
|
|
20220
|
+
filter: (node) => {
|
|
20221
|
+
if (["DEL", "S", "STRIKE"].includes(node.nodeName)) return true;
|
|
20222
|
+
if (node.nodeName === "SPAN") {
|
|
20223
|
+
const style = node.getAttribute("style") || "";
|
|
20224
|
+
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");
|
|
20225
|
+
}
|
|
20226
|
+
return false;
|
|
20227
|
+
},
|
|
20228
|
+
replacement: (content) => content.trim() ? `-${content}-` : content
|
|
20229
|
+
});
|
|
20230
|
+
service.addRule("confluenceMonospaceCode", {
|
|
20231
|
+
filter: (node) => {
|
|
20232
|
+
if (node.nodeName !== "SPAN") return false;
|
|
20233
|
+
const style = node.getAttribute("style") || "";
|
|
20234
|
+
const fontFamily = style.toLowerCase();
|
|
20235
|
+
return fontFamily.includes("monospace") || fontFamily.includes("courier") || fontFamily.includes("consolas") || fontFamily.includes("monaco") || fontFamily.includes("menlo") || fontFamily.includes("source code") || fontFamily.includes("fira code") || fontFamily.includes("roboto mono") || fontFamily.includes("ubuntu mono");
|
|
20236
|
+
},
|
|
20237
|
+
replacement: (content) => content.trim() ? `{{${content.trim().replace(/}+/g, (m) => m.split("").join(" "))}}}` : content
|
|
20238
|
+
});
|
|
20239
|
+
service.addRule("confluenceLink", {
|
|
20240
|
+
filter: (node) => node.nodeName === "A" && !!node.getAttribute("href"),
|
|
20241
|
+
replacement: (content, node) => {
|
|
20242
|
+
const href = node.getAttribute("href") || "";
|
|
20243
|
+
const text = content.trim().replace(/\|/g, " ");
|
|
20244
|
+
if (!text || text === href) return `[${href}]`;
|
|
20245
|
+
return `[${text}|${href}]`;
|
|
20246
|
+
}
|
|
20247
|
+
});
|
|
20248
|
+
service.addRule("confluenceImage", {
|
|
20249
|
+
filter: "img",
|
|
20250
|
+
replacement: (_content, node) => {
|
|
20251
|
+
const src = node.getAttribute("src") || "";
|
|
20252
|
+
return src ? `!${src}!` : "";
|
|
20253
|
+
}
|
|
20254
|
+
});
|
|
20255
|
+
service.addRule("confluenceHr", {
|
|
20256
|
+
filter: "hr",
|
|
20257
|
+
replacement: () => "\n\n----\n\n"
|
|
20258
|
+
});
|
|
20259
|
+
service.addRule("confluenceBlockquote", {
|
|
20260
|
+
filter: "blockquote",
|
|
20261
|
+
replacement: (content) => `
|
|
20262
|
+
|
|
20263
|
+
{quote}
|
|
20264
|
+
${content.trim()}
|
|
20265
|
+
{quote}
|
|
20266
|
+
|
|
20267
|
+
`
|
|
20268
|
+
});
|
|
20269
|
+
service.addRule("confluenceGoogleDocsHeadings", {
|
|
20270
|
+
filter: (node) => {
|
|
20271
|
+
if (node.nodeName !== "P" && node.nodeName !== "DIV") return false;
|
|
20272
|
+
const style = node.getAttribute("style") || "";
|
|
20273
|
+
const fontSizeMatch = style.match(/font-size:\s*(\d+(?:\.\d+)?)px/);
|
|
20274
|
+
if (fontSizeMatch && parseFloat(fontSizeMatch[1]) > 16) return true;
|
|
20275
|
+
if (style.includes("font-weight: bold") || style.includes("font-weight:bold")) {
|
|
20276
|
+
const textContent = node.textContent || "";
|
|
20277
|
+
return textContent.length < 100 && textContent.trim().length > 0;
|
|
20278
|
+
}
|
|
20279
|
+
return false;
|
|
20280
|
+
},
|
|
20281
|
+
replacement: (content, node) => {
|
|
20282
|
+
const style = node?.getAttribute("style") || "";
|
|
20283
|
+
const fontSizeMatch = style.match(/font-size:\s*(\d+(?:\.\d+)?)px/);
|
|
20284
|
+
const trimmed = content.trim();
|
|
20285
|
+
if (!trimmed) return content;
|
|
20286
|
+
if (!fontSizeMatch) {
|
|
20287
|
+
return `
|
|
20288
|
+
|
|
20289
|
+
*${trimmed}*
|
|
20290
|
+
|
|
20291
|
+
`;
|
|
20292
|
+
}
|
|
20293
|
+
const fontSize = parseFloat(fontSizeMatch[1]);
|
|
20294
|
+
let level = 5;
|
|
20295
|
+
if (fontSize >= 28) level = 1;
|
|
20296
|
+
else if (fontSize >= 24) level = 2;
|
|
20297
|
+
else if (fontSize >= 20) level = 3;
|
|
20298
|
+
else if (fontSize >= 18) level = 4;
|
|
20299
|
+
return `
|
|
20300
|
+
|
|
20301
|
+
h${level}. ${trimmed}
|
|
20302
|
+
|
|
20303
|
+
`;
|
|
20304
|
+
}
|
|
20305
|
+
});
|
|
20306
|
+
service.addRule("confluenceList", {
|
|
20307
|
+
filter: ["ul", "ol"],
|
|
20308
|
+
replacement: (_content, node) => {
|
|
20309
|
+
return processConfluenceList(node, service, 1);
|
|
20310
|
+
}
|
|
20311
|
+
});
|
|
20312
|
+
service.addRule("confluenceTable", {
|
|
20313
|
+
filter: "table",
|
|
20314
|
+
replacement: (_content, node) => {
|
|
20315
|
+
const table = node;
|
|
20316
|
+
const rows = Array.from(table.querySelectorAll("tr"));
|
|
20317
|
+
if (rows.length === 0) return "";
|
|
20318
|
+
let result = "\n";
|
|
20319
|
+
rows.forEach((row) => {
|
|
20320
|
+
const cells = Array.from(row.querySelectorAll("th, td"));
|
|
20321
|
+
const isHeaderRow = cells.some((c) => c.nodeName === "TH");
|
|
20322
|
+
const delim = isHeaderRow ? "||" : "|";
|
|
20323
|
+
const cellTexts = cells.map((c) => (c.textContent || "").trim());
|
|
20324
|
+
result += delim + cellTexts.join(delim) + delim + "\n";
|
|
20325
|
+
});
|
|
20326
|
+
return result + "\n";
|
|
20327
|
+
}
|
|
20328
|
+
});
|
|
20329
|
+
return service;
|
|
20330
|
+
}
|
|
20331
|
+
|
|
19981
20332
|
// ../../src/shared/conversion-engine.ts
|
|
19982
20333
|
var ConversionEngine = class {
|
|
19983
20334
|
githubService;
|
|
@@ -19992,21 +20343,21 @@ var ConversionEngine = class {
|
|
|
19992
20343
|
this.initializeServices();
|
|
19993
20344
|
}
|
|
19994
20345
|
initializeServices() {
|
|
19995
|
-
this.githubService = new
|
|
20346
|
+
this.githubService = new import_turndown2.default({
|
|
19996
20347
|
headingStyle: "atx",
|
|
19997
20348
|
hr: "---",
|
|
19998
20349
|
bulletListMarker: "-",
|
|
19999
20350
|
codeBlockStyle: "fenced",
|
|
20000
20351
|
emDelimiter: "_"
|
|
20001
20352
|
});
|
|
20002
|
-
this.commonmarkService = new
|
|
20353
|
+
this.commonmarkService = new import_turndown2.default({
|
|
20003
20354
|
headingStyle: "atx",
|
|
20004
20355
|
hr: "***",
|
|
20005
20356
|
bulletListMarker: "*",
|
|
20006
20357
|
codeBlockStyle: "indented",
|
|
20007
20358
|
emDelimiter: "*"
|
|
20008
20359
|
});
|
|
20009
|
-
this.customService = new
|
|
20360
|
+
this.customService = new import_turndown2.default({
|
|
20010
20361
|
headingStyle: "atx",
|
|
20011
20362
|
hr: "---",
|
|
20012
20363
|
bulletListMarker: "-",
|
|
@@ -20028,8 +20379,13 @@ var ConversionEngine = class {
|
|
|
20028
20379
|
this.discordService = this.createDiscordService();
|
|
20029
20380
|
this.redditService = this.createRedditService();
|
|
20030
20381
|
this.rmarkdownService = this.createRMarkdownService();
|
|
20031
|
-
|
|
20032
|
-
|
|
20382
|
+
const deps = {
|
|
20383
|
+
addListRules: this.addListRules.bind(this),
|
|
20384
|
+
addPdfPageMarkerRules: this.addPdfPageMarkerRules.bind(this),
|
|
20385
|
+
tableToPlainText: this.tableToPlainText.bind(this)
|
|
20386
|
+
};
|
|
20387
|
+
this.slackService = createSlackService(deps);
|
|
20388
|
+
this.confluenceService = createConfluenceService(deps);
|
|
20033
20389
|
}
|
|
20034
20390
|
/**
|
|
20035
20391
|
* Create Discord-optimized Turndown service
|
|
@@ -20039,7 +20395,7 @@ var ConversionEngine = class {
|
|
|
20039
20395
|
* - Images converted to links
|
|
20040
20396
|
*/
|
|
20041
20397
|
createDiscordService() {
|
|
20042
|
-
const service = new
|
|
20398
|
+
const service = new import_turndown2.default({
|
|
20043
20399
|
headingStyle: "atx",
|
|
20044
20400
|
hr: "---",
|
|
20045
20401
|
bulletListMarker: "-",
|
|
@@ -20216,7 +20572,7 @@ ${plainText}
|
|
|
20216
20572
|
* - Fenced code blocks (new Reddit)
|
|
20217
20573
|
*/
|
|
20218
20574
|
createRedditService() {
|
|
20219
|
-
const service = new
|
|
20575
|
+
const service = new import_turndown2.default({
|
|
20220
20576
|
headingStyle: "atx",
|
|
20221
20577
|
hr: "---",
|
|
20222
20578
|
bulletListMarker: "-",
|
|
@@ -20274,7 +20630,7 @@ ${plainText}
|
|
|
20274
20630
|
* - Math expression preservation
|
|
20275
20631
|
*/
|
|
20276
20632
|
createRMarkdownService() {
|
|
20277
|
-
const service = new
|
|
20633
|
+
const service = new import_turndown2.default({
|
|
20278
20634
|
headingStyle: "atx",
|
|
20279
20635
|
hr: "---",
|
|
20280
20636
|
bulletListMarker: "-",
|
|
@@ -20337,377 +20693,6 @@ ${plainText}
|
|
|
20337
20693
|
});
|
|
20338
20694
|
return service;
|
|
20339
20695
|
}
|
|
20340
|
-
/**
|
|
20341
|
-
* Create Slack mrkdwn-optimized Turndown service
|
|
20342
|
-
* - Bold uses *text* (single asterisk, not **)
|
|
20343
|
-
* - Italic uses _text_
|
|
20344
|
-
* - Strikethrough uses ~text~ (single tilde)
|
|
20345
|
-
* - Links use <url|text> format
|
|
20346
|
-
* - Headers converted to bold (Slack has no heading support)
|
|
20347
|
-
* - Tables converted to code blocks
|
|
20348
|
-
*/
|
|
20349
|
-
createSlackService() {
|
|
20350
|
-
const service = new import_turndown.default({
|
|
20351
|
-
headingStyle: "atx",
|
|
20352
|
-
hr: "---",
|
|
20353
|
-
bulletListMarker: "-",
|
|
20354
|
-
codeBlockStyle: "fenced",
|
|
20355
|
-
fence: "```",
|
|
20356
|
-
emDelimiter: "_"
|
|
20357
|
-
});
|
|
20358
|
-
this.addListRules(service);
|
|
20359
|
-
this.addPdfPageMarkerRules(service);
|
|
20360
|
-
service.addRule("slackBold", {
|
|
20361
|
-
filter: (node) => {
|
|
20362
|
-
if (node.nodeName === "STRONG" || node.nodeName === "B") return true;
|
|
20363
|
-
if (node.nodeName === "SPAN") {
|
|
20364
|
-
const style = node.getAttribute("style") || "";
|
|
20365
|
-
if (style.includes("font-weight: bold") || style.includes("font-weight:bold")) return true;
|
|
20366
|
-
const fwMatch = style.match(/font-weight:\s*(\d+)/);
|
|
20367
|
-
if (fwMatch && parseInt(fwMatch[1]) >= 600) return true;
|
|
20368
|
-
const ffMatch = style.match(/font-family:\s*['"]*([^'"]+)['"]*[;]?/);
|
|
20369
|
-
if (ffMatch && ffMatch[1].toLowerCase().includes("bold")) return true;
|
|
20370
|
-
}
|
|
20371
|
-
return false;
|
|
20372
|
-
},
|
|
20373
|
-
replacement: (content) => content.trim() ? `*${content}*` : content
|
|
20374
|
-
});
|
|
20375
|
-
service.addRule("slackItalic", {
|
|
20376
|
-
filter: (node) => {
|
|
20377
|
-
if (node.nodeName === "EM" || node.nodeName === "I") return true;
|
|
20378
|
-
if (node.nodeName === "SPAN") {
|
|
20379
|
-
const style = node.getAttribute("style") || "";
|
|
20380
|
-
if (style.includes("font-style: italic") || style.includes("font-style:italic")) return true;
|
|
20381
|
-
const ffMatch = style.match(/font-family:\s*['"]*([^'"]+)['"]*[;]?/);
|
|
20382
|
-
if (ffMatch && ffMatch[1].toLowerCase().includes("italic")) return true;
|
|
20383
|
-
}
|
|
20384
|
-
return false;
|
|
20385
|
-
},
|
|
20386
|
-
replacement: (content) => content.trim() ? `_${content}_` : content
|
|
20387
|
-
});
|
|
20388
|
-
service.addRule("slackStrikethrough", {
|
|
20389
|
-
filter: (node) => {
|
|
20390
|
-
if (["DEL", "S", "STRIKE"].includes(node.nodeName)) return true;
|
|
20391
|
-
if (node.nodeName === "SPAN") {
|
|
20392
|
-
const style = node.getAttribute("style") || "";
|
|
20393
|
-
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");
|
|
20394
|
-
}
|
|
20395
|
-
return false;
|
|
20396
|
-
},
|
|
20397
|
-
replacement: (content) => content.trim() ? `~${content}~` : content
|
|
20398
|
-
});
|
|
20399
|
-
service.addRule("slackMonospaceCode", {
|
|
20400
|
-
filter: (node) => {
|
|
20401
|
-
if (node.nodeName !== "SPAN") return false;
|
|
20402
|
-
const style = node.getAttribute("style") || "";
|
|
20403
|
-
const fontFamily = style.toLowerCase();
|
|
20404
|
-
return fontFamily.includes("monospace") || fontFamily.includes("courier") || fontFamily.includes("consolas") || fontFamily.includes("monaco") || fontFamily.includes("menlo") || fontFamily.includes("source code") || fontFamily.includes("fira code") || fontFamily.includes("roboto mono") || fontFamily.includes("ubuntu mono");
|
|
20405
|
-
},
|
|
20406
|
-
replacement: (content) => {
|
|
20407
|
-
const trimmed = content.trim();
|
|
20408
|
-
if (!trimmed) return content;
|
|
20409
|
-
return trimmed.includes("`") ? `\`\` ${trimmed} \`\`` : `\`${trimmed}\``;
|
|
20410
|
-
}
|
|
20411
|
-
});
|
|
20412
|
-
service.addRule("slackHeading", {
|
|
20413
|
-
filter: ["h1", "h2", "h3", "h4", "h5", "h6"],
|
|
20414
|
-
replacement: (content) => content.trim() ? `*${content.trim()}*
|
|
20415
|
-
|
|
20416
|
-
` : content
|
|
20417
|
-
});
|
|
20418
|
-
service.addRule("slackGoogleDocsHeadings", {
|
|
20419
|
-
filter: (node) => {
|
|
20420
|
-
if (node.nodeName !== "P" && node.nodeName !== "DIV") return false;
|
|
20421
|
-
const style = node.getAttribute("style") || "";
|
|
20422
|
-
const fontSizeMatch = style.match(/font-size:\s*(\d+(?:\.\d+)?)px/);
|
|
20423
|
-
if (fontSizeMatch && parseFloat(fontSizeMatch[1]) > 16) return true;
|
|
20424
|
-
if (style.includes("font-weight: bold") || style.includes("font-weight:bold")) {
|
|
20425
|
-
const textContent = node.textContent || "";
|
|
20426
|
-
return textContent.length < 100 && textContent.trim().length > 0;
|
|
20427
|
-
}
|
|
20428
|
-
return false;
|
|
20429
|
-
},
|
|
20430
|
-
replacement: (content) => content.trim() ? `*${content.trim()}*
|
|
20431
|
-
|
|
20432
|
-
` : content
|
|
20433
|
-
});
|
|
20434
|
-
service.addRule("slackUnderline", {
|
|
20435
|
-
filter: (node) => {
|
|
20436
|
-
if (node.nodeName === "U" || node.nodeName === "INS") return true;
|
|
20437
|
-
if (node.nodeName === "SPAN") {
|
|
20438
|
-
const style = node.getAttribute("style") || "";
|
|
20439
|
-
return style.includes("text-decoration: underline") || style.includes("text-decoration:underline");
|
|
20440
|
-
}
|
|
20441
|
-
return false;
|
|
20442
|
-
},
|
|
20443
|
-
replacement: (content) => content
|
|
20444
|
-
});
|
|
20445
|
-
service.addRule("slackLink", {
|
|
20446
|
-
filter: (node) => node.nodeName === "A" && !!node.getAttribute("href"),
|
|
20447
|
-
replacement: (content, node) => {
|
|
20448
|
-
const href = node.getAttribute("href") || "";
|
|
20449
|
-
const text = content.trim().replace(/\|/g, " ");
|
|
20450
|
-
if (!text || text === href) return `<${href}>`;
|
|
20451
|
-
return `<${href}|${text}>`;
|
|
20452
|
-
}
|
|
20453
|
-
});
|
|
20454
|
-
service.addRule("slackImage", {
|
|
20455
|
-
filter: "img",
|
|
20456
|
-
replacement: (_content, node) => {
|
|
20457
|
-
const src = node.getAttribute("src") || "";
|
|
20458
|
-
const alt = (node.getAttribute("alt") || "image").replace(/\|/g, " ");
|
|
20459
|
-
return `<${src}|${alt}>`;
|
|
20460
|
-
}
|
|
20461
|
-
});
|
|
20462
|
-
service.addRule("slackTable", {
|
|
20463
|
-
filter: "table",
|
|
20464
|
-
replacement: (_content, node) => {
|
|
20465
|
-
const plainText = this.tableToPlainText(node);
|
|
20466
|
-
return `\`\`\`
|
|
20467
|
-
${plainText}
|
|
20468
|
-
\`\`\`
|
|
20469
|
-
|
|
20470
|
-
`;
|
|
20471
|
-
}
|
|
20472
|
-
});
|
|
20473
|
-
return service;
|
|
20474
|
-
}
|
|
20475
|
-
/**
|
|
20476
|
-
* Create Confluence wiki markup Turndown service
|
|
20477
|
-
* - Headings: h1. h2. etc.
|
|
20478
|
-
* - Bold: *text*, Italic: _text_, Underline: +text+, Strikethrough: -text-
|
|
20479
|
-
* - Inline code: {{text}}, Code blocks: {code:language=x}...{code}
|
|
20480
|
-
* - Links: [text|url], Images: !url!
|
|
20481
|
-
* - Tables: ||header|| / |cell| format
|
|
20482
|
-
* - Lists: depth-aware * and # notation
|
|
20483
|
-
* - Blockquote: {quote}...{quote}
|
|
20484
|
-
*/
|
|
20485
|
-
createConfluenceService() {
|
|
20486
|
-
const service = new import_turndown.default({
|
|
20487
|
-
headingStyle: "atx",
|
|
20488
|
-
hr: "---",
|
|
20489
|
-
bulletListMarker: "-",
|
|
20490
|
-
codeBlockStyle: "fenced",
|
|
20491
|
-
emDelimiter: "_"
|
|
20492
|
-
});
|
|
20493
|
-
this.addPdfPageMarkerRules(service);
|
|
20494
|
-
service.addRule("confluenceHeading", {
|
|
20495
|
-
filter: ["h1", "h2", "h3", "h4", "h5", "h6"],
|
|
20496
|
-
replacement: (content, node) => {
|
|
20497
|
-
const level = parseInt(node.nodeName[1], 10);
|
|
20498
|
-
return `
|
|
20499
|
-
|
|
20500
|
-
h${level}. ${content.trim()}
|
|
20501
|
-
|
|
20502
|
-
`;
|
|
20503
|
-
}
|
|
20504
|
-
});
|
|
20505
|
-
service.addRule("confluenceCodeBlock", {
|
|
20506
|
-
filter: "pre",
|
|
20507
|
-
replacement: (_content, node) => {
|
|
20508
|
-
const codeEl = node.querySelector("code");
|
|
20509
|
-
const langMatch = codeEl?.className?.match(/language-(\w+)/);
|
|
20510
|
-
const lang = langMatch ? langMatch[1] : "";
|
|
20511
|
-
const codeContent = codeEl?.textContent || node.textContent || "";
|
|
20512
|
-
const langAttr = lang ? `:language=${lang}` : "";
|
|
20513
|
-
return `
|
|
20514
|
-
|
|
20515
|
-
{code${langAttr}}
|
|
20516
|
-
${codeContent}
|
|
20517
|
-
{code}
|
|
20518
|
-
|
|
20519
|
-
`;
|
|
20520
|
-
}
|
|
20521
|
-
});
|
|
20522
|
-
service.addRule("confluenceInlineCode", {
|
|
20523
|
-
filter: (node) => node.nodeName === "CODE" && node.parentNode?.nodeName !== "PRE",
|
|
20524
|
-
replacement: (content) => content ? `{{${content.replace(/}+/g, (m) => m.split("").join(" "))}}}` : ""
|
|
20525
|
-
});
|
|
20526
|
-
service.addRule("confluenceBold", {
|
|
20527
|
-
filter: (node) => {
|
|
20528
|
-
if (node.nodeName === "STRONG" || node.nodeName === "B") return true;
|
|
20529
|
-
if (node.nodeName === "SPAN") {
|
|
20530
|
-
const style = node.getAttribute("style") || "";
|
|
20531
|
-
if (style.includes("font-weight: bold") || style.includes("font-weight:bold")) return true;
|
|
20532
|
-
const fwMatch = style.match(/font-weight:\s*(\d+)/);
|
|
20533
|
-
if (fwMatch && parseInt(fwMatch[1]) >= 600) return true;
|
|
20534
|
-
const ffMatch = style.match(/font-family:\s*['"]*([^'"]+)['"]*[;]?/);
|
|
20535
|
-
if (ffMatch && ffMatch[1].toLowerCase().includes("bold")) return true;
|
|
20536
|
-
}
|
|
20537
|
-
return false;
|
|
20538
|
-
},
|
|
20539
|
-
replacement: (content) => content.trim() ? `*${content}*` : content
|
|
20540
|
-
});
|
|
20541
|
-
service.addRule("confluenceItalic", {
|
|
20542
|
-
filter: (node) => {
|
|
20543
|
-
if (node.nodeName === "EM" || node.nodeName === "I") return true;
|
|
20544
|
-
if (node.nodeName === "SPAN") {
|
|
20545
|
-
const style = node.getAttribute("style") || "";
|
|
20546
|
-
if (style.includes("font-style: italic") || style.includes("font-style:italic")) return true;
|
|
20547
|
-
const ffMatch = style.match(/font-family:\s*['"]*([^'"]+)['"]*[;]?/);
|
|
20548
|
-
if (ffMatch && ffMatch[1].toLowerCase().includes("italic")) return true;
|
|
20549
|
-
}
|
|
20550
|
-
return false;
|
|
20551
|
-
},
|
|
20552
|
-
replacement: (content) => content.trim() ? `_${content}_` : content
|
|
20553
|
-
});
|
|
20554
|
-
service.addRule("confluenceUnderline", {
|
|
20555
|
-
filter: (node) => {
|
|
20556
|
-
if (node.nodeName === "U" || node.nodeName === "INS") return true;
|
|
20557
|
-
if (node.nodeName === "SPAN") {
|
|
20558
|
-
const style = node.getAttribute("style") || "";
|
|
20559
|
-
return style.includes("text-decoration: underline") || style.includes("text-decoration:underline");
|
|
20560
|
-
}
|
|
20561
|
-
return false;
|
|
20562
|
-
},
|
|
20563
|
-
replacement: (content) => content.trim() ? `+${content}+` : content
|
|
20564
|
-
});
|
|
20565
|
-
service.addRule("confluenceStrikethrough", {
|
|
20566
|
-
filter: (node) => {
|
|
20567
|
-
if (["DEL", "S", "STRIKE"].includes(node.nodeName)) return true;
|
|
20568
|
-
if (node.nodeName === "SPAN") {
|
|
20569
|
-
const style = node.getAttribute("style") || "";
|
|
20570
|
-
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");
|
|
20571
|
-
}
|
|
20572
|
-
return false;
|
|
20573
|
-
},
|
|
20574
|
-
replacement: (content) => content.trim() ? `-${content}-` : content
|
|
20575
|
-
});
|
|
20576
|
-
service.addRule("confluenceMonospaceCode", {
|
|
20577
|
-
filter: (node) => {
|
|
20578
|
-
if (node.nodeName !== "SPAN") return false;
|
|
20579
|
-
const style = node.getAttribute("style") || "";
|
|
20580
|
-
const fontFamily = style.toLowerCase();
|
|
20581
|
-
return fontFamily.includes("monospace") || fontFamily.includes("courier") || fontFamily.includes("consolas") || fontFamily.includes("monaco") || fontFamily.includes("menlo") || fontFamily.includes("source code") || fontFamily.includes("fira code") || fontFamily.includes("roboto mono") || fontFamily.includes("ubuntu mono");
|
|
20582
|
-
},
|
|
20583
|
-
replacement: (content) => content.trim() ? `{{${content.trim().replace(/}+/g, (m) => m.split("").join(" "))}}}` : content
|
|
20584
|
-
});
|
|
20585
|
-
service.addRule("confluenceLink", {
|
|
20586
|
-
filter: (node) => node.nodeName === "A" && !!node.getAttribute("href"),
|
|
20587
|
-
replacement: (content, node) => {
|
|
20588
|
-
const href = node.getAttribute("href") || "";
|
|
20589
|
-
const text = content.trim().replace(/\|/g, " ");
|
|
20590
|
-
if (!text || text === href) return `[${href}]`;
|
|
20591
|
-
return `[${text}|${href}]`;
|
|
20592
|
-
}
|
|
20593
|
-
});
|
|
20594
|
-
service.addRule("confluenceImage", {
|
|
20595
|
-
filter: "img",
|
|
20596
|
-
replacement: (_content, node) => {
|
|
20597
|
-
const src = node.getAttribute("src") || "";
|
|
20598
|
-
return src ? `!${src}!` : "";
|
|
20599
|
-
}
|
|
20600
|
-
});
|
|
20601
|
-
service.addRule("confluenceHr", {
|
|
20602
|
-
filter: "hr",
|
|
20603
|
-
replacement: () => "\n\n----\n\n"
|
|
20604
|
-
});
|
|
20605
|
-
service.addRule("confluenceBlockquote", {
|
|
20606
|
-
filter: "blockquote",
|
|
20607
|
-
replacement: (content) => `
|
|
20608
|
-
|
|
20609
|
-
{quote}
|
|
20610
|
-
${content.trim()}
|
|
20611
|
-
{quote}
|
|
20612
|
-
|
|
20613
|
-
`
|
|
20614
|
-
});
|
|
20615
|
-
service.addRule("confluenceGoogleDocsHeadings", {
|
|
20616
|
-
filter: (node) => {
|
|
20617
|
-
if (node.nodeName !== "P" && node.nodeName !== "DIV") return false;
|
|
20618
|
-
const style = node.getAttribute("style") || "";
|
|
20619
|
-
const fontSizeMatch = style.match(/font-size:\s*(\d+(?:\.\d+)?)px/);
|
|
20620
|
-
if (fontSizeMatch && parseFloat(fontSizeMatch[1]) > 16) return true;
|
|
20621
|
-
if (style.includes("font-weight: bold") || style.includes("font-weight:bold")) {
|
|
20622
|
-
const textContent = node.textContent || "";
|
|
20623
|
-
return textContent.length < 100 && textContent.trim().length > 0;
|
|
20624
|
-
}
|
|
20625
|
-
return false;
|
|
20626
|
-
},
|
|
20627
|
-
replacement: (content, node) => {
|
|
20628
|
-
const style = node?.getAttribute("style") || "";
|
|
20629
|
-
const fontSizeMatch = style.match(/font-size:\s*(\d+(?:\.\d+)?)px/);
|
|
20630
|
-
const trimmed = content.trim();
|
|
20631
|
-
if (!trimmed) return content;
|
|
20632
|
-
if (!fontSizeMatch) {
|
|
20633
|
-
return `
|
|
20634
|
-
|
|
20635
|
-
*${trimmed}*
|
|
20636
|
-
|
|
20637
|
-
`;
|
|
20638
|
-
}
|
|
20639
|
-
const fontSize = parseFloat(fontSizeMatch[1]);
|
|
20640
|
-
let level = 5;
|
|
20641
|
-
if (fontSize >= 28) level = 1;
|
|
20642
|
-
else if (fontSize >= 24) level = 2;
|
|
20643
|
-
else if (fontSize >= 20) level = 3;
|
|
20644
|
-
else if (fontSize >= 18) level = 4;
|
|
20645
|
-
return `
|
|
20646
|
-
|
|
20647
|
-
h${level}. ${trimmed}
|
|
20648
|
-
|
|
20649
|
-
`;
|
|
20650
|
-
}
|
|
20651
|
-
});
|
|
20652
|
-
service.addRule("confluenceList", {
|
|
20653
|
-
filter: ["ul", "ol"],
|
|
20654
|
-
replacement: (_content, node) => {
|
|
20655
|
-
return this.processConfluenceList(node, service, 1);
|
|
20656
|
-
}
|
|
20657
|
-
});
|
|
20658
|
-
service.addRule("confluenceTable", {
|
|
20659
|
-
filter: "table",
|
|
20660
|
-
replacement: (_content, node) => {
|
|
20661
|
-
const table = node;
|
|
20662
|
-
const rows = Array.from(table.querySelectorAll("tr"));
|
|
20663
|
-
if (rows.length === 0) return "";
|
|
20664
|
-
let result = "\n";
|
|
20665
|
-
rows.forEach((row) => {
|
|
20666
|
-
const cells = Array.from(row.querySelectorAll("th, td"));
|
|
20667
|
-
const isHeaderRow = cells.some((c) => c.nodeName === "TH");
|
|
20668
|
-
const delim = isHeaderRow ? "||" : "|";
|
|
20669
|
-
const cellTexts = cells.map((c) => (c.textContent || "").trim());
|
|
20670
|
-
result += delim + cellTexts.join(delim) + delim + "\n";
|
|
20671
|
-
});
|
|
20672
|
-
return result + "\n";
|
|
20673
|
-
}
|
|
20674
|
-
});
|
|
20675
|
-
return service;
|
|
20676
|
-
}
|
|
20677
|
-
/**
|
|
20678
|
-
* Process a Confluence list element into depth-aware wiki markup.
|
|
20679
|
-
* Uses * for unordered and # for ordered, repeated for nesting depth.
|
|
20680
|
-
*/
|
|
20681
|
-
processConfluenceList(list, service, depth) {
|
|
20682
|
-
const isOrdered = list.nodeName === "OL";
|
|
20683
|
-
const marker = (isOrdered ? "#" : "*").repeat(depth);
|
|
20684
|
-
const items = Array.from(list.children).filter((c) => c.nodeName === "LI");
|
|
20685
|
-
let result = depth === 1 ? "\n" : "";
|
|
20686
|
-
items.forEach((item) => {
|
|
20687
|
-
const itemContent = this.processConfluenceListItem(item, service, depth);
|
|
20688
|
-
result += `${marker} ${itemContent}
|
|
20689
|
-
`;
|
|
20690
|
-
});
|
|
20691
|
-
return depth === 1 ? result + "\n" : result;
|
|
20692
|
-
}
|
|
20693
|
-
processConfluenceListItem(item, service, depth) {
|
|
20694
|
-
let content = "";
|
|
20695
|
-
const TEXT_NODE = 3;
|
|
20696
|
-
const ELEMENT_NODE = 1;
|
|
20697
|
-
Array.from(item.childNodes).forEach((child) => {
|
|
20698
|
-
if (child.nodeType === TEXT_NODE) {
|
|
20699
|
-
content += child.textContent || "";
|
|
20700
|
-
} else if (child.nodeType === ELEMENT_NODE) {
|
|
20701
|
-
const el = child;
|
|
20702
|
-
if (el.nodeName === "UL" || el.nodeName === "OL") {
|
|
20703
|
-
content += "\n" + this.processConfluenceList(el, service, depth + 1);
|
|
20704
|
-
} else {
|
|
20705
|
-
content += service.turndown(el.outerHTML);
|
|
20706
|
-
}
|
|
20707
|
-
}
|
|
20708
|
-
});
|
|
20709
|
-
return content.trim();
|
|
20710
|
-
}
|
|
20711
20696
|
/**
|
|
20712
20697
|
* Convert HTML table to plain text for Discord code blocks
|
|
20713
20698
|
*/
|
|
@@ -21122,34 +21107,52 @@ async function loadLibrary(format) {
|
|
|
21122
21107
|
}
|
|
21123
21108
|
}
|
|
21124
21109
|
async function importMammoth() {
|
|
21125
|
-
|
|
21110
|
+
const mod = await import("mammoth");
|
|
21111
|
+
const modDefault = mod.default;
|
|
21112
|
+
if (mod && !mod.convertToHtml && modDefault && modDefault.convertToHtml) {
|
|
21113
|
+
return mod.default;
|
|
21114
|
+
}
|
|
21115
|
+
return mod;
|
|
21126
21116
|
}
|
|
21127
21117
|
async function importXlsx() {
|
|
21128
|
-
|
|
21118
|
+
const mod = await import("xlsx");
|
|
21119
|
+
const modDefault = mod.default;
|
|
21120
|
+
if (mod && !mod.read && modDefault && modDefault.read) {
|
|
21121
|
+
return mod.default;
|
|
21122
|
+
}
|
|
21123
|
+
return mod;
|
|
21129
21124
|
}
|
|
21130
21125
|
async function importPdfjs() {
|
|
21131
|
-
if (typeof process !== "undefined"
|
|
21132
|
-
|
|
21133
|
-
|
|
21134
|
-
|
|
21135
|
-
const mod = await import(
|
|
21136
|
-
/* @vite-ignore */
|
|
21137
|
-
moduleName
|
|
21138
|
-
);
|
|
21139
|
-
if (mod && mod.createRequire) {
|
|
21140
|
-
requireWorker = mod.createRequire(import.meta.url);
|
|
21141
|
-
}
|
|
21142
|
-
} catch {
|
|
21143
|
-
}
|
|
21144
|
-
process.getBuiltinModule = (name) => {
|
|
21126
|
+
if (typeof process !== "undefined") {
|
|
21127
|
+
const proxyProcess = process;
|
|
21128
|
+
if (typeof proxyProcess.getBuiltinModule !== "function") {
|
|
21129
|
+
let requireWorker;
|
|
21145
21130
|
try {
|
|
21146
|
-
|
|
21131
|
+
const moduleName = "module";
|
|
21132
|
+
const mod2 = await import(
|
|
21133
|
+
/* @vite-ignore */
|
|
21134
|
+
moduleName
|
|
21135
|
+
);
|
|
21136
|
+
if (mod2 && typeof mod2.createRequire === "function") {
|
|
21137
|
+
requireWorker = mod2.createRequire(import.meta.url);
|
|
21138
|
+
}
|
|
21147
21139
|
} catch {
|
|
21148
|
-
return void 0;
|
|
21149
21140
|
}
|
|
21150
|
-
|
|
21141
|
+
proxyProcess.getBuiltinModule = (name) => {
|
|
21142
|
+
try {
|
|
21143
|
+
return requireWorker ? requireWorker(name) : void 0;
|
|
21144
|
+
} catch {
|
|
21145
|
+
return void 0;
|
|
21146
|
+
}
|
|
21147
|
+
};
|
|
21148
|
+
}
|
|
21149
|
+
}
|
|
21150
|
+
const mod = await import("pdfjs-dist/legacy/build/pdf.mjs");
|
|
21151
|
+
const modDefault = mod.default;
|
|
21152
|
+
if (mod && !mod.getDocument && modDefault && modDefault.getDocument) {
|
|
21153
|
+
return mod.default;
|
|
21151
21154
|
}
|
|
21152
|
-
return
|
|
21155
|
+
return mod;
|
|
21153
21156
|
}
|
|
21154
21157
|
async function loadLibraryInternal(format) {
|
|
21155
21158
|
try {
|
|
@@ -23126,8 +23129,8 @@ import { readFileSync as readFileSync4 } from "fs";
|
|
|
23126
23129
|
import { resolve, dirname as dirname3 } from "path";
|
|
23127
23130
|
import { fileURLToPath } from "url";
|
|
23128
23131
|
var getVersion = () => {
|
|
23129
|
-
if ("1.0.
|
|
23130
|
-
return "1.0.
|
|
23132
|
+
if ("1.0.9") {
|
|
23133
|
+
return "1.0.9";
|
|
23131
23134
|
}
|
|
23132
23135
|
try {
|
|
23133
23136
|
const __dirname = dirname3(fileURLToPath(import.meta.url));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "formatferry",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "FormatFerry CLI — Convert HTML, DOCX, PDF, XLSX, CSV to Markdown",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"markdown",
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"node": ">=18"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
|
+
"prepublishOnly": "npm run build",
|
|
25
26
|
"build": "node build.mjs",
|
|
26
27
|
"test": "vitest --run"
|
|
27
28
|
},
|