hwpkit-dev 0.0.1

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/dist/index.js ADDED
@@ -0,0 +1,3546 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ A4: () => A4,
34
+ ArchiveKit: () => ArchiveKit,
35
+ BinaryKit: () => BinaryKit,
36
+ DEFAULT_STROKE: () => DEFAULT_STROKE,
37
+ Metric: () => Metric,
38
+ Pipeline: () => Pipeline,
39
+ ShieldedParser: () => ShieldedParser,
40
+ TextKit: () => TextKit,
41
+ TreeWalker: () => TreeWalker,
42
+ XmlKit: () => XmlKit,
43
+ buildCell: () => buildCell,
44
+ buildGrid: () => buildGrid,
45
+ buildImg: () => buildImg,
46
+ buildPageNum: () => buildPageNum,
47
+ buildPara: () => buildPara,
48
+ buildRoot: () => buildRoot,
49
+ buildRow: () => buildRow,
50
+ buildSheet: () => buildSheet,
51
+ buildSpan: () => buildSpan,
52
+ countNodes: () => countNodes,
53
+ fail: () => fail,
54
+ registry: () => registry,
55
+ safeAlign: () => safeAlign,
56
+ safeFont: () => safeFont,
57
+ safeFontToKr: () => safeFontToKr,
58
+ safeHex: () => safeHex,
59
+ safeStrokeDocx: () => safeStrokeDocx,
60
+ safeStrokeHwpx: () => safeStrokeHwpx,
61
+ succeed: () => succeed,
62
+ validateRoot: () => validateRoot,
63
+ walkNode: () => walkNode
64
+ });
65
+ module.exports = __toCommonJS(index_exports);
66
+
67
+ // src/contract/result.ts
68
+ function succeed(data, warns = []) {
69
+ return { ok: true, data, warns };
70
+ }
71
+ function fail(error, warns = []) {
72
+ return { ok: false, error, warns };
73
+ }
74
+
75
+ // src/pipeline/registry.ts
76
+ var FormatRegistry = class {
77
+ constructor() {
78
+ this.decoders = /* @__PURE__ */ new Map();
79
+ this.encoders = /* @__PURE__ */ new Map();
80
+ }
81
+ registerDecoder(d) {
82
+ this.decoders.set(d.format, d);
83
+ }
84
+ registerEncoder(e) {
85
+ this.encoders.set(e.format, e);
86
+ }
87
+ getDecoder(fmt) {
88
+ return this.decoders.get(fmt);
89
+ }
90
+ getEncoder(fmt) {
91
+ return this.encoders.get(fmt);
92
+ }
93
+ supportedInputs() {
94
+ return [...this.decoders.keys()];
95
+ }
96
+ supportedOutputs() {
97
+ return [...this.encoders.keys()];
98
+ }
99
+ };
100
+ var registry = new FormatRegistry();
101
+
102
+ // src/model/doc-props.ts
103
+ var A4 = {
104
+ wPt: 595.28,
105
+ hPt: 841.89,
106
+ mt: 56.69,
107
+ mb: 56.69,
108
+ ml: 70.87,
109
+ mr: 70.87,
110
+ orient: "portrait"
111
+ };
112
+ var DEFAULT_STROKE = { kind: "solid", pt: 0.5, color: "000000" };
113
+
114
+ // src/model/builders.ts
115
+ function buildRoot(meta = {}, kids = []) {
116
+ return { tag: "root", meta, kids };
117
+ }
118
+ function buildSheet(kids = [], dims = A4, opts) {
119
+ const node = { tag: "sheet", dims, kids };
120
+ if (opts?.header) node.header = opts.header;
121
+ if (opts?.footer) node.footer = opts.footer;
122
+ return node;
123
+ }
124
+ function buildPageNum(format) {
125
+ return { tag: "pagenum", format };
126
+ }
127
+ function buildPara(kids = [], props = {}) {
128
+ return { tag: "para", props, kids };
129
+ }
130
+ function buildSpan(content, props = {}) {
131
+ const txt = { tag: "txt", content };
132
+ return { tag: "span", props, kids: [txt] };
133
+ }
134
+ function buildImg(b64, mime, w, h, alt) {
135
+ return { tag: "img", b64, mime, w, h, alt };
136
+ }
137
+ function buildGrid(kids, props = {}) {
138
+ return { tag: "grid", props, kids };
139
+ }
140
+ function buildRow(kids) {
141
+ return { tag: "row", kids };
142
+ }
143
+ function buildCell(kids, opts = {}) {
144
+ return { tag: "cell", cs: opts.cs ?? 1, rs: opts.rs ?? 1, props: opts.props ?? {}, kids };
145
+ }
146
+
147
+ // src/safety/ShieldedParser.ts
148
+ var ShieldedParser = class {
149
+ constructor() {
150
+ this.log = [];
151
+ }
152
+ /** 단일 요소 안전 파싱 */
153
+ guard(fn, fallback, label) {
154
+ try {
155
+ const v = fn();
156
+ if (v == null) {
157
+ this.warn(label, "returned null/undefined");
158
+ return fallback;
159
+ }
160
+ return v;
161
+ } catch (e) {
162
+ this.warn(label, e?.message ?? String(e));
163
+ return fallback;
164
+ }
165
+ }
166
+ /** 배열 각 요소 독립 파싱 (하나 실패해도 나머지 계속) */
167
+ guardAll(items, fn, fb, label) {
168
+ return items.map(
169
+ (x, i) => this.guard(() => fn(x, i), fb(x, i), `${label}[${i}]`)
170
+ );
171
+ }
172
+ /**
173
+ * 표 전용 4단계 폴백
174
+ * Lv1: Full → Lv2: Grid → Lv3: Flat → Lv4: Text
175
+ */
176
+ guardGrid(node, lv1Full, lv2Grid, lv3Flat, lv4Text, label) {
177
+ const levels = [
178
+ [lv1Full, 1],
179
+ [lv2Grid, 2],
180
+ [lv3Flat, 3],
181
+ [lv4Text, 4]
182
+ ];
183
+ for (const [fn, lv] of levels) {
184
+ try {
185
+ const v = fn(node);
186
+ if (v != null) {
187
+ if (lv > 1) this.warn(label, `degraded to level ${lv}`);
188
+ return { value: v, level: lv };
189
+ }
190
+ } catch (e) {
191
+ this.warn(label, `Lv${lv} failed: ${e?.message ?? String(e)}`);
192
+ }
193
+ }
194
+ this.warn(label, "ALL LEVELS FAILED \u2014 returning lv4Text forced");
195
+ return { value: lv4Text(null), level: 4 };
196
+ }
197
+ /** 이미지 안전 파싱 */
198
+ guardImg(node, fn, placeholder, label) {
199
+ try {
200
+ const v = fn(node);
201
+ if (v != null) return v;
202
+ } catch (e) {
203
+ this.warn(label, e?.message ?? String(e));
204
+ }
205
+ this.warn(label, "using placeholder image");
206
+ return placeholder(`[\uC774\uBBF8\uC9C0 \uB85C\uB4DC \uC2E4\uD328: ${label}]`);
207
+ }
208
+ warn(label, msg) {
209
+ const w = `[SHIELD] ${label}: ${msg}`;
210
+ console.warn(w);
211
+ this.log.push(w);
212
+ }
213
+ flush() {
214
+ const r = [...this.log];
215
+ this.log = [];
216
+ return r;
217
+ }
218
+ };
219
+
220
+ // src/safety/StyleBridge.ts
221
+ var Metric = {
222
+ // HWP 세계 (1 inch = 7200 HWPUNIT)
223
+ hwpToPt: (v) => v / 100,
224
+ ptToHwp: (v) => Math.round(v * 100),
225
+ hwpToDxa: (v) => Math.round(v / 5),
226
+ dxaToHwp: (v) => Math.round(v * 5),
227
+ hwpToEmu: (v) => Math.round(v * 127),
228
+ emuToHwp: (v) => Math.round(v / 127),
229
+ // DOCX 세계 (1 inch = 1440 dxa, 1 pt = 20 dxa)
230
+ dxaToPt: (v) => v / 20,
231
+ ptToDxa: (v) => Math.round(v * 20),
232
+ dxaToEmu: (v) => Math.round(v * 635),
233
+ emuToDxa: (v) => Math.round(v / 635),
234
+ emuToPt: (v) => v / 12700,
235
+ ptToEmu: (v) => Math.round(v * 12700),
236
+ // HWPX charPr height: 1000 = 10pt
237
+ hHeightToPt: (v) => v / 100,
238
+ ptToHHeight: (v) => Math.round(v * 100),
239
+ // DOCX half-point: 24 = 12pt
240
+ halfPtToPt: (v) => v / 2,
241
+ ptToHalfPt: (v) => Math.round(v * 2)
242
+ };
243
+ function safeHex(raw) {
244
+ if (raw == null) return void 0;
245
+ if (typeof raw === "number") {
246
+ if (raw <= 0) return "000000";
247
+ if (raw >= 16777215) return void 0;
248
+ return raw.toString(16).padStart(6, "0").toUpperCase();
249
+ }
250
+ let s = String(raw).replace(/^#/, "").toUpperCase();
251
+ if (/^[0-9A-F]{3}$/.test(s)) s = s[0] + s[0] + s[1] + s[1] + s[2] + s[2];
252
+ if (/^[0-9A-F]{6}$/.test(s)) return s;
253
+ if (s === "AUTO" || s === "NONE" || s === "TRANSPARENT") return void 0;
254
+ return void 0;
255
+ }
256
+ var ALIGN_MAP = {
257
+ LEFT: "left",
258
+ CENTER: "center",
259
+ RIGHT: "right",
260
+ JUSTIFY: "justify",
261
+ BOTH: "justify",
262
+ DISTRIBUTE: "justify",
263
+ left: "left",
264
+ center: "center",
265
+ right: "right",
266
+ both: "justify",
267
+ start: "left",
268
+ end: "right"
269
+ };
270
+ function safeAlign(raw) {
271
+ return ALIGN_MAP[raw ?? ""] ?? "justify";
272
+ }
273
+ var HWPX_STROKE = {
274
+ SOLID: "solid",
275
+ NONE: "none",
276
+ DASH: "dash",
277
+ DOT: "dot",
278
+ DOUBLE: "double",
279
+ LONG_DASH: "dash",
280
+ DASH_DOT: "dash"
281
+ };
282
+ var DOCX_STROKE = {
283
+ single: "solid",
284
+ none: "none",
285
+ nil: "none",
286
+ dashed: "dash",
287
+ dotted: "dot",
288
+ double: "double",
289
+ wave: "solid"
290
+ };
291
+ function safeStrokeHwpx(type, w, c) {
292
+ return {
293
+ kind: HWPX_STROKE[type ?? ""] ?? "solid",
294
+ pt: w != null ? Metric.hwpToPt(w) : 0.5,
295
+ color: safeHex(c) ?? "000000"
296
+ };
297
+ }
298
+ function safeStrokeDocx(val, sz, c) {
299
+ return {
300
+ kind: DOCX_STROKE[val ?? ""] ?? "solid",
301
+ pt: sz != null ? sz / 8 : 0.5,
302
+ color: safeHex(c) ?? "000000"
303
+ };
304
+ }
305
+ var FONT_MAP = {
306
+ "\uB9D1\uC740 \uACE0\uB515": "Malgun Gothic",
307
+ "\uBC14\uD0D5": "Batang",
308
+ "\uB3CB\uC6C0": "Dotum",
309
+ "\uAD74\uB9BC": "Gulim",
310
+ "\uD55C\uCEF4\uBC14\uD0D5": "Batang",
311
+ "\uD55C\uCEF4\uB3CB\uC6C0": "Malgun Gothic",
312
+ "\uD568\uCD08\uB86C\uBC14\uD0D5": "Batang",
313
+ "\uD568\uCD08\uB86C\uB3CB\uC6C0": "Malgun Gothic"
314
+ };
315
+ function safeFont(raw) {
316
+ return FONT_MAP[raw ?? ""] ?? raw ?? "Malgun Gothic";
317
+ }
318
+ var FONT_MAP_KR = {
319
+ "Malgun Gothic": "\uB9D1\uC740 \uACE0\uB515",
320
+ "Batang": "\uBC14\uD0D5",
321
+ "Dotum": "\uB3CB\uC6C0",
322
+ "Gulim": "\uAD74\uB9BC"
323
+ };
324
+ function safeFontToKr(raw) {
325
+ return FONT_MAP_KR[raw ?? ""] ?? raw ?? "\uB9D1\uC740 \uACE0\uB515";
326
+ }
327
+
328
+ // src/toolkit/ArchiveKit.ts
329
+ var import_pako = __toESM(require("pako"));
330
+ var ArchiveKit = {
331
+ async inflate(compressed) {
332
+ return import_pako.default.inflate(compressed);
333
+ },
334
+ async deflate(data) {
335
+ return import_pako.default.deflate(data, { level: 6 });
336
+ },
337
+ async unzip(zipData) {
338
+ const files = /* @__PURE__ */ new Map();
339
+ const view = new DataView(zipData.buffer, zipData.byteOffset, zipData.byteLength);
340
+ let offset = 0;
341
+ while (offset < zipData.length - 4) {
342
+ const sig = view.getUint32(offset, true);
343
+ if (sig === 67324752) {
344
+ const compressionMethod = view.getUint16(offset + 8, true);
345
+ const compressedSize = view.getUint32(offset + 18, true);
346
+ const uncompressedSize = view.getUint32(offset + 22, true);
347
+ const fileNameLength = view.getUint16(offset + 26, true);
348
+ const extraLength = view.getUint16(offset + 28, true);
349
+ const nameBytes = zipData.subarray(offset + 30, offset + 30 + fileNameLength);
350
+ const name = new TextDecoder("utf-8").decode(nameBytes);
351
+ const dataOffset = offset + 30 + fileNameLength + extraLength;
352
+ let fileData;
353
+ if (compressionMethod === 0) {
354
+ fileData = zipData.subarray(dataOffset, dataOffset + uncompressedSize);
355
+ } else if (compressionMethod === 8) {
356
+ const compressed = zipData.subarray(dataOffset, dataOffset + compressedSize);
357
+ fileData = import_pako.default.inflateRaw(compressed);
358
+ } else {
359
+ throw new Error(`Unsupported ZIP compression method: ${compressionMethod}`);
360
+ }
361
+ files.set(name, new Uint8Array(fileData));
362
+ offset = dataOffset + compressedSize;
363
+ } else if (sig === 33639248 || sig === 101010256) {
364
+ break;
365
+ } else {
366
+ offset++;
367
+ }
368
+ }
369
+ return files;
370
+ },
371
+ async zip(entries) {
372
+ const localHeaders = [];
373
+ const centralHeaders = [];
374
+ let localOffset = 0;
375
+ for (const entry of entries) {
376
+ const nameBytes = new TextEncoder().encode(entry.name);
377
+ const crc = crc32(entry.data);
378
+ const store = entry.name === "mimetype" || entry.name === "version.xml";
379
+ const method = store ? 0 : 8;
380
+ const payload = store ? entry.data : import_pako.default.deflateRaw(entry.data, { level: 6 });
381
+ const local = new Uint8Array(30 + nameBytes.length + payload.length);
382
+ const lv = new DataView(local.buffer);
383
+ lv.setUint32(0, 67324752, true);
384
+ lv.setUint16(4, 20, true);
385
+ lv.setUint16(6, 0, true);
386
+ lv.setUint16(8, method, true);
387
+ lv.setUint16(10, 0, true);
388
+ lv.setUint16(12, 33, true);
389
+ lv.setUint32(14, crc, true);
390
+ lv.setUint32(18, payload.length, true);
391
+ lv.setUint32(22, entry.data.length, true);
392
+ lv.setUint16(26, nameBytes.length, true);
393
+ lv.setUint16(28, 0, true);
394
+ local.set(nameBytes, 30);
395
+ local.set(payload, 30 + nameBytes.length);
396
+ const central = new Uint8Array(46 + nameBytes.length);
397
+ const cv = new DataView(central.buffer);
398
+ cv.setUint32(0, 33639248, true);
399
+ cv.setUint16(4, 20, true);
400
+ cv.setUint16(6, 20, true);
401
+ cv.setUint16(8, 0, true);
402
+ cv.setUint16(10, method, true);
403
+ cv.setUint16(12, 0, true);
404
+ cv.setUint16(14, 33, true);
405
+ cv.setUint32(16, crc, true);
406
+ cv.setUint32(20, payload.length, true);
407
+ cv.setUint32(24, entry.data.length, true);
408
+ cv.setUint16(28, nameBytes.length, true);
409
+ cv.setUint16(30, 0, true);
410
+ cv.setUint16(32, 0, true);
411
+ cv.setUint16(34, 0, true);
412
+ cv.setUint16(36, 0, true);
413
+ cv.setUint32(38, 0, true);
414
+ cv.setUint32(42, localOffset, true);
415
+ central.set(nameBytes, 46);
416
+ localHeaders.push(local);
417
+ centralHeaders.push(central);
418
+ localOffset += local.length;
419
+ }
420
+ const centralDir = concat(centralHeaders);
421
+ const eocd = new Uint8Array(22);
422
+ const ev = new DataView(eocd.buffer);
423
+ ev.setUint32(0, 101010256, true);
424
+ ev.setUint16(4, 0, true);
425
+ ev.setUint16(6, 0, true);
426
+ ev.setUint16(8, entries.length, true);
427
+ ev.setUint16(10, entries.length, true);
428
+ ev.setUint32(12, centralDir.length, true);
429
+ ev.setUint32(16, localOffset, true);
430
+ ev.setUint16(20, 0, true);
431
+ return concat([...localHeaders, centralDir, eocd]);
432
+ }
433
+ };
434
+ function concat(arrays) {
435
+ const total = arrays.reduce((s, a) => s + a.length, 0);
436
+ const out = new Uint8Array(total);
437
+ let offset = 0;
438
+ for (const a of arrays) {
439
+ out.set(a, offset);
440
+ offset += a.length;
441
+ }
442
+ return out;
443
+ }
444
+ function crc32(data) {
445
+ let crc = 4294967295;
446
+ for (const byte of data) {
447
+ crc ^= byte;
448
+ for (let i = 0; i < 8; i++) {
449
+ crc = crc & 1 ? crc >>> 1 ^ 3988292384 : crc >>> 1;
450
+ }
451
+ }
452
+ return (crc ^ 4294967295) >>> 0;
453
+ }
454
+
455
+ // src/toolkit/XmlKit.ts
456
+ var import_saxes = require("saxes");
457
+ function parseXmlStrict(xml) {
458
+ return new Promise((resolve, reject) => {
459
+ const parser = new import_saxes.SaxesParser({ xmlns: false });
460
+ const stack = [];
461
+ let result = null;
462
+ parser.on("error", (err) => reject(err));
463
+ parser.on("opentag", (node) => {
464
+ const obj = {};
465
+ const attrs = node.attributes;
466
+ if (attrs && Object.keys(attrs).length > 0) {
467
+ obj["_attr"] = { ...attrs };
468
+ }
469
+ stack.push({ tag: node.name, obj });
470
+ });
471
+ const appendText = (text) => {
472
+ if (stack.length > 0 && text) {
473
+ const frame = stack[stack.length - 1];
474
+ const cur = frame.obj["_text"];
475
+ frame.obj["_text"] = typeof cur === "string" ? cur + text : text;
476
+ }
477
+ };
478
+ parser.on("text", (text) => appendText(text));
479
+ parser.on("cdata", (cdata) => appendText(cdata));
480
+ parser.on("closetag", () => {
481
+ const frame = stack.pop();
482
+ if (!frame) return;
483
+ const { tag, obj } = frame;
484
+ if (typeof obj["_text"] === "string" && !obj["_text"].trim()) {
485
+ delete obj["_text"];
486
+ }
487
+ if (stack.length === 0) {
488
+ result = { [tag]: [obj] };
489
+ } else {
490
+ const parent = stack[stack.length - 1].obj;
491
+ const existing = parent[tag];
492
+ if (Array.isArray(existing)) {
493
+ existing.push(obj);
494
+ } else {
495
+ parent[tag] = [obj];
496
+ }
497
+ if (!parent["_childOrder"]) parent["_childOrder"] = [];
498
+ parent["_childOrder"].push(tag);
499
+ }
500
+ });
501
+ try {
502
+ parser.write(xml).close();
503
+ resolve(result);
504
+ } catch (e) {
505
+ reject(e);
506
+ }
507
+ });
508
+ }
509
+ var XmlKit = {
510
+ /** @deprecated Use parseStrict instead */
511
+ async parse(xml) {
512
+ return parseXmlStrict(xml);
513
+ },
514
+ async parseStrict(xml) {
515
+ return parseXmlStrict(xml);
516
+ },
517
+ attr(node, key) {
518
+ const a = node["_attr"];
519
+ return a?.[key];
520
+ },
521
+ text(node) {
522
+ if (node == null) return "";
523
+ if (typeof node === "string") return node;
524
+ const t = node["_text"];
525
+ return typeof t === "string" ? t : "";
526
+ }
527
+ };
528
+
529
+ // src/toolkit/TextKit.ts
530
+ var TextKit = {
531
+ decode(data, encoding = "utf-8") {
532
+ try {
533
+ return new TextDecoder(encoding, { fatal: true }).decode(data);
534
+ } catch {
535
+ return new TextDecoder("utf-8", { fatal: false }).decode(data);
536
+ }
537
+ },
538
+ encode(text) {
539
+ return new TextEncoder().encode(text);
540
+ },
541
+ escapeXml(s) {
542
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
543
+ },
544
+ unescapeXml(s) {
545
+ return s.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&apos;/g, "'");
546
+ },
547
+ normalizeWhitespace(s) {
548
+ return s.replace(/\s+/g, " ").trim();
549
+ },
550
+ stripControl(s) {
551
+ return s.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
552
+ },
553
+ base64Encode(data) {
554
+ let binary = "";
555
+ for (let i = 0; i < data.length; i++) {
556
+ binary += String.fromCharCode(data[i]);
557
+ }
558
+ return btoa(binary);
559
+ },
560
+ base64Decode(b64) {
561
+ const binary = atob(b64);
562
+ const bytes = new Uint8Array(binary.length);
563
+ for (let i = 0; i < binary.length; i++) {
564
+ bytes[i] = binary.charCodeAt(i);
565
+ }
566
+ return bytes;
567
+ }
568
+ };
569
+
570
+ // src/decoders/hwpx/HwpxDecoder.ts
571
+ var HwpxDecoder = class {
572
+ constructor() {
573
+ this.format = "hwpx";
574
+ }
575
+ async decode(data) {
576
+ const shield = new ShieldedParser();
577
+ const warns = [];
578
+ try {
579
+ const files = await ArchiveKit.unzip(data);
580
+ const bodyXml = files.get("Contents/section0.xml") ?? files.get("section0.xml") ?? findSectionFile(files);
581
+ if (!bodyXml) return fail("HWPX: section0.xml not found in archive");
582
+ const headXml = files.get("Contents/header.xml") ?? files.get("header.xml");
583
+ let meta = {};
584
+ let dims = { ...A4 };
585
+ let borderFills = /* @__PURE__ */ new Map();
586
+ let charPrs = /* @__PURE__ */ new Map();
587
+ let paraPrs = /* @__PURE__ */ new Map();
588
+ if (headXml) {
589
+ try {
590
+ const headStr = TextKit.decode(headXml);
591
+ const headObj = await XmlKit.parseStrict(headStr);
592
+ if (headObj) {
593
+ meta = extractMeta(headObj);
594
+ dims = extractDims(headObj) ?? dims;
595
+ borderFills = extractBorderFills(headObj);
596
+ charPrs = extractCharPrs(headObj);
597
+ paraPrs = extractParaPrs(headObj);
598
+ }
599
+ } catch {
600
+ }
601
+ }
602
+ const ctx = { files, shield, borderFills, charPrs, paraPrs, warns };
603
+ const bodyStr = TextKit.decode(bodyXml);
604
+ const bodyObj = await XmlKit.parseStrict(bodyStr);
605
+ const sections = normalizeSections(bodyObj);
606
+ const kids = shield.guardAll(
607
+ sections,
608
+ (sec) => decodeSection(sec, dims, ctx),
609
+ () => buildSheet([buildPara([buildSpan("[\uC139\uC158 \uD30C\uC2F1 \uC2E4\uD328]")])], dims),
610
+ "hwpx:section"
611
+ );
612
+ warns.push(...shield.flush());
613
+ return succeed(buildRoot(meta, kids), warns);
614
+ } catch (e) {
615
+ warns.push(...shield.flush());
616
+ return fail(`HWPX decode error: ${e?.message ?? String(e)}`, warns);
617
+ }
618
+ }
619
+ };
620
+ function findSectionFile(files) {
621
+ for (const [key, val] of files) {
622
+ if (key.toLowerCase().includes("section") && key.endsWith(".xml")) return val;
623
+ }
624
+ return void 0;
625
+ }
626
+ function normalizeSections(bodyObj) {
627
+ if (bodyObj?.["hs:sec"]) return toArr(bodyObj["hs:sec"]);
628
+ if (bodyObj?.["hp:SEC"]) return toArr(bodyObj["hp:SEC"]);
629
+ const root = bodyObj?.["hp:HWPML"] ?? bodyObj?.HWPML ?? bodyObj;
630
+ const body = root?.["hp:BODY"]?.[0] ?? root?.BODY?.[0] ?? root?.["hp:BODY"] ?? root?.BODY;
631
+ if (!body) return [bodyObj];
632
+ const sections = body?.["hp:SECTION"] ?? body?.SECTION ?? [];
633
+ return Array.isArray(sections) ? sections : [sections];
634
+ }
635
+ function getTag(obj, ...names) {
636
+ for (const n of names) {
637
+ const v = obj?.[n];
638
+ if (v != null) return toArr(v);
639
+ }
640
+ return [];
641
+ }
642
+ function extractMeta(headObj) {
643
+ try {
644
+ const root = headObj?.["hh:head"]?.[0] ?? headObj?.["hh:HEAD"]?.[0] ?? headObj?.HEAD?.[0] ?? headObj;
645
+ const info = root?.["hh:DOCSUMMARY"]?.[0] ?? root?.DOCSUMMARY?.[0];
646
+ if (!info) return {};
647
+ const a = (k) => info?.[`hh:${k}`]?.[0]?._text ?? info?.[k]?.[0]?._text ?? "";
648
+ return { title: a("TITLE") || void 0, author: a("AUTHOR") || void 0, subject: a("SUBJECT") || void 0 };
649
+ } catch {
650
+ return {};
651
+ }
652
+ }
653
+ function extractDims(headObj) {
654
+ try {
655
+ const root = headObj?.["hh:head"]?.[0] ?? headObj?.["hh:HEAD"]?.[0] ?? headObj?.HEAD?.[0] ?? headObj;
656
+ const refList = root?.["hh:refList"]?.[0] ?? root?.["hh:REFLIST"]?.[0] ?? root?.REFLIST?.[0];
657
+ if (!refList) return null;
658
+ const secPrList = refList?.["hh:SECPRLST"]?.[0]?.["hh:SECPR"] ?? refList?.SECPRLST?.[0]?.SECPR;
659
+ const sec = Array.isArray(secPrList) ? secPrList[0] : secPrList;
660
+ if (!sec) return null;
661
+ const pa = sec?.["hh:PAGEPROPERTY"]?.[0]?._attr ?? sec?.PAGEPROPERTY?.[0]?._attr;
662
+ if (!pa) return null;
663
+ return {
664
+ wPt: Metric.hwpToPt(Number(pa.Width ?? 59528)),
665
+ hPt: Metric.hwpToPt(Number(pa.Height ?? 84188)),
666
+ mt: Metric.hwpToPt(Number(pa.TopMargin ?? 5670)),
667
+ mb: Metric.hwpToPt(Number(pa.BottomMargin ?? 4252)),
668
+ ml: Metric.hwpToPt(Number(pa.LeftMargin ?? 8504)),
669
+ mr: Metric.hwpToPt(Number(pa.RightMargin ?? 8504)),
670
+ orient: Number(pa.Landscape) === 1 ? "landscape" : "portrait"
671
+ };
672
+ } catch {
673
+ return null;
674
+ }
675
+ }
676
+ function extractBorderFills(headObj) {
677
+ const map = /* @__PURE__ */ new Map();
678
+ try {
679
+ const root = headObj?.["hh:head"]?.[0] ?? headObj?.["hh:HEAD"]?.[0] ?? headObj?.HEAD?.[0] ?? headObj;
680
+ const refList = root?.["hh:refList"]?.[0] ?? root?.["hh:REFLIST"]?.[0] ?? root?.REFLIST?.[0];
681
+ if (!refList) return map;
682
+ const bfList = refList?.["hh:borderFills"]?.[0] ?? refList?.["hh:BORDERFILLLIST"]?.[0] ?? refList?.BORDERFILLLIST?.[0];
683
+ if (!bfList) return map;
684
+ const bfs = getTag(bfList, "hh:borderFill", "hh:BORDERFILL");
685
+ for (const bf of bfs) {
686
+ const attr = bf?._attr ?? {};
687
+ const id = Number(attr.id ?? 0);
688
+ if (id === 0) continue;
689
+ const info = {};
690
+ const top = bf?.["hh:topBorder"]?.[0]?._attr ?? bf?.["hh:top"]?.[0]?._attr ?? bf?.top?.[0]?._attr;
691
+ if (top) {
692
+ const mmVal = parseFloat(top.width) || void 0;
693
+ const hwpVal = mmVal != null ? mmVal * 2.835 * 100 : void 0;
694
+ info.stroke = safeStrokeHwpx(top.type, hwpVal, top.color);
695
+ }
696
+ const fillBrush = bf?.["hc:fillBrush"]?.[0] ?? bf?.["hh:fillBrush"]?.[0] ?? bf?.["hh:fill"]?.[0] ?? bf?.fill?.[0] ?? bf?.fillBrush?.[0];
697
+ if (fillBrush) {
698
+ const winBrush = fillBrush?.["hc:winBrush"]?.[0]?._attr ?? fillBrush?.["hh:winBrush"]?.[0]?._attr ?? fillBrush?.winBrush?.[0]?._attr;
699
+ if (winBrush?.faceColor && winBrush.faceColor !== "none") {
700
+ info.bgColor = safeHex(winBrush.faceColor);
701
+ }
702
+ }
703
+ map.set(id, info);
704
+ }
705
+ } catch {
706
+ }
707
+ return map;
708
+ }
709
+ function extractCharPrs(headObj) {
710
+ const map = /* @__PURE__ */ new Map();
711
+ try {
712
+ const root = headObj?.["hh:head"]?.[0] ?? headObj?.["hh:HEAD"]?.[0] ?? headObj?.HEAD?.[0] ?? headObj;
713
+ const refList = root?.["hh:refList"]?.[0] ?? root?.["hh:REFLIST"]?.[0] ?? root?.REFLIST?.[0];
714
+ if (!refList) return map;
715
+ const cpList = refList?.["hh:charProperties"]?.[0] ?? refList?.["hh:CHARPROPERTIES"]?.[0];
716
+ if (!cpList) return map;
717
+ const cps = getTag(cpList, "hh:charPr", "hh:CHARPR");
718
+ for (const cp of cps) {
719
+ const attr = cp?._attr ?? {};
720
+ const id = Number(attr.id ?? -1);
721
+ if (id < 0) continue;
722
+ const info = {};
723
+ if (attr.height) info.pt = Metric.hHeightToPt(Number(attr.height));
724
+ if (attr.textColor) info.color = safeHex(attr.textColor);
725
+ if (cp?.["hh:bold"]?.[0] != null) info.b = true;
726
+ if (cp?.["hh:italic"]?.[0] != null) info.i = true;
727
+ const ulAttr = cp?.["hh:underline"]?.[0]?._attr;
728
+ if (ulAttr?.type && ulAttr.type !== "NONE") info.u = true;
729
+ const stAttr = cp?.["hh:strikeout"]?.[0]?._attr;
730
+ if (stAttr?.shape && stAttr.shape !== "NONE" && stAttr.shape !== "3D") info.s = true;
731
+ map.set(id, info);
732
+ }
733
+ } catch {
734
+ }
735
+ return map;
736
+ }
737
+ function extractParaPrs(headObj) {
738
+ const map = /* @__PURE__ */ new Map();
739
+ try {
740
+ const root = headObj?.["hh:head"]?.[0] ?? headObj?.["hh:HEAD"]?.[0] ?? headObj?.HEAD?.[0] ?? headObj;
741
+ const refList = root?.["hh:refList"]?.[0] ?? root?.["hh:REFLIST"]?.[0] ?? root?.REFLIST?.[0];
742
+ if (!refList) return map;
743
+ const ppList = refList?.["hh:paraProperties"]?.[0] ?? refList?.["hh:PARAPROPERTIES"]?.[0];
744
+ if (!ppList) return map;
745
+ const pps = getTag(ppList, "hh:paraPr", "hh:PARAPR");
746
+ for (const pp of pps) {
747
+ const attr = pp?._attr ?? {};
748
+ const id = Number(attr.id ?? -1);
749
+ if (id < 0) continue;
750
+ const alignNode = pp?.["hh:align"]?.[0]?._attr ?? pp?.["hh:ALIGN"]?.[0]?._attr;
751
+ const align = alignNode?.horizontal ?? alignNode?.Horizontal;
752
+ map.set(id, { align });
753
+ }
754
+ } catch {
755
+ }
756
+ return map;
757
+ }
758
+ function addParaItems(p, items) {
759
+ const runs = getTag(p, "hp:run", "hp:RUN");
760
+ let hasTable = false;
761
+ for (const run of runs) {
762
+ const tbls = getTag(run, "hp:tbl", "hp:TABLE");
763
+ for (const tbl of tbls) {
764
+ items.push({ type: "table", node: tbl });
765
+ hasTable = true;
766
+ }
767
+ }
768
+ const hasText = runs.some((run) => {
769
+ const ts = getTag(run, "hp:t", "hp:T", "hp:CHAR");
770
+ return ts.some((t) => {
771
+ const text = typeof t === "string" ? t : t?._text ?? "";
772
+ return text.trim().length > 0;
773
+ });
774
+ });
775
+ if (hasText || !hasTable) {
776
+ items.push({ type: "para", node: p });
777
+ }
778
+ }
779
+ function decodeSection(sec, dims, ctx) {
780
+ const firstParas = getTag(sec, "hp:p", "hp:P");
781
+ const pageDims = extractSecPrDims(firstParas[0]) ?? dims;
782
+ const items = [];
783
+ const paras = getTag(sec, "hp:p", "hp:P");
784
+ const childOrder = sec?.["_childOrder"];
785
+ if (Array.isArray(childOrder)) {
786
+ let pi = 0;
787
+ for (const tag of childOrder) {
788
+ if ((tag === "hp:p" || tag === "hp:P") && pi < paras.length) {
789
+ const p = paras[pi++];
790
+ addParaItems(p, items);
791
+ }
792
+ }
793
+ while (pi < paras.length) addParaItems(paras[pi++], items);
794
+ } else {
795
+ for (const p of paras) addParaItems(p, items);
796
+ }
797
+ const kids = ctx.shield.guardAll(
798
+ items,
799
+ (item) => {
800
+ if (item.type === "table") {
801
+ const { value } = ctx.shield.guardGrid(
802
+ item.node,
803
+ (n) => decodeGrid(n, ctx),
804
+ (n) => decodeGridSimple(n, ctx),
805
+ (n) => decodeGridFlat(n),
806
+ (n) => decodeGridText(n),
807
+ "hwpx:table"
808
+ );
809
+ return value;
810
+ }
811
+ return decodePara(item.node, ctx);
812
+ },
813
+ () => buildPara([buildSpan("[\uD30C\uC2F1 \uC2E4\uD328]")]),
814
+ "hwpx:content"
815
+ );
816
+ const headerParas = decodeHeaderFooter(sec, "header", ctx);
817
+ const footerParas = decodeHeaderFooter(sec, "footer", ctx);
818
+ return buildSheet(
819
+ kids.filter(Boolean),
820
+ pageDims,
821
+ { header: headerParas, footer: footerParas }
822
+ );
823
+ }
824
+ function extractSecPrDims(p) {
825
+ if (!p) return null;
826
+ try {
827
+ const runs = getTag(p, "hp:run", "hp:RUN");
828
+ for (const run of runs) {
829
+ const secPr = run?.["hp:secPr"]?.[0] ?? run?.["hp:SECPR"]?.[0];
830
+ if (!secPr) continue;
831
+ const pagePr = secPr?.["hp:pagePr"]?.[0]?._attr ?? secPr?.["hp:PAGEPR"]?.[0]?._attr;
832
+ if (!pagePr) continue;
833
+ const margin = secPr?.["hp:pagePr"]?.[0]?.["hp:margin"]?.[0]?._attr ?? secPr?.["hp:PAGEPR"]?.[0]?.["hp:MARGIN"]?.[0]?._attr ?? {};
834
+ return {
835
+ wPt: Metric.hwpToPt(Number(pagePr.width ?? 59528)),
836
+ hPt: Metric.hwpToPt(Number(pagePr.height ?? 84188)),
837
+ mt: Metric.hwpToPt(Number(margin.top ?? 5670)),
838
+ mb: Metric.hwpToPt(Number(margin.bottom ?? 4252)),
839
+ ml: Metric.hwpToPt(Number(margin.left ?? 8504)),
840
+ mr: Metric.hwpToPt(Number(margin.right ?? 8504)),
841
+ orient: pagePr.landscape === "NARROWLY" ? "landscape" : "portrait"
842
+ };
843
+ }
844
+ } catch {
845
+ }
846
+ return null;
847
+ }
848
+ function decodeHeaderFooter(sec, kind, ctx) {
849
+ try {
850
+ const hf = sec?.["hp:headerFooter"]?.[0] ?? sec?.["hp:HEADERFOOTER"]?.[0] ?? sec?.headerFooter?.[0] ?? sec?.HEADERFOOTER?.[0];
851
+ if (!hf) return void 0;
852
+ const part = hf?.["hp:" + kind]?.[0] ?? hf?.["hp:" + kind.toUpperCase()]?.[0] ?? hf?.[kind]?.[0] ?? hf?.[kind.toUpperCase()]?.[0];
853
+ if (!part) return void 0;
854
+ const paras = getTag(part, "hp:p", "hp:P");
855
+ if (paras.length === 0) return void 0;
856
+ return paras.map((p) => decodePara(p, ctx));
857
+ } catch {
858
+ return void 0;
859
+ }
860
+ }
861
+ function decodePara(p, ctx) {
862
+ const pAttr = p?._attr ?? {};
863
+ const paraPrIdRef = Number(pAttr.paraPrIDRef ?? -1);
864
+ let align;
865
+ const paraPrDef = ctx.paraPrs.get(paraPrIdRef);
866
+ if (paraPrDef?.align) align = paraPrDef.align;
867
+ const inlineParaPr = p?.["hp:PARAPR"]?.[0] ?? p?.["hp:paraPr"]?.[0] ?? p?.PARAPR?.[0];
868
+ if (inlineParaPr) {
869
+ const alignNode = inlineParaPr?.["hp:ALIGN"]?.[0]?._attr ?? inlineParaPr?.["hp:align"]?.[0]?._attr ?? inlineParaPr?.ALIGN?.[0]?._attr;
870
+ if (alignNode?.Type) align = alignNode.Type;
871
+ if (alignNode?.horizontal) align = alignNode.horizontal;
872
+ }
873
+ const inlineAttr = inlineParaPr?._attr ?? {};
874
+ const props = { align: safeAlign(align) };
875
+ if (inlineAttr.listType) {
876
+ props.listOrd = inlineAttr.listType === "DIGIT" || inlineAttr.listType === "DECIMAL";
877
+ props.listLv = Number(inlineAttr.listLevel ?? 0);
878
+ }
879
+ const runs = getTag(p, "hp:run", "hp:RUN");
880
+ const kids = [];
881
+ for (const run of runs) {
882
+ const pics = getTag(run, "hp:pic", "hp:PIC");
883
+ for (const pic of pics) {
884
+ const img = decodePic(pic, ctx);
885
+ if (img) kids.push(img);
886
+ }
887
+ const pageNums = getTag(run, "hp:pageNum", "hp:PAGENUM");
888
+ if (pageNums.length > 0) {
889
+ const pn = pageNums[0]?._attr ?? {};
890
+ const fmt = pn.formatType === "ROMAN_LOWER" ? "roman" : pn.formatType === "ROMAN_UPPER" ? "romanCaps" : "decimal";
891
+ const pageNumNode = { tag: "pagenum", format: fmt };
892
+ const spanProps2 = resolveCharPr(run, ctx);
893
+ kids.push({ tag: "span", props: spanProps2, kids: [pageNumNode] });
894
+ continue;
895
+ }
896
+ const textNodes = getTag(run, "hp:t", "hp:T", "hp:CHAR");
897
+ const content = textNodes.map((t) => typeof t === "string" ? t : t?._text ?? t?._ ?? "").join("");
898
+ if (content === "" && (run?.["hp:secPr"]?.[0] || run?.["hp:SECPR"]?.[0]) && pics.length === 0) continue;
899
+ const spanProps = resolveCharPr(run, ctx);
900
+ kids.push(buildSpan(content, spanProps));
901
+ }
902
+ return buildPara(kids.filter(Boolean), props);
903
+ }
904
+ function resolveCharPr(run, ctx) {
905
+ const runAttr = run?._attr ?? {};
906
+ const charPrIdRef = Number(runAttr.charPrIDRef ?? -1);
907
+ const def = ctx.charPrs.get(charPrIdRef);
908
+ if (def) {
909
+ return {
910
+ b: def.b,
911
+ i: def.i,
912
+ u: def.u,
913
+ s: def.s,
914
+ pt: def.pt,
915
+ color: def.color,
916
+ font: def.font,
917
+ bg: def.bg
918
+ };
919
+ }
920
+ const ca = run?.["hp:CHARPR"]?.[0]?._attr ?? run?.["hp:charPr"]?.[0]?._attr ?? run?.CHARPR?.[0]?._attr ?? {};
921
+ return {
922
+ b: ca.Bold === "1" || ca.Bold === "true" || void 0,
923
+ i: ca.Italic === "1" || ca.Italic === "true" || void 0,
924
+ u: ca.Underline ? ca.Underline !== "NONE" : void 0,
925
+ s: ca.Strikeout ? ca.Strikeout !== "NONE" : void 0,
926
+ font: safeFont(ca.FontName ?? ca.FaceNameHangul),
927
+ pt: ca.Height ? Metric.hHeightToPt(Number(ca.Height)) : void 0,
928
+ color: safeHex(ca.TextColor),
929
+ bg: safeHex(ca.BgColor)
930
+ };
931
+ }
932
+ function decodePic(pic, ctx) {
933
+ try {
934
+ const szAttr = pic?.["hp:sz"]?.[0]?._attr ?? pic?.sz?.[0]?._attr ?? {};
935
+ const w = Metric.hwpToPt(Number(szAttr.width ?? 0));
936
+ const h = Metric.hwpToPt(Number(szAttr.height ?? 0));
937
+ const imgNode = pic?.["hp:img"]?.[0]?._attr ?? pic?.["hc:img"]?.[0]?._attr ?? pic?.img?.[0]?._attr ?? {};
938
+ const binRef = imgNode.binaryItemIDRef ?? imgNode.BinaryItemIDRef;
939
+ if (!binRef) return null;
940
+ let imgData;
941
+ for (const [key, val] of ctx.files) {
942
+ if (key.includes(binRef) || key.toLowerCase().includes(binRef.toLowerCase())) {
943
+ imgData = val;
944
+ break;
945
+ }
946
+ }
947
+ if (!imgData) return null;
948
+ const ext = binRef.split(".").pop()?.toLowerCase() ?? "png";
949
+ const mimeMap = {
950
+ png: "image/png",
951
+ jpg: "image/jpeg",
952
+ jpeg: "image/jpeg",
953
+ gif: "image/gif",
954
+ bmp: "image/bmp"
955
+ };
956
+ return buildImg(TextKit.base64Encode(imgData), mimeMap[ext] ?? "image/png", w, h);
957
+ } catch {
958
+ return null;
959
+ }
960
+ }
961
+ function decodeGrid(tbl, ctx) {
962
+ const tblAttr = tbl?._attr ?? {};
963
+ const borderFillId = Number(tblAttr.borderFillIDRef ?? 0);
964
+ const borderFill = ctx.borderFills.get(borderFillId);
965
+ const headerRow = tblAttr.repeatHeader === "1";
966
+ const gridProps = { headerRow: headerRow || void 0 };
967
+ if (borderFill?.stroke) gridProps.defaultStroke = borderFill.stroke;
968
+ const rowArr = getTag(tbl, "hp:tr", "hp:ROW");
969
+ const rowNodes = rowArr.map((row) => {
970
+ const cellArr = getTag(row, "hp:tc", "hp:CELL");
971
+ const cellNodes = cellArr.map((cell) => {
972
+ const ca = cell?._attr ?? {};
973
+ const cellBfId = Number(ca.borderFillIDRef ?? 0);
974
+ const cellBf = ctx.borderFills.get(cellBfId);
975
+ const cellProps = {
976
+ bg: cellBf?.bgColor ?? safeHex(ca.BgColor)
977
+ };
978
+ if (cellBf?.stroke) {
979
+ cellProps.top = cellBf.stroke;
980
+ cellProps.bot = cellBf.stroke;
981
+ cellProps.left = cellBf.stroke;
982
+ cellProps.right = cellBf.stroke;
983
+ }
984
+ const subList = cell?.["hp:subList"]?.[0] ?? cell?.subList?.[0];
985
+ const subAttr = subList?._attr ?? {};
986
+ if (subAttr.vertAlign) {
987
+ const vaMap = {
988
+ TOP: "top",
989
+ CENTER: "mid",
990
+ BOTTOM: "bot"
991
+ };
992
+ cellProps.va = vaMap[subAttr.vertAlign];
993
+ }
994
+ const cellSpan = cell?.["hp:cellSpan"]?.[0]?._attr ?? {};
995
+ const cs = Number(cellSpan.colSpan ?? ca.ColSpan ?? 1);
996
+ const rs = Number(cellSpan.rowSpan ?? ca.RowSpan ?? 1);
997
+ let paras;
998
+ if (subList) {
999
+ const subParas = getTag(subList, "hp:p", "hp:P");
1000
+ paras = subParas.map((p) => decodePara(p, ctx));
1001
+ } else {
1002
+ paras = getTag(cell, "hp:p", "hp:P").map((p) => decodePara(p, ctx));
1003
+ }
1004
+ return buildCell(
1005
+ paras.length > 0 ? paras : [buildPara([buildSpan("")])],
1006
+ { cs, rs, props: cellProps }
1007
+ );
1008
+ });
1009
+ return buildRow(cellNodes);
1010
+ });
1011
+ return buildGrid(rowNodes, gridProps);
1012
+ }
1013
+ function decodeGridSimple(tbl, ctx) {
1014
+ const rowArr = getTag(tbl, "hp:tr", "hp:ROW");
1015
+ const rowNodes = rowArr.map((row) => {
1016
+ const cellArr = getTag(row, "hp:tc", "hp:CELL");
1017
+ return buildRow(cellArr.map((cell) => buildCell([buildPara([buildSpan(cellText(cell))])])));
1018
+ });
1019
+ return buildGrid(rowNodes);
1020
+ }
1021
+ function decodeGridFlat(tbl) {
1022
+ return buildGrid([buildRow([buildCell([buildPara([buildSpan(tableText(tbl))])])])]);
1023
+ }
1024
+ function decodeGridText(tbl) {
1025
+ return buildPara([buildSpan(tableText(tbl))]);
1026
+ }
1027
+ function cellText(cell) {
1028
+ const subList = cell?.["hp:subList"]?.[0] ?? cell?.subList?.[0];
1029
+ const source = subList ?? cell;
1030
+ return getTag(source, "hp:p", "hp:P").map(
1031
+ (p) => getTag(p, "hp:run", "hp:RUN").map(
1032
+ (r) => getTag(r, "hp:t", "hp:T").map((t) => typeof t === "string" ? t : t?._text ?? t?._ ?? "").join("")
1033
+ ).join("")
1034
+ ).join(" ");
1035
+ }
1036
+ function tableText(tbl) {
1037
+ return getTag(tbl, "hp:tr", "hp:ROW").map(
1038
+ (row) => getTag(row, "hp:tc", "hp:CELL").map((c) => cellText(c)).join(" ")
1039
+ ).join("\n");
1040
+ }
1041
+ function toArr(v) {
1042
+ return v == null ? [] : Array.isArray(v) ? v : [v];
1043
+ }
1044
+ registry.registerDecoder(new HwpxDecoder());
1045
+
1046
+ // src/toolkit/BinaryKit.ts
1047
+ var BinaryKit = {
1048
+ readU16LE(buf, offset) {
1049
+ return buf[offset] | buf[offset + 1] << 8;
1050
+ },
1051
+ readU32LE(buf, offset) {
1052
+ return ((buf[offset] | buf[offset + 1] << 8 | buf[offset + 2] << 16) >>> 0) + buf[offset + 3] * 16777216;
1053
+ },
1054
+ isOle2(data) {
1055
+ return data.length >= 8 && data[0] === 208 && data[1] === 207 && data[2] === 17 && data[3] === 224 && data[4] === 161 && data[5] === 177 && data[6] === 26 && data[7] === 225;
1056
+ },
1057
+ parseCfb(data) {
1058
+ const streams = /* @__PURE__ */ new Map();
1059
+ if (!this.isOle2(data)) {
1060
+ throw new Error("Not a valid OLE2 file");
1061
+ }
1062
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
1063
+ const sectorSize = 1 << view.getUint16(30, true);
1064
+ const miniSectorSz = 1 << view.getUint16(32, true);
1065
+ const dirFirstSec = view.getUint32(48, true);
1066
+ const miniStreamCutoff = view.getUint32(56, true);
1067
+ const miniFatFirst = view.getUint32(60, true);
1068
+ const miniFatCnt = view.getUint32(64, true);
1069
+ const difatFirst = view.getUint32(68, true);
1070
+ const ENDOFCHAIN = 4294967294;
1071
+ const FREESECT = 4294967295;
1072
+ const sectorAt = (sec) => data.subarray(512 + sec * sectorSize, 512 + (sec + 1) * sectorSize);
1073
+ const fatSecNums = [];
1074
+ for (let i = 0; i < 109; i++) {
1075
+ const s = view.getUint32(76 + i * 4, true);
1076
+ if (s === FREESECT || s === ENDOFCHAIN) break;
1077
+ fatSecNums.push(s);
1078
+ }
1079
+ if (difatFirst !== ENDOFCHAIN && difatFirst !== FREESECT) {
1080
+ let difSec = difatFirst;
1081
+ while (difSec !== ENDOFCHAIN && difSec !== FREESECT) {
1082
+ const sec = sectorAt(difSec);
1083
+ const sv = new DataView(sec.buffer, sec.byteOffset, sec.byteLength);
1084
+ for (let i = 0; i < sectorSize / 4 - 1; i++) {
1085
+ const s = sv.getUint32(i * 4, true);
1086
+ if (s === FREESECT || s === ENDOFCHAIN) break;
1087
+ fatSecNums.push(s);
1088
+ }
1089
+ difSec = sv.getUint32(sectorSize - 4, true);
1090
+ }
1091
+ }
1092
+ const fat = [];
1093
+ for (const sec of fatSecNums) {
1094
+ const s = sectorAt(sec);
1095
+ const sv = new DataView(s.buffer, s.byteOffset, s.byteLength);
1096
+ for (let i = 0; i < sectorSize / 4; i++) {
1097
+ fat.push(sv.getUint32(i * 4, true));
1098
+ }
1099
+ }
1100
+ const readChain = (startSec) => {
1101
+ const chunks = [];
1102
+ let sec = startSec;
1103
+ while (sec !== ENDOFCHAIN && sec !== FREESECT && sec < fat.length) {
1104
+ chunks.push(sectorAt(sec));
1105
+ sec = fat[sec];
1106
+ }
1107
+ return concatUint8(chunks);
1108
+ };
1109
+ const dirData = readChain(dirFirstSec);
1110
+ const dirView = new DataView(dirData.buffer, dirData.byteOffset, dirData.byteLength);
1111
+ const dirCount = dirData.length / 128;
1112
+ const dirEntries = [];
1113
+ for (let i = 0; i < dirCount; i++) {
1114
+ const base = i * 128;
1115
+ const nameLen = dirView.getUint16(base + 64, true);
1116
+ const nameBytes = dirData.subarray(base, base + Math.max(0, nameLen - 2));
1117
+ const name = new TextDecoder("utf-16le").decode(nameBytes);
1118
+ const type = dirData[base + 66];
1119
+ const childId = dirView.getInt32(base + 76, true);
1120
+ const sibLeft = dirView.getInt32(base + 68, true);
1121
+ const sibRight = dirView.getInt32(base + 72, true);
1122
+ const startSec = dirView.getUint32(base + 116, true);
1123
+ const size = dirView.getUint32(base + 120, true);
1124
+ dirEntries.push({ name, type, startSec, size, childId, siblingLeftId: sibLeft, siblingRightId: sibRight });
1125
+ }
1126
+ const rootEntry = dirEntries[0];
1127
+ let miniStreamData = null;
1128
+ let miniFat = [];
1129
+ if (rootEntry && rootEntry.startSec !== ENDOFCHAIN && rootEntry.startSec !== FREESECT) {
1130
+ miniStreamData = readChain(rootEntry.startSec);
1131
+ }
1132
+ if (miniFatCnt > 0 && miniFatFirst !== ENDOFCHAIN && miniFatFirst !== FREESECT) {
1133
+ const mfData = readChain(miniFatFirst);
1134
+ const mfv = new DataView(mfData.buffer, mfData.byteOffset, mfData.byteLength);
1135
+ for (let i = 0; i < mfData.length / 4; i++) {
1136
+ miniFat.push(mfv.getUint32(i * 4, true));
1137
+ }
1138
+ }
1139
+ const readMiniChain = (startSec, size) => {
1140
+ if (!miniStreamData) return new Uint8Array(0);
1141
+ const chunks = [];
1142
+ let sec = startSec;
1143
+ let remaining = size;
1144
+ while (sec !== ENDOFCHAIN && sec !== FREESECT && sec < miniFat.length && remaining > 0) {
1145
+ const off = sec * miniSectorSz;
1146
+ const chunk = miniStreamData.subarray(off, off + Math.min(miniSectorSz, remaining));
1147
+ chunks.push(chunk);
1148
+ remaining -= chunk.length;
1149
+ sec = miniFat[sec];
1150
+ }
1151
+ return concatUint8(chunks).subarray(0, size);
1152
+ };
1153
+ const visit = (id, path) => {
1154
+ if (id < 0 || id >= dirEntries.length) return;
1155
+ const entry = dirEntries[id];
1156
+ const fullPath = path ? `${path}/${entry.name}` : entry.name;
1157
+ if (entry.type === 2) {
1158
+ let streamData;
1159
+ if (entry.size < miniStreamCutoff && miniStreamData) {
1160
+ streamData = readMiniChain(entry.startSec, entry.size);
1161
+ } else {
1162
+ streamData = readChain(entry.startSec).subarray(0, entry.size);
1163
+ }
1164
+ streams.set(fullPath, streamData);
1165
+ streams.set(entry.name, streamData);
1166
+ }
1167
+ if (entry.childId >= 0) visit(entry.childId, fullPath);
1168
+ if (entry.siblingLeftId >= 0) visit(entry.siblingLeftId, path);
1169
+ if (entry.siblingRightId >= 0) visit(entry.siblingRightId, path);
1170
+ };
1171
+ if (dirEntries.length > 0 && dirEntries[0].childId >= 0) {
1172
+ visit(dirEntries[0].childId, "");
1173
+ }
1174
+ return streams;
1175
+ }
1176
+ };
1177
+ function concatUint8(arrays) {
1178
+ const total = arrays.reduce((s, a) => s + a.length, 0);
1179
+ const out = new Uint8Array(total);
1180
+ let off = 0;
1181
+ for (const a of arrays) {
1182
+ out.set(a, off);
1183
+ off += a.length;
1184
+ }
1185
+ return out;
1186
+ }
1187
+
1188
+ // src/decoders/hwp/HwpScanner.ts
1189
+ var import_pako2 = __toESM(require("pako"));
1190
+ var HWPTAG_BEGIN = 16;
1191
+ var TAG_FACE_NAME = HWPTAG_BEGIN + 3;
1192
+ var TAG_BORDER_FILL = HWPTAG_BEGIN + 4;
1193
+ var TAG_CHAR_SHAPE = HWPTAG_BEGIN + 5;
1194
+ var TAG_PARA_SHAPE = HWPTAG_BEGIN + 9;
1195
+ var TAG_PARA_HEADER = HWPTAG_BEGIN + 50;
1196
+ var TAG_PARA_TEXT = HWPTAG_BEGIN + 51;
1197
+ var TAG_PARA_CHAR_SHAPE = HWPTAG_BEGIN + 52;
1198
+ var TAG_CTRL_HEADER = HWPTAG_BEGIN + 55;
1199
+ var TAG_PAGE_DEF = HWPTAG_BEGIN + 57;
1200
+ var TAG_LIST_HEADER = HWPTAG_BEGIN + 56;
1201
+ var TAG_TABLE_A = HWPTAG_BEGIN + 61;
1202
+ var TAG_CELL_A = HWPTAG_BEGIN + 62;
1203
+ var TAG_TABLE_B = HWPTAG_BEGIN + 64;
1204
+ var TAG_CELL_B = HWPTAG_BEGIN + 65;
1205
+ function isTableTag(t) {
1206
+ return t === TAG_TABLE_A || t === TAG_TABLE_B;
1207
+ }
1208
+ function isCellTag(t) {
1209
+ return t === TAG_CELL_A || t === TAG_CELL_B || t === TAG_LIST_HEADER;
1210
+ }
1211
+ var CTRL_TABLE = 1952607264;
1212
+ function parseRecords(data) {
1213
+ const out = [];
1214
+ let off = 0;
1215
+ while (off + 4 <= data.length) {
1216
+ const hdr = BinaryKit.readU32LE(data, off);
1217
+ const tag = hdr & 1023;
1218
+ const level = hdr >> 10 & 1023;
1219
+ let size = hdr >> 20 & 4095;
1220
+ off += 4;
1221
+ if (size === 4095) {
1222
+ if (off + 4 > data.length) break;
1223
+ size = BinaryKit.readU32LE(data, off);
1224
+ off += 4;
1225
+ }
1226
+ if (off + size > data.length) break;
1227
+ out.push({ tag, level, data: data.subarray(off, off + size) });
1228
+ off += size;
1229
+ }
1230
+ return out;
1231
+ }
1232
+ function tryInflate(data) {
1233
+ try {
1234
+ return import_pako2.default.inflateRaw(data);
1235
+ } catch {
1236
+ return data;
1237
+ }
1238
+ }
1239
+ function parseFileHeader(buf) {
1240
+ if (buf.length < 40) return { compressed: true, encrypted: false };
1241
+ const props = BinaryKit.readU32LE(buf, 36);
1242
+ return { compressed: (props & 1) !== 0, encrypted: (props & 2) !== 0 };
1243
+ }
1244
+ function parseDocInfo(data, compressed) {
1245
+ const raw = compressed ? tryInflate(data) : data;
1246
+ const recs = parseRecords(raw);
1247
+ const info = { faceNames: [], charShapes: [], paraShapes: [], borderFills: [] };
1248
+ for (const r of recs) {
1249
+ try {
1250
+ if (r.tag === TAG_FACE_NAME) info.faceNames.push(parseFaceName(r.data));
1251
+ if (r.tag === TAG_CHAR_SHAPE) info.charShapes.push(parseCharShape(r.data));
1252
+ if (r.tag === TAG_PARA_SHAPE) info.paraShapes.push(parseParaShape(r.data));
1253
+ if (r.tag === TAG_BORDER_FILL) info.borderFills.push(parseBorderFill(r.data));
1254
+ } catch {
1255
+ }
1256
+ }
1257
+ return info;
1258
+ }
1259
+ function parseFaceName(d) {
1260
+ if (d.length < 3) return "";
1261
+ const len = BinaryKit.readU16LE(d, 1);
1262
+ if (d.length < 3 + len * 2) return "";
1263
+ return new TextDecoder("utf-16le").decode(d.subarray(3, 3 + len * 2));
1264
+ }
1265
+ function parseCharShape(d) {
1266
+ const faceIds = [];
1267
+ for (let i = 0; i < 7; i++) faceIds.push(d.length >= (i + 1) * 2 ? BinaryKit.readU16LE(d, i * 2) : 0);
1268
+ const height = d.length >= 46 ? BinaryKit.readU32LE(d, 42) : 1e3;
1269
+ const attr = d.length >= 50 ? BinaryKit.readU32LE(d, 46) : 0;
1270
+ const ulType = attr >> 2 & 7;
1271
+ const skType = attr >> 18 & 7;
1272
+ const suType = attr >> 16 & 3;
1273
+ return {
1274
+ faceIds,
1275
+ height: height > 0 && height < 1e5 ? height : 1e3,
1276
+ italic: (attr & 1) !== 0,
1277
+ bold: (attr >> 1 & 1) !== 0,
1278
+ underline: ulType !== 0,
1279
+ strikeout: skType !== 0,
1280
+ superscript: suType === 1,
1281
+ subscript: suType === 2,
1282
+ textColor: d.length >= 56 ? colorRef(d, 52) : "000000"
1283
+ };
1284
+ }
1285
+ var ALIGN_TBL = { 0: "justify", 1: "left", 2: "right", 3: "center", 4: "justify" };
1286
+ function parseParaShape(d) {
1287
+ if (d.length < 4) return { align: "left", spaceBefore: 0, spaceAfter: 0, lineSpacing: 160, indent: 0 };
1288
+ const attr = BinaryKit.readU32LE(d, 0);
1289
+ return {
1290
+ align: ALIGN_TBL[attr & 7] ?? "left",
1291
+ indent: d.length >= 16 ? i32(d, 12) : 0,
1292
+ spaceBefore: d.length >= 20 ? i32(d, 16) : 0,
1293
+ spaceAfter: d.length >= 24 ? i32(d, 20) : 0,
1294
+ lineSpacing: d.length >= 28 ? i32(d, 24) : 160
1295
+ };
1296
+ }
1297
+ var BORDER_W_PT = [0.28, 0.34, 0.43, 0.57, 0.71, 0.85, 1.13, 1.42, 1.7, 1.98, 2.84, 4.25, 5.67, 8.5, 11.34, 14.17];
1298
+ var BORDER_KIND = { 0: "none", 1: "solid", 2: "dash", 3: "dot", 4: "dash", 5: "dash", 6: "dash", 7: "dot", 8: "double", 9: "double", 10: "double" };
1299
+ function parseBorderFill(d) {
1300
+ const borders = [];
1301
+ for (let i = 0; i < 4; i++) {
1302
+ const b = 2 + i * 6;
1303
+ if (b + 6 <= d.length) {
1304
+ borders.push({ type: d[b], widthPt: BORDER_W_PT[d[b + 1]] ?? 0.5, color: colorRef(d, b + 2) });
1305
+ } else {
1306
+ borders.push({ type: 0, widthPt: 0.5, color: "000000" });
1307
+ }
1308
+ }
1309
+ let bgColor;
1310
+ const fOff = 32;
1311
+ if (d.length >= fOff + 8) {
1312
+ const ft = BinaryKit.readU32LE(d, fOff);
1313
+ if (ft & 1) bgColor = colorRef(d, fOff + 4);
1314
+ }
1315
+ return { borders, bgColor };
1316
+ }
1317
+ function parseBody(raw, compressed, di, shield) {
1318
+ const recs = parseRecords(compressed ? tryInflate(raw) : raw);
1319
+ const content = [];
1320
+ let pageDims;
1321
+ let i = 0;
1322
+ while (i < recs.length) {
1323
+ if (recs[i].tag === TAG_PAGE_DEF) {
1324
+ pageDims = shield.guard(() => parsePageDef(recs[i].data), A4, "hwp:pageDef");
1325
+ i++;
1326
+ } else if (recs[i].tag === TAG_PARA_HEADER) {
1327
+ const r = shield.guard(
1328
+ () => parseParagraphGroup(recs, i, di, shield),
1329
+ { nodes: [], next: i + 1 },
1330
+ `hwp:para@${i}`
1331
+ );
1332
+ content.push(...r.nodes);
1333
+ i = r.next;
1334
+ } else {
1335
+ i++;
1336
+ }
1337
+ }
1338
+ return { content, pageDims };
1339
+ }
1340
+ function parseParagraphGroup(recs, start, di, shield) {
1341
+ const hdr = recs[start];
1342
+ const lv = hdr.level;
1343
+ const psId = hdr.data.length >= 10 ? BinaryKit.readU16LE(hdr.data, 8) : 0;
1344
+ const ps = di.paraShapes[psId];
1345
+ let text = null;
1346
+ let csPairs = [];
1347
+ const grids = [];
1348
+ let i = start + 1;
1349
+ while (i < recs.length && recs[i].level > lv) {
1350
+ const r = recs[i];
1351
+ if (r.tag === TAG_PARA_TEXT && r.level === lv + 1) {
1352
+ text = decodeParaText(r.data);
1353
+ i++;
1354
+ } else if (r.tag === TAG_PARA_CHAR_SHAPE && r.level === lv + 1) {
1355
+ csPairs = parseCharShapePairs(r.data);
1356
+ i++;
1357
+ } else if (r.tag === TAG_CTRL_HEADER && r.level === lv + 1) {
1358
+ if (r.data.length >= 4 && BinaryKit.readU32LE(r.data, 0) === CTRL_TABLE) {
1359
+ const tr = shield.guard(
1360
+ () => parseTableCtrl(recs, i, di, shield),
1361
+ { grid: null, next: skipKids(recs, i) },
1362
+ `hwp:tbl@${i}`
1363
+ );
1364
+ if (tr.grid) grids.push(tr.grid);
1365
+ i = tr.next;
1366
+ } else {
1367
+ i = skipKids(recs, i);
1368
+ }
1369
+ } else {
1370
+ i++;
1371
+ }
1372
+ }
1373
+ const nodes = [];
1374
+ if (text && text.chars.length > 0) {
1375
+ const joined = text.chars.map((c) => c.ch).join("");
1376
+ if (joined.trim()) {
1377
+ const spans = resolveCharShapes(text.chars, csPairs, di);
1378
+ nodes.push(buildPara(spans, buildParaProps(ps)));
1379
+ }
1380
+ }
1381
+ nodes.push(...grids);
1382
+ return { nodes, next: i };
1383
+ }
1384
+ function skipKids(recs, idx) {
1385
+ const lv = recs[idx].level;
1386
+ let i = idx + 1;
1387
+ while (i < recs.length && recs[i].level > lv) i++;
1388
+ return i;
1389
+ }
1390
+ var EXT_CTRL = /* @__PURE__ */ new Set([2, 3, 11, 12, 14, 15]);
1391
+ var INL_CTRL = /* @__PURE__ */ new Set([4, 5, 6, 7, 8]);
1392
+ function decodeParaText(d) {
1393
+ const chars = [];
1394
+ const controlPositions = [];
1395
+ let i = 0, pos = 0;
1396
+ while (i + 1 < d.length) {
1397
+ const c = d[i] | d[i + 1] << 8;
1398
+ if (c === 0) {
1399
+ i += 2;
1400
+ pos++;
1401
+ continue;
1402
+ }
1403
+ if (c === 13) {
1404
+ break;
1405
+ }
1406
+ if (c === 10) {
1407
+ chars.push({ pos, ch: "\n" });
1408
+ i += 2;
1409
+ pos++;
1410
+ continue;
1411
+ }
1412
+ if (EXT_CTRL.has(c)) {
1413
+ controlPositions.push(pos);
1414
+ i += 16;
1415
+ pos += 8;
1416
+ continue;
1417
+ }
1418
+ if (INL_CTRL.has(c)) {
1419
+ i += 16;
1420
+ pos += 8;
1421
+ continue;
1422
+ }
1423
+ if (c === 9) {
1424
+ chars.push({ pos, ch: " " });
1425
+ i += 16;
1426
+ pos += 8;
1427
+ continue;
1428
+ }
1429
+ if (c >= 1 && c <= 31) {
1430
+ i += 2;
1431
+ pos++;
1432
+ continue;
1433
+ }
1434
+ chars.push({ pos, ch: String.fromCharCode(c) });
1435
+ i += 2;
1436
+ pos++;
1437
+ }
1438
+ return { chars, controlPositions };
1439
+ }
1440
+ function parseCharShapePairs(d) {
1441
+ const out = [];
1442
+ for (let i = 0; i + 7 < d.length; i += 8)
1443
+ out.push([BinaryKit.readU32LE(d, i), BinaryKit.readU32LE(d, i + 4)]);
1444
+ return out;
1445
+ }
1446
+ function resolveCharShapes(chars, pairs, di) {
1447
+ if (chars.length === 0) return [buildSpan("")];
1448
+ const defaultId = pairs.length > 0 ? pairs[0][1] : 0;
1449
+ function idFor(pos) {
1450
+ let id = defaultId;
1451
+ for (const [p, sid] of pairs) {
1452
+ if (p <= pos) id = sid;
1453
+ else break;
1454
+ }
1455
+ return id;
1456
+ }
1457
+ const spans = [];
1458
+ let curId = idFor(chars[0].pos);
1459
+ let buf = chars[0].ch;
1460
+ for (let k = 1; k < chars.length; k++) {
1461
+ const sid = idFor(chars[k].pos);
1462
+ if (sid !== curId) {
1463
+ spans.push(styledSpan(buf, curId, di));
1464
+ buf = "";
1465
+ curId = sid;
1466
+ }
1467
+ buf += chars[k].ch;
1468
+ }
1469
+ if (buf) spans.push(styledSpan(buf, curId, di));
1470
+ return spans;
1471
+ }
1472
+ function styledSpan(text, shapeId, di) {
1473
+ const cs = di.charShapes[shapeId];
1474
+ if (!cs) return buildSpan(text);
1475
+ const props = {};
1476
+ const fid = cs.faceIds[0] ?? 0;
1477
+ if (fid < di.faceNames.length && di.faceNames[fid]) props.font = safeFont(di.faceNames[fid]);
1478
+ if (cs.height > 0) props.pt = Metric.hwpToPt(cs.height);
1479
+ if (cs.bold) props.b = true;
1480
+ if (cs.italic) props.i = true;
1481
+ if (cs.underline) props.u = true;
1482
+ if (cs.strikeout) props.s = true;
1483
+ if (cs.superscript) props.sup = true;
1484
+ if (cs.subscript) props.sub = true;
1485
+ const hex = safeHex(cs.textColor);
1486
+ if (hex && hex !== "000000") props.color = hex;
1487
+ return buildSpan(text, props);
1488
+ }
1489
+ function parseTableCtrl(recs, ctrlIdx, di, shield) {
1490
+ const ctrlLv = recs[ctrlIdx].level;
1491
+ let i = ctrlIdx + 1;
1492
+ let tblData = null;
1493
+ const cells = [];
1494
+ const tblLevel = ctrlLv + 1;
1495
+ while (i < recs.length && recs[i].level > ctrlLv) {
1496
+ const r = recs[i];
1497
+ if (isTableTag(r.tag) && r.level === tblLevel) {
1498
+ tblData = r.data;
1499
+ i++;
1500
+ } else if (r.tag === TAG_LIST_HEADER && r.level === tblLevel) {
1501
+ const cellData = r.data;
1502
+ const paraCount = cellData.length >= 2 ? BinaryKit.readU16LE(cellData, 0) : 0;
1503
+ i++;
1504
+ const cStart = i;
1505
+ let consumed = 0;
1506
+ while (i < recs.length && consumed < paraCount) {
1507
+ if (recs[i].tag === TAG_PARA_HEADER && recs[i].level === tblLevel) {
1508
+ consumed++;
1509
+ i++;
1510
+ while (i < recs.length && recs[i].level > tblLevel) i++;
1511
+ } else if (recs[i].level > tblLevel) {
1512
+ i++;
1513
+ } else {
1514
+ break;
1515
+ }
1516
+ }
1517
+ cells.push({ data: cellData, tag: TAG_LIST_HEADER, cStart, cEnd: i });
1518
+ } else if (isCellTag(r.tag) && r.level === tblLevel) {
1519
+ const cellData = r.data;
1520
+ const cellTag = r.tag;
1521
+ i++;
1522
+ const cStart = i;
1523
+ while (i < recs.length && recs[i].level > tblLevel) i++;
1524
+ cells.push({ data: cellData, tag: cellTag, cStart, cEnd: i });
1525
+ } else {
1526
+ i++;
1527
+ }
1528
+ }
1529
+ if (!tblData || cells.length === 0) return { grid: null, next: i };
1530
+ const rowCnt = tblData.length >= 6 ? BinaryKit.readU16LE(tblData, 4) : 1;
1531
+ const colCnt = tblData.length >= 8 ? BinaryKit.readU16LE(tblData, 6) : 1;
1532
+ const parsed = [];
1533
+ for (let ci = 0; ci < cells.length; ci++) {
1534
+ const c = cells[ci];
1535
+ const seqIdx = ci;
1536
+ const pc = shield.guard(
1537
+ () => parseCellRec(c.data, c.tag, recs, c.cStart, c.cEnd, di, shield, seqIdx, colCnt),
1538
+ { row: Math.floor(ci / (colCnt || 1)), col: ci % (colCnt || 1), cs: 1, rs: 1, widthHwp: 0, props: {}, paras: [buildPara([buildSpan("")])] },
1539
+ `hwp:cell@${c.cStart}`
1540
+ );
1541
+ parsed.push(pc);
1542
+ }
1543
+ const maxRow = parsed.reduce((m, c) => Math.max(m, c.row + c.rs), 0);
1544
+ const actualRowCnt = Math.max(rowCnt, maxRow);
1545
+ const posValid = parsed.every((c) => c.row >= 0 && c.col >= 0 && c.col < colCnt);
1546
+ if (!posValid) {
1547
+ let idx = 0;
1548
+ for (const c of parsed) {
1549
+ c.row = Math.floor(idx / colCnt);
1550
+ c.col = idx % colCnt;
1551
+ idx++;
1552
+ }
1553
+ }
1554
+ const colWidthsPt = new Array(colCnt).fill(0);
1555
+ for (const c of parsed) {
1556
+ if (c.cs === 1 && c.widthHwp > 0) {
1557
+ const wPt = Metric.hwpToPt(c.widthHwp);
1558
+ if (wPt > colWidthsPt[c.col]) colWidthsPt[c.col] = wPt;
1559
+ }
1560
+ }
1561
+ const zeroColumns = colWidthsPt.filter((w) => w === 0).length;
1562
+ if (zeroColumns > 0) {
1563
+ for (const c of parsed) {
1564
+ if (c.cs > 1 && c.widthHwp > 0) {
1565
+ let known = 0;
1566
+ let unknownCols = 0;
1567
+ for (let ci = c.col; ci < c.col + c.cs && ci < colCnt; ci++) {
1568
+ if (colWidthsPt[ci] > 0) known += colWidthsPt[ci];
1569
+ else unknownCols++;
1570
+ }
1571
+ if (unknownCols > 0) {
1572
+ const remaining = Metric.hwpToPt(c.widthHwp) - known;
1573
+ const each = remaining > 0 ? remaining / unknownCols : 0;
1574
+ for (let ci = c.col; ci < c.col + c.cs && ci < colCnt; ci++) {
1575
+ if (colWidthsPt[ci] === 0 && each > 0) colWidthsPt[ci] = each;
1576
+ }
1577
+ }
1578
+ }
1579
+ }
1580
+ }
1581
+ const rows = [];
1582
+ for (let r = 0; r < actualRowCnt; r++) {
1583
+ const rc = parsed.filter((c) => c.row === r).sort((a, b) => a.col - b.col);
1584
+ if (rc.length === 0) continue;
1585
+ rows.push(buildRow(rc.map(
1586
+ (c) => buildCell(c.paras.length ? c.paras : [buildPara([buildSpan("")])], { cs: c.cs, rs: c.rs, props: c.props })
1587
+ )));
1588
+ }
1589
+ if (rows.length === 0) return { grid: null, next: i };
1590
+ let defStroke;
1591
+ const bfOff = 18 + rowCnt * 2;
1592
+ if (tblData.length >= bfOff + 2) {
1593
+ const bfId = BinaryKit.readU16LE(tblData, bfOff);
1594
+ defStroke = strokeFromBF(bfId, di);
1595
+ }
1596
+ const gp = {};
1597
+ if (defStroke) gp.defaultStroke = defStroke;
1598
+ const hasWidths = colWidthsPt.some((w) => w > 0);
1599
+ if (hasWidths) gp.colWidths = colWidthsPt;
1600
+ return { grid: buildGrid(rows, gp), next: i };
1601
+ }
1602
+ function parseCellRec(d, tag, recs, cStart, cEnd, di, shield, seqIdx, colCnt) {
1603
+ let col, row, cs = 1, rs = 1;
1604
+ let widthHwp = 0;
1605
+ const props = {};
1606
+ const attr = d.length >= 6 ? BinaryKit.readU32LE(d, 2) : 0;
1607
+ const va = attr >> 6 & 3;
1608
+ if (va === 1) props.va = "mid";
1609
+ else if (va === 2) props.va = "bot";
1610
+ if (tag === TAG_LIST_HEADER && d.length >= 22) {
1611
+ col = BinaryKit.readU16LE(d, 8);
1612
+ row = BinaryKit.readU16LE(d, 10);
1613
+ rs = Math.max(1, BinaryKit.readU16LE(d, 12));
1614
+ cs = Math.max(1, BinaryKit.readU16LE(d, 14));
1615
+ widthHwp = BinaryKit.readU32LE(d, 16);
1616
+ const bfId = d.length >= 34 ? BinaryKit.readU16LE(d, 32) : 0;
1617
+ if (bfId > 0 && bfId <= di.borderFills.length) {
1618
+ const bf = di.borderFills[bfId - 1];
1619
+ if (bf.borders.length >= 4) {
1620
+ props.left = toStroke(bf.borders[0]);
1621
+ props.right = toStroke(bf.borders[1]);
1622
+ props.top = toStroke(bf.borders[2]);
1623
+ props.bot = toStroke(bf.borders[3]);
1624
+ }
1625
+ if (bf.bgColor && bf.bgColor !== "FFFFFF") props.bg = bf.bgColor;
1626
+ }
1627
+ } else if (tag !== TAG_LIST_HEADER) {
1628
+ col = d.length >= 8 ? BinaryKit.readU16LE(d, 6) : seqIdx % (colCnt || 1);
1629
+ row = d.length >= 10 ? BinaryKit.readU16LE(d, 8) : Math.floor(seqIdx / (colCnt || 1));
1630
+ cs = d.length >= 12 ? Math.max(1, BinaryKit.readU16LE(d, 10)) : 1;
1631
+ rs = d.length >= 14 ? Math.max(1, BinaryKit.readU16LE(d, 12)) : 1;
1632
+ widthHwp = d.length >= 18 ? BinaryKit.readU32LE(d, 14) : 0;
1633
+ const bfId = d.length >= 32 ? BinaryKit.readU16LE(d, 30) : 0;
1634
+ if (bfId > 0 && bfId <= di.borderFills.length) {
1635
+ const bf = di.borderFills[bfId - 1];
1636
+ if (bf.borders.length >= 4) {
1637
+ props.left = toStroke(bf.borders[0]);
1638
+ props.right = toStroke(bf.borders[1]);
1639
+ props.top = toStroke(bf.borders[2]);
1640
+ props.bot = toStroke(bf.borders[3]);
1641
+ }
1642
+ if (bf.bgColor && bf.bgColor !== "FFFFFF") props.bg = bf.bgColor;
1643
+ }
1644
+ } else {
1645
+ row = Math.floor(seqIdx / (colCnt || 1));
1646
+ col = seqIdx % (colCnt || 1);
1647
+ }
1648
+ const paras = [];
1649
+ let k = cStart;
1650
+ while (k < cEnd) {
1651
+ if (recs[k].tag === TAG_PARA_HEADER) {
1652
+ const r = shield.guard(
1653
+ () => {
1654
+ const hdr = recs[k];
1655
+ const lv = hdr.level;
1656
+ const psId = hdr.data.length >= 10 ? BinaryKit.readU16LE(hdr.data, 8) : 0;
1657
+ const ps = di.paraShapes[psId];
1658
+ let txt = null;
1659
+ let csp = [];
1660
+ let j = k + 1;
1661
+ while (j < cEnd && recs[j].level > lv) {
1662
+ if (recs[j].tag === TAG_PARA_TEXT) {
1663
+ txt = decodeParaText(recs[j].data);
1664
+ j++;
1665
+ } else if (recs[j].tag === TAG_PARA_CHAR_SHAPE) {
1666
+ csp = parseCharShapePairs(recs[j].data);
1667
+ j++;
1668
+ } else j++;
1669
+ }
1670
+ const spans = txt && txt.chars.length > 0 ? resolveCharShapes(txt.chars, csp, di) : [buildSpan("")];
1671
+ return { para: buildPara(spans, buildParaProps(ps)), next: j };
1672
+ },
1673
+ { para: buildPara([buildSpan("")]), next: k + 1 },
1674
+ `hwp:cellP@${k}`
1675
+ );
1676
+ paras.push(r.para);
1677
+ k = r.next;
1678
+ } else {
1679
+ k++;
1680
+ }
1681
+ }
1682
+ return { row, col, cs, rs, props, widthHwp, paras: paras.length ? paras : [buildPara([buildSpan("")])] };
1683
+ }
1684
+ function parsePageDef(d) {
1685
+ if (d.length < 24) return A4;
1686
+ const w = BinaryKit.readU32LE(d, 0);
1687
+ const h = BinaryKit.readU32LE(d, 4);
1688
+ const ml = BinaryKit.readU32LE(d, 8);
1689
+ const mr = BinaryKit.readU32LE(d, 12);
1690
+ const mt = BinaryKit.readU32LE(d, 16);
1691
+ const mb = BinaryKit.readU32LE(d, 20);
1692
+ const at = d.length >= 40 ? BinaryKit.readU32LE(d, 36) : 0;
1693
+ return {
1694
+ wPt: Metric.hwpToPt(w),
1695
+ hPt: Metric.hwpToPt(h),
1696
+ ml: Metric.hwpToPt(ml),
1697
+ mr: Metric.hwpToPt(mr),
1698
+ mt: Metric.hwpToPt(mt),
1699
+ mb: Metric.hwpToPt(mb),
1700
+ orient: at & 1 ? "landscape" : "portrait"
1701
+ };
1702
+ }
1703
+ function i32(d, o) {
1704
+ const u = BinaryKit.readU32LE(d, o);
1705
+ return u > 2147483647 ? u - 4294967296 : u;
1706
+ }
1707
+ function colorRef(d, o) {
1708
+ if (o + 3 > d.length) return "000000";
1709
+ return (d[o] << 16 | d[o + 1] << 8 | d[o + 2]).toString(16).padStart(6, "0").toUpperCase();
1710
+ }
1711
+ function toStroke(b) {
1712
+ return { kind: BORDER_KIND[b.type] ?? "solid", pt: b.widthPt, color: b.color };
1713
+ }
1714
+ function strokeFromBF(bfId, di) {
1715
+ if (bfId <= 0 || bfId > di.borderFills.length) return void 0;
1716
+ const bf = di.borderFills[bfId - 1];
1717
+ if (!bf.borders.length) return void 0;
1718
+ const b = bf.borders[0];
1719
+ return { kind: BORDER_KIND[b.type] ?? "solid", pt: b.widthPt, color: b.color };
1720
+ }
1721
+ function buildParaProps(ps) {
1722
+ if (!ps) return {};
1723
+ const p = {};
1724
+ if (ps.align && ps.align !== "left") p.align = ps.align;
1725
+ if (ps.spaceBefore > 0) p.spaceBefore = Metric.hwpToPt(ps.spaceBefore);
1726
+ if (ps.spaceAfter > 0) p.spaceAfter = Metric.hwpToPt(ps.spaceAfter);
1727
+ if (ps.lineSpacing > 0 && ps.lineSpacing !== 160) p.lineHeight = ps.lineSpacing / 100;
1728
+ if (ps.indent > 0) p.indentPt = Metric.hwpToPt(ps.indent);
1729
+ return p;
1730
+ }
1731
+ var HwpScanner = class {
1732
+ constructor() {
1733
+ this.format = "hwp";
1734
+ }
1735
+ async decode(data) {
1736
+ const shield = new ShieldedParser();
1737
+ const warns = [];
1738
+ try {
1739
+ if (!BinaryKit.isOle2(data)) return fail("HWP: Invalid OLE2 signature");
1740
+ const streams = BinaryKit.parseCfb(data);
1741
+ const fh = streams.get("FileHeader");
1742
+ const { compressed, encrypted } = fh ? parseFileHeader(fh) : { compressed: true, encrypted: false };
1743
+ if (encrypted) return fail("HWP: \uC554\uD638\uD654\uB41C \uD30C\uC77C\uC740 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
1744
+ const diRaw = streams.get("DocInfo");
1745
+ let di = { faceNames: [], charShapes: [], paraShapes: [], borderFills: [] };
1746
+ if (diRaw) {
1747
+ di = shield.guard(() => parseDocInfo(diRaw, compressed), di, "hwp:docInfo");
1748
+ }
1749
+ const allContent = [];
1750
+ let pageDims = A4;
1751
+ for (let s = 0; s < 100; s++) {
1752
+ const sec = streams.get(`BodyText/Section${s}`) ?? streams.get(`Section${s}`);
1753
+ if (!sec) {
1754
+ if (s === 0) {
1755
+ const fb = findBodySection(streams);
1756
+ if (fb) {
1757
+ const r2 = parseBody(fb, compressed, di, shield);
1758
+ allContent.push(...r2.content);
1759
+ if (r2.pageDims) pageDims = r2.pageDims;
1760
+ }
1761
+ }
1762
+ break;
1763
+ }
1764
+ const r = shield.guard(
1765
+ () => parseBody(sec, compressed, di, shield),
1766
+ { content: [], pageDims: void 0 },
1767
+ `hwp:sec${s}`
1768
+ );
1769
+ allContent.push(...r.content);
1770
+ if (r.pageDims) pageDims = r.pageDims;
1771
+ }
1772
+ warns.push(...shield.flush());
1773
+ const content = allContent.length > 0 ? allContent : [buildPara([buildSpan("")])];
1774
+ return succeed(buildRoot({}, [buildSheet(content, pageDims)]), warns);
1775
+ } catch (e) {
1776
+ warns.push(...shield.flush());
1777
+ return fail(`HWP decode error: ${e?.message ?? String(e)}`, warns);
1778
+ }
1779
+ }
1780
+ };
1781
+ function findBodySection(streams) {
1782
+ for (const [k, v] of streams)
1783
+ if (k.includes("Section") && !k.includes("Header") && !k.includes("Info")) return v;
1784
+ return void 0;
1785
+ }
1786
+ registry.registerDecoder(new HwpScanner());
1787
+
1788
+ // src/decoders/docx/DocxDecoder.ts
1789
+ var DocxDecoder = class {
1790
+ constructor() {
1791
+ this.format = "docx";
1792
+ }
1793
+ async decode(data) {
1794
+ const shield = new ShieldedParser();
1795
+ const warns = [];
1796
+ try {
1797
+ const files = await ArchiveKit.unzip(data);
1798
+ const docXml = files.get("word/document.xml");
1799
+ if (!docXml) return fail("DOCX: word/document.xml not found");
1800
+ const relsXml = files.get("word/_rels/document.xml.rels");
1801
+ const relsMap = relsXml ? await parseRels(TextKit.decode(relsXml)) : /* @__PURE__ */ new Map();
1802
+ const coreXml2 = files.get("docProps/core.xml");
1803
+ let meta = {};
1804
+ if (coreXml2) {
1805
+ try {
1806
+ meta = await parseCoreProps(TextKit.decode(coreXml2));
1807
+ } catch {
1808
+ }
1809
+ }
1810
+ const numXml = files.get("word/numbering.xml");
1811
+ let numMap = /* @__PURE__ */ new Map();
1812
+ if (numXml) {
1813
+ try {
1814
+ numMap = await parseNumbering(TextKit.decode(numXml));
1815
+ } catch {
1816
+ }
1817
+ }
1818
+ const docStr = TextKit.decode(docXml);
1819
+ const docObj = await XmlKit.parseStrict(docStr);
1820
+ const body = getBody(docObj);
1821
+ const dims = extractDims2(body) ?? { ...A4 };
1822
+ const elements = getBodyElements(body);
1823
+ const decCtx = { relsMap, files, shield, numMap, warns };
1824
+ const kids = shield.guardAll(
1825
+ elements,
1826
+ (el) => decodeElement(el, decCtx),
1827
+ () => buildPara([buildSpan("[\uC694\uC18C \uD30C\uC2F1 \uC2E4\uD328]")]),
1828
+ "docx:bodyElement"
1829
+ );
1830
+ const headerParas = await decodeHeaderFooter2("header", body, relsMap, files, decCtx);
1831
+ const footerParas = await decodeHeaderFooter2("footer", body, relsMap, files, decCtx);
1832
+ warns.push(...shield.flush());
1833
+ const sheet = buildSheet(
1834
+ kids.filter(Boolean),
1835
+ dims,
1836
+ { header: headerParas, footer: footerParas }
1837
+ );
1838
+ return succeed(buildRoot(meta, [sheet]), warns);
1839
+ } catch (e) {
1840
+ warns.push(...shield.flush());
1841
+ return fail(`DOCX decode error: ${e?.message ?? String(e)}`, warns);
1842
+ }
1843
+ }
1844
+ };
1845
+ function toArr2(v) {
1846
+ return v == null ? [] : Array.isArray(v) ? v : [v];
1847
+ }
1848
+ async function parseRels(xml) {
1849
+ const map = /* @__PURE__ */ new Map();
1850
+ try {
1851
+ const obj = await XmlKit.parseStrict(xml);
1852
+ for (const rel of toArr2(obj?.Relationships?.[0]?.Relationship)) {
1853
+ const a = rel?._attr ?? {};
1854
+ if (a.Id && a.Target) map.set(a.Id, a.Target);
1855
+ }
1856
+ } catch {
1857
+ }
1858
+ return map;
1859
+ }
1860
+ async function parseCoreProps(xml) {
1861
+ try {
1862
+ const obj = await XmlKit.parseStrict(xml);
1863
+ const c = obj?.["cp:coreProperties"]?.[0] ?? obj?.coreProperties?.[0] ?? {};
1864
+ return {
1865
+ title: c?.["dc:title"]?.[0]?._text ?? void 0,
1866
+ author: c?.["dc:creator"]?.[0]?._text ?? void 0,
1867
+ subject: c?.["dc:subject"]?.[0]?._text ?? void 0,
1868
+ created: c?.["dcterms:created"]?.[0]?._text ?? void 0,
1869
+ modified: c?.["dcterms:modified"]?.[0]?._text ?? void 0
1870
+ };
1871
+ } catch {
1872
+ return {};
1873
+ }
1874
+ }
1875
+ async function parseNumbering(xml) {
1876
+ const map = /* @__PURE__ */ new Map();
1877
+ try {
1878
+ const obj = await XmlKit.parseStrict(xml);
1879
+ const root = obj?.["w:numbering"]?.[0] ?? obj?.numbering?.[0] ?? obj;
1880
+ const absMap = /* @__PURE__ */ new Map();
1881
+ for (const abs of toArr2(root?.["w:abstractNum"] ?? root?.abstractNum)) {
1882
+ const absId = Number(abs?._attr?.["w:abstractNumId"] ?? abs?._attr?.abstractNumId ?? 0);
1883
+ const levels = /* @__PURE__ */ new Map();
1884
+ for (const lvl of toArr2(abs?.["w:lvl"] ?? abs?.lvl)) {
1885
+ const ilvl = Number(lvl?._attr?.["w:ilvl"] ?? lvl?._attr?.ilvl ?? 0);
1886
+ const fmtNode = lvl?.["w:numFmt"]?.[0]?._attr ?? lvl?.numFmt?.[0]?._attr ?? {};
1887
+ const fmt = fmtNode?.["w:val"] ?? fmtNode?.val ?? "decimal";
1888
+ levels.set(ilvl, { fmt, isOrdered: fmt !== "bullet" });
1889
+ }
1890
+ absMap.set(absId, levels);
1891
+ }
1892
+ for (const num of toArr2(root?.["w:num"] ?? root?.num)) {
1893
+ const numId = Number(num?._attr?.["w:numId"] ?? num?._attr?.numId ?? 0);
1894
+ const absRef = num?.["w:abstractNumId"]?.[0]?._attr ?? num?.abstractNumId?.[0]?._attr ?? {};
1895
+ const absId = Number(absRef?.["w:val"] ?? absRef?.val ?? 0);
1896
+ const levels = absMap.get(absId) ?? /* @__PURE__ */ new Map();
1897
+ map.set(numId, { levels });
1898
+ }
1899
+ } catch {
1900
+ }
1901
+ return map;
1902
+ }
1903
+ function getBody(obj) {
1904
+ return obj?.["w:document"]?.[0]?.["w:body"]?.[0] ?? obj?.document?.[0]?.body?.[0] ?? obj;
1905
+ }
1906
+ function extractDims2(body) {
1907
+ try {
1908
+ const sp = body?.["w:sectPr"]?.[0] ?? body?.sectPr?.[0];
1909
+ if (!sp) return null;
1910
+ const sz = sp?.["w:pgSz"]?.[0]?._attr ?? sp?.pgSz?.[0]?._attr;
1911
+ const mar = sp?.["w:pgMar"]?.[0]?._attr ?? sp?.pgMar?.[0]?._attr;
1912
+ if (!sz) return null;
1913
+ return {
1914
+ wPt: Metric.dxaToPt(Number(sz["w:w"] ?? sz.w ?? 11906)),
1915
+ hPt: Metric.dxaToPt(Number(sz["w:h"] ?? sz.h ?? 16838)),
1916
+ mt: Metric.dxaToPt(Number(mar?.["w:top"] ?? mar?.top ?? 1440)),
1917
+ mb: Metric.dxaToPt(Number(mar?.["w:bottom"] ?? mar?.bottom ?? 1440)),
1918
+ ml: Metric.dxaToPt(Number(mar?.["w:left"] ?? mar?.left ?? 1800)),
1919
+ mr: Metric.dxaToPt(Number(mar?.["w:right"] ?? mar?.right ?? 1800)),
1920
+ orient: (sz["w:orient"] ?? sz.orient) === "landscape" ? "landscape" : "portrait"
1921
+ };
1922
+ } catch {
1923
+ return null;
1924
+ }
1925
+ }
1926
+ function getBodyElements(body) {
1927
+ const paras = toArr2(body?.["w:p"] ?? body?.p);
1928
+ const tables = toArr2(body?.["w:tbl"] ?? body?.tbl);
1929
+ if (tables.length === 0) return paras.map((n) => ({ type: "para", node: n }));
1930
+ if (paras.length === 0) return tables.map((n) => ({ type: "table", node: n }));
1931
+ const childOrder = body?.["_childOrder"];
1932
+ if (Array.isArray(childOrder)) {
1933
+ const items = [];
1934
+ let pi = 0, ti = 0;
1935
+ for (const tag of childOrder) {
1936
+ if ((tag === "w:p" || tag === "p") && pi < paras.length) {
1937
+ items.push({ type: "para", node: paras[pi++] });
1938
+ } else if ((tag === "w:tbl" || tag === "tbl") && ti < tables.length) {
1939
+ items.push({ type: "table", node: tables[ti++] });
1940
+ }
1941
+ }
1942
+ while (pi < paras.length) items.push({ type: "para", node: paras[pi++] });
1943
+ while (ti < tables.length) items.push({ type: "table", node: tables[ti++] });
1944
+ return items;
1945
+ }
1946
+ return [
1947
+ ...paras.map((n) => ({ type: "para", node: n })),
1948
+ ...tables.map((n) => ({ type: "table", node: n }))
1949
+ ];
1950
+ }
1951
+ async function decodeHeaderFooter2(kind, body, relsMap, files, ctx) {
1952
+ try {
1953
+ const sp = body?.["w:sectPr"]?.[0] ?? body?.sectPr?.[0];
1954
+ if (!sp) return void 0;
1955
+ const refTag = kind === "header" ? "w:headerReference" : "w:footerReference";
1956
+ const refs = toArr2(sp?.[refTag] ?? sp?.[refTag.replace("w:", "")]);
1957
+ if (refs.length === 0) return void 0;
1958
+ const rId = refs[0]?._attr?.["r:id"] ?? refs[0]?._attr?.["r:Id"] ?? refs[0]?._attr?.id;
1959
+ if (!rId) return void 0;
1960
+ const target = relsMap.get(rId);
1961
+ if (!target) return void 0;
1962
+ const filePath = target.startsWith("/") ? target.slice(1) : `word/${target}`;
1963
+ const fileData = files.get(filePath);
1964
+ if (!fileData) return void 0;
1965
+ const xmlStr = TextKit.decode(fileData);
1966
+ const obj = await XmlKit.parseStrict(xmlStr);
1967
+ const rootTag = kind === "header" ? "w:hdr" : "w:ftr";
1968
+ const root = obj?.[rootTag]?.[0] ?? obj?.[rootTag.replace("w:", "")]?.[0] ?? obj;
1969
+ const paras = toArr2(root?.["w:p"] ?? root?.p);
1970
+ if (paras.length === 0) return void 0;
1971
+ return paras.map((p) => decodePara2(p, ctx));
1972
+ } catch {
1973
+ return void 0;
1974
+ }
1975
+ }
1976
+ function decodeElement(el, ctx) {
1977
+ if (el.type === "table") {
1978
+ const { value } = ctx.shield.guardGrid(
1979
+ el.node,
1980
+ (n) => decodeGrid2(n, ctx),
1981
+ (n) => decodeGridSimple2(n),
1982
+ (n) => decodeGridFlat2(n),
1983
+ (n) => decodeGridText2(n),
1984
+ "docx:table"
1985
+ );
1986
+ return value;
1987
+ }
1988
+ return decodePara2(el.node, ctx);
1989
+ }
1990
+ function decodePara2(p, ctx) {
1991
+ const pPr = p?.["w:pPr"]?.[0] ?? {};
1992
+ const alignVal = pPr?.["w:jc"]?.[0]?._attr?.["w:val"] ?? pPr?.["w:jc"]?.[0]?._attr?.val;
1993
+ const headStyle = pPr?.["w:pStyle"]?.[0]?._attr?.["w:val"] ?? pPr?.["w:pStyle"]?.[0]?._attr?.val ?? "";
1994
+ const props = {
1995
+ align: safeAlign(alignVal),
1996
+ heading: parseHeading(headStyle)
1997
+ };
1998
+ const numPr = pPr?.["w:numPr"]?.[0] ?? pPr?.numPr?.[0];
1999
+ if (numPr) {
2000
+ const ilvlNode = numPr?.["w:ilvl"]?.[0]?._attr ?? numPr?.ilvl?.[0]?._attr ?? {};
2001
+ const numIdNode = numPr?.["w:numId"]?.[0]?._attr ?? numPr?.numId?.[0]?._attr ?? {};
2002
+ const ilvl = Number(ilvlNode?.["w:val"] ?? ilvlNode?.val ?? 0);
2003
+ const numId = Number(numIdNode?.["w:val"] ?? numIdNode?.val ?? 0);
2004
+ props.listLv = ilvl;
2005
+ const numEntry = ctx.numMap.get(numId);
2006
+ if (numEntry) {
2007
+ const lvlInfo = numEntry.levels.get(ilvl) ?? numEntry.levels.get(0);
2008
+ props.listOrd = lvlInfo?.isOrdered ?? false;
2009
+ } else {
2010
+ props.listOrd = numId >= 2;
2011
+ }
2012
+ }
2013
+ const runs = toArr2(p?.["w:r"] ?? p?.r);
2014
+ const kids = ctx.shield.guardAll(
2015
+ runs,
2016
+ (run) => decodeRunOrImage(run, ctx),
2017
+ () => buildSpan(""),
2018
+ "docx:run"
2019
+ );
2020
+ return buildPara(kids.filter(Boolean), props);
2021
+ }
2022
+ function decodeRunOrImage(run, ctx) {
2023
+ const drawing = run?.["w:drawing"]?.[0] ?? run?.drawing?.[0];
2024
+ if (drawing) {
2025
+ const img = decodeDrawing(drawing, ctx);
2026
+ if (img) return img;
2027
+ }
2028
+ return decodeRun(run, ctx);
2029
+ }
2030
+ function decodeDrawing(drawing, ctx) {
2031
+ try {
2032
+ const inline = drawing?.["wp:inline"]?.[0] ?? drawing?.inline?.[0];
2033
+ const anchor = drawing?.["wp:anchor"]?.[0] ?? drawing?.anchor?.[0];
2034
+ const container = inline ?? anchor;
2035
+ if (!container) return null;
2036
+ const extent = container?.["wp:extent"]?.[0]?._attr ?? container?.extent?.[0]?._attr ?? {};
2037
+ const cx = Number(extent?.cx ?? 0);
2038
+ const cy = Number(extent?.cy ?? 0);
2039
+ const wPt = Metric.emuToPt(cx);
2040
+ const hPt = Metric.emuToPt(cy);
2041
+ const docPr = container?.["wp:docPr"]?.[0]?._attr ?? container?.docPr?.[0]?._attr ?? {};
2042
+ const alt = docPr?.descr ?? docPr?.name ?? "";
2043
+ const graphic = container?.["a:graphic"]?.[0] ?? container?.graphic?.[0];
2044
+ const graphicData = graphic?.["a:graphicData"]?.[0] ?? graphic?.graphicData?.[0];
2045
+ const pic = graphicData?.["pic:pic"]?.[0] ?? graphicData?.pic?.[0];
2046
+ const blipFill = pic?.["pic:blipFill"]?.[0] ?? pic?.blipFill?.[0];
2047
+ const blip = blipFill?.["a:blip"]?.[0]?._attr ?? blipFill?.blip?.[0]?._attr ?? {};
2048
+ const rId = blip?.["r:embed"] ?? blip?.embed;
2049
+ if (!rId) return null;
2050
+ const target = ctx.relsMap.get(rId);
2051
+ if (!target) return null;
2052
+ const filePath = target.startsWith("/") ? target.slice(1) : `word/${target}`;
2053
+ const fileData = ctx.files.get(filePath);
2054
+ if (!fileData) return null;
2055
+ const ext = target.split(".").pop()?.toLowerCase() ?? "png";
2056
+ const mimeMap = {
2057
+ png: "image/png",
2058
+ jpg: "image/jpeg",
2059
+ jpeg: "image/jpeg",
2060
+ gif: "image/gif",
2061
+ bmp: "image/bmp"
2062
+ };
2063
+ const mime = mimeMap[ext] ?? "image/png";
2064
+ return buildImg(TextKit.base64Encode(fileData), mime, wPt, hPt, alt || void 0);
2065
+ } catch {
2066
+ return null;
2067
+ }
2068
+ }
2069
+ function decodeRun(run, ctx) {
2070
+ const rPr = run?.["w:rPr"]?.[0] ?? run?.rPr?.[0] ?? {};
2071
+ const szAttr = rPr?.["w:sz"]?.[0]?._attr ?? rPr?.sz?.[0]?._attr ?? {};
2072
+ const szVal = szAttr?.["w:val"] ?? szAttr?.val;
2073
+ const colorAttr = rPr?.["w:color"]?.[0]?._attr ?? rPr?.color?.[0]?._attr ?? {};
2074
+ const colorVal = colorAttr?.["w:val"] ?? colorAttr?.val;
2075
+ const fontAttr = rPr?.["w:rFonts"]?.[0]?._attr ?? rPr?.rFonts?.[0]?._attr ?? {};
2076
+ const fontName = fontAttr?.["w:ascii"] ?? fontAttr?.ascii ?? fontAttr?.["w:hAnsi"] ?? fontAttr?.hAnsi ?? fontAttr?.["w:eastAsia"] ?? fontAttr?.eastAsia;
2077
+ const underVal = rPr?.["w:u"]?.[0]?._attr?.["w:val"] ?? rPr?.["w:u"]?.[0]?._attr?.val;
2078
+ const shdAttr = rPr?.["w:shd"]?.[0]?._attr ?? rPr?.shd?.[0]?._attr ?? {};
2079
+ const bgVal = safeHex(shdAttr?.["w:fill"] ?? shdAttr?.fill);
2080
+ const vertAlignVal = rPr?.["w:vertAlign"]?.[0]?._attr?.["w:val"] ?? rPr?.["w:vertAlign"]?.[0]?._attr?.val;
2081
+ const bNode = rPr?.["w:b"]?.[0] ?? rPr?.b?.[0];
2082
+ const isBold = bNode != null && (bNode?._attr?.["w:val"] ?? bNode?._attr?.val ?? "1") !== "0";
2083
+ const iNode = rPr?.["w:i"]?.[0] ?? rPr?.i?.[0];
2084
+ const isItalic = iNode != null && (iNode?._attr?.["w:val"] ?? iNode?._attr?.val ?? "1") !== "0";
2085
+ const sNode = rPr?.["w:strike"]?.[0] ?? rPr?.strike?.[0];
2086
+ const isStrike = sNode != null && (sNode?._attr?.["w:val"] ?? sNode?._attr?.val ?? "1") !== "0";
2087
+ const props = {
2088
+ b: isBold || void 0,
2089
+ i: isItalic || void 0,
2090
+ u: underVal && underVal !== "none" ? true : void 0,
2091
+ s: isStrike || void 0,
2092
+ sup: vertAlignVal === "superscript" || void 0,
2093
+ sub: vertAlignVal === "subscript" || void 0,
2094
+ pt: szVal ? Metric.halfPtToPt(Number(szVal)) : void 0,
2095
+ color: safeHex(colorVal),
2096
+ font: fontName ? safeFont(fontName) : void 0,
2097
+ bg: bgVal
2098
+ };
2099
+ const fldChar = run?.["w:fldChar"]?.[0]?._attr ?? run?.fldChar?.[0]?._attr;
2100
+ const instrText = run?.["w:instrText"]?.[0];
2101
+ const textNodes = toArr2(run?.["w:t"] ?? run?.t);
2102
+ const content = textNodes.map((t) => typeof t === "string" ? t : t?._ ?? t?._text ?? "").join("");
2103
+ if (instrText) {
2104
+ const instrStr = typeof instrText === "string" ? instrText : instrText?._text ?? "";
2105
+ if (instrStr.trim().toUpperCase() === "PAGE") {
2106
+ const pageNum = { tag: "pagenum", format: "decimal" };
2107
+ return { tag: "span", props, kids: [pageNum] };
2108
+ }
2109
+ }
2110
+ return buildSpan(content, props);
2111
+ }
2112
+ function decodeGrid2(tbl, ctx) {
2113
+ const tblPr = tbl?.["w:tblPr"]?.[0] ?? tbl?.tblPr?.[0] ?? {};
2114
+ const tblLookAttr = tblPr?.["w:tblLook"]?.[0]?._attr ?? tblPr?.tblLook?.[0]?._attr ?? {};
2115
+ const look = {
2116
+ firstRow: tblLookAttr?.["w:firstRow"] === "1" || void 0,
2117
+ lastRow: tblLookAttr?.["w:lastRow"] === "1" || void 0,
2118
+ firstCol: tblLookAttr?.["w:firstColumn"] === "1" || tblLookAttr?.["w:firstCol"] === "1" || void 0,
2119
+ lastCol: tblLookAttr?.["w:lastColumn"] === "1" || tblLookAttr?.["w:lastCol"] === "1" || void 0,
2120
+ bandedRows: tblLookAttr?.["w:noHBand"] === "0" || void 0,
2121
+ bandedCols: tblLookAttr?.["w:noVBand"] === "0" || void 0
2122
+ };
2123
+ const tblBorders = tblPr?.["w:tblBorders"]?.[0] ?? tblPr?.tblBorders?.[0];
2124
+ let defaultStroke = void 0;
2125
+ if (tblBorders) {
2126
+ const top = tblBorders?.["w:top"]?.[0]?._attr ?? tblBorders?.top?.[0]?._attr;
2127
+ if (top) {
2128
+ defaultStroke = safeStrokeDocx(
2129
+ top?.["w:val"] ?? top?.val,
2130
+ Number(top?.["w:sz"] ?? top?.sz ?? 4),
2131
+ top?.["w:color"] ?? top?.color
2132
+ );
2133
+ }
2134
+ }
2135
+ const gridProps = { look, defaultStroke };
2136
+ const rowArr = toArr2(tbl?.["w:tr"] ?? tbl?.tr);
2137
+ const rawGrid = rowArr.map((row) => {
2138
+ const cellArr = toArr2(row?.["w:tc"] ?? row?.tc);
2139
+ return cellArr.map((cell) => {
2140
+ const tcPr = cell?.["w:tcPr"]?.[0] ?? {};
2141
+ const gridSpan = Number(tcPr?.["w:gridSpan"]?.[0]?._attr?.["w:val"] ?? 1);
2142
+ const vMergeNode = tcPr?.["w:vMerge"]?.[0];
2143
+ const vMergeVal = vMergeNode?._attr?.["w:val"] ?? vMergeNode?._attr?.val;
2144
+ const vMergeRestart = vMergeVal === "restart";
2145
+ const vMergeContinue = vMergeNode != null && !vMergeRestart;
2146
+ return { cell, gridSpan, vMergeRestart, vMergeContinue };
2147
+ });
2148
+ });
2149
+ const rsMap = /* @__PURE__ */ new Map();
2150
+ for (let ri = 0; ri < rawGrid.length; ri++) {
2151
+ let gridCol = 0;
2152
+ for (let ci = 0; ci < rawGrid[ri].length; ci++) {
2153
+ const rc = rawGrid[ri][ci];
2154
+ if (rc.vMergeRestart) {
2155
+ let span = 1;
2156
+ for (let nr = ri + 1; nr < rawGrid.length; nr++) {
2157
+ let col = 0;
2158
+ let found = false;
2159
+ for (const nc of rawGrid[nr]) {
2160
+ if (col === gridCol && nc.vMergeContinue) {
2161
+ span++;
2162
+ found = true;
2163
+ break;
2164
+ }
2165
+ col += nc.gridSpan;
2166
+ }
2167
+ if (!found) break;
2168
+ }
2169
+ rsMap.set(`${ri},${ci}`, span);
2170
+ }
2171
+ gridCol += rc.gridSpan;
2172
+ }
2173
+ }
2174
+ const rowNodes = rawGrid.map((rawRow, ri) => {
2175
+ const row = rowArr[ri];
2176
+ const trPr = row?.["w:trPr"]?.[0] ?? row?.trPr?.[0] ?? {};
2177
+ const isHeaderRow = trPr?.["w:tblHeader"]?.[0] != null || trPr?.tblHeader?.[0] != null;
2178
+ if (ri === 0 && isHeaderRow) gridProps.headerRow = true;
2179
+ const cellNodes = [];
2180
+ for (let ci = 0; ci < rawRow.length; ci++) {
2181
+ const rc = rawRow[ci];
2182
+ if (rc.vMergeContinue) continue;
2183
+ const cell = rc.cell;
2184
+ const tcPr = cell?.["w:tcPr"]?.[0] ?? {};
2185
+ const bgAttr = tcPr?.["w:shd"]?.[0]?._attr ?? {};
2186
+ const bg = safeHex(bgAttr?.["w:fill"] ?? bgAttr?.fill);
2187
+ const tcBorders = tcPr?.["w:tcBorders"]?.[0] ?? tcPr?.tcBorders?.[0];
2188
+ const cp = { bg, isHeader: isHeaderRow || void 0 };
2189
+ if (tcBorders) {
2190
+ const dirs = [
2191
+ ["top", "top"],
2192
+ ["bottom", "bot"],
2193
+ ["left", "left"],
2194
+ ["right", "right"]
2195
+ ];
2196
+ for (const [xmlTag, propKey] of dirs) {
2197
+ const bdr = tcBorders?.["w:" + xmlTag]?.[0]?._attr ?? tcBorders?.[xmlTag]?.[0]?._attr;
2198
+ if (bdr) {
2199
+ cp[propKey] = safeStrokeDocx(
2200
+ bdr?.["w:val"] ?? bdr?.val,
2201
+ Number(bdr?.["w:sz"] ?? bdr?.sz ?? 4),
2202
+ bdr?.["w:color"] ?? bdr?.color
2203
+ );
2204
+ }
2205
+ }
2206
+ }
2207
+ const vaAttr = tcPr?.["w:vAlign"]?.[0]?._attr ?? tcPr?.vAlign?.[0]?._attr ?? {};
2208
+ const vaVal = vaAttr?.["w:val"] ?? vaAttr?.val;
2209
+ if (vaVal) {
2210
+ const vaMap = { top: "top", center: "mid", bottom: "bot" };
2211
+ cp.va = vaMap[vaVal];
2212
+ }
2213
+ const rs = rsMap.get(`${ri},${ci}`) ?? 1;
2214
+ const paras = toArr2(cell?.["w:p"] ?? cell?.p).map((p) => decodePara2(p, ctx));
2215
+ cellNodes.push(buildCell(
2216
+ paras.length > 0 ? paras : [buildPara([buildSpan("")])],
2217
+ { cs: rc.gridSpan, rs, props: cp }
2218
+ ));
2219
+ }
2220
+ return buildRow(cellNodes);
2221
+ });
2222
+ return buildGrid(rowNodes, gridProps);
2223
+ }
2224
+ function decodeGridSimple2(tbl) {
2225
+ const rowArr = toArr2(tbl?.["w:tr"] ?? tbl?.tr);
2226
+ const rowNodes = rowArr.map((row) => {
2227
+ const cellArr = toArr2(row?.["w:tc"] ?? row?.tc);
2228
+ return buildRow(cellArr.map((c) => buildCell([buildPara([buildSpan(cellText2(c))])])));
2229
+ });
2230
+ return buildGrid(rowNodes);
2231
+ }
2232
+ function decodeGridFlat2(tbl) {
2233
+ return buildGrid([buildRow([buildCell([buildPara([buildSpan(tableText2(tbl))])])])]);
2234
+ }
2235
+ function decodeGridText2(tbl) {
2236
+ return buildPara([buildSpan(tableText2(tbl))]);
2237
+ }
2238
+ function cellText2(cell) {
2239
+ return toArr2(cell?.["w:p"] ?? cell?.p).map(
2240
+ (p) => toArr2(p?.["w:r"] ?? p?.r).map(
2241
+ (r) => toArr2(r?.["w:t"] ?? r?.t).map((t) => typeof t === "string" ? t : t?._ ?? "").join("")
2242
+ ).join("")
2243
+ ).join(" ");
2244
+ }
2245
+ function tableText2(tbl) {
2246
+ return toArr2(tbl?.["w:tr"] ?? tbl?.tr).map(
2247
+ (row) => toArr2(row?.["w:tc"] ?? row?.tc).map((c) => cellText2(c)).join(" ")
2248
+ ).join("\n");
2249
+ }
2250
+ function parseHeading(style) {
2251
+ if (!style) return void 0;
2252
+ const m = style.match(/[Hh]eading(\d)/);
2253
+ if (m) {
2254
+ const n = Number(m[1]);
2255
+ if (n >= 1 && n <= 6) return n;
2256
+ }
2257
+ return void 0;
2258
+ }
2259
+ registry.registerDecoder(new DocxDecoder());
2260
+
2261
+ // src/decoders/md/MdDecoder.ts
2262
+ var MdDecoder = class {
2263
+ constructor() {
2264
+ this.format = "md";
2265
+ }
2266
+ async decode(data) {
2267
+ const shield = new ShieldedParser();
2268
+ const warns = [];
2269
+ try {
2270
+ const text = TextKit.decode(data);
2271
+ const lines = text.split(/\r?\n/);
2272
+ const kids = [];
2273
+ let i = 0;
2274
+ while (i < lines.length) {
2275
+ const line = lines[i];
2276
+ const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
2277
+ if (headingMatch) {
2278
+ const level = headingMatch[1].length;
2279
+ kids.push(buildPara([buildSpan(headingMatch[2], { b: level <= 2 })], { heading: level }));
2280
+ i++;
2281
+ continue;
2282
+ }
2283
+ if (line.includes("|") && i + 1 < lines.length && lines[i + 1].match(/^\s*\|?\s*[-:]+\s*\|/)) {
2284
+ const tableResult = shield.guard(() => parseMdTable(lines, i), null, `md:table@${i}`);
2285
+ if (tableResult) {
2286
+ kids.push(tableResult.node);
2287
+ i = tableResult.nextLine;
2288
+ continue;
2289
+ }
2290
+ }
2291
+ if (line.match(/^[-*_]{3,}$/)) {
2292
+ kids.push(buildPara([buildSpan("")], {}));
2293
+ i++;
2294
+ continue;
2295
+ }
2296
+ const listMatch = line.match(/^(\s*)([-*+]|\d+\.)\s+(.+)$/);
2297
+ if (listMatch) {
2298
+ kids.push(buildPara(parseInline(listMatch[3]), {
2299
+ listLv: Math.floor(listMatch[1].length / 2),
2300
+ listOrd: /\d+\./.test(listMatch[2])
2301
+ }));
2302
+ i++;
2303
+ continue;
2304
+ }
2305
+ const bqMatch = line.match(/^>\s*(.*)$/);
2306
+ if (bqMatch) {
2307
+ kids.push(buildPara([buildSpan(bqMatch[1])], { indentPt: 28 }));
2308
+ i++;
2309
+ continue;
2310
+ }
2311
+ if (line.startsWith("```")) {
2312
+ const codeLines = [];
2313
+ i++;
2314
+ while (i < lines.length && !lines[i].startsWith("```")) {
2315
+ codeLines.push(lines[i]);
2316
+ i++;
2317
+ }
2318
+ i++;
2319
+ kids.push(buildPara([buildSpan(codeLines.join("\n"), { font: "Courier New" })], {}));
2320
+ continue;
2321
+ }
2322
+ if (line.trim() === "") {
2323
+ i++;
2324
+ continue;
2325
+ }
2326
+ const alignMatch = line.match(/^<div\s+align="(center|right|left)">(.*?)<\/div>$/i);
2327
+ if (alignMatch) {
2328
+ const align = alignMatch[1].toLowerCase();
2329
+ kids.push(buildPara(parseInline(alignMatch[2]), { align }));
2330
+ i++;
2331
+ continue;
2332
+ }
2333
+ kids.push(buildPara(parseInline(line), {}));
2334
+ i++;
2335
+ }
2336
+ warns.push(...shield.flush());
2337
+ const sheet = buildSheet(kids.length > 0 ? kids : [buildPara([buildSpan("")])], A4);
2338
+ return succeed(buildRoot({}, [sheet]), warns);
2339
+ } catch (e) {
2340
+ warns.push(...shield.flush());
2341
+ return fail(`MD decode error: ${e?.message ?? String(e)}`, warns);
2342
+ }
2343
+ }
2344
+ };
2345
+ function parseInline(text) {
2346
+ const result = [];
2347
+ let rem = text;
2348
+ while (rem.length > 0) {
2349
+ let m = rem.match(/^(.*?)!\[([^\]]*)\]\((data:([^;]+);base64,([^)]+))\)(.*)/s);
2350
+ if (m) {
2351
+ if (m[1]) result.push(buildSpan(m[1]));
2352
+ const mime = m[4];
2353
+ const validMimes = ["image/png", "image/jpeg", "image/gif", "image/bmp"];
2354
+ result.push(buildImg(m[5], validMimes.includes(mime) ? mime : "image/png", 100, 100, m[2] || void 0));
2355
+ rem = m[6];
2356
+ continue;
2357
+ }
2358
+ m = rem.match(/^(.*?)!\[([^\]]*)\]\(([^)]+)\)(.*)/s);
2359
+ if (m) {
2360
+ if (m[1]) result.push(buildSpan(m[1]));
2361
+ result.push(buildSpan(`[\uC774\uBBF8\uC9C0: ${m[2] || m[3]}]`));
2362
+ rem = m[4];
2363
+ continue;
2364
+ }
2365
+ m = rem.match(/^(.*?)\*\*\*(.+?)\*\*\*(.*)/s);
2366
+ if (m) {
2367
+ if (m[1]) result.push(buildSpan(m[1]));
2368
+ result.push(buildSpan(m[2], { b: true, i: true }));
2369
+ rem = m[3];
2370
+ continue;
2371
+ }
2372
+ m = rem.match(/^(.*?)\*\*(.+?)\*\*(.*)/s);
2373
+ if (m) {
2374
+ if (m[1]) result.push(buildSpan(m[1]));
2375
+ result.push(buildSpan(m[2], { b: true }));
2376
+ rem = m[3];
2377
+ continue;
2378
+ }
2379
+ m = rem.match(/^(.*?)\*(.+?)\*(.*)/s);
2380
+ if (m) {
2381
+ if (m[1]) result.push(buildSpan(m[1]));
2382
+ result.push(buildSpan(m[2], { i: true }));
2383
+ rem = m[3];
2384
+ continue;
2385
+ }
2386
+ m = rem.match(/^(.*?)~~(.+?)~~(.*)/s);
2387
+ if (m) {
2388
+ if (m[1]) result.push(buildSpan(m[1]));
2389
+ result.push(buildSpan(m[2], { s: true }));
2390
+ rem = m[3];
2391
+ continue;
2392
+ }
2393
+ m = rem.match(/^(.*?)<u>(.+?)<\/u>(.*)/si);
2394
+ if (m) {
2395
+ if (m[1]) result.push(buildSpan(m[1]));
2396
+ result.push(buildSpan(m[2], { u: true }));
2397
+ rem = m[3];
2398
+ continue;
2399
+ }
2400
+ m = rem.match(/^(.*?)<sup>(.+?)<\/sup>(.*)/si);
2401
+ if (m) {
2402
+ if (m[1]) result.push(buildSpan(m[1]));
2403
+ result.push(buildSpan(m[2], { sup: true }));
2404
+ rem = m[3];
2405
+ continue;
2406
+ }
2407
+ m = rem.match(/^(.*?)<sub>(.+?)<\/sub>(.*)/si);
2408
+ if (m) {
2409
+ if (m[1]) result.push(buildSpan(m[1]));
2410
+ result.push(buildSpan(m[2], { sub: true }));
2411
+ rem = m[3];
2412
+ continue;
2413
+ }
2414
+ m = rem.match(/^(.*?)`(.+?)`(.*)/s);
2415
+ if (m) {
2416
+ if (m[1]) result.push(buildSpan(m[1]));
2417
+ result.push(buildSpan(m[2], { font: "Courier New" }));
2418
+ rem = m[3];
2419
+ continue;
2420
+ }
2421
+ result.push(buildSpan(rem));
2422
+ break;
2423
+ }
2424
+ return result.length > 0 ? result : [buildSpan(text)];
2425
+ }
2426
+ function parseMdTable(lines, startLine) {
2427
+ const parse = (line) => line.split("|").map((c) => c.trim()).filter((c, i, arr) => i > 0 || c !== "");
2428
+ const headers = parse(lines[startLine]);
2429
+ let cur = startLine + 2;
2430
+ const rows = [];
2431
+ while (cur < lines.length) {
2432
+ if (!lines[cur].includes("|")) break;
2433
+ const cells = parse(lines[cur]);
2434
+ if (cells.length === 0) break;
2435
+ rows.push(cells);
2436
+ cur++;
2437
+ }
2438
+ const allRows = [headers, ...rows];
2439
+ const gridRows = allRows.map(
2440
+ (row, ri) => buildRow(row.map((cell) => buildCell([buildPara([buildSpan(cell, ri === 0 ? { b: true } : {})])])))
2441
+ );
2442
+ return { node: buildGrid(gridRows), nextLine: cur };
2443
+ }
2444
+ registry.registerDecoder(new MdDecoder());
2445
+
2446
+ // src/encoders/hwpx/HwpxEncoder.ts
2447
+ var NS = [
2448
+ 'xmlns:ha="http://www.hancom.co.kr/hwpml/2011/app"',
2449
+ 'xmlns:hp="http://www.hancom.co.kr/hwpml/2011/paragraph"',
2450
+ 'xmlns:hp10="http://www.hancom.co.kr/hwpml/2016/paragraph"',
2451
+ 'xmlns:hs="http://www.hancom.co.kr/hwpml/2011/section"',
2452
+ 'xmlns:hc="http://www.hancom.co.kr/hwpml/2011/core"',
2453
+ 'xmlns:hh="http://www.hancom.co.kr/hwpml/2011/head"',
2454
+ 'xmlns:hhs="http://www.hancom.co.kr/hwpml/2011/history"',
2455
+ 'xmlns:hm="http://www.hancom.co.kr/hwpml/2011/master-page"',
2456
+ 'xmlns:hpf="http://www.hancom.co.kr/schema/2011/hpf"',
2457
+ 'xmlns:dc="http://purl.org/dc/elements/1.1/"',
2458
+ 'xmlns:opf="http://www.idpf.org/2007/opf/"',
2459
+ 'xmlns:ooxmlchart="http://www.hancom.co.kr/hwpml/2016/ooxmlchart"',
2460
+ 'xmlns:epub="http://www.idpf.org/2007/ops"',
2461
+ 'xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0"'
2462
+ ].join(" ");
2463
+ function charPrKey(p) {
2464
+ return `${p.b ? 1 : 0}|${p.i ? 1 : 0}|${p.u ? 1 : 0}|${p.s ? 1 : 0}|${p.pt ?? 10}|${p.color ?? "000000"}|${p.font ?? ""}|${p.bg ?? ""}`;
2465
+ }
2466
+ function paraPrKey(p) {
2467
+ return `${p.align ?? "left"}|${p.listOrd ?? ""}|${p.listLv ?? 0}`;
2468
+ }
2469
+ function registerFont(name, ctx) {
2470
+ const n = name || "\uAD74\uB9BC\uCCB4";
2471
+ const existing = ctx.fontMap.get(n);
2472
+ if (existing !== void 0) return existing;
2473
+ const id = ctx.fonts.length;
2474
+ ctx.fonts.push(n);
2475
+ ctx.fontMap.set(n, id);
2476
+ return id;
2477
+ }
2478
+ function registerCharPr(props, ctx) {
2479
+ const key = charPrKey(props);
2480
+ const existing = ctx.charPrMap.get(key);
2481
+ if (existing !== void 0) return existing;
2482
+ const fontName = safeFontToKr(props.font) || "\uAD74\uB9BC\uCCB4";
2483
+ const fontId = registerFont(fontName, ctx);
2484
+ const id = ctx.charPrs.length;
2485
+ const def = {
2486
+ id,
2487
+ height: Metric.ptToHHeight(props.pt ?? 10),
2488
+ bold: !!props.b,
2489
+ italic: !!props.i,
2490
+ underline: props.u ? "BOTTOM" : "NONE",
2491
+ strikeout: props.s ? "SOLID" : "NONE",
2492
+ textColor: props.color ? `#${props.color}` : "#000000",
2493
+ fontName,
2494
+ fontId,
2495
+ bg: props.bg
2496
+ };
2497
+ ctx.charPrs.push(def);
2498
+ ctx.charPrMap.set(key, id);
2499
+ return id;
2500
+ }
2501
+ function registerParaPr(props, ctx) {
2502
+ const key = paraPrKey(props);
2503
+ const existing = ctx.paraPrMap.get(key);
2504
+ if (existing !== void 0) return existing;
2505
+ const id = ctx.paraPrs.length;
2506
+ const def = {
2507
+ id,
2508
+ align: (props.align ?? "left").toUpperCase()
2509
+ };
2510
+ if (props.listOrd !== void 0) {
2511
+ def.listType = props.listOrd ? "DIGIT" : "BULLET";
2512
+ def.listLevel = props.listLv ?? 0;
2513
+ }
2514
+ ctx.paraPrs.push(def);
2515
+ ctx.paraPrMap.set(key, id);
2516
+ return id;
2517
+ }
2518
+ function scanContent(kids, ctx) {
2519
+ for (const kid of kids) {
2520
+ if (kid.tag === "para") scanPara(kid, ctx);
2521
+ else if (kid.tag === "grid") scanGrid(kid, ctx);
2522
+ }
2523
+ }
2524
+ function scanPara(para, ctx) {
2525
+ registerParaPr(para.props, ctx);
2526
+ for (const kid of para.kids) {
2527
+ if (kid.tag === "span") registerCharPr(kid.props, ctx);
2528
+ else if (kid.tag === "img") registerImage(kid, ctx);
2529
+ }
2530
+ }
2531
+ function scanGrid(grid, ctx) {
2532
+ for (const row of grid.kids)
2533
+ for (const cell of row.kids)
2534
+ for (const p of cell.kids) scanPara(p, ctx);
2535
+ }
2536
+ function scanParas(paras, ctx) {
2537
+ for (const p of paras) scanPara(p, ctx);
2538
+ }
2539
+ function mimeToExt(mime) {
2540
+ if (mime.includes("jpeg")) return "jpg";
2541
+ if (mime.includes("gif")) return "gif";
2542
+ if (mime.includes("bmp")) return "bmp";
2543
+ return "png";
2544
+ }
2545
+ function registerImage(img, ctx) {
2546
+ if (img._binId) return;
2547
+ const ext = mimeToExt(img.mime);
2548
+ const id = `BIN${String(ctx.nextBinNum).padStart(4, "0")}`;
2549
+ const name = `${id}.${ext}`;
2550
+ ctx.nextBinNum++;
2551
+ const data = TextKit.base64Decode(img.b64);
2552
+ ctx.bins.push({ id, name, data });
2553
+ img._binId = id;
2554
+ }
2555
+ function addBorderFill(ctx, stroke, bgColor) {
2556
+ const id = ctx.borderFills.length + 1;
2557
+ const s = stroke ?? DEFAULT_STROKE;
2558
+ const kindMap = { solid: "SOLID", dash: "DASH", dot: "DOT", double: "DOUBLE", none: "NONE" };
2559
+ const type = kindMap[s.kind] ?? "SOLID";
2560
+ const w = `${(s.pt * 0.3528).toFixed(2)} mm`;
2561
+ const c = s.color.startsWith("#") ? s.color : `#${s.color}`;
2562
+ let fill = "";
2563
+ if (bgColor) {
2564
+ const bc = bgColor.startsWith("#") ? bgColor : `#${bgColor}`;
2565
+ fill = `<hc:fillBrush><hc:winBrush faceColor="${bc}" hatchColor="none" alpha="0"/></hc:fillBrush>`;
2566
+ }
2567
+ const xml = `<hh:borderFill id="${id}" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0"><hh:slash type="NONE" Crooked="0" isCounter="0"/><hh:backSlash type="NONE" Crooked="0" isCounter="0"/><hh:leftBorder type="${type}" width="${w}" color="${c}"/><hh:rightBorder type="${type}" width="${w}" color="${c}"/><hh:topBorder type="${type}" width="${w}" color="${c}"/><hh:bottomBorder type="${type}" width="${w}" color="${c}"/><hh:diagonal type="SOLID" width="0.1 mm" color="#000000"/>${fill}</hh:borderFill>`;
2568
+ ctx.borderFills.push({ id, xml });
2569
+ return id;
2570
+ }
2571
+ var HwpxEncoder = class {
2572
+ constructor() {
2573
+ this.format = "hwpx";
2574
+ }
2575
+ async encode(doc) {
2576
+ try {
2577
+ const sheet = doc.kids[0];
2578
+ const dims = sheet?.dims ?? A4;
2579
+ const availableWidth = Metric.ptToHwp(dims.wPt) - Metric.ptToHwp(dims.ml) - Metric.ptToHwp(dims.mr);
2580
+ const ctx = {
2581
+ charPrs: [],
2582
+ charPrMap: /* @__PURE__ */ new Map(),
2583
+ paraPrs: [],
2584
+ paraPrMap: /* @__PURE__ */ new Map(),
2585
+ borderFills: [],
2586
+ bins: [],
2587
+ nextBinNum: 1,
2588
+ nextElementId: 1e4,
2589
+ availableWidth,
2590
+ fonts: [],
2591
+ fontMap: /* @__PURE__ */ new Map()
2592
+ };
2593
+ addBorderFill(ctx, { kind: "none", pt: 0.1, color: "000000" });
2594
+ addBorderFill(ctx, DEFAULT_STROKE);
2595
+ addBorderFill(ctx, { kind: "none", pt: 0.1, color: "000000" });
2596
+ registerCharPr({}, ctx);
2597
+ registerParaPr({}, ctx);
2598
+ scanContent(sheet?.kids ?? [], ctx);
2599
+ if (sheet?.header) scanParas(sheet.header, ctx);
2600
+ if (sheet?.footer) scanParas(sheet.footer, ctx);
2601
+ const previewText = extractPreviewText(sheet);
2602
+ const sectionData = TextKit.encode(sectionXml(sheet, dims, ctx));
2603
+ const headerData = TextKit.encode(headerXml(dims, doc.meta, ctx));
2604
+ const entries = [
2605
+ { name: "mimetype", data: TextKit.encode("application/hwp+zip") },
2606
+ { name: "version.xml", data: TextKit.encode(VERSION_XML) },
2607
+ { name: "Contents/header.xml", data: headerData },
2608
+ { name: "Contents/section0.xml", data: sectionData },
2609
+ { name: "Preview/PrvText.txt", data: TextKit.encode(previewText) },
2610
+ { name: "settings.xml", data: TextKit.encode(SETTINGS_XML) },
2611
+ { name: "META-INF/container.rdf", data: TextKit.encode(CONTAINER_RDF) },
2612
+ { name: "Contents/content.hpf", data: TextKit.encode(contentHpf(ctx, doc.meta)) },
2613
+ { name: "META-INF/container.xml", data: TextKit.encode(CONTAINER_XML) },
2614
+ { name: "META-INF/manifest.xml", data: TextKit.encode(MANIFEST_XML) }
2615
+ ];
2616
+ for (const bin of ctx.bins) {
2617
+ entries.push({ name: `BinData/${bin.name}`, data: bin.data });
2618
+ }
2619
+ return succeed(await ArchiveKit.zip(entries));
2620
+ } catch (e) {
2621
+ return fail(`HWPX encode error: ${e?.message ?? String(e)}`);
2622
+ }
2623
+ }
2624
+ };
2625
+ var VERSION_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><hv:HCFVersion xmlns:hv="http://www.hancom.co.kr/hwpml/2011/version" tagetApplication="WORDPROCESSOR" major="5" minor="1" micro="0" buildNumber="1" os="6" xmlVersion="1.2" application="Hancom Office Hangul" appVersion="11, 0, 0, 0"/>`;
2626
+ var CONTAINER_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><ocf:container xmlns:ocf="urn:oasis:names:tc:opendocument:xmlns:container" xmlns:hpf="http://www.hancom.co.kr/schema/2011/hpf"><ocf:rootfiles><ocf:rootfile full-path="Contents/content.hpf" media-type="application/hwpml-package+xml"/><ocf:rootfile full-path="Preview/PrvText.txt" media-type="text/plain"/><ocf:rootfile full-path="META-INF/container.rdf" media-type="application/rdf+xml"/></ocf:rootfiles></ocf:container>`;
2627
+ var CONTAINER_RDF = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about=""><ns0:hasPart xmlns:ns0="http://www.hancom.co.kr/hwpml/2016/meta/pkg#" rdf:resource="Contents/header.xml"/></rdf:Description><rdf:Description rdf:about="Contents/header.xml"><rdf:type rdf:resource="http://www.hancom.co.kr/hwpml/2016/meta/pkg#HeaderFile"/></rdf:Description><rdf:Description rdf:about=""><ns0:hasPart xmlns:ns0="http://www.hancom.co.kr/hwpml/2016/meta/pkg#" rdf:resource="Contents/section0.xml"/></rdf:Description><rdf:Description rdf:about="Contents/section0.xml"><rdf:type rdf:resource="http://www.hancom.co.kr/hwpml/2016/meta/pkg#SectionFile"/></rdf:Description><rdf:Description rdf:about=""><rdf:type rdf:resource="http://www.hancom.co.kr/hwpml/2016/meta/pkg#Document"/></rdf:Description></rdf:RDF>`;
2628
+ var MANIFEST_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><odf:manifest xmlns:odf="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"/>`;
2629
+ var SETTINGS_XML = `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><ha:HWPApplicationSetting xmlns:ha="http://www.hancom.co.kr/hwpml/2011/app" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0"><ha:CaretPosition listIDRef="0" paraIDRef="0" pos="0"/><config:config-item-set name="PrintInfo"><config:config-item name="PrintMethod" type="short">0</config:config-item><config:config-item name="ZoomX" type="short">100</config:config-item><config:config-item name="ZoomY" type="short">100</config:config-item></config:config-item-set></ha:HWPApplicationSetting>`;
2630
+ function contentHpf(ctx, meta) {
2631
+ const title = esc(meta?.title ?? "");
2632
+ const now = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
2633
+ let items = `<opf:item id="header" href="Contents/header.xml" media-type="application/xml"/><opf:item id="section0" href="Contents/section0.xml" media-type="application/xml"/><opf:item id="settings" href="settings.xml" media-type="application/xml"/>`;
2634
+ for (const bin of ctx.bins) {
2635
+ const ext = bin.name.split(".").pop()?.toLowerCase() ?? "png";
2636
+ const ct = ext === "png" ? "image/png" : ext === "jpg" || ext === "jpeg" ? "image/jpeg" : ext === "gif" ? "image/gif" : "image/bmp";
2637
+ items += `<opf:item id="${bin.id}" href="BinData/${bin.name}" media-type="${ct}" isEmbeded="1"/>`;
2638
+ }
2639
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><opf:package ${NS} version="" unique-identifier="" id=""><opf:metadata><opf:title>${title}</opf:title><opf:language>ko</opf:language><opf:meta name="creator" content="text"/><opf:meta name="subject" content="text"/><opf:meta name="description" content="text"/><opf:meta name="CreatedDate" content="text">${now}</opf:meta><opf:meta name="ModifiedDate" content="text">${now}</opf:meta><opf:meta name="keyword" content="text"/></opf:metadata><opf:manifest>${items}</opf:manifest><opf:spine><opf:itemref idref="header" linear="no"/><opf:itemref idref="section0" linear="yes"/></opf:spine></opf:package>`;
2640
+ }
2641
+ function headerXml(dims, meta, ctx) {
2642
+ const fontCount = ctx.fonts.length || 1;
2643
+ const langs = ["HANGUL", "LATIN", "HANJA", "JAPANESE", "OTHER", "SYMBOL", "USER"];
2644
+ let fontFaces = `<hh:fontfaces itemCnt="${langs.length}">`;
2645
+ for (const lang of langs) {
2646
+ fontFaces += `<hh:fontface lang="${lang}" fontCnt="${fontCount}">`;
2647
+ for (let fi = 0; fi < ctx.fonts.length; fi++) {
2648
+ fontFaces += `<hh:font id="${fi}" face="${esc(ctx.fonts[fi])}" type="TTF" isEmbedded="0"><hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/></hh:font>`;
2649
+ }
2650
+ if (ctx.fonts.length === 0) {
2651
+ fontFaces += `<hh:font id="0" face="\uAD74\uB9BC\uCCB4" type="TTF" isEmbedded="0"><hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/></hh:font>`;
2652
+ }
2653
+ fontFaces += `</hh:fontface>`;
2654
+ }
2655
+ fontFaces += `</hh:fontfaces>`;
2656
+ let charPrXml = "";
2657
+ for (const cp of ctx.charPrs) {
2658
+ const bold = cp.bold ? "<hh:bold/>" : "";
2659
+ const italic = cp.italic ? "<hh:italic/>" : "";
2660
+ const fid = cp.fontId ?? 0;
2661
+ charPrXml += `<hh:charPr id="${cp.id}" height="${cp.height}" textColor="${cp.textColor}" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="3"><hh:fontRef hangul="${fid}" latin="${fid}" hanja="${fid}" japanese="${fid}" other="${fid}" symbol="${fid}" user="${fid}"/><hh:ratio hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/><hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/><hh:relSz hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/><hh:offset hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>${bold}${italic}<hh:underline type="${cp.underline}" shape="SOLID" color="#000000"/><hh:strikeout shape="${cp.strikeout}" color="#000000"/><hh:outline type="NONE"/><hh:shadow type="NONE" color="#C0C0C0" offsetX="10" offsetY="10"/></hh:charPr>`;
2662
+ }
2663
+ let paraPrXml = "";
2664
+ for (const pp of ctx.paraPrs) {
2665
+ paraPrXml += `<hh:paraPr id="${pp.id}" tabPrIDRef="0" condense="0" fontLineHeight="0" snapToGrid="0" suppressLineNumbers="0" checked="0"><hh:align horizontal="${pp.align}" vertical="BASELINE"/><hh:heading type="NONE" idRef="0" level="0"/><hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="BREAK_WORD" widowOrphan="0" keepWithNext="0" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/><hh:autoSpacing eAsianEng="0" eAsianNum="0"/><hh:margin><hc:intent value="0" unit="HWPUNIT"/><hc:left value="0" unit="HWPUNIT"/><hc:right value="0" unit="HWPUNIT"/><hc:prev value="0" unit="HWPUNIT"/><hc:next value="0" unit="HWPUNIT"/></hh:margin><hh:lineSpacing type="PERCENT" value="160" unit="HWPUNIT"/><hh:border borderFillIDRef="1" offsetLeft="0" offsetRight="0" offsetTop="0" offsetBottom="0" connect="0" ignoreMargin="0"/></hh:paraPr>`;
2666
+ }
2667
+ const borderFillXml = ctx.borderFills.map((bf) => bf.xml).join("");
2668
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><hh:head ${NS} version="1.2" secCnt="1"><hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/><hh:refList>${fontFaces}<hh:borderFills itemCnt="${ctx.borderFills.length}">${borderFillXml}</hh:borderFills><hh:charProperties itemCnt="${ctx.charPrs.length}">${charPrXml}</hh:charProperties><hh:paraProperties itemCnt="${ctx.paraPrs.length}">${paraPrXml}</hh:paraProperties><hh:tabProperties itemCnt="1"><hh:tabPr id="0" autoTabLeft="0" autoTabRight="0"/></hh:tabProperties><hh:styles itemCnt="1"><hh:style id="0" type="PARA" name="\uBC14\uD0D5\uAE00" engName="Normal" paraPrIDRef="0" charPrIDRef="0" nextStyleIDRef="0" langID="1042" lockForm="0"/></hh:styles></hh:refList><hh:compatibleDocument targetProgram="HWP201X"><hh:layoutCompatibility/></hh:compatibleDocument><hh:docOption><hh:linkinfo path="" pageInherit="1" footnoteInherit="0"/></hh:docOption><hh:trackchageConfig flags="56"/></hh:head>`;
2669
+ }
2670
+ function sectionXml(sheet, dims, ctx) {
2671
+ const kids = sheet?.kids ?? [];
2672
+ const secPr = `<hp:secPr id="" textDirection="HORIZONTAL" spaceColumns="1134" tabStop="8000" outlineShapeIDRef="0" memoShapeIDRef="0" textVerticalWidthHead="0" masterPageCnt="0"><hp:grid lineGrid="0" charGrid="0" wonggojiFormat="0"/><hp:startNum pageStartsOn="BOTH" page="0" pic="0" tbl="0" equation="0"/><hp:visibility hideFirstHeader="0" hideFirstFooter="0" hideFirstMasterPage="0" border="SHOW_ALL" fill="SHOW_ALL" hideFirstPageNum="0" hideFirstEmptyLine="0" showLineNumber="0"/><hp:lineNumberShape restartType="0" countBy="0" distance="0" startNumber="0"/><hp:pagePr landscape="${dims.orient === "landscape" ? "NARROWLY" : "WIDELY"}" width="${Metric.ptToHwp(dims.wPt)}" height="${Metric.ptToHwp(dims.hPt)}" gutterType="LEFT_ONLY"><hp:margin header="2834" footer="2834" gutter="0" left="${Metric.ptToHwp(dims.ml)}" right="${Metric.ptToHwp(dims.mr)}" top="${Metric.ptToHwp(dims.mt)}" bottom="${Metric.ptToHwp(dims.mb)}"/></hp:pagePr><hp:footNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar=")" supscript="0"/><hp:noteLine length="-1" type="SOLID" width="0.12 mm" color="#000000"/><hp:noteSpacing betweenNotes="284" belowLine="568" aboveLine="852"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="EACH_COLUMN" beneathText="0"/></hp:footNotePr><hp:endNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar=")" supscript="0"/><hp:noteLine length="0" type="NONE" width="0.12 mm" color="#000000"/><hp:noteSpacing betweenNotes="0" belowLine="576" aboveLine="864"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="END_OF_DOCUMENT" beneathText="0"/></hp:endNotePr><hp:pageBorderFill type="BOTH" borderFillIDRef="1" textBorder="PAPER" headerInside="0" footerInside="0" fillArea="PAPER"><hp:offset left="1417" right="1417" top="1417" bottom="1417"/></hp:pageBorderFill><hp:pageBorderFill type="EVEN" borderFillIDRef="1" textBorder="PAPER" headerInside="0" footerInside="0" fillArea="PAPER"><hp:offset left="1417" right="1417" top="1417" bottom="1417"/></hp:pageBorderFill><hp:pageBorderFill type="ODD" borderFillIDRef="1" textBorder="PAPER" headerInside="0" footerInside="0" fillArea="PAPER"><hp:offset left="1417" right="1417" top="1417" bottom="1417"/></hp:pageBorderFill></hp:secPr><hp:ctrl><hp:colPr id="" type="NEWSPAPER" layout="LEFT" colCount="1" sameSz="1" sameGap="0"/></hp:ctrl>`;
2673
+ let contentXml = "";
2674
+ let isFirst = true;
2675
+ const defaultLineseg = `<hp:linesegarray><hp:lineseg textpos="0" vertpos="0" vertsize="1000" textheight="1000" baseline="850" spacing="600" horzpos="0" horzsize="${ctx.availableWidth}" flags="393216"/></hp:linesegarray>`;
2676
+ for (const kid of kids) {
2677
+ if (kid.tag === "para") {
2678
+ contentXml += encodePara(kid, ctx, isFirst ? secPr : "");
2679
+ isFirst = false;
2680
+ } else if (kid.tag === "grid") {
2681
+ const gridXml = encodeGrid(kid, ctx);
2682
+ const prefix = isFirst ? secPr : "";
2683
+ contentXml += `<hp:p id="${ctx.nextElementId++}" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0"><hp:run charPrIDRef="0">${prefix}${gridXml}</hp:run>${defaultLineseg}</hp:p>`;
2684
+ isFirst = false;
2685
+ }
2686
+ }
2687
+ if (contentXml === "") {
2688
+ contentXml = `<hp:p id="${ctx.nextElementId++}" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0"><hp:run charPrIDRef="0">${secPr}<hp:t></hp:t></hp:run>${defaultLineseg}</hp:p>`;
2689
+ }
2690
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><hs:sec ${NS}>${contentXml}</hs:sec>`;
2691
+ }
2692
+ function encodePara(para, ctx, secPr = "") {
2693
+ const paraPrId = registerParaPr(para.props, ctx);
2694
+ let runs = "";
2695
+ for (const kid of para.kids) {
2696
+ if (kid.tag === "span") {
2697
+ runs += encodeRun(kid, ctx);
2698
+ } else if (kid.tag === "img") {
2699
+ runs += encodeImage(kid, ctx);
2700
+ }
2701
+ }
2702
+ if (runs === "") {
2703
+ runs = `<hp:run charPrIDRef="0"><hp:t></hp:t></hp:run>`;
2704
+ }
2705
+ if (secPr) {
2706
+ const firstRunEnd = runs.indexOf(">");
2707
+ if (firstRunEnd > -1) {
2708
+ runs = runs.substring(0, firstRunEnd + 1) + secPr + runs.substring(firstRunEnd + 1);
2709
+ }
2710
+ }
2711
+ const fontSize = getFontSizeForPara(para, ctx);
2712
+ const vertsize = fontSize;
2713
+ const textheight = fontSize;
2714
+ const baseline = Math.round(fontSize * 0.85);
2715
+ const spacing = Math.round(fontSize * 0.6);
2716
+ const linesegarray = `<hp:linesegarray><hp:lineseg textpos="0" vertpos="0" vertsize="${vertsize}" textheight="${textheight}" baseline="${baseline}" spacing="${spacing}" horzpos="0" horzsize="${ctx.availableWidth}" flags="393216"/></hp:linesegarray>`;
2717
+ return `<hp:p id="${ctx.nextElementId++}" paraPrIDRef="${paraPrId}" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0">${runs}${linesegarray}</hp:p>`;
2718
+ }
2719
+ function getFontSizeForPara(para, ctx) {
2720
+ for (const kid of para.kids) {
2721
+ if (kid.tag === "span") {
2722
+ const charPrId = ctx.charPrMap.get(charPrKey(kid.props));
2723
+ if (charPrId !== void 0 && ctx.charPrs[charPrId]) {
2724
+ return ctx.charPrs[charPrId].height;
2725
+ }
2726
+ }
2727
+ }
2728
+ return 1e3;
2729
+ }
2730
+ function encodeRun(span, ctx) {
2731
+ const charPrId = registerCharPr(span.props, ctx);
2732
+ const parts = [];
2733
+ for (const kid of span.kids) {
2734
+ if (kid.tag === "txt") {
2735
+ if (kid.content) {
2736
+ parts.push(`<hp:t>${esc(kid.content)}</hp:t>`);
2737
+ } else {
2738
+ parts.push(`<hp:t></hp:t>`);
2739
+ }
2740
+ } else if (kid.tag === "pagenum") {
2741
+ const fmt = kid.format === "roman" ? "ROMAN_LOWER" : kid.format === "romanCaps" ? "ROMAN_UPPER" : "DIGIT";
2742
+ parts.push(`<hp:pageNum pageStartsOn="BOTH" formatType="${fmt}"/>`);
2743
+ } else if (kid.tag === "br") {
2744
+ parts.push(`<hp:t>
2745
+ </hp:t>`);
2746
+ }
2747
+ }
2748
+ return `<hp:run charPrIDRef="${charPrId}">${parts.join("")}</hp:run>`;
2749
+ }
2750
+ function encodeImage(img, ctx) {
2751
+ const binId = img._binId;
2752
+ if (!binId) return "";
2753
+ const charPrId = registerCharPr({}, ctx);
2754
+ const w = Metric.ptToHwp(img.w);
2755
+ const h = Metric.ptToHwp(img.h);
2756
+ return `<hp:run charPrIDRef="${charPrId}"><hp:pic id="${ctx.nextElementId++}" zOrder="0" numberingType="PICTURE" textWrap="TOP_AND_BOTTOM" textFlow="BOTH_SIDES" lock="0" dropcapstyle="None" pageBreak="CELL" treatAsChar="1"><hp:sz width="${w}" widthRelTo="ABSOLUTE" height="${h}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="1" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:imgRect x="0" y="0" w="${w}" h="${h}"/><hp:imgClip left="0" right="0" top="0" bottom="0"/><hp:img binaryItemIDRef="${binId}" bright="0" contrast="0" effect="REAL_PIC" alpha="0"/></hp:pic></hp:run>`;
2757
+ }
2758
+ function encodeGrid(grid, ctx) {
2759
+ const rowCount = grid.kids.length;
2760
+ let colCount = 0;
2761
+ for (const row of grid.kids) {
2762
+ let rowCols = 0;
2763
+ for (const cell of row.kids) rowCols += cell.cs;
2764
+ if (rowCols > colCount) colCount = rowCols;
2765
+ }
2766
+ if (colCount === 0) colCount = grid.kids[0]?.kids.length ?? 1;
2767
+ const totalWidth = ctx.availableWidth;
2768
+ const defaultColW = Math.round(totalWidth / (colCount || 1));
2769
+ const colWidths = [];
2770
+ if (grid.props.colWidths && grid.props.colWidths.length === colCount) {
2771
+ const srcPt = [...grid.props.colWidths];
2772
+ const knownTotal = srcPt.filter((w) => w > 0).reduce((s, w) => s + w, 0);
2773
+ const zeroCount = srcPt.filter((w) => w <= 0).length;
2774
+ const remaining = Math.max(0, Metric.hwpToPt(totalWidth) - knownTotal);
2775
+ const zeroFill = zeroCount > 0 ? remaining / zeroCount : 0;
2776
+ for (let i = 0; i < srcPt.length; i++) {
2777
+ if (srcPt[i] <= 0) srcPt[i] = zeroFill > 0 ? zeroFill : Metric.hwpToPt(defaultColW);
2778
+ }
2779
+ for (const wPt of srcPt) colWidths.push(Metric.ptToHwp(wPt));
2780
+ } else {
2781
+ for (let c = 0; c < colCount; c++) colWidths.push(defaultColW);
2782
+ }
2783
+ const rawTotal = colWidths.reduce((s, w) => s + w, 0);
2784
+ if (rawTotal > totalWidth * 1.05) {
2785
+ const scale = totalWidth / rawTotal;
2786
+ for (let i = 0; i < colWidths.length; i++) colWidths[i] = Math.round(colWidths[i] * scale);
2787
+ }
2788
+ const actualTotal = colWidths.reduce((s, w) => s + w, 0);
2789
+ const tblBfId = grid.props.defaultStroke ? addBorderFill(ctx, grid.props.defaultStroke) : 2;
2790
+ let rowsXml = "";
2791
+ for (let ri = 0; ri < grid.kids.length; ri++) {
2792
+ const row = grid.kids[ri];
2793
+ let cellsXml = "";
2794
+ let colIdx = 0;
2795
+ for (let ci = 0; ci < row.kids.length; ci++) {
2796
+ const cell = row.kids[ci];
2797
+ let cellBfId = tblBfId;
2798
+ if (cell.props.bg) {
2799
+ cellBfId = addBorderFill(ctx, grid.props.defaultStroke ?? DEFAULT_STROKE, cell.props.bg);
2800
+ }
2801
+ const parasXml = cell.kids.map((p) => encodePara(p, ctx)).join("");
2802
+ let cellW = 0;
2803
+ for (let sc = colIdx; sc < colIdx + cell.cs && sc < colWidths.length; sc++) cellW += colWidths[sc];
2804
+ if (cellW === 0) cellW = defaultColW * cell.cs;
2805
+ cellsXml += `<hp:tc name="" header="0" hasMargin="1" protect="0" editable="0" dirty="0" borderFillIDRef="${cellBfId}"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="${cell.props.va === "mid" ? "CENTER" : cell.props.va === "bot" ? "BOTTOM" : "TOP"}" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">${parasXml}</hp:subList><hp:cellAddr colAddr="${colIdx}" rowAddr="${ri}"/><hp:cellSpan colSpan="${cell.cs}" rowSpan="${cell.rs}"/><hp:cellSz width="${cellW}" height="1000"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
2806
+ colIdx += cell.cs;
2807
+ }
2808
+ rowsXml += `<hp:tr>${cellsXml}</hp:tr>`;
2809
+ }
2810
+ const headerRow = grid.props.headerRow ? ' repeatHeader="1"' : "";
2811
+ return `<hp:tbl id="${ctx.nextElementId++}" zOrder="0" numberingType="TABLE" textWrap="TOP_AND_BOTTOM" textFlow="BOTH_SIDES" lock="0" dropcapstyle="None" pageBreak="CELL"${headerRow} rowCnt="${rowCount}" colCnt="${colCount}" cellSpacing="0" borderFillIDRef="${tblBfId}" noAdjust="0"><hp:sz width="${actualTotal}" widthRelTo="ABSOLUTE" height="1000" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="1" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:inMargin left="138" right="138" top="138" bottom="138"/>${rowsXml}</hp:tbl>`;
2812
+ }
2813
+ function extractPreviewText(sheet) {
2814
+ if (!sheet) return "";
2815
+ const lines = [];
2816
+ for (const kid of sheet.kids) {
2817
+ if (kid.tag === "para") {
2818
+ const text = kid.kids.map((k) => {
2819
+ if (k.tag === "span") return k.kids.map((c) => c.tag === "txt" ? c.content : "").join("");
2820
+ return "";
2821
+ }).join("");
2822
+ if (text) lines.push(text);
2823
+ } else if (kid.tag === "grid") {
2824
+ for (const row of kid.kids) {
2825
+ const cells = row.kids.map(
2826
+ (cell) => cell.kids.map((p) => p.kids.map((k) => {
2827
+ if (k.tag === "span") return k.kids.map((c) => c.tag === "txt" ? c.content : "").join("");
2828
+ return "";
2829
+ }).join("")).join("")
2830
+ );
2831
+ lines.push(cells.join(" "));
2832
+ }
2833
+ }
2834
+ }
2835
+ return lines.join("\r\n");
2836
+ }
2837
+ function esc(s) {
2838
+ return TextKit.escapeXml(s);
2839
+ }
2840
+ registry.registerEncoder(new HwpxEncoder());
2841
+
2842
+ // src/encoders/docx/DocxEncoder.ts
2843
+ var DocxEncoder = class {
2844
+ constructor() {
2845
+ this.format = "docx";
2846
+ }
2847
+ async encode(doc) {
2848
+ try {
2849
+ const sheet = doc.kids[0];
2850
+ const dims = sheet?.dims ?? A4;
2851
+ const kids = sheet?.kids ?? [];
2852
+ const images = [];
2853
+ const ctx = { images, nextId: 10, nextImgNum: 1, warns: [] };
2854
+ collectImages(kids, ctx);
2855
+ let headerParas = sheet?.header;
2856
+ let footerParas = sheet?.footer;
2857
+ const hasHeader = headerParas && headerParas.length > 0;
2858
+ const hasFooter = footerParas && footerParas.length > 0;
2859
+ if (hasHeader) collectImagesFromParas(headerParas, ctx);
2860
+ if (hasFooter) collectImagesFromParas(footerParas, ctx);
2861
+ const headerRId = hasHeader ? `rId${ctx.nextId++}` : "";
2862
+ const footerRId = hasFooter ? `rId${ctx.nextId++}` : "";
2863
+ const numInfo = collectNumbering(kids);
2864
+ const entries = [
2865
+ { name: "[Content_Types].xml", data: TextKit.encode(contentTypes(images, hasHeader, hasFooter)) },
2866
+ { name: "_rels/.rels", data: TextKit.encode(pkgRels()) },
2867
+ { name: "word/document.xml", data: TextKit.encode(documentXml(kids, dims, ctx, headerRId, footerRId)) },
2868
+ { name: "word/styles.xml", data: TextKit.encode(stylesXml()) },
2869
+ { name: "word/settings.xml", data: TextKit.encode(settingsXml()) },
2870
+ { name: "word/_rels/document.xml.rels", data: TextKit.encode(docRels(images, headerRId, footerRId, numInfo.hasLists)) },
2871
+ { name: "docProps/app.xml", data: TextKit.encode(appXml()) },
2872
+ { name: "docProps/core.xml", data: TextKit.encode(coreXml(doc.meta)) }
2873
+ ];
2874
+ if (numInfo.hasLists) {
2875
+ entries.push({ name: "word/numbering.xml", data: TextKit.encode(numberingXml(numInfo)) });
2876
+ }
2877
+ if (hasHeader) {
2878
+ entries.push({ name: "word/header1.xml", data: TextKit.encode(headerFooterXml("hdr", headerParas, ctx)) });
2879
+ }
2880
+ if (hasFooter) {
2881
+ entries.push({ name: "word/footer1.xml", data: TextKit.encode(headerFooterXml("ftr", footerParas, ctx)) });
2882
+ }
2883
+ for (const img of images) {
2884
+ entries.push({ name: `word/media/${img.name}`, data: img.data });
2885
+ }
2886
+ return succeed(await ArchiveKit.zip(entries));
2887
+ } catch (e) {
2888
+ return fail(`DOCX encode error: ${e?.message ?? String(e)}`);
2889
+ }
2890
+ }
2891
+ };
2892
+ function mimeToExt2(mime) {
2893
+ if (mime.includes("jpeg")) return "jpeg";
2894
+ if (mime.includes("gif")) return "gif";
2895
+ if (mime.includes("bmp")) return "bmp";
2896
+ return "png";
2897
+ }
2898
+ function collectImages(kids, ctx) {
2899
+ for (const kid of kids) {
2900
+ if (kid.tag === "para") collectImagesFromPara(kid, ctx);
2901
+ else if (kid.tag === "grid") {
2902
+ for (const row of kid.kids)
2903
+ for (const cell of row.kids)
2904
+ for (const p of cell.kids) collectImagesFromPara(p, ctx);
2905
+ }
2906
+ }
2907
+ }
2908
+ function collectImagesFromParas(paras, ctx) {
2909
+ for (const p of paras) collectImagesFromPara(p, ctx);
2910
+ }
2911
+ function collectImagesFromPara(para, ctx) {
2912
+ for (const kid of para.kids) {
2913
+ if (kid.tag === "img") registerImage2(kid, ctx);
2914
+ }
2915
+ }
2916
+ function registerImage2(img, ctx) {
2917
+ if (img._rId) return;
2918
+ const ext = mimeToExt2(img.mime);
2919
+ const name = `image${ctx.nextImgNum++}.${ext}`;
2920
+ const rId = `rId${ctx.nextId++}`;
2921
+ const data = TextKit.base64Decode(img.b64);
2922
+ ctx.images.push({ rId, name, data, ext });
2923
+ img._rId = rId;
2924
+ }
2925
+ function collectNumbering(kids) {
2926
+ let hasBullet = false;
2927
+ let hasNumbered = false;
2928
+ for (const kid of kids) {
2929
+ if (kid.tag === "para") {
2930
+ if (kid.props.listOrd === true) hasNumbered = true;
2931
+ else if (kid.props.listOrd === false) hasBullet = true;
2932
+ }
2933
+ }
2934
+ return { hasLists: hasBullet || hasNumbered, hasBullet, hasNumbered };
2935
+ }
2936
+ function contentTypes(images, hasHeader, hasFooter) {
2937
+ const imgDefaults = /* @__PURE__ */ new Set();
2938
+ for (const img of images) imgDefaults.add(img.ext);
2939
+ let defaults = `<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
2940
+ <Default Extension="xml" ContentType="application/xml"/>`;
2941
+ for (const ext of imgDefaults) {
2942
+ const ct = ext === "png" ? "image/png" : ext === "jpeg" ? "image/jpeg" : ext === "gif" ? "image/gif" : "image/bmp";
2943
+ defaults += `
2944
+ <Default Extension="${ext}" ContentType="${ct}"/>`;
2945
+ }
2946
+ let overrides = `<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
2947
+ <Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
2948
+ <Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"/>
2949
+ <Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
2950
+ <Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>`;
2951
+ if (hasHeader) overrides += `
2952
+ <Override PartName="/word/header1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml"/>`;
2953
+ if (hasFooter) overrides += `
2954
+ <Override PartName="/word/footer1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"/>`;
2955
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2956
+ <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
2957
+ ${defaults}
2958
+ ${overrides}
2959
+ </Types>`;
2960
+ }
2961
+ function pkgRels() {
2962
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2963
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
2964
+ <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
2965
+ <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>
2966
+ <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
2967
+ </Relationships>`;
2968
+ }
2969
+ function docRels(images, headerRId, footerRId, hasLists) {
2970
+ let rels = `<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
2971
+ <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/>`;
2972
+ if (hasLists) {
2973
+ rels += `
2974
+ <Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml"/>`;
2975
+ }
2976
+ for (const img of images) {
2977
+ rels += `
2978
+ <Relationship Id="${img.rId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/${img.name}"/>`;
2979
+ }
2980
+ if (headerRId) {
2981
+ rels += `
2982
+ <Relationship Id="${headerRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml"/>`;
2983
+ }
2984
+ if (footerRId) {
2985
+ rels += `
2986
+ <Relationship Id="${footerRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" Target="footer1.xml"/>`;
2987
+ }
2988
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2989
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
2990
+ ${rels}
2991
+ </Relationships>`;
2992
+ }
2993
+ function appXml() {
2994
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2995
+ <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties">
2996
+ <Application>hwpkit</Application>
2997
+ </Properties>`;
2998
+ }
2999
+ function coreXml(meta) {
3000
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3001
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
3002
+ <cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3003
+ <dc:title>${esc2(meta.title ?? "")}</dc:title>
3004
+ <dc:creator>${esc2(meta.author ?? "")}</dc:creator>
3005
+ <dcterms:created xsi:type="dcterms:W3CDTF">${meta.created ?? now}</dcterms:created>
3006
+ <dcterms:modified xsi:type="dcterms:W3CDTF">${now}</dcterms:modified>
3007
+ </cp:coreProperties>`;
3008
+ }
3009
+ function stylesXml() {
3010
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
3011
+ <w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
3012
+ <w:docDefaults>
3013
+ <w:rPrDefault><w:rPr>
3014
+ <w:rFonts w:ascii="\uB9D1\uC740 \uACE0\uB515" w:eastAsia="\uB9D1\uC740 \uACE0\uB515" w:hAnsi="\uB9D1\uC740 \uACE0\uB515"/>
3015
+ <w:sz w:val="20"/>
3016
+ <w:szCs w:val="20"/>
3017
+ </w:rPr></w:rPrDefault>
3018
+ <w:pPrDefault><w:pPr>
3019
+ <w:spacing w:after="0" w:line="384" w:lineRule="auto"/>
3020
+ <w:jc w:val="both"/>
3021
+ </w:pPr></w:pPrDefault>
3022
+ </w:docDefaults>
3023
+ <w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/></w:style>
3024
+ <w:style w:type="paragraph" w:styleId="Heading1"><w:name w:val="heading 1"/><w:basedOn w:val="Normal"/><w:pPr><w:keepNext/><w:outlineLvl w:val="0"/></w:pPr><w:rPr><w:b/><w:sz w:val="44"/><w:szCs w:val="44"/></w:rPr></w:style>
3025
+ <w:style w:type="paragraph" w:styleId="Heading2"><w:name w:val="heading 2"/><w:basedOn w:val="Normal"/><w:pPr><w:keepNext/><w:outlineLvl w:val="1"/></w:pPr><w:rPr><w:b/><w:sz w:val="36"/><w:szCs w:val="36"/></w:rPr></w:style>
3026
+ <w:style w:type="paragraph" w:styleId="Heading3"><w:name w:val="heading 3"/><w:basedOn w:val="Normal"/><w:pPr><w:keepNext/><w:outlineLvl w:val="2"/></w:pPr><w:rPr><w:b/><w:sz w:val="28"/><w:szCs w:val="28"/></w:rPr></w:style>
3027
+ <w:style w:type="paragraph" w:styleId="Header"><w:name w:val="header"/><w:basedOn w:val="Normal"/></w:style>
3028
+ <w:style w:type="paragraph" w:styleId="Footer"><w:name w:val="footer"/><w:basedOn w:val="Normal"/></w:style>
3029
+ <w:style w:type="paragraph" w:styleId="ListParagraph"><w:name w:val="List Paragraph"/><w:basedOn w:val="Normal"/><w:pPr><w:ind w:left="720"/></w:pPr></w:style>
3030
+ <w:style w:type="table" w:styleId="TableGrid"><w:name w:val="Table Grid"/><w:tblPr><w:tblBorders><w:top w:val="single" w:sz="4" w:space="0" w:color="000000"/><w:left w:val="single" w:sz="4" w:space="0" w:color="000000"/><w:bottom w:val="single" w:sz="4" w:space="0" w:color="000000"/><w:right w:val="single" w:sz="4" w:space="0" w:color="000000"/><w:insideH w:val="single" w:sz="4" w:space="0" w:color="000000"/><w:insideV w:val="single" w:sz="4" w:space="0" w:color="000000"/></w:tblBorders></w:tblPr></w:style>
3031
+ </w:styles>`;
3032
+ }
3033
+ function settingsXml() {
3034
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
3035
+ <w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
3036
+ <w:zoom w:percent="100"/>
3037
+ <w:bordersDoNotSurroundHeader/>
3038
+ <w:bordersDoNotSurroundFooter/>
3039
+ <w:defaultTabStop w:val="800"/>
3040
+ <w:compat>
3041
+ <w:spaceForUL/>
3042
+ <w:balanceSingleByteDoubleByteWidth/>
3043
+ <w:doNotLeaveBackslashAlone/>
3044
+ <w:ulTrailSpace/>
3045
+ <w:doNotExpandShiftReturn/>
3046
+ <w:adjustLineHeightInTable/>
3047
+ <w:useFELayout/>
3048
+ </w:compat>
3049
+ </w:settings>`;
3050
+ }
3051
+ function numberingXml(info) {
3052
+ let abstractNums = "";
3053
+ let nums = "";
3054
+ if (info.hasBullet) {
3055
+ abstractNums += `<w:abstractNum w:abstractNumId="0">`;
3056
+ for (let lvl = 0; lvl < 9; lvl++) {
3057
+ const marker = lvl === 0 ? "\u25CF" : lvl === 1 ? "\u25CB" : "\u25A0";
3058
+ const indent = (lvl + 1) * 720;
3059
+ abstractNums += `<w:lvl w:ilvl="${lvl}"><w:numFmt w:val="bullet"/><w:lvlText w:val="${marker}"/><w:pPr><w:ind w:left="${indent}" w:hanging="360"/></w:pPr></w:lvl>`;
3060
+ }
3061
+ abstractNums += `</w:abstractNum>`;
3062
+ nums += `<w:num w:numId="1"><w:abstractNumId w:val="0"/></w:num>`;
3063
+ }
3064
+ if (info.hasNumbered) {
3065
+ abstractNums += `<w:abstractNum w:abstractNumId="1">`;
3066
+ for (let lvl = 0; lvl < 9; lvl++) {
3067
+ const fmt = lvl % 3 === 0 ? "decimal" : lvl % 3 === 1 ? "lowerLetter" : "lowerRoman";
3068
+ const indent = (lvl + 1) * 720;
3069
+ abstractNums += `<w:lvl w:ilvl="${lvl}"><w:start w:val="1"/><w:numFmt w:val="${fmt}"/><w:lvlText w:val="%${lvl + 1}."/><w:pPr><w:ind w:left="${indent}" w:hanging="360"/></w:pPr></w:lvl>`;
3070
+ }
3071
+ abstractNums += `</w:abstractNum>`;
3072
+ nums += `<w:num w:numId="2"><w:abstractNumId w:val="1"/></w:num>`;
3073
+ }
3074
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
3075
+ <w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
3076
+ ${abstractNums}
3077
+ ${nums}
3078
+ </w:numbering>`;
3079
+ }
3080
+ function headerFooterXml(type, paras, ctx) {
3081
+ const tag = type === "hdr" ? "w:hdr" : "w:ftr";
3082
+ const body = paras.map((p) => encodeParaInner(p, ctx)).join("\n");
3083
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
3084
+ <${tag} xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
3085
+ ${body}
3086
+ </${tag}>`;
3087
+ }
3088
+ function documentXml(kids, dims, ctx, headerRId, footerRId) {
3089
+ const body = kids.map((k) => encodeContent(k, ctx, dims)).join("\n");
3090
+ let sectRefs = "";
3091
+ if (headerRId) sectRefs += `
3092
+ <w:headerReference w:type="default" r:id="${headerRId}"/>`;
3093
+ if (footerRId) sectRefs += `
3094
+ <w:footerReference w:type="default" r:id="${footerRId}"/>`;
3095
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
3096
+ <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
3097
+ <w:body>
3098
+ ${body}
3099
+ <w:sectPr>${sectRefs}
3100
+ <w:pgSz w:w="${Metric.ptToDxa(dims.wPt)}" w:h="${Metric.ptToDxa(dims.hPt)}" w:orient="${dims.orient ?? "portrait"}"/>
3101
+ <w:pgMar w:top="${Metric.ptToDxa(dims.mt)}" w:right="${Metric.ptToDxa(dims.mr)}" w:bottom="${Metric.ptToDxa(dims.mb)}" w:left="${Metric.ptToDxa(dims.ml)}" w:header="709" w:footer="709" w:gutter="0"/>
3102
+ </w:sectPr>
3103
+ </w:body>
3104
+ </w:document>`;
3105
+ }
3106
+ function encodeContent(node, ctx, dims) {
3107
+ return node.tag === "grid" ? encodeGrid2(node, ctx, dims) : encodeParaInner(node, ctx);
3108
+ }
3109
+ function encodeParaInner(para, ctx) {
3110
+ const align = para.props.align ?? "left";
3111
+ const headStyle = para.props.heading ? `<w:pStyle w:val="Heading${para.props.heading}"/>` : "";
3112
+ let numPr = "";
3113
+ if (para.props.listOrd !== void 0) {
3114
+ const numId = para.props.listOrd ? 2 : 1;
3115
+ const ilvl = para.props.listLv ?? 0;
3116
+ numPr = `<w:pStyle w:val="ListParagraph"/><w:numPr><w:ilvl w:val="${ilvl}"/><w:numId w:val="${numId}"/></w:numPr>`;
3117
+ }
3118
+ const runs = para.kids.map((k) => {
3119
+ if (k.tag === "span") return encodeRun2(k, ctx);
3120
+ if (k.tag === "img") return encodeImage2(k, ctx);
3121
+ return "";
3122
+ }).join("");
3123
+ return ` <w:p>
3124
+ <w:pPr>${headStyle}${numPr}<w:jc w:val="${align === "justify" ? "both" : align}"/></w:pPr>
3125
+ ${runs}
3126
+ </w:p>`;
3127
+ }
3128
+ function encodeRun2(span, _ctx) {
3129
+ const p = span.props;
3130
+ const rPr = [];
3131
+ if (p.b) rPr.push("<w:b/>");
3132
+ if (p.i) rPr.push("<w:i/>");
3133
+ if (p.u) rPr.push('<w:u w:val="single"/>');
3134
+ if (p.s) rPr.push("<w:strike/>");
3135
+ if (p.sup) rPr.push('<w:vertAlign w:val="superscript"/>');
3136
+ if (p.sub) rPr.push('<w:vertAlign w:val="subscript"/>');
3137
+ if (p.pt) rPr.push(`<w:sz w:val="${Metric.ptToHalfPt(p.pt)}"/><w:szCs w:val="${Metric.ptToHalfPt(p.pt)}"/>`);
3138
+ if (p.color) rPr.push(`<w:color w:val="${p.color}"/>`);
3139
+ if (p.font) rPr.push(`<w:rFonts w:ascii="${esc2(p.font)}" w:hAnsi="${esc2(p.font)}" w:eastAsia="${esc2(p.font)}"/>`);
3140
+ if (p.bg) rPr.push(`<w:shd w:val="clear" w:color="auto" w:fill="${p.bg}"/>`);
3141
+ const parts = [];
3142
+ for (const kid of span.kids) {
3143
+ if (kid.tag === "txt") {
3144
+ parts.push(`<w:r><w:rPr>${rPr.join("")}</w:rPr><w:t xml:space="preserve">${esc2(kid.content)}</w:t></w:r>`);
3145
+ } else if (kid.tag === "pagenum") {
3146
+ parts.push(`<w:r><w:rPr>${rPr.join("")}</w:rPr><w:fldChar w:fldCharType="begin"/></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:instrText> PAGE </w:instrText></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:fldChar w:fldCharType="separate"/></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:t>1</w:t></w:r><w:r><w:rPr>${rPr.join("")}</w:rPr><w:fldChar w:fldCharType="end"/></w:r>`);
3147
+ } else if (kid.tag === "br") {
3148
+ parts.push(`<w:r><w:br/></w:r>`);
3149
+ } else if (kid.tag === "pb") {
3150
+ parts.push(`<w:r><w:br w:type="page"/></w:r>`);
3151
+ }
3152
+ }
3153
+ return parts.join("");
3154
+ }
3155
+ function encodeImage2(img, _ctx) {
3156
+ const rId = img._rId;
3157
+ if (!rId) return "";
3158
+ const cx = Metric.ptToEmu(img.w);
3159
+ const cy = Metric.ptToEmu(img.h);
3160
+ const alt = esc2(img.alt ?? "");
3161
+ return `<w:r><w:drawing><wp:inline distT="0" distB="0" distL="0" distR="0"><wp:extent cx="${cx}" cy="${cy}"/><wp:docPr id="${_ctx.nextId++}" name="Image" descr="${alt}"/><a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic><pic:nvPicPr><pic:cNvPr id="0" name="Image"/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip r:embed="${rId}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing></w:r>`;
3162
+ }
3163
+ function encodeGrid2(grid, ctx, dims) {
3164
+ const gp = grid.props;
3165
+ const look = gp.look;
3166
+ const firstRow = look?.firstRow ? "1" : "0";
3167
+ const lastRow = look?.lastRow ? "1" : "0";
3168
+ const firstCol = look?.firstCol ? "1" : "0";
3169
+ const lastCol = look?.lastCol ? "1" : "0";
3170
+ const noHBand = look?.bandedRows ? "0" : "1";
3171
+ const noVBand = look?.bandedCols ? "0" : "1";
3172
+ const d = dims ?? A4;
3173
+ const availDxa = Metric.ptToDxa(d.wPt - d.ml - d.mr);
3174
+ let colCount = 0;
3175
+ for (const row of grid.kids) {
3176
+ let rowCols = 0;
3177
+ for (const cell of row.kids) rowCols += cell.cs;
3178
+ if (rowCols > colCount) colCount = rowCols;
3179
+ }
3180
+ if (colCount === 0) colCount = grid.kids[0]?.kids.length ?? 1;
3181
+ const defaultColDxa = Math.round(availDxa / colCount);
3182
+ const colWidthsDxa = [];
3183
+ if (grid.props.colWidths && grid.props.colWidths.length === colCount) {
3184
+ const srcPt = [...grid.props.colWidths];
3185
+ const knownTotal = srcPt.filter((w) => w > 0).reduce((s, w) => s + w, 0);
3186
+ const zeroCount = srcPt.filter((w) => w <= 0).length;
3187
+ const remaining = Math.max(0, Metric.dxaToPt(availDxa) - knownTotal);
3188
+ const zeroFill = zeroCount > 0 ? remaining / zeroCount : 0;
3189
+ for (let i = 0; i < srcPt.length; i++) {
3190
+ if (srcPt[i] <= 0) srcPt[i] = zeroFill > 0 ? zeroFill : Metric.dxaToPt(defaultColDxa);
3191
+ }
3192
+ const srcWidths = srcPt.map((w) => Metric.ptToDxa(w));
3193
+ const srcTotal = srcWidths.reduce((s, w) => s + w, 0);
3194
+ const scale = srcTotal > availDxa ? availDxa / srcTotal : 1;
3195
+ for (const w of srcWidths) colWidthsDxa.push(Math.round(w * scale));
3196
+ } else {
3197
+ for (let c = 0; c < colCount; c++) colWidthsDxa.push(defaultColDxa);
3198
+ }
3199
+ const totalDxa = colWidthsDxa.reduce((s, w) => s + w, 0);
3200
+ const gridCols = colWidthsDxa.map((w) => `<w:gridCol w:w="${Math.round(w)}"/>`).join("");
3201
+ const vMergeMap = /* @__PURE__ */ new Map();
3202
+ for (let ri = 0; ri < grid.kids.length; ri++) {
3203
+ let colIdx = 0;
3204
+ for (const cell of grid.kids[ri].kids) {
3205
+ if (cell.rs > 1) {
3206
+ vMergeMap.set(`${ri},${colIdx}`, "restart");
3207
+ for (let sr = 1; sr < cell.rs; sr++) {
3208
+ vMergeMap.set(`${ri + sr},${colIdx}`, "continue");
3209
+ }
3210
+ }
3211
+ colIdx += cell.cs;
3212
+ }
3213
+ }
3214
+ const rows = grid.kids.map((row, ri) => {
3215
+ let colIdx = 0;
3216
+ const cellXmls = [];
3217
+ let srcCellIdx = 0;
3218
+ while (srcCellIdx < row.kids.length) {
3219
+ const cell = row.kids[srcCellIdx];
3220
+ const mergeType = vMergeMap.get(`${ri},${colIdx}`);
3221
+ const cp = cell.props;
3222
+ const tcPrParts = [];
3223
+ let cellW = 0;
3224
+ for (let sc = colIdx; sc < colIdx + cell.cs && sc < colWidthsDxa.length; sc++) cellW += colWidthsDxa[sc];
3225
+ if (cellW === 0) cellW = defaultColDxa * cell.cs;
3226
+ tcPrParts.push(`<w:tcW w:w="${Math.round(cellW)}" w:type="dxa"/>`);
3227
+ if (cell.cs > 1) tcPrParts.push(`<w:gridSpan w:val="${cell.cs}"/>`);
3228
+ if (cell.rs > 1) {
3229
+ tcPrParts.push(`<w:vMerge w:val="restart"/>`);
3230
+ }
3231
+ const borders = encodeCellBorders(cp);
3232
+ if (borders) tcPrParts.push(borders);
3233
+ if (cp.bg) tcPrParts.push(`<w:shd w:val="clear" w:color="auto" w:fill="${cp.bg}"/>`);
3234
+ if (cp.va) {
3235
+ const vaMap = { top: "top", mid: "center", bot: "bottom" };
3236
+ tcPrParts.push(`<w:vAlign w:val="${vaMap[cp.va] ?? "top"}"/>`);
3237
+ }
3238
+ const tcPr = `<w:tcPr>${tcPrParts.join("")}</w:tcPr>`;
3239
+ cellXmls.push(` <w:tc>${tcPr}${cell.kids.map((p) => encodeParaInner(p, ctx)).join("")}</w:tc>`);
3240
+ colIdx += cell.cs;
3241
+ srcCellIdx++;
3242
+ }
3243
+ const finalCells = [];
3244
+ let finalColIdx = 0;
3245
+ let cellIter = 0;
3246
+ const totalGridCols = colCount;
3247
+ finalColIdx = 0;
3248
+ cellIter = 0;
3249
+ for (let gc = 0; gc < totalGridCols; ) {
3250
+ const mergeType = vMergeMap.get(`${ri},${gc}`);
3251
+ if (mergeType === "continue") {
3252
+ let origCs = 1;
3253
+ for (let sr = ri - 1; sr >= 0; sr--) {
3254
+ const mt = vMergeMap.get(`${sr},${gc}`);
3255
+ if (mt === "restart") {
3256
+ let col = 0;
3257
+ for (const c of grid.kids[sr].kids) {
3258
+ if (col === gc) {
3259
+ origCs = c.cs;
3260
+ break;
3261
+ }
3262
+ col += c.cs;
3263
+ }
3264
+ break;
3265
+ }
3266
+ }
3267
+ let cw = 0;
3268
+ for (let sc = gc; sc < gc + origCs && sc < colWidthsDxa.length; sc++) cw += colWidthsDxa[sc];
3269
+ if (cw === 0) cw = defaultColDxa * origCs;
3270
+ let contParts = `<w:tcW w:w="${Math.round(cw)}" w:type="dxa"/>`;
3271
+ if (origCs > 1) contParts += `<w:gridSpan w:val="${origCs}"/>`;
3272
+ contParts += `<w:vMerge/>`;
3273
+ finalCells.push(` <w:tc><w:tcPr>${contParts}</w:tcPr><w:p><w:pPr/></w:p></w:tc>`);
3274
+ gc += origCs;
3275
+ } else {
3276
+ if (cellIter < cellXmls.length) {
3277
+ finalCells.push(cellXmls[cellIter]);
3278
+ gc += row.kids[cellIter]?.cs ?? 1;
3279
+ cellIter++;
3280
+ } else {
3281
+ gc++;
3282
+ }
3283
+ }
3284
+ }
3285
+ let trPr = "";
3286
+ if (ri === 0 && (gp.headerRow || look?.firstRow)) {
3287
+ trPr = "<w:trPr><w:tblHeader/></w:trPr>";
3288
+ }
3289
+ return ` <w:tr>${trPr}
3290
+ ${finalCells.join("\n")}
3291
+ </w:tr>`;
3292
+ }).join("\n");
3293
+ let tblBorders = "";
3294
+ if (gp.defaultStroke) {
3295
+ const s = gp.defaultStroke;
3296
+ const strokeKindMap = { solid: "single", dash: "dashed", dot: "dotted", double: "double", none: "none" };
3297
+ const val = strokeKindMap[s.kind] ?? "single";
3298
+ const sz = Math.round(s.pt * 8);
3299
+ const bdr = `w:val="${val}" w:sz="${sz}" w:space="0" w:color="${s.color}"`;
3300
+ tblBorders = `<w:tblBorders><w:top ${bdr}/><w:left ${bdr}/><w:bottom ${bdr}/><w:right ${bdr}/><w:insideH ${bdr}/><w:insideV ${bdr}/></w:tblBorders>`;
3301
+ }
3302
+ return ` <w:tbl>
3303
+ <w:tblPr><w:tblStyle w:val="TableGrid"/><w:tblW w:w="${Math.round(totalDxa)}" w:type="dxa"/><w:tblLayout w:type="fixed"/><w:tblLook w:val="04A0" w:firstRow="${firstRow}" w:lastRow="${lastRow}" w:firstColumn="${firstCol}" w:lastColumn="${lastCol}" w:noHBand="${noHBand}" w:noVBand="${noVBand}"/>${tblBorders}<w:tblCellMar><w:top w:w="28" w:type="dxa"/><w:left w:w="102" w:type="dxa"/><w:bottom w:w="28" w:type="dxa"/><w:right w:w="102" w:type="dxa"/></w:tblCellMar></w:tblPr>
3304
+ <w:tblGrid>${gridCols}</w:tblGrid>
3305
+ ${rows}
3306
+ </w:tbl>`;
3307
+ }
3308
+ function encodeCellBorders(cp) {
3309
+ if (!cp.top && !cp.bot && !cp.left && !cp.right) return "";
3310
+ const strokeKindMap = { solid: "single", dash: "dashed", dot: "dotted", double: "double", none: "none" };
3311
+ const encode = (s, tag) => {
3312
+ if (!s || !tag) return "";
3313
+ const val = strokeKindMap[s.kind] ?? "single";
3314
+ return `<w:${tag} w:val="${val}" w:sz="${Math.round(s.pt * 8)}" w:space="0" w:color="${s.color}"/>`;
3315
+ };
3316
+ return `<w:tcBorders>${encode(cp.top, "top")}${encode(cp.bot, "bottom")}${encode(cp.left, "left")}${encode(cp.right, "right")}</w:tcBorders>`;
3317
+ }
3318
+ function esc2(s) {
3319
+ return TextKit.escapeXml(s);
3320
+ }
3321
+ registry.registerEncoder(new DocxEncoder());
3322
+
3323
+ // src/encoders/md/MdEncoder.ts
3324
+ var MdEncoder = class {
3325
+ constructor() {
3326
+ this.format = "md";
3327
+ }
3328
+ async encode(doc) {
3329
+ try {
3330
+ const warns = [];
3331
+ const parts = [];
3332
+ for (const sheet of doc.kids) {
3333
+ if (sheet.header && sheet.header.length > 0) warns.push("[SHIELD] MD: \uBA38\uB9AC\uAE00(header) \uD45C\uD604 \uBD88\uAC00 \u2014 \uC190\uC2E4\uB428");
3334
+ if (sheet.footer && sheet.footer.length > 0) warns.push("[SHIELD] MD: \uBC14\uB2E5\uAE00(footer) \uD45C\uD604 \uBD88\uAC00 \u2014 \uC190\uC2E4\uB428");
3335
+ for (const kid of sheet.kids) parts.push(encodeContent2(kid, warns));
3336
+ }
3337
+ return succeed(TextKit.encode(parts.join("\n\n")), warns);
3338
+ } catch (e) {
3339
+ return fail(`MD encode error: ${e?.message ?? String(e)}`);
3340
+ }
3341
+ }
3342
+ };
3343
+ function encodeContent2(node, warns) {
3344
+ return node.tag === "grid" ? encodeGrid3(node, warns) : encodePara2(node, warns);
3345
+ }
3346
+ function encodePara2(para, warns) {
3347
+ const text = para.kids.map((k) => {
3348
+ if (k.tag === "span") return encodeSpan(k, warns);
3349
+ if (k.tag === "img") return encodeImage3(k);
3350
+ return "";
3351
+ }).join("");
3352
+ if (para.props.heading) return `${"#".repeat(para.props.heading)} ${text}`;
3353
+ if (para.props.listOrd !== void 0) {
3354
+ const indent = " ".repeat(para.props.listLv ?? 0);
3355
+ return `${indent}${para.props.listOrd ? "1." : "-"} ${text}`;
3356
+ }
3357
+ if (para.props.align && para.props.align !== "left" && para.props.align !== "justify") {
3358
+ return `<div align="${para.props.align}">${text}</div>`;
3359
+ }
3360
+ return text;
3361
+ }
3362
+ function encodeSpan(span, warns) {
3363
+ if (span.props.font) warns.push(`[SHIELD] MD: \uAE00\uAF34(${span.props.font}) \uD45C\uD604 \uBD88\uAC00 \u2014 \uC190\uC2E4\uB428`);
3364
+ if (span.props.pt) warns.push(`[SHIELD] MD: \uAE00\uC790 \uD06C\uAE30(${span.props.pt}pt) \uD45C\uD604 \uBD88\uAC00 \u2014 \uC190\uC2E4\uB428`);
3365
+ if (span.props.color) warns.push(`[SHIELD] MD: \uAE00\uC790 \uC0C9\uC0C1(#${span.props.color}) \uD45C\uD604 \uBD88\uAC00 \u2014 \uC190\uC2E4\uB428`);
3366
+ if (span.props.bg) warns.push(`[SHIELD] MD: \uBC30\uACBD \uC0C9\uC0C1(#${span.props.bg}) \uD45C\uD604 \uBD88\uAC00 \u2014 \uC190\uC2E4\uB428`);
3367
+ let hasPageNum = false;
3368
+ const textParts = [];
3369
+ for (const kid of span.kids) {
3370
+ if (kid.tag === "txt") textParts.push(kid.content);
3371
+ else if (kid.tag === "pagenum") {
3372
+ hasPageNum = true;
3373
+ warns.push("[SHIELD] MD: \uD398\uC774\uC9C0 \uBC88\uD638 \uD45C\uD604 \uBD88\uAC00 \u2014 \uC190\uC2E4\uB428");
3374
+ }
3375
+ }
3376
+ let r = textParts.join("");
3377
+ if (hasPageNum && r === "") r = "[\uD398\uC774\uC9C0 \uBC88\uD638]";
3378
+ if (span.props.b && span.props.i) r = `***${r}***`;
3379
+ else if (span.props.b) r = `**${r}**`;
3380
+ else if (span.props.i) r = `*${r}*`;
3381
+ if (span.props.s) r = `~~${r}~~`;
3382
+ if (span.props.u) r = `<u>${r}</u>`;
3383
+ if (span.props.sup) r = `<sup>${r}</sup>`;
3384
+ if (span.props.sub) r = `<sub>${r}</sub>`;
3385
+ return r;
3386
+ }
3387
+ function encodeImage3(img) {
3388
+ return `![${img.alt ?? ""}](data:${img.mime};base64,${img.b64})`;
3389
+ }
3390
+ function encodeGrid3(grid, warns) {
3391
+ if (grid.kids.length === 0) return "";
3392
+ if (grid.props.look) warns.push("[SHIELD] MD: \uD45C \uC2A4\uD0C0\uC77C(\uC0C9\uC0C1, \uD14C\uB450\uB9AC, \uBA38\uB9AC\uD589 \uAC15\uC870) \uD45C\uD604 \uBD88\uAC00 \u2014 \uC190\uC2E4\uB428");
3393
+ const rows = grid.kids.map(
3394
+ (row) => `| ${row.kids.map((cell) => cell.kids.map((p) => encodePara2(p, warns)).join(" ")).join(" | ")} |`
3395
+ );
3396
+ if (rows.length > 0) {
3397
+ const cols = grid.kids[0].kids.length;
3398
+ rows.splice(1, 0, `| ${Array(cols).fill("---").join(" | ")} |`);
3399
+ }
3400
+ return rows.join("\n");
3401
+ }
3402
+ registry.registerEncoder(new MdEncoder());
3403
+
3404
+ // src/pipeline/Pipeline.ts
3405
+ var Pipeline = class _Pipeline {
3406
+ constructor(raw, srcFmt) {
3407
+ this.raw = raw;
3408
+ this.srcFmt = srcFmt;
3409
+ }
3410
+ /** 파일을 열고 포맷을 자동 감지하거나 명시 */
3411
+ static open(input, fmt) {
3412
+ if (typeof input === "string") {
3413
+ return new _Pipeline(new TextEncoder().encode(input), fmt ?? "md");
3414
+ }
3415
+ return new _Pipeline(input, fmt ?? detectFormat(input));
3416
+ }
3417
+ /** File/Blob 비동기 입력 */
3418
+ static async openAsync(input, fmt) {
3419
+ if (input instanceof Uint8Array || typeof input === "string") {
3420
+ return _Pipeline.open(input, fmt);
3421
+ }
3422
+ const buf = await input.arrayBuffer();
3423
+ const data = new Uint8Array(buf);
3424
+ const detectedFmt = fmt ?? (input instanceof File ? getExt(input.name) : void 0) ?? detectFormat(data);
3425
+ return new _Pipeline(data, detectedFmt);
3426
+ }
3427
+ /** 목표 포맷으로 변환 */
3428
+ async to(targetFmt) {
3429
+ const decoder = registry.getDecoder(this.srcFmt);
3430
+ const encoder = registry.getEncoder(targetFmt);
3431
+ if (!decoder) return fail(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC785\uB825 \uD3EC\uB9F7: ${this.srcFmt}`);
3432
+ if (!encoder) return fail(`\uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uCD9C\uB825 \uD3EC\uB9F7: ${targetFmt}`);
3433
+ const docResult = await decoder.decode(this.raw);
3434
+ if (!docResult.ok) return docResult;
3435
+ const encResult = await encoder.encode(docResult.data);
3436
+ if (!encResult.ok) return { ...encResult, warns: [...docResult.warns, ...encResult.warns] };
3437
+ return { ...encResult, warns: [...docResult.warns, ...encResult.warns] };
3438
+ }
3439
+ /** DocRoot만 추출 (인코딩 없이) */
3440
+ async inspect() {
3441
+ const decoder = registry.getDecoder(this.srcFmt);
3442
+ if (!decoder) return fail(`\uB514\uCF54\uB354 \uC5C6\uC74C: ${this.srcFmt}`);
3443
+ return decoder.decode(this.raw);
3444
+ }
3445
+ };
3446
+ function detectFormat(data) {
3447
+ if (data[0] === 80 && data[1] === 75) return "zip";
3448
+ if (data[0] === 208 && data[1] === 207 && data[2] === 17 && data[3] === 224) return "hwp";
3449
+ return "md";
3450
+ }
3451
+ function getExt(name) {
3452
+ const parts = name.split(".");
3453
+ return parts.length > 1 ? parts[parts.length - 1].toLowerCase() : void 0;
3454
+ }
3455
+
3456
+ // src/walk/TreeWalker.ts
3457
+ function walkNode(node, cb, parent = null, depth = 0) {
3458
+ const result = cb(node, parent, depth);
3459
+ if (result === "stop") return false;
3460
+ if ("kids" in node && Array.isArray(node.kids)) {
3461
+ for (const kid of node.kids) {
3462
+ if (!walkNode(kid, cb, node, depth + 1)) return false;
3463
+ }
3464
+ }
3465
+ return true;
3466
+ }
3467
+ var TreeWalker = class {
3468
+ walk(root, cb) {
3469
+ walkNode(root, cb);
3470
+ }
3471
+ findAll(root, predicate) {
3472
+ const results = [];
3473
+ walkNode(root, (n) => {
3474
+ if (predicate(n)) results.push(n);
3475
+ });
3476
+ return results;
3477
+ }
3478
+ extractText(root) {
3479
+ const parts = [];
3480
+ walkNode(root, (n) => {
3481
+ if (n.tag === "txt") parts.push(n.content);
3482
+ if (n.tag === "br") parts.push("\n");
3483
+ if (n.tag === "pb") parts.push("\n\n");
3484
+ });
3485
+ return parts.join("");
3486
+ }
3487
+ };
3488
+
3489
+ // src/walk/tree-ops.ts
3490
+ function countNodes(root) {
3491
+ const counts = {};
3492
+ walkNode(root, (n) => {
3493
+ counts[n.tag] = (counts[n.tag] ?? 0) + 1;
3494
+ });
3495
+ return counts;
3496
+ }
3497
+ function validateRoot(root) {
3498
+ const errors = [];
3499
+ if (root.tag !== "root") errors.push('Root node must have tag "root"');
3500
+ if (!Array.isArray(root.kids)) errors.push("Root.kids must be an array");
3501
+ if (root.kids.length === 0) errors.push("Document has no sheets");
3502
+ walkNode(root, (n) => {
3503
+ if (n.tag === "cell" && n.kids.length === 0) {
3504
+ errors.push("CellNode must have at least one ParaNode child");
3505
+ }
3506
+ if (n.tag === "grid" && n.kids.length === 0) {
3507
+ errors.push("GridNode must have at least one RowNode");
3508
+ }
3509
+ });
3510
+ return errors;
3511
+ }
3512
+ // Annotate the CommonJS export names for ESM import in node:
3513
+ 0 && (module.exports = {
3514
+ A4,
3515
+ ArchiveKit,
3516
+ BinaryKit,
3517
+ DEFAULT_STROKE,
3518
+ Metric,
3519
+ Pipeline,
3520
+ ShieldedParser,
3521
+ TextKit,
3522
+ TreeWalker,
3523
+ XmlKit,
3524
+ buildCell,
3525
+ buildGrid,
3526
+ buildImg,
3527
+ buildPageNum,
3528
+ buildPara,
3529
+ buildRoot,
3530
+ buildRow,
3531
+ buildSheet,
3532
+ buildSpan,
3533
+ countNodes,
3534
+ fail,
3535
+ registry,
3536
+ safeAlign,
3537
+ safeFont,
3538
+ safeFontToKr,
3539
+ safeHex,
3540
+ safeStrokeDocx,
3541
+ safeStrokeHwpx,
3542
+ succeed,
3543
+ validateRoot,
3544
+ walkNode
3545
+ });
3546
+ //# sourceMappingURL=index.js.map