@pixerate/editor 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +20 -11
  2. package/dist/agent/index.cjs +8 -8
  3. package/dist/agent/index.d.cts +2 -2
  4. package/dist/agent/index.d.ts +2 -2
  5. package/dist/agent/index.js +2 -2
  6. package/dist/canvas/index.cjs +1269 -13
  7. package/dist/canvas/index.cjs.map +1 -1
  8. package/dist/canvas/index.d.cts +432 -6
  9. package/dist/canvas/index.d.ts +432 -6
  10. package/dist/canvas/index.js +1264 -8
  11. package/dist/canvas/index.js.map +1 -1
  12. package/dist/{chunk-U6NDQFOK.cjs → chunk-6M3BCTBD.cjs} +427 -138
  13. package/dist/chunk-6M3BCTBD.cjs.map +1 -0
  14. package/dist/{chunk-TVRC4KVT.cjs → chunk-AA4ZEVCC.cjs} +845 -90
  15. package/dist/chunk-AA4ZEVCC.cjs.map +1 -0
  16. package/dist/{chunk-LA7PEGU3.cjs → chunk-CL37JGFW.cjs} +4 -4
  17. package/dist/{chunk-LA7PEGU3.cjs.map → chunk-CL37JGFW.cjs.map} +1 -1
  18. package/dist/{chunk-A7DKIA72.js → chunk-DENSCKFC.js} +642 -69
  19. package/dist/chunk-DENSCKFC.js.map +1 -0
  20. package/dist/{chunk-4QPLEUL2.cjs → chunk-GVSMRPHB.cjs} +1046 -54
  21. package/dist/chunk-GVSMRPHB.cjs.map +1 -0
  22. package/dist/{chunk-KYRZDWM4.js → chunk-JJDLPEWL.js} +2 -2
  23. package/dist/{chunk-3TYMNULT.js → chunk-MJZBNWG7.js} +807 -52
  24. package/dist/chunk-MJZBNWG7.js.map +1 -0
  25. package/dist/{chunk-CYFJCKC4.js → chunk-QGHGJ56O.js} +997 -5
  26. package/dist/chunk-QGHGJ56O.js.map +1 -0
  27. package/dist/{chunk-GVW4P7BG.js → chunk-RU52I7QO.js} +305 -16
  28. package/dist/chunk-RU52I7QO.js.map +1 -0
  29. package/dist/{chunk-JYRIOFEN.cjs → chunk-SAZRENEZ.cjs} +647 -74
  30. package/dist/chunk-SAZRENEZ.cjs.map +1 -0
  31. package/dist/{controller-OUdxPY-X.d.ts → controller-B7GIybc4.d.cts} +139 -7
  32. package/dist/{controller-OUdxPY-X.d.cts → controller-B7GIybc4.d.ts} +139 -7
  33. package/dist/extensions/index.cjs +14 -4
  34. package/dist/extensions/index.cjs.map +1 -1
  35. package/dist/extensions/index.d.cts +3 -3
  36. package/dist/extensions/index.d.ts +3 -3
  37. package/dist/extensions/index.js +13 -3
  38. package/dist/{index-k3mFbPx_.d.cts → index-CCr_z9kF.d.cts} +3 -3
  39. package/dist/{index-Ng1pG7JE.d.ts → index-Ck6ajwXh.d.ts} +3 -3
  40. package/dist/index.cjs +250 -16
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +294 -8
  43. package/dist/index.d.ts +294 -8
  44. package/dist/index.js +241 -7
  45. package/dist/index.js.map +1 -1
  46. package/dist/{registry-iAHbqkYt.d.cts → registry-GJI4gToU.d.cts} +15 -4
  47. package/dist/{registry-iAHbqkYt.d.ts → registry-GJI4gToU.d.ts} +15 -4
  48. package/dist/serializers/index.cjs +3 -3
  49. package/dist/serializers/index.d.cts +1 -1
  50. package/dist/serializers/index.d.ts +1 -1
  51. package/dist/serializers/index.js +2 -2
  52. package/dist/spreadsheet/index.cjs +7 -3
  53. package/dist/spreadsheet/index.cjs.map +1 -1
  54. package/dist/spreadsheet/index.d.cts +33 -4
  55. package/dist/spreadsheet/index.d.ts +33 -4
  56. package/dist/spreadsheet/index.js +6 -2
  57. package/dist/{track-changes-G8JcWB8b.d.cts → track-changes-BSF58RK0.d.cts} +92 -9
  58. package/dist/{track-changes-G8JcWB8b.d.ts → track-changes-BSF58RK0.d.ts} +92 -9
  59. package/dist/{types-DMe0vFB1.d.cts → types-CJ4U-HHI.d.cts} +1 -1
  60. package/dist/{types-DMe0vFB1.d.ts → types-CJ4U-HHI.d.ts} +1 -1
  61. package/package.json +1 -1
  62. package/dist/chunk-3TYMNULT.js.map +0 -1
  63. package/dist/chunk-4QPLEUL2.cjs.map +0 -1
  64. package/dist/chunk-A7DKIA72.js.map +0 -1
  65. package/dist/chunk-CYFJCKC4.js.map +0 -1
  66. package/dist/chunk-GVW4P7BG.js.map +0 -1
  67. package/dist/chunk-JYRIOFEN.cjs.map +0 -1
  68. package/dist/chunk-TVRC4KVT.cjs.map +0 -1
  69. package/dist/chunk-U6NDQFOK.cjs.map +0 -1
  70. /package/dist/{chunk-KYRZDWM4.js.map → chunk-JJDLPEWL.js.map} +0 -0
@@ -13,15 +13,16 @@ import {
13
13
  rtfToPlainText,
14
14
  sanitizeImportedHtml,
15
15
  serializeRichClipboardPayload
16
- } from "./chunk-KYRZDWM4.js";
16
+ } from "./chunk-JJDLPEWL.js";
17
17
  import {
18
18
  CommentStore,
19
19
  TrackChanges,
20
20
  createReviewId,
21
+ escapeHtml,
21
22
  htmlToPlainText,
22
23
  markdownToTipTapHtml,
23
24
  plainTextToSlice
24
- } from "./chunk-3TYMNULT.js";
25
+ } from "./chunk-MJZBNWG7.js";
25
26
 
26
27
  // src/extensions/gradient-text.ts
27
28
  import { Mark } from "@tiptap/core";
@@ -2192,11 +2193,15 @@ var ImportAdapterRegistry = class {
2192
2193
  { fileName }
2193
2194
  );
2194
2195
  }
