ai-document-parser 0.1.101
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/LICENSE +21 -0
- package/LICENSES.md +26 -0
- package/README.md +106 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +124 -0
- package/dist/cli.js.map +1 -0
- package/dist/convert/converter.d.ts +7 -0
- package/dist/convert/converter.d.ts.map +1 -0
- package/dist/convert/converter.js +201 -0
- package/dist/convert/converter.js.map +1 -0
- package/dist/convert/emit.d.ts +15 -0
- package/dist/convert/emit.d.ts.map +1 -0
- package/dist/convert/emit.js +95 -0
- package/dist/convert/emit.js.map +1 -0
- package/dist/convert/index.d.ts +2 -0
- package/dist/convert/index.d.ts.map +1 -0
- package/dist/convert/index.js +2 -0
- package/dist/convert/index.js.map +1 -0
- package/dist/edit/docx-ooxml.d.ts +13 -0
- package/dist/edit/docx-ooxml.d.ts.map +1 -0
- package/dist/edit/docx-ooxml.js +182 -0
- package/dist/edit/docx-ooxml.js.map +1 -0
- package/dist/edit/index.d.ts +8 -0
- package/dist/edit/index.d.ts.map +1 -0
- package/dist/edit/index.js +26 -0
- package/dist/edit/index.js.map +1 -0
- package/dist/edit/spreadsheet.d.ts +19 -0
- package/dist/edit/spreadsheet.d.ts.map +1 -0
- package/dist/edit/spreadsheet.js +123 -0
- package/dist/edit/spreadsheet.js.map +1 -0
- package/dist/fonts/DejaVuSans.ttf +0 -0
- package/dist/fonts/LICENSE-DejaVu.txt +2 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/parse/detect.d.ts +19 -0
- package/dist/parse/detect.d.ts.map +1 -0
- package/dist/parse/detect.js +109 -0
- package/dist/parse/detect.js.map +1 -0
- package/dist/parse/formats.d.ts +14 -0
- package/dist/parse/formats.d.ts.map +1 -0
- package/dist/parse/formats.js +23 -0
- package/dist/parse/formats.js.map +1 -0
- package/dist/parse/index.d.ts +4 -0
- package/dist/parse/index.d.ts.map +1 -0
- package/dist/parse/index.js +4 -0
- package/dist/parse/index.js.map +1 -0
- package/dist/parse/legacy-doc.d.ts +15 -0
- package/dist/parse/legacy-doc.d.ts.map +1 -0
- package/dist/parse/legacy-doc.js +100 -0
- package/dist/parse/legacy-doc.js.map +1 -0
- package/dist/parse/pdf.d.ts +8 -0
- package/dist/parse/pdf.d.ts.map +1 -0
- package/dist/parse/pdf.js +34 -0
- package/dist/parse/pdf.js.map +1 -0
- package/dist/parse/pptx.d.ts +7 -0
- package/dist/parse/pptx.d.ts.map +1 -0
- package/dist/parse/pptx.js +107 -0
- package/dist/parse/pptx.js.map +1 -0
- package/dist/parse/router.d.ts +7 -0
- package/dist/parse/router.d.ts.map +1 -0
- package/dist/parse/router.js +286 -0
- package/dist/parse/router.js.map +1 -0
- package/dist/parse/text-formats.d.ts +19 -0
- package/dist/parse/text-formats.d.ts.map +1 -0
- package/dist/parse/text-formats.js +82 -0
- package/dist/parse/text-formats.js.map +1 -0
- package/dist/types.d.ts +105 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/errors.d.ts +8 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +17 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/paths.d.ts +4 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +20 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/text.d.ts +5 -0
- package/dist/utils/text.d.ts.map +1 -0
- package/dist/utils/text.js +16 -0
- package/dist/utils/text.js.map +1 -0
- package/dist/write/docx.d.ts +4 -0
- package/dist/write/docx.d.ts.map +1 -0
- package/dist/write/docx.js +31 -0
- package/dist/write/docx.js.map +1 -0
- package/dist/write/index.d.ts +9 -0
- package/dist/write/index.d.ts.map +1 -0
- package/dist/write/index.js +38 -0
- package/dist/write/index.js.map +1 -0
- package/dist/write/pdf.d.ts +4 -0
- package/dist/write/pdf.d.ts.map +1 -0
- package/dist/write/pdf.js +70 -0
- package/dist/write/pdf.js.map +1 -0
- package/dist/write/spreadsheet.d.ts +2 -0
- package/dist/write/spreadsheet.d.ts.map +1 -0
- package/dist/write/spreadsheet.js +2 -0
- package/dist/write/spreadsheet.js.map +1 -0
- package/fonts/DejaVuSans.ttf +0 -0
- package/fonts/LICENSE-DejaVu.txt +2 -0
- package/package.json +88 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clean-room rules for contributors (also summarized in AGENTS.md):
|
|
3
|
+
*
|
|
4
|
+
* 1. Implement parsers/converters from public format specs and public API behavior
|
|
5
|
+
* (tests + docs/API.md) — do not copy code from historical derived engines.
|
|
6
|
+
* 2. Prefer extending src/edit, src/write, src/parse over large opaque backends.
|
|
7
|
+
* 3. New format support lands behind parseDocument / convertDocument only.
|
|
8
|
+
*/
|
|
9
|
+
/** Normalized format ids returned by detect / parseDocument. */
|
|
10
|
+
export const CORE_PARSE_FORMATS = [
|
|
11
|
+
'docx',
|
|
12
|
+
'xlsx',
|
|
13
|
+
'xls',
|
|
14
|
+
'pdf',
|
|
15
|
+
'md',
|
|
16
|
+
'html',
|
|
17
|
+
'csv',
|
|
18
|
+
'doc',
|
|
19
|
+
'pptx',
|
|
20
|
+
];
|
|
21
|
+
export const CORE_PARSE_FORMAT_SET = new Set(CORE_PARSE_FORMATS);
|
|
22
|
+
export const CORE_FORMATS_HELP = 'docx, xlsx, xls, pptx, pdf, md, html, csv, legacy doc';
|
|
23
|
+
//# sourceMappingURL=formats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formats.js","sourceRoot":"","sources":["../../src/parse/formats.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,gEAAgE;AAChE,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,IAAI;IACJ,MAAM;IACN,KAAK;IACL,KAAK;IACL,MAAM;CACE,CAAC;AAIX,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAS,kBAAkB,CAAC,CAAC;AAEzE,MAAM,CAAC,MAAM,iBAAiB,GAC5B,uDAAuD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parse/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parse/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,kBAAkB,EAClB,4BAA4B,GAC7B,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare function readLegacyDocBuffer(buf: Buffer): Promise<{
|
|
2
|
+
text: string;
|
|
3
|
+
paragraphs: string[];
|
|
4
|
+
source: 'ai-document-parser-doc-binary';
|
|
5
|
+
}>;
|
|
6
|
+
export declare function readLegacyDoc(filePath: string): Promise<{
|
|
7
|
+
text: string;
|
|
8
|
+
paragraphs: string[];
|
|
9
|
+
source: 'ai-document-parser-doc-binary';
|
|
10
|
+
}>;
|
|
11
|
+
export declare function convertDocToDocx(docPath: string, docxPath?: string): Promise<{
|
|
12
|
+
docxPath: string;
|
|
13
|
+
paragraphCount: number;
|
|
14
|
+
}>;
|
|
15
|
+
//# sourceMappingURL=legacy-doc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-doc.d.ts","sourceRoot":"","sources":["../../src/parse/legacy-doc.ts"],"names":[],"mappings":"AAwFA,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,+BAA+B,CAAC;CACzC,CAAC,CAKD;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,+BAA+B,CAAC;CACzC,CAAC,CAGD;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAC,CAavD"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import * as CFB from 'cfb';
|
|
4
|
+
import { DocumentError } from '../utils/errors.js';
|
|
5
|
+
import { writeDocx } from '../write/docx.js';
|
|
6
|
+
const MIN_STRING_LEN = 3;
|
|
7
|
+
function extractUtf16Strings(buf, minChars = MIN_STRING_LEN) {
|
|
8
|
+
const out = [];
|
|
9
|
+
let i = 0;
|
|
10
|
+
while (i < buf.length - 1) {
|
|
11
|
+
const chars = [];
|
|
12
|
+
const start = i;
|
|
13
|
+
while (i < buf.length - 1) {
|
|
14
|
+
const code = buf.readUInt16LE(i);
|
|
15
|
+
const ok = code >= 0x20 &&
|
|
16
|
+
code !== 0x7f &&
|
|
17
|
+
(code < 0xd800 || code > 0xdfff) &&
|
|
18
|
+
code !== 0xfffe &&
|
|
19
|
+
code !== 0xffff;
|
|
20
|
+
if (!ok)
|
|
21
|
+
break;
|
|
22
|
+
chars.push(String.fromCharCode(code));
|
|
23
|
+
i += 2;
|
|
24
|
+
}
|
|
25
|
+
if (chars.length >= minChars) {
|
|
26
|
+
const s = chars.join('').trim();
|
|
27
|
+
if (s && !/^[\x00-\x1f]+$/.test(s))
|
|
28
|
+
out.push(s);
|
|
29
|
+
}
|
|
30
|
+
if (i === start)
|
|
31
|
+
i += 2;
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
function extractAsciiStrings(buf, minLen = MIN_STRING_LEN) {
|
|
36
|
+
const out = [];
|
|
37
|
+
const re = /[\x20-\x7e\u00a0-\u024f]{4,}/g;
|
|
38
|
+
const latin = buf.toString('latin1');
|
|
39
|
+
let m;
|
|
40
|
+
while ((m = re.exec(latin)) !== null) {
|
|
41
|
+
const s = m[0].trim();
|
|
42
|
+
if (s.length >= minLen && !/^W\0o\0r\0d/.test(s))
|
|
43
|
+
out.push(s);
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
function dedupeOrdered(parts) {
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
const result = [];
|
|
50
|
+
for (const p of parts) {
|
|
51
|
+
const key = p.replace(/\s+/g, ' ').trim();
|
|
52
|
+
if (key.length < MIN_STRING_LEN || seen.has(key))
|
|
53
|
+
continue;
|
|
54
|
+
seen.add(key);
|
|
55
|
+
result.push(key);
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
function extractTextFromWordDocument(data) {
|
|
60
|
+
const parts = dedupeOrdered([
|
|
61
|
+
...extractUtf16Strings(data),
|
|
62
|
+
...extractAsciiStrings(data),
|
|
63
|
+
]);
|
|
64
|
+
if (parts.length === 0) {
|
|
65
|
+
throw new DocumentError('PARSE_FAILED', 'Could not extract text from .doc (empty or encrypted file)');
|
|
66
|
+
}
|
|
67
|
+
return parts.join('\n');
|
|
68
|
+
}
|
|
69
|
+
function parseCfbBuffer(buf) {
|
|
70
|
+
const cfb = CFB.read(new Uint8Array(buf), { type: 'array' });
|
|
71
|
+
const entry = CFB.find(cfb, 'WordDocument');
|
|
72
|
+
if (!entry?.content) {
|
|
73
|
+
throw new DocumentError('UNSUPPORTED_FORMAT', 'File is not a Word 97–2003 .doc (missing WordDocument stream)');
|
|
74
|
+
}
|
|
75
|
+
const content = entry.content;
|
|
76
|
+
return Buffer.isBuffer(content)
|
|
77
|
+
? content
|
|
78
|
+
: Buffer.from(content);
|
|
79
|
+
}
|
|
80
|
+
export async function readLegacyDocBuffer(buf) {
|
|
81
|
+
const data = parseCfbBuffer(buf);
|
|
82
|
+
const text = extractTextFromWordDocument(data);
|
|
83
|
+
const paragraphs = text.split(/\n+/).filter((p) => p.trim().length > 0);
|
|
84
|
+
return { text, paragraphs, source: 'ai-document-parser-doc-binary' };
|
|
85
|
+
}
|
|
86
|
+
export async function readLegacyDoc(filePath) {
|
|
87
|
+
const buf = await readFile(filePath);
|
|
88
|
+
return readLegacyDocBuffer(buf);
|
|
89
|
+
}
|
|
90
|
+
export async function convertDocToDocx(docPath, docxPath) {
|
|
91
|
+
const { text } = await readLegacyDoc(docPath);
|
|
92
|
+
const out = docxPath ??
|
|
93
|
+
path.join(path.dirname(docPath), `${path.basename(docPath, path.extname(docPath))}.docx`);
|
|
94
|
+
await writeDocx(out, text);
|
|
95
|
+
return {
|
|
96
|
+
docxPath: out,
|
|
97
|
+
paragraphCount: text.split(/\n+/).filter(Boolean).length,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=legacy-doc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-doc.js","sourceRoot":"","sources":["../../src/parse/legacy-doc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf.d.ts","sourceRoot":"","sources":["../../src/parse/pdf.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,GAAG,MAAM,GACrB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,KAAK,CAAA;CAAE,CAAC,CA4B1C"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { DocumentError, wrapError } from '../utils/errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract plain text from a PDF using pdfjs-dist (public PDF.js API).
|
|
5
|
+
*/
|
|
6
|
+
export async function extractPdfText(input) {
|
|
7
|
+
try {
|
|
8
|
+
const data = typeof input === 'string' ? new Uint8Array(await readFile(input)) : new Uint8Array(input);
|
|
9
|
+
const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs');
|
|
10
|
+
const loadingTask = pdfjs.getDocument({
|
|
11
|
+
data,
|
|
12
|
+
useSystemFonts: true,
|
|
13
|
+
});
|
|
14
|
+
const pdf = await loadingTask.promise;
|
|
15
|
+
const parts = [];
|
|
16
|
+
for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
|
|
17
|
+
const page = await pdf.getPage(pageNum);
|
|
18
|
+
const content = await page.getTextContent();
|
|
19
|
+
const line = content.items
|
|
20
|
+
.map((item) => ('str' in item && typeof item.str === 'string' ? item.str : ''))
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.join(' ');
|
|
23
|
+
if (line.trim())
|
|
24
|
+
parts.push(line);
|
|
25
|
+
}
|
|
26
|
+
return { text: parts.join('\n').trim(), format: 'pdf' };
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
if (err instanceof DocumentError)
|
|
30
|
+
throw err;
|
|
31
|
+
throw wrapError('PARSE_FAILED', 'Failed to parse PDF', err);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=pdf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf.js","sourceRoot":"","sources":["../../src/parse/pdf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE9D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAsB;IAEtB,IAAI,CAAC;QACH,MAAM,IAAI,GACR,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;QAE5F,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,iCAAiC,CAAC,CAAC;QAC9D,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;YACpC,IAAI;YACJ,cAAc,EAAE,IAAI;SACrB,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC;QACtC,MAAM,KAAK,GAAa,EAAE,CAAC;QAE3B,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC;YACzD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK;iBACvB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;iBAC9E,MAAM,CAAC,OAAO,CAAC;iBACf,IAAI,CAAC,GAAG,CAAC,CAAC;YACb,IAAI,IAAI,CAAC,IAAI,EAAE;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAC1D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,aAAa;YAAE,MAAM,GAAG,CAAC;QAC5C,MAAM,SAAS,CAAC,cAAc,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PptxStructured } from '../types.js';
|
|
2
|
+
export declare function readPptxStructured(filePath: string): Promise<PptxStructured>;
|
|
3
|
+
export declare function readPptxStructuredFromBuffer(buf: Buffer): Promise<PptxStructured>;
|
|
4
|
+
/** Flatten slides to paragraphs (for text / convert emit). */
|
|
5
|
+
export declare function pptxToParagraphs(structured: PptxStructured): string[];
|
|
6
|
+
export declare function pptxToText(structured: PptxStructured): string;
|
|
7
|
+
//# sourceMappingURL=pptx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pptx.d.ts","sourceRoot":"","sources":["../../src/parse/pptx.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAmElD,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAQlF;AAED,wBAAsB,4BAA4B,CAChD,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,cAAc,CAAC,CAQzB;AAED,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,cAAc,GAAG,MAAM,EAAE,CAUrE;AAED,wBAAgB,UAAU,CAAC,UAAU,EAAE,cAAc,GAAG,MAAM,CAQ7D"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import JSZip from 'jszip';
|
|
3
|
+
import { DocumentError, wrapError } from '../utils/errors.js';
|
|
4
|
+
function decodeXmlEntities(s) {
|
|
5
|
+
return s
|
|
6
|
+
.replace(/</g, '<')
|
|
7
|
+
.replace(/>/g, '>')
|
|
8
|
+
.replace(/"/g, '"')
|
|
9
|
+
.replace(/'/g, "'")
|
|
10
|
+
.replace(/&/g, '&');
|
|
11
|
+
}
|
|
12
|
+
/** Extract visible text runs from a PPTX slide DrawingML fragment. */
|
|
13
|
+
function extractSlideTexts(xml) {
|
|
14
|
+
const texts = [];
|
|
15
|
+
const paraRegex = /<a:p[\s\S]*?<\/a:p>/g;
|
|
16
|
+
let pm;
|
|
17
|
+
while ((pm = paraRegex.exec(xml)) !== null) {
|
|
18
|
+
const parts = [];
|
|
19
|
+
const tRegex = /<a:t(?:\s[^>]*)?>([^<]*)<\/a:t>/g;
|
|
20
|
+
let tm;
|
|
21
|
+
while ((tm = tRegex.exec(pm[0])) !== null) {
|
|
22
|
+
parts.push(decodeXmlEntities(tm[1]));
|
|
23
|
+
}
|
|
24
|
+
const line = parts.join('').trim();
|
|
25
|
+
if (line)
|
|
26
|
+
texts.push(line);
|
|
27
|
+
}
|
|
28
|
+
// Fallback: any a:t outside well-formed a:p (rare)
|
|
29
|
+
if (texts.length === 0) {
|
|
30
|
+
const tRegex = /<a:t(?:\s[^>]*)?>([^<]*)<\/a:t>/g;
|
|
31
|
+
let tm;
|
|
32
|
+
while ((tm = tRegex.exec(xml)) !== null) {
|
|
33
|
+
const line = decodeXmlEntities(tm[1]).trim();
|
|
34
|
+
if (line)
|
|
35
|
+
texts.push(line);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return texts;
|
|
39
|
+
}
|
|
40
|
+
function listSlidePaths(zip) {
|
|
41
|
+
return Object.keys(zip.files)
|
|
42
|
+
.filter((n) => /^ppt\/slides\/slide\d+\.xml$/i.test(n) && !zip.files[n].dir)
|
|
43
|
+
.sort((a, b) => {
|
|
44
|
+
const na = Number(/slide(\d+)/i.exec(a)?.[1] ?? 0);
|
|
45
|
+
const nb = Number(/slide(\d+)/i.exec(b)?.[1] ?? 0);
|
|
46
|
+
return na - nb;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async function readPptxFromZip(zip) {
|
|
50
|
+
if (!zip.file('ppt/presentation.xml') && listSlidePaths(zip).length === 0) {
|
|
51
|
+
throw new DocumentError('PARSE_FAILED', 'Invalid pptx: missing ppt/presentation.xml / slides');
|
|
52
|
+
}
|
|
53
|
+
const slides = [];
|
|
54
|
+
for (const path of listSlidePaths(zip)) {
|
|
55
|
+
const file = zip.file(path);
|
|
56
|
+
if (!file)
|
|
57
|
+
continue;
|
|
58
|
+
const xml = await file.async('string');
|
|
59
|
+
slides.push(extractSlideTexts(xml));
|
|
60
|
+
}
|
|
61
|
+
return { format: 'pptx', slides };
|
|
62
|
+
}
|
|
63
|
+
export async function readPptxStructured(filePath) {
|
|
64
|
+
try {
|
|
65
|
+
const buf = await readFile(filePath);
|
|
66
|
+
return readPptxStructuredFromBuffer(buf);
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
if (err instanceof DocumentError)
|
|
70
|
+
throw err;
|
|
71
|
+
throw wrapError('PARSE_FAILED', `Failed to parse pptx ${filePath}`, err);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export async function readPptxStructuredFromBuffer(buf) {
|
|
75
|
+
try {
|
|
76
|
+
const zip = await JSZip.loadAsync(buf);
|
|
77
|
+
return readPptxFromZip(zip);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
if (err instanceof DocumentError)
|
|
81
|
+
throw err;
|
|
82
|
+
throw wrapError('PARSE_FAILED', 'Failed to parse pptx buffer', err);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Flatten slides to paragraphs (for text / convert emit). */
|
|
86
|
+
export function pptxToParagraphs(structured) {
|
|
87
|
+
const out = [];
|
|
88
|
+
structured.slides.forEach((texts, i) => {
|
|
89
|
+
if (texts.length === 0) {
|
|
90
|
+
out.push(`Slide ${i + 1}`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
for (const t of texts)
|
|
94
|
+
out.push(t);
|
|
95
|
+
});
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
export function pptxToText(structured) {
|
|
99
|
+
return structured.slides
|
|
100
|
+
.map((texts, i) => {
|
|
101
|
+
const body = texts.join('\n');
|
|
102
|
+
return body ? `## Slide ${i + 1}\n${body}` : `## Slide ${i + 1}`;
|
|
103
|
+
})
|
|
104
|
+
.join('\n\n')
|
|
105
|
+
.trim();
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=pptx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pptx.js","sourceRoot":"","sources":["../../src/parse/pptx.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DocumentInput, DocumentResult, ParseOptions } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parse a document into text, structured JSON (agent edit path), AST, or chunks.
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseDocument(input: DocumentInput, options?: ParseOptions): Promise<DocumentResult>;
|
|
6
|
+
export { convertDocToDocx } from './legacy-doc.js';
|
|
7
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/parse/router.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EACd,YAAY,EACb,MAAM,aAAa,CAAC;AAqErB;;GAEG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,aAAa,EACpB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,cAAc,CAAC,CA8KzB;AA4FD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { DocumentError, wrapError } from '../utils/errors.js';
|
|
2
|
+
import { isPathLike } from '../utils/paths.js';
|
|
3
|
+
import { readLegacyDoc, readLegacyDocBuffer } from './legacy-doc.js';
|
|
4
|
+
import { readDocxStructured, readDocxStructuredFromBuffer, } from '../edit/docx-ooxml.js';
|
|
5
|
+
import { readSpreadsheetStructuredAsync, readSpreadsheetStructuredFromBuffer, spreadsheetToText, } from '../edit/spreadsheet.js';
|
|
6
|
+
import { assertSupportedParse, detectFormatFromBuffer, detectFormatFromText, formatFromExt, isZipBuffer, refineZipFormat, } from './detect.js';
|
|
7
|
+
import { extractPdfText } from './pdf.js';
|
|
8
|
+
import { pptxToParagraphs, pptxToText, readPptxStructured, readPptxStructuredFromBuffer, } from './pptx.js';
|
|
9
|
+
import { parseCsv, parseHtml, parseMarkdown, readTextFile, } from './text-formats.js';
|
|
10
|
+
import { chunkText } from '../convert/emit.js';
|
|
11
|
+
function toBuffer(input) {
|
|
12
|
+
if (typeof input === 'string')
|
|
13
|
+
return null;
|
|
14
|
+
if (Buffer.isBuffer(input))
|
|
15
|
+
return input;
|
|
16
|
+
if (input instanceof ArrayBuffer)
|
|
17
|
+
return Buffer.from(input);
|
|
18
|
+
if (input instanceof Uint8Array)
|
|
19
|
+
return Buffer.from(input);
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
async function resolveFormat(input, buf, filePath) {
|
|
23
|
+
const fromExt = formatFromExt(filePath);
|
|
24
|
+
if (fromExt && fromExt !== 'unknown')
|
|
25
|
+
return fromExt;
|
|
26
|
+
if (buf) {
|
|
27
|
+
const guessed = detectFormatFromBuffer(buf);
|
|
28
|
+
if (guessed === 'docx' && isZipBuffer(buf)) {
|
|
29
|
+
return refineZipFormat(buf);
|
|
30
|
+
}
|
|
31
|
+
if (guessed)
|
|
32
|
+
return guessed;
|
|
33
|
+
}
|
|
34
|
+
if (typeof input === 'string' && !isPathLike(input)) {
|
|
35
|
+
return detectFormatFromText(input);
|
|
36
|
+
}
|
|
37
|
+
throw new DocumentError('UNSUPPORTED_FORMAT', 'Could not detect document format. Pass a path with a known extension.');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Parse a document into text, structured JSON (agent edit path), AST, or chunks.
|
|
41
|
+
*/
|
|
42
|
+
export async function parseDocument(input, options = {}) {
|
|
43
|
+
const output = options.output ?? 'text';
|
|
44
|
+
const buf = toBuffer(input);
|
|
45
|
+
const filePath = typeof input === 'string' && isPathLike(input) ? input : undefined;
|
|
46
|
+
try {
|
|
47
|
+
const format = await resolveFormat(input, buf, filePath);
|
|
48
|
+
assertSupportedParse(format);
|
|
49
|
+
// Legacy .doc
|
|
50
|
+
if (format === 'doc') {
|
|
51
|
+
const legacy = filePath
|
|
52
|
+
? await readLegacyDoc(filePath)
|
|
53
|
+
: await readLegacyDocBuffer(buf);
|
|
54
|
+
if (output === 'structured') {
|
|
55
|
+
const structured = {
|
|
56
|
+
format: 'doc',
|
|
57
|
+
paragraphs: legacy.paragraphs,
|
|
58
|
+
source: legacy.source,
|
|
59
|
+
};
|
|
60
|
+
const text = JSON.stringify(structured, null, 2);
|
|
61
|
+
return {
|
|
62
|
+
format: 'doc',
|
|
63
|
+
text,
|
|
64
|
+
charCount: text.length,
|
|
65
|
+
path: filePath,
|
|
66
|
+
structured,
|
|
67
|
+
warnings: [
|
|
68
|
+
{
|
|
69
|
+
code: 'LEGACY_DOC_LOW_FIDELITY',
|
|
70
|
+
message: 'Legacy .doc extraction is heuristic; formatting is not preserved.',
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return finish(format, legacy.text, filePath, output, {
|
|
76
|
+
paragraphs: legacy.paragraphs,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
// DOCX
|
|
80
|
+
if (format === 'docx') {
|
|
81
|
+
try {
|
|
82
|
+
const structured = filePath
|
|
83
|
+
? await readDocxStructured(filePath)
|
|
84
|
+
: await readDocxStructuredFromBuffer(buf);
|
|
85
|
+
const text = structured.paragraphs.join('\n');
|
|
86
|
+
if (output === 'structured') {
|
|
87
|
+
const payload = JSON.stringify(structured, null, 2);
|
|
88
|
+
return {
|
|
89
|
+
format: 'docx',
|
|
90
|
+
text: payload,
|
|
91
|
+
charCount: payload.length,
|
|
92
|
+
path: filePath,
|
|
93
|
+
structured,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return finish('docx', text, filePath, output, {
|
|
97
|
+
paragraphs: structured.paragraphs,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
// ZIP might be xlsx/pptx without a reliable extension
|
|
102
|
+
if (buf && isZipBuffer(buf)) {
|
|
103
|
+
try {
|
|
104
|
+
const refined = await refineZipFormat(buf);
|
|
105
|
+
if (refined === 'pptx') {
|
|
106
|
+
const structured = await readPptxStructuredFromBuffer(buf);
|
|
107
|
+
return pptxResult(structured, filePath, output);
|
|
108
|
+
}
|
|
109
|
+
if (refined === 'xlsx') {
|
|
110
|
+
const structured = readSpreadsheetStructuredFromBuffer(buf, 'xlsx');
|
|
111
|
+
return spreadsheetResult(structured, filePath, output);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
/* fall through */
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const structured = readSpreadsheetStructuredFromBuffer(buf, 'xlsx');
|
|
119
|
+
return spreadsheetResult(structured, filePath, output);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
/* fall through */
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// PPTX
|
|
129
|
+
if (format === 'pptx') {
|
|
130
|
+
const structured = filePath
|
|
131
|
+
? await readPptxStructured(filePath)
|
|
132
|
+
: await readPptxStructuredFromBuffer(buf);
|
|
133
|
+
return pptxResult(structured, filePath, output);
|
|
134
|
+
}
|
|
135
|
+
// Spreadsheets
|
|
136
|
+
if (format === 'xlsx' || format === 'xls') {
|
|
137
|
+
const structured = filePath
|
|
138
|
+
? await readSpreadsheetStructuredAsync(filePath)
|
|
139
|
+
: readSpreadsheetStructuredFromBuffer(buf, format);
|
|
140
|
+
return spreadsheetResult(structured, filePath, output);
|
|
141
|
+
}
|
|
142
|
+
// PDF
|
|
143
|
+
if (format === 'pdf') {
|
|
144
|
+
const { text } = await extractPdfText(filePath ?? buf);
|
|
145
|
+
return finish('pdf', text, filePath, output, { paragraphs: text.split(/\n+/) });
|
|
146
|
+
}
|
|
147
|
+
// MD / HTML / CSV
|
|
148
|
+
if (format === 'md' || format === 'html' || format === 'csv') {
|
|
149
|
+
const raw = filePath != null
|
|
150
|
+
? await readTextFile(filePath)
|
|
151
|
+
: buf
|
|
152
|
+
? buf.toString('utf8')
|
|
153
|
+
: typeof input === 'string'
|
|
154
|
+
? input
|
|
155
|
+
: '';
|
|
156
|
+
if (format === 'md') {
|
|
157
|
+
const parsed = parseMarkdown(raw);
|
|
158
|
+
if (output === 'structured') {
|
|
159
|
+
const structured = { format: 'md', paragraphs: parsed.paragraphs };
|
|
160
|
+
const payload = JSON.stringify(structured, null, 2);
|
|
161
|
+
return {
|
|
162
|
+
format: 'md',
|
|
163
|
+
text: payload,
|
|
164
|
+
charCount: payload.length,
|
|
165
|
+
path: filePath,
|
|
166
|
+
structured,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return finish('md', parsed.text, filePath, output, {
|
|
170
|
+
paragraphs: parsed.paragraphs,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (format === 'html') {
|
|
174
|
+
const parsed = parseHtml(raw);
|
|
175
|
+
if (output === 'structured') {
|
|
176
|
+
const structured = { format: 'html', paragraphs: parsed.paragraphs };
|
|
177
|
+
const payload = JSON.stringify(structured, null, 2);
|
|
178
|
+
return {
|
|
179
|
+
format: 'html',
|
|
180
|
+
text: payload,
|
|
181
|
+
charCount: payload.length,
|
|
182
|
+
path: filePath,
|
|
183
|
+
structured,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return finish('html', parsed.text, filePath, output, {
|
|
187
|
+
paragraphs: parsed.paragraphs,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
const parsed = parseCsv(raw);
|
|
191
|
+
if (output === 'structured') {
|
|
192
|
+
const structured = { format: 'csv', rows: parsed.rows };
|
|
193
|
+
const payload = JSON.stringify(structured, null, 2);
|
|
194
|
+
return {
|
|
195
|
+
format: 'csv',
|
|
196
|
+
text: payload,
|
|
197
|
+
charCount: payload.length,
|
|
198
|
+
path: filePath,
|
|
199
|
+
structured,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
return finish('csv', parsed.text, filePath, output, { rows: parsed.rows });
|
|
203
|
+
}
|
|
204
|
+
throw new DocumentError('UNSUPPORTED_FORMAT', `Unsupported format: ${format}`);
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
if (err instanceof DocumentError)
|
|
208
|
+
throw err;
|
|
209
|
+
throw wrapError('PARSE_FAILED', 'Failed to parse document', err);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function pptxResult(structured, filePath, output) {
|
|
213
|
+
if (output === 'structured') {
|
|
214
|
+
const payload = JSON.stringify(structured, null, 2);
|
|
215
|
+
return {
|
|
216
|
+
format: 'pptx',
|
|
217
|
+
text: payload,
|
|
218
|
+
charCount: payload.length,
|
|
219
|
+
path: filePath,
|
|
220
|
+
structured,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const text = pptxToText(structured);
|
|
224
|
+
return finish('pptx', text, filePath, output, {
|
|
225
|
+
slides: structured.slides,
|
|
226
|
+
paragraphs: pptxToParagraphs(structured),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function spreadsheetResult(structured, filePath, output) {
|
|
230
|
+
if (output === 'structured') {
|
|
231
|
+
const payload = JSON.stringify(structured, null, 2);
|
|
232
|
+
return {
|
|
233
|
+
format: structured.format,
|
|
234
|
+
text: payload,
|
|
235
|
+
charCount: payload.length,
|
|
236
|
+
path: filePath,
|
|
237
|
+
structured,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
const text = spreadsheetToText(structured);
|
|
241
|
+
return finish(structured.format, text, filePath, output, {
|
|
242
|
+
sheets: structured.sheets,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
function finish(format, text, filePath, output, shape) {
|
|
246
|
+
if (output === 'ast') {
|
|
247
|
+
return {
|
|
248
|
+
format,
|
|
249
|
+
text: '',
|
|
250
|
+
charCount: 0,
|
|
251
|
+
path: filePath,
|
|
252
|
+
ast: { type: format, ...shape },
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
if (output === 'chunks') {
|
|
256
|
+
const chunks = chunkText(text);
|
|
257
|
+
const payload = JSON.stringify(chunks, null, 2);
|
|
258
|
+
return {
|
|
259
|
+
format,
|
|
260
|
+
text: payload,
|
|
261
|
+
charCount: payload.length,
|
|
262
|
+
path: filePath,
|
|
263
|
+
chunks,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
// structured already handled by callers when needed
|
|
267
|
+
if (output === 'structured') {
|
|
268
|
+
const structured = { format, ...shape };
|
|
269
|
+
const payload = JSON.stringify(structured, null, 2);
|
|
270
|
+
return {
|
|
271
|
+
format,
|
|
272
|
+
text: payload,
|
|
273
|
+
charCount: payload.length,
|
|
274
|
+
path: filePath,
|
|
275
|
+
structured,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
format,
|
|
280
|
+
text,
|
|
281
|
+
charCount: text.length,
|
|
282
|
+
path: filePath,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
export { convertDocToDocx } from './legacy-doc.js';
|
|
286
|
+
//# sourceMappingURL=router.js.map
|