@statewalker/content-extractors 0.2.2 → 0.3.0
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/README.md +105 -10
- package/dist/collect-bytes.d.ts +10 -2
- package/dist/collect-bytes.d.ts.map +1 -1
- package/dist/collect-bytes.js +6 -4
- package/dist/collect-bytes.js.map +1 -1
- package/dist/extractor-registry.d.ts +2 -1
- package/dist/extractor-registry.d.ts.map +1 -1
- package/dist/extractor-registry.js +3 -2
- package/dist/extractor-registry.js.map +1 -1
- package/dist/extractors/docx-extractor.d.ts +5 -1
- package/dist/extractors/docx-extractor.d.ts.map +1 -1
- package/dist/extractors/docx-extractor.js +20 -11
- package/dist/extractors/docx-extractor.js.map +1 -1
- package/dist/extractors/html-extractor.d.ts +3 -0
- package/dist/extractors/html-extractor.d.ts.map +1 -1
- package/dist/extractors/html-extractor.js +8 -5
- package/dist/extractors/html-extractor.js.map +1 -1
- package/dist/extractors/index.d.ts +12 -9
- package/dist/extractors/index.d.ts.map +1 -1
- package/dist/extractors/index.js +23 -18
- package/dist/extractors/index.js.map +1 -1
- package/dist/extractors/markdown-extractor.d.ts +3 -0
- package/dist/extractors/markdown-extractor.d.ts.map +1 -1
- package/dist/extractors/markdown-extractor.js +8 -4
- package/dist/extractors/markdown-extractor.js.map +1 -1
- package/dist/extractors/pdf-extractor.d.ts +3 -0
- package/dist/extractors/pdf-extractor.d.ts.map +1 -1
- package/dist/extractors/pdf-extractor.js +17 -11
- package/dist/extractors/pdf-extractor.js.map +1 -1
- package/dist/extractors/text-extractor.d.ts +3 -0
- package/dist/extractors/text-extractor.d.ts.map +1 -1
- package/dist/extractors/text-extractor.js +8 -4
- package/dist/extractors/text-extractor.js.map +1 -1
- package/dist/extractors/xlsx-extractor.d.ts +5 -1
- package/dist/extractors/xlsx-extractor.d.ts.map +1 -1
- package/dist/extractors/xlsx-extractor.js +56 -36
- package/dist/extractors/xlsx-extractor.js.map +1 -1
- package/dist/html-to-markdown.d.ts +3 -1
- package/dist/html-to-markdown.d.ts.map +1 -1
- package/dist/html-to-markdown.js +9 -1
- package/dist/html-to-markdown.js.map +1 -1
- package/dist/index.d.ts +11 -9
- package/dist/index.js +9 -7
- package/dist/limits.d.ts +20 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +9 -0
- package/dist/limits.js.map +1 -0
- package/dist/markdown-to-html.d.ts +11 -3
- package/dist/markdown-to-html.d.ts.map +1 -1
- package/dist/markdown-to-html.js +13 -6
- package/dist/markdown-to-html.js.map +1 -1
- package/dist/mime-utils.js +3 -2
- package/dist/mime-utils.js.map +1 -1
- package/dist/zip-size.d.ts +16 -0
- package/dist/zip-size.d.ts.map +1 -0
- package/dist/zip-size.js +90 -0
- package/dist/zip-size.js.map +1 -0
- package/package.json +8 -4
- package/src/collect-bytes.ts +17 -2
- package/src/extractor-registry.ts +3 -2
- package/src/extractors/docx-extractor.ts +26 -11
- package/src/extractors/html-extractor.ts +8 -4
- package/src/extractors/index.ts +29 -23
- package/src/extractors/markdown-extractor.ts +8 -3
- package/src/extractors/pdf-extractor.ts +20 -11
- package/src/extractors/text-extractor.ts +8 -3
- package/src/extractors/xlsx-extractor.ts +72 -41
- package/src/html-to-markdown.ts +4 -1
- package/src/index.ts +2 -0
- package/src/limits.ts +20 -0
- package/src/markdown-to-html.ts +16 -10
- package/src/mime-utils.ts +3 -2
- package/src/zip-size.ts +113 -0
package/README.md
CHANGED
|
@@ -1,26 +1,121 @@
|
|
|
1
1
|
# @statewalker/content-extractors
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## What it is
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Turns files into Markdown text for indexing. Each extractor takes the file bytes as an iterable of `Uint8Array` chunks and returns text: PDF (page by page), DOCX (via HTML), XLSX (one Markdown table per sheet), HTML, Markdown and plain text. An `ExtractorRegistry` picks the extractor from the file name, with an optional MIME-type fallback.
|
|
6
|
+
|
|
7
|
+
## Why it exists
|
|
8
|
+
|
|
9
|
+
An indexer needs text, while documents arrive as PDF, Office files or HTML. Each format needs a different parser; this package wraps them behind one function type, `ContentExtractor`, so an ingestion pipeline can route any file by name without knowing the parsers. Producing Markdown keeps headings and tables, which `@statewalker/indexer-chunker` then uses as cut points.
|
|
10
|
+
|
|
11
|
+
## How to use
|
|
6
12
|
|
|
7
13
|
```sh
|
|
8
14
|
pnpm add @statewalker/content-extractors
|
|
9
15
|
```
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
| Import | Gives |
|
|
18
|
+
| --- | --- |
|
|
19
|
+
| `@statewalker/content-extractors` | Everything below. |
|
|
20
|
+
| `@statewalker/content-extractors/extractors` | The extractors and `createDefaultRegistry` only. |
|
|
21
|
+
| `@statewalker/content-extractors/types` | `ContentExtractor`, `ContentNormalizer` (types only). |
|
|
22
|
+
|
|
23
|
+
- `createDefaultRegistry(limits?)` — registry for `*.md`, `*.markdown`, `*.txt`, `*.html`, `*.htm`, `*.pdf`, `*.docx`, `*.docm`, `*.xlsx`; `limits` (`{ maxBytes?, maxUncompressedBytes? }`) applies to every extractor in it.
|
|
24
|
+
- `ExtractorRegistry` — `registerByPattern(pattern, extractor)`, `registerByMime(mime, extractor)`, `getByPath(path)`, `getByMime(mime)`, `get(path, mime?)`.
|
|
25
|
+
- Extractors with the default limits: `pdfExtractor`, `docxExtractor`, `xlsxExtractor`, `htmlExtractor`, `markdownExtractor`, `textExtractor`.
|
|
26
|
+
- Extractor factories with your own limits: `createPdfExtractor({ maxBytes? })`, `createDocxExtractor({ maxBytes?, maxUncompressedBytes? })`, `createXlsxExtractor({ maxBytes?, maxUncompressedBytes? })`, `createHtmlExtractor({ maxBytes? })`, `createMarkdownExtractor({ maxBytes? })`, `createTextExtractor({ maxBytes? })`.
|
|
27
|
+
- Limits: `DEFAULT_MAX_BYTES` (100 MiB), `DEFAULT_MAX_UNCOMPRESSED_BYTES` (500 MiB), types `ExtractorLimits`, `ZipExtractorLimits`.
|
|
28
|
+
- Helpers: `htmlToMarkdown(html)`, `markdownToHtml(markdown, { html? })`, `getMimeType(path)`, `collectBytes(chunks, { maxBytes? })`, `collectText(chunks, { maxBytes? })`, `zipUncompressedSize(bytes)`, `assertZipUncompressedSize(bytes, maxBytes)`.
|
|
29
|
+
|
|
30
|
+
## Examples
|
|
31
|
+
|
|
32
|
+
Extract a file by name:
|
|
12
33
|
|
|
13
34
|
```ts
|
|
35
|
+
import { readFile } from "node:fs/promises";
|
|
14
36
|
import { createDefaultRegistry } from "@statewalker/content-extractors";
|
|
15
37
|
|
|
16
38
|
const registry = createDefaultRegistry();
|
|
17
|
-
const
|
|
18
|
-
|
|
39
|
+
const extract = registry.get("report.pdf");
|
|
40
|
+
if (!extract) throw new Error("unsupported file type");
|
|
41
|
+
const markdown = (await extract([await readFile("report.pdf")])) as string;
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Streamed input works the same way (`AsyncIterable<Uint8Array>`, for example a `fetch` body):
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
const response = await fetch(url);
|
|
48
|
+
const extract = registry.get(url, response.headers.get("content-type") ?? undefined);
|
|
49
|
+
const text = await extract?.(response.body as AsyncIterable<Uint8Array>);
|
|
19
50
|
```
|
|
20
51
|
|
|
21
|
-
|
|
52
|
+
Route files without an extension by MIME type:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { createDefaultRegistry, htmlExtractor, pdfExtractor } from "@statewalker/content-extractors";
|
|
56
|
+
|
|
57
|
+
const registry = createDefaultRegistry();
|
|
58
|
+
registry.registerByMime("application/pdf", pdfExtractor);
|
|
59
|
+
registry.registerByMime("text/html", htmlExtractor);
|
|
60
|
+
registry.get("upload-1234", "application/pdf"); // pdfExtractor
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Change the size limits (see [Input size limits](#input-size-limits)):
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { createDefaultRegistry, createXlsxExtractor } from "@statewalker/content-extractors";
|
|
67
|
+
|
|
68
|
+
const registry = createDefaultRegistry({ maxBytes: 20 * 1024 * 1024 }); // 20 MiB per file
|
|
69
|
+
registry.registerByPattern("*.xlsx", createXlsxExtractor({ maxUncompressedBytes: 2 * 1024 ** 3 }));
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Helpers:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { getMimeType, htmlToMarkdown, markdownToHtml } from "@statewalker/content-extractors";
|
|
76
|
+
|
|
77
|
+
getMimeType("a.PDF"); // "application/pdf"
|
|
78
|
+
htmlToMarkdown("<h1>T</h1>"); // "# T"
|
|
79
|
+
htmlToMarkdown("<p>hi</p><script>alert(1)</script>"); // "hi": script, style, noscript, template are dropped
|
|
80
|
+
markdownToHtml("**b**"); // "<p><strong>b</strong></p>\n"
|
|
81
|
+
markdownToHtml("<b>x</b>"); // "<p><b>x</b></p>\n": raw HTML is escaped unless { html: true }
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Internals
|
|
85
|
+
|
|
86
|
+
### What each format produces
|
|
87
|
+
|
|
88
|
+
| Format | Parser | Output |
|
|
89
|
+
| --- | --- | --- |
|
|
90
|
+
| PDF | `unpdf` | `## Page N` section per non-empty page |
|
|
91
|
+
| DOCX, DOCM | `mammoth` to HTML, then `htmlToMarkdown` | Markdown with headings, lists, tables |
|
|
92
|
+
| XLSX | `exceljs` | `## <sheet name>` and a Markdown table per sheet; first row is the header; pipes in cells escaped, line breaks as spaces |
|
|
93
|
+
| HTML | `turndown` + GFM plugin | ATX headings, fenced code, GFM tables; `<script>`, `<style>`, `<noscript>`, `<template>` dropped |
|
|
94
|
+
| Markdown, text | none | UTF-8 decoded text as-is |
|
|
95
|
+
|
|
96
|
+
### Input size limits
|
|
97
|
+
|
|
98
|
+
Every built-in extractor reads at most `maxBytes` of input (default `DEFAULT_MAX_BYTES`, 100 MiB) and throws `Input exceeds the limit of N bytes` beyond it; reading stops as soon as the limit is passed, so an endless stream is not buffered. The DOCX, DOCM and XLSX extractors also read the ZIP central directory before handing the archive to mammoth or exceljs, add up the declared uncompressed sizes, and throw `Archive uncompressed size … exceeds the limit …` when the sum is over `maxUncompressedBytes` (default `DEFAULT_MAX_UNCOMPRESSED_BYTES`, 500 MiB). This refuses a small "zip bomb" before it is inflated. Bytes that are not a readable ZIP throw `Invalid ZIP archive: …`.
|
|
99
|
+
|
|
100
|
+
Pass limits to `createDefaultRegistry(limits)` or to a `create*Extractor(limits)` factory; `Infinity` turns a limit off. `collectBytes` and `collectText` have no limit unless `maxBytes` is given.
|
|
101
|
+
|
|
102
|
+
The uncompressed check trusts the sizes the archive declares. An archive that lies about them is still caught by JSZip (inside mammoth and exceljs), which compares the inflated size with the declared one, but only after inflating that entry.
|
|
103
|
+
|
|
104
|
+
### Things that surprise
|
|
105
|
+
|
|
106
|
+
- **The default registry has no MIME routes.** `createDefaultRegistry().get("upload-1234", "application/pdf")` returns `undefined`; register MIME types yourself as shown above.
|
|
107
|
+
- **Path matching is by suffix, longest first.** `*.test.html` beats `*.html`. Matching is case-insensitive on both the file name and the pattern (`*.PDF` matches `report.pdf`), and only the part after the last `/` is used. `getMimeType` also looks only after the last `/`: `notes.md/LICENSE` has no extension.
|
|
108
|
+
- **XLSX cells are flattened to one line.** A `|` becomes `\|` and each line break (CR, LF, CRLF) becomes one space, so a cell never adds a column or splits a row.
|
|
109
|
+
- **XLSX formula and rich-text cells come out as `[object Object]`**, and dates as `Date.toString()` in the local time zone. Plain numbers and strings are fine.
|
|
110
|
+
- **`ContentExtractor` returns `Promise<string | unknown>`.** All built-in extractors return a string; cast or check before use.
|
|
111
|
+
- **`markdownToHtml` escapes raw HTML by default.** Extracted files often come from untrusted uploads, so `<script>` or `<img onerror>` in them is shown as text. `{ html: true }` passes raw HTML through; use it only for trusted input, or sanitise the output before rendering it.
|
|
112
|
+
- **Everything is read into memory.** PDF, DOCX and XLSX parsers need one contiguous buffer, so `collectBytes` joins the chunks first, up to the `maxBytes` limit.
|
|
113
|
+
- `ContentNormalizer` is only an interface: a slot for a post-processing step (for example an LLM clean-up) that this package does not implement.
|
|
114
|
+
|
|
115
|
+
### Dependencies
|
|
116
|
+
|
|
117
|
+
`unpdf` (PDF text), `mammoth` (DOCX to HTML), `exceljs` (XLSX), `turndown`, `@joplin/turndown-plugin-gfm` and `@types/turndown` (HTML to Markdown), `markdown-it` (Markdown to HTML).
|
|
118
|
+
|
|
119
|
+
## License
|
|
22
120
|
|
|
23
|
-
|
|
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.
|
|
121
|
+
MIT
|
package/dist/collect-bytes.d.ts
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
//#region src/collect-bytes.d.ts
|
|
2
|
+
/** Options for {@link collectBytes} and {@link collectText}. */
|
|
3
|
+
export interface CollectOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Largest input accepted, in bytes. Reading stops and an error is thrown as soon as the total
|
|
6
|
+
* exceeds it, so an oversized or endless stream is never held in memory. No limit when omitted.
|
|
7
|
+
*/
|
|
8
|
+
maxBytes?: number;
|
|
9
|
+
}
|
|
2
10
|
/**
|
|
3
11
|
* Bridges the streaming world (chunked iterables from fetch, file reads,
|
|
4
12
|
* etc.) with libraries that require a single contiguous buffer (pdfjs-dist,
|
|
5
13
|
* mammoth). Returns the original chunk when only one arrives, avoiding
|
|
6
14
|
* an extra copy in the common single-read case.
|
|
7
15
|
*/
|
|
8
|
-
export declare function collectBytes(content: AsyncIterable<Uint8Array> | Iterable<Uint8Array
|
|
16
|
+
export declare function collectBytes(content: AsyncIterable<Uint8Array> | Iterable<Uint8Array>, options?: CollectOptions): Promise<Uint8Array>;
|
|
9
17
|
/**
|
|
10
18
|
* Shorthand for text-based extractors (plain text, markdown, HTML) that
|
|
11
19
|
* need the full content as a string. Avoids duplicating the
|
|
12
20
|
* collect-then-decode pattern across every text extractor.
|
|
13
21
|
*/
|
|
14
|
-
export declare function collectText(content: AsyncIterable<Uint8Array> | Iterable<Uint8Array
|
|
22
|
+
export declare function collectText(content: AsyncIterable<Uint8Array> | Iterable<Uint8Array>, options?: CollectOptions): Promise<string>;
|
|
15
23
|
//#endregion
|
|
16
24
|
//# sourceMappingURL=collect-bytes.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collect-bytes.d.ts","names":[],"sources":["../src/collect-bytes.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"collect-bytes.d.ts","names":[],"sources":["../src/collect-bytes.ts"],"mappings":";;iBACiB;;;;;EAKf;;;;;;;;wBASoB,aACpB,SAAS,cAAc,cAAc,SAAS,aAC9C,UAAS,iBACR,QAAQ;;;;;;wBA6BW,YACpB,SAAS,cAAc,cAAc,SAAS,aAC9C,UAAS,iBACR"}
|
package/dist/collect-bytes.js
CHANGED
|
@@ -5,12 +5,14 @@
|
|
|
5
5
|
* mammoth). Returns the original chunk when only one arrives, avoiding
|
|
6
6
|
* an extra copy in the common single-read case.
|
|
7
7
|
*/
|
|
8
|
-
async function collectBytes(content) {
|
|
8
|
+
async function collectBytes(content, options = {}) {
|
|
9
|
+
const { maxBytes = Number.POSITIVE_INFINITY } = options;
|
|
9
10
|
const chunks = [];
|
|
10
11
|
let totalLength = 0;
|
|
11
12
|
for await (const chunk of content) {
|
|
12
|
-
chunks.push(chunk);
|
|
13
13
|
totalLength += chunk.length;
|
|
14
|
+
if (totalLength > maxBytes) throw new Error(`Input exceeds the limit of ${maxBytes} bytes`);
|
|
15
|
+
chunks.push(chunk);
|
|
14
16
|
}
|
|
15
17
|
const first = chunks[0];
|
|
16
18
|
if (chunks.length === 1 && first) return first;
|
|
@@ -27,8 +29,8 @@ async function collectBytes(content) {
|
|
|
27
29
|
* need the full content as a string. Avoids duplicating the
|
|
28
30
|
* collect-then-decode pattern across every text extractor.
|
|
29
31
|
*/
|
|
30
|
-
async function collectText(content) {
|
|
31
|
-
const bytes = await collectBytes(content);
|
|
32
|
+
async function collectText(content, options = {}) {
|
|
33
|
+
const bytes = await collectBytes(content, options);
|
|
32
34
|
return new TextDecoder().decode(bytes);
|
|
33
35
|
}
|
|
34
36
|
//#endregion
|
|
@@ -1 +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
|
|
1
|
+
{"version":3,"file":"collect-bytes.js","names":[],"sources":["../src/collect-bytes.ts"],"sourcesContent":["/** Options for {@link collectBytes} and {@link collectText}. */\nexport interface CollectOptions {\n /**\n * Largest input accepted, in bytes. Reading stops and an error is thrown as soon as the total\n * exceeds it, so an oversized or endless stream is never held in memory. No limit when omitted.\n */\n maxBytes?: number;\n}\n\n/**\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 options: CollectOptions = {},\n): Promise<Uint8Array> {\n const { maxBytes = Number.POSITIVE_INFINITY } = options;\n const chunks: Uint8Array[] = [];\n let totalLength = 0;\n for await (const chunk of content) {\n totalLength += chunk.length;\n if (totalLength > maxBytes) {\n throw new Error(`Input exceeds the limit of ${maxBytes} bytes`);\n }\n chunks.push(chunk);\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 options: CollectOptions = {},\n): Promise<string> {\n const bytes = await collectBytes(content, options);\n return new TextDecoder().decode(bytes);\n}\n"],"mappings":";;;;;;;AAeA,eAAsB,aACpB,SACA,UAA0B,CAAC,GACN;CACrB,MAAM,EAAE,WAAW,OAAO,sBAAsB;CAChD,MAAM,SAAuB,CAAC;CAC9B,IAAI,cAAc;CAClB,WAAW,MAAM,SAAS,SAAS;EACjC,eAAe,MAAM;EACrB,IAAI,cAAc,UAChB,MAAM,IAAI,MAAM,8BAA8B,SAAS,OAAO;EAEhE,OAAO,KAAK,KAAK;CACnB;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,SACA,UAA0B,CAAC,GACV;CACjB,MAAM,QAAQ,MAAM,aAAa,SAAS,OAAO;CACjD,OAAO,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK;AACvC"}
|
|
@@ -12,7 +12,8 @@ export declare class ExtractorRegistry {
|
|
|
12
12
|
private mimeMap;
|
|
13
13
|
/**
|
|
14
14
|
* Associates a suffix pattern with an extractor so the registry can
|
|
15
|
-
* route files to the right handler based on their filename.
|
|
15
|
+
* route files to the right handler based on their filename. Patterns are
|
|
16
|
+
* case-insensitive, like the file names they are matched against.
|
|
16
17
|
*/
|
|
17
18
|
registerByPattern(pattern: string, extractor: ContentExtractor): void;
|
|
18
19
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractor-registry.d.ts","names":[],"sources":["../src/extractor-registry.ts"],"mappings":";;;;;;;;;qBASa;UACH;UACA
|
|
1
|
+
{"version":3,"file":"extractor-registry.d.ts","names":[],"sources":["../src/extractor-registry.ts"],"mappings":";;;;;;;;;qBASa;UACH;UACA;;;;;;EAOR,kBAAkB,iBAAiB,WAAW;;;;;EAQ9C,eAAe,kBAAkB,WAAW;;;;;EAQ5C,UAAU,eAAe;;EAoBzB,UAAU,mBAAmB;;;;;;EAS7B,IAAI,cAAc,oBAAoB"}
|
|
@@ -11,10 +11,11 @@ var ExtractorRegistry = class {
|
|
|
11
11
|
mimeMap = /* @__PURE__ */ new Map();
|
|
12
12
|
/**
|
|
13
13
|
* Associates a suffix pattern with an extractor so the registry can
|
|
14
|
-
* route files to the right handler based on their filename.
|
|
14
|
+
* route files to the right handler based on their filename. Patterns are
|
|
15
|
+
* case-insensitive, like the file names they are matched against.
|
|
15
16
|
*/
|
|
16
17
|
registerByPattern(pattern, extractor) {
|
|
17
|
-
this.patternMap.set(pattern, extractor);
|
|
18
|
+
this.patternMap.set(pattern.toLowerCase(), extractor);
|
|
18
19
|
}
|
|
19
20
|
/**
|
|
20
21
|
* Provides a fallback route for files that lack a recognizable extension
|
|
@@ -1 +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
|
|
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. Patterns are\n * case-insensitive, like the file names they are matched against.\n */\n registerByPattern(pattern: string, extractor: ContentExtractor): void {\n this.patternMap.set(pattern.toLowerCase(), 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;;;;;;CAOpD,kBAAkB,SAAiB,WAAmC;EACpE,KAAK,WAAW,IAAI,QAAQ,YAAY,GAAG,SAAS;CACtD;;;;;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"}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
+
import { ZipExtractorLimits } from "../limits.js";
|
|
1
2
|
import { ContentExtractor } from "../types.js";
|
|
2
3
|
//#region src/extractors/docx-extractor.d.ts
|
|
3
4
|
/**
|
|
4
5
|
* Unlocks Word document content for text-based pipelines via a two-stage
|
|
5
6
|
* conversion (DOCX -> HTML -> markdown). Supplies both `buffer` and
|
|
6
7
|
* `arrayBuffer` to mammoth so the same code runs in Node.js and browsers
|
|
7
|
-
* without environment detection.
|
|
8
|
+
* without environment detection. The input size and the archive's declared
|
|
9
|
+
* uncompressed size are checked before mammoth inflates it.
|
|
8
10
|
*/
|
|
11
|
+
export declare function createDocxExtractor(limits?: ZipExtractorLimits): ContentExtractor;
|
|
12
|
+
/** DOCX/DOCM extractor with the default limits. */
|
|
9
13
|
export declare const docxExtractor: ContentExtractor;
|
|
10
14
|
//#endregion
|
|
11
15
|
//# sourceMappingURL=docx-extractor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docx-extractor.d.ts","names":[],"sources":["../../src/extractors/docx-extractor.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"docx-extractor.d.ts","names":[],"sources":["../../src/extractors/docx-extractor.ts"],"mappings":";;;;;;;;;;wBAkBgB,oBAAoB,SAAQ,qBAA0B;;qBAiBzD,eAAe"}
|
|
@@ -1,23 +1,32 @@
|
|
|
1
1
|
import { collectBytes } from "../collect-bytes.js";
|
|
2
2
|
import { htmlToMarkdown } from "../html-to-markdown.js";
|
|
3
|
+
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_UNCOMPRESSED_BYTES } from "../limits.js";
|
|
4
|
+
import { assertZipUncompressedSize } from "../zip-size.js";
|
|
3
5
|
import mammoth from "mammoth";
|
|
4
6
|
//#region src/extractors/docx-extractor.ts
|
|
5
7
|
/**
|
|
6
8
|
* Unlocks Word document content for text-based pipelines via a two-stage
|
|
7
9
|
* conversion (DOCX -> HTML -> markdown). Supplies both `buffer` and
|
|
8
10
|
* `arrayBuffer` to mammoth so the same code runs in Node.js and browsers
|
|
9
|
-
* without environment detection.
|
|
11
|
+
* without environment detection. The input size and the archive's declared
|
|
12
|
+
* uncompressed size are checked before mammoth inflates it.
|
|
10
13
|
*/
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
arrayBuffer
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
function createDocxExtractor(limits = {}) {
|
|
15
|
+
const { maxBytes = DEFAULT_MAX_BYTES, maxUncompressedBytes = DEFAULT_MAX_UNCOMPRESSED_BYTES } = limits;
|
|
16
|
+
return async (content) => {
|
|
17
|
+
const bytes = await collectBytes(content, { maxBytes });
|
|
18
|
+
assertZipUncompressedSize(bytes, maxUncompressedBytes);
|
|
19
|
+
const arrayBuffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
20
|
+
const result = await mammoth.convertToHtml({
|
|
21
|
+
buffer: arrayBuffer,
|
|
22
|
+
arrayBuffer
|
|
23
|
+
});
|
|
24
|
+
return htmlToMarkdown(result.value);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/** DOCX/DOCM extractor with the default limits. */
|
|
28
|
+
const docxExtractor = createDocxExtractor();
|
|
20
29
|
//#endregion
|
|
21
|
-
export { docxExtractor };
|
|
30
|
+
export { createDocxExtractor, docxExtractor };
|
|
22
31
|
|
|
23
32
|
//# sourceMappingURL=docx-extractor.js.map
|
|
@@ -1 +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
|
|
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 {\n DEFAULT_MAX_BYTES,\n DEFAULT_MAX_UNCOMPRESSED_BYTES,\n type ZipExtractorLimits,\n} from \"../limits.js\";\nimport type { ContentExtractor } from \"../types.js\";\nimport { assertZipUncompressedSize } from \"../zip-size.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. The input size and the archive's declared\n * uncompressed size are checked before mammoth inflates it.\n */\nexport function createDocxExtractor(limits: ZipExtractorLimits = {}): ContentExtractor {\n const { maxBytes = DEFAULT_MAX_BYTES, maxUncompressedBytes = DEFAULT_MAX_UNCOMPRESSED_BYTES } =\n limits;\n return async (content) => {\n const bytes = await collectBytes(content, { maxBytes });\n assertZipUncompressedSize(bytes, maxUncompressedBytes);\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}\n\n/** DOCX/DOCM extractor with the default limits. */\nexport const docxExtractor: ContentExtractor = createDocxExtractor();\n"],"mappings":";;;;;;;;;;;;;AAkBA,SAAgB,oBAAoB,SAA6B,CAAC,GAAqB;CACrF,MAAM,EAAE,WAAW,mBAAmB,uBAAuB,mCAC3D;CACF,OAAO,OAAO,YAAY;EACxB,MAAM,QAAQ,MAAM,aAAa,SAAS,EAAE,SAAS,CAAC;EACtD,0BAA0B,OAAO,oBAAoB;EACrD,MAAM,cAAc,MAAM,OAAO,MAAM,MAAM,YAAY,MAAM,aAAa,MAAM,UAAU;EAE5F,MAAM,SAAS,MAAM,QAAQ,cAAc;GACzC,QAAQ;GACR;EACF,CAAgD;EAChD,OAAO,eAAe,OAAO,KAAK;CACpC;AACF;;AAGA,MAAa,gBAAkC,oBAAoB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ExtractorLimits } from "../limits.js";
|
|
1
2
|
import { ContentExtractor } from "../types.js";
|
|
2
3
|
//#region src/extractors/html-extractor.d.ts
|
|
3
4
|
/**
|
|
@@ -5,6 +6,8 @@ import { ContentExtractor } from "../types.js";
|
|
|
5
6
|
* text format. Delegates to `htmlToMarkdown` for the actual conversion,
|
|
6
7
|
* keeping this extractor focused on the bytes-to-string bridging step.
|
|
7
8
|
*/
|
|
9
|
+
export declare function createHtmlExtractor(limits?: ExtractorLimits): ContentExtractor;
|
|
10
|
+
/** HTML extractor with the default limits. */
|
|
8
11
|
export declare const htmlExtractor: ContentExtractor;
|
|
9
12
|
//#endregion
|
|
10
13
|
//# sourceMappingURL=html-extractor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-extractor.d.ts","names":[],"sources":["../../src/extractors/html-extractor.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"html-extractor.d.ts","names":[],"sources":["../../src/extractors/html-extractor.ts"],"mappings":";;;;;;;;wBAUgB,oBAAoB,SAAQ,kBAAuB;;qBAMtD,eAAe"}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { collectText } from "../collect-bytes.js";
|
|
2
2
|
import { htmlToMarkdown } from "../html-to-markdown.js";
|
|
3
|
+
import { DEFAULT_MAX_BYTES } from "../limits.js";
|
|
3
4
|
//#region src/extractors/html-extractor.ts
|
|
4
5
|
/**
|
|
5
6
|
* Converts HTML files to markdown so the pipeline outputs a uniform
|
|
6
7
|
* text format. Delegates to `htmlToMarkdown` for the actual conversion,
|
|
7
8
|
* keeping this extractor focused on the bytes-to-string bridging step.
|
|
8
9
|
*/
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
return htmlToMarkdown(
|
|
12
|
-
}
|
|
10
|
+
function createHtmlExtractor(limits = {}) {
|
|
11
|
+
const { maxBytes = DEFAULT_MAX_BYTES } = limits;
|
|
12
|
+
return async (content) => htmlToMarkdown(await collectText(content, { maxBytes }));
|
|
13
|
+
}
|
|
14
|
+
/** HTML extractor with the default limits. */
|
|
15
|
+
const htmlExtractor = createHtmlExtractor();
|
|
13
16
|
//#endregion
|
|
14
|
-
export { htmlExtractor };
|
|
17
|
+
export { createHtmlExtractor, htmlExtractor };
|
|
15
18
|
|
|
16
19
|
//# sourceMappingURL=html-extractor.js.map
|
|
@@ -1 +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
|
|
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 { DEFAULT_MAX_BYTES, type ExtractorLimits } from \"../limits.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 function createHtmlExtractor(limits: ExtractorLimits = {}): ContentExtractor {\n const { maxBytes = DEFAULT_MAX_BYTES } = limits;\n return async (content) => htmlToMarkdown(await collectText(content, { maxBytes }));\n}\n\n/** HTML extractor with the default limits. */\nexport const htmlExtractor: ContentExtractor = createHtmlExtractor();\n"],"mappings":";;;;;;;;;AAUA,SAAgB,oBAAoB,SAA0B,CAAC,GAAqB;CAClF,MAAM,EAAE,WAAW,sBAAsB;CACzC,OAAO,OAAO,YAAY,eAAe,MAAM,YAAY,SAAS,EAAE,SAAS,CAAC,CAAC;AACnF;;AAGA,MAAa,gBAAkC,oBAAoB"}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { ZipExtractorLimits } from "../limits.js";
|
|
2
|
+
import { createDocxExtractor, docxExtractor } from "./docx-extractor.js";
|
|
3
|
+
import { createHtmlExtractor, htmlExtractor } from "./html-extractor.js";
|
|
4
|
+
import { createMarkdownExtractor, markdownExtractor } from "./markdown-extractor.js";
|
|
5
|
+
import { createPdfExtractor, pdfExtractor } from "./pdf-extractor.js";
|
|
6
|
+
import { createTextExtractor, textExtractor } from "./text-extractor.js";
|
|
7
|
+
import { createXlsxExtractor, xlsxExtractor } from "./xlsx-extractor.js";
|
|
7
8
|
import { ExtractorRegistry } from "../extractor-registry.js";
|
|
8
9
|
//#region src/extractors/index.d.ts
|
|
9
10
|
/**
|
|
10
11
|
* Provides a batteries-included registry so most consumers can start
|
|
11
12
|
* extracting immediately without manual format registration. Custom
|
|
12
13
|
* registries are still supported for apps that need to override or
|
|
13
|
-
* limit the built-in set.
|
|
14
|
+
* limit the built-in set. `limits` applies to every registered extractor
|
|
15
|
+
* (`maxUncompressedBytes` only to DOCX, DOCM and XLSX); omitted limits
|
|
16
|
+
* take the defaults.
|
|
14
17
|
*/
|
|
15
|
-
export declare function createDefaultRegistry(): ExtractorRegistry;
|
|
18
|
+
export declare function createDefaultRegistry(limits?: ZipExtractorLimits): ExtractorRegistry;
|
|
16
19
|
//#endregion
|
|
17
|
-
export { docxExtractor, htmlExtractor, markdownExtractor, pdfExtractor, textExtractor, xlsxExtractor };
|
|
20
|
+
export { createDocxExtractor, createHtmlExtractor, createMarkdownExtractor, createPdfExtractor, createTextExtractor, createXlsxExtractor, docxExtractor, htmlExtractor, markdownExtractor, pdfExtractor, textExtractor, xlsxExtractor };
|
|
18
21
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/extractors/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/extractors/index.ts"],"mappings":";;;;;;;;;;;;;;;;;wBAwBgB,sBAAsB,SAAQ,qBAA0B"}
|
package/dist/extractors/index.js
CHANGED
|
@@ -1,31 +1,36 @@
|
|
|
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";
|
|
1
|
+
import { createDocxExtractor, docxExtractor } from "./docx-extractor.js";
|
|
2
|
+
import { createHtmlExtractor, htmlExtractor } from "./html-extractor.js";
|
|
3
|
+
import { createMarkdownExtractor, markdownExtractor } from "./markdown-extractor.js";
|
|
4
|
+
import { createPdfExtractor, pdfExtractor } from "./pdf-extractor.js";
|
|
5
|
+
import { createTextExtractor, textExtractor } from "./text-extractor.js";
|
|
6
|
+
import { createXlsxExtractor, xlsxExtractor } from "./xlsx-extractor.js";
|
|
7
7
|
import { ExtractorRegistry } from "../extractor-registry.js";
|
|
8
8
|
//#region src/extractors/index.ts
|
|
9
9
|
/**
|
|
10
10
|
* Provides a batteries-included registry so most consumers can start
|
|
11
11
|
* extracting immediately without manual format registration. Custom
|
|
12
12
|
* registries are still supported for apps that need to override or
|
|
13
|
-
* limit the built-in set.
|
|
13
|
+
* limit the built-in set. `limits` applies to every registered extractor
|
|
14
|
+
* (`maxUncompressedBytes` only to DOCX, DOCM and XLSX); omitted limits
|
|
15
|
+
* take the defaults.
|
|
14
16
|
*/
|
|
15
|
-
function createDefaultRegistry() {
|
|
17
|
+
function createDefaultRegistry(limits = {}) {
|
|
18
|
+
const markdown = createMarkdownExtractor(limits);
|
|
19
|
+
const html = createHtmlExtractor(limits);
|
|
20
|
+
const docx = createDocxExtractor(limits);
|
|
16
21
|
const registry = new ExtractorRegistry();
|
|
17
|
-
registry.registerByPattern("*.md",
|
|
18
|
-
registry.registerByPattern("*.markdown",
|
|
19
|
-
registry.registerByPattern("*.txt",
|
|
20
|
-
registry.registerByPattern("*.html",
|
|
21
|
-
registry.registerByPattern("*.htm",
|
|
22
|
-
registry.registerByPattern("*.pdf",
|
|
23
|
-
registry.registerByPattern("*.docx",
|
|
24
|
-
registry.registerByPattern("*.docm",
|
|
25
|
-
registry.registerByPattern("*.xlsx",
|
|
22
|
+
registry.registerByPattern("*.md", markdown);
|
|
23
|
+
registry.registerByPattern("*.markdown", markdown);
|
|
24
|
+
registry.registerByPattern("*.txt", createTextExtractor(limits));
|
|
25
|
+
registry.registerByPattern("*.html", html);
|
|
26
|
+
registry.registerByPattern("*.htm", html);
|
|
27
|
+
registry.registerByPattern("*.pdf", createPdfExtractor(limits));
|
|
28
|
+
registry.registerByPattern("*.docx", docx);
|
|
29
|
+
registry.registerByPattern("*.docm", docx);
|
|
30
|
+
registry.registerByPattern("*.xlsx", createXlsxExtractor(limits));
|
|
26
31
|
return registry;
|
|
27
32
|
}
|
|
28
33
|
//#endregion
|
|
29
|
-
export { createDefaultRegistry, docxExtractor, htmlExtractor, markdownExtractor, pdfExtractor, textExtractor, xlsxExtractor };
|
|
34
|
+
export { createDefaultRegistry, createDocxExtractor, createHtmlExtractor, createMarkdownExtractor, createPdfExtractor, createTextExtractor, createXlsxExtractor, docxExtractor, htmlExtractor, markdownExtractor, pdfExtractor, textExtractor, xlsxExtractor };
|
|
30
35
|
|
|
31
36
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +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 {
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/extractors/index.ts"],"sourcesContent":["export { createDocxExtractor, docxExtractor } from \"./docx-extractor.js\";\nexport { createHtmlExtractor, htmlExtractor } from \"./html-extractor.js\";\nexport { createMarkdownExtractor, markdownExtractor } from \"./markdown-extractor.js\";\nexport { createPdfExtractor, pdfExtractor } from \"./pdf-extractor.js\";\nexport { createTextExtractor, textExtractor } from \"./text-extractor.js\";\nexport { createXlsxExtractor, xlsxExtractor } from \"./xlsx-extractor.js\";\n\nimport { ExtractorRegistry } from \"../extractor-registry.js\";\nimport type { ZipExtractorLimits } from \"../limits.js\";\nimport { createDocxExtractor } from \"./docx-extractor.js\";\nimport { createHtmlExtractor } from \"./html-extractor.js\";\nimport { createMarkdownExtractor } from \"./markdown-extractor.js\";\nimport { createPdfExtractor } from \"./pdf-extractor.js\";\nimport { createTextExtractor } from \"./text-extractor.js\";\nimport { createXlsxExtractor } 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. `limits` applies to every registered extractor\n * (`maxUncompressedBytes` only to DOCX, DOCM and XLSX); omitted limits\n * take the defaults.\n */\nexport function createDefaultRegistry(limits: ZipExtractorLimits = {}): ExtractorRegistry {\n const markdown = createMarkdownExtractor(limits);\n const html = createHtmlExtractor(limits);\n const docx = createDocxExtractor(limits);\n const registry = new ExtractorRegistry();\n registry.registerByPattern(\"*.md\", markdown);\n registry.registerByPattern(\"*.markdown\", markdown);\n registry.registerByPattern(\"*.txt\", createTextExtractor(limits));\n registry.registerByPattern(\"*.html\", html);\n registry.registerByPattern(\"*.htm\", html);\n registry.registerByPattern(\"*.pdf\", createPdfExtractor(limits));\n registry.registerByPattern(\"*.docx\", docx);\n registry.registerByPattern(\"*.docm\", docx);\n registry.registerByPattern(\"*.xlsx\", createXlsxExtractor(limits));\n return registry;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAwBA,SAAgB,sBAAsB,SAA6B,CAAC,GAAsB;CACxF,MAAM,WAAW,wBAAwB,MAAM;CAC/C,MAAM,OAAO,oBAAoB,MAAM;CACvC,MAAM,OAAO,oBAAoB,MAAM;CACvC,MAAM,WAAW,IAAI,kBAAkB;CACvC,SAAS,kBAAkB,QAAQ,QAAQ;CAC3C,SAAS,kBAAkB,cAAc,QAAQ;CACjD,SAAS,kBAAkB,SAAS,oBAAoB,MAAM,CAAC;CAC/D,SAAS,kBAAkB,UAAU,IAAI;CACzC,SAAS,kBAAkB,SAAS,IAAI;CACxC,SAAS,kBAAkB,SAAS,mBAAmB,MAAM,CAAC;CAC9D,SAAS,kBAAkB,UAAU,IAAI;CACzC,SAAS,kBAAkB,UAAU,IAAI;CACzC,SAAS,kBAAkB,UAAU,oBAAoB,MAAM,CAAC;CAChE,OAAO;AACT"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ExtractorLimits } from "../limits.js";
|
|
1
2
|
import { ContentExtractor } from "../types.js";
|
|
2
3
|
//#region src/extractors/markdown-extractor.d.ts
|
|
3
4
|
/**
|
|
@@ -6,6 +7,8 @@ import { ContentExtractor } from "../types.js";
|
|
|
6
7
|
* the registry can distinguish `.md` from `.txt` -- allowing future
|
|
7
8
|
* markdown-specific processing without breaking existing registrations.
|
|
8
9
|
*/
|
|
10
|
+
export declare function createMarkdownExtractor(limits?: ExtractorLimits): ContentExtractor;
|
|
11
|
+
/** Markdown extractor with the default limits. */
|
|
9
12
|
export declare const markdownExtractor: ContentExtractor;
|
|
10
13
|
//#endregion
|
|
11
14
|
//# sourceMappingURL=markdown-extractor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown-extractor.d.ts","names":[],"sources":["../../src/extractors/markdown-extractor.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"markdown-extractor.d.ts","names":[],"sources":["../../src/extractors/markdown-extractor.ts"],"mappings":";;;;;;;;;wBAUgB,wBAAwB,SAAQ,kBAAuB;;qBAM1D,mBAAmB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { collectText } from "../collect-bytes.js";
|
|
2
|
+
import { DEFAULT_MAX_BYTES } from "../limits.js";
|
|
2
3
|
//#region src/extractors/markdown-extractor.ts
|
|
3
4
|
/**
|
|
4
5
|
* Passthrough extractor for markdown files. Functionally identical to
|
|
@@ -6,10 +7,13 @@ import { collectText } from "../collect-bytes.js";
|
|
|
6
7
|
* the registry can distinguish `.md` from `.txt` -- allowing future
|
|
7
8
|
* markdown-specific processing without breaking existing registrations.
|
|
8
9
|
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
};
|
|
10
|
+
function createMarkdownExtractor(limits = {}) {
|
|
11
|
+
const { maxBytes = DEFAULT_MAX_BYTES } = limits;
|
|
12
|
+
return (content) => collectText(content, { maxBytes });
|
|
13
|
+
}
|
|
14
|
+
/** Markdown extractor with the default limits. */
|
|
15
|
+
const markdownExtractor = createMarkdownExtractor();
|
|
12
16
|
//#endregion
|
|
13
|
-
export { markdownExtractor };
|
|
17
|
+
export { createMarkdownExtractor, markdownExtractor };
|
|
14
18
|
|
|
15
19
|
//# sourceMappingURL=markdown-extractor.js.map
|
|
@@ -1 +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
|
|
1
|
+
{"version":3,"file":"markdown-extractor.js","names":[],"sources":["../../src/extractors/markdown-extractor.ts"],"sourcesContent":["import { collectText } from \"../collect-bytes.js\";\nimport { DEFAULT_MAX_BYTES, type ExtractorLimits } from \"../limits.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 function createMarkdownExtractor(limits: ExtractorLimits = {}): ContentExtractor {\n const { maxBytes = DEFAULT_MAX_BYTES } = limits;\n return (content) => collectText(content, { maxBytes });\n}\n\n/** Markdown extractor with the default limits. */\nexport const markdownExtractor: ContentExtractor = createMarkdownExtractor();\n"],"mappings":";;;;;;;;;AAUA,SAAgB,wBAAwB,SAA0B,CAAC,GAAqB;CACtF,MAAM,EAAE,WAAW,sBAAsB;CACzC,QAAQ,YAAY,YAAY,SAAS,EAAE,SAAS,CAAC;AACvD;;AAGA,MAAa,oBAAsC,wBAAwB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ExtractorLimits } from "../limits.js";
|
|
1
2
|
import { ContentExtractor } from "../types.js";
|
|
2
3
|
//#region src/extractors/pdf-extractor.d.ts
|
|
3
4
|
/**
|
|
@@ -5,6 +6,8 @@ import { ContentExtractor } from "../types.js";
|
|
|
5
6
|
* section with a `## Page N` header. This preserves page boundaries in
|
|
6
7
|
* the indexed content, making search results more precise.
|
|
7
8
|
*/
|
|
9
|
+
export declare function createPdfExtractor(limits?: ExtractorLimits): ContentExtractor;
|
|
10
|
+
/** PDF extractor with the default limits. */
|
|
8
11
|
export declare const pdfExtractor: ContentExtractor;
|
|
9
12
|
//#endregion
|
|
10
13
|
//# sourceMappingURL=pdf-extractor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pdf-extractor.d.ts","names":[],"sources":["../../src/extractors/pdf-extractor.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"pdf-extractor.d.ts","names":[],"sources":["../../src/extractors/pdf-extractor.ts"],"mappings":";;;;;;;;wBAUgB,mBAAmB,SAAQ,kBAAuB;;qBAqBrD,cAAc"}
|