odf.js 1.12.0 → 1.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.
Files changed (178) hide show
  1. package/README.md +39 -0
  2. package/dist/codec.cjs +28 -0
  3. package/dist/codec.d.cts +72 -0
  4. package/dist/codec.d.ts +72 -0
  5. package/dist/codec.js +24 -0
  6. package/dist/image/sniff.cjs +28 -0
  7. package/dist/image/sniff.d.cts +5 -0
  8. package/dist/image/sniff.d.ts +5 -0
  9. package/dist/image/sniff.js +27 -0
  10. package/dist/index.cjs +156 -3242
  11. package/dist/index.d.cts +42 -679
  12. package/dist/index.d.ts +42 -679
  13. package/dist/index.js +42 -3129
  14. package/dist/manifest.cjs +252 -0
  15. package/dist/manifest.d.cts +41 -0
  16. package/dist/manifest.d.ts +41 -0
  17. package/dist/manifest.js +242 -0
  18. package/dist/media-type.cjs +27 -0
  19. package/dist/media-type.d.cts +20 -0
  20. package/dist/media-type.d.ts +20 -0
  21. package/dist/media-type.js +25 -0
  22. package/dist/mimetype.cjs +19 -0
  23. package/dist/mimetype.d.cts +7 -0
  24. package/dist/mimetype.d.ts +7 -0
  25. package/dist/mimetype.js +16 -0
  26. package/dist/model/node.cjs +67 -0
  27. package/dist/model/node.d.cts +2 -0
  28. package/dist/model/node.d.ts +2 -0
  29. package/dist/model/node.js +58 -0
  30. package/dist/model/package.cjs +19 -0
  31. package/dist/model/package.d.cts +114 -0
  32. package/dist/model/package.d.ts +114 -0
  33. package/dist/model/package.js +15 -0
  34. package/dist/node-CkBWRjNR.d.cts +83 -0
  35. package/dist/node-CkBWRjNR.d.ts +83 -0
  36. package/dist/ns.cjs +37 -0
  37. package/dist/ns.d.cts +32 -0
  38. package/dist/ns.d.ts +32 -0
  39. package/dist/ns.js +35 -0
  40. package/dist/package-io/read.cjs +35 -0
  41. package/dist/package-io/read.d.cts +5 -0
  42. package/dist/package-io/read.d.ts +5 -0
  43. package/dist/package-io/read.js +34 -0
  44. package/dist/package-io/write.cjs +36 -0
  45. package/dist/package-io/write.d.cts +7 -0
  46. package/dist/package-io/write.d.ts +7 -0
  47. package/dist/package-io/write.js +33 -0
  48. package/dist/styles/properties.cjs +286 -0
  49. package/dist/styles/properties.d.cts +45 -0
  50. package/dist/styles/properties.d.ts +45 -0
  51. package/dist/styles/properties.js +277 -0
  52. package/dist/styles/registry.cjs +212 -0
  53. package/dist/styles/registry.d.cts +37 -0
  54. package/dist/styles/registry.d.ts +37 -0
  55. package/dist/styles/registry.js +209 -0
  56. package/dist/styles/serialize.cjs +23 -0
  57. package/dist/styles/serialize.d.cts +7 -0
  58. package/dist/styles/serialize.d.ts +7 -0
  59. package/dist/styles/serialize.js +21 -0
  60. package/dist/styles/span.cjs +114 -0
  61. package/dist/styles/span.d.cts +5 -0
  62. package/dist/styles/span.d.ts +5 -0
  63. package/dist/styles/span.js +113 -0
  64. package/dist/typed/draw/shapes.cjs +314 -0
  65. package/dist/typed/draw/shapes.d.cts +14 -0
  66. package/dist/typed/draw/shapes.d.ts +14 -0
  67. package/dist/typed/draw/shapes.js +311 -0
  68. package/dist/typed/formula/read.cjs +48 -0
  69. package/dist/typed/formula/read.d.cts +12 -0
  70. package/dist/typed/formula/read.d.ts +12 -0
  71. package/dist/typed/formula/read.js +47 -0
  72. package/dist/typed/odb/read.cjs +112 -0
  73. package/dist/typed/odb/read.d.cts +17 -0
  74. package/dist/typed/odb/read.d.ts +17 -0
  75. package/dist/typed/odb/read.js +111 -0
  76. package/dist/typed/odg/read.cjs +30 -0
  77. package/dist/typed/odg/read.d.cts +10 -0
  78. package/dist/typed/odg/read.d.ts +10 -0
  79. package/dist/typed/odg/read.js +29 -0
  80. package/dist/typed/odm/read.cjs +37 -0
  81. package/dist/typed/odm/read.d.cts +15 -0
  82. package/dist/typed/odm/read.d.ts +15 -0
  83. package/dist/typed/odm/read.js +36 -0
  84. package/dist/typed/odp/read.cjs +39 -0
  85. package/dist/typed/odp/read.d.cts +10 -0
  86. package/dist/typed/odp/read.d.ts +10 -0
  87. package/dist/typed/odp/read.js +38 -0
  88. package/dist/typed/ods/read.cjs +318 -0
  89. package/dist/typed/ods/read.d.cts +10 -0
  90. package/dist/typed/ods/read.d.ts +10 -0
  91. package/dist/typed/ods/read.js +317 -0
  92. package/dist/typed/odt/read.cjs +112 -0
  93. package/dist/typed/odt/read.d.cts +10 -0
  94. package/dist/typed/odt/read.d.ts +10 -0
  95. package/dist/typed/odt/read.js +111 -0
  96. package/dist/typed/shared/a1.cjs +68 -0
  97. package/dist/typed/shared/a1.d.cts +18 -0
  98. package/dist/typed/shared/a1.d.ts +18 -0
  99. package/dist/typed/shared/a1.js +63 -0
  100. package/dist/typed/shared/cascade.cjs +102 -0
  101. package/dist/typed/shared/cascade.d.cts +22 -0
  102. package/dist/typed/shared/cascade.d.ts +22 -0
  103. package/dist/typed/shared/cascade.js +99 -0
  104. package/dist/typed/shared/color.cjs +14 -0
  105. package/dist/typed/shared/color.d.cts +6 -0
  106. package/dist/typed/shared/color.d.ts +6 -0
  107. package/dist/typed/shared/color.js +12 -0
  108. package/dist/typed/shared/geometry.cjs +79 -0
  109. package/dist/typed/shared/geometry.d.cts +12 -0
  110. package/dist/typed/shared/geometry.d.ts +12 -0
  111. package/dist/typed/shared/geometry.js +75 -0
  112. package/dist/typed/shared/masterpage.cjs +39 -0
  113. package/dist/typed/shared/masterpage.d.cts +8 -0
  114. package/dist/typed/shared/masterpage.d.ts +8 -0
  115. package/dist/typed/shared/masterpage.js +37 -0
  116. package/dist/typed/shared/metadata.cjs +42 -0
  117. package/dist/typed/shared/metadata.d.cts +7 -0
  118. package/dist/typed/shared/metadata.d.ts +7 -0
  119. package/dist/typed/shared/metadata.js +40 -0
  120. package/dist/typed/shared/paragraph.cjs +57 -0
  121. package/dist/typed/shared/paragraph.d.cts +7 -0
  122. package/dist/typed/shared/paragraph.d.ts +7 -0
  123. package/dist/typed/shared/paragraph.js +56 -0
  124. package/dist/typed/shared/path.cjs +261 -0
  125. package/dist/typed/shared/path.d.cts +34 -0
  126. package/dist/typed/shared/path.d.ts +34 -0
  127. package/dist/typed/shared/path.js +255 -0
  128. package/dist/typed/shared/style.cjs +8 -0
  129. package/dist/typed/shared/style.d.cts +2 -0
  130. package/dist/typed/shared/style.d.ts +2 -0
  131. package/dist/typed/shared/style.js +2 -0
  132. package/dist/typed/shared/table.cjs +84 -0
  133. package/dist/typed/shared/table.d.cts +7 -0
  134. package/dist/typed/shared/table.d.ts +7 -0
  135. package/dist/typed/shared/table.js +83 -0
  136. package/dist/typed/shared/text.cjs +43 -0
  137. package/dist/typed/shared/text.d.cts +8 -0
  138. package/dist/typed/shared/text.d.ts +8 -0
  139. package/dist/typed/shared/text.js +39 -0
  140. package/dist/typed/shared/transform.cjs +112 -0
  141. package/dist/typed/shared/transform.d.cts +26 -0
  142. package/dist/typed/shared/transform.d.ts +26 -0
  143. package/dist/typed/shared/transform.js +107 -0
  144. package/dist/typed/shared/units.cjs +35 -0
  145. package/dist/typed/shared/units.d.cts +2 -0
  146. package/dist/typed/shared/units.d.ts +2 -0
  147. package/dist/typed/shared/units.js +33 -0
  148. package/dist/units-7pCiECuP.d.cts +6 -0
  149. package/dist/units-7pCiECuP.d.ts +6 -0
  150. package/dist/util/base64.cjs +48 -0
  151. package/dist/util/base64.d.cts +5 -0
  152. package/dist/util/base64.d.ts +5 -0
  153. package/dist/util/base64.js +46 -0
  154. package/dist/xml/build.cjs +46 -0
  155. package/dist/xml/build.d.cts +5 -0
  156. package/dist/xml/build.d.ts +5 -0
  157. package/dist/xml/build.js +46 -0
  158. package/dist/xml/entities.cjs +19 -0
  159. package/dist/xml/entities.d.cts +5 -0
  160. package/dist/xml/entities.d.ts +5 -0
  161. package/dist/xml/entities.js +17 -0
  162. package/dist/xml/fragment.cjs +22 -0
  163. package/dist/xml/fragment.d.cts +6 -0
  164. package/dist/xml/fragment.d.ts +6 -0
  165. package/dist/xml/fragment.js +20 -0
  166. package/dist/xml/parse.cjs +88 -0
  167. package/dist/xml/parse.d.cts +5 -0
  168. package/dist/xml/parse.d.ts +5 -0
  169. package/dist/xml/parse.js +88 -0
  170. package/dist/xml/query.cjs +33 -0
  171. package/dist/xml/query.d.cts +9 -0
  172. package/dist/xml/query.d.ts +9 -0
  173. package/dist/xml/query.js +28 -0
  174. package/dist/zip.cjs +15 -0
  175. package/dist/zip.d.cts +9 -0
  176. package/dist/zip.d.ts +9 -0
  177. package/dist/zip.js +13 -0
  178. package/package.json +9 -1
