@quario/csv 0.7.1 → 0.8.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,50 @@
1
1
  # @quario/csv
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - **Every target factory now refuses an option it does not understand.** An unknown key, a key with
8
+ a value of the wrong type, or an `options` that is not an object throws a `TypeError` at the
9
+ factory call, naming the option path — `options.meta.title`, `options.page.size`. `@quario/docx`
10
+ already behaved this way. `@quario/pdf`, `@quario/html`, `@quario/xlsx` and `@quario/layout` read
11
+ the keys they knew and ignored the rest, so a typo cost you the option you meant to set with no
12
+ signal at any point. `csv()` takes no options, and it refuses an argument rather than discarding
13
+ one.
14
+
15
+ The check itself is one thing, so the engine now exports it: `hostOptions` closes a key set and
16
+ `hostMeta` validates the `{ title, author, subject }` contract the document targets share. A
17
+ fourth document property is one edit rather than three.
18
+
19
+ **What this changes for you.** One options object spread across several targets stops working if
20
+ any target does not know one of its keys — `const o = { page, fonts, meta }` passed to `pdf(o)`,
21
+ `html(o)` and `xlsx(o)` is three different key sets. An object holding only what its consumers
22
+ share is unaffected, so `{ page, fonts }` into both `pdf()` and `layout()` still works.
23
+ TypeScript does not warn about this: excess-property checking fires on an object literal and not
24
+ on a variable, so a bag held in a `const` compiles clean and throws when you call the factory.
25
+
26
+ Nullish is absence everywhere, at both levels, so `{ meta: config.meta ?? null }` and
27
+ `{ meta: { title: config.title } }` over a config that carries neither are both fine.
28
+ `html({ paths })` now takes `true` or `false` rather than anything truthy, so `paths: "no"` throws
29
+ instead of turning path stamping on. A `fonts` mapping given as an array is refused by
30
+ `@quario/html` and `@quario/layout` rather than read as families named `0`, `1`, `2`.
31
+
32
+ Every host-option failure is now a `TypeError` rather than a plain `Error`. A `catch` that tests
33
+ `instanceof Error` is unaffected. One that compares the constructor is not.
34
+
35
+ `@quario/docx` is relaxed in three places, each of them now accepting what it refused: `meta: null`
36
+ and `page: null` are absence rather than errors, a property written as `meta: { title: undefined }`
37
+ is a property you did not write rather than one of the wrong type, and an inherited enumerable key
38
+ is no longer reported as an option you wrote.
39
+
40
+ `@quario/pdf`, `@quario/xlsx` and `@quario/docx` now copy `meta` at the factory call. Mutating the
41
+ object you passed no longer changes what a configured target writes.
42
+
43
+ ### Patch Changes
44
+
45
+ - Updated dependencies
46
+ - quario@0.9.0
47
+
3
48
  ## 0.7.1
4
49
 
5
50
  ### Patch Changes
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @quario/csv
2
2
 
