docling.rs 0.20.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 +257 -0
- package/deps.js +188 -0
- package/index.d.ts +97 -0
- package/index.js +172 -0
- package/native.d.ts +157 -0
- package/native.js +322 -0
- package/package.json +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# docling.rs (Node.js / Bun bindings)
|
|
2
|
+
|
|
3
|
+
Native [Node.js](https://nodejs.org) / [Bun](https://bun.sh) bindings for
|
|
4
|
+
[docling.rs](https://github.com/artiz/docling.rs) — a Rust port of
|
|
5
|
+
[docling](https://github.com/docling-project/docling). Convert Markdown, HTML,
|
|
6
|
+
DOCX, PPTX, XLSX, EPUB, ODF, LaTeX, email, PDF, images and more into a unified
|
|
7
|
+
`DoclingDocument`, and export it as **Markdown** or docling-core **JSON**.
|
|
8
|
+
|
|
9
|
+
Built with [napi-rs](https://napi.rs), so it ships a real native addon (`.node`)
|
|
10
|
+
that loads in both Node.js and Bun (Bun implements N-API) — the same binary, no
|
|
11
|
+
rebuild between runtimes.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
Released versions ship **prebuilt** native binaries, so no Rust toolchain is
|
|
16
|
+
needed to use the package:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install docling.rs # or: bun add docling.rs
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Prebuilt platforms: Linux x64 / arm64 (glibc) and Windows x64. (macOS isn't
|
|
23
|
+
prebuilt — build from source, see below.) The right binary is pulled in
|
|
24
|
+
automatically as a platform-specific `optionalDependency` (`docling.rs-<triple>`). Releases are published to npm by
|
|
25
|
+
manually running the `npm publish` workflow
|
|
26
|
+
(`.github/workflows/npm-publish.yml`) — by default it builds the latest master
|
|
27
|
+
(the workspace version); optionally pass a release tag to build that instead.
|
|
28
|
+
Decoupled from the crates.io release.
|
|
29
|
+
|
|
30
|
+
## Build from source
|
|
31
|
+
|
|
32
|
+
This package lives in the docling.rs Cargo workspace and can also build the
|
|
33
|
+
addon from Rust source — needed for local development or an unsupported
|
|
34
|
+
platform. You need a Rust toolchain (1.82+) and Node.js 14+ (or Bun).
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
cd crates/docling-node
|
|
38
|
+
npm install # installs @napi-rs/cli
|
|
39
|
+
npm run build # release build → docling.rs.<platform>.node + native.js/.d.ts
|
|
40
|
+
# npm run build:debug # faster, unoptimized
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
> The addon statically links the ONNX runtime used by the PDF/image pipeline, so
|
|
44
|
+
> the built `.node` is large. Declarative formats (Markdown, HTML, DOCX, …) don't
|
|
45
|
+
> touch it; only PDF/image conversion loads the ML models (downloaded on first
|
|
46
|
+
> use, like the CLI).
|
|
47
|
+
|
|
48
|
+
## Quick start
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
import { convertFile, convert, DocumentConverter } from 'docling.rs'
|
|
52
|
+
|
|
53
|
+
// Convert a file — format detected from the extension.
|
|
54
|
+
const { content } = convertFile('report.docx')
|
|
55
|
+
console.log(content) // Markdown
|
|
56
|
+
|
|
57
|
+
// Convert in-memory bytes (e.g. an upload) — pass the format explicitly.
|
|
58
|
+
const md = convert({ name: 'notes', data: Buffer.from('# Hi\n'), format: 'md' })
|
|
59
|
+
|
|
60
|
+
// docling-core JSON instead of Markdown.
|
|
61
|
+
const json = convertFile('report.docx', { to: 'json' })
|
|
62
|
+
|
|
63
|
+
// Reuse a converter across many documents.
|
|
64
|
+
const converter = new DocumentConverter({ strict: true })
|
|
65
|
+
const a = converter.convert({ name: 'a.md', data: Buffer.from('# A\n') })
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
CommonJS works too: `const { convertFile } = require('docling.rs')`.
|
|
69
|
+
|
|
70
|
+
### Async (off the event loop)
|
|
71
|
+
|
|
72
|
+
Conversion is CPU-bound; the `*Async` variants run it on the libuv thread pool
|
|
73
|
+
so the event loop stays free. Prefer these for PDF/image and for servers.
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
import { convertFileAsync } from 'docling.rs'
|
|
77
|
+
|
|
78
|
+
const res = await convertFileAsync('paper.pdf', { to: 'json' })
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Streaming Markdown
|
|
82
|
+
|
|
83
|
+
`streamFileMarkdown` yields Markdown chunks in document order as conversion
|
|
84
|
+
progresses. For PDF (whose pages convert in parallel) output starts flowing
|
|
85
|
+
before the whole document is done; concatenating the chunks reproduces the
|
|
86
|
+
buffered `content` byte-for-byte.
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
import { streamFileMarkdown } from 'docling.rs'
|
|
90
|
+
|
|
91
|
+
for await (const chunk of streamFileMarkdown('paper.pdf')) {
|
|
92
|
+
process.stdout.write(chunk)
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### PDF / images: getting the ML models
|
|
97
|
+
|
|
98
|
+
Declarative formats (Markdown, HTML, DOCX, XLSX, …) are pure Rust and need
|
|
99
|
+
nothing. The **PDF/image** path needs native assets that are *not* bundled in the
|
|
100
|
+
addon — pdfium plus the ONNX models (layout, OCR, TableFormer). Converting a
|
|
101
|
+
PDF/image/METS input **throws** until they're on disk. Fetch them with a
|
|
102
|
+
one-liner from your app's directory (where you'll `npm install docling.rs`):
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
curl -fsSL https://raw.githubusercontent.com/artiz/docling.rs/master/scripts/download_dependencies.sh | sh
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
import { convertFileAsync } from 'docling.rs'
|
|
110
|
+
|
|
111
|
+
const res = await convertFileAsync('paper.pdf', { to: 'markdown' }) // ✅ works
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`scripts/download_dependencies.sh` fetches everything from this repo's
|
|
115
|
+
[GitHub Releases](https://github.com/artiz/docling.rs/releases) straight into
|
|
116
|
+
`./models` and `./.pdfium` — which this package (and the Rust CLI) look for by
|
|
117
|
+
default, relative to the process's current directory, so no env vars or setup
|
|
118
|
+
call are needed afterwards:
|
|
119
|
+
|
|
120
|
+
| Asset | Destination |
|
|
121
|
+
| --- | --- |
|
|
122
|
+
| **pdfium** | `.pdfium/lib/libpdfium.so` |
|
|
123
|
+
| **layout** (`layout_heron.onnx`) | `models/layout_heron.onnx` |
|
|
124
|
+
| **OCR** rec model + dictionary | `models/ocr_rec.onnx`, `models/ppocr_keys_v1.txt` |
|
|
125
|
+
| **TableFormer** | `models/tableformer/{encoder,decoder,bbox}.onnx` |
|
|
126
|
+
|
|
127
|
+
> **layout + TableFormer are PyTorch→ONNX exports**
|
|
128
|
+
> (`docling-project/docling-layout-heron`, Apache-2.0;
|
|
129
|
+
> `docling-project/docling-models`, CDLA-Permissive-2.0/Apache-2.0 — see
|
|
130
|
+
> [`MODELS_NOTICE.md`](../../MODELS_NOTICE.md) for full attribution), not
|
|
131
|
+
> docling.rs's own weights — docling.rs hosts the converted `.onnx` as a
|
|
132
|
+
> GitHub Release purely so you don't need a local Python/torch toolchain.
|
|
133
|
+
> pdfium and the OCR model are re-hosted, unmodified, from their own public
|
|
134
|
+
> releases, on the same host for convenience.
|
|
135
|
+
>
|
|
136
|
+
> Run it from wherever your app lives — the script only writes to `./models`
|
|
137
|
+
> and `./.pdfium` under the current directory, e.g. in a container build step:
|
|
138
|
+
> ```bash
|
|
139
|
+
> cd /path/to/your/app && curl -fsSL https://raw.githubusercontent.com/artiz/docling.rs/master/scripts/download_dependencies.sh | sh
|
|
140
|
+
> ```
|
|
141
|
+
>
|
|
142
|
+
> To use your own export/host instead, point the env vars at it directly:
|
|
143
|
+
> `DOCLING_LAYOUT_ONNX`, `DOCLING_OCR_REC_ONNX`, `DOCLING_OCR_DICT`,
|
|
144
|
+
> `DOCLING_TABLEFORMER_{ENCODER,DECODER,BBOX}`, `PDFIUM_DYNAMIC_LIB_PATH` — an
|
|
145
|
+
> env var always wins over the `./models` / `./.pdfium` default.
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
checkDependencies() // { home, pdfium, layout, ocr, tableformer, ready, missing }
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Reusing a warm `Pipeline` (many PDFs)
|
|
152
|
+
|
|
153
|
+
The one-shot `convertFile` / `convertFileAsync` rebuild the pipeline — reloading
|
|
154
|
+
every ONNX model — on each call. To convert many PDFs/images, reuse a `Pipeline`
|
|
155
|
+
so the models load **once**:
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
import { Pipeline } from 'docling.rs'
|
|
159
|
+
|
|
160
|
+
const pipeline = new Pipeline({ strict: true })
|
|
161
|
+
for (const path of pdfPaths) {
|
|
162
|
+
const { content } = pipeline.convertFile(path, { to: 'markdown' }) // warm models
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`Pipeline` handles `pdf` and `image` inputs (the ML pipeline) and is synchronous
|
|
167
|
+
— reuse one instance behind a job queue.
|
|
168
|
+
|
|
169
|
+
### Images
|
|
170
|
+
|
|
171
|
+
Pick how pictures render in Markdown with `imageMode`:
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
// Inline, self-contained: 
|
|
175
|
+
convertFile('slides.pptx', { imageMode: 'embedded' })
|
|
176
|
+
|
|
177
|
+
// Referenced: links + the image bytes to write yourself.
|
|
178
|
+
const res = convertFile('slides.pptx', { imageMode: 'referenced', artifactsDir: 'assets' })
|
|
179
|
+
for (const img of res.images) {
|
|
180
|
+
await fs.writeFile(img.path, img.data) // e.g. assets/image_000000.png
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
JSON output always embeds extracted images as data URIs.
|
|
185
|
+
|
|
186
|
+
## API
|
|
187
|
+
|
|
188
|
+
### Functions
|
|
189
|
+
|
|
190
|
+
| Function | Returns | Notes |
|
|
191
|
+
| --- | --- | --- |
|
|
192
|
+
| `convertFile(path, options?)` | `ConvertResult` | Detects format from the extension. |
|
|
193
|
+
| `convert(input, options?)` | `ConvertResult` | In-memory bytes (`{ name, data, format? }`). |
|
|
194
|
+
| `convertFileAsync(path, options?)` | `Promise<ConvertResult>` | Off the event loop. |
|
|
195
|
+
| `convertAsync(input, options?)` | `Promise<ConvertResult>` | Off the event loop. |
|
|
196
|
+
| `streamFileMarkdown(path, options?)` | `AsyncGenerator<string>` | Markdown chunks in document order. |
|
|
197
|
+
| `supportedFormats()` | `string[]` | Supported input format ids. |
|
|
198
|
+
| `formatFromName(name)` | `string \| null` | Detect a format id from a filename/extension. |
|
|
199
|
+
| `checkDependencies(options?)` | `DependencyStatus` | Report which PDF/image deps are present. |
|
|
200
|
+
|
|
201
|
+
`Pipeline` is the reusable warm PDF/image converter: `new Pipeline(converterOptions)`
|
|
202
|
+
then `convertFile` / `convert`.
|
|
203
|
+
|
|
204
|
+
`DocumentConverter` is the reusable form: `new DocumentConverter(converterOptions)`
|
|
205
|
+
then `convert` / `convertFile` / `convertFileAsync` / `convertAsync` /
|
|
206
|
+
`convertFileStreaming`. Converter config (`strict`, `fetchImages`,
|
|
207
|
+
`allowedFormats`) is set once on the constructor; output options (`to`,
|
|
208
|
+
`imageMode`, `artifactsDir`) are per call.
|
|
209
|
+
|
|
210
|
+
### Options
|
|
211
|
+
|
|
212
|
+
- `to`: `"markdown"` (default) or `"json"`.
|
|
213
|
+
- `imageMode`: `"placeholder"` (default), `"embedded"`, or `"referenced"`.
|
|
214
|
+
- `artifactsDir`: directory name used in `referenced` links (default `"artifacts"`).
|
|
215
|
+
- `strict`: cleaner, more conformant Markdown instead of docling's byte-for-byte
|
|
216
|
+
legacy output (Markdown only).
|
|
217
|
+
- `fetchImages`: for HTML/EPUB, resolve and embed external `<img src>`. Off by
|
|
218
|
+
default; fetches http(s) URLs over the network — enable only for trusted input.
|
|
219
|
+
- `allowedFormats`: restrict the converter to these format ids/extensions.
|
|
220
|
+
|
|
221
|
+
### `ConvertResult`
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
interface ConvertResult {
|
|
225
|
+
content: string // Markdown or JSON, per `to`
|
|
226
|
+
format: string // detected input format id
|
|
227
|
+
status: string // "success" | "partial_success" | "failure"
|
|
228
|
+
inputName: string
|
|
229
|
+
images: { path: string; data: Buffer }[] // for the `referenced` image mode
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Full TypeScript types are generated into `index.d.ts` / `native.d.ts`.
|
|
234
|
+
|
|
235
|
+
## Examples
|
|
236
|
+
|
|
237
|
+
The [`examples/`](examples) folder is a self-contained project that depends on
|
|
238
|
+
the published `docling.rs` package — `npm install` there, then run any of them:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
cd examples
|
|
242
|
+
npm install
|
|
243
|
+
node node-basic.mjs # ESM: file, bytes, JSON, reuse
|
|
244
|
+
bun run bun-basic.ts # Bun + TypeScript: async + streaming
|
|
245
|
+
node pdf-pipeline.mjs # warm Pipeline for PDFs (run scripts/download_dependencies.sh first)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
- [`examples/node-basic.mjs`](examples/node-basic.mjs) — Node.js (ESM): file, bytes, JSON, reuse.
|
|
249
|
+
- [`examples/bun-basic.ts`](examples/bun-basic.ts) — Bun + TypeScript, with async and streaming.
|
|
250
|
+
- [`examples/pdf-pipeline.mjs`](examples/pdf-pipeline.mjs) — warm `Pipeline` for PDFs.
|
|
251
|
+
|
|
252
|
+
The smoke test exercises the locally-built addon instead: `npm run build` once at
|
|
253
|
+
the package root, then `node test/smoke.mjs` (or `bun test/smoke.mjs`).
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT, same as the rest of docling.rs.
|
package/deps.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Dependency *resolution* for the PDF/image ML pipeline.
|
|
2
|
+
//
|
|
3
|
+
// The declarative backends (Markdown, HTML, DOCX, XLSX, …) are pure Rust and
|
|
4
|
+
// need nothing. The PDF/image path needs native assets that are NOT bundled in
|
|
5
|
+
// the addon (they're large and licensed separately from docling.rs's own MIT
|
|
6
|
+
// code):
|
|
7
|
+
//
|
|
8
|
+
// - libpdfium (PDF text extraction + page rasterization) — required for PDF
|
|
9
|
+
// - RT-DETR layout model (models/layout_heron.onnx) — required for PDF & image
|
|
10
|
+
// - PP-OCR rec + dict (models/ocr_rec.onnx, ppocr_keys_v1.txt) — used for pages with no text layer
|
|
11
|
+
// - TableFormer (models/tableformer/{encoder,decoder,bbox}.onnx) — optional; geometric fallback otherwise
|
|
12
|
+
//
|
|
13
|
+
// This module does NOT download anything — `scripts/download_dependencies.sh`
|
|
14
|
+
// does that, fetching everything from this repo's GitHub Releases straight
|
|
15
|
+
// into `./models` and `./.pdfium` (see MODELS_NOTICE.md for attribution: the
|
|
16
|
+
// layout model and TableFormer are PyTorch→ONNX exports of docling-project's
|
|
17
|
+
// own models, re-hosted here as a convenience). This module just resolves
|
|
18
|
+
// where those files (or an explicit `DOCLING_*` / `PDFIUM_DYNAMIC_LIB_PATH`
|
|
19
|
+
// override) should live, reports whether they're present, and wires the
|
|
20
|
+
// matching env vars in-process so the native pipeline finds them — mirroring
|
|
21
|
+
// the CWD-relative defaults already baked into the Rust pipeline itself, so a
|
|
22
|
+
// plain `convertFileAsync(...)` call needs no explicit setup once
|
|
23
|
+
// `download_dependencies.sh` has run.
|
|
24
|
+
|
|
25
|
+
'use strict'
|
|
26
|
+
|
|
27
|
+
const fs = require('fs')
|
|
28
|
+
const os = require('os')
|
|
29
|
+
const path = require('path')
|
|
30
|
+
|
|
31
|
+
// Formats whose conversion requires the ML models + native libs above.
|
|
32
|
+
const ML_FORMATS = new Set(['pdf', 'image', 'mets_gbs'])
|
|
33
|
+
|
|
34
|
+
// pdfium's shared-library filename, by platform.
|
|
35
|
+
function pdfiumLibName() {
|
|
36
|
+
switch (process.platform) {
|
|
37
|
+
case 'linux':
|
|
38
|
+
return 'libpdfium.so'
|
|
39
|
+
case 'darwin':
|
|
40
|
+
return 'libpdfium.dylib'
|
|
41
|
+
case 'win32':
|
|
42
|
+
return 'pdfium.dll'
|
|
43
|
+
default:
|
|
44
|
+
throw new Error(`unsupported platform for pdfium: ${process.platform}/${process.arch}`)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Resolve the install home directory (absolute), and which `pdfium/`-vs-
|
|
50
|
+
* `.pdfium/` layout it uses. Precedence: an explicit `dir` > `$DOCLING_RS_HOME`
|
|
51
|
+
* > the current directory, *if* it already has a local `models/` or `.pdfium/`
|
|
52
|
+
* (the layout `scripts/download_dependencies.sh` and `scripts/pdf_setup.sh`
|
|
53
|
+
* both produce, and the one the native Rust pipeline's own env-var-less
|
|
54
|
+
* defaults already resolve — `models/layout_heron.onnx`, `.pdfium/lib/…` —
|
|
55
|
+
* relative to *its* CWD) > `~/.cache/docling.rs`. This lets a plain
|
|
56
|
+
* `convertFileAsync(...)` call succeed with zero setup (no env vars) whenever
|
|
57
|
+
* the app is run from a directory that already has the dependencies
|
|
58
|
+
* downloaded next to it.
|
|
59
|
+
*/
|
|
60
|
+
function homeDir(dir) {
|
|
61
|
+
if (dir) return { home: path.resolve(dir), dotPdfium: false }
|
|
62
|
+
if (process.env.DOCLING_RS_HOME) return { home: path.resolve(process.env.DOCLING_RS_HOME), dotPdfium: false }
|
|
63
|
+
const cwd = process.cwd()
|
|
64
|
+
const hasLocal =
|
|
65
|
+
fs.existsSync(path.join(cwd, 'models', 'layout_heron.onnx')) ||
|
|
66
|
+
fs.existsSync(path.join(cwd, '.pdfium', 'lib', pdfiumLibName()))
|
|
67
|
+
if (hasLocal) return { home: cwd, dotPdfium: true }
|
|
68
|
+
return { home: path.join(os.homedir(), '.cache', 'docling.rs'), dotPdfium: false }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The resolved on-disk location of each dependency: an existing `DOCLING_*` /
|
|
73
|
+
* `PDFIUM_DYNAMIC_LIB_PATH` environment variable wins (so a local Python export
|
|
74
|
+
* is honored), else the path under the install home directory.
|
|
75
|
+
*/
|
|
76
|
+
function resolvePaths(dir) {
|
|
77
|
+
const { home, dotPdfium } = homeDir(dir)
|
|
78
|
+
const models = path.join(home, 'models')
|
|
79
|
+
|
|
80
|
+
const pdfiumLibDir =
|
|
81
|
+
process.env.PDFIUM_DYNAMIC_LIB_PATH || path.join(home, dotPdfium ? '.pdfium' : 'pdfium', 'lib')
|
|
82
|
+
return {
|
|
83
|
+
home,
|
|
84
|
+
models,
|
|
85
|
+
pdfiumLibDir,
|
|
86
|
+
pdfiumLib: path.join(pdfiumLibDir, pdfiumLibName()),
|
|
87
|
+
layout: process.env.DOCLING_LAYOUT_ONNX || path.join(models, 'layout_heron.onnx'),
|
|
88
|
+
ocrRec: process.env.DOCLING_OCR_REC_ONNX || path.join(models, 'ocr_rec.onnx'),
|
|
89
|
+
ocrDict: process.env.DOCLING_OCR_DICT || path.join(models, 'ppocr_keys_v1.txt'),
|
|
90
|
+
tfEncoder:
|
|
91
|
+
process.env.DOCLING_TABLEFORMER_ENCODER || path.join(models, 'tableformer', 'encoder.onnx'),
|
|
92
|
+
tfDecoder:
|
|
93
|
+
process.env.DOCLING_TABLEFORMER_DECODER || path.join(models, 'tableformer', 'decoder.onnx'),
|
|
94
|
+
tfBbox: process.env.DOCLING_TABLEFORMER_BBOX || path.join(models, 'tableformer', 'bbox.onnx'),
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Report which dependencies are present on disk. `ready` is true when the
|
|
100
|
+
* minimum for PDF (pdfium + layout) is present.
|
|
101
|
+
*/
|
|
102
|
+
function checkDependencies(options = {}) {
|
|
103
|
+
const p = resolvePaths(options.dir)
|
|
104
|
+
const has = (f) => fs.existsSync(f)
|
|
105
|
+
const status = {
|
|
106
|
+
home: p.home,
|
|
107
|
+
pdfium: has(p.pdfiumLib),
|
|
108
|
+
layout: has(p.layout),
|
|
109
|
+
ocr: has(p.ocrRec) && has(p.ocrDict),
|
|
110
|
+
tableformer: has(p.tfEncoder) && has(p.tfDecoder) && has(p.tfBbox),
|
|
111
|
+
}
|
|
112
|
+
status.ready = status.pdfium && status.layout
|
|
113
|
+
status.missing = [
|
|
114
|
+
!status.pdfium && 'pdfium',
|
|
115
|
+
!status.layout && 'layout_heron.onnx',
|
|
116
|
+
].filter(Boolean)
|
|
117
|
+
return status
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Point the current process at installed assets (so the native pipeline finds them). */
|
|
121
|
+
function exportEnv(p) {
|
|
122
|
+
if (fs.existsSync(p.pdfiumLib)) process.env.PDFIUM_DYNAMIC_LIB_PATH = p.pdfiumLibDir
|
|
123
|
+
if (fs.existsSync(p.layout)) process.env.DOCLING_LAYOUT_ONNX = p.layout
|
|
124
|
+
if (fs.existsSync(p.ocrRec)) process.env.DOCLING_OCR_REC_ONNX = p.ocrRec
|
|
125
|
+
if (fs.existsSync(p.ocrDict)) process.env.DOCLING_OCR_DICT = p.ocrDict
|
|
126
|
+
if (fs.existsSync(p.tfEncoder)) process.env.DOCLING_TABLEFORMER_ENCODER = p.tfEncoder
|
|
127
|
+
if (fs.existsSync(p.tfDecoder)) process.env.DOCLING_TABLEFORMER_DECODER = p.tfDecoder
|
|
128
|
+
if (fs.existsSync(p.tfBbox)) process.env.DOCLING_TABLEFORMER_BBOX = p.tfBbox
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* A copy-pasteable next step, shown when a PDF/image/METS conversion is
|
|
133
|
+
* attempted without the dependencies on disk.
|
|
134
|
+
*/
|
|
135
|
+
function downloadGuide() {
|
|
136
|
+
return [
|
|
137
|
+
'Run this once from your app\'s directory (fetches pdfium + the ONNX',
|
|
138
|
+
'models — layout, OCR, TableFormer — from this repo\'s GitHub Releases',
|
|
139
|
+
'straight into ./models and ./.pdfium, which this package looks for by',
|
|
140
|
+
'default; no env vars needed afterwards):',
|
|
141
|
+
'',
|
|
142
|
+
' curl -fsSL https://raw.githubusercontent.com/artiz/docling.rs/master/scripts/download_dependencies.sh | sh',
|
|
143
|
+
'',
|
|
144
|
+
'or, from a checkout of the repo:',
|
|
145
|
+
'',
|
|
146
|
+
' scripts/download_dependencies.sh',
|
|
147
|
+
'',
|
|
148
|
+
'TableFormer is optional (tables fall back to geometric reconstruction',
|
|
149
|
+
'without it). To use your own export/host instead, point the DOCLING_*',
|
|
150
|
+
'env vars at it directly: DOCLING_LAYOUT_ONNX, DOCLING_OCR_REC_ONNX,',
|
|
151
|
+
'DOCLING_OCR_DICT, DOCLING_TABLEFORMER_{ENCODER,DECODER,BBOX},',
|
|
152
|
+
'PDFIUM_DYNAMIC_LIB_PATH — see MODELS_NOTICE.md for licensing.',
|
|
153
|
+
'',
|
|
154
|
+
'Declarative formats (md, html, docx, xlsx, …) need none of this — only',
|
|
155
|
+
'PDF, image and METS conversion do.',
|
|
156
|
+
].join('\n')
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Throw a clear, actionable error if `format` needs the ML pipeline but its
|
|
161
|
+
* dependencies aren't installed. Called before ML conversions; also wires up
|
|
162
|
+
* the `DOCLING_*` / `PDFIUM_DYNAMIC_LIB_PATH` env vars for whatever is present,
|
|
163
|
+
* so a checkout with `scripts/download_dependencies.sh` already run just works.
|
|
164
|
+
*/
|
|
165
|
+
function assertMlReady(format, dir) {
|
|
166
|
+
if (!ML_FORMATS.has(format)) return
|
|
167
|
+
const p = resolvePaths(dir)
|
|
168
|
+
exportEnv(p)
|
|
169
|
+
const status = checkDependencies({ dir })
|
|
170
|
+
// Image needs layout (+OCR), but not pdfium; PDF/METS need both.
|
|
171
|
+
const needPdfium = format !== 'image'
|
|
172
|
+
const missing = [!status.layout && 'layout_heron.onnx', needPdfium && !status.pdfium && 'pdfium'].filter(
|
|
173
|
+
Boolean,
|
|
174
|
+
)
|
|
175
|
+
if (missing.length === 0) return
|
|
176
|
+
throw new Error(
|
|
177
|
+
`Converting '${format}' requires the PDF/ML dependencies, which are not installed: ` +
|
|
178
|
+
`${missing.join(', ')}.\n\n${downloadGuide()}`,
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports = {
|
|
183
|
+
ML_FORMATS,
|
|
184
|
+
checkDependencies,
|
|
185
|
+
assertMlReady,
|
|
186
|
+
resolvePaths,
|
|
187
|
+
exportEnv,
|
|
188
|
+
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Public type surface for the `docling.rs` npm package. Re-exports the native
|
|
2
|
+
// binding's option/result types and unguarded functions, and declares the
|
|
3
|
+
// JS-wrapped classes, the dependency API, and the streaming helper.
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
ConverterOptions,
|
|
7
|
+
OutputOptions,
|
|
8
|
+
ConvertOptions,
|
|
9
|
+
ConvertInput,
|
|
10
|
+
ConvertResult,
|
|
11
|
+
} from './native'
|
|
12
|
+
|
|
13
|
+
export type { ConverterOptions, OutputOptions, ConvertOptions, ConvertInput, ConvertResult }
|
|
14
|
+
|
|
15
|
+
// Format helpers pass straight through from the native binding.
|
|
16
|
+
export { supportedFormats, formatFromName } from './native'
|
|
17
|
+
|
|
18
|
+
/** Callback form used by the native streaming API (prefer {@link streamFileMarkdown}). */
|
|
19
|
+
export type StreamCallback = (err: Error | null, chunk: string | undefined | null) => void
|
|
20
|
+
|
|
21
|
+
/** Convert a file on disk (format detected from the extension). Throws for PDF/image/METS if deps aren't installed. */
|
|
22
|
+
export declare function convertFile(path: string, options?: ConvertOptions | null): ConvertResult
|
|
23
|
+
/** Convert in-memory bytes. Throws for PDF/image/METS if deps aren't installed. */
|
|
24
|
+
export declare function convert(input: ConvertInput, options?: ConvertOptions | null): ConvertResult
|
|
25
|
+
/** Async (Promise) file conversion, off the event loop. Rejects for PDF/image/METS if deps aren't installed. */
|
|
26
|
+
export declare function convertFileAsync(path: string, options?: ConvertOptions | null): Promise<ConvertResult>
|
|
27
|
+
/** Async (Promise) bytes conversion, off the event loop. */
|
|
28
|
+
export declare function convertAsync(input: ConvertInput, options?: ConvertOptions | null): Promise<ConvertResult>
|
|
29
|
+
|
|
30
|
+
/** A reusable converter holding config (strict / fetchImages / allowedFormats). */
|
|
31
|
+
export declare class DocumentConverter {
|
|
32
|
+
constructor(options?: ConverterOptions | null)
|
|
33
|
+
convertFile(path: string, options?: OutputOptions | null): ConvertResult
|
|
34
|
+
convert(input: ConvertInput, options?: OutputOptions | null): ConvertResult
|
|
35
|
+
convertFileAsync(path: string, options?: OutputOptions | null): Promise<ConvertResult>
|
|
36
|
+
convertAsync(input: ConvertInput, options?: OutputOptions | null): Promise<ConvertResult>
|
|
37
|
+
convertFileStreaming(path: string, callback: StreamCallback, options?: OutputOptions | null): void
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A reusable PDF/image pipeline that keeps the ONNX models loaded across calls.
|
|
42
|
+
* Use instead of the per-call functions when converting many PDFs/images — the
|
|
43
|
+
* one-shot path reloads every model each call. Handles `pdf` and `image` inputs.
|
|
44
|
+
*/
|
|
45
|
+
export declare class Pipeline {
|
|
46
|
+
constructor(options?: ConverterOptions | null)
|
|
47
|
+
convertFile(path: string, options?: OutputOptions | null): ConvertResult
|
|
48
|
+
convert(input: ConvertInput, options?: OutputOptions | null): ConvertResult
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// --- dependency provisioning (PDF/image ML pipeline) -----------------------
|
|
52
|
+
|
|
53
|
+
/** Where installed dependencies live and which are present. */
|
|
54
|
+
export interface DependencyStatus {
|
|
55
|
+
/** Install home directory. */
|
|
56
|
+
home: string
|
|
57
|
+
/** libpdfium present. */
|
|
58
|
+
pdfium: boolean
|
|
59
|
+
/** Layout model (layout_heron.onnx) present. */
|
|
60
|
+
layout: boolean
|
|
61
|
+
/** OCR model + dictionary present. */
|
|
62
|
+
ocr: boolean
|
|
63
|
+
/** TableFormer encoder/decoder/bbox present. */
|
|
64
|
+
tableformer: boolean
|
|
65
|
+
/** True when the minimum for PDF (pdfium + layout) is present. */
|
|
66
|
+
ready: boolean
|
|
67
|
+
/** Human-readable list of the missing required assets. */
|
|
68
|
+
missing: string[]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Report which PDF/image dependencies are present on disk. Fetch them with
|
|
73
|
+
* `scripts/download_dependencies.sh` (see the package README) — this function
|
|
74
|
+
* only reports status, it does not download anything.
|
|
75
|
+
*/
|
|
76
|
+
export declare function checkDependencies(options?: { dir?: string }): DependencyStatus
|
|
77
|
+
|
|
78
|
+
// --- streaming --------------------------------------------------------------
|
|
79
|
+
|
|
80
|
+
/** Options for {@link streamFileMarkdown} (converter config + streamable output). */
|
|
81
|
+
export interface StreamOptions {
|
|
82
|
+
strict?: boolean
|
|
83
|
+
fetchImages?: boolean
|
|
84
|
+
allowedFormats?: string[]
|
|
85
|
+
imageMode?: 'placeholder' | 'embedded'
|
|
86
|
+
artifactsDir?: string
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Stream a file's Markdown in chunks, in document order, as conversion
|
|
91
|
+
* progresses — the win for PDF, whose pages convert in parallel. Concatenating
|
|
92
|
+
* the chunks reproduces the buffered `convertFile(path).content` byte-for-byte.
|
|
93
|
+
*/
|
|
94
|
+
export declare function streamFileMarkdown(
|
|
95
|
+
filePath: string,
|
|
96
|
+
options?: StreamOptions,
|
|
97
|
+
): AsyncGenerator<string, void, unknown>
|
package/index.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
// Public entry point for the `docling.rs` npm package.
|
|
2
|
+
//
|
|
3
|
+
// Wraps the native N-API binding (loaded by `native.js`, which picks the right
|
|
4
|
+
// prebuilt `.node` for the host platform) with two things:
|
|
5
|
+
// 1. dependency guards — converting a PDF/image/METS input throws a clear
|
|
6
|
+
// error unless the ML models + pdfium are on disk (see
|
|
7
|
+
// scripts/download_dependencies.sh);
|
|
8
|
+
// 2. a `streamFileMarkdown` async generator over Markdown chunks.
|
|
9
|
+
//
|
|
10
|
+
// Works in Node.js and Bun (Bun implements N-API).
|
|
11
|
+
|
|
12
|
+
'use strict'
|
|
13
|
+
|
|
14
|
+
const native = require('./native.js')
|
|
15
|
+
const { checkDependencies, assertMlReady } = require('./deps.js')
|
|
16
|
+
|
|
17
|
+
// Resolve the format id of an input for the ML guard. Uses the native
|
|
18
|
+
// extension→format map; falls back to an explicitly-passed format string.
|
|
19
|
+
function mlFormatOf(name, format) {
|
|
20
|
+
if (format) {
|
|
21
|
+
return native.formatFromName(`x.${String(format).replace(/^\./, '')}`) || String(format)
|
|
22
|
+
}
|
|
23
|
+
return native.formatFromName(name || '') || ''
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// --- guarded one-shot functions --------------------------------------------
|
|
27
|
+
|
|
28
|
+
function convertFile(path, options) {
|
|
29
|
+
assertMlReady(mlFormatOf(path))
|
|
30
|
+
return native.convertFile(path, options)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function convert(input, options) {
|
|
34
|
+
assertMlReady(mlFormatOf(input && input.name, input && input.format))
|
|
35
|
+
return native.convert(input, options)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// async so a guard failure surfaces as a rejected promise, not a sync throw.
|
|
39
|
+
async function convertFileAsync(path, options) {
|
|
40
|
+
assertMlReady(mlFormatOf(path))
|
|
41
|
+
return native.convertFileAsync(path, options)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function convertAsync(input, options) {
|
|
45
|
+
assertMlReady(mlFormatOf(input && input.name, input && input.format))
|
|
46
|
+
return native.convertAsync(input, options)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// --- guarded classes --------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
class DocumentConverter {
|
|
52
|
+
constructor(options) {
|
|
53
|
+
this._inner = new native.DocumentConverter(options)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
convertFile(path, options) {
|
|
57
|
+
assertMlReady(mlFormatOf(path))
|
|
58
|
+
return this._inner.convertFile(path, options)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
convert(input, options) {
|
|
62
|
+
assertMlReady(mlFormatOf(input && input.name, input && input.format))
|
|
63
|
+
return this._inner.convert(input, options)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async convertFileAsync(path, options) {
|
|
67
|
+
assertMlReady(mlFormatOf(path))
|
|
68
|
+
return this._inner.convertFileAsync(path, options)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async convertAsync(input, options) {
|
|
72
|
+
assertMlReady(mlFormatOf(input && input.name, input && input.format))
|
|
73
|
+
return this._inner.convertAsync(input, options)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
convertFileStreaming(path, callback, options) {
|
|
77
|
+
assertMlReady(mlFormatOf(path))
|
|
78
|
+
return this._inner.convertFileStreaming(path, callback, options)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// The warm PDF/image pipeline is inherently ML — always guarded.
|
|
83
|
+
class Pipeline {
|
|
84
|
+
constructor(options) {
|
|
85
|
+
this._inner = new native.Pipeline(options)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
convertFile(path, options) {
|
|
89
|
+
assertMlReady(mlFormatOf(path))
|
|
90
|
+
return this._inner.convertFile(path, options)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
convert(input, options) {
|
|
94
|
+
assertMlReady(mlFormatOf(input && input.name, input && input.format))
|
|
95
|
+
return this._inner.convert(input, options)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// --- streaming --------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Stream a file's Markdown in chunks, in document order, as conversion
|
|
103
|
+
* progresses — the win for PDF, whose pages convert in parallel.
|
|
104
|
+
*
|
|
105
|
+
* Yields each Markdown chunk; concatenating every chunk reproduces the buffered
|
|
106
|
+
* `convertFile(path).content` byte-for-byte.
|
|
107
|
+
*
|
|
108
|
+
* @param {string} filePath
|
|
109
|
+
* @param {object} [options]
|
|
110
|
+
* @returns {AsyncGenerator<string, void, unknown>}
|
|
111
|
+
*/
|
|
112
|
+
async function* streamFileMarkdown(filePath, options = {}) {
|
|
113
|
+
assertMlReady(mlFormatOf(filePath))
|
|
114
|
+
const { strict, fetchImages, allowedFormats, imageMode, artifactsDir } = options
|
|
115
|
+
const converter = new native.DocumentConverter({ strict, fetchImages, allowedFormats })
|
|
116
|
+
|
|
117
|
+
// Bridge the native (err, chunk) callback into an async generator. Chunks are
|
|
118
|
+
// delivered on the event loop (via a threadsafe function); a null chunk ends
|
|
119
|
+
// the stream, a non-null err ends it with a throw.
|
|
120
|
+
const queue = []
|
|
121
|
+
let done = false
|
|
122
|
+
let failure = null
|
|
123
|
+
let notify = null
|
|
124
|
+
const wake = () => {
|
|
125
|
+
if (notify) {
|
|
126
|
+
const n = notify
|
|
127
|
+
notify = null
|
|
128
|
+
n()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
converter.convertFileStreaming(
|
|
133
|
+
filePath,
|
|
134
|
+
(err, chunk) => {
|
|
135
|
+
if (err) {
|
|
136
|
+
failure = err
|
|
137
|
+
done = true
|
|
138
|
+
} else if (chunk === null || chunk === undefined) {
|
|
139
|
+
done = true
|
|
140
|
+
} else {
|
|
141
|
+
queue.push(chunk)
|
|
142
|
+
}
|
|
143
|
+
wake()
|
|
144
|
+
},
|
|
145
|
+
{ imageMode, artifactsDir },
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
while (true) {
|
|
149
|
+
if (queue.length > 0) {
|
|
150
|
+
yield queue.shift()
|
|
151
|
+
continue
|
|
152
|
+
}
|
|
153
|
+
if (failure) throw failure
|
|
154
|
+
if (done) return
|
|
155
|
+
await new Promise((resolve) => {
|
|
156
|
+
notify = resolve
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// --- exports (explicit, so ESM named imports work in Node and Bun) ----------
|
|
162
|
+
|
|
163
|
+
module.exports.convert = convert
|
|
164
|
+
module.exports.convertFile = convertFile
|
|
165
|
+
module.exports.convertAsync = convertAsync
|
|
166
|
+
module.exports.convertFileAsync = convertFileAsync
|
|
167
|
+
module.exports.DocumentConverter = DocumentConverter
|
|
168
|
+
module.exports.Pipeline = Pipeline
|
|
169
|
+
module.exports.streamFileMarkdown = streamFileMarkdown
|
|
170
|
+
module.exports.checkDependencies = checkDependencies
|
|
171
|
+
module.exports.supportedFormats = native.supportedFormats
|
|
172
|
+
module.exports.formatFromName = native.formatFromName
|
package/native.d.ts
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/* auto-generated by NAPI-RS */
|
|
5
|
+
|
|
6
|
+
/** Config for a reusable [`DocumentConverter`]. */
|
|
7
|
+
export interface ConverterOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Emit cleaner, more conformant Markdown (code-fence languages preserved,
|
|
10
|
+
* no inline-run spacing artifacts) instead of docling's byte-for-byte
|
|
11
|
+
* legacy output. Markdown only. Default `false`.
|
|
12
|
+
*/
|
|
13
|
+
strict?: boolean
|
|
14
|
+
/**
|
|
15
|
+
* For HTML/EPUB, resolve external `<img src>` (data: URIs, local files,
|
|
16
|
+
* http(s) URLs, EPUB entries) and embed the bytes. Off by default; when on,
|
|
17
|
+
* http(s) URLs are fetched over the network — enable only for trusted input.
|
|
18
|
+
*/
|
|
19
|
+
fetchImages?: boolean
|
|
20
|
+
/**
|
|
21
|
+
* Restrict the converter to these formats (ids like `"md"`, `"pdf"`, or
|
|
22
|
+
* extensions like `".html"`); anything else is rejected. Default: accept all.
|
|
23
|
+
*/
|
|
24
|
+
allowedFormats?: Array<string>
|
|
25
|
+
}
|
|
26
|
+
/** Per-call output options (how to render the converted document). */
|
|
27
|
+
export interface OutputOptions {
|
|
28
|
+
/** `"markdown"` (default) or `"json"` (docling-core DoclingDocument wire format). */
|
|
29
|
+
to?: string
|
|
30
|
+
/**
|
|
31
|
+
* Picture handling for Markdown: `"placeholder"` (default), `"embedded"`
|
|
32
|
+
* (base64 data URIs inline), or `"referenced"` (returns image files in
|
|
33
|
+
* `images`). Ignored for JSON, which always embeds images as data URIs.
|
|
34
|
+
*/
|
|
35
|
+
imageMode?: string
|
|
36
|
+
/** Directory name used in `referenced` image links. Default `"artifacts"`. */
|
|
37
|
+
artifactsDir?: string
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* All options for the one-shot module-level functions (converter config +
|
|
41
|
+
* output options in a single object).
|
|
42
|
+
*/
|
|
43
|
+
export interface ConvertOptions {
|
|
44
|
+
strict?: boolean
|
|
45
|
+
fetchImages?: boolean
|
|
46
|
+
allowedFormats?: Array<string>
|
|
47
|
+
to?: string
|
|
48
|
+
imageMode?: string
|
|
49
|
+
artifactsDir?: string
|
|
50
|
+
}
|
|
51
|
+
/** In-memory input for [`DocumentConverter::convert`] / [`convert`]. */
|
|
52
|
+
export interface ConvertInput {
|
|
53
|
+
/** Logical document name (used as the docling document name). */
|
|
54
|
+
name: string
|
|
55
|
+
/** Raw file bytes. */
|
|
56
|
+
data: Buffer
|
|
57
|
+
/**
|
|
58
|
+
* Format id or extension (e.g. `"md"`, `"pdf"`, `".html"`). Omit to infer
|
|
59
|
+
* from an extension on `name`.
|
|
60
|
+
*/
|
|
61
|
+
format?: string
|
|
62
|
+
}
|
|
63
|
+
/** One extracted image file, returned for the `referenced` image mode. */
|
|
64
|
+
export interface ImageArtifact {
|
|
65
|
+
/** Path relative to the Markdown file (e.g. `"artifacts/image_000000.png"`). */
|
|
66
|
+
path: string
|
|
67
|
+
/** The image bytes to write at `path`. */
|
|
68
|
+
data: Buffer
|
|
69
|
+
}
|
|
70
|
+
/** The result of a conversion. */
|
|
71
|
+
export interface ConvertResult {
|
|
72
|
+
/** The rendered document: Markdown or JSON, per `to`. */
|
|
73
|
+
content: string
|
|
74
|
+
/** Detected input format id (e.g. `"md"`, `"pdf"`). */
|
|
75
|
+
format: string
|
|
76
|
+
/** `"success"`, `"partial_success"`, or `"failure"`. */
|
|
77
|
+
status: string
|
|
78
|
+
/** The document name. */
|
|
79
|
+
inputName: string
|
|
80
|
+
/**
|
|
81
|
+
* For the `referenced` image mode, the image files to write next to the
|
|
82
|
+
* Markdown; empty otherwise.
|
|
83
|
+
*/
|
|
84
|
+
images: Array<ImageArtifact>
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Convert a file on disk. Detects the format from the extension and (for
|
|
88
|
+
* HTML/EPUB image fetching) resolves relative `<img src>` against the file's
|
|
89
|
+
* directory.
|
|
90
|
+
*/
|
|
91
|
+
export declare function convertFile(path: string, options?: ConvertOptions | undefined | null): ConvertResult
|
|
92
|
+
/** Convert in-memory bytes. */
|
|
93
|
+
export declare function convert(input: ConvertInput, options?: ConvertOptions | undefined | null): ConvertResult
|
|
94
|
+
/**
|
|
95
|
+
* Async (Promise-returning) [`convert_file`]. The CPU-bound work runs on the
|
|
96
|
+
* libuv thread pool, keeping the event loop free — use this for PDF/image.
|
|
97
|
+
*/
|
|
98
|
+
export declare function convertFileAsync(path: string, options?: ConvertOptions | undefined | null): Promise<ConvertResult>
|
|
99
|
+
/** Async (Promise-returning) [`convert`]. */
|
|
100
|
+
export declare function convertAsync(input: ConvertInput, options?: ConvertOptions | undefined | null): Promise<ConvertResult>
|
|
101
|
+
/** The list of supported input format ids. */
|
|
102
|
+
export declare function supportedFormats(): Array<string>
|
|
103
|
+
/**
|
|
104
|
+
* Detect a format id from a filename or extension (e.g. `"report.pdf"` →
|
|
105
|
+
* `"pdf"`). Returns `null` for unknown extensions.
|
|
106
|
+
*/
|
|
107
|
+
export declare function formatFromName(name: string): string | null
|
|
108
|
+
/**
|
|
109
|
+
* A reusable converter. Holds config (strict / fetch-images / allowed formats)
|
|
110
|
+
* so you can convert many documents without re-parsing options each time —
|
|
111
|
+
* the analogue of the Rust `DocumentConverter`.
|
|
112
|
+
*/
|
|
113
|
+
export declare class DocumentConverter {
|
|
114
|
+
constructor(options?: ConverterOptions | undefined | null)
|
|
115
|
+
/** Convert a file on disk (sync). */
|
|
116
|
+
convertFile(path: string, options?: OutputOptions | undefined | null): ConvertResult
|
|
117
|
+
/** Convert in-memory bytes (sync). */
|
|
118
|
+
convert(input: ConvertInput, options?: OutputOptions | undefined | null): ConvertResult
|
|
119
|
+
/** Async (Promise-returning) file conversion (runs off the event loop). */
|
|
120
|
+
convertFileAsync(path: string, options?: OutputOptions | undefined | null): Promise<ConvertResult>
|
|
121
|
+
/** Async (Promise-returning) bytes conversion (runs off the event loop). */
|
|
122
|
+
convertAsync(input: ConvertInput, options?: OutputOptions | undefined | null): Promise<ConvertResult>
|
|
123
|
+
/**
|
|
124
|
+
* Stream a file's Markdown in chunks, in document order, as conversion
|
|
125
|
+
* progresses (the headline win for PDF, whose pages convert in parallel).
|
|
126
|
+
*
|
|
127
|
+
* `callback` is invoked as `(err, chunk)`: once per Markdown chunk with
|
|
128
|
+
* `chunk` a string, once with `chunk === null` at the end, or once with a
|
|
129
|
+
* non-null `err` on failure. Only `placeholder` / `embedded` image modes
|
|
130
|
+
* stream; `referenced` is rejected. Prefer the `streamFileMarkdown`
|
|
131
|
+
* async-generator wrapper in JS over calling this directly.
|
|
132
|
+
*/
|
|
133
|
+
convertFileStreaming(path: string, callback: (err: Error | null, arg: string | undefined | null) => any, options?: OutputOptions | undefined | null): void
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* A reusable PDF/image pipeline that keeps the ONNX models (layout, OCR,
|
|
137
|
+
* TableFormer) loaded across calls — the analogue of the Rust `Pipeline`. Use
|
|
138
|
+
* this instead of the per-call `convertFile` when converting many PDFs/images:
|
|
139
|
+
* the one-shot functions rebuild the pipeline (reloading every model) each
|
|
140
|
+
* call, whereas this loads them once.
|
|
141
|
+
*
|
|
142
|
+
* Handles `pdf` and `image` inputs (the ML pipeline). Models load lazily on
|
|
143
|
+
* first use, so constructing a `Pipeline` is cheap; the first conversion pays
|
|
144
|
+
* the model-load cost. Synchronous and single-threaded — reuse one instance
|
|
145
|
+
* for a sequence of documents (e.g. behind a job queue).
|
|
146
|
+
*/
|
|
147
|
+
export declare class Pipeline {
|
|
148
|
+
/**
|
|
149
|
+
* Construct the pipeline. Only `strict` is read (cleaner Markdown);
|
|
150
|
+
* `fetchImages` / `allowedFormats` don't apply to the PDF/image pipeline.
|
|
151
|
+
*/
|
|
152
|
+
constructor(options?: ConverterOptions | undefined | null)
|
|
153
|
+
/** Convert a PDF or image file, reusing the warm models. */
|
|
154
|
+
convertFile(path: string, options?: OutputOptions | undefined | null): ConvertResult
|
|
155
|
+
/** Convert PDF or image bytes, reusing the warm models. */
|
|
156
|
+
convert(input: ConvertInput, options?: OutputOptions | undefined | null): ConvertResult
|
|
157
|
+
}
|
package/native.js
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/* prettier-ignore */
|
|
4
|
+
|
|
5
|
+
/* auto-generated by NAPI-RS */
|
|
6
|
+
|
|
7
|
+
const { existsSync, readFileSync } = require('fs')
|
|
8
|
+
const { join } = require('path')
|
|
9
|
+
|
|
10
|
+
const { platform, arch } = process
|
|
11
|
+
|
|
12
|
+
let nativeBinding = null
|
|
13
|
+
let localFileExisted = false
|
|
14
|
+
let loadError = null
|
|
15
|
+
|
|
16
|
+
function isMusl() {
|
|
17
|
+
// For Node 10
|
|
18
|
+
if (!process.report || typeof process.report.getReport !== 'function') {
|
|
19
|
+
try {
|
|
20
|
+
const lddPath = require('child_process').execSync('which ldd').toString().trim()
|
|
21
|
+
return readFileSync(lddPath, 'utf8').includes('musl')
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
const { glibcVersionRuntime } = process.report.getReport().header
|
|
27
|
+
return !glibcVersionRuntime
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (platform) {
|
|
32
|
+
case 'android':
|
|
33
|
+
switch (arch) {
|
|
34
|
+
case 'arm64':
|
|
35
|
+
localFileExisted = existsSync(join(__dirname, 'docling-rs.android-arm64.node'))
|
|
36
|
+
try {
|
|
37
|
+
if (localFileExisted) {
|
|
38
|
+
nativeBinding = require('./docling-rs.android-arm64.node')
|
|
39
|
+
} else {
|
|
40
|
+
nativeBinding = require('docling.rs-android-arm64')
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
loadError = e
|
|
44
|
+
}
|
|
45
|
+
break
|
|
46
|
+
case 'arm':
|
|
47
|
+
localFileExisted = existsSync(join(__dirname, 'docling-rs.android-arm-eabi.node'))
|
|
48
|
+
try {
|
|
49
|
+
if (localFileExisted) {
|
|
50
|
+
nativeBinding = require('./docling-rs.android-arm-eabi.node')
|
|
51
|
+
} else {
|
|
52
|
+
nativeBinding = require('docling.rs-android-arm-eabi')
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
loadError = e
|
|
56
|
+
}
|
|
57
|
+
break
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Unsupported architecture on Android ${arch}`)
|
|
60
|
+
}
|
|
61
|
+
break
|
|
62
|
+
case 'win32':
|
|
63
|
+
switch (arch) {
|
|
64
|
+
case 'x64':
|
|
65
|
+
localFileExisted = existsSync(
|
|
66
|
+
join(__dirname, 'docling-rs.win32-x64-msvc.node')
|
|
67
|
+
)
|
|
68
|
+
try {
|
|
69
|
+
if (localFileExisted) {
|
|
70
|
+
nativeBinding = require('./docling-rs.win32-x64-msvc.node')
|
|
71
|
+
} else {
|
|
72
|
+
nativeBinding = require('docling.rs-win32-x64-msvc')
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
loadError = e
|
|
76
|
+
}
|
|
77
|
+
break
|
|
78
|
+
case 'ia32':
|
|
79
|
+
localFileExisted = existsSync(
|
|
80
|
+
join(__dirname, 'docling-rs.win32-ia32-msvc.node')
|
|
81
|
+
)
|
|
82
|
+
try {
|
|
83
|
+
if (localFileExisted) {
|
|
84
|
+
nativeBinding = require('./docling-rs.win32-ia32-msvc.node')
|
|
85
|
+
} else {
|
|
86
|
+
nativeBinding = require('docling.rs-win32-ia32-msvc')
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
loadError = e
|
|
90
|
+
}
|
|
91
|
+
break
|
|
92
|
+
case 'arm64':
|
|
93
|
+
localFileExisted = existsSync(
|
|
94
|
+
join(__dirname, 'docling-rs.win32-arm64-msvc.node')
|
|
95
|
+
)
|
|
96
|
+
try {
|
|
97
|
+
if (localFileExisted) {
|
|
98
|
+
nativeBinding = require('./docling-rs.win32-arm64-msvc.node')
|
|
99
|
+
} else {
|
|
100
|
+
nativeBinding = require('docling.rs-win32-arm64-msvc')
|
|
101
|
+
}
|
|
102
|
+
} catch (e) {
|
|
103
|
+
loadError = e
|
|
104
|
+
}
|
|
105
|
+
break
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
|
108
|
+
}
|
|
109
|
+
break
|
|
110
|
+
case 'darwin':
|
|
111
|
+
localFileExisted = existsSync(join(__dirname, 'docling-rs.darwin-universal.node'))
|
|
112
|
+
try {
|
|
113
|
+
if (localFileExisted) {
|
|
114
|
+
nativeBinding = require('./docling-rs.darwin-universal.node')
|
|
115
|
+
} else {
|
|
116
|
+
nativeBinding = require('docling.rs-darwin-universal')
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
} catch {}
|
|
120
|
+
switch (arch) {
|
|
121
|
+
case 'x64':
|
|
122
|
+
localFileExisted = existsSync(join(__dirname, 'docling-rs.darwin-x64.node'))
|
|
123
|
+
try {
|
|
124
|
+
if (localFileExisted) {
|
|
125
|
+
nativeBinding = require('./docling-rs.darwin-x64.node')
|
|
126
|
+
} else {
|
|
127
|
+
nativeBinding = require('docling.rs-darwin-x64')
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
loadError = e
|
|
131
|
+
}
|
|
132
|
+
break
|
|
133
|
+
case 'arm64':
|
|
134
|
+
localFileExisted = existsSync(
|
|
135
|
+
join(__dirname, 'docling-rs.darwin-arm64.node')
|
|
136
|
+
)
|
|
137
|
+
try {
|
|
138
|
+
if (localFileExisted) {
|
|
139
|
+
nativeBinding = require('./docling-rs.darwin-arm64.node')
|
|
140
|
+
} else {
|
|
141
|
+
nativeBinding = require('docling.rs-darwin-arm64')
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {
|
|
144
|
+
loadError = e
|
|
145
|
+
}
|
|
146
|
+
break
|
|
147
|
+
default:
|
|
148
|
+
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
|
149
|
+
}
|
|
150
|
+
break
|
|
151
|
+
case 'freebsd':
|
|
152
|
+
if (arch !== 'x64') {
|
|
153
|
+
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
|
154
|
+
}
|
|
155
|
+
localFileExisted = existsSync(join(__dirname, 'docling-rs.freebsd-x64.node'))
|
|
156
|
+
try {
|
|
157
|
+
if (localFileExisted) {
|
|
158
|
+
nativeBinding = require('./docling-rs.freebsd-x64.node')
|
|
159
|
+
} else {
|
|
160
|
+
nativeBinding = require('docling.rs-freebsd-x64')
|
|
161
|
+
}
|
|
162
|
+
} catch (e) {
|
|
163
|
+
loadError = e
|
|
164
|
+
}
|
|
165
|
+
break
|
|
166
|
+
case 'linux':
|
|
167
|
+
switch (arch) {
|
|
168
|
+
case 'x64':
|
|
169
|
+
if (isMusl()) {
|
|
170
|
+
localFileExisted = existsSync(
|
|
171
|
+
join(__dirname, 'docling-rs.linux-x64-musl.node')
|
|
172
|
+
)
|
|
173
|
+
try {
|
|
174
|
+
if (localFileExisted) {
|
|
175
|
+
nativeBinding = require('./docling-rs.linux-x64-musl.node')
|
|
176
|
+
} else {
|
|
177
|
+
nativeBinding = require('docling.rs-linux-x64-musl')
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
loadError = e
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
localFileExisted = existsSync(
|
|
184
|
+
join(__dirname, 'docling-rs.linux-x64-gnu.node')
|
|
185
|
+
)
|
|
186
|
+
try {
|
|
187
|
+
if (localFileExisted) {
|
|
188
|
+
nativeBinding = require('./docling-rs.linux-x64-gnu.node')
|
|
189
|
+
} else {
|
|
190
|
+
nativeBinding = require('docling.rs-linux-x64-gnu')
|
|
191
|
+
}
|
|
192
|
+
} catch (e) {
|
|
193
|
+
loadError = e
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break
|
|
197
|
+
case 'arm64':
|
|
198
|
+
if (isMusl()) {
|
|
199
|
+
localFileExisted = existsSync(
|
|
200
|
+
join(__dirname, 'docling-rs.linux-arm64-musl.node')
|
|
201
|
+
)
|
|
202
|
+
try {
|
|
203
|
+
if (localFileExisted) {
|
|
204
|
+
nativeBinding = require('./docling-rs.linux-arm64-musl.node')
|
|
205
|
+
} else {
|
|
206
|
+
nativeBinding = require('docling.rs-linux-arm64-musl')
|
|
207
|
+
}
|
|
208
|
+
} catch (e) {
|
|
209
|
+
loadError = e
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
localFileExisted = existsSync(
|
|
213
|
+
join(__dirname, 'docling-rs.linux-arm64-gnu.node')
|
|
214
|
+
)
|
|
215
|
+
try {
|
|
216
|
+
if (localFileExisted) {
|
|
217
|
+
nativeBinding = require('./docling-rs.linux-arm64-gnu.node')
|
|
218
|
+
} else {
|
|
219
|
+
nativeBinding = require('docling.rs-linux-arm64-gnu')
|
|
220
|
+
}
|
|
221
|
+
} catch (e) {
|
|
222
|
+
loadError = e
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
break
|
|
226
|
+
case 'arm':
|
|
227
|
+
if (isMusl()) {
|
|
228
|
+
localFileExisted = existsSync(
|
|
229
|
+
join(__dirname, 'docling-rs.linux-arm-musleabihf.node')
|
|
230
|
+
)
|
|
231
|
+
try {
|
|
232
|
+
if (localFileExisted) {
|
|
233
|
+
nativeBinding = require('./docling-rs.linux-arm-musleabihf.node')
|
|
234
|
+
} else {
|
|
235
|
+
nativeBinding = require('docling.rs-linux-arm-musleabihf')
|
|
236
|
+
}
|
|
237
|
+
} catch (e) {
|
|
238
|
+
loadError = e
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
localFileExisted = existsSync(
|
|
242
|
+
join(__dirname, 'docling-rs.linux-arm-gnueabihf.node')
|
|
243
|
+
)
|
|
244
|
+
try {
|
|
245
|
+
if (localFileExisted) {
|
|
246
|
+
nativeBinding = require('./docling-rs.linux-arm-gnueabihf.node')
|
|
247
|
+
} else {
|
|
248
|
+
nativeBinding = require('docling.rs-linux-arm-gnueabihf')
|
|
249
|
+
}
|
|
250
|
+
} catch (e) {
|
|
251
|
+
loadError = e
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
break
|
|
255
|
+
case 'riscv64':
|
|
256
|
+
if (isMusl()) {
|
|
257
|
+
localFileExisted = existsSync(
|
|
258
|
+
join(__dirname, 'docling-rs.linux-riscv64-musl.node')
|
|
259
|
+
)
|
|
260
|
+
try {
|
|
261
|
+
if (localFileExisted) {
|
|
262
|
+
nativeBinding = require('./docling-rs.linux-riscv64-musl.node')
|
|
263
|
+
} else {
|
|
264
|
+
nativeBinding = require('docling.rs-linux-riscv64-musl')
|
|
265
|
+
}
|
|
266
|
+
} catch (e) {
|
|
267
|
+
loadError = e
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
localFileExisted = existsSync(
|
|
271
|
+
join(__dirname, 'docling-rs.linux-riscv64-gnu.node')
|
|
272
|
+
)
|
|
273
|
+
try {
|
|
274
|
+
if (localFileExisted) {
|
|
275
|
+
nativeBinding = require('./docling-rs.linux-riscv64-gnu.node')
|
|
276
|
+
} else {
|
|
277
|
+
nativeBinding = require('docling.rs-linux-riscv64-gnu')
|
|
278
|
+
}
|
|
279
|
+
} catch (e) {
|
|
280
|
+
loadError = e
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break
|
|
284
|
+
case 's390x':
|
|
285
|
+
localFileExisted = existsSync(
|
|
286
|
+
join(__dirname, 'docling-rs.linux-s390x-gnu.node')
|
|
287
|
+
)
|
|
288
|
+
try {
|
|
289
|
+
if (localFileExisted) {
|
|
290
|
+
nativeBinding = require('./docling-rs.linux-s390x-gnu.node')
|
|
291
|
+
} else {
|
|
292
|
+
nativeBinding = require('docling.rs-linux-s390x-gnu')
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {
|
|
295
|
+
loadError = e
|
|
296
|
+
}
|
|
297
|
+
break
|
|
298
|
+
default:
|
|
299
|
+
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
|
300
|
+
}
|
|
301
|
+
break
|
|
302
|
+
default:
|
|
303
|
+
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!nativeBinding) {
|
|
307
|
+
if (loadError) {
|
|
308
|
+
throw loadError
|
|
309
|
+
}
|
|
310
|
+
throw new Error(`Failed to load native binding`)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const { convertFile, convert, convertFileAsync, convertAsync, DocumentConverter, Pipeline, supportedFormats, formatFromName } = nativeBinding
|
|
314
|
+
|
|
315
|
+
module.exports.convertFile = convertFile
|
|
316
|
+
module.exports.convert = convert
|
|
317
|
+
module.exports.convertFileAsync = convertFileAsync
|
|
318
|
+
module.exports.convertAsync = convertAsync
|
|
319
|
+
module.exports.DocumentConverter = DocumentConverter
|
|
320
|
+
module.exports.Pipeline = Pipeline
|
|
321
|
+
module.exports.supportedFormats = supportedFormats
|
|
322
|
+
module.exports.formatFromName = formatFromName
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "docling.rs",
|
|
3
|
+
"version": "0.20.0",
|
|
4
|
+
"description": "Node.js / Bun bindings for docling.rs — a Rust port of docling. Convert Markdown, HTML, DOCX, PPTX, XLSX, PDF, images and more into a unified DoclingDocument (Markdown or docling-core JSON).",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"docling",
|
|
7
|
+
"document",
|
|
8
|
+
"pdf",
|
|
9
|
+
"markdown",
|
|
10
|
+
"docx",
|
|
11
|
+
"converter",
|
|
12
|
+
"napi",
|
|
13
|
+
"bun"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/artiz/docling.rs.git",
|
|
19
|
+
"directory": "crates/docling-node"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/artiz/docling.rs",
|
|
22
|
+
"main": "index.js",
|
|
23
|
+
"types": "index.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./index.d.ts",
|
|
27
|
+
"import": "./index.js",
|
|
28
|
+
"require": "./index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"napi": {
|
|
32
|
+
"name": "docling-rs",
|
|
33
|
+
"triples": {
|
|
34
|
+
"defaults": false,
|
|
35
|
+
"additional": [
|
|
36
|
+
"x86_64-unknown-linux-gnu",
|
|
37
|
+
"aarch64-unknown-linux-gnu",
|
|
38
|
+
"x86_64-pc-windows-msvc"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">= 14"
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"index.js",
|
|
47
|
+
"index.d.ts",
|
|
48
|
+
"deps.js",
|
|
49
|
+
"native.js",
|
|
50
|
+
"native.d.ts",
|
|
51
|
+
"README.md"
|
|
52
|
+
],
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "napi build --platform --release --strip --js native.js --dts native.d.ts",
|
|
55
|
+
"build:debug": "napi build --platform --js native.js --dts native.d.ts",
|
|
56
|
+
"artifacts": "napi artifacts",
|
|
57
|
+
"prepublishOnly": "napi prepublish -t npm --skip-gh-release",
|
|
58
|
+
"version": "napi version",
|
|
59
|
+
"test": "node test/smoke.mjs",
|
|
60
|
+
"example": "npm --prefix examples install && node examples/node-basic.mjs",
|
|
61
|
+
"example:bun": "npm --prefix examples install && bun run examples/bun-basic.ts"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@napi-rs/cli": "^2.18.4"
|
|
65
|
+
},
|
|
66
|
+
"optionalDependencies": {
|
|
67
|
+
"docling.rs-linux-x64-gnu": "0.20.0",
|
|
68
|
+
"docling.rs-linux-arm64-gnu": "0.20.0",
|
|
69
|
+
"docling.rs-win32-x64-msvc": "0.20.0"
|
|
70
|
+
}
|
|
71
|
+
}
|