quario 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,140 @@
1
1
  # quario
2
2
 
3
+ ## 0.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - A band gains a `grid` item: splits that share one column geometry.
8
+
9
+ A statement is twenty lines of a label and an amount, on the same two widths. As splits, each line restated its widths:
10
+
11
+ ```jsonc
12
+ { "type": "split", "slots": [
13
+ { "type": "text", "value": "Opening", "width": 70 },
14
+ { "type": "text", "value": "{{ @.opening }}", "width": 30, "style": { "align": "right" } }
15
+ ] }
16
+ ```
17
+
18
+ A grid states the widths, and each column's style, once:
19
+
20
+ ```jsonc
21
+ {
22
+ "type": "grid",
23
+ "columns": [{ "width": 70 }, { "width": 30, "style": { "align": "right" } }],
24
+ "rows": [
25
+ { "slots": [{ "type": "text", "value": "Opening" }, { "type": "text", "value": "{{ @.opening }}" }] },
26
+ {},
27
+ { "slots": [{ "type": "text", "value": "Total" }, { "type": "text", "value": "{{ @.total }}" }], "style": { "bold": true } }
28
+ ]
29
+ }
30
+ ```
31
+
32
+ A row is a split without `type`, and it keeps every rule a split has. A column's `style` is the layer under each of its slots, and a slot's own declarations win. A row that names fewer slots than there are columns leaves the rest empty, so `{}` is a spacer line and a one-slot row is a label-only line.
33
+
34
+ Each row reaches a target as the split it is, so the event stream does not change and no target needed an update. No existing report changes.
35
+
36
+ - The package now ships a JSON Schema of the report document.
37
+
38
+ The file is `lib/schema.json`, and the package exports it as `quario/schema.json`. Point `$schema` at the installed copy, and an editor checks the document and shows the documentation for each key:
39
+
40
+ ```jsonc
41
+ { "$schema": "./node_modules/quario/lib/schema.json", "data": "$.orders[*]" }
42
+ ```
43
+
44
+ A report document accepts one new top-level key, `$schema`. Its value must be a string. The engine checks the type and reads nothing else, so a document keeps its `$schema` through an upgrade. Anywhere below the top level, `$schema` stays an unknown key.
45
+
46
+ The JSON Schema proves the shape of each value, and `validate()` still proves the document. A document can pass the JSON Schema and fail `validate()`: a rule across two values, a reserved name, or an expression that does not compile. The strict structured-output modes of OpenAI and Anthropic do not accept the file, because a report document leaves most of its keys out.
47
+
48
+ The TypeScript declarations are stricter in one place. A parameter's value under `params` is now typed as any JSON value except a plain object. The engine always read a plain object there as a declaration, so a document that the new type refuses was never the document it looked like.
49
+
50
+ - **A license key has an end date and no start date.** A key covers every version released on or before its `to` date. Before, a key also named a `from` date, and a version released before that date stayed marked. The engine now ignores a `from` in a key. When a key ends before the release date of the installed version, the warning names both dates.
51
+ - A value the runtime has no text form for is now a located render error rather than `[object Object]` in the document.
52
+
53
+ A cell reaches its reader through `String(value)`. A plain object, a `Map` and a `Set` have no text form of their own, so that falls back to a tag: `[object Object]`, `[object Map]`, `[object Set]`. A tag lays out, paginates and lands in a worksheet cell, and the document is wrong. A few values have no text form at all, and `String()` throws on them — an object with no prototype, a boxed symbol. The engine now refuses both kinds and names the cell:
54
+
55
+ ```
56
+ detail[0].value [{{ @.address }}]: a value with no text form, which would print as [object Object]
57
+ ```
58
+
59
+ The rule reads the value, not its source, so a registered function's result and a data field answer to it alike. A value that says what it is still prints it: a class with its own `toString`, an array (`[1, 2]` prints `1,2`), a `Date`. An absent read still prints nothing. A computed property is outside the rule, because a group's `by` is an identity rather than text — `by: "=@"` makes each row its own instance — and a `where` and a `visible` are read for truth.
60
+
61
+ Every entry in the function registry must be a function. `plan` reports one that is not at `functions.<name>`, where before it raised an unhandled `TypeError` out of `plan` itself at a caller who had only asked a question.
62
+
63
+ A report that printed `[object Object]` stops rendering. It was printing a value no reader could use.
64
+
65
+ - A document may now name its paper and turn it, and its margin may name each side.
66
+
67
+ ```jsonc
68
+ {
69
+ "page": {
70
+ "size": "letter",
71
+ "orientation": "landscape",
72
+ "margin": { "top": 36, "right": 29, "bottom": 36, "left": 29 }
73
+ }
74
+ }
75
+ ```
76
+
77
+ `page.size` takes `"A4"` or `"letter"`. A `[width, height]` pair stays a target option. `page.orientation` takes `"portrait"` or `"landscape"`, and it turns whichever paper is in force. `page.margin` still takes one number for all four sides.
78
+
79
+ The rule `page.margin` already followed now covers all three keys. The document's key wins where it declares one, a target option applies where it does not, and both declaring the same key is a render error. `orientation` in a document beside a target's `size` is not both.
80
+
81
+ Each target writes the paper: the PDF and the layout draw on it, HTML writes an `@page` size and per-side margin, and DOCX writes `pgSz` with `w:orient` and `pgMar` per side. XLSX writes the paper code, the orientation and each print margin. CSV withdraws all three.
82
+
83
+ The capability descriptors gain `page.size` and `page.orientation`, and both are names a document may mark `required`.
84
+
85
+ A target's margin error now reads `expected a non-negative number, or { top, right, bottom, left }, that leaves the page room`.
86
+
87
+ - `params` is now what the report declares it needs, and a render may supply one.
88
+
89
+ A bare value under `params` still **is** the parameter's value, so a document of constants reads the way it always did:
90
+
91
+ ```jsonc
92
+ { "params": { "year": 2025, "branded": true } }
93
+ ```
94
+
95
+ A plain object is a **declaration** instead, closed at `default` and `type`:
96
+
97
+ ```jsonc
98
+ {
99
+ "params": {
100
+ "year": { "type": "number", "default": 2025 },
101
+ "region": { "type": "string" }
102
+ }
103
+ }
104
+ ```
105
+
106
+ `type` names a JSON kind — `string`, `number`, `boolean`, `array`, `object` — because a parameter is a JSON value. There is no `date` and no `enum`.
107
+
108
+ **`default` absent makes the parameter required.** The engine rejects a render that supplies no value for it, before any expression runs. That is the main thing declaring buys: a report that states what it needs hears about it when a render does not bring it.
109
+
110
+ A host supplies values as the last argument to `render` and to `stream`:
111
+
112
+ ```js
113
+ await report.render(html(), data, { region: "EU" });
114
+ ```
115
+
116
+ Only a declared key may be supplied, a supplied value answers to the declared `type`, and values stay JSON and deep-frozen — now per render rather than once at compile.
117
+
118
+ **One kind of document changes meaning.** The engine reads an object-valued parameter as a declaration, so a document that wrote one for its value wraps it:
119
+
120
+ ```jsonc
121
+ { "params": { "config": { "default": { "retries": 3 } } } }
122
+ ```
123
+
124
+ An empty object is the sharpest case. `{ "config": {} }` now declares a parameter with no default, so every render of that document is refused until one supplies a value, or until the document wraps it.
125
+
126
+ Nothing else moves. A bare string, number, boolean or array is untouched.
127
+
128
+ A declaration may also carry a `label`, the text a person reads for the parameter. A labelled parameter is one a person supplies, so a host panel shows only those. The engine never renders a label.
129
+
130
+ A `null` default beside a `type` makes a typed parameter optional, and a render may then supply `null`:
131
+
132
+ ```jsonc
133
+ { "params": { "branch": { "type": "string", "default": null, "label": "Branch" } } }
134
+ ```
135
+
136
+ A host reads what a document declares from `report.params` and from `plan(...).params`: one frozen `{ name, required, type?, default?, label? }` per parameter, in declaration order. A plan carries them whether or not the document compiled, so an editor can render a panel beside the problems.
137
+
3
138
  ## 0.12.0