2195
- const context = createImportContext(input, { fileName, mimeType, target: adapter.target });
2196
+ const context = createImportContext(input, { fileName, mimeType, target: adapter.target, registry: this });
2196
2197
  try {
2197
2198
  const result = await adapter.import(input, context);
2198
2199
  return { adapterId: adapter.id, target: adapter.target, fileName, mimeType, result };
2199
2200
  } catch (error) {
2201
+ if (error instanceof ImportError) {
2202
+ if (error.fileName !== void 0 || fileName === void 0) throw error;
2203
+ throw new ImportError(error.code, error.message, { fileName, cause: error.cause });
2204
+ }
2200
2205
  throw new ImportError(
2201
2206
  "adapter_failed",
2202
2207
  `Import adapter "${adapter.id}" failed: ${error instanceof Error ? error.message : String(error)}`,
@@ -2206,6 +2211,980 @@ var ImportAdapterRegistry = class {
2206
2211
  }
2207
2212
  };
2208
2213
 
2214
+ // src/import/zip.ts
2215
+ var ZipError = class extends Error {
2216
+ code;
2217
+ entryName;
2218
+ constructor(code, message, details = {}) {
2219
+ super(message, details.cause !== void 0 ? { cause: details.cause } : void 0);
2220
+ this.name = "ZipError";
2221
+ this.code = code;
2222
+ this.entryName = details.entryName;
2223
+ }
2224
+ };
2225
+ var DEFAULT_ZIP_MAX_ENTRIES = 1e4;
2226
+ var DEFAULT_ZIP_MAX_TOTAL_SIZE = 256 * 1024 * 1024;
2227
+ var SIG_EOCD = 101010256;
2228
+ var SIG_ZIP64_EOCD = 101075792;
2229
+ var SIG_ZIP64_LOCATOR = 117853008;
2230
+ var SIG_CENTRAL = 33639248;
2231
+ var SIG_LOCAL = 67324752;
2232
+ var EOCD_SIZE = 22;
2233
+ var MAX_COMMENT = 65535;
2234
+ var crcTable = null;
2235
+ function zipCrc32(data) {
2236
+ if (!crcTable) {
2237
+ crcTable = new Uint32Array(256);
2238
+ for (let n = 0; n < 256; n++) {
2239
+ let c = n;
2240
+ for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
2241
+ crcTable[n] = c >>> 0;
2242
+ }
2243
+ }
2244
+ let crc = 4294967295;
2245
+ for (let i = 0; i < data.length; i++) crc = crcTable[(crc ^ data[i]) & 255] ^ crc >>> 8;
2246
+ return (crc ^ 4294967295) >>> 0;
2247
+ }
2248
+ function toBytes(data) {
2249
+ if (ArrayBuffer.isView(data)) return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
2250
+ return new Uint8Array(data);
2251
+ }
2252
+ function isUnsafeZipPath(name) {
2253
+ if (!name || name.includes("\0")) return true;
2254
+ const normalized = name.replace(/\\/g, "/");
2255
+ if (normalized.startsWith("/") || /^[a-zA-Z]:/.test(normalized)) return true;
2256
+ return normalized.split("/").some((segment) => segment === "..");
2257
+ }
2258
+ var utf8 = new TextDecoder("utf-8");
2259
+ var CP437_HIGH = "\xC7\xFC\xE9\xE2\xE4\xE0\xE5\xE7\xEA\xEB\xE8\xEF\xEE\xEC\xC4\xC5\xC9\xE6\xC6\xF4\xF6\xF2\xFB\xF9\xFF\xD6\xDC\xA2\xA3\xA5\u20A7\u0192\xE1\xED\xF3\xFA\xF1\xD1\xAA\xBA\xBF\u2310\xAC\xBD\xBC\xA1\xAB\xBB\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255D\u255C\u255B\u2510\u2514\u2534\u252C\u251C\u2500\u253C\u255E\u255F\u255A\u2554\u2569\u2566\u2560\u2550\u256C\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256B\u256A\u2518\u250C\u2588\u2584\u258C\u2590\u2580\u03B1\xDF\u0393\u03C0\u03A3\u03C3\xB5\u03C4\u03A6\u0398\u03A9\u03B4\u221E\u03C6\u03B5\u2229\u2261\xB1\u2265\u2264\u2320\u2321\xF7\u2248\xB0\u2219\xB7\u221A\u207F\xB2\u25A0\xA0";
2260
+ function decodeName(bytes, isUtf8) {
2261
+ if (isUtf8 || bytes.every((b) => b < 128)) return utf8.decode(bytes);
2262
+ let out = "";
2263
+ for (const b of bytes) out += b < 128 ? String.fromCharCode(b) : CP437_HIGH[b - 128];
2264
+ return out;
2265
+ }
2266
+ var ZipArchive = class {
2267
+ constructor(bytes, entries, maxTotalSize) {
2268
+ this.bytes = bytes;
2269
+ this.maxTotalSize = maxTotalSize;
2270
+ this.entries = entries;
2271
+ entries.forEach((entry) => {
2272
+ if (!this.byName.has(entry.name)) this.byName.set(entry.name, entry);
2273
+ });
2274
+ }
2275
+ bytes;
2276
+ maxTotalSize;
2277
+ /** Entries in central-directory order. */
2278
+ entries;
2279
+ byName = /* @__PURE__ */ new Map();
2280
+ extracted = 0;
2281
+ /** Looks up an entry by exact name (a leading `/` is ignored). */
2282
+ get(name) {
2283
+ return this.byName.get(name.replace(/^\/+/, ""));
2284
+ }
2285
+ has(name) {
2286
+ return !!this.get(name);
2287
+ }
2288
+ /** Uncompressed bytes extracted so far (counted against `maxTotalSize`). */
2289
+ get extractedSize() {
2290
+ return this.extracted;
2291
+ }
2292
+ /** Extracts an entry's data, verifying its size and CRC-32. */
2293
+ async read(entryOrName) {
2294
+ const entry = typeof entryOrName === "string" ? this.get(entryOrName) : entryOrName;
2295
+ if (!entry) {
2296
+ throw new ZipError("entry_not_found", `ZIP entry "${String(entryOrName)}" not found.`, {
2297
+ entryName: String(entryOrName)
2298
+ });
2299
+ }
2300
+ const name = entry.name;
2301
+ if (entry.encrypted) {
2302
+ throw new ZipError("encrypted", `ZIP entry "${name}" is encrypted; encrypted archives are not supported.`, {
2303
+ entryName: name
2304
+ });
2305
+ }
2306
+ if (entry.isDirectory) return new Uint8Array(0);
2307
+ const remaining = this.maxTotalSize - this.extracted;
2308
+ if (entry.size > remaining) {
2309
+ throw new ZipError(
2310
+ "too_large",
2311
+ `Extracting "${name}" (${entry.size} bytes) would exceed the ${this.maxTotalSize}-byte limit.`,
2312
+ { entryName: name }
2313
+ );
2314
+ }
2315
+ const { bytes } = this;
2316
+ const offset = entry.localHeaderOffset;
2317
+ if (offset + 30 > bytes.length || readU32(bytes, offset) !== SIG_LOCAL) {
2318
+ throw new ZipError("corrupt_entry", `ZIP entry "${name}" has no valid local header.`, { entryName: name });
2319
+ }
2320
+ const dataStart = offset + 30 + readU16(bytes, offset + 26) + readU16(bytes, offset + 28);
2321
+ const dataEnd = dataStart + entry.compressedSize;
2322
+ if (dataEnd > bytes.length) {
2323
+ throw new ZipError("corrupt_entry", `ZIP entry "${name}" is truncated.`, { entryName: name });
2324
+ }
2325
+ const raw = bytes.subarray(dataStart, dataEnd);
2326
+ let data;
2327
+ if (entry.method === 0) {
2328
+ if (entry.compressedSize !== entry.size) {
2329
+ throw new ZipError("corrupt_entry", `Stored ZIP entry "${name}" has inconsistent sizes.`, { entryName: name });
2330
+ }
2331
+ data = raw.slice();
2332
+ } else if (entry.method === 8) {
2333
+ data = await inflateRaw(raw, entry.size, name);
2334
+ } else {
2335
+ throw new ZipError(
2336
+ "unsupported_feature",
2337
+ `ZIP entry "${name}" uses unsupported compression method ${entry.method}; only stored and deflate are supported.`,
2338
+ { entryName: name }
2339
+ );
2340
+ }
2341
+ if (data.length !== entry.size) {
2342
+ throw new ZipError("corrupt_entry", `ZIP entry "${name}" size does not match the directory.`, { entryName: name });
2343
+ }
2344
+ this.extracted += data.length;
2345
+ if (zipCrc32(data) !== entry.crc32) {
2346
+ throw new ZipError("corrupt_entry", `ZIP entry "${name}" failed its CRC-32 check.`, { entryName: name });
2347
+ }
2348
+ return data;
2349
+ }
2350
+ /** Extracts an entry and decodes it as UTF-8 (a leading BOM is removed). */
2351
+ async readText(entryOrName) {
2352
+ const text = utf8.decode(await this.read(entryOrName));
2353
+ return text.charCodeAt(0) === 65279 ? text.slice(1) : text;
2354
+ }
2355
+ };
2356
+ function readU16(bytes, offset) {
2357
+ return bytes[offset] | bytes[offset + 1] << 8;
2358
+ }
2359
+ function readU32(bytes, offset) {
2360
+ return (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24) >>> 0;
2361
+ }
2362
+ function readU64(bytes, offset) {
2363
+ const value = readU32(bytes, offset) + readU32(bytes, offset + 4) * 4294967296;
2364
+ if (!Number.isSafeInteger(value)) {
2365
+ throw new ZipError("unsupported_feature", "ZIP64 value exceeds the supported range.");
2366
+ }
2367
+ return value;
2368
+ }
2369
+ async function inflateRaw(raw, limit, entryName) {
2370
+ const Stream = globalThis.DecompressionStream;
2371
+ if (typeof Stream !== "function") {
2372
+ throw new ZipError(
2373
+ "unsupported_environment",
2374
+ "Inflating ZIP entries needs DecompressionStream (modern browsers, Node 18+).",
2375
+ { entryName }
2376
+ );
2377
+ }
2378
+ const stream = new Stream("deflate-raw");
2379
+ const writer = stream.writable.getWriter();
2380
+ const reader = stream.readable.getReader();
2381
+ const CHUNK = 64 * 1024;
2382
+ const feeding = (async () => {
2383
+ for (let i = 0; i < raw.length; i += CHUNK) await writer.write(raw.subarray(i, i + CHUNK));
2384
+ await writer.close();
2385
+ })();
2386
+ feeding.catch(() => {
2387
+ });
2388
+ const chunks = [];
2389
+ let total = 0;
2390
+ try {
2391
+ for (; ; ) {
2392
+ const { done, value } = await reader.read();
2393
+ if (done) break;
2394
+ total += value.length;
2395
+ if (total > limit) {
2396
+ throw new ZipError(
2397
+ "corrupt_entry",
2398
+ `ZIP entry "${entryName}" inflates beyond its declared size of ${limit} bytes.`,
2399
+ { entryName }
2400
+ );
2401
+ }
2402
+ chunks.push(value);
2403
+ }
2404
+ } catch (error) {
2405
+ reader.cancel().catch(() => {
2406
+ });
2407
+ writer.abort().catch(() => {
2408
+ });
2409
+ if (error instanceof ZipError) throw error;
2410
+ throw new ZipError("corrupt_entry", `ZIP entry "${entryName}" has an invalid deflate stream.`, {
2411
+ entryName,
2412
+ cause: error
2413
+ });
2414
+ }
2415
+ await feeding.catch(() => {
2416
+ });
2417
+ const out = new Uint8Array(total);
2418
+ let pos = 0;
2419
+ for (const chunk of chunks) {
2420
+ out.set(chunk, pos);
2421
+ pos += chunk.length;
2422
+ }
2423
+ return out;
2424
+ }
2425
+ function findEndOfCentralDirectory(bytes) {
2426
+ const min = Math.max(0, bytes.length - EOCD_SIZE - MAX_COMMENT);
2427
+ for (let i = bytes.length - EOCD_SIZE; i >= min; i--) {
2428
+ if (readU32(bytes, i) === SIG_EOCD && i + EOCD_SIZE + readU16(bytes, i + 20) <= bytes.length) return i;
2429
+ }
2430
+ return -1;
2431
+ }
2432
+ async function readZip(data, options = {}) {
2433
+ const bytes = toBytes(data);
2434
+ const maxEntries = options.maxEntries ?? DEFAULT_ZIP_MAX_ENTRIES;
2435
+ const maxTotalSize = options.maxTotalSize ?? DEFAULT_ZIP_MAX_TOTAL_SIZE;
2436
+ const eocd = findEndOfCentralDirectory(bytes);
2437
+ if (eocd < 0) throw new ZipError("invalid_archive", "Not a ZIP archive (no end of central directory record).");
2438
+ let diskNumber = readU16(bytes, eocd + 4);
2439
+ let cdDisk = readU16(bytes, eocd + 6);
2440
+ let count = readU16(bytes, eocd + 10);
2441
+ let cdSize = readU32(bytes, eocd + 12);
2442
+ let cdOffset = readU32(bytes, eocd + 16);
2443
+ if (count === 65535 || cdSize === 4294967295 || cdOffset === 4294967295) {
2444
+ const locator = eocd - 20;
2445
+ if (locator < 0 || readU32(bytes, locator) !== SIG_ZIP64_LOCATOR) {
2446
+ throw new ZipError("invalid_archive", "ZIP64 archive is missing its end of central directory locator.");
2447
+ }
2448
+ const record = readU64(bytes, locator + 8);
2449
+ if (record + 56 > bytes.length || readU32(bytes, record) !== SIG_ZIP64_EOCD) {
2450
+ throw new ZipError("invalid_archive", "ZIP64 end of central directory record not found.");
2451
+ }
2452
+ diskNumber = readU32(bytes, record + 16);
2453
+ cdDisk = readU32(bytes, record + 20);
2454
+ count = readU64(bytes, record + 32);
2455
+ cdSize = readU64(bytes, record + 40);
2456
+ cdOffset = readU64(bytes, record + 48);
2457
+ }
2458
+ if (diskNumber !== 0 || cdDisk !== 0) {
2459
+ throw new ZipError("unsupported_feature", "Multi-disk (spanned) ZIP archives are not supported.");
2460
+ }
2461
+ if (count > maxEntries) {
2462
+ throw new ZipError("too_many_entries", `ZIP archive has ${count} entries; the limit is ${maxEntries}.`);
2463
+ }
2464
+ if (cdOffset + cdSize > bytes.length) {
2465
+ throw new ZipError("invalid_archive", "ZIP central directory lies outside the file.");
2466
+ }
2467
+ const entries = [];
2468
+ let p = cdOffset;
2469
+ for (let i = 0; i < count; i++) {
2470
+ if (p + 46 > bytes.length || readU32(bytes, p) !== SIG_CENTRAL) {
2471
+ throw new ZipError("invalid_archive", "ZIP central directory is corrupt.");
2472
+ }
2473
+ const flags = readU16(bytes, p + 8);
2474
+ const method = readU16(bytes, p + 10);
2475
+ const crc32 = readU32(bytes, p + 16);
2476
+ let compressedSize = readU32(bytes, p + 20);
2477
+ let size = readU32(bytes, p + 24);
2478
+ const nameLength = readU16(bytes, p + 28);
2479
+ const extraLength = readU16(bytes, p + 30);
2480
+ const commentLength = readU16(bytes, p + 32);
2481
+ let localHeaderOffset = readU32(bytes, p + 42);
2482
+ const nameStart = p + 46;
2483
+ const extraStart = nameStart + nameLength;
2484
+ const next = extraStart + extraLength + commentLength;
2485
+ if (next > bytes.length) throw new ZipError("invalid_archive", "ZIP central directory is truncated.");
2486
+ for (let e = extraStart; e + 4 <= extraStart + extraLength; ) {
2487
+ const id = readU16(bytes, e);
2488
+ const len = readU16(bytes, e + 2);
2489
+ if (id === 1) {
2490
+ let f = e + 4;
2491
+ const end = f + len;
2492
+ if (size === 4294967295 && f + 8 <= end) {
2493
+ size = readU64(bytes, f);
2494
+ f += 8;
2495
+ }
2496
+ if (compressedSize === 4294967295 && f + 8 <= end) {
2497
+ compressedSize = readU64(bytes, f);
2498
+ f += 8;
2499
+ }
2500
+ if (localHeaderOffset === 4294967295 && f + 8 <= end) localHeaderOffset = readU64(bytes, f);
2501
+ }
2502
+ e += 4 + len;
2503
+ }
2504
+ const rawName = decodeName(bytes.subarray(nameStart, extraStart), (flags & 2048) !== 0);
2505
+ const name = rawName.replace(/\\/g, "/");
2506
+ p = next;
2507
+ if (isUnsafeZipPath(rawName)) {
2508
+ if (options.unsafePaths === "skip") continue;
2509
+ throw new ZipError("unsafe_path", `ZIP entry name "${rawName}" is absolute or escapes the archive root.`, {
2510
+ entryName: rawName
2511
+ });
2512
+ }
2513
+ entries.push({
2514
+ name,
2515
+ isDirectory: name.endsWith("/"),
2516
+ encrypted: (flags & 1) !== 0,
2517
+ method,
2518
+ compressedSize,
2519
+ size,
2520
+ crc32,
2521
+ localHeaderOffset
2522
+ });
2523
+ }
2524
+ return new ZipArchive(bytes, entries, maxTotalSize);
2525
+ }
2526
+
2527
+ // src/import/docx.ts
2528
+ var DOCX_MIME_TYPES = [
2529
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
2530
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.template",
2531
+ "application/vnd.ms-word.document.macroenabled.12"
2532
+ ];
2533
+ var DEFAULT_DOCX_MAX_IMAGE_SIZE = 10 * 1024 * 1024;
2534
+ var W_NAMESPACES = /* @__PURE__ */ new Set([
2535
+ "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
2536
+ "http://purl.oclc.org/ooxml/wordprocessingml/main"
2537
+ ]);
2538
+ var IMAGE_MIME_TYPES = {
2539
+ png: "image/png",
2540
+ jpg: "image/jpeg",
2541
+ jpeg: "image/jpeg",
2542
+ jpe: "image/jpeg",
2543
+ gif: "image/gif",
2544
+ webp: "image/webp"
2545
+ };
2546
+ function isW(node, localName) {
2547
+ if (!node || node.nodeType !== 1) return false;
2548
+ const el = node;
2549
+ if (localName !== void 0 && el.localName !== localName) return false;
2550
+ return W_NAMESPACES.has(el.namespaceURI ?? "") || el.prefix === "w";
2551
+ }
2552
+ function childElements(el) {
2553
+ const out = [];
2554
+ for (let node = el.firstChild; node; node = node.nextSibling) {
2555
+ if (node.nodeType === 1) out.push(node);
2556
+ }
2557
+ return out;
2558
+ }
2559
+ function wChild(el, localName) {
2560
+ if (!el) return void 0;
2561
+ return childElements(el).find((child) => isW(child, localName));
2562
+ }
2563
+ function attr(el, localName) {
2564
+ if (!el) return void 0;
2565
+ for (const a of Array.from(el.attributes)) {
2566
+ if (a.localName === localName) return a.value;
2567
+ }
2568
+ return void 0;
2569
+ }
2570
+ function descendants(el, localName) {
2571
+ return Array.from(el.getElementsByTagName("*")).filter((node) => node.localName === localName);
2572
+ }
2573
+ function toggle(el) {
2574
+ if (!el) return void 0;
2575
+ const value = attr(el, "val")?.toLowerCase();
2576
+ return value === void 0 || !["0", "false", "off", "none"].includes(value);
2577
+ }
2578
+ function parseXml(Parser, xml, partName) {
2579
+ const doc = new Parser().parseFromString(xml, "application/xml");
2580
+ if (!doc.documentElement || doc.getElementsByTagName("parsererror").length > 0) {
2581
+ throw new ImportError("invalid_file", `DOCX part "${partName}" is not well-formed XML.`);
2582
+ }
2583
+ return doc;
2584
+ }
2585
+ function dirname(path) {
2586
+ const index = path.lastIndexOf("/");
2587
+ return index === -1 ? "" : path.slice(0, index + 1);
2588
+ }
2589
+ function resolvePartPath(baseDir, target) {
2590
+ const raw = target.startsWith("/") ? target.slice(1) : baseDir + target;
2591
+ const out = [];
2592
+ for (const segment of raw.split("/")) {
2593
+ if (segment === "" || segment === ".") continue;
2594
+ if (segment === "..") out.pop();
2595
+ else out.push(segment);
2596
+ }
2597
+ return out.join("/");
2598
+ }
2599
+ function relsPathFor(partPath) {
2600
+ return `${dirname(partPath)}_rels/${partPath.slice(dirname(partPath).length)}.rels`;
2601
+ }
2602
+ async function readXmlPart(zip, Parser, path) {
2603
+ const entry = zip.get(path) ?? zip.entries.find((e) => e.name.toLowerCase() === path.toLowerCase());
2604
+ if (!entry) return null;
2605
+ return parseXml(Parser, await zip.readText(entry), path);
2606
+ }
2607
+ async function readRelationships(zip, Parser, partPath) {
2608
+ const rels = /* @__PURE__ */ new Map();
2609
+ const doc = await readXmlPart(zip, Parser, relsPathFor(partPath));
2610
+ if (!doc) return rels;
2611
+ const baseDir = dirname(partPath);
2612
+ descendants(doc, "Relationship").forEach((rel) => {
2613
+ const id = attr(rel, "Id");
2614
+ const target = attr(rel, "Target") ?? "";
2615
+ if (!id) return;
2616
+ const external = attr(rel, "TargetMode")?.toLowerCase() === "external";
2617
+ rels.set(id, {
2618
+ type: attr(rel, "Type") ?? "",
2619
+ target: external ? target : resolvePartPath(baseDir, target),
2620
+ external
2621
+ });
2622
+ });
2623
+ return rels;
2624
+ }
2625
+ function toBase64(bytes) {
2626
+ let binary = "";
2627
+ const CHUNK = 32768;
2628
+ for (let i = 0; i < bytes.length; i += CHUNK) {
2629
+ binary += String.fromCharCode.apply(null, Array.from(bytes.subarray(i, i + CHUNK)));
2630
+ }
2631
+ return btoa(binary);
2632
+ }
2633
+ async function loadImages(zip, root, rels, options) {
2634
+ const images = /* @__PURE__ */ new Map();
2635
+ if (options.images === false) return images;
2636
+ const maxSize = options.maxImageSize ?? DEFAULT_DOCX_MAX_IMAGE_SIZE;
2637
+ const ids = /* @__PURE__ */ new Set();
2638
+ descendants(root, "blip").forEach((blip) => {
2639
+ const id = attr(blip, "embed");
2640
+ if (id) ids.add(id);
2641
+ });
2642
+ descendants(root, "imagedata").forEach((data) => {
2643
+ const id = attr(data, "id");
2644
+ if (id) ids.add(id);
2645
+ });
2646
+ for (const id of ids) {
2647
+ const rel = rels.get(id);
2648
+ if (!rel || rel.external) continue;
2649
+ const mime = IMAGE_MIME_TYPES[rel.target.split(".").pop()?.toLowerCase() ?? ""];
2650
+ const entry = zip.get(rel.target);
2651
+ if (!mime || !entry || entry.size > maxSize) continue;
2652
+ images.set(id, `data:${mime};base64,${toBase64(await zip.read(entry))}`);
2653
+ }
2654
+ return images;
2655
+ }
2656
+ function readFormat(rPr) {
2657
+ const format = {};
2658
+ if (!rPr) return format;
2659
+ const set = (key, value) => {
2660
+ if (value !== void 0) format[key] = value;
2661
+ };
2662
+ set("b", toggle(wChild(rPr, "b")));
2663
+ set("i", toggle(wChild(rPr, "i")));
2664
+ set("u", toggle(wChild(rPr, "u")));
2665
+ const strike = toggle(wChild(rPr, "strike"));
2666
+ const dstrike = toggle(wChild(rPr, "dstrike"));
2667
+ if (strike !== void 0 || dstrike !== void 0) format.s = !!(strike || dstrike);
2668
+ const vertAlign = attr(wChild(rPr, "vertAlign"), "val");
2669
+ if (vertAlign) {
2670
+ format.sup = vertAlign === "superscript";
2671
+ format.sub = vertAlign === "subscript";
2672
+ }
2673
+ return format;
2674
+ }
2675
+ function readNumPr(pPr) {
2676
+ const numPr = wChild(pPr, "numPr");
2677
+ if (!numPr) return void 0;
2678
+ const numId = attr(wChild(numPr, "numId"), "val");
2679
+ if (numId === void 0) return void 0;
2680
+ return { numId, ilvl: Number(attr(wChild(numPr, "ilvl"), "val") ?? 0) || 0 };
2681
+ }
2682
+ function readStyles(doc) {
2683
+ const styles = /* @__PURE__ */ new Map();
2684
+ if (!doc) return styles;
2685
+ descendants(doc, "style").forEach((style) => {
2686
+ const id = attr(style, "styleId");
2687
+ if (!id) return;
2688
+ const pPr = wChild(style, "pPr");
2689
+ const outline = attr(wChild(pPr, "outlineLvl"), "val");
2690
+ styles.set(id, {
2691
+ name: attr(wChild(style, "name"), "val") ?? id,
2692
+ basedOn: attr(wChild(style, "basedOn"), "val"),
2693
+ outlineLevel: outline !== void 0 ? Number(outline) : void 0,
2694
+ numPr: readNumPr(pPr),
2695
+ format: readFormat(wChild(style, "rPr"))
2696
+ });
2697
+ });
2698
+ return styles;
2699
+ }
2700
+ function styleChain(styles, id) {
2701
+ const chain = [];
2702
+ const seen = /* @__PURE__ */ new Set();
2703
+ while (id && !seen.has(id)) {
2704
+ seen.add(id);
2705
+ const style = styles.get(id);
2706
+ if (!style) break;
2707
+ chain.push(style);
2708
+ id = style.basedOn;
2709
+ }
2710
+ return chain;
2711
+ }
2712
+ function styleHeadingLevel(styles, id) {
2713
+ if (id && /^heading([1-6])$/i.test(id)) return Number(id.slice(-1));
2714
+ for (const style of styleChain(styles, id)) {
2715
+ const byName = /^heading\s*([1-6])$/i.exec(style.name);
2716
+ if (byName) return Number(byName[1]);
2717
+ if (/^title$/i.test(style.name)) return 1;
2718
+ if (style.outlineLevel !== void 0) {
2719
+ return style.outlineLevel >= 0 && style.outlineLevel <= 5 ? style.outlineLevel + 1 : void 0;
2720
+ }
2721
+ }
2722
+ if (id && /^title$/i.test(id)) return 1;
2723
+ return void 0;
2724
+ }
2725
+ function readNumbering(doc) {
2726
+ const numbering = { abstracts: /* @__PURE__ */ new Map(), nums: /* @__PURE__ */ new Map() };
2727
+ if (!doc) return numbering;
2728
+ descendants(doc, "abstractNum").forEach((abstract) => {
2729
+ const id = attr(abstract, "abstractNumId");
2730
+ if (id === void 0) return;
2731
+ const levels = /* @__PURE__ */ new Map();
2732
+ childElements(abstract).filter((el) => isW(el, "lvl")).forEach((lvl) => {
2733
+ const format = attr(wChild(lvl, "numFmt"), "val") ?? "bullet";
2734
+ levels.set(Number(attr(lvl, "ilvl") ?? 0), {
2735
+ ordered: format !== "bullet" && format !== "none",
2736
+ start: Number(attr(wChild(lvl, "start"), "val") ?? 1) || 1
2737
+ });
2738
+ });
2739
+ numbering.abstracts.set(id, levels);
2740
+ });
2741
+ descendants(doc, "num").forEach((num) => {
2742
+ const id = attr(num, "numId");
2743
+ const abstractId = attr(wChild(num, "abstractNumId"), "val");
2744
+ if (id === void 0 || abstractId === void 0) return;
2745
+ const starts = /* @__PURE__ */ new Map();
2746
+ childElements(num).filter((el) => isW(el, "lvlOverride")).forEach((override) => {
2747
+ const start2 = attr(wChild(override, "startOverride"), "val");
2748
+ if (start2 !== void 0) starts.set(Number(attr(override, "ilvl") ?? 0), Number(start2));
2749
+ });
2750
+ numbering.nums.set(id, { abstractId, starts });
2751
+ });
2752
+ return numbering;
2753
+ }
2754
+ var formatKey = (f) => `${f.b ? 1 : 0}${f.i ? 1 : 0}${f.u ? 1 : 0}${f.s ? 1 : 0}${f.sup ? 1 : 0}${f.sub ? 1 : 0}|${f.href ?? ""}`;
2755
+ function wrapFormat(inner, f) {
2756
+ let html = inner;
2757
+ if (f.sup) html = `<sup>${html}</sup>`;
2758
+ else if (f.sub) html = `<sub>${html}</sub>`;
2759
+ if (f.s) html = `<s>${html}</s>`;
2760
+ if (f.u) html = `<u>${html}</u>`;
2761
+ if (f.i) html = `<em>${html}</em>`;
2762
+ if (f.b) html = `<strong>${html}</strong>`;
2763
+ if (f.href) html = `<a href="${escapeHtml(f.href)}">${html}</a>`;
2764
+ return html;
2765
+ }
2766
+ function renderSegments(segments) {
2767
+ let html = "";
2768
+ let i = 0;
2769
+ while (i < segments.length) {
2770
+ const key = formatKey(segments[i].format);
2771
+ let inner = "";
2772
+ let j = i;
2773
+ for (; j < segments.length && formatKey(segments[j].format) === key; j++) {
2774
+ const seg = segments[j];
2775
+ if (seg.kind === "text") inner += escapeHtml(seg.text);
2776
+ else if (seg.kind === "br") inner += "<br>";
2777
+ else if (seg.kind === "img") inner += `<img src="${escapeHtml(seg.src)}" alt="${escapeHtml(seg.alt)}">`;
2778
+ else inner += `<sup>${seg.n}</sup>`;
2779
+ }
2780
+ html += wrapFormat(inner, segments[i].format);
2781
+ i = j;
2782
+ }
2783
+ return html;
2784
+ }
2785
+ function parseHyperlinkInstruction(instr) {
2786
+ const match = /^\s*HYPERLINK\b(.*)$/i.exec(instr);
2787
+ if (!match) return void 0;
2788
+ const rest = match[1];
2789
+ const anchor = /\\l\s+"([^"]*)"/.exec(rest)?.[1];
2790
+ const target = /^\s*(?:"([^"]*)"|([^\s\\]+))/.exec(rest);
2791
+ const url = target?.[1] ?? target?.[2];
2792
+ if (url) return anchor ? `${url}#${anchor}` : url;
2793
+ return anchor ? `#${anchor}` : void 0;
2794
+ }
2795
+ var ParagraphRenderer = class {
2796
+ constructor(ctx, part) {
2797
+ this.ctx = ctx;
2798
+ this.part = part;
2799
+ }
2800
+ ctx;
2801
+ part;
2802
+ segments = [];
2803
+ /** Open complex fields (`w:fldChar`), innermost last. */
2804
+ fields = [];
2805
+ render(p) {
2806
+ this.walk(p, {});
2807
+ return renderSegments(this.segments);
2808
+ }
2809
+ fieldHref() {
2810
+ for (let i = this.fields.length - 1; i >= 0; i--) {
2811
+ if (this.fields[i].separated && this.fields[i].href) return this.fields[i].href;
2812
+ }
2813
+ return void 0;
2814
+ }
2815
+ inFieldInstruction() {
2816
+ return this.fields.some((field) => !field.separated);
2817
+ }
2818
+ walk(el, base) {
2819
+ const accepted = this.ctx.tracked === "accepted";
2820
+ for (const child of childElements(el)) {
2821
+ if (!isW(child)) {
2822
+ continue;
2823
+ }
2824
+ switch (child.localName) {
2825
+ case "r":
2826
+ this.run(child, base);
2827
+ break;
2828
+ case "hyperlink": {
2829
+ const relId = attr(child, "id");
2830
+ const rel = relId ? this.part.rels.get(relId) : void 0;
2831
+ const anchor = attr(child, "anchor");
2832
+ const href = rel ? rel.target + (anchor ? `#${anchor}` : "") : anchor ? `#${anchor}` : void 0;
2833
+ this.walk(child, href ? { ...base, href } : base);
2834
+ break;
2835
+ }
2836
+ case "fldSimple": {
2837
+ const href = parseHyperlinkInstruction(attr(child, "instr") ?? "");
2838
+ this.walk(child, href ? { ...base, href } : base);
2839
+ break;
2840
+ }
2841
+ case "ins":
2842
+ case "moveTo":
2843
+ if (accepted) this.walk(child, base);
2844
+ break;
2845
+ case "del":
2846
+ case "moveFrom":
2847
+ if (!accepted) this.walk(child, base);
2848
+ break;
2849
+ case "sdt":
2850
+ this.walk(wChild(child, "sdtContent") ?? child, base);
2851
+ break;
2852
+ case "smartTag":
2853
+ case "customXml":
2854
+ case "dir":
2855
+ case "bdo":
2856
+ case "sdtContent":
2857
+ this.walk(child, base);
2858
+ break;
2859
+ default:
2860
+ break;
2861
+ }
2862
+ }
2863
+ }
2864
+ run(r, base) {
2865
+ const rPr = wChild(r, "rPr");
2866
+ const styleFormat = this.ctx.styles.get(attr(wChild(rPr, "rStyle"), "val") ?? "")?.format ?? {};
2867
+ const own = readFormat(rPr);
2868
+ const format = { ...base, ...styleFormat, ...own };
2869
+ for (const child of childElements(r)) {
2870
+ this.runChild(child, format);
2871
+ }
2872
+ }
2873
+ runChild(child, format) {
2874
+ const push = (segment) => {
2875
+ if (this.inFieldInstruction()) return;
2876
+ const href = format.href ?? this.fieldHref();
2877
+ this.segments.push(href && !format.href ? { ...segment, format: { ...format, href } } : segment);
2878
+ };
2879
+ if (child.localName === "AlternateContent") {
2880
+ const branch = childElements(child).find(
2881
+ (b) => descendants(b, "blip").length || descendants(b, "imagedata").length
2882
+ );
2883
+ if (branch) this.image(branch, format, push);
2884
+ return;
2885
+ }
2886
+ if (!isW(child)) return;
2887
+ switch (child.localName) {
2888
+ case "t":
2889
+ push({ kind: "text", text: child.textContent ?? "", format });
2890
+ break;
2891
+ case "delText":
2892
+ if (this.ctx.tracked === "original") push({ kind: "text", text: child.textContent ?? "", format });
2893
+ break;
2894
+ case "tab":
2895
+ case "ptab":
2896
+ push({ kind: "text", text: " ", format });
2897
+ break;
2898
+ case "br": {
2899
+ const type = attr(child, "type");
2900
+ if (type !== "page" && type !== "column") push({ kind: "br", format });
2901
+ break;
2902
+ }
2903
+ case "cr":
2904
+ push({ kind: "br", format });
2905
+ break;
2906
+ case "noBreakHyphen":
2907
+ push({ kind: "text", text: "\u2011", format });
2908
+ break;
2909
+ case "drawing":
2910
+ case "pict":
2911
+ case "object":
2912
+ this.image(child, format, push);
2913
+ break;
2914
+ case "footnoteReference":
2915
+ case "endnoteReference": {
2916
+ const kind = child.localName === "footnoteReference" ? "footnote" : "endnote";
2917
+ const key = `${kind}:${attr(child, "id")}`;
2918
+ if (!this.ctx.notes.has(key)) break;
2919
+ let index = this.ctx.noteOrder.indexOf(key);
2920
+ if (index === -1) index = this.ctx.noteOrder.push(key) - 1;
2921
+ push({ kind: "note", n: index + 1, format: { ...format, sup: false, sub: false } });
2922
+ break;
2923
+ }
2924
+ case "fldChar": {
2925
+ const type = attr(child, "fldCharType");
2926
+ if (type === "begin") this.fields.push({ instr: "", separated: false });
2927
+ else if (type === "separate") {
2928
+ const field = this.fields[this.fields.length - 1];
2929
+ if (field) {
2930
+ field.separated = true;
2931
+ field.href = parseHyperlinkInstruction(field.instr);
2932
+ }
2933
+ } else if (type === "end") this.fields.pop();
2934
+ break;
2935
+ }
2936
+ case "instrText": {
2937
+ const field = this.fields[this.fields.length - 1];
2938
+ if (field && !field.separated) field.instr += child.textContent ?? "";
2939
+ break;
2940
+ }
2941
+ default:
2942
+ break;
2943
+ }
2944
+ }
2945
+ image(container, format, push) {
2946
+ const blip = descendants(container, "blip")[0];
2947
+ const imageData = descendants(container, "imagedata")[0];
2948
+ const id = blip ? attr(blip, "embed") : attr(imageData, "id");
2949
+ const src = id ? this.part.images.get(id) : void 0;
2950
+ if (!src) return;
2951
+ const docPr = descendants(container, "docPr")[0];
2952
+ const alt = attr(docPr, "descr") || attr(docPr, "title") || attr(imageData, "title") || "";
2953
+ push({ kind: "img", src, alt, format });
2954
+ }
2955
+ };
2956
+ function flattenBlocks(container, ctx, out = []) {
2957
+ const accepted = ctx.tracked === "accepted";
2958
+ for (const child of childElements(container)) {
2959
+ if (!isW(child)) continue;
2960
+ switch (child.localName) {
2961
+ case "p":
2962
+ case "tbl":
2963
+ out.push(child);
2964
+ break;
2965
+ case "sdt":
2966
+ flattenBlocks(wChild(child, "sdtContent") ?? child, ctx, out);
2967
+ break;
2968
+ case "sdtContent":
2969
+ case "customXml":
2970
+ flattenBlocks(child, ctx, out);
2971
+ break;
2972
+ case "ins":
2973
+ case "moveTo":
2974
+ if (accepted) flattenBlocks(child, ctx, out);
2975
+ break;
2976
+ case "del":
2977
+ case "moveFrom":
2978
+ if (!accepted) flattenBlocks(child, ctx, out);
2979
+ break;
2980
+ default:
2981
+ break;
2982
+ }
2983
+ }
2984
+ return out;
2985
+ }
2986
+ function paragraphInfo(p, ctx) {
2987
+ const pPr = wChild(p, "pPr");
2988
+ const styleId = attr(wChild(pPr, "pStyle"), "val");
2989
+ const outline = attr(wChild(pPr, "outlineLvl"), "val");
2990
+ let heading;
2991
+ if (outline !== void 0) {
2992
+ const level = Number(outline);
2993
+ heading = level >= 0 && level <= 5 ? level + 1 : void 0;
2994
+ } else {
2995
+ heading = styleHeadingLevel(ctx.styles, styleId);
2996
+ }
2997
+ let numPr = readNumPr(pPr);
2998
+ if (!numPr) numPr = styleChain(ctx.styles, styleId).find((style) => style.numPr)?.numPr;
2999
+ let list;
3000
+ if (numPr && numPr.numId !== "0" && heading === void 0) {
3001
+ const num = ctx.numbering.nums.get(numPr.numId);
3002
+ const def = num ? ctx.numbering.abstracts.get(num.abstractId)?.get(numPr.ilvl) : void 0;
3003
+ list = {
3004
+ level: Math.max(0, Math.min(numPr.ilvl, 8)),
3005
+ ordered: def?.ordered ?? false,
3006
+ start: num?.starts.get(numPr.ilvl) ?? def?.start ?? 1
3007
+ };
3008
+ }
3009
+ return { heading, list };
3010
+ }
3011
+ function renderBlocks(container, ctx, part) {
3012
+ let html = "";
3013
+ const stack = [];
3014
+ const closeList = () => {
3015
+ const top = stack.pop();
3016
+ html += `</li></${top.tag}>`;
3017
+ };
3018
+ const closeAll = () => {
3019
+ while (stack.length) closeList();
3020
+ };
3021
+ for (const block of flattenBlocks(container, ctx)) {
3022
+ if (block.localName === "tbl") {
3023
+ closeAll();
3024
+ html += renderTable(block, ctx, part);
3025
+ continue;
3026
+ }
3027
+ const { heading, list } = paragraphInfo(block, ctx);
3028
+ const inner = new ParagraphRenderer(ctx, part).render(block);
3029
+ const blockHtml = heading ? `<h${heading}>${inner}</h${heading}>` : `<p>${inner}</p>`;
3030
+ if (!list) {
3031
+ closeAll();
3032
+ html += blockHtml;
3033
+ continue;
3034
+ }
3035
+ const tag = list.ordered ? "ol" : "ul";
3036
+ while (stack.length && stack[stack.length - 1].level > list.level) closeList();
3037
+ const top = stack[stack.length - 1];
3038
+ if (top && top.level === list.level && top.tag === tag) {
3039
+ html += "</li><li>";
3040
+ } else {
3041
+ if (top && top.level === list.level) closeList();
3042
+ const start2 = tag === "ol" && list.start !== 1 ? ` start="${list.start}"` : "";
3043
+ html += `<${tag}${start2}><li>`;
3044
+ stack.push({ level: list.level, tag });
3045
+ }
3046
+ html += blockHtml;
3047
+ }
3048
+ closeAll();
3049
+ return html;
3050
+ }
3051
+ function renderTable(tbl, ctx, part) {
3052
+ const rows = [];
3053
+ const collectRows = (container) => {
3054
+ for (const child of childElements(container)) {
3055
+ if (isW(child, "tr")) {
3056
+ const header = !!toggle(wChild(wChild(child, "trPr"), "tblHeader"));
3057
+ const cells = [];
3058
+ let col = 0;
3059
+ const collectCells = (row) => {
3060
+ for (const cellEl of childElements(row)) {
3061
+ if (isW(cellEl, "tc")) {
3062
+ const tcPr = wChild(cellEl, "tcPr");
3063
+ const span = Math.max(1, Number(attr(wChild(tcPr, "gridSpan"), "val") ?? 1) || 1);
3064
+ const vMerge = wChild(tcPr, "vMerge");
3065
+ const merge = vMerge ? attr(vMerge, "val") === "restart" ? "restart" : "continue" : void 0;
3066
+ cells.push({ el: cellEl, col, span, merge, header });
3067
+ col += span;
3068
+ } else if (isW(cellEl, "sdt")) {
3069
+ collectCells(wChild(cellEl, "sdtContent") ?? cellEl);
3070
+ }
3071
+ }
3072
+ };
3073
+ collectCells(child);
3074
+ rows.push(cells);
3075
+ } else if (isW(child, "sdt")) {
3076
+ collectRows(wChild(child, "sdtContent") ?? child);
3077
+ }
3078
+ }
3079
+ };
3080
+ collectRows(tbl);
3081
+ let html = "<table><tbody>";
3082
+ rows.forEach((cells, rowIndex) => {
3083
+ html += "<tr>";
3084
+ for (const cell of cells) {
3085
+ if (cell.merge === "continue") continue;
3086
+ let rowspan = 1;
3087
+ if (cell.merge === "restart") {
3088
+ for (let r = rowIndex + 1; r < rows.length; r++) {
3089
+ const below = rows[r].find((c) => c.col === cell.col);
3090
+ if (below?.merge !== "continue") break;
3091
+ rowspan++;
3092
+ }
3093
+ }
3094
+ const tag = cell.header ? "th" : "td";
3095
+ const attrs = `${cell.span > 1 ? ` colspan="${cell.span}"` : ""}${rowspan > 1 ? ` rowspan="${rowspan}"` : ""}`;
3096
+ html += `<${tag}${attrs}>${renderBlocks(cell.el, ctx, part) || "<p></p>"}</${tag}>`;
3097
+ }
3098
+ html += "</tr>";
3099
+ });
3100
+ return `${html}</tbody></table>`;
3101
+ }
3102
+ function getDomParser(options) {
3103
+ const Parser = options.DOMParser ?? globalThis.DOMParser ?? globalThis.window?.DOMParser;
3104
+ if (typeof Parser !== "function") {
3105
+ throw new ImportError(
3106
+ "unsupported_environment",
3107
+ "DOCX import needs a DOMParser. In Node, pass one with createDocxImportAdapter({ DOMParser }) (e.g. from jsdom)."
3108
+ );
3109
+ }
3110
+ return Parser;
3111
+ }
3112
+ async function docxToDocumentImport(data, options = {}) {
3113
+ const Parser = getDomParser(options);
3114
+ let zip;
3115
+ try {
3116
+ zip = await readZip(data, { maxTotalSize: 100 * 1024 * 1024, maxEntries: 5e3, ...options.zip });
3117
+ } catch (error) {
3118
+ if (error?.code === "invalid_archive") {
3119
+ throw new ImportError("invalid_file", "Not a DOCX file (the file is not a ZIP package).", { cause: error });
3120
+ }
3121
+ throw error;
3122
+ }
3123
+ let mainPath = "word/document.xml";
3124
+ const packageRels = await readXmlPart(zip, Parser, "_rels/.rels");
3125
+ if (packageRels) {
3126
+ const office = descendants(packageRels, "Relationship").find(
3127
+ (rel) => /\/officeDocument$/.test(attr(rel, "Type") ?? "")
3128
+ );
3129
+ const target = attr(office, "Target");
3130
+ if (target) mainPath = resolvePartPath("", target);
3131
+ }
3132
+ const documentXml = await readXmlPart(zip, Parser, mainPath);
3133
+ const body = documentXml ? descendants(documentXml, "body").find((el) => isW(el)) : void 0;
3134
+ if (!documentXml || !body) {
3135
+ throw new ImportError("invalid_file", "Not a Word document (no main document part with a body).");
3136
+ }
3137
+ const rels = await readRelationships(zip, Parser, mainPath);
3138
+ const partByType = (suffix) => Array.from(rels.values()).find((rel) => !rel.external && rel.type.endsWith(`/${suffix}`))?.target;
3139
+ const baseDir = dirname(mainPath);
3140
+ const stylesPath = partByType("styles") ?? `${baseDir}styles.xml`;
3141
+ const numberingPath = partByType("numbering") ?? `${baseDir}numbering.xml`;
3142
+ const ctx = {
3143
+ styles: readStyles(await readXmlPart(zip, Parser, stylesPath)),
3144
+ numbering: readNumbering(await readXmlPart(zip, Parser, numberingPath)),
3145
+ notes: /* @__PURE__ */ new Map(),
3146
+ noteOrder: [],
3147
+ tracked: options.trackedChanges ?? "accepted"
3148
+ };
3149
+ for (const kind of ["footnote", "endnote"]) {
3150
+ const path = partByType(`${kind}s`) ?? `${baseDir}${kind}s.xml`;
3151
+ const notesXml = await readXmlPart(zip, Parser, path);
3152
+ if (!notesXml) continue;
3153
+ const noteRels = await readRelationships(zip, Parser, path);
3154
+ const part2 = { rels: noteRels, images: await loadImages(zip, notesXml, noteRels, options) };
3155
+ descendants(notesXml, kind).filter((note) => isW(note)).forEach((note) => {
3156
+ const type = attr(note, "type");
3157
+ if (type && type !== "normal") return;
3158
+ ctx.notes.set(`${kind}:${attr(note, "id")}`, { element: note, part: part2 });
3159
+ });
3160
+ }
3161
+ const part = { rels, images: await loadImages(zip, documentXml, rels, options) };
3162
+ let html = renderBlocks(body, ctx, part);
3163
+ if (ctx.noteOrder.length) {
3164
+ let notesHtml = "";
3165
+ for (let i = 0; i < ctx.noteOrder.length; i++) {
3166
+ const note = ctx.notes.get(ctx.noteOrder[i]);
3167
+ notesHtml += `<li>${renderBlocks(note.element, ctx, note.part) || "<p></p>"}</li>`;
3168
+ }
3169
+ html += `<hr><ol>${notesHtml}</ol>`;
3170
+ }
3171
+ const sanitized = sanitizeImportedHtml(html);
3172
+ return { html: sanitized, text: htmlToPlainText(sanitized) };
3173
+ }
3174
+ function createDocxImportAdapter(options = {}) {
3175
+ return {
3176
+ id: options.id ?? "docx",
3177
+ label: "Word document",
3178
+ mimeTypes: DOCX_MIME_TYPES,
3179
+ extensions: [".docx", ".docm", ".dotx"],
3180
+ target: "document",
3181
+ async import(_input, context) {
3182
+ return docxToDocumentImport(await context.readArrayBuffer(), options);
3183
+ }
3184
+ };
3185
+ }
3186
+ var docxImportAdapter = createDocxImportAdapter();
3187
+
2209
3188
  // src/import/adapters.ts
