@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,212 @@
|
|
|
1
|
+
/** A blank A4 report: header with title, empty body, footer with page numbers. */
|
|
2
|
+
export function blankReport(name?: string): {
|
|
3
|
+
$schema: string;
|
|
4
|
+
name: string;
|
|
5
|
+
page: {
|
|
6
|
+
size: string;
|
|
7
|
+
orientation: string;
|
|
8
|
+
margins: number[];
|
|
9
|
+
};
|
|
10
|
+
parameters: any[];
|
|
11
|
+
dataSources: any[];
|
|
12
|
+
dataSets: any[];
|
|
13
|
+
styles: {
|
|
14
|
+
base: {
|
|
15
|
+
fontFamily: string;
|
|
16
|
+
fontSize: number;
|
|
17
|
+
color: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
sections: {
|
|
21
|
+
pageHeader: {
|
|
22
|
+
height: number;
|
|
23
|
+
items: {
|
|
24
|
+
id: string;
|
|
25
|
+
type: string;
|
|
26
|
+
name: string;
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
w: number;
|
|
30
|
+
h: number;
|
|
31
|
+
value: string;
|
|
32
|
+
canGrow: boolean;
|
|
33
|
+
style: {
|
|
34
|
+
fontSize: number;
|
|
35
|
+
fontWeight: string;
|
|
36
|
+
};
|
|
37
|
+
}[];
|
|
38
|
+
};
|
|
39
|
+
body: {
|
|
40
|
+
height: number;
|
|
41
|
+
items: any[];
|
|
42
|
+
};
|
|
43
|
+
pageFooter: {
|
|
44
|
+
height: number;
|
|
45
|
+
items: {
|
|
46
|
+
id: string;
|
|
47
|
+
type: string;
|
|
48
|
+
name: string;
|
|
49
|
+
x: number;
|
|
50
|
+
y: number;
|
|
51
|
+
w: number;
|
|
52
|
+
h: number;
|
|
53
|
+
value: string;
|
|
54
|
+
canGrow: boolean;
|
|
55
|
+
style: {
|
|
56
|
+
fontSize: number;
|
|
57
|
+
color: string;
|
|
58
|
+
textAlign: string;
|
|
59
|
+
};
|
|
60
|
+
}[];
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* A pageless dashboard: number tiles, two charts and a table on one page that grows to fit.
|
|
66
|
+
* The inline sample rows are there so the dashboard shows something at once; replace the data source.
|
|
67
|
+
*/
|
|
68
|
+
export function blankDashboard(name?: string): {
|
|
69
|
+
$schema: string;
|
|
70
|
+
name: string;
|
|
71
|
+
page: {
|
|
72
|
+
size: string;
|
|
73
|
+
width: number;
|
|
74
|
+
margins: number[];
|
|
75
|
+
minHeight: number;
|
|
76
|
+
};
|
|
77
|
+
parameters: any[];
|
|
78
|
+
dataSources: {
|
|
79
|
+
name: string;
|
|
80
|
+
type: string;
|
|
81
|
+
data: {
|
|
82
|
+
rows: {
|
|
83
|
+
month: number;
|
|
84
|
+
monthName: string;
|
|
85
|
+
region: string;
|
|
86
|
+
sales: number;
|
|
87
|
+
orders: number;
|
|
88
|
+
}[];
|
|
89
|
+
};
|
|
90
|
+
}[];
|
|
91
|
+
dataSets: {
|
|
92
|
+
name: string;
|
|
93
|
+
source: string;
|
|
94
|
+
path: string;
|
|
95
|
+
}[];
|
|
96
|
+
styles: {
|
|
97
|
+
base: {
|
|
98
|
+
fontFamily: string;
|
|
99
|
+
fontSize: number;
|
|
100
|
+
color: string;
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
sections: {
|
|
104
|
+
pageHeader: {
|
|
105
|
+
height: number;
|
|
106
|
+
items: any[];
|
|
107
|
+
};
|
|
108
|
+
body: {
|
|
109
|
+
height: number;
|
|
110
|
+
items: ({
|
|
111
|
+
type: string;
|
|
112
|
+
name: string;
|
|
113
|
+
x: any;
|
|
114
|
+
y: number;
|
|
115
|
+
w: number;
|
|
116
|
+
h: number;
|
|
117
|
+
value: any;
|
|
118
|
+
style: {
|
|
119
|
+
fontSize: number;
|
|
120
|
+
color: string;
|
|
121
|
+
fontWeight?: undefined;
|
|
122
|
+
};
|
|
123
|
+
} | {
|
|
124
|
+
type: string;
|
|
125
|
+
name: any;
|
|
126
|
+
x: any;
|
|
127
|
+
y: number;
|
|
128
|
+
w: number;
|
|
129
|
+
h: number;
|
|
130
|
+
value: any;
|
|
131
|
+
style: {
|
|
132
|
+
fontSize: number;
|
|
133
|
+
fontWeight: string;
|
|
134
|
+
color?: undefined;
|
|
135
|
+
};
|
|
136
|
+
} | {
|
|
137
|
+
type: string;
|
|
138
|
+
name: string;
|
|
139
|
+
x: number;
|
|
140
|
+
y: number;
|
|
141
|
+
w: number;
|
|
142
|
+
h: number;
|
|
143
|
+
chartType: string;
|
|
144
|
+
dataSet: string;
|
|
145
|
+
title: string;
|
|
146
|
+
category: string;
|
|
147
|
+
series: {
|
|
148
|
+
name: string;
|
|
149
|
+
value: string;
|
|
150
|
+
}[];
|
|
151
|
+
seriesGroup: string;
|
|
152
|
+
stacked: boolean;
|
|
153
|
+
legend: string;
|
|
154
|
+
valueFormat: string;
|
|
155
|
+
rowGroup?: undefined;
|
|
156
|
+
columnGroup?: undefined;
|
|
157
|
+
value?: undefined;
|
|
158
|
+
corner?: undefined;
|
|
159
|
+
columnSort?: undefined;
|
|
160
|
+
} | {
|
|
161
|
+
type: string;
|
|
162
|
+
name: string;
|
|
163
|
+
x: number;
|
|
164
|
+
y: number;
|
|
165
|
+
w: number;
|
|
166
|
+
h: number;
|
|
167
|
+
chartType: string;
|
|
168
|
+
dataSet: string;
|
|
169
|
+
title: string;
|
|
170
|
+
category: string;
|
|
171
|
+
series: {
|
|
172
|
+
name: string;
|
|
173
|
+
value: string;
|
|
174
|
+
}[];
|
|
175
|
+
legend: string;
|
|
176
|
+
valueFormat: string;
|
|
177
|
+
seriesGroup?: undefined;
|
|
178
|
+
stacked?: undefined;
|
|
179
|
+
rowGroup?: undefined;
|
|
180
|
+
columnGroup?: undefined;
|
|
181
|
+
value?: undefined;
|
|
182
|
+
corner?: undefined;
|
|
183
|
+
columnSort?: undefined;
|
|
184
|
+
} | {
|
|
185
|
+
type: string;
|
|
186
|
+
name: string;
|
|
187
|
+
x: number;
|
|
188
|
+
y: number;
|
|
189
|
+
w: number;
|
|
190
|
+
h: number;
|
|
191
|
+
dataSet: string;
|
|
192
|
+
rowGroup: string;
|
|
193
|
+
columnGroup: string;
|
|
194
|
+
value: string;
|
|
195
|
+
valueFormat: string;
|
|
196
|
+
corner: string;
|
|
197
|
+
columnSort: string;
|
|
198
|
+
chartType?: undefined;
|
|
199
|
+
title?: undefined;
|
|
200
|
+
category?: undefined;
|
|
201
|
+
series?: undefined;
|
|
202
|
+
seriesGroup?: undefined;
|
|
203
|
+
stacked?: undefined;
|
|
204
|
+
legend?: undefined;
|
|
205
|
+
})[];
|
|
206
|
+
};
|
|
207
|
+
pageFooter: {
|
|
208
|
+
height: number;
|
|
209
|
+
items: any[];
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** The nearest known name: a typo (2 edits) or the start of a longer one (noRows → noRowsText). */
|
|
2
|
+
export function didYouMean(k: any, known: any): any;
|
|
3
|
+
/**
|
|
4
|
+
* Structural checks. Errors stop the render; warnings do not. exprErrors: the errors that are an item's expression
|
|
5
|
+
* that does not parse. They are in `errors` too (the designer shows them), but render() goes on and draws #Error in
|
|
6
|
+
* that item or cell with a warning, as SSRS does.
|
|
7
|
+
* @param {any} def
|
|
8
|
+
*/
|
|
9
|
+
export function validate(def: any): {
|
|
10
|
+
errors: string[];
|
|
11
|
+
warnings: any[];
|
|
12
|
+
exprErrors: any[];
|
|
13
|
+
checkOnly: any[];
|
|
14
|
+
} | {
|
|
15
|
+
errors: any[];
|
|
16
|
+
warnings: string[];
|
|
17
|
+
exprErrors: any[];
|
|
18
|
+
checkOnly: any[];
|
|
19
|
+
};
|
|
20
|
+
export const SCHEMA_ID: "pagewright/report@1";
|
|
21
|
+
export const SCHEMA_ALIAS: "reportwright/report@1";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An in-memory sorter (the browser, the CLI): the server passes one that spills runs to disk (server/spill.js).
|
|
3
|
+
* @param {(a: any, b: any) => number} cmp
|
|
4
|
+
*/
|
|
5
|
+
export function memorySorter(cmp: (a: any, b: any) => number): {
|
|
6
|
+
push(r: any): void;
|
|
7
|
+
drain(): AsyncGenerator<any, void, unknown>;
|
|
8
|
+
close(): Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* @param {any} def0 the report definition
|
|
12
|
+
* @param {{ format: 'csv'|'xlsx', parameters?: object, timeZone?: string, now?: Date, state?: any, loadReport?: (id: string) => Promise<any>,
|
|
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,
|
|
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 } }>}
|
|
17
|
+
*/
|
|
18
|
+
export function planStream(def0: any, opts: {
|
|
19
|
+
format: "csv" | "xlsx";
|
|
20
|
+
parameters?: object;
|
|
21
|
+
timeZone?: string;
|
|
22
|
+
now?: Date;
|
|
23
|
+
state?: any;
|
|
24
|
+
loadReport?: (id: string) => Promise<any>;
|
|
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;
|
|
39
|
+
} | {
|
|
40
|
+
why?: undefined;
|
|
41
|
+
name: string;
|
|
42
|
+
columns: number[];
|
|
43
|
+
title: string;
|
|
44
|
+
timeZone: string | null;
|
|
45
|
+
locale: string | null;
|
|
46
|
+
currency: string | null;
|
|
47
|
+
warnings: string[];
|
|
48
|
+
rows: () => AsyncGenerator<any>;
|
|
49
|
+
records: () => AsyncGenerator<any>;
|
|
50
|
+
grouped: () => AsyncGenerator<any>;
|
|
51
|
+
stats: {
|
|
52
|
+
rows: number;
|
|
53
|
+
};
|
|
54
|
+
}>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge style layers. Later layers win. Values that hold expressions
|
|
3
|
+
* are evaluated in the given context (conditional formatting).
|
|
4
|
+
* @param {(object|null|undefined)[]} layers @param {any} ctx
|
|
5
|
+
*/
|
|
6
|
+
export function resolveStyle(layers: (object | null | undefined)[], ctx: any): any;
|
|
7
|
+
/** "1 solid #ccc" | "none" | {width, style, color} → {width, style, color} | null */
|
|
8
|
+
export function parseBorder(b: any): {
|
|
9
|
+
width: any;
|
|
10
|
+
style: any;
|
|
11
|
+
color: any;
|
|
12
|
+
};
|
|
13
|
+
/** Four borders after side overrides. */
|
|
14
|
+
export function borders(st: any): {
|
|
15
|
+
top: {
|
|
16
|
+
width: any;
|
|
17
|
+
style: any;
|
|
18
|
+
color: any;
|
|
19
|
+
};
|
|
20
|
+
right: {
|
|
21
|
+
width: any;
|
|
22
|
+
style: any;
|
|
23
|
+
color: any;
|
|
24
|
+
};
|
|
25
|
+
bottom: {
|
|
26
|
+
width: any;
|
|
27
|
+
style: any;
|
|
28
|
+
color: any;
|
|
29
|
+
};
|
|
30
|
+
left: {
|
|
31
|
+
width: any;
|
|
32
|
+
style: any;
|
|
33
|
+
color: any;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export namespace BASE_STYLE {
|
|
37
|
+
let fontFamily: string;
|
|
38
|
+
let fontSize: number;
|
|
39
|
+
let fontWeight: string;
|
|
40
|
+
let fontStyle: string;
|
|
41
|
+
let color: string;
|
|
42
|
+
let backgroundColor: any;
|
|
43
|
+
let backgroundImage: any;
|
|
44
|
+
let backgroundFit: string;
|
|
45
|
+
let textAlign: string;
|
|
46
|
+
let verticalAlign: string;
|
|
47
|
+
let padding: number;
|
|
48
|
+
let lineHeight: number;
|
|
49
|
+
let border: any;
|
|
50
|
+
let borderTop: any;
|
|
51
|
+
let borderRight: any;
|
|
52
|
+
let borderBottom: any;
|
|
53
|
+
let borderLeft: any;
|
|
54
|
+
let format: any;
|
|
55
|
+
let wrap: boolean;
|
|
56
|
+
let textDecoration: string;
|
|
57
|
+
let textDecorationColor: any;
|
|
58
|
+
let writingMode: string;
|
|
59
|
+
let fill: any;
|
|
60
|
+
let stroke: string;
|
|
61
|
+
let strokeWidth: number;
|
|
62
|
+
let strokeDash: string;
|
|
63
|
+
let radius: number;
|
|
64
|
+
}
|
|
65
|
+
export function padding(st: any): any;
|
|
66
|
+
export namespace DASH {
|
|
67
|
+
let solid: any;
|
|
68
|
+
let dashed: number[];
|
|
69
|
+
let dotted: number[];
|
|
70
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/** The file behind a key, relative to /fonts: what the FontStore loader reads or fetches. */
|
|
2
|
+
export function fontFile(key: any): string;
|
|
3
|
+
/**
|
|
4
|
+
* Fonts uploaded to this server: [{ id, family, weight, style }], key "u-<id>", file "custom/<id>".
|
|
5
|
+
* Replaces the previous list. A family named like a bundled one is skipped (the server refuses those).
|
|
6
|
+
* @param {{ id: string, family: string, weight?: number, style?: string }[]} list
|
|
7
|
+
*/
|
|
8
|
+
export function setCustomFonts(list: {
|
|
9
|
+
id: string;
|
|
10
|
+
family: string;
|
|
11
|
+
weight?: number;
|
|
12
|
+
style?: string;
|
|
13
|
+
}[]): void;
|
|
14
|
+
/**
|
|
15
|
+
* 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
|
+
* @param {string} [family] @param {string|number} [weight] @param {string} [style]
|
|
18
|
+
*/
|
|
19
|
+
export function resolveFontKey(family?: string, weight?: string | number, style?: string): string;
|
|
20
|
+
/** CSS description of a font key, for SVG/HTML output. */
|
|
21
|
+
export function fontCss(key: any): {
|
|
22
|
+
family: string;
|
|
23
|
+
weight: number;
|
|
24
|
+
style: string;
|
|
25
|
+
};
|
|
26
|
+
/** The bundled fallback faces for `key` (one per script), for CSS font-family lists. */
|
|
27
|
+
export function fallbackKeys(key: any): string[];
|
|
28
|
+
/**
|
|
29
|
+
* CSS unicode-range for a bundled fallback face, else null: its script's blocks plus the marks, joiners and
|
|
30
|
+
* dotted circle a run in that font can carry. A browser then downloads the face only for text in that script
|
|
31
|
+
* (without it, a font-family list of fallbacks fetches every face before the one that has the glyph).
|
|
32
|
+
* @param {string} key
|
|
33
|
+
*/
|
|
34
|
+
export function unicodeRange(key: string): string;
|
|
35
|
+
/** The bundled fallback face for a code point, in the weight and style of `key`; null when there is none. */
|
|
36
|
+
export function fallbackKey(cp: any, key: any): string;
|
|
37
|
+
/**
|
|
38
|
+
* The fallback faces (regular and bold, one per script) and the shaper that text in these strings will need. render()
|
|
39
|
+
* loads them before the layout: a face found missing during the layout means laying everything out again.
|
|
40
|
+
* ponytail: regular and bold only (italic text in a fallback script uses them too, see resolveFontKey).
|
|
41
|
+
* @param {Iterable<any>} texts
|
|
42
|
+
* @returns {string[]}
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* The faces a report definition names before layout: every object with fontFamily, fontWeight or fontStyle (styles,
|
|
46
|
+
* named styles, item and rich-text styles, table and group styles), and the bold face a chart's titles use. Loaded up
|
|
47
|
+
* front, so a report that uses bold or italic lays out in one pass. Data (dataSources, inline data) is not read.
|
|
48
|
+
* @param {any} def @returns {string[]} face keys
|
|
49
|
+
*/
|
|
50
|
+
export function fontsForDef(def: any): string[];
|
|
51
|
+
export function fontsFor(texts: any): any[];
|
|
52
|
+
/** The optional families (scripts/fetch-fonts-cjk.mjs). */
|
|
53
|
+
export const OPTIONAL_KEYS: string[];
|
|
54
|
+
/** family → its faces: the bundled families, then the fonts uploaded to the server (setCustomFonts). @type {Record<string, Face[]>} */
|
|
55
|
+
export const FONT_FAMILIES: Record<string, Face[]>;
|
|
56
|
+
export const BUNDLED_FAMILIES: string[];
|
|
57
|
+
export const DEFAULT_FAMILY: "Inter";
|
|
58
|
+
/** Loaded before every render. Fallback and uploaded fonts load when a report needs them. */
|
|
59
|
+
export const ALL_FONT_KEYS: string[];
|
|
60
|
+
/** The one face a render cannot do without: the fallback for every other face that is missing or failed. */
|
|
61
|
+
export const CORE_FONT_KEY: "Inter-Regular";
|
|
62
|
+
/** The bundled Latin faces, loaded before layout. The optional CJK and emoji faces (~40 MB once installed) stay lazy: loaded only when text needs them. */
|
|
63
|
+
export const PRELOAD_KEYS: string[];
|
|
64
|
+
/** The HarfBuzz shaper (WASM). FontStore loads it like a font, from /fonts/harfbuzz.wasm, once text needs shaping. */
|
|
65
|
+
export const SHAPER: "harfbuzz";
|
|
66
|
+
export function allFontKeys(): string[];
|
|
67
|
+
/**
|
|
68
|
+
* Loads font files once and keeps the parsed fontkit objects; SHAPER loads the HarfBuzz shaper.
|
|
69
|
+
* The loader returns the bytes of fontFile(key) under /fonts.
|
|
70
|
+
*/
|
|
71
|
+
export class FontStore {
|
|
72
|
+
/** @param {(key: string) => Promise<ArrayBuffer|Uint8Array>} loader */
|
|
73
|
+
constructor(loader: (key: string) => Promise<ArrayBuffer | Uint8Array>);
|
|
74
|
+
loader: (key: string) => Promise<ArrayBuffer | Uint8Array>;
|
|
75
|
+
/** @type {Map<string, any>} */ fonts: Map<string, any>;
|
|
76
|
+
/** @type {Map<string, Uint8Array>} */ bytes: Map<string, Uint8Array>;
|
|
77
|
+
/** @type {Map<string, Promise<void>>} */ pending: Map<string, Promise<void>>;
|
|
78
|
+
/** keys that did not load: their text falls back to the default font @type {Set<string>} */ failed: Set<string>;
|
|
79
|
+
/** @type {any} */ shaper: any;
|
|
80
|
+
/** @type {Map<string, any>} HarfBuzz fonts by key */ hb: Map<string, any>;
|
|
81
|
+
/** @param {string[]} keys */
|
|
82
|
+
load(keys?: string[]): Promise<void>;
|
|
83
|
+
/** @param {string} key */
|
|
84
|
+
has(key: string): boolean;
|
|
85
|
+
/** The HarfBuzz font for a loaded key (the shaper must be loaded). @param {string} key */
|
|
86
|
+
hbFont(key: string): any;
|
|
87
|
+
/** @param {string} key */
|
|
88
|
+
get(key: string): any;
|
|
89
|
+
}
|
|
90
|
+
export type Face = {
|
|
91
|
+
key: string;
|
|
92
|
+
family: string;
|
|
93
|
+
weight: number;
|
|
94
|
+
style: "normal" | "italic";
|
|
95
|
+
file: string;
|
|
96
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grapheme clusters: where a too-long word may break. Intl.Segmenter when there is one; else code points with
|
|
3
|
+
* marks, joiners and variation selectors kept on the character before (and the character after a ZWJ).
|
|
4
|
+
* @param {string} s @param {boolean} [intl] false: the fallback (tests)
|
|
5
|
+
*/
|
|
6
|
+
export function clusters(s: string, intl?: boolean): string[];
|
|
7
|
+
/**
|
|
8
|
+
* Where a line may break inside text written without spaces: the word boundaries ICU's dictionaries find
|
|
9
|
+
* (Node and browsers ship them for Thai, Lao, Khmer and Myanmar), as UTF-16 indices next to an SA character.
|
|
10
|
+
* Without a segmenter there are none (UAX #14 then treats SA as letters), and a word too long for its line
|
|
11
|
+
* breaks between grapheme clusters, as any long word does.
|
|
12
|
+
* @param {string} text @param {Intl.Segmenter|null} [segmenter]
|
|
13
|
+
* @returns {Set<number>}
|
|
14
|
+
*/
|
|
15
|
+
export function saBreaks(text: string, segmenter?: Intl.Segmenter | null): Set<number>;
|
|
16
|
+
/**
|
|
17
|
+
* Last step of a layout: text items whose font did not load switch to the font they were measured in, and
|
|
18
|
+
* lines that need it get their runs. Mutates the items (they are fresh objects from the layout).
|
|
19
|
+
* @param {any[]} items @param {TextMeasurer} m
|
|
20
|
+
*/
|
|
21
|
+
export function finishText(items: any[], m: TextMeasurer): void;
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {{ font: string, x: number, w: number, text: string, rtl?: boolean, shaped?: boolean, glyphs: number[] }} Run
|
|
24
|
+
* One font, one direction. x and w in points from the start of the line; glyphs: [id, x, y, cluster] per glyph
|
|
25
|
+
* in visual order, x from the start of the run, y up, cluster = UTF-16 index into `text`.
|
|
26
|
+
*/
|
|
27
|
+
export class TextMeasurer {
|
|
28
|
+
/** @param {import('./fonts.js').FontStore} store */
|
|
29
|
+
constructor(store: import("./fonts.js").FontStore);
|
|
30
|
+
store: import("./fonts.js").FontStore;
|
|
31
|
+
/** @type {Map<string, any>} per loaded face: its metrics and advances (see face()) */
|
|
32
|
+
faces: Map<string, any>;
|
|
33
|
+
/** text layouts of boxes in a static (frozen) style: style → width → text → layout (items/paint.js) */
|
|
34
|
+
boxes: WeakMap<object, any>;
|
|
35
|
+
boxCount: number;
|
|
36
|
+
/** a frozen style's font key, size, padding and line height (items/paint.js) */
|
|
37
|
+
looks: WeakMap<object, any>;
|
|
38
|
+
/** @type {Map<string, Map<number, boolean>>} */
|
|
39
|
+
cover: Map<string, Map<number, boolean>>;
|
|
40
|
+
/** @type {Map<string, any>} complex layouts at size 1 */
|
|
41
|
+
cache: Map<string, any>;
|
|
42
|
+
/** fonts (or the shaper) that text needed but the store has not loaded: render() loads them and lays out again @type {Set<string>} */
|
|
43
|
+
missing: Set<string>;
|
|
44
|
+
/** characters no font could draw @type {Set<string>} */
|
|
45
|
+
noGlyph: Set<string>;
|
|
46
|
+
/**
|
|
47
|
+
* The key to measure with: `key` when loaded; else (not loaded yet, or failed) the bundled face of the same weight
|
|
48
|
+
* and style when that is loaded, else the core regular face. A key not yet loaded is asked for in the next pass.
|
|
49
|
+
*/
|
|
50
|
+
usable(key: any): any;
|
|
51
|
+
/**
|
|
52
|
+
* A loaded face's numbers, read once: fontkit's getters (unitsPerEm, ascent…) decode tables on every read.
|
|
53
|
+
* adv: advances per code point (-1 = not on the fast path); words: fast-path units per string (a table repeats them).
|
|
54
|
+
* @param {string} key a loaded key
|
|
55
|
+
*/
|
|
56
|
+
face(key: string): any;
|
|
57
|
+
/** Font units of `text` on the fast path, or -1 when it needs the complex path. */
|
|
58
|
+
fast(text: any, key: any): any;
|
|
59
|
+
/**
|
|
60
|
+
* Advance width in points. @param {string} text @param {string} key @param {number} size
|
|
61
|
+
* @param {'ltr'|'rtl'} [dir] paragraph direction (default: from the first strong character)
|
|
62
|
+
*/
|
|
63
|
+
width(text: string, key: string, size: number, dir?: "ltr" | "rtl"): number;
|
|
64
|
+
/**
|
|
65
|
+
* Where underline and strike-through go, from the font's own tables (post and OS/2), in points:
|
|
66
|
+
* y offsets of the stroke centre from the baseline (positive = down, as on the page) and thicknesses.
|
|
67
|
+
* A font without the tables falls back to proportions of its descent and x-height.
|
|
68
|
+
* @param {string} key @param {number} size
|
|
69
|
+
*/
|
|
70
|
+
decoration(key: string, size: number): {
|
|
71
|
+
underlineY: number;
|
|
72
|
+
underlineWidth: number;
|
|
73
|
+
strikeY: number;
|
|
74
|
+
strikeWidth: number;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Superscript and subscript from the font's OS/2 table, in em: the size of the small text and how far its
|
|
78
|
+
* baseline moves (rise up for superscript, drop down for subscript). Fonts without the values get the
|
|
79
|
+
* proportions most fonts use.
|
|
80
|
+
* @param {string} key
|
|
81
|
+
*/
|
|
82
|
+
script(key: string): {
|
|
83
|
+
supScale: any;
|
|
84
|
+
supRise: any;
|
|
85
|
+
subScale: any;
|
|
86
|
+
subDrop: any;
|
|
87
|
+
};
|
|
88
|
+
/** @param {string} key @param {number} size */
|
|
89
|
+
metrics(key: string, size: number): any;
|
|
90
|
+
/**
|
|
91
|
+
* The visually ordered runs of one line, or null when the line is simple (draw `text` as it is).
|
|
92
|
+
* @param {string} text @param {string} key @param {number} size @param {'ltr'|'rtl'} [dir]
|
|
93
|
+
* @returns {Run[]|null}
|
|
94
|
+
*/
|
|
95
|
+
runs(text: string, key: string, size: number, dir?: "ltr" | "rtl"): Run[] | null;
|
|
96
|
+
/** Paragraph direction of text that needs shaping, bidi or CJK breaks, else undefined. */
|
|
97
|
+
direction(text: any, key: any): "ltr" | "rtl";
|
|
98
|
+
/**
|
|
99
|
+
* Greedy line breaking. Simple paragraphs break at spaces (a word longer than the line breaks by
|
|
100
|
+
* character), exactly as before. Others also break between CJK characters (kinsoku applied), never
|
|
101
|
+
* inside a grapheme cluster (a conjunct, a letter and its marks), and remember their direction.
|
|
102
|
+
* @param {string} text @param {string} key @param {number} size @param {number} maxWidth
|
|
103
|
+
* @returns {{text: string, width: number, dir?: 'ltr'|'rtl'}[]}
|
|
104
|
+
*/
|
|
105
|
+
wrap(text: string, key: string, size: number, maxWidth: number): {
|
|
106
|
+
text: string;
|
|
107
|
+
width: number;
|
|
108
|
+
dir?: "ltr" | "rtl";
|
|
109
|
+
}[];
|
|
110
|
+
/** @param {string} para @param {string} key @param {number} size @param {number} maxWidth @param {'ltr'|'rtl'} dir @param {number} sp @param {any[]} out */
|
|
111
|
+
wrapComplex(para: string, key: string, size: number, maxWidth: number, dir: "ltr" | "rtl", sp: number, out: any[]): void;
|
|
112
|
+
/** Cut a line so it fits, then add "…". */
|
|
113
|
+
ellipsize(text: any, key: any, size: any, maxWidth: any, dir: any): any;
|
|
114
|
+
/** Does this font have a glyph for the character? */
|
|
115
|
+
has(key: any, cp: any): boolean;
|
|
116
|
+
/** The font for one character: the chosen one, else the bundled fallback for its script, else the one before. */
|
|
117
|
+
pick(cp: any, key: any, prev: any): any;
|
|
118
|
+
/**
|
|
119
|
+
* Bidi levels, a font per character, runs (one font, level, script, and space or not), shaping,
|
|
120
|
+
* then visual order. Cached at size 1.
|
|
121
|
+
* @param {string} text @param {string} key a loaded key @param {'ltr'|'rtl'|undefined} dir
|
|
122
|
+
* @returns {{ w: number, rtl: boolean, runs: Run[] }}
|
|
123
|
+
*/
|
|
124
|
+
layout(text: string, key: string, dir: "ltr" | "rtl" | undefined): {
|
|
125
|
+
w: number;
|
|
126
|
+
rtl: boolean;
|
|
127
|
+
runs: Run[];
|
|
128
|
+
};
|
|
129
|
+
/** One run at size 1: HarfBuzz for complex scripts and right-to-left text, else character-map glyphs. @returns {Run} */
|
|
130
|
+
shapeRun(text: any, key: any, rtl: any, script: any): Run;
|
|
131
|
+
unshaped: boolean;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* One font, one direction. x and w in points from the start of the line; glyphs: [id, x, y, cluster] per glyph
|
|
135
|
+
* in visual order, x from the start of the run, y up, cluster = UTF-16 index into `text`.
|
|
136
|
+
*/
|
|
137
|
+
export type Run = {
|
|
138
|
+
font: string;
|
|
139
|
+
x: number;
|
|
140
|
+
w: number;
|
|
141
|
+
text: string;
|
|
142
|
+
rtl?: boolean;
|
|
143
|
+
shaped?: boolean;
|
|
144
|
+
glyphs: number[];
|
|
145
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} html
|
|
3
|
+
* @param {{ baseSize?: number, warn?: (msg: string) => void }} [opt]
|
|
4
|
+
* @returns {{ blocks: RichBlock[] }}
|
|
5
|
+
*/
|
|
6
|
+
export function parseRich(html: string, opt?: {
|
|
7
|
+
baseSize?: number;
|
|
8
|
+
warn?: (msg: string) => void;
|
|
9
|
+
}): {
|
|
10
|
+
blocks: RichBlock[];
|
|
11
|
+
};
|
|
12
|
+
export namespace RICH_LIMITS {
|
|
13
|
+
let maxLength: number;
|
|
14
|
+
let maxDepth: number;
|
|
15
|
+
let maxRuns: number;
|
|
16
|
+
let maxBlocks: number;
|
|
17
|
+
let maxBreaks: number;
|
|
18
|
+
let maxAttrs: number;
|
|
19
|
+
let maxDecls: number;
|
|
20
|
+
}
|
|
21
|
+
/** A link target rich text may use: the same allow-list as url actions (src/engine/url.js). */
|
|
22
|
+
export const safeHref: typeof safeUrl;
|
|
23
|
+
export type RichStyle = {
|
|
24
|
+
fontFamily?: string;
|
|
25
|
+
fontSize?: number;
|
|
26
|
+
fontWeight?: string;
|
|
27
|
+
fontStyle?: string;
|
|
28
|
+
color?: string;
|
|
29
|
+
background?: string;
|
|
30
|
+
underline?: boolean;
|
|
31
|
+
strike?: boolean;
|
|
32
|
+
script?: "sup" | "sub";
|
|
33
|
+
href?: string;
|
|
34
|
+
align?: string;
|
|
35
|
+
};
|
|
36
|
+
export type RichRun = {
|
|
37
|
+
text: string;
|
|
38
|
+
st: RichStyle;
|
|
39
|
+
};
|
|
40
|
+
export type RichBlock = {
|
|
41
|
+
tag: string;
|
|
42
|
+
align?: string;
|
|
43
|
+
level: number;
|
|
44
|
+
marker?: string;
|
|
45
|
+
spaceAfter?: boolean;
|
|
46
|
+
runs: RichRun[];
|
|
47
|
+
};
|
|
48
|
+
import { safeUrl } from '../url.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** @param {Uint8Array} wasm */
|
|
2
|
+
export function createShaper(wasm: Uint8Array): Promise<{
|
|
3
|
+
/**
|
|
4
|
+
* A HarfBuzz font for these bytes. It lives as long as the shaper: fonts are few and reused.
|
|
5
|
+
* @param {Uint8Array} bytes @returns {{ ptr: number, upem: number }}
|
|
6
|
+
*/
|
|
7
|
+
font(bytes: Uint8Array): {
|
|
8
|
+
ptr: number;
|
|
9
|
+
upem: number;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Shape one run (one font, one script, one direction).
|
|
13
|
+
* @param {{ ptr: number }} font @param {string} text @param {boolean} rtl
|
|
14
|
+
* @param {boolean} [plain] kerning and ligatures off (a simple-script run in a right-to-left context)
|
|
15
|
+
* @returns {number[]} [glyph id, x advance, x offset, y offset, cluster (UTF-16 index)] per glyph, in visual order
|
|
16
|
+
*/
|
|
17
|
+
shape(font: {
|
|
18
|
+
ptr: number;
|
|
19
|
+
}, text: string, rtl: boolean, plain?: boolean): number[];
|
|
20
|
+
}>;
|