4
139
 
5
140
  ### Minor Changes
package/README.md CHANGED
@@ -70,8 +70,8 @@ key verification as `{ licensed, licensee?, id? }`.
70
70
 
71
71
  ### `report(schema, functions?)`
72
72
 
73
- Compiles a report and returns the compiled report. `stream(data)` is the raw event generator.
74
- `render(target, data)` takes a self-naming `{ name, compile }` object from a target factory
73
+ Compiles a report and returns the compiled report. `stream(data, params)` is the raw event generator, and `params` are the values this render supplies for what the document declares.
74
+ `render(target, data, params)` takes a self-naming `{ name, compile }` object from a target factory
75
75
  (e.g. `html()` from `@quario/html`) or your own.
76
76
 
77
77
  A render is async: quario awaits key verification before the target sees its first event. A
@@ -209,6 +209,33 @@ validate({ data: "$.o[*]", sort: [{ by: "=@.a", dir: "up" }] });
209
209
  `report()` throws on the first problem instead. Validation and compilation share one traversal,
210
210
  so `validate()` can never disagree with what `report()` accepts.
211
211
 
212
+ ### JSON Schema
213
+
214
+ The package ships a JSON Schema of the report document. Point `$schema` at the installed copy,
215
+ and your editor checks the document and shows the documentation for each key:
216
+
217
+ ```json
218
+ {
219
+ "$schema": "./node_modules/quario/lib/schema.json",
220
+ "data": "$.orders[*]",
221
+ "detail": [{ "type": "text", "value": "{{ @.product }}" }]
222
+ }
223
+ ```
224
+
225
+ The path is relative to the report file. The engine accepts the `$schema` key and does not read
226
+ it.
227
+
228
+ Code reads the same file through the package export:
229
+
230
+ ```js
231
+ import schema from "quario/schema.json" with { type: "json" };
232
+ ```
233
+
234
+ The JSON Schema proves the shape of each value. It does not replace `validate()`. Rules that
235
+ join two or more values, and every expression and template, stay with `validate()`. Use the
236
+ JSON Schema to constrain what an editor or a model writes. Use `validate()` to accept a
237
+ document.
238
+
212
239
  ### `quario().plan(schema, functions?, { targets }?)`
