@office-kit/pptx-editor 0.1.0 → 0.2.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 +34 -1
- package/dist/{agent-tools-emRGeP2H.js → agent-tools-EU7Eb-FV.js} +167 -32
- package/dist/agent-tools-EU7Eb-FV.js.map +1 -0
- package/dist/agent-tools-bDB2Jq41.d.ts +28 -0
- package/dist/{deck-merge-XZc2oNxd.js → deck-merge-Dj_XHQQM.js} +210 -23
- package/dist/deck-merge-Dj_XHQQM.js.map +1 -0
- package/dist/headless.d.ts +55 -0
- package/dist/headless.js +232 -0
- package/dist/headless.js.map +1 -0
- package/dist/{index-BFQN6sI6.d.ts → index-cdzLrufG.d.ts} +3 -26
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.js +1 -1
- package/dist/merge.js +1 -1
- package/dist/shape-ref-B5iNfYWh.js +109 -0
- package/dist/shape-ref-B5iNfYWh.js.map +1 -0
- package/dist/{src-iNPXxN6v.js → src-CJWOpCx6.js} +27 -110
- package/dist/src-CJWOpCx6.js.map +1 -0
- package/package.json +7 -3
- package/dist/agent-tools-emRGeP2H.js.map +0 -1
- package/dist/deck-merge-XZc2oNxd.js.map +0 -1
- package/dist/src-iNPXxN6v.js.map +0 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PresentationData, SlideShapeData } from "@office-kit/pptx";
|
|
2
|
+
|
|
3
|
+
//#region src/core/agent-tools.d.ts
|
|
4
|
+
/** A JSON value: what a tool takes as input and gives back. */
|
|
5
|
+
type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
|
|
6
|
+
readonly [key: string]: JsonValue;
|
|
7
|
+
};
|
|
8
|
+
/** A JSON Schema (draft 2020-12) object. */
|
|
9
|
+
type JsonSchema = {
|
|
10
|
+
readonly [key: string]: JsonValue;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* A tool definition in the shape model APIs take: Anthropic's `tools` entries
|
|
14
|
+
* as they are; for OpenAI, `{ type: 'function', function: { name, description,
|
|
15
|
+
* parameters: input_schema } }`.
|
|
16
|
+
*/
|
|
17
|
+
interface EditorTool {
|
|
18
|
+
/** The `@office-kit/pptx` export it calls, or a read tool's name. */
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly description: string;
|
|
21
|
+
/** The input, as a self-contained JSON Schema (draft 2020-12) object. */
|
|
22
|
+
readonly input_schema: JsonSchema & {
|
|
23
|
+
readonly type: "object";
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { JsonSchema as n, JsonValue as r, EditorTool as t };
|
|
28
|
+
//# sourceMappingURL=agent-tools-bDB2Jq41.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { strFromU8, strToU8,
|
|
1
|
+
import { Inflate, inflateSync, strFromU8, strToU8, zipSync } from "fflate";
|
|
2
2
|
//#region ../../src/internal/opc/zip.ts
|
|
3
3
|
const STORE_BY_EXTENSION = new Set([
|
|
4
4
|
"png",
|
|
@@ -36,20 +36,173 @@ const extensionOf = (name) => {
|
|
|
36
36
|
* negligible savings.
|
|
37
37
|
*/
|
|
38
38
|
const shouldStore = (name) => STORE_BY_EXTENSION.has(extensionOf(name));
|
|
39
|
+
const SIG_LOCAL_HEADER = 67324752;
|
|
40
|
+
const SIG_CENTRAL_HEADER = 33639248;
|
|
41
|
+
const SIG_EOCD = 101010256;
|
|
42
|
+
const SIG_ZIP64_EOCD = 101075792;
|
|
43
|
+
const SIG_ZIP64_LOCATOR = 117853008;
|
|
44
|
+
const EOCD_SIZE = 22;
|
|
45
|
+
const MAX_COMMENT_LENGTH = 65535;
|
|
46
|
+
const ZIP64_LOCATOR_SIZE = 20;
|
|
47
|
+
const ZIP64_EOCD_MIN_SIZE = 56;
|
|
48
|
+
const CENTRAL_HEADER_SIZE = 46;
|
|
49
|
+
const LOCAL_HEADER_SIZE = 30;
|
|
50
|
+
const ZIP64_EXTRA_ID = 1;
|
|
51
|
+
const ZIP64_SENTINEL_32 = 4294967295;
|
|
52
|
+
const FLAG_UTF8 = 2048;
|
|
53
|
+
const METHOD_STORE = 0;
|
|
54
|
+
const METHOD_DEFLATE = 8;
|
|
55
|
+
const INFLATE_CHUNK_SIZE = 16 * 1024;
|
|
56
|
+
const MAX_DEFLATE_RATIO = 1032;
|
|
57
|
+
const DEFLATE_RATIO_SLACK = 1024;
|
|
58
|
+
const invalid = (reason) => /* @__PURE__ */ new Error(`invalid ZIP: ${reason}`);
|
|
59
|
+
const u16 = (d, at) => d[at] | d[at + 1] << 8;
|
|
60
|
+
const u32 = (d, at) => (d[at] | d[at + 1] << 8 | d[at + 2] << 16 | d[at + 3] << 24) >>> 0;
|
|
61
|
+
const u64 = (d, at) => {
|
|
62
|
+
const value = u32(d, at) + u32(d, at + 4) * 2 ** 32;
|
|
63
|
+
if (!Number.isSafeInteger(value)) throw invalid("ZIP64 value out of range");
|
|
64
|
+
return value;
|
|
65
|
+
};
|
|
66
|
+
const requireRange = (d, at, length, what) => {
|
|
67
|
+
if (at < 0 || length < 0 || at + length > d.length) throw invalid(`${what} is out of bounds`);
|
|
68
|
+
};
|
|
69
|
+
const findEocd = (d) => {
|
|
70
|
+
const lowest = Math.max(0, d.length - EOCD_SIZE - MAX_COMMENT_LENGTH);
|
|
71
|
+
for (let at = d.length - EOCD_SIZE; at >= lowest; at--) if (u32(d, at) === SIG_EOCD) return at;
|
|
72
|
+
throw invalid("end of central directory not found");
|
|
73
|
+
};
|
|
74
|
+
const readCentralDirectoryLocation = (d) => {
|
|
75
|
+
const eocd = findEocd(d);
|
|
76
|
+
const locator = eocd - ZIP64_LOCATOR_SIZE;
|
|
77
|
+
if (locator >= 0 && u32(d, locator) === SIG_ZIP64_LOCATOR) {
|
|
78
|
+
const zip64Eocd = u32(d, locator + 8) + u32(d, locator + 12) * 2 ** 32;
|
|
79
|
+
if (zip64Eocd + ZIP64_EOCD_MIN_SIZE <= d.length && u32(d, zip64Eocd) === SIG_ZIP64_EOCD) return {
|
|
80
|
+
count: u64(d, zip64Eocd + 32),
|
|
81
|
+
offset: u64(d, zip64Eocd + 48)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
count: u16(d, eocd + 10),
|
|
86
|
+
offset: u32(d, eocd + 16)
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
const resolveZip64Sizes = (d, extraStart, extraEnd, sizes) => {
|
|
90
|
+
const needUncompressed = sizes.uncompressedSize === ZIP64_SENTINEL_32;
|
|
91
|
+
const needCompressed = sizes.compressedSize === ZIP64_SENTINEL_32;
|
|
92
|
+
const needOffset = sizes.localHeaderOffset === ZIP64_SENTINEL_32;
|
|
93
|
+
if (!needUncompressed && !needCompressed && !needOffset) return sizes;
|
|
94
|
+
for (let at = extraStart; at + 4 <= extraEnd; at += 4 + u16(d, at + 2)) {
|
|
95
|
+
if (u16(d, at) !== ZIP64_EXTRA_ID) continue;
|
|
96
|
+
const fieldEnd = at + 4 + u16(d, at + 2);
|
|
97
|
+
if (fieldEnd > extraEnd) break;
|
|
98
|
+
let cursor = at + 4;
|
|
99
|
+
const next = () => {
|
|
100
|
+
if (cursor + 8 > fieldEnd) throw invalid("ZIP64 extra field is truncated");
|
|
101
|
+
const value = u64(d, cursor);
|
|
102
|
+
cursor += 8;
|
|
103
|
+
return value;
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
uncompressedSize: needUncompressed ? next() : sizes.uncompressedSize,
|
|
107
|
+
compressedSize: needCompressed ? next() : sizes.compressedSize,
|
|
108
|
+
localHeaderOffset: needOffset ? next() : sizes.localHeaderOffset
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
throw invalid("ZIP64 sizes without a ZIP64 extra field");
|
|
112
|
+
};
|
|
113
|
+
const overflowError = (name, declaredSize) => invalid(`entry "${name}" inflates beyond its declared size of ${declaredSize} bytes`);
|
|
114
|
+
const corruptError = (name, error) => {
|
|
115
|
+
return invalid(`entry "${name}" is not valid DEFLATE data: ${error instanceof Error ? error.message : String(error)}`);
|
|
116
|
+
};
|
|
117
|
+
const inflateSmallEntry = (compressed, declaredSize, name) => {
|
|
118
|
+
if (compressed.length === 0) return new Uint8Array(0);
|
|
119
|
+
let out;
|
|
120
|
+
try {
|
|
121
|
+
out = inflateSync(compressed, { out: new Uint8Array(declaredSize + 1) });
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (error instanceof RangeError) throw overflowError(name, declaredSize);
|
|
124
|
+
throw corruptError(name, error);
|
|
125
|
+
}
|
|
126
|
+
if (out.length > declaredSize) throw overflowError(name, declaredSize);
|
|
127
|
+
return out;
|
|
128
|
+
};
|
|
129
|
+
const inflateLargeEntry = (compressed, declaredSize, name) => {
|
|
130
|
+
const out = new Uint8Array(declaredSize);
|
|
131
|
+
let overflowed = false;
|
|
132
|
+
let produced = 0;
|
|
133
|
+
const inflater = new Inflate((chunk) => {
|
|
134
|
+
if (produced + chunk.length > declaredSize) {
|
|
135
|
+
overflowed = true;
|
|
136
|
+
throw overflowError(name, declaredSize);
|
|
137
|
+
}
|
|
138
|
+
out.set(chunk, produced);
|
|
139
|
+
produced += chunk.length;
|
|
140
|
+
});
|
|
141
|
+
for (let at = 0; at < compressed.length; at += INFLATE_CHUNK_SIZE) {
|
|
142
|
+
const end = Math.min(at + INFLATE_CHUNK_SIZE, compressed.length);
|
|
143
|
+
try {
|
|
144
|
+
inflater.push(compressed.subarray(at, end), end === compressed.length);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (overflowed) throw error;
|
|
147
|
+
throw corruptError(name, error);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return out.subarray(0, produced);
|
|
151
|
+
};
|
|
152
|
+
const inflateEntry = (compressed, declaredSize, name) => {
|
|
153
|
+
if (declaredSize > compressed.length * MAX_DEFLATE_RATIO + DEFLATE_RATIO_SLACK) throw invalid(`entry "${name}" declares ${declaredSize} bytes, more than ${compressed.length} compressed bytes can hold`);
|
|
154
|
+
const out = compressed.length <= INFLATE_CHUNK_SIZE ? inflateSmallEntry(compressed, declaredSize, name) : inflateLargeEntry(compressed, declaredSize, name);
|
|
155
|
+
if (out.length !== declaredSize) throw invalid(`entry "${name}" inflates to ${out.length} bytes, not its declared ${declaredSize}`);
|
|
156
|
+
return out;
|
|
157
|
+
};
|
|
39
158
|
/**
|
|
40
159
|
* Reads a ZIP archive (a `.pptx` file is a ZIP) and returns entries in
|
|
41
|
-
* central-directory order. Throws if `input` is not a valid ZIP
|
|
160
|
+
* central-directory order. Throws if `input` is not a valid ZIP, if two
|
|
161
|
+
* entries share a name, or if an entry's data does not match the size its
|
|
162
|
+
* central-directory record declares.
|
|
42
163
|
*/
|
|
43
164
|
const readZip = (input) => {
|
|
44
|
-
const
|
|
165
|
+
const { offset, count } = readCentralDirectoryLocation(input);
|
|
45
166
|
const entries = [];
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
167
|
+
const seen = /* @__PURE__ */ new Set();
|
|
168
|
+
let cursor = offset;
|
|
169
|
+
for (let i = 0; i < count; i++) {
|
|
170
|
+
requireRange(input, cursor, CENTRAL_HEADER_SIZE, "central directory");
|
|
171
|
+
if (u32(input, cursor) !== SIG_CENTRAL_HEADER) throw invalid("bad central directory signature");
|
|
172
|
+
const flags = u16(input, cursor + 8);
|
|
173
|
+
const method = u16(input, cursor + 10);
|
|
174
|
+
const nameLength = u16(input, cursor + 28);
|
|
175
|
+
const extraLength = u16(input, cursor + 30);
|
|
176
|
+
const commentLength = u16(input, cursor + 32);
|
|
177
|
+
const nameStart = cursor + CENTRAL_HEADER_SIZE;
|
|
178
|
+
const extraStart = nameStart + nameLength;
|
|
179
|
+
const recordEnd = extraStart + extraLength + commentLength;
|
|
180
|
+
requireRange(input, cursor, recordEnd - cursor, "central directory");
|
|
181
|
+
const name = strFromU8(input.subarray(nameStart, extraStart), (flags & FLAG_UTF8) === 0);
|
|
182
|
+
const { compressedSize, uncompressedSize, localHeaderOffset } = resolveZip64Sizes(input, extraStart, extraStart + extraLength, {
|
|
183
|
+
compressedSize: u32(input, cursor + 20),
|
|
184
|
+
uncompressedSize: u32(input, cursor + 24),
|
|
185
|
+
localHeaderOffset: u32(input, cursor + 42)
|
|
186
|
+
});
|
|
187
|
+
cursor = recordEnd;
|
|
188
|
+
if (seen.has(name)) throw invalid(`duplicate entry "${name}"`);
|
|
189
|
+
seen.add(name);
|
|
190
|
+
requireRange(input, localHeaderOffset, LOCAL_HEADER_SIZE, `local header of "${name}"`);
|
|
191
|
+
if (u32(input, localHeaderOffset) !== SIG_LOCAL_HEADER) throw invalid(`bad local header signature for "${name}"`);
|
|
192
|
+
const dataStart = localHeaderOffset + LOCAL_HEADER_SIZE + u16(input, localHeaderOffset + 26) + u16(input, localHeaderOffset + 28);
|
|
193
|
+
requireRange(input, dataStart, compressedSize, `data of "${name}"`);
|
|
194
|
+
const compressed = input.subarray(dataStart, dataStart + compressedSize);
|
|
195
|
+
if (method === METHOD_STORE) {
|
|
196
|
+
if (compressedSize !== uncompressedSize) throw invalid(`stored entry "${name}" has mismatched sizes`);
|
|
197
|
+
entries.push({
|
|
198
|
+
name,
|
|
199
|
+
data: compressed.slice()
|
|
200
|
+
});
|
|
201
|
+
} else if (method === METHOD_DEFLATE) entries.push({
|
|
50
202
|
name,
|
|
51
|
-
data
|
|
203
|
+
data: inflateEntry(compressed, uncompressedSize, name)
|
|
52
204
|
});
|
|
205
|
+
else throw invalid(`entry "${name}" uses unsupported compression method ${method}`);
|
|
53
206
|
}
|
|
54
207
|
return { entries };
|
|
55
208
|
};
|
|
@@ -102,7 +255,7 @@ const dirname = (name) => {
|
|
|
102
255
|
};
|
|
103
256
|
/**
|
|
104
257
|
* Resolves a relationship Target (which may be relative) against a base part
|
|
105
|
-
* name. Returns the absolute part name (always starts with `/`).
|
|
258
|
+
* name, or against `PACKAGE_ROOT` for a package-root relationship. Returns the absolute part name (always starts with `/`).
|
|
106
259
|
*
|
|
107
260
|
* `target` is from a Relationship element's `Target` attribute when
|
|
108
261
|
* `TargetMode="Internal"`. External targets must not be passed through here.
|
|
@@ -110,7 +263,7 @@ const dirname = (name) => {
|
|
|
110
263
|
const resolveTarget = (basePart, target) => {
|
|
111
264
|
if (target === "") throw new Error("relationship target is empty");
|
|
112
265
|
if (target.startsWith("/")) return partName(target);
|
|
113
|
-
const baseDir = dirname(basePart);
|
|
266
|
+
const baseDir = basePart === "/" ? "/" : dirname(basePart);
|
|
114
267
|
const stack = baseDir === "/" ? [] : baseDir.slice(1).split("/");
|
|
115
268
|
for (const segment of target.split("/")) {
|
|
116
269
|
if (segment === "" || segment === ".") continue;
|
|
@@ -561,13 +714,46 @@ const rawName = (prefix, localName) => prefix === "" ? localName : `${prefix}:${
|
|
|
561
714
|
const writeAttr = (a) => {
|
|
562
715
|
return ` ${rawName(a.name.prefix, a.name.localName)}="${escapeAttr(a.value)}"`;
|
|
563
716
|
};
|
|
564
|
-
const
|
|
717
|
+
const DOCUMENT_SCOPE = new Map([["xml", NS.xml]]);
|
|
718
|
+
const missingDecls = (e, scope) => {
|
|
719
|
+
let added = null;
|
|
720
|
+
for (let i = -1; i < e.attrs.length; i++) {
|
|
721
|
+
const name = i < 0 ? e.name : e.attrs[i].name;
|
|
722
|
+
if (i >= 0 && name.prefix === "") continue;
|
|
723
|
+
const own = e.prefixDecls.get(name.prefix) ?? added?.get(name.prefix);
|
|
724
|
+
if (own === void 0) {
|
|
725
|
+
if ((scope.get(name.prefix) ?? "") === name.namespaceURI) continue;
|
|
726
|
+
added ??= /* @__PURE__ */ new Map();
|
|
727
|
+
added.set(name.prefix, name.namespaceURI);
|
|
728
|
+
} else if (own !== name.namespaceURI) throw new Error(`prefix "${name.prefix}" on <${rawName(e.name.prefix, e.name.localName)}> is bound to both ${own} and ${name.namespaceURI}`);
|
|
729
|
+
}
|
|
730
|
+
return added;
|
|
731
|
+
};
|
|
732
|
+
const writeDecls = (decls, parts) => {
|
|
733
|
+
for (const [prefix, uri] of decls) {
|
|
734
|
+
const decl = prefix === "" ? "xmlns" : `xmlns:${prefix}`;
|
|
735
|
+
parts.push(` ${decl}="${escapeAttr(uri)}"`);
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
const withDecls = (scope, decls) => {
|
|
739
|
+
if (decls.size === 0) return scope;
|
|
740
|
+
const next = new Map(scope);
|
|
741
|
+
for (const [prefix, uri] of decls) next.set(prefix, uri);
|
|
742
|
+
return next;
|
|
743
|
+
};
|
|
744
|
+
const writeElement = (e, parts, scope) => {
|
|
565
745
|
const name = rawName(e.name.prefix, e.name.localName);
|
|
566
746
|
parts.push("<");
|
|
567
747
|
parts.push(name);
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
748
|
+
writeDecls(e.prefixDecls, parts);
|
|
749
|
+
let childScope = scope;
|
|
750
|
+
if (scope) {
|
|
751
|
+
const added = missingDecls(e, scope);
|
|
752
|
+
childScope = withDecls(scope, e.prefixDecls);
|
|
753
|
+
if (added) {
|
|
754
|
+
writeDecls(added, parts);
|
|
755
|
+
childScope = withDecls(childScope, added);
|
|
756
|
+
}
|
|
571
757
|
}
|
|
572
758
|
for (const a of e.attrs) parts.push(writeAttr(a));
|
|
573
759
|
if (e.children.length === 0) {
|
|
@@ -575,15 +761,15 @@ const writeElement = (e, parts) => {
|
|
|
575
761
|
return;
|
|
576
762
|
}
|
|
577
763
|
parts.push(">");
|
|
578
|
-
for (const child of e.children) writeNode(child, parts);
|
|
764
|
+
for (const child of e.children) writeNode(child, parts, childScope);
|
|
579
765
|
parts.push("</");
|
|
580
766
|
parts.push(name);
|
|
581
767
|
parts.push(">");
|
|
582
768
|
};
|
|
583
|
-
const writeNode = (n, parts) => {
|
|
769
|
+
const writeNode = (n, parts, scope) => {
|
|
584
770
|
switch (n.kind) {
|
|
585
771
|
case "element":
|
|
586
|
-
writeElement(n, parts);
|
|
772
|
+
writeElement(n, parts, scope);
|
|
587
773
|
return;
|
|
588
774
|
case "text":
|
|
589
775
|
parts.push(escapeText(n.data));
|
|
@@ -609,6 +795,7 @@ const writeNode = (n, parts) => {
|
|
|
609
795
|
return;
|
|
610
796
|
}
|
|
611
797
|
};
|
|
798
|
+
const XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
|
|
612
799
|
const writeDeclaration = (doc, parts) => {
|
|
613
800
|
if (!doc.decl) return;
|
|
614
801
|
parts.push("<?xml version=\"");
|
|
@@ -629,15 +816,15 @@ const writeDeclaration = (doc, parts) => {
|
|
|
629
816
|
const serializeXml = (doc, options = {}) => {
|
|
630
817
|
const parts = [];
|
|
631
818
|
if (doc.decl) writeDeclaration(doc, parts);
|
|
632
|
-
else if (options.standaloneDeclaration ?? true) parts.push(
|
|
633
|
-
for (const p of doc.prolog) writeNode(p, parts);
|
|
634
|
-
writeElement(doc.root, parts);
|
|
635
|
-
for (const e of doc.epilog) writeNode(e, parts);
|
|
819
|
+
else if (options.standaloneDeclaration ?? true) parts.push(XML_DECLARATION);
|
|
820
|
+
for (const p of doc.prolog) writeNode(p, parts, null);
|
|
821
|
+
writeElement(doc.root, parts, DOCUMENT_SCOPE);
|
|
822
|
+
for (const e of doc.epilog) writeNode(e, parts, null);
|
|
636
823
|
return parts.join("");
|
|
637
824
|
};
|
|
638
825
|
const serializeFragment = (element) => {
|
|
639
826
|
const parts = [];
|
|
640
|
-
writeElement(element, parts);
|
|
827
|
+
writeElement(element, parts, null);
|
|
641
828
|
return parts.join("");
|
|
642
829
|
};
|
|
643
830
|
//#endregion
|
|
@@ -1301,4 +1488,4 @@ function describeConflict(conflict) {
|
|
|
1301
1488
|
//#endregion
|
|
1302
1489
|
export { sameDeck as i, describeConflict as n, mergeDecks as r, comparablePart as t };
|
|
1303
1490
|
|
|
1304
|
-
//# sourceMappingURL=deck-merge-
|
|
1491
|
+
//# sourceMappingURL=deck-merge-Dj_XHQQM.js.map
|