kordoc 3.13.0 → 3.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -1
- package/dist/{-MRPDPE2X.js → -H7N62NZU.js} +24 -13
- package/dist/{chunk-33CIKNL4.js → chunk-5RHRQ7HK.js} +479 -258
- package/dist/chunk-5RHRQ7HK.js.map +1 -0
- package/dist/{chunk-MEXUFQVC.cjs → chunk-BIP4JAVG.cjs} +5 -5
- package/dist/chunk-BIP4JAVG.cjs.map +1 -0
- package/dist/chunk-DCZVOIEO.cjs.map +1 -1
- package/dist/chunk-FGL7BH4P.js +1019 -0
- package/dist/chunk-FGL7BH4P.js.map +1 -0
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-Q6UXVJXI.js → chunk-IC56KHBL.js} +2 -2
- package/dist/chunk-JFNWJFKP.js +185 -0
- package/dist/chunk-JFNWJFKP.js.map +1 -0
- package/dist/{chunk-YXOT7P5B.js → chunk-LYL4IL3E.js} +5 -5
- package/dist/{chunk-YXOT7P5B.js.map → chunk-LYL4IL3E.js.map} +1 -1
- package/dist/{chunk-O4WFPOFN.js → chunk-Q7EGGW3H.js} +5 -5
- package/dist/{chunk-O4WFPOFN.js.map → chunk-Q7EGGW3H.js.map} +1 -1
- package/dist/{chunk-TWACKS3K.js → chunk-WD5NUUU6.js} +571 -729
- package/dist/chunk-WD5NUUU6.js.map +1 -0
- package/dist/cli.js +125 -12
- package/dist/cli.js.map +1 -1
- package/dist/formula-5NKVS2LR.cjs.map +1 -1
- package/dist/index.cjs +1668 -449
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +144 -6
- package/dist/index.d.ts +144 -6
- package/dist/index.js +1502 -283
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +93 -12
- package/dist/mcp.js.map +1 -1
- package/dist/page-range-P7SDW6LR.cjs.map +1 -1
- package/dist/{parser-Z3IL2ESY.js → parser-5G247XYD.js} +54 -6
- package/dist/parser-5G247XYD.js.map +1 -0
- package/dist/{parser-DZBI3EA2.cjs → parser-6V7F3GET.cjs} +66 -18
- package/dist/parser-6V7F3GET.cjs.map +1 -0
- package/dist/{parser-XUNGOH76.js → parser-HBHCD7TE.js} +55 -7
- package/dist/parser-HBHCD7TE.js.map +1 -0
- package/dist/provider-G4C2V2PD.cjs.map +1 -1
- package/dist/render-VA4NHROW.js +10 -0
- package/dist/seal-UVDRGHEF.js +10 -0
- package/dist/seal-UVDRGHEF.js.map +1 -0
- package/dist/{watch-G5NFIT5L.js → watch-HIYNOSFD.js} +7 -5
- package/dist/{watch-G5NFIT5L.js.map → watch-HIYNOSFD.js.map} +1 -1
- package/package.json +4 -3
- package/dist/chunk-33CIKNL4.js.map +0 -1
- package/dist/chunk-MEXUFQVC.cjs.map +0 -1
- package/dist/chunk-TWACKS3K.js.map +0 -1
- package/dist/parser-DZBI3EA2.cjs.map +0 -1
- package/dist/parser-XUNGOH76.js.map +0 -1
- package/dist/parser-Z3IL2ESY.js.map +0 -1
- package/dist/render-VZ4OGHZU.js +0 -9
- /package/dist/{-MRPDPE2X.js.map → -H7N62NZU.js.map} +0 -0
- /package/dist/{chunk-Q6UXVJXI.js.map → chunk-IC56KHBL.js.map} +0 -0
- /package/dist/{render-VZ4OGHZU.js.map → render-VA4NHROW.js.map} +0 -0
|
@@ -1,39 +1,53 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
HEADING_RATIO_H1,
|
|
4
|
+
HEADING_RATIO_H2,
|
|
5
|
+
HEADING_RATIO_H3,
|
|
6
|
+
MAX_COLS,
|
|
7
|
+
MAX_ROWS,
|
|
8
|
+
blocksToMarkdown,
|
|
9
|
+
buildTable,
|
|
10
|
+
convertTableToText,
|
|
11
|
+
flattenLayoutTables,
|
|
12
|
+
mapPuaText
|
|
13
|
+
} from "./chunk-LYL4IL3E.js";
|
|
2
14
|
import {
|
|
3
15
|
detectFormat,
|
|
4
16
|
detectOle2Format,
|
|
5
17
|
detectZipFormat,
|
|
6
18
|
parseLenientCfb
|
|
7
19
|
} from "./chunk-MEPHGCPQ.js";
|
|
20
|
+
import {
|
|
21
|
+
parsePageRange
|
|
22
|
+
} from "./chunk-MOL7MDBG.js";
|
|
23
|
+
import {
|
|
24
|
+
allLinesegRemovalSplices,
|
|
25
|
+
applySplices,
|
|
26
|
+
buildParagraphSplices,
|
|
27
|
+
buildRangeSplices,
|
|
28
|
+
escapeXmlText,
|
|
29
|
+
findElementEnd,
|
|
30
|
+
paraTText,
|
|
31
|
+
paraTextPureT,
|
|
32
|
+
patchZipEntries,
|
|
33
|
+
scanSectionXml
|
|
34
|
+
} from "./chunk-FGL7BH4P.js";
|
|
35
|
+
import {
|
|
36
|
+
SPACE_EM_FIXED,
|
|
37
|
+
charWidthEm1000,
|
|
38
|
+
fitRatioForFewerLines
|
|
39
|
+
} from "./chunk-5RHRQ7HK.js";
|
|
8
40
|
import {
|
|
9
41
|
MAX_DECOMPRESS_SIZE,
|
|
10
42
|
MAX_XML_DEPTH,
|
|
11
43
|
MAX_ZIP_ENTRIES,
|
|
12
|
-
SPACE_EM_FIXED,
|
|
13
44
|
applyPageText,
|
|
14
|
-
charWidthEm1000,
|
|
15
45
|
clampSpan,
|
|
16
46
|
createSectionShared,
|
|
17
47
|
createXmlParser,
|
|
18
48
|
extractTextFromNode,
|
|
19
|
-
findChildByLocalName
|
|
20
|
-
|
|
21
|
-
} from "./chunk-33CIKNL4.js";
|
|
22
|
-
import {
|
|
23
|
-
HEADING_RATIO_H1,
|
|
24
|
-
HEADING_RATIO_H2,
|
|
25
|
-
HEADING_RATIO_H3,
|
|
26
|
-
MAX_COLS,
|
|
27
|
-
MAX_ROWS,
|
|
28
|
-
blocksToMarkdown,
|
|
29
|
-
buildTable,
|
|
30
|
-
convertTableToText,
|
|
31
|
-
flattenLayoutTables,
|
|
32
|
-
mapPuaText
|
|
33
|
-
} from "./chunk-YXOT7P5B.js";
|
|
34
|
-
import {
|
|
35
|
-
parsePageRange
|
|
36
|
-
} from "./chunk-MOL7MDBG.js";
|
|
49
|
+
findChildByLocalName
|
|
50
|
+
} from "./chunk-JFNWJFKP.js";
|
|
37
51
|
import {
|
|
38
52
|
KordocError,
|
|
39
53
|
classifyError,
|
|
@@ -44,7 +58,7 @@ import {
|
|
|
44
58
|
sanitizeHref,
|
|
45
59
|
stripDtd,
|
|
46
60
|
toArrayBuffer
|
|
47
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-IC56KHBL.js";
|
|
48
62
|
|
|
49
63
|
// src/index.ts
|
|
50
64
|
import { readFile } from "fs/promises";
|
|
@@ -640,10 +654,22 @@ function findEnclosingBrackets(eqString, startIdx) {
|
|
|
640
654
|
}
|
|
641
655
|
return null;
|
|
642
656
|
}
|
|
657
|
+
function maskLiteralSpans(eqString) {
|
|
658
|
+
return eqString.replace(/"[^"]*"/g, (m) => "\uFFFF".repeat(m.length)).replace(/\\text\{[^}]*\}/g, (m) => "\uFFFF".repeat(m.length));
|
|
659
|
+
}
|
|
660
|
+
function findKeywordToken(eqString, word, from = 0) {
|
|
661
|
+
const masked = maskLiteralSpans(eqString);
|
|
662
|
+
for (let i = masked.indexOf(word, from); i !== -1; i = masked.indexOf(word, i + 1)) {
|
|
663
|
+
const okL = i === 0 || masked[i - 1] === " ";
|
|
664
|
+
const okR = i + word.length === masked.length || masked[i + word.length] === " ";
|
|
665
|
+
if (okL && okR) return i;
|
|
666
|
+
}
|
|
667
|
+
return -1;
|
|
668
|
+
}
|
|
643
669
|
function replaceFrac(eqString) {
|
|
644
670
|
const hmlFrac = "over";
|
|
645
671
|
while (true) {
|
|
646
|
-
const cursor = eqString
|
|
672
|
+
const cursor = findKeywordToken(eqString, hmlFrac);
|
|
647
673
|
if (cursor === -1) break;
|
|
648
674
|
try {
|
|
649
675
|
const [numStart, numEnd] = findBrackets(eqString, cursor, 0);
|
|
@@ -659,12 +685,12 @@ function replaceFrac(eqString) {
|
|
|
659
685
|
}
|
|
660
686
|
function replaceRootOf(eqString) {
|
|
661
687
|
while (true) {
|
|
662
|
-
const rootCursor = eqString
|
|
688
|
+
const rootCursor = findKeywordToken(eqString, "root");
|
|
663
689
|
if (rootCursor === -1) break;
|
|
664
690
|
try {
|
|
665
|
-
const ofCursor = eqString.indexOf("of");
|
|
666
|
-
if (ofCursor === -1) return eqString;
|
|
667
691
|
const elem1 = findBrackets(eqString, rootCursor, 1);
|
|
692
|
+
const ofCursor = findKeywordToken(eqString, "of", elem1[1]);
|
|
693
|
+
if (ofCursor === -1) return eqString;
|
|
668
694
|
const elem2 = findBrackets(eqString, ofCursor, 1);
|
|
669
695
|
const e1 = eqString.slice(elem1[0] + 1, elem1[1] - 1);
|
|
670
696
|
const e2 = eqString.slice(elem2[0] + 1, elem2[1] - 1);
|
|
@@ -2082,7 +2108,6 @@ function appendParaText(state, data, resolveControl) {
|
|
|
2082
2108
|
break;
|
|
2083
2109
|
}
|
|
2084
2110
|
result += "\n";
|
|
2085
|
-
if (i + 14 <= data.length) i += 14;
|
|
2086
2111
|
break;
|
|
2087
2112
|
}
|
|
2088
2113
|
case CHAR_PARA:
|
|
@@ -17955,6 +17980,7 @@ function collectOmmlRoots(p) {
|
|
|
17955
17980
|
const tag = el.localName || el.tagName?.replace(/^[^:]+:/, "") || "";
|
|
17956
17981
|
if (tag === "oMath" || tag === "oMathPara") {
|
|
17957
17982
|
out.push(el);
|
|
17983
|
+
} else if (tag === "txbxContent" || tag === "Fallback") {
|
|
17958
17984
|
} else {
|
|
17959
17985
|
walk(el);
|
|
17960
17986
|
}
|
|
@@ -18079,6 +18105,13 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
|
|
|
18079
18105
|
for (const tr of trElements) {
|
|
18080
18106
|
const row = [];
|
|
18081
18107
|
let col = 0;
|
|
18108
|
+
const trPrEls = getChildElements(tr, "trPr");
|
|
18109
|
+
if (trPrEls.length > 0) {
|
|
18110
|
+
const gridBeforeEls = getChildElements(trPrEls[0], "gridBefore");
|
|
18111
|
+
if (gridBeforeEls.length > 0) {
|
|
18112
|
+
col = parseInt(getAttr(gridBeforeEls[0], "val") ?? "0", 10) || 0;
|
|
18113
|
+
}
|
|
18114
|
+
}
|
|
18082
18115
|
for (const tc of getChildElements(tr, "tc")) {
|
|
18083
18116
|
let colSpan = 1;
|
|
18084
18117
|
let vMerge = null;
|
|
@@ -18093,12 +18126,28 @@ function parseTable(tbl, styles, numbering, footnotes, rels) {
|
|
|
18093
18126
|
vMerge = getAttr(vMergeEls[0], "val") === "restart" ? "restart" : "continue";
|
|
18094
18127
|
}
|
|
18095
18128
|
}
|
|
18096
|
-
const text =
|
|
18129
|
+
const text = collectCellText(tc, styles, numbering, footnotes, rels, 0).join("\n");
|
|
18097
18130
|
row.push({ col, colSpan, vMerge, text });
|
|
18098
18131
|
col += colSpan;
|
|
18099
18132
|
}
|
|
18100
18133
|
rawRows.push(row);
|
|
18101
18134
|
}
|
|
18135
|
+
for (let r = 0; r < rawRows.length; r++) {
|
|
18136
|
+
for (const cell of rawRows[r]) {
|
|
18137
|
+
if (cell.vMerge !== "continue" || !cell.text) continue;
|
|
18138
|
+
let start;
|
|
18139
|
+
for (let pr = r - 1; pr >= 0 && !start; pr--) {
|
|
18140
|
+
start = rawRows[pr].find((pc) => pc.col === cell.col && pc.vMerge !== "continue");
|
|
18141
|
+
}
|
|
18142
|
+
if (start) {
|
|
18143
|
+
start.text = start.text ? `${start.text}
|
|
18144
|
+
${cell.text}` : cell.text;
|
|
18145
|
+
cell.text = "";
|
|
18146
|
+
} else {
|
|
18147
|
+
cell.vMerge = null;
|
|
18148
|
+
}
|
|
18149
|
+
}
|
|
18150
|
+
}
|
|
18102
18151
|
const cellRows = rawRows.map(
|
|
18103
18152
|
(row, r) => row.filter((cell) => cell.vMerge !== "continue").map((cell) => {
|
|
18104
18153
|
let rowSpan = 1;
|
|
@@ -18588,6 +18637,81 @@ function countSections(body) {
|
|
|
18588
18637
|
}
|
|
18589
18638
|
|
|
18590
18639
|
// src/form/match.ts
|
|
18640
|
+
function parseYMD(v) {
|
|
18641
|
+
const d = v.replace(/\D/g, "");
|
|
18642
|
+
let y, m, day;
|
|
18643
|
+
if (d.length >= 8) {
|
|
18644
|
+
y = d.slice(0, 4);
|
|
18645
|
+
m = d.slice(4, 6);
|
|
18646
|
+
day = d.slice(6, 8);
|
|
18647
|
+
} else if (d.length === 6) {
|
|
18648
|
+
const yy = +d.slice(0, 2);
|
|
18649
|
+
y = String(yy <= 29 ? 2e3 + yy : 1900 + yy);
|
|
18650
|
+
m = d.slice(2, 4);
|
|
18651
|
+
day = d.slice(4, 6);
|
|
18652
|
+
} else return null;
|
|
18653
|
+
return { y, yy: y.slice(2), m, d: day };
|
|
18654
|
+
}
|
|
18655
|
+
function fmtDate(v, style) {
|
|
18656
|
+
const p = parseYMD(v);
|
|
18657
|
+
if (!p) return v;
|
|
18658
|
+
return (style || "yyyy-mm-dd").replace(/yyyy/g, p.y).replace(/yy/g, p.yy).replace(/mm/g, p.m).replace(/dd/g, p.d).replace(/m/g, String(+p.m)).replace(/d/g, String(+p.d));
|
|
18659
|
+
}
|
|
18660
|
+
function maskDigits(v, pattern) {
|
|
18661
|
+
const ds = v.replace(/\D/g, "");
|
|
18662
|
+
let i = 0;
|
|
18663
|
+
return pattern.replace(/#/g, () => ds[i++] ?? "");
|
|
18664
|
+
}
|
|
18665
|
+
function fmtPhone(v, style) {
|
|
18666
|
+
const d = v.replace(/\D/g, "");
|
|
18667
|
+
if (d.length < 9) return v;
|
|
18668
|
+
const a = d.slice(0, 3), b = d.slice(3, -4), c = d.slice(-4);
|
|
18669
|
+
switch (style) {
|
|
18670
|
+
case "digits":
|
|
18671
|
+
return d;
|
|
18672
|
+
case "dot":
|
|
18673
|
+
return `${a}.${b}.${c}`;
|
|
18674
|
+
case "space":
|
|
18675
|
+
return `${a} ${b} ${c}`;
|
|
18676
|
+
case "intl":
|
|
18677
|
+
return `+82-${d.slice(1, 3)}-${b}-${c}`;
|
|
18678
|
+
case "intl-paren":
|
|
18679
|
+
return `82)${d.slice(1, 3)}-${b}-${c}`;
|
|
18680
|
+
default:
|
|
18681
|
+
return `${a}-${b}-${c}`;
|
|
18682
|
+
}
|
|
18683
|
+
}
|
|
18684
|
+
function fmtRRN(v, style) {
|
|
18685
|
+
const d = v.replace(/\D/g, "");
|
|
18686
|
+
if (d.length !== 13) return v;
|
|
18687
|
+
switch (style) {
|
|
18688
|
+
case "digits":
|
|
18689
|
+
return d;
|
|
18690
|
+
case "front":
|
|
18691
|
+
return d.slice(0, 6);
|
|
18692
|
+
case "masked":
|
|
18693
|
+
return `${d.slice(0, 6)}-${d[6]}******`;
|
|
18694
|
+
default:
|
|
18695
|
+
return `${d.slice(0, 6)}-${d.slice(6)}`;
|
|
18696
|
+
}
|
|
18697
|
+
}
|
|
18698
|
+
function formatFillValue(value, format) {
|
|
18699
|
+
if (!format) return value;
|
|
18700
|
+
const ci = format.indexOf(":");
|
|
18701
|
+
const kind = ci >= 0 ? format.slice(0, ci) : format;
|
|
18702
|
+
const style = ci >= 0 ? format.slice(ci + 1) : "";
|
|
18703
|
+
if (kind === "date") return fmtDate(value, style);
|
|
18704
|
+
if (kind === "phone") return fmtPhone(value, style);
|
|
18705
|
+
if (kind === "rrn") return fmtRRN(value, style);
|
|
18706
|
+
if (kind === "mask") return maskDigits(value, style);
|
|
18707
|
+
if (kind === "digits") return value.replace(/\D/g, "");
|
|
18708
|
+
if (kind === "upper") return value.toUpperCase();
|
|
18709
|
+
if (kind === "lower") return value.toLowerCase();
|
|
18710
|
+
if (kind === "nospace") return value.replace(/\s+/g, "");
|
|
18711
|
+
if (format.includes("#")) return maskDigits(value, format);
|
|
18712
|
+
if (/(yyyy|yy|mm|dd)/.test(format)) return fmtDate(value, format);
|
|
18713
|
+
return value;
|
|
18714
|
+
}
|
|
18591
18715
|
var ValueCursor = class {
|
|
18592
18716
|
constructor(values) {
|
|
18593
18717
|
this.values = values;
|
|
@@ -18739,11 +18863,32 @@ function padInsertion(text, pos, value) {
|
|
|
18739
18863
|
}
|
|
18740
18864
|
function normalizeValues(values) {
|
|
18741
18865
|
const map = /* @__PURE__ */ new Map();
|
|
18742
|
-
for (const [label,
|
|
18743
|
-
|
|
18866
|
+
for (const [label, raw] of Object.entries(values)) {
|
|
18867
|
+
const { value, format } = typeof raw === "object" && !Array.isArray(raw) ? raw : { value: raw, format: void 0 };
|
|
18868
|
+
map.set(normalizeLabel(label), Array.isArray(value) ? value.map((v) => formatFillValue(v, format)) : formatFillValue(value, format));
|
|
18744
18869
|
}
|
|
18745
18870
|
return map;
|
|
18746
18871
|
}
|
|
18872
|
+
async function fillWithUniqueGuard(values, run) {
|
|
18873
|
+
const first = await run(values);
|
|
18874
|
+
const counts = /* @__PURE__ */ new Map();
|
|
18875
|
+
for (const f of first.filled) {
|
|
18876
|
+
if (f.key) counts.set(f.key, (counts.get(f.key) ?? 0) + 1);
|
|
18877
|
+
}
|
|
18878
|
+
const isArrayValue = (normKey) => {
|
|
18879
|
+
for (const [label, raw] of Object.entries(values)) {
|
|
18880
|
+
if (normalizeLabel(label) !== normKey) continue;
|
|
18881
|
+
return Array.isArray(typeof raw === "object" && !Array.isArray(raw) ? raw.value : raw);
|
|
18882
|
+
}
|
|
18883
|
+
return false;
|
|
18884
|
+
};
|
|
18885
|
+
const dup = new Set([...counts].filter(([k, n]) => n >= 2 && !isArrayValue(k)).map(([k]) => k));
|
|
18886
|
+
if (dup.size === 0) return { ...first, rejected: [] };
|
|
18887
|
+
const filtered = Object.fromEntries(Object.entries(values).filter(([label]) => !dup.has(normalizeLabel(label))));
|
|
18888
|
+
const second = await run(filtered);
|
|
18889
|
+
const rejected = Object.keys(values).filter((label) => dup.has(normalizeLabel(label)));
|
|
18890
|
+
return { ...second, rejected };
|
|
18891
|
+
}
|
|
18747
18892
|
function resolveUnmatched(normalizedValues, matchedLabels, originalValues) {
|
|
18748
18893
|
return [...normalizedValues.keys()].filter((k) => !matchedLabels.has(k)).map((k) => {
|
|
18749
18894
|
for (const orig of Object.keys(originalValues)) {
|
|
@@ -19013,7 +19158,7 @@ function fillFormFields(blocks, values) {
|
|
|
19013
19158
|
cell.text = result.text;
|
|
19014
19159
|
patternFilledCells.add(cell);
|
|
19015
19160
|
for (const m of result.matches) {
|
|
19016
|
-
filled.push({ label: m.label, value: m.value, row: r, col: c });
|
|
19161
|
+
filled.push({ label: m.label, value: m.value, row: r, col: c, key: m.key });
|
|
19017
19162
|
}
|
|
19018
19163
|
}
|
|
19019
19164
|
}
|
|
@@ -19093,7 +19238,8 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
|
|
|
19093
19238
|
label: labelCell.text.trim().replace(/[::]\s*$/, ""),
|
|
19094
19239
|
value: newValue,
|
|
19095
19240
|
row: r,
|
|
19096
|
-
col: c
|
|
19241
|
+
col: c,
|
|
19242
|
+
key: matchKey
|
|
19097
19243
|
});
|
|
19098
19244
|
}
|
|
19099
19245
|
}
|
|
@@ -19122,7 +19268,8 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
|
|
|
19122
19268
|
label: headerCell.text.trim(),
|
|
19123
19269
|
value: newValue,
|
|
19124
19270
|
row: r,
|
|
19125
|
-
col: c
|
|
19271
|
+
col: c,
|
|
19272
|
+
key: matchKey
|
|
19126
19273
|
});
|
|
19127
19274
|
}
|
|
19128
19275
|
}
|
|
@@ -19139,7 +19286,7 @@ function fillInlineFields(text, values, filled, matchedLabels) {
|
|
|
19139
19286
|
const newValue = values.consume(matchKey);
|
|
19140
19287
|
if (newValue === void 0) continue;
|
|
19141
19288
|
matchedLabels.add(matchKey);
|
|
19142
|
-
filled.push({ label: seg.label.trim(), value: newValue, row: -1, col: -1 });
|
|
19289
|
+
filled.push({ label: seg.label.trim(), value: newValue, row: -1, col: -1, key: matchKey });
|
|
19143
19290
|
out += text.slice(pos, seg.valueStart);
|
|
19144
19291
|
out += seg.valueStart === seg.valueEnd ? padInsertion(text, seg.valueStart, newValue) : newValue;
|
|
19145
19292
|
pos = seg.valueEnd;
|
|
@@ -19150,677 +19297,6 @@ function fillInlineFields(text, values, filled, matchedLabels) {
|
|
|
19150
19297
|
|
|
19151
19298
|
// src/form/filler-hwpx.ts
|
|
19152
19299
|
import JSZip5 from "jszip";
|
|
19153
|
-
|
|
19154
|
-
// src/roundtrip/source-map.ts
|
|
19155
|
-
function escapeXmlText(text) {
|
|
19156
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
19157
|
-
}
|
|
19158
|
-
function decodeXmlEntities(text) {
|
|
19159
|
-
return text.replace(/&(lt|gt|amp|quot|apos|#x?[0-9a-fA-F]+);/g, (m, ent) => {
|
|
19160
|
-
switch (ent) {
|
|
19161
|
-
case "lt":
|
|
19162
|
-
return "<";
|
|
19163
|
-
case "gt":
|
|
19164
|
-
return ">";
|
|
19165
|
-
case "amp":
|
|
19166
|
-
return "&";
|
|
19167
|
-
case "quot":
|
|
19168
|
-
return '"';
|
|
19169
|
-
case "apos":
|
|
19170
|
-
return "'";
|
|
19171
|
-
}
|
|
19172
|
-
try {
|
|
19173
|
-
const code = ent[1] === "x" || ent[1] === "X" ? parseInt(ent.slice(2), 16) : parseInt(ent.slice(1), 10);
|
|
19174
|
-
if (!isNaN(code) && code >= 0 && code <= 1114111) return String.fromCodePoint(code);
|
|
19175
|
-
} catch {
|
|
19176
|
-
}
|
|
19177
|
-
return m;
|
|
19178
|
-
});
|
|
19179
|
-
}
|
|
19180
|
-
function tContentToText(raw) {
|
|
19181
|
-
return decodeXmlEntities(
|
|
19182
|
-
raw.replace(/<\/?(?:[A-Za-z0-9_]+:)?(?:tab|fwSpace|hwSpace|br|lineBreak)(?:\s[^>]*)?\/?>/g, " ").replace(/<[^>]*>/g, "")
|
|
19183
|
-
);
|
|
19184
|
-
}
|
|
19185
|
-
var TAG_RE = /<!--[\s\S]*?-->|<!\[CDATA\[[\s\S]*?\]\]>|<\?[\s\S]*?\?>|<!(?:"[^"]*"|'[^']*'|[^>"'])*>|<\/([^\s>]+)\s*>|<([^\s/>!?]+)((?:"[^"]*"|'[^']*'|[^>"'])*?)(\/?)>/g;
|
|
19186
|
-
var T_BARRIER = /* @__PURE__ */ new Set([
|
|
19187
|
-
"tbl",
|
|
19188
|
-
"ctrl",
|
|
19189
|
-
"caption",
|
|
19190
|
-
"pic",
|
|
19191
|
-
"shape",
|
|
19192
|
-
"drawingObject",
|
|
19193
|
-
"drawText",
|
|
19194
|
-
"shapeComment",
|
|
19195
|
-
"memogroup",
|
|
19196
|
-
"memo",
|
|
19197
|
-
"hiddenComment",
|
|
19198
|
-
"equation",
|
|
19199
|
-
"parameters",
|
|
19200
|
-
"subList",
|
|
19201
|
-
"p"
|
|
19202
|
-
]);
|
|
19203
|
-
var PARA_CONTAINER = /* @__PURE__ */ new Set([
|
|
19204
|
-
"tc",
|
|
19205
|
-
"ctrl",
|
|
19206
|
-
"caption",
|
|
19207
|
-
"drawText",
|
|
19208
|
-
"pic",
|
|
19209
|
-
"shape",
|
|
19210
|
-
"drawingObject",
|
|
19211
|
-
"memogroup",
|
|
19212
|
-
"memo",
|
|
19213
|
-
"hiddenComment",
|
|
19214
|
-
"footNote",
|
|
19215
|
-
"endNote",
|
|
19216
|
-
"fn",
|
|
19217
|
-
"en"
|
|
19218
|
-
// 각주/미주 — 파서는 호스트 블록 footnoteText로만 흡수
|
|
19219
|
-
]);
|
|
19220
|
-
var TABLE_BARRIER = /* @__PURE__ */ new Set([
|
|
19221
|
-
"tbl",
|
|
19222
|
-
"ctrl",
|
|
19223
|
-
"caption",
|
|
19224
|
-
"memogroup",
|
|
19225
|
-
"memo",
|
|
19226
|
-
"hiddenComment"
|
|
19227
|
-
]);
|
|
19228
|
-
function localOf(qname) {
|
|
19229
|
-
const i = qname.indexOf(":");
|
|
19230
|
-
return i >= 0 ? qname.slice(i + 1) : qname;
|
|
19231
|
-
}
|
|
19232
|
-
function prefixOf(qname) {
|
|
19233
|
-
const i = qname.indexOf(":");
|
|
19234
|
-
return i >= 0 ? qname.slice(0, i) : "";
|
|
19235
|
-
}
|
|
19236
|
-
function scanSectionXml(xml, sectionIndex) {
|
|
19237
|
-
const stack = [];
|
|
19238
|
-
const bodyParagraphs = [];
|
|
19239
|
-
const tables = [];
|
|
19240
|
-
const headerTexts = [];
|
|
19241
|
-
const footerTexts = [];
|
|
19242
|
-
const excludedParagraphs = [];
|
|
19243
|
-
const orphanTables = [];
|
|
19244
|
-
const paraStack = [];
|
|
19245
|
-
const tableStack = [];
|
|
19246
|
-
const rowStack = [];
|
|
19247
|
-
const trStartStack = [];
|
|
19248
|
-
const cellStack = [];
|
|
19249
|
-
let pendingT = null;
|
|
19250
|
-
const ctrlSubStack = [];
|
|
19251
|
-
const classifyPara = () => {
|
|
19252
|
-
let sawDrawText = false;
|
|
19253
|
-
for (let i = stack.length - 1; i >= 0; i--) {
|
|
19254
|
-
const l = stack[i].local;
|
|
19255
|
-
if (l === "tc") return { kind: "cell", inTextbox: sawDrawText };
|
|
19256
|
-
if (l === "drawText") {
|
|
19257
|
-
sawDrawText = true;
|
|
19258
|
-
continue;
|
|
19259
|
-
}
|
|
19260
|
-
if (PARA_CONTAINER.has(l)) return { kind: "excluded", inTextbox: sawDrawText };
|
|
19261
|
-
}
|
|
19262
|
-
return sawDrawText ? { kind: "draw", inTextbox: true } : { kind: "body", inTextbox: false };
|
|
19263
|
-
};
|
|
19264
|
-
const owningPara = () => {
|
|
19265
|
-
if (paraStack.length === 0) return null;
|
|
19266
|
-
for (let i = stack.length - 1; i >= 0; i--) {
|
|
19267
|
-
const l = stack[i].local;
|
|
19268
|
-
if (l === "p") return paraStack[paraStack.length - 1];
|
|
19269
|
-
if (T_BARRIER.has(l)) return null;
|
|
19270
|
-
}
|
|
19271
|
-
return null;
|
|
19272
|
-
};
|
|
19273
|
-
const isTableTopLevel = () => {
|
|
19274
|
-
for (let i = stack.length - 1; i >= 0; i--) {
|
|
19275
|
-
if (TABLE_BARRIER.has(stack[i].local)) return false;
|
|
19276
|
-
}
|
|
19277
|
-
return true;
|
|
19278
|
-
};
|
|
19279
|
-
const currentCtrlSub = () => ctrlSubStack.length > 0 ? ctrlSubStack[ctrlSubStack.length - 1] : null;
|
|
19280
|
-
TAG_RE.lastIndex = 0;
|
|
19281
|
-
let m;
|
|
19282
|
-
while ((m = TAG_RE.exec(xml)) !== null) {
|
|
19283
|
-
const [full, closeName, openName, , selfClose] = m;
|
|
19284
|
-
if (closeName === void 0 && openName === void 0) continue;
|
|
19285
|
-
if (closeName !== void 0) {
|
|
19286
|
-
const local2 = localOf(closeName);
|
|
19287
|
-
if (local2 === "t" && pendingT) {
|
|
19288
|
-
const { para, contentStart: contentStart2 } = pendingT;
|
|
19289
|
-
para.tRanges.push({ contentStart: contentStart2, contentEnd: m.index });
|
|
19290
|
-
para.text += tContentToText(xml.slice(contentStart2, m.index));
|
|
19291
|
-
pendingT = null;
|
|
19292
|
-
}
|
|
19293
|
-
for (let i = stack.length - 1; i >= 0; i--) {
|
|
19294
|
-
if (stack[i].local === local2) {
|
|
19295
|
-
stack.length = i;
|
|
19296
|
-
break;
|
|
19297
|
-
}
|
|
19298
|
-
}
|
|
19299
|
-
if (local2 === "p") {
|
|
19300
|
-
const para = paraStack.pop();
|
|
19301
|
-
if (para && para.kind === "excluded") {
|
|
19302
|
-
const sub = currentCtrlSub();
|
|
19303
|
-
if (sub && para.text.trim()) sub.texts.push(para.text);
|
|
19304
|
-
}
|
|
19305
|
-
} else if (local2 === "tc") {
|
|
19306
|
-
const cell = cellStack.pop();
|
|
19307
|
-
const row = rowStack[rowStack.length - 1];
|
|
19308
|
-
if (cell && row) row.push(cell);
|
|
19309
|
-
} else if (local2 === "tr") {
|
|
19310
|
-
const row = rowStack[rowStack.length - 1];
|
|
19311
|
-
const table = tableStack[tableStack.length - 1];
|
|
19312
|
-
if (row && table && row.length > 0) {
|
|
19313
|
-
table.rows.push(row);
|
|
19314
|
-
const trStart = trStartStack[trStartStack.length - 1];
|
|
19315
|
-
if (trStart >= 0) table.rowRanges.push({ start: trStart, end: m.index + full.length });
|
|
19316
|
-
}
|
|
19317
|
-
if (rowStack.length > 0) rowStack[rowStack.length - 1] = [];
|
|
19318
|
-
if (trStartStack.length > 0) trStartStack[trStartStack.length - 1] = -1;
|
|
19319
|
-
} else if (local2 === "tbl") {
|
|
19320
|
-
const table = tableStack.pop();
|
|
19321
|
-
rowStack.pop();
|
|
19322
|
-
trStartStack.pop();
|
|
19323
|
-
if (table) {
|
|
19324
|
-
finalizeTable(table);
|
|
19325
|
-
if (!table.topLevel) {
|
|
19326
|
-
const cell = cellStack[cellStack.length - 1];
|
|
19327
|
-
if (cell) cell.tables.push(table);
|
|
19328
|
-
else orphanTables.push(table);
|
|
19329
|
-
}
|
|
19330
|
-
}
|
|
19331
|
-
} else if (local2 === "header" || local2 === "footer") {
|
|
19332
|
-
const sub = ctrlSubStack[ctrlSubStack.length - 1];
|
|
19333
|
-
if (sub) {
|
|
19334
|
-
ctrlSubStack.pop();
|
|
19335
|
-
const joined = sub.texts.join("\n").trim();
|
|
19336
|
-
if (joined) (sub.kind === "header" ? headerTexts : footerTexts).push(joined);
|
|
19337
|
-
}
|
|
19338
|
-
}
|
|
19339
|
-
continue;
|
|
19340
|
-
}
|
|
19341
|
-
const qname = openName;
|
|
19342
|
-
const local = localOf(qname);
|
|
19343
|
-
const attrsRaw = m[3] || "";
|
|
19344
|
-
const isSelfClose = selfClose === "/";
|
|
19345
|
-
const contentStart = m.index + full.length;
|
|
19346
|
-
if (isSelfClose) {
|
|
19347
|
-
if (local === "t") {
|
|
19348
|
-
const para = owningPara();
|
|
19349
|
-
if (para) para.tRanges.push({ contentStart: m.index, contentEnd: m.index + full.length, selfClosing: true, prefix: prefixOf(qname) });
|
|
19350
|
-
} else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "br" || local === "lineBreak") {
|
|
19351
|
-
if (!pendingT) {
|
|
19352
|
-
const para = owningPara();
|
|
19353
|
-
if (para) para.text += " ";
|
|
19354
|
-
}
|
|
19355
|
-
} else if (local === "run" || local === "r") {
|
|
19356
|
-
const para = owningPara();
|
|
19357
|
-
if (para && !para.selfCloseRun) para.selfCloseRun = { start: m.index, end: m.index + full.length };
|
|
19358
|
-
} else if (local === "cellAddr") {
|
|
19359
|
-
const cell = cellStack[cellStack.length - 1];
|
|
19360
|
-
if (cell && insideCurrentTable(stack, tableStack)) {
|
|
19361
|
-
const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
|
|
19362
|
-
const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
|
|
19363
|
-
if (!isNaN(ca)) cell.colAddr = ca;
|
|
19364
|
-
if (!isNaN(ra)) cell.rowAddr = ra;
|
|
19365
|
-
cell.addrTagRange = { start: m.index, end: m.index + full.length };
|
|
19366
|
-
}
|
|
19367
|
-
} else if (local === "cellSpan") {
|
|
19368
|
-
const cell = cellStack[cellStack.length - 1];
|
|
19369
|
-
if (cell && insideCurrentTable(stack, tableStack)) {
|
|
19370
|
-
const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
|
|
19371
|
-
const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
|
|
19372
|
-
cell.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
|
|
19373
|
-
cell.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
|
|
19374
|
-
}
|
|
19375
|
-
}
|
|
19376
|
-
continue;
|
|
19377
|
-
}
|
|
19378
|
-
if (local === "t") {
|
|
19379
|
-
const para = owningPara();
|
|
19380
|
-
if (para) pendingT = { para, contentStart };
|
|
19381
|
-
stack.push({ local, qname, contentStart });
|
|
19382
|
-
continue;
|
|
19383
|
-
}
|
|
19384
|
-
stack.push({ local, qname, contentStart });
|
|
19385
|
-
if (local === "p") {
|
|
19386
|
-
const para = {
|
|
19387
|
-
sectionIndex,
|
|
19388
|
-
kind: "excluded",
|
|
19389
|
-
// 분류는 push 직후 스택 기준 (자기 자신 제외)
|
|
19390
|
-
start: m.index,
|
|
19391
|
-
tRanges: [],
|
|
19392
|
-
text: ""
|
|
19393
|
-
};
|
|
19394
|
-
stack.pop();
|
|
19395
|
-
const cls = classifyPara();
|
|
19396
|
-
para.kind = cls.kind;
|
|
19397
|
-
if (cls.inTextbox) para.inTextbox = true;
|
|
19398
|
-
stack.push({ local, qname, contentStart });
|
|
19399
|
-
paraStack.push(para);
|
|
19400
|
-
if (para.kind === "body" || para.kind === "draw") bodyParagraphs.push(para);
|
|
19401
|
-
else if (para.kind === "cell") {
|
|
19402
|
-
const cell = cellStack[cellStack.length - 1];
|
|
19403
|
-
if (cell) cell.paragraphs.push(para);
|
|
19404
|
-
} else if (para.kind === "excluded") {
|
|
19405
|
-
excludedParagraphs.push(para);
|
|
19406
|
-
}
|
|
19407
|
-
} else if (local === "run" || local === "r") {
|
|
19408
|
-
const para = owningPara();
|
|
19409
|
-
if (para && para.runPrefix === void 0) para.runPrefix = prefixOf(qname);
|
|
19410
|
-
} else if (local === "tbl") {
|
|
19411
|
-
const table = {
|
|
19412
|
-
sectionIndex,
|
|
19413
|
-
start: m.index,
|
|
19414
|
-
topLevel: false,
|
|
19415
|
-
rows: [],
|
|
19416
|
-
rowRanges: [],
|
|
19417
|
-
cellByAnchor: /* @__PURE__ */ new Map()
|
|
19418
|
-
};
|
|
19419
|
-
stack.pop();
|
|
19420
|
-
table.topLevel = isTableTopLevel();
|
|
19421
|
-
stack.push({ local, qname, contentStart });
|
|
19422
|
-
tableStack.push(table);
|
|
19423
|
-
rowStack.push([]);
|
|
19424
|
-
trStartStack.push(-1);
|
|
19425
|
-
if (table.topLevel) tables.push(table);
|
|
19426
|
-
} else if (local === "tr") {
|
|
19427
|
-
if (rowStack.length > 0) rowStack[rowStack.length - 1] = [];
|
|
19428
|
-
if (trStartStack.length > 0) trStartStack[trStartStack.length - 1] = m.index;
|
|
19429
|
-
} else if (local === "tc") {
|
|
19430
|
-
cellStack.push({ colSpan: 1, rowSpan: 1, paragraphs: [], tables: [] });
|
|
19431
|
-
} else if (local === "cellAddr" || local === "cellSpan") {
|
|
19432
|
-
const cell = cellStack[cellStack.length - 1];
|
|
19433
|
-
if (cell && insideCurrentTable(stack, tableStack)) {
|
|
19434
|
-
if (local === "cellAddr") {
|
|
19435
|
-
const ca = parseInt(getAttr2(attrsRaw, "colAddr") || "", 10);
|
|
19436
|
-
const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
|
|
19437
|
-
if (!isNaN(ca)) cell.colAddr = ca;
|
|
19438
|
-
if (!isNaN(ra)) cell.rowAddr = ra;
|
|
19439
|
-
cell.addrTagRange = { start: m.index, end: contentStart };
|
|
19440
|
-
} else {
|
|
19441
|
-
const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
|
|
19442
|
-
const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
|
|
19443
|
-
cell.colSpan = isNaN(cs) || cs < 1 ? 1 : cs;
|
|
19444
|
-
cell.rowSpan = isNaN(rs) || rs < 1 ? 1 : rs;
|
|
19445
|
-
}
|
|
19446
|
-
}
|
|
19447
|
-
} else if (local === "header" || local === "footer") {
|
|
19448
|
-
if (stack.some((f) => f.local === "ctrl")) {
|
|
19449
|
-
ctrlSubStack.push({ kind: local, texts: [] });
|
|
19450
|
-
}
|
|
19451
|
-
} else if (local === "tab" || local === "fwSpace" || local === "hwSpace" || local === "br" || local === "lineBreak") {
|
|
19452
|
-
const para = owningPara();
|
|
19453
|
-
if (para) para.text += " ";
|
|
19454
|
-
}
|
|
19455
|
-
}
|
|
19456
|
-
for (const para of bodyParagraphs) fillRunInsertPos(para, xml);
|
|
19457
|
-
for (const para of excludedParagraphs) fillRunInsertPos(para, xml);
|
|
19458
|
-
const fillTableInsertPos = (table, depth = 0) => {
|
|
19459
|
-
if (depth > 16) return;
|
|
19460
|
-
for (const row of table.rows) {
|
|
19461
|
-
for (const cell of row) {
|
|
19462
|
-
for (const para of cell.paragraphs) fillRunInsertPos(para, xml);
|
|
19463
|
-
for (const nested of cell.tables) fillTableInsertPos(nested, depth + 1);
|
|
19464
|
-
}
|
|
19465
|
-
}
|
|
19466
|
-
};
|
|
19467
|
-
for (const table of tables) fillTableInsertPos(table);
|
|
19468
|
-
for (const table of orphanTables) fillTableInsertPos(table);
|
|
19469
|
-
return { sectionIndex, xml, bodyParagraphs, tables, headerTexts, footerTexts, excludedParagraphs, orphanTables };
|
|
19470
|
-
}
|
|
19471
|
-
function getAttr2(attrsRaw, name) {
|
|
19472
|
-
const re = new RegExp(`(?:^|\\s)${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`);
|
|
19473
|
-
const m = attrsRaw.match(re);
|
|
19474
|
-
return m ? m[1] ?? m[2] : void 0;
|
|
19475
|
-
}
|
|
19476
|
-
function insideCurrentTable(stack, tableStack) {
|
|
19477
|
-
if (tableStack.length === 0) return false;
|
|
19478
|
-
for (let i = stack.length - 1; i >= 0; i--) {
|
|
19479
|
-
const l = stack[i].local;
|
|
19480
|
-
if (l === "tc") return true;
|
|
19481
|
-
if (l === "tbl") return false;
|
|
19482
|
-
}
|
|
19483
|
-
return false;
|
|
19484
|
-
}
|
|
19485
|
-
function fillRunInsertPos(para, xml) {
|
|
19486
|
-
if (para.tRanges.length > 0) return;
|
|
19487
|
-
const pEnd = findElementEnd(xml, para.start);
|
|
19488
|
-
if (pEnd < 0) return;
|
|
19489
|
-
const slice = xml.slice(para.start, pEnd);
|
|
19490
|
-
const runOpen = slice.match(/<((?:[A-Za-z0-9_]+:)?run)(?:\s(?:"[^"]*"|'[^']*'|[^>"'])*?)?(\/?)>/);
|
|
19491
|
-
if (!runOpen || runOpen.index === void 0) return;
|
|
19492
|
-
if (runOpen[2] === "/") return;
|
|
19493
|
-
const qname = runOpen[1];
|
|
19494
|
-
const closeIdx = slice.indexOf(`</${qname}>`, runOpen.index);
|
|
19495
|
-
if (closeIdx < 0) return;
|
|
19496
|
-
para.runInsertPos = para.start + closeIdx;
|
|
19497
|
-
para.runPrefix = prefixOf(qname);
|
|
19498
|
-
}
|
|
19499
|
-
function findElementEnd(xml, start) {
|
|
19500
|
-
const open = xml.slice(start).match(/^<([^\s/>!?]+)/);
|
|
19501
|
-
if (!open) return -1;
|
|
19502
|
-
const qname = open[1];
|
|
19503
|
-
const re = new RegExp(`<${qname}(?=[\\s/>])(?:"[^"]*"|'[^']*'|[^>"'])*?(/?)>|</${qname}\\s*>`, "g");
|
|
19504
|
-
re.lastIndex = start;
|
|
19505
|
-
let depth = 0;
|
|
19506
|
-
let mm;
|
|
19507
|
-
while ((mm = re.exec(xml)) !== null) {
|
|
19508
|
-
if (mm[0].startsWith("</")) {
|
|
19509
|
-
depth--;
|
|
19510
|
-
if (depth === 0) return mm.index + mm[0].length;
|
|
19511
|
-
} else if (mm[1] !== "/") {
|
|
19512
|
-
depth++;
|
|
19513
|
-
}
|
|
19514
|
-
}
|
|
19515
|
-
return -1;
|
|
19516
|
-
}
|
|
19517
|
-
function finalizeTable(table) {
|
|
19518
|
-
const hasAddr = table.rows.some((row) => row.some((c) => c.colAddr !== void 0 && c.rowAddr !== void 0));
|
|
19519
|
-
if (hasAddr) {
|
|
19520
|
-
for (const row of table.rows) {
|
|
19521
|
-
for (const cell of row) {
|
|
19522
|
-
if (cell.rowAddr !== void 0 && cell.colAddr !== void 0) {
|
|
19523
|
-
table.cellByAnchor.set(`${cell.rowAddr},${cell.colAddr}`, cell);
|
|
19524
|
-
}
|
|
19525
|
-
}
|
|
19526
|
-
}
|
|
19527
|
-
return;
|
|
19528
|
-
}
|
|
19529
|
-
const numRows = table.rows.length;
|
|
19530
|
-
const occupied = Array.from({ length: numRows }, () => []);
|
|
19531
|
-
for (let rowIdx = 0; rowIdx < numRows; rowIdx++) {
|
|
19532
|
-
let colIdx = 0;
|
|
19533
|
-
for (const cell of table.rows[rowIdx]) {
|
|
19534
|
-
while (occupied[rowIdx][colIdx]) colIdx++;
|
|
19535
|
-
cell.rowAddr = rowIdx;
|
|
19536
|
-
cell.colAddr = colIdx;
|
|
19537
|
-
table.cellByAnchor.set(`${rowIdx},${colIdx}`, cell);
|
|
19538
|
-
for (let r = rowIdx; r < Math.min(rowIdx + cell.rowSpan, numRows); r++) {
|
|
19539
|
-
for (let c = colIdx; c < colIdx + cell.colSpan; c++) {
|
|
19540
|
-
occupied[r][c] = true;
|
|
19541
|
-
}
|
|
19542
|
-
}
|
|
19543
|
-
colIdx += cell.colSpan;
|
|
19544
|
-
}
|
|
19545
|
-
}
|
|
19546
|
-
}
|
|
19547
|
-
function buildParagraphSplices(para, newText, xml) {
|
|
19548
|
-
if (newText && xml) {
|
|
19549
|
-
const orig = paraTText(para, xml);
|
|
19550
|
-
if (orig && orig.trim() !== "") {
|
|
19551
|
-
const lead = orig.match(/^\s*/)[0];
|
|
19552
|
-
const trail = orig.match(/\s*$/)[0];
|
|
19553
|
-
if ((lead || trail) && newText.trim() !== "") {
|
|
19554
|
-
newText = lead + newText.replace(/^\s+|\s+$/g, "") + trail;
|
|
19555
|
-
}
|
|
19556
|
-
}
|
|
19557
|
-
}
|
|
19558
|
-
const escaped = escapeXmlText(newText);
|
|
19559
|
-
if (para.tRanges.length > 0) {
|
|
19560
|
-
const splices = [];
|
|
19561
|
-
const first = para.tRanges[0];
|
|
19562
|
-
if (first.selfClosing) {
|
|
19563
|
-
const prefix = first.prefix ? first.prefix + ":" : "";
|
|
19564
|
-
splices.push({ start: first.contentStart, end: first.contentEnd, replacement: `<${prefix}t>${escaped}</${prefix}t>` });
|
|
19565
|
-
} else {
|
|
19566
|
-
splices.push({ start: first.contentStart, end: first.contentEnd, replacement: escaped });
|
|
19567
|
-
}
|
|
19568
|
-
for (let i = 1; i < para.tRanges.length; i++) {
|
|
19569
|
-
const r = para.tRanges[i];
|
|
19570
|
-
if (!r.selfClosing && r.contentStart < r.contentEnd) {
|
|
19571
|
-
splices.push({ start: r.contentStart, end: r.contentEnd, replacement: "" });
|
|
19572
|
-
}
|
|
19573
|
-
}
|
|
19574
|
-
return splices;
|
|
19575
|
-
}
|
|
19576
|
-
if (para.runInsertPos !== void 0) {
|
|
19577
|
-
if (!newText) return [];
|
|
19578
|
-
const prefix = para.runPrefix ? para.runPrefix + ":" : "";
|
|
19579
|
-
return [{ start: para.runInsertPos, end: para.runInsertPos, replacement: `<${prefix}t>${escaped}</${prefix}t>` }];
|
|
19580
|
-
}
|
|
19581
|
-
if (para.selfCloseRun && xml) {
|
|
19582
|
-
if (!newText) return [];
|
|
19583
|
-
const { start, end } = para.selfCloseRun;
|
|
19584
|
-
const tag = xml.slice(start, end);
|
|
19585
|
-
const qm = tag.match(/^<([^\s/>]+)/);
|
|
19586
|
-
if (!qm || !tag.endsWith("/>")) return null;
|
|
19587
|
-
const qname = qm[1];
|
|
19588
|
-
const colon = qname.indexOf(":");
|
|
19589
|
-
const prefix = colon >= 0 ? qname.slice(0, colon) + ":" : "";
|
|
19590
|
-
const opened = tag.slice(0, tag.length - 2).trimEnd() + ">";
|
|
19591
|
-
return [{ start, end, replacement: `${opened}<${prefix}t>${escaped}</${prefix}t></${qname}>` }];
|
|
19592
|
-
}
|
|
19593
|
-
return newText ? null : [];
|
|
19594
|
-
}
|
|
19595
|
-
function paraTText(para, xml) {
|
|
19596
|
-
let text = "";
|
|
19597
|
-
for (const t of para.tRanges) {
|
|
19598
|
-
if (t.selfClosing) continue;
|
|
19599
|
-
const raw = xml.slice(t.contentStart, t.contentEnd);
|
|
19600
|
-
if (/[<&]/.test(raw)) return null;
|
|
19601
|
-
text += raw;
|
|
19602
|
-
}
|
|
19603
|
-
return text;
|
|
19604
|
-
}
|
|
19605
|
-
function paraTextPureT(para, xml) {
|
|
19606
|
-
let len = 0;
|
|
19607
|
-
for (const t of para.tRanges) {
|
|
19608
|
-
if (t.selfClosing) continue;
|
|
19609
|
-
len += tContentToText(xml.slice(t.contentStart, t.contentEnd)).length;
|
|
19610
|
-
}
|
|
19611
|
-
return len === para.text.length;
|
|
19612
|
-
}
|
|
19613
|
-
function buildRangeSplices(para, xml, start, end, replacement) {
|
|
19614
|
-
if (start < 0 || end < start) return null;
|
|
19615
|
-
const segs = [];
|
|
19616
|
-
let offset = 0;
|
|
19617
|
-
for (const t of para.tRanges) {
|
|
19618
|
-
if (t.selfClosing) continue;
|
|
19619
|
-
const raw = xml.slice(t.contentStart, t.contentEnd);
|
|
19620
|
-
if (/[<&]/.test(raw)) return null;
|
|
19621
|
-
segs.push({ contentStart: t.contentStart, from: offset, to: offset + raw.length });
|
|
19622
|
-
offset += raw.length;
|
|
19623
|
-
}
|
|
19624
|
-
if (segs.length === 0 || end > offset) return null;
|
|
19625
|
-
const escaped = escapeXmlText(replacement);
|
|
19626
|
-
if (start === end) {
|
|
19627
|
-
for (const seg of segs) {
|
|
19628
|
-
if (start >= seg.from && start <= seg.to) {
|
|
19629
|
-
const at = seg.contentStart + (start - seg.from);
|
|
19630
|
-
return [{ start: at, end: at, replacement: escaped }];
|
|
19631
|
-
}
|
|
19632
|
-
}
|
|
19633
|
-
return null;
|
|
19634
|
-
}
|
|
19635
|
-
const splices = [];
|
|
19636
|
-
let placed = false;
|
|
19637
|
-
for (const seg of segs) {
|
|
19638
|
-
if (seg.to <= start || seg.from >= end) continue;
|
|
19639
|
-
const localStart = Math.max(seg.from, start) - seg.from;
|
|
19640
|
-
const localEnd = Math.min(seg.to, end) - seg.from;
|
|
19641
|
-
splices.push({
|
|
19642
|
-
start: seg.contentStart + localStart,
|
|
19643
|
-
end: seg.contentStart + localEnd,
|
|
19644
|
-
replacement: placed ? "" : escaped
|
|
19645
|
-
});
|
|
19646
|
-
placed = true;
|
|
19647
|
-
}
|
|
19648
|
-
return placed ? splices : null;
|
|
19649
|
-
}
|
|
19650
|
-
function allLinesegRemovalSplices(xml) {
|
|
19651
|
-
const segRe = /<(\w+:)?linesegarray\b[^>]*?(?:\/>|>[\s\S]*?<\/\1linesegarray>)/g;
|
|
19652
|
-
const splices = [];
|
|
19653
|
-
let m;
|
|
19654
|
-
while ((m = segRe.exec(xml)) !== null) {
|
|
19655
|
-
splices.push({ start: m.index, end: m.index + m[0].length, replacement: "" });
|
|
19656
|
-
}
|
|
19657
|
-
return splices;
|
|
19658
|
-
}
|
|
19659
|
-
function applySplices(xml, splices) {
|
|
19660
|
-
const sorted = [...splices].sort((a, b) => a.start - b.start);
|
|
19661
|
-
for (let i = 1; i < sorted.length; i++) {
|
|
19662
|
-
if (sorted[i].start < sorted[i - 1].end) {
|
|
19663
|
-
throw new Error("\uC18C\uC2A4\uB9F5 splice \uBC94\uC704 \uACB9\uCE68 \u2014 \uB0B4\uBD80 \uC624\uB958");
|
|
19664
|
-
}
|
|
19665
|
-
}
|
|
19666
|
-
let result = xml;
|
|
19667
|
-
for (let i = sorted.length - 1; i >= 0; i--) {
|
|
19668
|
-
const s = sorted[i];
|
|
19669
|
-
result = result.slice(0, s.start) + s.replacement + result.slice(s.end);
|
|
19670
|
-
}
|
|
19671
|
-
return result;
|
|
19672
|
-
}
|
|
19673
|
-
|
|
19674
|
-
// src/roundtrip/zip-patch.ts
|
|
19675
|
-
import { deflateRawSync } from "zlib";
|
|
19676
|
-
var EOCD_SIG = 101010256;
|
|
19677
|
-
var CD_SIG = 33639248;
|
|
19678
|
-
var LOCAL_SIG = 67324752;
|
|
19679
|
-
var ZIP64_EOCD_LOC_SIG = 117853008;
|
|
19680
|
-
function copyBytes(buf, start, end) {
|
|
19681
|
-
return new Uint8Array(buf.subarray(start, end));
|
|
19682
|
-
}
|
|
19683
|
-
function parseCentralDirectory(buf) {
|
|
19684
|
-
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
19685
|
-
const minEocd = Math.max(0, buf.length - 22 - 65535);
|
|
19686
|
-
let eocdOffset = -1;
|
|
19687
|
-
for (let i = buf.length - 22; i >= minEocd; i--) {
|
|
19688
|
-
if (view.getUint32(i, true) === EOCD_SIG && i + 22 + view.getUint16(i + 20, true) === buf.length) {
|
|
19689
|
-
eocdOffset = i;
|
|
19690
|
-
break;
|
|
19691
|
-
}
|
|
19692
|
-
}
|
|
19693
|
-
if (eocdOffset < 0) {
|
|
19694
|
-
for (let i = buf.length - 22; i >= minEocd; i--) {
|
|
19695
|
-
if (view.getUint32(i, true) !== EOCD_SIG) continue;
|
|
19696
|
-
if (i + 22 + view.getUint16(i + 20, true) > buf.length) continue;
|
|
19697
|
-
const cand = view.getUint32(i + 16, true);
|
|
19698
|
-
if (cand < buf.length - 4 && view.getUint32(cand, true) === CD_SIG) {
|
|
19699
|
-
eocdOffset = i;
|
|
19700
|
-
break;
|
|
19701
|
-
}
|
|
19702
|
-
}
|
|
19703
|
-
}
|
|
19704
|
-
if (eocdOffset < 0) throw new KordocError("ZIP EOCD\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
19705
|
-
const totalEntries = view.getUint16(eocdOffset + 10, true);
|
|
19706
|
-
const cdSize = view.getUint32(eocdOffset + 12, true);
|
|
19707
|
-
const cdOffset = view.getUint32(eocdOffset + 16, true);
|
|
19708
|
-
if (cdOffset === 4294967295 || totalEntries === 65535) throw new KordocError("ZIP64\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
19709
|
-
if (eocdOffset >= 20 && view.getUint32(eocdOffset - 20, true) === ZIP64_EOCD_LOC_SIG) {
|
|
19710
|
-
throw new KordocError("ZIP64\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
19711
|
-
}
|
|
19712
|
-
const decoder = new TextDecoder("utf-8");
|
|
19713
|
-
const entries = [];
|
|
19714
|
-
let pos = cdOffset;
|
|
19715
|
-
for (let i = 0; i < totalEntries; i++) {
|
|
19716
|
-
if (view.getUint32(pos, true) !== CD_SIG) throw new KordocError("ZIP Central Directory \uC190\uC0C1");
|
|
19717
|
-
const flags = view.getUint16(pos + 8, true);
|
|
19718
|
-
const method = view.getUint16(pos + 10, true);
|
|
19719
|
-
const crc = view.getUint32(pos + 16, true);
|
|
19720
|
-
const compSize = view.getUint32(pos + 20, true);
|
|
19721
|
-
const uncompSize = view.getUint32(pos + 24, true);
|
|
19722
|
-
const nameLen = view.getUint16(pos + 28, true);
|
|
19723
|
-
const extraLen = view.getUint16(pos + 30, true);
|
|
19724
|
-
const commentLen = view.getUint16(pos + 32, true);
|
|
19725
|
-
const localOffset = view.getUint32(pos + 42, true);
|
|
19726
|
-
if (compSize === 4294967295 || uncompSize === 4294967295 || localOffset === 4294967295) {
|
|
19727
|
-
throw new KordocError("ZIP64\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
19728
|
-
}
|
|
19729
|
-
const name = decoder.decode(buf.subarray(pos + 46, pos + 46 + nameLen));
|
|
19730
|
-
const cdEnd = pos + 46 + nameLen + extraLen + commentLen;
|
|
19731
|
-
entries.push({ cdStart: pos, cdEnd, name, flags, method, crc, compSize, uncompSize, localOffset });
|
|
19732
|
-
pos = cdEnd;
|
|
19733
|
-
}
|
|
19734
|
-
return { entries, cdOffset, cdSize, eocdOffset };
|
|
19735
|
-
}
|
|
19736
|
-
var CRC_TABLE = (() => {
|
|
19737
|
-
const table = new Uint32Array(256);
|
|
19738
|
-
for (let n = 0; n < 256; n++) {
|
|
19739
|
-
let c = n;
|
|
19740
|
-
for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
19741
|
-
table[n] = c >>> 0;
|
|
19742
|
-
}
|
|
19743
|
-
return table;
|
|
19744
|
-
})();
|
|
19745
|
-
function crc32(data) {
|
|
19746
|
-
let crc = 4294967295;
|
|
19747
|
-
for (let i = 0; i < data.length; i++) {
|
|
19748
|
-
crc = CRC_TABLE[(crc ^ data[i]) & 255] ^ crc >>> 8;
|
|
19749
|
-
}
|
|
19750
|
-
return (crc ^ 4294967295) >>> 0;
|
|
19751
|
-
}
|
|
19752
|
-
function patchZipEntries(original, replacements) {
|
|
19753
|
-
const { entries, cdOffset, eocdOffset } = parseCentralDirectory(original);
|
|
19754
|
-
const view = new DataView(original.buffer, original.byteOffset, original.byteLength);
|
|
19755
|
-
for (const name of replacements.keys()) {
|
|
19756
|
-
if (!entries.some((e) => e.name === name)) throw new KordocError(`ZIP\uC5D0 \uC5C6\uB294 \uC5D4\uD2B8\uB9AC: ${name}`);
|
|
19757
|
-
}
|
|
19758
|
-
const byLocal = [...entries].sort((a, b) => a.localOffset - b.localOffset);
|
|
19759
|
-
const segments = [];
|
|
19760
|
-
const newLocalOffset = /* @__PURE__ */ new Map();
|
|
19761
|
-
const newMeta = /* @__PURE__ */ new Map();
|
|
19762
|
-
let offset = 0;
|
|
19763
|
-
for (let i = 0; i < byLocal.length; i++) {
|
|
19764
|
-
const e = byLocal[i];
|
|
19765
|
-
const segEnd = i + 1 < byLocal.length ? byLocal[i + 1].localOffset : cdOffset;
|
|
19766
|
-
newLocalOffset.set(e, offset);
|
|
19767
|
-
const newData = replacements.get(e.name);
|
|
19768
|
-
if (newData === void 0) {
|
|
19769
|
-
const seg = original.subarray(e.localOffset, segEnd);
|
|
19770
|
-
segments.push(seg);
|
|
19771
|
-
offset += seg.length;
|
|
19772
|
-
continue;
|
|
19773
|
-
}
|
|
19774
|
-
if (view.getUint32(e.localOffset, true) !== LOCAL_SIG) throw new KordocError("ZIP \uB85C\uCEEC \uD5E4\uB354 \uC2DC\uADF8\uB2C8\uCC98 \uBD88\uC77C\uCE58");
|
|
19775
|
-
const nameLen = view.getUint16(e.localOffset + 26, true);
|
|
19776
|
-
const extraLen = view.getUint16(e.localOffset + 28, true);
|
|
19777
|
-
const headerLen = 30 + nameLen + extraLen;
|
|
19778
|
-
const header = copyBytes(original, e.localOffset, e.localOffset + headerLen);
|
|
19779
|
-
const hview = new DataView(header.buffer, header.byteOffset, header.byteLength);
|
|
19780
|
-
const method = e.method;
|
|
19781
|
-
const compData = method === 0 ? newData : new Uint8Array(deflateRawSync(newData));
|
|
19782
|
-
const crc = crc32(newData);
|
|
19783
|
-
const flags = e.flags & ~8;
|
|
19784
|
-
hview.setUint16(6, flags, true);
|
|
19785
|
-
hview.setUint32(14, crc, true);
|
|
19786
|
-
hview.setUint32(18, compData.length, true);
|
|
19787
|
-
hview.setUint32(22, newData.length, true);
|
|
19788
|
-
segments.push(header, compData);
|
|
19789
|
-
offset += headerLen + compData.length;
|
|
19790
|
-
newMeta.set(e, { crc, compSize: compData.length, uncompSize: newData.length, flags });
|
|
19791
|
-
}
|
|
19792
|
-
const newCdOffset = offset;
|
|
19793
|
-
for (const e of entries) {
|
|
19794
|
-
const cd = copyBytes(original, e.cdStart, e.cdEnd);
|
|
19795
|
-
const cview = new DataView(cd.buffer, cd.byteOffset, cd.byteLength);
|
|
19796
|
-
cview.setUint32(42, newLocalOffset.get(e), true);
|
|
19797
|
-
const meta = newMeta.get(e);
|
|
19798
|
-
if (meta) {
|
|
19799
|
-
cview.setUint16(8, meta.flags, true);
|
|
19800
|
-
cview.setUint32(16, meta.crc, true);
|
|
19801
|
-
cview.setUint32(20, meta.compSize, true);
|
|
19802
|
-
cview.setUint32(24, meta.uncompSize, true);
|
|
19803
|
-
}
|
|
19804
|
-
segments.push(cd);
|
|
19805
|
-
offset += cd.length;
|
|
19806
|
-
}
|
|
19807
|
-
const newCdSize = offset - newCdOffset;
|
|
19808
|
-
const eocd = copyBytes(original, eocdOffset);
|
|
19809
|
-
const eview = new DataView(eocd.buffer, eocd.byteOffset, eocd.byteLength);
|
|
19810
|
-
eview.setUint32(12, newCdSize, true);
|
|
19811
|
-
eview.setUint32(16, newCdOffset, true);
|
|
19812
|
-
segments.push(eocd);
|
|
19813
|
-
offset += eocd.length;
|
|
19814
|
-
const result = new Uint8Array(offset);
|
|
19815
|
-
let pos = 0;
|
|
19816
|
-
for (const seg of segments) {
|
|
19817
|
-
result.set(seg, pos);
|
|
19818
|
-
pos += seg.length;
|
|
19819
|
-
}
|
|
19820
|
-
return result;
|
|
19821
|
-
}
|
|
19822
|
-
|
|
19823
|
-
// src/form/filler-hwpx.ts
|
|
19824
19300
|
async function fillHwpx(hwpxBuffer, values) {
|
|
19825
19301
|
const u8 = new Uint8Array(hwpxBuffer);
|
|
19826
19302
|
const zip = await JSZip5.loadAsync(hwpxBuffer);
|
|
@@ -19976,7 +19452,8 @@ async function fillHwpx(hwpxBuffer, values) {
|
|
|
19976
19452
|
label: cellLabelText(headerCells[colIdx]).trim(),
|
|
19977
19453
|
value: newValue,
|
|
19978
19454
|
row: rowIdx,
|
|
19979
|
-
col: colIdx
|
|
19455
|
+
col: colIdx,
|
|
19456
|
+
key: matchKey
|
|
19980
19457
|
});
|
|
19981
19458
|
}
|
|
19982
19459
|
}
|
|
@@ -20513,12 +19990,14 @@ function generateContainerXml() {
|
|
|
20513
19990
|
</ocf:rootfiles>
|
|
20514
19991
|
</ocf:container>`;
|
|
20515
19992
|
}
|
|
20516
|
-
function generateManifest() {
|
|
19993
|
+
function generateManifest(chartParts = []) {
|
|
19994
|
+
const chartItems = chartParts.map((p, i) => `
|
|
19995
|
+
<opf:item id="chart${i + 1}" href="${p.name}" media-type="application/xml"/>`).join("");
|
|
20517
19996
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
20518
19997
|
<opf:package xmlns:opf="${NS_OPF}" xmlns:hpf="${NS_HPF}" xmlns:hh="${NS_HEAD}">
|
|
20519
19998
|
<opf:manifest>
|
|
20520
19999
|
<opf:item id="header" href="Contents/header.xml" media-type="application/xml"/>
|
|
20521
|
-
<opf:item id="section0" href="Contents/section0.xml" media-type="application/xml"
|
|
20000
|
+
<opf:item id="section0" href="Contents/section0.xml" media-type="application/xml"/>${chartItems}
|
|
20522
20001
|
</opf:manifest>
|
|
20523
20002
|
<opf:spine>
|
|
20524
20003
|
<opf:itemref idref="header" linear="no"/>
|
|
@@ -21487,6 +20966,9 @@ function readCommand(input, idx, depth) {
|
|
|
21487
20966
|
const body = readGroupOrToken(input, name.next, depth);
|
|
21488
20967
|
return { value: `${ACCENT_COMMANDS[command]}{${body.value}}`, next: body.next };
|
|
21489
20968
|
}
|
|
20969
|
+
if (command === ",") return { value: "`", next: name.next };
|
|
20970
|
+
if (command === ";" || command === ":") return { value: "~", next: name.next };
|
|
20971
|
+
if (command === "!") return { value: "", next: name.next };
|
|
21490
20972
|
if (command === "mathrm" || command === "text") {
|
|
21491
20973
|
const start = skipSpaces(input, name.next);
|
|
21492
20974
|
if (input[start] === "{") {
|
|
@@ -21562,6 +21044,210 @@ function generateEquationParagraph(input, zOrder = 0) {
|
|
|
21562
21044
|
return `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${generateEquationXml(script, zOrder)}</hp:run></hp:p>`;
|
|
21563
21045
|
}
|
|
21564
21046
|
|
|
21047
|
+
// src/hwpx/chart-gen.ts
|
|
21048
|
+
var XML_ESC = { "&": "&", "<": "<", ">": ">" };
|
|
21049
|
+
var xmlEscape = (s) => s.replace(/[&<>]/g, (c) => XML_ESC[c]);
|
|
21050
|
+
var CHART_TYPES = {
|
|
21051
|
+
0: { el: "barChart", dir: "col", grp: "clustered" },
|
|
21052
|
+
1: { el: "barChart", dir: "col", grp: "stacked", overlap: 100 },
|
|
21053
|
+
2: { el: "lineChart", grp: "standard", marker: true },
|
|
21054
|
+
3: { el: "barChart", dir: "bar", grp: "clustered" },
|
|
21055
|
+
4: { el: "barChart", dir: "bar", grp: "stacked", overlap: 100 },
|
|
21056
|
+
5: { el: "scatterChart", scatter: true },
|
|
21057
|
+
6: { el: "pieChart", pie: true },
|
|
21058
|
+
7: { el: "pieChart", pie: true, explode: true },
|
|
21059
|
+
8: { el: "doughnutChart", pie: true, hole: 50 },
|
|
21060
|
+
9: { el: "areaChart", grp: "standard" },
|
|
21061
|
+
10: { el: "areaChart", grp: "stacked" },
|
|
21062
|
+
11: { el: "radarChart", radar: true },
|
|
21063
|
+
12: { el: "bar3DChart", dir: "col", grp: "clustered" },
|
|
21064
|
+
13: { el: "bar3DChart", dir: "col", grp: "stacked", overlap: 100 },
|
|
21065
|
+
14: { el: "bar3DChart", dir: "bar", grp: "clustered" },
|
|
21066
|
+
15: { el: "bar3DChart", dir: "bar", grp: "stacked", overlap: 100 },
|
|
21067
|
+
16: { el: "pie3DChart", pie: true },
|
|
21068
|
+
17: { el: "pie3DChart", pie: true, explode: true },
|
|
21069
|
+
18: { el: "area3DChart", grp: "standard" },
|
|
21070
|
+
19: { el: "area3DChart", grp: "stacked" }
|
|
21071
|
+
};
|
|
21072
|
+
var CHART_ALIAS = {
|
|
21073
|
+
column: 0,
|
|
21074
|
+
col: 0,
|
|
21075
|
+
\uC138\uB85C\uB9C9\uB300: 0,
|
|
21076
|
+
\uB9C9\uB300: 0,
|
|
21077
|
+
column_stacked: 1,
|
|
21078
|
+
\uC138\uB85C\uB9C9\uB300_\uB204\uC801: 1,
|
|
21079
|
+
line: 2,
|
|
21080
|
+
\uC120: 2,
|
|
21081
|
+
\uAEBE\uC740\uC120: 2,
|
|
21082
|
+
bar: 3,
|
|
21083
|
+
\uAC00\uB85C\uB9C9\uB300: 3,
|
|
21084
|
+
bar_stacked: 4,
|
|
21085
|
+
scatter: 5,
|
|
21086
|
+
\uBD84\uC0B0: 5,
|
|
21087
|
+
pie: 6,
|
|
21088
|
+
\uC6D0: 6,
|
|
21089
|
+
\uD30C\uC774: 6,
|
|
21090
|
+
pie_explode: 7,
|
|
21091
|
+
doughnut: 8,
|
|
21092
|
+
donut: 8,
|
|
21093
|
+
\uB3C4\uB11B: 8,
|
|
21094
|
+
area: 9,
|
|
21095
|
+
\uC601\uC5ED: 9,
|
|
21096
|
+
area_stacked: 10,
|
|
21097
|
+
radar: 11,
|
|
21098
|
+
\uBC29\uC0AC\uD615: 11,
|
|
21099
|
+
bar3d: 12,
|
|
21100
|
+
column3d: 12,
|
|
21101
|
+
pie3d: 16
|
|
21102
|
+
};
|
|
21103
|
+
function chartSpec(t) {
|
|
21104
|
+
if (!t) return CHART_TYPES[0];
|
|
21105
|
+
const key = CHART_ALIAS[t.toLowerCase()] ?? Number(t);
|
|
21106
|
+
return CHART_TYPES[key] ?? CHART_TYPES[0];
|
|
21107
|
+
}
|
|
21108
|
+
var HU_PER_MM = 7200 / 25.4;
|
|
21109
|
+
var RESERVED_KEYS = /* @__PURE__ */ new Set(["type", "cat", "size", "colors", "point_colors", "title"]);
|
|
21110
|
+
function parseChartFence(text) {
|
|
21111
|
+
let type;
|
|
21112
|
+
let cat = null;
|
|
21113
|
+
let widthMm = 32250 / HU_PER_MM;
|
|
21114
|
+
let heightMm = 18750 / HU_PER_MM;
|
|
21115
|
+
let colors = null;
|
|
21116
|
+
let pointColors = null;
|
|
21117
|
+
const series = [];
|
|
21118
|
+
for (const rawLine of text.split("\n")) {
|
|
21119
|
+
const line = rawLine.trim();
|
|
21120
|
+
if (!line || line.startsWith("#")) continue;
|
|
21121
|
+
const colon = line.search(/[::]/);
|
|
21122
|
+
if (colon <= 0) continue;
|
|
21123
|
+
const key = line.slice(0, colon).trim();
|
|
21124
|
+
const value = line.slice(colon + 1).trim();
|
|
21125
|
+
const keyLower = key.toLowerCase();
|
|
21126
|
+
if (keyLower === "type") {
|
|
21127
|
+
type = value;
|
|
21128
|
+
} else if (keyLower === "cat") {
|
|
21129
|
+
cat = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
21130
|
+
} else if (keyLower === "size") {
|
|
21131
|
+
const m = value.match(/^(\d+(?:\.\d+)?)\s*[x×]\s*(\d+(?:\.\d+)?)$/i);
|
|
21132
|
+
if (m) {
|
|
21133
|
+
widthMm = Number(m[1]);
|
|
21134
|
+
heightMm = Number(m[2]);
|
|
21135
|
+
}
|
|
21136
|
+
} else if (keyLower === "colors") {
|
|
21137
|
+
colors = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
21138
|
+
} else if (keyLower === "point_colors") {
|
|
21139
|
+
pointColors = value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
21140
|
+
} else if (keyLower === "title") {
|
|
21141
|
+
} else if (!RESERVED_KEYS.has(keyLower)) {
|
|
21142
|
+
const nums = value.split(",").map((s) => Number(s.trim()));
|
|
21143
|
+
if (nums.length > 0 && nums.every((n) => Number.isFinite(n))) {
|
|
21144
|
+
series.push({ name: key, values: nums });
|
|
21145
|
+
}
|
|
21146
|
+
}
|
|
21147
|
+
}
|
|
21148
|
+
if (series.length === 0) return null;
|
|
21149
|
+
const spec = chartSpec(type);
|
|
21150
|
+
const catFinal = cat ?? series[0].values.map((_, i) => `\uD56D\uBAA9 ${i + 1}`);
|
|
21151
|
+
let finalSeries = spec.pie ? [series[0]] : series;
|
|
21152
|
+
finalSeries = finalSeries.map((s) => ({ ...s }));
|
|
21153
|
+
if (spec.pie) {
|
|
21154
|
+
const slice = colors ?? pointColors;
|
|
21155
|
+
if (slice) finalSeries[0].pointColors = slice;
|
|
21156
|
+
} else {
|
|
21157
|
+
if (colors) finalSeries.forEach((s, i) => {
|
|
21158
|
+
s.color = colors[i % colors.length];
|
|
21159
|
+
});
|
|
21160
|
+
if (pointColors && finalSeries[0]) finalSeries[0].pointColors = pointColors;
|
|
21161
|
+
}
|
|
21162
|
+
return {
|
|
21163
|
+
spec,
|
|
21164
|
+
cat: catFinal,
|
|
21165
|
+
series: finalSeries,
|
|
21166
|
+
widthHu: Math.round(widthMm * HU_PER_MM),
|
|
21167
|
+
heightHu: Math.round(heightMm * HU_PER_MM)
|
|
21168
|
+
};
|
|
21169
|
+
}
|
|
21170
|
+
var colLetter = (i) => String.fromCharCode(66 + i);
|
|
21171
|
+
function strCachePts(vals) {
|
|
21172
|
+
return `<c:ptCount val="${vals.length}"/>` + vals.map((v, i) => `<c:pt idx="${i}"><c:v>${xmlEscape(v)}</c:v></c:pt>`).join("");
|
|
21173
|
+
}
|
|
21174
|
+
function numCachePts(vals) {
|
|
21175
|
+
return `<c:formatCode>General</c:formatCode><c:ptCount val="${vals.length}"/>` + vals.map((v, i) => `<c:pt idx="${i}"><c:v>${Number(v) || 0}</c:v></c:pt>`).join("");
|
|
21176
|
+
}
|
|
21177
|
+
function chartColorFill(color) {
|
|
21178
|
+
if (color == null) return null;
|
|
21179
|
+
const c = color.trim();
|
|
21180
|
+
if (/^accent[1-6]$/i.test(c)) return `<a:solidFill><a:schemeClr val="${c.toLowerCase()}"/></a:solidFill>`;
|
|
21181
|
+
const hex = c.replace(/^#/, "").toUpperCase();
|
|
21182
|
+
if (/^[0-9A-F]{6}$/.test(hex)) return `<a:solidFill><a:srgbClr val="${hex}"/></a:solidFill>`;
|
|
21183
|
+
return null;
|
|
21184
|
+
}
|
|
21185
|
+
function serSpPr(color, stroke) {
|
|
21186
|
+
const f = chartColorFill(color);
|
|
21187
|
+
if (!f) return "<c:spPr/>";
|
|
21188
|
+
return stroke ? `<c:spPr><a:ln w="28575" cap="flat" cmpd="sng" algn="ctr">${f}<a:prstDash val="solid"/><a:round/></a:ln></c:spPr>` : `<c:spPr>${f}</c:spPr>`;
|
|
21189
|
+
}
|
|
21190
|
+
function dPtXml(pointColors, pie) {
|
|
21191
|
+
if (!pointColors?.length) return "";
|
|
21192
|
+
return pointColors.map((col, i) => {
|
|
21193
|
+
const f = chartColorFill(col);
|
|
21194
|
+
if (!f) return "";
|
|
21195
|
+
const mid = pie ? '<c:invertIfNegative val="0"/><c:bubble3D val="0"/><c:explosion val="0"/>' : '<c:bubble3D val="0"/>';
|
|
21196
|
+
return `<c:dPt><c:idx val="${i}"/>${mid}<c:spPr>${f}</c:spPr></c:dPt>`;
|
|
21197
|
+
}).join("");
|
|
21198
|
+
}
|
|
21199
|
+
function stdSer(idx, name, cat, values, explode, color, pointColors, stroke, pie) {
|
|
21200
|
+
const cl = colLetter(idx);
|
|
21201
|
+
return `<c:ser><c:idx val="${idx}"/><c:order val="${idx}"/><c:tx><c:strRef><c:f>Sheet1!$${cl}$1</c:f><c:strCache><c:ptCount val="1"/><c:pt idx="0"><c:v>${xmlEscape(name)}</c:v></c:pt></c:strCache></c:strRef></c:tx>${serSpPr(color, stroke)}<c:invertIfNegative val="0"/>` + (explode ? `<c:explosion val="25"/>` : "") + dPtXml(pointColors, pie) + `<c:cat><c:strRef><c:f>Sheet1!$A$2:$A$${cat.length + 1}</c:f><c:strCache>${strCachePts(cat)}</c:strCache></c:strRef></c:cat><c:val><c:numRef><c:f>Sheet1!$${cl}$2:$${cl}$${values.length + 1}</c:f><c:numCache>${numCachePts(values)}</c:numCache></c:numRef></c:val></c:ser>`;
|
|
21202
|
+
}
|
|
21203
|
+
function scatterSer(idx, name, xvals, yvals) {
|
|
21204
|
+
const cl = colLetter(idx);
|
|
21205
|
+
return `<c:ser><c:idx val="${idx}"/><c:order val="${idx}"/><c:tx><c:strRef><c:f>Sheet1!$${cl}$1</c:f><c:strCache><c:ptCount val="1"/><c:pt idx="0"><c:v>${xmlEscape(name)}</c:v></c:pt></c:strCache></c:strRef></c:tx><c:spPr><a:ln w="28575"><a:noFill/></a:ln></c:spPr><c:marker><c:symbol val="circle"/><c:size val="7"/></c:marker><c:xVal><c:numRef><c:f>Sheet1!$A$2:$A$${xvals.length + 1}</c:f><c:numCache>${numCachePts(xvals)}</c:numCache></c:numRef></c:xVal><c:yVal><c:numRef><c:f>Sheet1!$${cl}$2:$${cl}$${yvals.length + 1}</c:f><c:numCache>${numCachePts(yvals)}</c:numCache></c:numRef></c:yVal></c:ser>`;
|
|
21206
|
+
}
|
|
21207
|
+
function catAxXml(id, pos, cross) {
|
|
21208
|
+
return `<c:catAx><c:axId val="${id}"/><c:scaling><c:orientation val="minMax"/></c:scaling><c:axPos val="${pos}"/><c:crossAx val="${cross}"/><c:delete val="0"/><c:majorTickMark val="out"/><c:minorTickMark val="none"/><c:tickLblPos val="nextTo"/><c:crosses val="autoZero"/><c:auto val="1"/><c:lblAlgn val="ctr"/><c:lblOffset val="100"/><c:noMultiLvlLbl val="0"/></c:catAx>`;
|
|
21209
|
+
}
|
|
21210
|
+
function valAxXml(id, pos, cross) {
|
|
21211
|
+
return `<c:valAx><c:axId val="${id}"/><c:scaling><c:orientation val="minMax"/></c:scaling><c:axPos val="${pos}"/><c:majorGridlines/><c:numFmt formatCode="General" sourceLinked="1"/><c:crossAx val="${cross}"/><c:delete val="0"/><c:majorTickMark val="out"/><c:minorTickMark val="none"/><c:tickLblPos val="nextTo"/><c:crosses val="autoZero"/><c:crossBetween val="between"/></c:valAx>`;
|
|
21212
|
+
}
|
|
21213
|
+
function buildChartSpaceXml(fence) {
|
|
21214
|
+
const { spec, cat, series } = fence;
|
|
21215
|
+
const NS = 'xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart"';
|
|
21216
|
+
const ax1 = "111111111";
|
|
21217
|
+
const ax2 = "222222222";
|
|
21218
|
+
let plot;
|
|
21219
|
+
if (spec.scatter) {
|
|
21220
|
+
const n = Math.max(0, ...series.map((s) => s.values.length));
|
|
21221
|
+
const xs = Array.from({ length: n }, (_, i) => {
|
|
21222
|
+
const c = cat[i];
|
|
21223
|
+
const v = Number(c);
|
|
21224
|
+
return c !== void 0 && c !== "" && Number.isFinite(v) ? v : i + 1;
|
|
21225
|
+
});
|
|
21226
|
+
const sers = series.map((s, i) => scatterSer(i, s.name, xs, s.values)).join("");
|
|
21227
|
+
plot = `<c:scatterChart><c:scatterStyle val="lineMarker"/><c:varyColors val="0"/>${sers}<c:axId val="${ax1}"/><c:axId val="${ax2}"/></c:scatterChart>` + valAxXml(ax1, "b", ax2) + valAxXml(ax2, "l", ax1);
|
|
21228
|
+
} else if (spec.pie) {
|
|
21229
|
+
const s0 = series[0];
|
|
21230
|
+
plot = `<c:${spec.el}><c:varyColors val="1"/>${stdSer(0, s0.name, cat, s0.values, !!spec.explode, s0.color, s0.pointColors, false, true)}<c:firstSliceAng val="0"/>` + (spec.hole != null ? `<c:holeSize val="${spec.hole}"/>` : "") + `</c:${spec.el}>`;
|
|
21231
|
+
} else {
|
|
21232
|
+
const stroke = spec.el === "lineChart" || spec.el === "radarChart" || !!spec.radar;
|
|
21233
|
+
const sers = series.map((s, i) => stdSer(i, s.name, cat, s.values, false, s.color, s.pointColors, stroke, false)).join("");
|
|
21234
|
+
const horiz = spec.dir === "bar";
|
|
21235
|
+
let inner = "";
|
|
21236
|
+
if (spec.dir) inner += `<c:barDir val="${spec.dir}"/>`;
|
|
21237
|
+
if (spec.grp) inner += `<c:grouping val="${spec.grp}"/>`;
|
|
21238
|
+
if (spec.radar) inner += `<c:radarStyle val="standard"/>`;
|
|
21239
|
+
inner += `<c:varyColors val="0"/>${sers}`;
|
|
21240
|
+
if (spec.marker) inner += `<c:marker val="1"/>`;
|
|
21241
|
+
if (spec.el.startsWith("bar")) inner += `<c:gapWidth val="150"/><c:overlap val="${spec.overlap ?? 0}"/>`;
|
|
21242
|
+
inner += `<c:axId val="${ax1}"/><c:axId val="${ax2}"/>`;
|
|
21243
|
+
plot = `<c:${spec.el}>${inner}</c:${spec.el}>` + catAxXml(ax1, horiz ? "l" : "b", ax2) + valAxXml(ax2, horiz ? "b" : "l", ax1);
|
|
21244
|
+
}
|
|
21245
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><c:chartSpace ${NS}><c:date1904 val="0"/><c:roundedCorners val="0"/><c:chart><c:autoTitleDeleted val="0"/><c:plotArea><c:layout/>${plot}</c:plotArea><c:legend><c:legendPos val="r"/><c:overlay val="0"/></c:legend><c:plotVisOnly val="1"/><c:dispBlanksAs val="gap"/></c:chart></c:chartSpace>`;
|
|
21246
|
+
}
|
|
21247
|
+
function buildChartElementXml(partName, widthHu, heightHu, id) {
|
|
21248
|
+
return `<hp:chart id="${id}" zOrder="0" numberingType="PICTURE" textWrap="TOP_AND_BOTTOM" textFlow="BOTH_SIDES" lock="0" dropcapstyle="None" chartIDRef="${partName}"><hp:sz width="${widthHu}" widthRelTo="ABSOLUTE" height="${heightHu}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="1" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="709" right="709" top="709" bottom="709"/></hp:chart>`;
|
|
21249
|
+
}
|
|
21250
|
+
|
|
21565
21251
|
// src/hwpx/gen-section.ts
|
|
21566
21252
|
function generateSecPr(gongmun) {
|
|
21567
21253
|
const m = gongmun ? {
|
|
@@ -21574,7 +21260,7 @@ function generateSecPr(gongmun) {
|
|
|
21574
21260
|
} : { top: 8504, bottom: 4252, left: 5670, right: 4252, header: 2835, footer: 2835 };
|
|
21575
21261
|
return `<hp:secPr textDirection="HORIZONTAL" spaceColumns="1134" tabStop="8000" outlineShapeIDRef="1" memoShapeIDRef="0" textVerticalWidthHead="0" masterPageCnt="0"><hp:grid lineGrid="0" charGrid="0" wonggojiFormat="0"/><hp:startNum pageStartsOn="BOTH" page="0" pic="0" tbl="0" equation="0"/><hp:visibility hideFirstHeader="0" hideFirstFooter="0" hideFirstMasterPage="0" border="SHOW_ALL" fill="SHOW_ALL" hideFirstPageNum="0" hideFirstEmptyLine="0" showLineNumber="0"/><hp:pagePr landscape="WIDELY" width="59528" height="84188" gutterType="LEFT_ONLY"><hp:margin header="${m.header}" footer="${m.footer}" gutter="0" left="${m.left}" right="${m.right}" top="${m.top}" bottom="${m.bottom}"/></hp:pagePr><hp:footNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar=")" supscript="0"/><hp:noteLine length="-1" type="SOLID" width="0.12 mm" color="#000000"/><hp:noteSpacing betweenNotes="283" belowLine="567" aboveLine="850"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="EACH_COLUMN" beneathText="0"/></hp:footNotePr><hp:endNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar=")" supscript="0"/><hp:noteLine length="14692344" type="SOLID" width="0.12 mm" color="#000000"/><hp:noteSpacing betweenNotes="0" belowLine="567" aboveLine="850"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="END_OF_DOCUMENT" beneathText="0"/></hp:endNotePr></hp:secPr>`;
|
|
21576
21262
|
}
|
|
21577
|
-
function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null) {
|
|
21263
|
+
function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null, chartParts = null) {
|
|
21578
21264
|
const paraXmls = [];
|
|
21579
21265
|
let isFirst = true;
|
|
21580
21266
|
const orderedCounters = {};
|
|
@@ -21605,6 +21291,21 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
|
|
|
21605
21291
|
break;
|
|
21606
21292
|
}
|
|
21607
21293
|
case "code_block": {
|
|
21294
|
+
if (chartParts !== null && (block.lang || "").toLowerCase() === "chart") {
|
|
21295
|
+
const fence = parseChartFence(block.text || "");
|
|
21296
|
+
if (fence) {
|
|
21297
|
+
const partName = `Chart/chart${chartParts.length + 1}.xml`;
|
|
21298
|
+
chartParts.push({ name: partName, xml: buildChartSpaceXml(fence) });
|
|
21299
|
+
const chartEl = buildChartElementXml(partName, fence.widthHu, fence.heightHu, 91e5 + blockIdx);
|
|
21300
|
+
if (isFirst) {
|
|
21301
|
+
const secRun = `<hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run>`;
|
|
21302
|
+
paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
|
|
21303
|
+
isFirst = false;
|
|
21304
|
+
}
|
|
21305
|
+
xml = `<hp:p paraPrIDRef="${PARA_NORMAL}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_NORMAL}">${chartEl}</hp:run></hp:p>`;
|
|
21306
|
+
break;
|
|
21307
|
+
}
|
|
21308
|
+
}
|
|
21608
21309
|
const codeLines = (block.text || "").split("\n");
|
|
21609
21310
|
xml = codeLines.map((line) => generateParagraph(line || " ", PARA_CODE)).join("\n ");
|
|
21610
21311
|
break;
|
|
@@ -21714,13 +21415,15 @@ async function markdownToHwpx(markdown, options) {
|
|
|
21714
21415
|
const blocks = parseMarkdownToBlocks(markdown);
|
|
21715
21416
|
const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
|
|
21716
21417
|
const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
|
|
21717
|
-
const
|
|
21418
|
+
const chartParts = [];
|
|
21419
|
+
const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts);
|
|
21718
21420
|
const zip = new JSZip6();
|
|
21719
21421
|
zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
|
|
21720
21422
|
zip.file("META-INF/container.xml", generateContainerXml());
|
|
21721
|
-
zip.file("Contents/content.hpf", generateManifest());
|
|
21423
|
+
zip.file("Contents/content.hpf", generateManifest(chartParts));
|
|
21722
21424
|
zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun, fit?.variants ?? []));
|
|
21723
21425
|
zip.file("Contents/section0.xml", sectionXml);
|
|
21426
|
+
for (const part of chartParts) zip.file(part.name, part.xml);
|
|
21724
21427
|
zip.file("Preview/PrvText.txt", buildPrvText(blocks));
|
|
21725
21428
|
return await zip.generateAsync({ type: "arraybuffer" });
|
|
21726
21429
|
}
|
|
@@ -22839,7 +22542,7 @@ async function resolveHeaderEntryName(zip) {
|
|
|
22839
22542
|
}
|
|
22840
22543
|
|
|
22841
22544
|
// src/roundtrip/hwp5-patch.ts
|
|
22842
|
-
import { deflateRawSync
|
|
22545
|
+
import { deflateRawSync } from "zlib";
|
|
22843
22546
|
import { createRequire as createRequire2 } from "module";
|
|
22844
22547
|
|
|
22845
22548
|
// src/roundtrip/ole-surgeon.ts
|
|
@@ -23354,7 +23057,7 @@ async function patchHwp(original, editedMarkdown, options) {
|
|
|
23354
23057
|
for (let i = 0; i < scans.length; i++) {
|
|
23355
23058
|
if (scans[i].repl.size === 0 && scans[i].inserts.size === 0) continue;
|
|
23356
23059
|
const newStream = serializeRecords(scans[i].records, scans[i].repl, scans[i].inserts);
|
|
23357
|
-
const content = compressed ?
|
|
23060
|
+
const content = compressed ? deflateRawSync(newStream) : newStream;
|
|
23358
23061
|
out = replaceOleStream(out, sectionPaths[i], content);
|
|
23359
23062
|
}
|
|
23360
23063
|
data = new Uint8Array(out);
|
|
@@ -23489,10 +23192,11 @@ function handleModified(orig, edited, ctx) {
|
|
|
23489
23192
|
function patchParagraph(block, orig, edited, ctx, skip) {
|
|
23490
23193
|
const mapping = ctx.paraMap.get(orig.blockIdx);
|
|
23491
23194
|
if (!mapping?.para) return skip("\uBB38\uB2E8 \uC18C\uC2A4\uB9F5 \uB9E4\uD551 \uC2E4\uD328 (\uBA38\uB9AC\uB9D0/\uAE00\uC0C1\uC790/\uCEA1\uC158 \uC601\uC5ED\uC774\uAC70\uB098 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58)");
|
|
23492
|
-
|
|
23493
|
-
|
|
23195
|
+
const restoreBr = (s) => s.replace(/\s*<br\s*\/?\s*>\s*/gi, "\n");
|
|
23196
|
+
let newPlain = restoreBr(textUnitToPlain(edited.raw, block));
|
|
23197
|
+
if (block.text && block.text.includes("\n") && !newPlain.includes("\n")) {
|
|
23198
|
+
return skip("\uB2E4\uC911\uC904 \uBB38\uB2E8 \uC218\uC815\uC5D0 <br> \uC5C6\uC74C \u2014 \uC904\uBC14\uAFC8 \uC704\uCE58 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0 (\uC904\uBC14\uAFC8\uC740 <br>\uB85C \uD45C\uAE30)");
|
|
23494
23199
|
}
|
|
23495
|
-
let newPlain = textUnitToPlain(edited.raw, block);
|
|
23496
23200
|
if (block.footnoteText) {
|
|
23497
23201
|
const noteMatch = newPlain.match(/\s*\(주: ([\s\S]*)\)$/);
|
|
23498
23202
|
if (noteMatch) {
|
|
@@ -23514,7 +23218,7 @@ function patchParagraph(block, orig, edited, ctx, skip) {
|
|
|
23514
23218
|
ctx.skipped.push({ reason: "\uC790\uB3D9\uBC88\uD638 \uC811\uB450 \uC2DD\uBCC4 \uC2E4\uD328 \u2014 \uBC88\uD638 \uD3EC\uD568 \uD14D\uC2A4\uD2B8\uB85C \uC801\uC6A9 (\uBDF0\uC5B4\uC5D0\uC11C \uC911\uBCF5 \uD45C\uC2DC \uAC00\uB2A5)", after: summarize(newPlain) });
|
|
23515
23219
|
}
|
|
23516
23220
|
}
|
|
23517
|
-
const origPlain = textUnitToPlain(orig.raw, block);
|
|
23221
|
+
const origPlain = restoreBr(textUnitToPlain(orig.raw, block));
|
|
23518
23222
|
if (newPlain === origPlain) return skip("\uD14D\uC2A4\uD2B8 \uC678 \uBCC0\uACBD(\uD5E4\uB529 \uB808\uBCA8/\uC11C\uC2DD)\uB9CC \uAC10\uC9C0 \u2014 \uC2A4\uD0C0\uC77C \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
23519
23223
|
if (sanitizeText(newPlain) !== newPlain) {
|
|
23520
23224
|
return skip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uD328\uCE58 \uC2DC \uC6D0\uBB38 \uBCF4\uC874 \uBD88\uAC00\uB85C \uBBF8\uC9C0\uC6D0");
|
|
@@ -23542,6 +23246,28 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
|
|
|
23542
23246
|
}
|
|
23543
23247
|
const beforeParts = origRows[r][c].split(/<br\s*\/?>/i);
|
|
23544
23248
|
const afterParts = editedRows[r][c].split(/<br\s*\/?>/i);
|
|
23249
|
+
if (cell.paras.length === 1) {
|
|
23250
|
+
const beforeEach = beforeParts.map(gfmCellToPlain);
|
|
23251
|
+
const afterEach = afterParts.map(gfmCellToPlain);
|
|
23252
|
+
if (beforeEach.some((p) => p === null) || afterEach.some((p) => p === null)) {
|
|
23253
|
+
cellSkip("\uC11C\uC2DD/\uB9C1\uD06C/\uC774\uBBF8\uC9C0 \uD3EC\uD568 \uC140 \uC218\uC815\uC740 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
23254
|
+
continue;
|
|
23255
|
+
}
|
|
23256
|
+
const before = beforeEach.join("\n");
|
|
23257
|
+
const after = afterEach.join("\n");
|
|
23258
|
+
if (before === after) continue;
|
|
23259
|
+
const para = cell.paras[0];
|
|
23260
|
+
if (normForMatch(para.rawText) !== normForMatch(before)) {
|
|
23261
|
+
cellSkip("\uC140 \uD14D\uC2A4\uD2B8 \uBD88\uC77C\uCE58 \u2014 \uC18C\uC2A4\uB9F5 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
23262
|
+
continue;
|
|
23263
|
+
}
|
|
23264
|
+
if (afterEach.some((l) => sanitizeText(l) !== l)) {
|
|
23265
|
+
cellSkip("\uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
23266
|
+
continue;
|
|
23267
|
+
}
|
|
23268
|
+
applied += stageParaPatch(ctx.scans[para.sectionIndex], para, after, cellSkip);
|
|
23269
|
+
continue;
|
|
23270
|
+
}
|
|
23545
23271
|
if (beforeParts.length !== cell.paras.length || afterParts.length !== cell.paras.length) {
|
|
23546
23272
|
cellSkip("\uC140 \uBB38\uB2E8 \uC218 \uBCC0\uACBD \u2014 \uBBF8\uC9C0\uC6D0 (\uBB38\uB2E8 \uCD94\uAC00/\uC0AD\uC81C)");
|
|
23547
23273
|
continue;
|
|
@@ -23686,13 +23412,13 @@ function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, a
|
|
|
23686
23412
|
const assigned = [];
|
|
23687
23413
|
for (let i = 0; i < targets.length; i++) {
|
|
23688
23414
|
if (i < newLines.length) {
|
|
23689
|
-
assigned.push(i === targets.length - 1 && newLines.length > targets.length ? newLines.slice(i).join("
|
|
23415
|
+
assigned.push(i === targets.length - 1 && newLines.length > targets.length ? newLines.slice(i).join("\n") : newLines[i]);
|
|
23690
23416
|
} else {
|
|
23691
23417
|
assigned.push("");
|
|
23692
23418
|
}
|
|
23693
23419
|
}
|
|
23694
23420
|
if (newLines.length > targets.length) {
|
|
23695
|
-
ctx.skipped.push({ reason: "\uC140 \uB0B4 \uC904 \
|
|
23421
|
+
ctx.skipped.push({ reason: "\uC140 \uB0B4 \uCD94\uAC00 \uC904\uC744 \uB9C8\uC9C0\uB9C9 \uBB38\uB2E8\uC5D0 \uAC15\uC81C \uC904\uBC14\uAFC8\uC73C\uB85C \uBCD1\uD569(\uBB38\uB2E8 \uC0DD\uC131 \uB300\uC2E0)", after: summarize(after), partial: true });
|
|
23696
23422
|
} else if (newLines.length < nonEmpty.length && nonEmpty.length > 1) {
|
|
23697
23423
|
ctx.skipped.push({ reason: "\uC140 \uB0B4 \uC904 \uC0AD\uC81C\uB294 \uBB38\uB2E8 \uC81C\uAC70 \uBBF8\uC9C0\uC6D0 \u2014 \uBE48 \uBB38\uB2E8 \uC794\uC874(\uBDF0\uC5B4\uC5D0 \uBE48 \uC904 \uD45C\uC2DC \uAC00\uB2A5)", before: summarize(before), after: summarize(after), partial: true });
|
|
23698
23424
|
}
|
|
@@ -23750,8 +23476,7 @@ function splitParaText(data) {
|
|
|
23750
23476
|
i += 16;
|
|
23751
23477
|
toks.push({ start, end: i, units: 1, plain: false, visible: false });
|
|
23752
23478
|
} else {
|
|
23753
|
-
|
|
23754
|
-
toks.push({ start, end: i, units: 1, plain: false, visible: true });
|
|
23479
|
+
toks.push({ start, end: i, units: 1, plain: true, visible: true });
|
|
23755
23480
|
}
|
|
23756
23481
|
break;
|
|
23757
23482
|
default: {
|
|
@@ -23814,13 +23539,31 @@ function rebuildCharShape(csData, coreStartUnit) {
|
|
|
23814
23539
|
});
|
|
23815
23540
|
return { buf, count: kept.length };
|
|
23816
23541
|
}
|
|
23542
|
+
function synthesizeLineSegs(lineSegData, newRaw, startUnits) {
|
|
23543
|
+
if (lineSegData.length < 36) return null;
|
|
23544
|
+
const seg0 = lineSegData.subarray(0, 36);
|
|
23545
|
+
const vPos0 = seg0.readInt32LE(4);
|
|
23546
|
+
const pitch = seg0.readInt32LE(8) + seg0.readInt32LE(20);
|
|
23547
|
+
if (pitch <= 0) return null;
|
|
23548
|
+
const lines = newRaw.split("\n");
|
|
23549
|
+
const segs = [];
|
|
23550
|
+
let pos = startUnits;
|
|
23551
|
+
for (let k = 0; k < lines.length; k++) {
|
|
23552
|
+
const s = Buffer.from(seg0);
|
|
23553
|
+
s.writeUInt32LE((k === 0 ? 0 : pos) >>> 0, 0);
|
|
23554
|
+
s.writeInt32LE(vPos0 + k * pitch, 4);
|
|
23555
|
+
segs.push(s);
|
|
23556
|
+
pos += lines[k].length + 1;
|
|
23557
|
+
}
|
|
23558
|
+
return { buf: Buffer.concat(segs), count: lines.length };
|
|
23559
|
+
}
|
|
23817
23560
|
function stageParaPatch(scan, para, newPlain, skip) {
|
|
23818
23561
|
if (!scan.safe) return skip("\uC139\uC158 \uB808\uCF54\uB4DC \uC7AC\uC9C1\uB82C\uD654 \uBD88\uC77C\uCE58 \u2014 \uC548\uC804\uC744 \uC704\uD574 \uC774 \uC139\uC158\uC740 \uBBF8\uC9C0\uC6D0");
|
|
23819
23562
|
if (para.textIdx === -2) return skip("\uBCF5\uC218 PARA_TEXT \uB808\uCF54\uB4DC \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
23820
23563
|
if (para.rangeTagCount > 0) return skip("\uBC94\uC704 \uD0DC\uADF8(\uD615\uAD11\uD39C/\uAD50\uC815\uBD80\uD638) \uBB38\uB2E8 \u2014 \uBBF8\uC9C0\uC6D0 (v1)");
|
|
23821
23564
|
if (para.charShapeIdx < 0 || para.lineSegIdx < 0) return skip("\uBB38\uB2E8 \uB808\uCF54\uB4DC \uAD6C\uC131 \uBE44\uC815\uD615 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
23822
23565
|
if (scan.repl.has(para.headerIdx)) return skip("\uB3D9\uC77C \uBB38\uB2E8 \uC911\uBCF5 \uC218\uC815 \u2014 \uCCAB \uC218\uC815\uB9CC \uC801\uC6A9");
|
|
23823
|
-
if (/[\u0000-\u001f]/.test(newPlain)) return skip("\uC0C8 \uD14D\uC2A4\uD2B8\uC5D0 \uC81C\uC5B4\uBB38\uC790 \uD3EC\uD568 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
23566
|
+
if (/[\u0000-\u0009\u000b-\u001f]/.test(newPlain)) return skip("\uC0C8 \uD14D\uC2A4\uD2B8\uC5D0 \uC81C\uC5B4\uBB38\uC790 \uD3EC\uD568 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
23824
23567
|
const records = scan.records;
|
|
23825
23568
|
const headerRec = records[para.headerIdx];
|
|
23826
23569
|
const charShapeRec = records[para.charShapeIdx];
|
|
@@ -23840,6 +23583,13 @@ function stageParaPatch(scan, para, newPlain, skip) {
|
|
|
23840
23583
|
const cs2 = rebuildCharShape(charShapeRec.data, 0);
|
|
23841
23584
|
scan.repl.set(para.charShapeIdx, cs2.buf);
|
|
23842
23585
|
newHeader2.writeUInt16LE(cs2.count, 12);
|
|
23586
|
+
if (newPlain.includes("\n")) {
|
|
23587
|
+
const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newPlain, 0);
|
|
23588
|
+
if (synth) {
|
|
23589
|
+
scan.repl.set(para.lineSegIdx, synth.buf);
|
|
23590
|
+
newHeader2.writeUInt16LE(synth.count, 16);
|
|
23591
|
+
}
|
|
23592
|
+
}
|
|
23843
23593
|
scan.repl.set(para.headerIdx, newHeader2);
|
|
23844
23594
|
return 1;
|
|
23845
23595
|
}
|
|
@@ -23860,15 +23610,108 @@ function stageParaPatch(scan, para, newPlain, skip) {
|
|
|
23860
23610
|
const cs = rebuildCharShape(charShapeRec.data, seg.prefixUnits);
|
|
23861
23611
|
scan.repl.set(para.charShapeIdx, cs.buf);
|
|
23862
23612
|
newHeader.writeUInt16LE(cs.count, 12);
|
|
23613
|
+
if (newRaw.includes("\n")) {
|
|
23614
|
+
const synth = synthesizeLineSegs(records[para.lineSegIdx].data, newRaw, seg.prefixUnits);
|
|
23615
|
+
if (synth) {
|
|
23616
|
+
scan.repl.set(para.lineSegIdx, synth.buf);
|
|
23617
|
+
newHeader.writeUInt16LE(synth.count, 16);
|
|
23618
|
+
}
|
|
23619
|
+
}
|
|
23863
23620
|
scan.repl.set(para.headerIdx, newHeader);
|
|
23864
23621
|
return 1;
|
|
23865
23622
|
}
|
|
23866
23623
|
|
|
23867
|
-
// src/
|
|
23624
|
+
// src/validate.ts
|
|
23868
23625
|
import JSZip8 from "jszip";
|
|
23626
|
+
import { DOMParser as DOMParser4 } from "@xmldom/xmldom";
|
|
23627
|
+
var REQUIRED_FILES = [
|
|
23628
|
+
"mimetype",
|
|
23629
|
+
"META-INF/container.xml",
|
|
23630
|
+
"Contents/content.hpf",
|
|
23631
|
+
"Contents/header.xml",
|
|
23632
|
+
"Contents/section0.xml"
|
|
23633
|
+
];
|
|
23634
|
+
var EXPECTED_MIMETYPE = "application/hwp+zip";
|
|
23635
|
+
var XML_SUFFIXES = [".xml", ".hpf", ".rdf"];
|
|
23636
|
+
var SECTION_FILE_RE = /^Contents\/section\d+\.xml$/;
|
|
23637
|
+
var SECCNT_RE = /<(?:\w+:)?head\b[^>]*?\bsecCnt="(\d+)"/;
|
|
23638
|
+
var OPF_HREF_RE = /<opf:item\b[^>]*?\bhref="([^"]*)"/g;
|
|
23639
|
+
async function validateHwpx(buffer) {
|
|
23640
|
+
const issues = [];
|
|
23641
|
+
let zip;
|
|
23642
|
+
try {
|
|
23643
|
+
zip = await JSZip8.loadAsync(buffer);
|
|
23644
|
+
} catch (err) {
|
|
23645
|
+
return {
|
|
23646
|
+
ok: false,
|
|
23647
|
+
issues: [{ message: `\uC720\uD6A8\uD55C ZIP\uC774 \uC544\uB2D8: ${err instanceof Error ? err.message : String(err)}` }],
|
|
23648
|
+
entryCount: 0
|
|
23649
|
+
};
|
|
23650
|
+
}
|
|
23651
|
+
const rawNames = Object.keys(zip.files);
|
|
23652
|
+
const names = rawNames.filter((n) => !zip.files[n].dir);
|
|
23653
|
+
if (names.length === 0) return { ok: false, issues: [{ message: "\uBE48 ZIP" }], entryCount: 0 };
|
|
23654
|
+
if (rawNames[0] !== "mimetype") {
|
|
23655
|
+
issues.push({ message: `\uCCAB zip \uC5D4\uD2B8\uB9AC\uAC00 '${rawNames[0]}' \u2014 'mimetype'\uC774\uC5B4\uC57C \uD568` });
|
|
23656
|
+
}
|
|
23657
|
+
const nameset = new Set(names);
|
|
23658
|
+
if (nameset.has("mimetype")) {
|
|
23659
|
+
const mt = (await zip.files["mimetype"].async("string")).trim();
|
|
23660
|
+
if (mt !== EXPECTED_MIMETYPE) {
|
|
23661
|
+
issues.push({ path: "mimetype", message: `\uB0B4\uC6A9\uC774 '${mt}' \u2014 '${EXPECTED_MIMETYPE}'\uC774\uC5B4\uC57C \uD568` });
|
|
23662
|
+
}
|
|
23663
|
+
}
|
|
23664
|
+
for (const req of REQUIRED_FILES) {
|
|
23665
|
+
if (!nameset.has(req)) issues.push({ message: `\uD544\uC218 \uD30C\uC77C \uB204\uB77D: ${req}` });
|
|
23666
|
+
}
|
|
23667
|
+
for (const name of names) {
|
|
23668
|
+
if (!XML_SUFFIXES.some((s) => name.endsWith(s))) continue;
|
|
23669
|
+
const text = await zip.files[name].async("string");
|
|
23670
|
+
let firstError = null;
|
|
23671
|
+
try {
|
|
23672
|
+
new DOMParser4({
|
|
23673
|
+
onError(level, msg2) {
|
|
23674
|
+
if (level !== "warning" && firstError === null) firstError = String(msg2);
|
|
23675
|
+
}
|
|
23676
|
+
}).parseFromString(text, "text/xml");
|
|
23677
|
+
} catch (err) {
|
|
23678
|
+
firstError ??= err instanceof Error ? err.message : String(err);
|
|
23679
|
+
}
|
|
23680
|
+
if (firstError !== null) {
|
|
23681
|
+
issues.push({ path: name, message: `XML \uC6F0\uD3FC\uB4DC \uC704\uBC18: ${firstError.split("\n")[0]}` });
|
|
23682
|
+
}
|
|
23683
|
+
}
|
|
23684
|
+
if (nameset.has("Contents/header.xml")) {
|
|
23685
|
+
const header = await zip.files["Contents/header.xml"].async("string");
|
|
23686
|
+
const m = SECCNT_RE.exec(header);
|
|
23687
|
+
if (m) {
|
|
23688
|
+
const declared = Number(m[1]);
|
|
23689
|
+
const actual = names.filter((n) => SECTION_FILE_RE.test(n)).length;
|
|
23690
|
+
if (declared !== actual) {
|
|
23691
|
+
issues.push({
|
|
23692
|
+
path: "Contents/header.xml",
|
|
23693
|
+
message: `secCnt=${declared}\uC778\uB370 \uC2E4\uC81C sectionN.xml\uC740 ${actual}\uAC1C \u2014 \uD55C\uCEF4\uB3C5\uC2A4\uAC00 \uC5F4\uAE30\uB97C \uAC70\uBD80\uD568`
|
|
23694
|
+
});
|
|
23695
|
+
}
|
|
23696
|
+
}
|
|
23697
|
+
}
|
|
23698
|
+
if (nameset.has("Contents/content.hpf")) {
|
|
23699
|
+
const hpf = await zip.files["Contents/content.hpf"].async("string");
|
|
23700
|
+
for (const m of hpf.matchAll(OPF_HREF_RE)) {
|
|
23701
|
+
const href = m[1];
|
|
23702
|
+
if (!nameset.has(href) && !nameset.has(`Contents/${href}`)) {
|
|
23703
|
+
issues.push({ path: "Contents/content.hpf", message: `manifest\uAC00 \uC5C6\uB294 \uD30C\uC77C\uC744 \uCC38\uC870: ${href}` });
|
|
23704
|
+
}
|
|
23705
|
+
}
|
|
23706
|
+
}
|
|
23707
|
+
return { ok: issues.length === 0, issues, entryCount: names.length };
|
|
23708
|
+
}
|
|
23709
|
+
|
|
23710
|
+
// src/roundtrip/session.ts
|
|
23711
|
+
import JSZip9 from "jszip";
|
|
23869
23712
|
async function buildState(bytes) {
|
|
23870
23713
|
const parsed = await parseHwpxDocument(u8ToArrayBuffer2(bytes));
|
|
23871
|
-
const zip = await
|
|
23714
|
+
const zip = await JSZip9.loadAsync(bytes);
|
|
23872
23715
|
const sectionPaths = await resolveSectionEntryNames(zip);
|
|
23873
23716
|
if (sectionPaths.length === 0) {
|
|
23874
23717
|
throw new Error("HWPX \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
@@ -24449,7 +24292,7 @@ async function parseHwp(buffer, options) {
|
|
|
24449
24292
|
async function parsePdf(buffer, options) {
|
|
24450
24293
|
let parsePdfDocument;
|
|
24451
24294
|
try {
|
|
24452
|
-
const mod = await import("./parser-
|
|
24295
|
+
const mod = await import("./parser-HBHCD7TE.js");
|
|
24453
24296
|
parsePdfDocument = mod.parsePdfDocument;
|
|
24454
24297
|
} catch {
|
|
24455
24298
|
return {
|
|
@@ -24542,16 +24385,14 @@ async function fillForm(input, values, outputFormat = "markdown") {
|
|
|
24542
24385
|
export {
|
|
24543
24386
|
extractHwpxMetadataOnly,
|
|
24544
24387
|
extractHwp5MetadataOnly,
|
|
24388
|
+
formatFillValue,
|
|
24545
24389
|
ValueCursor,
|
|
24390
|
+
fillWithUniqueGuard,
|
|
24546
24391
|
isLabelCell,
|
|
24547
24392
|
extractFormFields,
|
|
24548
24393
|
inferFieldType,
|
|
24549
24394
|
extractFormSchema,
|
|
24550
24395
|
fillFormFields,
|
|
24551
|
-
scanSectionXml,
|
|
24552
|
-
buildParagraphSplices,
|
|
24553
|
-
buildRangeSplices,
|
|
24554
|
-
applySplices,
|
|
24555
24396
|
fillHwpx,
|
|
24556
24397
|
PRESET_ALIAS,
|
|
24557
24398
|
normalizeGongmunPreset,
|
|
@@ -24560,6 +24401,7 @@ export {
|
|
|
24560
24401
|
diffBlocks,
|
|
24561
24402
|
patchHwpx,
|
|
24562
24403
|
patchHwp,
|
|
24404
|
+
validateHwpx,
|
|
24563
24405
|
HwpxSession,
|
|
24564
24406
|
openHwpxDocument,
|
|
24565
24407
|
patchHwpxBlocks,
|
|
@@ -24577,4 +24419,4 @@ export {
|
|
|
24577
24419
|
parseHwpml,
|
|
24578
24420
|
fillForm
|
|
24579
24421
|
};
|
|
24580
|
-
//# sourceMappingURL=chunk-
|
|
24422
|
+
//# sourceMappingURL=chunk-WD5NUUU6.js.map
|