2210
3189
  var markdownImportAdapter = {
2211
3190
  id: "markdown",
@@ -2255,7 +3234,8 @@ var BUILT_IN_IMPORT_ADAPTERS = [
2255
3234
  markdownImportAdapter,
2256
3235
  htmlImportAdapter,
2257
3236
  plainTextImportAdapter,
2258
- rtfImportAdapter
3237
+ rtfImportAdapter,
3238
+ docxImportAdapter
2259
3239
  ];
2260
3240
  function createImportAdapterRegistry(options = {}) {
2261
3241
  const registry = new ImportAdapterRegistry();
@@ -4418,6 +5398,18 @@ export {
4418
5398
  ImportError,
4419
5399
  createImportContext,
4420
5400
  ImportAdapterRegistry,
5401
+ ZipError,
5402
+ DEFAULT_ZIP_MAX_ENTRIES,
5403
+ DEFAULT_ZIP_MAX_TOTAL_SIZE,
5404
+ zipCrc32,
5405
+ isUnsafeZipPath,
5406
+ ZipArchive,
5407
+ readZip,
5408
+ DOCX_MIME_TYPES,
5409
+ DEFAULT_DOCX_MAX_IMAGE_SIZE,
5410
+ docxToDocumentImport,
5411
+ createDocxImportAdapter,
5412
+ docxImportAdapter,
4421
5413
  markdownImportAdapter,
4422
5414
  htmlImportAdapter,
4423
5415
  plainTextImportAdapter,
@@ -4477,4 +5469,4 @@ export {
4477
5469
  getDocumentStructureCommandItems,
4478
5470
  createRichTextPreset
4479
5471
  };
4480
- //# sourceMappingURL=chunk-CYFJCKC4.js.map
5472
+ //# sourceMappingURL=chunk-QGHGJ56O.js.map