@quario/docx 0.1.0 → 0.1.1
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 +43 -0
- package/README.md +14 -14
- package/lib/index.d.ts +5 -1
- package/lib/index.js +11 -44
- package/lib/page.js +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,48 @@
|
|
|
1
1
|
# @quario/docx
|
|
2
2
|
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
### Patch 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
|
+
- Updated dependencies
|
|
44
|
+
- quario@0.9.0
|
|
45
|
+
|
|
3
46
|
## 0.1.0
|
|
4
47
|
|
|
5
48
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ npm install quario @quario/docx
|
|
|
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 resolves a `Uint8Array
|
|
14
|
+
browser-ready through any standards-based ESM bundler. The renderer resolves a `Uint8Array`. You
|
|
15
15
|
write the file.
|
|
16
16
|
|
|
17
17
|
## Quick start
|
|
@@ -39,8 +39,8 @@ writeFileSync("orders.docx", bytes);
|
|
|
39
39
|
|
|
40
40
|
## Options
|
|
41
41
|
|
|
42
|
-
Both are optional
|
|
43
|
-
|
|
42
|
+
Both are optional. The factory call validates both: an unknown option, or one of the wrong type,
|
|
43
|
+
throws there rather than at the first render.
|
|
44
44
|
|
|
45
45
|
```js
|
|
46
46
|
docx({
|
|
@@ -56,25 +56,25 @@ docx({
|
|
|
56
56
|
|
|
57
57
|
## What it renders
|
|
58
58
|
|
|
59
|
-
A report's bands become paragraphs
|
|
59
|
+
A report's bands become paragraphs. A table detail becomes a **real Word table** carrying the
|
|
60
60
|
author's column shares as a fixed grid, with `span` as `gridSpan` and a header row that repeats
|
|
61
|
-
after every page break. A split is a borderless one-row table
|
|
62
|
-
column, carrying its `alt` as the drawing's description.
|
|
61
|
+
after every page break. A split is a borderless one-row table. An image is an inline picture at
|
|
62
|
+
its natural size, capped at the text column, carrying its `alt` as the drawing's description.
|
|
63
63
|
|
|
64
64
|
The grouping becomes the **navigation pane**: a group header's first item takes `Heading{depth+1}`
|
|
65
65
|
from this package's own `styles.xml`, so no theme typography leaks in. Everything a report declares
|
|
66
|
-
is direct formatting on the runs and paragraphs that wear it
|
|
66
|
+
is direct formatting on the runs and paragraphs that wear it. `Normal` stays empty, because a look
|
|
67
67
|
that depends on a style lookup is a look three readers may resolve three ways.
|
|
68
68
|
|
|
69
69
|
Page bands become a section's header and footer. A bare `{{ page.number }}` or `{{ page.total }}`
|
|
70
|
-
becomes a live `PAGE` / `NUMPAGES` field the reader's own application recomputes
|
|
71
|
-
from them
|
|
70
|
+
becomes a live `PAGE` / `NUMPAGES` field the reader's own application recomputes. Anything computed
|
|
71
|
+
from them freezes at the value the render saw. A group's `reset: "page"` opens a section that
|
|
72
72
|
restarts the numbering, and `break: "page"` starts the instance on a fresh page.
|
|
73
73
|
|
|
74
74
|
## Determinism
|
|
75
75
|
|
|
76
|
-
Two renders of one report are byte-identical, on **every supported runtime
|
|
77
|
-
JavaScript, so its deflate output does not vary by engine.
|
|
76
|
+
Two renders of one report are byte-identical, on **every supported runtime**. `fflate` is pure
|
|
77
|
+
JavaScript, so its deflate output does not vary by engine. The package stamps every entry
|
|
78
78
|
1980-01-01 and nothing in the document carries a clock, so a digest over the bytes is a fair test.
|
|
79
79
|
|
|
80
80
|
## Documentation
|
|
@@ -87,10 +87,10 @@ of a declaration.
|
|
|
87
87
|
|
|
88
88
|
## License
|
|
89
89
|
|
|
90
|
-
Commercial software with readable source.
|
|
91
|
-
licenses at [getquario.com](https://getquario.com). See the bundled LICENSE.
|
|
90
|
+
Commercial software with readable source. Evaluation is free, unlimited, and watermarked.
|
|
91
|
+
Per-developer licenses at [getquario.com](https://getquario.com). See the bundled LICENSE.
|
|
92
92
|
|
|
93
|
-
Pass your license key once, on the instance
|
|
93
|
+
Pass your license key once, on the instance. quario verifies it offline:
|
|
94
94
|
|
|
95
95
|
```js
|
|
96
96
|
const q = quario({ license: "quario_..." });
|
package/lib/index.d.ts
CHANGED
|
@@ -18,7 +18,11 @@ export interface DocxMeta {
|
|
|
18
18
|
subject?: string;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
/**
|
|
21
|
+
/**
|
|
22
|
+
* Host controls, taken and validated at the factory call: an option this
|
|
23
|
+
* target does not understand, or one of the wrong type, throws a `TypeError`
|
|
24
|
+
* there rather than costing the host the option in silence.
|
|
25
|
+
*/
|
|
22
26
|
export interface DocxOptions {
|
|
23
27
|
page?: DocxPage;
|
|
24
28
|
meta?: DocxMeta;
|
package/lib/index.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* `furniture.js` for the parts a page band becomes, `styles.js` for the base
|
|
12
12
|
* every part inherits, and `text.js` for the runs all of them are made of.
|
|
13
13
|
*/
|
|
14
|
-
import { walk } from "quario";
|
|
14
|
+
import { hostMeta, hostOptions, walk } from "quario";
|
|
15
15
|
import { bodyOf } from "./body.js";
|
|
16
16
|
import { DOCUMENT_NS, furnish } from "./furniture.js";
|
|
17
17
|
import { STYLES } from "./stylepart.js";
|
|
@@ -29,44 +29,6 @@ const WML = "application/vnd.openxmlformats-officedocument.wordprocessingml";
|
|
|
29
29
|
// own default, and what the page bands will be laid against.
|
|
30
30
|
const FURNITURE = 720;
|
|
31
31
|
|
|
32
|
-
/** @type {(msg: string) => never} */
|
|
33
|
-
let err = (msg) => {
|
|
34
|
-
throw Error(msg);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// Split from `object` below rather than inlined: the three terms together
|
|
38
|
-
// breach the complexity budget `npm run fallow` holds this package to.
|
|
39
|
-
/** @type {(value: any) => boolean} */
|
|
40
|
-
let plain = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
41
|
-
|
|
42
|
-
/** @type {(value: any, at: string) => any} */
|
|
43
|
-
let object = (value, at) => {
|
|
44
|
-
// oxlint-disable-next-line no-unused-expressions
|
|
45
|
-
value === undefined || plain(value) || err(at + ": expected an object");
|
|
46
|
-
return value;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
/** @type {(value: any, keys: string[], at: string) => void} */
|
|
50
|
-
let only = (value, keys, at) => {
|
|
51
|
-
for (let key in value) if (!keys.includes(key)) err(at + ': unknown option "' + key + '"');
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
// The three document properties a host may write.
|
|
55
|
-
let PROPERTIES = ["title", "author", "subject"];
|
|
56
|
-
|
|
57
|
-
// The document properties, validated: strings, and never a date. What a host
|
|
58
|
-
// cannot write is what keeps a render deterministic -- `core.xml` is the one
|
|
59
|
-
// part with a slot for a clock, and it has none of them.
|
|
60
|
-
/** @type {(meta: any) => any} */
|
|
61
|
-
let metaOf = (meta) => {
|
|
62
|
-
object(meta, "options.meta");
|
|
63
|
-
only(meta, PROPERTIES, "options.meta");
|
|
64
|
-
for (let key in meta)
|
|
65
|
-
// oxlint-disable-next-line no-unused-expressions
|
|
66
|
-
typeof meta[key] === "string" || err("options.meta." + key + ": expected a string");
|
|
67
|
-
return meta;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
32
|
/**
|
|
71
33
|
* One section. The child order is the schema's and Word is strict about it:
|
|
72
34
|
* the part references, then `type`, the geometry, `pgNumType`, `cols`, and
|
|
@@ -191,15 +153,20 @@ let parts = (body, meta, furniture, rels) => ({
|
|
|
191
153
|
* bytes described in SCHEMA.md ("The DOCX target"). Options are taken and
|
|
192
154
|
* validated at the factory call.
|
|
193
155
|
*
|
|
194
|
-
*
|
|
156
|
+
* The options are described once, in the hand-written public declarations,
|
|
157
|
+
* and read back here -- a second copy in JSDoc is a copy that drifts.
|
|
158
|
+
* @import { DocxOptions } from './index.d.ts'
|
|
159
|
+
*
|
|
160
|
+
* @param {DocxOptions} [options] Host controls (see SCHEMA.md, "The DOCX target").
|
|
195
161
|
* @returns {{name: "docx", compile: (stream: any) => (data?: any) => Promise<Uint8Array>}}
|
|
196
162
|
* The target (see SCHEMA.md, "Instances and targets").
|
|
197
163
|
*/
|
|
198
164
|
export function docx(options) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
let
|
|
165
|
+
hostOptions(options, ["page", "meta"], "options");
|
|
166
|
+
// Closed here rather than in `pageBox`, for the reason the layout package
|
|
167
|
+
// gives at the same call: the surface elements share that function.
|
|
168
|
+
let page = hostOptions(options?.page, ["size", "margin"], "options.page");
|
|
169
|
+
let meta = hostMeta(options?.meta, "options.meta");
|
|
203
170
|
// The size fails here rather than at the first render: a host wrote it, so
|
|
204
171
|
// a host hears about it where it was written. The margin is validated again
|
|
205
172
|
// per render, because the document may be the one declaring it.
|
package/lib/page.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quario/docx",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "The Word render target for quario — a flow target: real Word tables, a navigable outline, live page-number fields",
|
|
5
5
|
"homepage": "https://getquario.com",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@arethetypeswrong/cli": "^0.18.3",
|
|
43
43
|
"@size-limit/preset-small-lib": "^13.0.3",
|
|
44
|
-
"quario": "^0.
|
|
44
|
+
"quario": "^0.9.0",
|
|
45
45
|
"size-limit": "^13.0.3",
|
|
46
46
|
"typescript": "^7.0.2"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"quario": "^0.
|
|
49
|
+
"quario": "^0.9.0"
|
|
50
50
|
},
|
|
51
51
|
"size-limit": [
|
|
52
52
|
{
|