@ryangarber/markitdown-ts 0.1.2 → 0.1.4

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.cjs CHANGED
@@ -29,8 +29,8 @@ let linkedom = require("linkedom");
29
29
  let mammoth = require("mammoth");
30
30
  mammoth = __toESM(mammoth, 1);
31
31
  let unpdf = require("unpdf");
32
- let xlsx = require("xlsx");
33
- xlsx = __toESM(xlsx, 1);
32
+ let exceljs = require("exceljs");
33
+ exceljs = __toESM(exceljs, 1);
34
34
  let _xmldom_xmldom = require("@xmldom/xmldom");
35
35
  let fflate = require("fflate");
36
36
  //#region src/bytes.ts
@@ -160,12 +160,13 @@ var HtmlConverter = class {
160
160
  }
161
161
  async convertHtml(html) {
162
162
  const document = parseHtmlDocument(html);
163
- document.querySelectorAll("script, style").forEach((element) => {
163
+ const title = document.title;
164
+ document.querySelectorAll("script, style, title").forEach((element) => {
164
165
  element.remove();
165
166
  });
166
- const markdown = new CustomTurnDown().convertSoup(document.body ?? document);
167
+ const markdown = new CustomTurnDown().convertSoup(document);
167
168
  return {
168
- title: document.title || null,
169
+ title: title || null,
169
170
  markdown,
170
171
  text_content: markdown
171
172
  };
@@ -176,14 +177,17 @@ var HtmlConverter = class {
176
177
  var DocxConverter = class extends HtmlConverter {
177
178
  async convert(source, options) {
178
179
  if (options.file_extension?.toLowerCase() !== ".docx") return null;
179
- const html = await mammoth.default.convertToHtml({ arrayBuffer: toArrayBuffer(source) }, {
180
+ let mammothInput = { arrayBuffer: toArrayBuffer(source) };
181
+ if (typeof process !== "undefined" && process.versions !== null && process.versions.node !== null) mammothInput = { buffer: Buffer.from(source) };
182
+ const mammothOptions = {
180
183
  styleMap: options.styleMap,
181
184
  includeEmbeddedStyleMap: options.includeEmbeddedStyleMap,
182
185
  includeDefaultStyleMap: options.includeDefaultStyleMap,
183
186
  ignoreEmptyParagraphs: options.ignoreEmptyParagraphs,
184
- idPrefix: options.idPrefix,
185
- transformDocument: options.transformDocument
186
- });
187
+ idPrefix: options.idPrefix
188
+ };
189
+ if (options.transformDocument) mammothOptions.transformDocument = options.transformDocument;
190
+ const html = await mammoth.default.convertToHtml(mammothInput, mammothOptions);
187
191
  return this.convertHtml(html.value);
188
192
  }
189
193
  };
@@ -305,26 +309,45 @@ var WikipediaConverter = class {
305
309
  };
306
310
  //#endregion
307
311
  //#region src/converters/xlsx.ts
312
+ const { Workbook } = exceljs.default;
308
313
  var XlsxConverter = class extends HtmlConverter {
309
314
  async convert(source, options) {
310
315
  if (options.file_extension?.toLowerCase() !== ".xlsx") return null;
311
- const workbook = xlsx.read(source, { type: "array" });
316
+ const workbook = new Workbook();
317
+ await workbook.xlsx.load(toArrayBuffer(source));
312
318
  const sections = [];
313
- for (const sheetName of workbook.SheetNames) {
314
- const sheet = workbook.Sheets[sheetName];
315
- if (sheet?.["!ref"]) {
316
- const result = await this.convertHtml(xlsx.utils.sheet_to_html(sheet));
317
- sections.push(`## ${sheetName}\n${result?.markdown.trim() ?? ""}`);
318
- }
319
+ for (const worksheet of workbook.worksheets) {
320
+ const html = worksheetToHtml(worksheet);
321
+ if (!html) continue;
322
+ const result = await this.convertHtml(html);
323
+ sections.push(`## ${worksheet.name}\n${result?.markdown.trim() ?? ""}`);
319
324
  }
320
325
  const markdown = sections.join("\n\n");
321
326
  return {
322
- title: workbook.Props?.Title || "Untitled",
327
+ title: workbook.title || "Untitled",
323
328
  markdown,
324
329
  text_content: markdown
325
330
  };
326
331
  }
327
332
  };
333
+ function worksheetToHtml(worksheet) {
334
+ const columnCount = worksheet.columnCount;
335
+ if (!columnCount || !worksheet.actualRowCount) return "";
336
+ const rows = [];
337
+ worksheet.eachRow({ includeEmpty: true }, (row) => {
338
+ const cells = [];
339
+ for (let column = 1; column <= columnCount; column++) cells.push(`<td>${escapeHtml(cellText(row.getCell(column)))}</td>`);
340
+ rows.push(`<tr>${cells.join("")}</tr>`);
341
+ });
342
+ return `<html><body><table>${rows.join("")}</table></body></html>`;
343
+ }
344
+ function cellText(cell) {
345
+ if (cell.isMerged && cell.master !== cell) return "";
346
+ return cell.text;
347
+ }
348
+ function escapeHtml(value) {
349
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
350
+ }
328
351
  //#endregion
329
352
  //#region src/converters/xml-rss-atom.ts
330
353
  var RSSConverter = class {
@@ -527,7 +550,7 @@ var MarkItDown = class {
527
550
  if (typeof source === "string" || source instanceof URL) return this.convertUrl(source.toString(), options);
528
551
  if (isResponse(source)) return this.convertResponse(source, options);
529
552
  const extensions = /* @__PURE__ */ new Set();
530
- this.addExtension(extensions, options.file_extension);
553
+ this.addExtension(extensions, options.file_extension?.replace(/^\./, ""));
531
554
  if (isBlob(source)) {
532
555
  this.addExtension(extensions, extensionFromMime(source.type));
533
556
  if ("name" in source && typeof source.name === "string") this.addExtension(extensions, extensionFromPathname(source.name));
@@ -580,6 +603,7 @@ var MarkItDown = class {
580
603
  return result;
581
604
  }
582
605
  } catch (error) {
606
+ if (options.debug) console.error("Converter threw error:", error);
583
607
  lastError = error;
584
608
  }
585
609
  const formats = [...extensions].join(", ");
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["TurndownService","turndownPluginGfm","parseHTML","getDocumentProxy","extractText","getMeta","XLSX","DOMParser","unzipSync"],"sources":["../src/bytes.ts","../src/custom-turndown.ts","../src/html-document.ts","../src/converters/bingserp.ts","../src/converters/html.ts","../src/converters/docx.ts","../src/converters/ipynb.ts","../src/converters/pdf.ts","../src/mime.ts","../src/converters/plain-text.ts","../src/converters/wikipedia.ts","../src/converters/xlsx.ts","../src/converters/xml-rss-atom.ts","../src/converters/youtube.ts","../src/converters/zip.ts","../src/markitdown.ts"],"sourcesContent":["import type { ByteSource } from \"./types\";\n\nexport async function toUint8Array(source: ByteSource): Promise<Uint8Array> {\n if (source instanceof Uint8Array) {\n return source;\n }\n\n if (isBlob(source)) {\n return new Uint8Array(await source.arrayBuffer());\n }\n\n if (ArrayBuffer.isView(source)) {\n return new Uint8Array(source.buffer, source.byteOffset, source.byteLength);\n }\n\n return new Uint8Array(source);\n}\n\nexport function toArrayBuffer(source: Uint8Array): ArrayBuffer {\n return source.slice().buffer;\n}\n\nexport function decodeText(source: Uint8Array): string {\n return new TextDecoder().decode(source);\n}\n\nexport function isBlob(value: unknown): value is Blob {\n return typeof Blob !== \"undefined\" && value instanceof Blob;\n}\n\nexport function normalizeExtension(extension: string): string {\n if (!extension) {\n return \"\";\n }\n\n const normalized = extension.toLowerCase();\n return normalized.startsWith(\".\") ? normalized : `.${normalized}`;\n}\n","import turndownPluginGfm from \"@joplin/turndown-plugin-gfm\";\nimport TurndownService from \"turndown\";\n\nexport class CustomTurnDown {\n convertSoup(document: string | Node): string {\n const service = new TurndownService({ headingStyle: \"atx\" });\n service.use(turndownPluginGfm.gfm);\n\n service.addRule(\"anchor tags\", {\n filter: [\"a\"],\n replacement(content, node) {\n if (!content) return \"\";\n\n const prefix = content.startsWith(\" \") ? \" \" : \"\";\n const suffix = content.endsWith(\" \") ? \" \" : \"\";\n const text = content.trim().replace(/\\n\\n.*/g, \"\");\n if (!text) return \"\";\n\n const element = node as unknown as Element;\n const href = element.getAttribute(\"href\");\n let title = element.getAttribute(\"title\") ?? \"\";\n if (!href) return `${prefix}${text}${suffix}`;\n\n try {\n const url = new URL(href);\n if (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n return `${prefix}${text}${suffix}`;\n }\n } catch {\n if (\n !href.startsWith(\"/\") &&\n !href.startsWith(\"#\") &&\n !href.startsWith(\"./\") &&\n !href.startsWith(\"../\")\n ) {\n return `${prefix}${text}${suffix}`;\n }\n }\n\n if (text.replace(/\\\\_/g, \"_\") === href && !title) {\n return `<${href}>`;\n }\n if (!title) title = href;\n return `${prefix}[${text}](${href}${title ? ` \"${title}\"` : \"\"})${suffix}`;\n }\n });\n\n service.addRule(\"img tags\", {\n filter: [\"img\"],\n replacement(_content, node) {\n const element = node as unknown as Element;\n const alt = element.getAttribute(\"alt\") ?? \"\";\n let source = element.getAttribute(\"src\") ?? \"\";\n const title = element.getAttribute(\"title\");\n if (source.startsWith(\"data:\")) {\n source = `${source.split(\",\", 1)[0]}...`;\n }\n return `![${alt}](${source}${title ? ` \"${title}\"` : \"\"})`;\n }\n });\n\n return service.turndown(document as TurndownService.Node);\n }\n}\n","import { parseHTML } from \"linkedom\";\n\nexport function parseHtmlDocument(html: string): Document {\n return parseHTML(html).document as unknown as Document;\n}\n","import { decodeText } from \"../bytes\";\nimport { CustomTurnDown } from \"../custom-turndown\";\nimport { parseHtmlDocument } from \"../html-document\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nconst BING_SEARCH_URL = /^https:\\/\\/www\\.bing\\.com\\/search\\?q=/i;\nconst BASE64_ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\nexport class BingSerpConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n const extension = options.file_extension?.toLowerCase() ?? \"\";\n const url = options.url ?? \"\";\n if ((extension !== \".html\" && extension !== \".htm\") || !BING_SEARCH_URL.test(url)) {\n return null;\n }\n\n const document = parseHtmlDocument(decodeText(source));\n const query = new URL(url).searchParams.get(\"q\") ?? \"\";\n\n document.querySelectorAll(\".tptt\").forEach((element) => {\n if (element.textContent) {\n element.textContent += \" \";\n }\n });\n document.querySelectorAll(\".algoSlug_icon\").forEach((element) => {\n element.remove();\n });\n\n const turndown = new CustomTurnDown();\n const results = [...document.querySelectorAll(\".b_algo\")].map((result) => {\n result.querySelectorAll(\"a[href]\").forEach((anchor) => {\n const href = anchor.getAttribute(\"href\");\n if (!href) {\n return;\n }\n try {\n const encoded = new URL(href, url).searchParams.get(\"u\");\n if (encoded) {\n anchor.setAttribute(\"href\", decodeBingUrl(encoded));\n }\n } catch {\n // Preserve malformed links as they appeared in the source document.\n }\n });\n\n return turndown\n .convertSoup(result)\n .split(/\\n+/)\n .map((line) => line.trim())\n .filter(Boolean)\n .join(\"\\n\");\n });\n\n const markdown = `## A Bing search for '${query}' found the following results:\\n\\n${results.join(\"\\n\\n\")}`;\n return { title: document.title || null, markdown, text_content: markdown };\n }\n}\n\nfunction decodeBingUrl(encoded: string): string {\n const input = encoded.slice(2).replace(/-/g, \"+\").replace(/_/g, \"/\").replace(/=+$/, \"\");\n const bytes: number[] = [];\n let bits = 0;\n let bitCount = 0;\n\n for (const character of input) {\n const value = BASE64_ALPHABET.indexOf(character);\n if (value < 0) {\n return encoded;\n }\n bits = (bits << 6) | value;\n bitCount += 6;\n if (bitCount >= 8) {\n bitCount -= 8;\n bytes.push((bits >> bitCount) & 0xff);\n }\n }\n\n return new TextDecoder().decode(new Uint8Array(bytes));\n}\n","import { decodeText } from \"../bytes\";\nimport { CustomTurnDown } from \"../custom-turndown\";\nimport { parseHtmlDocument } from \"../html-document\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class HtmlConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions): Promise<ConverterResult> {\n const extension = options.file_extension?.toLowerCase() ?? \"\";\n if (extension !== \".html\" && extension !== \".htm\") {\n return null;\n }\n\n return this.convertHtml(decodeText(source));\n }\n\n async convertHtml(html: string): Promise<ConverterResult> {\n const document = parseHtmlDocument(html);\n document.querySelectorAll(\"script, style\").forEach((element) => {\n element.remove();\n });\n\n const markdown = new CustomTurnDown().convertSoup(document.body ?? document);\n return {\n title: document.title || null,\n markdown,\n text_content: markdown\n };\n }\n}\n","import mammoth from \"mammoth\";\nimport { toArrayBuffer } from \"../bytes\";\nimport type { ConverterOptions, ConverterResult } from \"../types\";\nimport { HtmlConverter } from \"./html\";\n\nexport class DocxConverter extends HtmlConverter {\n async convert(source: Uint8Array, options: ConverterOptions): Promise<ConverterResult> {\n if (options.file_extension?.toLowerCase() !== \".docx\") {\n return null;\n }\n\n const html = await mammoth.convertToHtml(\n { arrayBuffer: toArrayBuffer(source) },\n {\n styleMap: options.styleMap,\n includeEmbeddedStyleMap: options.includeEmbeddedStyleMap,\n includeDefaultStyleMap: options.includeDefaultStyleMap,\n ignoreEmptyParagraphs: options.ignoreEmptyParagraphs,\n idPrefix: options.idPrefix,\n transformDocument: options.transformDocument\n }\n );\n return this.convertHtml(html.value);\n }\n}\n","import { decodeText } from \"../bytes\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\ntype NotebookCell = {\n cell_type?: string;\n source?: string[];\n};\n\ntype Notebook = {\n cells?: NotebookCell[];\n metadata?: { title?: string };\n};\n\nexport class IpynbConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n if (options.file_extension?.toLowerCase() !== \".ipynb\") {\n return null;\n }\n\n const notebook = JSON.parse(decodeText(source)) as Notebook;\n const output: string[] = [];\n let title: string | null = notebook.metadata?.title ?? null;\n\n for (const cell of notebook.cells ?? []) {\n const lines = cell.source ?? [];\n if (cell.cell_type === \"markdown\") {\n output.push(lines.join(\"\"));\n title ??=\n lines\n .find((line) => line.startsWith(\"# \"))\n ?.slice(2)\n .trim() ?? null;\n } else if (cell.cell_type === \"code\") {\n output.push(`\\`\\`\\`python\\n${lines.join(\"\")}\\n\\`\\`\\``);\n } else if (cell.cell_type === \"raw\") {\n output.push(`\\`\\`\\`\\n${lines.join(\"\")}\\n\\`\\`\\``);\n }\n }\n\n const markdown = output.join(\"\\n\\n\");\n return { title, markdown, text_content: markdown };\n }\n}\n","import { extractText, getDocumentProxy, getMeta } from \"unpdf\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class PdfConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions): Promise<ConverterResult> {\n if (options.file_extension?.toLowerCase() !== \".pdf\") {\n return null;\n }\n\n const pdf = await getDocumentProxy(source.slice());\n try {\n const [{ text }, { info }] = await Promise.all([\n extractText(pdf, { mergePages: true }),\n getMeta(pdf)\n ]);\n const title = typeof info.Title === \"string\" && info.Title.trim() ? info.Title : null;\n\n return { title, markdown: text, text_content: text };\n } finally {\n await pdf.loadingTask.destroy();\n }\n }\n}\n","const MIME_EXTENSIONS: Record<string, string> = {\n \"application/atom+xml\": \".atom\",\n \"application/json\": \".json\",\n \"application/pdf\": \".pdf\",\n \"application/zip\": \".zip\",\n \"application/rss+xml\": \".rss\",\n \"application/x-pdf\": \".pdf\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\": \".xlsx\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\": \".docx\",\n \"application/xml\": \".xml\",\n \"text/csv\": \".csv\",\n \"text/html\": \".html\",\n \"text/markdown\": \".md\",\n \"text/plain\": \".txt\",\n \"text/xml\": \".xml\"\n};\n\nconst TEXT_EXTENSIONS = new Set([\".csv\", \".json\", \".log\", \".markdown\", \".md\", \".text\", \".txt\"]);\n\nexport function extensionFromMime(contentType: string | null | undefined): string | null {\n if (!contentType) {\n return null;\n }\n\n const mime = contentType.split(\";\", 1)[0]?.trim().toLowerCase() ?? \"\";\n return MIME_EXTENSIONS[mime] ?? (mime.startsWith(\"text/\") ? \".txt\" : null);\n}\n\nexport function isTextExtension(extension: string): boolean {\n return TEXT_EXTENSIONS.has(extension.toLowerCase());\n}\n\nexport function extensionFromPathname(pathname: string): string | null {\n const filename = pathname.split(\"/\").pop() ?? \"\";\n const dot = filename.lastIndexOf(\".\");\n return dot > 0 ? filename.slice(dot).toLowerCase() : null;\n}\n","import { decodeText } from \"../bytes\";\nimport { isTextExtension } from \"../mime\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class PlainTextConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n if (!isTextExtension(options.file_extension ?? \"\")) {\n return null;\n }\n\n const content = decodeText(source);\n return { title: null, markdown: content, text_content: content };\n }\n}\n","import { decodeText } from \"../bytes\";\nimport { CustomTurnDown } from \"../custom-turndown\";\nimport { parseHtmlDocument } from \"../html-document\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nconst WIKIPEDIA_URL = /^https?:\\/\\/[a-z]{2,3}\\.wikipedia\\.org\\//i;\n\nexport class WikipediaConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n const extension = options.file_extension?.toLowerCase() ?? \"\";\n if ((extension !== \".html\" && extension !== \".htm\") || !WIKIPEDIA_URL.test(options.url ?? \"\")) {\n return null;\n }\n\n const document = parseHtmlDocument(decodeText(source));\n document.querySelectorAll(\"script, style\").forEach((element) => {\n element.remove();\n });\n\n const body = document.querySelector(\"div#mw-content-text\");\n const pageTitle = document.querySelector(\"span.mw-page-title-main\")?.textContent?.trim();\n const title = pageTitle || document.title || null;\n const markdown = body\n ? `# ${title ?? \"Wikipedia\"}\\n\\n${new CustomTurnDown().convertSoup(body)}`\n : new CustomTurnDown().convertSoup(document);\n\n return { title, markdown, text_content: markdown };\n }\n}\n","import * as XLSX from \"xlsx\";\nimport type { ConverterOptions, ConverterResult } from \"../types\";\nimport { HtmlConverter } from \"./html\";\n\nexport class XlsxConverter extends HtmlConverter {\n async convert(source: Uint8Array, options: ConverterOptions): Promise<ConverterResult> {\n if (options.file_extension?.toLowerCase() !== \".xlsx\") {\n return null;\n }\n\n const workbook = XLSX.read(source, { type: \"array\" });\n const sections: string[] = [];\n\n for (const sheetName of workbook.SheetNames) {\n const sheet = workbook.Sheets[sheetName];\n if (sheet?.[\"!ref\"]) {\n const result = await this.convertHtml(XLSX.utils.sheet_to_html(sheet));\n sections.push(`## ${sheetName}\\n${result?.markdown.trim() ?? \"\"}`);\n }\n }\n\n const markdown = sections.join(\"\\n\\n\");\n return {\n title: workbook.Props?.Title || \"Untitled\",\n markdown,\n text_content: markdown\n };\n }\n}\n","import type { Document, Element } from \"@xmldom/xmldom\";\nimport { DOMParser } from \"@xmldom/xmldom\";\nimport { decodeText } from \"../bytes\";\nimport { CustomTurnDown } from \"../custom-turndown\";\nimport { parseHtmlDocument } from \"../html-document\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class RSSConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n const extension = options.file_extension?.toLowerCase() ?? \"\";\n if (![\".xml\", \".rss\", \".atom\"].includes(extension)) {\n return null;\n }\n\n const document = new DOMParser().parseFromString(decodeText(source), \"text/xml\");\n if (document.getElementsByTagName(\"rss\").length > 0) {\n return this.parseRss(document);\n }\n if (document.getElementsByTagName(\"feed\")[0]?.getElementsByTagName(\"entry\").length) {\n return this.parseAtom(document);\n }\n return null;\n }\n\n private parseAtom(document: Document): ConverterResult {\n const root = document.getElementsByTagName(\"feed\")[0];\n if (!root) return null;\n\n const title = getText(root, \"title\");\n const subtitle = getText(root, \"subtitle\");\n const sections = [`# ${title ?? \"Feed\"}`];\n if (subtitle) sections.push(subtitle);\n\n for (const entry of [...root.getElementsByTagName(\"entry\")]) {\n const entryTitle = getText(entry, \"title\");\n const updated = getText(entry, \"updated\");\n const summary = getText(entry, \"summary\");\n const content = getText(entry, \"content\");\n const lines: string[] = [];\n if (entryTitle) lines.push(`## ${entryTitle}`);\n if (updated) lines.push(`Updated on: ${updated}`);\n if (summary) lines.push(parseContent(summary));\n if (content) lines.push(parseContent(content));\n sections.push(lines.join(\"\\n\"));\n }\n\n const markdown = sections.join(\"\\n\\n\");\n return { title, markdown, text_content: markdown };\n }\n\n private parseRss(document: Document): ConverterResult {\n const channel = document.getElementsByTagName(\"rss\")[0]?.getElementsByTagName(\"channel\")[0];\n if (!channel) return null;\n\n const title = getText(channel, \"title\");\n const description = getText(channel, \"description\");\n const sections: string[] = title ? [`# ${title}`] : [];\n if (description) sections.push(description);\n\n for (const item of [...channel.getElementsByTagName(\"item\")]) {\n const itemTitle = getText(item, \"title\");\n const published = getText(item, \"pubDate\");\n const itemDescription = getText(item, \"description\");\n const content = getText(item, \"content:encoded\");\n const lines: string[] = [];\n if (itemTitle) lines.push(`## ${itemTitle}`);\n if (published) lines.push(`Published on: ${published}`);\n if (itemDescription) lines.push(parseContent(itemDescription));\n if (content) lines.push(parseContent(content));\n sections.push(lines.join(\"\\n\"));\n }\n\n const markdown = sections.join(\"\\n\\n\");\n return { title, markdown, text_content: markdown };\n }\n}\n\nfunction parseContent(content: string): string {\n return new CustomTurnDown().convertSoup(parseHtmlDocument(content).documentElement);\n}\n\nfunction getText(element: Element, tagName: string): string | null {\n const node = element.getElementsByTagName(tagName)[0];\n return node?.textContent?.trim() || null;\n}\n","import { decodeText } from \"../bytes\";\nimport { parseHtmlDocument } from \"../html-document\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class YouTubeConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n const extension = options.file_extension?.toLowerCase() ?? \"\";\n if (\n (extension !== \".html\" && extension !== \".htm\") ||\n !options.url?.startsWith(\"https://www.youtube.com/watch?\")\n ) {\n return null;\n }\n\n const document = parseHtmlDocument(decodeText(source));\n const metadata: Record<string, string> = { title: document.title };\n\n document.querySelectorAll(\"meta\").forEach((meta) => {\n const content = meta.getAttribute(\"content\");\n const key =\n meta.getAttribute(\"itemprop\") ?? meta.getAttribute(\"property\") ?? meta.getAttribute(\"name\");\n if (key && content) {\n metadata[key] = content;\n }\n });\n\n try {\n for (const script of document.querySelectorAll(\"script\")) {\n const content = script.textContent ?? \"\";\n if (!content.includes(\"ytInitialData\")) {\n continue;\n }\n const start = content.indexOf(\"{\");\n const end = content.lastIndexOf(\"}\");\n if (start >= 0 && end > start) {\n const description = findKey(\n JSON.parse(content.slice(start, end + 1)),\n \"attributedDescriptionBodyText\"\n );\n if (isRecord(description) && typeof description.content === \"string\") {\n metadata.description = description.content;\n }\n }\n break;\n }\n } catch {\n // Meta description remains available when the page implementation changes.\n }\n\n const title = first(metadata, [\"title\", \"og:title\", \"name\"]) || document.title || null;\n const lines = [\"# YouTube\"];\n if (title) {\n lines.push(`## ${title}`);\n }\n\n const stats: string[] = [];\n const views = first(metadata, [\"interactionCount\"]);\n const keywords = first(metadata, [\"keywords\"]);\n const runtime = first(metadata, [\"duration\"]);\n if (views) stats.push(`- **Views:** ${views}`);\n if (keywords) stats.push(`- **Keywords:** ${keywords}`);\n if (runtime) stats.push(`- **Runtime:** ${runtime}`);\n if (stats.length > 0) {\n lines.push(`### Video Metadata\\n${stats.join(\"\\n\")}`);\n }\n\n const description = first(metadata, [\"description\", \"og:description\"]);\n if (description) {\n lines.push(`### Description\\n${description}`);\n }\n\n const markdown = lines.join(\"\\n\\n\");\n return { title, markdown, text_content: markdown };\n }\n}\n\nfunction first(metadata: Record<string, string>, keys: string[]): string | null {\n for (const key of keys) {\n if (metadata[key]) return metadata[key];\n }\n return null;\n}\n\nfunction findKey(value: unknown, key: string): unknown {\n if (Array.isArray(value)) {\n for (const item of value) {\n const match = findKey(item, key);\n if (match !== undefined) return match;\n }\n } else if (isRecord(value)) {\n if (key in value) return value[key];\n for (const item of Object.values(value)) {\n const match = findKey(item, key);\n if (match !== undefined) return match;\n }\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n","import { unzipSync } from \"fflate\";\nimport { extensionFromPathname } from \"../mime\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class ZipConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n if (options.file_extension?.toLowerCase() !== \".zip\") {\n return null;\n }\n\n const files = unzipSync(source, {\n filter: (file) => !file.name.endsWith(\"/\")\n });\n const converters = options._parent_converters ?? [];\n const zipName = options.url ?? \"archive.zip\";\n const sections = [`Content from the zip file \\`${zipName}\\`:`];\n\n for (const [name, bytes] of Object.entries(files)) {\n const result = await convertEntry(bytes, name, converters, options);\n if (result) {\n sections.push(`## File: ${name}\\n\\n${result.markdown}`);\n }\n }\n\n const markdown = sections.join(\"\\n\\n\");\n return { title: null, markdown, text_content: markdown };\n }\n}\n\nasync function convertEntry(\n source: Uint8Array,\n name: string,\n converters: DocumentConverter[],\n options: ConverterOptions\n): Promise<ConverterResult> {\n const extension = extensionFromPathname(name);\n if (!extension) {\n return null;\n }\n\n const entryOptions: ConverterOptions = {\n ...options,\n file_extension: extension,\n url: undefined,\n _parent_converters: converters\n };\n\n for (const converter of converters) {\n try {\n const result = await converter.convert(source, entryOptions);\n if (result) {\n return result;\n }\n } catch {\n // Match the original ZipConverter: skip entries that fail conversion.\n }\n }\n\n return null;\n}\n","import { isBlob, toUint8Array } from \"./bytes\";\nimport { BingSerpConverter } from \"./converters/bingserp\";\nimport { DocxConverter } from \"./converters/docx\";\nimport { HtmlConverter } from \"./converters/html\";\nimport { IpynbConverter } from \"./converters/ipynb\";\nimport { PdfConverter } from \"./converters/pdf\";\nimport { PlainTextConverter } from \"./converters/plain-text\";\nimport { WikipediaConverter } from \"./converters/wikipedia\";\nimport { XlsxConverter } from \"./converters/xlsx\";\nimport { RSSConverter } from \"./converters/xml-rss-atom\";\nimport { YouTubeConverter } from \"./converters/youtube\";\nimport { ZipConverter } from \"./converters/zip\";\nimport { extensionFromMime, extensionFromPathname } from \"./mime\";\nimport type { ByteSource, ConverterOptions, ConverterResult, DocumentConverter } from \"./types\";\n\nexport type ConversionSource = ByteSource | Response | URL | string;\n\nexport class MarkItDown {\n private readonly converters: DocumentConverter[] = [];\n\n constructor() {\n this.registerConverter(new PlainTextConverter());\n this.registerConverter(new HtmlConverter());\n this.registerConverter(new ZipConverter());\n this.registerConverter(new RSSConverter());\n this.registerConverter(new WikipediaConverter());\n this.registerConverter(new YouTubeConverter());\n this.registerConverter(new BingSerpConverter());\n this.registerConverter(new DocxConverter());\n this.registerConverter(new XlsxConverter());\n this.registerConverter(new PdfConverter());\n this.registerConverter(new IpynbConverter());\n }\n\n /** Convert a URL, response, blob, array buffer, data view, or typed array. */\n async convert(\n source: ConversionSource,\n options: ConverterOptions = {}\n ): Promise<ConverterResult> {\n if (typeof source === \"string\" || source instanceof URL) {\n return this.convertUrl(source.toString(), options);\n }\n\n if (isResponse(source)) {\n return this.convertResponse(source, options);\n }\n\n const extensions = new Set<string>();\n this.addExtension(extensions, options.file_extension);\n\n if (isBlob(source)) {\n this.addExtension(extensions, extensionFromMime(source.type));\n if (\"name\" in source && typeof source.name === \"string\") {\n this.addExtension(extensions, extensionFromPathname(source.name));\n }\n }\n\n if (extensions.size === 0) {\n throw new Error(\n \"Could not determine the file type. Provide `file_extension` when converting bytes.\"\n );\n }\n\n return this.convertBytes(await toUint8Array(source), extensions, options);\n }\n\n /**\n * @deprecated Pass the byte source directly to `convert`.\n */\n async convertBuffer(\n source: ByteSource,\n options: ConverterOptions & { file_extension: string }\n ): Promise<ConverterResult> {\n return this.convert(source, options);\n }\n\n private async convertUrl(\n source: string,\n { fetch: fetchImplementation = globalThis.fetch, ...options }: ConverterOptions\n ): Promise<ConverterResult> {\n const url = new URL(source);\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n throw new Error(`Unsupported URL protocol: ${url.protocol}`);\n }\n if (!fetchImplementation) {\n throw new Error(\"No fetch implementation is available.\");\n }\n\n const response = await fetchImplementation(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch URL: ${url}, status: ${response.status}`);\n }\n\n return this.convertResponse(response, { ...options, url: url.toString() });\n }\n\n private async convertResponse(\n response: Response,\n options: ConverterOptions\n ): Promise<ConverterResult> {\n const extensions = new Set<string>();\n this.addExtension(extensions, options.file_extension);\n this.addExtension(extensions, extensionFromMime(response.headers.get(\"content-type\")));\n\n const disposition = response.headers.get(\"content-disposition\") ?? \"\";\n const filename = disposition.match(/filename\\*?=(?:UTF-8''|[\"']?)([^;\"']+)/i)?.[1];\n if (filename) {\n this.addExtension(extensions, extensionFromPathname(decodeURIComponent(filename.trim())));\n }\n\n const responseUrl = options.url || response.url;\n if (responseUrl) {\n this.addExtension(extensions, extensionFromPathname(new URL(responseUrl).pathname));\n }\n\n if (extensions.size === 0) {\n throw new Error(\n \"Could not determine the file type. Provide `file_extension` or a Content-Type header.\"\n );\n }\n\n return this.convertBytes(new Uint8Array(await response.arrayBuffer()), extensions, {\n ...options,\n url: responseUrl\n });\n }\n\n private async convertBytes(\n source: Uint8Array,\n extensions: Set<string>,\n options: ConverterOptions\n ): Promise<ConverterResult> {\n let lastError: unknown;\n\n for (const extension of extensions) {\n for (const converter of this.converters) {\n try {\n const result = await converter.convert(source, {\n ...options,\n file_extension: extension,\n _parent_converters: this.converters\n });\n if (result) {\n result.markdown = result.markdown\n .replace(/\\r\\n|\\r|\\n/g, \"\\n\")\n .trim()\n .replace(/\\n{3,}/g, \"\\n\\n\");\n result.text_content = result.markdown;\n return result;\n }\n } catch (error) {\n lastError = error;\n }\n }\n }\n\n const formats = [...extensions].join(\", \");\n if (lastError) {\n throw new Error(`Could not convert ${formats} to Markdown: ${String(lastError)}`);\n }\n throw new Error(`Unsupported file type: ${formats}.`);\n }\n\n private addExtension(extensions: Set<string>, extension: string | null | undefined): void {\n if (!extension) {\n return;\n }\n extensions.add(\n extension.startsWith(\".\") ? extension.toLowerCase() : `.${extension.toLowerCase()}`\n );\n }\n\n private registerConverter(converter: DocumentConverter): void {\n this.converters.unshift(converter);\n }\n}\n\nfunction isResponse(value: unknown): value is Response {\n return typeof Response !== \"undefined\" && value instanceof Response;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["TurndownService","turndownPluginGfm","parseHTML","getDocumentProxy","extractText","getMeta","ExcelJS","DOMParser","unzipSync"],"sources":["../src/bytes.ts","../src/custom-turndown.ts","../src/html-document.ts","../src/converters/bingserp.ts","../src/converters/html.ts","../src/converters/docx.ts","../src/converters/ipynb.ts","../src/converters/pdf.ts","../src/mime.ts","../src/converters/plain-text.ts","../src/converters/wikipedia.ts","../src/converters/xlsx.ts","../src/converters/xml-rss-atom.ts","../src/converters/youtube.ts","../src/converters/zip.ts","../src/markitdown.ts"],"sourcesContent":["import type { ByteSource } from \"./types\";\n\nexport async function toUint8Array(source: ByteSource): Promise<Uint8Array> {\n if (source instanceof Uint8Array) {\n return source;\n }\n\n if (isBlob(source)) {\n return new Uint8Array(await source.arrayBuffer());\n }\n\n if (ArrayBuffer.isView(source)) {\n return new Uint8Array(source.buffer, source.byteOffset, source.byteLength);\n }\n\n return new Uint8Array(source);\n}\n\nexport function toArrayBuffer(source: Uint8Array): ArrayBuffer {\n return source.slice().buffer;\n}\n\nexport function decodeText(source: Uint8Array): string {\n return new TextDecoder().decode(source);\n}\n\nexport function isBlob(value: unknown): value is Blob {\n return typeof Blob !== \"undefined\" && value instanceof Blob;\n}\n\nexport function normalizeExtension(extension: string): string {\n if (!extension) {\n return \"\";\n }\n\n const normalized = extension.toLowerCase();\n return normalized.startsWith(\".\") ? normalized : `.${normalized}`;\n}\n","import turndownPluginGfm from \"@joplin/turndown-plugin-gfm\";\nimport TurndownService from \"turndown\";\n\nexport class CustomTurnDown {\n convertSoup(document: string | Node): string {\n const service = new TurndownService({ headingStyle: \"atx\" });\n service.use(turndownPluginGfm.gfm);\n\n service.addRule(\"anchor tags\", {\n filter: [\"a\"],\n replacement(content, node) {\n if (!content) return \"\";\n\n const prefix = content.startsWith(\" \") ? \" \" : \"\";\n const suffix = content.endsWith(\" \") ? \" \" : \"\";\n const text = content.trim().replace(/\\n\\n.*/g, \"\");\n if (!text) return \"\";\n\n const element = node as unknown as Element;\n const href = element.getAttribute(\"href\");\n let title = element.getAttribute(\"title\") ?? \"\";\n if (!href) return `${prefix}${text}${suffix}`;\n\n try {\n const url = new URL(href);\n if (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n return `${prefix}${text}${suffix}`;\n }\n } catch {\n if (\n !href.startsWith(\"/\") &&\n !href.startsWith(\"#\") &&\n !href.startsWith(\"./\") &&\n !href.startsWith(\"../\")\n ) {\n return `${prefix}${text}${suffix}`;\n }\n }\n\n if (text.replace(/\\\\_/g, \"_\") === href && !title) {\n return `<${href}>`;\n }\n if (!title) title = href;\n return `${prefix}[${text}](${href}${title ? ` \"${title}\"` : \"\"})${suffix}`;\n }\n });\n\n service.addRule(\"img tags\", {\n filter: [\"img\"],\n replacement(_content, node) {\n const element = node as unknown as Element;\n const alt = element.getAttribute(\"alt\") ?? \"\";\n let source = element.getAttribute(\"src\") ?? \"\";\n const title = element.getAttribute(\"title\");\n if (source.startsWith(\"data:\")) {\n source = `${source.split(\",\", 1)[0]}...`;\n }\n return `![${alt}](${source}${title ? ` \"${title}\"` : \"\"})`;\n }\n });\n\n return service.turndown(document as TurndownService.Node);\n }\n}\n","import { parseHTML } from \"linkedom\";\n\nexport function parseHtmlDocument(html: string): Document {\n return parseHTML(html).document as unknown as Document;\n}\n","import { decodeText } from \"../bytes\";\nimport { CustomTurnDown } from \"../custom-turndown\";\nimport { parseHtmlDocument } from \"../html-document\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nconst BING_SEARCH_URL = /^https:\\/\\/www\\.bing\\.com\\/search\\?q=/i;\nconst BASE64_ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\nexport class BingSerpConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n const extension = options.file_extension?.toLowerCase() ?? \"\";\n const url = options.url ?? \"\";\n if ((extension !== \".html\" && extension !== \".htm\") || !BING_SEARCH_URL.test(url)) {\n return null;\n }\n\n const document = parseHtmlDocument(decodeText(source));\n const query = new URL(url).searchParams.get(\"q\") ?? \"\";\n\n document.querySelectorAll(\".tptt\").forEach((element) => {\n if (element.textContent) {\n element.textContent += \" \";\n }\n });\n document.querySelectorAll(\".algoSlug_icon\").forEach((element) => {\n element.remove();\n });\n\n const turndown = new CustomTurnDown();\n const results = [...document.querySelectorAll(\".b_algo\")].map((result) => {\n result.querySelectorAll(\"a[href]\").forEach((anchor) => {\n const href = anchor.getAttribute(\"href\");\n if (!href) {\n return;\n }\n try {\n const encoded = new URL(href, url).searchParams.get(\"u\");\n if (encoded) {\n anchor.setAttribute(\"href\", decodeBingUrl(encoded));\n }\n } catch {\n // Preserve malformed links as they appeared in the source document.\n }\n });\n\n return turndown\n .convertSoup(result)\n .split(/\\n+/)\n .map((line) => line.trim())\n .filter(Boolean)\n .join(\"\\n\");\n });\n\n const markdown = `## A Bing search for '${query}' found the following results:\\n\\n${results.join(\"\\n\\n\")}`;\n return { title: document.title || null, markdown, text_content: markdown };\n }\n}\n\nfunction decodeBingUrl(encoded: string): string {\n const input = encoded.slice(2).replace(/-/g, \"+\").replace(/_/g, \"/\").replace(/=+$/, \"\");\n const bytes: number[] = [];\n let bits = 0;\n let bitCount = 0;\n\n for (const character of input) {\n const value = BASE64_ALPHABET.indexOf(character);\n if (value < 0) {\n return encoded;\n }\n bits = (bits << 6) | value;\n bitCount += 6;\n if (bitCount >= 8) {\n bitCount -= 8;\n bytes.push((bits >> bitCount) & 0xff);\n }\n }\n\n return new TextDecoder().decode(new Uint8Array(bytes));\n}\n","import { decodeText } from \"../bytes\";\nimport { CustomTurnDown } from \"../custom-turndown\";\nimport { parseHtmlDocument } from \"../html-document\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class HtmlConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions): Promise<ConverterResult> {\n const extension = options.file_extension?.toLowerCase() ?? \"\";\n if (extension !== \".html\" && extension !== \".htm\") {\n return null;\n }\n\n return this.convertHtml(decodeText(source));\n }\n\n async convertHtml(html: string): Promise<ConverterResult> {\n const document = parseHtmlDocument(html);\n\n const title = document.title;\n document.querySelectorAll(\"script, style, title\").forEach((element) => {\n element.remove();\n });\n\n const markdown = new CustomTurnDown().convertSoup(document);\n return {\n title: title || null,\n markdown,\n text_content: markdown\n };\n }\n}\n","import mammoth from \"mammoth\";\nimport { toArrayBuffer } from \"../bytes\";\nimport type { ConverterOptions, ConverterResult } from \"../types\";\nimport { HtmlConverter } from \"./html\";\n\nexport class DocxConverter extends HtmlConverter {\n async convert(source: Uint8Array, options: ConverterOptions): Promise<ConverterResult> {\n if (options.file_extension?.toLowerCase() !== \".docx\") {\n return null;\n }\n\n let mammothInput: Parameters<typeof mammoth.convertToHtml>[0] = {\n arrayBuffer: toArrayBuffer(source)\n };\n\n if (\n typeof process !== \"undefined\" &&\n process.versions !== null &&\n process.versions.node !== null\n ) {\n mammothInput = { buffer: Buffer.from(source) };\n }\n\n const mammothOptions: Parameters<typeof mammoth.convertToHtml>[1] = {\n styleMap: options.styleMap,\n includeEmbeddedStyleMap: options.includeEmbeddedStyleMap,\n includeDefaultStyleMap: options.includeDefaultStyleMap,\n ignoreEmptyParagraphs: options.ignoreEmptyParagraphs,\n idPrefix: options.idPrefix\n };\n\n if (options.transformDocument) {\n mammothOptions.transformDocument = options.transformDocument;\n }\n\n const html = await mammoth.convertToHtml(mammothInput, mammothOptions);\n\n return this.convertHtml(html.value);\n }\n}\n","import { decodeText } from \"../bytes\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\ntype NotebookCell = {\n cell_type?: string;\n source?: string[];\n};\n\ntype Notebook = {\n cells?: NotebookCell[];\n metadata?: { title?: string };\n};\n\nexport class IpynbConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n if (options.file_extension?.toLowerCase() !== \".ipynb\") {\n return null;\n }\n\n const notebook = JSON.parse(decodeText(source)) as Notebook;\n const output: string[] = [];\n let title: string | null = notebook.metadata?.title ?? null;\n\n for (const cell of notebook.cells ?? []) {\n const lines = cell.source ?? [];\n if (cell.cell_type === \"markdown\") {\n output.push(lines.join(\"\"));\n title ??=\n lines\n .find((line) => line.startsWith(\"# \"))\n ?.slice(2)\n .trim() ?? null;\n } else if (cell.cell_type === \"code\") {\n output.push(`\\`\\`\\`python\\n${lines.join(\"\")}\\n\\`\\`\\``);\n } else if (cell.cell_type === \"raw\") {\n output.push(`\\`\\`\\`\\n${lines.join(\"\")}\\n\\`\\`\\``);\n }\n }\n\n const markdown = output.join(\"\\n\\n\");\n return { title, markdown, text_content: markdown };\n }\n}\n","import { extractText, getDocumentProxy, getMeta } from \"unpdf\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class PdfConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions): Promise<ConverterResult> {\n if (options.file_extension?.toLowerCase() !== \".pdf\") {\n return null;\n }\n\n const pdf = await getDocumentProxy(source.slice());\n try {\n const [{ text }, { info }] = await Promise.all([\n extractText(pdf, { mergePages: true }),\n getMeta(pdf)\n ]);\n const title = typeof info.Title === \"string\" && info.Title.trim() ? info.Title : null;\n\n return { title, markdown: text, text_content: text };\n } finally {\n await pdf.loadingTask.destroy();\n }\n }\n}\n","const MIME_EXTENSIONS: Record<string, string> = {\n \"application/atom+xml\": \".atom\",\n \"application/json\": \".json\",\n \"application/pdf\": \".pdf\",\n \"application/zip\": \".zip\",\n \"application/rss+xml\": \".rss\",\n \"application/x-pdf\": \".pdf\",\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\": \".xlsx\",\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\": \".docx\",\n \"application/xml\": \".xml\",\n \"text/csv\": \".csv\",\n \"text/html\": \".html\",\n \"text/markdown\": \".md\",\n \"text/plain\": \".txt\",\n \"text/xml\": \".xml\"\n};\n\nconst TEXT_EXTENSIONS = new Set([\".csv\", \".json\", \".log\", \".markdown\", \".md\", \".text\", \".txt\"]);\n\nexport function extensionFromMime(contentType: string | null | undefined): string | null {\n if (!contentType) {\n return null;\n }\n\n const mime = contentType.split(\";\", 1)[0]?.trim().toLowerCase() ?? \"\";\n return MIME_EXTENSIONS[mime] ?? (mime.startsWith(\"text/\") ? \".txt\" : null);\n}\n\nexport function isTextExtension(extension: string): boolean {\n return TEXT_EXTENSIONS.has(extension.toLowerCase());\n}\n\nexport function extensionFromPathname(pathname: string): string | null {\n const filename = pathname.split(\"/\").pop() ?? \"\";\n const dot = filename.lastIndexOf(\".\");\n return dot > 0 ? filename.slice(dot).toLowerCase() : null;\n}\n","import { decodeText } from \"../bytes\";\nimport { isTextExtension } from \"../mime\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class PlainTextConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n if (!isTextExtension(options.file_extension ?? \"\")) {\n return null;\n }\n\n const content = decodeText(source);\n return { title: null, markdown: content, text_content: content };\n }\n}\n","import { decodeText } from \"../bytes\";\nimport { CustomTurnDown } from \"../custom-turndown\";\nimport { parseHtmlDocument } from \"../html-document\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nconst WIKIPEDIA_URL = /^https?:\\/\\/[a-z]{2,3}\\.wikipedia\\.org\\//i;\n\nexport class WikipediaConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n const extension = options.file_extension?.toLowerCase() ?? \"\";\n if ((extension !== \".html\" && extension !== \".htm\") || !WIKIPEDIA_URL.test(options.url ?? \"\")) {\n return null;\n }\n\n const document = parseHtmlDocument(decodeText(source));\n document.querySelectorAll(\"script, style\").forEach((element) => {\n element.remove();\n });\n\n const body = document.querySelector(\"div#mw-content-text\");\n const pageTitle = document.querySelector(\"span.mw-page-title-main\")?.textContent?.trim();\n const title = pageTitle || document.title || null;\n const markdown = body\n ? `# ${title ?? \"Wikipedia\"}\\n\\n${new CustomTurnDown().convertSoup(body)}`\n : new CustomTurnDown().convertSoup(document);\n\n return { title, markdown, text_content: markdown };\n }\n}\n","import ExcelJS, { type Cell, type Worksheet } from \"exceljs\";\nimport { toArrayBuffer } from \"../bytes\";\nimport type { ConverterOptions, ConverterResult } from \"../types\";\nimport { HtmlConverter } from \"./html\";\n\nconst { Workbook } = ExcelJS;\n\nexport class XlsxConverter extends HtmlConverter {\n async convert(source: Uint8Array, options: ConverterOptions): Promise<ConverterResult> {\n if (options.file_extension?.toLowerCase() !== \".xlsx\") {\n return null;\n }\n\n const workbook = new Workbook();\n await workbook.xlsx.load(toArrayBuffer(source));\n const sections: string[] = [];\n\n for (const worksheet of workbook.worksheets) {\n const html = worksheetToHtml(worksheet);\n if (!html) {\n continue;\n }\n const result = await this.convertHtml(html);\n sections.push(`## ${worksheet.name}\\n${result?.markdown.trim() ?? \"\"}`);\n }\n\n const markdown = sections.join(\"\\n\\n\");\n return {\n title: workbook.title || \"Untitled\",\n markdown,\n text_content: markdown\n };\n }\n}\n\nfunction worksheetToHtml(worksheet: Worksheet): string {\n const columnCount = worksheet.columnCount;\n if (!columnCount || !worksheet.actualRowCount) {\n return \"\";\n }\n\n const rows: string[] = [];\n worksheet.eachRow({ includeEmpty: true }, (row) => {\n const cells: string[] = [];\n for (let column = 1; column <= columnCount; column++) {\n cells.push(`<td>${escapeHtml(cellText(row.getCell(column)))}</td>`);\n }\n rows.push(`<tr>${cells.join(\"\")}</tr>`);\n });\n\n return `<html><body><table>${rows.join(\"\")}</table></body></html>`;\n}\n\nfunction cellText(cell: Cell): string {\n if (cell.isMerged && cell.master !== cell) {\n return \"\";\n }\n return cell.text;\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\");\n}\n","import type { Document, Element } from \"@xmldom/xmldom\";\nimport { DOMParser } from \"@xmldom/xmldom\";\nimport { decodeText } from \"../bytes\";\nimport { CustomTurnDown } from \"../custom-turndown\";\nimport { parseHtmlDocument } from \"../html-document\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class RSSConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n const extension = options.file_extension?.toLowerCase() ?? \"\";\n if (![\".xml\", \".rss\", \".atom\"].includes(extension)) {\n return null;\n }\n\n const document = new DOMParser().parseFromString(decodeText(source), \"text/xml\");\n if (document.getElementsByTagName(\"rss\").length > 0) {\n return this.parseRss(document);\n }\n if (document.getElementsByTagName(\"feed\")[0]?.getElementsByTagName(\"entry\").length) {\n return this.parseAtom(document);\n }\n return null;\n }\n\n private parseAtom(document: Document): ConverterResult {\n const root = document.getElementsByTagName(\"feed\")[0];\n if (!root) return null;\n\n const title = getText(root, \"title\");\n const subtitle = getText(root, \"subtitle\");\n const sections = [`# ${title ?? \"Feed\"}`];\n if (subtitle) sections.push(subtitle);\n\n for (const entry of [...root.getElementsByTagName(\"entry\")]) {\n const entryTitle = getText(entry, \"title\");\n const updated = getText(entry, \"updated\");\n const summary = getText(entry, \"summary\");\n const content = getText(entry, \"content\");\n const lines: string[] = [];\n if (entryTitle) lines.push(`## ${entryTitle}`);\n if (updated) lines.push(`Updated on: ${updated}`);\n if (summary) lines.push(parseContent(summary));\n if (content) lines.push(parseContent(content));\n sections.push(lines.join(\"\\n\"));\n }\n\n const markdown = sections.join(\"\\n\\n\");\n return { title, markdown, text_content: markdown };\n }\n\n private parseRss(document: Document): ConverterResult {\n const channel = document.getElementsByTagName(\"rss\")[0]?.getElementsByTagName(\"channel\")[0];\n if (!channel) return null;\n\n const title = getText(channel, \"title\");\n const description = getText(channel, \"description\");\n const sections: string[] = title ? [`# ${title}`] : [];\n if (description) sections.push(description);\n\n for (const item of [...channel.getElementsByTagName(\"item\")]) {\n const itemTitle = getText(item, \"title\");\n const published = getText(item, \"pubDate\");\n const itemDescription = getText(item, \"description\");\n const content = getText(item, \"content:encoded\");\n const lines: string[] = [];\n if (itemTitle) lines.push(`## ${itemTitle}`);\n if (published) lines.push(`Published on: ${published}`);\n if (itemDescription) lines.push(parseContent(itemDescription));\n if (content) lines.push(parseContent(content));\n sections.push(lines.join(\"\\n\"));\n }\n\n const markdown = sections.join(\"\\n\\n\");\n return { title, markdown, text_content: markdown };\n }\n}\n\nfunction parseContent(content: string): string {\n return new CustomTurnDown().convertSoup(parseHtmlDocument(content).documentElement);\n}\n\nfunction getText(element: Element, tagName: string): string | null {\n const node = element.getElementsByTagName(tagName)[0];\n return node?.textContent?.trim() || null;\n}\n","import { decodeText } from \"../bytes\";\nimport { parseHtmlDocument } from \"../html-document\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class YouTubeConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n const extension = options.file_extension?.toLowerCase() ?? \"\";\n if (\n (extension !== \".html\" && extension !== \".htm\") ||\n !options.url?.startsWith(\"https://www.youtube.com/watch?\")\n ) {\n return null;\n }\n\n const document = parseHtmlDocument(decodeText(source));\n const metadata: Record<string, string> = { title: document.title };\n\n document.querySelectorAll(\"meta\").forEach((meta) => {\n const content = meta.getAttribute(\"content\");\n const key =\n meta.getAttribute(\"itemprop\") ?? meta.getAttribute(\"property\") ?? meta.getAttribute(\"name\");\n if (key && content) {\n metadata[key] = content;\n }\n });\n\n try {\n for (const script of document.querySelectorAll(\"script\")) {\n const content = script.textContent ?? \"\";\n if (!content.includes(\"ytInitialData\")) {\n continue;\n }\n const start = content.indexOf(\"{\");\n const end = content.lastIndexOf(\"}\");\n if (start >= 0 && end > start) {\n const description = findKey(\n JSON.parse(content.slice(start, end + 1)),\n \"attributedDescriptionBodyText\"\n );\n if (isRecord(description) && typeof description.content === \"string\") {\n metadata.description = description.content;\n }\n }\n break;\n }\n } catch {\n // Meta description remains available when the page implementation changes.\n }\n\n const title = first(metadata, [\"title\", \"og:title\", \"name\"]) || document.title || null;\n const lines = [\"# YouTube\"];\n if (title) {\n lines.push(`## ${title}`);\n }\n\n const stats: string[] = [];\n const views = first(metadata, [\"interactionCount\"]);\n const keywords = first(metadata, [\"keywords\"]);\n const runtime = first(metadata, [\"duration\"]);\n if (views) stats.push(`- **Views:** ${views}`);\n if (keywords) stats.push(`- **Keywords:** ${keywords}`);\n if (runtime) stats.push(`- **Runtime:** ${runtime}`);\n if (stats.length > 0) {\n lines.push(`### Video Metadata\\n${stats.join(\"\\n\")}`);\n }\n\n const description = first(metadata, [\"description\", \"og:description\"]);\n if (description) {\n lines.push(`### Description\\n${description}`);\n }\n\n const markdown = lines.join(\"\\n\\n\");\n return { title, markdown, text_content: markdown };\n }\n}\n\nfunction first(metadata: Record<string, string>, keys: string[]): string | null {\n for (const key of keys) {\n if (metadata[key]) return metadata[key];\n }\n return null;\n}\n\nfunction findKey(value: unknown, key: string): unknown {\n if (Array.isArray(value)) {\n for (const item of value) {\n const match = findKey(item, key);\n if (match !== undefined) return match;\n }\n } else if (isRecord(value)) {\n if (key in value) return value[key];\n for (const item of Object.values(value)) {\n const match = findKey(item, key);\n if (match !== undefined) return match;\n }\n }\n return undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n","import { unzipSync } from \"fflate\";\nimport { extensionFromPathname } from \"../mime\";\nimport type { ConverterOptions, ConverterResult, DocumentConverter } from \"../types\";\n\nexport class ZipConverter implements DocumentConverter {\n async convert(source: Uint8Array, options: ConverterOptions = {}): Promise<ConverterResult> {\n if (options.file_extension?.toLowerCase() !== \".zip\") {\n return null;\n }\n\n const files = unzipSync(source, {\n filter: (file) => !file.name.endsWith(\"/\")\n });\n const converters = options._parent_converters ?? [];\n const zipName = options.url ?? \"archive.zip\";\n const sections = [`Content from the zip file \\`${zipName}\\`:`];\n\n for (const [name, bytes] of Object.entries(files)) {\n const result = await convertEntry(bytes, name, converters, options);\n if (result) {\n sections.push(`## File: ${name}\\n\\n${result.markdown}`);\n }\n }\n\n const markdown = sections.join(\"\\n\\n\");\n return { title: null, markdown, text_content: markdown };\n }\n}\n\nasync function convertEntry(\n source: Uint8Array,\n name: string,\n converters: DocumentConverter[],\n options: ConverterOptions\n): Promise<ConverterResult> {\n const extension = extensionFromPathname(name);\n if (!extension) {\n return null;\n }\n\n const entryOptions: ConverterOptions = {\n ...options,\n file_extension: extension,\n url: undefined,\n _parent_converters: converters\n };\n\n for (const converter of converters) {\n try {\n const result = await converter.convert(source, entryOptions);\n if (result) {\n return result;\n }\n } catch {\n // Match the original ZipConverter: skip entries that fail conversion.\n }\n }\n\n return null;\n}\n","import { isBlob, toUint8Array } from \"./bytes\";\nimport { BingSerpConverter } from \"./converters/bingserp\";\nimport { DocxConverter } from \"./converters/docx\";\nimport { HtmlConverter } from \"./converters/html\";\nimport { IpynbConverter } from \"./converters/ipynb\";\nimport { PdfConverter } from \"./converters/pdf\";\nimport { PlainTextConverter } from \"./converters/plain-text\";\nimport { WikipediaConverter } from \"./converters/wikipedia\";\nimport { XlsxConverter } from \"./converters/xlsx\";\nimport { RSSConverter } from \"./converters/xml-rss-atom\";\nimport { YouTubeConverter } from \"./converters/youtube\";\nimport { ZipConverter } from \"./converters/zip\";\nimport { extensionFromMime, extensionFromPathname } from \"./mime\";\nimport type { ByteSource, ConverterOptions, ConverterResult, DocumentConverter } from \"./types\";\n\nexport type ConversionSource = ByteSource | Response | URL | string;\n\nexport class MarkItDown {\n private readonly converters: DocumentConverter[] = [];\n\n constructor() {\n this.registerConverter(new PlainTextConverter());\n this.registerConverter(new HtmlConverter());\n this.registerConverter(new ZipConverter());\n this.registerConverter(new RSSConverter());\n this.registerConverter(new WikipediaConverter());\n this.registerConverter(new YouTubeConverter());\n this.registerConverter(new BingSerpConverter());\n this.registerConverter(new DocxConverter());\n this.registerConverter(new XlsxConverter());\n this.registerConverter(new PdfConverter());\n this.registerConverter(new IpynbConverter());\n }\n\n /** Convert a URL, response, blob, array buffer, data view, or typed array. */\n async convert(\n source: ConversionSource,\n options: ConverterOptions = {}\n ): Promise<ConverterResult> {\n if (typeof source === \"string\" || source instanceof URL) {\n return this.convertUrl(source.toString(), options);\n }\n\n if (isResponse(source)) {\n return this.convertResponse(source, options);\n }\n\n const extensions = new Set<string>();\n this.addExtension(extensions, options.file_extension?.replace(/^\\./, \"\"));\n\n if (isBlob(source)) {\n this.addExtension(extensions, extensionFromMime(source.type));\n if (\"name\" in source && typeof source.name === \"string\") {\n this.addExtension(extensions, extensionFromPathname(source.name));\n }\n }\n\n if (extensions.size === 0) {\n throw new Error(\n \"Could not determine the file type. Provide `file_extension` when converting bytes.\"\n );\n }\n\n return this.convertBytes(await toUint8Array(source), extensions, options);\n }\n\n /**\n * @deprecated Pass the byte source directly to `convert`.\n */\n async convertBuffer(\n source: ByteSource,\n options: ConverterOptions & { file_extension: string }\n ): Promise<ConverterResult> {\n return this.convert(source, options);\n }\n\n private async convertUrl(\n source: string,\n { fetch: fetchImplementation = globalThis.fetch, ...options }: ConverterOptions\n ): Promise<ConverterResult> {\n const url = new URL(source);\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") {\n throw new Error(`Unsupported URL protocol: ${url.protocol}`);\n }\n if (!fetchImplementation) {\n throw new Error(\"No fetch implementation is available.\");\n }\n\n const response = await fetchImplementation(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch URL: ${url}, status: ${response.status}`);\n }\n\n return this.convertResponse(response, { ...options, url: url.toString() });\n }\n\n private async convertResponse(\n response: Response,\n options: ConverterOptions\n ): Promise<ConverterResult> {\n const extensions = new Set<string>();\n this.addExtension(extensions, options.file_extension);\n this.addExtension(extensions, extensionFromMime(response.headers.get(\"content-type\")));\n\n const disposition = response.headers.get(\"content-disposition\") ?? \"\";\n const filename = disposition.match(/filename\\*?=(?:UTF-8''|[\"']?)([^;\"']+)/i)?.[1];\n if (filename) {\n this.addExtension(extensions, extensionFromPathname(decodeURIComponent(filename.trim())));\n }\n\n const responseUrl = options.url || response.url;\n if (responseUrl) {\n this.addExtension(extensions, extensionFromPathname(new URL(responseUrl).pathname));\n }\n\n if (extensions.size === 0) {\n throw new Error(\n \"Could not determine the file type. Provide `file_extension` or a Content-Type header.\"\n );\n }\n\n return this.convertBytes(new Uint8Array(await response.arrayBuffer()), extensions, {\n ...options,\n url: responseUrl\n });\n }\n\n private async convertBytes(\n source: Uint8Array,\n extensions: Set<string>,\n options: ConverterOptions\n ): Promise<ConverterResult> {\n let lastError: unknown;\n\n for (const extension of extensions) {\n for (const converter of this.converters) {\n try {\n const result = await converter.convert(source, {\n ...options,\n file_extension: extension,\n _parent_converters: this.converters\n });\n if (result) {\n result.markdown = result.markdown\n .replace(/\\r\\n|\\r|\\n/g, \"\\n\")\n .trim()\n .replace(/\\n{3,}/g, \"\\n\\n\");\n result.text_content = result.markdown;\n return result;\n }\n } catch (error) {\n if (options.debug) {\n console.error(\"Converter threw error:\", error);\n }\n lastError = error;\n }\n }\n }\n\n const formats = [...extensions].join(\", \");\n if (lastError) {\n throw new Error(`Could not convert ${formats} to Markdown: ${String(lastError)}`);\n }\n throw new Error(`Unsupported file type: ${formats}.`);\n }\n\n private addExtension(extensions: Set<string>, extension: string | null | undefined): void {\n if (!extension) {\n return;\n }\n extensions.add(\n extension.startsWith(\".\") ? extension.toLowerCase() : `.${extension.toLowerCase()}`\n );\n }\n\n private registerConverter(converter: DocumentConverter): void {\n this.converters.unshift(converter);\n }\n}\n\nfunction isResponse(value: unknown): value is Response {\n return typeof Response !== \"undefined\" && value instanceof Response;\n}\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -27,6 +27,7 @@ type ConverterOptions = {
27
27
  idPrefix?: string;
28
28
  transformDocument?: (element: unknown) => unknown;
29
29
  _parent_converters?: DocumentConverter[];
30
+ debug?: boolean;
30
31
  };
31
32
  interface DocumentConverter {
32
33
  convert(source: Uint8Array, options: ConverterOptions): Promise<ConverterResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/markitdown.ts"],"mappings":";KAAY;EACV;EACA;;EAEA;;;;;;;;KASU,aAAa,aAAa,kBAAkB,kBAAkB;KAE9D;;EAEV;;EAEA;;EAEA,eAAe;;EAEf;EACA;EACA;EACA;EACA;EACA,qBAAqB;EACrB,qBAAqB;;UAGN;EACf,QAAQ,QAAQ,YAAY,SAAS,mBAAmB,QAAQ;;;;KClBtD,mBAAmB,aAAa,WAAW;cAE1C;mBACM;EAEjB;;EAeM,QACJ,QAAQ,kBACR,UAAS,mBACR,QAAQ;;;;EA+BL,cACJ,QAAQ,YACR,SAAS;IAAqB;MAC7B,QAAQ;UAIG;UAoBA;UA+BA;UAoCN;UASA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/markitdown.ts"],"mappings":";KAAY;EACV;EACA;;EAEA;;;;;;;;KASU,aAAa,aAAa,kBAAkB,kBAAkB;KAE9D;;EAEV;;EAEA;;EAEA,eAAe;;EAEf;EACA;EACA;EACA;EACA;EACA,qBAAqB;EACrB,qBAAqB;EACrB;;UAGe;EACf,QAAQ,QAAQ,YAAY,SAAS,mBAAmB,QAAQ;;;;KCnBtD,mBAAmB,aAAa,WAAW;cAE1C;mBACM;EAEjB;;EAeM,QACJ,QAAQ,kBACR,UAAS,mBACR,QAAQ;;;;EA+BL,cACJ,QAAQ,YACR,SAAS;IAAqB;MAC7B,QAAQ;UAIG;UAoBA;UA+BA;UAuCN;UASA"}
package/dist/index.d.ts CHANGED
@@ -27,6 +27,7 @@ type ConverterOptions = {
27
27
  idPrefix?: string;
28
28
  transformDocument?: (element: unknown) => unknown;
29
29
  _parent_converters?: DocumentConverter[];
30
+ debug?: boolean;
30
31
  };
31
32
  interface DocumentConverter {
32
33
  convert(source: Uint8Array, options: ConverterOptions): Promise<ConverterResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/markitdown.ts"],"mappings":";KAAY;EACV;EACA;;EAEA;;;;;;;;KASU,aAAa,aAAa,kBAAkB,kBAAkB;KAE9D;;EAEV;;EAEA;;EAEA,eAAe;;EAEf;EACA;EACA;EACA;EACA;EACA,qBAAqB;EACrB,qBAAqB;;UAGN;EACf,QAAQ,QAAQ,YAAY,SAAS,mBAAmB,QAAQ;;;;KClBtD,mBAAmB,aAAa,WAAW;cAE1C;mBACM;EAEjB;;EAeM,QACJ,QAAQ,kBACR,UAAS,mBACR,QAAQ;;;;EA+BL,cACJ,QAAQ,YACR,SAAS;IAAqB;MAC7B,QAAQ;UAIG;UAoBA;UA+BA;UAoCN;UASA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/markitdown.ts"],"mappings":";KAAY;EACV;EACA;;EAEA;;;;;;;;KASU,aAAa,aAAa,kBAAkB,kBAAkB;KAE9D;;EAEV;;EAEA;;EAEA,eAAe;;EAEf;EACA;EACA;EACA;EACA;EACA,qBAAqB;EACrB,qBAAqB;EACrB;;UAGe;EACf,QAAQ,QAAQ,YAAY,SAAS,mBAAmB,QAAQ;;;;KCnBtD,mBAAmB,aAAa,WAAW;cAE1C;mBACM;EAEjB;;EAeM,QACJ,QAAQ,kBACR,UAAS,mBACR,QAAQ;;;;EA+BL,cACJ,QAAQ,YACR,SAAS;IAAqB;MAC7B,QAAQ;UAIG;UAoBA;UA+BA;UAuCN;UASA"}
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import TurndownService from "turndown";
3
3
  import { parseHTML } from "linkedom";
4
4
  import mammoth from "mammoth";
5
5
  import { extractText, getDocumentProxy, getMeta } from "unpdf";
6
- import * as XLSX from "xlsx";
6
+ import ExcelJS from "exceljs";
7
7
  import { DOMParser } from "@xmldom/xmldom";
8
8
  import { unzipSync } from "fflate";
9
9
  //#region src/bytes.ts
@@ -133,12 +133,13 @@ var HtmlConverter = class {
133
133
  }
134
134
  async convertHtml(html) {
135
135
  const document = parseHtmlDocument(html);
136
- document.querySelectorAll("script, style").forEach((element) => {
136
+ const title = document.title;
137
+ document.querySelectorAll("script, style, title").forEach((element) => {
137
138
  element.remove();
138
139
  });
139
- const markdown = new CustomTurnDown().convertSoup(document.body ?? document);
140
+ const markdown = new CustomTurnDown().convertSoup(document);
140
141
  return {
141
- title: document.title || null,
142
+ title: title || null,
142
143
  markdown,
143
144
  text_content: markdown
144
145
  };
@@ -149,14 +150,17 @@ var HtmlConverter = class {
149
150
  var DocxConverter = class extends HtmlConverter {
150
151
  async convert(source, options) {
151
152
  if (options.file_extension?.toLowerCase() !== ".docx") return null;
152
- const html = await mammoth.convertToHtml({ arrayBuffer: toArrayBuffer(source) }, {
153
+ let mammothInput = { arrayBuffer: toArrayBuffer(source) };
154
+ if (typeof process !== "undefined" && process.versions !== null && process.versions.node !== null) mammothInput = { buffer: Buffer.from(source) };
155
+ const mammothOptions = {
153
156
  styleMap: options.styleMap,
154
157
  includeEmbeddedStyleMap: options.includeEmbeddedStyleMap,
155
158
  includeDefaultStyleMap: options.includeDefaultStyleMap,
156
159
  ignoreEmptyParagraphs: options.ignoreEmptyParagraphs,
157
- idPrefix: options.idPrefix,
158
- transformDocument: options.transformDocument
159
- });
160
+ idPrefix: options.idPrefix
161
+ };
162
+ if (options.transformDocument) mammothOptions.transformDocument = options.transformDocument;
163
+ const html = await mammoth.convertToHtml(mammothInput, mammothOptions);
160
164
  return this.convertHtml(html.value);
161
165
  }
162
166
  };
@@ -278,26 +282,45 @@ var WikipediaConverter = class {
278
282
  };
279
283
  //#endregion
280
284
  //#region src/converters/xlsx.ts
285
+ const { Workbook } = ExcelJS;
281
286
  var XlsxConverter = class extends HtmlConverter {
282
287
  async convert(source, options) {
283
288
  if (options.file_extension?.toLowerCase() !== ".xlsx") return null;
284
- const workbook = XLSX.read(source, { type: "array" });
289
+ const workbook = new Workbook();
290
+ await workbook.xlsx.load(toArrayBuffer(source));
285
291
  const sections = [];
286
- for (const sheetName of workbook.SheetNames) {
287
- const sheet = workbook.Sheets[sheetName];
288
- if (sheet?.["!ref"]) {
289
- const result = await this.convertHtml(XLSX.utils.sheet_to_html(sheet));
290
- sections.push(`## ${sheetName}\n${result?.markdown.trim() ?? ""}`);
291
- }
292
+ for (const worksheet of workbook.worksheets) {
293
+ const html = worksheetToHtml(worksheet);
294
+ if (!html) continue;
295
+ const result = await this.convertHtml(html);
296
+ sections.push(`## ${worksheet.name}\n${result?.markdown.trim() ?? ""}`);
292
297
  }
293
298
  const markdown = sections.join("\n\n");
294
299
  return {
295
- title: workbook.Props?.Title || "Untitled",
300
+ title: workbook.title || "Untitled",
296
301
  markdown,
297
302
  text_content: markdown
298
303
  };
299
304
  }
300
305
  };
306
+ function worksheetToHtml(worksheet) {
307
+ const columnCount = worksheet.columnCount;
308
+ if (!columnCount || !worksheet.actualRowCount) return "";
309
+ const rows = [];
310
+ worksheet.eachRow({ includeEmpty: true }, (row) => {
311
+ const cells = [];
312
+ for (let column = 1; column <= columnCount; column++) cells.push(`<td>${escapeHtml(cellText(row.getCell(column)))}</td>`);
313
+ rows.push(`<tr>${cells.join("")}</tr>`);
314
+ });
315
+ return `<html><body><table>${rows.join("")}</table></body></html>`;
316
+ }
317
+ function cellText(cell) {
318
+ if (cell.isMerged && cell.master !== cell) return "";
319
+ return cell.text;
320
+ }
321
+ function escapeHtml(value) {
322
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
323
+ }
301
324
  //#endregion
302
325
  //#region src/converters/xml-rss-atom.ts
303
326
  var RSSConverter = class {
@@ -500,7 +523,7 @@ var MarkItDown = class {
500
523
  if (typeof source === "string" || source instanceof URL) return this.convertUrl(source.toString(), options);
501
524
  if (isResponse(source)) return this.convertResponse(source, options);
502
525
  const extensions = /* @__PURE__ */ new Set();
503
- this.addExtension(extensions, options.file_extension);
526
+ this.addExtension(extensions, options.file_extension?.replace(/^\./, ""));
504
527
  if (isBlob(source)) {
505
528
  this.addExtension(extensions, extensionFromMime(source.type));
506
529
  if ("name" in source && typeof source.name === "string") this.addExtension(extensions, extensionFromPathname(source.name));
@@ -553,6 +576,7 @@ var MarkItDown = class {
553
576
  return result;
554
577
  }
555
578
  } catch (error) {
579
+ if (options.debug) console.error("Converter threw error:", error);
556
580
  lastError = error;
557
581
  }
558
582
  const formats = [...extensions].join(", ");