3
3
  **The CSV render target for [quario](https://www.npmjs.com/package/quario).** Renders a report
4
- definition to CSV records with typed fields: a bare number stays a number's decimal, a Date
5
- stays ISO 8601 UTC, and text that would open as a spreadsheet formula is neutralized.
4
+ definition to CSV records with typed fields. A bare number stays a number's decimal, and a Date
5
+ stays ISO 8601 UTC. This target neutralizes text that would open as a spreadsheet formula.
6
6
 
7
7
  ## Install
8
8
 
@@ -11,7 +11,7 @@ npm install quario @quario/csv
11
11
  ```
12
12
 
13
13
  The engine is a peer dependency, installed beside the target. ESM-only, Node 22+, and
14
- browser-ready through any standards-based ESM bundler. The renderer returns a string; you
14
+ browser-ready through any standards-based ESM bundler. The renderer returns a string. You
15
15
  encode the file.
16
16
 
17
17
  ## Quick start
@@ -54,15 +54,16 @@ Chair,120
54
54
  Lamp,40
55
55
  ```
56
56
 
57
- Any schema the other targets render works here unchanged. A CSV file has no pages, so page
58
- bands are ignored. Interpolate the bare value, not a formatter, when you want a typed field:
59
- `{{ @.amount }}` writes `1000`; `{{ currency(@.amount) }}` writes text.
57
+ Any schema the other targets render works here unchanged. A CSV file has no pages, so this target
58
+ ignores page bands. Interpolate the bare value, not a formatter, when you want a typed field.
59
+ `{{ @.amount }}` writes `1000`, and `{{ currency(@.amount) }}` writes text.
60
60
 
61
61
  ## API
62
62
 
63
63
  ### `csv()`
64
64
 
65
- The target factory takes no options and returns the target you pass to `render`.
65
+ The target factory takes no options and returns the target you pass to `render`. It refuses an argument rather than
66
+ discarding one. It throws a `TypeError` if you give it one.
66
67
  `report()` compiles once and `report.render(csv(), data)` resolves the string. Compile at
67
68
  startup, render per request. Definition problems throw at `report()`, at compile time.
68
69
 
@@ -75,7 +76,7 @@ The compiled report carries `stream` (the raw event generator), `names`, `functi
75
76
  `paths`, like every quario report. Engine-level options (`query` budgets, the license key)
76
77
  live on the instance, and `q.license` settles with the verification result.
77
78
 
78
- Rendering is asynchronous and hands the loop back between batches, so a large report never
79
+ Rendering is asynchronous and returns the loop between batches, so a large report never
79
80
  blocks the host. Render-time failures reject with located errors.
80
81
 
81
82
  ## Mapping
@@ -83,12 +84,14 @@ blocks the host. Render-time failures reject with located errors.
83
84
  The banded walk flattened as records in render order: report-header items, then per group
84
85
  instance its header items, nested content, and footer items, then the table's header record,
85
86
  data records, and total records, then report-footer items. Grouping exists as that order
86
- alone. Group boundaries add no records of their own, and `break: "page"` and `reset: "page"`
87
- are ignored. This target is unpaginated: `report-start.page` band closures are ignored.
87
+ alone. Group boundaries add no records of their own, and this target ignores `break: "page"`
88
+ and `reset: "page"`. This target paginates nothing, so it ignores `report-start.page` band
89
+ closures.
88
90
 
89
- Each item takes one record with one field; a split takes one record with a field per slot, and a
90
- spanning cell writes empty fields for the columns it covers so positions hold. A report that is one
91
- table and no other bands has its column headers as record 1; any other band makes the file ragged.
91
+ Each item takes one record with one field. A split takes one record with a field per slot, and a
92
+ spanning cell writes empty fields for the columns it covers so positions hold. A report that is
93
+ one table and no other bands has its column headers as record 1. Any other band makes the file
94
+ ragged.
92
95
 
93
96
  ### Typed fields
94
97
 
@@ -97,8 +100,8 @@ number as ECMAScript ToString, a boolean as `true`/`false`, a `Date` as ISO 8601
97
100
  other cell joins to display text with `text()`, then the injection guard, then RFC 4180
98
101
  quoting.
99
102
 
100
- **Display-text fields that would open as spreadsheet formulas are mangled.** A leading `=`,
101
- `+`, `-`, `@`, TAB, or CR gets an apostrophe. A consumer that parses the file back does not
103
+ **This target mangles display-text fields that would open as spreadsheet formulas.** A leading
104
+ `=`, `+`, `-`, `@`, TAB, or CR gets an apostrophe. A consumer that parses the file back does not
102
105
  round-trip those fields. The XLSX target does the opposite: it writes an inert string and
103
106
  does not mangle. See
104
107
  [The CSV target](https://getquario.com/docs/diving-deeper/csv-target/#design-decisions).
@@ -107,16 +110,16 @@ A hidden cell keeps its column slot as an empty field.
107
110
 
108
111
  ### Withdrawn, and the unread page bands
109
112
 
110
- `style`, column `width`, slot `width`, page columns and images are withdrawn: a record carries no
111
- presentation, no width and no page, so there is nothing here for any of them to resolve against. An
112
- image emits no record, though an image in a slot still writes its empty field. Page bands are the
113
- one unread declaration this target never calls their closures, so an expression inside one is
114
- never evaluated and never raises here.
113
+ This target withdraws `style`, column `width`, slot `width`, page columns and images. A record
114
+ carries no presentation, no width and no page, so there is nothing here for any of them to
115
+ resolve against. An image emits no record, though an image in a slot still writes its empty
116
+ field. Page bands are the one unread declaration. This target never calls their closures, so an
117
+ expression inside one never runs and never raises here.
115
118
 
116
119
  ### Text shape
117
120
 
118
121
  No BOM. Records separated by LF, not CRLF. The string ends with a newline. Quoting follows
119
- RFC 4180; the line ending does not.
122
+ RFC 4180. The line ending does not.
120
123
 
121
124
  ## Unlicensed marking
122
125
 
@@ -141,10 +144,10 @@ specification of what a report may declare, and
141
144
 
142
145
  ## License
143
146
 
144
- Commercial software with readable source. Free, unlimited, watermarked evaluation; per-developer
145
- licenses at [getquario.com](https://getquario.com). See the bundled LICENSE.
147
+ Commercial software with readable source. Evaluation is free, unlimited, and watermarked.
148
+ Per-developer licenses at [getquario.com](https://getquario.com). See the bundled LICENSE.
146
149
 
147
- Pass your license key once, on the instance; it is verified offline:
150
+ Pass your license key once, on the instance. quario verifies it offline:
148
151
 
149
152
  ```js
150
153
  const q = quario({ license: "quario_..." });
package/lib/index.d.ts CHANGED
@@ -4,5 +4,8 @@ import type { Target } from "quario";
4
4
  * The CSV render target:
5
5
  * `quario().report(schema).render(csv(), data)` resolves the records
6
6
  * described in SCHEMA.md ("The CSV target").
7
+ *
8
+ * It takes no options, and an argument is a `TypeError` at the call rather
9
+ * than an argument quietly discarded.
7
10
  */
8
11
  export function csv(): Target<"csv", Promise<string>>;
package/lib/index.js CHANGED
@@ -32,10 +32,20 @@ let field = (cell) => {
32
32
  * string (the host encodes the file). Rendering runs the engine's `walk`
33
33
  * driver over the handlers below, so large reports stay cooperative.
34
34
  *
35
+ * This target reads no host options, and refuses an argument rather than
36
+ * discarding one: a host writing `csv({ delimiter: ";" })` believes something
37
+ * about the output that is not true, and nothing later would tell them
38
+ * (`docs/adr/0072`). The rule the other targets state over a key set, this
39
+ * one states over the whole call. Nullish is absence here as everywhere, so
40
+ * `csv(config.options)` over a config carrying none is not a mistake.
41
+ *
42
+ * @param {...never} rest Nothing: an option is a definition error.
35
43
  * @returns {{name: "csv", compile: (stream: any) => (data?: any) => Promise<string>}}
36
44
  * The target (see SCHEMA.md, "Instances and targets").
37
45
  */
38
- export function csv() {
46
+ export function csv(...rest) {
47
+ if (rest.some((option) => option != null))
48
+ throw TypeError("options: this target takes no options");
39
49
  return {
40
50
  name: "csv",
41
51
  compile: (stream) => async (data) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quario/csv",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "description": "The CSV render target for quario — in the makings, not yet released",
5
5
  "homepage": "https://getquario.com",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -38,12 +38,12 @@
38
38
  "devDependencies": {
39
39
  "@arethetypeswrong/cli": "^0.18.3",
40
40
  "@size-limit/preset-small-lib": "^13.0.3",
41
- "quario": "^0.8.0",
41
+ "quario": "^0.9.0",
42
42
  "size-limit": "^13.0.3",
43
43
  "typescript": "^7.0.2"
44
44
  },
45
45
  "peerDependencies": {
46
- "quario": "^0.8.0"
46
+ "quario": "^0.9.0"
47
47
  },
48
48
  "size-limit": [
49
49
  {