quario 0.0.1 → 0.2.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 +156 -0
- package/LICENSE +219 -0
- package/README.md +237 -1
- package/lib/index.d.ts +617 -0
- package/lib/index.js +290 -0
- package/lib/license.js +141 -0
- package/lib/locate.js +67 -0
- package/lib/names.js +19 -0
- package/lib/plan.js +1388 -0
- package/lib/scope.js +162 -0
- package/lib/stream.js +177 -0
- package/lib/style.js +81 -0
- package/package.json +55 -2
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,617 @@
|
|
|
1
|
+
import type { PadvinderErrorCode, QueryOptions, QueryPath, TrefferErrorCode } from "padvinder";
|
|
2
|
+
import type { XprsnErrorCode, XprsnSignature } from "xprsn";
|
|
3
|
+
import type {
|
|
4
|
+
LiteralToken as SjabloonLiteralToken,
|
|
5
|
+
SjabloonBlock,
|
|
6
|
+
SjabloonErrorCode,
|
|
7
|
+
ValueToken as SjabloonValueToken,
|
|
8
|
+
} from "sjabloon";
|
|
9
|
+
|
|
10
|
+
// Re-exported so render targets type the stream's `paths` metadata from
|
|
11
|
+
// 'quario' alone, without their own padvinder dependency.
|
|
12
|
+
export type { QueryPath } from "padvinder";
|
|
13
|
+
|
|
14
|
+
export type FunctionRegistry = Record<string, (...args: any[]) => any>;
|
|
15
|
+
export type ExpressionValue<T = unknown> = T | `=${string}`;
|
|
16
|
+
export type ReducerSpec = string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A value a JSON document can hold. `params` accepts these and nothing else:
|
|
20
|
+
* a Date, Map, Set or typed array is a definition error, as are `NaN` and
|
|
21
|
+
* `Infinity`, which this type cannot exclude but the traversal rejects.
|
|
22
|
+
*/
|
|
23
|
+
export type JsonValue =
|
|
24
|
+
| null
|
|
25
|
+
| boolean
|
|
26
|
+
| number
|
|
27
|
+
| string
|
|
28
|
+
| JsonValue[]
|
|
29
|
+
| { [key: string]: JsonValue };
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The closed, target-neutral style vocabulary. Literal values are validated
|
|
33
|
+
* strictly (unknown names and mistyped literals are definition errors);
|
|
34
|
+
* `=` expression results are coerced leniently by each target at render.
|
|
35
|
+
* Colors are `#rgb`/`#rrggbb` hex only. Each target maps the declarations to
|
|
36
|
+
* its own formatting model (the HTML target to inline CSS, the PDF target to
|
|
37
|
+
* faces, points, and rects).
|
|
38
|
+
*/
|
|
39
|
+
export interface StyleDeclarations {
|
|
40
|
+
/** `'sans'` | `'serif'` | `'mono'`, or an embedded font family name. */
|
|
41
|
+
family?: ExpressionValue<string>;
|
|
42
|
+
/** Font size in points. */
|
|
43
|
+
size?: ExpressionValue<number>;
|
|
44
|
+
bold?: ExpressionValue<boolean>;
|
|
45
|
+
italic?: ExpressionValue<boolean>;
|
|
46
|
+
underline?: ExpressionValue<boolean>;
|
|
47
|
+
strikethrough?: ExpressionValue<boolean>;
|
|
48
|
+
/** Render the text in capitals. Capitals, not small caps. */
|
|
49
|
+
uppercase?: ExpressionValue<boolean>;
|
|
50
|
+
/** Text color, `#rgb`/`#rrggbb`. */
|
|
51
|
+
color?: ExpressionValue<string>;
|
|
52
|
+
/** Background color, `#rgb`/`#rrggbb`. */
|
|
53
|
+
background?: ExpressionValue<string>;
|
|
54
|
+
/** Horizontal alignment within the cell. */
|
|
55
|
+
align?: ExpressionValue<Align>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface SortKey {
|
|
59
|
+
by: `=${string}`;
|
|
60
|
+
dir?: "asc" | "desc";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** A cell value: one template string. */
|
|
64
|
+
export type CellValue = string;
|
|
65
|
+
|
|
66
|
+
export type Align = "left" | "center" | "right";
|
|
67
|
+
|
|
68
|
+
export interface Cell {
|
|
69
|
+
value: CellValue;
|
|
70
|
+
visible?: ExpressionValue<boolean>;
|
|
71
|
+
/** Literal only — never an expression. */
|
|
72
|
+
style?: StyleDeclarations;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface TextItem extends Cell {
|
|
76
|
+
type: "text";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** How an image is sized: at its intrinsic size, or scaled to the content width. */
|
|
80
|
+
export type ImageFit = "natural" | "width";
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The declarations an image item accepts. The rest of the vocabulary describes
|
|
84
|
+
* text, which an image does not have, so any other name on one is a definition
|
|
85
|
+
* error. A narrowing of the one vocabulary rather than a second list of its
|
|
86
|
+
* own, so the two cannot drift.
|
|
87
|
+
*/
|
|
88
|
+
export type ImageStyleDeclarations = Pick<StyleDeclarations, "background" | "align">;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* What a report default declares: the two declarations a typeface is made of.
|
|
92
|
+
* Anything else is a definition error, as on an image item.
|
|
93
|
+
*/
|
|
94
|
+
export type ReportStyleDeclarations = Pick<StyleDeclarations, "family" | "size">;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* A host-supplied raster graphic in the band flow. `source` is an expression
|
|
98
|
+
* (never a literal — JSON has no way to write bytes) yielding the complete
|
|
99
|
+
* image file as a `Uint8Array` of PNG or JPEG bytes; nullish skips the item
|
|
100
|
+
* silently, anything else invalid is a located render error.
|
|
101
|
+
*/
|
|
102
|
+
export interface ImageItem {
|
|
103
|
+
type: "image";
|
|
104
|
+
source: `=${string}`;
|
|
105
|
+
/** Defaults to `"natural"`. */
|
|
106
|
+
fit?: ImageFit;
|
|
107
|
+
/** The image's textual stand-in, as a cell value. */
|
|
108
|
+
alt?: CellValue;
|
|
109
|
+
visible?: ExpressionValue<boolean>;
|
|
110
|
+
style?: ImageStyleDeclarations;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* One slot of a split: an ordinary item, plus the width share that is a slot
|
|
115
|
+
* property rather than an item one. A split may not stand in a slot —
|
|
116
|
+
* placement inside placement is the coordinate system quario does not have.
|
|
117
|
+
*/
|
|
118
|
+
export type SplitSlot = (TextItem | ImageItem) & {
|
|
119
|
+
/** Slot width as a percentage of the content width (0 < width <= 100). */
|
|
120
|
+
width?: number;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Items placed across the content width rather than stacked down the band —
|
|
125
|
+
* the invoice header's "seller left, customer right". A split is always the
|
|
126
|
+
* full content width and never nests; a slot that renders nothing keeps its
|
|
127
|
+
* width, so the line's geometry does not move with the data.
|
|
128
|
+
*/
|
|
129
|
+
export interface SplitItem {
|
|
130
|
+
type: "split";
|
|
131
|
+
slots: [SplitSlot, SplitSlot, ...SplitSlot[]];
|
|
132
|
+
visible?: ExpressionValue<boolean>;
|
|
133
|
+
style?: StyleDeclarations;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** One item in a band: text, an image, or a split. Future types may be additive. */
|
|
137
|
+
export type Item = TextItem | ImageItem | SplitItem;
|
|
138
|
+
|
|
139
|
+
export interface TableHeader {
|
|
140
|
+
value: CellValue;
|
|
141
|
+
/** Literal only — never an expression. */
|
|
142
|
+
style?: StyleDeclarations;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export interface TableColumn extends Cell {
|
|
146
|
+
header: string | TableHeader;
|
|
147
|
+
/** Column width as a percentage of the table width (0 < width <= 100). */
|
|
148
|
+
width?: number;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface TableRow {
|
|
152
|
+
visible?: ExpressionValue<boolean>;
|
|
153
|
+
style?: StyleDeclarations;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface TableDetail {
|
|
157
|
+
row?: TableRow;
|
|
158
|
+
columns: [TableColumn, ...TableColumn[]];
|
|
159
|
+
total?: Cell[];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface Group {
|
|
163
|
+
name: string;
|
|
164
|
+
by: `=${string}`;
|
|
165
|
+
/** Start every instance of this group on a new page (paginated targets). */
|
|
166
|
+
break?: "page";
|
|
167
|
+
/**
|
|
168
|
+
* Restart `page.number` / `page.total` at every instance. Each instance also
|
|
169
|
+
* starts on a fresh page, the same rule `break` has.
|
|
170
|
+
*/
|
|
171
|
+
reset?: "page";
|
|
172
|
+
/**
|
|
173
|
+
* Flow each instance's content in this many page columns (integer >= 2).
|
|
174
|
+
* Columned regions cannot nest.
|
|
175
|
+
*/
|
|
176
|
+
columns?: number;
|
|
177
|
+
sort?: SortKey[];
|
|
178
|
+
/**
|
|
179
|
+
* Keep this many rows after this group's `sort`. Integer >= 1. Rows past
|
|
180
|
+
* the count are dropped from aggregates and runners, unlike `visible`.
|
|
181
|
+
*/
|
|
182
|
+
take?: number;
|
|
183
|
+
aggregates?: Record<string, ReducerSpec>;
|
|
184
|
+
/** Running accumulators, read as `run.<name>` on detail rows. */
|
|
185
|
+
run?: Record<string, ReducerSpec>;
|
|
186
|
+
header?: Item[];
|
|
187
|
+
footer?: Item[];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Page header/footer bands, rendered once per page by paginated targets
|
|
192
|
+
* (unpaginated targets ignore them). Cells read `$` and the `page` anchor
|
|
193
|
+
* (`page.number` / `page.total`, 1-based, the current sequence); `@` stays unbound.
|
|
194
|
+
*/
|
|
195
|
+
export interface PageBands {
|
|
196
|
+
header?: Item[];
|
|
197
|
+
footer?: Item[];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export interface ReportSchema {
|
|
201
|
+
params?: Record<string, JsonValue>;
|
|
202
|
+
data: string;
|
|
203
|
+
where?: `=${string}`;
|
|
204
|
+
sort?: SortKey[];
|
|
205
|
+
/**
|
|
206
|
+
* Keep this many rows after the report `sort`. Integer >= 1. Rows past the
|
|
207
|
+
* count are dropped from aggregates and runners, unlike `visible`.
|
|
208
|
+
*/
|
|
209
|
+
take?: number;
|
|
210
|
+
aggregates?: Record<string, ReducerSpec>;
|
|
211
|
+
/** Running accumulators, read as `run.<name>` on detail rows. */
|
|
212
|
+
run?: Record<string, ReducerSpec>;
|
|
213
|
+
/**
|
|
214
|
+
* The report default: the typeface this document is set in. It sits under
|
|
215
|
+
* the targets' band-role defaults and under every item's own `style`, so a
|
|
216
|
+
* declared `size` does not change a report header's headline size.
|
|
217
|
+
*/
|
|
218
|
+
style?: ReportStyleDeclarations;
|
|
219
|
+
header?: Item[];
|
|
220
|
+
empty?: Item[];
|
|
221
|
+
/**
|
|
222
|
+
* Flow the report body in this many page columns (integer >= 2). Columned
|
|
223
|
+
* regions cannot nest.
|
|
224
|
+
*/
|
|
225
|
+
columns?: number;
|
|
226
|
+
groups?: Group[];
|
|
227
|
+
detail?: Item[] | TableDetail;
|
|
228
|
+
footer?: Item[];
|
|
229
|
+
page?: PageBands;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* One render target — the rollup-plugin shape: self-naming, with `compile`
|
|
234
|
+
* called per `render(target, data)` call against the public event stream, so
|
|
235
|
+
* it must be cheap and stateless; per-render work belongs in the renderer it
|
|
236
|
+
* returns. Official factories (`html()`, `pdf()`, `xlsx()`, `csv()`) return these; a
|
|
237
|
+
* custom target is any object honoring the contract (SCHEMA.md, "Instances
|
|
238
|
+
* and targets"). A renderer may return its output synchronously; `render` is
|
|
239
|
+
* always a promise.
|
|
240
|
+
*/
|
|
241
|
+
export interface Target<Name extends string = string, Out = unknown> {
|
|
242
|
+
/** A diagnostic label — a plain identifier naming what the target is. */
|
|
243
|
+
name: Name;
|
|
244
|
+
/** Builds this target's renderer over one compiled event stream. */
|
|
245
|
+
compile: (stream: ReportEventStream) => (data?: unknown) => Out;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export interface QuarioOptions {
|
|
249
|
+
query?: QueryOptions;
|
|
250
|
+
/**
|
|
251
|
+
* License key (LICENSE section 6). Verified offline once, when the instance
|
|
252
|
+
* is created; `license` settles with the result. Without a key, or with one
|
|
253
|
+
* whose validity window does not cover this version's release date, every
|
|
254
|
+
* report this instance compiles marks its output as unlicensed.
|
|
255
|
+
*/
|
|
256
|
+
license?: string;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** The settled result of an instance's license key verification. */
|
|
260
|
+
export interface LicenseInfo {
|
|
261
|
+
licensed: boolean;
|
|
262
|
+
licensee?: string;
|
|
263
|
+
id?: string;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export type ItemRole =
|
|
267
|
+
| "report-header"
|
|
268
|
+
| "empty"
|
|
269
|
+
| "group-header"
|
|
270
|
+
| "detail"
|
|
271
|
+
| "group-footer"
|
|
272
|
+
| "report-footer"
|
|
273
|
+
| "page-header"
|
|
274
|
+
| "page-footer";
|
|
275
|
+
|
|
276
|
+
/** One static text run of a cell's template, verbatim (sjabloon's literal token). */
|
|
277
|
+
export type LiteralToken = SjabloonLiteralToken;
|
|
278
|
+
|
|
279
|
+
/** One interpolation's pre-stringify value (sjabloon's value token). */
|
|
280
|
+
export type ValueToken = SjabloonValueToken;
|
|
281
|
+
|
|
282
|
+
export type Token = LiteralToken | ValueToken;
|
|
283
|
+
|
|
284
|
+
export interface EventCell {
|
|
285
|
+
tokens: Token[];
|
|
286
|
+
style?: Record<string, unknown>;
|
|
287
|
+
/**
|
|
288
|
+
* The definition's schema path, on cells that belong to one: a `row` cell
|
|
289
|
+
* carries its column's (`detail.columns[i]`), a `total-row` cell its
|
|
290
|
+
* `detail.total[i]` entry. Absent on page-band cells reached by closure.
|
|
291
|
+
*/
|
|
292
|
+
path?: string;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** The page anchor a paginated target passes to page band closures. */
|
|
296
|
+
export interface PageInfo {
|
|
297
|
+
/** 1-based page number of the current sequence. */
|
|
298
|
+
number: number;
|
|
299
|
+
/** Page count of the current sequence. */
|
|
300
|
+
total: number;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Per-render page band closures on `report-start` (present only when the
|
|
305
|
+
* schema declares page bands). A paginated target calls them once per page;
|
|
306
|
+
* each call returns resolved `page-header`/`page-footer` item events.
|
|
307
|
+
*/
|
|
308
|
+
export interface PageBandRenderers {
|
|
309
|
+
header?: (page: PageInfo) => (ItemEvent | ImageEvent)[];
|
|
310
|
+
footer?: (page: PageInfo) => (ItemEvent | ImageEvent)[];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export interface ReportStartEvent {
|
|
314
|
+
type: "report-start";
|
|
315
|
+
params: Record<string, JsonValue>;
|
|
316
|
+
aggregates: Record<string, unknown>;
|
|
317
|
+
page?: PageBandRenderers;
|
|
318
|
+
/** The declared page column count, present when the root declares one. */
|
|
319
|
+
columns?: number;
|
|
320
|
+
/**
|
|
321
|
+
* The resolved report default, present when the report declares one. It is
|
|
322
|
+
* a report-level fact rather than something merged into each item's style,
|
|
323
|
+
* so a consumer composes it once — under its own band-role defaults, and
|
|
324
|
+
* under every event's own `style`. Ignoring it renders the report in the
|
|
325
|
+
* consumer's own baseline, which is what a consumer written before this
|
|
326
|
+
* field already does.
|
|
327
|
+
*/
|
|
328
|
+
style?: Record<string, unknown>;
|
|
329
|
+
/**
|
|
330
|
+
* The marking wording, present when this render is not covered by a valid
|
|
331
|
+
* license key — including while verification is still settling (await the
|
|
332
|
+
* stream's `license` promise first, as the shipped targets do). Absent
|
|
333
|
+
* otherwise. Each target renders this text in its own idiom; the engine
|
|
334
|
+
* states it so no target has to know it.
|
|
335
|
+
*/
|
|
336
|
+
marking?: string;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export interface ItemEvent {
|
|
340
|
+
type: "item";
|
|
341
|
+
role: ItemRole;
|
|
342
|
+
/** The item definition's schema path, e.g. `detail[0]`. */
|
|
343
|
+
path: string;
|
|
344
|
+
tokens: Token[];
|
|
345
|
+
style?: Record<string, unknown>;
|
|
346
|
+
run?: Record<string, unknown>;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** The format the engine sniffed from an image's bytes. */
|
|
350
|
+
export type ImageFormat = "png" | "jpeg";
|
|
351
|
+
|
|
352
|
+
export interface ImageEvent {
|
|
353
|
+
type: "image";
|
|
354
|
+
role: ItemRole;
|
|
355
|
+
/** The image definition's schema path. */
|
|
356
|
+
path: string;
|
|
357
|
+
/** The bytes exactly as the `source` expression yielded them. */
|
|
358
|
+
bytes: Uint8Array;
|
|
359
|
+
/** Sniffed from the bytes' magic numbers, so no consumer repeats it. */
|
|
360
|
+
format: ImageFormat;
|
|
361
|
+
fit: ImageFit;
|
|
362
|
+
/** The rendered `alt` template, present when the item declares one. */
|
|
363
|
+
alt?: Token[];
|
|
364
|
+
style?: Record<string, unknown>;
|
|
365
|
+
run?: Record<string, unknown>;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Opens a split: the slot geometry, then one ordinary `item` or `image` event
|
|
370
|
+
* per slot in order, then `split-end`. A consumer with no handler for the
|
|
371
|
+
* bracket still receives the slot items and renders them stacked.
|
|
372
|
+
*/
|
|
373
|
+
export interface SplitStartEvent {
|
|
374
|
+
type: "split-start";
|
|
375
|
+
role: ItemRole;
|
|
376
|
+
/** One entry per slot, in order; `width` is absent on a width-less slot. */
|
|
377
|
+
slots: { width?: number }[];
|
|
378
|
+
style?: Record<string, unknown>;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export interface SplitEndEvent {
|
|
382
|
+
type: "split-end";
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export interface GroupStartEvent {
|
|
386
|
+
type: "group-start";
|
|
387
|
+
name: string;
|
|
388
|
+
/** The group definition's schema path, e.g. `groups[0]`. */
|
|
389
|
+
path: string;
|
|
390
|
+
depth: number;
|
|
391
|
+
key: unknown;
|
|
392
|
+
aggregates: Record<string, unknown>;
|
|
393
|
+
break?: "page";
|
|
394
|
+
/** Restart `page.number` / `page.total` at every instance (paginated targets). */
|
|
395
|
+
reset?: "page";
|
|
396
|
+
/** The declared page column count, present when the group declares one. */
|
|
397
|
+
columns?: number;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export interface GroupEndEvent {
|
|
401
|
+
type: "group-end";
|
|
402
|
+
name: string;
|
|
403
|
+
depth: number;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export interface TableStartEvent {
|
|
407
|
+
type: "table-start";
|
|
408
|
+
/** Always `detail` — the table definition's schema path. */
|
|
409
|
+
path: string;
|
|
410
|
+
columns: { header: EventCell; path: string; width?: number }[];
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export interface RowEvent {
|
|
414
|
+
type: "row";
|
|
415
|
+
cells: EventCell[];
|
|
416
|
+
style?: Record<string, unknown>;
|
|
417
|
+
run?: Record<string, unknown>;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export interface TotalRowEvent {
|
|
421
|
+
type: "total-row";
|
|
422
|
+
cells: EventCell[];
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export interface TableEndEvent {
|
|
426
|
+
type: "table-end";
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export interface ReportEndEvent {
|
|
430
|
+
type: "report-end";
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export type ReportEvent =
|
|
434
|
+
| ReportStartEvent
|
|
435
|
+
| ItemEvent
|
|
436
|
+
| ImageEvent
|
|
437
|
+
| SplitStartEvent
|
|
438
|
+
| SplitEndEvent
|
|
439
|
+
| GroupStartEvent
|
|
440
|
+
| GroupEndEvent
|
|
441
|
+
| TableStartEvent
|
|
442
|
+
| RowEvent
|
|
443
|
+
| TotalRowEvent
|
|
444
|
+
| TableEndEvent
|
|
445
|
+
| ReportEndEvent;
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* One registry function a compiled report calls: its arity (the function's
|
|
449
|
+
* declared parameter count, or its own numeric `arity` where `length`
|
|
450
|
+
* misleads) and its own `doc` string when it carries one — xprsn's
|
|
451
|
+
* `signatures()` convention, in call-first-seen order. Aliased so hosts type
|
|
452
|
+
* the metadata from 'quario' alone, without their own xprsn dependency.
|
|
453
|
+
*/
|
|
454
|
+
export type FunctionSignature = XprsnSignature;
|
|
455
|
+
|
|
456
|
+
export interface ReportEventStream {
|
|
457
|
+
(data?: unknown): Generator<ReportEvent, void, undefined>;
|
|
458
|
+
readonly names: readonly string[];
|
|
459
|
+
readonly functions: readonly FunctionSignature[];
|
|
460
|
+
readonly paths: readonly QueryPath[];
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Per-event handlers for `walk`, keyed by event type; a missing handler
|
|
465
|
+
* ignores that event.
|
|
466
|
+
*/
|
|
467
|
+
export type WalkHandlers = {
|
|
468
|
+
[K in ReportEvent["type"]]?: (event: Extract<ReportEvent, { type: K }>) => void;
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* The walk driver: dispatch one render's event stream to per-event handlers,
|
|
473
|
+
* in stream order and exactly once each, pulling lazily and handing the loop
|
|
474
|
+
* back between batches. Handlers are synchronous — a promise one returns is
|
|
475
|
+
* not awaited. The stream's first event reaches its handler before a second one
|
|
476
|
+
* is pulled, so a target settles what it needs from `report-start` there rather
|
|
477
|
+
* than pulling the stream itself; no opening event is required, and a stream
|
|
478
|
+
* that starts part-way through walks like any other.
|
|
479
|
+
*/
|
|
480
|
+
export function walk(events: Iterable<ReportEvent>, handlers: WalkHandlers): Promise<void>;
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Hand the event loop back to the host, resolving once it has had its turn.
|
|
484
|
+
* The walk driver calls it between batches; a target running a loop of its own
|
|
485
|
+
* calls it the same way, so a long report never blocks the host.
|
|
486
|
+
*/
|
|
487
|
+
export function breathe(): Promise<void>;
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Every code a located diagnostic can carry, which is a code from whichever
|
|
491
|
+
* engine decided the fault: quario relocates xprsn's directly, sjabloon
|
|
492
|
+
* carries xprsn's on a fault inside an expression, and padvinder carries
|
|
493
|
+
* treffer's on a pattern literal rejected when the query compiles.
|
|
494
|
+
*
|
|
495
|
+
* `TrefferErrorCode` reaches this union through padvinder, which re-exports
|
|
496
|
+
* it, so quario needs no treffer dependency to name it here.
|
|
497
|
+
*/
|
|
498
|
+
export type QuarioErrorCode =
|
|
499
|
+
| SjabloonErrorCode
|
|
500
|
+
| XprsnErrorCode
|
|
501
|
+
| PadvinderErrorCode
|
|
502
|
+
| TrefferErrorCode;
|
|
503
|
+
|
|
504
|
+
export interface QuarioDiagnostic extends Error {
|
|
505
|
+
/** Absent on option and target-definition faults; present on every other diagnostic. */
|
|
506
|
+
readonly code?: QuarioErrorCode;
|
|
507
|
+
readonly start?: number;
|
|
508
|
+
readonly end?: number;
|
|
509
|
+
readonly limit?: number;
|
|
510
|
+
readonly actual?: number;
|
|
511
|
+
readonly blocks?: readonly SjabloonBlock[];
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/** The compiled report: `stream` plus its metadata, rendered per target. */
|
|
515
|
+
export interface CompiledReport {
|
|
516
|
+
/** The raw event seam: one generator of report events per call. */
|
|
517
|
+
stream(data?: unknown): Generator<ReportEvent, void, undefined>;
|
|
518
|
+
readonly names: readonly string[];
|
|
519
|
+
readonly functions: readonly FunctionSignature[];
|
|
520
|
+
readonly paths: readonly QueryPath[];
|
|
521
|
+
/**
|
|
522
|
+
* Render this compiled report through one target. Resolves the target's
|
|
523
|
+
* output, whether the target renders synchronously or not; target shape
|
|
524
|
+
* problems throw synchronously as definition errors.
|
|
525
|
+
*/
|
|
526
|
+
render<Out>(target: Target<string, Out>, data?: unknown): Promise<Awaited<Out>>;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* One definition problem, structurally: the schema path it sits at, the
|
|
531
|
+
* offending author source when the problem came from compiling one, the whole
|
|
532
|
+
* located message (`validate()`'s string is exactly this field), and the
|
|
533
|
+
* engine's located diagnostic when one authenticated the fault — every
|
|
534
|
+
* problem keeps its own, offsets included, not only the first.
|
|
535
|
+
*/
|
|
536
|
+
export interface Problem {
|
|
537
|
+
readonly path: string;
|
|
538
|
+
readonly source?: string;
|
|
539
|
+
readonly message: string;
|
|
540
|
+
readonly diagnostic?: QuarioDiagnostic;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* The plan: both readings of the one traversal, kept. `report` is the
|
|
545
|
+
* compiled report, or null while the document has problems; `problems` is the
|
|
546
|
+
* structured list `validate()` flattens to strings; `anchors` maps each
|
|
547
|
+
* compiled source's schema path to the anchors and group handles it reads —
|
|
548
|
+
* the unfiltered complement of `names`, which excludes them.
|
|
549
|
+
*/
|
|
550
|
+
export interface Plan {
|
|
551
|
+
readonly report: CompiledReport | null;
|
|
552
|
+
readonly problems: readonly Problem[];
|
|
553
|
+
readonly anchors: Readonly<Record<string, readonly string[]>>;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export interface Quario {
|
|
557
|
+
/**
|
|
558
|
+
* Settles when this instance's license key verification completes;
|
|
559
|
+
* `{ licensed: false }` without a key. Never rejects.
|
|
560
|
+
*/
|
|
561
|
+
readonly license: Promise<LicenseInfo>;
|
|
562
|
+
/** Compile a definition once; every target renders from it. */
|
|
563
|
+
report(schema: ReportSchema, functions?: FunctionRegistry): CompiledReport;
|
|
564
|
+
/**
|
|
565
|
+
* The one traversal, whole: compiled report (null on problems), structured
|
|
566
|
+
* problems, and per-node anchor sets — one descent per edit for a host that
|
|
567
|
+
* validates and renders in a loop.
|
|
568
|
+
*/
|
|
569
|
+
plan(schema: unknown, functions?: FunctionRegistry): Plan;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Create a configured instance: host-level options (license key, query
|
|
574
|
+
* budgets).
|
|
575
|
+
*/
|
|
576
|
+
export function quario(options?: QuarioOptions): Quario;
|
|
577
|
+
|
|
578
|
+
export function validate(schema: unknown, functions?: FunctionRegistry): string[];
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* True when a caught value is one of the stack's located diagnostics —
|
|
582
|
+
* re-thrown by quario with an engine original behind it, or thrown by
|
|
583
|
+
* xprsn/sjabloon/padvinder directly. Authenticated by identity: an error
|
|
584
|
+
* merely shaped like a diagnostic does not pass.
|
|
585
|
+
*/
|
|
586
|
+
export function isDiagnostic(e: unknown): e is QuarioDiagnostic;
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* Join a token stream to display text: literals verbatim, values through
|
|
590
|
+
* `display()`. Re-exported from sjabloon.
|
|
591
|
+
*/
|
|
592
|
+
export function text(tokens: readonly Token[]): string;
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Display text for one token value — the scalar rule `text()` joins with,
|
|
596
|
+
* re-exported from sjabloon so targets stringify exactly as the stream does.
|
|
597
|
+
* A valid `Date` renders as ISO 8601 UTC (`toISOString()`), deterministically
|
|
598
|
+
* across machines; an invalid `Date` stays `"Invalid Date"`; nullish displays
|
|
599
|
+
* empty; everything else is `String(value)`.
|
|
600
|
+
*/
|
|
601
|
+
export function display(value: unknown): string;
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* The typed-cell seam: exactly one value token holding a finite number, a
|
|
605
|
+
* boolean, or a valid Date keeps its pre-stringify value; anything else —
|
|
606
|
+
* including a lone null — reports `undefined` and joins to display text.
|
|
607
|
+
*/
|
|
608
|
+
export function typed(tokens: readonly Token[]): number | boolean | Date | undefined;
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Whether a band item's `role` names one of the report's own bands — its
|
|
612
|
+
* header, its footer, the `empty` band that replaces its body, or a page band —
|
|
613
|
+
* rather than a group instance's. Shipped so a consumer that needs the split
|
|
614
|
+
* does not restate the list. Page-band roles answer true although no walk emits
|
|
615
|
+
* one: the question is whose band a role names, not what a walk can hand over.
|
|
616
|
+
*/
|
|
617
|
+
export function isReportBand(role: string | undefined): boolean;
|