@reportwright/engine 0.12.0 → 0.13.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/CHANGELOG.md +133 -1
- package/README.md +133 -12
- package/THIRD-PARTY-NOTICES.md +52 -0
- package/dist/index.js +6066 -4454
- package/dist/pdfstreamworker.js +2 -2
- package/dist/types/packages/engine/entry.d.ts +87 -5
- package/dist/types/src/engine/data/guard.d.ts +4 -1
- package/dist/types/src/engine/data/index.d.ts +14 -1
- package/dist/types/src/engine/expr/evaluate.d.ts +1 -0
- package/dist/types/src/engine/index.d.ts +11 -3
- package/dist/types/src/engine/items/chart-kit.d.ts +6 -0
- package/dist/types/src/engine/lazylibs.d.ts +46 -0
- package/dist/types/src/engine/notices.d.ts +1 -0
- package/dist/types/src/engine/options.d.ts +10 -0
- package/dist/types/src/engine/schema/report.schema.d.ts +3 -0
- package/dist/types/src/engine/stream.d.ts +32 -35
- package/dist/types/src/engine/text/fonts.d.ts +30 -5
- package/dist/types/src/engine/text/measure.d.ts +6 -0
- package/dist/types/src/engine/text/standard.d.ts +42 -0
- package/dist/types/src/exporters/docx.d.ts +19 -1
- package/dist/types/src/exporters/html.d.ts +9 -5
- package/dist/types/src/exporters/officestream.d.ts +27 -0
- package/dist/types/src/exporters/pdf.d.ts +5 -3
- package/dist/types/src/exporters/pdfpaint.d.ts +3 -11
- package/dist/types/src/exporters/pdfstandard.d.ts +23 -0
- package/dist/types/src/exporters/pdfstream.d.ts +16 -8
- package/dist/types/src/exporters/pdfstreamtags.d.ts +8 -1
- package/dist/types/src/exporters/spill.d.ts +20 -0
- package/dist/types/src/exporters/subset.d.ts +15 -0
- package/dist/types/src/exporters/xlsxstream.d.ts +22 -0
- package/examples/stream-1m.mjs +21 -8
- package/package.json +5 -3
- package/pool/worker.js +1 -1
- package/report.d.ts +1 -0
- package/schema.json +3 -0
package/dist/pdfstreamworker.js
CHANGED
|
@@ -21,7 +21,7 @@ parentPort.on('message', async (/** @type {any} */ job) => {
|
|
|
21
21
|
const m = await render(job.def, { ...job.opts, fontStore, sources: { __rows: { rows: job.rows } }, pageWindow: job.pageWindow });
|
|
22
22
|
// a writer of its own for the names and glyphs (nothing is written): the pages' links name pages by placeholder
|
|
23
23
|
const rec = createPdfStream({ write() {} }, { fontStore });
|
|
24
|
-
const env = paintEnv(rec, fontStore, { drillBase: job.drillBase, pageRef: (i) => `@@P${i}
|
|
24
|
+
const env = paintEnv(rec, fontStore, { drillBase: job.drillBase, pageRef: (i) => `@@P${i}@@`, embedAll: job.embedAll });
|
|
25
25
|
const pages = [], transfer = [];
|
|
26
26
|
for (let k = 0; k < Math.min(job.keep, m.pages.length); k++) {
|
|
27
27
|
const pg = m.pages[k];
|
|
@@ -31,7 +31,7 @@ parentPort.on('message', async (/** @type {any} */ job) => {
|
|
|
31
31
|
pages.push({ deflated: z, annots, width: pg.width, height: pg.height, firstRow: pg.firstRow, rowHead: pg.rowHead, headLevel: pg.headLevel });
|
|
32
32
|
}
|
|
33
33
|
parentPort.postMessage({ id: job.id, count: m.pages.length, nextFirst: m.pages[job.keep]?.firstRow, pages, used: rec.used(),
|
|
34
|
-
shaped: [...env.shaped].map(([k, g]) => [k, [...g]]), bookmarks: m.bookmarks, headings: m.headings, warnings: m.warnings, ms: Date.now() - t0 }, transfer);
|
|
34
|
+
shaped: [...env.shaped].map(([k, g]) => [k, [...g]]), embedded: [...env.embedded || []], bookmarks: m.bookmarks, headings: m.headings, warnings: m.warnings, ms: Date.now() - t0 }, transfer);
|
|
35
35
|
} catch (e) {
|
|
36
36
|
parentPort.postMessage({ id: job.id, error: { message: String(/** @type {any} */ (e)?.message || e), status: /** @type {any} */ (e)?.status, timeout: /** @type {any} */ (e)?.timeout } });
|
|
37
37
|
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
export function defaultFontStore(opts?: {
|
|
9
9
|
fontsUrl?: string;
|
|
10
10
|
}): FontStore;
|
|
11
|
+
export function render(def0: any, opts?: import("../../src/engine/index.js").RenderOptions): Promise<any>;
|
|
11
12
|
/**
|
|
12
13
|
* @typedef {Omit<NonNullable<Parameters<typeof exportPdfFull>[2]>, 'subset' | 'pdfa'> & {
|
|
13
14
|
* fonts?: FontStore, subset?: false | NonNullable<Parameters<typeof exportPdfFull>[2]>['subset'],
|
|
@@ -49,10 +50,17 @@ export function exportPptx(model: any, options?: NonNullable<Parameters<typeof e
|
|
|
49
50
|
fonts?: FontStore;
|
|
50
51
|
}, ...args: any[]): Promise<Uint8Array>;
|
|
51
52
|
/**
|
|
52
|
-
* @typedef {RenderOptions & Omit<PdfOptions, 'fonts'> & { fonts?: FontStore, tagged?: { lang?: string },
|
|
53
|
-
* window?: number, parallel?: number, maxRows?: number, id?: string
|
|
53
|
+
* @typedef {RenderOptions & Omit<PdfOptions, 'fonts'> & { fonts?: FontStore, tagged?: { lang?: string, maxElements?: number },
|
|
54
|
+
* window?: number, parallel?: number, maxRows?: number, id?: string, presorted?: boolean, signal?: AbortSignal,
|
|
55
|
+
* spill?: false | { dir?: string, maxMB?: number }, sorter?: (cmp: (a: any, b: any) => number) => any }} PdfStreamOptions
|
|
54
56
|
* render()'s options and exportPdf's, plus: window (rows laid out at once, 1000), parallel (Node: worker threads
|
|
55
|
-
* that lay out and paint pages, opt-in; the file is the same
|
|
57
|
+
* that lay out and paint pages, opt-in; the file is the same, each thread costs memory), maxRows (rows read,
|
|
58
|
+
* 5,000,000), id (the file ID). presorted: the rows come in the report's order (its sort, its groups together), so
|
|
59
|
+
* they are not sorted, only checked as they pass (a row out of order stops the export). spill: where a sort's runs go
|
|
60
|
+
* (Node: the system temp folder, 2 GB at most; false sorts in memory); in a browser a sort is in memory.
|
|
61
|
+
* timeoutMs: the whole export's time limit, waits for the sink included (504, code 'ETIMEDOUT'). signal: an
|
|
62
|
+
* AbortSignal that stops the export at its next wait (rejects with the signal's reason, an AbortError); sqlRows gets
|
|
63
|
+
* it as its third argument ({ signal }) so a database cursor can cancel its query.
|
|
56
64
|
*/
|
|
57
65
|
/**
|
|
58
66
|
* Report definition → PDF written to a sink as it is made, for reports too large to hold as a page model: a flowing
|
|
@@ -73,6 +81,66 @@ export function exportPdfStream(def: any, options: PdfStreamOptions, sink: {
|
|
|
73
81
|
warnings: string[];
|
|
74
82
|
why?: string;
|
|
75
83
|
}>;
|
|
84
|
+
/**
|
|
85
|
+
* Report definition → .docx written to a sink as its pages are laid out (exportPdfStream's sink, timeoutMs, signal,
|
|
86
|
+
* window, maxRows, sqlRows and spill): a flowing table report is never held whole; any other report is rendered whole
|
|
87
|
+
* and written in one piece (the result's why says why).
|
|
88
|
+
* @param {any} def @param {RenderOptions & { fonts?: FontStore, title?: string, lang?: string, figures?: boolean, timeoutMs?: number, signal?: AbortSignal,
|
|
89
|
+
* window?: number, maxRows?: number, spill?: false | { dir?: string, maxMB?: number } }} options
|
|
90
|
+
* @param {{ write(bytes: Uint8Array): any, once?: (ev: string, cb: () => void) => any }} sink not closed
|
|
91
|
+
* @returns {Promise<{ streamed: boolean, pages?: number, warnings: string[], why?: string }>}
|
|
92
|
+
*/
|
|
93
|
+
export function exportDocxStream(def: any, options: RenderOptions & {
|
|
94
|
+
fonts?: FontStore;
|
|
95
|
+
title?: string;
|
|
96
|
+
lang?: string;
|
|
97
|
+
figures?: boolean;
|
|
98
|
+
timeoutMs?: number;
|
|
99
|
+
signal?: AbortSignal;
|
|
100
|
+
window?: number;
|
|
101
|
+
maxRows?: number;
|
|
102
|
+
spill?: false | {
|
|
103
|
+
dir?: string;
|
|
104
|
+
maxMB?: number;
|
|
105
|
+
};
|
|
106
|
+
}, sink: {
|
|
107
|
+
write(bytes: Uint8Array): any;
|
|
108
|
+
once?: (ev: string, cb: () => void) => any;
|
|
109
|
+
}): Promise<{
|
|
110
|
+
streamed: boolean;
|
|
111
|
+
pages?: number;
|
|
112
|
+
warnings: string[];
|
|
113
|
+
why?: string;
|
|
114
|
+
}>;
|
|
115
|
+
/**
|
|
116
|
+
* Report definition → .xlsx written to a sink row by row (exportPdfStream's sink, timeoutMs, signal, maxRows, sqlRows
|
|
117
|
+
* and spill); any other report is rendered whole and written in one piece (the result's why says why).
|
|
118
|
+
* @param {any} def @param {RenderOptions & { fonts?: FontStore, title?: string, currency?: string, formulas?: boolean, timeoutMs?: number, signal?: AbortSignal,
|
|
119
|
+
* maxRows?: number, spill?: false | { dir?: string, maxMB?: number } }} options
|
|
120
|
+
* @param {{ write(bytes: Uint8Array): any, once?: (ev: string, cb: () => void) => any }} sink not closed
|
|
121
|
+
* @returns {Promise<{ streamed: boolean, rows?: number, warnings: string[], why?: string }>}
|
|
122
|
+
*/
|
|
123
|
+
export function exportXlsxStream(def: any, options: RenderOptions & {
|
|
124
|
+
fonts?: FontStore;
|
|
125
|
+
title?: string;
|
|
126
|
+
currency?: string;
|
|
127
|
+
formulas?: boolean;
|
|
128
|
+
timeoutMs?: number;
|
|
129
|
+
signal?: AbortSignal;
|
|
130
|
+
maxRows?: number;
|
|
131
|
+
spill?: false | {
|
|
132
|
+
dir?: string;
|
|
133
|
+
maxMB?: number;
|
|
134
|
+
};
|
|
135
|
+
}, sink: {
|
|
136
|
+
write(bytes: Uint8Array): any;
|
|
137
|
+
once?: (ev: string, cb: () => void) => any;
|
|
138
|
+
}): Promise<{
|
|
139
|
+
streamed: boolean;
|
|
140
|
+
rows?: number;
|
|
141
|
+
warnings: string[];
|
|
142
|
+
why?: string;
|
|
143
|
+
}>;
|
|
76
144
|
export { validate } from "../../src/engine/schema/validate.js";
|
|
77
145
|
export { exportHtml } from "../../src/exporters/html.js";
|
|
78
146
|
export { exportCsv } from "../../src/exporters/csv.js";
|
|
@@ -95,17 +163,31 @@ export type PdfOptions = Omit<NonNullable<Parameters<typeof exportPdfFull>[2]>,
|
|
|
95
163
|
};
|
|
96
164
|
/**
|
|
97
165
|
* render()'s options and exportPdf's, plus: window (rows laid out at once, 1000), parallel (Node: worker threads
|
|
98
|
-
* that lay out and paint pages, opt-in; the file is the same
|
|
166
|
+
* that lay out and paint pages, opt-in; the file is the same, each thread costs memory), maxRows (rows read,
|
|
167
|
+
* 5,000,000), id (the file ID). presorted: the rows come in the report's order (its sort, its groups together), so
|
|
168
|
+
* they are not sorted, only checked as they pass (a row out of order stops the export). spill: where a sort's runs go
|
|
169
|
+
* (Node: the system temp folder, 2 GB at most; false sorts in memory); in a browser a sort is in memory.
|
|
170
|
+
* timeoutMs: the whole export's time limit, waits for the sink included (504, code 'ETIMEDOUT'). signal: an
|
|
171
|
+
* AbortSignal that stops the export at its next wait (rejects with the signal's reason, an AbortError); sqlRows gets
|
|
172
|
+
* it as its third argument ({ signal }) so a database cursor can cancel its query.
|
|
99
173
|
*/
|
|
100
174
|
export type PdfStreamOptions = RenderOptions & Omit<PdfOptions, "fonts"> & {
|
|
101
175
|
fonts?: FontStore;
|
|
102
176
|
tagged?: {
|
|
103
177
|
lang?: string;
|
|
178
|
+
maxElements?: number;
|
|
104
179
|
};
|
|
105
180
|
window?: number;
|
|
106
181
|
parallel?: number;
|
|
107
182
|
maxRows?: number;
|
|
108
183
|
id?: string;
|
|
184
|
+
presorted?: boolean;
|
|
185
|
+
signal?: AbortSignal;
|
|
186
|
+
spill?: false | {
|
|
187
|
+
dir?: string;
|
|
188
|
+
maxMB?: number;
|
|
189
|
+
};
|
|
190
|
+
sorter?: (cmp: (a: any, b: any) => number) => any;
|
|
109
191
|
};
|
|
110
192
|
export type RenderOptions = import("../../src/engine/index.js").RenderOptions;
|
|
111
193
|
import { FontStore } from '../../src/engine/index.js';
|
|
@@ -120,6 +202,6 @@ import { paintEnv } from '../../src/exporters/pdfstream.js';
|
|
|
120
202
|
import { latin1 } from '../../src/exporters/pdfpaint.js';
|
|
121
203
|
import { exportPdf as exportPdfFull } from '../../src/exporters/pdf.js';
|
|
122
204
|
export { fontFile, createSubsetter };
|
|
123
|
-
export {
|
|
205
|
+
export { FontStore, ITEMS, parameterOptions, resolveParameters } from "../../src/engine/index.js";
|
|
124
206
|
export { blankReport, blankDashboard } from "../../src/engine/schema/template.js";
|
|
125
207
|
export { tableFor, matrixFor } from "../../src/designer/tableGen.js";
|
|
@@ -16,11 +16,14 @@ export function redirectRequest(from: URL, to: URL, req: any, status: number): a
|
|
|
16
16
|
/**
|
|
17
17
|
* The guarded default fetch (see the top of this file). In Node every hop goes through nodeRequest (address pinned);
|
|
18
18
|
* in a browser through `base` with redirects by hand (literal addresses checked; a browser has no DNS to ask).
|
|
19
|
-
* @param {{ allowHosts?: string[] }} opt
|
|
19
|
+
* @param {{ allowHosts?: string[], viaBase?: boolean }} opt viaBase: every hop through `base`, in Node too (the browser
|
|
20
|
+
* viewer's fetch, which its tests run in Node)
|
|
21
|
+
* @param {typeof fetch} base
|
|
20
22
|
* @returns {typeof fetch}
|
|
21
23
|
*/
|
|
22
24
|
export function guardedFetch(opt: {
|
|
23
25
|
allowHosts?: string[];
|
|
26
|
+
viaBase?: boolean;
|
|
24
27
|
}, base: typeof fetch): typeof fetch;
|
|
25
28
|
/**
|
|
26
29
|
* Any fetch with the engine's time limit and byte cap.
|
|
@@ -13,13 +13,26 @@ export function jsonPathRows(obj: any, path: any): {
|
|
|
13
13
|
* A raw value as the field's type. Numbers in text are read the locale's way ("12,5" and "1.234,56" in de-DE, "1,234.5"
|
|
14
14
|
* and "(1,234)" in en-US); dates without a zone are the wall clock of the report's zone. A value that does not read
|
|
15
15
|
* is null, and opt.bad hears of it (the data set warns once).
|
|
16
|
-
* @param {any} v @param {string} type @param {{ locale?: string, timeZone?: string, bad?: (v: any) => void }} [opt]
|
|
16
|
+
* @param {any} v @param {string} type @param {{ locale?: string, timeZone?: string, bad?: (v: any) => void, empty?: () => void }} [opt]
|
|
17
17
|
*/
|
|
18
18
|
export function coerce(v: any, type: string, opt?: {
|
|
19
19
|
locale?: string;
|
|
20
20
|
timeZone?: string;
|
|
21
21
|
bad?: (v: any) => void;
|
|
22
|
+
empty?: () => void;
|
|
22
23
|
}): any;
|
|
24
|
+
/**
|
|
25
|
+
* Counts, per field, the values that do not read as the field's type (and the empty ones), for one warning per field.
|
|
26
|
+
* Shared by the whole render (buildDataSets) and the streaming export, which both type rows with coerce().
|
|
27
|
+
* @param {string} dsName @param {(msg: string) => void} warn
|
|
28
|
+
*/
|
|
29
|
+
export function badValues(dsName: string, warn: (msg: string) => void): {
|
|
30
|
+
/** the row being typed, 1-based */
|
|
31
|
+
at: (n: number) => void;
|
|
32
|
+
/** coerce() options for one field, on top of base */
|
|
33
|
+
opt: (fd: any, base: any) => any;
|
|
34
|
+
done: () => void;
|
|
35
|
+
};
|
|
23
36
|
/**
|
|
24
37
|
* Guess field names and types from sample rows. A string that looks like an ISO date (2024-01-31, 2024-01-31T10:00Z)
|
|
25
38
|
* becomes a date field; dates: false (a data set's detectDates: false) keeps it text. To keep one field as text,
|
|
@@ -92,6 +92,7 @@ export const OVER_TIME: "The report ran past its time limit.";
|
|
|
92
92
|
export const ROW_PARENT: WeakMap<object, any>;
|
|
93
93
|
/** The aggregates a streaming export folds row by row (aggregator). */
|
|
94
94
|
export const FOLDS: Set<string>;
|
|
95
|
+
export function isAggregate(name: any): boolean;
|
|
95
96
|
export namespace FUNCTIONS {
|
|
96
97
|
function format(ctx: any, v: any, f: any): any;
|
|
97
98
|
function upper(ctx: any, s: any): any;
|
|
@@ -70,8 +70,6 @@ export class ReportError extends Error {
|
|
|
70
70
|
constructor(msg: string, extra?: object);
|
|
71
71
|
}
|
|
72
72
|
export const BAND_ITEMS: 250000;
|
|
73
|
-
/** The start of the warning for CJK text without the optional CJK fonts (the viewer opens its warnings for it). */
|
|
74
|
-
export const NO_CJK_FONTS: "Text in Japanese/Chinese/Korean needs the optional CJK fonts: npm run fonts:cjk";
|
|
75
73
|
/**
|
|
76
74
|
* Options for render(). All optional.
|
|
77
75
|
*/
|
|
@@ -90,6 +88,10 @@ export type RenderOptions = {
|
|
|
90
88
|
* the fonts; share one across renders (a new one loads them again)
|
|
91
89
|
*/
|
|
92
90
|
fontStore?: import("./text/fonts.js").FontStore;
|
|
91
|
+
/**
|
|
92
|
+
* the viewer: load only the core face up front; the other bundled faces when the layout first needs one
|
|
93
|
+
*/
|
|
94
|
+
lazyFonts?: boolean;
|
|
93
95
|
/**
|
|
94
96
|
* loads a font the store does not have
|
|
95
97
|
*/
|
|
@@ -174,6 +176,11 @@ export type RenderOptions = {
|
|
|
174
176
|
* the zone dates show in, when the report sets none
|
|
175
177
|
*/
|
|
176
178
|
timeZone?: string;
|
|
179
|
+
/**
|
|
180
|
+
* the engine package's render() warns once (model.warnings, and the console once
|
|
181
|
+
* per process) when a data set has more rows than this, pointing at exportPdfStream (default 100000; 0 or false: no warning)
|
|
182
|
+
*/
|
|
183
|
+
largeReportRows?: number | false;
|
|
177
184
|
/**
|
|
178
185
|
* internal (subreports): the width the child body is laid out to
|
|
179
186
|
*/
|
|
@@ -232,8 +239,9 @@ export type RenderOptions = {
|
|
|
232
239
|
} | null)[];
|
|
233
240
|
};
|
|
234
241
|
};
|
|
242
|
+
import { NO_CJK_FONTS } from './notices.js';
|
|
235
243
|
import { FontStore } from './text/fonts.js';
|
|
236
244
|
import { TextMeasurer } from './text/measure.js';
|
|
237
245
|
import { ITEMS } from './items/index.js';
|
|
238
246
|
import { finishText } from './text/measure.js';
|
|
239
|
-
export { FontStore, TextMeasurer, ITEMS, finishText };
|
|
247
|
+
export { NO_CJK_FONTS, FontStore, TextMeasurer, ITEMS, finishText };
|
|
@@ -10,6 +10,12 @@ export function niceScale(min: any, max: any, ticks?: number): {
|
|
|
10
10
|
hi: number;
|
|
11
11
|
step: number;
|
|
12
12
|
};
|
|
13
|
+
/** A nice scale whose step is the span over the ticks: niceScale rounds the span first, which can add a whole step. */
|
|
14
|
+
export function niceScaleSpan(min: any, max: any, ticks?: number): {
|
|
15
|
+
lo: number;
|
|
16
|
+
hi: number;
|
|
17
|
+
step: number;
|
|
18
|
+
};
|
|
13
19
|
/** Ticks from lo to hi by step, rounded so 0.1 + 0.2 reads 0.3. At most 200 (a bad min/max cannot loop for ever). */
|
|
14
20
|
export function linearTicks(lo: any, hi: any, step: any): any[];
|
|
15
21
|
/** Powers of ten covering [min, max] (both > 0); at least two. */
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pdf-lib and fontkit, loaded on first use rather than at import: evaluating them was most of the engine's import time
|
|
3
|
+
* (about 110 ms and 180 ms on an M2). await loadFontkit() (a font is parsed) or loadPdfLib() (exportPdf) first; the
|
|
4
|
+
* bindings below are set then (ES modules' live bindings: `import { PDFName } from './lazylibs.js'` sees them).
|
|
5
|
+
* Node: require() (both are CommonJS; import() of one costs ~60 ms more, its named exports read by Node's CJS lexer
|
|
6
|
+
* through every re-exported file). Elsewhere (a bundler, a browser): import(), which a bundler may split into a chunk.
|
|
7
|
+
*/
|
|
8
|
+
/** @typedef {typeof import('pdf-lib')} PdfLib */
|
|
9
|
+
/** @typedef {import('pdf-lib').PDFDocument} PDFDocument */
|
|
10
|
+
/** @typedef {import('pdf-lib').PDFName} PDFName */
|
|
11
|
+
/** @typedef {import('pdf-lib').PDFString} PDFString */
|
|
12
|
+
/** @typedef {import('pdf-lib').PDFHexString} PDFHexString */
|
|
13
|
+
/** @typedef {import('pdf-lib').PDFRawStream} PDFRawStream */
|
|
14
|
+
/** @typedef {import('pdf-lib').PDFStream} PDFStream */
|
|
15
|
+
/** @typedef {import('pdf-lib').PDFArray} PDFArray */
|
|
16
|
+
/** @typedef {import('pdf-lib').PDFDict} PDFDict */
|
|
17
|
+
/** @typedef {import('pdf-lib').PDFNumber} PDFNumber */
|
|
18
|
+
/** @typedef {import('pdf-lib').PDFBool} PDFBool */
|
|
19
|
+
/** @type {any} @pdf-lib/fontkit */ export let fontkit: any;
|
|
20
|
+
export type PDFDocument = import("pdf-lib").PDFDocument;
|
|
21
|
+
/** @type {PdfLib['PDFDocument']} */ export let PDFDocument: PdfLib["PDFDocument"];
|
|
22
|
+
export type PDFName = import("pdf-lib").PDFName;
|
|
23
|
+
/** @type {PdfLib['PDFName']} */ export let PDFName: PdfLib["PDFName"];
|
|
24
|
+
export type PDFString = import("pdf-lib").PDFString;
|
|
25
|
+
/** @type {PdfLib['PDFString']} */ export let PDFString: PdfLib["PDFString"];
|
|
26
|
+
export type PDFHexString = import("pdf-lib").PDFHexString;
|
|
27
|
+
/** @type {PdfLib['PDFHexString']} */ export let PDFHexString: PdfLib["PDFHexString"];
|
|
28
|
+
export type PDFRawStream = import("pdf-lib").PDFRawStream;
|
|
29
|
+
/** @type {PdfLib['PDFRawStream']} */ export let PDFRawStream: PdfLib["PDFRawStream"];
|
|
30
|
+
export type PDFStream = import("pdf-lib").PDFStream;
|
|
31
|
+
/** @type {PdfLib['PDFStream']} */ export let PDFStream: PdfLib["PDFStream"];
|
|
32
|
+
export type PDFArray = import("pdf-lib").PDFArray;
|
|
33
|
+
/** @type {PdfLib['PDFArray']} */ export let PDFArray: PdfLib["PDFArray"];
|
|
34
|
+
export type PDFDict = import("pdf-lib").PDFDict;
|
|
35
|
+
/** @type {PdfLib['PDFDict']} */ export let PDFDict: PdfLib["PDFDict"];
|
|
36
|
+
export type PDFNumber = import("pdf-lib").PDFNumber;
|
|
37
|
+
/** @type {PdfLib['PDFNumber']} */ export let PDFNumber: PdfLib["PDFNumber"];
|
|
38
|
+
export type PDFBool = import("pdf-lib").PDFBool;
|
|
39
|
+
/** @type {PdfLib['PDFBool']} */ export let PDFBool: PdfLib["PDFBool"];
|
|
40
|
+
/** @type {PdfLib['rgb']} */ export let rgb: PdfLib["rgb"];
|
|
41
|
+
/** @type {PdfLib['pushGraphicsState']} */ export let pushGraphicsState: PdfLib["pushGraphicsState"];
|
|
42
|
+
/** @type {PdfLib['popGraphicsState']} */ export let popGraphicsState: PdfLib["popGraphicsState"];
|
|
43
|
+
/** @type {PdfLib['concatTransformationMatrix']} */ export let concatTransformationMatrix: PdfLib["concatTransformationMatrix"];
|
|
44
|
+
export function loadFontkit(): Promise<void>;
|
|
45
|
+
export function loadPdfLib(): Promise<void>;
|
|
46
|
+
export type PdfLib = typeof import("pdf-lib");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const NO_CJK_FONTS: "Text in Japanese/Chinese/Korean needs the optional CJK fonts: npm i @reportwright/fonts-cjk, then npx reportwright-fonts-cjk (npm); in the app, npm run fonts:cjk";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The warnings for the keys of opts that are not options, each with the nearest option (Levenshtein 2 at most) as
|
|
3
|
+
* "Did you mean". A key close to a security option (encrypt, prepare) throws instead: carrying on would write a file
|
|
4
|
+
* without the password or signature the caller asked for.
|
|
5
|
+
* @param {any} opts @param {Set<string>} [known]
|
|
6
|
+
* @returns {string[]}
|
|
7
|
+
*/
|
|
8
|
+
export function checkOptions(opts: any, known?: Set<string>): string[];
|
|
9
|
+
/** every option the three functions (and what they pass on) read */
|
|
10
|
+
export const KNOWN_OPTIONS: Set<string>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* An in-memory sorter (the browser, the CLI): the server passes one that spills runs to disk (
|
|
2
|
+
* An in-memory sorter (the browser, the CLI): the server passes one that spills runs to disk (exporters/spill.js; exportPdfStream's default in Node).
|
|
3
3
|
* @param {(a: any, b: any) => number} cmp
|
|
4
4
|
*/
|
|
5
5
|
export function memorySorter(cmp: (a: any, b: any) => number): {
|
|
@@ -11,43 +11,40 @@ export function memorySorter(cmp: (a: any, b: any) => number): {
|
|
|
11
11
|
* @param {any} def0 the report definition
|
|
12
12
|
* @param {{ format: 'csv'|'xlsx', parameters?: object, timeZone?: string, now?: Date, state?: any, loadReport?: (id: string) => Promise<any>,
|
|
13
13
|
* reportId?: string, fetch?: typeof fetch, baseUrl?: string, sql?: (src: any, p: any) => Promise<object[]>,
|
|
14
|
-
* sqlRows?: (src: any, p: any) => AsyncIterable<object[]>, sources?: Record<string, any>, sorter?: (cmp: (a: any, b: any) => number) => any,
|
|
14
|
+
* sqlRows?: (src: any, p: any, o: { signal?: AbortSignal }) => AsyncIterable<object[]>, signal?: AbortSignal, sources?: Record<string, any>, sorter?: (cmp: (a: any, b: any) => number) => any, presorted?: boolean,
|
|
15
15
|
* deadline?: number, timeoutMs?: number, maxRows?: number, maxJsonRowBytes?: number, maxJsonWholeBytes?: number }} opts
|
|
16
|
-
* @returns {Promise<{ why: string } | { why?: undefined, name: string, columns: number[], title: string, timeZone: string|null, locale: string|null, currency: string|null, warnings: string[], rows: () => AsyncGenerator<any>, records: () => AsyncGenerator<any>, grouped: () => AsyncGenerator<any>, stats: { rows: number } }>}
|
|
16
|
+
* @returns {Promise<{ why: string } | { why?: undefined, name: string, columns: number[], title: string, timeZone: string|null, locale: string|null, currency: string|null, warnings: string[], rows: () => AsyncGenerator<any>, records: () => AsyncGenerator<any>, grouped: () => AsyncGenerator<any>, fieldList: () => Promise<any[]>, stats: { rows: number } }>}
|
|
17
17
|
*/
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
reportId?: string;
|
|
26
|
-
fetch?: typeof fetch;
|
|
27
|
-
baseUrl?: string;
|
|
28
|
-
sql?: (src: any, p: any) => Promise<object[]>;
|
|
29
|
-
sqlRows?: (src: any, p: any) => AsyncIterable<object[]>;
|
|
30
|
-
sources?: Record<string, any>;
|
|
31
|
-
sorter?: (cmp: (a: any, b: any) => number) => any;
|
|
32
|
-
deadline?: number;
|
|
33
|
-
timeoutMs?: number;
|
|
34
|
-
maxRows?: number;
|
|
35
|
-
maxJsonRowBytes?: number;
|
|
36
|
-
maxJsonWholeBytes?: number;
|
|
37
|
-
}): Promise<{
|
|
38
|
-
why: string;
|
|
18
|
+
/**
|
|
19
|
+
* The batches of a sqlRows source: an async or sync iterable of arrays of rows, each checked (a single row is a common slip).
|
|
20
|
+
* @param {Function} sqlRows @param {any} src @param {any} p @param {AbortSignal} [signal]
|
|
21
|
+
*/
|
|
22
|
+
export function sqlBatches(sqlRows: Function, src: any, p: any, signal?: AbortSignal): AsyncGenerator<any[], void, unknown>;
|
|
23
|
+
export function planStream(def0: any, opts: any): Promise<{
|
|
24
|
+
why: any;
|
|
39
25
|
} | {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
26
|
+
name: any;
|
|
27
|
+
columns: any;
|
|
28
|
+
title: any;
|
|
29
|
+
timeZone: any;
|
|
30
|
+
locale: any;
|
|
31
|
+
currency: any;
|
|
32
|
+
warnings: any[];
|
|
33
|
+
rows: () => AsyncGenerator<{
|
|
34
|
+
kind: any;
|
|
35
|
+
level: any;
|
|
36
|
+
cells: {
|
|
37
|
+
col: number;
|
|
38
|
+
value: any;
|
|
39
|
+
format: any;
|
|
40
|
+
bold: boolean;
|
|
41
|
+
span: number;
|
|
42
|
+
colIndex: number;
|
|
43
|
+
}[];
|
|
44
|
+
}, void, unknown>;
|
|
45
|
+
records: (grouped?: boolean) => AsyncGenerator<any, void, unknown>;
|
|
46
|
+
grouped: () => AsyncGenerator<any, void, unknown>;
|
|
47
|
+
fieldList: () => Promise<any>;
|
|
51
48
|
stats: {
|
|
52
49
|
rows: number;
|
|
53
50
|
};
|
|
@@ -11,12 +11,32 @@ export function setCustomFonts(list: {
|
|
|
11
11
|
weight?: number;
|
|
12
12
|
style?: string;
|
|
13
13
|
}[]): void;
|
|
14
|
+
/**
|
|
15
|
+
* The family a fontFamily value names: a registered family (any case), else the first of a CSS list that is one, else a
|
|
16
|
+
* generic name's family. Anything else is unknown: Inter, or JetBrains Mono for a monospace name, and `unknown` is the
|
|
17
|
+
* name the render warns about.
|
|
18
|
+
* @param {string} name @returns {{ family: string, unknown?: string }}
|
|
19
|
+
*/
|
|
20
|
+
export function familyOf(name: string): {
|
|
21
|
+
family: string;
|
|
22
|
+
unknown?: string;
|
|
23
|
+
};
|
|
14
24
|
/**
|
|
15
25
|
* The face for a family, weight and style, matched as CSS does: style first (italic faces when asked
|
|
16
|
-
* and there are some), then the nearest weight (CSS Fonts 4, §5.2). Unknown families use Inter
|
|
17
|
-
*
|
|
26
|
+
* and there are some), then the nearest weight (CSS Fonts 4, §5.2). Unknown families use Inter (JetBrains Mono for a
|
|
27
|
+
* monospace name), and their names go into `unknown`, for the render's warning (N39).
|
|
28
|
+
* @param {string} [family] @param {string|number} [weight] @param {string} [style] @param {Set<string>} [unknown]
|
|
29
|
+
*/
|
|
30
|
+
export function resolveFontKey(family?: string, weight?: string | number, style?: string, unknown?: Set<string>): string;
|
|
31
|
+
/**
|
|
32
|
+
* The embedded face that stands in for a standard font where one must be embedded (PDF/A, PDF/UA, form fields) and for
|
|
33
|
+
* the characters its encoding lacks: JetBrains Mono for Courier, else Inter, in the same weight and style. No
|
|
34
|
+
* metric-compatible face (Liberation, say) ships, so its widths differ. Any other key is returned as it is.
|
|
35
|
+
* @param {string} key
|
|
18
36
|
*/
|
|
19
|
-
export function
|
|
37
|
+
export function embeddedFace(key: string): string;
|
|
38
|
+
/** The name Word, Excel and PowerPoint know for a font key's family (the standard fonts by their Windows equivalents). */
|
|
39
|
+
export function officeFamily(key: any): any;
|
|
20
40
|
/** CSS description of a font key, for SVG/HTML output. */
|
|
21
41
|
export function fontCss(key: any): {
|
|
22
42
|
family: string;
|
|
@@ -45,10 +65,12 @@ export function fallbackKey(cp: any, key: any): string;
|
|
|
45
65
|
* The faces a report definition names before layout: every object with fontFamily, fontWeight or fontStyle (styles,
|
|
46
66
|
* named styles, item and rich-text styles, table and group styles), and the bold face a chart's titles use. Loaded up
|
|
47
67
|
* front, so a report that uses bold or italic lays out in one pass. Data (dataSources, inline data) is not read.
|
|
48
|
-
*
|
|
68
|
+
* Unknown family names go into `unknown` (the render warns about them).
|
|
69
|
+
* @param {any} def @param {Set<string>} [unknown] @returns {string[]} face keys
|
|
49
70
|
*/
|
|
50
|
-
export function fontsForDef(def: any): string[];
|
|
71
|
+
export function fontsForDef(def: any, unknown?: Set<string>): string[];
|
|
51
72
|
export function fontsFor(texts: any): any[];
|
|
73
|
+
export { isStandard };
|
|
52
74
|
/** The optional families (scripts/fetch-fonts-cjk.mjs). */
|
|
53
75
|
export const OPTIONAL_KEYS: string[];
|
|
54
76
|
/** family → its faces: the bundled families, then the fonts uploaded to the server (setCustomFonts). @type {Record<string, Face[]>} */
|
|
@@ -63,6 +85,7 @@ export const CORE_FONT_KEY: "Inter-Regular";
|
|
|
63
85
|
export const PRELOAD_KEYS: string[];
|
|
64
86
|
/** The HarfBuzz shaper (WASM). FontStore loads it like a font, from /fonts/harfbuzz.wasm, once text needs shaping. */
|
|
65
87
|
export const SHAPER: "harfbuzz";
|
|
88
|
+
export function standardCss(key: string): string | null;
|
|
66
89
|
export function allFontKeys(): string[];
|
|
67
90
|
/**
|
|
68
91
|
* Loads font files once and keeps the parsed fontkit objects; SHAPER loads the HarfBuzz shaper.
|
|
@@ -93,4 +116,6 @@ export type Face = {
|
|
|
93
116
|
weight: number;
|
|
94
117
|
style: "normal" | "italic";
|
|
95
118
|
file: string;
|
|
119
|
+
standard?: boolean;
|
|
96
120
|
};
|
|
121
|
+
import { isStandard } from './standard.js';
|
|
@@ -19,6 +19,8 @@ export function saBreaks(text: string, segmenter?: Intl.Segmenter | null): Set<n
|
|
|
19
19
|
* @param {any[]} items @param {TextMeasurer} m
|
|
20
20
|
*/
|
|
21
21
|
export function finishText(items: any[], m: TextMeasurer): void;
|
|
22
|
+
/** Unicode format characters (Cf): bidi marks and embeddings, joiners, soft hyphen. They have no shape of their own. */
|
|
23
|
+
export const FORMAT_CHAR: RegExp;
|
|
22
24
|
/**
|
|
23
25
|
* @typedef {{ font: string, x: number, w: number, text: string, rtl?: boolean, shaped?: boolean, glyphs: number[] }} Run
|
|
24
26
|
* One font, one direction. x and w in points from the start of the line; glyphs: [id, x, y, cluster] per glyph
|
|
@@ -43,6 +45,10 @@ export class TextMeasurer {
|
|
|
43
45
|
missing: Set<string>;
|
|
44
46
|
/** characters no font could draw @type {Set<string>} */
|
|
45
47
|
noGlyph: Set<string>;
|
|
48
|
+
/** font names the text asked for that are not available (resolveFontKey): the render warns @type {Set<string>} */
|
|
49
|
+
unknownFonts: Set<string>;
|
|
50
|
+
/** standard-font key → the characters its encoding lacks, drawn in embeddedFace(key): the render warns @type {Map<string, Set<string>>} */
|
|
51
|
+
substituted: Map<string, Set<string>>;
|
|
46
52
|
/**
|
|
47
53
|
* The key to measure with: `key` when loaded; else (not loaded yet, or failed) the bundled face of the same weight
|
|
48
54
|
* and style when that is loaded, else the core regular face. A key not yet loaded is asked for in the next pass.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A standard font as a fontkit-like object (unitsPerEm 1000). Loaded on first use: the metrics are about 130 KB.
|
|
3
|
+
* @param {string} key a PostScript name of STANDARD_FACES
|
|
4
|
+
*/
|
|
5
|
+
export function standardFont(key: string): Promise<{
|
|
6
|
+
standard: boolean;
|
|
7
|
+
postscriptName: string;
|
|
8
|
+
familyName: any;
|
|
9
|
+
unitsPerEm: number;
|
|
10
|
+
ascent: any;
|
|
11
|
+
descent: any;
|
|
12
|
+
capHeight: any;
|
|
13
|
+
xHeight: any;
|
|
14
|
+
italicAngle: number;
|
|
15
|
+
underlinePosition: any;
|
|
16
|
+
underlineThickness: any;
|
|
17
|
+
bbox: {
|
|
18
|
+
minX: any;
|
|
19
|
+
minY: any;
|
|
20
|
+
maxX: any;
|
|
21
|
+
maxY: any;
|
|
22
|
+
};
|
|
23
|
+
/** WinAnsi for the text fonts (Symbol and ZapfDingbats use their own built-in encodings) */
|
|
24
|
+
winAnsi: boolean;
|
|
25
|
+
widths: any[];
|
|
26
|
+
/** @param {number} cp */
|
|
27
|
+
hasGlyphForCodePoint: (cp: number) => boolean;
|
|
28
|
+
/** @param {number} cp */
|
|
29
|
+
glyphForCodePoint: (cp: number) => any;
|
|
30
|
+
getGlyph: (id: number) => any;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* The 14 standard PDF fonts (Helvetica, Times, Courier in four faces each, Symbol, ZapfDingbats): every PDF reader has
|
|
34
|
+
* them, so a PDF names them and embeds nothing. Their metrics are Adobe's AFM files, as @pdf-lib/standard-fonts (pdf-lib's
|
|
35
|
+
* own dependency) ships them; this wraps one in the part of fontkit's font API the engine and the PDF exporters read, so
|
|
36
|
+
* layout measures with the widths the PDF's /Widths array gives. A glyph ID here is the character's code in the font's
|
|
37
|
+
* encoding (WinAnsi; Symbol and ZapfDingbats have their own), one byte; 0 = not in the encoding.
|
|
38
|
+
*/
|
|
39
|
+
/** [family, PostScript name, weight, style] */
|
|
40
|
+
export const STANDARD_FACES: (string | number)[][];
|
|
41
|
+
export const STANDARD_KEYS: Set<string>;
|
|
42
|
+
export function isStandard(key: string): boolean;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
/** The string cut into pieces of at most about max chars, each ending at a '>' (a tag boundary), so their join is s. */
|
|
2
|
+
export function slices(s: any, max: any): any[];
|
|
1
3
|
/** Left, right or centre, from where the lines sit in their box. */
|
|
2
4
|
export function alignOf(it: any): "center" | "left" | "right" | "both";
|
|
3
5
|
/**
|
|
4
6
|
* @param {any} model render() output
|
|
5
7
|
* @param {{ title?: string, author?: string, lang?: string, fontStore?: any, fetchImage?: (src: string) => Promise<Uint8Array|null>,
|
|
6
|
-
* rasterize?: (svg: string, w: number, h: number, scale: number) => Promise<Uint8Array|null>, figures?: boolean }} [opt]
|
|
8
|
+
* rasterize?: (svg: string, w: number, h: number, scale: number) => Promise<Uint8Array|null>, figures?: boolean, xmlChunk?: number }} [opt]
|
|
9
|
+
* xmlChunk: the document XML is written to the zip in pieces of about this many chars (default 4M; tests lower it)
|
|
7
10
|
* fontStore: text in pictures as outlines (else the reader's fallback font); fetchImage: pictures by URL;
|
|
8
11
|
* rasterize: the PNG fallback of a picture (default: a canvas in a browser, sharp in Node); figures: false leaves them out.
|
|
9
12
|
* @returns {Promise<Uint8Array>}
|
|
@@ -16,4 +19,19 @@ export function exportDocx(model: any, opt?: {
|
|
|
16
19
|
fetchImage?: (src: string) => Promise<Uint8Array | null>;
|
|
17
20
|
rasterize?: (svg: string, w: number, h: number, scale: number) => Promise<Uint8Array | null>;
|
|
18
21
|
figures?: boolean;
|
|
22
|
+
xmlChunk?: number;
|
|
19
23
|
}): Promise<Uint8Array>;
|
|
24
|
+
/**
|
|
25
|
+
* The .docx of pages as they come (an array, or an async iterable: exportDocxStream's pages, a window at a time), its
|
|
26
|
+
* zip bytes handed to put as they are made (awaited: back-pressure). Each page's XML goes into word/document.xml's
|
|
27
|
+
* deflater once the page is converted, so neither the pages nor the document XML are held whole; the parts that name
|
|
28
|
+
* the pictures follow the document. model: the model, or a paged plan's info (width, height; locale, name).
|
|
29
|
+
* @param {Iterable<any>|AsyncIterable<any>} pages @param {{ width: number, height: number, locale?: string, name?: string }} model
|
|
30
|
+
* @param {NonNullable<Parameters<typeof exportDocx>[1]>} opt @param {(bytes: Uint8Array) => any} put
|
|
31
|
+
*/
|
|
32
|
+
export function writeDocx(pages: Iterable<any> | AsyncIterable<any>, model: {
|
|
33
|
+
width: number;
|
|
34
|
+
height: number;
|
|
35
|
+
locale?: string;
|
|
36
|
+
name?: string;
|
|
37
|
+
}, opt: NonNullable<Parameters<typeof exportDocx>[1]>, put: (bytes: Uint8Array) => any): Promise<void>;
|
|
@@ -4,12 +4,15 @@
|
|
|
4
4
|
* drill-through opens the ReportWright viewer at drillBase (without one it is shown disabled).
|
|
5
5
|
* Unless static, a file whose report has tables also gets a Tables view (htmldata.js): the tables as HTML, re-sorted on
|
|
6
6
|
* their interactive-sort columns, groups opened and closed, rows filtered, by one inline script the file's CSP allows.
|
|
7
|
+
* exportHtml(model, { fonts, ...options }). The 0.7 form exportHtml(model, fontStore, options) still works (deprecated).
|
|
7
8
|
* @param {any} model
|
|
8
|
-
* @param {import('../engine/text/fonts.js').FontStore}
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* @param {{ fonts?: import('../engine/text/fonts.js').FontStore, fontStore?: import('../engine/text/fonts.js').FontStore, title?: string, drillBase?: string, subset?: (font: Uint8Array, cps: Iterable<number>, o?: { layout?: boolean }) => Promise<Uint8Array>,
|
|
10
|
+
* static?: boolean, locale?: string, currency?: string, lang?: string, strings?: Partial<typeof DATA_STRINGS>, timeoutMs?: number } | import('../engine/text/fonts.js').FontStore} [options]
|
|
11
|
+
* @param {any} [legacyOpt] the options of the 0.7 form
|
|
11
12
|
*/
|
|
12
|
-
export function exportHtml(model: any,
|
|
13
|
+
export function exportHtml(model: any, options?: {
|
|
14
|
+
fonts?: import("../engine/text/fonts.js").FontStore;
|
|
15
|
+
fontStore?: import("../engine/text/fonts.js").FontStore;
|
|
13
16
|
title?: string;
|
|
14
17
|
drillBase?: string;
|
|
15
18
|
subset?: (font: Uint8Array, cps: Iterable<number>, o?: {
|
|
@@ -20,5 +23,6 @@ export function exportHtml(model: any, fontStore: import("../engine/text/fonts.j
|
|
|
20
23
|
currency?: string;
|
|
21
24
|
lang?: string;
|
|
22
25
|
strings?: Partial<typeof DATA_STRINGS>;
|
|
23
|
-
|
|
26
|
+
timeoutMs?: number;
|
|
27
|
+
} | import("../engine/text/fonts.js").FontStore, legacyOpt?: any): Promise<string>;
|
|
24
28
|
import { DATA_STRINGS } from './htmldata.js';
|