formatferry 1.0.40 → 1.0.41

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.
Files changed (2) hide show
  1. package/dist/index.js +224 -144
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -58011,6 +58011,153 @@ import DOMPurifyImport from "dompurify";
58011
58011
  // ../../src/shared/constants.ts
58012
58012
  var MAX_INTERMEDIATE_HTML_CHARS = 256 * 1024 * 1024;
58013
58013
 
58014
+ // ../../src/shared/linkedom-sanitizer.ts
58015
+ var FORBID_CONTENTS = /* @__PURE__ */ new Set([
58016
+ "annotation-xml",
58017
+ "audio",
58018
+ "colgroup",
58019
+ "desc",
58020
+ "foreignobject",
58021
+ "head",
58022
+ "iframe",
58023
+ "math",
58024
+ "mi",
58025
+ "mn",
58026
+ "mo",
58027
+ "ms",
58028
+ "mtext",
58029
+ "noembed",
58030
+ "noframes",
58031
+ "noscript",
58032
+ "plaintext",
58033
+ "script",
58034
+ "selectedcontent",
58035
+ "style",
58036
+ "svg",
58037
+ "template",
58038
+ "thead",
58039
+ "title",
58040
+ "video",
58041
+ "xmp"
58042
+ ]);
58043
+ var BLOCK_UNWRAP_TAGS = /* @__PURE__ */ new Set([
58044
+ "address",
58045
+ "article",
58046
+ "aside",
58047
+ "center",
58048
+ "details",
58049
+ "dialog",
58050
+ "dir",
58051
+ "dd",
58052
+ "dl",
58053
+ "dt",
58054
+ "fieldset",
58055
+ "figcaption",
58056
+ "figure",
58057
+ "footer",
58058
+ "form",
58059
+ "header",
58060
+ "hgroup",
58061
+ "legend",
58062
+ "main",
58063
+ "menu",
58064
+ "nav",
58065
+ "search",
58066
+ "section",
58067
+ "summary"
58068
+ ]);
58069
+ var DATA_URI_TAGS = /* @__PURE__ */ new Set(["audio", "video", "img", "source", "image", "track"]);
58070
+ var URI_SAFE_ATTRIBUTES = /* @__PURE__ */ new Set([
58071
+ "alt",
58072
+ "class",
58073
+ "for",
58074
+ "id",
58075
+ "label",
58076
+ "name",
58077
+ "pattern",
58078
+ "placeholder",
58079
+ "role",
58080
+ "summary",
58081
+ "title",
58082
+ "value",
58083
+ "style",
58084
+ "xmlns"
58085
+ ]);
58086
+ var IS_ALLOWED_URI = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i;
58087
+ var ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
58088
+ var ELEMENT_NODE = 1;
58089
+ var COMMENT_NODE = 8;
58090
+ function toSet(list) {
58091
+ return new Set((list ?? []).map((s) => s.toLowerCase()));
58092
+ }
58093
+ function attrAllowed(name, allowed, wildcards) {
58094
+ return allowed.has(name) || wildcards.some((prefix) => name.startsWith(prefix));
58095
+ }
58096
+ function isSafeValue(tag, name, value) {
58097
+ if (URI_SAFE_ATTRIBUTES.has(name) || !value) return true;
58098
+ if (IS_ALLOWED_URI.test(value.replace(ATTR_WHITESPACE, ""))) return true;
58099
+ return (name === "src" || name === "href" || name === "xlink:href") && value.startsWith("data:") && DATA_URI_TAGS.has(tag);
58100
+ }
58101
+ function sanitizeWithLinkedom(html, config, parse) {
58102
+ if (!html) return "";
58103
+ const allowedTags = toSet(config.ALLOWED_TAGS);
58104
+ const forbidTags = toSet(config.FORBID_TAGS);
58105
+ const allowedAttrList = (config.ALLOWED_ATTR ?? []).map((s) => s.toLowerCase());
58106
+ const allowedAttrs = new Set(allowedAttrList.filter((a) => !a.endsWith("*")));
58107
+ const attrWildcards = allowedAttrList.filter((a) => a.endsWith("*")).map((a) => a.slice(0, -1));
58108
+ const forbidAttrs = toSet(config.FORBID_ATTR);
58109
+ const doc = parse(`<!DOCTYPE html><html><head></head><body>${html}</body></html>`);
58110
+ const body = doc.body;
58111
+ if (!body) return "";
58112
+ const toUnwrap = [];
58113
+ const hadChildren = /* @__PURE__ */ new Set();
58114
+ const stack = [body];
58115
+ while (stack.length > 0) {
58116
+ const parent = stack.pop();
58117
+ for (const child of Array.from(parent.childNodes)) {
58118
+ if (child.nodeType === COMMENT_NODE) {
58119
+ parent.removeChild(child);
58120
+ continue;
58121
+ }
58122
+ if (child.nodeType !== ELEMENT_NODE) continue;
58123
+ const el = child;
58124
+ const tag = el.nodeName.toLowerCase();
58125
+ if (!allowedTags.has(tag) || forbidTags.has(tag)) {
58126
+ if (FORBID_CONTENTS.has(tag)) {
58127
+ parent.removeChild(el);
58128
+ } else {
58129
+ toUnwrap.push(el);
58130
+ if (el.firstChild) hadChildren.add(el);
58131
+ stack.push(el);
58132
+ }
58133
+ continue;
58134
+ }
58135
+ for (const attr of Array.from(el.attributes)) {
58136
+ const name = attr.name.toLowerCase();
58137
+ if (name.startsWith("on") || forbidAttrs.has(name) || !attrAllowed(name, allowedAttrs, attrWildcards) || !isSafeValue(tag, name, attr.value)) {
58138
+ el.removeAttribute(attr.name);
58139
+ }
58140
+ }
58141
+ stack.push(el);
58142
+ }
58143
+ }
58144
+ const wrapBlocks = allowedTags.has("div") && !forbidTags.has("div");
58145
+ for (let i = toUnwrap.length - 1; i >= 0; i--) {
58146
+ const el = toUnwrap[i];
58147
+ const parent = el.parentNode;
58148
+ if (!parent) continue;
58149
+ if (wrapBlocks && hadChildren.has(el) && BLOCK_UNWRAP_TAGS.has(el.nodeName.toLowerCase())) {
58150
+ const div = doc.createElement("div");
58151
+ while (el.firstChild) div.appendChild(el.firstChild);
58152
+ parent.replaceChild(div, el);
58153
+ continue;
58154
+ }
58155
+ while (el.firstChild) parent.insertBefore(el.firstChild, el);
58156
+ parent.removeChild(el);
58157
+ }
58158
+ return body.innerHTML;
58159
+ }
58160
+
58014
58161
  // ../../src/shared/input-sanitizer.ts
