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.
- package/README.md +39 -0
- package/dist/codec.cjs +28 -0
- package/dist/codec.d.cts +72 -0
- package/dist/codec.d.ts +72 -0
- package/dist/codec.js +24 -0
- package/dist/image/sniff.cjs +28 -0
- package/dist/image/sniff.d.cts +5 -0
- package/dist/image/sniff.d.ts +5 -0
- package/dist/image/sniff.js +27 -0
- package/dist/index.cjs +156 -3242
- package/dist/index.d.cts +42 -679
- package/dist/index.d.ts +42 -679
- package/dist/index.js +42 -3129
- package/dist/manifest.cjs +252 -0
- package/dist/manifest.d.cts +41 -0
- package/dist/manifest.d.ts +41 -0
- package/dist/manifest.js +242 -0
- package/dist/media-type.cjs +27 -0
- package/dist/media-type.d.cts +20 -0
- package/dist/media-type.d.ts +20 -0
- package/dist/media-type.js +25 -0
- package/dist/mimetype.cjs +19 -0
- package/dist/mimetype.d.cts +7 -0
- package/dist/mimetype.d.ts +7 -0
- package/dist/mimetype.js +16 -0
- package/dist/model/node.cjs +67 -0
- package/dist/model/node.d.cts +2 -0
- package/dist/model/node.d.ts +2 -0
- package/dist/model/node.js +58 -0
- package/dist/model/package.cjs +19 -0
- package/dist/model/package.d.cts +114 -0
- package/dist/model/package.d.ts +114 -0
- package/dist/model/package.js +15 -0
- package/dist/node-CkBWRjNR.d.cts +83 -0
- package/dist/node-CkBWRjNR.d.ts +83 -0
- package/dist/ns.cjs +37 -0
- package/dist/ns.d.cts +32 -0
- package/dist/ns.d.ts +32 -0
- package/dist/ns.js +35 -0
- package/dist/package-io/read.cjs +35 -0
- package/dist/package-io/read.d.cts +5 -0
- package/dist/package-io/read.d.ts +5 -0
- package/dist/package-io/read.js +34 -0
- package/dist/package-io/write.cjs +36 -0
- package/dist/package-io/write.d.cts +7 -0
- package/dist/package-io/write.d.ts +7 -0
- package/dist/package-io/write.js +33 -0
- package/dist/styles/properties.cjs +286 -0
- package/dist/styles/properties.d.cts +45 -0
- package/dist/styles/properties.d.ts +45 -0
- package/dist/styles/properties.js +277 -0
- package/dist/styles/registry.cjs +212 -0
- package/dist/styles/registry.d.cts +37 -0
- package/dist/styles/registry.d.ts +37 -0
- package/dist/styles/registry.js +209 -0
- package/dist/styles/serialize.cjs +23 -0
- package/dist/styles/serialize.d.cts +7 -0
- package/dist/styles/serialize.d.ts +7 -0
- package/dist/styles/serialize.js +21 -0
- package/dist/styles/span.cjs +114 -0
- package/dist/styles/span.d.cts +5 -0
- package/dist/styles/span.d.ts +5 -0
- package/dist/styles/span.js +113 -0
- package/dist/typed/draw/shapes.cjs +314 -0
- package/dist/typed/draw/shapes.d.cts +14 -0
- package/dist/typed/draw/shapes.d.ts +14 -0
- package/dist/typed/draw/shapes.js +311 -0
- package/dist/typed/formula/read.cjs +48 -0
- package/dist/typed/formula/read.d.cts +12 -0
- package/dist/typed/formula/read.d.ts +12 -0
- package/dist/typed/formula/read.js +47 -0
- package/dist/typed/odb/read.cjs +112 -0
- package/dist/typed/odb/read.d.cts +17 -0
- package/dist/typed/odb/read.d.ts +17 -0
- package/dist/typed/odb/read.js +111 -0
- package/dist/typed/odg/read.cjs +30 -0
- package/dist/typed/odg/read.d.cts +10 -0
- package/dist/typed/odg/read.d.ts +10 -0
- package/dist/typed/odg/read.js +29 -0
- package/dist/typed/odm/read.cjs +37 -0
- package/dist/typed/odm/read.d.cts +15 -0
- package/dist/typed/odm/read.d.ts +15 -0
- package/dist/typed/odm/read.js +36 -0
- package/dist/typed/odp/read.cjs +39 -0
- package/dist/typed/odp/read.d.cts +10 -0
- package/dist/typed/odp/read.d.ts +10 -0
- package/dist/typed/odp/read.js +38 -0
- package/dist/typed/ods/read.cjs +318 -0
- package/dist/typed/ods/read.d.cts +10 -0
- package/dist/typed/ods/read.d.ts +10 -0
- package/dist/typed/ods/read.js +317 -0
- package/dist/typed/odt/read.cjs +112 -0
- package/dist/typed/odt/read.d.cts +10 -0
- package/dist/typed/odt/read.d.ts +10 -0
- package/dist/typed/odt/read.js +111 -0
- package/dist/typed/shared/a1.cjs +68 -0
- package/dist/typed/shared/a1.d.cts +18 -0
- package/dist/typed/shared/a1.d.ts +18 -0
- package/dist/typed/shared/a1.js +63 -0
- package/dist/typed/shared/cascade.cjs +102 -0
- package/dist/typed/shared/cascade.d.cts +22 -0
- package/dist/typed/shared/cascade.d.ts +22 -0
- package/dist/typed/shared/cascade.js +99 -0
- package/dist/typed/shared/color.cjs +14 -0
- package/dist/typed/shared/color.d.cts +6 -0
- package/dist/typed/shared/color.d.ts +6 -0
- package/dist/typed/shared/color.js +12 -0
- package/dist/typed/shared/geometry.cjs +79 -0
- package/dist/typed/shared/geometry.d.cts +12 -0
- package/dist/typed/shared/geometry.d.ts +12 -0
- package/dist/typed/shared/geometry.js +75 -0
- package/dist/typed/shared/masterpage.cjs +39 -0
- package/dist/typed/shared/masterpage.d.cts +8 -0
- package/dist/typed/shared/masterpage.d.ts +8 -0
- package/dist/typed/shared/masterpage.js +37 -0
- package/dist/typed/shared/metadata.cjs +42 -0
- package/dist/typed/shared/metadata.d.cts +7 -0
- package/dist/typed/shared/metadata.d.ts +7 -0
- package/dist/typed/shared/metadata.js +40 -0
- package/dist/typed/shared/paragraph.cjs +57 -0
- package/dist/typed/shared/paragraph.d.cts +7 -0
- package/dist/typed/shared/paragraph.d.ts +7 -0
- package/dist/typed/shared/paragraph.js +56 -0
- package/dist/typed/shared/path.cjs +261 -0
- package/dist/typed/shared/path.d.cts +34 -0
- package/dist/typed/shared/path.d.ts +34 -0
- package/dist/typed/shared/path.js +255 -0
- package/dist/typed/shared/style.cjs +8 -0
- package/dist/typed/shared/style.d.cts +2 -0
- package/dist/typed/shared/style.d.ts +2 -0
- package/dist/typed/shared/style.js +2 -0
- package/dist/typed/shared/table.cjs +84 -0
- package/dist/typed/shared/table.d.cts +7 -0
- package/dist/typed/shared/table.d.ts +7 -0
- package/dist/typed/shared/table.js +83 -0
- package/dist/typed/shared/text.cjs +43 -0
- package/dist/typed/shared/text.d.cts +8 -0
- package/dist/typed/shared/text.d.ts +8 -0
- package/dist/typed/shared/text.js +39 -0
- package/dist/typed/shared/transform.cjs +112 -0
- package/dist/typed/shared/transform.d.cts +26 -0
- package/dist/typed/shared/transform.d.ts +26 -0
- package/dist/typed/shared/transform.js +107 -0
- package/dist/typed/shared/units.cjs +35 -0
- package/dist/typed/shared/units.d.cts +2 -0
- package/dist/typed/shared/units.d.ts +2 -0
- package/dist/typed/shared/units.js +33 -0
- package/dist/units-7pCiECuP.d.cts +6 -0
- package/dist/units-7pCiECuP.d.ts +6 -0
- package/dist/util/base64.cjs +48 -0
- package/dist/util/base64.d.cts +5 -0
- package/dist/util/base64.d.ts +5 -0
- package/dist/util/base64.js +46 -0
- package/dist/xml/build.cjs +46 -0
- package/dist/xml/build.d.cts +5 -0
- package/dist/xml/build.d.ts +5 -0
- package/dist/xml/build.js +46 -0
- package/dist/xml/entities.cjs +19 -0
- package/dist/xml/entities.d.cts +5 -0
- package/dist/xml/entities.d.ts +5 -0
- package/dist/xml/entities.js +17 -0
- package/dist/xml/fragment.cjs +22 -0
- package/dist/xml/fragment.d.cts +6 -0
- package/dist/xml/fragment.d.ts +6 -0
- package/dist/xml/fragment.js +20 -0
- package/dist/xml/parse.cjs +88 -0
- package/dist/xml/parse.d.cts +5 -0
- package/dist/xml/parse.d.ts +5 -0
- package/dist/xml/parse.js +88 -0
- package/dist/xml/query.cjs +33 -0
- package/dist/xml/query.d.cts +9 -0
- package/dist/xml/query.d.ts +9 -0
- package/dist/xml/query.js +28 -0
- package/dist/zip.cjs +15 -0
- package/dist/zip.d.cts +9 -0
- package/dist/zip.d.ts +9 -0
- package/dist/zip.js +13 -0
- 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 };
|
package/dist/manifest.js
ADDED
|
@@ -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 };
|