213
240
 
214
241
  The one traversal, whole — for hosts that validate and render in a loop, like an editor. Returns
package/lib/index.d.ts CHANGED
@@ -12,7 +12,46 @@ import type {
12
12
  export type { QueryPath } from "padvinder";
13
13
 
14
14
  export type FunctionRegistry = Record<string, (...args: any[]) => any>;
15
- export type ExpressionValue<T = unknown> = T | `=${string}`;
15
+ // Named so its pattern reaches every field that takes an expression, which is
16
+ // how the generated JSON Schema tells an expression from a literal.
17
+ /**
18
+ * An `=` expression: xprsn source after the leading `=`.
19
+ *
20
+ * @pattern ^=
21
+ */
22
+ export type Expression = `=${string}`;
23
+ export type ExpressionValue<T = unknown> = T | Expression;
24
+
25
+ // The literal shapes the traversal checks one value at a time, named so each
26
+ // carries its rule as a tag. TypeScript reads each as the plain type. The tags
27
+ // are for the JSON Schema generated from this file (`lib/schema.json`), which
28
+ // holds each one to the check it mirrors in `style.js` or `plan.js`.
29
+
30
+ /** `#rgb` or `#rrggbb`. @pattern ^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$ */
31
+ type Color = string;
32
+ /** A three-letter ISO 4217 code, by shape. @pattern ^[A-Z]{3}$ */
33
+ type CurrencyCode = string;
34
+ /** @minLength 1 */
35
+ type NonEmpty = string;
36
+ /** Points, zero or more. @minimum 0 */
37
+ type Points = number;
38
+ /** Points, more than zero. @exclusiveMinimum 0 */
39
+ type PositivePoints = number;
40
+ /** A share of the width, in percent. @exclusiveMinimum 0 @maximum 100 */
41
+ type WidthShare = number;
42
+ /** @asType integer @minimum 1 */
43
+ type Count = number;
44
+ /** @asType integer @minimum 2 */
45
+ type ColumnCount = number;
46
+ /** @asType integer @minimum 0 @maximum 20 */
47
+ type Digits = number;
48
+ /** @minItems 1 */
49
+ type StyledRuns = StyledRun[];
50
+ /**
51
+ * A parameter's value when it is not a declaration: any JSON value but a plain
52
+ * object, which `params` reads as a declaration.
53
+ */
54
+ type ParamValue = null | boolean | number | string | JsonValue[];
16
55
  export type ReducerSpec = string;
17
56
 
18
57
  /**
@@ -50,16 +89,16 @@ export type LineStyle = "solid" | "dashed" | "dotted";
50
89
  */
51
90
  export type BoxDeclarations = {
52
91
  /** Inset on that side, in points (>= 0). */
53
- [S in Side as `padding${S}`]?: ExpressionValue<number>;
92
+ [S in Side as `padding${S}`]?: ExpressionValue<Points>;
54
93
  } & {
55
94
  /** Stroke width on that side, in points (>= 0). `0` is a complete side that draws nothing. */
56
- [S in Side as `border${S}Width`]?: ExpressionValue<number>;
95
+ [S in Side as `border${S}Width`]?: ExpressionValue<Points>;
57
96
  } & {
58
97
  /** Line style of that side. */
59
98
  [S in Side as `border${S}Style`]?: ExpressionValue<LineStyle>;
60
99
  } & {
61
100
  /** Stroke color of that side, `#rgb`/`#rrggbb`. */
62
- [S in Side as `border${S}Color`]?: ExpressionValue<string>;
101
+ [S in Side as `border${S}Color`]?: ExpressionValue<Color>;
63
102
  };
64
103
 
65
104
  /**
@@ -72,9 +111,9 @@ export type BoxDeclarations = {
72
111
  */
73
112
  export interface StyleDeclarations extends BoxDeclarations {
74
113
  /** `'sans'` | `'serif'` | `'mono'`, or an embedded font family name. */
75
- family?: ExpressionValue<string>;
114
+ family?: ExpressionValue<NonEmpty>;
76
115
  /** Font size in points. */
77
- size?: ExpressionValue<number>;
116
+ size?: ExpressionValue<PositivePoints>;
78
117
  bold?: ExpressionValue<boolean>;
79
118
  italic?: ExpressionValue<boolean>;
80
119
  underline?: ExpressionValue<boolean>;
@@ -82,9 +121,9 @@ export interface StyleDeclarations extends BoxDeclarations {
82
121
  /** Render the text in capitals. Capitals, not small caps. */
83
122
  uppercase?: ExpressionValue<boolean>;
84
123
  /** Text color, `#rgb`/`#rrggbb`. */
85
- color?: ExpressionValue<string>;
124
+ color?: ExpressionValue<Color>;
86
125
  /** Background color, `#rgb`/`#rrggbb`. */
87
- background?: ExpressionValue<string>;
126
+ background?: ExpressionValue<Color>;
88
127
  /** Horizontal alignment within the cell. */
89
128
  align?: ExpressionValue<Align>;
90
129
  /**
@@ -107,7 +146,7 @@ export interface StyleDeclarations extends BoxDeclarations {
107
146
  * the cell's own answer still, so the cell presents as display text rather
108
147
  * than falling back to the instance's currency. Unread without the kind.
109
148
  */
110
- currency?: ExpressionValue<string>;
149
+ currency?: ExpressionValue<CurrencyCode>;
111
150
  /**
112
151
  * Where this cell's text points: a URL, or `#` and a group's `label` for a
113
152
  * destination inside the document. The one declaration the engine judges
@@ -115,15 +154,15 @@ export interface StyleDeclarations extends BoxDeclarations {
115
154
  * allowlist before it crosses, and a refused value is omitted, so the text
116
155
  * renders and the link does not. A table row refuses it.
117
156
  */
118
- href?: ExpressionValue<string>;
157
+ href?: ExpressionValue<NonEmpty>;
119
158
  /** Blank space before this item, in points. */
120
- spaceBefore?: ExpressionValue<number>;
159
+ spaceBefore?: ExpressionValue<Points>;
121
160
  /** Blank space after this item, in points. */
122
- spaceAfter?: ExpressionValue<number>;
161
+ spaceAfter?: ExpressionValue<Points>;
123
162
  }
124
163
 
125
164
  export interface SortKey {
126
- by: `=${string}`;
165
+ by: Expression;
127
166
  dir?: "asc" | "desc";
128
167
  }
129
168
 
@@ -135,7 +174,7 @@ export interface SortKey {
135
174
  export const RUN_STYLE_NAMES: readonly string[];
136
175
 
137
176
  /**
138
- * The names a [report default](../../../SCHEMA.md#style-declarations) may
177
+ * The names a [report default](https://getquario.com/docs/reference/style-declarations) may
139
178
  * declare, in the vocabulary's own order. A tool that offers them — the
140
179
  * editor's Document panel — reads this rather than keeping a copy.
141
180
  */
@@ -149,7 +188,7 @@ export const REPORT_STYLE_NAMES: readonly string[];
149
188
  export const ZERO_DASH: string;
150
189
 
151
190
  /**
152
- * The declarations a document may mark [`required`](../../../SCHEMA.md#validation),
191
+ * The declarations a document may mark [`required`](https://getquario.com/docs/diving-deeper/validating),
153
192
  * in the order the support matrix states them. Every published target's
154
193
  * `capabilities` descriptor answers for exactly these, which is what makes a
155
194
  * marking checkable.
@@ -159,7 +198,7 @@ export const REQUIRABLE: readonly string[];
159
198
  /**
160
199
  * The same names as a type, so a marking no target could answer for is an
161
200
  * error where an author writes it rather than a
162
- * [`plan`](../../../SCHEMA.md#validation) problem after the fact. This
201
+ * [`plan`](https://getquario.com/docs/diving-deeper/validating) problem after the fact. This
163
202
  * package's suite holds the two to each other in both directions, so neither
164
203
  * can gain a name the other lacks.
165
204
  */
@@ -169,6 +208,8 @@ export type RequirableName =
169
208
  | "break"
170
209
  | "reset"
171
210
  | "page.margin"
211
+ | "page.size"
212
+ | "page.orientation"
172
213
  | "header.height"
173
214
  | "groups"
174
215
  | "label"
@@ -225,7 +266,7 @@ export interface StyledRun {
225
266
  * cell written as one template string is one run, so a one-run array says
226
267
  * exactly what that string says.
227
268
  */
228
- export type CellValue = string | StyledRun[];
269
+ export type CellValue = string | StyledRuns;
229
270
 
230
271
  export type Align = "left" | "center" | "right";
231
272
  export type VAlign = "top" | "middle" | "bottom";
@@ -252,7 +293,7 @@ export type FormatDeclaration =
252
293
  | FormatKind
253
294
  | {
254
295
  kind: "number" | "currency" | "percent";
255
- digits?: number;
296
+ digits?: Digits;
256
297
  negative?: NegativeReading;
257
298
  zero?: ZeroReading;
258
299
  }
@@ -315,7 +356,7 @@ export type ReportStyleDeclarations = Pick<StyleDeclarations, "family" | "size">
315
356
  */
316
357
  export interface ImageItem {
317
358
  type: "image";
318
- source: `=${string}`;
359
+ source: Expression;
319
360
  /** Defaults to `"natural"`. */
320
361
  fit?: ImageFit;
321
362
  /**
@@ -381,7 +422,7 @@ export type SplitSlot = (
381
422
  | (Omit<ImageItem, "style"> & { style?: SlotImageStyleDeclarations })
382
423
  ) & {
383
424
  /** Slot width as a percentage of the content width (0 < width <= 100). */
384
- width?: number;
425
+ width?: WidthShare;
385
426
  };
386
427
 
387
428
  /**
@@ -397,8 +438,50 @@ export interface SplitItem {
397
438
  style?: StyleDeclarations;
398
439
  }
399
440
 
400
- /** One item in a band: text, an image, or a split. Future types may be additive. */
401
- export type Item = TextItem | ImageItem | SplitItem;
441
+ /**
442
+ * One slot of a grid row: a split slot less `width`, which the slot takes
443
+ * from its column.
444
+ */
445
+ export type GridSlot =
446
+ | (Omit<TextItem, "style"> & { style?: SlotStyleDeclarations })
447
+ | (Omit<ImageItem, "style"> & { style?: SlotImageStyleDeclarations });
448
+
449
+ /**
450
+ * One column of a grid: the width share every row's slot in this position
451
+ * takes, and the declarations each of those slots layers its own over.
452
+ */
453
+ export interface GridColumn {
454
+ /** Column width as a percentage of the content width (0 < width <= 100). */
455
+ width?: WidthShare;
456
+ style?: SlotStyleDeclarations;
457
+ }
458
+
459
+ /**
460
+ * One line on a grid's geometry: a split without `type`. A row naming fewer
461
+ * slots than the grid has columns leaves the rest empty, so `{}` is a
462
+ * spacer line of the row's size.
463
+ */
464
+ export interface GridRow {
465
+ slots?: GridSlot[];
466
+ visible?: ExpressionValue<boolean>;
467
+ style?: StyleDeclarations;
468
+ }
469
+
470
+ /**
471
+ * Splits that share one column geometry: the widths, and each column's
472
+ * style, are stated once and every row is laid on them. Every rule a split
473
+ * has, a row has — full content width, no nesting, never broken across a
474
+ * page — and each row crosses the event stream as the split bracket it is.
475
+ */
476
+ export interface GridItem {
477
+ type: "grid";
478
+ columns: [GridColumn, GridColumn, ...GridColumn[]];
479
+ rows: [GridRow, ...GridRow[]];
480
+ visible?: ExpressionValue<boolean>;
481
+ }
482
+
483
+ /** One item in a band: text, an image, a split, or a grid. Future types may be additive. */
484
+ export type Item = TextItem | ImageItem | SplitItem | GridItem;
402
485
 
403
486
  export interface TableHeader {
404
487
  value: CellValue;
@@ -408,7 +491,7 @@ export interface TableHeader {
408
491
  * How many columns this header covers — a literal integer >= 1, never an
409
492
  * expression; absent is 1. The columns it covers omit their own `header`.
410
493
  */
411
- span?: number;
494
+ span?: Count;
412
495
  }
413
496
 
414
497
  export interface TableColumn extends Omit<Cell, "style"> {
@@ -420,7 +503,7 @@ export interface TableColumn extends Omit<Cell, "style"> {
420
503
  */
421
504
  header?: string | TableHeader;
422
505
  /** Column width as a percentage of the table width (0 < width <= 100). */
423
- width?: number;
506
+ width?: WidthShare;
424
507
  }
425
508
 
426
509
  export interface TableRow {
@@ -439,7 +522,7 @@ export type TotalCell = Omit<Cell, "style"> & {
439
522
  * How many columns this cell covers — a literal integer >= 1, never an
440
523
  * expression; absent is 1.
441
524
  */
442
- span?: number;
525
+ span?: Count;
443
526
  };
444
527
 
445
528
  export interface TotalRow {
@@ -476,7 +559,7 @@ export interface TableDetail {
476
559
 
477
560
  export interface Group {
478
561
  name: string;
479
- by: `=${string}`;
562
+ by: Expression;
480
563
  /**
481
564
  * This instance's name for **navigation** rather than for the page: one
482
565
  * template, resolved once per instance in group scope, where the handle and
@@ -490,7 +573,7 @@ export interface Group {
490
573
  * and the content between them does not. A target with a way to hide a row
491
574
  * and keep it -- the worksheet -- hides those rows, where a reader opens the
492
575
  * group again. The rest drop them, and the
493
- * [matrix](../../../SCHEMA.md#what-each-target-makes-of-a-declaration) says
576
+ * [matrix](https://getquario.com/docs/reference/support-matrix) says
494
577
  * which does which.
495
578
  */
496
579
  collapsed?: boolean;
@@ -509,13 +592,13 @@ export interface Group {
509
592
  * Flow each instance's content in this many page columns (integer >= 2).
510
593
  * Columned regions cannot nest.
511
594
  */
512
- columns?: number;
595
+ columns?: ColumnCount;
513
596
  sort?: SortKey[];
514
597
  /**
515
598
  * Keep this many rows after this group's `sort`. Integer >= 1. Rows past
516
599
  * the count are dropped from aggregates and runners, unlike `visible`.
517
600
  */
518
- take?: number;
601
+ take?: Count;
519
602
  aggregates?: Record<string, ReducerSpec>;
520
603
  /** Running accumulators, read as `run.<name>` on detail rows. */
521
604
  run?: Record<string, ReducerSpec>;
@@ -531,15 +614,81 @@ export interface Group {
531
614
  export interface PageBands {
532
615
  header?: Item[];
533
616
  footer?: Item[];
534
- /** Inset on all four sides, in points. Required when the report header declares `height`. */
535
- margin?: number;
617
+ /**
618
+ * The inset from the paper's edge, in points: one number for all four
619
+ * sides, or each side named. Required when the report header declares
620
+ * `height`. A target's own `margin` option applies where this is absent,
621
+ * and declaring both is a render error.
622
+ */
623
+ margin?: Points | PageMargin;
624
+ /**
625
+ * The report's paper, by name. A `[width, height]` pair is a target option
626
+ * only. A target's own `size` option applies where this is absent, and
627
+ * declaring both is a render error.
628
+ */
629
+ size?: PaperName;
630
+ /** Which way the paper is turned. */
631
+ orientation?: Orientation;
632
+ }
633
+
634
+ /** A margin that names each side, in points. All four are required. */
635
+ export interface PageMargin {
636
+ top: Points;
637
+ right: Points;
638
+ bottom: Points;
639
+ left: Points;
640
+ }
641
+
642
+ /** The named paper sizes a document may declare. */
643
+ export type PaperName = "A4" | "letter";
644
+
645
+ /** Which way the paper is turned. */
646
+ export type Orientation = "portrait" | "landscape";
647
+
648
+ /**
649
+ * What a report declares it needs. A bare value under `params` *is* the
650
+ * parameter's value; a plain object is a declaration. `default` absent means
651
+ * the parameter is required, and a render that supplies none is rejected
652
+ * before any expression runs. `type` names a JSON kind, because a parameter
653
+ * is a JSON value. A `null` default beside a `type` makes the parameter
654
+ * optional and lets a render supply `null`.
655
+ */
656
+ export interface ParamDeclaration {
657
+ default?: JsonValue;
658
+ type?: ParamType;
659
+ /**
660
+ * The text a person reads for this parameter. A parameter with a label is
661
+ * one a person supplies; the engine never renders it.
662
+ */
663
+ label?: string;
664
+ }
665
+
666
+ export type ParamType = "string" | "number" | "boolean" | "array" | "object";
667
+
668
+ /**
669
+ * One declared parameter, as a host reads it: the surface a parameter panel
670
+ * asks what to render. `type`, `default` and `label` are present only where
671
+ * the document wrote one, and `required` is the absence of a default.
672
+ */
673
+ export interface DeclaredParam {
674
+ readonly name: string;
675
+ readonly required: boolean;
676
+ readonly type?: ParamType;
677
+ readonly default?: JsonValue;
678
+ /** Present where the document wrote one: a person supplies this parameter. */
679
+ readonly label?: string;
536
680
  }
537
681
 
538
682
  export interface ReportSchema {
539
- params?: Record<string, JsonValue>;
683
+ /**
684
+ * Where an editor finds this document's JSON Schema. The engine checks that
685
+ * it is a string and reads nothing else.
686
+ */
687
+ $schema?: string;
688
+ params?: Record<string, ParamValue | ParamDeclaration>;
540
689
  /**
541
690
  * The declarations this document cannot do without, each marked `true`.
542
- * Only [`plan`](../../../SCHEMA.md#validation) reads it, against the target
691
+ * Only [`plan`](https://getquario.com/docs/diving-deeper/validating) reads it, against the target
543
692
  * descriptors its caller names: every required declaration one of them
544
693
  * withdraws or leaves unread becomes a problem of its own at
545
694
  * `required.<name>`, which nulls the report as any other problem does. No
@@ -547,13 +696,13 @@ export interface ReportSchema {
547
696
  */
548
697
  required?: Partial<Record<RequirableName, true>>;
549
698
  data: string;
550
- where?: `=${string}`;
699
+ where?: Expression;
551
700
  sort?: SortKey[];
552
701
  /**
553
702
  * Keep this many rows after the report `sort`. Integer >= 1. Rows past the
554
703
  * count are dropped from aggregates and runners, unlike `visible`.
555
704
  */
556
- take?: number;
705
+ take?: Count;
557
706
  aggregates?: Record<string, ReducerSpec>;
558
707
  /** Running accumulators, read as `run.<name>` on detail rows. */
559
708
  run?: Record<string, ReducerSpec>;
@@ -567,13 +716,13 @@ export interface ReportSchema {
567
716
  * Dual-shaped like `detail`: an item array, or `{ height, items }` when the
568
717
  * header pins a flow box from the page top.
569
718
  */
570
- header?: Item[] | { height: number; items: Item[] };
719
+ header?: Item[] | { height: PositivePoints; items: Item[] };
571
720
  empty?: Item[];
572
721
  /**
573
722
  * Flow the report body in this many page columns (integer >= 2). Columned
574
723
  * regions cannot nest.
575
724
  */
576
- columns?: number;
725
+ columns?: ColumnCount;
577
726
  groups?: Group[];
578
727
  detail?: Item[] | TableDetail;
579
728
  footer?: Item[];
@@ -601,8 +750,8 @@ export interface QuarioOptions {
601
750
  /**
602
751
  * License key (LICENSE section 6). Verified offline once, when the instance
603
752
  * is created; `license` settles with the result. Without a key, or with one
604
- * whose validity window does not cover this version's release date, every
605
- * report this instance compiles marks its output as unlicensed.
753
+ * that ends before this version's release date, every report this instance
754
+ * compiles marks its output as unlicensed.
606
755
  */
607
756
  license?: string;
608
757
  /** Locale for `format`. Defaults to `"en-US"` when a kind is presented. */
@@ -755,8 +904,12 @@ export interface ReportStartEvent {
755
904
  * states it so no target has to know it.
756
905
  */
757
906
  marking?: string;
758
- /** The document's `page.margin`, when declared. */
759
- margin?: number;
907
+ /** The document's `page.margin`, when declared, in the shape the author wrote it. */
908
+ margin?: number | PageMargin;
909
+ /** The document's `page.size`, when declared. */
910
+ size?: PaperName;
911
+ /** The document's `page.orientation`, when declared. */
912
+ orientation?: Orientation;
760
913
  /** The report header's authored `height`, when the object form is used. */
761
914
  headerHeight?: number;
762
915
  /** Present when the instance was constructed with `locale`. */
@@ -953,7 +1106,7 @@ export type WalkEvent = ReportEvent | SplitEvent;
953
1106
  export function splits(events: Iterable<ReportEvent>): Generator<WalkEvent, void>;
954
1107
 
955
1108
  /**
956
- * Each [collapsed](../../../SCHEMA.md#group-definition) instance shut: its
1109
+ * Each [collapsed](https://getquario.com/docs/reference/report-schema#group) instance shut: its
957
1110
  * brackets and its own header and footer items survive, and everything
958
1111
  * between them is dropped, nested instances whole.
959
1112
  *
@@ -1010,7 +1163,11 @@ export interface QuarioDiagnostic extends Error {
1010
1163
  /** The compiled report: `stream` plus its metadata, rendered per target. */
1011
1164
  export interface CompiledReport {
1012
1165
  /** The raw event seam: one generator of report events per call. */
1013
- stream(data?: unknown): Generator<ReportEvent, void, undefined>;
1166
+ stream(
1167
+ data?: unknown,
1168
+ params?: Readonly<Record<string, JsonValue>>,
1169
+ ): Generator<ReportEvent, void, undefined>;
1170
+ readonly params: readonly DeclaredParam[];
1014
1171
  readonly names: readonly string[];
1015
1172
  readonly functions: readonly FunctionSignature[];
1016
1173
  readonly paths: readonly QueryPath[];
@@ -1019,7 +1176,11 @@ export interface CompiledReport {
1019
1176
  * output, whether the target renders synchronously or not; target shape
1020
1177
  * problems throw synchronously as definition errors.
1021
1178
  */
1022
- render<Out>(target: Target<string, Out>, data?: unknown): Promise<Awaited<Out>>;
1179
+ render<Out>(
1180
+ target: Target<string, Out>,
1181
+ data?: unknown,
1182
+ params?: Readonly<Record<string, JsonValue>>,
1183
+ ): Promise<Awaited<Out>>;
1023
1184
  }
1024
1185
 
1025
1186
  /**
@@ -1083,6 +1244,7 @@ export interface PlanOptions {
1083
1244
 
1084
1245
  export interface Plan {
1085
1246
  readonly report: CompiledReport | null;
1247
+ readonly params: readonly DeclaredParam[];
1086
1248
  readonly problems: readonly Problem[];
1087
1249
  readonly anchors: Readonly<Record<string, readonly string[]>>;
1088
1250
  readonly warnings: readonly Warning[];