@coco-vexel/coco-office 0.0.0-stage → 1.0.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/LICENSE +202 -0
- package/README.md +120 -2
- package/THIRD_PARTY_NOTICES.md +1188 -0
- package/dist/excel-worker-browser.cjs +6544 -0
- package/dist/excel-worker-browser.cjs.map +1 -0
- package/dist/excel-worker-browser.d.cts +2 -0
- package/dist/excel-worker-browser.d.ts +2 -0
- package/dist/excel-worker-browser.js +6523 -0
- package/dist/excel-worker-browser.js.map +1 -0
- package/dist/excel-worker.cjs +6547 -0
- package/dist/excel-worker.cjs.map +1 -0
- package/dist/excel-worker.d.cts +2 -0
- package/dist/excel-worker.d.ts +2 -0
- package/dist/excel-worker.js +6526 -0
- package/dist/excel-worker.js.map +1 -0
- package/dist/excel.cjs +12523 -0
- package/dist/excel.cjs.map +1 -0
- package/dist/excel.d.cts +2252 -0
- package/dist/excel.d.ts +2252 -0
- package/dist/excel.js +12368 -0
- package/dist/excel.js.map +1 -0
- package/dist/index.cjs +19 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel-worker-browser.cjs +12304 -0
- package/dist/kernel-worker-browser.cjs.map +1 -0
- package/dist/kernel-worker-browser.d.cts +2 -0
- package/dist/kernel-worker-browser.d.ts +2 -0
- package/dist/kernel-worker-browser.js +12283 -0
- package/dist/kernel-worker-browser.js.map +1 -0
- package/dist/kernel-worker.cjs +12309 -0
- package/dist/kernel-worker.cjs.map +1 -0
- package/dist/kernel-worker.d.cts +2 -0
- package/dist/kernel-worker.d.ts +2 -0
- package/dist/kernel-worker.js +12288 -0
- package/dist/kernel-worker.js.map +1 -0
- package/dist/pack.cjs +459 -0
- package/dist/pack.cjs.map +1 -0
- package/dist/pack.d.cts +119 -0
- package/dist/pack.d.ts +119 -0
- package/dist/pack.js +408 -0
- package/dist/pack.js.map +1 -0
- package/dist/ppt.cjs +7427 -0
- package/dist/ppt.cjs.map +1 -0
- package/dist/ppt.d.cts +1432 -0
- package/dist/ppt.d.ts +1432 -0
- package/dist/ppt.js +7355 -0
- package/dist/ppt.js.map +1 -0
- package/dist/shared.cjs +105 -0
- package/dist/shared.cjs.map +1 -0
- package/dist/shared.d.cts +31 -0
- package/dist/shared.d.ts +31 -0
- package/dist/shared.js +81 -0
- package/dist/shared.js.map +1 -0
- package/dist/types-BVkkdcfh.d.cts +54 -0
- package/dist/types-BVkkdcfh.d.ts +54 -0
- package/dist/types-C2vQfM-b.d.cts +102 -0
- package/dist/types-C2vQfM-b.d.ts +102 -0
- package/dist/view-DAkeR0RW.d.ts +1199 -0
- package/dist/view-DX2YAG5A.d.cts +1199 -0
- package/dist/word-view.cjs +1824 -0
- package/dist/word-view.cjs.map +1 -0
- package/dist/word-view.d.cts +2 -0
- package/dist/word-view.d.ts +2 -0
- package/dist/word-view.js +1791 -0
- package/dist/word-view.js.map +1 -0
- package/dist/word.cjs +14106 -0
- package/dist/word.cjs.map +1 -0
- package/dist/word.d.cts +3042 -0
- package/dist/word.d.ts +3042 -0
- package/dist/word.js +14011 -0
- package/dist/word.js.map +1 -0
- package/package.json +103 -3
package/dist/pack.d.ts
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { P as Part, a as Package } from './types-BVkkdcfh.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Part 构造 / 变更 / 查询 的辅助函数。
|
|
5
|
+
*
|
|
6
|
+
* 所有 Part 的"创建"都走这里(而非直接字面量),以便:
|
|
7
|
+
* - 守住 path 格式(无前导斜杠)
|
|
8
|
+
* - 守住 XML / 二进制 互斥
|
|
9
|
+
* - 统一 `_dirty` / `_originalBytes` 初始化语义
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
interface CreateXmlPartSpec {
|
|
13
|
+
/** Part 路径,无前导斜杠,如 'word/document.xml' */
|
|
14
|
+
path: string;
|
|
15
|
+
/** MIME content type */
|
|
16
|
+
contentType: string;
|
|
17
|
+
/** 已解析好的 XML DOM(slimdom Document) */
|
|
18
|
+
xmlDom: Document;
|
|
19
|
+
/**
|
|
20
|
+
* 装载时的原始字节。
|
|
21
|
+
* - 传入(来自装载路径):`_dirty` 初始为 `false`,可在 `toZip` 时零 serialize 复用
|
|
22
|
+
* - 省略(新建 part 的场景,后续 #9/#10 的插入新 XML part):`_dirty` 初始为 `true`
|
|
23
|
+
*/
|
|
24
|
+
originalBytes?: Uint8Array;
|
|
25
|
+
}
|
|
26
|
+
interface CreateBinaryPartSpec {
|
|
27
|
+
/** Part 路径,无前导斜杠,如 'word/media/image1.png' */
|
|
28
|
+
path: string;
|
|
29
|
+
/** MIME content type,如 'image/png' */
|
|
30
|
+
contentType: string;
|
|
31
|
+
/** 二进制载荷 */
|
|
32
|
+
bytes: Uint8Array;
|
|
33
|
+
/**
|
|
34
|
+
* 装载时的原始字节;二进制通常装载即最终态,省略时默认 = `bytes`。
|
|
35
|
+
* 二进制 part 初始 `_dirty` 恒为 `false`。
|
|
36
|
+
*/
|
|
37
|
+
originalBytes?: Uint8Array;
|
|
38
|
+
}
|
|
39
|
+
/** 从已解析的 XML DOM 创建 XML part。`originalBytes` 传入 → dirty=false;否则 dirty=true(新建场景) */
|
|
40
|
+
declare function createXmlPart(spec: CreateXmlPartSpec): Part;
|
|
41
|
+
/** 从二进制字节创建 binary part。`originalBytes` 省略时默认 = `bytes`。dirty 恒为 false */
|
|
42
|
+
declare function createBinaryPart(spec: CreateBinaryPartSpec): Part;
|
|
43
|
+
/** 标记 part 被改动过。toZip / toFlatOpc 会重 serialize 此 part */
|
|
44
|
+
declare function markDirty(part: Part): void;
|
|
45
|
+
/** 查询 part 是否被改动(read-only;读操作不改 part) */
|
|
46
|
+
declare function isDirty(part: Part): boolean;
|
|
47
|
+
/** XML part 判定(拥有 xmlDom) */
|
|
48
|
+
declare function isXmlPart(part: Part): boolean;
|
|
49
|
+
/** 二进制 part 判定(拥有 bytes 但无 xmlDom) */
|
|
50
|
+
declare function isBinaryPart(part: Part): boolean;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Package 集合层:create / set / get / has / delete / list
|
|
54
|
+
*
|
|
55
|
+
* Package 只是 path→Part 的 Map 容器;零业务语义,存储格式由 adapter 层(#9 zip / #10 Flat OPC)决定。
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
/** 空包。后续由 adapter 层填充 parts */
|
|
59
|
+
declare function createPackage(): Package;
|
|
60
|
+
/** 以 part.path 为 key 放入 pkg。已存在同 path 时覆盖 */
|
|
61
|
+
declare function setPart(pkg: Package, part: Part): void;
|
|
62
|
+
/** 按 path 取回 part;不存在返 undefined */
|
|
63
|
+
declare function getPart(pkg: Package, path: string): Part | undefined;
|
|
64
|
+
/** 按 path 判断存在 */
|
|
65
|
+
declare function hasPart(pkg: Package, path: string): boolean;
|
|
66
|
+
/** 删除 part,返回是否删除成功(存在即删、不存在返 false) */
|
|
67
|
+
declare function deletePart(pkg: Package, path: string): boolean;
|
|
68
|
+
/** 所有 parts 快照数组(稳定遍历顺序 = Map 插入顺序) */
|
|
69
|
+
declare function listParts(pkg: Package): Part[];
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 从 zip 字节重建 Package。
|
|
73
|
+
*
|
|
74
|
+
* 行为:
|
|
75
|
+
* - 先读 `[Content_Types].xml`,构建 contentType 查找器
|
|
76
|
+
* - 遍历 zip entries,跳过目录
|
|
77
|
+
* - 每个 entry 按 contentType 决定 XML / 二进制,创建对应 Part
|
|
78
|
+
* - `[Content_Types].xml` 也作为 XML part 存入 Package
|
|
79
|
+
*/
|
|
80
|
+
declare function fromZip(buf: Uint8Array | ArrayBuffer): Promise<Package>;
|
|
81
|
+
/**
|
|
82
|
+
* 将 Package 序列化回 zip 字节。
|
|
83
|
+
*
|
|
84
|
+
* 行为:
|
|
85
|
+
* - `_dirty === false` 且持有 `_originalBytes` → 直接复用字节(零 serialize)
|
|
86
|
+
* - `_dirty === true` 的 XML part → slimdom serialize
|
|
87
|
+
* - `_dirty === true` 的二进制 part → 使用 `bytes`
|
|
88
|
+
*/
|
|
89
|
+
declare function toZip(pkg: Package): Promise<Uint8Array>;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 从 Flat OPC 字符串重建 Package。
|
|
93
|
+
*
|
|
94
|
+
* - 忽略顶部 `<?mso-application?>` PI(解析器自动处理)
|
|
95
|
+
* - `<pkg:xmlData>` 里的根元素被提取重新序列化为该 part 的独立 XML 文档
|
|
96
|
+
* - `<pkg:binaryData>` 做 base64 解码
|
|
97
|
+
* - **不**产生 `[Content_Types].xml` part(Flat OPC 形态不含它)
|
|
98
|
+
*/
|
|
99
|
+
declare function fromFlatOpc(xml: string): Package;
|
|
100
|
+
/**
|
|
101
|
+
* 将 Package 序列化为 Flat OPC 字符串。
|
|
102
|
+
*
|
|
103
|
+
* - 顶部插入 `<?mso-application progid="Word.Document"?>` PI
|
|
104
|
+
* - 跳过 `[Content_Types].xml` part(Flat OPC 不需要)
|
|
105
|
+
* - XML part:导入 `xmlDom` 的根元素到新 Flat OPC document,包进 `<pkg:xmlData>`
|
|
106
|
+
* - 二进制 part:字节 base64 编码,包进 `<pkg:binaryData>`,加 `pkg:compression="store"`
|
|
107
|
+
*/
|
|
108
|
+
declare function toFlatOpc(pkg: Package): string;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* 如果 Package 里已有 `[Content_Types].xml` part,返回 false,不做改动。
|
|
112
|
+
* 否则,按当前 parts 的 contentType 合成一份最小 CT XML 并加入 Package,返回 true。
|
|
113
|
+
*
|
|
114
|
+
* 合成策略:每个非 CT part 产生一个 `<Override PartName="/path" ContentType="..."/>`。
|
|
115
|
+
* 不尝试推导 Default 扩展名(正确性优先,简洁性次之)。
|
|
116
|
+
*/
|
|
117
|
+
declare function ensureContentTypes(pkg: Package): boolean;
|
|
118
|
+
|
|
119
|
+
export { type CreateBinaryPartSpec, type CreateXmlPartSpec, Package, Part, createBinaryPart, createPackage, createXmlPart, deletePart, ensureContentTypes, fromFlatOpc, fromZip, getPart, hasPart, isBinaryPart, isDirty, isXmlPart, listParts, markDirty, setPart, toFlatOpc, toZip };
|
package/dist/pack.js
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/pack/part.ts
|
|
5
|
+
function assertPath(path) {
|
|
6
|
+
if (typeof path !== "string" || path.length === 0) {
|
|
7
|
+
throw new Error(`invalid part path: must be non-empty string, got: ${JSON.stringify(path)}`);
|
|
8
|
+
}
|
|
9
|
+
if (path.startsWith("/")) {
|
|
10
|
+
throw new Error(`invalid part path: must not start with '/', got: ${path}`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
__name(assertPath, "assertPath");
|
|
14
|
+
function assertContentType(contentType) {
|
|
15
|
+
if (typeof contentType !== "string" || contentType.length === 0) {
|
|
16
|
+
throw new Error(`invalid contentType: must be non-empty string`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
__name(assertContentType, "assertContentType");
|
|
20
|
+
function createXmlPart(spec) {
|
|
21
|
+
assertPath(spec.path);
|
|
22
|
+
assertContentType(spec.contentType);
|
|
23
|
+
if (!spec.xmlDom) {
|
|
24
|
+
throw new Error(`createXmlPart: xmlDom required for ${spec.path}`);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
path: spec.path,
|
|
28
|
+
contentType: spec.contentType,
|
|
29
|
+
xmlDom: spec.xmlDom,
|
|
30
|
+
_originalBytes: spec.originalBytes,
|
|
31
|
+
_dirty: spec.originalBytes === void 0
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
__name(createXmlPart, "createXmlPart");
|
|
35
|
+
function createBinaryPart(spec) {
|
|
36
|
+
var _a;
|
|
37
|
+
assertPath(spec.path);
|
|
38
|
+
assertContentType(spec.contentType);
|
|
39
|
+
if (!spec.bytes) {
|
|
40
|
+
throw new Error(`createBinaryPart: bytes required for ${spec.path}`);
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
path: spec.path,
|
|
44
|
+
contentType: spec.contentType,
|
|
45
|
+
bytes: spec.bytes,
|
|
46
|
+
_originalBytes: (_a = spec.originalBytes) != null ? _a : spec.bytes,
|
|
47
|
+
_dirty: false
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
__name(createBinaryPart, "createBinaryPart");
|
|
51
|
+
function markDirty(part) {
|
|
52
|
+
part._dirty = true;
|
|
53
|
+
}
|
|
54
|
+
__name(markDirty, "markDirty");
|
|
55
|
+
function isDirty(part) {
|
|
56
|
+
return part._dirty;
|
|
57
|
+
}
|
|
58
|
+
__name(isDirty, "isDirty");
|
|
59
|
+
function isXmlPart(part) {
|
|
60
|
+
return part.xmlDom !== void 0;
|
|
61
|
+
}
|
|
62
|
+
__name(isXmlPart, "isXmlPart");
|
|
63
|
+
function isBinaryPart(part) {
|
|
64
|
+
return part.bytes !== void 0 && part.xmlDom === void 0;
|
|
65
|
+
}
|
|
66
|
+
__name(isBinaryPart, "isBinaryPart");
|
|
67
|
+
|
|
68
|
+
// src/pack/package.ts
|
|
69
|
+
function createPackage() {
|
|
70
|
+
return { parts: /* @__PURE__ */ new Map() };
|
|
71
|
+
}
|
|
72
|
+
__name(createPackage, "createPackage");
|
|
73
|
+
function setPart(pkg, part) {
|
|
74
|
+
pkg.parts.set(part.path, part);
|
|
75
|
+
}
|
|
76
|
+
__name(setPart, "setPart");
|
|
77
|
+
function getPart(pkg, path) {
|
|
78
|
+
return pkg.parts.get(path);
|
|
79
|
+
}
|
|
80
|
+
__name(getPart, "getPart");
|
|
81
|
+
function hasPart(pkg, path) {
|
|
82
|
+
return pkg.parts.has(path);
|
|
83
|
+
}
|
|
84
|
+
__name(hasPart, "hasPart");
|
|
85
|
+
function deletePart(pkg, path) {
|
|
86
|
+
return pkg.parts.delete(path);
|
|
87
|
+
}
|
|
88
|
+
__name(deletePart, "deletePart");
|
|
89
|
+
function listParts(pkg) {
|
|
90
|
+
return Array.from(pkg.parts.values());
|
|
91
|
+
}
|
|
92
|
+
__name(listParts, "listParts");
|
|
93
|
+
|
|
94
|
+
// src/pack/zip.ts
|
|
95
|
+
import JSZip from "jszip";
|
|
96
|
+
import { parseXmlDocument as parseXmlDocument2, serializeToWellFormedString } from "slimdom";
|
|
97
|
+
|
|
98
|
+
// src/pack/content-types.ts
|
|
99
|
+
import { parseXmlDocument } from "slimdom";
|
|
100
|
+
var CONTENT_TYPES_PATH = "[Content_Types].xml";
|
|
101
|
+
var CONTENT_TYPES_NS = "http://schemas.openxmlformats.org/package/2006/content-types";
|
|
102
|
+
var CONTENT_TYPES_CTYPE = "application/vnd.openxmlformats-package.content-types+xml";
|
|
103
|
+
function xmlAttr(v) {
|
|
104
|
+
return v.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
105
|
+
}
|
|
106
|
+
__name(xmlAttr, "xmlAttr");
|
|
107
|
+
function ensureContentTypes(pkg) {
|
|
108
|
+
if (getPart(pkg, CONTENT_TYPES_PATH)) return false;
|
|
109
|
+
const overrides = [];
|
|
110
|
+
for (const part of pkg.parts.values()) {
|
|
111
|
+
if (part.path === CONTENT_TYPES_PATH) continue;
|
|
112
|
+
overrides.push(
|
|
113
|
+
` <Override PartName="/${xmlAttr(part.path)}" ContentType="${xmlAttr(part.contentType)}"/>`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
const xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
117
|
+
<Types xmlns="${CONTENT_TYPES_NS}">
|
|
118
|
+
` + overrides.join("\n") + (overrides.length > 0 ? "\n" : "") + `</Types>`;
|
|
119
|
+
setPart(
|
|
120
|
+
pkg,
|
|
121
|
+
createXmlPart({
|
|
122
|
+
path: CONTENT_TYPES_PATH,
|
|
123
|
+
contentType: CONTENT_TYPES_CTYPE,
|
|
124
|
+
xmlDom: parseXmlDocument(xml),
|
|
125
|
+
originalBytes: new TextEncoder().encode(xml)
|
|
126
|
+
})
|
|
127
|
+
);
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
__name(ensureContentTypes, "ensureContentTypes");
|
|
131
|
+
|
|
132
|
+
// src/pack/zip.ts
|
|
133
|
+
var CONTENT_TYPES_PATH2 = "[Content_Types].xml";
|
|
134
|
+
var CONTENT_TYPES_NS2 = "http://schemas.openxmlformats.org/package/2006/content-types";
|
|
135
|
+
var CONTENT_TYPES_CTYPE2 = "application/vnd.openxmlformats-package.content-types+xml";
|
|
136
|
+
function isXmlContentType(ct) {
|
|
137
|
+
const normalized = ct.toLowerCase();
|
|
138
|
+
if (normalized.startsWith("image/") || normalized.startsWith("audio/") || normalized.startsWith("video/") || normalized === "application/octet-stream" || normalized === "application/vnd.openxmlformats-officedocument.oleobject" || normalized.startsWith("application/vnd.ms-office.")) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return normalized.endsWith("+xml") || normalized === "application/xml" || normalized === "text/xml";
|
|
142
|
+
}
|
|
143
|
+
__name(isXmlContentType, "isXmlContentType");
|
|
144
|
+
function parseContentTypes(xml) {
|
|
145
|
+
const doc = parseXmlDocument2(xml);
|
|
146
|
+
const defaults = /* @__PURE__ */ new Map();
|
|
147
|
+
const overrides = /* @__PURE__ */ new Map();
|
|
148
|
+
const defaultEls = doc.getElementsByTagNameNS(CONTENT_TYPES_NS2, "Default");
|
|
149
|
+
for (let i = 0; i < defaultEls.length; i++) {
|
|
150
|
+
const el = defaultEls[i];
|
|
151
|
+
if (!el) continue;
|
|
152
|
+
const ext = el.getAttribute("Extension");
|
|
153
|
+
const ct = el.getAttribute("ContentType");
|
|
154
|
+
if (ext && ct) defaults.set(ext.toLowerCase(), ct);
|
|
155
|
+
}
|
|
156
|
+
const overrideEls = doc.getElementsByTagNameNS(CONTENT_TYPES_NS2, "Override");
|
|
157
|
+
for (let i = 0; i < overrideEls.length; i++) {
|
|
158
|
+
const el = overrideEls[i];
|
|
159
|
+
if (!el) continue;
|
|
160
|
+
const partName = el.getAttribute("PartName");
|
|
161
|
+
const ct = el.getAttribute("ContentType");
|
|
162
|
+
if (partName && ct) {
|
|
163
|
+
overrides.set(partName.replace(/^\//, ""), ct);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
resolve(partName) {
|
|
168
|
+
const override = overrides.get(partName);
|
|
169
|
+
if (override) return override;
|
|
170
|
+
const dot = partName.lastIndexOf(".");
|
|
171
|
+
if (dot === -1) return void 0;
|
|
172
|
+
return defaults.get(partName.slice(dot + 1).toLowerCase());
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
__name(parseContentTypes, "parseContentTypes");
|
|
177
|
+
async function fromZip(buf) {
|
|
178
|
+
const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
|
|
179
|
+
const zip = await JSZip.loadAsync(bytes);
|
|
180
|
+
const pkg = createPackage();
|
|
181
|
+
const ctFile = zip.file(CONTENT_TYPES_PATH2);
|
|
182
|
+
if (!ctFile) {
|
|
183
|
+
throw new Error(`fromZip: missing ${CONTENT_TYPES_PATH2}; not a valid OOXML package`);
|
|
184
|
+
}
|
|
185
|
+
const ctXml = await ctFile.async("string");
|
|
186
|
+
const resolver = parseContentTypes(ctXml);
|
|
187
|
+
const ctBytes = await ctFile.async("uint8array");
|
|
188
|
+
setPart(
|
|
189
|
+
pkg,
|
|
190
|
+
createXmlPart({
|
|
191
|
+
path: CONTENT_TYPES_PATH2,
|
|
192
|
+
contentType: CONTENT_TYPES_CTYPE2,
|
|
193
|
+
xmlDom: parseXmlDocument2(ctXml),
|
|
194
|
+
originalBytes: ctBytes
|
|
195
|
+
})
|
|
196
|
+
);
|
|
197
|
+
const entryPaths = [];
|
|
198
|
+
zip.forEach((relativePath, entry) => {
|
|
199
|
+
if (entry.dir) return;
|
|
200
|
+
if (relativePath === CONTENT_TYPES_PATH2) return;
|
|
201
|
+
entryPaths.push(relativePath);
|
|
202
|
+
});
|
|
203
|
+
for (const path of entryPaths) {
|
|
204
|
+
const entry = zip.file(path);
|
|
205
|
+
if (!entry) continue;
|
|
206
|
+
const contentType = resolver.resolve(path);
|
|
207
|
+
if (!contentType) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`fromZip: no ContentType for part '${path}' (not in Default by extension, not in Override by partName)`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
const entryBytes = await entry.async("uint8array");
|
|
213
|
+
if (isXmlContentType(contentType)) {
|
|
214
|
+
const xmlText = await entry.async("string");
|
|
215
|
+
const xmlDom = parseXmlDocument2(xmlText);
|
|
216
|
+
setPart(pkg, createXmlPart({ path, contentType, xmlDom, originalBytes: entryBytes }));
|
|
217
|
+
} else {
|
|
218
|
+
setPart(pkg, createBinaryPart({ path, contentType, bytes: entryBytes }));
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return pkg;
|
|
222
|
+
}
|
|
223
|
+
__name(fromZip, "fromZip");
|
|
224
|
+
async function toZip(pkg) {
|
|
225
|
+
ensureContentTypes(pkg);
|
|
226
|
+
const zip = new JSZip();
|
|
227
|
+
for (const part of pkg.parts.values()) {
|
|
228
|
+
const bytes = partToBytes(part);
|
|
229
|
+
zip.file(part.path, bytes, { createFolders: false });
|
|
230
|
+
}
|
|
231
|
+
return await zip.generateAsync({
|
|
232
|
+
type: "uint8array",
|
|
233
|
+
compression: "DEFLATE",
|
|
234
|
+
compressionOptions: { level: 6 }
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
__name(toZip, "toZip");
|
|
238
|
+
function partToBytes(part) {
|
|
239
|
+
if (!part._dirty && part._originalBytes) {
|
|
240
|
+
return part._originalBytes;
|
|
241
|
+
}
|
|
242
|
+
if (isXmlPart(part)) {
|
|
243
|
+
if (!part.xmlDom) {
|
|
244
|
+
throw new Error(`toZip: XML part '${part.path}' missing xmlDom`);
|
|
245
|
+
}
|
|
246
|
+
const text = serializeToWellFormedString(part.xmlDom);
|
|
247
|
+
return new TextEncoder().encode(text);
|
|
248
|
+
}
|
|
249
|
+
if (part.bytes) return part.bytes;
|
|
250
|
+
if (part._originalBytes) return part._originalBytes;
|
|
251
|
+
throw new Error(`toZip: binary part '${part.path}' has no bytes`);
|
|
252
|
+
}
|
|
253
|
+
__name(partToBytes, "partToBytes");
|
|
254
|
+
|
|
255
|
+
// src/pack/flat-opc.ts
|
|
256
|
+
import { parseXmlDocument as parseXmlDocument3, serializeToWellFormedString as serializeToWellFormedString2 } from "slimdom";
|
|
257
|
+
var PKG_NS = "http://schemas.microsoft.com/office/2006/xmlPackage";
|
|
258
|
+
var CONTENT_TYPES_PATH3 = "[Content_Types].xml";
|
|
259
|
+
function isXmlContentType2(ct) {
|
|
260
|
+
return ct.endsWith("+xml") || ct === "application/xml" || ct === "text/xml";
|
|
261
|
+
}
|
|
262
|
+
__name(isXmlContentType2, "isXmlContentType");
|
|
263
|
+
function base64Encode(bytes) {
|
|
264
|
+
let binStr = "";
|
|
265
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
266
|
+
binStr += String.fromCharCode(bytes[i]);
|
|
267
|
+
}
|
|
268
|
+
return btoa(binStr);
|
|
269
|
+
}
|
|
270
|
+
__name(base64Encode, "base64Encode");
|
|
271
|
+
function base64Decode(b64) {
|
|
272
|
+
const cleaned = b64.replace(/\s+/g, "");
|
|
273
|
+
const binStr = atob(cleaned);
|
|
274
|
+
const bytes = new Uint8Array(binStr.length);
|
|
275
|
+
for (let i = 0; i < binStr.length; i++) {
|
|
276
|
+
bytes[i] = binStr.charCodeAt(i);
|
|
277
|
+
}
|
|
278
|
+
return bytes;
|
|
279
|
+
}
|
|
280
|
+
__name(base64Decode, "base64Decode");
|
|
281
|
+
function firstElementChild(el) {
|
|
282
|
+
const kids = el.childNodes;
|
|
283
|
+
for (let i = 0; i < kids.length; i++) {
|
|
284
|
+
const n = kids[i];
|
|
285
|
+
if (n && n.nodeType === 1) return n;
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
__name(firstElementChild, "firstElementChild");
|
|
290
|
+
function fromFlatOpc(xml) {
|
|
291
|
+
var _a;
|
|
292
|
+
const flatDoc = parseXmlDocument3(xml);
|
|
293
|
+
const pkg = createPackage();
|
|
294
|
+
const partEls = flatDoc.getElementsByTagNameNS(PKG_NS, "part");
|
|
295
|
+
for (let i = 0; i < partEls.length; i++) {
|
|
296
|
+
const partEl = partEls[i];
|
|
297
|
+
if (!partEl) continue;
|
|
298
|
+
const pkgName = partEl.getAttributeNS(PKG_NS, "name");
|
|
299
|
+
const ctype = partEl.getAttributeNS(PKG_NS, "contentType");
|
|
300
|
+
if (!pkgName || !ctype) {
|
|
301
|
+
throw new Error(`fromFlatOpc: <pkg:part> missing name or contentType`);
|
|
302
|
+
}
|
|
303
|
+
const path = pkgName.replace(/^\//, "");
|
|
304
|
+
if (!path) continue;
|
|
305
|
+
if (path === CONTENT_TYPES_PATH3) continue;
|
|
306
|
+
let xmlData = null;
|
|
307
|
+
let binaryData = null;
|
|
308
|
+
const kids = partEl.childNodes;
|
|
309
|
+
for (let j = 0; j < kids.length; j++) {
|
|
310
|
+
const k = kids[j];
|
|
311
|
+
if (!k || k.nodeType !== 1) continue;
|
|
312
|
+
const e = k;
|
|
313
|
+
if (e.namespaceURI !== PKG_NS) continue;
|
|
314
|
+
if (e.localName === "xmlData" && !xmlData) xmlData = e;
|
|
315
|
+
else if (e.localName === "binaryData" && !binaryData) binaryData = e;
|
|
316
|
+
}
|
|
317
|
+
if (xmlData) {
|
|
318
|
+
const rootChild = firstElementChild(xmlData);
|
|
319
|
+
if (!rootChild) {
|
|
320
|
+
throw new Error(`fromFlatOpc: empty <pkg:xmlData> for part '${path}'`);
|
|
321
|
+
}
|
|
322
|
+
const xmlText = serializeToWellFormedString2(rootChild);
|
|
323
|
+
const originalBytes = new TextEncoder().encode(xmlText);
|
|
324
|
+
const dom = parseXmlDocument3(xmlText);
|
|
325
|
+
setPart(pkg, createXmlPart({ path, contentType: ctype, xmlDom: dom, originalBytes }));
|
|
326
|
+
} else if (binaryData) {
|
|
327
|
+
const b64 = (_a = binaryData.textContent) != null ? _a : "";
|
|
328
|
+
const bytes = base64Decode(b64);
|
|
329
|
+
setPart(pkg, createBinaryPart({ path, contentType: ctype, bytes }));
|
|
330
|
+
} else {
|
|
331
|
+
if (isXmlContentType2(ctype)) {
|
|
332
|
+
throw new Error(`fromFlatOpc: XML part '${path}' has no <pkg:xmlData>`);
|
|
333
|
+
}
|
|
334
|
+
setPart(pkg, createBinaryPart({ path, contentType: ctype, bytes: new Uint8Array() }));
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return pkg;
|
|
338
|
+
}
|
|
339
|
+
__name(fromFlatOpc, "fromFlatOpc");
|
|
340
|
+
function toFlatOpc(pkg) {
|
|
341
|
+
const seed = `<pkg:package xmlns:pkg="${PKG_NS}"/>`;
|
|
342
|
+
const flatDoc = parseXmlDocument3(seed);
|
|
343
|
+
const root = flatDoc.documentElement;
|
|
344
|
+
if (!root) {
|
|
345
|
+
throw new Error("toFlatOpc: failed to create <pkg:package> root");
|
|
346
|
+
}
|
|
347
|
+
for (const part of pkg.parts.values()) {
|
|
348
|
+
if (part.path === CONTENT_TYPES_PATH3) continue;
|
|
349
|
+
const partEl = flatDoc.createElementNS(PKG_NS, "pkg:part");
|
|
350
|
+
partEl.setAttributeNS(PKG_NS, "pkg:name", "/" + part.path);
|
|
351
|
+
partEl.setAttributeNS(PKG_NS, "pkg:contentType", part.contentType);
|
|
352
|
+
if (isXmlPart(part)) {
|
|
353
|
+
appendXmlData(flatDoc, partEl, part);
|
|
354
|
+
} else {
|
|
355
|
+
partEl.setAttributeNS(PKG_NS, "pkg:compression", "store");
|
|
356
|
+
appendBinaryData(flatDoc, partEl, part);
|
|
357
|
+
}
|
|
358
|
+
root.appendChild(partEl);
|
|
359
|
+
}
|
|
360
|
+
const pi = flatDoc.createProcessingInstruction("mso-application", 'progid="Word.Document"');
|
|
361
|
+
flatDoc.insertBefore(pi, flatDoc.documentElement);
|
|
362
|
+
return serializeToWellFormedString2(flatDoc);
|
|
363
|
+
}
|
|
364
|
+
__name(toFlatOpc, "toFlatOpc");
|
|
365
|
+
function appendXmlData(flatDoc, partEl, part) {
|
|
366
|
+
if (!part.xmlDom || !part.xmlDom.documentElement) {
|
|
367
|
+
throw new Error(`toFlatOpc: XML part '${part.path}' missing xmlDom or root`);
|
|
368
|
+
}
|
|
369
|
+
const xmlData = flatDoc.createElementNS(PKG_NS, "pkg:xmlData");
|
|
370
|
+
const imported = flatDoc.importNode(
|
|
371
|
+
part.xmlDom.documentElement,
|
|
372
|
+
true
|
|
373
|
+
);
|
|
374
|
+
xmlData.appendChild(imported);
|
|
375
|
+
partEl.appendChild(xmlData);
|
|
376
|
+
}
|
|
377
|
+
__name(appendXmlData, "appendXmlData");
|
|
378
|
+
function appendBinaryData(flatDoc, partEl, part) {
|
|
379
|
+
var _a;
|
|
380
|
+
const bytes = (_a = part.bytes) != null ? _a : part._originalBytes;
|
|
381
|
+
if (!bytes) {
|
|
382
|
+
throw new Error(`toFlatOpc: binary part '${part.path}' has no bytes`);
|
|
383
|
+
}
|
|
384
|
+
const binEl = flatDoc.createElementNS(PKG_NS, "pkg:binaryData");
|
|
385
|
+
binEl.textContent = base64Encode(bytes);
|
|
386
|
+
partEl.appendChild(binEl);
|
|
387
|
+
}
|
|
388
|
+
__name(appendBinaryData, "appendBinaryData");
|
|
389
|
+
export {
|
|
390
|
+
createBinaryPart,
|
|
391
|
+
createPackage,
|
|
392
|
+
createXmlPart,
|
|
393
|
+
deletePart,
|
|
394
|
+
ensureContentTypes,
|
|
395
|
+
fromFlatOpc,
|
|
396
|
+
fromZip,
|
|
397
|
+
getPart,
|
|
398
|
+
hasPart,
|
|
399
|
+
isBinaryPart,
|
|
400
|
+
isDirty,
|
|
401
|
+
isXmlPart,
|
|
402
|
+
listParts,
|
|
403
|
+
markDirty,
|
|
404
|
+
setPart,
|
|
405
|
+
toFlatOpc,
|
|
406
|
+
toZip
|
|
407
|
+
};
|
|
408
|
+
//# sourceMappingURL=pack.js.map
|
package/dist/pack.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/pack/part.ts","../src/pack/package.ts","../src/pack/zip.ts","../src/pack/content-types.ts","../src/pack/flat-opc.ts"],"sourcesContent":["/**\n * Part 构造 / 变更 / 查询 的辅助函数。\n *\n * 所有 Part 的\"创建\"都走这里(而非直接字面量),以便:\n * - 守住 path 格式(无前导斜杠)\n * - 守住 XML / 二进制 互斥\n * - 统一 `_dirty` / `_originalBytes` 初始化语义\n */\nimport type { Part } from './types.js';\n\nexport interface CreateXmlPartSpec {\n /** Part 路径,无前导斜杠,如 'word/document.xml' */\n path: string;\n /** MIME content type */\n contentType: string;\n /** 已解析好的 XML DOM(slimdom Document) */\n xmlDom: Document;\n /**\n * 装载时的原始字节。\n * - 传入(来自装载路径):`_dirty` 初始为 `false`,可在 `toZip` 时零 serialize 复用\n * - 省略(新建 part 的场景,后续 #9/#10 的插入新 XML part):`_dirty` 初始为 `true`\n */\n originalBytes?: Uint8Array;\n}\n\nexport interface CreateBinaryPartSpec {\n /** Part 路径,无前导斜杠,如 'word/media/image1.png' */\n path: string;\n /** MIME content type,如 'image/png' */\n contentType: string;\n /** 二进制载荷 */\n bytes: Uint8Array;\n /**\n * 装载时的原始字节;二进制通常装载即最终态,省略时默认 = `bytes`。\n * 二进制 part 初始 `_dirty` 恒为 `false`。\n */\n originalBytes?: Uint8Array;\n}\n\nfunction assertPath(path: string): void {\n if (typeof path !== 'string' || path.length === 0) {\n throw new Error(`invalid part path: must be non-empty string, got: ${JSON.stringify(path)}`);\n }\n if (path.startsWith('/')) {\n throw new Error(`invalid part path: must not start with '/', got: ${path}`);\n }\n}\n\nfunction assertContentType(contentType: string): void {\n if (typeof contentType !== 'string' || contentType.length === 0) {\n throw new Error(`invalid contentType: must be non-empty string`);\n }\n}\n\n/** 从已解析的 XML DOM 创建 XML part。`originalBytes` 传入 → dirty=false;否则 dirty=true(新建场景) */\nexport function createXmlPart(spec: CreateXmlPartSpec): Part {\n assertPath(spec.path);\n assertContentType(spec.contentType);\n if (!spec.xmlDom) {\n throw new Error(`createXmlPart: xmlDom required for ${spec.path}`);\n }\n return {\n path: spec.path,\n contentType: spec.contentType,\n xmlDom: spec.xmlDom,\n _originalBytes: spec.originalBytes,\n _dirty: spec.originalBytes === undefined,\n };\n}\n\n/** 从二进制字节创建 binary part。`originalBytes` 省略时默认 = `bytes`。dirty 恒为 false */\nexport function createBinaryPart(spec: CreateBinaryPartSpec): Part {\n assertPath(spec.path);\n assertContentType(spec.contentType);\n if (!spec.bytes) {\n throw new Error(`createBinaryPart: bytes required for ${spec.path}`);\n }\n return {\n path: spec.path,\n contentType: spec.contentType,\n bytes: spec.bytes,\n _originalBytes: spec.originalBytes ?? spec.bytes,\n _dirty: false,\n };\n}\n\n/** 标记 part 被改动过。toZip / toFlatOpc 会重 serialize 此 part */\nexport function markDirty(part: Part): void {\n part._dirty = true;\n}\n\n/** 查询 part 是否被改动(read-only;读操作不改 part) */\nexport function isDirty(part: Part): boolean {\n return part._dirty;\n}\n\n/** XML part 判定(拥有 xmlDom) */\nexport function isXmlPart(part: Part): boolean {\n return part.xmlDom !== undefined;\n}\n\n/** 二进制 part 判定(拥有 bytes 但无 xmlDom) */\nexport function isBinaryPart(part: Part): boolean {\n return part.bytes !== undefined && part.xmlDom === undefined;\n}\n","/**\n * Package 集合层:create / set / get / has / delete / list\n *\n * Package 只是 path→Part 的 Map 容器;零业务语义,存储格式由 adapter 层(#9 zip / #10 Flat OPC)决定。\n */\nimport type { Package, Part } from './types.js';\n\n/** 空包。后续由 adapter 层填充 parts */\nexport function createPackage(): Package {\n return { parts: new Map() };\n}\n\n/** 以 part.path 为 key 放入 pkg。已存在同 path 时覆盖 */\nexport function setPart(pkg: Package, part: Part): void {\n pkg.parts.set(part.path, part);\n}\n\n/** 按 path 取回 part;不存在返 undefined */\nexport function getPart(pkg: Package, path: string): Part | undefined {\n return pkg.parts.get(path);\n}\n\n/** 按 path 判断存在 */\nexport function hasPart(pkg: Package, path: string): boolean {\n return pkg.parts.has(path);\n}\n\n/** 删除 part,返回是否删除成功(存在即删、不存在返 false) */\nexport function deletePart(pkg: Package, path: string): boolean {\n return pkg.parts.delete(path);\n}\n\n/** 所有 parts 快照数组(稳定遍历顺序 = Map 插入顺序) */\nexport function listParts(pkg: Package): Part[] {\n return Array.from(pkg.parts.values());\n}\n","/**\n * zip ↔ Package 互转(docs/01 §3.2)。\n *\n * - `fromZip(buf)` 解压 .docx,按 `[Content_Types].xml` 恢复每个 part 的 contentType\n * - `toZip(pkg)` 反向:dirty=false 的 part 复用 `_originalBytes`,dirty=true 的按 XML / 二进制重序列化\n *\n * 本实现目标:小文档正确性。极大档性能调优(lazy parse 等)归后续 issue。\n */\nimport JSZip from 'jszip';\nimport { parseXmlDocument, serializeToWellFormedString } from 'slimdom';\nimport type { Package, Part } from './types.js';\nimport { createBinaryPart, createXmlPart, isXmlPart } from './part.js';\nimport { createPackage, setPart } from './package.js';\nimport { ensureContentTypes } from './content-types.js';\n\n/** Content Types 子集 */\nconst CONTENT_TYPES_PATH = '[Content_Types].xml';\nconst CONTENT_TYPES_NS = 'http://schemas.openxmlformats.org/package/2006/content-types';\nconst CONTENT_TYPES_CTYPE = 'application/vnd.openxmlformats-package.content-types+xml';\n\n/**\n * 判断 contentType 是否为 XML 类(决定走 parseXmlDocument 还是保留字节):\n * - 以 `+xml` 结尾(OOXML 所有子 part 的惯例)\n * - 或完全等于 `application/xml` / `text/xml`\n */\nfunction isXmlContentType(ct: string): boolean {\n const normalized = ct.toLowerCase();\n if (\n normalized.startsWith('image/') ||\n normalized.startsWith('audio/') ||\n normalized.startsWith('video/') ||\n normalized === 'application/octet-stream' ||\n normalized === 'application/vnd.openxmlformats-officedocument.oleobject' ||\n normalized.startsWith('application/vnd.ms-office.')\n ) {\n return false;\n }\n return normalized.endsWith('+xml') || normalized === 'application/xml' || normalized === 'text/xml';\n}\n\n/** 解析 [Content_Types].xml 构建 partName → contentType 的查找器 */\ninterface ContentTypeResolver {\n /** partName 无前导 `/`,如 'word/document.xml' */\n resolve(partName: string): string | undefined;\n}\n\nfunction parseContentTypes(xml: string): ContentTypeResolver {\n const doc = parseXmlDocument(xml) as unknown as Document;\n const defaults = new Map<string, string>(); // extension(小写) → contentType\n const overrides = new Map<string, string>(); // partName(无 /)→ contentType\n\n const defaultEls = doc.getElementsByTagNameNS(CONTENT_TYPES_NS, 'Default');\n for (let i = 0; i < defaultEls.length; i++) {\n const el = defaultEls[i];\n if (!el) continue;\n const ext = el.getAttribute('Extension');\n const ct = el.getAttribute('ContentType');\n if (ext && ct) defaults.set(ext.toLowerCase(), ct);\n }\n\n const overrideEls = doc.getElementsByTagNameNS(CONTENT_TYPES_NS, 'Override');\n for (let i = 0; i < overrideEls.length; i++) {\n const el = overrideEls[i];\n if (!el) continue;\n const partName = el.getAttribute('PartName');\n const ct = el.getAttribute('ContentType');\n if (partName && ct) {\n // PartName 以 `/` 开头,剥掉前导斜杠与 Package 内部 path 对齐\n overrides.set(partName.replace(/^\\//, ''), ct);\n }\n }\n\n return {\n resolve(partName: string): string | undefined {\n const override = overrides.get(partName);\n if (override) return override;\n const dot = partName.lastIndexOf('.');\n if (dot === -1) return undefined;\n return defaults.get(partName.slice(dot + 1).toLowerCase());\n },\n };\n}\n\n/**\n * 从 zip 字节重建 Package。\n *\n * 行为:\n * - 先读 `[Content_Types].xml`,构建 contentType 查找器\n * - 遍历 zip entries,跳过目录\n * - 每个 entry 按 contentType 决定 XML / 二进制,创建对应 Part\n * - `[Content_Types].xml` 也作为 XML part 存入 Package\n */\nexport async function fromZip(buf: Uint8Array | ArrayBuffer): Promise<Package> {\n const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);\n const zip = await JSZip.loadAsync(bytes);\n const pkg = createPackage();\n\n const ctFile = zip.file(CONTENT_TYPES_PATH);\n if (!ctFile) {\n throw new Error(`fromZip: missing ${CONTENT_TYPES_PATH}; not a valid OOXML package`);\n }\n const ctXml = await ctFile.async('string');\n const resolver = parseContentTypes(ctXml);\n const ctBytes = await ctFile.async('uint8array');\n setPart(\n pkg,\n createXmlPart({\n path: CONTENT_TYPES_PATH,\n contentType: CONTENT_TYPES_CTYPE,\n xmlDom: parseXmlDocument(ctXml) as unknown as Document,\n originalBytes: ctBytes,\n }),\n );\n\n // 遍历非 [Content_Types].xml 的 entry\n const entryPaths: string[] = [];\n zip.forEach((relativePath, entry) => {\n if (entry.dir) return;\n if (relativePath === CONTENT_TYPES_PATH) return;\n entryPaths.push(relativePath);\n });\n\n for (const path of entryPaths) {\n const entry = zip.file(path);\n if (!entry) continue;\n const contentType = resolver.resolve(path);\n if (!contentType) {\n throw new Error(\n `fromZip: no ContentType for part '${path}' (not in Default by extension, not in Override by partName)`,\n );\n }\n const entryBytes = await entry.async('uint8array');\n\n if (isXmlContentType(contentType)) {\n const xmlText = await entry.async('string');\n const xmlDom = parseXmlDocument(xmlText) as unknown as Document;\n setPart(pkg, createXmlPart({ path, contentType, xmlDom, originalBytes: entryBytes }));\n } else {\n setPart(pkg, createBinaryPart({ path, contentType, bytes: entryBytes }));\n }\n }\n\n return pkg;\n}\n\n/**\n * 将 Package 序列化回 zip 字节。\n *\n * 行为:\n * - `_dirty === false` 且持有 `_originalBytes` → 直接复用字节(零 serialize)\n * - `_dirty === true` 的 XML part → slimdom serialize\n * - `_dirty === true` 的二进制 part → 使用 `bytes`\n */\nexport async function toZip(pkg: Package): Promise<Uint8Array> {\n // Flat OPC → Package 的路径不会产生 [Content_Types].xml;此处补齐以保证产出的 zip 合法。\n // 对 fromZip 出来的 Package 无副作用(CT 已在)。\n ensureContentTypes(pkg);\n\n const zip = new JSZip();\n\n for (const part of pkg.parts.values()) {\n const bytes = partToBytes(part);\n // createFolders=false 显式禁止 JSZip 为含 '/' 的 path 自动创建中间目录 entry——\n // OOXML 规范不允许 zip 包内有空目录 entry,Word 见到会判\"文档已损坏\"拒打开\n // (WPS 宽松能开但产物不合规)。JSZip 3.x 默认 true,必须显式关。\n zip.file(part.path, bytes, { createFolders: false });\n }\n\n // OOXML 主体是高度可压缩的 XML;默认 STORE 会让产物比 Word 原生输出大 10-18×。\n return await zip.generateAsync({\n type: 'uint8array',\n compression: 'DEFLATE',\n compressionOptions: { level: 6 },\n });\n}\n\nfunction partToBytes(part: Part): Uint8Array {\n // dirty=false 且有原始字节:零 serialize\n if (!part._dirty && part._originalBytes) {\n return part._originalBytes;\n }\n\n if (isXmlPart(part)) {\n if (!part.xmlDom) {\n throw new Error(`toZip: XML part '${part.path}' missing xmlDom`);\n }\n // xmlDom 在我们的类型里是 lib.dom 的 Document(消费方友好),slimdom 的 Node 结构兼容但 TS\n // 类型不同;通过 `as never` 绕开 dts 检查,运行时正常。\n const text = serializeToWellFormedString(part.xmlDom as never);\n return new TextEncoder().encode(text);\n }\n\n // 二进制\n if (part.bytes) return part.bytes;\n if (part._originalBytes) return part._originalBytes;\n throw new Error(`toZip: binary part '${part.path}' has no bytes`);\n}\n","/**\n * [Content_Types].xml 的合成与维护。\n *\n * 为什么单列一个模块:\n * - zip 形态要求 [Content_Types].xml 存在(否则 Word/WPS 打不开)\n * - Flat OPC 形态里 contentType 已内联在 <pkg:part> 上,不含 CT 文件\n * - 因此 `fromFlatOpc` 出来的 Package 缺 CT;直接 `toZip` 会产出坏 docx\n *\n * 本模块提供 `ensureContentTypes(pkg)`:若 CT part 缺失,按当前 parts 的\n * (path → contentType)合成一份最小 CT XML 并加入 Package。\n *\n * `toZip` 会在打包前自动调一次,确保产出的 zip 始终可打开。\n */\nimport { parseXmlDocument } from 'slimdom';\nimport { createXmlPart } from './part.js';\nimport { getPart, setPart } from './package.js';\nimport type { Package } from './types.js';\n\nconst CONTENT_TYPES_PATH = '[Content_Types].xml';\nconst CONTENT_TYPES_NS = 'http://schemas.openxmlformats.org/package/2006/content-types';\nconst CONTENT_TYPES_CTYPE = 'application/vnd.openxmlformats-package.content-types+xml';\n\n/** XML 属性值转义(Content Type 里可能含 `+`,但没有 `<` `&` 等需要转义的字符;仍做一遍以防) */\nfunction xmlAttr(v: string): string {\n return v\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\n/**\n * 如果 Package 里已有 `[Content_Types].xml` part,返回 false,不做改动。\n * 否则,按当前 parts 的 contentType 合成一份最小 CT XML 并加入 Package,返回 true。\n *\n * 合成策略:每个非 CT part 产生一个 `<Override PartName=\"/path\" ContentType=\"...\"/>`。\n * 不尝试推导 Default 扩展名(正确性优先,简洁性次之)。\n */\nexport function ensureContentTypes(pkg: Package): boolean {\n if (getPart(pkg, CONTENT_TYPES_PATH)) return false;\n\n const overrides: string[] = [];\n for (const part of pkg.parts.values()) {\n if (part.path === CONTENT_TYPES_PATH) continue;\n overrides.push(\n ` <Override PartName=\"/${xmlAttr(part.path)}\" ContentType=\"${xmlAttr(part.contentType)}\"/>`,\n );\n }\n\n const xml =\n `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\\n` +\n `<Types xmlns=\"${CONTENT_TYPES_NS}\">\\n` +\n overrides.join('\\n') +\n (overrides.length > 0 ? '\\n' : '') +\n `</Types>`;\n\n setPart(\n pkg,\n createXmlPart({\n path: CONTENT_TYPES_PATH,\n contentType: CONTENT_TYPES_CTYPE,\n xmlDom: parseXmlDocument(xml) as unknown as Document,\n originalBytes: new TextEncoder().encode(xml),\n }),\n );\n\n return true;\n}\n","/**\n * Flat OPC ↔ Package 互转(docs/01 §3.3)。\n *\n * Flat OPC 是 WPS `Document.WordOpenXML` 返回的形态,整个包展开成一份大 XML:\n *\n * <?xml version=\"1.0\" standalone=\"yes\"?>\n * <?mso-application progid=\"Word.Document\"?>\n * <pkg:package xmlns:pkg=\"http://schemas.microsoft.com/office/2006/xmlPackage\">\n * <pkg:part pkg:name=\"/word/document.xml\" pkg:contentType=\"...+xml\">\n * <pkg:xmlData>\n * <w:document xmlns:w=\"...\">...</w:document>\n * </pkg:xmlData>\n * </pkg:part>\n * <pkg:part pkg:name=\"/word/media/image1.png\" pkg:contentType=\"image/png\" pkg:compression=\"store\">\n * <pkg:binaryData>iVBORw0KG...=</pkg:binaryData>\n * </pkg:part>\n * ...\n * </pkg:package>\n *\n * **注意**:Flat OPC 里 contentType 直接写在每个 `<pkg:part>` 上,\n * 没有 `[Content_Types].xml` 这个 part 本身。互转时 `[Content_Types].xml` 只在 zip 形态下存在。\n */\nimport { parseXmlDocument, serializeToWellFormedString } from 'slimdom';\nimport type { Package, Part } from './types.js';\nimport { createBinaryPart, createXmlPart, isXmlPart } from './part.js';\nimport { createPackage, setPart } from './package.js';\n\nconst PKG_NS = 'http://schemas.microsoft.com/office/2006/xmlPackage';\nconst CONTENT_TYPES_PATH = '[Content_Types].xml';\n\nfunction isXmlContentType(ct: string): boolean {\n return ct.endsWith('+xml') || ct === 'application/xml' || ct === 'text/xml';\n}\n\n/** Uint8Array → base64(兼容 Node 16+ / 浏览器 / WPS WebView) */\nfunction base64Encode(bytes: Uint8Array): string {\n let binStr = '';\n for (let i = 0; i < bytes.length; i++) {\n binStr += String.fromCharCode(bytes[i]!);\n }\n return btoa(binStr);\n}\n\n/** base64 → Uint8Array */\nfunction base64Decode(b64: string): Uint8Array {\n const cleaned = b64.replace(/\\s+/g, '');\n const binStr = atob(cleaned);\n const bytes = new Uint8Array(binStr.length);\n for (let i = 0; i < binStr.length; i++) {\n bytes[i] = binStr.charCodeAt(i);\n }\n return bytes;\n}\n\n/** 取元素的第一个 Element 类型子节点(跳过文本 / 注释 / 空白) */\nfunction firstElementChild(el: Element): Element | null {\n const kids = el.childNodes;\n for (let i = 0; i < kids.length; i++) {\n const n = kids[i];\n if (n && n.nodeType === 1) return n as Element;\n }\n return null;\n}\n\n/**\n * 从 Flat OPC 字符串重建 Package。\n *\n * - 忽略顶部 `<?mso-application?>` PI(解析器自动处理)\n * - `<pkg:xmlData>` 里的根元素被提取重新序列化为该 part 的独立 XML 文档\n * - `<pkg:binaryData>` 做 base64 解码\n * - **不**产生 `[Content_Types].xml` part(Flat OPC 形态不含它)\n */\nexport function fromFlatOpc(xml: string): Package {\n const flatDoc = parseXmlDocument(xml) as unknown as Document;\n const pkg = createPackage();\n\n const partEls = flatDoc.getElementsByTagNameNS(PKG_NS, 'part');\n for (let i = 0; i < partEls.length; i++) {\n const partEl = partEls[i];\n if (!partEl) continue;\n\n const pkgName = partEl.getAttributeNS(PKG_NS, 'name');\n const ctype = partEl.getAttributeNS(PKG_NS, 'contentType');\n if (!pkgName || !ctype) {\n throw new Error(`fromFlatOpc: <pkg:part> missing name or contentType`);\n }\n const path = pkgName.replace(/^\\//, '');\n if (!path) continue;\n\n // [Content_Types].xml 理论上不会出现在 Flat OPC 里;若遇到,跳过\n if (path === CONTENT_TYPES_PATH) continue;\n\n // 查找 xmlData 或 binaryData(只取第一个,跨命名空间断言)\n let xmlData: Element | null = null;\n let binaryData: Element | null = null;\n const kids = partEl.childNodes;\n for (let j = 0; j < kids.length; j++) {\n const k = kids[j];\n if (!k || k.nodeType !== 1) continue;\n const e = k as Element;\n if (e.namespaceURI !== PKG_NS) continue;\n if (e.localName === 'xmlData' && !xmlData) xmlData = e;\n else if (e.localName === 'binaryData' && !binaryData) binaryData = e;\n }\n\n if (xmlData) {\n const rootChild = firstElementChild(xmlData);\n if (!rootChild) {\n throw new Error(`fromFlatOpc: empty <pkg:xmlData> for part '${path}'`);\n }\n // 将子元素序列化出来,再独立解析为该 part 的 Document\n const xmlText = serializeToWellFormedString(rootChild as never);\n const originalBytes = new TextEncoder().encode(xmlText);\n const dom = parseXmlDocument(xmlText) as unknown as Document;\n setPart(pkg, createXmlPart({ path, contentType: ctype, xmlDom: dom, originalBytes }));\n } else if (binaryData) {\n const b64 = binaryData.textContent ?? '';\n const bytes = base64Decode(b64);\n setPart(pkg, createBinaryPart({ path, contentType: ctype, bytes }));\n } else {\n // 既无 xmlData 也无 binaryData — 按类型决定:XML contentType 用空元素,二进制用空字节\n if (isXmlContentType(ctype)) {\n throw new Error(`fromFlatOpc: XML part '${path}' has no <pkg:xmlData>`);\n }\n setPart(pkg, createBinaryPart({ path, contentType: ctype, bytes: new Uint8Array() }));\n }\n }\n\n return pkg;\n}\n\n/**\n * 将 Package 序列化为 Flat OPC 字符串。\n *\n * - 顶部插入 `<?mso-application progid=\"Word.Document\"?>` PI\n * - 跳过 `[Content_Types].xml` part(Flat OPC 不需要)\n * - XML part:导入 `xmlDom` 的根元素到新 Flat OPC document,包进 `<pkg:xmlData>`\n * - 二进制 part:字节 base64 编码,包进 `<pkg:binaryData>`,加 `pkg:compression=\"store\"`\n */\nexport function toFlatOpc(pkg: Package): string {\n // slimdom 的 DOMImplementation 构造签名与 lib.dom 不同(需要一个虚拟 document 作为 context);\n // 直接用 parseXmlDocument 生成一个带 pkg:package 根的空文档,避免跨类型适配。\n const seed = `<pkg:package xmlns:pkg=\"${PKG_NS}\"/>`;\n const flatDoc = parseXmlDocument(seed) as unknown as Document;\n const root = flatDoc.documentElement;\n if (!root) {\n throw new Error('toFlatOpc: failed to create <pkg:package> root');\n }\n\n for (const part of pkg.parts.values()) {\n if (part.path === CONTENT_TYPES_PATH) continue;\n\n const partEl = flatDoc.createElementNS(PKG_NS, 'pkg:part');\n partEl.setAttributeNS(PKG_NS, 'pkg:name', '/' + part.path);\n partEl.setAttributeNS(PKG_NS, 'pkg:contentType', part.contentType);\n\n if (isXmlPart(part)) {\n appendXmlData(flatDoc, partEl, part);\n } else {\n partEl.setAttributeNS(PKG_NS, 'pkg:compression', 'store');\n appendBinaryData(flatDoc, partEl, part);\n }\n\n root.appendChild(partEl);\n }\n\n // 顶部加 <?mso-application?> PI\n const pi = flatDoc.createProcessingInstruction('mso-application', 'progid=\"Word.Document\"');\n flatDoc.insertBefore(pi as never, flatDoc.documentElement as never);\n\n return serializeToWellFormedString(flatDoc as never);\n}\n\nfunction appendXmlData(flatDoc: Document, partEl: Element, part: Part): void {\n if (!part.xmlDom || !part.xmlDom.documentElement) {\n throw new Error(`toFlatOpc: XML part '${part.path}' missing xmlDom or root`);\n }\n const xmlData = flatDoc.createElementNS(PKG_NS, 'pkg:xmlData');\n // importNode 深拷贝原 part 的根元素到 Flat OPC document,命名空间保留\n const imported = flatDoc.importNode(\n part.xmlDom.documentElement as never,\n true,\n ) as unknown as Node;\n xmlData.appendChild(imported);\n partEl.appendChild(xmlData);\n}\n\nfunction appendBinaryData(flatDoc: Document, partEl: Element, part: Part): void {\n const bytes = part.bytes ?? part._originalBytes;\n if (!bytes) {\n throw new Error(`toFlatOpc: binary part '${part.path}' has no bytes`);\n }\n const binEl = flatDoc.createElementNS(PKG_NS, 'pkg:binaryData');\n binEl.textContent = base64Encode(bytes);\n partEl.appendChild(binEl);\n}\n"],"mappings":"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","names":["parseXmlDocument","CONTENT_TYPES_PATH","CONTENT_TYPES_NS","CONTENT_TYPES_CTYPE","parseXmlDocument","parseXmlDocument","serializeToWellFormedString","CONTENT_TYPES_PATH","isXmlContentType","parseXmlDocument","serializeToWellFormedString"]}
|