58015
58162
  function resolveDOMPurify() {
58016
58163
  const shimInstance = globalThis.__FF_DOMPurify;
@@ -58056,12 +58203,42 @@ var InputSanitizer = class {
58056
58203
  if (!html || typeof html !== "string") {
58057
58204
  return "";
58058
58205
  }
58059
- return this.domEnv.DOMPurify.sanitize(html, {
58060
- ALLOWED_TAGS: this.purifyConfig.ALLOWED_TAGS,
58061
- ALLOWED_ATTR: this.purifyConfig.ALLOWED_ATTR,
58062
- FORBID_TAGS: this.purifyConfig.FORBID_TAGS,
58063
- FORBID_ATTR: this.purifyConfig.FORBID_ATTR
58064
- });
58206
+ const purify = this.domEnv.DOMPurify;
58207
+ const hook = this.blockUnwrapHook();
58208
+ const useHook = hook && purify.addHook && purify.removeHook;
58209
+ if (useHook) purify.addHook("uponSanitizeElement", hook);
58210
+ try {
58211
+ return purify.sanitize(html, {
58212
+ ALLOWED_TAGS: this.purifyConfig.ALLOWED_TAGS,
58213
+ ALLOWED_ATTR: this.purifyConfig.ALLOWED_ATTR,
58214
+ FORBID_TAGS: this.purifyConfig.FORBID_TAGS,
58215
+ FORBID_ATTR: this.purifyConfig.FORBID_ATTR
58216
+ });
58217
+ } finally {
58218
+ if (useHook) purify.removeHook("uponSanitizeElement", hook);
58219
+ }
58220
+ }
58221
+ /**
58222
+ * DOMPurify unwraps a disallowed element by moving its children up, so
58223
+ * `<header>Head</header><nav>Nav</nav>` came out as "HeadNav". For a
58224
+ * block-level element, move its children into a <div> first: DOMPurify then
58225
+ * hoists that <div>, and Turndown gives the content its own paragraph. Same
58226
+ * rule as the linkedom sanitiser (BLOCK_UNWRAP_TAGS, #177).
58227
+ */
58228
+ blockUnwrapHook() {
58229
+ const allowed = new Set((this.purifyConfig.ALLOWED_TAGS ?? []).map((t) => t.toLowerCase()));
58230
+ const forbidden = new Set((this.purifyConfig.FORBID_TAGS ?? []).map((t) => t.toLowerCase()));
58231
+ if (!allowed.has("div") || forbidden.has("div")) return void 0;
58232
+ return (node, data) => {
58233
+ const tag = data.tagName.toLowerCase();
58234
+ if (!BLOCK_UNWRAP_TAGS.has(tag) || allowed.has(tag) && !forbidden.has(tag)) return;
58235
+ const el = node;
58236
+ const doc = el.ownerDocument;
58237
+ if (!doc || !el.firstChild) return;
58238
+ const div = doc.createElement("div");
58239
+ while (el.firstChild) div.appendChild(el.firstChild);
58240
+ el.appendChild(div);
58241
+ };
58065
58242
  }
58066
58243
  /**
58067
58244
  * Sanitize HTML content to prevent XSS attacks
@@ -58238,6 +58415,13 @@ var InputSanitizer = class {
58238
58415
  "th",
58239
58416
  "figure",
58240
58417
  "figcaption",
58418
+ // Definition lists and disclosure widgets (#177): unwrapped, their
58419
+ // text ran together ("TermDefinition", "MoreHidden").
58420
+ "dl",
58421
+ "dt",
58422
+ "dd",
58423
+ "details",
58424
+ "summary",
58241
58425
  "a",
58242
58426
  "img",
58243
58427
  "sup",
@@ -59128,7 +59312,21 @@ var ConversionEngine = class {
59128
59312
  this.rmarkdownService,
59129
59313
  this.slackService,
59130
59314
  this.confluenceService
59131
- ].forEach((service) => this.addGoogleDocsWrapperRule(service));
59315
+ ].forEach((service) => {
59316
+ this.addGoogleDocsWrapperRule(service);
59317
+ this.addDisclosureBlockRule(service);
59318
+ });
59319
+ }
59320
+ /**
59321
+ * Turndown's block list has no DETAILS or SUMMARY, so it treated them as
59322
+ * inline and `<details><summary>More</summary>Hidden</details>` came out as
59323
+ * "MoreHidden". Give them block spacing like a <div> (#177).
59324
+ */
59325
+ addDisclosureBlockRule(service) {
59326
+ service.addRule("disclosureBlock", {
59327
+ filter: ["details", "summary"],
59328
+ replacement: (content) => "\n\n" + content + "\n\n"
59329
+ });
59132
59330
  }
59133
59331
  /**
59134
59332
  * Google Docs wraps every copied selection in
@@ -63814,118 +64012,6 @@ function buildCachedProvider(config, lastValidated) {
63814
64012
  return new CachedEntitlementProvider(cachedState);
63815
64013
  }
63816
64014
 
63817
- // ../../src/shared/linkedom-sanitizer.ts
63818
- var FORBID_CONTENTS = /* @__PURE__ */ new Set([
63819
- "annotation-xml",
63820
- "audio",
63821
- "colgroup",
63822
- "desc",
63823
- "foreignobject",
63824
- "head",
63825
- "iframe",
63826
- "math",
63827
- "mi",
63828
- "mn",
63829
- "mo",
63830
- "ms",
63831
- "mtext",
63832
- "noembed",
63833
- "noframes",
63834
- "noscript",
63835
- "plaintext",
63836
- "script",
63837
- "selectedcontent",
63838
- "style",
63839
- "svg",
63840
- "template",
63841
- "thead",
63842
- "title",
63843
- "video",
63844
- "xmp"
63845
- ]);
63846
- var DATA_URI_TAGS = /* @__PURE__ */ new Set(["audio", "video", "img", "source", "image", "track"]);
63847
- var URI_SAFE_ATTRIBUTES = /* @__PURE__ */ new Set([
63848
- "alt",
63849
- "class",
63850
- "for",
63851
- "id",
63852
- "label",
63853
- "name",
63854
- "pattern",
63855
- "placeholder",
63856
- "role",
63857
- "summary",
63858
- "title",
63859
- "value",
63860
- "style",
63861
- "xmlns"
63862
- ]);
63863
- var IS_ALLOWED_URI = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i;
63864
- var ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g;
63865
- var ELEMENT_NODE = 1;
63866
- var COMMENT_NODE = 8;
63867
- function toSet(list) {
63868
- return new Set((list ?? []).map((s) => s.toLowerCase()));
63869
- }
63870
- function attrAllowed(name, allowed, wildcards) {
63871
- return allowed.has(name) || wildcards.some((prefix) => name.startsWith(prefix));
63872
- }
63873
- function isSafeValue(tag, name, value) {
63874
- if (URI_SAFE_ATTRIBUTES.has(name) || !value) return true;
63875
- if (IS_ALLOWED_URI.test(value.replace(ATTR_WHITESPACE, ""))) return true;
63876
- return (name === "src" || name === "href" || name === "xlink:href") && value.startsWith("data:") && DATA_URI_TAGS.has(tag);
63877
- }
63878
- function sanitizeWithLinkedom(html, config, parse) {
63879
- if (!html) return "";
63880
- const allowedTags = toSet(config.ALLOWED_TAGS);
63881
- const forbidTags = toSet(config.FORBID_TAGS);
63882
- const allowedAttrList = (config.ALLOWED_ATTR ?? []).map((s) => s.toLowerCase());
63883
- const allowedAttrs = new Set(allowedAttrList.filter((a) => !a.endsWith("*")));
63884
- const attrWildcards = allowedAttrList.filter((a) => a.endsWith("*")).map((a) => a.slice(0, -1));
63885
- const forbidAttrs = toSet(config.FORBID_ATTR);
63886
- const doc = parse(`<!DOCTYPE html><html><head></head><body>${html}</body></html>`);
63887
- const body = doc.body;
63888
- if (!body) return "";
63889
- const toUnwrap = [];
63890
- const stack = [body];
63891
- while (stack.length > 0) {
63892
- const parent = stack.pop();
63893
- for (const child of Array.from(parent.childNodes)) {
63894
- if (child.nodeType === COMMENT_NODE) {
63895
- parent.removeChild(child);
63896
- continue;
63897
- }
63898
- if (child.nodeType !== ELEMENT_NODE) continue;
63899
- const el = child;
63900
- const tag = el.nodeName.toLowerCase();
63901
- if (!allowedTags.has(tag) || forbidTags.has(tag)) {
63902
- if (FORBID_CONTENTS.has(tag)) {
63903
- parent.removeChild(el);
63904
- } else {
63905
- toUnwrap.push(el);
63906
- stack.push(el);
63907
- }
63908
- continue;
63909
- }
63910
- for (const attr of Array.from(el.attributes)) {
63911
- const name = attr.name.toLowerCase();
63912
- if (name.startsWith("on") || forbidAttrs.has(name) || !attrAllowed(name, allowedAttrs, attrWildcards) || !isSafeValue(tag, name, attr.value)) {
63913
- el.removeAttribute(attr.name);
63914
- }
63915
- }
63916
- stack.push(el);
63917
- }
63918
- }
63919
- for (let i = toUnwrap.length - 1; i >= 0; i--) {
63920
- const el = toUnwrap[i];
63921
- const parent = el.parentNode;
63922
- if (!parent) continue;
63923
- while (el.firstChild) parent.insertBefore(el.firstChild, el);
63924
- parent.removeChild(el);
63925
- }
63926
- return body.innerHTML;
63927
- }
63928
-
63929
64015
  // ../../src/shared/token-estimator.ts
63930
64016
  var CJK_REGEX3 = /[\u4e00-\u9fff\u3400-\u4dbf\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g;
63931
64017
  var MAX_INPUT_LENGTH = 1e6;
@@ -64390,7 +64476,7 @@ function readStdin() {
64390
64476
  }
64391
64477
  async function htmlToMarkdown(html, format, applyAtlassianNormalization = false) {
64392
64478
  const processedHtml = applyAtlassianNormalization ? normalizeAtlassianHTML(html) : html;
64393
- const engine = new ConversionEngine();
64479
+ const engine = new ConversionEngine({ dom: linkedomDomEnvironment() });
64394
64480
  const result = await engine.convert(processedHtml, {
64395
64481
  format,
64396
64482
  preserveTables: true,
@@ -64404,12 +64490,11 @@ async function binaryToMarkdown(buffer, type, format) {
64404
64490
  buffer.byteOffset,
64405
64491
  buffer.byteOffset + buffer.byteLength
64406
64492
  );
64407
- const engine = new ConversionEngine();
64493
+ const engine = new ConversionEngine({ dom: linkedomDomEnvironment() });
64408
64494
  switch (type) {
64409
64495
  case "docx": {
64410
64496
  const result = await docxAdapter.parseToHtml(buffer);
64411
- const sanitized = sanitizeHTML(result.html);
64412
- const converted = await engine.convert(sanitized, {
64497
+ const converted = await engine.convert(result.html, {
64413
64498
  format,
64414
64499
  preserveTables: true,
64415
64500
  preserveLists: true,
@@ -64419,8 +64504,7 @@ async function binaryToMarkdown(buffer, type, format) {
64419
64504
  }
64420
64505
  case "pdf": {
64421
64506
  const result = await pdfAdapter.parseToText(toArrayBuffer());
64422
- const sanitized = sanitizeHTML(result.html);
64423
- const converted = await engine.convert(sanitized, {
64507
+ const converted = await engine.convert(result.html, {
64424
64508
  format,
64425
64509
  preserveTables: true,
64426
64510
  preserveLists: true,
@@ -64431,8 +64515,7 @@ async function binaryToMarkdown(buffer, type, format) {
64431
64515
  case "xlsx":
64432
64516
  case "csv": {
64433
64517
  const result = await spreadsheetAdapter.parseToHtml(toArrayBuffer(), type, 0);
64434
- const sanitized = sanitizeHTML(result.html);
64435
- const converted = await engine.convert(sanitized, {
64518
+ const converted = await engine.convert(result.html, {
64436
64519
  format,
64437
64520
  preserveTables: true,
64438
64521
  preserveLists: true,
@@ -64442,8 +64525,7 @@ async function binaryToMarkdown(buffer, type, format) {
64442
64525
  }
64443
64526
  case "json": {
64444
64527
  const result = await dataAdapter.parseJsonToHtml(toArrayBuffer());
64445
- const sanitized = sanitizeHTML(result.html);
64446
- const converted = await engine.convert(sanitized, {
64528
+ const converted = await engine.convert(result.html, {
64447
64529
  format,
64448
64530
  preserveTables: true,
64449
64531
  preserveLists: true,
@@ -64453,8 +64535,7 @@ async function binaryToMarkdown(buffer, type, format) {
64453
64535
  }
64454
64536
  case "xml": {
64455
64537
  const result = await dataAdapter.parseXmlToHtml(toArrayBuffer());
64456
- const sanitized = sanitizeHTML(result.html);
64457
- const converted = await engine.convert(sanitized, {
64538
+ const converted = await engine.convert(result.html, {
64458
64539
  format,
64459
64540
  preserveTables: true,
64460
64541
  preserveLists: true,
@@ -64464,8 +64545,7 @@ async function binaryToMarkdown(buffer, type, format) {
64464
64545
  }
64465
64546
  case "pptx": {
64466
64547
  const result = await pptxAdapter.parseToHtml(toArrayBuffer());
64467
- const sanitized = sanitizeHTML(result.html);
64468
- const converted = await engine.convert(sanitized, {
64548
+ const converted = await engine.convert(result.html, {
64469
64549
  format,
64470
64550
  preserveTables: true,
64471
64551
  preserveLists: true,
@@ -64477,7 +64557,7 @@ async function binaryToMarkdown(buffer, type, format) {
64477
64557
  }
64478
64558
  function linkedomDomEnvironment() {
64479
64559
  const parseHTML2 = globalThis.__FF_parseHTML;
64480
- if (!parseHTML2) throw new Error("The CLI shim must be loaded before converting a URL");
64560
+ if (!parseHTML2) throw new Error("The CLI shim must be loaded before converting");
64481
64561
  const parseDocument = (html) => parseHTML2(html).document;
64482
64562
  const { window: window3 } = parseHTML2("<!DOCTYPE html><html><head></head><body></body></html>");
64483
64563
  return {
@@ -64685,9 +64765,9 @@ async function convertFile(filePath, format) {
64685
64765
  const ext = extname2(filePath).toLowerCase();
64686
64766
  if (!SUPPORTED_EXTENSIONS.has(ext)) throw new Error(`Unsupported file type: ${ext}`);
64687
64767
  const buffer = readFileSync4(filePath);
64688
- const engine = new ConversionEngine();
64768
+ const engine = new ConversionEngine({ dom: linkedomDomEnvironment() });
64689
64769
  if (ext === ".html" || ext === ".htm") {
64690
- const result = await engine.convert(sanitizeHTML(buffer.toString("utf8")), {
64770
+ const result = await engine.convert(buffer.toString("utf8"), {
64691
64771
  format,
64692
64772
  preserveTables: true,
64693
64773
  preserveLists: true,
@@ -64698,32 +64778,32 @@ async function convertFile(filePath, format) {
64698
64778
  const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
64699
64779
  if (ext === ".docx") {
64700
64780
  const r = await docxAdapter.parseToHtml(arrayBuffer);
64701
- const c = await engine.convert(sanitizeHTML(r.html), { format, preserveTables: true, preserveLists: true, customRules: [] });
64781
+ const c = await engine.convert(r.html, { format, preserveTables: true, preserveLists: true, customRules: [] });
64702
64782
  return { markdown: c.markdown, warnings: r.warnings ?? [] };
64703
64783
  }
64704
64784
  if (ext === ".pdf") {
64705
64785
  const r = await pdfAdapter.parseToText(arrayBuffer);
64706
- const c = await engine.convert(sanitizeHTML(r.html), { format, preserveTables: true, preserveLists: true, customRules: [] });
64786
+ const c = await engine.convert(r.html, { format, preserveTables: true, preserveLists: true, customRules: [] });
64707
64787
  return { markdown: c.markdown, warnings: r.warnings ?? [] };
64708
64788
  }
64709
64789
  if (ext === ".xlsx" || ext === ".csv") {
64710
64790
  const r = await spreadsheetAdapter.parseToHtml(arrayBuffer, ext.slice(1), 0);
64711
- const c = await engine.convert(sanitizeHTML(r.html), { format, preserveTables: true, preserveLists: true, customRules: [] });
64791
+ const c = await engine.convert(r.html, { format, preserveTables: true, preserveLists: true, customRules: [] });
64712
64792
  return { markdown: c.markdown, warnings: r.warnings ?? [] };
64713
64793
  }
64714
64794
  if (ext === ".json") {
64715
64795
  const r = await dataAdapter.parseJsonToHtml(arrayBuffer);
64716
- const c = await engine.convert(sanitizeHTML(r.html), { format, preserveTables: true, preserveLists: true, customRules: [] });
64796
+ const c = await engine.convert(r.html, { format, preserveTables: true, preserveLists: true, customRules: [] });
64717
64797
  return { markdown: c.markdown, warnings: r.warnings ?? [] };
64718
64798
  }
64719
64799
  if (ext === ".xml") {
64720
64800
  const r = await dataAdapter.parseXmlToHtml(arrayBuffer);
64721
- const c = await engine.convert(sanitizeHTML(r.html), { format, preserveTables: true, preserveLists: true, customRules: [] });
64801
+ const c = await engine.convert(r.html, { format, preserveTables: true, preserveLists: true, customRules: [] });
64722
64802
  return { markdown: c.markdown, warnings: r.warnings ?? [] };
64723
64803
  }
64724
64804
  if (ext === ".pptx") {
64725
64805
  const r = await pptxAdapter.parseToHtml(arrayBuffer);
64726
- const c = await engine.convert(sanitizeHTML(r.html), { format, preserveTables: true, preserveLists: true, customRules: [] });
64806
+ const c = await engine.convert(r.html, { format, preserveTables: true, preserveLists: true, customRules: [] });
64727
64807
  return { markdown: c.markdown, warnings: r.warnings ?? [] };
64728
64808
  }
64729
64809
  throw new Error(`Unsupported file type: ${ext}`);
@@ -65027,8 +65107,8 @@ import { readFileSync as readFileSync5 } from "fs";
65027
65107
  import { resolve, dirname as dirname3 } from "path";
65028
65108
  import { fileURLToPath } from "url";
65029
65109
  var getVersion = () => {
65030
- if ("1.0.40") {
65031
- return "1.0.40";
65110
+ if ("1.0.41") {
65111
+ return "1.0.41";
65032
65112
  }
65033
65113
  try {
65034
65114
  const __dirname2 = dirname3(fileURLToPath(import.meta.url));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "formatferry",
3
- "version": "1.0.40",
3
+ "version": "1.0.41",
4
4
  "description": "Format Ferry CLI — Convert HTML, DOCX, PDF, XLSX, CSV, JSON, XML, PPTX to Markdown",
5
5
  "keywords": [
6
6
  "markdown",