kordoc 4.18.1 → 4.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -6
- package/dist/{-X4KTLQC6.js → -WOKB25R2.js} +13 -11
- package/dist/{chunk-UTVMLJZE.js → chunk-2I2RTJJ5.js} +433 -71
- package/dist/chunk-2I2RTJJ5.js.map +1 -0
- package/dist/{chunk-Q5N4YS3T.cjs → chunk-2ZBLQVAS.cjs} +20 -13
- package/dist/chunk-2ZBLQVAS.cjs.map +1 -0
- package/dist/{chunk-KXR4CTFT.js → chunk-3FZGL3IL.js} +2 -2
- package/dist/{chunk-R2IFWAHI.js → chunk-5X7XWYR2.js} +2 -2
- package/dist/{chunk-PWRY4W6Q.js → chunk-6GLTGOP6.js} +2 -2
- package/dist/{chunk-SQQ4ITJ5.js → chunk-AZQWESRH.js} +2 -2
- package/dist/{chunk-KBZ3MQJX.js → chunk-BGOR5GCF.js} +2 -2
- package/dist/{chunk-WWOTHS2E.js → chunk-BJ6RYYXV.js} +205 -7
- package/dist/chunk-BJ6RYYXV.js.map +1 -0
- package/dist/{chunk-VDIXNEWV.js → chunk-CAN5P6N6.js} +10 -5
- package/dist/chunk-CAN5P6N6.js.map +1 -0
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-SIZ63E5G.cjs → chunk-HZV52V2X.cjs} +3 -3
- package/dist/chunk-HZV52V2X.cjs.map +1 -0
- package/dist/{chunk-X625PCZM.js → chunk-IXX3WHIE.js} +3 -3
- package/dist/{chunk-6V7QRQY3.js → chunk-J2A46VCA.js} +125 -87
- package/dist/chunk-J2A46VCA.js.map +1 -0
- package/dist/chunk-J55UQC5H.cjs.map +1 -1
- package/dist/{chunk-AQUNBGXH.js → chunk-KSJ7GKNQ.js} +2 -2
- package/dist/{chunk-Z4KCEERM.js → chunk-NES5U4JK.js} +3 -3
- package/dist/{chunk-MTTYJEKA.js → chunk-OOX2GZZ4.js} +2 -2
- package/dist/{chunk-HUGBJVAA.js → chunk-PSJLB3SZ.js} +16 -9
- package/dist/chunk-PSJLB3SZ.js.map +1 -0
- package/dist/{chunk-NQR3VKWN.js → chunk-RDBTOE5X.js} +2 -2
- package/dist/{chunk-2VFZQ634.js → chunk-RRURZDEK.js} +2 -2
- package/dist/{chunk-6N5BOPJI.js → chunk-RSDUH4XF.js} +4 -3
- package/dist/chunk-RSDUH4XF.js.map +1 -0
- package/dist/{chunk-PCSOJ523.cjs → chunk-SHRRD2TD.cjs} +10 -5
- package/dist/chunk-SHRRD2TD.cjs.map +1 -0
- package/dist/{chunk-TMC4A3FM.js → chunk-UVUKT3IQ.js} +13 -7
- package/dist/chunk-UVUKT3IQ.js.map +1 -0
- package/dist/{chunk-IXAXI2S3.cjs → chunk-V4BKT65D.cjs} +3 -3
- package/dist/chunk-V4BKT65D.cjs.map +1 -0
- package/dist/{chunk-I7YWXECO.js → chunk-VGDTONTB.js} +10 -5
- package/dist/chunk-VGDTONTB.js.map +1 -0
- package/dist/{chunk-K35WIYBD.js → chunk-W3RADOLO.js} +5 -4
- package/dist/chunk-W3RADOLO.js.map +1 -0
- package/dist/{chunk-5PNQIF3V.js → chunk-W7P4GPOV.js} +4 -4
- package/dist/{chunk-7DC2KL3V.cjs → chunk-WN5YLP7H.cjs} +161 -43
- package/dist/chunk-WN5YLP7H.cjs.map +1 -0
- package/dist/{chunk-IUMV45TX.cjs → chunk-ZD5WNQNC.cjs} +12 -12
- package/dist/chunk-ZD5WNQNC.cjs.map +1 -0
- package/dist/{chunk-CWJ5KY2F.js → chunk-ZN3LHNJG.js} +176 -43
- package/dist/chunk-ZN3LHNJG.js.map +1 -0
- package/dist/chunks-OQDRDICD.js +10 -0
- package/dist/cli.js +55 -34
- package/dist/cli.js.map +1 -1
- package/dist/{formula-W3GQC6L6.cjs → formula-BQ5RW5XD.cjs} +9 -9
- package/dist/formula-BQ5RW5XD.cjs.map +1 -0
- package/dist/{formula-LICM6K27.js → formula-GPCOJJXN.js} +3 -3
- package/dist/{formula-T4Q2UHWO.js → formula-QZAOKPBX.js} +4 -4
- package/dist/{image-ocr-WZJURDX6.js → image-ocr-POCME5I4.js} +6 -6
- package/dist/{image-ocr-XB2NFKGZ.js → image-ocr-TWNNVTZS.js} +9 -9
- package/dist/{image-ocr-7PNHBD2G.cjs → image-ocr-VKIUBLBX.cjs} +15 -15
- package/dist/image-ocr-VKIUBLBX.cjs.map +1 -0
- package/dist/index.cjs +1264 -778
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +606 -120
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +30 -31
- package/dist/mcp.js.map +1 -1
- package/dist/{model-bundle-O2XYR54X.js → model-bundle-THYUL7GG.js} +5 -5
- package/dist/{models-SKK3NH3V.js → models-U22N4RXX.js} +5 -5
- package/dist/page-range-QHHFTL7X.cjs.map +1 -1
- package/dist/{parser-PJUZSMFR.cjs → parser-JOMFOZLH.cjs} +213 -252
- package/dist/parser-JOMFOZLH.cjs.map +1 -0
- package/dist/{parser-4D2M5BKY.js → parser-NKP2NCSV.js} +27 -66
- package/dist/parser-NKP2NCSV.js.map +1 -0
- package/dist/{parser-5G5G7HHG.js → parser-SCXRLOW7.js} +24 -63
- package/dist/parser-SCXRLOW7.js.map +1 -0
- package/dist/pdf-ocr-NF4AY5MI.cjs +16 -0
- package/dist/pdf-ocr-NF4AY5MI.cjs.map +1 -0
- package/dist/pdf-ocr-OLII3WAG.js +15 -0
- package/dist/pdf-ocr-VJL7ON2Q.js +19 -0
- package/dist/{profile-io-BAQTYPK7.js → profile-io-UI3TZBYH.js} +3 -3
- package/dist/{rasterize-A2ZEACKV.js → rasterize-XMBV5H2I.js} +3 -3
- package/dist/{redact-doc-26KN2LSZ.js → redact-doc-7ZZMHDBO.js} +11 -11
- package/dist/{render-62ZUDMHB.js → render-SWRTUDAV.js} +7 -7
- package/dist/seal-UKKJZHKE.js +10 -0
- package/dist/{setup-2A3E6WRE.js → setup-43JJEEU7.js} +3 -3
- package/dist/visual-D2563HCJ.js +20 -0
- package/dist/{watch-D2T5FEKT.js → watch-NRATQ472.js} +14 -14
- package/dist/watch-NRATQ472.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-6N5BOPJI.js.map +0 -1
- package/dist/chunk-6V7QRQY3.js.map +0 -1
- package/dist/chunk-7DC2KL3V.cjs.map +0 -1
- package/dist/chunk-CWJ5KY2F.js.map +0 -1
- package/dist/chunk-HUGBJVAA.js.map +0 -1
- package/dist/chunk-I7YWXECO.js.map +0 -1
- package/dist/chunk-IUMV45TX.cjs.map +0 -1
- package/dist/chunk-IXAXI2S3.cjs.map +0 -1
- package/dist/chunk-K35WIYBD.js.map +0 -1
- package/dist/chunk-PCSOJ523.cjs.map +0 -1
- package/dist/chunk-Q5N4YS3T.cjs.map +0 -1
- package/dist/chunk-SIZ63E5G.cjs.map +0 -1
- package/dist/chunk-TMC4A3FM.js.map +0 -1
- package/dist/chunk-UTVMLJZE.js.map +0 -1
- package/dist/chunk-VDIXNEWV.js.map +0 -1
- package/dist/chunk-WWOTHS2E.js.map +0 -1
- package/dist/chunks-ACUC63N3.js +0 -10
- package/dist/formula-W3GQC6L6.cjs.map +0 -1
- package/dist/image-ocr-7PNHBD2G.cjs.map +0 -1
- package/dist/parser-4D2M5BKY.js.map +0 -1
- package/dist/parser-5G5G7HHG.js.map +0 -1
- package/dist/parser-PJUZSMFR.cjs.map +0 -1
- package/dist/pdf-ocr-EGWOIB6O.cjs +0 -16
- package/dist/pdf-ocr-EGWOIB6O.cjs.map +0 -1
- package/dist/pdf-ocr-NJTFXBRC.js +0 -19
- package/dist/pdf-ocr-ZXR6Q6BK.js +0 -15
- package/dist/seal-3GXC2API.js +0 -10
- package/dist/visual-4ZBZRMCM.js +0 -20
- package/dist/watch-D2T5FEKT.js.map +0 -1
- /package/dist/{-X4KTLQC6.js.map → -WOKB25R2.js.map} +0 -0
- /package/dist/{chunk-KXR4CTFT.js.map → chunk-3FZGL3IL.js.map} +0 -0
- /package/dist/{chunk-R2IFWAHI.js.map → chunk-5X7XWYR2.js.map} +0 -0
- /package/dist/{chunk-PWRY4W6Q.js.map → chunk-6GLTGOP6.js.map} +0 -0
- /package/dist/{chunk-SQQ4ITJ5.js.map → chunk-AZQWESRH.js.map} +0 -0
- /package/dist/{chunk-KBZ3MQJX.js.map → chunk-BGOR5GCF.js.map} +0 -0
- /package/dist/{chunk-X625PCZM.js.map → chunk-IXX3WHIE.js.map} +0 -0
- /package/dist/{chunk-AQUNBGXH.js.map → chunk-KSJ7GKNQ.js.map} +0 -0
- /package/dist/{chunk-Z4KCEERM.js.map → chunk-NES5U4JK.js.map} +0 -0
- /package/dist/{chunk-MTTYJEKA.js.map → chunk-OOX2GZZ4.js.map} +0 -0
- /package/dist/{chunk-NQR3VKWN.js.map → chunk-RDBTOE5X.js.map} +0 -0
- /package/dist/{chunk-2VFZQ634.js.map → chunk-RRURZDEK.js.map} +0 -0
- /package/dist/{chunk-5PNQIF3V.js.map → chunk-W7P4GPOV.js.map} +0 -0
- /package/dist/{chunks-ACUC63N3.js.map → chunks-OQDRDICD.js.map} +0 -0
- /package/dist/{formula-LICM6K27.js.map → formula-GPCOJJXN.js.map} +0 -0
- /package/dist/{formula-T4Q2UHWO.js.map → formula-QZAOKPBX.js.map} +0 -0
- /package/dist/{image-ocr-WZJURDX6.js.map → image-ocr-POCME5I4.js.map} +0 -0
- /package/dist/{image-ocr-XB2NFKGZ.js.map → image-ocr-TWNNVTZS.js.map} +0 -0
- /package/dist/{model-bundle-O2XYR54X.js.map → model-bundle-THYUL7GG.js.map} +0 -0
- /package/dist/{models-SKK3NH3V.js.map → models-U22N4RXX.js.map} +0 -0
- /package/dist/{pdf-ocr-NJTFXBRC.js.map → pdf-ocr-OLII3WAG.js.map} +0 -0
- /package/dist/{pdf-ocr-ZXR6Q6BK.js.map → pdf-ocr-VJL7ON2Q.js.map} +0 -0
- /package/dist/{profile-io-BAQTYPK7.js.map → profile-io-UI3TZBYH.js.map} +0 -0
- /package/dist/{rasterize-A2ZEACKV.js.map → rasterize-XMBV5H2I.js.map} +0 -0
- /package/dist/{redact-doc-26KN2LSZ.js.map → redact-doc-7ZZMHDBO.js.map} +0 -0
- /package/dist/{render-62ZUDMHB.js.map → render-SWRTUDAV.js.map} +0 -0
- /package/dist/{seal-3GXC2API.js.map → seal-UKKJZHKE.js.map} +0 -0
- /package/dist/{setup-2A3E6WRE.js.map → setup-43JJEEU7.js.map} +0 -0
- /package/dist/{visual-4ZBZRMCM.js.map → visual-D2563HCJ.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
blocksToPages
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6GLTGOP6.js";
|
|
5
5
|
import {
|
|
6
6
|
allLinesegRemovalSplices,
|
|
7
7
|
applySplices,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
paraTextPureT,
|
|
16
16
|
patchZipEntries,
|
|
17
17
|
scanSectionXml
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-NES5U4JK.js";
|
|
19
19
|
import {
|
|
20
20
|
CONVERT_MAP,
|
|
21
21
|
FLAG_COMPRESSED,
|
|
@@ -31,6 +31,8 @@ import {
|
|
|
31
31
|
TAG_PARA_HEADER,
|
|
32
32
|
TAG_PARA_TEXT,
|
|
33
33
|
TAG_TABLE,
|
|
34
|
+
TOC_ENTRY_BLOCKS,
|
|
35
|
+
TOC_LEADER,
|
|
34
36
|
appendParaText,
|
|
35
37
|
blocksPlainText,
|
|
36
38
|
buildAddressedTable,
|
|
@@ -61,19 +63,21 @@ import {
|
|
|
61
63
|
prepareWrap,
|
|
62
64
|
renderDocumentToScene,
|
|
63
65
|
romanNumeral,
|
|
64
|
-
simulateWrap
|
|
65
|
-
|
|
66
|
+
simulateWrap,
|
|
67
|
+
takeTocLeaders
|
|
68
|
+
} from "./chunk-ZN3LHNJG.js";
|
|
66
69
|
import {
|
|
67
70
|
CELL_EDGES,
|
|
68
71
|
HEADING_RATIO_H1,
|
|
69
72
|
HEADING_RATIO_H2,
|
|
70
73
|
HEADING_RATIO_H3,
|
|
74
|
+
escapeLiteralTags,
|
|
71
75
|
plainScripts,
|
|
72
76
|
stripScriptTags,
|
|
73
77
|
tidyScriptTags,
|
|
74
78
|
unframeLayoutTables,
|
|
75
79
|
wrapScript
|
|
76
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-UVUKT3IQ.js";
|
|
77
81
|
import {
|
|
78
82
|
parsePageRange
|
|
79
83
|
} from "./chunk-VQFA55IC.js";
|
|
@@ -92,7 +96,7 @@ import {
|
|
|
92
96
|
findChildByLocalName,
|
|
93
97
|
localName,
|
|
94
98
|
rawTextContent
|
|
95
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-RSDUH4XF.js";
|
|
96
100
|
import {
|
|
97
101
|
MAX_COLS,
|
|
98
102
|
MAX_ROWS,
|
|
@@ -107,7 +111,7 @@ import {
|
|
|
107
111
|
hasStructuredCellContent,
|
|
108
112
|
mapPuaText,
|
|
109
113
|
noteSuffix
|
|
110
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-W3RADOLO.js";
|
|
111
115
|
import {
|
|
112
116
|
KordocError,
|
|
113
117
|
classifyError,
|
|
@@ -115,6 +119,7 @@ import {
|
|
|
115
119
|
escapeHtml,
|
|
116
120
|
isPathTraversal,
|
|
117
121
|
normalizeSectionHref,
|
|
122
|
+
partExtension,
|
|
118
123
|
precheckZipSize,
|
|
119
124
|
sanitizeError,
|
|
120
125
|
sanitizeHref,
|
|
@@ -122,20 +127,20 @@ import {
|
|
|
122
127
|
toArrayBuffer,
|
|
123
128
|
unescapeHtml,
|
|
124
129
|
unzipLimitBytes
|
|
125
|
-
} from "./chunk-
|
|
130
|
+
} from "./chunk-VGDTONTB.js";
|
|
126
131
|
|
|
127
132
|
// src/table/visual.ts
|
|
128
133
|
import { readFile as readFile2 } from "fs/promises";
|
|
129
134
|
|
|
130
135
|
// src/plain-markdown.ts
|
|
131
136
|
function toPlainMarkdown(md) {
|
|
132
|
-
return plainScripts(md).replace(/!\[[^\]\n]*\]\([^)\n]*\)/g, "").replace(/<img\b[^>]*>/gi, "").replace(/(?<!!)\[([^\]\n]*)\]\((?:https?|mailto|ftp):[^)\s]*\)/g, "$1").replace(
|
|
137
|
+
return plainScripts(md).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();
|
|
133
138
|
}
|
|
134
139
|
|
|
135
140
|
// src/html-tables.ts
|
|
136
141
|
var TABLE_TAG = /(<\/?(?:table|tr|th|td)\b[^>]*>)/i;
|
|
137
142
|
function pipeCellToHtml(cell2) {
|
|
138
|
-
return cell2.split(/(<br
|
|
143
|
+
return cell2.split(/(<br>|(?<!\\)<\/?(?:u|sup|sub)>|<img\b[^>]*>)/).map((part, i) => i % 2 ? part : part.replace(/\\([\\`*_{}[\]()#+\-.!|~<>$])/g, "$1").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")).join("");
|
|
139
144
|
}
|
|
140
145
|
function splitPipeRow(line) {
|
|
141
146
|
const t = line.trim().replace(/^\|/, "").replace(/(?<!\\)\|$/, "");
|
|
@@ -628,7 +633,7 @@ function parseParaHeadings(doc, map) {
|
|
|
628
633
|
if (map.size > 0) break;
|
|
629
634
|
}
|
|
630
635
|
}
|
|
631
|
-
function detectHwpxHeadings(blocks, styleMap) {
|
|
636
|
+
function detectHwpxHeadings(blocks, styleMap, tocTexts) {
|
|
632
637
|
if (blocks.some((b) => b.type === "heading")) return;
|
|
633
638
|
let baseFontSize = 0;
|
|
634
639
|
const sizeFreq = /* @__PURE__ */ new Map();
|
|
@@ -645,7 +650,7 @@ function detectHwpxHeadings(blocks, styleMap) {
|
|
|
645
650
|
}
|
|
646
651
|
}
|
|
647
652
|
for (const block of blocks) {
|
|
648
|
-
if (block.type !== "paragraph" || !block.text) continue;
|
|
653
|
+
if (block.type !== "paragraph" || !block.text || TOC_ENTRY_BLOCKS.has(block) || tocTexts?.has(block.text.trim())) continue;
|
|
649
654
|
const text = block.text.trim();
|
|
650
655
|
if (text.length === 0 || text.length > 200 || /^\d+$/.test(text)) continue;
|
|
651
656
|
let level = 0;
|
|
@@ -1183,7 +1188,7 @@ function extractRunSpans(para2, ctx, mode, requireMixed) {
|
|
|
1183
1188
|
const tkids = rc.childNodes;
|
|
1184
1189
|
for (let k = 0; k < (tkids?.length ?? 0); k++) {
|
|
1185
1190
|
const tk = tkids[k];
|
|
1186
|
-
if (tk.nodeType === 3 || tk.nodeType === 4) text += escapeLiteralDollar(tk.textContent || "");
|
|
1191
|
+
if (tk.nodeType === 3 || tk.nodeType === 4) text += escapeLiteralTags(escapeLiteralDollar(tk.textContent || ""));
|
|
1187
1192
|
else if (tk.nodeType === 1) {
|
|
1188
1193
|
const ttag = (tk.tagName || tk.localName || "").replace(/^[^:]+:/, "");
|
|
1189
1194
|
if (ttag === "tab" || ttag === "fwSpace" || ttag === "hwSpace" || ttag === "nbSpace") text += " ";
|
|
@@ -1297,13 +1302,13 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
|
|
|
1297
1302
|
}
|
|
1298
1303
|
if (tableCtx) tableStack.push(tableCtx);
|
|
1299
1304
|
const newTable = { rows: [], currentRow: [], cell: null, sourceId: el.getAttribute("id") ?? void 0 };
|
|
1300
|
-
walkSection(el, blocks, newTable, tableStack, ctx, depth + 1);
|
|
1305
|
+
inIndependentDeletionStory(ctx.shared.track, () => walkSection(el, blocks, newTable, tableStack, ctx, depth + 1));
|
|
1301
1306
|
tableCtx = completeTable(newTable, tableStack, blocks, ctx);
|
|
1302
1307
|
break;
|
|
1303
1308
|
}
|
|
1304
1309
|
// 표/도표 캡션 — IRTable.caption으로 보존 (v3.0, 기존 무음 드롭 수정)
|
|
1305
1310
|
case "caption": {
|
|
1306
|
-
const cap = collectSubListContent(el, ctx);
|
|
1311
|
+
const cap = inIndependentDeletionStory(ctx.shared.track, () => collectSubListContent(el, ctx));
|
|
1307
1312
|
if (cap.text) {
|
|
1308
1313
|
if (tableCtx) {
|
|
1309
1314
|
tableCtx.caption = (tableCtx.caption ? tableCtx.caption + "\n" : "") + cap.text;
|
|
@@ -1356,13 +1361,16 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
|
|
|
1356
1361
|
case "p": {
|
|
1357
1362
|
const paraPg = ctx.paraPage?.get(el);
|
|
1358
1363
|
if (paraPg !== void 0 && ctx.pageBase !== void 0) ctx.page = ctx.pageBase + paraPg + 1;
|
|
1359
|
-
const { text: rawText, href, footnote, style, segments, placeholderSpans } = extractParagraphInfo(el, ctx.styleMap, ctx);
|
|
1364
|
+
const { text: rawText, href, footnote, style, segments, placeholderSpans, tocEntry } = extractParagraphInfo(el, ctx.styleMap, ctx);
|
|
1360
1365
|
let text = rawText;
|
|
1361
1366
|
let headingLevel;
|
|
1362
1367
|
const ph = resolveParaHeading(el, ctx);
|
|
1363
1368
|
if (text) {
|
|
1364
1369
|
if (ph?.prefix) text = ph.prefix + " " + text;
|
|
1365
|
-
headingLevel = ph?.headingLevel;
|
|
1370
|
+
headingLevel = tocEntry ? void 0 : ph?.headingLevel;
|
|
1371
|
+
if (tocEntry) {
|
|
1372
|
+
for (const line of text.split("\n")) if (line.trim()) ctx.shared.tocTexts.add(line.trim());
|
|
1373
|
+
}
|
|
1366
1374
|
}
|
|
1367
1375
|
if (segments) {
|
|
1368
1376
|
const cell2 = tableCtx?.cell ?? null;
|
|
@@ -1424,6 +1432,7 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
|
|
|
1424
1432
|
}
|
|
1425
1433
|
const block = { type: headingLevel ? "heading" : "paragraph", text, pageNumber: ctx.page };
|
|
1426
1434
|
if (headingLevel) block.level = headingLevel;
|
|
1435
|
+
if (tocEntry) TOC_ENTRY_BLOCKS.add(block);
|
|
1427
1436
|
if (style) block.style = style;
|
|
1428
1437
|
if (href) block.href = href;
|
|
1429
1438
|
if (footnote) block.footnoteText = footnote;
|
|
@@ -1447,6 +1456,15 @@ function walkSection(node, blocks, tableCtx, tableStack, ctx, depth = 0) {
|
|
|
1447
1456
|
if (spanMode !== "foreign" && el.getAttribute("paraPrIDRef") === KORDOC_PARA_QUOTE) block.quote = true;
|
|
1448
1457
|
}
|
|
1449
1458
|
if (!headingLevel && !block.spans && placeholderSpans) block.spans = withPrefixSpan(placeholderSpans, ph?.prefix);
|
|
1459
|
+
if (headingLevel && placeholderSpans) {
|
|
1460
|
+
const shown = withPrefixSpan(placeholderSpans.filter((s) => !s.placeholder), ph?.prefix).map((s) => s.text).join("").trim();
|
|
1461
|
+
if (shown) block.text = shown;
|
|
1462
|
+
else {
|
|
1463
|
+
block.type = "paragraph";
|
|
1464
|
+
delete block.level;
|
|
1465
|
+
block.spans = withPrefixSpan(placeholderSpans, ph?.prefix);
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1450
1468
|
blocks.push(block);
|
|
1451
1469
|
} else {
|
|
1452
1470
|
blocks.push({ type: "paragraph", text, pageNumber: ctx.page });
|
|
@@ -1688,10 +1706,10 @@ function walkParagraphChildren(node, blocks, tableCtx, tableStack, ctx, depth =
|
|
|
1688
1706
|
}
|
|
1689
1707
|
if (tableCtx) tableStack.push(tableCtx);
|
|
1690
1708
|
const newTable = { rows: [], currentRow: [], cell: null, inline: isInlineTbl(el), sourceId: el.getAttribute("id") ?? void 0 };
|
|
1691
|
-
walkSection(el, blocks, newTable, tableStack, ctx, d + 1);
|
|
1709
|
+
inIndependentDeletionStory(ctx.shared.track, () => walkSection(el, blocks, newTable, tableStack, ctx, d + 1));
|
|
1692
1710
|
tableCtx = completeTable(newTable, tableStack, blocks, ctx);
|
|
1693
1711
|
} else if (localTag === "caption" && !inShape) {
|
|
1694
|
-
const cap = collectSubListContent(el, ctx);
|
|
1712
|
+
const cap = inIndependentDeletionStory(ctx.shared.track, () => collectSubListContent(el, ctx));
|
|
1695
1713
|
if (cap.text) {
|
|
1696
1714
|
if (tableCtx?.cell) mergeBlocksIntoCell(tableCtx.cell, [{ type: "paragraph", text: cap.text, pageNumber: ctx.page }]);
|
|
1697
1715
|
else if (tableCtx) {
|
|
@@ -1856,7 +1874,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
|
|
|
1856
1874
|
const open = openFields.pop();
|
|
1857
1875
|
if (open?.rangeIdx !== void 0) linkRanges[open.rangeIdx].end = text.length;
|
|
1858
1876
|
if (open?.guide !== void 0 && open.start !== void 0) {
|
|
1859
|
-
const value = text.slice(open.start).replace(
|
|
1877
|
+
const value = text.slice(open.start).replace(/\\([$<])/g, "$1");
|
|
1860
1878
|
if (value && (value === open.guide || value.trimEnd() === open.guide)) {
|
|
1861
1879
|
text = text.slice(0, open.start) + PH_OPEN + text.slice(open.start) + PH_CLOSE;
|
|
1862
1880
|
}
|
|
@@ -1887,7 +1905,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
|
|
|
1887
1905
|
// 아니므로 방출하지 않는다
|
|
1888
1906
|
case "header":
|
|
1889
1907
|
case "footer": {
|
|
1890
|
-
if (!ctx) break;
|
|
1908
|
+
if (!ctx || isInDeletedRange(ctx)) break;
|
|
1891
1909
|
const t = collectSubListText(k, ctx);
|
|
1892
1910
|
if (t && hasPageAutoNum(k) && !/\p{L}/u.test(t)) break;
|
|
1893
1911
|
if (t) {
|
|
@@ -1965,7 +1983,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
|
|
|
1965
1983
|
ctx.warnings?.push({ page: ctx.page, message: "\uBCC0\uACBD\uCD94\uC801 \uC0AD\uC81C \uD14D\uC2A4\uD2B8 \uCD9C\uB825 \uC81C\uC678", code: "HIDDEN_TEXT_FILTERED" });
|
|
1966
1984
|
}
|
|
1967
1985
|
} else {
|
|
1968
|
-
text += escapeLiteralDollar(t.replace(/\x1E/g, ""));
|
|
1986
|
+
text += escapeLiteralTags(escapeLiteralDollar(t.replace(/\x1E/g, "")));
|
|
1969
1987
|
}
|
|
1970
1988
|
continue;
|
|
1971
1989
|
}
|
|
@@ -1985,8 +2003,9 @@ function extractParagraphInfo(para2, styleMap, ctx) {
|
|
|
1985
2003
|
// 점 채움을 탭 하나로 바꾸고 쪽 번호를 남기는 것과 같다). 종전엔 채움 탭 뒤를 쪽 번호로 보고 잘라, 목차 쪽 번호만이 아니라
|
|
1986
2004
|
// 일정표 "사용자 의견조사 ····· '26년 8~9월"(gate-fill 36646162)의 일정, 줄바꿈 뒤 다음 목차 항목
|
|
1987
2005
|
// "<참고2> 직종별사업체노동력조사 개요"(rhwp issue6044)까지 사라졌다
|
|
2006
|
+
// (채움 탭은 목차 항목 판정까지 TOC_LEADER 표지로 들고 가다 보통 탭으로 바꾼다 — toc-entry.ts)
|
|
1988
2007
|
case "tab":
|
|
1989
|
-
text += " ";
|
|
2008
|
+
text += /^(?:|0|NONE)$/i.test(child.getAttribute("leader") ?? "") ? " " : TOC_LEADER;
|
|
1990
2009
|
break;
|
|
1991
2010
|
case "br":
|
|
1992
2011
|
if ((child.getAttribute("type") || "line") === "line") text += "\n";
|
|
@@ -2008,9 +2027,10 @@ function extractParagraphInfo(para2, styleMap, ctx) {
|
|
|
2008
2027
|
if (isInlineTbl(child)) text += "";
|
|
2009
2028
|
break;
|
|
2010
2029
|
// 양식 선택 상자·라디오 단추 — 한컴이 그리는 상자 기호와 캡션 글 (종전엔 통째로 빠졌다: form-002 "원천기술형"·서울 결재 "부분공개")
|
|
2030
|
+
// 지운 구간의 양식 단추·수식은 글처럼 내지 않는다 (최종본)
|
|
2011
2031
|
case "checkBtn":
|
|
2012
2032
|
case "radioBtn":
|
|
2013
|
-
text += formButtonText(child, tag === "radioBtn");
|
|
2033
|
+
if (!isInDeletedRange(ctx)) text += formButtonText(child, tag === "radioBtn");
|
|
2014
2034
|
break;
|
|
2015
2035
|
// 하이퍼링크
|
|
2016
2036
|
case "hyperlink": {
|
|
@@ -2080,6 +2100,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
|
|
|
2080
2100
|
// 스크립트가 담겨 있음. hml-equation-parser 로 LaTeX 변환 후 `$...$`
|
|
2081
2101
|
// 로 래핑. 실패/빈 스크립트면 무시 (대체 텍스트 누출 방지).
|
|
2082
2102
|
case "equation": {
|
|
2103
|
+
if (isInDeletedRange(ctx)) break;
|
|
2083
2104
|
const script = findChildByLocalName(child, "script");
|
|
2084
2105
|
const raw = script ? extractTextFromNode(script) : "";
|
|
2085
2106
|
if (raw.trim()) {
|
|
@@ -2133,6 +2154,9 @@ function extractParagraphInfo(para2, styleMap, ctx) {
|
|
|
2133
2154
|
if (applied.length) href = void 0;
|
|
2134
2155
|
}
|
|
2135
2156
|
text = tidyScriptTags(text);
|
|
2157
|
+
const toc = takeTocLeaders(text);
|
|
2158
|
+
text = toc.text;
|
|
2159
|
+
const tocEntry = toc.tocEntry;
|
|
2136
2160
|
const cleanParaText = (raw) => {
|
|
2137
2161
|
let t = raw.replace(/[ \t]+/g, " ").trim();
|
|
2138
2162
|
if (/^그림입니다\.?\s*원본\s*그림의\s*(이름|크기)/.test(t)) t = "";
|
|
@@ -2168,7 +2192,7 @@ function extractParagraphInfo(para2, styleMap, ctx) {
|
|
|
2168
2192
|
if (!style.fontSize && !style.bold && !style.italic) style = void 0;
|
|
2169
2193
|
}
|
|
2170
2194
|
}
|
|
2171
|
-
return { text: cleanText, href, footnote, style, segments, placeholderSpans };
|
|
2195
|
+
return { text: cleanText, href, footnote, style, segments, placeholderSpans, ...tocEntry ? { tocEntry } : {} };
|
|
2172
2196
|
}
|
|
2173
2197
|
function withPrefixSpan(spans, prefix) {
|
|
2174
2198
|
return prefix ? [{ text: prefix + " " }, ...spans] : spans;
|
|
@@ -2647,7 +2671,7 @@ async function parseHwpxDocument(buffer, options) {
|
|
|
2647
2671
|
applyPageText(blocks, shared);
|
|
2648
2672
|
const images = await extractImagesFromZip(zip, blocks, decompressed, warnings, !options?.pages, shared.track.deletedImageRefs);
|
|
2649
2673
|
const shown = options?.layoutTables === "keep" ? blocks : unframeLayoutTables(blocks, !!options?.keepTrailingEmptyCols);
|
|
2650
|
-
detectHwpxHeadings(shown, styleMap);
|
|
2674
|
+
detectHwpxHeadings(shown, styleMap, shared.tocTexts);
|
|
2651
2675
|
const outline = shown.filter((b) => b.type === "heading" && b.level && b.text).map((b) => ({ level: b.level, text: b.text, pageNumber: b.pageNumber }));
|
|
2652
2676
|
const markdown = blocksToMarkdown(shown);
|
|
2653
2677
|
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 };
|
|
@@ -15384,7 +15408,7 @@ function parseCharStream(reader, charCount, ctx, para2) {
|
|
|
15384
15408
|
continue;
|
|
15385
15409
|
}
|
|
15386
15410
|
if (ch >= 32) {
|
|
15387
|
-
para2.text += escapeLiteralDollar(decodeJohabText(ch) ?? "");
|
|
15411
|
+
para2.text += escapeLiteralTags(escapeLiteralDollar(decodeJohabText(ch) ?? ""));
|
|
15388
15412
|
continue;
|
|
15389
15413
|
}
|
|
15390
15414
|
if (ch === 9) {
|
|
@@ -15732,7 +15756,7 @@ function collectRichText(root) {
|
|
|
15732
15756
|
const el = children[i];
|
|
15733
15757
|
const local = el.localName || el.tagName?.replace(/^[^:]+:/, "") || "";
|
|
15734
15758
|
if (local === "rPh") continue;
|
|
15735
|
-
if (local === "t") out += el.textContent ?? "";
|
|
15759
|
+
if (local === "t") out += escapeLiteralTags(escapeLiteralDollar(el.textContent ?? ""));
|
|
15736
15760
|
else walk(el);
|
|
15737
15761
|
}
|
|
15738
15762
|
};
|
|
@@ -16356,14 +16380,14 @@ function extractSheetCells(records, bofIndex, sst, convertNum) {
|
|
|
16356
16380
|
const h = readCellHeader(rec.data);
|
|
16357
16381
|
if (h && rec.data.length >= 10) {
|
|
16358
16382
|
const isst = rec.data.readUInt32LE(6);
|
|
16359
|
-
cells.push({ row: h.row, col: h.col, value: sst[isst] ?? "" });
|
|
16383
|
+
cells.push({ row: h.row, col: h.col, value: escapeLiteralTags(escapeLiteralDollar(sst[isst] ?? "")) });
|
|
16360
16384
|
}
|
|
16361
16385
|
break;
|
|
16362
16386
|
}
|
|
16363
16387
|
case OP_LABEL: {
|
|
16364
16388
|
const h = readCellHeader(rec.data);
|
|
16365
16389
|
if (h) {
|
|
16366
|
-
cells.push({ row: h.row, col: h.col, value: decodeLabelString(rec.data) });
|
|
16390
|
+
cells.push({ row: h.row, col: h.col, value: escapeLiteralTags(escapeLiteralDollar(decodeLabelString(rec.data))) });
|
|
16367
16391
|
}
|
|
16368
16392
|
break;
|
|
16369
16393
|
}
|
|
@@ -16379,7 +16403,7 @@ function extractSheetCells(records, bofIndex, sst, convertNum) {
|
|
|
16379
16403
|
cells.push({
|
|
16380
16404
|
row: h.row,
|
|
16381
16405
|
col: h.col,
|
|
16382
|
-
value: decodeFormulaStringRecord(next.data)
|
|
16406
|
+
value: escapeLiteralTags(escapeLiteralDollar(decodeFormulaStringRecord(next.data)))
|
|
16383
16407
|
});
|
|
16384
16408
|
i = j;
|
|
16385
16409
|
} else {
|
|
@@ -17091,6 +17115,7 @@ function isDisplayMath(el) {
|
|
|
17091
17115
|
// src/docx/parser.ts
|
|
17092
17116
|
var MAX_DECOMPRESS_SIZE4 = unzipLimitBytes(100 * 1024 * 1024);
|
|
17093
17117
|
var MEDIA_PART_RE = /^word\/(?:media|embeddings)\//;
|
|
17118
|
+
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;
|
|
17094
17119
|
function matchesLocal(el, localName3) {
|
|
17095
17120
|
return el.localName === localName3 || (el.tagName?.endsWith(`:${localName3}`) ?? false);
|
|
17096
17121
|
}
|
|
@@ -17282,7 +17307,7 @@ function parseFootnotes(xml) {
|
|
|
17282
17307
|
const runs = findElements(p, "r");
|
|
17283
17308
|
for (const r of runs) {
|
|
17284
17309
|
const tElements = getChildElements(r, "t");
|
|
17285
|
-
for (const t of tElements) texts.push(t.textContent ?? "");
|
|
17310
|
+
for (const t of tElements) texts.push(escapeLiteralTags(escapeLiteralDollar(t.textContent ?? "")));
|
|
17286
17311
|
}
|
|
17287
17312
|
}
|
|
17288
17313
|
notes.set(id, texts.join("").trim());
|
|
@@ -17313,7 +17338,7 @@ function collectOmmlRoots(p) {
|
|
|
17313
17338
|
function extractRun(r) {
|
|
17314
17339
|
let text = "";
|
|
17315
17340
|
for (const el of effectiveChildElements(r)) {
|
|
17316
|
-
if (matchesLocal(el, "t")) text += el.textContent ?? "";
|
|
17341
|
+
if (matchesLocal(el, "t")) text += escapeLiteralTags(escapeLiteralDollar(el.textContent ?? ""));
|
|
17317
17342
|
else if (matchesLocal(el, "br") || matchesLocal(el, "cr")) text += "\n";
|
|
17318
17343
|
else if (matchesLocal(el, "tab")) text += " ";
|
|
17319
17344
|
else if (matchesLocal(el, "sym")) text += symbolChar(getAttr(el, "font"), getAttr(el, "char"));
|
|
@@ -17609,7 +17634,7 @@ async function buildImageMap(zip, rels, doc, warnings, readBytes) {
|
|
|
17609
17634
|
let data = null;
|
|
17610
17635
|
if (readBytes) data = await imgFile.async("uint8array");
|
|
17611
17636
|
imgIdx++;
|
|
17612
|
-
const ext = imgPath
|
|
17637
|
+
const ext = partExtension(imgPath);
|
|
17613
17638
|
const mimeMap = {
|
|
17614
17639
|
png: "image/png",
|
|
17615
17640
|
jpg: "image/jpeg",
|
|
@@ -17708,7 +17733,7 @@ async function parseHeaderFooterBlocks(zip, doc, rels, kind, styles, numbering,
|
|
|
17708
17733
|
}
|
|
17709
17734
|
async function parseDocxDocument(buffer, options) {
|
|
17710
17735
|
const readImages = options?.images !== false;
|
|
17711
|
-
precheckZipSize(buffer, MAX_DECOMPRESS_SIZE4, void 0, { re: MEDIA_PART_RE, skip: !readImages });
|
|
17736
|
+
precheckZipSize(buffer, MAX_DECOMPRESS_SIZE4, void 0, { re: MEDIA_PART_RE, skip: !readImages, never: NEVER_READ_RE });
|
|
17712
17737
|
const zip = await JSZip4.loadAsync(buffer);
|
|
17713
17738
|
const warnings = [];
|
|
17714
17739
|
const docFile = zip.file("word/document.xml");
|
|
@@ -17824,8 +17849,328 @@ async function parseDocxDocument(buffer, options) {
|
|
|
17824
17849
|
};
|
|
17825
17850
|
}
|
|
17826
17851
|
|
|
17827
|
-
// src/
|
|
17852
|
+
// src/pptx/parser.ts
|
|
17853
|
+
import JSZip5 from "jszip";
|
|
17828
17854
|
import { DOMParser as DOMParser3 } from "@xmldom/xmldom";
|
|
17855
|
+
var MAX_DECOMPRESS_SIZE5 = unzipLimitBytes(100 * 1024 * 1024);
|
|
17856
|
+
var MEDIA_PART_RE2 = /^ppt\/(?:media|embeddings)\//;
|
|
17857
|
+
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;
|
|
17858
|
+
var MAX_ZIP_ENTRIES2 = 1e4;
|
|
17859
|
+
var MAX_SLIDES = 2e3;
|
|
17860
|
+
var SKIP_PLACEHOLDERS = /* @__PURE__ */ new Set(["sldNum", "dt", "ftr", "hdr", "sldImg"]);
|
|
17861
|
+
var BULLET_PLACEHOLDERS = /* @__PURE__ */ new Set(["body", "obj"]);
|
|
17862
|
+
var REL_NOTES = "/notesSlide";
|
|
17863
|
+
var REL_IMAGE = "/image";
|
|
17864
|
+
var SLIDE_PART_RE = /^ppt\/slides\/slide(\d+)\.xml$/;
|
|
17865
|
+
var IMAGE_MIME = {
|
|
17866
|
+
png: "image/png",
|
|
17867
|
+
jpg: "image/jpeg",
|
|
17868
|
+
jpeg: "image/jpeg",
|
|
17869
|
+
gif: "image/gif",
|
|
17870
|
+
bmp: "image/bmp",
|
|
17871
|
+
wmf: "image/wmf",
|
|
17872
|
+
emf: "image/emf",
|
|
17873
|
+
tif: "image/tiff",
|
|
17874
|
+
tiff: "image/tiff",
|
|
17875
|
+
svg: "image/svg+xml"
|
|
17876
|
+
};
|
|
17877
|
+
function parseXml3(text) {
|
|
17878
|
+
return new DOMParser3().parseFromString(stripDtd(text), "text/xml");
|
|
17879
|
+
}
|
|
17880
|
+
function getAttr2(el, name) {
|
|
17881
|
+
const attrs = el.attributes;
|
|
17882
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
17883
|
+
const attr = attrs[i];
|
|
17884
|
+
if (attr.localName === name || attr.name === name) return attr.value;
|
|
17885
|
+
}
|
|
17886
|
+
return null;
|
|
17887
|
+
}
|
|
17888
|
+
var NS_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
17889
|
+
function getRelId(el) {
|
|
17890
|
+
const attrs = el.attributes;
|
|
17891
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
17892
|
+
const attr = attrs[i];
|
|
17893
|
+
if (attr.localName === "id" && (attr.namespaceURI === NS_REL || attr.name === "r:id")) return attr.value;
|
|
17894
|
+
}
|
|
17895
|
+
return null;
|
|
17896
|
+
}
|
|
17897
|
+
function findPath(el, ...names) {
|
|
17898
|
+
for (const name of names) {
|
|
17899
|
+
if (!el) return null;
|
|
17900
|
+
el = findChildByLocalName(el, name);
|
|
17901
|
+
}
|
|
17902
|
+
return el;
|
|
17903
|
+
}
|
|
17904
|
+
function resolvePart(baseDir, target) {
|
|
17905
|
+
if (target.startsWith("/")) return target.slice(1);
|
|
17906
|
+
const parts = baseDir ? baseDir.split("/") : [];
|
|
17907
|
+
for (const seg of target.split("/")) {
|
|
17908
|
+
if (seg === "..") parts.pop();
|
|
17909
|
+
else if (seg && seg !== ".") parts.push(seg);
|
|
17910
|
+
}
|
|
17911
|
+
return parts.join("/");
|
|
17912
|
+
}
|
|
17913
|
+
async function readRels(zip, part) {
|
|
17914
|
+
const map = /* @__PURE__ */ new Map();
|
|
17915
|
+
const slash = part.lastIndexOf("/");
|
|
17916
|
+
const dir = slash >= 0 ? part.slice(0, slash) : "";
|
|
17917
|
+
const file = zip.file(`${dir ? dir + "/" : ""}_rels/${part.slice(slash + 1)}.rels`);
|
|
17918
|
+
if (!file) return map;
|
|
17919
|
+
const doc = parseXml3(await file.async("text"));
|
|
17920
|
+
for (const rel of childrenByLocalName(doc.documentElement, "Relationship")) {
|
|
17921
|
+
const id = getAttr2(rel, "Id");
|
|
17922
|
+
const target = getAttr2(rel, "Target");
|
|
17923
|
+
if (!id || !target || getAttr2(rel, "TargetMode") === "External") continue;
|
|
17924
|
+
map.set(id, { type: getAttr2(rel, "Type") ?? "", target: resolvePart(dir, target) });
|
|
17925
|
+
}
|
|
17926
|
+
return map;
|
|
17927
|
+
}
|
|
17928
|
+
async function slideParts(zip) {
|
|
17929
|
+
const ordered = [];
|
|
17930
|
+
const presFile = zip.file("ppt/presentation.xml");
|
|
17931
|
+
if (presFile) {
|
|
17932
|
+
const pres = parseXml3(await presFile.async("text"));
|
|
17933
|
+
const rels = await readRels(zip, "ppt/presentation.xml");
|
|
17934
|
+
const list = findChildByLocalName(pres.documentElement, "sldIdLst");
|
|
17935
|
+
for (const sld of list ? childrenByLocalName(list, "sldId") : []) {
|
|
17936
|
+
const target = rels.get(getRelId(sld) ?? "")?.target;
|
|
17937
|
+
if (target && zip.file(target)) ordered.push(target);
|
|
17938
|
+
}
|
|
17939
|
+
}
|
|
17940
|
+
if (ordered.length === 0) {
|
|
17941
|
+
const names = Object.keys(zip.files).filter((n) => SLIDE_PART_RE.test(n));
|
|
17942
|
+
names.sort((a, b) => Number(SLIDE_PART_RE.exec(a)[1]) - Number(SLIDE_PART_RE.exec(b)[1]));
|
|
17943
|
+
ordered.push(...names);
|
|
17944
|
+
}
|
|
17945
|
+
if (ordered.length > MAX_SLIDES) throw new KordocError(`PPTX \uC2AC\uB77C\uC774\uB4DC \uC218 \uCD08\uACFC: ${ordered.length} (\uCD5C\uB300 ${MAX_SLIDES})`);
|
|
17946
|
+
return ordered;
|
|
17947
|
+
}
|
|
17948
|
+
function paragraphText(p) {
|
|
17949
|
+
let text = "";
|
|
17950
|
+
for (const child of elementChildren(p)) {
|
|
17951
|
+
const name = localName(child);
|
|
17952
|
+
if (name === "r" || name === "fld") {
|
|
17953
|
+
const t = findChildByLocalName(child, "t");
|
|
17954
|
+
const rPr = findChildByLocalName(child, "rPr");
|
|
17955
|
+
const baseline = Number(rPr ? getAttr2(rPr, "baseline") ?? 0 : 0);
|
|
17956
|
+
if (t) text += wrapScript(escapeLiteralTags(escapeLiteralDollar(rawTextContent(t))), baseline > 0 ? "sup" : baseline < 0 ? "sub" : null);
|
|
17957
|
+
} else if (name === "br") {
|
|
17958
|
+
text += " ";
|
|
17959
|
+
}
|
|
17960
|
+
}
|
|
17961
|
+
return tidyScriptTags(text.replace(/\s+/g, " ").trim());
|
|
17962
|
+
}
|
|
17963
|
+
function bodyParagraphs(txBody) {
|
|
17964
|
+
const out = [];
|
|
17965
|
+
for (const p of childrenByLocalName(txBody, "p")) {
|
|
17966
|
+
const text = paragraphText(p);
|
|
17967
|
+
if (!text) continue;
|
|
17968
|
+
const pPr = findChildByLocalName(p, "pPr");
|
|
17969
|
+
let bullet;
|
|
17970
|
+
if (pPr) {
|
|
17971
|
+
if (findChildByLocalName(pPr, "buNone")) bullet = "none";
|
|
17972
|
+
else if (findChildByLocalName(pPr, "buAutoNum")) bullet = "ordered";
|
|
17973
|
+
else if (findChildByLocalName(pPr, "buChar") || findChildByLocalName(pPr, "buBlip")) bullet = "unordered";
|
|
17974
|
+
}
|
|
17975
|
+
const lvl = Math.max(0, parseInt(pPr ? getAttr2(pPr, "lvl") ?? "0" : "0", 10) || 0);
|
|
17976
|
+
out.push({ text, lvl, bullet });
|
|
17977
|
+
}
|
|
17978
|
+
return out;
|
|
17979
|
+
}
|
|
17980
|
+
function placeholderType(sp) {
|
|
17981
|
+
const ph = findPath(sp, "nvSpPr", "nvPr", "ph");
|
|
17982
|
+
return ph ? getAttr2(ph, "type") ?? "obj" : null;
|
|
17983
|
+
}
|
|
17984
|
+
function pushParagraphs(paras, bulletDefault, page, out) {
|
|
17985
|
+
let lastList = null;
|
|
17986
|
+
for (const para2 of paras) {
|
|
17987
|
+
const bullet = para2.bullet ?? (bulletDefault ? "unordered" : "none");
|
|
17988
|
+
if (bullet === "none") {
|
|
17989
|
+
out.push({ type: "paragraph", text: para2.text, pageNumber: page });
|
|
17990
|
+
lastList = null;
|
|
17991
|
+
continue;
|
|
17992
|
+
}
|
|
17993
|
+
const item = { type: "list", text: para2.text, listType: bullet, pageNumber: page };
|
|
17994
|
+
if (para2.lvl > 0 && lastList) {
|
|
17995
|
+
;
|
|
17996
|
+
(lastList.children ??= []).push(item);
|
|
17997
|
+
} else {
|
|
17998
|
+
out.push(item);
|
|
17999
|
+
lastList = item;
|
|
18000
|
+
}
|
|
18001
|
+
}
|
|
18002
|
+
}
|
|
18003
|
+
function parseTable2(tbl2, page, keepEmptyCols) {
|
|
18004
|
+
const rows = childrenByLocalName(tbl2, "tr");
|
|
18005
|
+
if (rows.length === 0) return null;
|
|
18006
|
+
const cellRows = rows.map((tr, r) => {
|
|
18007
|
+
const cells = [];
|
|
18008
|
+
childrenByLocalName(tr, "tc").forEach((tc2, c) => {
|
|
18009
|
+
if (getAttr2(tc2, "hMerge") === "1" || getAttr2(tc2, "vMerge") === "1") return;
|
|
18010
|
+
const txBody = findChildByLocalName(tc2, "txBody");
|
|
18011
|
+
const text = txBody ? bodyParagraphs(txBody).map((p) => p.text).join("\n") : "";
|
|
18012
|
+
cells.push({
|
|
18013
|
+
text,
|
|
18014
|
+
colSpan: Math.max(1, parseInt(getAttr2(tc2, "gridSpan") ?? "1", 10) || 1),
|
|
18015
|
+
rowSpan: Math.max(1, parseInt(getAttr2(tc2, "rowSpan") ?? "1", 10) || 1),
|
|
18016
|
+
colAddr: c,
|
|
18017
|
+
rowAddr: r
|
|
18018
|
+
});
|
|
18019
|
+
});
|
|
18020
|
+
return cells;
|
|
18021
|
+
});
|
|
18022
|
+
const table2 = buildTable(cellRows, { keepAnchoredEmptyCols: keepEmptyCols });
|
|
18023
|
+
if (table2.rows === 0 || table2.cols === 0) return null;
|
|
18024
|
+
return { type: "table", table: table2, pageNumber: page };
|
|
18025
|
+
}
|
|
18026
|
+
async function pictureBlock(pic, ctx) {
|
|
18027
|
+
const blip = findPath(pic, "blipFill", "blip");
|
|
18028
|
+
const embed = blip ? getAttr2(blip, "embed") : null;
|
|
18029
|
+
const rel = embed ? ctx.rels.get(embed) : void 0;
|
|
18030
|
+
if (!rel || !rel.type.endsWith(REL_IMAGE)) return null;
|
|
18031
|
+
let filename = ctx.imageNames.get(rel.target);
|
|
18032
|
+
if (!filename) {
|
|
18033
|
+
const file = ctx.zip.file(rel.target);
|
|
18034
|
+
if (!file) return null;
|
|
18035
|
+
const ext = partExtension(rel.target);
|
|
18036
|
+
filename = `image_${String(ctx.imageNames.size + 1).padStart(3, "0")}.${ext}`;
|
|
18037
|
+
try {
|
|
18038
|
+
if (ctx.options?.images !== false) {
|
|
18039
|
+
const data = await file.async("uint8array");
|
|
18040
|
+
ctx.images.push({ filename, data, mimeType: IMAGE_MIME[ext] ?? detectImageMime(data) ?? "application/octet-stream", source: rel.target });
|
|
18041
|
+
}
|
|
18042
|
+
} catch (err) {
|
|
18043
|
+
ctx.warnings.push({
|
|
18044
|
+
page: ctx.page,
|
|
18045
|
+
code: "SKIPPED_IMAGE",
|
|
18046
|
+
message: `PPTX \uC774\uBBF8\uC9C0 \uCD94\uCD9C \uC2E4\uD328 (${rel.target}): ${err instanceof Error ? err.message : String(err)}`
|
|
18047
|
+
});
|
|
18048
|
+
return null;
|
|
18049
|
+
}
|
|
18050
|
+
ctx.imageNames.set(rel.target, filename);
|
|
18051
|
+
}
|
|
18052
|
+
return { type: "image", text: filename, pageNumber: ctx.page };
|
|
18053
|
+
}
|
|
18054
|
+
async function walkShapes(tree, ctx, out, depth = 0) {
|
|
18055
|
+
if (depth > MAX_XML_DEPTH) return;
|
|
18056
|
+
for (const el of elementChildren(tree)) {
|
|
18057
|
+
switch (localName(el)) {
|
|
18058
|
+
case "grpSp":
|
|
18059
|
+
await walkShapes(el, ctx, out, depth + 1);
|
|
18060
|
+
break;
|
|
18061
|
+
case "AlternateContent": {
|
|
18062
|
+
const choice = findChildByLocalName(el, "Choice");
|
|
18063
|
+
if (choice) await walkShapes(choice, ctx, out, depth + 1);
|
|
18064
|
+
break;
|
|
18065
|
+
}
|
|
18066
|
+
case "sp": {
|
|
18067
|
+
const ph = placeholderType(el);
|
|
18068
|
+
const txBody = findChildByLocalName(el, "txBody");
|
|
18069
|
+
if (ph && SKIP_PLACEHOLDERS.has(ph) || !txBody) break;
|
|
18070
|
+
const paras = bodyParagraphs(txBody);
|
|
18071
|
+
if (paras.length === 0) break;
|
|
18072
|
+
if (ph === "title" || ph === "ctrTitle") {
|
|
18073
|
+
out.push({ type: "heading", level: ph === "ctrTitle" ? 1 : 2, text: paras.map((p) => p.text).join(" "), pageNumber: ctx.page });
|
|
18074
|
+
} else {
|
|
18075
|
+
pushParagraphs(paras, ph !== null && BULLET_PLACEHOLDERS.has(ph), ctx.page, out);
|
|
18076
|
+
}
|
|
18077
|
+
break;
|
|
18078
|
+
}
|
|
18079
|
+
case "graphicFrame": {
|
|
18080
|
+
const data = findPath(el, "graphic", "graphicData");
|
|
18081
|
+
const tbl2 = data ? findChildByLocalName(data, "tbl") : null;
|
|
18082
|
+
if (tbl2) {
|
|
18083
|
+
const block = parseTable2(tbl2, ctx.page, ctx.options?.keepTrailingEmptyCols);
|
|
18084
|
+
if (block) out.push(block);
|
|
18085
|
+
} else if (data) {
|
|
18086
|
+
const uri = getAttr2(data, "uri") ?? "";
|
|
18087
|
+
const kind = /chart/i.test(uri) ? "\uCC28\uD2B8" : /diagram/i.test(uri) ? "SmartArt" : "\uAC1C\uCCB4";
|
|
18088
|
+
ctx.warnings.push({ page: ctx.page, code: "UNSUPPORTED_ELEMENT", message: `PPTX ${kind}\uC758 \uAE00\uC740 \uC77D\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (${ctx.page}\uCABD)` });
|
|
18089
|
+
}
|
|
18090
|
+
break;
|
|
18091
|
+
}
|
|
18092
|
+
case "pic": {
|
|
18093
|
+
const block = await pictureBlock(el, ctx);
|
|
18094
|
+
if (block) out.push(block);
|
|
18095
|
+
break;
|
|
18096
|
+
}
|
|
18097
|
+
}
|
|
18098
|
+
}
|
|
18099
|
+
}
|
|
18100
|
+
async function notesText(zip, rels) {
|
|
18101
|
+
const rel = [...rels.values()].find((r) => r.type.endsWith(REL_NOTES));
|
|
18102
|
+
const file = rel ? zip.file(rel.target) : null;
|
|
18103
|
+
if (!file) return "";
|
|
18104
|
+
const tree = findPath(parseXml3(await file.async("text")).documentElement, "cSld", "spTree");
|
|
18105
|
+
const texts = [];
|
|
18106
|
+
for (const sp of tree ? childrenByLocalName(tree, "sp") : []) {
|
|
18107
|
+
const txBody = findChildByLocalName(sp, "txBody");
|
|
18108
|
+
if (placeholderType(sp) === "body" && txBody) texts.push(...bodyParagraphs(txBody).map((p) => p.text));
|
|
18109
|
+
}
|
|
18110
|
+
return texts.join(" ");
|
|
18111
|
+
}
|
|
18112
|
+
async function parsePptxDocument(buffer, options) {
|
|
18113
|
+
precheckZipSize(buffer, MAX_DECOMPRESS_SIZE5, MAX_ZIP_ENTRIES2, { re: MEDIA_PART_RE2, skip: options?.images === false, never: NEVER_READ_RE2 });
|
|
18114
|
+
const zip = await JSZip5.loadAsync(buffer);
|
|
18115
|
+
if (!zip.file("ppt/presentation.xml")) {
|
|
18116
|
+
throw new KordocError("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 PPTX \uD30C\uC77C: ppt/presentation.xml\uC774 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
18117
|
+
}
|
|
18118
|
+
const warnings = [];
|
|
18119
|
+
const blocks = [];
|
|
18120
|
+
const imageNames = /* @__PURE__ */ new Map();
|
|
18121
|
+
const images = [];
|
|
18122
|
+
const slides = await slideParts(zip);
|
|
18123
|
+
const pageFilter = options?.pages ? parsePageRange(options.pages, slides.length) : null;
|
|
18124
|
+
for (let i = 0; i < slides.length; i++) {
|
|
18125
|
+
const page = i + 1;
|
|
18126
|
+
if (pageFilter && !pageFilter.has(page)) continue;
|
|
18127
|
+
const root = parseXml3(await zip.file(slides[i]).async("text")).documentElement;
|
|
18128
|
+
if (getAttr2(root, "show") === "0") {
|
|
18129
|
+
warnings.push({ page, code: "HIDDEN_TEXT_FILTERED", message: `PPTX \uC228\uAE34 \uC2AC\uB77C\uC774\uB4DC ${page}\uCABD\uC744 \uAC74\uB108\uB701\uB2C8\uB2E4` });
|
|
18130
|
+
continue;
|
|
18131
|
+
}
|
|
18132
|
+
const rels = await readRels(zip, slides[i]);
|
|
18133
|
+
const tree = findPath(root, "cSld", "spTree");
|
|
18134
|
+
if (tree) await walkShapes(tree, { zip, rels, page, warnings, options, imageNames, images }, blocks);
|
|
18135
|
+
const notes = await notesText(zip, rels);
|
|
18136
|
+
if (notes) blocks.push({ type: "paragraph", text: `\uBC1C\uD45C\uC790 \uB178\uD2B8: ${notes}`, quote: true, pageNumber: page });
|
|
18137
|
+
}
|
|
18138
|
+
const metadata = { pageCount: slides.length, pageMode: "layout" };
|
|
18139
|
+
const coreFile = zip.file("docProps/core.xml");
|
|
18140
|
+
if (coreFile) {
|
|
18141
|
+
try {
|
|
18142
|
+
const coreDoc = parseXml3(await coreFile.async("text"));
|
|
18143
|
+
const getFirst = (tag) => {
|
|
18144
|
+
const els = coreDoc.getElementsByTagName(tag);
|
|
18145
|
+
return els.length > 0 ? (els[0].textContent ?? "").trim() || void 0 : void 0;
|
|
18146
|
+
};
|
|
18147
|
+
metadata.title = getFirst("dc:title") || getFirst("dcterms:title");
|
|
18148
|
+
metadata.author = getFirst("dc:creator");
|
|
18149
|
+
metadata.description = getFirst("dc:description");
|
|
18150
|
+
const created = getFirst("dcterms:created");
|
|
18151
|
+
if (created) metadata.createdAt = created;
|
|
18152
|
+
const modified = getFirst("dcterms:modified");
|
|
18153
|
+
if (modified) metadata.modifiedAt = modified;
|
|
18154
|
+
} catch (err) {
|
|
18155
|
+
warnings.push({
|
|
18156
|
+
code: "PARTIAL_PARSE",
|
|
18157
|
+
message: `PPTX \uBA54\uD0C0\uB370\uC774\uD130(core.xml) \uD30C\uC2F1 \uC2E4\uD328: ${err instanceof Error ? err.message : String(err)}`
|
|
18158
|
+
});
|
|
18159
|
+
}
|
|
18160
|
+
}
|
|
18161
|
+
const outline = blocks.filter((b) => b.type === "heading").map((b) => ({ level: b.level ?? 2, text: b.text ?? "", pageNumber: b.pageNumber }));
|
|
18162
|
+
return {
|
|
18163
|
+
markdown: blocksToMarkdown(blocks),
|
|
18164
|
+
blocks,
|
|
18165
|
+
metadata,
|
|
18166
|
+
outline: outline.length > 0 ? outline : void 0,
|
|
18167
|
+
warnings: warnings.length > 0 ? warnings : void 0,
|
|
18168
|
+
images: images.length > 0 ? images : void 0
|
|
18169
|
+
};
|
|
18170
|
+
}
|
|
18171
|
+
|
|
18172
|
+
// src/hwpml/parser.ts
|
|
18173
|
+
import { DOMParser as DOMParser4 } from "@xmldom/xmldom";
|
|
17829
18174
|
var MAX_TABLE_ROWS = 5e3;
|
|
17830
18175
|
var MAX_TABLE_COLS = 500;
|
|
17831
18176
|
var MAX_HWPML_BYTES = 50 * 1024 * 1024;
|
|
@@ -17837,7 +18182,7 @@ function parseHwpmlDocument(buffer, options) {
|
|
|
17837
18182
|
const normalized = text.replace(/ /g, " ");
|
|
17838
18183
|
const xml = stripDtd(normalized);
|
|
17839
18184
|
const warnings = [];
|
|
17840
|
-
const parser = new
|
|
18185
|
+
const parser = new DOMParser4({
|
|
17841
18186
|
onError: (_level, msg2) => {
|
|
17842
18187
|
warnings.push({ message: `HWPML XML \uD30C\uC2F1 \uACBD\uACE0: ${msg2}`, code: "MALFORMED_XML" });
|
|
17843
18188
|
}
|
|
@@ -17930,7 +18275,7 @@ function walkContent(node, blocks, paraShapeMap, sectionNum, warnings, inHeaderF
|
|
|
17930
18275
|
}
|
|
17931
18276
|
if (tag === "TABLE") {
|
|
17932
18277
|
if (!inHeaderFooter) {
|
|
17933
|
-
|
|
18278
|
+
parseTable3(el, blocks, paraShapeMap, sectionNum, warnings, keep);
|
|
17934
18279
|
}
|
|
17935
18280
|
continue;
|
|
17936
18281
|
}
|
|
@@ -17949,7 +18294,7 @@ function walkTablesInP(node, blocks, paraShapeMap, sectionNum, warnings, keep, d
|
|
|
17949
18294
|
if (el.nodeType !== 1) continue;
|
|
17950
18295
|
const tag = localName(el);
|
|
17951
18296
|
if (tag === "TABLE") {
|
|
17952
|
-
|
|
18297
|
+
parseTable3(el, blocks, paraShapeMap, sectionNum, warnings, keep);
|
|
17953
18298
|
continue;
|
|
17954
18299
|
}
|
|
17955
18300
|
if (tag === "FOOTNOTE" || tag === "ENDNOTE" || tag === "HEADER" || tag === "FOOTER") continue;
|
|
@@ -17982,7 +18327,7 @@ function collectCharText(node, parts, depth = 0) {
|
|
|
17982
18327
|
if (tag === "CHAR") {
|
|
17983
18328
|
for (const c of Array.from(el.childNodes)) {
|
|
17984
18329
|
const t = c.nodeType === 1 ? localName(c) === "TAB" ? " " : rawTextContent(c) : c.nodeType === 3 || c.nodeType === 4 ? c.nodeValue ?? "" : "";
|
|
17985
|
-
if (t) parts.push(t);
|
|
18330
|
+
if (t) parts.push(escapeLiteralTags(t));
|
|
17986
18331
|
}
|
|
17987
18332
|
} else if (tag === "TABLE" || tag === "PICTURE" || tag === "SHAPEOBJECT") {
|
|
17988
18333
|
} else if (tag === "AUTONUM") {
|
|
@@ -17991,7 +18336,7 @@ function collectCharText(node, parts, depth = 0) {
|
|
|
17991
18336
|
}
|
|
17992
18337
|
}
|
|
17993
18338
|
}
|
|
17994
|
-
function
|
|
18339
|
+
function parseTable3(el, blocks, _paraShapeMap, sectionNum, warnings, keep) {
|
|
17995
18340
|
const table2 = buildHmlTable(el, warnings, keep, 0);
|
|
17996
18341
|
if (!table2) return;
|
|
17997
18342
|
const caption = extractShapeCaption(el);
|
|
@@ -18933,10 +19278,10 @@ function fillInlineFields(text, values, filled, matchedLabels, blockedLabels) {
|
|
|
18933
19278
|
}
|
|
18934
19279
|
|
|
18935
19280
|
// src/form/filler-hwpx.ts
|
|
18936
|
-
import
|
|
19281
|
+
import JSZip7 from "jszip";
|
|
18937
19282
|
|
|
18938
19283
|
// src/form/click-here.ts
|
|
18939
|
-
import
|
|
19284
|
+
import JSZip6 from "jszip";
|
|
18940
19285
|
var FIELD_BEGIN_RE = /<([A-Za-z0-9_]+:)?fieldBegin\b([^>]*?)(\/?)>/g;
|
|
18941
19286
|
function attrOf2(attrs, name) {
|
|
18942
19287
|
const m = attrs.match(new RegExp(`(?:^|\\s)${name}="([^"]*)"`));
|
|
@@ -19052,7 +19397,7 @@ function fillClickHereInXml(xml, cursor, blockedLabels) {
|
|
|
19052
19397
|
}
|
|
19053
19398
|
async function extractClickHereFields(hwpxBuffer) {
|
|
19054
19399
|
precheckZipSize(hwpxBuffer);
|
|
19055
|
-
const zip = await
|
|
19400
|
+
const zip = await JSZip6.loadAsync(hwpxBuffer);
|
|
19056
19401
|
const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
|
|
19057
19402
|
const fields = [];
|
|
19058
19403
|
for (let si = 0; si < sectionPaths.length; si++) {
|
|
@@ -19073,7 +19418,7 @@ async function extractClickHereFields(hwpxBuffer) {
|
|
|
19073
19418
|
async function fillHwpx(hwpxBuffer, values, blockedLabels) {
|
|
19074
19419
|
const u8 = new Uint8Array(hwpxBuffer);
|
|
19075
19420
|
precheckZipSize(hwpxBuffer);
|
|
19076
|
-
const zip = await
|
|
19421
|
+
const zip = await JSZip7.loadAsync(hwpxBuffer);
|
|
19077
19422
|
const sectionPaths = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
|
|
19078
19423
|
if (sectionPaths.length === 0) {
|
|
19079
19424
|
throw new KordocError("HWPX\uC5D0\uC11C \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
@@ -19532,7 +19877,7 @@ function chooseTableRepresentation(table2, opts = {}) {
|
|
|
19532
19877
|
}
|
|
19533
19878
|
|
|
19534
19879
|
// src/hwpx/generator.ts
|
|
19535
|
-
import
|
|
19880
|
+
import JSZip8 from "jszip";
|
|
19536
19881
|
|
|
19537
19882
|
// src/hwpx/geometry.ts
|
|
19538
19883
|
var A4_W_HU = 59528;
|
|
@@ -22363,7 +22708,7 @@ function sanitizeText(text) {
|
|
|
22363
22708
|
return result;
|
|
22364
22709
|
}
|
|
22365
22710
|
function normForMatch(text) {
|
|
22366
|
-
return sanitizeText(text.replace(/\\\$/g, "$")).replace(/\s+/g, " ").trim();
|
|
22711
|
+
return sanitizeText(text.replace(/\\\$/g, "$").replace(/\\(?=<\/?(?:u|sup|sub)>)/g, "")).replace(/\s+/g, " ").trim();
|
|
22367
22712
|
}
|
|
22368
22713
|
function unescapeGfm(text) {
|
|
22369
22714
|
return text.replace(/\\([~*_`|#<$\\])/g, "$1");
|
|
@@ -24204,7 +24549,8 @@ function renderListItem(block, blockIdx, ctx) {
|
|
|
24204
24549
|
ctx.prevWasOrdered = false;
|
|
24205
24550
|
}
|
|
24206
24551
|
const indentPrefix = " ".repeat(indent);
|
|
24207
|
-
|
|
24552
|
+
const markerRun = `<hp:run charPrIDRef="${CHAR_NORMAL}"><hp:t>${escapeTextXml(indentPrefix + marker)}</hp:t></hp:run>`;
|
|
24553
|
+
return `<hp:p paraPrIDRef="${PARA_LIST}" styleIDRef="0">${markerRun}${generateRuns(block.text || "")}</hp:p>`;
|
|
24208
24554
|
}
|
|
24209
24555
|
function renderHr(ctx) {
|
|
24210
24556
|
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>`;
|
|
@@ -25712,7 +26058,7 @@ async function markdownToHwpx(markdown, options) {
|
|
|
25712
26058
|
if (remap2 && remap2.tables.length > 0 && remap2.tables.every((t) => !t.used)) {
|
|
25713
26059
|
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)`);
|
|
25714
26060
|
}
|
|
25715
|
-
const zip2 = new
|
|
26061
|
+
const zip2 = new JSZip8();
|
|
25716
26062
|
zip2.file("mimetype", "application/hwp+zip", { compression: "STORE" });
|
|
25717
26063
|
zip2.file("META-INF/container.xml", generateContainerXml());
|
|
25718
26064
|
zip2.file("Contents/content.hpf", generateManifest(chartParts2, images2.manifestItems(), "gongmun"));
|
|
@@ -25759,7 +26105,7 @@ async function markdownToHwpx(markdown, options) {
|
|
|
25759
26105
|
}
|
|
25760
26106
|
}
|
|
25761
26107
|
const extraBorderFills = [...remap?.borderFillXmls ?? [], ...bfReg?.emit() ?? []];
|
|
25762
|
-
const zip = new
|
|
26108
|
+
const zip = new JSZip8();
|
|
25763
26109
|
zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
|
|
25764
26110
|
zip.file("META-INF/container.xml", generateContainerXml());
|
|
25765
26111
|
zip.file("Contents/content.hpf", generateManifest(chartParts, images.manifestItems(), gongmun ? "gongmun" : "default"));
|
|
@@ -25979,7 +26325,7 @@ function readBuiltinTemplateSample(t) {
|
|
|
25979
26325
|
}
|
|
25980
26326
|
|
|
25981
26327
|
// src/hwpx/extract-profile.ts
|
|
25982
|
-
import
|
|
26328
|
+
import JSZip9 from "jszip";
|
|
25983
26329
|
function elemsByLocal(root, name) {
|
|
25984
26330
|
const all = root.getElementsByTagName("*");
|
|
25985
26331
|
const out = [];
|
|
@@ -26066,7 +26412,7 @@ function num(s) {
|
|
|
26066
26412
|
const n = parseInt(s, 10);
|
|
26067
26413
|
return Number.isFinite(n) ? n : void 0;
|
|
26068
26414
|
}
|
|
26069
|
-
function
|
|
26415
|
+
function parseTable4(tbl2, tableIndex, borderFills, charPrs) {
|
|
26070
26416
|
const rows = num(tbl2.getAttribute("rowCnt")) ?? 0;
|
|
26071
26417
|
const cols = num(tbl2.getAttribute("colCnt")) ?? 0;
|
|
26072
26418
|
const sz = findChildByLocalName(tbl2, "sz");
|
|
@@ -26182,7 +26528,7 @@ function pick(map, keys) {
|
|
|
26182
26528
|
}
|
|
26183
26529
|
async function hwpxToProfile(input) {
|
|
26184
26530
|
const buf = input instanceof ArrayBuffer ? input : toArrayBuffer(input);
|
|
26185
|
-
const zip = await
|
|
26531
|
+
const zip = await JSZip9.loadAsync(buf);
|
|
26186
26532
|
const parser = createXmlParser();
|
|
26187
26533
|
const headerFile = zip.file("Contents/header.xml") ?? zip.file(/[Hh]eader\.xml$/)?.[0];
|
|
26188
26534
|
let headerXml = "<root/>";
|
|
@@ -26197,7 +26543,7 @@ async function hwpxToProfile(input) {
|
|
|
26197
26543
|
const doc = parser.parseFromString(await f.async("text"), "text/xml");
|
|
26198
26544
|
for (const tbl2 of elemsByLocal(doc, "tbl")) {
|
|
26199
26545
|
if (!isTopLevelTable(tbl2)) continue;
|
|
26200
|
-
tables.push(
|
|
26546
|
+
tables.push(parseTable4(tbl2, tableIndex++, borderFills, charPrs));
|
|
26201
26547
|
}
|
|
26202
26548
|
}
|
|
26203
26549
|
return { schema_version: "0.3.0", tables };
|
|
@@ -26899,7 +27245,7 @@ function muncheLintWarnings(text, limit = 10) {
|
|
|
26899
27245
|
}
|
|
26900
27246
|
|
|
26901
27247
|
// src/roundtrip/patcher.ts
|
|
26902
|
-
import
|
|
27248
|
+
import JSZip10 from "jszip";
|
|
26903
27249
|
|
|
26904
27250
|
// src/roundtrip/table-rows.ts
|
|
26905
27251
|
var ROW_OBJECT_RE = /<(?:[A-Za-z0-9_]+:)?(?:tbl|pic|equation|ole|container|shape|drawingObject|drawText|video|chart|fieldBegin|fieldEnd|ctrl)\b/;
|
|
@@ -28765,13 +29111,17 @@ async function patchHwpx(original, editedMarkdown, options) {
|
|
|
28765
29111
|
const parsed = await parseHwpxDocument(u8ToArrayBuffer(original), { layoutTables: "keep" });
|
|
28766
29112
|
origBlocks = parsed.blocks;
|
|
28767
29113
|
const visual = await parseHwpxDocument(u8ToArrayBuffer(original));
|
|
29114
|
+
if (parsed.markdown !== visual.markdown && editedMarkdown === visual.markdown) {
|
|
29115
|
+
const verification2 = options?.verify === false ? void 0 : diffUnitLists(splitMarkdownUnits(visual.markdown), splitMarkdownUnits(editedMarkdown));
|
|
29116
|
+
return { success: true, data: new Uint8Array(original), applied: 0, skipped, verification: verification2 };
|
|
29117
|
+
}
|
|
28768
29118
|
if (editedFromVisual(parsed.markdown, visual.markdown, editedMarkdown)) return { success: false, applied: 0, skipped, error: LAYOUT_MODE_MISMATCH };
|
|
28769
29119
|
} catch (err) {
|
|
28770
29120
|
return { success: false, applied: 0, skipped, error: `\uC6D0\uBCF8 HWPX \uD30C\uC2F1 \uC2E4\uD328: ${err instanceof Error ? err.message : String(err)}` };
|
|
28771
29121
|
}
|
|
28772
29122
|
let zip;
|
|
28773
29123
|
try {
|
|
28774
|
-
zip = await
|
|
29124
|
+
zip = await JSZip10.loadAsync(original);
|
|
28775
29125
|
} catch {
|
|
28776
29126
|
return { success: false, applied: 0, skipped, error: "ZIP \uB85C\uB4DC \uC2E4\uD328" };
|
|
28777
29127
|
}
|
|
@@ -29216,8 +29566,8 @@ async function resolveHeaderEntryName(zip) {
|
|
|
29216
29566
|
}
|
|
29217
29567
|
|
|
29218
29568
|
// src/validate.ts
|
|
29219
|
-
import
|
|
29220
|
-
import { DOMParser as
|
|
29569
|
+
import JSZip11 from "jszip";
|
|
29570
|
+
import { DOMParser as DOMParser5 } from "@xmldom/xmldom";
|
|
29221
29571
|
var REQUIRED_FILES = [
|
|
29222
29572
|
"mimetype",
|
|
29223
29573
|
"META-INF/container.xml",
|
|
@@ -29234,7 +29584,7 @@ async function validateHwpx(buffer) {
|
|
|
29234
29584
|
const issues = [];
|
|
29235
29585
|
let zip;
|
|
29236
29586
|
try {
|
|
29237
|
-
zip = await
|
|
29587
|
+
zip = await JSZip11.loadAsync(buffer);
|
|
29238
29588
|
} catch (err) {
|
|
29239
29589
|
return {
|
|
29240
29590
|
ok: false,
|
|
@@ -29263,7 +29613,7 @@ async function validateHwpx(buffer) {
|
|
|
29263
29613
|
const text = await zip.files[name].async("string");
|
|
29264
29614
|
let firstError = null;
|
|
29265
29615
|
try {
|
|
29266
|
-
new
|
|
29616
|
+
new DOMParser5({
|
|
29267
29617
|
onError(level, msg2) {
|
|
29268
29618
|
if (level !== "warning" && firstError === null) firstError = String(msg2);
|
|
29269
29619
|
}
|
|
@@ -29302,12 +29652,12 @@ async function validateHwpx(buffer) {
|
|
|
29302
29652
|
}
|
|
29303
29653
|
|
|
29304
29654
|
// src/roundtrip/session.ts
|
|
29305
|
-
import
|
|
29655
|
+
import JSZip12 from "jszip";
|
|
29306
29656
|
async function buildState(bytes) {
|
|
29307
29657
|
const format2 = detectFormat(new Uint8Array(bytes.subarray(0, 512)).buffer);
|
|
29308
29658
|
if (format2 !== "hwpx") throw new Error(`HWPX \uC138\uC158\uC740 HWPX \uBB38\uC11C\uB9CC \uC5FD\uB2C8\uB2E4 (\uAC10\uC9C0\uB41C \uD3EC\uB9F7: ${format2}) \u2014 HWP 5.x \uB294 patchHwp \uB85C \uD328\uCE58\uD558\uC138\uC694`);
|
|
29309
29659
|
const parsed = await parseHwpxDocument(u8ToArrayBuffer2(bytes), { layoutTables: "keep" });
|
|
29310
|
-
const zip = await
|
|
29660
|
+
const zip = await JSZip12.loadAsync(bytes);
|
|
29311
29661
|
const sectionPaths = await resolveSectionEntryNames(zip);
|
|
29312
29662
|
if (sectionPaths.length === 0) {
|
|
29313
29663
|
throw new Error("HWPX \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
@@ -29681,9 +30031,12 @@ async function parse(input, options) {
|
|
|
29681
30031
|
}
|
|
29682
30032
|
if (result.success && opts?.classifyTables) classifyTableTree(result.blocks);
|
|
29683
30033
|
let out = result;
|
|
29684
|
-
if (result.success &&
|
|
29685
|
-
|
|
29686
|
-
|
|
30034
|
+
if (result.success && opts?.pages && result.pageCount && parsePageRange(opts.pages, result.pageCount).size === 0) {
|
|
30035
|
+
out = { ...result, warnings: [...result.warnings ?? [], { 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` }] };
|
|
30036
|
+
}
|
|
30037
|
+
if (out.success && !out.pages) {
|
|
30038
|
+
const pages = blocksToPages(out.blocks);
|
|
30039
|
+
if (pages) out = { ...out, pages };
|
|
29687
30040
|
}
|
|
29688
30041
|
if (out.success && opts?.plain) {
|
|
29689
30042
|
out = { ...out, markdown: toPlainMarkdown(out.markdown), ...out.pages ? { pages: out.pages.map((p) => ({ ...p, markdown: toPlainMarkdown(p.markdown) })) } : {} };
|
|
@@ -29710,9 +30063,7 @@ async function dispatch(format2, buffer, opts) {
|
|
|
29710
30063
|
const zipFormat = await detectZipFormat(buffer);
|
|
29711
30064
|
if (zipFormat === "xlsx") return parseXlsx(buffer, opts);
|
|
29712
30065
|
if (zipFormat === "docx") return parseDocx(buffer, opts);
|
|
29713
|
-
if (zipFormat === "pptx")
|
|
29714
|
-
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" };
|
|
29715
|
-
}
|
|
30066
|
+
if (zipFormat === "pptx") return parsePptx(buffer, opts);
|
|
29716
30067
|
return parseHwpx(buffer, opts);
|
|
29717
30068
|
}
|
|
29718
30069
|
case "hwp": {
|
|
@@ -29737,7 +30088,7 @@ function scriptsOff(r, off) {
|
|
|
29737
30088
|
}
|
|
29738
30089
|
async function parseImage(buffer, options) {
|
|
29739
30090
|
try {
|
|
29740
|
-
const { parseImageDocument } = await import("./image-ocr-
|
|
30091
|
+
const { parseImageDocument } = await import("./image-ocr-TWNNVTZS.js");
|
|
29741
30092
|
const { blocks, warnings } = await parseImageDocument(buffer, options);
|
|
29742
30093
|
stripScriptTags({ blocks });
|
|
29743
30094
|
return {
|
|
@@ -29797,7 +30148,7 @@ async function parseHwp(buffer, options) {
|
|
|
29797
30148
|
async function parsePdf(buffer, options) {
|
|
29798
30149
|
let parsePdfDocument;
|
|
29799
30150
|
try {
|
|
29800
|
-
const mod = await import("./parser-
|
|
30151
|
+
const mod = await import("./parser-NKP2NCSV.js");
|
|
29801
30152
|
parsePdfDocument = mod.parsePdfDocument;
|
|
29802
30153
|
} catch {
|
|
29803
30154
|
return {
|
|
@@ -29839,6 +30190,14 @@ async function parseDocx(buffer, options) {
|
|
|
29839
30190
|
return { success: false, fileType: "docx", error: sanitizeError(err), code: classifyError(err) };
|
|
29840
30191
|
}
|
|
29841
30192
|
}
|
|
30193
|
+
async function parsePptx(buffer, options) {
|
|
30194
|
+
try {
|
|
30195
|
+
const { markdown, blocks, metadata, outline, warnings, images } = await parsePptxDocument(buffer, options);
|
|
30196
|
+
return scriptsOff({ success: true, fileType: "pptx", markdown, blocks, metadata, outline, warnings, images: images?.length ? images : void 0, pageCount: metadata?.pageCount }, options?.scriptTags === false);
|
|
30197
|
+
} catch (err) {
|
|
30198
|
+
return { success: false, fileType: "pptx", error: sanitizeError(err), code: classifyError(err) };
|
|
30199
|
+
}
|
|
30200
|
+
}
|
|
29842
30201
|
async function parseHwpml(buffer, options) {
|
|
29843
30202
|
try {
|
|
29844
30203
|
const { markdown, blocks, metadata, outline, warnings } = parseHwpmlDocument(buffer, options);
|
|
@@ -29954,6 +30313,8 @@ async function extractTables(input, options = {}) {
|
|
|
29954
30313
|
}
|
|
29955
30314
|
|
|
29956
30315
|
export {
|
|
30316
|
+
toPlainMarkdown,
|
|
30317
|
+
toHtmlTables,
|
|
29957
30318
|
extractHwpxMetadataOnly,
|
|
29958
30319
|
formatFillValue,
|
|
29959
30320
|
ValueCursor,
|
|
@@ -30006,7 +30367,8 @@ export {
|
|
|
30006
30367
|
parseXlsx,
|
|
30007
30368
|
parseXls,
|
|
30008
30369
|
parseDocx,
|
|
30370
|
+
parsePptx,
|
|
30009
30371
|
parseHwpml,
|
|
30010
30372
|
fillForm
|
|
30011
30373
|
};
|
|
30012
|
-
//# sourceMappingURL=chunk-
|
|
30374
|
+
//# sourceMappingURL=chunk-2I2RTJJ5.js.map
|