kordoc 2.2.2 → 2.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-R34CFFNV.js → chunk-SY2RFVLW.js} +1089 -149
- package/dist/chunk-SY2RFVLW.js.map +1 -0
- package/dist/cli.js +149 -4
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +847 -248
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +97 -7
- package/dist/index.d.ts +97 -7
- package/dist/index.js +843 -248
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +126 -6
- package/dist/mcp.js.map +1 -1
- package/dist/{watch-VNJDVUVQ.js → watch-5P7DJ3HG.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-R34CFFNV.js.map +0 -1
- /package/dist/{watch-VNJDVUVQ.js.map → watch-5P7DJ3HG.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -139,7 +139,7 @@ import { inflateRawSync } from "zlib";
|
|
|
139
139
|
import { DOMParser } from "@xmldom/xmldom";
|
|
140
140
|
|
|
141
141
|
// src/utils.ts
|
|
142
|
-
var VERSION = true ? "2.2.
|
|
142
|
+
var VERSION = true ? "2.2.4" : "0.0.0-dev";
|
|
143
143
|
function toArrayBuffer(buf) {
|
|
144
144
|
if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {
|
|
145
145
|
return buf.buffer;
|
|
@@ -457,9 +457,47 @@ function blocksToMarkdown(blocks) {
|
|
|
457
457
|
}
|
|
458
458
|
return lines.join("\n").trim();
|
|
459
459
|
}
|
|
460
|
+
function hasMergedCells(table) {
|
|
461
|
+
for (const row of table.cells) {
|
|
462
|
+
for (const cell of row) {
|
|
463
|
+
if (cell.colSpan > 1 || cell.rowSpan > 1) return true;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
function tableToHtml(table) {
|
|
469
|
+
const { cells, rows: numRows, cols: numCols } = table;
|
|
470
|
+
const skip = /* @__PURE__ */ new Set();
|
|
471
|
+
const lines = ["<table>"];
|
|
472
|
+
for (let r = 0; r < numRows; r++) {
|
|
473
|
+
const tag = r === 0 ? "th" : "td";
|
|
474
|
+
const rowHtml = [];
|
|
475
|
+
for (let c = 0; c < numCols; c++) {
|
|
476
|
+
if (skip.has(`${r},${c}`)) continue;
|
|
477
|
+
const cell = cells[r]?.[c];
|
|
478
|
+
if (!cell) continue;
|
|
479
|
+
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
480
|
+
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
481
|
+
if (dr === 0 && dc === 0) continue;
|
|
482
|
+
if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
const text = sanitizeText(cell.text).replace(/\n/g, "<br>");
|
|
486
|
+
const attrs = [];
|
|
487
|
+
if (cell.colSpan > 1) attrs.push(`colspan="${cell.colSpan}"`);
|
|
488
|
+
if (cell.rowSpan > 1) attrs.push(`rowspan="${cell.rowSpan}"`);
|
|
489
|
+
const attrStr = attrs.length ? " " + attrs.join(" ") : "";
|
|
490
|
+
rowHtml.push(`<${tag}${attrStr}>${text}</${tag}>`);
|
|
491
|
+
}
|
|
492
|
+
if (rowHtml.length) lines.push(`<tr>${rowHtml.join("")}</tr>`);
|
|
493
|
+
}
|
|
494
|
+
lines.push("</table>");
|
|
495
|
+
return lines.join("\n");
|
|
496
|
+
}
|
|
460
497
|
function tableToMarkdown(table) {
|
|
461
498
|
if (table.rows === 0 || table.cols === 0) return "";
|
|
462
499
|
const { cells, rows: numRows, cols: numCols } = table;
|
|
500
|
+
if (hasMergedCells(table)) return tableToHtml(table);
|
|
463
501
|
if (numRows === 1 && numCols === 1) {
|
|
464
502
|
const content = sanitizeText(cells[0][0].text);
|
|
465
503
|
if (!content) return "";
|
|
@@ -5525,21 +5563,21 @@ async function parseXlsxDocument(buffer, options) {
|
|
|
5525
5563
|
import JSZip4 from "jszip";
|
|
5526
5564
|
import { DOMParser as DOMParser3 } from "@xmldom/xmldom";
|
|
5527
5565
|
var MAX_DECOMPRESS_SIZE4 = 100 * 1024 * 1024;
|
|
5528
|
-
function getChildElements(parent,
|
|
5566
|
+
function getChildElements(parent, localName2) {
|
|
5529
5567
|
const result = [];
|
|
5530
5568
|
const children = parent.childNodes;
|
|
5531
5569
|
for (let i = 0; i < children.length; i++) {
|
|
5532
5570
|
const node = children[i];
|
|
5533
5571
|
if (node.nodeType === 1) {
|
|
5534
5572
|
const el = node;
|
|
5535
|
-
if (el.localName ===
|
|
5573
|
+
if (el.localName === localName2 || el.tagName?.endsWith(`:${localName2}`)) {
|
|
5536
5574
|
result.push(el);
|
|
5537
5575
|
}
|
|
5538
5576
|
}
|
|
5539
5577
|
}
|
|
5540
5578
|
return result;
|
|
5541
5579
|
}
|
|
5542
|
-
function findElements(parent,
|
|
5580
|
+
function findElements(parent, localName2) {
|
|
5543
5581
|
const result = [];
|
|
5544
5582
|
const walk = (node) => {
|
|
5545
5583
|
const children = node.childNodes;
|
|
@@ -5547,7 +5585,7 @@ function findElements(parent, localName) {
|
|
|
5547
5585
|
const child = children[i];
|
|
5548
5586
|
if (child.nodeType === 1) {
|
|
5549
5587
|
const el = child;
|
|
5550
|
-
if (el.localName ===
|
|
5588
|
+
if (el.localName === localName2 || el.tagName?.endsWith(`:${localName2}`)) {
|
|
5551
5589
|
result.push(el);
|
|
5552
5590
|
}
|
|
5553
5591
|
walk(el);
|
|
@@ -5557,11 +5595,11 @@ function findElements(parent, localName) {
|
|
|
5557
5595
|
walk(parent);
|
|
5558
5596
|
return result;
|
|
5559
5597
|
}
|
|
5560
|
-
function getAttr(el,
|
|
5598
|
+
function getAttr(el, localName2) {
|
|
5561
5599
|
const attrs = el.attributes;
|
|
5562
5600
|
for (let i = 0; i < attrs.length; i++) {
|
|
5563
5601
|
const attr = attrs[i];
|
|
5564
|
-
if (attr.localName ===
|
|
5602
|
+
if (attr.localName === localName2 || attr.name === localName2) return attr.value;
|
|
5565
5603
|
}
|
|
5566
5604
|
return null;
|
|
5567
5605
|
}
|
|
@@ -5908,11 +5946,11 @@ async function parseDocxDocument(buffer, options) {
|
|
|
5908
5946
|
const node = children[i];
|
|
5909
5947
|
if (node.nodeType !== 1) continue;
|
|
5910
5948
|
const el = node;
|
|
5911
|
-
const
|
|
5912
|
-
if (
|
|
5949
|
+
const localName2 = el.localName ?? el.tagName?.split(":").pop();
|
|
5950
|
+
if (localName2 === "p") {
|
|
5913
5951
|
const block = parseParagraph(el, styles, numbering, footnotes, rels);
|
|
5914
5952
|
if (block) blocks.push(block);
|
|
5915
|
-
} else if (
|
|
5953
|
+
} else if (localName2 === "tbl") {
|
|
5916
5954
|
const block = parseTable(el, styles, numbering, footnotes, rels);
|
|
5917
5955
|
if (block) blocks.push(block);
|
|
5918
5956
|
}
|
|
@@ -5950,183 +5988,6 @@ async function parseDocxDocument(buffer, options) {
|
|
|
5950
5988
|
};
|
|
5951
5989
|
}
|
|
5952
5990
|
|
|
5953
|
-
// src/diff/text-diff.ts
|
|
5954
|
-
function similarity(a, b) {
|
|
5955
|
-
if (a === b) return 1;
|
|
5956
|
-
if (!a || !b) return 0;
|
|
5957
|
-
const maxLen = Math.max(a.length, b.length);
|
|
5958
|
-
if (maxLen === 0) return 1;
|
|
5959
|
-
return 1 - levenshtein(a, b) / maxLen;
|
|
5960
|
-
}
|
|
5961
|
-
function normalizedSimilarity(a, b) {
|
|
5962
|
-
return similarity(normalize(a), normalize(b));
|
|
5963
|
-
}
|
|
5964
|
-
function normalize(s) {
|
|
5965
|
-
return s.replace(/\s+/g, " ").trim();
|
|
5966
|
-
}
|
|
5967
|
-
var MAX_LEVENSHTEIN_LEN = 1e4;
|
|
5968
|
-
function levenshtein(a, b) {
|
|
5969
|
-
if (a.length + b.length > MAX_LEVENSHTEIN_LEN) {
|
|
5970
|
-
const sampleLen = Math.min(500, a.length, b.length);
|
|
5971
|
-
let diffs = 0;
|
|
5972
|
-
for (let i = 0; i < sampleLen; i++) if (a[i] !== b[i]) diffs++;
|
|
5973
|
-
const sampleRate = sampleLen > 0 ? diffs / sampleLen : 1;
|
|
5974
|
-
return Math.abs(a.length - b.length) + Math.round(Math.min(a.length, b.length) * sampleRate);
|
|
5975
|
-
}
|
|
5976
|
-
if (a.length > b.length) [a, b] = [b, a];
|
|
5977
|
-
const m = a.length;
|
|
5978
|
-
const n = b.length;
|
|
5979
|
-
let prev = Array.from({ length: m + 1 }, (_, i) => i);
|
|
5980
|
-
let curr = new Array(m + 1);
|
|
5981
|
-
for (let j = 1; j <= n; j++) {
|
|
5982
|
-
curr[0] = j;
|
|
5983
|
-
for (let i = 1; i <= m; i++) {
|
|
5984
|
-
if (a[i - 1] === b[j - 1]) {
|
|
5985
|
-
curr[i] = prev[i - 1];
|
|
5986
|
-
} else {
|
|
5987
|
-
curr[i] = 1 + Math.min(prev[i - 1], prev[i], curr[i - 1]);
|
|
5988
|
-
}
|
|
5989
|
-
}
|
|
5990
|
-
;
|
|
5991
|
-
[prev, curr] = [curr, prev];
|
|
5992
|
-
}
|
|
5993
|
-
return prev[m];
|
|
5994
|
-
}
|
|
5995
|
-
|
|
5996
|
-
// src/diff/compare.ts
|
|
5997
|
-
var SIMILARITY_THRESHOLD = 0.4;
|
|
5998
|
-
async function compare(bufferA, bufferB, options) {
|
|
5999
|
-
const [resultA, resultB] = await Promise.all([
|
|
6000
|
-
parse(bufferA, options),
|
|
6001
|
-
parse(bufferB, options)
|
|
6002
|
-
]);
|
|
6003
|
-
if (!resultA.success) throw new Error(`\uBB38\uC11CA \uD30C\uC2F1 \uC2E4\uD328: ${resultA.error}`);
|
|
6004
|
-
if (!resultB.success) throw new Error(`\uBB38\uC11CB \uD30C\uC2F1 \uC2E4\uD328: ${resultB.error}`);
|
|
6005
|
-
return diffBlocks(resultA.blocks, resultB.blocks);
|
|
6006
|
-
}
|
|
6007
|
-
function diffBlocks(blocksA, blocksB) {
|
|
6008
|
-
const aligned = alignBlocks(blocksA, blocksB);
|
|
6009
|
-
const stats = { added: 0, removed: 0, modified: 0, unchanged: 0 };
|
|
6010
|
-
const diffs = [];
|
|
6011
|
-
for (const [a, b] of aligned) {
|
|
6012
|
-
if (a && b) {
|
|
6013
|
-
const sim = blockSimilarity(a, b);
|
|
6014
|
-
if (sim >= 0.99) {
|
|
6015
|
-
diffs.push({ type: "unchanged", before: a, after: b, similarity: 1 });
|
|
6016
|
-
stats.unchanged++;
|
|
6017
|
-
} else {
|
|
6018
|
-
const diff = { type: "modified", before: a, after: b, similarity: sim };
|
|
6019
|
-
if (a.type === "table" && b.type === "table" && a.table && b.table) {
|
|
6020
|
-
diff.cellDiffs = diffTableCells(a.table, b.table);
|
|
6021
|
-
}
|
|
6022
|
-
diffs.push(diff);
|
|
6023
|
-
stats.modified++;
|
|
6024
|
-
}
|
|
6025
|
-
} else if (a) {
|
|
6026
|
-
diffs.push({ type: "removed", before: a });
|
|
6027
|
-
stats.removed++;
|
|
6028
|
-
} else if (b) {
|
|
6029
|
-
diffs.push({ type: "added", after: b });
|
|
6030
|
-
stats.added++;
|
|
6031
|
-
}
|
|
6032
|
-
}
|
|
6033
|
-
return { stats, diffs };
|
|
6034
|
-
}
|
|
6035
|
-
function alignBlocks(a, b) {
|
|
6036
|
-
const m = a.length, n = b.length;
|
|
6037
|
-
if (m * n > 1e7) return fallbackAlign(a, b);
|
|
6038
|
-
const simCache = /* @__PURE__ */ new Map();
|
|
6039
|
-
const getSim = (i2, j2) => {
|
|
6040
|
-
const key = `${i2},${j2}`;
|
|
6041
|
-
let v = simCache.get(key);
|
|
6042
|
-
if (v === void 0) {
|
|
6043
|
-
v = blockSimilarity(a[i2], b[j2]);
|
|
6044
|
-
simCache.set(key, v);
|
|
6045
|
-
}
|
|
6046
|
-
return v;
|
|
6047
|
-
};
|
|
6048
|
-
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
|
|
6049
|
-
for (let i2 = 1; i2 <= m; i2++) {
|
|
6050
|
-
for (let j2 = 1; j2 <= n; j2++) {
|
|
6051
|
-
if (getSim(i2 - 1, j2 - 1) >= SIMILARITY_THRESHOLD) {
|
|
6052
|
-
dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
|
|
6053
|
-
} else {
|
|
6054
|
-
dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
6055
|
-
}
|
|
6056
|
-
}
|
|
6057
|
-
}
|
|
6058
|
-
const pairs = [];
|
|
6059
|
-
let i = m, j = n;
|
|
6060
|
-
while (i > 0 && j > 0) {
|
|
6061
|
-
if (getSim(i - 1, j - 1) >= SIMILARITY_THRESHOLD && dp[i][j] === dp[i - 1][j - 1] + 1) {
|
|
6062
|
-
pairs.push([i - 1, j - 1]);
|
|
6063
|
-
i--;
|
|
6064
|
-
j--;
|
|
6065
|
-
} else if (dp[i - 1][j] >= dp[i][j - 1]) {
|
|
6066
|
-
i--;
|
|
6067
|
-
} else {
|
|
6068
|
-
j--;
|
|
6069
|
-
}
|
|
6070
|
-
}
|
|
6071
|
-
pairs.reverse();
|
|
6072
|
-
const result = [];
|
|
6073
|
-
let ai = 0, bi = 0;
|
|
6074
|
-
for (const [pi, pj] of pairs) {
|
|
6075
|
-
while (ai < pi) result.push([a[ai++], null]);
|
|
6076
|
-
while (bi < pj) result.push([null, b[bi++]]);
|
|
6077
|
-
result.push([a[ai++], b[bi++]]);
|
|
6078
|
-
}
|
|
6079
|
-
while (ai < m) result.push([a[ai++], null]);
|
|
6080
|
-
while (bi < n) result.push([null, b[bi++]]);
|
|
6081
|
-
return result;
|
|
6082
|
-
}
|
|
6083
|
-
function fallbackAlign(a, b) {
|
|
6084
|
-
const result = [];
|
|
6085
|
-
const len = Math.max(a.length, b.length);
|
|
6086
|
-
for (let i = 0; i < len; i++) {
|
|
6087
|
-
result.push([a[i] || null, b[i] || null]);
|
|
6088
|
-
}
|
|
6089
|
-
return result;
|
|
6090
|
-
}
|
|
6091
|
-
function blockSimilarity(a, b) {
|
|
6092
|
-
if (a.type !== b.type) return 0;
|
|
6093
|
-
if (a.text !== void 0 && b.text !== void 0) {
|
|
6094
|
-
return normalizedSimilarity(a.text || "", b.text || "");
|
|
6095
|
-
}
|
|
6096
|
-
if (a.type === "table" && a.table && b.table) {
|
|
6097
|
-
return tableSimilarity(a.table, b.table);
|
|
6098
|
-
}
|
|
6099
|
-
if (a.type === b.type) return 1;
|
|
6100
|
-
return 0;
|
|
6101
|
-
}
|
|
6102
|
-
function tableSimilarity(a, b) {
|
|
6103
|
-
const dimSim = 1 - Math.abs(a.rows * a.cols - b.rows * b.cols) / Math.max(a.rows * a.cols, b.rows * b.cols, 1);
|
|
6104
|
-
const textsA = a.cells.flat().map((c) => c.text).join(" ");
|
|
6105
|
-
const textsB = b.cells.flat().map((c) => c.text).join(" ");
|
|
6106
|
-
const contentSim = normalizedSimilarity(textsA, textsB);
|
|
6107
|
-
return dimSim * 0.3 + contentSim * 0.7;
|
|
6108
|
-
}
|
|
6109
|
-
function diffTableCells(a, b) {
|
|
6110
|
-
const maxRows = Math.max(a.rows, b.rows);
|
|
6111
|
-
const maxCols = Math.max(a.cols, b.cols);
|
|
6112
|
-
const result = [];
|
|
6113
|
-
for (let r = 0; r < maxRows; r++) {
|
|
6114
|
-
const row = [];
|
|
6115
|
-
for (let c = 0; c < maxCols; c++) {
|
|
6116
|
-
const cellA = r < a.rows && c < a.cols ? a.cells[r][c].text : void 0;
|
|
6117
|
-
const cellB = r < b.rows && c < b.cols ? b.cells[r][c].text : void 0;
|
|
6118
|
-
let type;
|
|
6119
|
-
if (cellA === void 0) type = "added";
|
|
6120
|
-
else if (cellB === void 0) type = "removed";
|
|
6121
|
-
else if (cellA === cellB) type = "unchanged";
|
|
6122
|
-
else type = "modified";
|
|
6123
|
-
row.push({ type, before: cellA, after: cellB });
|
|
6124
|
-
}
|
|
6125
|
-
result.push(row);
|
|
6126
|
-
}
|
|
6127
|
-
return result;
|
|
6128
|
-
}
|
|
6129
|
-
|
|
6130
5991
|
// src/form/recognize.ts
|
|
6131
5992
|
var LABEL_KEYWORDS = /* @__PURE__ */ new Set([
|
|
6132
5993
|
"\uC131\uBA85",
|
|
@@ -6167,15 +6028,20 @@ var LABEL_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
6167
6028
|
"\uB2E8\uAC00",
|
|
6168
6029
|
"\uD569\uACC4",
|
|
6169
6030
|
"\uACC4",
|
|
6170
|
-
"\uC18C\uACC4"
|
|
6031
|
+
"\uC18C\uACC4",
|
|
6032
|
+
"\uB4F1\uB85D\uAE30\uC900\uC9C0",
|
|
6033
|
+
"\uBCF8\uC801",
|
|
6034
|
+
"\uC704\uC784\uC778",
|
|
6035
|
+
"\uCCAD\uAD6C\uC0AC\uC720",
|
|
6036
|
+
"\uC18C\uBA85\uC790\uB8CC"
|
|
6171
6037
|
]);
|
|
6172
6038
|
function isLabelCell(text) {
|
|
6173
|
-
const trimmed = text.trim();
|
|
6039
|
+
const trimmed = text.trim().replace(/[¹²³⁴⁵⁶⁷⁸⁹⁰*※]+$/g, "").trim();
|
|
6174
6040
|
if (!trimmed || trimmed.length > 30) return false;
|
|
6175
6041
|
for (const kw of LABEL_KEYWORDS) {
|
|
6176
6042
|
if (trimmed.includes(kw)) return true;
|
|
6177
6043
|
}
|
|
6178
|
-
if (/^[가-힣\s()
|
|
6044
|
+
if (/^[가-힣\s()()·::]+$/.test(trimmed) && trimmed.replace(/\s/g, "").length >= 2 && trimmed.replace(/\s/g, "").length <= 8 && !/\d/.test(trimmed)) return true;
|
|
6179
6045
|
if (/^[가-힣A-Za-z\s]+[::]$/.test(trimmed)) return true;
|
|
6180
6046
|
return false;
|
|
6181
6047
|
}
|
|
@@ -6208,7 +6074,7 @@ function extractFromTable(table) {
|
|
|
6208
6074
|
for (let c = 0; c < table.cols - 1; c++) {
|
|
6209
6075
|
const labelCell = table.cells[r][c];
|
|
6210
6076
|
const valueCell = table.cells[r][c + 1];
|
|
6211
|
-
if (isLabelCell(labelCell.text)
|
|
6077
|
+
if (isLabelCell(labelCell.text)) {
|
|
6212
6078
|
fields.push({
|
|
6213
6079
|
label: labelCell.text.trim().replace(/[::]\s*$/, ""),
|
|
6214
6080
|
value: valueCell.text.trim(),
|
|
@@ -6253,65 +6119,574 @@ function extractInlineFields(text) {
|
|
|
6253
6119
|
return fields;
|
|
6254
6120
|
}
|
|
6255
6121
|
|
|
6256
|
-
// src/
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
var NS_PARA = "http://www.hancom.co.kr/hwpml/2011/paragraph";
|
|
6260
|
-
var NS_HEAD = "http://www.hancom.co.kr/hwpml/2011/head";
|
|
6261
|
-
var NS_OPF = "http://www.idpf.org/2007/opf/";
|
|
6262
|
-
var NS_HPF = "http://www.hancom.co.kr/schema/2011/hpf";
|
|
6263
|
-
var NS_OCF = "urn:oasis:names:tc:opendocument:xmlns:container";
|
|
6264
|
-
var CHAR_NORMAL = 0;
|
|
6265
|
-
var CHAR_BOLD = 1;
|
|
6266
|
-
var CHAR_ITALIC = 2;
|
|
6267
|
-
var CHAR_BOLD_ITALIC = 3;
|
|
6268
|
-
var CHAR_CODE = 4;
|
|
6269
|
-
var CHAR_H1 = 5;
|
|
6270
|
-
var CHAR_H2 = 6;
|
|
6271
|
-
var CHAR_H3 = 7;
|
|
6272
|
-
var CHAR_H4 = 8;
|
|
6273
|
-
var PARA_NORMAL = 0;
|
|
6274
|
-
var PARA_H1 = 1;
|
|
6275
|
-
var PARA_H2 = 2;
|
|
6276
|
-
var PARA_H3 = 3;
|
|
6277
|
-
var PARA_H4 = 4;
|
|
6278
|
-
var PARA_CODE = 5;
|
|
6279
|
-
var PARA_QUOTE = 6;
|
|
6280
|
-
var PARA_LIST = 7;
|
|
6281
|
-
async function markdownToHwpx(markdown) {
|
|
6282
|
-
const blocks = parseMarkdownToBlocks(markdown);
|
|
6283
|
-
const sectionXml = blocksToSectionXml(blocks);
|
|
6284
|
-
const zip = new JSZip5();
|
|
6285
|
-
zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
|
|
6286
|
-
zip.file("META-INF/container.xml", generateContainerXml());
|
|
6287
|
-
zip.file("Contents/content.hpf", generateManifest());
|
|
6288
|
-
zip.file("Contents/header.xml", generateHeaderXml());
|
|
6289
|
-
zip.file("Contents/section0.xml", sectionXml);
|
|
6290
|
-
return await zip.generateAsync({ type: "arraybuffer" });
|
|
6122
|
+
// src/form/match.ts
|
|
6123
|
+
function normalizeLabel(label) {
|
|
6124
|
+
return label.trim().replace(/[::\s()()·]/g, "");
|
|
6291
6125
|
}
|
|
6292
|
-
function
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
let
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
const codeLines = [];
|
|
6307
|
-
i++;
|
|
6308
|
-
while (i < lines.length && !lines[i].startsWith(fence)) {
|
|
6309
|
-
codeLines.push(lines[i]);
|
|
6310
|
-
i++;
|
|
6126
|
+
function findMatchingKey(cellLabel, values) {
|
|
6127
|
+
if (values.has(cellLabel)) return cellLabel;
|
|
6128
|
+
let bestKey;
|
|
6129
|
+
let bestLen = 0;
|
|
6130
|
+
for (const key of values.keys()) {
|
|
6131
|
+
if (cellLabel.startsWith(key)) {
|
|
6132
|
+
if (key.length >= cellLabel.length * 0.6 && key.length > bestLen) {
|
|
6133
|
+
bestLen = key.length;
|
|
6134
|
+
bestKey = key;
|
|
6135
|
+
}
|
|
6136
|
+
} else if (key.startsWith(cellLabel)) {
|
|
6137
|
+
if (cellLabel.length >= key.length * 0.6 && cellLabel.length > bestLen) {
|
|
6138
|
+
bestLen = cellLabel.length;
|
|
6139
|
+
bestKey = key;
|
|
6311
6140
|
}
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6141
|
+
}
|
|
6142
|
+
}
|
|
6143
|
+
return bestKey;
|
|
6144
|
+
}
|
|
6145
|
+
function isKeywordLabel(text) {
|
|
6146
|
+
const trimmed = text.trim().replace(/[¹²³⁴⁵⁶⁷⁸⁹⁰*※]+$/g, "").trim();
|
|
6147
|
+
if (!trimmed || trimmed.length > 15) return false;
|
|
6148
|
+
for (const kw of LABEL_KEYWORDS) {
|
|
6149
|
+
if (trimmed.includes(kw)) return true;
|
|
6150
|
+
}
|
|
6151
|
+
return false;
|
|
6152
|
+
}
|
|
6153
|
+
function fillInCellPatterns(cellText, values, matchedLabels) {
|
|
6154
|
+
let text = cellText;
|
|
6155
|
+
const matches = [];
|
|
6156
|
+
text = text.replace(
|
|
6157
|
+
/([가-힣A-Za-z]+)\(\s{1,}\)([가-힣A-Za-z]*)/g,
|
|
6158
|
+
(match, prefix, suffix) => {
|
|
6159
|
+
const label = prefix + suffix;
|
|
6160
|
+
const normalizedLabel = normalizeLabel(label);
|
|
6161
|
+
const matchKey = values.has(normalizedLabel) ? normalizedLabel : values.has(normalizeLabel(prefix)) ? normalizeLabel(prefix) : void 0;
|
|
6162
|
+
if (matchKey === void 0) return match;
|
|
6163
|
+
const newValue = values.get(matchKey);
|
|
6164
|
+
matchedLabels.add(matchKey);
|
|
6165
|
+
matches.push({ key: matchKey, label, value: newValue });
|
|
6166
|
+
return `${prefix}(${newValue})${suffix}`;
|
|
6167
|
+
}
|
|
6168
|
+
);
|
|
6169
|
+
text = text.replace(
|
|
6170
|
+
/□([가-힣A-Za-z]+)/g,
|
|
6171
|
+
(match, keyword) => {
|
|
6172
|
+
const normalizedKw = normalizeLabel(keyword);
|
|
6173
|
+
const matchKey = values.has(normalizedKw) ? normalizedKw : void 0;
|
|
6174
|
+
if (matchKey === void 0) return match;
|
|
6175
|
+
const val = values.get(matchKey);
|
|
6176
|
+
const isTruthy = ["\u2611", "\u2713", "\u2714", "v", "V", "true", "1", "yes", "o", "O"].includes(val.trim()) || val.trim() === "";
|
|
6177
|
+
if (!isTruthy) return match;
|
|
6178
|
+
matchedLabels.add(matchKey);
|
|
6179
|
+
matches.push({ key: matchKey, label: `\u25A1${keyword}`, value: "\u2611" });
|
|
6180
|
+
return `\u2611${keyword}`;
|
|
6181
|
+
}
|
|
6182
|
+
);
|
|
6183
|
+
text = text.replace(
|
|
6184
|
+
/\(([가-힣A-Za-z]+)[::]\s{1,}\)/g,
|
|
6185
|
+
(match, keyword) => {
|
|
6186
|
+
const normalizedKw = normalizeLabel(keyword);
|
|
6187
|
+
const matchKey = values.has(normalizedKw) ? normalizedKw : void 0;
|
|
6188
|
+
if (matchKey === void 0) return match;
|
|
6189
|
+
const newValue = values.get(matchKey);
|
|
6190
|
+
matchedLabels.add(matchKey);
|
|
6191
|
+
matches.push({ key: matchKey, label: keyword, value: newValue });
|
|
6192
|
+
return `(${keyword}\uFF1A${newValue})`;
|
|
6193
|
+
}
|
|
6194
|
+
);
|
|
6195
|
+
return matches.length > 0 ? { text, matches } : null;
|
|
6196
|
+
}
|
|
6197
|
+
function normalizeValues(values) {
|
|
6198
|
+
const map = /* @__PURE__ */ new Map();
|
|
6199
|
+
for (const [label, value] of Object.entries(values)) {
|
|
6200
|
+
map.set(normalizeLabel(label), value);
|
|
6201
|
+
}
|
|
6202
|
+
return map;
|
|
6203
|
+
}
|
|
6204
|
+
function resolveUnmatched(normalizedValues, matchedLabels, originalValues) {
|
|
6205
|
+
return [...normalizedValues.keys()].filter((k) => !matchedLabels.has(k)).map((k) => {
|
|
6206
|
+
for (const orig of Object.keys(originalValues)) {
|
|
6207
|
+
if (normalizeLabel(orig) === k) return orig;
|
|
6208
|
+
}
|
|
6209
|
+
return k;
|
|
6210
|
+
});
|
|
6211
|
+
}
|
|
6212
|
+
|
|
6213
|
+
// src/form/filler.ts
|
|
6214
|
+
function fillFormFields(blocks, values) {
|
|
6215
|
+
const cloned = structuredClone(blocks);
|
|
6216
|
+
const filled = [];
|
|
6217
|
+
const matchedLabels = /* @__PURE__ */ new Set();
|
|
6218
|
+
const normalizedValues = normalizeValues(values);
|
|
6219
|
+
const patternFilledCells = /* @__PURE__ */ new Set();
|
|
6220
|
+
for (const block of cloned) {
|
|
6221
|
+
if (block.type !== "table" || !block.table) continue;
|
|
6222
|
+
for (let r = 0; r < block.table.rows; r++) {
|
|
6223
|
+
for (let c = 0; c < block.table.cols; c++) {
|
|
6224
|
+
const cell = block.table.cells[r]?.[c];
|
|
6225
|
+
if (!cell) continue;
|
|
6226
|
+
const result = fillInCellPatterns(cell.text, normalizedValues, matchedLabels);
|
|
6227
|
+
if (result) {
|
|
6228
|
+
cell.text = result.text;
|
|
6229
|
+
patternFilledCells.add(`${r},${c}`);
|
|
6230
|
+
for (const m of result.matches) {
|
|
6231
|
+
filled.push({ label: m.label, value: m.value, row: r, col: c });
|
|
6232
|
+
}
|
|
6233
|
+
}
|
|
6234
|
+
}
|
|
6235
|
+
}
|
|
6236
|
+
}
|
|
6237
|
+
for (const block of cloned) {
|
|
6238
|
+
if (block.type !== "table" || !block.table) continue;
|
|
6239
|
+
fillTable(block.table, normalizedValues, filled, matchedLabels, patternFilledCells);
|
|
6240
|
+
}
|
|
6241
|
+
for (const block of cloned) {
|
|
6242
|
+
if (block.type !== "paragraph" || !block.text) continue;
|
|
6243
|
+
const newText = fillInlineFields(block.text, normalizedValues, filled, matchedLabels);
|
|
6244
|
+
if (newText !== block.text) block.text = newText;
|
|
6245
|
+
}
|
|
6246
|
+
const unmatched = resolveUnmatched(normalizedValues, matchedLabels, values);
|
|
6247
|
+
return { blocks: cloned, filled, unmatched };
|
|
6248
|
+
}
|
|
6249
|
+
function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
|
|
6250
|
+
if (table.cols < 2) return;
|
|
6251
|
+
for (let r = 0; r < table.rows; r++) {
|
|
6252
|
+
for (let c = 0; c < table.cols - 1; c++) {
|
|
6253
|
+
const labelCell = table.cells[r][c];
|
|
6254
|
+
const valueCell = table.cells[r][c + 1];
|
|
6255
|
+
if (!labelCell || !valueCell) continue;
|
|
6256
|
+
if (!isLabelCell(labelCell.text)) continue;
|
|
6257
|
+
if (isKeywordLabel(valueCell.text)) continue;
|
|
6258
|
+
const normalizedCellLabel = normalizeLabel(labelCell.text);
|
|
6259
|
+
if (!normalizedCellLabel) continue;
|
|
6260
|
+
const matchKey = findMatchingKey(normalizedCellLabel, values);
|
|
6261
|
+
if (matchKey === void 0) continue;
|
|
6262
|
+
const newValue = values.get(matchKey);
|
|
6263
|
+
if (patternFilledCells?.has(`${r},${c + 1}`)) {
|
|
6264
|
+
valueCell.text = newValue + " " + valueCell.text;
|
|
6265
|
+
} else {
|
|
6266
|
+
valueCell.text = newValue;
|
|
6267
|
+
}
|
|
6268
|
+
matchedLabels.add(matchKey);
|
|
6269
|
+
filled.push({
|
|
6270
|
+
label: labelCell.text.trim().replace(/[::]\s*$/, ""),
|
|
6271
|
+
value: newValue,
|
|
6272
|
+
row: r,
|
|
6273
|
+
col: c
|
|
6274
|
+
});
|
|
6275
|
+
}
|
|
6276
|
+
}
|
|
6277
|
+
if (table.rows >= 2 && table.cols >= 2) {
|
|
6278
|
+
const headerRow = table.cells[0];
|
|
6279
|
+
const allLabels = headerRow.every((cell) => {
|
|
6280
|
+
const t = cell.text.trim();
|
|
6281
|
+
return t.length > 0 && t.length <= 20 && isLabelCell(t);
|
|
6282
|
+
});
|
|
6283
|
+
if (!allLabels) return;
|
|
6284
|
+
for (let r = 1; r < table.rows; r++) {
|
|
6285
|
+
for (let c = 0; c < table.cols; c++) {
|
|
6286
|
+
const headerLabel = normalizeLabel(headerRow[c].text);
|
|
6287
|
+
const matchKey = findMatchingKey(headerLabel, values);
|
|
6288
|
+
if (matchKey === void 0) continue;
|
|
6289
|
+
if (matchedLabels.has(matchKey)) continue;
|
|
6290
|
+
const newValue = values.get(matchKey);
|
|
6291
|
+
table.cells[r][c].text = newValue;
|
|
6292
|
+
matchedLabels.add(matchKey);
|
|
6293
|
+
filled.push({
|
|
6294
|
+
label: headerRow[c].text.trim(),
|
|
6295
|
+
value: newValue,
|
|
6296
|
+
row: r,
|
|
6297
|
+
col: c
|
|
6298
|
+
});
|
|
6299
|
+
}
|
|
6300
|
+
}
|
|
6301
|
+
}
|
|
6302
|
+
}
|
|
6303
|
+
function fillInlineFields(text, values, filled, matchedLabels) {
|
|
6304
|
+
return text.replace(
|
|
6305
|
+
/([가-힣A-Za-z]{2,10})\s*[::]\s*([^\n,;]{0,100})/g,
|
|
6306
|
+
(match, rawLabel, _oldValue) => {
|
|
6307
|
+
const normalized = normalizeLabel(rawLabel);
|
|
6308
|
+
const matchKey = findMatchingKey(normalized, values);
|
|
6309
|
+
if (matchKey === void 0) return match;
|
|
6310
|
+
const newValue = values.get(matchKey);
|
|
6311
|
+
matchedLabels.add(matchKey);
|
|
6312
|
+
filled.push({
|
|
6313
|
+
label: rawLabel.trim(),
|
|
6314
|
+
value: newValue,
|
|
6315
|
+
row: -1,
|
|
6316
|
+
col: -1
|
|
6317
|
+
});
|
|
6318
|
+
return `${rawLabel}: ${newValue}`;
|
|
6319
|
+
}
|
|
6320
|
+
);
|
|
6321
|
+
}
|
|
6322
|
+
|
|
6323
|
+
// src/form/filler-hwpx.ts
|
|
6324
|
+
import JSZip5 from "jszip";
|
|
6325
|
+
import { DOMParser as DOMParser4, XMLSerializer } from "@xmldom/xmldom";
|
|
6326
|
+
async function fillHwpx(hwpxBuffer, values) {
|
|
6327
|
+
const zip = await JSZip5.loadAsync(hwpxBuffer);
|
|
6328
|
+
const filled = [];
|
|
6329
|
+
const matchedLabels = /* @__PURE__ */ new Set();
|
|
6330
|
+
const normalizedValues = normalizeValues(values);
|
|
6331
|
+
const sectionFiles = Object.keys(zip.files).filter((name) => /[Ss]ection\d+\.xml$/i.test(name)).sort();
|
|
6332
|
+
if (sectionFiles.length === 0) {
|
|
6333
|
+
throw new KordocError("HWPX\uC5D0\uC11C \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
6334
|
+
}
|
|
6335
|
+
const xmlParser = new DOMParser4();
|
|
6336
|
+
const xmlSerializer = new XMLSerializer();
|
|
6337
|
+
for (const sectionPath of sectionFiles) {
|
|
6338
|
+
const zipEntry = zip.file(sectionPath);
|
|
6339
|
+
if (!zipEntry) continue;
|
|
6340
|
+
const rawXml = await zipEntry.async("text");
|
|
6341
|
+
const doc = xmlParser.parseFromString(stripDtd(rawXml), "text/xml");
|
|
6342
|
+
if (!doc.documentElement) continue;
|
|
6343
|
+
let modified = false;
|
|
6344
|
+
const tables = findAllElements(doc.documentElement, "tbl");
|
|
6345
|
+
const cellPatternApplied = /* @__PURE__ */ new Set();
|
|
6346
|
+
for (const tblEl of tables) {
|
|
6347
|
+
const allCells = findAllElements(tblEl, "tc");
|
|
6348
|
+
for (const tcEl of allCells) {
|
|
6349
|
+
const tNodes = collectCellTextNodes(tcEl);
|
|
6350
|
+
const fullText = tNodes.map((n) => n.text).join("");
|
|
6351
|
+
const result = fillInCellPatterns(fullText, normalizedValues, matchedLabels);
|
|
6352
|
+
if (!result) continue;
|
|
6353
|
+
applyTextReplacements(tNodes, fullText, result.text);
|
|
6354
|
+
cellPatternApplied.add(tcEl);
|
|
6355
|
+
for (const m of result.matches) {
|
|
6356
|
+
filled.push({ label: m.label, value: m.value, row: -1, col: -1 });
|
|
6357
|
+
}
|
|
6358
|
+
modified = true;
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
for (const tblEl of tables) {
|
|
6362
|
+
const rows = findDirectChildren(tblEl, "tr");
|
|
6363
|
+
for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {
|
|
6364
|
+
const trEl = rows[rowIdx];
|
|
6365
|
+
const cells = findDirectChildren(trEl, "tc");
|
|
6366
|
+
for (let colIdx = 0; colIdx < cells.length - 1; colIdx++) {
|
|
6367
|
+
const labelText = extractCellText(cells[colIdx]);
|
|
6368
|
+
if (!isLabelCell(labelText)) continue;
|
|
6369
|
+
const valueCell = cells[colIdx + 1];
|
|
6370
|
+
const valueText = extractCellText(valueCell);
|
|
6371
|
+
if (isKeywordLabel(valueText)) continue;
|
|
6372
|
+
const normalizedCellLabel = normalizeLabel(labelText);
|
|
6373
|
+
if (!normalizedCellLabel) continue;
|
|
6374
|
+
const matchKey = findMatchingKey(normalizedCellLabel, normalizedValues);
|
|
6375
|
+
if (matchKey === void 0) continue;
|
|
6376
|
+
const newValue = normalizedValues.get(matchKey);
|
|
6377
|
+
if (cellPatternApplied.has(valueCell)) {
|
|
6378
|
+
prependCellText(valueCell, newValue);
|
|
6379
|
+
} else {
|
|
6380
|
+
replaceCellText(valueCell, newValue);
|
|
6381
|
+
}
|
|
6382
|
+
matchedLabels.add(matchKey);
|
|
6383
|
+
filled.push({
|
|
6384
|
+
label: labelText.trim().replace(/[::]\s*$/, ""),
|
|
6385
|
+
value: newValue,
|
|
6386
|
+
row: rowIdx,
|
|
6387
|
+
col: colIdx
|
|
6388
|
+
});
|
|
6389
|
+
modified = true;
|
|
6390
|
+
}
|
|
6391
|
+
}
|
|
6392
|
+
if (rows.length >= 2) {
|
|
6393
|
+
const headerCells = findDirectChildren(rows[0], "tc");
|
|
6394
|
+
const allLabels = headerCells.every((cell) => {
|
|
6395
|
+
const t = extractCellText(cell).trim();
|
|
6396
|
+
return t.length > 0 && t.length <= 20 && isLabelCell(t);
|
|
6397
|
+
});
|
|
6398
|
+
if (allLabels) {
|
|
6399
|
+
for (let rowIdx = 1; rowIdx < rows.length; rowIdx++) {
|
|
6400
|
+
const dataCells = findDirectChildren(rows[rowIdx], "tc");
|
|
6401
|
+
for (let colIdx = 0; colIdx < Math.min(headerCells.length, dataCells.length); colIdx++) {
|
|
6402
|
+
const headerLabel = normalizeLabel(extractCellText(headerCells[colIdx]));
|
|
6403
|
+
const matchKey = findMatchingKey(headerLabel, normalizedValues);
|
|
6404
|
+
if (matchKey === void 0) continue;
|
|
6405
|
+
if (matchedLabels.has(matchKey)) continue;
|
|
6406
|
+
const newValue = normalizedValues.get(matchKey);
|
|
6407
|
+
replaceCellText(dataCells[colIdx], newValue);
|
|
6408
|
+
matchedLabels.add(matchKey);
|
|
6409
|
+
filled.push({
|
|
6410
|
+
label: extractCellText(headerCells[colIdx]).trim(),
|
|
6411
|
+
value: newValue,
|
|
6412
|
+
row: rowIdx,
|
|
6413
|
+
col: colIdx
|
|
6414
|
+
});
|
|
6415
|
+
modified = true;
|
|
6416
|
+
}
|
|
6417
|
+
}
|
|
6418
|
+
}
|
|
6419
|
+
}
|
|
6420
|
+
}
|
|
6421
|
+
const allParagraphs = findAllElements(doc.documentElement, "p");
|
|
6422
|
+
for (const pEl of allParagraphs) {
|
|
6423
|
+
if (isInsideTable(pEl)) continue;
|
|
6424
|
+
const tNodes = collectTextNodes(pEl);
|
|
6425
|
+
const fullText = tNodes.map((n) => n.text).join("");
|
|
6426
|
+
const pattern = /([가-힣A-Za-z]{2,10})\s*[::]\s*([^\n,;]{0,100})/g;
|
|
6427
|
+
let match;
|
|
6428
|
+
while ((match = pattern.exec(fullText)) !== null) {
|
|
6429
|
+
const rawLabel = match[1];
|
|
6430
|
+
const normalized = normalizeLabel(rawLabel);
|
|
6431
|
+
const matchKey = findMatchingKey(normalized, normalizedValues);
|
|
6432
|
+
if (matchKey === void 0) continue;
|
|
6433
|
+
const newValue = normalizedValues.get(matchKey);
|
|
6434
|
+
const valueStart = match.index + match[0].length - match[2].length;
|
|
6435
|
+
const valueEnd = match.index + match[0].length;
|
|
6436
|
+
replaceTextRange(tNodes, valueStart, valueEnd, newValue);
|
|
6437
|
+
matchedLabels.add(matchKey);
|
|
6438
|
+
filled.push({ label: rawLabel.trim(), value: newValue, row: -1, col: -1 });
|
|
6439
|
+
modified = true;
|
|
6440
|
+
break;
|
|
6441
|
+
}
|
|
6442
|
+
}
|
|
6443
|
+
if (modified) {
|
|
6444
|
+
const newXml = xmlSerializer.serializeToString(doc);
|
|
6445
|
+
zip.file(sectionPath, newXml);
|
|
6446
|
+
}
|
|
6447
|
+
}
|
|
6448
|
+
const unmatched = resolveUnmatched(normalizedValues, matchedLabels, values);
|
|
6449
|
+
const buffer = await zip.generateAsync({ type: "arraybuffer" });
|
|
6450
|
+
return { buffer, filled, unmatched };
|
|
6451
|
+
}
|
|
6452
|
+
function localName(el) {
|
|
6453
|
+
return (el.tagName || el.localName || "").replace(/^[^:]+:/, "");
|
|
6454
|
+
}
|
|
6455
|
+
function findAllElements(node, tagLocalName) {
|
|
6456
|
+
const result = [];
|
|
6457
|
+
const walk = (n) => {
|
|
6458
|
+
const children = n.childNodes;
|
|
6459
|
+
if (!children) return;
|
|
6460
|
+
for (let i = 0; i < children.length; i++) {
|
|
6461
|
+
const child = children[i];
|
|
6462
|
+
if (child.nodeType !== 1) continue;
|
|
6463
|
+
if (localName(child) === tagLocalName) result.push(child);
|
|
6464
|
+
walk(child);
|
|
6465
|
+
}
|
|
6466
|
+
};
|
|
6467
|
+
walk(node);
|
|
6468
|
+
return result;
|
|
6469
|
+
}
|
|
6470
|
+
function findDirectChildren(parent, tagLocalName) {
|
|
6471
|
+
const result = [];
|
|
6472
|
+
const children = parent.childNodes;
|
|
6473
|
+
if (!children) return result;
|
|
6474
|
+
for (let i = 0; i < children.length; i++) {
|
|
6475
|
+
const child = children[i];
|
|
6476
|
+
if (child.nodeType === 1 && localName(child) === tagLocalName) {
|
|
6477
|
+
result.push(child);
|
|
6478
|
+
}
|
|
6479
|
+
}
|
|
6480
|
+
return result;
|
|
6481
|
+
}
|
|
6482
|
+
function isInsideTable(el) {
|
|
6483
|
+
let parent = el.parentNode;
|
|
6484
|
+
while (parent) {
|
|
6485
|
+
if (parent.nodeType === 1 && localName(parent) === "tbl") return true;
|
|
6486
|
+
parent = parent.parentNode;
|
|
6487
|
+
}
|
|
6488
|
+
return false;
|
|
6489
|
+
}
|
|
6490
|
+
function extractCellText(tcEl) {
|
|
6491
|
+
const parts = [];
|
|
6492
|
+
const walk = (node) => {
|
|
6493
|
+
const children = node.childNodes;
|
|
6494
|
+
if (!children) return;
|
|
6495
|
+
for (let i = 0; i < children.length; i++) {
|
|
6496
|
+
const child = children[i];
|
|
6497
|
+
if (child.nodeType === 3) {
|
|
6498
|
+
parts.push(child.textContent || "");
|
|
6499
|
+
} else if (child.nodeType === 1) {
|
|
6500
|
+
const tag = localName(child);
|
|
6501
|
+
if (tag === "t") walk(child);
|
|
6502
|
+
else if (tag === "run" || tag === "r" || tag === "p" || tag === "subList") walk(child);
|
|
6503
|
+
else if (tag === "tab") parts.push(" ");
|
|
6504
|
+
else if (tag === "br") parts.push("\n");
|
|
6505
|
+
}
|
|
6506
|
+
}
|
|
6507
|
+
};
|
|
6508
|
+
walk(tcEl);
|
|
6509
|
+
return parts.join("");
|
|
6510
|
+
}
|
|
6511
|
+
function prependCellText(tcEl, text) {
|
|
6512
|
+
const tElements = findAllElements(tcEl, "t");
|
|
6513
|
+
if (tElements.length === 0) return;
|
|
6514
|
+
const firstT = tElements[0];
|
|
6515
|
+
const existing = firstT.textContent || "";
|
|
6516
|
+
clearChildren(firstT);
|
|
6517
|
+
firstT.appendChild(firstT.ownerDocument.createTextNode(text + " " + existing));
|
|
6518
|
+
}
|
|
6519
|
+
function replaceCellText(tcEl, newValue) {
|
|
6520
|
+
const paragraphs = findAllElements(tcEl, "p");
|
|
6521
|
+
if (paragraphs.length === 0) return;
|
|
6522
|
+
const firstP = paragraphs[0];
|
|
6523
|
+
const runs = findAllElements(firstP, "run").concat(findAllElements(firstP, "r"));
|
|
6524
|
+
if (runs.length > 0) {
|
|
6525
|
+
setRunText(runs[0], newValue);
|
|
6526
|
+
for (let i = 1; i < runs.length; i++) {
|
|
6527
|
+
setRunText(runs[i], "");
|
|
6528
|
+
}
|
|
6529
|
+
} else {
|
|
6530
|
+
const tElements = findAllElements(firstP, "t");
|
|
6531
|
+
if (tElements.length > 0) {
|
|
6532
|
+
clearChildren(tElements[0]);
|
|
6533
|
+
tElements[0].appendChild(tElements[0].ownerDocument.createTextNode(newValue));
|
|
6534
|
+
for (let i = 1; i < tElements.length; i++) {
|
|
6535
|
+
clearChildren(tElements[i]);
|
|
6536
|
+
}
|
|
6537
|
+
}
|
|
6538
|
+
}
|
|
6539
|
+
for (let i = 1; i < paragraphs.length; i++) {
|
|
6540
|
+
const p = paragraphs[i];
|
|
6541
|
+
if (p.parentNode) {
|
|
6542
|
+
const pRuns = findAllElements(p, "run").concat(findAllElements(p, "r"));
|
|
6543
|
+
for (const run of pRuns) setRunText(run, "");
|
|
6544
|
+
const pTs = findAllElements(p, "t");
|
|
6545
|
+
for (const t of pTs) clearChildren(t);
|
|
6546
|
+
}
|
|
6547
|
+
}
|
|
6548
|
+
}
|
|
6549
|
+
function setRunText(runEl, text) {
|
|
6550
|
+
const tElements = findAllElements(runEl, "t");
|
|
6551
|
+
if (tElements.length > 0) {
|
|
6552
|
+
clearChildren(tElements[0]);
|
|
6553
|
+
tElements[0].appendChild(tElements[0].ownerDocument.createTextNode(text));
|
|
6554
|
+
for (let i = 1; i < tElements.length; i++) {
|
|
6555
|
+
clearChildren(tElements[i]);
|
|
6556
|
+
}
|
|
6557
|
+
}
|
|
6558
|
+
}
|
|
6559
|
+
function clearChildren(el) {
|
|
6560
|
+
while (el.firstChild) el.removeChild(el.firstChild);
|
|
6561
|
+
}
|
|
6562
|
+
function collectTextNodes(pEl) {
|
|
6563
|
+
const tElements = findAllElements(pEl, "t");
|
|
6564
|
+
const result = [];
|
|
6565
|
+
let offset = 0;
|
|
6566
|
+
for (const t of tElements) {
|
|
6567
|
+
const text = t.textContent || "";
|
|
6568
|
+
result.push({ element: t, text, offset });
|
|
6569
|
+
offset += text.length;
|
|
6570
|
+
}
|
|
6571
|
+
return result;
|
|
6572
|
+
}
|
|
6573
|
+
function replaceTextRange(tNodes, globalStart, globalEnd, newValue) {
|
|
6574
|
+
let replaced = false;
|
|
6575
|
+
for (const node of tNodes) {
|
|
6576
|
+
const nodeStart = node.offset;
|
|
6577
|
+
const nodeEnd = node.offset + node.text.length;
|
|
6578
|
+
if (nodeEnd <= globalStart || nodeStart >= globalEnd) continue;
|
|
6579
|
+
const localStart = Math.max(0, globalStart - nodeStart);
|
|
6580
|
+
const localEnd = Math.min(node.text.length, globalEnd - nodeStart);
|
|
6581
|
+
if (!replaced) {
|
|
6582
|
+
const before = node.text.slice(0, localStart);
|
|
6583
|
+
const after = node.text.slice(localEnd);
|
|
6584
|
+
const newText = before + newValue + after;
|
|
6585
|
+
clearChildren(node.element);
|
|
6586
|
+
node.element.appendChild(node.element.ownerDocument.createTextNode(newText));
|
|
6587
|
+
replaced = true;
|
|
6588
|
+
} else {
|
|
6589
|
+
const before = node.text.slice(0, localStart);
|
|
6590
|
+
const after = node.text.slice(localEnd);
|
|
6591
|
+
const newText = before + after;
|
|
6592
|
+
clearChildren(node.element);
|
|
6593
|
+
node.element.appendChild(node.element.ownerDocument.createTextNode(newText));
|
|
6594
|
+
}
|
|
6595
|
+
}
|
|
6596
|
+
}
|
|
6597
|
+
function collectCellTextNodes(tcEl) {
|
|
6598
|
+
const tElements = findAllElements(tcEl, "t");
|
|
6599
|
+
const result = [];
|
|
6600
|
+
let offset = 0;
|
|
6601
|
+
for (const t of tElements) {
|
|
6602
|
+
const text = t.textContent || "";
|
|
6603
|
+
result.push({ element: t, text, offset });
|
|
6604
|
+
offset += text.length;
|
|
6605
|
+
}
|
|
6606
|
+
return result;
|
|
6607
|
+
}
|
|
6608
|
+
function applyTextReplacements(tNodes, originalFull, replacedFull) {
|
|
6609
|
+
if (originalFull === replacedFull) return;
|
|
6610
|
+
if (tNodes.length === 1) {
|
|
6611
|
+
clearChildren(tNodes[0].element);
|
|
6612
|
+
tNodes[0].element.appendChild(
|
|
6613
|
+
tNodes[0].element.ownerDocument.createTextNode(replacedFull)
|
|
6614
|
+
);
|
|
6615
|
+
return;
|
|
6616
|
+
}
|
|
6617
|
+
let diffStart = 0;
|
|
6618
|
+
while (diffStart < originalFull.length && diffStart < replacedFull.length && originalFull[diffStart] === replacedFull[diffStart]) {
|
|
6619
|
+
diffStart++;
|
|
6620
|
+
}
|
|
6621
|
+
let diffEndOrig = originalFull.length;
|
|
6622
|
+
let diffEndRepl = replacedFull.length;
|
|
6623
|
+
while (diffEndOrig > diffStart && diffEndRepl > diffStart && originalFull[diffEndOrig - 1] === replacedFull[diffEndRepl - 1]) {
|
|
6624
|
+
diffEndOrig--;
|
|
6625
|
+
diffEndRepl--;
|
|
6626
|
+
}
|
|
6627
|
+
const newPart = replacedFull.slice(diffStart, diffEndRepl);
|
|
6628
|
+
replaceTextRange(tNodes, diffStart, diffEndOrig, newPart);
|
|
6629
|
+
}
|
|
6630
|
+
|
|
6631
|
+
// src/hwpx/generator.ts
|
|
6632
|
+
import JSZip6 from "jszip";
|
|
6633
|
+
var NS_SECTION = "http://www.hancom.co.kr/hwpml/2011/section";
|
|
6634
|
+
var NS_PARA = "http://www.hancom.co.kr/hwpml/2011/paragraph";
|
|
6635
|
+
var NS_HEAD = "http://www.hancom.co.kr/hwpml/2011/head";
|
|
6636
|
+
var NS_OPF = "http://www.idpf.org/2007/opf/";
|
|
6637
|
+
var NS_HPF = "http://www.hancom.co.kr/schema/2011/hpf";
|
|
6638
|
+
var NS_OCF = "urn:oasis:names:tc:opendocument:xmlns:container";
|
|
6639
|
+
var CHAR_NORMAL = 0;
|
|
6640
|
+
var CHAR_BOLD = 1;
|
|
6641
|
+
var CHAR_ITALIC = 2;
|
|
6642
|
+
var CHAR_BOLD_ITALIC = 3;
|
|
6643
|
+
var CHAR_CODE = 4;
|
|
6644
|
+
var CHAR_H1 = 5;
|
|
6645
|
+
var CHAR_H2 = 6;
|
|
6646
|
+
var CHAR_H3 = 7;
|
|
6647
|
+
var CHAR_H4 = 8;
|
|
6648
|
+
var PARA_NORMAL = 0;
|
|
6649
|
+
var PARA_H1 = 1;
|
|
6650
|
+
var PARA_H2 = 2;
|
|
6651
|
+
var PARA_H3 = 3;
|
|
6652
|
+
var PARA_H4 = 4;
|
|
6653
|
+
var PARA_CODE = 5;
|
|
6654
|
+
var PARA_QUOTE = 6;
|
|
6655
|
+
var PARA_LIST = 7;
|
|
6656
|
+
async function markdownToHwpx(markdown) {
|
|
6657
|
+
const blocks = parseMarkdownToBlocks(markdown);
|
|
6658
|
+
const sectionXml = blocksToSectionXml(blocks);
|
|
6659
|
+
const zip = new JSZip6();
|
|
6660
|
+
zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
|
|
6661
|
+
zip.file("META-INF/container.xml", generateContainerXml());
|
|
6662
|
+
zip.file("Contents/content.hpf", generateManifest());
|
|
6663
|
+
zip.file("Contents/header.xml", generateHeaderXml());
|
|
6664
|
+
zip.file("Contents/section0.xml", sectionXml);
|
|
6665
|
+
return await zip.generateAsync({ type: "arraybuffer" });
|
|
6666
|
+
}
|
|
6667
|
+
function parseMarkdownToBlocks(md) {
|
|
6668
|
+
const lines = md.split("\n");
|
|
6669
|
+
const blocks = [];
|
|
6670
|
+
let i = 0;
|
|
6671
|
+
while (i < lines.length) {
|
|
6672
|
+
const line = lines[i];
|
|
6673
|
+
if (!line.trim()) {
|
|
6674
|
+
i++;
|
|
6675
|
+
continue;
|
|
6676
|
+
}
|
|
6677
|
+
const fenceMatch = line.match(/^(`{3,}|~{3,})(.*)$/);
|
|
6678
|
+
if (fenceMatch) {
|
|
6679
|
+
const fence = fenceMatch[1];
|
|
6680
|
+
const lang = fenceMatch[2].trim();
|
|
6681
|
+
const codeLines = [];
|
|
6682
|
+
i++;
|
|
6683
|
+
while (i < lines.length && !lines[i].startsWith(fence)) {
|
|
6684
|
+
codeLines.push(lines[i]);
|
|
6685
|
+
i++;
|
|
6686
|
+
}
|
|
6687
|
+
if (i < lines.length) i++;
|
|
6688
|
+
blocks.push({ type: "code_block", text: codeLines.join("\n"), lang });
|
|
6689
|
+
continue;
|
|
6315
6690
|
}
|
|
6316
6691
|
if (/^(\*{3,}|-{3,}|_{3,})\s*$/.test(line.trim())) {
|
|
6317
6692
|
blocks.push({ type: "hr" });
|
|
@@ -6641,6 +7016,183 @@ function blocksToSectionXml(blocks) {
|
|
|
6641
7016
|
</hs:sec>`;
|
|
6642
7017
|
}
|
|
6643
7018
|
|
|
7019
|
+
// src/diff/text-diff.ts
|
|
7020
|
+
function similarity(a, b) {
|
|
7021
|
+
if (a === b) return 1;
|
|
7022
|
+
if (!a || !b) return 0;
|
|
7023
|
+
const maxLen = Math.max(a.length, b.length);
|
|
7024
|
+
if (maxLen === 0) return 1;
|
|
7025
|
+
return 1 - levenshtein(a, b) / maxLen;
|
|
7026
|
+
}
|
|
7027
|
+
function normalizedSimilarity(a, b) {
|
|
7028
|
+
return similarity(normalize(a), normalize(b));
|
|
7029
|
+
}
|
|
7030
|
+
function normalize(s) {
|
|
7031
|
+
return s.replace(/\s+/g, " ").trim();
|
|
7032
|
+
}
|
|
7033
|
+
var MAX_LEVENSHTEIN_LEN = 1e4;
|
|
7034
|
+
function levenshtein(a, b) {
|
|
7035
|
+
if (a.length + b.length > MAX_LEVENSHTEIN_LEN) {
|
|
7036
|
+
const sampleLen = Math.min(500, a.length, b.length);
|
|
7037
|
+
let diffs = 0;
|
|
7038
|
+
for (let i = 0; i < sampleLen; i++) if (a[i] !== b[i]) diffs++;
|
|
7039
|
+
const sampleRate = sampleLen > 0 ? diffs / sampleLen : 1;
|
|
7040
|
+
return Math.abs(a.length - b.length) + Math.round(Math.min(a.length, b.length) * sampleRate);
|
|
7041
|
+
}
|
|
7042
|
+
if (a.length > b.length) [a, b] = [b, a];
|
|
7043
|
+
const m = a.length;
|
|
7044
|
+
const n = b.length;
|
|
7045
|
+
let prev = Array.from({ length: m + 1 }, (_, i) => i);
|
|
7046
|
+
let curr = new Array(m + 1);
|
|
7047
|
+
for (let j = 1; j <= n; j++) {
|
|
7048
|
+
curr[0] = j;
|
|
7049
|
+
for (let i = 1; i <= m; i++) {
|
|
7050
|
+
if (a[i - 1] === b[j - 1]) {
|
|
7051
|
+
curr[i] = prev[i - 1];
|
|
7052
|
+
} else {
|
|
7053
|
+
curr[i] = 1 + Math.min(prev[i - 1], prev[i], curr[i - 1]);
|
|
7054
|
+
}
|
|
7055
|
+
}
|
|
7056
|
+
;
|
|
7057
|
+
[prev, curr] = [curr, prev];
|
|
7058
|
+
}
|
|
7059
|
+
return prev[m];
|
|
7060
|
+
}
|
|
7061
|
+
|
|
7062
|
+
// src/diff/compare.ts
|
|
7063
|
+
var SIMILARITY_THRESHOLD = 0.4;
|
|
7064
|
+
async function compare(bufferA, bufferB, options) {
|
|
7065
|
+
const [resultA, resultB] = await Promise.all([
|
|
7066
|
+
parse(bufferA, options),
|
|
7067
|
+
parse(bufferB, options)
|
|
7068
|
+
]);
|
|
7069
|
+
if (!resultA.success) throw new Error(`\uBB38\uC11CA \uD30C\uC2F1 \uC2E4\uD328: ${resultA.error}`);
|
|
7070
|
+
if (!resultB.success) throw new Error(`\uBB38\uC11CB \uD30C\uC2F1 \uC2E4\uD328: ${resultB.error}`);
|
|
7071
|
+
return diffBlocks(resultA.blocks, resultB.blocks);
|
|
7072
|
+
}
|
|
7073
|
+
function diffBlocks(blocksA, blocksB) {
|
|
7074
|
+
const aligned = alignBlocks(blocksA, blocksB);
|
|
7075
|
+
const stats = { added: 0, removed: 0, modified: 0, unchanged: 0 };
|
|
7076
|
+
const diffs = [];
|
|
7077
|
+
for (const [a, b] of aligned) {
|
|
7078
|
+
if (a && b) {
|
|
7079
|
+
const sim = blockSimilarity(a, b);
|
|
7080
|
+
if (sim >= 0.99) {
|
|
7081
|
+
diffs.push({ type: "unchanged", before: a, after: b, similarity: 1 });
|
|
7082
|
+
stats.unchanged++;
|
|
7083
|
+
} else {
|
|
7084
|
+
const diff = { type: "modified", before: a, after: b, similarity: sim };
|
|
7085
|
+
if (a.type === "table" && b.type === "table" && a.table && b.table) {
|
|
7086
|
+
diff.cellDiffs = diffTableCells(a.table, b.table);
|
|
7087
|
+
}
|
|
7088
|
+
diffs.push(diff);
|
|
7089
|
+
stats.modified++;
|
|
7090
|
+
}
|
|
7091
|
+
} else if (a) {
|
|
7092
|
+
diffs.push({ type: "removed", before: a });
|
|
7093
|
+
stats.removed++;
|
|
7094
|
+
} else if (b) {
|
|
7095
|
+
diffs.push({ type: "added", after: b });
|
|
7096
|
+
stats.added++;
|
|
7097
|
+
}
|
|
7098
|
+
}
|
|
7099
|
+
return { stats, diffs };
|
|
7100
|
+
}
|
|
7101
|
+
function alignBlocks(a, b) {
|
|
7102
|
+
const m = a.length, n = b.length;
|
|
7103
|
+
if (m * n > 1e7) return fallbackAlign(a, b);
|
|
7104
|
+
const simCache = /* @__PURE__ */ new Map();
|
|
7105
|
+
const getSim = (i2, j2) => {
|
|
7106
|
+
const key = `${i2},${j2}`;
|
|
7107
|
+
let v = simCache.get(key);
|
|
7108
|
+
if (v === void 0) {
|
|
7109
|
+
v = blockSimilarity(a[i2], b[j2]);
|
|
7110
|
+
simCache.set(key, v);
|
|
7111
|
+
}
|
|
7112
|
+
return v;
|
|
7113
|
+
};
|
|
7114
|
+
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
|
|
7115
|
+
for (let i2 = 1; i2 <= m; i2++) {
|
|
7116
|
+
for (let j2 = 1; j2 <= n; j2++) {
|
|
7117
|
+
if (getSim(i2 - 1, j2 - 1) >= SIMILARITY_THRESHOLD) {
|
|
7118
|
+
dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
|
|
7119
|
+
} else {
|
|
7120
|
+
dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
7121
|
+
}
|
|
7122
|
+
}
|
|
7123
|
+
}
|
|
7124
|
+
const pairs = [];
|
|
7125
|
+
let i = m, j = n;
|
|
7126
|
+
while (i > 0 && j > 0) {
|
|
7127
|
+
if (getSim(i - 1, j - 1) >= SIMILARITY_THRESHOLD && dp[i][j] === dp[i - 1][j - 1] + 1) {
|
|
7128
|
+
pairs.push([i - 1, j - 1]);
|
|
7129
|
+
i--;
|
|
7130
|
+
j--;
|
|
7131
|
+
} else if (dp[i - 1][j] >= dp[i][j - 1]) {
|
|
7132
|
+
i--;
|
|
7133
|
+
} else {
|
|
7134
|
+
j--;
|
|
7135
|
+
}
|
|
7136
|
+
}
|
|
7137
|
+
pairs.reverse();
|
|
7138
|
+
const result = [];
|
|
7139
|
+
let ai = 0, bi = 0;
|
|
7140
|
+
for (const [pi, pj] of pairs) {
|
|
7141
|
+
while (ai < pi) result.push([a[ai++], null]);
|
|
7142
|
+
while (bi < pj) result.push([null, b[bi++]]);
|
|
7143
|
+
result.push([a[ai++], b[bi++]]);
|
|
7144
|
+
}
|
|
7145
|
+
while (ai < m) result.push([a[ai++], null]);
|
|
7146
|
+
while (bi < n) result.push([null, b[bi++]]);
|
|
7147
|
+
return result;
|
|
7148
|
+
}
|
|
7149
|
+
function fallbackAlign(a, b) {
|
|
7150
|
+
const result = [];
|
|
7151
|
+
const len = Math.max(a.length, b.length);
|
|
7152
|
+
for (let i = 0; i < len; i++) {
|
|
7153
|
+
result.push([a[i] || null, b[i] || null]);
|
|
7154
|
+
}
|
|
7155
|
+
return result;
|
|
7156
|
+
}
|
|
7157
|
+
function blockSimilarity(a, b) {
|
|
7158
|
+
if (a.type !== b.type) return 0;
|
|
7159
|
+
if (a.text !== void 0 && b.text !== void 0) {
|
|
7160
|
+
return normalizedSimilarity(a.text || "", b.text || "");
|
|
7161
|
+
}
|
|
7162
|
+
if (a.type === "table" && a.table && b.table) {
|
|
7163
|
+
return tableSimilarity(a.table, b.table);
|
|
7164
|
+
}
|
|
7165
|
+
if (a.type === b.type) return 1;
|
|
7166
|
+
return 0;
|
|
7167
|
+
}
|
|
7168
|
+
function tableSimilarity(a, b) {
|
|
7169
|
+
const dimSim = 1 - Math.abs(a.rows * a.cols - b.rows * b.cols) / Math.max(a.rows * a.cols, b.rows * b.cols, 1);
|
|
7170
|
+
const textsA = a.cells.flat().map((c) => c.text).join(" ");
|
|
7171
|
+
const textsB = b.cells.flat().map((c) => c.text).join(" ");
|
|
7172
|
+
const contentSim = normalizedSimilarity(textsA, textsB);
|
|
7173
|
+
return dimSim * 0.3 + contentSim * 0.7;
|
|
7174
|
+
}
|
|
7175
|
+
function diffTableCells(a, b) {
|
|
7176
|
+
const maxRows = Math.max(a.rows, b.rows);
|
|
7177
|
+
const maxCols = Math.max(a.cols, b.cols);
|
|
7178
|
+
const result = [];
|
|
7179
|
+
for (let r = 0; r < maxRows; r++) {
|
|
7180
|
+
const row = [];
|
|
7181
|
+
for (let c = 0; c < maxCols; c++) {
|
|
7182
|
+
const cellA = r < a.rows && c < a.cols ? a.cells[r][c].text : void 0;
|
|
7183
|
+
const cellB = r < b.rows && c < b.cols ? b.cells[r][c].text : void 0;
|
|
7184
|
+
let type;
|
|
7185
|
+
if (cellA === void 0) type = "added";
|
|
7186
|
+
else if (cellB === void 0) type = "removed";
|
|
7187
|
+
else if (cellA === cellB) type = "unchanged";
|
|
7188
|
+
else type = "modified";
|
|
7189
|
+
row.push({ type, before: cellA, after: cellB });
|
|
7190
|
+
}
|
|
7191
|
+
result.push(row);
|
|
7192
|
+
}
|
|
7193
|
+
return result;
|
|
7194
|
+
}
|
|
7195
|
+
|
|
6644
7196
|
// src/index.ts
|
|
6645
7197
|
async function parse(input, options) {
|
|
6646
7198
|
let buffer;
|
|
@@ -6717,6 +7269,45 @@ async function parseDocx(buffer, options) {
|
|
|
6717
7269
|
return { success: false, fileType: "docx", error: err instanceof Error ? err.message : "DOCX \uD30C\uC2F1 \uC2E4\uD328", code: classifyError(err) };
|
|
6718
7270
|
}
|
|
6719
7271
|
}
|
|
7272
|
+
async function fillForm(input, values, outputFormat = "markdown") {
|
|
7273
|
+
let buffer;
|
|
7274
|
+
if (typeof input === "string") {
|
|
7275
|
+
const buf = await readFile(input);
|
|
7276
|
+
buffer = toArrayBuffer(buf);
|
|
7277
|
+
} else if (Buffer.isBuffer(input)) {
|
|
7278
|
+
buffer = toArrayBuffer(input);
|
|
7279
|
+
} else {
|
|
7280
|
+
buffer = input;
|
|
7281
|
+
}
|
|
7282
|
+
if (outputFormat === "hwpx-preserve") {
|
|
7283
|
+
const format = detectFormat(buffer);
|
|
7284
|
+
if (format === "hwpx") {
|
|
7285
|
+
const zipFormat = await detectZipFormat(buffer);
|
|
7286
|
+
if (zipFormat !== "hwpx") {
|
|
7287
|
+
throw new Error(`hwpx-preserve \uD3EC\uB9F7\uC740 HWPX \uC785\uB825\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4 (\uAC10\uC9C0\uB41C \uD3EC\uB9F7: ${zipFormat})`);
|
|
7288
|
+
}
|
|
7289
|
+
} else {
|
|
7290
|
+
throw new Error(`hwpx-preserve \uD3EC\uB9F7\uC740 HWPX \uC785\uB825\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4 (\uAC10\uC9C0\uB41C \uD3EC\uB9F7: ${format})`);
|
|
7291
|
+
}
|
|
7292
|
+
const hwpxResult = await fillHwpx(buffer, values);
|
|
7293
|
+
return {
|
|
7294
|
+
output: hwpxResult.buffer,
|
|
7295
|
+
format: "hwpx-preserve",
|
|
7296
|
+
fill: { filled: hwpxResult.filled, unmatched: hwpxResult.unmatched }
|
|
7297
|
+
};
|
|
7298
|
+
}
|
|
7299
|
+
const parsed = await parse(buffer);
|
|
7300
|
+
if (!parsed.success) {
|
|
7301
|
+
throw new Error(`\uC11C\uC2DD \uD30C\uC2F1 \uC2E4\uD328: ${parsed.error}`);
|
|
7302
|
+
}
|
|
7303
|
+
const fill = fillFormFields(parsed.blocks, values);
|
|
7304
|
+
const markdown = blocksToMarkdown(fill.blocks);
|
|
7305
|
+
if (outputFormat === "hwpx") {
|
|
7306
|
+
const hwpxBuffer = await markdownToHwpx(markdown);
|
|
7307
|
+
return { output: hwpxBuffer, format: "hwpx", fill };
|
|
7308
|
+
}
|
|
7309
|
+
return { output: markdown, format: "markdown", fill };
|
|
7310
|
+
}
|
|
6720
7311
|
export {
|
|
6721
7312
|
VERSION,
|
|
6722
7313
|
blocksToMarkdown,
|
|
@@ -6725,7 +7316,11 @@ export {
|
|
|
6725
7316
|
detectZipFormat,
|
|
6726
7317
|
diffBlocks,
|
|
6727
7318
|
extractFormFields,
|
|
7319
|
+
fillForm,
|
|
7320
|
+
fillFormFields,
|
|
7321
|
+
fillHwpx,
|
|
6728
7322
|
isHwpxFile,
|
|
7323
|
+
isLabelCell,
|
|
6729
7324
|
isOldHwpFile,
|
|
6730
7325
|
isPdfFile,
|
|
6731
7326
|
isZipFile,
|