n8n-nodes-kordoc 0.1.39 → 0.1.40

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.
@@ -44,6 +44,9 @@ var init_cjs_shims = __esm({
44
44
  });
45
45
 
46
46
  // .kordoc-source/src/script-tags.ts
47
+ function escapeLiteralTags(text2) {
48
+ return text2.includes("<") ? text2.replace(LITERAL_TAG, "\\<") : text2;
49
+ }
47
50
  function wrapScript(text2, kind) {
48
51
  if (!kind) return text2;
49
52
  const m = /^(\s*)([\s\S]*?)(\s*)$/.exec(text2);
@@ -51,11 +54,11 @@ function wrapScript(text2, kind) {
51
54
  }
52
55
  function tidyScriptTags(text2) {
53
56
  if (!text2.includes("<su")) return text2;
54
- return text2.replace(/<\/(sup|sub)><\1>/g, "").replace(/<(sup|sub)>(\s+)/g, "$2<$1>").replace(/(\s+)<\/(sup|sub)>/g, "</$2>$1").replace(/<(sup|sub)><\/\1>/g, "");
57
+ return text2.replace(/(?<!\\)<\/(sup|sub)><\1>/g, "").replace(/(?<!\\)<(sup|sub)>(\s+)/g, "$2<$1>").replace(/(\s+)<\/(sup|sub)>/g, "</$2>$1").replace(/(?<!\\)<(sup|sub)><\/\1>/g, "");
55
58
  }
56
59
  function plainScripts(md2) {
57
60
  if (!md2.includes("<su")) return md2;
58
- return md2.replace(/<(sup|sub)>([^<\n]*)<\/\1>/g, (_, kind, body) => {
61
+ return md2.replace(/(?<!\\)<(sup|sub)>([^<\n]*)<\/\1>/g, (_, kind, body) => {
59
62
  const mark = kind === "sup" ? "^" : "_";
60
63
  return /^(?:[+\-−]?[\p{L}\p{N}]+|[*∗†‡§¶]+)$/u.test(body) ? mark + body : `${mark}(${body})`;
61
64
  });
@@ -85,12 +88,70 @@ function stripScriptTags(r) {
85
88
  for (const p of (_a2 = r.pages) != null ? _a2 : []) p.markdown = s(p.markdown);
86
89
  return r;
87
90
  }
88
- var TAG_RE;
91
+ var LITERAL_TAG, TAG_RE;
89
92
  var init_script_tags = __esm({
90
93
  ".kordoc-source/src/script-tags.ts"() {
91
94
  "use strict";
92
95
  init_cjs_shims();
93
- TAG_RE = /<\/?su[bp]>/g;
96
+ LITERAL_TAG = /<(?=\/?(?:u|sup|sub)>)/g;
97
+ TAG_RE = /(?<!\\)<\/?su[bp]>/g;
98
+ }
99
+ });
100
+
101
+ // .kordoc-source/src/page-range.ts
102
+ var page_range_exports = {};
103
+ __export(page_range_exports, {
104
+ hasRequestedPagesAfter: () => hasRequestedPagesAfter,
105
+ parsePageRange: () => parsePageRange
106
+ });
107
+ function parsePageRange(spec, maxPages) {
108
+ const result = /* @__PURE__ */ new Set();
109
+ if (maxPages <= 0) return result;
110
+ if (Array.isArray(spec)) {
111
+ for (const n of spec) {
112
+ const page = Math.round(n);
113
+ if (page >= 1 && page <= maxPages) result.add(page);
114
+ }
115
+ return result;
116
+ }
117
+ if (typeof spec !== "string" || spec.trim() === "") return result;
118
+ const parts = spec.split(",");
119
+ for (const part of parts) {
120
+ const trimmed = part.trim();
121
+ if (!trimmed) continue;
122
+ const rangeMatch = trimmed.match(/^(\d+)\s*-\s*(\d+)$/);
123
+ if (rangeMatch) {
124
+ const start = Math.max(1, parseInt(rangeMatch[1], 10));
125
+ const end = Math.min(maxPages, parseInt(rangeMatch[2], 10));
126
+ for (let i = start; i <= end; i++) result.add(i);
127
+ } else {
128
+ const page = parseInt(trimmed, 10);
129
+ if (!isNaN(page) && page >= 1 && page <= maxPages) result.add(page);
130
+ }
131
+ }
132
+ return result;
133
+ }
134
+ function hasRequestedPagesAfter(spec, maxParsed, total) {
135
+ if (total <= 0 || total <= maxParsed) return false;
136
+ const beyond = (page) => page >= 1 && page <= total && page > maxParsed;
137
+ if (Array.isArray(spec)) return spec.some((n) => beyond(Math.round(n)));
138
+ if (typeof spec !== "string" || spec.trim() === "") return false;
139
+ for (const part of spec.split(",")) {
140
+ const trimmed = part.trim();
141
+ if (!trimmed) continue;
142
+ const rangeMatch = trimmed.match(/^(\d+)\s*-\s*(\d+)$/);
143
+ if (rangeMatch) {
144
+ const start = Math.max(1, parseInt(rangeMatch[1], 10), Math.floor(maxParsed) + 1);
145
+ const end = Math.min(total, parseInt(rangeMatch[2], 10));
146
+ if (start <= end) return true;
147
+ } else if (beyond(parseInt(trimmed, 10))) return true;
148
+ }
149
+ return false;
150
+ }
151
+ var init_page_range = __esm({
152
+ ".kordoc-source/src/page-range.ts"() {
153
+ "use strict";
154
+ init_cjs_shims();
94
155
  }
95
156
  });
96
157
 
@@ -9872,9 +9933,9 @@ var require_lib3 = __commonJS({
9872
9933
  "node_modules/jszip/lib/index.js"(exports2, module2) {
9873
9934
  "use strict";
9874
9935
  init_cjs_shims();
9875
- function JSZip15() {
9876
- if (!(this instanceof JSZip15)) {
9877
- return new JSZip15();
9936
+ function JSZip16() {
9937
+ if (!(this instanceof JSZip16)) {
9938
+ return new JSZip16();
9878
9939
  }
9879
9940
  if (arguments.length) {
9880
9941
  throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");
@@ -9883,7 +9944,7 @@ var require_lib3 = __commonJS({
9883
9944
  this.comment = null;
9884
9945
  this.root = "";
9885
9946
  this.clone = function() {
9886
- var newObj = new JSZip15();
9947
+ var newObj = new JSZip16();
9887
9948
  for (var i in this) {
9888
9949
  if (typeof this[i] !== "function") {
9889
9950
  newObj[i] = this[i];
@@ -9892,16 +9953,16 @@ var require_lib3 = __commonJS({
9892
9953
  return newObj;
9893
9954
  };
9894
9955
  }
9895
- JSZip15.prototype = require_object();
9896
- JSZip15.prototype.loadAsync = require_load();
9897
- JSZip15.support = require_support();
9898
- JSZip15.defaults = require_defaults();
9899
- JSZip15.version = "3.10.1";
9900
- JSZip15.loadAsync = function(content, options) {
9901
- return new JSZip15().loadAsync(content, options);
9956
+ JSZip16.prototype = require_object();
9957
+ JSZip16.prototype.loadAsync = require_load();
9958
+ JSZip16.support = require_support();
9959
+ JSZip16.defaults = require_defaults();
9960
+ JSZip16.version = "3.10.1";
9961
+ JSZip16.loadAsync = function(content, options) {
9962
+ return new JSZip16().loadAsync(content, options);
9902
9963
  };
9903
- JSZip15.external = require_external();
9904
- module2.exports = JSZip15;
9964
+ JSZip16.external = require_external();
9965
+ module2.exports = JSZip16;
9905
9966
  }
9906
9967
  });
9907
9968
 
@@ -9975,8 +10036,9 @@ function precheckZipSize(buffer, maxUncompressedSize = 256 * 1024 * 1024, maxEnt
9975
10036
  const extraLen = data.getUint16(pos + 30, true);
9976
10037
  const commentLen = data.getUint16(pos + 32, true);
9977
10038
  const isMedia = !!media && pos + 46 + nameLen <= len && media.re.test(new TextDecoder().decode(new Uint8Array(buffer, pos + 46, nameLen)));
9978
- if (isMedia) mediaUncompressed += size;
9979
- if (!(isMedia && (media == null ? void 0 : media.skip))) totalUncompressed += size;
10039
+ const never = isMedia && !!(media == null ? void 0 : media.never) && media.never.test(new TextDecoder().decode(new Uint8Array(buffer, pos + 46, nameLen)));
10040
+ if (isMedia && !never) mediaUncompressed += size;
10041
+ if (!(isMedia && ((media == null ? void 0 : media.skip) || never))) totalUncompressed += size;
9980
10042
  pos += 46 + nameLen + extraLen + commentLen;
9981
10043
  }
9982
10044
  if (totalUncompressed > maxUncompressedSize) {
@@ -10030,12 +10092,16 @@ function classifyError(err) {
10030
10092
  if (msg2.includes("\uC2DC\uADF8\uB2C8\uCC98") || msg2.includes("\uBCF5\uAD6C\uD560 \uC218 \uC5C6")) return "CORRUPTED";
10031
10093
  return "PARSE_ERROR";
10032
10094
  }
10095
+ function partExtension(path) {
10096
+ var _a2, _b;
10097
+ return ((_b = (_a2 = /\.([A-Za-z0-9]{1,5})$/.exec(path.slice(path.lastIndexOf("/") + 1))) == null ? void 0 : _a2[1]) != null ? _b : "bin").toLowerCase();
10098
+ }
10033
10099
  var VERSION, KordocError, MAX_UNZIP_ENV_MB, SAFE_HREF_RE, HREF_ESCAPE, HTML_ENTITY, OPTIONAL_DEP_INSTALL_HINT;
10034
10100
  var init_utils = __esm({
10035
10101
  ".kordoc-source/src/utils.ts"() {
10036
10102
  "use strict";
10037
10103
  init_cjs_shims();
10038
- VERSION = true ? "4.18.0" : "0.0.0-dev";
10104
+ VERSION = true ? "4.18.3" : "0.0.0-dev";
10039
10105
  KordocError = class extends Error {
10040
10106
  constructor(message) {
10041
10107
  super(message);
@@ -10649,7 +10715,7 @@ function escapeGfm(text2) {
10649
10715
  spans.push(m);
10650
10716
  return NUL + (spans.length - 1) + NUL;
10651
10717
  });
10652
- const escaped = masked.replace(/\\(?=[!-#%-\/:-@\[-\x60{}~])/g, "\\\\").replace(/([~*_`])/g, "\\$1").replace(/(?<!\\)\|/g, "\\|").replace(/^([ \t]*)(?=#{1,6}(?:[ \t]|$))/gm, "$1\\").replace(/<(?!\/?(?:u|sup|sub)>)(?=[A-Za-z/!?])/g, "\\<");
10718
+ const escaped = masked.replace(/\\(?=[!-#%-\/:-@\[-\x60{}~])(?!<\/?(?:u|sup|sub)>)/g, "\\\\").replace(/([~*_`])/g, "\\$1").replace(/(?<!\\)\|/g, "\\|").replace(/^([ \t]*)(?=#{1,6}(?:[ \t]|$))/gm, "$1\\").replace(/<(?!\/?(?:u|sup|sub)>)(?=[A-Za-z/!?])/g, "\\<");
10653
10719
  return escaped.replace(new RegExp(NUL + "(\\d+)" + NUL, "g"), (_, n) => spans[Number(n)]);
10654
10720
  }
10655
10721
  function escapeLiteralDollar(text2) {
@@ -10823,6 +10889,7 @@ function blocksToMarkdown(blocks) {
10823
10889
  if (block2.type === "paragraph" && (block2.text || block2.footnoteText)) {
10824
10890
  let text2 = sanitizeText((_a2 = block2.text) != null ? _a2 : "");
10825
10891
  if (!text2 && !block2.footnoteText) continue;
10892
+ if (lines.length && lines[lines.length - 1] !== "") lines.push("");
10826
10893
  if (/^\[별표\s*\d+/.test(text2)) {
10827
10894
  const nextBlock = blocks[i + 1];
10828
10895
  if ((nextBlock == null ? void 0 : nextBlock.type) === "paragraph" && nextBlock.text && /관련\)?$/.test(nextBlock.text)) {
@@ -10917,7 +10984,7 @@ function visibleText(b) {
10917
10984
  return ((_a2 = b.spans) == null ? void 0 : _a2.some((s) => s.placeholder)) ? b.spans.filter((s) => !s.placeholder).map((s) => s.text).join("") : (_b = b.text) != null ? _b : "";
10918
10985
  }
10919
10986
  function escapeHtmlCellText(text2) {
10920
- return escapeHtml(text2).replace(/&lt;(\/?)(u|sup|sub)&gt;/g, "<$1$2>");
10987
+ return escapeHtml(text2).replace(/(\\)?&lt;(\/?)(u|sup|sub)&gt;/g, (_, esc2, sl, tag) => esc2 ? `&lt;${sl}${tag}&gt;` : `<${sl}${tag}>`);
10921
10988
  }
10922
10989
  function cellInnerHtml(cell2) {
10923
10990
  var _a2;
@@ -11087,7 +11154,7 @@ function ruleGrids(t, anchors2) {
11087
11154
  return { H, V };
11088
11155
  }
11089
11156
  function toTex(s) {
11090
- return s.replace(/<\/?u>/g, "").replace(/([\\{}%#&_$])/g, "\\$1").replace(/<sup>(.*?)<\/sup>/g, "^{$1}").replace(/<sub>(.*?)<\/sub>/g, "_{$1}").replace(/[가-힣ㄱ-ㅎㅏ-ㅣ][가-힣ㄱ-ㅎㅏ-ㅣ\s·ㆍ]*/g, (m) => `\\text{${m.trim()}}`).trim();
11157
+ return s.replace(/\\\$/g, "$").replace(/\\</g, "").replace(/<\/?u>/g, "").replace(/([\\{}%#&_$])/g, "\\$1").replace(/<sup>(.*?)<\/sup>/g, "^{$1}").replace(/<sub>(.*?)<\/sub>/g, "_{$1}").replace(/\u0001/g, "<").replace(/[가-힣ㄱ-ㅎㅏ-ㅣ][가-힣ㄱ-ㅎㅏ-ㅣ\s·ㆍ]*/g, (m) => `\\text{${m.trim()}}`).trim();
11091
11158
  }
11092
11159
  function fractionPart(cell2) {
11093
11160
  var _a2;
@@ -11101,7 +11168,8 @@ function mergeFractions(t, anchors2, H, V) {
11101
11168
  for (const u of anchors2) {
11102
11169
  const d = at.get((u.r + u.rs) * t.cols + u.c);
11103
11170
  if (!d || d.cs !== u.cs || u.rs !== 1 || d.rs !== 1 || !fractionPart(u.cell) || !fractionPart(d.cell)) continue;
11104
- if (u.cs === t.cols && anchors2.length !== 2) continue;
11171
+ const besideText = anchors2.some((a) => a !== u && a !== d && a.r <= d.r && a.r + a.rs > u.r && a.cell.text.trim());
11172
+ if (!besideText && anchors2.filter((a) => a.cell.text.trim()).length !== 2) continue;
11105
11173
  const bar = d.r, c1 = u.c, c2 = u.c + u.cs;
11106
11174
  let ok = true;
11107
11175
  for (let c = c1; c < c2 && ok; c++) if (!H[bar][c]) ok = false;
@@ -11152,9 +11220,10 @@ function bandTable(t, anchors2, V, H, r0, r1, keepEmptyCols) {
11152
11220
  const shift = (y) => y - drop.filter((d) => d < y).length;
11153
11221
  list2 = list2.filter((a) => !drop.includes(a.r)).map((a) => ({ ...a, r: shift(a.r), rs: shift(a.r + a.rs) - shift(a.r) })).filter((a) => a.rs > 0);
11154
11222
  }
11223
+ const emptyBand = list2.every(blank2);
11155
11224
  for (let right = keepEmptyCols ? 0 : Math.max(...list2.map((a) => a.c + a.cs)); right > 1; ) {
11156
11225
  const starts = list2.filter((a) => a.c === right - 1);
11157
- if (!starts.length || !starts.every(blank2)) break;
11226
+ if (!starts.length || !starts.every(blank2) || starts.length === list2.length) break;
11158
11227
  list2 = list2.filter((a) => a.c !== right - 1).map((a) => a.c + a.cs === right ? { ...a, cs: a.cs - 1 } : a);
11159
11228
  right--;
11160
11229
  }
@@ -11175,7 +11244,7 @@ function bandTable(t, anchors2, V, H, r0, r1, keepEmptyCols) {
11175
11244
  a.cell.colSpan = cx.indexOf(a.c + a.cs) - c;
11176
11245
  cells[r][c] = a.cell;
11177
11246
  }
11178
- return { rows, cols, cells, hasHeader: t.hasHeader };
11247
+ return { rows, cols, cells, hasHeader: t.hasHeader, ...emptyBand ? { renderAsTable: true } : {} };
11179
11248
  }
11180
11249
  function textRow(row, out, pageNumber, keepEmptyCols) {
11181
11250
  var _a2;
@@ -11212,8 +11281,18 @@ function unframeTable(t, pageNumber, keepEmptyCols) {
11212
11281
  const ruled = ruledRows(t, anchors2, H, V);
11213
11282
  if (ruled.every(Boolean)) {
11214
11283
  const whole = bandTable(t, anchors2, V, H, 0, t.rows - 1, keepEmptyCols);
11215
- if (!whole || whole.rows === t.rows && whole.cols === t.cols) return null;
11216
- return [{ type: "table", table: { ...t, rows: whole.rows, cols: whole.cols, cells: whole.cells }, pageNumber }];
11284
+ if (!whole) return null;
11285
+ if (whole.rows === t.rows && whole.cols === t.cols) {
11286
+ if (whole.renderAsTable) t.renderAsTable = true;
11287
+ return null;
11288
+ }
11289
+ return [{ type: "table", table: {
11290
+ ...t,
11291
+ rows: whole.rows,
11292
+ cols: whole.cols,
11293
+ cells: whole.cells,
11294
+ ...whole.renderAsTable ? { renderAsTable: true } : {}
11295
+ }, pageNumber }];
11217
11296
  }
11218
11297
  const out = [];
11219
11298
  if ((_a2 = t.captionBlocks) == null ? void 0 : _a2.length) out.push(...t.captionBlocks);
@@ -11264,63 +11343,6 @@ var init_layout_frames = __esm({
11264
11343
  }
11265
11344
  });
11266
11345
 
11267
- // .kordoc-source/src/page-range.ts
11268
- var page_range_exports = {};
11269
- __export(page_range_exports, {
11270
- hasRequestedPagesAfter: () => hasRequestedPagesAfter,
11271
- parsePageRange: () => parsePageRange
11272
- });
11273
- function parsePageRange(spec, maxPages) {
11274
- const result = /* @__PURE__ */ new Set();
11275
- if (maxPages <= 0) return result;
11276
- if (Array.isArray(spec)) {
11277
- for (const n of spec) {
11278
- const page = Math.round(n);
11279
- if (page >= 1 && page <= maxPages) result.add(page);
11280
- }
11281
- return result;
11282
- }
11283
- if (typeof spec !== "string" || spec.trim() === "") return result;
11284
- const parts = spec.split(",");
11285
- for (const part of parts) {
11286
- const trimmed = part.trim();
11287
- if (!trimmed) continue;
11288
- const rangeMatch = trimmed.match(/^(\d+)\s*-\s*(\d+)$/);
11289
- if (rangeMatch) {
11290
- const start = Math.max(1, parseInt(rangeMatch[1], 10));
11291
- const end = Math.min(maxPages, parseInt(rangeMatch[2], 10));
11292
- for (let i = start; i <= end; i++) result.add(i);
11293
- } else {
11294
- const page = parseInt(trimmed, 10);
11295
- if (!isNaN(page) && page >= 1 && page <= maxPages) result.add(page);
11296
- }
11297
- }
11298
- return result;
11299
- }
11300
- function hasRequestedPagesAfter(spec, maxParsed, total) {
11301
- if (total <= 0 || total <= maxParsed) return false;
11302
- const beyond = (page) => page >= 1 && page <= total && page > maxParsed;
11303
- if (Array.isArray(spec)) return spec.some((n) => beyond(Math.round(n)));
11304
- if (typeof spec !== "string" || spec.trim() === "") return false;
11305
- for (const part of spec.split(",")) {
11306
- const trimmed = part.trim();
11307
- if (!trimmed) continue;
11308
- const rangeMatch = trimmed.match(/^(\d+)\s*-\s*(\d+)$/);
11309
- if (rangeMatch) {
11310
- const start = Math.max(1, parseInt(rangeMatch[1], 10), Math.floor(maxParsed) + 1);
11311
- const end = Math.min(total, parseInt(rangeMatch[2], 10));
11312
- if (start <= end) return true;
11313
- } else if (beyond(parseInt(trimmed, 10))) return true;
11314
- }
11315
- return false;
11316
- }
11317
- var init_page_range = __esm({
11318
- ".kordoc-source/src/page-range.ts"() {
11319
- "use strict";
11320
- init_cjs_shims();
11321
- }
11322
- });
11323
-
11324
11346
  // node_modules/@xmldom/xmldom/lib/conventions.js
11325
11347
  var require_conventions = __commonJS({
11326
11348
  "node_modules/@xmldom/xmldom/lib/conventions.js"(exports2) {
@@ -17379,7 +17401,7 @@ var require_dom_parser = __commonJS({
17379
17401
  function normalizeLineEndings(input) {
17380
17402
  return input.replace(/\r[\n\u0085]/g, "\n").replace(/[\r\u0085\u2028\u2029]/g, "\n");
17381
17403
  }
17382
- function DOMParser6(options) {
17404
+ function DOMParser7(options) {
17383
17405
  options = options || {};
17384
17406
  if (options.locator === void 0) {
17385
17407
  options.locator = true;
@@ -17396,7 +17418,7 @@ var require_dom_parser = __commonJS({
17396
17418
  this.locator = !!options.locator;
17397
17419
  this.xmlns = this.assign(/* @__PURE__ */ Object.create(null), options.xmlns);
17398
17420
  }
17399
- DOMParser6.prototype.parseFromString = function(source, mimeType) {
17421
+ DOMParser7.prototype.parseFromString = function(source, mimeType) {
17400
17422
  if (!isValidMimeType(mimeType)) {
17401
17423
  throw new TypeError('DOMParser.parseFromString: the provided mimeType "' + mimeType + '" is not valid.');
17402
17424
  }
@@ -17618,7 +17640,7 @@ var require_dom_parser = __commonJS({
17618
17640
  throw "onWarningStopParsing";
17619
17641
  }
17620
17642
  exports2.__DOMHandler = DOMHandler;
17621
- exports2.DOMParser = DOMParser6;
17643
+ exports2.DOMParser = DOMParser7;
17622
17644
  exports2.normalizeLineEndings = normalizeLineEndings;
17623
17645
  exports2.onErrorStopParsing = onErrorStopParsing;
17624
17646
  exports2.onWarningStopParsing = onWarningStopParsing;
@@ -23252,7 +23274,7 @@ function isTableOfContents(table3) {
23252
23274
  const texts = row.map((cell2) => cell2.text.trim());
23253
23275
  const last = texts[texts.length - 1];
23254
23276
  if (!last) continue;
23255
- if (!PAGE_LABEL.test(last)) return false;
23277
+ if (!PAGE_LABEL2.test(last)) return false;
23256
23278
  if (/\p{L}/u.test(texts.slice(0, -1).join(""))) entries++;
23257
23279
  labels.push(last);
23258
23280
  }
@@ -23332,19 +23354,21 @@ function isExamLayoutTable(table3) {
23332
23354
  const layout2 = texts.filter((text2) => /\$|[①-⑤]|문\d+)/.test(text2) || !/[\p{L}\p{N}]/u.test(text2)).length;
23333
23355
  return layout2 >= texts.length * 0.6;
23334
23356
  }
23335
- var TOC_BLOCKS, PAGE_LABEL, NUMERIC_CELL;
23357
+ var TOC_BLOCKS, PAGE_LABEL2, NUMERIC_CELL;
23336
23358
  var init_table_roles = __esm({
23337
23359
  ".kordoc-source/src/pdf/table-roles.ts"() {
23338
23360
  "use strict";
23339
23361
  init_cjs_shims();
23340
23362
  TOC_BLOCKS = /* @__PURE__ */ new WeakSet();
23341
- PAGE_LABEL = /^(?:\d{1,4}|[ivxlc]{1,7})$/i;
23363
+ PAGE_LABEL2 = /^(?:\d{1,4}|[ivxlc]{1,7})$/i;
23342
23364
  NUMERIC_CELL = /^[\s\d.,%()+\-–−$€£¥]*\d[\s\d.,%()+\-–−$€£¥]*$/;
23343
23365
  }
23344
23366
  });
23345
23367
 
23346
23368
  // .kordoc-source/src/pdf/cluster-detector.ts
23347
23369
  function detectClusterTables(items, pageNum, rejected) {
23370
+ const tab = sideTabGlyphs(items);
23371
+ if (tab.size) items = items.filter((i) => !tab.has(i));
23348
23372
  if (items.length < MIN_ROWS * MIN_COLS) return [];
23349
23373
  const { merged, originMap } = mergeEvenSpacedClusters(items);
23350
23374
  const rows = mergeOverlappingRows(groupByBaseline(merged));
@@ -23404,6 +23428,35 @@ function detectClusterTables(items, pageNum, rejected) {
23404
23428
  return !prose;
23405
23429
  });
23406
23430
  }
23431
+ function sideTabGlyphs(items) {
23432
+ const found = /* @__PURE__ */ new Set();
23433
+ const singles = items.filter((i) => i.fontSize > 0 && [...i.text.trim()].length === 1);
23434
+ if (singles.length < SIDE_TAB_MIN) return found;
23435
+ const cols = [];
23436
+ for (const it of [...singles].sort((a, b) => a.x - b.x)) {
23437
+ const c = cols.find((col) => Math.abs(col[0].x - it.x) <= Math.max(1.5, it.fontSize * 0.25));
23438
+ if (c) c.push(it);
23439
+ else cols.push([it]);
23440
+ }
23441
+ for (const col of cols) {
23442
+ if (col.length < SIDE_TAB_MIN) continue;
23443
+ if (col.filter((g4) => /[\p{L}\p{N}]/u.test(g4.text)).length < col.length * 0.8) continue;
23444
+ col.sort((a, b) => b.y - a.y);
23445
+ const fs = [...col.map((i) => i.fontSize)].sort((a, b) => a - b)[col.length >> 1];
23446
+ if (col.slice(1).some((it, k) => col[k].y - it.y > fs * 3)) continue;
23447
+ const members = new Set(col);
23448
+ const top = col[0].y + fs, bottom = col[col.length - 1].y - fs;
23449
+ const others = items.filter((i) => !members.has(i) && i.y <= top && i.y >= bottom);
23450
+ const left = Math.min(...col.map((i) => i.x)), right = Math.max(...col.map((i) => i.x + i.w));
23451
+ const rest = items.filter((i) => !members.has(i) && i.text.trim());
23452
+ const outside = rest.every((i) => i.x >= right + fs) || rest.every((i) => i.x + i.w <= left - fs);
23453
+ if (!outside) continue;
23454
+ const alone = col.filter((g4) => !others.some((i) => Math.abs(i.y - g4.y) <= Y_TOL)).length;
23455
+ if (alone < col.length * 0.4) continue;
23456
+ for (const g4 of col) found.add(g4);
23457
+ }
23458
+ return found;
23459
+ }
23407
23460
  function detectCompactStatisticalTables(rows, pageNum) {
23408
23461
  const found = [];
23409
23462
  const parts = /* @__PURE__ */ new Map();
@@ -24121,7 +24174,7 @@ function joinCellItems(items) {
24121
24174
  return s;
24122
24175
  }).join(" ");
24123
24176
  }
24124
- var Y_TOL, COL_CLUSTER_TOL, MIN_ROWS, MIN_COLS, MIN_GAP_FACTOR, MIN_GAP_ABSOLUTE, MIN_COL_FILL_RATIO;
24177
+ var Y_TOL, COL_CLUSTER_TOL, MIN_ROWS, MIN_COLS, MIN_GAP_FACTOR, MIN_GAP_ABSOLUTE, MIN_COL_FILL_RATIO, SIDE_TAB_MIN;
24125
24178
  var init_cluster_detector = __esm({
24126
24179
  ".kordoc-source/src/pdf/cluster-detector.ts"() {
24127
24180
  "use strict";
@@ -24136,6 +24189,7 @@ var init_cluster_detector = __esm({
24136
24189
  MIN_GAP_FACTOR = 2;
24137
24190
  MIN_GAP_ABSOLUTE = 20;
24138
24191
  MIN_COL_FILL_RATIO = 0.4;
24192
+ SIDE_TAB_MIN = 6;
24139
24193
  }
24140
24194
  });
24141
24195
 
@@ -24386,7 +24440,9 @@ function findVerticalCutWithOutlierFilter(items, minGap) {
24386
24440
  const filtered = items.filter((i) => i.w >= narrowThreshold);
24387
24441
  if (filtered.length >= 2 && filtered.length < items.length && filtered.length >= items.length * 0.7) {
24388
24442
  const filteredCut = findVerticalCut(filtered);
24389
- if (filteredCut.gap > edgeCut.gap && filteredCut.gap >= minGap) {
24443
+ const sameRow = (a, b) => Math.abs(a.y - b.y) <= Math.max(a.fontSize, b.fontSize) * 0.5;
24444
+ const inLine = items.some((r) => r.w < narrowThreshold && r.x < filteredCut.position && r.x + r.w > filteredCut.position && filtered.some((o) => sameRow(o, r) && o.x + o.w <= r.x + 1) && filtered.some((o) => sameRow(o, r) && o.x >= r.x + r.w - 1));
24445
+ if (filteredCut.gap > edgeCut.gap && filteredCut.gap >= minGap && !inLine) {
24390
24446
  return filteredCut;
24391
24447
  }
24392
24448
  }
@@ -26777,6 +26833,87 @@ var init_text_box_table = __esm({
26777
26833
  }
26778
26834
  });
26779
26835
 
26836
+ // .kordoc-source/src/pdf/side-tabs.ts
26837
+ function isSideTabTable(box, table3, others, pageWidth, pageHeight) {
26838
+ if (table3.cols !== 1 || box.x2 - box.x1 > pageWidth * BAND || box.y2 - box.y1 < pageHeight * TAB_MIN_HEIGHT) return false;
26839
+ const side = box.x1 >= pageWidth * (1 - BAND) ? "R" : box.x2 <= pageWidth * BAND ? "L" : null;
26840
+ if (!side) return false;
26841
+ const texts = table3.cells.flat().map((c) => c.text.replace(/\s+/g, ""));
26842
+ if (!texts.some(Boolean) || texts.some((t) => [...t].length > TAB_CELL_CHARS)) return false;
26843
+ return others.every((it) => it.y < box.y1 || it.y > box.y2 || (side === "R" ? it.x + it.w <= box.x1 + 1 : it.x >= box.x2 - 1));
26844
+ }
26845
+ function removeSideTabs(blocks, pageWidths) {
26846
+ var _a2, _b, _c, _d, _e;
26847
+ const edges = /* @__PURE__ */ new Map();
26848
+ for (const b of blocks) {
26849
+ if (!b.bbox || b.pageNumber === void 0 || [...(_b = (_a2 = b.text) == null ? void 0 : _a2.trim()) != null ? _b : ""].length <= MAX_CHARS) continue;
26850
+ const e = (_c = edges.get(b.pageNumber)) != null ? _c : { lefts: [], rights: [] };
26851
+ e.lefts.push(b.bbox.x);
26852
+ e.rights.push(b.bbox.x + b.bbox.width);
26853
+ edges.set(b.pageNumber, e);
26854
+ }
26855
+ const q = (xs, p) => {
26856
+ const v = [...xs].sort((a, b) => a - b);
26857
+ return v[Math.min(v.length - 1, Math.floor(p * v.length))];
26858
+ };
26859
+ const body = /* @__PURE__ */ new Map();
26860
+ for (const [page, e] of edges) body.set(page, { left: q(e.lefts, 0.2), right: q(e.rights, 0.8) });
26861
+ const all = [...body.values()];
26862
+ const fallback = all.length ? { left: q(all.map((e) => e.left), 0.5), right: q(all.map((e) => e.right), 0.5) } : void 0;
26863
+ const key = (b) => {
26864
+ var _a3, _b2;
26865
+ const w = b.pageNumber !== void 0 ? pageWidths.get(b.pageNumber) : void 0;
26866
+ const text2 = (_a3 = b.text) == null ? void 0 : _a3.trim();
26867
+ const area = (_b2 = b.pageNumber !== void 0 ? body.get(b.pageNumber) : void 0) != null ? _b2 : fallback;
26868
+ if (b.type === "table") {
26869
+ if (!w || !b.bbox || !b.table || !SIDE_TAB_TABLES.has(b.table)) return null;
26870
+ return `${b.bbox.x >= w * (1 - BAND) ? "R" : "L"}${Math.round(b.bbox.x / 8)}`;
26871
+ }
26872
+ if (!w || !area || !b.bbox || !text2 || [...text2].length > MAX_CHARS) return null;
26873
+ const side = b.bbox.x + b.bbox.width <= Math.min(w * BAND, area.left - 1) ? "L" : b.bbox.x >= Math.max(w * (1 - BAND), area.right + 1) ? "R" : null;
26874
+ return side && text2.replace(/\s+/g, "");
26875
+ };
26876
+ const pages = /* @__PURE__ */ new Map();
26877
+ for (const b of blocks) {
26878
+ const k = key(b);
26879
+ if (k) pages.set(k, ((_d = pages.get(k)) != null ? _d : /* @__PURE__ */ new Set()).add(b.pageNumber));
26880
+ }
26881
+ const running = /* @__PURE__ */ new Set();
26882
+ for (const [k, ps] of pages) {
26883
+ const list2 = [...ps].sort((a, b) => a - b);
26884
+ const steps = list2.slice(1).map((p, i) => p - list2[i]).sort((a, b) => a - b);
26885
+ const gap = Math.max(RUN_GAP, ((_e = steps[steps.length >> 1]) != null ? _e : 1) * 3);
26886
+ let run = [];
26887
+ const flush = () => {
26888
+ if (run.length >= MIN_REPEAT && run.length >= (run[run.length - 1] - run[0] + 1) * 0.4) for (const p of run) running.add(`${p}\0${k}`);
26889
+ run = [];
26890
+ };
26891
+ for (const p of list2) {
26892
+ if (run.length && p - run[run.length - 1] > gap) flush();
26893
+ run.push(p);
26894
+ }
26895
+ flush();
26896
+ }
26897
+ return running.size ? blocks.filter((b) => {
26898
+ const k = key(b);
26899
+ return !k || !running.has(`${b.pageNumber}\0${k}`);
26900
+ }) : blocks;
26901
+ }
26902
+ var BAND, MAX_CHARS, MIN_REPEAT, RUN_GAP, TAB_CELL_CHARS, TAB_MIN_HEIGHT, SIDE_TAB_TABLES;
26903
+ var init_side_tabs = __esm({
26904
+ ".kordoc-source/src/pdf/side-tabs.ts"() {
26905
+ "use strict";
26906
+ init_cjs_shims();
26907
+ BAND = 0.12;
26908
+ MAX_CHARS = 10;
26909
+ MIN_REPEAT = 3;
26910
+ RUN_GAP = 5;
26911
+ TAB_CELL_CHARS = 24;
26912
+ TAB_MIN_HEIGHT = 0.3;
26913
+ SIDE_TAB_TABLES = /* @__PURE__ */ new WeakSet();
26914
+ }
26915
+ });
26916
+
26780
26917
  // .kordoc-source/src/pdf/page-regions.ts
26781
26918
  function splitTwoColumnProse(items, cutX) {
26782
26919
  const left = [];
@@ -27124,6 +27261,11 @@ function extractPageBlocksWithLines(items, pageNum, opList, pageWidth, pageHeigh
27124
27261
  if (carry) carry.clip = void 0;
27125
27262
  return [];
27126
27263
  }
27264
+ const tab = sideTabGlyphs(items);
27265
+ if (tab.size) {
27266
+ const glyphs = [...tab].sort((a, b) => b.y - a.y).map((g4) => ({ type: "paragraph", text: g4.text.trim(), pageNumber: pageNum, bbox: computeBBox([g4], pageNum), style: dominantStyle([g4]) }));
27267
+ return [...glyphs, ...extractPageBlocksWithLines(items.filter((i) => !tab.has(i)), pageNum, opList, pageWidth, pageHeight, extraLines, detectTables, carry, lexicon)];
27268
+ }
27127
27269
  const lex = lexicon != null ? lexicon : new WrapLexicon();
27128
27270
  for (const line of streamLines(items)) lex.addLine(mergeLineSimple(line));
27129
27271
  const extracted = extractLines(opList.fnArray, opList.argsArray);
@@ -27293,7 +27435,7 @@ function buildFrameCellBlocks(cellItems, nested, pageNum, wrap) {
27293
27435
  const tables = [...nested].sort((a, b) => b.bbox.y + b.bbox.height - (a.bbox.y + a.bbox.height));
27294
27436
  const blocks = [];
27295
27437
  let rest = [...cellItems];
27296
- const pushParagraphs = (items) => {
27438
+ const pushParagraphs2 = (items) => {
27297
27439
  if (items.length === 0) return;
27298
27440
  for (const line of cleanCellText(cellTextToString(items, wrap)).split("\n")) {
27299
27441
  const t = line.trim();
@@ -27302,11 +27444,11 @@ function buildFrameCellBlocks(cellItems, nested, pageNum, wrap) {
27302
27444
  };
27303
27445
  for (const tb of tables) {
27304
27446
  const bottom = tb.bbox.y;
27305
- pushParagraphs(rest.filter((it) => it.y >= bottom));
27447
+ pushParagraphs2(rest.filter((it) => it.y >= bottom));
27306
27448
  rest = rest.filter((it) => it.y < bottom);
27307
27449
  blocks.push(tb);
27308
27450
  }
27309
- pushParagraphs(rest);
27451
+ pushParagraphs2(rest);
27310
27452
  const text2 = blocks.map((b) => {
27311
27453
  var _a2;
27312
27454
  return b.type === "table" && b.table ? b.table.cells.flat().map((c) => c.text).filter(Boolean).join("\n") : (_a2 = b.text) != null ? _a2 : "";
@@ -27481,6 +27623,12 @@ function extractBlocksWithGrids(items, pageNum, pageWidth, pageHeight, grids, ho
27481
27623
  const emptyPart = !hasContent2 && !!grid.cells && !grid.clipParent && !nestedAttached;
27482
27624
  if (!hasContent2 && !emptyPart) continue;
27483
27625
  if (emptyPart) EMPTY_PARTS.add(irTable);
27626
+ const ownItems = numCols === 1 ? new Set(tableItems) : null;
27627
+ if (ownItems && isSideTabTable(grid.bbox, irTable, items.filter((it) => !ownItems.has(it)), pageWidth, pageHeight)) {
27628
+ SIDE_TAB_TABLES.add(irTable);
27629
+ blocks.push({ type: "table", table: irTable, pageNumber: pageNum, bbox: { page: pageNum, x: grid.bbox.x1, y: grid.bbox.y1, width: gridW, height: grid.bbox.y2 - grid.bbox.y1 } });
27630
+ continue;
27631
+ }
27484
27632
  if (grid.clipParent) {
27485
27633
  const nb = { page: pageNum, x: grid.bbox.x1, y: grid.bbox.y1, width: grid.bbox.x2 - grid.bbox.x1, height: grid.bbox.y2 - grid.bbox.y1 };
27486
27634
  pendingNested.push({ parent: grid.clipParent, block: { type: "table", table: irTable, pageNumber: pageNum, bbox: nb } });
@@ -27988,6 +28136,7 @@ var init_page_blocks = __esm({
27988
28136
  init_local_regions();
27989
28137
  init_paragraph_lines();
27990
28138
  init_table_roles();
28139
+ init_side_tabs();
27991
28140
  init_page_regions();
27992
28141
  STRIKE_MAX_THICKNESS = 2;
27993
28142
  STRIKE_MAX_THICKNESS_RATIO = 0.25;
@@ -29296,6 +29445,15 @@ function filledToBottom(U, bottom) {
29296
29445
  const lu = U[U.length - 1];
29297
29446
  return lu.y - bottom < (U[0].y - lu.y) / (U.length - 1) + FILL_SLACK * (lu.h || 10);
29298
29447
  }
29448
+ function nextItemHead(prev, next) {
29449
+ const a = ITEM_MARK.exec(prev), b = ITEM_MARK.exec(next);
29450
+ if (!a || !b) return false;
29451
+ const succ = (x, y) => /^\d+$/.test(x) ? /^\d+$/.test(y) && Number(y) === Number(x) + 1 : KO_ITEMS.indexOf(x) >= 0 && KO_ITEMS.indexOf(y) === KO_ITEMS.indexOf(x) + 1;
29452
+ if (a[1] && b[1]) return succ(a[1], b[1]);
29453
+ if (a[2] && b[2]) return succ(a[2], b[2]) && prev.trimStart()[a[2].length] === next.trimStart()[b[2].length];
29454
+ if (a[3] && b[3]) return succ(a[3], b[3]);
29455
+ return false;
29456
+ }
29299
29457
  function continuesAcross(u, d, x1, x2) {
29300
29458
  const U = CELL_LINES.get(u), D = CELL_LINES.get(d);
29301
29459
  if (!(U == null ? void 0 : U.length) || !(D == null ? void 0 : D.length)) return false;
@@ -29424,6 +29582,11 @@ function mergeSplitRow(table3, owner, first, colXs, textOnly = false, cut = NO_C
29424
29582
  if (!carriedSplit) {
29425
29583
  const norm2 = (c) => flowText(c.text).replace(/\s+/g, "");
29426
29584
  if (pairs.some(([u, d]) => hasContent(d.cell) && norm2(cell2(d)) !== norm2(cell2(u)) && lineEnded(cell2(u), colXs[u.c], colXs[u.c + u.cs], cell2(d)))) return false;
29585
+ const oneLine = (c) => {
29586
+ var _a2;
29587
+ return ((_a2 = CELL_LINES.get(c)) == null ? void 0 : _a2.length) === 1;
29588
+ };
29589
+ if (pairs.some(([u, d]) => nextItemHead(cell2(u).text, cell2(d).text)) && pairs.some(([u, d]) => hasContent(u.cell) && hasContent(d.cell) && oneLine(cell2(u)) && oneLine(cell2(d)) && norm2(cell2(u)) !== norm2(cell2(d)))) return false;
29427
29590
  const flows = ([u, d]) => continuesAcross(cell2(u), cell2(d), colXs[u.c], colXs[u.c + u.cs]) || clauseContinues(cell2(u), cell2(d));
29428
29591
  if (!(cut.open && !newCell)) {
29429
29592
  if (pairs.some((p) => p[1].rs > 1 && !flows(p))) return false;
@@ -29747,7 +29910,7 @@ function shiftedSame(px, cx, allowShift = true) {
29747
29910
  const dx = allowShift ? px[px.length - 1] - cx[cx.length - 1] : 0;
29748
29911
  return px.every((x, k) => Math.abs(x - cx[k] - dx) <= CONTINUATION_COL_TOL);
29749
29912
  }
29750
- var flowText, PART_COL_TOL, PART_COL_SNAP, indexOf, rowText, hasText, FULL_LINE_TOL, FULL_LINE_MIN_FRAC, FULL_LINE_EDGE_MIN, SINGLE_LINE_WORD_GAP, SHORT_LINE_GAP, STRADDLE_MAX_LINES, STRADDLE_BOTTOM, STRADDLE_BOTTOM_ONE_ROW, FILL_SLACK, CARRIED_MIN_COL_W, LABEL_ROOM, HANGING_MIN, HANGING_TOL, OUTLINE_HEAD, OUTLINE_ITEM, hasContent, CLAUSE_OPEN_ENDING, batchim, KO_ORDER, NO_CUT, NEIGHBOR_TABLE_EPSILON, PAGE_NUMBER_TEXT, ANNEX_HEAD_RE, CONTINUATION_COL_TOL, FOREIGN_FIRST_ROW_CELLS, PAGE_EDGE_BAND, RESTART_MIN_ANCHORS, TITLE_ROW_MAX_CHARS, RESTART_LOOKBACK_PAGES;
29913
+ var flowText, PART_COL_TOL, PART_COL_SNAP, indexOf, rowText, hasText, FULL_LINE_TOL, FULL_LINE_MIN_FRAC, FULL_LINE_EDGE_MIN, SINGLE_LINE_WORD_GAP, SHORT_LINE_GAP, STRADDLE_MAX_LINES, STRADDLE_BOTTOM, STRADDLE_BOTTOM_ONE_ROW, FILL_SLACK, CARRIED_MIN_COL_W, LABEL_ROOM, HANGING_MIN, HANGING_TOL, KO_ITEMS, ITEM_MARK, OUTLINE_HEAD, OUTLINE_ITEM, hasContent, CLAUSE_OPEN_ENDING, batchim, KO_ORDER, NO_CUT, NEIGHBOR_TABLE_EPSILON, PAGE_NUMBER_TEXT, ANNEX_HEAD_RE, CONTINUATION_COL_TOL, FOREIGN_FIRST_ROW_CELLS, PAGE_EDGE_BAND, RESTART_MIN_ANCHORS, TITLE_ROW_MAX_CHARS, RESTART_LOOKBACK_PAGES;
29751
29914
  var init_table_parts = __esm({
29752
29915
  ".kordoc-source/src/pdf/table-parts.ts"() {
29753
29916
  "use strict";
@@ -29786,6 +29949,8 @@ var init_table_parts = __esm({
29786
29949
  LABEL_ROOM = 1.5;
29787
29950
  HANGING_MIN = 0.5;
29788
29951
  HANGING_TOL = 1;
29952
+ KO_ITEMS = "\uAC00\uB098\uB2E4\uB77C\uB9C8\uBC14\uC0AC\uC544\uC790\uCC28\uCE74\uD0C0\uD30C\uD558\uAC70\uB108\uB354\uB7EC\uBA38\uBC84\uC11C\uC5B4\uC800\uCC98\uCEE4\uD130\uD37C\uD5C8\uACE0\uB178\uB3C4\uB85C\uBAA8\uBCF4\uC18C\uC624\uC870\uCD08\uCF54\uD1A0\uD3EC\uD638\uAD6C\uB204\uB450\uB8E8\uBB34\uBD80\uC218\uC6B0\uC8FC\uCD94\uCFE0\uD22C\uD478\uD6C4";
29953
+ ITEM_MARK = /^\s*(?:([가-힣])\.|(\d{1,3})[.)]|\(([가-힣\d]{1,3})\))(?=\s)/;
29789
29954
  OUTLINE_HEAD = /^[□■]\s*\S/;
29790
29955
  OUTLINE_ITEM = /^[ㅇ○◦\-‐–·․‧※*]\s*\S/;
29791
29956
  hasContent = (cell2) => {
@@ -30871,70 +31036,6 @@ var init_two_up = __esm({
30871
31036
  }
30872
31037
  });
30873
31038
 
30874
- // .kordoc-source/src/pdf/side-tabs.ts
30875
- function removeSideTabs(blocks, pageWidths) {
30876
- var _a2, _b, _c, _d;
30877
- const edges = /* @__PURE__ */ new Map();
30878
- for (const b of blocks) {
30879
- if (!b.bbox || b.pageNumber === void 0 || [...(_b = (_a2 = b.text) == null ? void 0 : _a2.trim()) != null ? _b : ""].length <= MAX_CHARS) continue;
30880
- const e = (_c = edges.get(b.pageNumber)) != null ? _c : { lefts: [], rights: [] };
30881
- e.lefts.push(b.bbox.x);
30882
- e.rights.push(b.bbox.x + b.bbox.width);
30883
- edges.set(b.pageNumber, e);
30884
- }
30885
- const q = (xs, p) => {
30886
- const v = [...xs].sort((a, b) => a - b);
30887
- return v[Math.min(v.length - 1, Math.floor(p * v.length))];
30888
- };
30889
- const body = /* @__PURE__ */ new Map();
30890
- for (const [page, e] of edges) body.set(page, { left: q(e.lefts, 0.2), right: q(e.rights, 0.8) });
30891
- const all = [...body.values()];
30892
- const fallback = all.length ? { left: q(all.map((e) => e.left), 0.5), right: q(all.map((e) => e.right), 0.5) } : void 0;
30893
- const key = (b) => {
30894
- var _a3, _b2;
30895
- const w = b.pageNumber !== void 0 ? pageWidths.get(b.pageNumber) : void 0;
30896
- const text2 = (_a3 = b.text) == null ? void 0 : _a3.trim();
30897
- const area = (_b2 = b.pageNumber !== void 0 ? body.get(b.pageNumber) : void 0) != null ? _b2 : fallback;
30898
- if (!w || !area || !b.bbox || !text2 || b.type === "table" || [...text2].length > MAX_CHARS) return null;
30899
- const side = b.bbox.x + b.bbox.width <= Math.min(w * BAND, area.left - 1) ? "L" : b.bbox.x >= Math.max(w * (1 - BAND), area.right + 1) ? "R" : null;
30900
- return side && text2.replace(/\s+/g, "");
30901
- };
30902
- const pages = /* @__PURE__ */ new Map();
30903
- for (const b of blocks) {
30904
- const k = key(b);
30905
- if (k) pages.set(k, ((_d = pages.get(k)) != null ? _d : /* @__PURE__ */ new Set()).add(b.pageNumber));
30906
- }
30907
- const running = /* @__PURE__ */ new Set();
30908
- for (const [k, ps] of pages) {
30909
- const list2 = [...ps].sort((a, b) => a - b);
30910
- let run = [];
30911
- const flush = () => {
30912
- if (run.length >= MIN_REPEAT && run.length >= (run[run.length - 1] - run[0] + 1) * 0.4) for (const p of run) running.add(`${p}\0${k}`);
30913
- run = [];
30914
- };
30915
- for (const p of list2) {
30916
- if (run.length && p - run[run.length - 1] > RUN_GAP) flush();
30917
- run.push(p);
30918
- }
30919
- flush();
30920
- }
30921
- return running.size ? blocks.filter((b) => {
30922
- const k = key(b);
30923
- return !k || !running.has(`${b.pageNumber}\0${k}`);
30924
- }) : blocks;
30925
- }
30926
- var BAND, MAX_CHARS, MIN_REPEAT, RUN_GAP;
30927
- var init_side_tabs = __esm({
30928
- ".kordoc-source/src/pdf/side-tabs.ts"() {
30929
- "use strict";
30930
- init_cjs_shims();
30931
- BAND = 0.12;
30932
- MAX_CHARS = 10;
30933
- MIN_REPEAT = 3;
30934
- RUN_GAP = 5;
30935
- }
30936
- });
30937
-
30938
31039
  // .kordoc-source/src/pdf/footnotes.ts
30939
31040
  function footnoteSeparators(horizontals, pageWidth, pageHeight) {
30940
31041
  return horizontals.filter((l) => l.x2 - l.x1 >= 30 && l.x2 - l.x1 <= pageWidth * 0.45 && l.y1 < pageHeight * 0.6).map((l) => l.y1);
@@ -32621,6 +32722,7 @@ async function parsePdfDocument(buffer, options) {
32621
32722
  if (!faceNames.has(face)) faceNames.set(face, ((_c = (_b = fontObj(face)) == null ? void 0 : _b.name) != null ? _c : "").replace(/^[A-Z]{6}\+/, ""));
32622
32723
  }
32623
32724
  for (const it of visible) if (it.text.includes("$")) it.text = escapeLiteralDollar(it.text);
32725
+ for (const it of visible) if (it.text.includes("<")) it.text = escapeLiteralTags(it.text);
32624
32726
  wrapEquationRuns(visible, (face) => faceNames.get(face));
32625
32727
  const pageArea = pageW * pageH;
32626
32728
  if (pageArea > 0) {
@@ -33067,6 +33169,7 @@ __export(src_exports, {
33067
33169
  parseHwpx: () => parseHwpx,
33068
33170
  parseImage: () => parseImage,
33069
33171
  parsePdf: () => parsePdf,
33172
+ parsePptx: () => parsePptx,
33070
33173
  parseXls: () => parseXls,
33071
33174
  parseXlsx: () => parseXlsx,
33072
33175
  patchHwp: () => patchHwp,
@@ -33099,14 +33202,17 @@ init_script_tags();
33099
33202
  init_cjs_shims();
33100
33203
  init_script_tags();
33101
33204
  function toPlainMarkdown(md2) {
33102
- return plainScripts(md2).replace(/!\[[^\]\n]*\]\([^)\n]*\)/g, "").replace(/<img\b[^>]*>/gi, "").replace(/(?<!!)\[([^\]\n]*)\]\((?:https?|mailto|ftp):[^)\s]*\)/g, "$1").replace(/<\/?u>/g, "").replace(/(?<!\\)\*\*(?=\S)([^\n]*?\S)(?<!\\)\*\*/g, "$1").replace(/(<br>)+(?=<\/t[dh]>)/g, "").replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
33205
+ return plainScripts(md2).replace(/!\[[^\]\n]*\]\([^)\n]*\)/g, "").replace(/<img\b[^>]*>/gi, "").replace(/(?<!!)\[([^\]\n]*)\]\((?:https?|mailto|ftp):[^)\s]*\)/g, "$1").replace(/(?<!\\)<\/?u>/g, "").replace(/(?<!\\)\*\*(?=\S)([^\n]*?\S)(?<!\\)\*\*/g, "$1").replace(/(<br>)+(?=<\/t[dh]>)/g, "").replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
33103
33206
  }
33104
33207
 
33208
+ // .kordoc-source/src/index.ts
33209
+ init_page_range();
33210
+
33105
33211
  // .kordoc-source/src/html-tables.ts
33106
33212
  init_cjs_shims();
33107
33213
  var TABLE_TAG = /(<\/?(?:table|tr|th|td)\b[^>]*>)/i;
33108
33214
  function pipeCellToHtml(cell2) {
33109
- return cell2.split(/(<br>|<\/?(?:u|sup|sub)>|<img\b[^>]*>)/).map((part, i) => i % 2 ? part : part.replace(/\\([\\`*_{}[\]()#+\-.!|~<>$])/g, "$1").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")).join("");
33215
+ return cell2.split(/(<br>|(?<!\\)<\/?(?:u|sup|sub)>|<img\b[^>]*>)/).map((part, i) => i % 2 ? part : part.replace(/\\([\\`*_{}[\]()#+\-.!|~<>$])/g, "$1").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")).join("");
33110
33216
  }
33111
33217
  function splitPipeRow(line) {
33112
33218
  const t = line.trim().replace(/^\|/, "").replace(/(?<!\\)\|$/, "");
@@ -33651,7 +33757,8 @@ function createSectionShared() {
33651
33757
  numState: /* @__PURE__ */ new Map(),
33652
33758
  pageText: { headers: [], footers: [] },
33653
33759
  track: { deleteDepth: 0, warned: false, deletedObjects: /* @__PURE__ */ new WeakSet(), deletedImageRefs: /* @__PURE__ */ new Set() },
33654
- pageState: { base: 0, allUsable: true }
33760
+ pageState: { base: 0, allUsable: true },
33761
+ tocTexts: /* @__PURE__ */ new Set()
33655
33762
  };
33656
33763
  }
33657
33764
  function createXmlParser(warnings) {
@@ -33763,6 +33870,24 @@ async function decryptHwpxInPlace(zip, manifestXml, password) {
33763
33870
  init_cjs_shims();
33764
33871
  init_utils();
33765
33872
  init_types();
33873
+
33874
+ // .kordoc-source/src/toc-entry.ts
33875
+ init_cjs_shims();
33876
+ var TOC_LEADER = "";
33877
+ var LEADERS = /\x1F/g;
33878
+ var PAGE_LABEL = /^(?:\d{1,4}|[ivxlc]{1,7}|\d{1,3}\s*[-–]\s*\d{1,4}|[-–]\s*\d{1,4}\s*[-–])$/i;
33879
+ var TOC_ENTRY_BLOCKS = /* @__PURE__ */ new WeakSet();
33880
+ function takeTocLeaders(text2) {
33881
+ if (!text2.includes(TOC_LEADER)) return { text: text2, tocEntry: false };
33882
+ const lines = text2.replace(/\x1E/g, "").split("\n").filter((l) => l.trim());
33883
+ const tocEntry = lines.length > 0 && lines.every((l) => {
33884
+ const at = l.lastIndexOf(TOC_LEADER);
33885
+ return at > 0 && /\S/.test(l.slice(0, at).replace(LEADERS, "")) && PAGE_LABEL.test(l.slice(at + 1).trim());
33886
+ });
33887
+ return { text: text2.replace(LEADERS, " "), tocEntry };
33888
+ }
33889
+
33890
+ // .kordoc-source/src/hwpx/styles.ts
33766
33891
  function isRealStrikeShape(shape) {
33767
33892
  switch (shape) {
33768
33893
  case "SOLID":
@@ -33996,7 +34121,7 @@ function parseParaHeadings(doc, map2) {
33996
34121
  if (map2.size > 0) break;
33997
34122
  }
33998
34123
  }
33999
- function detectHwpxHeadings(blocks, styleMap) {
34124
+ function detectHwpxHeadings(blocks, styleMap, tocTexts) {
34000
34125
  var _a2, _b;
34001
34126
  if (blocks.some((b) => b.type === "heading")) return;
34002
34127
  let baseFontSize = 0;
@@ -34014,7 +34139,7 @@ function detectHwpxHeadings(blocks, styleMap) {
34014
34139
  }
34015
34140
  }
34016
34141
  for (const block2 of blocks) {
34017
- if (block2.type !== "paragraph" || !block2.text) continue;
34142
+ if (block2.type !== "paragraph" || !block2.text || TOC_ENTRY_BLOCKS.has(block2) || (tocTexts == null ? void 0 : tocTexts.has(block2.text.trim()))) continue;
34018
34143
  const text2 = block2.text.trim();
34019
34144
  if (text2.length === 0 || text2.length > 200 || /^\d+$/.test(text2)) continue;
34020
34145
  let level = 0;
@@ -35068,6 +35193,7 @@ function noteAutoNumOf(el) {
35068
35193
  init_cjs_shims();
35069
35194
  init_builder();
35070
35195
  init_script_tags();
35196
+ init_script_tags();
35071
35197
  var KORDOC_CHAR_CODE = "4";
35072
35198
  var KORDOC_PARA_QUOTE = "6";
35073
35199
  function spanModeOf(layout2) {
@@ -35100,7 +35226,7 @@ function extractRunSpans(para2, ctx, mode, requireMixed) {
35100
35226
  const tkids = rc.childNodes;
35101
35227
  for (let k = 0; k < ((_b = tkids == null ? void 0 : tkids.length) != null ? _b : 0); k++) {
35102
35228
  const tk = tkids[k];
35103
- if (tk.nodeType === 3 || tk.nodeType === 4) text2 += escapeLiteralDollar(tk.textContent || "");
35229
+ if (tk.nodeType === 3 || tk.nodeType === 4) text2 += escapeLiteralTags(escapeLiteralDollar(tk.textContent || ""));
35104
35230
  else if (tk.nodeType === 1) {
35105
35231
  const ttag = (tk.tagName || tk.localName || "").replace(/^[^:]+:/, "");
35106
35232
  if (ttag === "tab" || ttag === "fwSpace" || ttag === "hwSpace" || ttag === "nbSpace") text2 += " ";
@@ -35216,13 +35342,13 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
35216
35342
  }
35217
35343
  if (tableCtx) tableStack.push(tableCtx);
35218
35344
  const newTable = { rows: [], currentRow: [], cell: null, sourceId: (_a2 = el.getAttribute("id")) != null ? _a2 : void 0 };
35219
- walkSection(el, blocks, newTable, tableStack, ctx, depth + 1);
35345
+ inIndependentDeletionStory(ctx.shared.track, () => walkSection(el, blocks, newTable, tableStack, ctx, depth + 1));
35220
35346
  tableCtx = completeTable(newTable, tableStack, blocks, ctx);
35221
35347
  break;
35222
35348
  }
35223
35349
  // 표/도표 캡션 — IRTable.caption으로 보존 (v3.0, 기존 무음 드롭 수정)
35224
35350
  case "caption": {
35225
- const cap = collectSubListContent(el, ctx);
35351
+ const cap = inIndependentDeletionStory(ctx.shared.track, () => collectSubListContent(el, ctx));
35226
35352
  if (cap.text) {
35227
35353
  if (tableCtx) {
35228
35354
  tableCtx.caption = (tableCtx.caption ? tableCtx.caption + "\n" : "") + cap.text;
@@ -35275,13 +35401,16 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
35275
35401
  case "p": {
35276
35402
  const paraPg = (_e = ctx.paraPage) == null ? void 0 : _e.get(el);
35277
35403
  if (paraPg !== void 0 && ctx.pageBase !== void 0) ctx.page = ctx.pageBase + paraPg + 1;
35278
- const { text: rawText, href, footnote, style, segments, placeholderSpans } = extractParagraphInfo(el, ctx.styleMap, ctx);
35404
+ const { text: rawText, href, footnote, style, segments, placeholderSpans, tocEntry } = extractParagraphInfo(el, ctx.styleMap, ctx);
35279
35405
  let text2 = rawText;
35280
35406
  let headingLevel;
35281
35407
  const ph = resolveParaHeading(el, ctx);
35282
35408
  if (text2) {
35283
35409
  if (ph == null ? void 0 : ph.prefix) text2 = ph.prefix + " " + text2;
35284
- headingLevel = ph == null ? void 0 : ph.headingLevel;
35410
+ headingLevel = tocEntry ? void 0 : ph == null ? void 0 : ph.headingLevel;
35411
+ if (tocEntry) {
35412
+ for (const line of text2.split("\n")) if (line.trim()) ctx.shared.tocTexts.add(line.trim());
35413
+ }
35285
35414
  }
35286
35415
  if (segments) {
35287
35416
  const cell2 = (_f = tableCtx == null ? void 0 : tableCtx.cell) != null ? _f : null;
@@ -35344,6 +35473,7 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
35344
35473
  }
35345
35474
  const block2 = { type: headingLevel ? "heading" : "paragraph", text: text2, pageNumber: ctx.page };
35346
35475
  if (headingLevel) block2.level = headingLevel;
35476
+ if (tocEntry) TOC_ENTRY_BLOCKS.add(block2);
35347
35477
  if (style) block2.style = style;
35348
35478
  if (href) block2.href = href;
35349
35479
  if (footnote) block2.footnoteText = footnote;
@@ -35367,6 +35497,15 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
35367
35497
  if (spanMode !== "foreign" && el.getAttribute("paraPrIDRef") === KORDOC_PARA_QUOTE) block2.quote = true;
35368
35498
  }
35369
35499
  if (!headingLevel && !block2.spans && placeholderSpans) block2.spans = withPrefixSpan(placeholderSpans, ph == null ? void 0 : ph.prefix);
35500
+ if (headingLevel && placeholderSpans) {
35501
+ const shown = withPrefixSpan(placeholderSpans.filter((s) => !s.placeholder), ph == null ? void 0 : ph.prefix).map((s) => s.text).join("").trim();
35502
+ if (shown) block2.text = shown;
35503
+ else {
35504
+ block2.type = "paragraph";
35505
+ delete block2.level;
35506
+ block2.spans = withPrefixSpan(placeholderSpans, ph == null ? void 0 : ph.prefix);
35507
+ }
35508
+ }
35370
35509
  blocks.push(block2);
35371
35510
  } else {
35372
35511
  blocks.push({ type: "paragraph", text: text2, pageNumber: ctx.page });
@@ -35612,10 +35751,10 @@ function walkParagraphChildren(node, blocks, tableCtx, tableStack, ctx, depth =
35612
35751
  }
35613
35752
  if (tableCtx) tableStack.push(tableCtx);
35614
35753
  const newTable = { rows: [], currentRow: [], cell: null, inline: isInlineTbl(el), sourceId: (_a2 = el.getAttribute("id")) != null ? _a2 : void 0 };
35615
- walkSection(el, blocks, newTable, tableStack, ctx, d + 1);
35754
+ inIndependentDeletionStory(ctx.shared.track, () => walkSection(el, blocks, newTable, tableStack, ctx, d + 1));
35616
35755
  tableCtx = completeTable(newTable, tableStack, blocks, ctx);
35617
35756
  } else if (localTag === "caption" && !inShape) {
35618
- const cap = collectSubListContent(el, ctx);
35757
+ const cap = inIndependentDeletionStory(ctx.shared.track, () => collectSubListContent(el, ctx));
35619
35758
  if (cap.text) {
35620
35759
  if (tableCtx == null ? void 0 : tableCtx.cell) mergeBlocksIntoCell(tableCtx.cell, [{ type: "paragraph", text: cap.text, pageNumber: ctx.page }]);
35621
35760
  else if (tableCtx) {
@@ -35786,7 +35925,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35786
35925
  const open = openFields.pop();
35787
35926
  if ((open == null ? void 0 : open.rangeIdx) !== void 0) linkRanges[open.rangeIdx].end = text2.length;
35788
35927
  if ((open == null ? void 0 : open.guide) !== void 0 && open.start !== void 0) {
35789
- const value = text2.slice(open.start).replace(/\\\$/g, "$");
35928
+ const value = text2.slice(open.start).replace(/\\([$<])/g, "$1");
35790
35929
  if (value && (value === open.guide || value.trimEnd() === open.guide)) {
35791
35930
  text2 = text2.slice(0, open.start) + PH_OPEN + text2.slice(open.start) + PH_CLOSE;
35792
35931
  }
@@ -35818,7 +35957,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35818
35957
  // 아니므로 방출하지 않는다
35819
35958
  case "header":
35820
35959
  case "footer": {
35821
- if (!ctx) break;
35960
+ if (!ctx || isInDeletedRange(ctx)) break;
35822
35961
  const t = collectSubListText(k, ctx);
35823
35962
  if (t && hasPageAutoNum(k) && !/\p{L}/u.test(t)) break;
35824
35963
  if (t) {
@@ -35883,7 +36022,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35883
36022
  }
35884
36023
  };
35885
36024
  const walk = (node, depth = 0) => {
35886
- var _a2, _b, _c;
36025
+ var _a2, _b, _c, _d;
35887
36026
  if (depth > MAX_XML_DEPTH) return;
35888
36027
  const children = node.childNodes;
35889
36028
  if (!children) return;
@@ -35897,7 +36036,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35897
36036
  (_a2 = ctx.warnings) == null ? void 0 : _a2.push({ page: ctx.page, message: "\uBCC0\uACBD\uCD94\uC801 \uC0AD\uC81C \uD14D\uC2A4\uD2B8 \uCD9C\uB825 \uC81C\uC678", code: "HIDDEN_TEXT_FILTERED" });
35898
36037
  }
35899
36038
  } else {
35900
- text2 += escapeLiteralDollar(t.replace(/\x1E/g, ""));
36039
+ text2 += escapeLiteralTags(escapeLiteralDollar(t.replace(/\x1E/g, "")));
35901
36040
  }
35902
36041
  continue;
35903
36042
  }
@@ -35917,8 +36056,9 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35917
36056
  // 점 채움을 탭 하나로 바꾸고 쪽 번호를 남기는 것과 같다). 종전엔 채움 탭 뒤를 쪽 번호로 보고 잘라, 목차 쪽 번호만이 아니라
35918
36057
  // 일정표 "사용자 의견조사 ····· '26년 8~9월"(gate-fill 36646162)의 일정, 줄바꿈 뒤 다음 목차 항목
35919
36058
  // "<참고2> 직종별사업체노동력조사 개요"(rhwp issue6044)까지 사라졌다
36059
+ // (채움 탭은 목차 항목 판정까지 TOC_LEADER 표지로 들고 가다 보통 탭으로 바꾼다 — toc-entry.ts)
35920
36060
  case "tab":
35921
- text2 += " ";
36061
+ text2 += /^(?:|0|NONE)$/i.test((_b = child.getAttribute("leader")) != null ? _b : "") ? " " : TOC_LEADER;
35922
36062
  break;
35923
36063
  case "br":
35924
36064
  if ((child.getAttribute("type") || "line") === "line") text2 += "\n";
@@ -35940,9 +36080,10 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35940
36080
  if (isInlineTbl(child)) text2 += "";
35941
36081
  break;
35942
36082
  // 양식 선택 상자·라디오 단추 — 한컴이 그리는 상자 기호와 캡션 글 (종전엔 통째로 빠졌다: form-002 "원천기술형"·서울 결재 "부분공개")
36083
+ // 지운 구간의 양식 단추·수식은 글처럼 내지 않는다 (최종본)
35943
36084
  case "checkBtn":
35944
36085
  case "radioBtn":
35945
- text2 += formButtonText(child, tag === "radioBtn");
36086
+ if (!isInDeletedRange(ctx)) text2 += formButtonText(child, tag === "radioBtn");
35946
36087
  break;
35947
36088
  // 하이퍼링크
35948
36089
  case "hyperlink": {
@@ -35964,7 +36105,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
35964
36105
  // 대체 표현 묶음 — 한컴은 지원하는 hp:case 하나만 그린다(차트, 없으면 hp:default 의 OLE).
35965
36106
  // 둘 다 순회하면 같은 캡션이 두 번 나온다 (1790387 [그림 5] 이중 방출)
35966
36107
  case "switch": {
35967
- const branch = (_b = findChildByLocalName(child, "case")) != null ? _b : findChildByLocalName(child, "default");
36108
+ const branch = (_c = findChildByLocalName(child, "case")) != null ? _c : findChildByLocalName(child, "default");
35968
36109
  if (branch) walk(branch, depth + 1);
35969
36110
  break;
35970
36111
  }
@@ -36012,6 +36153,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
36012
36153
  // 스크립트가 담겨 있음. hml-equation-parser 로 LaTeX 변환 후 `$...$`
36013
36154
  // 로 래핑. 실패/빈 스크립트면 무시 (대체 텍스트 누출 방지).
36014
36155
  case "equation": {
36156
+ if (isInDeletedRange(ctx)) break;
36015
36157
  const script = findChildByLocalName(child, "script");
36016
36158
  const raw = script ? extractTextFromNode(script) : "";
36017
36159
  if (raw.trim()) {
@@ -36036,7 +36178,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
36036
36178
  case "run": {
36037
36179
  const runCharPr = child.getAttribute("charPrIDRef");
36038
36180
  if (tag === "r" && runCharPr && !charPrId) charPrId = runCharPr;
36039
- const script = runCharPr ? (_c = styleMap == null ? void 0 : styleMap.charProperties.get(runCharPr)) == null ? void 0 : _c.script : void 0;
36181
+ const script = runCharPr ? (_d = styleMap == null ? void 0 : styleMap.charProperties.get(runCharPr)) == null ? void 0 : _d.script : void 0;
36040
36182
  const start = text2.length, nLinks = linkRanges.length, nOpen = openFields.length;
36041
36183
  walk(child, depth + 1);
36042
36184
  if (script && linkRanges.length === nLinks && openFields.length === nOpen && runHasOnlyText(child)) {
@@ -36065,6 +36207,9 @@ function extractParagraphInfo(para2, styleMap, ctx) {
36065
36207
  if (applied.length) href = void 0;
36066
36208
  }
36067
36209
  text2 = tidyScriptTags(text2);
36210
+ const toc = takeTocLeaders(text2);
36211
+ text2 = toc.text;
36212
+ const tocEntry = toc.tocEntry;
36068
36213
  const cleanParaText = (raw) => {
36069
36214
  let t = raw.replace(/[ \t]+/g, " ").trim();
36070
36215
  if (/^그림입니다\.?\s*원본\s*그림의\s*(이름|크기)/.test(t)) t = "";
@@ -36100,7 +36245,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
36100
36245
  if (!style.fontSize && !style.bold && !style.italic) style = void 0;
36101
36246
  }
36102
36247
  }
36103
- return { text: cleanText, href, footnote, style, segments, placeholderSpans };
36248
+ return { text: cleanText, href, footnote, style, segments, placeholderSpans, ...tocEntry ? { tocEntry } : {} };
36104
36249
  }
36105
36250
  function withPrefixSpan(spans, prefix) {
36106
36251
  return prefix ? [{ text: prefix + " " }, ...spans] : spans;
@@ -36313,6 +36458,11 @@ function parseDocInfo(records) {
36313
36458
  return { charShapes, paraShapes, styles, binData, numberings, bullets, borderEdges };
36314
36459
  }
36315
36460
  var LITERAL_DOLLAR_MARK = "\uFDD0";
36461
+ var LITERAL_LT_MARK = "\uFDD1";
36462
+ var LITERAL_LT_TAG = /\uFDD1(?=\/?(?:u|sup|sub)>)/g;
36463
+ function resolveLiteralLt(text2) {
36464
+ return text2.includes(LITERAL_LT_MARK) ? text2.replace(LITERAL_LT_TAG, "\\<").replaceAll(LITERAL_LT_MARK, "<") : text2;
36465
+ }
36316
36466
  function createParaTextState() {
36317
36467
  return { text: "", ctrlIdx: 0, fieldStack: [], fieldRanges: [] };
36318
36468
  }
@@ -36379,8 +36529,9 @@ function appendParaText(state, data, resolveControl) {
36379
36529
  // ── inline 타입 (2바이트 + 14바이트 확장) ──
36380
36530
  // 확장 u16[7] 중 [2] 의 하위 바이트 = 채움 모양(0 없음·3 점선 …), 상위 = 탭 종류+1 (rhwp tab_extended 실측).
36381
36531
  // 채움 탭도 보통 탭 — 채움선은 글이 아니고 뒤 글(목차 쪽 번호 등)은 남긴다 (HWPX section-walker "tab" 과 같은 정책)
36532
+ // 본문 파서(tocLeaders)는 목차 항목 판정까지 채움 탭을 TOC_LEADER 표지로 받는다 (#121)
36382
36533
  case CHAR_TAB:
36383
- result += " ";
36534
+ result += state.tocLeaders && i + 6 <= data.length && (data.readUInt16LE(i + 4) & 255) !== 0 ? TOC_LEADER : " ";
36384
36535
  if (i + 14 <= data.length) i += 14;
36385
36536
  break;
36386
36537
  default:
@@ -36413,7 +36564,7 @@ function appendParaText(state, data, resolveControl) {
36413
36564
  break;
36414
36565
  }
36415
36566
  }
36416
- result += ch === 36 && state.dollarMark ? LITERAL_DOLLAR_MARK : String.fromCharCode(ch);
36567
+ result += !state.dollarMark ? String.fromCharCode(ch) : ch === 36 ? LITERAL_DOLLAR_MARK : ch === 60 ? LITERAL_LT_MARK : String.fromCharCode(ch);
36417
36568
  }
36418
36569
  break;
36419
36570
  }
@@ -37073,7 +37224,7 @@ async function parseHwpxDocument(buffer, options) {
37073
37224
  applyPageText(blocks, shared);
37074
37225
  const images = await extractImagesFromZip(zip, blocks, decompressed, warnings, !(options == null ? void 0 : options.pages), shared.track.deletedImageRefs);
37075
37226
  const shown = (options == null ? void 0 : options.layoutTables) === "keep" ? blocks : unframeLayoutTables(blocks, !!(options == null ? void 0 : options.keepTrailingEmptyCols));
37076
- detectHwpxHeadings(shown, styleMap);
37227
+ detectHwpxHeadings(shown, styleMap, shared.tocTexts);
37077
37228
  const outline = shown.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
37078
37229
  const markdown = blocksToMarkdown(shown);
37079
37230
  return { markdown, blocks: shown, metadata, outline: outline.length > 0 ? outline : void 0, warnings: warnings.length > 0 ? warnings : void 0, images: images.length > 0 ? images : void 0 };
@@ -38318,6 +38469,7 @@ function emitParagraphBlocks(p) {
38318
38469
  pageNumber
38319
38470
  };
38320
38471
  if (p.headingLevel > 0) block2.level = p.headingLevel;
38472
+ if (p.tocEntry) TOC_ENTRY_BLOCKS.add(block2);
38321
38473
  if (style) {
38322
38474
  block2.style = style;
38323
38475
  if (style.strike || style.underline) block2.text = headMarker ? `${headMarker} ${decorate(trimmed)}` : decorate(trimmed);
@@ -38519,6 +38671,7 @@ function createHwp5DocState() {
38519
38671
  outlineNumberingId: 0,
38520
38672
  autoCounters: /* @__PURE__ */ new Map(),
38521
38673
  headerTexts: /* @__PURE__ */ new Set(),
38674
+ tocTexts: /* @__PURE__ */ new Set(),
38522
38675
  headerBlocks: [],
38523
38676
  footerBlocks: []
38524
38677
  };
@@ -38597,6 +38750,7 @@ function parseParagraph(records, start, end, ctx) {
38597
38750
  }
38598
38751
  const state = createParaTextState();
38599
38752
  state.dollarMark = true;
38753
+ state.tocLeaders = true;
38600
38754
  state.scriptAt = scriptLookup(charShapeRuns, ctx.docInfo);
38601
38755
  const resolver = (idx, id) => {
38602
38756
  var _a3;
@@ -38622,7 +38776,7 @@ function parseParagraph(records, start, end, ctx) {
38622
38776
  const anchor = text2.slice(r.start, r.end);
38623
38777
  if (ctrl.guide !== void 0) {
38624
38778
  if (ctx.doc.includeFieldPlaceholders) continue;
38625
- const plain4 = anchor.replaceAll(LITERAL_DOLLAR_MARK, "$");
38779
+ const plain4 = anchor.replaceAll(LITERAL_DOLLAR_MARK, "$").replaceAll(LITERAL_LT_MARK, "<");
38626
38780
  if (plain4 === ctrl.guide || plain4.trimEnd() === ctrl.guide) {
38627
38781
  text2 = text2.slice(0, r.start) + text2.slice(r.end);
38628
38782
  applied.push([r.start, r.end]);
@@ -38638,13 +38792,16 @@ function parseParagraph(records, start, end, ctx) {
38638
38792
  }
38639
38793
  }
38640
38794
  if (text2.includes(LITERAL_DOLLAR_MARK)) text2 = text2.replaceAll(LITERAL_DOLLAR_MARK, "\\$");
38795
+ text2 = resolveLiteralLt(text2);
38641
38796
  text2 = tidyScriptTags(text2);
38797
+ const toc = takeTocLeaders(text2);
38798
+ text2 = toc.text;
38642
38799
  let headingLevel = 0;
38643
38800
  let headMarker = null;
38644
38801
  const ps = ctx.docInfo && paraShapeId >= 0 && paraShapeId < ctx.docInfo.paraShapes.length ? ctx.docInfo.paraShapes[paraShapeId] : null;
38645
38802
  if (ps && ps.headType > 0) {
38646
38803
  if (ps.headType === 1) {
38647
- headingLevel = Math.min(ps.paraLevel + 1, 6);
38804
+ if (!toc.tocEntry) headingLevel = Math.min(ps.paraLevel + 1, 6);
38648
38805
  }
38649
38806
  if (ps.headType === 1 || ps.headType === 2) {
38650
38807
  const nid = ps.numberingId || (ps.headType === 1 ? ctx.doc.outlineNumberingId : 0);
@@ -38662,10 +38819,17 @@ function parseParagraph(records, start, end, ctx) {
38662
38819
  if (bullet && bullet.char !== "\uFFFF") headMarker = bullet.char;
38663
38820
  }
38664
38821
  }
38822
+ if (toc.tocEntry) {
38823
+ for (const line of text2.split("\n")) if (line.trim()) {
38824
+ ctx.doc.tocTexts.add(line.trim());
38825
+ if (headMarker) ctx.doc.tocTexts.add(`${headMarker} ${line.trim()}`);
38826
+ }
38827
+ }
38665
38828
  return emitParagraphBlocks({
38666
38829
  text: text2,
38667
38830
  headMarker,
38668
38831
  headingLevel,
38832
+ tocEntry: toc.tocEntry,
38669
38833
  style: ctx.docInfo && charShapeIds.length > 0 ? resolveCharStyle(charShapeIds, ctx.docInfo) : void 0,
38670
38834
  footnotes: ctrls.filter((c) => c.footnote).map((c) => c.footnote),
38671
38835
  // 컨트롤 파생 블록 (표/이미지/글상자) — 컨트롤 순서대로
@@ -39230,7 +39394,7 @@ function parseHwp5Document(buffer, options) {
39230
39394
  flatBlocks = deduped;
39231
39395
  }
39232
39396
  if (docInfo) {
39233
- detectHwp5Headings(flatBlocks, docInfo);
39397
+ detectHwp5Headings(flatBlocks, docInfo, doc.tocTexts);
39234
39398
  }
39235
39399
  const outline = flatBlocks.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
39236
39400
  let markdown = blocksToMarkdown(flatBlocks);
@@ -39263,7 +39427,7 @@ function parseDocInfoFromStream(raw, compressed) {
39263
39427
  return null;
39264
39428
  }
39265
39429
  }
39266
- function detectHwp5Headings(blocks, docInfo) {
39430
+ function detectHwp5Headings(blocks, docInfo, tocTexts) {
39267
39431
  var _a2, _b;
39268
39432
  let baseFontSize = 0;
39269
39433
  const sizeFreq = /* @__PURE__ */ new Map();
@@ -39294,7 +39458,7 @@ function detectHwp5Headings(blocks, docInfo) {
39294
39458
  if (baseFontSize <= 0) return;
39295
39459
  for (const block2 of blocks) {
39296
39460
  if (block2.type === "heading") continue;
39297
- if (block2.type !== "paragraph" || !block2.text) continue;
39461
+ if (block2.type !== "paragraph" || !block2.text || TOC_ENTRY_BLOCKS.has(block2) || (tocTexts == null ? void 0 : tocTexts.has(block2.text.trim()))) continue;
39298
39462
  const text2 = block2.text.trim();
39299
39463
  if (text2.length === 0 || text2.length > 200) continue;
39300
39464
  if (/^\d+$/.test(text2)) continue;
@@ -39484,6 +39648,7 @@ init_cjs_shims();
39484
39648
  var import_zlib5 = require("zlib");
39485
39649
  init_utils();
39486
39650
  init_builder();
39651
+ init_script_tags();
39487
39652
 
39488
39653
  // .kordoc-source/src/hwp3/drawing.ts
39489
39654
  init_cjs_shims();
@@ -52225,7 +52390,7 @@ function parseCharStream(reader, charCount, ctx, para2) {
52225
52390
  continue;
52226
52391
  }
52227
52392
  if (ch >= 32) {
52228
- para2.text += escapeLiteralDollar((_a2 = decodeJohabText(ch)) != null ? _a2 : "");
52393
+ para2.text += escapeLiteralTags(escapeLiteralDollar((_a2 = decodeJohabText(ch)) != null ? _a2 : ""));
52229
52394
  continue;
52230
52395
  }
52231
52396
  if (ch === 9) {
@@ -52458,6 +52623,7 @@ var import_jszip4 = __toESM(require_lib3(), 1);
52458
52623
  var import_xmldom2 = __toESM(require_lib4(), 1);
52459
52624
  init_utils();
52460
52625
  init_builder();
52626
+ init_script_tags();
52461
52627
 
52462
52628
  // .kordoc-source/src/xlsx/sheet-blocks.ts
52463
52629
  init_cjs_shims();
@@ -52587,7 +52753,7 @@ function collectRichText(root) {
52587
52753
  const el = children[i];
52588
52754
  const local = el.localName || ((_a2 = el.tagName) == null ? void 0 : _a2.replace(/^[^:]+:/, "")) || "";
52589
52755
  if (local === "rPh") continue;
52590
- if (local === "t") out += (_b = el.textContent) != null ? _b : "";
52756
+ if (local === "t") out += escapeLiteralTags(escapeLiteralDollar((_b = el.textContent) != null ? _b : ""));
52591
52757
  else walk(el);
52592
52758
  }
52593
52759
  };
@@ -53118,6 +53284,8 @@ function decodeSST(records) {
53118
53284
 
53119
53285
  // .kordoc-source/src/xls/cell.ts
53120
53286
  init_cjs_shims();
53287
+ init_script_tags();
53288
+ init_builder();
53121
53289
  function errorCodeToText(code2) {
53122
53290
  switch (code2) {
53123
53291
  case 0:
@@ -53229,14 +53397,14 @@ function extractSheetCells(records, bofIndex, sst, convertNum) {
53229
53397
  const h = readCellHeader(rec.data);
53230
53398
  if (h && rec.data.length >= 10) {
53231
53399
  const isst = rec.data.readUInt32LE(6);
53232
- cells.push({ row: h.row, col: h.col, value: (_a2 = sst[isst]) != null ? _a2 : "" });
53400
+ cells.push({ row: h.row, col: h.col, value: escapeLiteralTags(escapeLiteralDollar((_a2 = sst[isst]) != null ? _a2 : "")) });
53233
53401
  }
53234
53402
  break;
53235
53403
  }
53236
53404
  case OP_LABEL: {
53237
53405
  const h = readCellHeader(rec.data);
53238
53406
  if (h) {
53239
- cells.push({ row: h.row, col: h.col, value: decodeLabelString(rec.data) });
53407
+ cells.push({ row: h.row, col: h.col, value: escapeLiteralTags(escapeLiteralDollar(decodeLabelString(rec.data))) });
53240
53408
  }
53241
53409
  break;
53242
53410
  }
@@ -53252,7 +53420,7 @@ function extractSheetCells(records, bofIndex, sst, convertNum) {
53252
53420
  cells.push({
53253
53421
  row: h.row,
53254
53422
  col: h.col,
53255
- value: decodeFormulaStringRecord(next.data)
53423
+ value: escapeLiteralTags(escapeLiteralDollar(decodeFormulaStringRecord(next.data)))
53256
53424
  });
53257
53425
  i = j;
53258
53426
  } else {
@@ -53980,6 +54148,7 @@ function isDisplayMath(el) {
53980
54148
  // .kordoc-source/src/docx/parser.ts
53981
54149
  var MAX_DECOMPRESS_SIZE5 = unzipLimitBytes(100 * 1024 * 1024);
53982
54150
  var MEDIA_PART_RE = /^word\/(?:media|embeddings)\//;
54151
+ var NEVER_READ_RE = /^word\/(?:embeddings\/.*|media\/.+\.(?:mp4|m4v|mov|avi|wmv|mpe?g|mkv|webm|mp3|wav|m4a|wma|aac|ogg|flac|mid|bin))$/i;
53983
54152
  function matchesLocal(el, localName3) {
53984
54153
  var _a2, _b;
53985
54154
  return el.localName === localName3 || ((_b = (_a2 = el.tagName) == null ? void 0 : _a2.endsWith(`:${localName3}`)) != null ? _b : false);
@@ -54176,7 +54345,7 @@ function parseFootnotes(xml) {
54176
54345
  const runs = findElements(p, "r");
54177
54346
  for (const r of runs) {
54178
54347
  const tElements = getChildElements(r, "t");
54179
- for (const t of tElements) texts.push((_a2 = t.textContent) != null ? _a2 : "");
54348
+ for (const t of tElements) texts.push(escapeLiteralTags(escapeLiteralDollar((_a2 = t.textContent) != null ? _a2 : "")));
54180
54349
  }
54181
54350
  }
54182
54351
  notes.set(id, texts.join("").trim());
@@ -54209,7 +54378,7 @@ function extractRun(r) {
54209
54378
  var _a2;
54210
54379
  let text2 = "";
54211
54380
  for (const el of effectiveChildElements(r)) {
54212
- if (matchesLocal(el, "t")) text2 += (_a2 = el.textContent) != null ? _a2 : "";
54381
+ if (matchesLocal(el, "t")) text2 += escapeLiteralTags(escapeLiteralDollar((_a2 = el.textContent) != null ? _a2 : ""));
54213
54382
  else if (matchesLocal(el, "br") || matchesLocal(el, "cr")) text2 += "\n";
54214
54383
  else if (matchesLocal(el, "tab")) text2 += " ";
54215
54384
  else if (matchesLocal(el, "sym")) text2 += symbolChar(getAttr(el, "font"), getAttr(el, "char"));
@@ -54485,7 +54654,7 @@ function collectCellText(tc2, styles, numbering, footnotes, rels, depth) {
54485
54654
  return parts;
54486
54655
  }
54487
54656
  async function buildImageMap(zip, rels, doc, warnings, readBytes) {
54488
- var _a2, _b, _c, _d;
54657
+ var _a2, _b;
54489
54658
  const imageMap = /* @__PURE__ */ new Map();
54490
54659
  const images = [];
54491
54660
  let imgIdx = 0;
@@ -54509,7 +54678,7 @@ async function buildImageMap(zip, rels, doc, warnings, readBytes) {
54509
54678
  let data = null;
54510
54679
  if (readBytes) data = await imgFile.async("uint8array");
54511
54680
  imgIdx++;
54512
- const ext = (_b = (_a2 = imgPath.split(".").pop()) == null ? void 0 : _a2.toLowerCase()) != null ? _b : "png";
54681
+ const ext = partExtension(imgPath);
54513
54682
  const mimeMap = {
54514
54683
  png: "image/png",
54515
54684
  jpg: "image/jpeg",
@@ -54524,7 +54693,7 @@ async function buildImageMap(zip, rels, doc, warnings, readBytes) {
54524
54693
  };
54525
54694
  const filename = `image_${String(imgIdx).padStart(3, "0")}.${ext}`;
54526
54695
  if (data) {
54527
- const mimeType = (_d = (_c = mimeMap[ext]) != null ? _c : detectImageMime(data)) != null ? _d : "application/octet-stream";
54696
+ const mimeType = (_b = (_a2 = mimeMap[ext]) != null ? _a2 : detectImageMime(data)) != null ? _b : "application/octet-stream";
54528
54697
  images.push({ filename, data, mimeType, source: imgPath });
54529
54698
  }
54530
54699
  imageMap.set(embedId, filename);
@@ -54614,7 +54783,7 @@ async function parseHeaderFooterBlocks(zip, doc, rels, kind, styles, numbering,
54614
54783
  async function parseDocxDocument(buffer, options) {
54615
54784
  var _a2, _b;
54616
54785
  const readImages = (options == null ? void 0 : options.images) !== false;
54617
- precheckZipSize(buffer, MAX_DECOMPRESS_SIZE5, void 0, { re: MEDIA_PART_RE, skip: !readImages });
54786
+ precheckZipSize(buffer, MAX_DECOMPRESS_SIZE5, void 0, { re: MEDIA_PART_RE, skip: !readImages, never: NEVER_READ_RE });
54618
54787
  const zip = await import_jszip5.default.loadAsync(buffer);
54619
54788
  const warnings = [];
54620
54789
  const docFile = zip.file("word/document.xml");
@@ -54734,10 +54903,349 @@ async function parseDocxDocument(buffer, options) {
54734
54903
  };
54735
54904
  }
54736
54905
 
54737
- // .kordoc-source/src/hwpml/parser.ts
54906
+ // .kordoc-source/src/pptx/parser.ts
54738
54907
  init_cjs_shims();
54908
+ var import_jszip6 = __toESM(require_lib3(), 1);
54739
54909
  var import_xmldom4 = __toESM(require_lib4(), 1);
54910
+ init_utils();
54911
+ init_page_range();
54912
+ init_builder();
54913
+ init_script_tags();
54914
+ var MAX_DECOMPRESS_SIZE6 = unzipLimitBytes(100 * 1024 * 1024);
54915
+ var MEDIA_PART_RE2 = /^ppt\/(?:media|embeddings)\//;
54916
+ var NEVER_READ_RE2 = /^ppt\/(?:embeddings\/.*|media\/.+\.(?:mp4|m4v|mov|avi|wmv|mpe?g|mkv|webm|mp3|wav|m4a|wma|aac|ogg|flac|mid|bin))$/i;
54917
+ var MAX_ZIP_ENTRIES2 = 1e4;
54918
+ var MAX_SLIDES = 2e3;
54919
+ var SKIP_PLACEHOLDERS = /* @__PURE__ */ new Set(["sldNum", "dt", "ftr", "hdr", "sldImg"]);
54920
+ var BULLET_PLACEHOLDERS = /* @__PURE__ */ new Set(["body", "obj"]);
54921
+ var REL_NOTES = "/notesSlide";
54922
+ var REL_IMAGE = "/image";
54923
+ var SLIDE_PART_RE = /^ppt\/slides\/slide(\d+)\.xml$/;
54924
+ var IMAGE_MIME = {
54925
+ png: "image/png",
54926
+ jpg: "image/jpeg",
54927
+ jpeg: "image/jpeg",
54928
+ gif: "image/gif",
54929
+ bmp: "image/bmp",
54930
+ wmf: "image/wmf",
54931
+ emf: "image/emf",
54932
+ tif: "image/tiff",
54933
+ tiff: "image/tiff",
54934
+ svg: "image/svg+xml"
54935
+ };
54936
+ function parseXml3(text2) {
54937
+ return new import_xmldom4.DOMParser().parseFromString(stripDtd(text2), "text/xml");
54938
+ }
54939
+ function getAttr2(el, name) {
54940
+ const attrs = el.attributes;
54941
+ for (let i = 0; i < attrs.length; i++) {
54942
+ const attr = attrs[i];
54943
+ if (attr.localName === name || attr.name === name) return attr.value;
54944
+ }
54945
+ return null;
54946
+ }
54947
+ var NS_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
54948
+ function getRelId(el) {
54949
+ const attrs = el.attributes;
54950
+ for (let i = 0; i < attrs.length; i++) {
54951
+ const attr = attrs[i];
54952
+ if (attr.localName === "id" && (attr.namespaceURI === NS_REL || attr.name === "r:id")) return attr.value;
54953
+ }
54954
+ return null;
54955
+ }
54956
+ function findPath(el, ...names) {
54957
+ for (const name of names) {
54958
+ if (!el) return null;
54959
+ el = findChildByLocalName(el, name);
54960
+ }
54961
+ return el;
54962
+ }
54963
+ function resolvePart(baseDir, target) {
54964
+ if (target.startsWith("/")) return target.slice(1);
54965
+ const parts = baseDir ? baseDir.split("/") : [];
54966
+ for (const seg of target.split("/")) {
54967
+ if (seg === "..") parts.pop();
54968
+ else if (seg && seg !== ".") parts.push(seg);
54969
+ }
54970
+ return parts.join("/");
54971
+ }
54972
+ async function readRels(zip, part) {
54973
+ var _a2;
54974
+ const map2 = /* @__PURE__ */ new Map();
54975
+ const slash = part.lastIndexOf("/");
54976
+ const dir = slash >= 0 ? part.slice(0, slash) : "";
54977
+ const file = zip.file(`${dir ? dir + "/" : ""}_rels/${part.slice(slash + 1)}.rels`);
54978
+ if (!file) return map2;
54979
+ const doc = parseXml3(await file.async("text"));
54980
+ for (const rel of childrenByLocalName(doc.documentElement, "Relationship")) {
54981
+ const id = getAttr2(rel, "Id");
54982
+ const target = getAttr2(rel, "Target");
54983
+ if (!id || !target || getAttr2(rel, "TargetMode") === "External") continue;
54984
+ map2.set(id, { type: (_a2 = getAttr2(rel, "Type")) != null ? _a2 : "", target: resolvePart(dir, target) });
54985
+ }
54986
+ return map2;
54987
+ }
54988
+ async function slideParts(zip) {
54989
+ var _a2, _b;
54990
+ const ordered = [];
54991
+ const presFile = zip.file("ppt/presentation.xml");
54992
+ if (presFile) {
54993
+ const pres = parseXml3(await presFile.async("text"));
54994
+ const rels = await readRels(zip, "ppt/presentation.xml");
54995
+ const list2 = findChildByLocalName(pres.documentElement, "sldIdLst");
54996
+ for (const sld of list2 ? childrenByLocalName(list2, "sldId") : []) {
54997
+ const target = (_b = rels.get((_a2 = getRelId(sld)) != null ? _a2 : "")) == null ? void 0 : _b.target;
54998
+ if (target && zip.file(target)) ordered.push(target);
54999
+ }
55000
+ }
55001
+ if (ordered.length === 0) {
55002
+ const names = Object.keys(zip.files).filter((n) => SLIDE_PART_RE.test(n));
55003
+ names.sort((a, b) => Number(SLIDE_PART_RE.exec(a)[1]) - Number(SLIDE_PART_RE.exec(b)[1]));
55004
+ ordered.push(...names);
55005
+ }
55006
+ if (ordered.length > MAX_SLIDES) throw new KordocError(`PPTX \uC2AC\uB77C\uC774\uB4DC \uC218 \uCD08\uACFC: ${ordered.length} (\uCD5C\uB300 ${MAX_SLIDES})`);
55007
+ return ordered;
55008
+ }
55009
+ function paragraphText(p) {
55010
+ var _a2;
55011
+ let text2 = "";
55012
+ for (const child of elementChildren(p)) {
55013
+ const name = localName(child);
55014
+ if (name === "r" || name === "fld") {
55015
+ const t = findChildByLocalName(child, "t");
55016
+ const rPr = findChildByLocalName(child, "rPr");
55017
+ const baseline = Number(rPr ? (_a2 = getAttr2(rPr, "baseline")) != null ? _a2 : 0 : 0);
55018
+ if (t) text2 += wrapScript(escapeLiteralTags(escapeLiteralDollar(rawTextContent(t))), baseline > 0 ? "sup" : baseline < 0 ? "sub" : null);
55019
+ } else if (name === "br") {
55020
+ text2 += " ";
55021
+ }
55022
+ }
55023
+ return tidyScriptTags(text2.replace(/\s+/g, " ").trim());
55024
+ }
55025
+ function bodyParagraphs(txBody) {
55026
+ var _a2;
55027
+ const out = [];
55028
+ for (const p of childrenByLocalName(txBody, "p")) {
55029
+ const text2 = paragraphText(p);
55030
+ if (!text2) continue;
55031
+ const pPr = findChildByLocalName(p, "pPr");
55032
+ let bullet;
55033
+ if (pPr) {
55034
+ if (findChildByLocalName(pPr, "buNone")) bullet = "none";
55035
+ else if (findChildByLocalName(pPr, "buAutoNum")) bullet = "ordered";
55036
+ else if (findChildByLocalName(pPr, "buChar") || findChildByLocalName(pPr, "buBlip")) bullet = "unordered";
55037
+ }
55038
+ const lvl = Math.max(0, parseInt(pPr ? (_a2 = getAttr2(pPr, "lvl")) != null ? _a2 : "0" : "0", 10) || 0);
55039
+ out.push({ text: text2, lvl, bullet });
55040
+ }
55041
+ return out;
55042
+ }
55043
+ function placeholderType(sp) {
55044
+ var _a2;
55045
+ const ph = findPath(sp, "nvSpPr", "nvPr", "ph");
55046
+ return ph ? (_a2 = getAttr2(ph, "type")) != null ? _a2 : "obj" : null;
55047
+ }
55048
+ function pushParagraphs(paras, bulletDefault, page, out) {
55049
+ var _a2, _b;
55050
+ let lastList = null;
55051
+ for (const para2 of paras) {
55052
+ const bullet = (_a2 = para2.bullet) != null ? _a2 : bulletDefault ? "unordered" : "none";
55053
+ if (bullet === "none") {
55054
+ out.push({ type: "paragraph", text: para2.text, pageNumber: page });
55055
+ lastList = null;
55056
+ continue;
55057
+ }
55058
+ const item = { type: "list", text: para2.text, listType: bullet, pageNumber: page };
55059
+ if (para2.lvl > 0 && lastList) {
55060
+ ;
55061
+ ((_b = lastList.children) != null ? _b : lastList.children = []).push(item);
55062
+ } else {
55063
+ out.push(item);
55064
+ lastList = item;
55065
+ }
55066
+ }
55067
+ }
55068
+ function parseTable2(tbl2, page, keepEmptyCols) {
55069
+ const rows = childrenByLocalName(tbl2, "tr");
55070
+ if (rows.length === 0) return null;
55071
+ const cellRows = rows.map((tr, r) => {
55072
+ const cells = [];
55073
+ childrenByLocalName(tr, "tc").forEach((tc2, c) => {
55074
+ var _a2, _b;
55075
+ if (getAttr2(tc2, "hMerge") === "1" || getAttr2(tc2, "vMerge") === "1") return;
55076
+ const txBody = findChildByLocalName(tc2, "txBody");
55077
+ const text2 = txBody ? bodyParagraphs(txBody).map((p) => p.text).join("\n") : "";
55078
+ cells.push({
55079
+ text: text2,
55080
+ colSpan: Math.max(1, parseInt((_a2 = getAttr2(tc2, "gridSpan")) != null ? _a2 : "1", 10) || 1),
55081
+ rowSpan: Math.max(1, parseInt((_b = getAttr2(tc2, "rowSpan")) != null ? _b : "1", 10) || 1),
55082
+ colAddr: c,
55083
+ rowAddr: r
55084
+ });
55085
+ });
55086
+ return cells;
55087
+ });
55088
+ const table3 = buildTable(cellRows, { keepAnchoredEmptyCols: keepEmptyCols });
55089
+ if (table3.rows === 0 || table3.cols === 0) return null;
55090
+ return { type: "table", table: table3, pageNumber: page };
55091
+ }
55092
+ async function pictureBlock(pic, ctx) {
55093
+ var _a2, _b, _c;
55094
+ const blip = findPath(pic, "blipFill", "blip");
55095
+ const embed = blip ? getAttr2(blip, "embed") : null;
55096
+ const rel = embed ? ctx.rels.get(embed) : void 0;
55097
+ if (!rel || !rel.type.endsWith(REL_IMAGE)) return null;
55098
+ let filename = ctx.imageNames.get(rel.target);
55099
+ if (!filename) {
55100
+ const file = ctx.zip.file(rel.target);
55101
+ if (!file) return null;
55102
+ const ext = partExtension(rel.target);
55103
+ filename = `image_${String(ctx.imageNames.size + 1).padStart(3, "0")}.${ext}`;
55104
+ try {
55105
+ if (((_a2 = ctx.options) == null ? void 0 : _a2.images) !== false) {
55106
+ const data = await file.async("uint8array");
55107
+ ctx.images.push({ filename, data, mimeType: (_c = (_b = IMAGE_MIME[ext]) != null ? _b : detectImageMime(data)) != null ? _c : "application/octet-stream", source: rel.target });
55108
+ }
55109
+ } catch (err) {
55110
+ ctx.warnings.push({
55111
+ page: ctx.page,
55112
+ code: "SKIPPED_IMAGE",
55113
+ message: `PPTX \uC774\uBBF8\uC9C0 \uCD94\uCD9C \uC2E4\uD328 (${rel.target}): ${err instanceof Error ? err.message : String(err)}`
55114
+ });
55115
+ return null;
55116
+ }
55117
+ ctx.imageNames.set(rel.target, filename);
55118
+ }
55119
+ return { type: "image", text: filename, pageNumber: ctx.page };
55120
+ }
55121
+ async function walkShapes(tree, ctx, out, depth = 0) {
55122
+ var _a2, _b;
55123
+ if (depth > MAX_XML_DEPTH) return;
55124
+ for (const el of elementChildren(tree)) {
55125
+ switch (localName(el)) {
55126
+ case "grpSp":
55127
+ await walkShapes(el, ctx, out, depth + 1);
55128
+ break;
55129
+ case "AlternateContent": {
55130
+ const choice = findChildByLocalName(el, "Choice");
55131
+ if (choice) await walkShapes(choice, ctx, out, depth + 1);
55132
+ break;
55133
+ }
55134
+ case "sp": {
55135
+ const ph = placeholderType(el);
55136
+ const txBody = findChildByLocalName(el, "txBody");
55137
+ if (ph && SKIP_PLACEHOLDERS.has(ph) || !txBody) break;
55138
+ const paras = bodyParagraphs(txBody);
55139
+ if (paras.length === 0) break;
55140
+ if (ph === "title" || ph === "ctrTitle") {
55141
+ out.push({ type: "heading", level: ph === "ctrTitle" ? 1 : 2, text: paras.map((p) => p.text).join(" "), pageNumber: ctx.page });
55142
+ } else {
55143
+ pushParagraphs(paras, ph !== null && BULLET_PLACEHOLDERS.has(ph), ctx.page, out);
55144
+ }
55145
+ break;
55146
+ }
55147
+ case "graphicFrame": {
55148
+ const data = findPath(el, "graphic", "graphicData");
55149
+ const tbl2 = data ? findChildByLocalName(data, "tbl") : null;
55150
+ if (tbl2) {
55151
+ const block2 = parseTable2(tbl2, ctx.page, (_a2 = ctx.options) == null ? void 0 : _a2.keepTrailingEmptyCols);
55152
+ if (block2) out.push(block2);
55153
+ } else if (data) {
55154
+ const uri = (_b = getAttr2(data, "uri")) != null ? _b : "";
55155
+ const kind = /chart/i.test(uri) ? "\uCC28\uD2B8" : /diagram/i.test(uri) ? "SmartArt" : "\uAC1C\uCCB4";
55156
+ ctx.warnings.push({ page: ctx.page, code: "UNSUPPORTED_ELEMENT", message: `PPTX ${kind}\uC758 \uAE00\uC740 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (${ctx.page}\uCABD)` });
55157
+ }
55158
+ break;
55159
+ }
55160
+ case "pic": {
55161
+ const block2 = await pictureBlock(el, ctx);
55162
+ if (block2) out.push(block2);
55163
+ break;
55164
+ }
55165
+ }
55166
+ }
55167
+ }
55168
+ async function notesText(zip, rels) {
55169
+ const rel = [...rels.values()].find((r) => r.type.endsWith(REL_NOTES));
55170
+ const file = rel ? zip.file(rel.target) : null;
55171
+ if (!file) return "";
55172
+ const tree = findPath(parseXml3(await file.async("text")).documentElement, "cSld", "spTree");
55173
+ const texts = [];
55174
+ for (const sp of tree ? childrenByLocalName(tree, "sp") : []) {
55175
+ const txBody = findChildByLocalName(sp, "txBody");
55176
+ if (placeholderType(sp) === "body" && txBody) texts.push(...bodyParagraphs(txBody).map((p) => p.text));
55177
+ }
55178
+ return texts.join(" ");
55179
+ }
55180
+ async function parsePptxDocument(buffer, options) {
55181
+ precheckZipSize(buffer, MAX_DECOMPRESS_SIZE6, MAX_ZIP_ENTRIES2, { re: MEDIA_PART_RE2, skip: (options == null ? void 0 : options.images) === false, never: NEVER_READ_RE2 });
55182
+ const zip = await import_jszip6.default.loadAsync(buffer);
55183
+ if (!zip.file("ppt/presentation.xml")) {
55184
+ throw new KordocError("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 PPTX \uD30C\uC77C: ppt/presentation.xml\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
55185
+ }
55186
+ const warnings = [];
55187
+ const blocks = [];
55188
+ const imageNames = /* @__PURE__ */ new Map();
55189
+ const images = [];
55190
+ const slides = await slideParts(zip);
55191
+ const pageFilter = (options == null ? void 0 : options.pages) ? parsePageRange(options.pages, slides.length) : null;
55192
+ for (let i = 0; i < slides.length; i++) {
55193
+ const page = i + 1;
55194
+ if (pageFilter && !pageFilter.has(page)) continue;
55195
+ const root = parseXml3(await zip.file(slides[i]).async("text")).documentElement;
55196
+ if (getAttr2(root, "show") === "0") {
55197
+ warnings.push({ page, code: "HIDDEN_TEXT_FILTERED", message: `PPTX \uC228\uAE34 \uC2AC\uB77C\uC774\uB4DC ${page}\uCABD\uC744 \uAC74\uB108\uB701\uB2C8\uB2E4` });
55198
+ continue;
55199
+ }
55200
+ const rels = await readRels(zip, slides[i]);
55201
+ const tree = findPath(root, "cSld", "spTree");
55202
+ if (tree) await walkShapes(tree, { zip, rels, page, warnings, options, imageNames, images }, blocks);
55203
+ const notes = await notesText(zip, rels);
55204
+ if (notes) blocks.push({ type: "paragraph", text: `\uBC1C\uD45C\uC790 \uB178\uD2B8: ${notes}`, quote: true, pageNumber: page });
55205
+ }
55206
+ const metadata = { pageCount: slides.length, pageMode: "layout" };
55207
+ const coreFile = zip.file("docProps/core.xml");
55208
+ if (coreFile) {
55209
+ try {
55210
+ const coreDoc = parseXml3(await coreFile.async("text"));
55211
+ const getFirst = (tag) => {
55212
+ var _a2;
55213
+ const els = coreDoc.getElementsByTagName(tag);
55214
+ return els.length > 0 ? ((_a2 = els[0].textContent) != null ? _a2 : "").trim() || void 0 : void 0;
55215
+ };
55216
+ metadata.title = getFirst("dc:title") || getFirst("dcterms:title");
55217
+ metadata.author = getFirst("dc:creator");
55218
+ metadata.description = getFirst("dc:description");
55219
+ const created = getFirst("dcterms:created");
55220
+ if (created) metadata.createdAt = created;
55221
+ const modified = getFirst("dcterms:modified");
55222
+ if (modified) metadata.modifiedAt = modified;
55223
+ } catch (err) {
55224
+ warnings.push({
55225
+ code: "PARTIAL_PARSE",
55226
+ message: `PPTX \uBA54\uD0C0\uB370\uC774\uD130(core.xml) \uD30C\uC2F1 \uC2E4\uD328: ${err instanceof Error ? err.message : String(err)}`
55227
+ });
55228
+ }
55229
+ }
55230
+ const outline = blocks.filter((b) => b.type === "heading").map((b) => {
55231
+ var _a2, _b;
55232
+ return { level: (_a2 = b.level) != null ? _a2 : 2, text: (_b = b.text) != null ? _b : "", pageNumber: b.pageNumber };
55233
+ });
55234
+ return {
55235
+ markdown: blocksToMarkdown(blocks),
55236
+ blocks,
55237
+ metadata,
55238
+ outline: outline.length > 0 ? outline : void 0,
55239
+ warnings: warnings.length > 0 ? warnings : void 0,
55240
+ images: images.length > 0 ? images : void 0
55241
+ };
55242
+ }
55243
+
55244
+ // .kordoc-source/src/hwpml/parser.ts
55245
+ init_cjs_shims();
55246
+ var import_xmldom5 = __toESM(require_lib4(), 1);
54740
55247
  init_builder();
55248
+ init_script_tags();
54741
55249
  init_page_range();
54742
55250
  init_utils();
54743
55251
  var MAX_TABLE_ROWS = 5e3;
@@ -54752,7 +55260,7 @@ function parseHwpmlDocument(buffer, options) {
54752
55260
  const normalized = text2.replace(/&nbsp;/g, "&#160;");
54753
55261
  const xml = stripDtd(normalized);
54754
55262
  const warnings = [];
54755
- const parser = new import_xmldom4.DOMParser({
55263
+ const parser = new import_xmldom5.DOMParser({
54756
55264
  onError: (_level, msg2) => {
54757
55265
  warnings.push({ message: `HWPML XML \uD30C\uC2F1 \uACBD\uACE0: ${msg2}`, code: "MALFORMED_XML" });
54758
55266
  }
@@ -54849,7 +55357,7 @@ function walkContent(node, blocks, paraShapeMap, sectionNum, warnings, inHeaderF
54849
55357
  }
54850
55358
  if (tag === "TABLE") {
54851
55359
  if (!inHeaderFooter) {
54852
- parseTable2(el, blocks, paraShapeMap, sectionNum, warnings, keep);
55360
+ parseTable3(el, blocks, paraShapeMap, sectionNum, warnings, keep);
54853
55361
  }
54854
55362
  continue;
54855
55363
  }
@@ -54868,7 +55376,7 @@ function walkTablesInP(node, blocks, paraShapeMap, sectionNum, warnings, keep, d
54868
55376
  if (el.nodeType !== 1) continue;
54869
55377
  const tag = localName(el);
54870
55378
  if (tag === "TABLE") {
54871
- parseTable2(el, blocks, paraShapeMap, sectionNum, warnings, keep);
55379
+ parseTable3(el, blocks, paraShapeMap, sectionNum, warnings, keep);
54872
55380
  continue;
54873
55381
  }
54874
55382
  if (tag === "FOOTNOTE" || tag === "ENDNOTE" || tag === "HEADER" || tag === "FOOTER") continue;
@@ -54903,7 +55411,7 @@ function collectCharText(node, parts, depth = 0) {
54903
55411
  if (tag === "CHAR") {
54904
55412
  for (const c of Array.from(el.childNodes)) {
54905
55413
  const t = c.nodeType === 1 ? localName(c) === "TAB" ? " " : rawTextContent(c) : c.nodeType === 3 || c.nodeType === 4 ? (_a2 = c.nodeValue) != null ? _a2 : "" : "";
54906
- if (t) parts.push(t);
55414
+ if (t) parts.push(escapeLiteralTags(t));
54907
55415
  }
54908
55416
  } else if (tag === "TABLE" || tag === "PICTURE" || tag === "SHAPEOBJECT") {
54909
55417
  } else if (tag === "AUTONUM") {
@@ -54912,7 +55420,7 @@ function collectCharText(node, parts, depth = 0) {
54912
55420
  }
54913
55421
  }
54914
55422
  }
54915
- function parseTable2(el, blocks, _paraShapeMap, sectionNum, warnings, keep) {
55423
+ function parseTable3(el, blocks, _paraShapeMap, sectionNum, warnings, keep) {
54916
55424
  const table3 = buildHmlTable(el, warnings, keep, 0);
54917
55425
  if (!table3) return;
54918
55426
  const caption = extractShapeCaption(el);
@@ -55883,11 +56391,11 @@ function fillInlineFields(text2, values, filled, matchedLabels, blockedLabels) {
55883
56391
 
55884
56392
  // .kordoc-source/src/form/filler-hwpx.ts
55885
56393
  init_cjs_shims();
55886
- var import_jszip7 = __toESM(require_lib3(), 1);
56394
+ var import_jszip8 = __toESM(require_lib3(), 1);
55887
56395
 
55888
56396
  // .kordoc-source/src/form/click-here.ts
55889
56397
  init_cjs_shims();
55890
- var import_jszip6 = __toESM(require_lib3(), 1);
56398
+ var import_jszip7 = __toESM(require_lib3(), 1);
55891
56399
 
55892
56400
  // .kordoc-source/src/roundtrip/source-map.ts
55893
56401
  init_cjs_shims();
@@ -55974,7 +56482,7 @@ function prefixOf(qname) {
55974
56482
  }
55975
56483
  function scanSectionXml(xml, sectionIndex) {
55976
56484
  const stack = [];
55977
- const bodyParagraphs = [];
56485
+ const bodyParagraphs2 = [];
55978
56486
  const tables = [];
55979
56487
  const headerTexts = [];
55980
56488
  const footerTexts = [];
@@ -56097,8 +56605,8 @@ function scanSectionXml(xml, sectionIndex) {
56097
56605
  } else if (local === "cellAddr") {
56098
56606
  const cell2 = cellStack[cellStack.length - 1];
56099
56607
  if (cell2 && insideCurrentTable(stack, tableStack)) {
56100
- const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
56101
- const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
56608
+ const ca = parseInt(getAttr3(attrsRaw, "colAddr") || "", 10);
56609
+ const ra = parseInt(getAttr3(attrsRaw, "rowAddr") || "", 10);
56102
56610
  if (!isNaN(ca)) cell2.colAddr = ca;
56103
56611
  if (!isNaN(ra)) cell2.rowAddr = ra;
56104
56612
  cell2.addrTagRange = { start: m.index, end: m.index + full.length };
@@ -56106,8 +56614,8 @@ function scanSectionXml(xml, sectionIndex) {
56106
56614
  } else if (local === "cellSpan") {
56107
56615
  const cell2 = cellStack[cellStack.length - 1];
56108
56616
  if (cell2 && insideCurrentTable(stack, tableStack)) {
56109
- const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
56110
- const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
56617
+ const cs = parseInt(getAttr3(attrsRaw, "colSpan") || "1", 10);
56618
+ const rs = parseInt(getAttr3(attrsRaw, "rowSpan") || "1", 10);
56111
56619
  cell2.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
56112
56620
  cell2.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
56113
56621
  }
@@ -56136,7 +56644,7 @@ function scanSectionXml(xml, sectionIndex) {
56136
56644
  if (cls.inTextbox) para2.inTextbox = true;
56137
56645
  stack.push({ local, qname, contentStart });
56138
56646
  paraStack.push(para2);
56139
- if (para2.kind === "body" || para2.kind === "draw") bodyParagraphs.push(para2);
56647
+ if (para2.kind === "body" || para2.kind === "draw") bodyParagraphs2.push(para2);
56140
56648
  else if (para2.kind === "cell") {
56141
56649
  const cell2 = cellStack[cellStack.length - 1];
56142
56650
  if (cell2) cell2.paragraphs.push(para2);
@@ -56171,14 +56679,14 @@ function scanSectionXml(xml, sectionIndex) {
56171
56679
  const cell2 = cellStack[cellStack.length - 1];
56172
56680
  if (cell2 && insideCurrentTable(stack, tableStack)) {
56173
56681
  if (local === "cellAddr") {
56174
- const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
56175
- const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
56682
+ const ca = parseInt(getAttr3(attrsRaw, "colAddr") || "", 10);
56683
+ const ra = parseInt(getAttr3(attrsRaw, "rowAddr") || "", 10);
56176
56684
  if (!isNaN(ca)) cell2.colAddr = ca;
56177
56685
  if (!isNaN(ra)) cell2.rowAddr = ra;
56178
56686
  cell2.addrTagRange = { start: m.index, end: contentStart };
56179
56687
  } else {
56180
- const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
56181
- const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
56688
+ const cs = parseInt(getAttr3(attrsRaw, "colSpan") || "1", 10);
56689
+ const rs = parseInt(getAttr3(attrsRaw, "rowSpan") || "1", 10);
56182
56690
  cell2.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
56183
56691
  cell2.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
56184
56692
  }
@@ -56192,7 +56700,7 @@ function scanSectionXml(xml, sectionIndex) {
56192
56700
  if (para2) para2.text += " ";
56193
56701
  }
56194
56702
  }
56195
- for (const para2 of bodyParagraphs) fillRunInsertPos(para2, xml);
56703
+ for (const para2 of bodyParagraphs2) fillRunInsertPos(para2, xml);
56196
56704
  for (const para2 of excludedParagraphs) fillRunInsertPos(para2, xml);
56197
56705
  const fillTableInsertPos = (table3, depth = 0) => {
56198
56706
  if (depth > 16) return;
@@ -56205,9 +56713,9 @@ function scanSectionXml(xml, sectionIndex) {
56205
56713
  };
56206
56714
  for (const table3 of tables) fillTableInsertPos(table3);
56207
56715
  for (const table3 of orphanTables) fillTableInsertPos(table3);
56208
- return { sectionIndex, xml, bodyParagraphs, tables, headerTexts, footerTexts, excludedParagraphs, orphanTables };
56716
+ return { sectionIndex, xml, bodyParagraphs: bodyParagraphs2, tables, headerTexts, footerTexts, excludedParagraphs, orphanTables };
56209
56717
  }
56210
- function getAttr2(attrsRaw, name) {
56718
+ function getAttr3(attrsRaw, name) {
56211
56719
  var _a2;
56212
56720
  const re = new RegExp(`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`);
56213
56721
  const m = attrsRaw.match(re);
@@ -56535,7 +57043,7 @@ function fillClickHereInXml(xml, cursor, blockedLabels) {
56535
57043
  }
56536
57044
  async function extractClickHereFields(hwpxBuffer) {
56537
57045
  precheckZipSize(hwpxBuffer);
56538
- const zip = await import_jszip6.default.loadAsync(hwpxBuffer);
57046
+ const zip = await import_jszip7.default.loadAsync(hwpxBuffer);
56539
57047
  const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
56540
57048
  const fields = [];
56541
57049
  for (let si = 0; si < sectionPaths.length; si++) {
@@ -56770,7 +57278,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
56770
57278
  var _a2, _b, _c, _d, _e;
56771
57279
  const u8 = new Uint8Array(hwpxBuffer);
56772
57280
  precheckZipSize(hwpxBuffer);
56773
- const zip = await import_jszip7.default.loadAsync(hwpxBuffer);
57281
+ const zip = await import_jszip8.default.loadAsync(hwpxBuffer);
56774
57282
  const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
56775
57283
  if (sectionPaths.length === 0) {
56776
57284
  throw new KordocError("HWPX\uC5D0\uC11C \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
@@ -57252,7 +57760,7 @@ init_page_markdown();
57252
57760
 
57253
57761
  // .kordoc-source/src/hwpx/generator.ts
57254
57762
  init_cjs_shims();
57255
- var import_jszip8 = __toESM(require_lib3(), 1);
57763
+ var import_jszip9 = __toESM(require_lib3(), 1);
57256
57764
 
57257
57765
  // .kordoc-source/src/hwpx/gongmun.ts
57258
57766
  init_cjs_shims();
@@ -61772,7 +62280,7 @@ function sanitizeText2(text2) {
61772
62280
  return result;
61773
62281
  }
61774
62282
  function normForMatch(text2) {
61775
- return sanitizeText2(text2.replace(/\\\$/g, "$")).replace(/\s+/g, " ").trim();
62283
+ return sanitizeText2(text2.replace(/\\\$/g, "$").replace(/\\(?=<\/?(?:u|sup|sub)>)/g, "")).replace(/\s+/g, " ").trim();
61776
62284
  }
61777
62285
  function unescapeGfm(text2) {
61778
62286
  return text2.replace(/\\([~*_`|#<$\\])/g, "$1");
@@ -63665,7 +64173,8 @@ function renderListItem(block2, blockIdx, ctx) {
63665
64173
  ctx.prevWasOrdered = false;
63666
64174
  }
63667
64175
  const indentPrefix = " ".repeat(indent);
63668
- return generateParagraph(indentPrefix + marker + (block2.text || ""), PARA_LIST);
64176
+ const markerRun = `<hp:run charPrIDRef="${CHAR_NORMAL}"><hp:t>${escapeTextXml(indentPrefix + marker)}</hp:t></hp:run>`;
64177
+ return `<hp:p paraPrIDRef="${PARA_LIST}" styleIDRef="0">${markerRun}${generateRuns(block2.text || "")}</hp:p>`;
63669
64178
  }
63670
64179
  function renderHr(ctx) {
63671
64180
  return ctx.gongmun ? `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}"><hp:t></hp:t></hp:run></hp:p>` : `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0"><hp:t>\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500</hp:t></hp:run></hp:p>`;
@@ -65208,7 +65717,7 @@ async function markdownToHwpx(markdown, options) {
65208
65717
  if (remap2 && remap2.tables.length > 0 && remap2.tables.every((t) => !t.used)) {
65209
65718
  console.warn(`[kordoc] format profile: \uD504\uB85C\uD544 \uD45C ${remap2.tables.length}\uAC1C\uAC00 \uBB38\uC11C \uD45C\uC640 \uB9E4\uCE6D\uB418\uC9C0 \uC54A\uC544 \uBBF8\uC801\uC6A9 (\uD589\xB7\uC5F4/\uCCAB \uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58)`);
65210
65719
  }
65211
- const zip2 = new import_jszip8.default();
65720
+ const zip2 = new import_jszip9.default();
65212
65721
  zip2.file("mimetype", "application/hwp+zip", { compression: "STORE" });
65213
65722
  zip2.file("META-INF/container.xml", generateContainerXml());
65214
65723
  zip2.file("Contents/content.hpf", generateManifest(chartParts2, images2.manifestItems(), "gongmun"));
@@ -65255,7 +65764,7 @@ async function markdownToHwpx(markdown, options) {
65255
65764
  }
65256
65765
  }
65257
65766
  const extraBorderFills = [...(_n = remap == null ? void 0 : remap.borderFillXmls) != null ? _n : [], ...(_o = bfReg == null ? void 0 : bfReg.emit()) != null ? _o : []];
65258
- const zip = new import_jszip8.default();
65767
+ const zip = new import_jszip9.default();
65259
65768
  zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
65260
65769
  zip.file("META-INF/container.xml", generateContainerXml());
65261
65770
  zip.file("Contents/content.hpf", generateManifest(chartParts, images.manifestItems(), gongmun ? "gongmun" : "default"));
@@ -65489,7 +65998,7 @@ function readBuiltinTemplateSample(t) {
65489
65998
 
65490
65999
  // .kordoc-source/src/form/seal.ts
65491
66000
  init_cjs_shims();
65492
- var import_jszip9 = __toESM(require_lib3(), 1);
66001
+ var import_jszip10 = __toESM(require_lib3(), 1);
65493
66002
  init_utils();
65494
66003
 
65495
66004
  // .kordoc-source/src/render/head-styles.ts
@@ -65847,7 +66356,7 @@ async function placeSealHwpx(hwpxBuffer, ops) {
65847
66356
  if (ops.length === 0) throw new KordocError("place_seal: \uBC30\uCE58\uD560 \uB3C4\uC7A5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
65848
66357
  const u8 = new Uint8Array(hwpxBuffer);
65849
66358
  precheckZipSize(hwpxBuffer);
65850
- const zip = await import_jszip9.default.loadAsync(hwpxBuffer);
66359
+ const zip = await import_jszip10.default.loadAsync(hwpxBuffer);
65851
66360
  const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort((a, b) => {
65852
66361
  var _a3, _b2, _c2, _d2;
65853
66362
  return Number((_b2 = (_a3 = a.match(/(\d+)\.xml$/i)) == null ? void 0 : _a3[1]) != null ? _b2 : 0) - Number((_d2 = (_c2 = b.match(/(\d+)\.xml$/i)) == null ? void 0 : _c2[1]) != null ? _d2 : 0);
@@ -66015,7 +66524,7 @@ async function placeSealHwpx(hwpxBuffer, ops) {
66015
66524
 
66016
66525
  // .kordoc-source/src/hwpx/extract-profile.ts
66017
66526
  init_cjs_shims();
66018
- var import_jszip10 = __toESM(require_lib3(), 1);
66527
+ var import_jszip11 = __toESM(require_lib3(), 1);
66019
66528
  init_utils();
66020
66529
  function elemsByLocal(root, name) {
66021
66530
  const all = root.getElementsByTagName("*");
@@ -66103,7 +66612,7 @@ function num(s) {
66103
66612
  const n = parseInt(s, 10);
66104
66613
  return Number.isFinite(n) ? n : void 0;
66105
66614
  }
66106
- function parseTable3(tbl2, tableIndex, borderFills, charPrs) {
66615
+ function parseTable4(tbl2, tableIndex, borderFills, charPrs) {
66107
66616
  var _a2, _b, _c, _d, _e, _f;
66108
66617
  const rows = (_a2 = num(tbl2.getAttribute("rowCnt"))) != null ? _a2 : 0;
66109
66618
  const cols = (_b = num(tbl2.getAttribute("colCnt"))) != null ? _b : 0;
@@ -66228,7 +66737,7 @@ function pick(map2, keys) {
66228
66737
  async function hwpxToProfile(input) {
66229
66738
  var _a2, _b;
66230
66739
  const buf = input instanceof ArrayBuffer ? input : toArrayBuffer(input);
66231
- const zip = await import_jszip10.default.loadAsync(buf);
66740
+ const zip = await import_jszip11.default.loadAsync(buf);
66232
66741
  const parser = createXmlParser();
66233
66742
  const headerFile = (_b = zip.file("Contents/header.xml")) != null ? _b : (_a2 = zip.file(/[Hh]eader\.xml$/)) == null ? void 0 : _a2[0];
66234
66743
  let headerXml = "<root/>";
@@ -66246,7 +66755,7 @@ async function hwpxToProfile(input) {
66246
66755
  const doc = parser.parseFromString(await f.async("text"), "text/xml");
66247
66756
  for (const tbl2 of elemsByLocal(doc, "tbl")) {
66248
66757
  if (!isTopLevelTable(tbl2)) continue;
66249
- tables.push(parseTable3(tbl2, tableIndex++, borderFills, charPrs));
66758
+ tables.push(parseTable4(tbl2, tableIndex++, borderFills, charPrs));
66250
66759
  }
66251
66760
  }
66252
66761
  return { schema_version: "0.3.0", tables };
@@ -66955,7 +67464,7 @@ function muncheLintWarnings(text2, limit = 10) {
66955
67464
 
66956
67465
  // .kordoc-source/src/roundtrip/patcher.ts
66957
67466
  init_cjs_shims();
66958
- var import_jszip11 = __toESM(require_lib3(), 1);
67467
+ var import_jszip12 = __toESM(require_lib3(), 1);
66959
67468
  init_builder();
66960
67469
 
66961
67470
  // .kordoc-source/src/roundtrip/table-patch.ts
@@ -68169,7 +68678,12 @@ async function patchHwp(original, editedMarkdown, options) {
68169
68678
  try {
68170
68679
  const kept = parseHwp5Document(originalBuf, { layoutTables: "keep" });
68171
68680
  origBlocks = kept.blocks;
68172
- if (editedFromVisual(kept.markdown, parseHwp5Document(originalBuf).markdown, editedMarkdown)) return fail(LAYOUT_MODE_MISMATCH);
68681
+ const visual = parseHwp5Document(originalBuf).markdown;
68682
+ if (kept.markdown !== visual && editedMarkdown === visual) {
68683
+ const verification2 = (options == null ? void 0 : options.verify) === false ? void 0 : diffUnitLists(splitMarkdownUnits(visual), splitMarkdownUnits(editedMarkdown));
68684
+ return { success: true, data: new Uint8Array(original), applied: 0, skipped, verification: verification2 };
68685
+ }
68686
+ if (editedFromVisual(kept.markdown, visual, editedMarkdown)) return fail(LAYOUT_MODE_MISMATCH);
68173
68687
  } catch (err) {
68174
68688
  return fail(`\uC6D0\uBCF8 HWP \uD30C\uC2F1 \uC2E4\uD328: ${msg(err)}`);
68175
68689
  }
@@ -68840,13 +69354,17 @@ async function patchHwpx(original, editedMarkdown, options) {
68840
69354
  const parsed = await parseHwpxDocument(u8ToArrayBuffer(original), { layoutTables: "keep" });
68841
69355
  origBlocks = parsed.blocks;
68842
69356
  const visual = await parseHwpxDocument(u8ToArrayBuffer(original));
69357
+ if (parsed.markdown !== visual.markdown && editedMarkdown === visual.markdown) {
69358
+ const verification2 = (options == null ? void 0 : options.verify) === false ? void 0 : diffUnitLists(splitMarkdownUnits(visual.markdown), splitMarkdownUnits(editedMarkdown));
69359
+ return { success: true, data: new Uint8Array(original), applied: 0, skipped, verification: verification2 };
69360
+ }
68843
69361
  if (editedFromVisual(parsed.markdown, visual.markdown, editedMarkdown)) return { success: false, applied: 0, skipped, error: LAYOUT_MODE_MISMATCH };
68844
69362
  } catch (err) {
68845
69363
  return { success: false, applied: 0, skipped, error: `\uC6D0\uBCF8 HWPX \uD30C\uC2F1 \uC2E4\uD328: ${err instanceof Error ? err.message : String(err)}` };
68846
69364
  }
68847
69365
  let zip;
68848
69366
  try {
68849
- zip = await import_jszip11.default.loadAsync(original);
69367
+ zip = await import_jszip12.default.loadAsync(original);
68850
69368
  } catch {
68851
69369
  return { success: false, applied: 0, skipped, error: "ZIP \uB85C\uB4DC \uC2E4\uD328" };
68852
69370
  }
@@ -69296,8 +69814,8 @@ async function resolveHeaderEntryName(zip) {
69296
69814
 
69297
69815
  // .kordoc-source/src/validate.ts
69298
69816
  init_cjs_shims();
69299
- var import_jszip12 = __toESM(require_lib3(), 1);
69300
- var import_xmldom5 = __toESM(require_lib4(), 1);
69817
+ var import_jszip13 = __toESM(require_lib3(), 1);
69818
+ var import_xmldom6 = __toESM(require_lib4(), 1);
69301
69819
  var REQUIRED_FILES = [
69302
69820
  "mimetype",
69303
69821
  "META-INF/container.xml",
@@ -69314,7 +69832,7 @@ async function validateHwpx(buffer) {
69314
69832
  const issues = [];
69315
69833
  let zip;
69316
69834
  try {
69317
- zip = await import_jszip12.default.loadAsync(buffer);
69835
+ zip = await import_jszip13.default.loadAsync(buffer);
69318
69836
  } catch (err) {
69319
69837
  return {
69320
69838
  ok: false,
@@ -69343,7 +69861,7 @@ async function validateHwpx(buffer) {
69343
69861
  const text2 = await zip.files[name].async("string");
69344
69862
  let firstError = null;
69345
69863
  try {
69346
- new import_xmldom5.DOMParser({
69864
+ new import_xmldom6.DOMParser({
69347
69865
  onError(level, msg2) {
69348
69866
  if (level !== "warning" && firstError === null) firstError = String(msg2);
69349
69867
  }
@@ -71886,12 +72404,12 @@ function blocksToChunks(blocks, options) {
71886
72404
 
71887
72405
  // .kordoc-source/src/roundtrip/session.ts
71888
72406
  init_cjs_shims();
71889
- var import_jszip13 = __toESM(require_lib3(), 1);
72407
+ var import_jszip14 = __toESM(require_lib3(), 1);
71890
72408
  async function buildState(bytes) {
71891
72409
  const format3 = detectFormat(new Uint8Array(bytes.subarray(0, 512)).buffer);
71892
72410
  if (format3 !== "hwpx") throw new Error(`HWPX \uC138\uC158\uC740 HWPX \uBB38\uC11C\uB9CC \uC5FD\uB2C8\uB2E4 (\uAC10\uC9C0\uB41C \uD3EC\uB9F7: ${format3}) \u2014 HWP 5.x \uB294 patchHwp \uB85C \uD328\uCE58\uD558\uC138\uC694`);
71893
72411
  const parsed = await parseHwpxDocument(u8ToArrayBuffer2(bytes), { layoutTables: "keep" });
71894
- const zip = await import_jszip13.default.loadAsync(bytes);
72412
+ const zip = await import_jszip14.default.loadAsync(bytes);
71895
72413
  const sectionPaths = await resolveSectionEntryNames(zip);
71896
72414
  if (sectionPaths.length === 0) {
71897
72415
  throw new Error("HWPX \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
@@ -78035,7 +78553,7 @@ init_cjs_shims();
78035
78553
 
78036
78554
  // .kordoc-source/src/render/svg-render.ts
78037
78555
  init_cjs_shims();
78038
- var import_jszip14 = __toESM(require_lib3(), 1);
78556
+ var import_jszip15 = __toESM(require_lib3(), 1);
78039
78557
  init_utils();
78040
78558
 
78041
78559
  // .kordoc-source/src/render/layout.ts
@@ -78148,7 +78666,7 @@ var CHAR_CTRL_1SLOT = /* @__PURE__ */ new Set(["lineBreak", "hyphen", "nbSpace",
78148
78666
  function pushFillers(chars, n, prId) {
78149
78667
  for (let i = 0; i < n; i++) chars.push({ ch: "", prId });
78150
78668
  }
78151
- function pushTextSlots(t, chars, prId, depth) {
78669
+ function pushTextSlots(t, chars, prId, depth, del = { deleted: 0 }) {
78152
78670
  var _a2;
78153
78671
  if (depth > 32) return;
78154
78672
  const kids = t.childNodes;
@@ -78157,19 +78675,24 @@ function pushTextSlots(t, chars, prId, depth) {
78157
78675
  const c = kids[i];
78158
78676
  if (c.nodeType === 3 || c.nodeType === 4) {
78159
78677
  for (const cp of (_a2 = c.textContent) != null ? _a2 : "") {
78160
- chars.push({ ch: cp, prId });
78678
+ chars.push({ ch: del.deleted ? "" : cp, prId });
78161
78679
  if (cp.length === 2) chars.push({ ch: "", prId });
78162
78680
  }
78163
78681
  } else if (c.nodeType === 1) {
78164
78682
  const el = c;
78165
78683
  const tag = ln(el);
78166
- if (tag === "tab") {
78167
- chars.push({ ch: "", prId, tab: true, tabW: num2(el, "width") });
78168
- pushFillers(chars, 7, prId);
78684
+ if (tag === "deleteBegin" || tag === "deleteEnd") {
78685
+ del.deleted = deletionDelta(el, del.deleted);
78686
+ } else if (tag === "tab") {
78687
+ if (del.deleted) pushFillers(chars, 8, prId);
78688
+ else {
78689
+ chars.push({ ch: "", prId, tab: true, tabW: num2(el, "width") });
78690
+ pushFillers(chars, 7, prId);
78691
+ }
78169
78692
  } else if (CHAR_CTRL_1SLOT.has(tag)) {
78170
- chars.push(tag === "nbSpace" ? { ch: " ", prId, nb: true } : { ch: tag === "fwSpace" ? " " : "", prId });
78693
+ chars.push(del.deleted ? { ch: "", prId } : tag === "nbSpace" ? { ch: " ", prId, nb: true } : { ch: tag === "fwSpace" ? " " : "", prId });
78171
78694
  } else {
78172
- pushTextSlots(el, chars, prId, depth + 1);
78695
+ pushTextSlots(el, chars, prId, depth + 1, del);
78173
78696
  }
78174
78697
  }
78175
78698
  }
@@ -78194,7 +78717,7 @@ function prepareDeletedRanges(root, depth = 0) {
78194
78717
  deletedStarts.set(p, deleted);
78195
78718
  const scan = (el, xmlDepth) => {
78196
78719
  if (xmlDepth > 64) return;
78197
- if (ln(el) === "ctrl") for (const ch of elements(el)) scan(ch, xmlDepth + 1);
78720
+ if (ln(el) === "ctrl" || ln(el) === "t") for (const ch of elements(el)) scan(ch, xmlDepth + 1);
78198
78721
  else {
78199
78722
  if (ln(el) === "deleteBegin" || ln(el) === "deleteEnd") deleted = deletionDelta(el, deleted);
78200
78723
  deletedControls.set(el, deleted > 0);
@@ -78227,9 +78750,9 @@ function buildPara(p) {
78227
78750
  for (const ch of elements(runEl)) {
78228
78751
  const cn = ln(ch);
78229
78752
  if (cn === "t") {
78230
- const start = chars.length;
78231
- pushTextSlots(ch, chars, prId, 0);
78232
- if (deleted) for (let i = start; i < chars.length; i++) chars[i] = { ch: "", prId };
78753
+ const del = { deleted };
78754
+ pushTextSlots(ch, chars, prId, 0, del);
78755
+ deleted = del.deleted;
78233
78756
  } else if (OBJ_TAGS.has(cn)) {
78234
78757
  const sz = findChildByLocalName(ch, "sz");
78235
78758
  const pos = findChildByLocalName(ch, "pos");
@@ -78664,22 +79187,48 @@ function rotatedBounds(box, rotations) {
78664
79187
  if (!rotations.length) return box;
78665
79188
  let points = [[box.x, box.y], [box.x + box.w, box.y], [box.x + box.w, box.y + box.h], [box.x, box.y + box.h]];
78666
79189
  for (let i = rotations.length - 1; i >= 0; i--) {
78667
- const { angle, cx, cy } = rotations[i];
79190
+ const r = rotations[i];
79191
+ if (Array.isArray(r)) {
79192
+ points = points.map(([x2, y2]) => [r[0] * x2 + r[2] * y2 + r[4], r[1] * x2 + r[3] * y2 + r[5]]);
79193
+ continue;
79194
+ }
79195
+ const { angle, cx, cy } = r;
78668
79196
  const a = angle * Math.PI / 180, c = Math.cos(a), s = Math.sin(a);
78669
79197
  points = points.map(([x2, y2]) => [cx + c * (x2 - cx) - s * (y2 - cy), cy + s * (x2 - cx) + c * (y2 - cy)]);
78670
79198
  }
78671
79199
  const x = Math.min(...points.map((p) => p[0])), y = Math.min(...points.map((p) => p[1]));
78672
79200
  return { x, y, w: Math.max(...points.map((p) => p[0])) - x, h: Math.max(...points.map((p) => p[1])) - y };
78673
79201
  }
78674
- function objectGeometry(el, x, y, w, h) {
79202
+ function mulAffine(m, n) {
79203
+ return [
79204
+ m[0] * n[0] + m[2] * n[1],
79205
+ m[1] * n[0] + m[3] * n[1],
79206
+ m[0] * n[2] + m[2] * n[3],
79207
+ m[1] * n[2] + m[3] * n[3],
79208
+ m[0] * n[4] + m[2] * n[5] + m[4],
79209
+ m[1] * n[4] + m[3] * n[5] + m[5]
79210
+ ];
79211
+ }
79212
+ function renderingMatrix(el) {
79213
+ const info = findChildByLocalName(el, "renderingInfo");
79214
+ if (!info) return null;
79215
+ let m = null;
79216
+ for (const c of elements(info)) {
79217
+ const tag = ln(c);
79218
+ if (tag !== "transMatrix" && tag !== "scaMatrix" && tag !== "rotMatrix") continue;
79219
+ const n = [num2(c, "e1", 1), num2(c, "e4"), num2(c, "e2"), num2(c, "e5", 1), num2(c, "e3"), num2(c, "e6")];
79220
+ m = m ? mulAffine(m, n) : n;
79221
+ }
79222
+ return m;
79223
+ }
79224
+ function objectGeometry(el, x, y, w, h, boxW = w, boxH = h) {
78675
79225
  const rot = findChildByLocalName(el, "rotationInfo");
78676
79226
  const angle = num2(rot, "angle") % 360;
78677
79227
  if (!angle) return { x, y, w, h, bbox: { x, y, w, h }, transform: "" };
78678
- const org = findChildByLocalName(el, "orgSz");
78679
- const cx = x + num2(rot, "centerX", num2(org, "width", w) / 2) * (w / (num2(org, "width") || w || 1));
78680
- const cy = y + num2(rot, "centerY", num2(org, "height", h) / 2) * (h / (num2(org, "height") || h || 1));
79228
+ const cx = x + boxW / 2, cy = y + boxH / 2;
79229
+ const fx = cx - w / 2, fy = cy - h / 2;
78681
79230
  const rotation = { angle, cx: Math.round(cx), cy: Math.round(cy) };
78682
- return { x, y, w, h, bbox: rotatedBounds({ x, y, w, h }, [rotation]), rotation, transform: `rotate(${angle} ${pt(cx)} ${pt(cy)})` };
79231
+ return { x: fx, y: fy, w, h, bbox: rotatedBounds({ x: fx, y: fy, w, h }, [rotation]), rotation, transform: `rotate(${angle} ${pt(cx)} ${pt(cy)})` };
78683
79232
  }
78684
79233
  function shapeFill(el, defs, images, warn) {
78685
79234
  var _a2, _b, _c;
@@ -78728,31 +79277,34 @@ function shapeFill(el, defs, images, warn) {
78728
79277
  }
78729
79278
  return "none";
78730
79279
  }
78731
- function shapeGeometry(o, x, y, defs, images, warn) {
79280
+ function shapeGeometry(o, boxX, boxY, defs, images, warn, local = false) {
78732
79281
  var _a2;
78733
79282
  const el = o.el, org = findChildByLocalName(el, "orgSz"), cur = findChildByLocalName(el, "curSz");
78734
79283
  const ow = num2(org, "width"), oh = num2(org, "height");
78735
- const w = num2(cur, "width") || ow || o.width, h = num2(cur, "height") || oh || o.height;
79284
+ const w = (local ? ow : num2(cur, "width")) || ow || num2(cur, "width") || o.width;
79285
+ const h = (local ? oh : num2(cur, "height")) || oh || num2(cur, "height") || o.height;
79286
+ const geometry = local ? { x: boxX, y: boxY, w, h, bbox: { x: boxX, y: boxY, w, h }, transform: "" } : objectGeometry(el, boxX, boxY, w, h, o.width || w, o.height || h);
79287
+ const { x, y } = geometry;
78736
79288
  const sx = ow > 0 ? w / ow : 1, sy = oh > 0 ? h / oh : 1;
78737
79289
  const line = findChildByLocalName(el, "lineShape"), style = (_a2 = line == null ? void 0 : line.getAttribute("style")) != null ? _a2 : "SOLID";
78738
79290
  const color = esc((line == null ? void 0 : line.getAttribute("color")) || "#000000");
78739
79291
  const strokeW = style === "NONE" ? 0 : Math.max(0.2, num2(line, "width", 33) / 100 * 2.834645);
78740
79292
  const dash = /DASH|DOT/.test(style) ? ` stroke-dasharray="${style.includes("DOT") ? "1,1.5" : "3,1.5"}"` : "";
78741
- const stroke = strokeW ? ` stroke="${color}" stroke-width="${strokeW.toFixed(2)}"${dash}` : "";
79293
+ const keepWidth = local ? ` vector-effect="non-scaling-stroke"` : "";
79294
+ const stroke = strokeW ? ` stroke="${color}" stroke-width="${strokeW.toFixed(2)}"${dash}${keepWidth}` : "";
78742
79295
  const fill = ` fill="${shapeFill(el, defs, images, warn)}"`;
78743
79296
  let svg = "";
78744
79297
  if (o.tag === "rect") svg = `<rect x="${pt(x)}" y="${pt(y)}" width="${pt(w)}" height="${pt(h)}"${fill}${stroke}/>`;
78745
79298
  else if (o.tag === "ellipse") svg = `<ellipse cx="${pt(x + w / 2)}" cy="${pt(y + h / 2)}" rx="${pt(w / 2)}" ry="${pt(h / 2)}"${fill}${stroke}/>`;
78746
79299
  else if (o.tag === "line") {
78747
79300
  const s = findChildByLocalName(el, "startPt"), e = findChildByLocalName(el, "endPt");
78748
- svg = `<line x1="${pt(x + num2(s, "x") * sx)}" y1="${pt(y + num2(s, "y") * sy)}" x2="${pt(x + num2(e, "x") * sx)}" y2="${pt(y + num2(e, "y") * sy)}" stroke="${color}" stroke-width="${(strokeW || 0.3).toFixed(2)}"${dash}/>`;
79301
+ svg = `<line x1="${pt(x + num2(s, "x") * sx)}" y1="${pt(y + num2(s, "y") * sy)}" x2="${pt(x + num2(e, "x") * sx)}" y2="${pt(y + num2(e, "y") * sy)}" stroke="${color}" stroke-width="${(strokeW || 0.3).toFixed(2)}"${dash}${keepWidth}/>`;
78749
79302
  } else if (o.tag === "polygon" || o.tag === "curv") {
78750
79303
  const pts = elements(el).filter((c) => ln(c) === "pt").map((c) => `${pt(x + num2(c, "x") * sx)},${pt(y + num2(c, "y") * sy)}`);
78751
79304
  if (pts.length >= 2) svg = `<polygon points="${pts.join(" ")}"${fill}${stroke}/>`;
78752
79305
  } else if (o.tag === "curve") {
78753
79306
  const segs = elements(el).filter((c) => ln(c) === "seg");
78754
- if (segs.some((s) => s.getAttribute("type") !== "LINE")) warn("curve:bezier", "\uBE44\uC120\uD615 \uACE1\uC120 \uB80C\uB354 \uBBF8\uC9C0\uC6D0 \u2014 \uC0DD\uB7B5");
78755
- else if (segs.length) {
79307
+ if (segs.length) {
78756
79308
  let path = "", lastX, lastY;
78757
79309
  for (const s of segs) {
78758
79310
  const x1 = num2(s, "x1"), y1 = num2(s, "y1"), x2 = num2(s, "x2"), y2 = num2(s, "y2");
@@ -78764,7 +79316,7 @@ function shapeGeometry(o, x, y, defs, images, warn) {
78764
79316
  svg = `<path d="${path}"${fill}${stroke}/>`;
78765
79317
  }
78766
79318
  } else if (o.tag === "arc") svg = `<ellipse cx="${pt(x + w / 2)}" cy="${pt(y + h / 2)}" rx="${pt(w / 2)}" ry="${pt(h / 2)}" fill="none"${stroke || ` stroke="${color}" stroke-width="0.3"`}/>`;
78767
- return { ...objectGeometry(el, x, y, w, h), svg };
79319
+ return { ...geometry, svg };
78768
79320
  }
78769
79321
 
78770
79322
  // .kordoc-source/src/render/svg-render.ts
@@ -79063,6 +79615,7 @@ function drawObject(o, x, y, baseV, areaW, ctx, depth) {
79063
79615
  if (o.tag === "tbl") drawTable(o.el, x, y, ctx, depth + 1);
79064
79616
  else if (o.tag === "pic") drawPic(o.el, x, y, ctx);
79065
79617
  else if (o.tag === "container") {
79618
+ if (drawGroupByMatrix(o, x, y, baseV, areaW, ctx, depth)) return;
79066
79619
  for (const ch of elements(o.el)) {
79067
79620
  const tag = ln(ch);
79068
79621
  if (!OBJ_TAGS.has(tag)) continue;
@@ -79079,8 +79632,42 @@ function drawObject(o, x, y, baseV, areaW, ctx, depth) {
79079
79632
  warnOnce(ctx, `shape:${o.tag}`, `\uAC1C\uCCB4(${o.tag}) \uB80C\uB354 \uBBF8\uC9C0\uC6D0 \u2014 \uC0DD\uB7B5`);
79080
79633
  }
79081
79634
  }
79082
- function drawShape(o, x, y, ctx, depth) {
79083
- const geometry = shapeGeometry(o, x, y, ctx.defs, ctx.images, (key, msg2) => warnOnce(ctx, key, msg2));
79635
+ function drawGroupByMatrix(o, x, y, baseV, areaW, ctx, depth) {
79636
+ const top = renderingMatrix(o.el);
79637
+ const leaves = [];
79638
+ const collect = (el) => {
79639
+ for (const ch of elements(el)) {
79640
+ const tag = ln(ch);
79641
+ if (!OBJ_TAGS.has(tag)) continue;
79642
+ if (tag === "container") {
79643
+ if (!collect(ch)) return false;
79644
+ } else if (renderingMatrix(ch)) leaves.push(ch);
79645
+ else return false;
79646
+ }
79647
+ return true;
79648
+ };
79649
+ if (!top || !collect(o.el)) return false;
79650
+ const org = findChildByLocalName(o.el, "orgSz");
79651
+ const box = rotatedBounds({ x: 0, y: 0, w: num2(org, "width"), h: num2(org, "height") }, [top]);
79652
+ const base2 = [1, 0, 0, 1, x - box.x, y - box.y];
79653
+ for (const leaf2 of leaves) {
79654
+ const m = mulAffine(base2, renderingMatrix(leaf2));
79655
+ const tag = ln(leaf2), lorg = findChildByLocalName(leaf2, "orgSz");
79656
+ const w = num2(lorg, "width") || num2(findChildByLocalName(leaf2, "curSz"), "width");
79657
+ const h = num2(lorg, "height") || num2(findChildByLocalName(leaf2, "curSz"), "height");
79658
+ ctx.regionRotations.push(m);
79659
+ emit(ctx, `<g transform="matrix(${m.slice(0, 4).map((v) => Math.round(v * 1e6) / 1e6).join(" ")} ${pt2(m[4])} ${pt2(m[5])})">`);
79660
+ const sub = { el: leaf2, tag, index: 0, inline: true, width: w, height: h, omL: 0, omR: 0 };
79661
+ if (tag === "pic") drawPicFrame(leaf2, 0, 0, w, h, "", ctx);
79662
+ else if (SHAPE_TAGS.has(tag)) drawShape(sub, 0, 0, ctx, depth + 1, [Math.hypot(m[0], m[1]) || 1, Math.hypot(m[2], m[3]) || 1]);
79663
+ else drawObject(sub, 0, 0, baseV, areaW, ctx, depth + 1);
79664
+ emit(ctx, "</g>");
79665
+ ctx.regionRotations.pop();
79666
+ }
79667
+ return true;
79668
+ }
79669
+ function drawShape(o, x, y, ctx, depth, groupScale) {
79670
+ const geometry = shapeGeometry(o, x, y, ctx.defs, ctx.images, (key, msg2) => warnOnce(ctx, key, msg2), !!groupScale);
79084
79671
  const b = geometry;
79085
79672
  if (geometry.rotation) ctx.regionRotations.push(geometry.rotation);
79086
79673
  ctx.stats.shapes++;
@@ -79092,7 +79679,17 @@ function drawShape(o, x, y, ctx, depth) {
79092
79679
  const dt = findChildByLocalName(o.el, "drawText");
79093
79680
  const sub = dt ? findChildByLocalName(dt, "subList") : null;
79094
79681
  if (sub) {
79095
- for (const p of elements(sub)) if (ln(p) === "p") drawPara(p, x, y, geometry.w, ctx, depth + 1);
79682
+ const [sx, sy] = groupScale != null ? groupScale : [1, 1];
79683
+ const unscale = sx !== 1 || sy !== 1;
79684
+ if (unscale) {
79685
+ emit(ctx, `<g transform="scale(${1 / sx} ${1 / sy})">`);
79686
+ ctx.regionRotations.push([1 / sx, 0, 0, 1 / sy, 0, 0]);
79687
+ }
79688
+ for (const p of elements(sub)) if (ln(p) === "p") drawPara(p, geometry.x * sx, geometry.y * sy, geometry.w * sx, ctx, depth + 1);
79689
+ if (unscale) {
79690
+ ctx.regionRotations.pop();
79691
+ emit(ctx, "</g>");
79692
+ }
79096
79693
  }
79097
79694
  if (geometry.rotation) ctx.regionRotations.pop();
79098
79695
  if (geometry.transform) emit(ctx, "</g>");
@@ -79175,16 +79772,31 @@ function imageSymbol(loaded, ctx) {
79175
79772
  }
79176
79773
  function drawPic(pic, x, y, ctx) {
79177
79774
  const sz = findChildByLocalName(pic, "sz");
79178
- const w = num2(sz, "width", 5669), h = num2(sz, "height", 5669);
79775
+ let w = num2(sz, "width", 5669), h = num2(sz, "height", 5669);
79776
+ const cur = findChildByLocalName(pic, "curSz");
79777
+ const rotated = objectGeometry(pic, x, y, num2(cur, "width") || w, num2(cur, "height") || h, w, h);
79778
+ if (rotated.rotation) {
79779
+ x = rotated.x;
79780
+ y = rotated.y;
79781
+ w = rotated.w;
79782
+ h = rotated.h;
79783
+ ctx.regionRotations.push(rotated.rotation);
79784
+ }
79785
+ drawPicFrame(pic, x, y, w, h, rotated.transform, ctx);
79786
+ if (rotated.rotation) ctx.regionRotations.pop();
79787
+ }
79788
+ function drawPicFrame(pic, x, y, w, h, transform, ctx) {
79179
79789
  const img = findFirst(pic, "img");
79180
79790
  const ref = img == null ? void 0 : img.getAttribute("binaryItemIDRef");
79181
79791
  const loaded = ref != null ? ctx.images.get(ref) : void 0;
79182
79792
  const imgId = ctx.regions.add("image", bboxOf(ctx, x, y, w, h), { sourceId: ref != null ? ref : void 0, parentId: parentId(ctx) });
79183
79793
  emit(ctx, regionOpenTag(imgId, "image", pageNo(ctx)));
79794
+ const close = transform ? "</g></g>" : "</g>";
79795
+ if (transform) emit(ctx, `<g transform="${transform}">`);
79184
79796
  if (!loaded) {
79185
79797
  emit(ctx, `<rect x="${pt2(x)}" y="${pt2(y)}" width="${pt2(w)}" height="${pt2(h)}" fill="#eee" stroke="#c00" stroke-width="0.5"/>`);
79186
79798
  warnOnce(ctx, `img:${ref}`, `\uC774\uBBF8\uC9C0 \uBC14\uC774\uB108\uB9AC \uB204\uB77D: ${ref != null ? ref : "(ref \uC5C6\uC74C)"}`);
79187
- emit(ctx, "</g>");
79799
+ emit(ctx, close);
79188
79800
  return;
79189
79801
  }
79190
79802
  ctx.stats.images++;
@@ -79206,7 +79818,7 @@ function drawPic(pic, x, y, ctx) {
79206
79818
  } else {
79207
79819
  emit(ctx, `<use href="#${symId}" x="${pt2(x)}" y="${pt2(y)}" width="${pt2(w)}" height="${pt2(h)}"/>`);
79208
79820
  }
79209
- emit(ctx, "</g>");
79821
+ emit(ctx, close);
79210
79822
  }
79211
79823
  function sniffMime(name, bytes) {
79212
79824
  const lower = name.toLowerCase();
@@ -79336,7 +79948,7 @@ async function renderHwpxInternal(input, options) {
79336
79948
  precheckZipSize(ab, MAX_DECOMPRESS_SIZE, MAX_ZIP_ENTRIES);
79337
79949
  let zip;
79338
79950
  try {
79339
- zip = await import_jszip14.default.loadAsync(input);
79951
+ zip = await import_jszip15.default.loadAsync(input);
79340
79952
  } catch {
79341
79953
  throw new KordocError("HWPX(ZIP) \uD615\uC2DD\uC774 \uC544\uB2D9\uB2C8\uB2E4 \u2014 \uB80C\uB354\uB294 HWPX\uB9CC \uC9C0\uC6D0");
79342
79954
  }
@@ -80373,6 +80985,7 @@ init_builder();
80373
80985
  init_page_markdown();
80374
80986
  init_utils();
80375
80987
  async function parse(input, options) {
80988
+ var _a2;
80376
80989
  let buffer;
80377
80990
  const opts = typeof input === "string" && !(options == null ? void 0 : options.filePath) ? { ...options, filePath: input } : options;
80378
80991
  if (typeof input === "string") {
@@ -80399,9 +81012,12 @@ async function parse(input, options) {
80399
81012
  }
80400
81013
  if (result.success && (opts == null ? void 0 : opts.classifyTables)) classifyTableTree(result.blocks);
80401
81014
  let out = result;
80402
- if (result.success && !result.pages) {
80403
- const pages = blocksToPages(result.blocks);
80404
- if (pages) out = { ...result, pages };
81015
+ if (result.success && (opts == null ? void 0 : opts.pages) && result.pageCount && parsePageRange(opts.pages, result.pageCount).size === 0) {
81016
+ out = { ...result, warnings: [...(_a2 = result.warnings) != null ? _a2 : [], { code: "PARTIAL_PARSE", message: `\uC694\uCCAD\uD55C \uCABD \uBC94\uC704(${opts.pages})\uAC00 \uBB38\uC11C \uCABD(1~${result.pageCount})\uACFC \uACB9\uCE58\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4` }] };
81017
+ }
81018
+ if (out.success && !out.pages) {
81019
+ const pages = blocksToPages(out.blocks);
81020
+ if (pages) out = { ...out, pages };
80405
81021
  }
80406
81022
  if (out.success && (opts == null ? void 0 : opts.plain)) {
80407
81023
  out = { ...out, markdown: toPlainMarkdown(out.markdown), ...out.pages ? { pages: out.pages.map((p) => ({ ...p, markdown: toPlainMarkdown(p.markdown) })) } : {} };
@@ -80428,9 +81044,7 @@ async function dispatch(format3, buffer, opts) {
80428
81044
  const zipFormat = await detectZipFormat(buffer);
80429
81045
  if (zipFormat === "xlsx") return parseXlsx(buffer, opts);
80430
81046
  if (zipFormat === "docx") return parseDocx(buffer, opts);
80431
- if (zipFormat === "pptx") {
80432
- return { success: false, fileType: "pptx", error: "PPTX \uD30C\uC77C\uC740 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD\uC785\uB2C8\uB2E4.", code: "UNSUPPORTED_FORMAT" };
80433
- }
81047
+ if (zipFormat === "pptx") return parsePptx(buffer, opts);
80434
81048
  return parseHwpx(buffer, opts);
80435
81049
  }
80436
81050
  case "hwp": {
@@ -80557,6 +81171,14 @@ async function parseDocx(buffer, options) {
80557
81171
  return { success: false, fileType: "docx", error: sanitizeError(err), code: classifyError(err) };
80558
81172
  }
80559
81173
  }
81174
+ async function parsePptx(buffer, options) {
81175
+ try {
81176
+ const { markdown, blocks, metadata, outline, warnings, images } = await parsePptxDocument(buffer, options);
81177
+ return scriptsOff({ success: true, fileType: "pptx", markdown, blocks, metadata, outline, warnings, images: (images == null ? void 0 : images.length) ? images : void 0, pageCount: metadata == null ? void 0 : metadata.pageCount }, (options == null ? void 0 : options.scriptTags) === false);
81178
+ } catch (err) {
81179
+ return { success: false, fileType: "pptx", error: sanitizeError(err), code: classifyError(err) };
81180
+ }
81181
+ }
80560
81182
  async function parseHwpml(buffer, options) {
80561
81183
  try {
80562
81184
  const { markdown, blocks, metadata, outline, warnings } = parseHwpmlDocument(buffer, options);
@@ -80670,6 +81292,7 @@ async function fillForm(input, values, outputFormat = "markdown") {
80670
81292
  parseHwpx,
80671
81293
  parseImage,
80672
81294
  parsePdf,
81295
+ parsePptx,
80673
81296
  parseXls,
80674
81297
  parseXlsx,
80675
81298
  patchHwp,