@reportwright/engine 0.0.0-stage → 0.12.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 +233 -0
- package/LICENSE +23 -0
- package/README.md +105 -2
- package/dist/index.js +22548 -0
- package/dist/pdfstreamworker.js +38 -0
- package/dist/types/packages/engine/entry.d.ts +125 -0
- package/dist/types/src/designer/tableGen.d.ts +119 -0
- package/dist/types/src/engine/data/guard.d.ts +50 -0
- package/dist/types/src/engine/data/index.d.ts +120 -0
- package/dist/types/src/engine/data/odata.d.ts +35 -0
- package/dist/types/src/engine/data/stream.d.ts +48 -0
- package/dist/types/src/engine/data/xml.d.ts +108 -0
- package/dist/types/src/engine/expr/evaluate.d.ts +183 -0
- package/dist/types/src/engine/expr/format.d.ts +122 -0
- package/dist/types/src/engine/expr/javafmt.d.ts +26 -0
- package/dist/types/src/engine/expr/parser.d.ts +29 -0
- package/dist/types/src/engine/image.d.ts +107 -0
- package/dist/types/src/engine/index.d.ts +239 -0
- package/dist/types/src/engine/items/barcode.d.ts +121 -0
- package/dist/types/src/engine/items/cells.d.ts +11 -0
- package/dist/types/src/engine/items/chart-kit.d.ts +75 -0
- package/dist/types/src/engine/items/chart-more.d.ts +52 -0
- package/dist/types/src/engine/items/chart-round.d.ts +28 -0
- package/dist/types/src/engine/items/chart.d.ts +42 -0
- package/dist/types/src/engine/items/hpage.d.ts +33 -0
- package/dist/types/src/engine/items/index.d.ts +117 -0
- package/dist/types/src/engine/items/map.d.ts +11 -0
- package/dist/types/src/engine/items/paint.d.ts +138 -0
- package/dist/types/src/engine/items/pivot.d.ts +45 -0
- package/dist/types/src/engine/items/rich.d.ts +105 -0
- package/dist/types/src/engine/items/toc.d.ts +10 -0
- package/dist/types/src/engine/items/visuals.d.ts +5 -0
- package/dist/types/src/engine/layout.d.ts +24 -0
- package/dist/types/src/engine/paged.d.ts +19 -0
- package/dist/types/src/engine/paginate/index.d.ts +17 -0
- package/dist/types/src/engine/reuse.d.ts +120 -0
- package/dist/types/src/engine/schema/report.schema.d.ts +2421 -0
- package/dist/types/src/engine/schema/template.d.ts +212 -0
- package/dist/types/src/engine/schema/validate.d.ts +21 -0
- package/dist/types/src/engine/stream.d.ts +54 -0
- package/dist/types/src/engine/style.d.ts +70 -0
- package/dist/types/src/engine/text/fonts.d.ts +96 -0
- package/dist/types/src/engine/text/measure.d.ts +145 -0
- package/dist/types/src/engine/text/rich.d.ts +48 -0
- package/dist/types/src/engine/text/shaper.d.ts +20 -0
- package/dist/types/src/engine/units.d.ts +53 -0
- package/dist/types/src/engine/url.d.ts +23 -0
- package/dist/types/src/exporters/color.d.ts +9 -0
- package/dist/types/src/exporters/csv.d.ts +44 -0
- package/dist/types/src/exporters/deadline.d.ts +6 -0
- package/dist/types/src/exporters/docx.d.ts +19 -0
- package/dist/types/src/exporters/encrypt.d.ts +39 -0
- package/dist/types/src/exporters/figures.d.ts +112 -0
- package/dist/types/src/exporters/html.d.ts +24 -0
- package/dist/types/src/exporters/htmldata.d.ts +32 -0
- package/dist/types/src/exporters/pdf.d.ts +45 -0
- package/dist/types/src/exporters/pdfa.d.ts +42 -0
- package/dist/types/src/exporters/pdfpaint.d.ts +107 -0
- package/dist/types/src/exporters/pdfstream.d.ts +198 -0
- package/dist/types/src/exporters/pdfstreamtags.d.ts +38 -0
- package/dist/types/src/exporters/pdfua.d.ts +17 -0
- package/dist/types/src/exporters/png.d.ts +10 -0
- package/dist/types/src/exporters/pptx.d.ts +14 -0
- package/dist/types/src/exporters/regions.d.ts +30 -0
- package/dist/types/src/exporters/subset.d.ts +5 -0
- package/dist/types/src/exporters/svg.d.ts +26 -0
- package/dist/types/src/exporters/svgimage.d.ts +33 -0
- package/dist/types/src/exporters/xlsx.d.ts +61 -0
- package/dist/types/src/exporters/xlsxchart.d.ts +26 -0
- package/dist/types/src/exporters/xlsxwriter.d.ts +83 -0
- package/dist/types/src/importers/xml.d.ts +34 -0
- package/examples/stream-1m.mjs +87 -0
- package/index.d.ts +3 -0
- package/package.json +79 -4
- package/pool/index.d.ts +23 -0
- package/pool/index.js +85 -0
- package/pool/worker.js +27 -0
- package/report.d.ts +638 -0
- package/schema.json +2517 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
// A paint worker of a streaming PDF (pdfstream.js, opts.parallel): it lays out the windows of rows it is sent
|
|
3
|
+
// (engine/paged.js jobs, with the pages already counted) and paints their pages with the same painter and names as the
|
|
4
|
+
// writer, then sends back each page's compressed content stream and what it used (fonts, glyphs, opacities). Node only.
|
|
5
|
+
import { render, FontStore, __streamPaint } from './index.js';
|
|
6
|
+
const { createPdfStream, paintPage, paintEnv, latin1 } = __streamPaint;
|
|
7
|
+
|
|
8
|
+
const proc = /** @type {any} */ (globalThis).process;
|
|
9
|
+
const { parentPort, workerData } = proc.getBuiltinModule('node:worker_threads');
|
|
10
|
+
const zlib = proc.getBuiltinModule('node:zlib');
|
|
11
|
+
const bytes = new Map(workerData.fonts);
|
|
12
|
+
const fontStore = new FontStore(async (k) => {
|
|
13
|
+
const b = bytes.get(k);
|
|
14
|
+
if (!b) throw new Error(`The font "${k}" was not sent to the paint worker`);
|
|
15
|
+
return b;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
parentPort.on('message', async (/** @type {any} */ job) => {
|
|
19
|
+
try {
|
|
20
|
+
const t0 = Date.now();
|
|
21
|
+
const m = await render(job.def, { ...job.opts, fontStore, sources: { __rows: { rows: job.rows } }, pageWindow: job.pageWindow });
|
|
22
|
+
// a writer of its own for the names and glyphs (nothing is written): the pages' links name pages by placeholder
|
|
23
|
+
const rec = createPdfStream({ write() {} }, { fontStore });
|
|
24
|
+
const env = paintEnv(rec, fontStore, { drillBase: job.drillBase, pageRef: (i) => `@@P${i}@@` });
|
|
25
|
+
const pages = [], transfer = [];
|
|
26
|
+
for (let k = 0; k < Math.min(job.keep, m.pages.length); k++) {
|
|
27
|
+
const pg = m.pages[k];
|
|
28
|
+
const { content, annots } = paintPage(pg, pg.height ?? job.height, env);
|
|
29
|
+
const z = new Uint8Array(zlib.deflateSync(latin1(content), { level: 9 })); // as pdfpaint.js's deflate
|
|
30
|
+
transfer.push(z.buffer);
|
|
31
|
+
pages.push({ deflated: z, annots, width: pg.width, height: pg.height, firstRow: pg.firstRow, rowHead: pg.rowHead, headLevel: pg.headLevel });
|
|
32
|
+
}
|
|
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);
|
|
35
|
+
} catch (e) {
|
|
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
|
+
}
|
|
38
|
+
});
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A FontStore over the @reportwright/fonts package (install it next to the engine). Throws when it isn't installed.
|
|
3
|
+
* In a bundled browser app, pass `fontsUrl`: the URL (or, in Node, the path) of a copy of the package's public/fonts
|
|
4
|
+
* folder; each font is read from there, and a missing one is an error.
|
|
5
|
+
* @param {{ fontsUrl?: string }} [opts]
|
|
6
|
+
* @returns {FontStore}
|
|
7
|
+
*/
|
|
8
|
+
export function defaultFontStore(opts?: {
|
|
9
|
+
fontsUrl?: string;
|
|
10
|
+
}): FontStore;
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {Omit<NonNullable<Parameters<typeof exportPdfFull>[2]>, 'subset' | 'pdfa'> & {
|
|
13
|
+
* fonts?: FontStore, subset?: false | NonNullable<Parameters<typeof exportPdfFull>[2]>['subset'],
|
|
14
|
+
* pdfa?: boolean | { icc?: Uint8Array, [k: string]: unknown } }} PdfOptions
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Page model → PDF bytes: exportPdf(model, { fonts, title, ... }). fonts: the FontStore render() used (default: the
|
|
18
|
+
* one over @reportwright/fonts). Fonts are subset with harfbuzz-subset.wasm from @reportwright/fonts (when it can't be
|
|
19
|
+
* loaded the full font is embedded); `subset: false` embeds every font in full, a function replaces the subsetter.
|
|
20
|
+
* The 0.7 form exportPdf(model, fontStore, options) still works in 0.8 (deprecated).
|
|
21
|
+
* @param {any} model render() output
|
|
22
|
+
* @param {PdfOptions} [options]
|
|
23
|
+
* @returns {Promise<Uint8Array>}
|
|
24
|
+
*/
|
|
25
|
+
export function exportPdf(model: any, options?: PdfOptions, ...args: any[]): Promise<Uint8Array>;
|
|
26
|
+
/**
|
|
27
|
+
* Page model → .xlsx bytes: exportXlsx(model, { fonts, currency, formulas, ... }) (needs render(def, { exportData: true })).
|
|
28
|
+
* The 0.7 form exportXlsx(model, ExcelJS, options) still works in 0.8 (deprecated; ExcelJS is not used).
|
|
29
|
+
* @param {any} model @param {NonNullable<Parameters<typeof exportXlsxFull>[1]> & { fonts?: FontStore }} [options]
|
|
30
|
+
* @returns {Promise<Uint8Array>}
|
|
31
|
+
*/
|
|
32
|
+
export function exportXlsx(model: any, options?: NonNullable<Parameters<typeof exportXlsxFull>[1]> & {
|
|
33
|
+
fonts?: FontStore;
|
|
34
|
+
}, ...args: any[]): Promise<Uint8Array>;
|
|
35
|
+
/**
|
|
36
|
+
* Page model → .docx bytes: exportDocx(model, { fonts, ... }) (needs render(def, { exportData: true })).
|
|
37
|
+
* @param {any} model @param {NonNullable<Parameters<typeof exportDocxFull>[1]> & { fonts?: FontStore }} [options]
|
|
38
|
+
* @returns {Promise<Uint8Array>}
|
|
39
|
+
*/
|
|
40
|
+
export function exportDocx(model: any, options?: NonNullable<Parameters<typeof exportDocxFull>[1]> & {
|
|
41
|
+
fonts?: FontStore;
|
|
42
|
+
}, ...args: any[]): Promise<Uint8Array>;
|
|
43
|
+
/**
|
|
44
|
+
* Page model → .pptx bytes: exportPptx(model, { fonts, ... }).
|
|
45
|
+
* @param {any} model @param {NonNullable<Parameters<typeof exportPptxFull>[1]> & { fonts?: FontStore }} [options]
|
|
46
|
+
* @returns {Promise<Uint8Array>}
|
|
47
|
+
*/
|
|
48
|
+
export function exportPptx(model: any, options?: NonNullable<Parameters<typeof exportPptxFull>[1]> & {
|
|
49
|
+
fonts?: FontStore;
|
|
50
|
+
}, ...args: any[]): Promise<Uint8Array>;
|
|
51
|
+
/**
|
|
52
|
+
* @typedef {RenderOptions & Omit<PdfOptions, 'fonts'> & { fonts?: FontStore, tagged?: { lang?: string },
|
|
53
|
+
* window?: number, parallel?: number, maxRows?: number, id?: string }} PdfStreamOptions
|
|
54
|
+
* 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), maxRows (rows read, 5,000,000), id (the file ID).
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* Report definition → PDF written to a sink as it is made, for reports too large to hold as a page model: a flowing
|
|
59
|
+
* table (and its groups) is laid out a window of rows at a time and each page leaves memory once written. Other
|
|
60
|
+
* reports are rendered whole and written by exportPdf in one piece (the result says why). sink: a Node Writable
|
|
61
|
+
* (fs.createWriteStream) or anything with write(bytes) that may return a promise (back-pressure); it is not closed.
|
|
62
|
+
* @param {any} def the report definition
|
|
63
|
+
* @param {PdfStreamOptions} options
|
|
64
|
+
* @param {{ write(bytes: Uint8Array): any, once?: (ev: string, cb: () => void) => any }} sink
|
|
65
|
+
* @returns {Promise<{ streamed: boolean, pages: number, warnings: string[], why?: string }>}
|
|
66
|
+
*/
|
|
67
|
+
export function exportPdfStream(def: any, options: PdfStreamOptions, sink: {
|
|
68
|
+
write(bytes: Uint8Array): any;
|
|
69
|
+
once?: (ev: string, cb: () => void) => any;
|
|
70
|
+
}): Promise<{
|
|
71
|
+
streamed: boolean;
|
|
72
|
+
pages: number;
|
|
73
|
+
warnings: string[];
|
|
74
|
+
why?: string;
|
|
75
|
+
}>;
|
|
76
|
+
export { validate } from "../../src/engine/schema/validate.js";
|
|
77
|
+
export { exportHtml } from "../../src/exporters/html.js";
|
|
78
|
+
export { exportCsv } from "../../src/exporters/csv.js";
|
|
79
|
+
export { needsExportData } from "../../src/exporters/regions.js";
|
|
80
|
+
export { pageToSvg } from "../../src/exporters/svg.js";
|
|
81
|
+
export namespace __streamPaint {
|
|
82
|
+
export { createPdfStream };
|
|
83
|
+
export { paintPage };
|
|
84
|
+
export { paintEnv };
|
|
85
|
+
export { latin1 };
|
|
86
|
+
}
|
|
87
|
+
export { planPaged } from "../../src/engine/paged.js";
|
|
88
|
+
export type PdfOptions = Omit<NonNullable<Parameters<typeof exportPdfFull>[2]>, "subset" | "pdfa"> & {
|
|
89
|
+
fonts?: FontStore;
|
|
90
|
+
subset?: false | NonNullable<Parameters<typeof exportPdfFull>[2]>["subset"];
|
|
91
|
+
pdfa?: boolean | {
|
|
92
|
+
icc?: Uint8Array;
|
|
93
|
+
[k: string]: unknown;
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* 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), maxRows (rows read, 5,000,000), id (the file ID).
|
|
99
|
+
*/
|
|
100
|
+
export type PdfStreamOptions = RenderOptions & Omit<PdfOptions, "fonts"> & {
|
|
101
|
+
fonts?: FontStore;
|
|
102
|
+
tagged?: {
|
|
103
|
+
lang?: string;
|
|
104
|
+
};
|
|
105
|
+
window?: number;
|
|
106
|
+
parallel?: number;
|
|
107
|
+
maxRows?: number;
|
|
108
|
+
id?: string;
|
|
109
|
+
};
|
|
110
|
+
export type RenderOptions = import("../../src/engine/index.js").RenderOptions;
|
|
111
|
+
import { FontStore } from '../../src/engine/index.js';
|
|
112
|
+
import { exportXlsx as exportXlsxFull } from '../../src/exporters/xlsx.js';
|
|
113
|
+
import { exportDocx as exportDocxFull } from '../../src/exporters/docx.js';
|
|
114
|
+
import { exportPptx as exportPptxFull } from '../../src/exporters/pptx.js';
|
|
115
|
+
import { fontFile } from '../../src/engine/text/fonts.js';
|
|
116
|
+
import { createSubsetter } from '../../src/exporters/subset.js';
|
|
117
|
+
import { createPdfStream } from '../../src/exporters/pdfstream.js';
|
|
118
|
+
import { paintPage } from '../../src/exporters/pdfstream.js';
|
|
119
|
+
import { paintEnv } from '../../src/exporters/pdfstream.js';
|
|
120
|
+
import { latin1 } from '../../src/exporters/pdfpaint.js';
|
|
121
|
+
import { exportPdf as exportPdfFull } from '../../src/exporters/pdf.js';
|
|
122
|
+
export { fontFile, createSubsetter };
|
|
123
|
+
export { render, FontStore, ITEMS, parameterOptions, resolveParameters } from "../../src/engine/index.js";
|
|
124
|
+
export { blankReport, blankDashboard } from "../../src/engine/schema/template.js";
|
|
125
|
+
export { tableFor, matrixFor } from "../../src/designer/tableGen.js";
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/** "dueDate" → "Due date", "customer_name" → "Customer name"; all-caps names stay. */
|
|
2
|
+
export function labelOf(name: any): any;
|
|
3
|
+
/**
|
|
4
|
+
* One format per field, the same in detail rows, subtotals, totals and charts:
|
|
5
|
+
* ids, years and month numbers plain (0); counts N0; money N2 (C2 when the report has a currency); dates 12 Jan 2026;
|
|
6
|
+
* other numbers N0 when every sample value is whole, else N2. Without sample rows the name decides.
|
|
7
|
+
* @param {{ name: string, type?: string }} f @param {any[]} [rows] @param {{ currency?: string }} [opt]
|
|
8
|
+
*/
|
|
9
|
+
export function formatFor(f: {
|
|
10
|
+
name: string;
|
|
11
|
+
type?: string;
|
|
12
|
+
}, rows?: any[], { currency }?: {
|
|
13
|
+
currency?: string;
|
|
14
|
+
}): "0" | "dd MMM yyyy" | "C2" | "N0" | "N2";
|
|
15
|
+
/** A compact axis format for values up to `max`: 300M, 2,730M, 50K (none below 20 of the unit: 15,000 stays as it is). */
|
|
16
|
+
export function compactFormat(max: any): string | number;
|
|
17
|
+
/**
|
|
18
|
+
* @param {{ name: string, fields?: { name: string, type?: string }[] }} ds
|
|
19
|
+
* @param {{ layout?: 'list'|'grouped'|'summary', groupBy?: string, width?: number, rows?: any[], fields?: string[], currency?: string }} opt
|
|
20
|
+
* fields: which fields, in order (default all); rows: sample rows, to pick number formats; currency: the symbol for money cells
|
|
21
|
+
*/
|
|
22
|
+
export function tableFor(ds: {
|
|
23
|
+
name: string;
|
|
24
|
+
fields?: {
|
|
25
|
+
name: string;
|
|
26
|
+
type?: string;
|
|
27
|
+
}[];
|
|
28
|
+
}, opt?: {
|
|
29
|
+
layout?: "list" | "grouped" | "summary";
|
|
30
|
+
groupBy?: string;
|
|
31
|
+
width?: number;
|
|
32
|
+
rows?: any[];
|
|
33
|
+
fields?: string[];
|
|
34
|
+
currency?: string;
|
|
35
|
+
}): {
|
|
36
|
+
type: string;
|
|
37
|
+
dataSet: any;
|
|
38
|
+
w: number;
|
|
39
|
+
h: number;
|
|
40
|
+
repeatHeader: boolean;
|
|
41
|
+
columns: any;
|
|
42
|
+
header: {
|
|
43
|
+
height: number;
|
|
44
|
+
style: {
|
|
45
|
+
fontWeight: string;
|
|
46
|
+
backgroundColor: string;
|
|
47
|
+
borderBottom: string;
|
|
48
|
+
};
|
|
49
|
+
cells: any;
|
|
50
|
+
}[];
|
|
51
|
+
detail: {
|
|
52
|
+
height: number;
|
|
53
|
+
style: {
|
|
54
|
+
borderBottom: string;
|
|
55
|
+
};
|
|
56
|
+
cells: any;
|
|
57
|
+
}[];
|
|
58
|
+
footer: {
|
|
59
|
+
height: number;
|
|
60
|
+
style: {
|
|
61
|
+
fontWeight: string;
|
|
62
|
+
borderTop: string;
|
|
63
|
+
};
|
|
64
|
+
cells: any;
|
|
65
|
+
}[];
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* @param {{ name: string, fields?: { name: string, type?: string }[] }} ds
|
|
69
|
+
* @param {{ rows: string, columns: string, value: string, agg?: string, width?: number, sample?: any[], currency?: string }} opt
|
|
70
|
+
*/
|
|
71
|
+
export function matrixFor(ds: {
|
|
72
|
+
name: string;
|
|
73
|
+
fields?: {
|
|
74
|
+
name: string;
|
|
75
|
+
type?: string;
|
|
76
|
+
}[];
|
|
77
|
+
}, { rows, columns, value, agg, width, sample, currency }: {
|
|
78
|
+
rows: string;
|
|
79
|
+
columns: string;
|
|
80
|
+
value: string;
|
|
81
|
+
agg?: string;
|
|
82
|
+
width?: number;
|
|
83
|
+
sample?: any[];
|
|
84
|
+
currency?: string;
|
|
85
|
+
}): {
|
|
86
|
+
type: string;
|
|
87
|
+
dataSet: string;
|
|
88
|
+
w: number;
|
|
89
|
+
h: number;
|
|
90
|
+
corner: any;
|
|
91
|
+
rowGroups: {
|
|
92
|
+
name: any;
|
|
93
|
+
expr: string;
|
|
94
|
+
sort: string;
|
|
95
|
+
total: string;
|
|
96
|
+
}[];
|
|
97
|
+
columnGroups: {
|
|
98
|
+
name: string;
|
|
99
|
+
expr: string;
|
|
100
|
+
sort: string;
|
|
101
|
+
total: string;
|
|
102
|
+
}[];
|
|
103
|
+
values: {
|
|
104
|
+
value: string;
|
|
105
|
+
format: string;
|
|
106
|
+
}[];
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* The fields Instant visuals starts with: the text field with the fewest distinct values (2 to 24; never an id, a
|
|
110
|
+
* code or a field unique on almost every row), a second such field when there is one, and the first additive number
|
|
111
|
+
* (an amount, not an id or a rate). No rows yet: by name and type only. A 180 × 180 pivot of Id by Borrower helps nobody.
|
|
112
|
+
* @param {{ name: string, type?: string }[]} fields @param {any[]} rows
|
|
113
|
+
* @returns {string[]}
|
|
114
|
+
*/
|
|
115
|
+
export function instantPicks(fields: {
|
|
116
|
+
name: string;
|
|
117
|
+
type?: string;
|
|
118
|
+
}[], rows?: any[]): string[];
|
|
119
|
+
export function isCode(name: any): boolean;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** True for an address no data source may reach by default. @param {string} host a hostname as URL gives it */
|
|
2
|
+
export function privateHost(host: string): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Check one URL the default fetch would request: scheme, credentials, and a literal address. Anything it cannot
|
|
5
|
+
* read is refused (fail closed). A name is checked again, as resolved, by the Node transport's lookup.
|
|
6
|
+
* @param {string} input @param {string[]} allow lower-case host names
|
|
7
|
+
* @returns {URL}
|
|
8
|
+
*/
|
|
9
|
+
export function checkUrl(input: string, allow: string[]): URL;
|
|
10
|
+
/**
|
|
11
|
+
* The request for a redirect hop, or an error: https → http is refused; another origin keeps only CROSS_ORIGIN_KEEP;
|
|
12
|
+
* 303 (and 301/302 after a non-GET) becomes a GET without a body.
|
|
13
|
+
* @param {URL} from @param {URL} to @param {any} req @param {number} status
|
|
14
|
+
*/
|
|
15
|
+
export function redirectRequest(from: URL, to: URL, req: any, status: number): any;
|
|
16
|
+
/**
|
|
17
|
+
* The guarded default fetch (see the top of this file). In Node every hop goes through nodeRequest (address pinned);
|
|
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 @param {typeof fetch} base
|
|
20
|
+
* @returns {typeof fetch}
|
|
21
|
+
*/
|
|
22
|
+
export function guardedFetch(opt: {
|
|
23
|
+
allowHosts?: string[];
|
|
24
|
+
}, base: typeof fetch): typeof fetch;
|
|
25
|
+
/**
|
|
26
|
+
* Any fetch with the engine's time limit and byte cap.
|
|
27
|
+
* @param {typeof fetch} f @param {{ fetchTimeoutMs?: number, maxFetchBytes?: number, deadline?: number }} opt
|
|
28
|
+
* @returns {typeof fetch}
|
|
29
|
+
*/
|
|
30
|
+
export function boundedFetch(f: typeof fetch, opt: {
|
|
31
|
+
fetchTimeoutMs?: number;
|
|
32
|
+
maxFetchBytes?: number;
|
|
33
|
+
deadline?: number;
|
|
34
|
+
}): typeof fetch;
|
|
35
|
+
/**
|
|
36
|
+
* A URL safe to print: no userinfo, and the query and fragment shown as ?… / #… (their values can hold keys and tokens).
|
|
37
|
+
* @param {string} s
|
|
38
|
+
*/
|
|
39
|
+
export function redactUrl(s: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* A failed request as an error that says why: the cause code (DNS, refused, reset, TLS, timeout) and the redacted URL.
|
|
42
|
+
* An error that already carries a status (a refused address, a redirect) passes through.
|
|
43
|
+
* @param {any} e @param {any} input
|
|
44
|
+
*/
|
|
45
|
+
export function fetchFailure(e: any, input: any): any;
|
|
46
|
+
export namespace FETCH_DEFAULTS {
|
|
47
|
+
let timeoutMs: number;
|
|
48
|
+
let maxBytes: number;
|
|
49
|
+
let hops: number;
|
|
50
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/** Minimal JSONPath: $, $.a.b, $.a[0].b, $.a[*].b, $['a b'] */
|
|
2
|
+
export function jsonPath(obj: any, path: any): any;
|
|
3
|
+
/**
|
|
4
|
+
* jsonPath that also says, for each result of a [*] spread, which object held the spread collection
|
|
5
|
+
* (for $.books[*].positions[*], the book of each position): Parent.* in the data set's rows.
|
|
6
|
+
* @returns {{rows: any, parents: any[]|null}}
|
|
7
|
+
*/
|
|
8
|
+
export function jsonPathRows(obj: any, path: any): {
|
|
9
|
+
rows: any;
|
|
10
|
+
parents: any[] | null;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
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
|
+
* 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
|
+
* 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]
|
|
17
|
+
*/
|
|
18
|
+
export function coerce(v: any, type: string, opt?: {
|
|
19
|
+
locale?: string;
|
|
20
|
+
timeZone?: string;
|
|
21
|
+
bad?: (v: any) => void;
|
|
22
|
+
}): any;
|
|
23
|
+
/**
|
|
24
|
+
* Guess field names and types from sample rows. A string that looks like an ISO date (2024-01-31, 2024-01-31T10:00Z)
|
|
25
|
+
* becomes a date field; dates: false (a data set's detectDates: false) keeps it text. To keep one field as text,
|
|
26
|
+
* declare the data set's fields with that one as type "string".
|
|
27
|
+
* @param {any[]} rows @param {{ dates?: boolean }} [opt]
|
|
28
|
+
*/
|
|
29
|
+
export function detectFields(rows: any[], { dates }?: {
|
|
30
|
+
dates?: boolean;
|
|
31
|
+
}): {
|
|
32
|
+
name: any;
|
|
33
|
+
type: any;
|
|
34
|
+
}[];
|
|
35
|
+
/** One-character CSV option: "tab" and "\\t" mean a tab. */
|
|
36
|
+
export function csvChar(v: any, dflt: any, what: any): any;
|
|
37
|
+
/**
|
|
38
|
+
* Parse CSV text into objects. One forward scan, O(n): a quote opens a quoted field only at the start of
|
|
39
|
+
* a field; inside, a doubled quote is a quote, and separators and line breaks are data.
|
|
40
|
+
* @param {string} text
|
|
41
|
+
* @param {{separator?: string, quote?: string, headerRow?: boolean, startRow?: number}} [opts]
|
|
42
|
+
* startRow: 1-based record where the header (or the data, without a header row) starts.
|
|
43
|
+
*/
|
|
44
|
+
export function parseCsv(text: string, opts?: {
|
|
45
|
+
separator?: string;
|
|
46
|
+
quote?: string;
|
|
47
|
+
headerRow?: boolean;
|
|
48
|
+
startRow?: number;
|
|
49
|
+
}): {
|
|
50
|
+
[k: string]: string;
|
|
51
|
+
}[];
|
|
52
|
+
/**
|
|
53
|
+
* Load every data source used by the report.
|
|
54
|
+
* @param {any} def
|
|
55
|
+
* @param {{params: object, fetch?: typeof fetch, baseUrl?: string, reportId?: string,
|
|
56
|
+
* sql?: (src: any, params: Record<string, any>) => Promise<object[]>, sqlPreview?: boolean}} opt
|
|
57
|
+
* sql: runs a SQL source directly (server renders). Without it the server runs the saved report's
|
|
58
|
+
* query: the browser sends the report id and source name, never SQL.
|
|
59
|
+
*/
|
|
60
|
+
export function loadSources(def: any, opt: {
|
|
61
|
+
params: object;
|
|
62
|
+
fetch?: typeof fetch;
|
|
63
|
+
baseUrl?: string;
|
|
64
|
+
reportId?: string;
|
|
65
|
+
sql?: (src: any, params: Record<string, any>) => Promise<object[]>;
|
|
66
|
+
sqlPreview?: boolean;
|
|
67
|
+
}): Promise<{}>;
|
|
68
|
+
/**
|
|
69
|
+
* The response of a rest (JSON) or csv source, unread, for a streaming render: the same URL, headers, body and proxy as
|
|
70
|
+
* loadSources. init.pwStream asks the server's fetch for its streaming size cap (safeFetch) instead of the whole-body one.
|
|
71
|
+
* @param {any} src @param {any} ctx @param {{ fetch?: typeof fetch, baseUrl?: string }} opt
|
|
72
|
+
* @returns {Promise<Response>}
|
|
73
|
+
*/
|
|
74
|
+
export function sourceResponse(src: any, ctx: any, opt: {
|
|
75
|
+
fetch?: typeof fetch;
|
|
76
|
+
baseUrl?: string;
|
|
77
|
+
}): Promise<Response>;
|
|
78
|
+
/**
|
|
79
|
+
* A response whose Content-Type names a charset other than UTF-8 is re-encoded to UTF-8 as it streams, so every reader
|
|
80
|
+
* (text, the CSV and JSON splitters) gets the text the server meant. TextDecoder knows the labels; an unknown one is an error.
|
|
81
|
+
* @param {Response} res
|
|
82
|
+
*/
|
|
83
|
+
export function utf8Response(res: Response): Response;
|
|
84
|
+
/**
|
|
85
|
+
* Build typed rows for every data set.
|
|
86
|
+
* @param {any} def @param {Record<string, any>} sources @param {any} baseCtx
|
|
87
|
+
*/
|
|
88
|
+
export function buildDataSets(def: any, sources: Record<string, any>, baseCtx: any): Record<string, any[]>;
|
|
89
|
+
/**
|
|
90
|
+
* Rows a region bound to a data set should show: for a nested data set inside a list (or group) bound to its
|
|
91
|
+
* parent, only the current parent rows' children; anywhere else, all rows.
|
|
92
|
+
* @param {any[]} rows @param {any} ctx
|
|
93
|
+
*/
|
|
94
|
+
export function related(rows: any[], ctx: any): any;
|
|
95
|
+
/**
|
|
96
|
+
* Filters run in the order listed. Row filters (=, <, in, like, Between …) test each row; set filters
|
|
97
|
+
* (TopN, BottomN, TopPercent, BottomPercent) rank all rows left by the filters before them.
|
|
98
|
+
* @param {any[]} rows @param {any[]|undefined} filters
|
|
99
|
+
*/
|
|
100
|
+
export function applyFilters(rows: any[], filters: any[] | undefined, baseCtx: any): any[];
|
|
101
|
+
export function rowFilter(f: any, c: any): boolean;
|
|
102
|
+
/** Compare two rows' sort keys as applySort does (nulls last, or lowest with nullOrder "low"; the report's collation);
|
|
103
|
+
* 0 when equal (the caller keeps the rows' order). @param {any[]} sort */
|
|
104
|
+
export function compareKeys(ka: any, kb: any, sort: any[], ctx: any): number;
|
|
105
|
+
/** @param {any[]} rows @param {any[]|undefined} sort */
|
|
106
|
+
export function applySort(rows: any[], sort: any[] | undefined, baseCtx: any): any[];
|
|
107
|
+
/**
|
|
108
|
+
* The raw rows of a source at a data set path: XPath for an XML source, JSONPath otherwise (the designer's Detect and Use).
|
|
109
|
+
* @param {any} raw @param {string} [path]
|
|
110
|
+
*/
|
|
111
|
+
export function sourceRows(raw: any, path?: string): any[];
|
|
112
|
+
/** Source types whose data is fetched (an xml or csv source with inline data is not). */
|
|
113
|
+
export const FETCHED_TYPES: string[];
|
|
114
|
+
export const SET_OPS: Set<string>;
|
|
115
|
+
export function sortKeys(sort: any[], c: any): any[];
|
|
116
|
+
export function sourceUrl(url: any, params: any): string;
|
|
117
|
+
import { evaluate } from '../expr/evaluate.js';
|
|
118
|
+
import { compile } from '../expr/evaluate.js';
|
|
119
|
+
import { isXmlDoc } from './xml.js';
|
|
120
|
+
export { evaluate, compile, isXmlDoc };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** ReportWright field type of an Edm type. @param {string} [edm] */
|
|
2
|
+
export function odataFieldType(edm?: string): "string" | "number" | "boolean" | "date";
|
|
3
|
+
/**
|
|
4
|
+
* Entity sets of a $metadata (CSDL) document, with their properties (base types included) and navigation properties.
|
|
5
|
+
* @param {string} text
|
|
6
|
+
* @returns {{ name: string, type: string, properties: { name: string, type: string }[], navigation: string[] }[]}
|
|
7
|
+
*/
|
|
8
|
+
export function odataMetadata(text: string): {
|
|
9
|
+
name: string;
|
|
10
|
+
type: string;
|
|
11
|
+
properties: {
|
|
12
|
+
name: string;
|
|
13
|
+
type: string;
|
|
14
|
+
}[];
|
|
15
|
+
navigation: string[];
|
|
16
|
+
}[];
|
|
17
|
+
/** An OData literal for a value of an Edm type (or of the value's own JS type). */
|
|
18
|
+
export function odataLiteral(v: any, type: any): string;
|
|
19
|
+
/**
|
|
20
|
+
* The query string of an OData source. `value(x)` evaluates a filter value, top or skip ({Parameters.x}, =expr or text).
|
|
21
|
+
* A filter whose value is empty (an unset parameter) is left out, so it means "all".
|
|
22
|
+
* @param {any} src @param {(v: any) => any} value
|
|
23
|
+
*/
|
|
24
|
+
export function odataQuery(src: any, value: (v: any) => any): string;
|
|
25
|
+
/** The entity set's URL: the service root + the entity set + the query. @param {string} root @param {any} src @param {(v: any) => any} value */
|
|
26
|
+
export function odataUrl(root: string, src: any, value: (v: any) => any): string;
|
|
27
|
+
/** One page of a response: its rows (v4 value, v2 d.results / d) and the next link, if any. @param {any} json */
|
|
28
|
+
export function odataPage(json: any): {
|
|
29
|
+
rows: any;
|
|
30
|
+
next: string;
|
|
31
|
+
};
|
|
32
|
+
/** Rows without OData annotations, numbers and dates read by the source's property types. */
|
|
33
|
+
export function odataClean(rows: any, types?: {}): any;
|
|
34
|
+
export const ODATA_MAX_PAGES: 100;
|
|
35
|
+
export const ODATA_DEFAULT_PAGES: 10;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The keys a JSONPath walks to reach the rows, when the splitter can follow it: $, $.a.b, $['a b'], with a [*] at the
|
|
3
|
+
* end at most. Null for any other path (indexes, spreads in the middle): read the whole body instead.
|
|
4
|
+
* @param {string} [path] @returns {string[]|null}
|
|
5
|
+
*/
|
|
6
|
+
export function splitPath(path?: string): string[] | null;
|
|
7
|
+
/**
|
|
8
|
+
* The rows of a JSON body at a path, in batches, without holding the body: the bytes are scanned for the array the
|
|
9
|
+
* path names, and its elements are parsed (JSON.parse, a batch at a time) as they complete. A body whose shape the path
|
|
10
|
+
* does not meet that way (an object where the rows should be, a path with indexes) is read whole and taken through
|
|
11
|
+
* jsonPathRows, exactly as a whole-body read would: maxWholeBytes caps that case. Every cap counts the text actually read
|
|
12
|
+
* (characters), not a declared length: the body before the rows (maxWholeBytes), one row (maxElementBytes, so one huge
|
|
13
|
+
* string or a row that never ends cannot grow without bound) and the nesting (maxDepth).
|
|
14
|
+
* @param {any} body @param {string|undefined} path
|
|
15
|
+
* @param {{ maxElementBytes?: number, maxWholeBytes?: number, maxDepth?: number, batch?: number }} [o]
|
|
16
|
+
* @returns {AsyncGenerator<any[]>}
|
|
17
|
+
*/
|
|
18
|
+
export function jsonRows(body: any, path: string | undefined, { maxElementBytes, maxWholeBytes, maxDepth, batch }?: {
|
|
19
|
+
maxElementBytes?: number;
|
|
20
|
+
maxWholeBytes?: number;
|
|
21
|
+
maxDepth?: number;
|
|
22
|
+
batch?: number;
|
|
23
|
+
}): AsyncGenerator<any[]>;
|
|
24
|
+
/**
|
|
25
|
+
* CSV records as they arrive: the same reading as parseCsv (a quote opens a quoted field only at the start of a field;
|
|
26
|
+
* inside, a doubled quote is a quote and separators and line breaks are data; text after the closing quote is kept;
|
|
27
|
+
* \n, \r\n and \r end a record), across chunk boundaries.
|
|
28
|
+
* @param {any} body @param {{ sep: string, quote: string, maxFieldBytes?: number }} o @returns {AsyncGenerator<string[][]>}
|
|
29
|
+
*/
|
|
30
|
+
export function csvRecords(body: any, { sep, quote, maxFieldBytes }: {
|
|
31
|
+
sep: string;
|
|
32
|
+
quote: string;
|
|
33
|
+
maxFieldBytes?: number;
|
|
34
|
+
}, batch?: number): AsyncGenerator<string[][]>;
|
|
35
|
+
/**
|
|
36
|
+
* CSV rows as objects, as parseCsv gives them (startRow, the header row's names, blank lines dropped), in batches.
|
|
37
|
+
* headerRow: false needs every row's width first: not read this way (null).
|
|
38
|
+
* @param {any} body @param {{ separator?: string, quote?: string, headerRow?: boolean, startRow?: number }} src
|
|
39
|
+
* @param {(v: any, d: string, what: string) => string} csvChar @param {number} [maxFieldBytes]
|
|
40
|
+
*/
|
|
41
|
+
export function csvRows(body: any, src: {
|
|
42
|
+
separator?: string;
|
|
43
|
+
quote?: string;
|
|
44
|
+
headerRow?: boolean;
|
|
45
|
+
startRow?: number;
|
|
46
|
+
}, csvChar: (v: any, d: string, what: string) => string, maxFieldBytes?: number): AsyncGenerator<{
|
|
47
|
+
[k: string]: string;
|
|
48
|
+
}[], void, unknown>;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An XML source's value: the root element and the source's prefix → namespace URI map.
|
|
3
|
+
* @param {string} text @param {{ namespaces?: Record<string, string> }} [src]
|
|
4
|
+
*/
|
|
5
|
+
export function xmlDocument(text: string, src?: {
|
|
6
|
+
namespaces?: Record<string, string>;
|
|
7
|
+
}): {
|
|
8
|
+
$xml: import("../../importers/xml.js").XmlElement;
|
|
9
|
+
$ns: {
|
|
10
|
+
[x: string]: string;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
/** A SOAP response's Body content (its first element), or the Fault's message as an error. @param {string} text */
|
|
14
|
+
export function soapBody(text: string, src?: {}): {
|
|
15
|
+
$xml: import("../../importers/xml.js").XmlElement;
|
|
16
|
+
$ns: {
|
|
17
|
+
[x: string]: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
/** @param {string} path @returns {{ abs: boolean, steps: Step[] }} */
|
|
21
|
+
export function compileXPath(path: string): {
|
|
22
|
+
abs: boolean;
|
|
23
|
+
steps: Step[];
|
|
24
|
+
};
|
|
25
|
+
/** The text of an element and all its descendants, trimmed (XPath's string value). @param {XmlElement} el */
|
|
26
|
+
export function stringValue(el: XmlElement): string;
|
|
27
|
+
/**
|
|
28
|
+
* Evaluate a path: elements, or strings for @attr / text().
|
|
29
|
+
* @param {{ $xml: XmlElement, $ns: Record<string, string> }} doc
|
|
30
|
+
* @param {string} path
|
|
31
|
+
* @param {XmlElement} [context] for a relative path (a field of a row); a relative path without one starts at the root
|
|
32
|
+
* @returns {(XmlElement|string)[]}
|
|
33
|
+
*/
|
|
34
|
+
export function selectXml(doc: {
|
|
35
|
+
$xml: XmlElement;
|
|
36
|
+
$ns: Record<string, string>;
|
|
37
|
+
}, path: string, context?: XmlElement): (XmlElement | string)[];
|
|
38
|
+
/** A field's value: the first result of a path relative to the row element, as text. */
|
|
39
|
+
export function xmlValue(doc: any, el: any, path: any): string;
|
|
40
|
+
/**
|
|
41
|
+
* A row object from an element: its attributes, each child element (text for a leaf, an object for a child with
|
|
42
|
+
* children of its own, a list when the name repeats), and its own text under its name when it has no child elements.
|
|
43
|
+
* @param {XmlElement} el
|
|
44
|
+
*/
|
|
45
|
+
export function xmlObject(el: XmlElement): Record<string, any>;
|
|
46
|
+
/**
|
|
47
|
+
* Every repeating element in the document (an element whose parent has more than one child of that name), as the
|
|
48
|
+
* response explorer shows lists: { path, rows, objects, fields, spreads }. One linear walk; fields from the first 50 rows.
|
|
49
|
+
* @param {{ $xml: XmlElement }} doc
|
|
50
|
+
*/
|
|
51
|
+
export function xmlRowPaths(doc: {
|
|
52
|
+
$xml: XmlElement;
|
|
53
|
+
}): {
|
|
54
|
+
path: string;
|
|
55
|
+
rows: number;
|
|
56
|
+
objects: boolean;
|
|
57
|
+
fields: string[];
|
|
58
|
+
spreads: number;
|
|
59
|
+
}[];
|
|
60
|
+
/** The likeliest rows: the most rows, then the shallowest. */
|
|
61
|
+
export function bestXmlRows(doc: any): {
|
|
62
|
+
path: string;
|
|
63
|
+
rows: number;
|
|
64
|
+
objects: boolean;
|
|
65
|
+
fields: string[];
|
|
66
|
+
spreads: number;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Row elements and row objects for a data set path ("$" or empty: the likeliest repeating element).
|
|
70
|
+
* @param {{ $xml: XmlElement, $ns: Record<string, string> }} doc @param {string} [path]
|
|
71
|
+
*/
|
|
72
|
+
export function xmlRows(doc: {
|
|
73
|
+
$xml: XmlElement;
|
|
74
|
+
$ns: Record<string, string>;
|
|
75
|
+
}, path?: string): {
|
|
76
|
+
els: import("../../importers/xml.js").XmlElement[];
|
|
77
|
+
rows: Record<string, any>[];
|
|
78
|
+
} | {
|
|
79
|
+
els: any;
|
|
80
|
+
rows: {
|
|
81
|
+
value: string | import("../../importers/xml.js").XmlElement;
|
|
82
|
+
}[];
|
|
83
|
+
};
|
|
84
|
+
export const XPATH_MAX: 512;
|
|
85
|
+
export function isXmlDoc(v: any): boolean;
|
|
86
|
+
export function xmlEscape(s: any): string;
|
|
87
|
+
export { XmlError };
|
|
88
|
+
export type XmlElement = import("../../importers/xml.js").XmlElement;
|
|
89
|
+
export type Test = {
|
|
90
|
+
kind: "name";
|
|
91
|
+
prefix: string;
|
|
92
|
+
local: string;
|
|
93
|
+
} | {
|
|
94
|
+
kind: "self";
|
|
95
|
+
} | {
|
|
96
|
+
kind: "parent";
|
|
97
|
+
} | {
|
|
98
|
+
kind: "attr";
|
|
99
|
+
local: string;
|
|
100
|
+
} | {
|
|
101
|
+
kind: "text";
|
|
102
|
+
};
|
|
103
|
+
export type Step = {
|
|
104
|
+
desc: boolean;
|
|
105
|
+
test: Test;
|
|
106
|
+
preds: any[];
|
|
107
|
+
};
|
|
108
|
+
import { XmlError } from '../../importers/xml.js';
|