@@ -0,0 +1,252 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_util_base64 = require("./util/base64.cjs");
3
+ const require_package_io_write = require("./package-io/write.cjs");
4
+ const require_ns = require("./ns.cjs");
5
+ const require_media_type = require("./media-type.cjs");
6
+ const require_image_sniff = require("./image/sniff.cjs");
7
+ const require_mimetype = require("./mimetype.cjs");
8
+ const require_xml_fragment = require("./xml/fragment.cjs");
9
+ const require_xml_entities = require("./xml/entities.cjs");
10
+ let zod = require("zod");
11
+ //#region src/manifest.ts
12
+ const ManifestEntrySchema = zod.z.object({
13
+ fullPath: zod.z.string(),
14
+ mediaType: zod.z.string(),
15
+ version: zod.z.string().optional()
16
+ });
17
+ const ManifestSchema = zod.z.object({
18
+ version: zod.z.string(),
19
+ entries: zod.z.array(ManifestEntrySchema)
20
+ });
21
+ const ManifestProblemSchema = zod.z.object({
22
+ severity: zod.z.enum(["error", "warning"]),
23
+ message: zod.z.string(),
24
+ path: zod.z.string().optional()
25
+ });
26
+ const DEFAULT_MANIFEST_VERSION = "1.3";
27
+ const STANDARD_XML_PART_NAMES = /* @__PURE__ */ new Set([
28
+ "content.xml",
29
+ "styles.xml",
30
+ "meta.xml",
31
+ "settings.xml"
32
+ ]);
33
+ function findChildElement(nodes, tag) {
34
+ for (const node of nodes) if (node.type === "element" && node.tag === tag) return node;
35
+ }
36
+ function attrValue(element, name) {
37
+ return element.attributes.find((attribute) => attribute.name === name)?.value;
38
+ }
39
+ function readManifest(pkg) {
40
+ const part = pkg.parts[require_package_io_write.MANIFEST_PART];
41
+ if (part?.kind !== "xml") throw new Error(`package has no ${require_package_io_write.MANIFEST_PART} XML part to read`);
42
+ const root = findChildElement(part.nodes, "manifest:manifest");
43
+ if (root === void 0) throw new Error(`${require_package_io_write.MANIFEST_PART} has no manifest:manifest root element`);
44
+ const version = attrValue(root, "manifest:version");
45
+ if (version === void 0) throw new Error(`${require_package_io_write.MANIFEST_PART}'s manifest:manifest root is missing the required manifest:version attribute`);
46
+ const entries = [];
47
+ for (const child of root.children) {
48
+ if (child.type !== "element" || child.tag !== "manifest:file-entry") continue;
49
+ const fullPath = attrValue(child, "manifest:full-path");
50
+ const mediaType = attrValue(child, "manifest:media-type");
51
+ if (fullPath === void 0 || mediaType === void 0) throw new Error(`${require_package_io_write.MANIFEST_PART} has a manifest:file-entry missing manifest:full-path or manifest:media-type`);
52
+ const entryVersion = attrValue(child, "manifest:version");
53
+ entries.push(entryVersion === void 0 ? {
54
+ fullPath,
55
+ mediaType
56
+ } : {
57
+ fullPath,
58
+ mediaType,
59
+ version: entryVersion
60
+ });
61
+ }
62
+ return {
63
+ version,
64
+ entries
65
+ };
66
+ }
67
+ function subdocumentDirectories(partPaths) {
68
+ const dirs = [];
69
+ for (const path of partPaths) if (path.endsWith("/content.xml")) dirs.push(path.slice(0, path.length - 11));
70
+ return dirs;
71
+ }
72
+ function resolvePartMediaType(path, bytes, overrides) {
73
+ const override = overrides?.[path];
74
+ if (override !== void 0) return override;
75
+ const baseName = path.slice(path.lastIndexOf("/") + 1);
76
+ if (STANDARD_XML_PART_NAMES.has(baseName)) return "text/xml";
77
+ const dotIndex = baseName.lastIndexOf(".");
78
+ const extension = dotIndex === -1 ? "" : baseName.slice(dotIndex + 1);
79
+ const byExtension = extension === "" ? void 0 : require_media_type.mediaTypeForExtension(extension);
80
+ if (byExtension !== void 0) return byExtension;
81
+ if (bytes !== void 0) {
82
+ const sniffed = require_image_sniff.sniffImageFormat(bytes);
83
+ if (sniffed === "png") return "image/png";
84
+ if (sniffed === "jpeg") return "image/jpeg";
85
+ }
86
+ return "";
87
+ }
88
+ function buildManifest(pkg, options = {}) {
89
+ const version = options.version ?? DEFAULT_MANIFEST_VERSION;
90
+ const documentMediaType = options.documentMediaType ?? require_mimetype.readMimetype(pkg);
91
+ if (documentMediaType === void 0) throw new Error("buildManifest: package has no \"mimetype\" part and no documentMediaType override was supplied -- the manifest root entry requires a known document media type");
92
+ const entries = [{
93
+ fullPath: "/",
94
+ mediaType: documentMediaType,
95
+ version
96
+ }];
97
+ const partPaths = Object.keys(pkg.parts);
98
+ for (const dir of new Set(subdocumentDirectories(partPaths))) entries.push({
99
+ fullPath: dir,
100
+ mediaType: resolvePartMediaType(dir, void 0, options.mediaTypeOverrides)
101
+ });
102
+ for (const [path, part] of Object.entries(pkg.parts)) {
103
+ if (path === "mimetype" || path === "META-INF/manifest.xml") continue;
104
+ const bytes = part.kind === "binary" ? require_util_base64.base64ToBytes(part.base64) : void 0;
105
+ entries.push({
106
+ fullPath: path,
107
+ mediaType: resolvePartMediaType(path, bytes, options.mediaTypeOverrides)
108
+ });
109
+ }
110
+ return {
111
+ version,
112
+ entries
113
+ };
114
+ }
115
+ function buildManifestNodes(manifest) {
116
+ const fileEntries = manifest.entries.map((entry) => {
117
+ const attrs = { "manifest:full-path": require_xml_entities.encodeXmlText(entry.fullPath) };
118
+ if (entry.version !== void 0) attrs["manifest:version"] = require_xml_entities.encodeXmlText(entry.version);
119
+ attrs["manifest:media-type"] = require_xml_entities.encodeXmlText(entry.mediaType);
120
+ return require_xml_fragment.el("manifest:file-entry", attrs);
121
+ });
122
+ return [{
123
+ type: "declaration",
124
+ attributes: [{
125
+ name: "version",
126
+ value: "1.0"
127
+ }, {
128
+ name: "encoding",
129
+ value: "UTF-8"
130
+ }]
131
+ }, require_xml_fragment.el("manifest:manifest", {
132
+ ...require_ns.xmlnsAttributes(["manifest"]),
133
+ "manifest:version": require_xml_entities.encodeXmlText(manifest.version)
134
+ }, fileEntries)];
135
+ }
136
+ function writeManifest(pkg, manifest) {
137
+ pkg.parts[require_package_io_write.MANIFEST_PART] = {
138
+ kind: "xml",
139
+ nodes: buildManifestNodes(manifest)
140
+ };
141
+ }
142
+ function syncManifest(pkg, options) {
143
+ writeManifest(pkg, buildManifest(pkg, options));
144
+ }
145
+ function validateManifest(pkg) {
146
+ const problems = [];
147
+ const manifestPart = pkg.parts[require_package_io_write.MANIFEST_PART];
148
+ if (manifestPart === void 0) {
149
+ problems.push({
150
+ severity: "error",
151
+ message: `package has no ${require_package_io_write.MANIFEST_PART} part`
152
+ });
153
+ return problems;
154
+ }
155
+ if (manifestPart.kind !== "xml") {
156
+ problems.push({
157
+ severity: "error",
158
+ message: `${require_package_io_write.MANIFEST_PART} part is not XML`
159
+ });
160
+ return problems;
161
+ }
162
+ const root = findChildElement(manifestPart.nodes, "manifest:manifest");
163
+ if (root === void 0) {
164
+ problems.push({
165
+ severity: "error",
166
+ message: `${require_package_io_write.MANIFEST_PART} has no manifest:manifest root element`
167
+ });
168
+ return problems;
169
+ }
170
+ let manifest;
171
+ try {
172
+ manifest = readManifest(pkg);
173
+ } catch (error) {
174
+ problems.push({
175
+ severity: "error",
176
+ message: `failed to parse ${require_package_io_write.MANIFEST_PART}: ${error instanceof Error ? error.message : String(error)}`
177
+ });
178
+ return problems;
179
+ }
180
+ const rootEntry = manifest.entries.find((entry) => entry.fullPath === "/");
181
+ if (rootEntry === void 0) problems.push({
182
+ severity: "error",
183
+ message: "manifest has no root (\"/\") entry"
184
+ });
185
+ else {
186
+ const documentMediaType = require_mimetype.readMimetype(pkg);
187
+ if (documentMediaType !== void 0 && documentMediaType !== rootEntry.mediaType) problems.push({
188
+ severity: "error",
189
+ message: `manifest root entry media type "${rootEntry.mediaType}" does not match the mimetype part's media type "${documentMediaType}"`,
190
+ path: "/"
191
+ });
192
+ }
193
+ const partPaths = new Set(Object.keys(pkg.parts).filter((path) => path !== "mimetype" && path !== "META-INF/manifest.xml"));
194
+ const manifestPaths = new Set(manifest.entries.map((entry) => entry.fullPath));
195
+ for (const entry of manifest.entries) {
196
+ if (entry.fullPath === "/" || entry.fullPath.endsWith("/")) continue;
197
+ if (!partPaths.has(entry.fullPath)) problems.push({
198
+ severity: "warning",
199
+ message: `manifest lists "${entry.fullPath}" but the package has no such part`,
200
+ path: entry.fullPath
201
+ });
202
+ }
203
+ for (const path of partPaths) if (!manifestPaths.has(path)) problems.push({
204
+ severity: "warning",
205
+ message: `package has part "${path}" not listed in the manifest`,
206
+ path
207
+ });
208
+ for (const child of root.children) {
209
+ if (child.type !== "element" || child.tag !== "manifest:file-entry") continue;
210
+ if (!child.children.some((grandchild) => grandchild.type === "element" && grandchild.tag === "manifest:encryption-data")) continue;
211
+ const fullPath = attrValue(child, "manifest:full-path");
212
+ if (fullPath === void 0) continue;
213
+ problems.push({
214
+ severity: "warning",
215
+ message: `entry "${fullPath}" carries manifest:encryption-data -- odf.js does not implement ODF encryption/decryption`,
216
+ path: fullPath
217
+ });
218
+ }
219
+ return problems;
220
+ }
221
+ function setDocumentMediaType(pkg, mediaType, version = DEFAULT_MANIFEST_VERSION) {
222
+ require_mimetype.writeMimetype(pkg, mediaType);
223
+ const rootEntry = {
224
+ fullPath: "/",
225
+ mediaType,
226
+ version
227
+ };
228
+ if (pkg.parts["META-INF/manifest.xml"] === void 0) {
229
+ writeManifest(pkg, {
230
+ version,
231
+ entries: [rootEntry]
232
+ });
233
+ return;
234
+ }
235
+ const existing = readManifest(pkg);
236
+ const rootIndex = existing.entries.findIndex((entry) => entry.fullPath === "/");
237
+ writeManifest(pkg, {
238
+ version,
239
+ entries: rootIndex === -1 ? [rootEntry, ...existing.entries] : existing.entries.map((entry, index) => index === rootIndex ? rootEntry : entry)
240
+ });
241
+ }
242
+ //#endregion
243
+ exports.MANIFEST_PART = require_package_io_write.MANIFEST_PART;
244
+ exports.ManifestEntrySchema = ManifestEntrySchema;
245
+ exports.ManifestProblemSchema = ManifestProblemSchema;
246
+ exports.ManifestSchema = ManifestSchema;
247
+ exports.buildManifest = buildManifest;
248
+ exports.readManifest = readManifest;
249
+ exports.setDocumentMediaType = setDocumentMediaType;
250
+ exports.syncManifest = syncManifest;
251
+ exports.validateManifest = validateManifest;
252
+ exports.writeManifest = writeManifest;
@@ -0,0 +1,41 @@
1
+ import { Package } from "./model/package.cjs";
2
+ import { MANIFEST_PART } from "./package-io/write.cjs";
3
+ import { z } from "zod";
4
+ //#region src/manifest.d.ts
5
+ declare const ManifestEntrySchema: z.ZodObject<{
6
+ fullPath: z.ZodString;
7
+ mediaType: z.ZodString;
8
+ version: z.ZodOptional<z.ZodString>;
9
+ }, z.core.$strip>;
10
+ type ManifestEntry = z.infer<typeof ManifestEntrySchema>;
11
+ declare const ManifestSchema: z.ZodObject<{
12
+ version: z.ZodString;
13
+ entries: z.ZodArray<z.ZodObject<{
14
+ fullPath: z.ZodString;
15
+ mediaType: z.ZodString;
16
+ version: z.ZodOptional<z.ZodString>;
17
+ }, z.core.$strip>>;
18
+ }, z.core.$strip>;
19
+ type Manifest = z.infer<typeof ManifestSchema>;
20
+ declare const ManifestProblemSchema: z.ZodObject<{
21
+ severity: z.ZodEnum<{
22
+ error: "error";
23
+ warning: "warning";
24
+ }>;
25
+ message: z.ZodString;
26
+ path: z.ZodOptional<z.ZodString>;
27
+ }, z.core.$strip>;
28
+ type ManifestProblem = z.infer<typeof ManifestProblemSchema>;
29
+ declare function readManifest(pkg: Package): Manifest;
30
+ interface BuildManifestOptions {
31
+ documentMediaType?: string;
32
+ version?: string;
33
+ mediaTypeOverrides?: Readonly<Record<string, string>>;
34
+ }
35
+ declare function buildManifest(pkg: Package, options?: BuildManifestOptions): Manifest;
36
+ declare function writeManifest(pkg: Package, manifest: Manifest): void;
37
+ declare function syncManifest(pkg: Package, options?: BuildManifestOptions): void;
38
+ declare function validateManifest(pkg: Package): ManifestProblem[];
39
+ declare function setDocumentMediaType(pkg: Package, mediaType: string, version?: string): void;
40
+ //#endregion
41
+ export { BuildManifestOptions, MANIFEST_PART, Manifest, ManifestEntry, ManifestEntrySchema, ManifestProblem, ManifestProblemSchema, ManifestSchema, buildManifest, readManifest, setDocumentMediaType, syncManifest, validateManifest, writeManifest };
@@ -0,0 +1,41 @@
1
+ import { Package } from "./model/package.js";
2
+ import { MANIFEST_PART } from "./package-io/write.js";
3
+ import { z } from "zod";
4
+ //#region src/manifest.d.ts
5
+ declare const ManifestEntrySchema: z.ZodObject<{
6
+ fullPath: z.ZodString;
7
+ mediaType: z.ZodString;
8
+ version: z.ZodOptional<z.ZodString>;
9
+ }, z.core.$strip>;
10
+ type ManifestEntry = z.infer<typeof ManifestEntrySchema>;
11
+ declare const ManifestSchema: z.ZodObject<{
12
+ version: z.ZodString;
13
+ entries: z.ZodArray<z.ZodObject<{
14
+ fullPath: z.ZodString;
15
+ mediaType: z.ZodString;
16
+ version: z.ZodOptional<z.ZodString>;
17
+ }, z.core.$strip>>;
18
+ }, z.core.$strip>;
19
+ type Manifest = z.infer<typeof ManifestSchema>;
20
+ declare const ManifestProblemSchema: z.ZodObject<{
21
+ severity: z.ZodEnum<{
22
+ error: "error";
23
+ warning: "warning";
24
+ }>;
25
+ message: z.ZodString;
26
+ path: z.ZodOptional<z.ZodString>;
27
+ }, z.core.$strip>;
28
+ type ManifestProblem = z.infer<typeof ManifestProblemSchema>;
29
+ declare function readManifest(pkg: Package): Manifest;
30
+ interface BuildManifestOptions {
31
+ documentMediaType?: string;
32
+ version?: string;
33
+ mediaTypeOverrides?: Readonly<Record<string, string>>;
34
+ }
35
+ declare function buildManifest(pkg: Package, options?: BuildManifestOptions): Manifest;
36
+ declare function writeManifest(pkg: Package, manifest: Manifest): void;
37
+ declare function syncManifest(pkg: Package, options?: BuildManifestOptions): void;
38
+ declare function validateManifest(pkg: Package): ManifestProblem[];
39
+ declare function setDocumentMediaType(pkg: Package, mediaType: string, version?: string): void;
40
+ //#endregion
41
+ export { BuildManifestOptions, MANIFEST_PART, Manifest, ManifestEntry, ManifestEntrySchema, ManifestProblem, ManifestProblemSchema, ManifestSchema, buildManifest, readManifest, setDocumentMediaType, syncManifest, validateManifest, writeManifest };
@@ -0,0 +1,242 @@
1
+ import { base64ToBytes } from "./util/base64.js";
2
+ import { MANIFEST_PART } from "./package-io/write.js";
3
+ import { xmlnsAttributes } from "./ns.js";
4
+ import { mediaTypeForExtension } from "./media-type.js";
5
+ import { sniffImageFormat } from "./image/sniff.js";
6
+ import { readMimetype, writeMimetype } from "./mimetype.js";
7
+ import { el } from "./xml/fragment.js";
8
+ import { encodeXmlText } from "./xml/entities.js";
9
+ import { z } from "zod";
10
+ //#region src/manifest.ts
11
+ const ManifestEntrySchema = z.object({
12
+ fullPath: z.string(),
13
+ mediaType: z.string(),
14
+ version: z.string().optional()
15
+ });
16
+ const ManifestSchema = z.object({
17
+ version: z.string(),
18
+ entries: z.array(ManifestEntrySchema)
19
+ });
20
+ const ManifestProblemSchema = z.object({
21
+ severity: z.enum(["error", "warning"]),
22
+ message: z.string(),
23
+ path: z.string().optional()
24
+ });
25
+ const DEFAULT_MANIFEST_VERSION = "1.3";
26
+ const STANDARD_XML_PART_NAMES = /* @__PURE__ */ new Set([
27
+ "content.xml",
28
+ "styles.xml",
29
+ "meta.xml",
30
+ "settings.xml"
31
+ ]);
32
+ function findChildElement(nodes, tag) {
33
+ for (const node of nodes) if (node.type === "element" && node.tag === tag) return node;
34
+ }
35
+ function attrValue(element, name) {
36
+ return element.attributes.find((attribute) => attribute.name === name)?.value;
37
+ }
38
+ function readManifest(pkg) {
39
+ const part = pkg.parts[MANIFEST_PART];
40
+ if (part?.kind !== "xml") throw new Error(`package has no ${MANIFEST_PART} XML part to read`);
41
+ const root = findChildElement(part.nodes, "manifest:manifest");
42
+ if (root === void 0) throw new Error(`${MANIFEST_PART} has no manifest:manifest root element`);
43
+ const version = attrValue(root, "manifest:version");
44
+ if (version === void 0) throw new Error(`${MANIFEST_PART}'s manifest:manifest root is missing the required manifest:version attribute`);
45
+ const entries = [];
46
+ for (const child of root.children) {
47
+ if (child.type !== "element" || child.tag !== "manifest:file-entry") continue;
48
+ const fullPath = attrValue(child, "manifest:full-path");
49
+ const mediaType = attrValue(child, "manifest:media-type");
50
+ if (fullPath === void 0 || mediaType === void 0) throw new Error(`${MANIFEST_PART} has a manifest:file-entry missing manifest:full-path or manifest:media-type`);
51
+ const entryVersion = attrValue(child, "manifest:version");
52
+ entries.push(entryVersion === void 0 ? {
53
+ fullPath,
54
+ mediaType
55
+ } : {
56
+ fullPath,
57
+ mediaType,
58
+ version: entryVersion
59
+ });
60
+ }
61
+ return {
62
+ version,
63
+ entries
64
+ };
65
+ }
66
+ function subdocumentDirectories(partPaths) {
67
+ const dirs = [];
68
+ for (const path of partPaths) if (path.endsWith("/content.xml")) dirs.push(path.slice(0, path.length - 11));
69
+ return dirs;
70
+ }
71
+ function resolvePartMediaType(path, bytes, overrides) {
72
+ const override = overrides?.[path];
73
+ if (override !== void 0) return override;
74
+ const baseName = path.slice(path.lastIndexOf("/") + 1);
75
+ if (STANDARD_XML_PART_NAMES.has(baseName)) return "text/xml";
76
+ const dotIndex = baseName.lastIndexOf(".");
77
+ const extension = dotIndex === -1 ? "" : baseName.slice(dotIndex + 1);
78
+ const byExtension = extension === "" ? void 0 : mediaTypeForExtension(extension);
79
+ if (byExtension !== void 0) return byExtension;
80
+ if (bytes !== void 0) {
81
+ const sniffed = sniffImageFormat(bytes);
82
+ if (sniffed === "png") return "image/png";
83
+ if (sniffed === "jpeg") return "image/jpeg";
84
+ }
85
+ return "";
86
+ }
87
+ function buildManifest(pkg, options = {}) {
88
+ const version = options.version ?? DEFAULT_MANIFEST_VERSION;
89
+ const documentMediaType = options.documentMediaType ?? readMimetype(pkg);
90
+ if (documentMediaType === void 0) throw new Error("buildManifest: package has no \"mimetype\" part and no documentMediaType override was supplied -- the manifest root entry requires a known document media type");
91
+ const entries = [{
92
+ fullPath: "/",
93
+ mediaType: documentMediaType,
94
+ version
95
+ }];
96
+ const partPaths = Object.keys(pkg.parts);
97
+ for (const dir of new Set(subdocumentDirectories(partPaths))) entries.push({
98
+ fullPath: dir,
99
+ mediaType: resolvePartMediaType(dir, void 0, options.mediaTypeOverrides)
100
+ });
101
+ for (const [path, part] of Object.entries(pkg.parts)) {
102
+ if (path === "mimetype" || path === "META-INF/manifest.xml") continue;
103
+ const bytes = part.kind === "binary" ? base64ToBytes(part.base64) : void 0;
104
+ entries.push({
105
+ fullPath: path,
106
+ mediaType: resolvePartMediaType(path, bytes, options.mediaTypeOverrides)
107
+ });
108
+ }
109
+ return {
110
+ version,
111
+ entries
112
+ };
113
+ }
114
+ function buildManifestNodes(manifest) {
115
+ const fileEntries = manifest.entries.map((entry) => {
116
+ const attrs = { "manifest:full-path": encodeXmlText(entry.fullPath) };
117
+ if (entry.version !== void 0) attrs["manifest:version"] = encodeXmlText(entry.version);
118
+ attrs["manifest:media-type"] = encodeXmlText(entry.mediaType);
119
+ return el("manifest:file-entry", attrs);
120
+ });
121
+ return [{
122
+ type: "declaration",
123
+ attributes: [{
124
+ name: "version",
125
+ value: "1.0"
126
+ }, {
127
+ name: "encoding",
128
+ value: "UTF-8"
129
+ }]
130
+ }, el("manifest:manifest", {
131
+ ...xmlnsAttributes(["manifest"]),
132
+ "manifest:version": encodeXmlText(manifest.version)
133
+ }, fileEntries)];
134
+ }
135
+ function writeManifest(pkg, manifest) {
136
+ pkg.parts[MANIFEST_PART] = {
137
+ kind: "xml",
138
+ nodes: buildManifestNodes(manifest)
139
+ };
140
+ }
141
+ function syncManifest(pkg, options) {
142
+ writeManifest(pkg, buildManifest(pkg, options));
143
+ }
144
+ function validateManifest(pkg) {
145
+ const problems = [];
146
+ const manifestPart = pkg.parts[MANIFEST_PART];
147
+ if (manifestPart === void 0) {
148
+ problems.push({
149
+ severity: "error",
150
+ message: `package has no ${MANIFEST_PART} part`
151
+ });
152
+ return problems;
153
+ }
154
+ if (manifestPart.kind !== "xml") {
155
+ problems.push({
156
+ severity: "error",
157
+ message: `${MANIFEST_PART} part is not XML`
158
+ });
159
+ return problems;
160
+ }
161
+ const root = findChildElement(manifestPart.nodes, "manifest:manifest");
162
+ if (root === void 0) {
163
+ problems.push({
164
+ severity: "error",
165
+ message: `${MANIFEST_PART} has no manifest:manifest root element`
166
+ });
167
+ return problems;
168
+ }
169
+ let manifest;
170
+ try {
171
+ manifest = readManifest(pkg);
172
+ } catch (error) {
173
+ problems.push({
174
+ severity: "error",
175
+ message: `failed to parse ${MANIFEST_PART}: ${error instanceof Error ? error.message : String(error)}`
176
+ });
177
+ return problems;
178
+ }
179
+ const rootEntry = manifest.entries.find((entry) => entry.fullPath === "/");
180
+ if (rootEntry === void 0) problems.push({
181
+ severity: "error",
182
+ message: "manifest has no root (\"/\") entry"
183
+ });
184
+ else {
185
+ const documentMediaType = readMimetype(pkg);
186
+ if (documentMediaType !== void 0 && documentMediaType !== rootEntry.mediaType) problems.push({
187
+ severity: "error",
188
+ message: `manifest root entry media type "${rootEntry.mediaType}" does not match the mimetype part's media type "${documentMediaType}"`,
189
+ path: "/"
190
+ });
191
+ }
192
+ const partPaths = new Set(Object.keys(pkg.parts).filter((path) => path !== "mimetype" && path !== "META-INF/manifest.xml"));
193
+ const manifestPaths = new Set(manifest.entries.map((entry) => entry.fullPath));
194
+ for (const entry of manifest.entries) {
195
+ if (entry.fullPath === "/" || entry.fullPath.endsWith("/")) continue;
196
+ if (!partPaths.has(entry.fullPath)) problems.push({
197
+ severity: "warning",
198
+ message: `manifest lists "${entry.fullPath}" but the package has no such part`,
199
+ path: entry.fullPath
200
+ });
201
+ }
202
+ for (const path of partPaths) if (!manifestPaths.has(path)) problems.push({
203
+ severity: "warning",
204
+ message: `package has part "${path}" not listed in the manifest`,
205
+ path
206
+ });
207
+ for (const child of root.children) {
208
+ if (child.type !== "element" || child.tag !== "manifest:file-entry") continue;
209
+ if (!child.children.some((grandchild) => grandchild.type === "element" && grandchild.tag === "manifest:encryption-data")) continue;
210
+ const fullPath = attrValue(child, "manifest:full-path");
211
+ if (fullPath === void 0) continue;
212
+ problems.push({
213
+ severity: "warning",
214
+ message: `entry "${fullPath}" carries manifest:encryption-data -- odf.js does not implement ODF encryption/decryption`,
215
+ path: fullPath
216
+ });
217
+ }
218
+ return problems;
219
+ }
220
+ function setDocumentMediaType(pkg, mediaType, version = DEFAULT_MANIFEST_VERSION) {
221
+ writeMimetype(pkg, mediaType);
222
+ const rootEntry = {
223
+ fullPath: "/",
224
+ mediaType,
225
+ version
226
+ };
227
+ if (pkg.parts["META-INF/manifest.xml"] === void 0) {
228
+ writeManifest(pkg, {
229
+ version,
230
+ entries: [rootEntry]
231
+ });
232
+ return;
233
+ }
234
+ const existing = readManifest(pkg);
235
+ const rootIndex = existing.entries.findIndex((entry) => entry.fullPath === "/");
236
+ writeManifest(pkg, {
237
+ version,
238
+ entries: rootIndex === -1 ? [rootEntry, ...existing.entries] : existing.entries.map((entry, index) => index === rootIndex ? rootEntry : entry)
239
+ });
240
+ }
241
+ //#endregion
242
+ export { MANIFEST_PART, ManifestEntrySchema, ManifestProblemSchema, ManifestSchema, buildManifest, readManifest, setDocumentMediaType, syncManifest, validateManifest, writeManifest };
@@ -0,0 +1,27 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/media-type.ts
3
+ const ODF_MEDIA_TYPES = Object.freeze({
4
+ odt: "application/vnd.oasis.opendocument.text",
5
+ ott: "application/vnd.oasis.opendocument.text-template",
6
+ ods: "application/vnd.oasis.opendocument.spreadsheet",
7
+ ots: "application/vnd.oasis.opendocument.spreadsheet-template",
8
+ odp: "application/vnd.oasis.opendocument.presentation",
9
+ otp: "application/vnd.oasis.opendocument.presentation-template",
10
+ odg: "application/vnd.oasis.opendocument.graphics",
11
+ otg: "application/vnd.oasis.opendocument.graphics-template",
12
+ odf: "application/vnd.oasis.opendocument.formula",
13
+ otf: "application/vnd.oasis.opendocument.formula-template",
14
+ odm: "application/vnd.oasis.opendocument.text-master",
15
+ otm: "application/vnd.oasis.opendocument.text-master-template",
16
+ odb: "application/vnd.oasis.opendocument.base"
17
+ });
18
+ function isOdfExtension(extension) {
19
+ return Object.hasOwn(ODF_MEDIA_TYPES, extension);
20
+ }
21
+ function mediaTypeForExtension(extension) {
22
+ const lower = extension.toLowerCase();
23
+ return isOdfExtension(lower) ? ODF_MEDIA_TYPES[lower] : void 0;
24
+ }
25
+ //#endregion
26
+ exports.ODF_MEDIA_TYPES = ODF_MEDIA_TYPES;
27
+ exports.mediaTypeForExtension = mediaTypeForExtension;
@@ -0,0 +1,20 @@
1
+ //#region src/media-type.d.ts
2
+ declare const ODF_MEDIA_TYPES: Readonly<{
3
+ odt: "application/vnd.oasis.opendocument.text";
4
+ ott: "application/vnd.oasis.opendocument.text-template";
5
+ ods: "application/vnd.oasis.opendocument.spreadsheet";
6
+ ots: "application/vnd.oasis.opendocument.spreadsheet-template";
7
+ odp: "application/vnd.oasis.opendocument.presentation";
8
+ otp: "application/vnd.oasis.opendocument.presentation-template";
9
+ odg: "application/vnd.oasis.opendocument.graphics";
10
+ otg: "application/vnd.oasis.opendocument.graphics-template";
11
+ odf: "application/vnd.oasis.opendocument.formula";
12
+ otf: "application/vnd.oasis.opendocument.formula-template";
13
+ odm: "application/vnd.oasis.opendocument.text-master";
14
+ otm: "application/vnd.oasis.opendocument.text-master-template";
15
+ odb: "application/vnd.oasis.opendocument.base";
16
+ }>;
17
+ type OdfExtension = keyof typeof ODF_MEDIA_TYPES;
18
+ declare function mediaTypeForExtension(extension: string): string | undefined;
19
+ //#endregion
20
+ export { ODF_MEDIA_TYPES, OdfExtension, mediaTypeForExtension };
@@ -0,0 +1,20 @@
1
+ //#region src/media-type.d.ts
2
+ declare const ODF_MEDIA_TYPES: Readonly<{
3
+ odt: "application/vnd.oasis.opendocument.text";
4
+ ott: "application/vnd.oasis.opendocument.text-template";
5
+ ods: "application/vnd.oasis.opendocument.spreadsheet";
6
+ ots: "application/vnd.oasis.opendocument.spreadsheet-template";
7
+ odp: "application/vnd.oasis.opendocument.presentation";
8
+ otp: "application/vnd.oasis.opendocument.presentation-template";
9
+ odg: "application/vnd.oasis.opendocument.graphics";
10
+ otg: "application/vnd.oasis.opendocument.graphics-template";
11
+ odf: "application/vnd.oasis.opendocument.formula";
12
+ otf: "application/vnd.oasis.opendocument.formula-template";
13
+ odm: "application/vnd.oasis.opendocument.text-master";
14
+ otm: "application/vnd.oasis.opendocument.text-master-template";
15
+ odb: "application/vnd.oasis.opendocument.base";
16
+ }>;
17
+ type OdfExtension = keyof typeof ODF_MEDIA_TYPES;
18
+ declare function mediaTypeForExtension(extension: string): string | undefined;
19
+ //#endregion
20
+ export { ODF_MEDIA_TYPES, OdfExtension, mediaTypeForExtension };
@@ -0,0 +1,25 @@
1
+ //#region src/media-type.ts
2
+ const ODF_MEDIA_TYPES = Object.freeze({
3
+ odt: "application/vnd.oasis.opendocument.text",
4
+ ott: "application/vnd.oasis.opendocument.text-template",
5
+ ods: "application/vnd.oasis.opendocument.spreadsheet",
6
+ ots: "application/vnd.oasis.opendocument.spreadsheet-template",
7
+ odp: "application/vnd.oasis.opendocument.presentation",
8
+ otp: "application/vnd.oasis.opendocument.presentation-template",
9
+ odg: "application/vnd.oasis.opendocument.graphics",
10
+ otg: "application/vnd.oasis.opendocument.graphics-template",
11
+ odf: "application/vnd.oasis.opendocument.formula",
12
+ otf: "application/vnd.oasis.opendocument.formula-template",
13
+ odm: "application/vnd.oasis.opendocument.text-master",
14
+ otm: "application/vnd.oasis.opendocument.text-master-template",
15
+ odb: "application/vnd.oasis.opendocument.base"
16
+ });
17
+ function isOdfExtension(extension) {
18
+ return Object.hasOwn(ODF_MEDIA_TYPES, extension);
19
+ }
20
+ function mediaTypeForExtension(extension) {
21
+ const lower = extension.toLowerCase();
22
+ return isOdfExtension(lower) ? ODF_MEDIA_TYPES[lower] : void 0;
23
+ }
24
+ //#endregion
25
+ export { ODF_MEDIA_TYPES, mediaTypeForExtension };