quario 0.11.1 → 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 +165 -0
- package/README.md +29 -2
- package/lib/index.d.ts +297 -47
- package/lib/index.js +168 -15
- package/lib/license.js +12 -10
- package/lib/names.js +2 -0
- package/lib/plan.js +537 -105
- package/lib/schema.json +1279 -0
- package/lib/scope.js +7 -0
- package/package.json +10 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,170 @@
|
|
|
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
|
+
|
|
138
|
+
## 0.12.0
|
|
139
|
+
|
|
140
|
+
### Minor Changes
|
|
141
|
+
|
|
142
|
+
- A registered function may be asynchronous. The engine resolves every such call before the banded walk, in one wave, and the walk itself stays synchronous.
|
|
143
|
+
|
|
144
|
+
Write the call as the whole value of a cell in a detail row, and take its arguments from the row:
|
|
145
|
+
|
|
146
|
+
```jsonc
|
|
147
|
+
{ "data": "$.orders[*]", "detail": [{ "type": "text", "value": "{{ customerName(@.customerId) }}" }] }
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
The engine calls the function once for every row it renders, starts every call together, and waits for all of them before the first event reaches a target. A row that `where` or `take` removed is never fetched. Deduplication and any limit on how many calls run at once belong to the function itself: a report over ten thousand rows starts ten thousand calls.
|
|
151
|
+
|
|
152
|
+
Three rules hold. The call is the whole value of a cell, so `{{ lookup(@.id).name }}` and `{{ "#" + lookup(@.id) }}` are errors that name the function and the cell. The arguments come from the row, so a cell that reads no row cannot hold one. And `render()` resolves, while `stream()` reports the call it cannot wait for.
|
|
153
|
+
|
|
154
|
+
A function that rejects fails the render with an error that names the function and the cell, and keeps the class the function threw.
|
|
155
|
+
|
|
156
|
+
### Patch Changes
|
|
157
|
+
|
|
158
|
+
- **The declarations now refuse what the engine refuses.** Eight style declarations type-checked at nodes the engine rejects them on, so a report that compiled could still fail to render: `valign` on a stacked item, flow spacing on a table cell or a total cell, and `format`, `currency`, `href` and flow spacing on a row box. Each site now states the narrowing the engine has always applied, through four new exported types — `StackedStyleDeclarations`, `CellStyleDeclarations`, `RowStyleDeclarations`, and the `SlotStyleDeclarations` that was already there.
|
|
159
|
+
|
|
160
|
+
No document that the engine accepts has stopped type-checking. The narrowing removes only names the engine was already refusing.
|
|
161
|
+
|
|
162
|
+
**`SCHEMA.md` now states two keys it always admitted.** The document-shape block never listed `required`, and the group-definition block never listed `collapsed` — the latter while three target sections linked to that section for it, and while the section said a group is collapsible without a field for it. Both are stated now, `collapsed` with the paragraph it never had.
|
|
163
|
+
|
|
164
|
+
- **The declarations now carry `required`, and a group's `label` and `collapsed`.** `ReportSchema` states `required`, and `Group` states both `label` and `collapsed`. The engine has admitted all three and `SCHEMA.md` specifies them, so a TypeScript author marking a declaration required, naming an instance for navigation, or opening a group shut was told it was an error and had to cast.
|
|
165
|
+
|
|
166
|
+
`required` is keyed by a new exported type, `RequirableName`, which spells the same names `REQUIRABLE` carries. A marking no target could answer for is therefore an error where an author writes it, rather than a `plan` problem after the fact — `{ "negative": true }` names a modifier inside `format` rather than a declaration a target answers for, and the compiler now says so. `collapsed` reads `boolean`, because the engine accepts `false` for it as plainly as `true`.
|
|
167
|
+
|
|
3
168
|
## 0.11.1
|
|
4
169
|
|
|
5
170
|
### Patch 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
|