doc-model.js 0.0.0 → 1.5.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/LICENSE +21 -0
- package/README.md +35 -0
- package/dist/index.cjs +602 -0
- package/dist/index.d.cts +2416 -0
- package/dist/index.d.ts +2416 -0
- package/dist/index.js +539 -0
- package/package.json +83 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Joseph Mearman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# document-schema.js
|
|
2
|
+
|
|
3
|
+
[](https://github.com/ExaDev/document-schema.js) [](https://www.npmjs.com/package/document-schema.js) [](https://github.com/ExaDev/document-schema.js/releases/latest) [](https://github.com/ExaDev/document-schema.js/actions)
|
|
4
|
+
|
|
5
|
+
> The canonical, format-agnostic content and layout schema pivot shared by [ooxml.js](https://github.com/ExaDev/ooxml.js), [odf.js](https://github.com/ExaDev/odf.js), and [documents.js](https://github.com/ExaDev/documents.js).
|
|
6
|
+
|
|
7
|
+
Both `ooxml.js` and `documents.js` independently arrived at the same content vocabulary -- paragraphs, runs, tables, images, shapes, slides -- because `documents.js`'s docx/pptx-to-PDF pipeline needed a richer model than `ooxml.js`'s own readers originally produced, and that model was later ported back into `ooxml.js` itself. The result was two field-identical copies maintained in two places. This package is the fix: one schema, imported by every format package instead of redefined by each. It also sidesteps a circular dependency that would otherwise appear once `odf.js` exists, since `documents.js` depends on both `ooxml.js` and `odf.js`.
|
|
8
|
+
|
|
9
|
+
`ContentDocument` (the semantic pivot) is a discriminated union of four kinds: `wordprocessing` (docx/odt-style sections of paragraphs/runs/tables/images), `presentation` (pptx/odp-style slides of shapes), `spreadsheet` (xlsx/ods-style sheets of cells, columns, rows, and print settings), and `drawing` (odg-style pages of shapes plus vector primitives -- rect/ellipse/line/path). `ContentEmbeddedObjectSchema` lets any of the four embed another whole `ContentDocument`. `LayoutDocument` (the PDF-rendering pivot) is pages of positioned `LayoutItem`s -- `text`/`image`/`rect`/`line`/`ellipse`/`path`/`link` -- in PDF user-space coordinates, with `LayoutPathSchema` modelling a general vector path rather than only axis-aligned rectangles. `DocumentPackageSchema` is a small envelope pairing the two: `content` required, `layout` optional (it's a derived artifact, absent until something lays the content out), correlated via each item's own `sourcePath` when both are present -- a pairing this schema does not itself keep in sync or detect as stale.
|
|
10
|
+
|
|
11
|
+
It contains only [Zod](https://zod.dev) schemas, their inferred types, and a handful of trivial schema-attached helpers (hex-colour conversion, a recursive structural type guard for the mutually-recursive table/block/embedded-object types). There is no XML, ZIP, PDF, or other binary handling here, and no `zod` dependency other than `zod` itself.
|
|
12
|
+
|
|
13
|
+
The GitHub repository is [`ExaDev/document-schema.js`](https://github.com/ExaDev/document-schema.js), matching the published npm package name; `document-content-model` (the repository's original name, kept resolving), `doc-model.js`, `doc-schema.js`, `document-schema`, and `document-model.js` republish the identical build as aliases on npmjs.org, alongside a scoped `@exadev/document-content-model` alias on GitHub Packages. A CI matrix job (`publish-aliases` in `.github/workflows/ci.yml`) rewrites `package.json`'s `name` and registry via `npm pkg set` after each release and publishes under each alias in turn -- install whichever name you already depend on.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { ContentDocumentSchema, DocumentPackageSchema, LayoutDocumentSchema } from 'document-schema.js';
|
|
19
|
+
|
|
20
|
+
const content = ContentDocumentSchema.parse(someWordprocessingOrPresentationValue);
|
|
21
|
+
const layout = LayoutDocumentSchema.parse(somePageLayoutValue);
|
|
22
|
+
const pkg = DocumentPackageSchema.parse({ formatVersion: 1, content, layout });
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Used by
|
|
26
|
+
|
|
27
|
+
- [ooxml.js](https://github.com/ExaDev/ooxml.js) — its `readDocx`/`readPptx`/`readXlsxContent` return `ContentSection[]`/`ContentSlide[]`/spreadsheet `ContentSheet[]` typed against this package's own schemas, not a locally-defined lookalike.
|
|
28
|
+
- [odf.js](https://github.com/ExaDev/odf.js) — its ODF typed readers (`readOdt`, `readOdp`, `readOds`, `readOdg`, …) return the same shared types, so an ODF document and an OOXML document speak the identical pivot.
|
|
29
|
+
- [documents.js](https://github.com/ExaDev/documents.js) — the primary consumer of both `ContentDocument` and `LayoutDocument`, which it converts between via its layout engines and PDF codec, and of `DocumentPackage` as the `onDocument` side-channel value its conversion functions hand back.
|
|
30
|
+
|
|
31
|
+
None of these three packages depend on each other for this vocabulary — each depends on `document-schema.js` (or one of its aliases above) directly, which is the whole point: one schema, not three independently-maintained, drift-prone copies.
|
|
32
|
+
|
|
33
|
+
## License
|
|
34
|
+
|
|
35
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let zod = require("zod");
|
|
3
|
+
//#region src/color.ts
|
|
4
|
+
const ColorSchema = zod.z.object({
|
|
5
|
+
r: zod.z.number().min(0).max(1),
|
|
6
|
+
g: zod.z.number().min(0).max(1),
|
|
7
|
+
b: zod.z.number().min(0).max(1)
|
|
8
|
+
});
|
|
9
|
+
const COLOR_BLACK = {
|
|
10
|
+
r: 0,
|
|
11
|
+
g: 0,
|
|
12
|
+
b: 0
|
|
13
|
+
};
|
|
14
|
+
const HEX_COLOR_PATTERN = /^#?([0-9a-fA-F]{6})$/;
|
|
15
|
+
const HEX_BYTE_MAX = 255;
|
|
16
|
+
function rgbHexToColor(hex) {
|
|
17
|
+
const match = HEX_COLOR_PATTERN.exec(hex);
|
|
18
|
+
if (match === null) throw new Error(`not a 6-digit hex colour: ${hex}`);
|
|
19
|
+
const digits = match[1];
|
|
20
|
+
if (digits === void 0) throw new Error(`not a 6-digit hex colour: ${hex}`);
|
|
21
|
+
const r = Number.parseInt(digits.slice(0, 2), 16);
|
|
22
|
+
const g = Number.parseInt(digits.slice(2, 4), 16);
|
|
23
|
+
const b = Number.parseInt(digits.slice(4, 6), 16);
|
|
24
|
+
return {
|
|
25
|
+
r: r / HEX_BYTE_MAX,
|
|
26
|
+
g: g / HEX_BYTE_MAX,
|
|
27
|
+
b: b / HEX_BYTE_MAX
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function toHexByte(component) {
|
|
31
|
+
return Math.round(component * HEX_BYTE_MAX).toString(16).padStart(2, "0");
|
|
32
|
+
}
|
|
33
|
+
function colorToRgbHex(color) {
|
|
34
|
+
return `${toHexByte(color.r)}${toHexByte(color.g)}${toHexByte(color.b)}`;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/geometry.ts
|
|
38
|
+
const BoxSchema = zod.z.object({
|
|
39
|
+
xPt: zod.z.number(),
|
|
40
|
+
yPt: zod.z.number(),
|
|
41
|
+
widthPt: zod.z.number().nonnegative(),
|
|
42
|
+
heightPt: zod.z.number().nonnegative()
|
|
43
|
+
});
|
|
44
|
+
const PageSizeSchema = zod.z.object({
|
|
45
|
+
widthPt: zod.z.number().positive(),
|
|
46
|
+
heightPt: zod.z.number().positive()
|
|
47
|
+
});
|
|
48
|
+
const MarginsSchema = zod.z.object({
|
|
49
|
+
topPt: zod.z.number().nonnegative(),
|
|
50
|
+
rightPt: zod.z.number().nonnegative(),
|
|
51
|
+
bottomPt: zod.z.number().nonnegative(),
|
|
52
|
+
leftPt: zod.z.number().nonnegative()
|
|
53
|
+
});
|
|
54
|
+
const PAGE_SIZE_LETTER = {
|
|
55
|
+
widthPt: 612,
|
|
56
|
+
heightPt: 792
|
|
57
|
+
};
|
|
58
|
+
const PAGE_SIZE_A4 = {
|
|
59
|
+
widthPt: 595.28,
|
|
60
|
+
heightPt: 841.89
|
|
61
|
+
};
|
|
62
|
+
const SLIDE_SIZE_WIDESCREEN = {
|
|
63
|
+
widthPt: 960,
|
|
64
|
+
heightPt: 540
|
|
65
|
+
};
|
|
66
|
+
const SLIDE_SIZE_STANDARD = {
|
|
67
|
+
widthPt: 720,
|
|
68
|
+
heightPt: 540
|
|
69
|
+
};
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/style.ts
|
|
72
|
+
const AlignmentSchema = zod.z.enum([
|
|
73
|
+
"left",
|
|
74
|
+
"center",
|
|
75
|
+
"right",
|
|
76
|
+
"justify"
|
|
77
|
+
]);
|
|
78
|
+
const LayoutFontSchema = zod.z.object({
|
|
79
|
+
family: zod.z.string(),
|
|
80
|
+
weight: zod.z.enum(["normal", "bold"]),
|
|
81
|
+
style: zod.z.enum(["normal", "italic"])
|
|
82
|
+
});
|
|
83
|
+
const DEFAULT_LAYOUT_FONT = {
|
|
84
|
+
family: "Helvetica",
|
|
85
|
+
weight: "normal",
|
|
86
|
+
style: "normal"
|
|
87
|
+
};
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/metadata.ts
|
|
90
|
+
const LayoutMetadataSchema = zod.z.object({
|
|
91
|
+
title: zod.z.string().optional(),
|
|
92
|
+
author: zod.z.string().optional(),
|
|
93
|
+
subject: zod.z.string().optional(),
|
|
94
|
+
keywords: zod.z.array(zod.z.string()).optional(),
|
|
95
|
+
creator: zod.z.string().optional(),
|
|
96
|
+
producer: zod.z.string().optional(),
|
|
97
|
+
createdIso: zod.z.string().optional(),
|
|
98
|
+
modifiedIso: zod.z.string().optional()
|
|
99
|
+
});
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/content.ts
|
|
102
|
+
const ContentRunSchema = zod.z.object({
|
|
103
|
+
text: zod.z.string(),
|
|
104
|
+
bold: zod.z.boolean().optional(),
|
|
105
|
+
italic: zod.z.boolean().optional(),
|
|
106
|
+
underline: zod.z.boolean().optional(),
|
|
107
|
+
strike: zod.z.boolean().optional(),
|
|
108
|
+
fontFamily: zod.z.string().optional(),
|
|
109
|
+
sizePt: zod.z.number().positive().optional(),
|
|
110
|
+
color: ColorSchema.optional(),
|
|
111
|
+
hyperlink: zod.z.string().optional(),
|
|
112
|
+
sourcePath: zod.z.string().optional()
|
|
113
|
+
});
|
|
114
|
+
const ContentListMembershipSchema = zod.z.object({
|
|
115
|
+
numId: zod.z.string(),
|
|
116
|
+
level: zod.z.number().int().nonnegative()
|
|
117
|
+
});
|
|
118
|
+
const ContentParagraphSchema = zod.z.object({
|
|
119
|
+
kind: zod.z.literal("paragraph"),
|
|
120
|
+
runs: zod.z.array(ContentRunSchema),
|
|
121
|
+
styleId: zod.z.string().optional(),
|
|
122
|
+
alignment: AlignmentSchema.optional(),
|
|
123
|
+
list: ContentListMembershipSchema.optional(),
|
|
124
|
+
spacingBeforePt: zod.z.number().optional(),
|
|
125
|
+
spacingAfterPt: zod.z.number().optional(),
|
|
126
|
+
lineSpacing: zod.z.number().positive().optional(),
|
|
127
|
+
indentLeftPt: zod.z.number().optional(),
|
|
128
|
+
indentFirstLinePt: zod.z.number().optional(),
|
|
129
|
+
sourcePath: zod.z.string().optional()
|
|
130
|
+
});
|
|
131
|
+
const ContentImageBlockSchema = zod.z.object({
|
|
132
|
+
kind: zod.z.literal("image"),
|
|
133
|
+
format: zod.z.enum(["png", "jpeg"]),
|
|
134
|
+
base64: zod.z.string(),
|
|
135
|
+
widthPt: zod.z.number().positive(),
|
|
136
|
+
heightPt: zod.z.number().positive(),
|
|
137
|
+
altText: zod.z.string().optional(),
|
|
138
|
+
sourcePath: zod.z.string().optional()
|
|
139
|
+
});
|
|
140
|
+
const ContentPageBreakSchema = zod.z.object({
|
|
141
|
+
kind: zod.z.literal("pageBreak"),
|
|
142
|
+
sourcePath: zod.z.string().optional()
|
|
143
|
+
});
|
|
144
|
+
function isRecord(value) {
|
|
145
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
146
|
+
}
|
|
147
|
+
function isContentRun(value) {
|
|
148
|
+
return isRecord(value) && typeof value.text === "string";
|
|
149
|
+
}
|
|
150
|
+
function isContentTableCell(value) {
|
|
151
|
+
return isRecord(value) && Array.isArray(value.blocks) && value.blocks.every(isContentBlock);
|
|
152
|
+
}
|
|
153
|
+
function isContentTableRow(value) {
|
|
154
|
+
return isRecord(value) && Array.isArray(value.cells) && value.cells.every(isContentTableCell) && (value.heightPt === void 0 || typeof value.heightPt === "number");
|
|
155
|
+
}
|
|
156
|
+
function isContentEmbeddedObjectKind(value) {
|
|
157
|
+
return value === "formula" || value === "wordprocessing" || value === "presentation" || value === "spreadsheet" || value === "drawing";
|
|
158
|
+
}
|
|
159
|
+
function isContentEmbeddedObject(value) {
|
|
160
|
+
return isRecord(value) && isContentEmbeddedObjectKind(value.objectKind) && BoxSchema.safeParse(value.frame).success && ContentDocumentSchema.safeParse(value.document).success;
|
|
161
|
+
}
|
|
162
|
+
function isContentEmbeddedObjectBlock(value) {
|
|
163
|
+
return isRecord(value) && value.kind === "embeddedObject" && isContentEmbeddedObject(value);
|
|
164
|
+
}
|
|
165
|
+
function isContentBlock(value) {
|
|
166
|
+
if (!isRecord(value)) return false;
|
|
167
|
+
const kind = value.kind;
|
|
168
|
+
if (kind === "paragraph") return Array.isArray(value.runs) && value.runs.every(isContentRun);
|
|
169
|
+
if (kind === "image") return (value.format === "png" || value.format === "jpeg") && typeof value.base64 === "string" && typeof value.widthPt === "number" && typeof value.heightPt === "number";
|
|
170
|
+
if (kind === "pageBreak") return true;
|
|
171
|
+
if (kind === "table") return Array.isArray(value.rows) && value.rows.every(isContentTableRow) && Array.isArray(value.columnWidthsPt) && value.columnWidthsPt.every((w) => typeof w === "number");
|
|
172
|
+
if (kind === "embeddedObject") return isContentEmbeddedObject(value);
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
const ContentBlockSchema = zod.z.custom(isContentBlock);
|
|
176
|
+
const ContentEmbeddedObjectSchema = zod.z.custom(isContentEmbeddedObject);
|
|
177
|
+
const ContentEmbeddedObjectBlockSchema = zod.z.custom(isContentEmbeddedObjectBlock);
|
|
178
|
+
const ContentTableCellSchema = zod.z.object({
|
|
179
|
+
blocks: zod.z.array(ContentBlockSchema),
|
|
180
|
+
colSpan: zod.z.number().int().positive().optional(),
|
|
181
|
+
rowSpan: zod.z.number().int().positive().optional(),
|
|
182
|
+
background: ColorSchema.optional()
|
|
183
|
+
});
|
|
184
|
+
const ContentTableRowSchema = zod.z.object({
|
|
185
|
+
cells: zod.z.array(ContentTableCellSchema),
|
|
186
|
+
heightPt: zod.z.number().positive().optional()
|
|
187
|
+
});
|
|
188
|
+
const ContentTableSchema = zod.z.object({
|
|
189
|
+
kind: zod.z.literal("table"),
|
|
190
|
+
rows: zod.z.array(ContentTableRowSchema),
|
|
191
|
+
columnWidthsPt: zod.z.array(zod.z.number().positive()),
|
|
192
|
+
sourcePath: zod.z.string().optional()
|
|
193
|
+
});
|
|
194
|
+
const ContentSectionSchema = zod.z.object({
|
|
195
|
+
pageSize: PageSizeSchema,
|
|
196
|
+
margins: MarginsSchema,
|
|
197
|
+
blocks: zod.z.array(ContentBlockSchema)
|
|
198
|
+
});
|
|
199
|
+
const ContentShapeSchema = zod.z.object({
|
|
200
|
+
name: zod.z.string().optional(),
|
|
201
|
+
frame: BoxSchema,
|
|
202
|
+
rotationDeg: zod.z.number().optional(),
|
|
203
|
+
insetLeftPt: zod.z.number().nonnegative(),
|
|
204
|
+
insetTopPt: zod.z.number().nonnegative(),
|
|
205
|
+
insetRightPt: zod.z.number().nonnegative(),
|
|
206
|
+
insetBottomPt: zod.z.number().nonnegative(),
|
|
207
|
+
fontScale: zod.z.number().positive().optional(),
|
|
208
|
+
lineSpacingReduction: zod.z.number().nonnegative().optional(),
|
|
209
|
+
sourcePath: zod.z.string().optional(),
|
|
210
|
+
blocks: zod.z.array(ContentBlockSchema)
|
|
211
|
+
});
|
|
212
|
+
const ContentSlideSchema = zod.z.object({
|
|
213
|
+
size: PageSizeSchema,
|
|
214
|
+
shapes: zod.z.array(ContentShapeSchema),
|
|
215
|
+
notes: zod.z.string()
|
|
216
|
+
});
|
|
217
|
+
const ContentCellValueSchema = zod.z.discriminatedUnion("kind", [
|
|
218
|
+
zod.z.object({
|
|
219
|
+
kind: zod.z.literal("number"),
|
|
220
|
+
value: zod.z.number()
|
|
221
|
+
}),
|
|
222
|
+
zod.z.object({
|
|
223
|
+
kind: zod.z.literal("percentage"),
|
|
224
|
+
value: zod.z.number()
|
|
225
|
+
}),
|
|
226
|
+
zod.z.object({
|
|
227
|
+
kind: zod.z.literal("currency"),
|
|
228
|
+
value: zod.z.number(),
|
|
229
|
+
currency: zod.z.string().optional()
|
|
230
|
+
}),
|
|
231
|
+
zod.z.object({
|
|
232
|
+
kind: zod.z.literal("boolean"),
|
|
233
|
+
value: zod.z.boolean()
|
|
234
|
+
}),
|
|
235
|
+
zod.z.object({
|
|
236
|
+
kind: zod.z.literal("date"),
|
|
237
|
+
value: zod.z.string()
|
|
238
|
+
}),
|
|
239
|
+
zod.z.object({
|
|
240
|
+
kind: zod.z.literal("time"),
|
|
241
|
+
value: zod.z.string()
|
|
242
|
+
}),
|
|
243
|
+
zod.z.object({
|
|
244
|
+
kind: zod.z.literal("string"),
|
|
245
|
+
value: zod.z.string()
|
|
246
|
+
}),
|
|
247
|
+
zod.z.object({
|
|
248
|
+
kind: zod.z.literal("error"),
|
|
249
|
+
value: zod.z.string()
|
|
250
|
+
}),
|
|
251
|
+
zod.z.object({ kind: zod.z.literal("empty") })
|
|
252
|
+
]);
|
|
253
|
+
const ContentSheetCellSchema = zod.z.object({
|
|
254
|
+
row: zod.z.number().int().nonnegative(),
|
|
255
|
+
column: zod.z.number().int().nonnegative(),
|
|
256
|
+
value: ContentCellValueSchema,
|
|
257
|
+
formula: zod.z.string().optional(),
|
|
258
|
+
displayText: zod.z.string(),
|
|
259
|
+
runs: zod.z.array(ContentRunSchema).optional(),
|
|
260
|
+
colSpan: zod.z.number().int().positive().optional(),
|
|
261
|
+
rowSpan: zod.z.number().int().positive().optional()
|
|
262
|
+
});
|
|
263
|
+
const ContentSheetColumnSchema = zod.z.object({
|
|
264
|
+
index: zod.z.number().int().nonnegative(),
|
|
265
|
+
widthPt: zod.z.number().nonnegative(),
|
|
266
|
+
hidden: zod.z.boolean().optional()
|
|
267
|
+
});
|
|
268
|
+
const ContentSheetRowSchema = zod.z.object({
|
|
269
|
+
index: zod.z.number().int().nonnegative(),
|
|
270
|
+
heightPt: zod.z.number().nonnegative(),
|
|
271
|
+
hidden: zod.z.boolean().optional()
|
|
272
|
+
});
|
|
273
|
+
const ContentSheetPrintRangeSchema = zod.z.object({
|
|
274
|
+
startRow: zod.z.number().int().nonnegative(),
|
|
275
|
+
startColumn: zod.z.number().int().nonnegative(),
|
|
276
|
+
endRow: zod.z.number().int().nonnegative(),
|
|
277
|
+
endColumn: zod.z.number().int().nonnegative()
|
|
278
|
+
});
|
|
279
|
+
const ContentSheetRepeatRangeSchema = zod.z.object({
|
|
280
|
+
start: zod.z.number().int().nonnegative(),
|
|
281
|
+
end: zod.z.number().int().nonnegative()
|
|
282
|
+
});
|
|
283
|
+
const ContentSheetPrintSettingsSchema = zod.z.object({
|
|
284
|
+
pageSize: PageSizeSchema,
|
|
285
|
+
margins: MarginsSchema,
|
|
286
|
+
printRange: ContentSheetPrintRangeSchema.optional(),
|
|
287
|
+
scale: zod.z.number().positive().optional(),
|
|
288
|
+
fitToPages: zod.z.object({
|
|
289
|
+
width: zod.z.number().int().positive(),
|
|
290
|
+
height: zod.z.number().int().positive()
|
|
291
|
+
}).optional(),
|
|
292
|
+
repeatRows: ContentSheetRepeatRangeSchema.optional(),
|
|
293
|
+
repeatColumns: ContentSheetRepeatRangeSchema.optional(),
|
|
294
|
+
gridlines: zod.z.boolean(),
|
|
295
|
+
headers: zod.z.boolean(),
|
|
296
|
+
pageOrder: zod.z.enum(["downThenOver", "overThenDown"]),
|
|
297
|
+
manualBreaks: zod.z.object({
|
|
298
|
+
rows: zod.z.array(zod.z.number().int().nonnegative()),
|
|
299
|
+
columns: zod.z.array(zod.z.number().int().nonnegative())
|
|
300
|
+
}).optional()
|
|
301
|
+
});
|
|
302
|
+
const ContentSheetImageSchema = ContentImageBlockSchema.extend({
|
|
303
|
+
anchorRow: zod.z.number().int().nonnegative(),
|
|
304
|
+
anchorColumn: zod.z.number().int().nonnegative(),
|
|
305
|
+
offsetXPt: zod.z.number(),
|
|
306
|
+
offsetYPt: zod.z.number()
|
|
307
|
+
});
|
|
308
|
+
const ContentSheetSchema = zod.z.object({
|
|
309
|
+
name: zod.z.string(),
|
|
310
|
+
cells: zod.z.array(ContentSheetCellSchema),
|
|
311
|
+
columns: zod.z.array(ContentSheetColumnSchema),
|
|
312
|
+
rows: zod.z.array(ContentSheetRowSchema),
|
|
313
|
+
images: zod.z.array(ContentSheetImageSchema),
|
|
314
|
+
printSettings: ContentSheetPrintSettingsSchema,
|
|
315
|
+
embeddedObjects: zod.z.array(ContentEmbeddedObjectSchema).optional()
|
|
316
|
+
});
|
|
317
|
+
const ContentStrokeSchema = zod.z.object({
|
|
318
|
+
color: ColorSchema,
|
|
319
|
+
widthPt: zod.z.number().positive()
|
|
320
|
+
});
|
|
321
|
+
const ContentPathPointSchema = zod.z.object({
|
|
322
|
+
xPt: zod.z.number(),
|
|
323
|
+
yPt: zod.z.number()
|
|
324
|
+
});
|
|
325
|
+
const ContentPathSegmentSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
|
|
326
|
+
kind: zod.z.literal("line"),
|
|
327
|
+
to: ContentPathPointSchema
|
|
328
|
+
}), zod.z.object({
|
|
329
|
+
kind: zod.z.literal("cubic"),
|
|
330
|
+
control1: ContentPathPointSchema,
|
|
331
|
+
control2: ContentPathPointSchema,
|
|
332
|
+
to: ContentPathPointSchema
|
|
333
|
+
})]);
|
|
334
|
+
const ContentSubpathSchema = zod.z.object({
|
|
335
|
+
start: ContentPathPointSchema,
|
|
336
|
+
segments: zod.z.array(ContentPathSegmentSchema),
|
|
337
|
+
closed: zod.z.boolean()
|
|
338
|
+
});
|
|
339
|
+
const ContentVectorSchema = zod.z.discriminatedUnion("kind", [
|
|
340
|
+
zod.z.object({
|
|
341
|
+
kind: zod.z.literal("rect"),
|
|
342
|
+
frame: BoxSchema,
|
|
343
|
+
fill: ColorSchema.optional(),
|
|
344
|
+
stroke: ContentStrokeSchema.optional(),
|
|
345
|
+
sourcePath: zod.z.string().optional()
|
|
346
|
+
}),
|
|
347
|
+
zod.z.object({
|
|
348
|
+
kind: zod.z.literal("ellipse"),
|
|
349
|
+
frame: BoxSchema,
|
|
350
|
+
fill: ColorSchema.optional(),
|
|
351
|
+
stroke: ContentStrokeSchema.optional(),
|
|
352
|
+
sourcePath: zod.z.string().optional()
|
|
353
|
+
}),
|
|
354
|
+
zod.z.object({
|
|
355
|
+
kind: zod.z.literal("line"),
|
|
356
|
+
from: ContentPathPointSchema,
|
|
357
|
+
to: ContentPathPointSchema,
|
|
358
|
+
stroke: ContentStrokeSchema,
|
|
359
|
+
sourcePath: zod.z.string().optional()
|
|
360
|
+
}),
|
|
361
|
+
zod.z.object({
|
|
362
|
+
kind: zod.z.literal("path"),
|
|
363
|
+
frame: BoxSchema,
|
|
364
|
+
subpaths: zod.z.array(ContentSubpathSchema),
|
|
365
|
+
fill: ColorSchema.optional(),
|
|
366
|
+
fillRule: zod.z.enum(["nonzero", "evenodd"]).optional(),
|
|
367
|
+
stroke: ContentStrokeSchema.optional(),
|
|
368
|
+
sourcePath: zod.z.string().optional()
|
|
369
|
+
})
|
|
370
|
+
]);
|
|
371
|
+
const ContentDrawPageSchema = zod.z.object({
|
|
372
|
+
size: PageSizeSchema,
|
|
373
|
+
shapes: zod.z.array(ContentShapeSchema),
|
|
374
|
+
vectors: zod.z.array(ContentVectorSchema)
|
|
375
|
+
});
|
|
376
|
+
const CONTENT_FORMAT_VERSION = 1;
|
|
377
|
+
const ContentDocumentSchema = zod.z.discriminatedUnion("kind", [
|
|
378
|
+
zod.z.object({
|
|
379
|
+
kind: zod.z.literal("wordprocessing"),
|
|
380
|
+
formatVersion: zod.z.literal(1),
|
|
381
|
+
metadata: LayoutMetadataSchema,
|
|
382
|
+
sections: zod.z.array(ContentSectionSchema)
|
|
383
|
+
}),
|
|
384
|
+
zod.z.object({
|
|
385
|
+
kind: zod.z.literal("presentation"),
|
|
386
|
+
formatVersion: zod.z.literal(1),
|
|
387
|
+
metadata: LayoutMetadataSchema,
|
|
388
|
+
slides: zod.z.array(ContentSlideSchema)
|
|
389
|
+
}),
|
|
390
|
+
zod.z.object({
|
|
391
|
+
kind: zod.z.literal("spreadsheet"),
|
|
392
|
+
formatVersion: zod.z.literal(1),
|
|
393
|
+
metadata: LayoutMetadataSchema,
|
|
394
|
+
sheets: zod.z.array(ContentSheetSchema)
|
|
395
|
+
}),
|
|
396
|
+
zod.z.object({
|
|
397
|
+
kind: zod.z.literal("drawing"),
|
|
398
|
+
formatVersion: zod.z.literal(1),
|
|
399
|
+
metadata: LayoutMetadataSchema,
|
|
400
|
+
pages: zod.z.array(ContentDrawPageSchema)
|
|
401
|
+
})
|
|
402
|
+
]);
|
|
403
|
+
//#endregion
|
|
404
|
+
//#region src/layout.ts
|
|
405
|
+
const LAYOUT_FORMAT_VERSION = 1;
|
|
406
|
+
const LayoutTextSchema = zod.z.object({
|
|
407
|
+
kind: zod.z.literal("text"),
|
|
408
|
+
text: zod.z.string(),
|
|
409
|
+
xPt: zod.z.number(),
|
|
410
|
+
yPt: zod.z.number(),
|
|
411
|
+
font: LayoutFontSchema,
|
|
412
|
+
sizePt: zod.z.number().positive(),
|
|
413
|
+
color: ColorSchema,
|
|
414
|
+
widthPt: zod.z.number().nonnegative().optional(),
|
|
415
|
+
rotationDeg: zod.z.number().optional(),
|
|
416
|
+
underline: zod.z.boolean().optional(),
|
|
417
|
+
sourcePath: zod.z.string().optional()
|
|
418
|
+
});
|
|
419
|
+
const LayoutImageSchema = zod.z.object({
|
|
420
|
+
kind: zod.z.literal("image"),
|
|
421
|
+
imageId: zod.z.string(),
|
|
422
|
+
xPt: zod.z.number(),
|
|
423
|
+
yPt: zod.z.number(),
|
|
424
|
+
widthPt: zod.z.number().positive(),
|
|
425
|
+
heightPt: zod.z.number().positive(),
|
|
426
|
+
rotationDeg: zod.z.number().optional(),
|
|
427
|
+
sourcePath: zod.z.string().optional()
|
|
428
|
+
});
|
|
429
|
+
const LayoutRectSchema = zod.z.object({
|
|
430
|
+
kind: zod.z.literal("rect"),
|
|
431
|
+
xPt: zod.z.number(),
|
|
432
|
+
yPt: zod.z.number(),
|
|
433
|
+
widthPt: zod.z.number().nonnegative(),
|
|
434
|
+
heightPt: zod.z.number().nonnegative(),
|
|
435
|
+
fill: ColorSchema.optional(),
|
|
436
|
+
stroke: zod.z.object({
|
|
437
|
+
color: ColorSchema,
|
|
438
|
+
widthPt: zod.z.number().positive()
|
|
439
|
+
}).optional(),
|
|
440
|
+
sourcePath: zod.z.string().optional()
|
|
441
|
+
});
|
|
442
|
+
const LayoutLineSchema = zod.z.object({
|
|
443
|
+
kind: zod.z.literal("line"),
|
|
444
|
+
x1Pt: zod.z.number(),
|
|
445
|
+
y1Pt: zod.z.number(),
|
|
446
|
+
x2Pt: zod.z.number(),
|
|
447
|
+
y2Pt: zod.z.number(),
|
|
448
|
+
color: ColorSchema,
|
|
449
|
+
widthPt: zod.z.number().positive(),
|
|
450
|
+
sourcePath: zod.z.string().optional()
|
|
451
|
+
});
|
|
452
|
+
const LayoutEllipseSchema = zod.z.object({
|
|
453
|
+
kind: zod.z.literal("ellipse"),
|
|
454
|
+
xPt: zod.z.number(),
|
|
455
|
+
yPt: zod.z.number(),
|
|
456
|
+
widthPt: zod.z.number().positive(),
|
|
457
|
+
heightPt: zod.z.number().positive(),
|
|
458
|
+
fill: ColorSchema.optional(),
|
|
459
|
+
stroke: zod.z.object({
|
|
460
|
+
color: ColorSchema,
|
|
461
|
+
widthPt: zod.z.number().positive()
|
|
462
|
+
}).optional(),
|
|
463
|
+
sourcePath: zod.z.string().optional()
|
|
464
|
+
});
|
|
465
|
+
const LayoutPathSegmentSchema = zod.z.discriminatedUnion("kind", [zod.z.object({
|
|
466
|
+
kind: zod.z.literal("line"),
|
|
467
|
+
xPt: zod.z.number(),
|
|
468
|
+
yPt: zod.z.number()
|
|
469
|
+
}), zod.z.object({
|
|
470
|
+
kind: zod.z.literal("cubic"),
|
|
471
|
+
c1xPt: zod.z.number(),
|
|
472
|
+
c1yPt: zod.z.number(),
|
|
473
|
+
c2xPt: zod.z.number(),
|
|
474
|
+
c2yPt: zod.z.number(),
|
|
475
|
+
xPt: zod.z.number(),
|
|
476
|
+
yPt: zod.z.number()
|
|
477
|
+
})]);
|
|
478
|
+
const LayoutSubpathSchema = zod.z.object({
|
|
479
|
+
startXPt: zod.z.number(),
|
|
480
|
+
startYPt: zod.z.number(),
|
|
481
|
+
segments: zod.z.array(LayoutPathSegmentSchema),
|
|
482
|
+
closed: zod.z.boolean()
|
|
483
|
+
});
|
|
484
|
+
const LayoutPathSchema = zod.z.object({
|
|
485
|
+
kind: zod.z.literal("path"),
|
|
486
|
+
subpaths: zod.z.array(LayoutSubpathSchema),
|
|
487
|
+
fill: ColorSchema.optional(),
|
|
488
|
+
fillRule: zod.z.enum(["nonzero", "evenodd"]).optional(),
|
|
489
|
+
stroke: zod.z.object({
|
|
490
|
+
color: ColorSchema,
|
|
491
|
+
widthPt: zod.z.number().positive()
|
|
492
|
+
}).optional(),
|
|
493
|
+
sourcePath: zod.z.string().optional()
|
|
494
|
+
});
|
|
495
|
+
const LayoutLinkSchema = zod.z.object({
|
|
496
|
+
kind: zod.z.literal("link"),
|
|
497
|
+
uri: zod.z.string(),
|
|
498
|
+
xPt: zod.z.number(),
|
|
499
|
+
yPt: zod.z.number(),
|
|
500
|
+
widthPt: zod.z.number().nonnegative(),
|
|
501
|
+
heightPt: zod.z.number().nonnegative(),
|
|
502
|
+
sourcePath: zod.z.string().optional()
|
|
503
|
+
});
|
|
504
|
+
const LayoutItemSchema = zod.z.discriminatedUnion("kind", [
|
|
505
|
+
LayoutTextSchema,
|
|
506
|
+
LayoutImageSchema,
|
|
507
|
+
LayoutRectSchema,
|
|
508
|
+
LayoutLineSchema,
|
|
509
|
+
LayoutEllipseSchema,
|
|
510
|
+
LayoutPathSchema,
|
|
511
|
+
LayoutLinkSchema
|
|
512
|
+
]);
|
|
513
|
+
const LayoutPageSchema = zod.z.object({
|
|
514
|
+
widthPt: zod.z.number().positive(),
|
|
515
|
+
heightPt: zod.z.number().positive(),
|
|
516
|
+
items: zod.z.array(LayoutItemSchema),
|
|
517
|
+
notes: zod.z.string().optional()
|
|
518
|
+
});
|
|
519
|
+
const LayoutImageAssetSchema = zod.z.object({
|
|
520
|
+
format: zod.z.enum(["png", "jpeg"]),
|
|
521
|
+
base64: zod.z.string(),
|
|
522
|
+
widthPx: zod.z.number().int().positive(),
|
|
523
|
+
heightPx: zod.z.number().int().positive()
|
|
524
|
+
});
|
|
525
|
+
const LayoutDocumentSchema = zod.z.object({
|
|
526
|
+
formatVersion: zod.z.literal(1),
|
|
527
|
+
metadata: LayoutMetadataSchema,
|
|
528
|
+
pages: zod.z.array(LayoutPageSchema),
|
|
529
|
+
images: zod.z.record(zod.z.string(), LayoutImageAssetSchema)
|
|
530
|
+
});
|
|
531
|
+
//#endregion
|
|
532
|
+
//#region src/package.ts
|
|
533
|
+
const DOCUMENT_PACKAGE_FORMAT_VERSION = 1;
|
|
534
|
+
const DocumentPackageSchema = zod.z.object({
|
|
535
|
+
formatVersion: zod.z.literal(1),
|
|
536
|
+
content: ContentDocumentSchema,
|
|
537
|
+
layout: LayoutDocumentSchema.optional()
|
|
538
|
+
});
|
|
539
|
+
//#endregion
|
|
540
|
+
exports.AlignmentSchema = AlignmentSchema;
|
|
541
|
+
exports.BoxSchema = BoxSchema;
|
|
542
|
+
exports.COLOR_BLACK = COLOR_BLACK;
|
|
543
|
+
exports.CONTENT_FORMAT_VERSION = CONTENT_FORMAT_VERSION;
|
|
544
|
+
exports.ColorSchema = ColorSchema;
|
|
545
|
+
exports.ContentBlockSchema = ContentBlockSchema;
|
|
546
|
+
exports.ContentCellValueSchema = ContentCellValueSchema;
|
|
547
|
+
exports.ContentDocumentSchema = ContentDocumentSchema;
|
|
548
|
+
exports.ContentDrawPageSchema = ContentDrawPageSchema;
|
|
549
|
+
exports.ContentEmbeddedObjectBlockSchema = ContentEmbeddedObjectBlockSchema;
|
|
550
|
+
exports.ContentEmbeddedObjectSchema = ContentEmbeddedObjectSchema;
|
|
551
|
+
exports.ContentImageBlockSchema = ContentImageBlockSchema;
|
|
552
|
+
exports.ContentListMembershipSchema = ContentListMembershipSchema;
|
|
553
|
+
exports.ContentPageBreakSchema = ContentPageBreakSchema;
|
|
554
|
+
exports.ContentParagraphSchema = ContentParagraphSchema;
|
|
555
|
+
exports.ContentPathPointSchema = ContentPathPointSchema;
|
|
556
|
+
exports.ContentPathSegmentSchema = ContentPathSegmentSchema;
|
|
557
|
+
exports.ContentRunSchema = ContentRunSchema;
|
|
558
|
+
exports.ContentSectionSchema = ContentSectionSchema;
|
|
559
|
+
exports.ContentShapeSchema = ContentShapeSchema;
|
|
560
|
+
exports.ContentSheetCellSchema = ContentSheetCellSchema;
|
|
561
|
+
exports.ContentSheetColumnSchema = ContentSheetColumnSchema;
|
|
562
|
+
exports.ContentSheetImageSchema = ContentSheetImageSchema;
|
|
563
|
+
exports.ContentSheetPrintRangeSchema = ContentSheetPrintRangeSchema;
|
|
564
|
+
exports.ContentSheetPrintSettingsSchema = ContentSheetPrintSettingsSchema;
|
|
565
|
+
exports.ContentSheetRepeatRangeSchema = ContentSheetRepeatRangeSchema;
|
|
566
|
+
exports.ContentSheetRowSchema = ContentSheetRowSchema;
|
|
567
|
+
exports.ContentSheetSchema = ContentSheetSchema;
|
|
568
|
+
exports.ContentSlideSchema = ContentSlideSchema;
|
|
569
|
+
exports.ContentStrokeSchema = ContentStrokeSchema;
|
|
570
|
+
exports.ContentSubpathSchema = ContentSubpathSchema;
|
|
571
|
+
exports.ContentTableCellSchema = ContentTableCellSchema;
|
|
572
|
+
exports.ContentTableRowSchema = ContentTableRowSchema;
|
|
573
|
+
exports.ContentTableSchema = ContentTableSchema;
|
|
574
|
+
exports.ContentVectorSchema = ContentVectorSchema;
|
|
575
|
+
exports.DEFAULT_LAYOUT_FONT = DEFAULT_LAYOUT_FONT;
|
|
576
|
+
exports.DOCUMENT_PACKAGE_FORMAT_VERSION = DOCUMENT_PACKAGE_FORMAT_VERSION;
|
|
577
|
+
exports.DocumentPackageSchema = DocumentPackageSchema;
|
|
578
|
+
exports.LAYOUT_FORMAT_VERSION = LAYOUT_FORMAT_VERSION;
|
|
579
|
+
exports.LayoutDocumentSchema = LayoutDocumentSchema;
|
|
580
|
+
exports.LayoutEllipseSchema = LayoutEllipseSchema;
|
|
581
|
+
exports.LayoutFontSchema = LayoutFontSchema;
|
|
582
|
+
exports.LayoutImageAssetSchema = LayoutImageAssetSchema;
|
|
583
|
+
exports.LayoutImageSchema = LayoutImageSchema;
|
|
584
|
+
exports.LayoutItemSchema = LayoutItemSchema;
|
|
585
|
+
exports.LayoutLineSchema = LayoutLineSchema;
|
|
586
|
+
exports.LayoutLinkSchema = LayoutLinkSchema;
|
|
587
|
+
exports.LayoutMetadataSchema = LayoutMetadataSchema;
|
|
588
|
+
exports.LayoutPageSchema = LayoutPageSchema;
|
|
589
|
+
exports.LayoutPathSchema = LayoutPathSchema;
|
|
590
|
+
exports.LayoutPathSegmentSchema = LayoutPathSegmentSchema;
|
|
591
|
+
exports.LayoutRectSchema = LayoutRectSchema;
|
|
592
|
+
exports.LayoutSubpathSchema = LayoutSubpathSchema;
|
|
593
|
+
exports.LayoutTextSchema = LayoutTextSchema;
|
|
594
|
+
exports.MarginsSchema = MarginsSchema;
|
|
595
|
+
exports.PAGE_SIZE_A4 = PAGE_SIZE_A4;
|
|
596
|
+
exports.PAGE_SIZE_LETTER = PAGE_SIZE_LETTER;
|
|
597
|
+
exports.PageSizeSchema = PageSizeSchema;
|
|
598
|
+
exports.SLIDE_SIZE_STANDARD = SLIDE_SIZE_STANDARD;
|
|
599
|
+
exports.SLIDE_SIZE_WIDESCREEN = SLIDE_SIZE_WIDESCREEN;
|
|
600
|
+
exports.colorToRgbHex = colorToRgbHex;
|
|
601
|
+
exports.isContentBlock = isContentBlock;
|
|
602
|
+
exports.rgbHexToColor = rgbHexToColor;
|