@statewalker/content-extractors 0.2.2

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 (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -0
  3. package/dist/collect-bytes.d.ts +16 -0
  4. package/dist/collect-bytes.d.ts.map +1 -0
  5. package/dist/collect-bytes.js +37 -0
  6. package/dist/collect-bytes.js.map +1 -0
  7. package/dist/extractor-registry.d.ts +38 -0
  8. package/dist/extractor-registry.d.ts.map +1 -0
  9. package/dist/extractor-registry.js +61 -0
  10. package/dist/extractor-registry.js.map +1 -0
  11. package/dist/extractors/docx-extractor.d.ts +11 -0
  12. package/dist/extractors/docx-extractor.d.ts.map +1 -0
  13. package/dist/extractors/docx-extractor.js +23 -0
  14. package/dist/extractors/docx-extractor.js.map +1 -0
  15. package/dist/extractors/html-extractor.d.ts +10 -0
  16. package/dist/extractors/html-extractor.d.ts.map +1 -0
  17. package/dist/extractors/html-extractor.js +16 -0
  18. package/dist/extractors/html-extractor.js.map +1 -0
  19. package/dist/extractors/index.d.ts +18 -0
  20. package/dist/extractors/index.d.ts.map +1 -0
  21. package/dist/extractors/index.js +31 -0
  22. package/dist/extractors/index.js.map +1 -0
  23. package/dist/extractors/markdown-extractor.d.ts +11 -0
  24. package/dist/extractors/markdown-extractor.d.ts.map +1 -0
  25. package/dist/extractors/markdown-extractor.js +15 -0
  26. package/dist/extractors/markdown-extractor.js.map +1 -0
  27. package/dist/extractors/pdf-extractor.d.ts +10 -0
  28. package/dist/extractors/pdf-extractor.d.ts.map +1 -0
  29. package/dist/extractors/pdf-extractor.js +22 -0
  30. package/dist/extractors/pdf-extractor.js.map +1 -0
  31. package/dist/extractors/text-extractor.d.ts +10 -0
  32. package/dist/extractors/text-extractor.d.ts.map +1 -0
  33. package/dist/extractors/text-extractor.js +14 -0
  34. package/dist/extractors/text-extractor.js.map +1 -0
  35. package/dist/extractors/xlsx-extractor.d.ts +11 -0
  36. package/dist/extractors/xlsx-extractor.d.ts.map +1 -0
  37. package/dist/extractors/xlsx-extractor.js +49 -0
  38. package/dist/extractors/xlsx-extractor.js.map +1 -0
  39. package/dist/html-to-markdown.d.ts +10 -0
  40. package/dist/html-to-markdown.d.ts.map +1 -0
  41. package/dist/html-to-markdown.js +25 -0
  42. package/dist/html-to-markdown.js.map +1 -0
  43. package/dist/index.d.ts +14 -0
  44. package/dist/index.js +13 -0
  45. package/dist/markdown-to-html.d.ts +10 -0
  46. package/dist/markdown-to-html.d.ts.map +1 -0
  47. package/dist/markdown-to-html.js +22 -0
  48. package/dist/markdown-to-html.js.map +1 -0
  49. package/dist/mime-utils.d.ts +10 -0
  50. package/dist/mime-utils.d.ts.map +1 -0
  51. package/dist/mime-utils.js +29 -0
  52. package/dist/mime-utils.js.map +1 -0
  53. package/dist/types.d.ts +29 -0
  54. package/dist/types.d.ts.map +1 -0
  55. package/dist/types.js +1 -0
  56. package/package.json +71 -0
  57. package/src/collect-bytes.ts +39 -0
  58. package/src/extractor-registry.ts +69 -0
  59. package/src/extractors/docx-extractor.ts +21 -0
  60. package/src/extractors/html-extractor.ts +13 -0
  61. package/src/extractors/index.ts +34 -0
  62. package/src/extractors/markdown-extractor.ts +12 -0
  63. package/src/extractors/pdf-extractor.ts +23 -0
  64. package/src/extractors/text-extractor.ts +11 -0
  65. package/src/extractors/xlsx-extractor.ts +57 -0
  66. package/src/html-to-markdown.ts +22 -0
  67. package/src/index.ts +7 -0
  68. package/src/markdown-to-html.ts +21 -0
  69. package/src/mime-utils.ts +25 -0
  70. package/src/turndown-plugin-gfm.d.ts +7 -0
  71. package/src/types.ts +24 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mikhail Kotelnikov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # @statewalker/content-extractors
2
+
3
+ Content extractors: turn PDF, DOCX, XLSX, Markdown, and HTML into markdown **text** via a mime-aware registry.
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ pnpm add @statewalker/content-extractors
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { createDefaultRegistry } from "@statewalker/content-extractors";
15
+
16
+ const registry = createDefaultRegistry();
17
+ const extractor = registry.get("report.pdf");
18
+ const markdown = await extractor?.(pdfBytes); // string
19
+ ```
20
+
21
+ ## API
22
+
23
+ - `ContentExtractor` — the core contract: `bytes → Promise<string>`.
24
+ - `ExtractorRegistry` / `createDefaultRegistry` — resolve an extractor by path or MIME type.
25
+ - Format handlers under `./extractors` (PDF, DOCX, XLSX, Markdown, HTML).
26
+ - `html-to-markdown`, `markdown-to-html`, `mime-utils`, `collect-bytes` helpers.
@@ -0,0 +1,16 @@
1
+ //#region src/collect-bytes.d.ts
2
+ /**
3
+ * Bridges the streaming world (chunked iterables from fetch, file reads,
4
+ * etc.) with libraries that require a single contiguous buffer (pdfjs-dist,
5
+ * mammoth). Returns the original chunk when only one arrives, avoiding
6
+ * an extra copy in the common single-read case.
7
+ */
8
+ export declare function collectBytes(content: AsyncIterable<Uint8Array> | Iterable<Uint8Array>): Promise<Uint8Array>;
9
+ /**
10
+ * Shorthand for text-based extractors (plain text, markdown, HTML) that
11
+ * need the full content as a string. Avoids duplicating the
12
+ * collect-then-decode pattern across every text extractor.
13
+ */
14
+ export declare function collectText(content: AsyncIterable<Uint8Array> | Iterable<Uint8Array>): Promise<string>;
15
+ //#endregion
16
+ //# sourceMappingURL=collect-bytes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect-bytes.d.ts","names":[],"sources":["../src/collect-bytes.ts"],"mappings":";;;;;;;wBAMsB,aACpB,SAAS,cAAc,cAAc,SAAS,cAC7C,QAAQ;;;;;;wBAyBW,YACpB,SAAS,cAAc,cAAc,SAAS,cAC7C"}
@@ -0,0 +1,37 @@
1
+ //#region src/collect-bytes.ts
2
+ /**
3
+ * Bridges the streaming world (chunked iterables from fetch, file reads,
4
+ * etc.) with libraries that require a single contiguous buffer (pdfjs-dist,
5
+ * mammoth). Returns the original chunk when only one arrives, avoiding
6
+ * an extra copy in the common single-read case.
7
+ */
8
+ async function collectBytes(content) {
9
+ const chunks = [];
10
+ let totalLength = 0;
11
+ for await (const chunk of content) {
12
+ chunks.push(chunk);
13
+ totalLength += chunk.length;
14
+ }
15
+ const first = chunks[0];
16
+ if (chunks.length === 1 && first) return first;
17
+ const result = new Uint8Array(totalLength);
18
+ let offset = 0;
19
+ for (const chunk of chunks) {
20
+ result.set(chunk, offset);
21
+ offset += chunk.length;
22
+ }
23
+ return result;
24
+ }
25
+ /**
26
+ * Shorthand for text-based extractors (plain text, markdown, HTML) that
27
+ * need the full content as a string. Avoids duplicating the
28
+ * collect-then-decode pattern across every text extractor.
29
+ */
30
+ async function collectText(content) {
31
+ const bytes = await collectBytes(content);
32
+ return new TextDecoder().decode(bytes);
33
+ }
34
+ //#endregion
35
+ export { collectBytes, collectText };
36
+
37
+ //# sourceMappingURL=collect-bytes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collect-bytes.js","names":[],"sources":["../src/collect-bytes.ts"],"sourcesContent":["/**\n * Bridges the streaming world (chunked iterables from fetch, file reads,\n * etc.) with libraries that require a single contiguous buffer (pdfjs-dist,\n * mammoth). Returns the original chunk when only one arrives, avoiding\n * an extra copy in the common single-read case.\n */\nexport async function collectBytes(\n content: AsyncIterable<Uint8Array> | Iterable<Uint8Array>,\n): Promise<Uint8Array> {\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n for await (const chunk of content) {\n chunks.push(chunk);\n totalLength += chunk.length;\n }\n const first = chunks[0];\n if (chunks.length === 1 && first) {\n return first;\n }\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n return result;\n}\n\n/**\n * Shorthand for text-based extractors (plain text, markdown, HTML) that\n * need the full content as a string. Avoids duplicating the\n * collect-then-decode pattern across every text extractor.\n */\nexport async function collectText(\n content: AsyncIterable<Uint8Array> | Iterable<Uint8Array>,\n): Promise<string> {\n const bytes = await collectBytes(content);\n return new TextDecoder().decode(bytes);\n}\n"],"mappings":";;;;;;;AAMA,eAAsB,aACpB,SACqB;CACrB,MAAM,SAAuB,CAAC;CAC9B,IAAI,cAAc;CAClB,WAAW,MAAM,SAAS,SAAS;EACjC,OAAO,KAAK,KAAK;EACjB,eAAe,MAAM;CACvB;CACA,MAAM,QAAQ,OAAO;CACrB,IAAI,OAAO,WAAW,KAAK,OACzB,OAAO;CAET,MAAM,SAAS,IAAI,WAAW,WAAW;CACzC,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,QAAQ;EAC1B,OAAO,IAAI,OAAO,MAAM;EACxB,UAAU,MAAM;CAClB;CACA,OAAO;AACT;;;;;;AAOA,eAAsB,YACpB,SACiB;CACjB,MAAM,QAAQ,MAAM,aAAa,OAAO;CACxC,OAAO,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK;AACvC"}
@@ -0,0 +1,38 @@
1
+ import { ContentExtractor } from "./types.js";
2
+ //#region src/extractor-registry.d.ts
3
+ /**
4
+ * Central routing table that decouples file-format knowledge from the
5
+ * extraction pipeline. New formats can be added without touching pipeline
6
+ * code. Longest-suffix matching ensures compound extensions (e.g.
7
+ * `*.tar.gz`) win over shorter ones, and MIME-type fallback handles
8
+ * files that arrive without a recognizable extension.
9
+ */
10
+ export declare class ExtractorRegistry {
11
+ private patternMap;
12
+ private mimeMap;
13
+ /**
14
+ * Associates a suffix pattern with an extractor so the registry can
15
+ * route files to the right handler based on their filename.
16
+ */
17
+ registerByPattern(pattern: string, extractor: ContentExtractor): void;
18
+ /**
19
+ * Provides a fallback route for files that lack a recognizable extension
20
+ * (e.g. temp files or HTTP responses identified only by Content-Type).
21
+ */
22
+ registerByMime(mimeType: string, extractor: ContentExtractor): void;
23
+ /**
24
+ * Resolves by filename suffix, preferring the most specific match so
25
+ * compound extensions like `*.test.html` beat `*.html` when both exist.
26
+ */
27
+ getByPath(path: string): ContentExtractor | undefined;
28
+ /** Direct MIME lookup -- used internally by `get` as the fallback path. */
29
+ getByMime(mimeType: string): ContentExtractor | undefined;
30
+ /**
31
+ * Single entry point for the pipeline -- tries the most reliable signal
32
+ * (file extension) first, then falls back to MIME type so callers never
33
+ * need to worry about the resolution strategy.
34
+ */
35
+ get(path: string, mimeType?: string): ContentExtractor | undefined;
36
+ }
37
+ //#endregion
38
+ //# sourceMappingURL=extractor-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor-registry.d.ts","names":[],"sources":["../src/extractor-registry.ts"],"mappings":";;;;;;;;;qBASa;UACH;UACA;;;;;EAMR,kBAAkB,iBAAiB,WAAW;;;;;EAQ9C,eAAe,kBAAkB,WAAW;;;;;EAQ5C,UAAU,eAAe;;EAoBzB,UAAU,mBAAmB;;;;;;EAS7B,IAAI,cAAc,oBAAoB"}
@@ -0,0 +1,61 @@
1
+ //#region src/extractor-registry.ts
2
+ /**
3
+ * Central routing table that decouples file-format knowledge from the
4
+ * extraction pipeline. New formats can be added without touching pipeline
5
+ * code. Longest-suffix matching ensures compound extensions (e.g.
6
+ * `*.tar.gz`) win over shorter ones, and MIME-type fallback handles
7
+ * files that arrive without a recognizable extension.
8
+ */
9
+ var ExtractorRegistry = class {
10
+ patternMap = /* @__PURE__ */ new Map();
11
+ mimeMap = /* @__PURE__ */ new Map();
12
+ /**
13
+ * Associates a suffix pattern with an extractor so the registry can
14
+ * route files to the right handler based on their filename.
15
+ */
16
+ registerByPattern(pattern, extractor) {
17
+ this.patternMap.set(pattern, extractor);
18
+ }
19
+ /**
20
+ * Provides a fallback route for files that lack a recognizable extension
21
+ * (e.g. temp files or HTTP responses identified only by Content-Type).
22
+ */
23
+ registerByMime(mimeType, extractor) {
24
+ this.mimeMap.set(mimeType, extractor);
25
+ }
26
+ /**
27
+ * Resolves by filename suffix, preferring the most specific match so
28
+ * compound extensions like `*.test.html` beat `*.html` when both exist.
29
+ */
30
+ getByPath(path) {
31
+ const lowerFilename = (path.includes("/") ? path.slice(path.lastIndexOf("/") + 1) : path).toLowerCase();
32
+ let bestMatch;
33
+ let bestLength = 0;
34
+ for (const [pattern, extractor] of this.patternMap) {
35
+ const suffix = pattern.startsWith("*") ? pattern.slice(1) : pattern;
36
+ if (lowerFilename.endsWith(suffix) && suffix.length > bestLength) {
37
+ bestMatch = extractor;
38
+ bestLength = suffix.length;
39
+ }
40
+ }
41
+ return bestMatch;
42
+ }
43
+ /** Direct MIME lookup -- used internally by `get` as the fallback path. */
44
+ getByMime(mimeType) {
45
+ return this.mimeMap.get(mimeType);
46
+ }
47
+ /**
48
+ * Single entry point for the pipeline -- tries the most reliable signal
49
+ * (file extension) first, then falls back to MIME type so callers never
50
+ * need to worry about the resolution strategy.
51
+ */
52
+ get(path, mimeType) {
53
+ const byPath = this.getByPath(path);
54
+ if (byPath) return byPath;
55
+ if (mimeType) return this.getByMime(mimeType);
56
+ }
57
+ };
58
+ //#endregion
59
+ export { ExtractorRegistry };
60
+
61
+ //# sourceMappingURL=extractor-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extractor-registry.js","names":[],"sources":["../src/extractor-registry.ts"],"sourcesContent":["import type { ContentExtractor } from \"./types.js\";\n\n/**\n * Central routing table that decouples file-format knowledge from the\n * extraction pipeline. New formats can be added without touching pipeline\n * code. Longest-suffix matching ensures compound extensions (e.g.\n * `*.tar.gz`) win over shorter ones, and MIME-type fallback handles\n * files that arrive without a recognizable extension.\n */\nexport class ExtractorRegistry {\n private patternMap = new Map<string, ContentExtractor>();\n private mimeMap = new Map<string, ContentExtractor>();\n\n /**\n * Associates a suffix pattern with an extractor so the registry can\n * route files to the right handler based on their filename.\n */\n registerByPattern(pattern: string, extractor: ContentExtractor): void {\n this.patternMap.set(pattern, extractor);\n }\n\n /**\n * Provides a fallback route for files that lack a recognizable extension\n * (e.g. temp files or HTTP responses identified only by Content-Type).\n */\n registerByMime(mimeType: string, extractor: ContentExtractor): void {\n this.mimeMap.set(mimeType, extractor);\n }\n\n /**\n * Resolves by filename suffix, preferring the most specific match so\n * compound extensions like `*.test.html` beat `*.html` when both exist.\n */\n getByPath(path: string): ContentExtractor | undefined {\n const filename = path.includes(\"/\") ? path.slice(path.lastIndexOf(\"/\") + 1) : path;\n const lowerFilename = filename.toLowerCase();\n\n let bestMatch: ContentExtractor | undefined;\n let bestLength = 0;\n\n for (const [pattern, extractor] of this.patternMap) {\n // Pattern format: *.ext or *.compound.ext\n const suffix = pattern.startsWith(\"*\") ? pattern.slice(1) : pattern;\n if (lowerFilename.endsWith(suffix) && suffix.length > bestLength) {\n bestMatch = extractor;\n bestLength = suffix.length;\n }\n }\n\n return bestMatch;\n }\n\n /** Direct MIME lookup -- used internally by `get` as the fallback path. */\n getByMime(mimeType: string): ContentExtractor | undefined {\n return this.mimeMap.get(mimeType);\n }\n\n /**\n * Single entry point for the pipeline -- tries the most reliable signal\n * (file extension) first, then falls back to MIME type so callers never\n * need to worry about the resolution strategy.\n */\n get(path: string, mimeType?: string): ContentExtractor | undefined {\n const byPath = this.getByPath(path);\n if (byPath) return byPath;\n if (mimeType) return this.getByMime(mimeType);\n return undefined;\n }\n}\n"],"mappings":";;;;;;;;AASA,IAAa,oBAAb,MAA+B;CAC7B,6BAAqB,IAAI,IAA8B;CACvD,0BAAkB,IAAI,IAA8B;;;;;CAMpD,kBAAkB,SAAiB,WAAmC;EACpE,KAAK,WAAW,IAAI,SAAS,SAAS;CACxC;;;;;CAMA,eAAe,UAAkB,WAAmC;EAClE,KAAK,QAAQ,IAAI,UAAU,SAAS;CACtC;;;;;CAMA,UAAU,MAA4C;EAEpD,MAAM,iBADW,KAAK,SAAS,GAAG,IAAI,KAAK,MAAM,KAAK,YAAY,GAAG,IAAI,CAAC,IAAI,KAAA,CAC/C,YAAY;EAE3C,IAAI;EACJ,IAAI,aAAa;EAEjB,KAAK,MAAM,CAAC,SAAS,cAAc,KAAK,YAAY;GAElD,MAAM,SAAS,QAAQ,WAAW,GAAG,IAAI,QAAQ,MAAM,CAAC,IAAI;GAC5D,IAAI,cAAc,SAAS,MAAM,KAAK,OAAO,SAAS,YAAY;IAChE,YAAY;IACZ,aAAa,OAAO;GACtB;EACF;EAEA,OAAO;CACT;;CAGA,UAAU,UAAgD;EACxD,OAAO,KAAK,QAAQ,IAAI,QAAQ;CAClC;;;;;;CAOA,IAAI,MAAc,UAAiD;EACjE,MAAM,SAAS,KAAK,UAAU,IAAI;EAClC,IAAI,QAAQ,OAAO;EACnB,IAAI,UAAU,OAAO,KAAK,UAAU,QAAQ;CAE9C;AACF"}
@@ -0,0 +1,11 @@
1
+ import { ContentExtractor } from "../types.js";
2
+ //#region src/extractors/docx-extractor.d.ts
3
+ /**
4
+ * Unlocks Word document content for text-based pipelines via a two-stage
5
+ * conversion (DOCX -> HTML -> markdown). Supplies both `buffer` and
6
+ * `arrayBuffer` to mammoth so the same code runs in Node.js and browsers
7
+ * without environment detection.
8
+ */
9
+ export declare const docxExtractor: ContentExtractor;
10
+ //#endregion
11
+ //# sourceMappingURL=docx-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docx-extractor.d.ts","names":[],"sources":["../../src/extractors/docx-extractor.ts"],"mappings":";;;;;;;;qBAWa,eAAe"}
@@ -0,0 +1,23 @@
1
+ import { collectBytes } from "../collect-bytes.js";
2
+ import { htmlToMarkdown } from "../html-to-markdown.js";
3
+ import mammoth from "mammoth";
4
+ //#region src/extractors/docx-extractor.ts
5
+ /**
6
+ * Unlocks Word document content for text-based pipelines via a two-stage
7
+ * conversion (DOCX -> HTML -> markdown). Supplies both `buffer` and
8
+ * `arrayBuffer` to mammoth so the same code runs in Node.js and browsers
9
+ * without environment detection.
10
+ */
11
+ const docxExtractor = async (content) => {
12
+ const bytes = await collectBytes(content);
13
+ const arrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
14
+ const result = await mammoth.convertToHtml({
15
+ buffer: arrayBuffer,
16
+ arrayBuffer
17
+ });
18
+ return htmlToMarkdown(result.value);
19
+ };
20
+ //#endregion
21
+ export { docxExtractor };
22
+
23
+ //# sourceMappingURL=docx-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docx-extractor.js","names":[],"sources":["../../src/extractors/docx-extractor.ts"],"sourcesContent":["import mammoth from \"mammoth\";\nimport { collectBytes } from \"../collect-bytes.js\";\nimport { htmlToMarkdown } from \"../html-to-markdown.js\";\nimport type { ContentExtractor } from \"../types.js\";\n\n/**\n * Unlocks Word document content for text-based pipelines via a two-stage\n * conversion (DOCX -> HTML -> markdown). Supplies both `buffer` and\n * `arrayBuffer` to mammoth so the same code runs in Node.js and browsers\n * without environment detection.\n */\nexport const docxExtractor: ContentExtractor = async (content) => {\n const bytes = await collectBytes(content);\n const arrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);\n // mammoth uses \"buffer\" in Node.js and \"arrayBuffer\" in browsers\n const result = await mammoth.convertToHtml({\n buffer: arrayBuffer,\n arrayBuffer,\n } as Parameters<typeof mammoth.convertToHtml>[0]);\n return htmlToMarkdown(result.value);\n};\n"],"mappings":";;;;;;;;;;AAWA,MAAa,gBAAkC,OAAO,YAAY;CAChE,MAAM,QAAQ,MAAM,aAAa,OAAO;CACxC,MAAM,cAAc,MAAM,OAAO,MAAM,MAAM,YAAY,MAAM,aAAa,MAAM,UAAU;CAE5F,MAAM,SAAS,MAAM,QAAQ,cAAc;EACzC,QAAQ;EACR;CACF,CAAgD;CAChD,OAAO,eAAe,OAAO,KAAK;AACpC"}
@@ -0,0 +1,10 @@
1
+ import { ContentExtractor } from "../types.js";
2
+ //#region src/extractors/html-extractor.d.ts
3
+ /**
4
+ * Converts HTML files to markdown so the pipeline outputs a uniform
5
+ * text format. Delegates to `htmlToMarkdown` for the actual conversion,
6
+ * keeping this extractor focused on the bytes-to-string bridging step.
7
+ */
8
+ export declare const htmlExtractor: ContentExtractor;
9
+ //#endregion
10
+ //# sourceMappingURL=html-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-extractor.d.ts","names":[],"sources":["../../src/extractors/html-extractor.ts"],"mappings":";;;;;;;qBASa,eAAe"}
@@ -0,0 +1,16 @@
1
+ import { collectText } from "../collect-bytes.js";
2
+ import { htmlToMarkdown } from "../html-to-markdown.js";
3
+ //#region src/extractors/html-extractor.ts
4
+ /**
5
+ * Converts HTML files to markdown so the pipeline outputs a uniform
6
+ * text format. Delegates to `htmlToMarkdown` for the actual conversion,
7
+ * keeping this extractor focused on the bytes-to-string bridging step.
8
+ */
9
+ const htmlExtractor = async (content) => {
10
+ const html = await collectText(content);
11
+ return htmlToMarkdown(html);
12
+ };
13
+ //#endregion
14
+ export { htmlExtractor };
15
+
16
+ //# sourceMappingURL=html-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-extractor.js","names":[],"sources":["../../src/extractors/html-extractor.ts"],"sourcesContent":["import { collectText } from \"../collect-bytes.js\";\nimport { htmlToMarkdown } from \"../html-to-markdown.js\";\nimport type { ContentExtractor } from \"../types.js\";\n\n/**\n * Converts HTML files to markdown so the pipeline outputs a uniform\n * text format. Delegates to `htmlToMarkdown` for the actual conversion,\n * keeping this extractor focused on the bytes-to-string bridging step.\n */\nexport const htmlExtractor: ContentExtractor = async (content) => {\n const html = await collectText(content);\n return htmlToMarkdown(html);\n};\n"],"mappings":";;;;;;;;AASA,MAAa,gBAAkC,OAAO,YAAY;CAChE,MAAM,OAAO,MAAM,YAAY,OAAO;CACtC,OAAO,eAAe,IAAI;AAC5B"}
@@ -0,0 +1,18 @@
1
+ import { docxExtractor } from "./docx-extractor.js";
2
+ import { htmlExtractor } from "./html-extractor.js";
3
+ import { markdownExtractor } from "./markdown-extractor.js";
4
+ import { pdfExtractor } from "./pdf-extractor.js";
5
+ import { textExtractor } from "./text-extractor.js";
6
+ import { xlsxExtractor } from "./xlsx-extractor.js";
7
+ import { ExtractorRegistry } from "../extractor-registry.js";
8
+ //#region src/extractors/index.d.ts
9
+ /**
10
+ * Provides a batteries-included registry so most consumers can start
11
+ * extracting immediately without manual format registration. Custom
12
+ * registries are still supported for apps that need to override or
13
+ * limit the built-in set.
14
+ */
15
+ export declare function createDefaultRegistry(): ExtractorRegistry;
16
+ //#endregion
17
+ export { docxExtractor, htmlExtractor, markdownExtractor, pdfExtractor, textExtractor, xlsxExtractor };
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/extractors/index.ts"],"mappings":";;;;;;;;;;;;;;wBAqBgB,yBAAyB"}
@@ -0,0 +1,31 @@
1
+ import { docxExtractor } from "./docx-extractor.js";
2
+ import { htmlExtractor } from "./html-extractor.js";
3
+ import { markdownExtractor } from "./markdown-extractor.js";
4
+ import { pdfExtractor } from "./pdf-extractor.js";
5
+ import { textExtractor } from "./text-extractor.js";
6
+ import { xlsxExtractor } from "./xlsx-extractor.js";
7
+ import { ExtractorRegistry } from "../extractor-registry.js";
8
+ //#region src/extractors/index.ts
9
+ /**
10
+ * Provides a batteries-included registry so most consumers can start
11
+ * extracting immediately without manual format registration. Custom
12
+ * registries are still supported for apps that need to override or
13
+ * limit the built-in set.
14
+ */
15
+ function createDefaultRegistry() {
16
+ const registry = new ExtractorRegistry();
17
+ registry.registerByPattern("*.md", markdownExtractor);
18
+ registry.registerByPattern("*.markdown", markdownExtractor);
19
+ registry.registerByPattern("*.txt", textExtractor);
20
+ registry.registerByPattern("*.html", htmlExtractor);
21
+ registry.registerByPattern("*.htm", htmlExtractor);
22
+ registry.registerByPattern("*.pdf", pdfExtractor);
23
+ registry.registerByPattern("*.docx", docxExtractor);
24
+ registry.registerByPattern("*.docm", docxExtractor);
25
+ registry.registerByPattern("*.xlsx", xlsxExtractor);
26
+ return registry;
27
+ }
28
+ //#endregion
29
+ export { createDefaultRegistry, docxExtractor, htmlExtractor, markdownExtractor, pdfExtractor, textExtractor, xlsxExtractor };
30
+
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/extractors/index.ts"],"sourcesContent":["export { docxExtractor } from \"./docx-extractor.js\";\nexport { htmlExtractor } from \"./html-extractor.js\";\nexport { markdownExtractor } from \"./markdown-extractor.js\";\nexport { pdfExtractor } from \"./pdf-extractor.js\";\nexport { textExtractor } from \"./text-extractor.js\";\nexport { xlsxExtractor } from \"./xlsx-extractor.js\";\n\nimport { ExtractorRegistry } from \"../extractor-registry.js\";\nimport { docxExtractor } from \"./docx-extractor.js\";\nimport { htmlExtractor } from \"./html-extractor.js\";\nimport { markdownExtractor } from \"./markdown-extractor.js\";\nimport { pdfExtractor } from \"./pdf-extractor.js\";\nimport { textExtractor } from \"./text-extractor.js\";\nimport { xlsxExtractor } from \"./xlsx-extractor.js\";\n\n/**\n * Provides a batteries-included registry so most consumers can start\n * extracting immediately without manual format registration. Custom\n * registries are still supported for apps that need to override or\n * limit the built-in set.\n */\nexport function createDefaultRegistry(): ExtractorRegistry {\n const registry = new ExtractorRegistry();\n registry.registerByPattern(\"*.md\", markdownExtractor);\n registry.registerByPattern(\"*.markdown\", markdownExtractor);\n registry.registerByPattern(\"*.txt\", textExtractor);\n registry.registerByPattern(\"*.html\", htmlExtractor);\n registry.registerByPattern(\"*.htm\", htmlExtractor);\n registry.registerByPattern(\"*.pdf\", pdfExtractor);\n registry.registerByPattern(\"*.docx\", docxExtractor);\n registry.registerByPattern(\"*.docm\", docxExtractor);\n registry.registerByPattern(\"*.xlsx\", xlsxExtractor);\n return registry;\n}\n"],"mappings":";;;;;;;;;;;;;;AAqBA,SAAgB,wBAA2C;CACzD,MAAM,WAAW,IAAI,kBAAkB;CACvC,SAAS,kBAAkB,QAAQ,iBAAiB;CACpD,SAAS,kBAAkB,cAAc,iBAAiB;CAC1D,SAAS,kBAAkB,SAAS,aAAa;CACjD,SAAS,kBAAkB,UAAU,aAAa;CAClD,SAAS,kBAAkB,SAAS,aAAa;CACjD,SAAS,kBAAkB,SAAS,YAAY;CAChD,SAAS,kBAAkB,UAAU,aAAa;CAClD,SAAS,kBAAkB,UAAU,aAAa;CAClD,SAAS,kBAAkB,UAAU,aAAa;CAClD,OAAO;AACT"}
@@ -0,0 +1,11 @@
1
+ import { ContentExtractor } from "../types.js";
2
+ //#region src/extractors/markdown-extractor.d.ts
3
+ /**
4
+ * Passthrough extractor for markdown files. Functionally identical to
5
+ * `textExtractor` but registered under its own extension patterns so
6
+ * the registry can distinguish `.md` from `.txt` -- allowing future
7
+ * markdown-specific processing without breaking existing registrations.
8
+ */
9
+ export declare const markdownExtractor: ContentExtractor;
10
+ //#endregion
11
+ //# sourceMappingURL=markdown-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-extractor.d.ts","names":[],"sources":["../../src/extractors/markdown-extractor.ts"],"mappings":";;;;;;;;qBASa,mBAAmB"}
@@ -0,0 +1,15 @@
1
+ import { collectText } from "../collect-bytes.js";
2
+ //#region src/extractors/markdown-extractor.ts
3
+ /**
4
+ * Passthrough extractor for markdown files. Functionally identical to
5
+ * `textExtractor` but registered under its own extension patterns so
6
+ * the registry can distinguish `.md` from `.txt` -- allowing future
7
+ * markdown-specific processing without breaking existing registrations.
8
+ */
9
+ const markdownExtractor = async (content) => {
10
+ return collectText(content);
11
+ };
12
+ //#endregion
13
+ export { markdownExtractor };
14
+
15
+ //# sourceMappingURL=markdown-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-extractor.js","names":[],"sources":["../../src/extractors/markdown-extractor.ts"],"sourcesContent":["import { collectText } from \"../collect-bytes.js\";\nimport type { ContentExtractor } from \"../types.js\";\n\n/**\n * Passthrough extractor for markdown files. Functionally identical to\n * `textExtractor` but registered under its own extension patterns so\n * the registry can distinguish `.md` from `.txt` -- allowing future\n * markdown-specific processing without breaking existing registrations.\n */\nexport const markdownExtractor: ContentExtractor = async (content) => {\n return collectText(content);\n};\n"],"mappings":";;;;;;;;AASA,MAAa,oBAAsC,OAAO,YAAY;CACpE,OAAO,YAAY,OAAO;AAC5B"}
@@ -0,0 +1,10 @@
1
+ import { ContentExtractor } from "../types.js";
2
+ //#region src/extractors/pdf-extractor.d.ts
3
+ /**
4
+ * Extracts PDF content page-by-page, formatting each page as a markdown
5
+ * section with a `## Page N` header. This preserves page boundaries in
6
+ * the indexed content, making search results more precise.
7
+ */
8
+ export declare const pdfExtractor: ContentExtractor;
9
+ //#endregion
10
+ //# sourceMappingURL=pdf-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf-extractor.d.ts","names":[],"sources":["../../src/extractors/pdf-extractor.ts"],"mappings":";;;;;;;qBASa,cAAc"}
@@ -0,0 +1,22 @@
1
+ import { collectBytes } from "../collect-bytes.js";
2
+ import { extractText } from "unpdf";
3
+ //#region src/extractors/pdf-extractor.ts
4
+ /**
5
+ * Extracts PDF content page-by-page, formatting each page as a markdown
6
+ * section with a `## Page N` header. This preserves page boundaries in
7
+ * the indexed content, making search results more precise.
8
+ */
9
+ const pdfExtractor = async (content) => {
10
+ const bytes = await collectBytes(content);
11
+ const { text: pages } = await extractText(bytes);
12
+ const sections = [];
13
+ for (let i = 0; i < pages.length; i++) {
14
+ const pageText = pages[i]?.trim();
15
+ if (pageText) sections.push(`## Page ${i + 1}\n\n${pageText}`);
16
+ }
17
+ return sections.join("\n\n");
18
+ };
19
+ //#endregion
20
+ export { pdfExtractor };
21
+
22
+ //# sourceMappingURL=pdf-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf-extractor.js","names":[],"sources":["../../src/extractors/pdf-extractor.ts"],"sourcesContent":["import { extractText } from \"unpdf\";\nimport { collectBytes } from \"../collect-bytes.js\";\nimport type { ContentExtractor } from \"../types.js\";\n\n/**\n * Extracts PDF content page-by-page, formatting each page as a markdown\n * section with a `## Page N` header. This preserves page boundaries in\n * the indexed content, making search results more precise.\n */\nexport const pdfExtractor: ContentExtractor = async (content) => {\n const bytes = await collectBytes(content);\n const { text: pages } = await extractText(bytes);\n\n const sections: string[] = [];\n for (let i = 0; i < pages.length; i++) {\n const pageText = pages[i]?.trim();\n if (pageText) {\n sections.push(`## Page ${i + 1}\\n\\n${pageText}`);\n }\n }\n\n return sections.join(\"\\n\\n\");\n};\n"],"mappings":";;;;;;;;AASA,MAAa,eAAiC,OAAO,YAAY;CAC/D,MAAM,QAAQ,MAAM,aAAa,OAAO;CACxC,MAAM,EAAE,MAAM,UAAU,MAAM,YAAY,KAAK;CAE/C,MAAM,WAAqB,CAAC;CAC5B,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,WAAW,MAAM,EAAE,EAAE,KAAK;EAChC,IAAI,UACF,SAAS,KAAK,WAAW,IAAI,EAAE,MAAM,UAAU;CAEnD;CAEA,OAAO,SAAS,KAAK,MAAM;AAC7B"}
@@ -0,0 +1,10 @@
1
+ import { ContentExtractor } from "../types.js";
2
+ //#region src/extractors/text-extractor.d.ts
3
+ /**
4
+ * Identity extractor for plain text -- no conversion needed, just
5
+ * decode bytes to a string. Exists as a distinct entry so `.txt` files
6
+ * route through the same pipeline as every other format.
7
+ */
8
+ export declare const textExtractor: ContentExtractor;
9
+ //#endregion
10
+ //# sourceMappingURL=text-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-extractor.d.ts","names":[],"sources":["../../src/extractors/text-extractor.ts"],"mappings":";;;;;;;qBAQa,eAAe"}
@@ -0,0 +1,14 @@
1
+ import { collectText } from "../collect-bytes.js";
2
+ //#region src/extractors/text-extractor.ts
3
+ /**
4
+ * Identity extractor for plain text -- no conversion needed, just
5
+ * decode bytes to a string. Exists as a distinct entry so `.txt` files
6
+ * route through the same pipeline as every other format.
7
+ */
8
+ const textExtractor = async (content) => {
9
+ return collectText(content);
10
+ };
11
+ //#endregion
12
+ export { textExtractor };
13
+
14
+ //# sourceMappingURL=text-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-extractor.js","names":[],"sources":["../../src/extractors/text-extractor.ts"],"sourcesContent":["import { collectText } from \"../collect-bytes.js\";\nimport type { ContentExtractor } from \"../types.js\";\n\n/**\n * Identity extractor for plain text -- no conversion needed, just\n * decode bytes to a string. Exists as a distinct entry so `.txt` files\n * route through the same pipeline as every other format.\n */\nexport const textExtractor: ContentExtractor = async (content) => {\n return collectText(content);\n};\n"],"mappings":";;;;;;;AAQA,MAAa,gBAAkC,OAAO,YAAY;CAChE,OAAO,YAAY,OAAO;AAC5B"}
@@ -0,0 +1,11 @@
1
+ import { ContentExtractor } from "../types.js";
2
+ //#region src/extractors/xlsx-extractor.d.ts
3
+ /**
4
+ * Converts Excel spreadsheets into markdown tables so the content
5
+ * is searchable and consumable by text-based pipelines. Each worksheet
6
+ * becomes a separate section with a level-2 heading. Empty sheets are
7
+ * skipped to avoid noise.
8
+ */
9
+ export declare const xlsxExtractor: ContentExtractor;
10
+ //#endregion
11
+ //# sourceMappingURL=xlsx-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xlsx-extractor.d.ts","names":[],"sources":["../../src/extractors/xlsx-extractor.ts"],"mappings":";;;;;;;;qBAUa,eAAe"}
@@ -0,0 +1,49 @@
1
+ import { collectBytes } from "../collect-bytes.js";
2
+ import ExcelJS from "exceljs";
3
+ //#region src/extractors/xlsx-extractor.ts
4
+ /**
5
+ * Converts Excel spreadsheets into markdown tables so the content
6
+ * is searchable and consumable by text-based pipelines. Each worksheet
7
+ * becomes a separate section with a level-2 heading. Empty sheets are
8
+ * skipped to avoid noise.
9
+ */
10
+ const xlsxExtractor = async (content) => {
11
+ const bytes = await collectBytes(content);
12
+ const workbook = new ExcelJS.Workbook();
13
+ const arrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
14
+ await workbook.xlsx.load(arrayBuffer);
15
+ const sections = [];
16
+ workbook.eachSheet((sheet) => {
17
+ const rows = [];
18
+ sheet.eachRow((row) => {
19
+ const cells = [];
20
+ row.eachCell({ includeEmpty: true }, (cell) => {
21
+ try {
22
+ const v = cell.value;
23
+ cells.push(v == null ? "" : String(v));
24
+ } catch {
25
+ cells.push("");
26
+ }
27
+ });
28
+ rows.push(cells);
29
+ });
30
+ if (rows.length === 0) return;
31
+ const colCount = Math.max(...rows.map((r) => r.length));
32
+ const [headers, ...dataRows] = rows.map((r) => {
33
+ while (r.length < colCount) r.push("");
34
+ return r;
35
+ });
36
+ if (!headers) return;
37
+ const table = [
38
+ `| ${headers.join(" | ")} |`,
39
+ `| ${headers.map(() => "---").join(" | ")} |`,
40
+ ...dataRows.map((r) => `| ${r.join(" | ")} |`)
41
+ ].join("\n");
42
+ sections.push(`## ${sheet.name}\n\n${table}`);
43
+ });
44
+ return sections.join("\n\n");
45
+ };
46
+ //#endregion
47
+ export { xlsxExtractor };
48
+
49
+ //# sourceMappingURL=xlsx-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xlsx-extractor.js","names":[],"sources":["../../src/extractors/xlsx-extractor.ts"],"sourcesContent":["import ExcelJS from \"exceljs\";\nimport { collectBytes } from \"../collect-bytes.js\";\nimport type { ContentExtractor } from \"../types.js\";\n\n/**\n * Converts Excel spreadsheets into markdown tables so the content\n * is searchable and consumable by text-based pipelines. Each worksheet\n * becomes a separate section with a level-2 heading. Empty sheets are\n * skipped to avoid noise.\n */\nexport const xlsxExtractor: ContentExtractor = async (content) => {\n const bytes = await collectBytes(content);\n const workbook = new ExcelJS.Workbook();\n const arrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);\n await workbook.xlsx.load(arrayBuffer as ArrayBuffer);\n\n const sections: string[] = [];\n\n workbook.eachSheet((sheet) => {\n const rows: string[][] = [];\n\n sheet.eachRow((row) => {\n const cells: string[] = [];\n row.eachCell({ includeEmpty: true }, (cell) => {\n try {\n const v = cell.value;\n cells.push(v == null ? \"\" : String(v));\n } catch {\n cells.push(\"\");\n }\n });\n rows.push(cells);\n });\n\n if (rows.length === 0) return;\n\n // Normalize column count to the widest row\n const colCount = Math.max(...rows.map((r) => r.length));\n const padded = rows.map((r) => {\n while (r.length < colCount) r.push(\"\");\n return r;\n });\n\n // First row as headers, rest as data\n const [headers, ...dataRows] = padded;\n if (!headers) return;\n\n const headerLine = `| ${headers.join(\" | \")} |`;\n const separator = `| ${headers.map(() => \"---\").join(\" | \")} |`;\n const bodyLines = dataRows.map((r) => `| ${r.join(\" | \")} |`);\n\n const table = [headerLine, separator, ...bodyLines].join(\"\\n\");\n sections.push(`## ${sheet.name}\\n\\n${table}`);\n });\n\n return sections.join(\"\\n\\n\");\n};\n"],"mappings":";;;;;;;;;AAUA,MAAa,gBAAkC,OAAO,YAAY;CAChE,MAAM,QAAQ,MAAM,aAAa,OAAO;CACxC,MAAM,WAAW,IAAI,QAAQ,SAAS;CACtC,MAAM,cAAc,MAAM,OAAO,MAAM,MAAM,YAAY,MAAM,aAAa,MAAM,UAAU;CAC5F,MAAM,SAAS,KAAK,KAAK,WAA0B;CAEnD,MAAM,WAAqB,CAAC;CAE5B,SAAS,WAAW,UAAU;EAC5B,MAAM,OAAmB,CAAC;EAE1B,MAAM,SAAS,QAAQ;GACrB,MAAM,QAAkB,CAAC;GACzB,IAAI,SAAS,EAAE,cAAc,KAAK,IAAI,SAAS;IAC7C,IAAI;KACF,MAAM,IAAI,KAAK;KACf,MAAM,KAAK,KAAK,OAAO,KAAK,OAAO,CAAC,CAAC;IACvC,QAAQ;KACN,MAAM,KAAK,EAAE;IACf;GACF,CAAC;GACD,KAAK,KAAK,KAAK;EACjB,CAAC;EAED,IAAI,KAAK,WAAW,GAAG;EAGvB,MAAM,WAAW,KAAK,IAAI,GAAG,KAAK,KAAK,MAAM,EAAE,MAAM,CAAC;EAOtD,MAAM,CAAC,SAAS,GAAG,YANJ,KAAK,KAAK,MAAM;GAC7B,OAAO,EAAE,SAAS,UAAU,EAAE,KAAK,EAAE;GACrC,OAAO;EACT,CAGoC;EACpC,IAAI,CAAC,SAAS;EAMd,MAAM,QAAQ;GAAC,KAJS,QAAQ,KAAK,KAAK,EAAE;GAIjB,KAHJ,QAAQ,UAAU,KAAK,CAAC,CAAC,KAAK,KAAK,EAAE;GAGtB,GAFpB,SAAS,KAAK,MAAM,KAAK,EAAE,KAAK,KAAK,EAAE,GAER;EAAC,CAAC,CAAC,KAAK,IAAI;EAC7D,SAAS,KAAK,MAAM,MAAM,KAAK,MAAM,OAAO;CAC9C,CAAC;CAED,OAAO,SAAS,KAAK,MAAM;AAC7B"}
@@ -0,0 +1,10 @@
1
+ //#region src/html-to-markdown.d.ts
2
+ /**
3
+ * Normalizes HTML into markdown so downstream consumers get a uniform
4
+ * text format regardless of whether the source was HTML, DOCX (via
5
+ * mammoth's HTML output), or any other HTML-producing extractor.
6
+ * Uses Turndown with GFM tables and strikethrough support.
7
+ */
8
+ export declare function htmlToMarkdown(html: string): string;
9
+ //#endregion
10
+ //# sourceMappingURL=html-to-markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-to-markdown.d.ts","names":[],"sources":["../src/html-to-markdown.ts"],"mappings":";;;;;;;wBAUgB,eAAe"}
@@ -0,0 +1,25 @@
1
+ import { gfm } from "@joplin/turndown-plugin-gfm";
2
+ import TurndownService from "turndown";
3
+ //#region src/html-to-markdown.ts
4
+ /**
5
+ * Normalizes HTML into markdown so downstream consumers get a uniform
6
+ * text format regardless of whether the source was HTML, DOCX (via
7
+ * mammoth's HTML output), or any other HTML-producing extractor.
8
+ * Uses Turndown with GFM tables and strikethrough support.
9
+ */
10
+ function htmlToMarkdown(html) {
11
+ const turndownService = new TurndownService({
12
+ headingStyle: "atx",
13
+ hr: "---",
14
+ bulletListMarker: "*",
15
+ codeBlockStyle: "fenced",
16
+ emDelimiter: "*",
17
+ strongDelimiter: "**"
18
+ });
19
+ turndownService.use(gfm);
20
+ return turndownService.turndown(html);
21
+ }
22
+ //#endregion
23
+ export { htmlToMarkdown };
24
+
25
+ //# sourceMappingURL=html-to-markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-to-markdown.js","names":[],"sources":["../src/html-to-markdown.ts"],"sourcesContent":["/// <reference path=\"./turndown-plugin-gfm.d.ts\" />\nimport { gfm } from \"@joplin/turndown-plugin-gfm\";\nimport TurndownService from \"turndown\";\n\n/**\n * Normalizes HTML into markdown so downstream consumers get a uniform\n * text format regardless of whether the source was HTML, DOCX (via\n * mammoth's HTML output), or any other HTML-producing extractor.\n * Uses Turndown with GFM tables and strikethrough support.\n */\nexport function htmlToMarkdown(html: string): string {\n const turndownService = new TurndownService({\n headingStyle: \"atx\",\n hr: \"---\",\n bulletListMarker: \"*\",\n codeBlockStyle: \"fenced\",\n emDelimiter: \"*\",\n strongDelimiter: \"**\",\n });\n turndownService.use(gfm);\n return turndownService.turndown(html);\n}\n"],"mappings":";;;;;;;;;AAUA,SAAgB,eAAe,MAAsB;CACnD,MAAM,kBAAkB,IAAI,gBAAgB;EAC1C,cAAc;EACd,IAAI;EACJ,kBAAkB;EAClB,gBAAgB;EAChB,aAAa;EACb,iBAAiB;CACnB,CAAC;CACD,gBAAgB,IAAI,GAAG;CACvB,OAAO,gBAAgB,SAAS,IAAI;AACtC"}
@@ -0,0 +1,14 @@
1
+ import { ContentExtractor, ContentNormalizer } from "./types.js";
2
+ import { docxExtractor } from "./extractors/docx-extractor.js";
3
+ import { htmlExtractor } from "./extractors/html-extractor.js";
4
+ import { markdownExtractor } from "./extractors/markdown-extractor.js";
5
+ import { pdfExtractor } from "./extractors/pdf-extractor.js";
6
+ import { textExtractor } from "./extractors/text-extractor.js";
7
+ import { xlsxExtractor } from "./extractors/xlsx-extractor.js";
8
+ import { ExtractorRegistry } from "./extractor-registry.js";
9
+ import { createDefaultRegistry } from "./extractors/index.js";
10
+ import { collectBytes, collectText } from "./collect-bytes.js";
11
+ import { htmlToMarkdown } from "./html-to-markdown.js";
12
+ import { markdownToHtml } from "./markdown-to-html.js";
13
+ import { getMimeType } from "./mime-utils.js";
14
+ export { ContentExtractor, ContentNormalizer, ExtractorRegistry, collectBytes, collectText, createDefaultRegistry, docxExtractor, getMimeType, htmlExtractor, htmlToMarkdown, markdownExtractor, markdownToHtml, pdfExtractor, textExtractor, xlsxExtractor };