kordoc 3.5.3 → 3.7.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 +16 -1
- package/dist/{-N2SJBI4R.js → -7UC4ZWBS.js} +21 -5
- package/dist/chunk-DCZVOIEO.cjs.map +1 -1
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-3Z2RAKIL.js → chunk-IJJMVTU5.js} +2 -2
- package/dist/chunk-IJJMVTU5.js.map +1 -0
- package/dist/{chunk-JOLDAN3Q.js → chunk-MEVKYW55.js} +2 -2
- package/dist/chunk-MEVKYW55.js.map +1 -0
- package/dist/{chunk-GUDFEDFK.js → chunk-NXRABCWW.js} +1588 -695
- package/dist/chunk-NXRABCWW.js.map +1 -0
- package/dist/{chunk-53XNKPN6.cjs → chunk-QZCP3UWU.cjs} +2 -2
- package/dist/chunk-QZCP3UWU.cjs.map +1 -0
- package/dist/cli.js +4 -4
- package/dist/formula-5NKVS2LR.cjs.map +1 -1
- package/dist/index.cjs +1787 -894
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +130 -8
- package/dist/index.d.ts +130 -8
- package/dist/index.js +1588 -695
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +3 -3
- package/dist/page-range-P7SDW6LR.cjs.map +1 -1
- package/dist/{parser-IAROZTY3.js → parser-DR5CTZ74.js} +2 -2
- package/dist/{parser-CK5C6FF4.cjs → parser-RFLPUZ7P.cjs} +14 -14
- package/dist/parser-RFLPUZ7P.cjs.map +1 -0
- package/dist/{parser-CPFIB47T.js → parser-ZHJFQR44.js} +2 -2
- package/dist/provider-G4C2V2PD.cjs.map +1 -1
- package/dist/{watch-ZYNP3QFT.js → watch-UIX447QV.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-3Z2RAKIL.js.map +0 -1
- package/dist/chunk-53XNKPN6.cjs.map +0 -1
- package/dist/chunk-GUDFEDFK.js.map +0 -1
- package/dist/chunk-JOLDAN3Q.js.map +0 -1
- package/dist/parser-CK5C6FF4.cjs.map +0 -1
- /package/dist/{-N2SJBI4R.js.map → -7UC4ZWBS.js.map} +0 -0
- /package/dist/{parser-IAROZTY3.js.map → parser-DR5CTZ74.js.map} +0 -0
- /package/dist/{parser-CPFIB47T.js.map → parser-ZHJFQR44.js.map} +0 -0
- /package/dist/{watch-ZYNP3QFT.js.map → watch-UIX447QV.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
sanitizeHref,
|
|
20
20
|
stripDtd,
|
|
21
21
|
toArrayBuffer
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-MEVKYW55.js";
|
|
23
23
|
import {
|
|
24
24
|
parsePageRange
|
|
25
25
|
} from "./chunk-GE43BE46.js";
|
|
@@ -1450,9 +1450,32 @@ function detectHwpxHeadings(blocks, styleMap) {
|
|
|
1450
1450
|
function buildTableWithCellMeta(state) {
|
|
1451
1451
|
const table = buildTable(state.rows);
|
|
1452
1452
|
if (state.caption) table.caption = state.caption;
|
|
1453
|
+
const anchors = [];
|
|
1454
|
+
{
|
|
1455
|
+
const covered = /* @__PURE__ */ new Set();
|
|
1456
|
+
for (let r = 0; r < table.rows; r++) {
|
|
1457
|
+
for (let c = 0; c < table.cols; c++) {
|
|
1458
|
+
if (covered.has(`${r},${c}`)) continue;
|
|
1459
|
+
const cell = table.cells[r]?.[c];
|
|
1460
|
+
if (!cell) continue;
|
|
1461
|
+
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
1462
|
+
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
1463
|
+
if (dr === 0 && dc === 0) continue;
|
|
1464
|
+
if (r + dr < table.rows && c + dc < table.cols) covered.add(`${r + dr},${c + dc}`);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
anchors.push(cell);
|
|
1468
|
+
c += cell.colSpan - 1;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
const srcCount = state.rows.reduce((s, r) => s + r.length, 0);
|
|
1473
|
+
const ordinalReliable = anchors.length === srcCount;
|
|
1453
1474
|
const claimed = /* @__PURE__ */ new Set();
|
|
1475
|
+
let flatIdx = -1;
|
|
1454
1476
|
for (const row of state.rows) {
|
|
1455
1477
|
for (const src of row) {
|
|
1478
|
+
flatIdx++;
|
|
1456
1479
|
const needsBlocks = src.hasStructure && src.blocks && src.blocks.length > 0;
|
|
1457
1480
|
if (!needsBlocks && !src.isHeader) continue;
|
|
1458
1481
|
let target;
|
|
@@ -1471,6 +1494,10 @@ function buildTableWithCellMeta(state) {
|
|
|
1471
1494
|
}
|
|
1472
1495
|
}
|
|
1473
1496
|
}
|
|
1497
|
+
if (!target && ordinalReliable) {
|
|
1498
|
+
const cand = anchors[flatIdx];
|
|
1499
|
+
if (cand && !claimed.has(cand)) target = cand;
|
|
1500
|
+
}
|
|
1474
1501
|
if (!target) continue;
|
|
1475
1502
|
claimed.add(target);
|
|
1476
1503
|
if (needsBlocks) target.blocks = src.blocks;
|
|
@@ -18694,6 +18721,45 @@ function countSections(body) {
|
|
|
18694
18721
|
}
|
|
18695
18722
|
|
|
18696
18723
|
// src/form/match.ts
|
|
18724
|
+
var ValueCursor = class {
|
|
18725
|
+
constructor(values) {
|
|
18726
|
+
this.values = values;
|
|
18727
|
+
}
|
|
18728
|
+
nextIdx = /* @__PURE__ */ new Map();
|
|
18729
|
+
keys() {
|
|
18730
|
+
return this.values.keys();
|
|
18731
|
+
}
|
|
18732
|
+
has(key) {
|
|
18733
|
+
return this.values.has(key);
|
|
18734
|
+
}
|
|
18735
|
+
isArray(key) {
|
|
18736
|
+
return Array.isArray(this.values.get(key));
|
|
18737
|
+
}
|
|
18738
|
+
/** 남은 값이 있으면 true (스칼라는 항상 true) */
|
|
18739
|
+
available(key) {
|
|
18740
|
+
const v = this.values.get(key);
|
|
18741
|
+
if (v === void 0) return false;
|
|
18742
|
+
return typeof v === "string" || (this.nextIdx.get(key) ?? 0) < v.length;
|
|
18743
|
+
}
|
|
18744
|
+
/** 현재 값 미리보기 (소진 없음) */
|
|
18745
|
+
peek(key) {
|
|
18746
|
+
const v = this.values.get(key);
|
|
18747
|
+
if (v === void 0) return void 0;
|
|
18748
|
+
if (typeof v === "string") return v;
|
|
18749
|
+
const i = this.nextIdx.get(key) ?? 0;
|
|
18750
|
+
return i < v.length ? v[i] : void 0;
|
|
18751
|
+
}
|
|
18752
|
+
/** 값 소비 — 배열이면 커서 전진, 소진 시 undefined */
|
|
18753
|
+
consume(key) {
|
|
18754
|
+
const v = this.values.get(key);
|
|
18755
|
+
if (v === void 0) return void 0;
|
|
18756
|
+
if (typeof v === "string") return v;
|
|
18757
|
+
const i = this.nextIdx.get(key) ?? 0;
|
|
18758
|
+
if (i >= v.length) return void 0;
|
|
18759
|
+
this.nextIdx.set(key, i + 1);
|
|
18760
|
+
return v[i];
|
|
18761
|
+
}
|
|
18762
|
+
};
|
|
18697
18763
|
function normalizeLabel(label) {
|
|
18698
18764
|
return label.trim().replace(/[::\s()()·]/g, "");
|
|
18699
18765
|
}
|
|
@@ -18732,9 +18798,9 @@ function fillInCellPatterns(cellText, values, matchedLabels) {
|
|
|
18732
18798
|
(match, prefix, suffix) => {
|
|
18733
18799
|
const label = prefix + suffix;
|
|
18734
18800
|
const normalizedLabel = normalizeLabel(label);
|
|
18735
|
-
const matchKey = values.
|
|
18801
|
+
const matchKey = values.available(normalizedLabel) ? normalizedLabel : values.available(normalizeLabel(prefix)) ? normalizeLabel(prefix) : void 0;
|
|
18736
18802
|
if (matchKey === void 0) return match;
|
|
18737
|
-
const newValue = values.
|
|
18803
|
+
const newValue = values.consume(matchKey);
|
|
18738
18804
|
matchedLabels.add(matchKey);
|
|
18739
18805
|
matches.push({ key: matchKey, label, value: newValue });
|
|
18740
18806
|
return `${prefix}(${newValue})${suffix}`;
|
|
@@ -18744,11 +18810,12 @@ function fillInCellPatterns(cellText, values, matchedLabels) {
|
|
|
18744
18810
|
/□([가-힣A-Za-z]+)/g,
|
|
18745
18811
|
(match, keyword) => {
|
|
18746
18812
|
const normalizedKw = normalizeLabel(keyword);
|
|
18747
|
-
const matchKey = values.
|
|
18813
|
+
const matchKey = values.available(normalizedKw) ? normalizedKw : void 0;
|
|
18748
18814
|
if (matchKey === void 0) return match;
|
|
18749
|
-
const val = values.
|
|
18815
|
+
const val = values.peek(matchKey);
|
|
18750
18816
|
const isTruthy = ["\u2611", "\u2713", "\u2714", "v", "V", "true", "1", "yes", "o", "O"].includes(val.trim()) || val.trim() === "";
|
|
18751
18817
|
if (!isTruthy) return match;
|
|
18818
|
+
values.consume(matchKey);
|
|
18752
18819
|
matchedLabels.add(matchKey);
|
|
18753
18820
|
matches.push({ key: matchKey, label: `\u25A1${keyword}`, value: "\u2611" });
|
|
18754
18821
|
return `\u2611${keyword}`;
|
|
@@ -18758,9 +18825,9 @@ function fillInCellPatterns(cellText, values, matchedLabels) {
|
|
|
18758
18825
|
/\(([가-힣A-Za-z]+)[::]\s{1,}\)/g,
|
|
18759
18826
|
(match, keyword) => {
|
|
18760
18827
|
const normalizedKw = normalizeLabel(keyword);
|
|
18761
|
-
const matchKey = values.
|
|
18828
|
+
const matchKey = values.available(normalizedKw) ? normalizedKw : void 0;
|
|
18762
18829
|
if (matchKey === void 0) return match;
|
|
18763
|
-
const newValue = values.
|
|
18830
|
+
const newValue = values.consume(matchKey);
|
|
18764
18831
|
matchedLabels.add(matchKey);
|
|
18765
18832
|
matches.push({ key: matchKey, label: keyword, value: newValue });
|
|
18766
18833
|
return `(${keyword}\uFF1A${newValue})`;
|
|
@@ -18866,14 +18933,66 @@ var LABEL_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
18866
18933
|
"\uCCAD\uAD6C\uC0AC\uC720",
|
|
18867
18934
|
"\uC18C\uBA85\uC790\uB8CC"
|
|
18868
18935
|
]);
|
|
18936
|
+
var ENGLISH_LABEL_WORDS = /* @__PURE__ */ new Set([
|
|
18937
|
+
"name",
|
|
18938
|
+
"date",
|
|
18939
|
+
"address",
|
|
18940
|
+
"tel",
|
|
18941
|
+
"phone",
|
|
18942
|
+
"mobile",
|
|
18943
|
+
"fax",
|
|
18944
|
+
"email",
|
|
18945
|
+
"e-mail",
|
|
18946
|
+
"dept",
|
|
18947
|
+
"department",
|
|
18948
|
+
"division",
|
|
18949
|
+
"title",
|
|
18950
|
+
"position",
|
|
18951
|
+
"grade",
|
|
18952
|
+
"rank",
|
|
18953
|
+
"birth",
|
|
18954
|
+
"nationality",
|
|
18955
|
+
"sex",
|
|
18956
|
+
"gender",
|
|
18957
|
+
"signature",
|
|
18958
|
+
"sign",
|
|
18959
|
+
"seal",
|
|
18960
|
+
"remarks",
|
|
18961
|
+
"note",
|
|
18962
|
+
"period",
|
|
18963
|
+
"place",
|
|
18964
|
+
"purpose",
|
|
18965
|
+
"reason",
|
|
18966
|
+
"amount",
|
|
18967
|
+
"total",
|
|
18968
|
+
"sum",
|
|
18969
|
+
"qty",
|
|
18970
|
+
"quantity",
|
|
18971
|
+
"unit",
|
|
18972
|
+
"no",
|
|
18973
|
+
"id",
|
|
18974
|
+
"passport"
|
|
18975
|
+
]);
|
|
18976
|
+
var ENGLISH_STOPWORDS = /* @__PURE__ */ new Set(["of", "the", "and", "or", "in"]);
|
|
18977
|
+
var NUMERIC_VALUE_RE = /^제?\d+(?:[.,]\d+)*[십백천만억조]*(?:원|명|건|개|회|부|매|장|점|호|번|년|월|일|시|분|초|개월|주년|차례|퍼센트)?$/;
|
|
18978
|
+
var SENTENCE_ENDING_RE = /(?:입니다|합니다|습니다|하세요|십시오|시오|바랍니다|바람|할 것|할것|하며|하고|한다|된다|됨|음|임)$/;
|
|
18869
18979
|
function isLabelCell(text) {
|
|
18870
18980
|
const trimmed = text.trim().replace(/[¹²³⁴⁵⁶⁷⁸⁹⁰*※]+$/g, "").trim();
|
|
18871
18981
|
if (!trimmed || trimmed.length > 30) return false;
|
|
18872
18982
|
for (const kw of LABEL_KEYWORDS) {
|
|
18873
18983
|
if (trimmed.includes(kw)) return true;
|
|
18874
18984
|
}
|
|
18875
|
-
|
|
18985
|
+
const compact = trimmed.replace(/\s/g, "");
|
|
18986
|
+
if (/^[가-힣0-9()()·::\-]+$/.test(compact) && compact.length >= 2 && compact.length <= 12 && (compact.match(/[가-힣]/g) ?? []).length >= 2 && (compact.length <= 8 || trimmed.split(/\s+/).length <= 2) && !NUMERIC_VALUE_RE.test(compact) && !SENTENCE_ENDING_RE.test(trimmed) && !/^[((]주[))]|^주식회사/.test(compact)) {
|
|
18987
|
+
return true;
|
|
18988
|
+
}
|
|
18876
18989
|
if (/^[가-힣A-Za-z\s]+[::]$/.test(trimmed)) return true;
|
|
18990
|
+
if (/^[A-Za-z][A-Za-z\s./&-]*$/.test(trimmed) && trimmed.length <= 20) {
|
|
18991
|
+
const words = trimmed.toLowerCase().split(/[\s/&]+/).filter((w) => w && !ENGLISH_STOPWORDS.has(w));
|
|
18992
|
+
if (words.length >= 1 && words.length <= 3 && words.every((w) => ENGLISH_LABEL_WORDS.has(w.replace(/\.$/, "")))) {
|
|
18993
|
+
return true;
|
|
18994
|
+
}
|
|
18995
|
+
}
|
|
18877
18996
|
return false;
|
|
18878
18997
|
}
|
|
18879
18998
|
function extractFormFields(blocks) {
|
|
@@ -19014,17 +19133,18 @@ function fillFormFields(blocks, values) {
|
|
|
19014
19133
|
const filled = [];
|
|
19015
19134
|
const matchedLabels = /* @__PURE__ */ new Set();
|
|
19016
19135
|
const normalizedValues = normalizeValues(values);
|
|
19136
|
+
const cursor = new ValueCursor(normalizedValues);
|
|
19137
|
+
const allTables = collectIRTables(cloned, 0);
|
|
19017
19138
|
const patternFilledCells = /* @__PURE__ */ new Set();
|
|
19018
|
-
for (const
|
|
19019
|
-
|
|
19020
|
-
|
|
19021
|
-
|
|
19022
|
-
const cell = block.table.cells[r]?.[c];
|
|
19139
|
+
for (const table of allTables) {
|
|
19140
|
+
for (let r = 0; r < table.rows; r++) {
|
|
19141
|
+
for (let c = 0; c < table.cols; c++) {
|
|
19142
|
+
const cell = table.cells[r]?.[c];
|
|
19023
19143
|
if (!cell) continue;
|
|
19024
|
-
const result = fillInCellPatterns(cell.text,
|
|
19144
|
+
const result = fillInCellPatterns(cell.text, cursor, matchedLabels);
|
|
19025
19145
|
if (result) {
|
|
19026
19146
|
cell.text = result.text;
|
|
19027
|
-
patternFilledCells.add(
|
|
19147
|
+
patternFilledCells.add(cell);
|
|
19028
19148
|
for (const m of result.matches) {
|
|
19029
19149
|
filled.push({ label: m.label, value: m.value, row: r, col: c });
|
|
19030
19150
|
}
|
|
@@ -19032,33 +19152,71 @@ function fillFormFields(blocks, values) {
|
|
|
19032
19152
|
}
|
|
19033
19153
|
}
|
|
19034
19154
|
}
|
|
19035
|
-
for (const
|
|
19036
|
-
|
|
19037
|
-
fillTable(block.table, normalizedValues, filled, matchedLabels, patternFilledCells);
|
|
19155
|
+
for (const table of allTables) {
|
|
19156
|
+
fillTable(table, cursor, filled, matchedLabels, patternFilledCells);
|
|
19038
19157
|
}
|
|
19039
19158
|
for (const block of cloned) {
|
|
19040
19159
|
if (block.type !== "paragraph" || !block.text) continue;
|
|
19041
|
-
const newText = fillInlineFields(block.text,
|
|
19160
|
+
const newText = fillInlineFields(block.text, cursor, filled, matchedLabels);
|
|
19042
19161
|
if (newText !== block.text) block.text = newText;
|
|
19043
19162
|
}
|
|
19044
19163
|
const unmatched = resolveUnmatched(normalizedValues, matchedLabels, values);
|
|
19045
19164
|
return { blocks: cloned, filled, unmatched };
|
|
19046
19165
|
}
|
|
19166
|
+
function collectIRTables(blocks, depth) {
|
|
19167
|
+
if (depth > 16) return [];
|
|
19168
|
+
const out = [];
|
|
19169
|
+
for (const block of blocks) {
|
|
19170
|
+
if (block.type !== "table" || !block.table) continue;
|
|
19171
|
+
out.push(block.table);
|
|
19172
|
+
for (const row of block.table.cells) {
|
|
19173
|
+
for (const cell of row) {
|
|
19174
|
+
if (cell?.blocks?.length) out.push(...collectIRTables(cell.blocks, depth + 1));
|
|
19175
|
+
}
|
|
19176
|
+
}
|
|
19177
|
+
}
|
|
19178
|
+
return out;
|
|
19179
|
+
}
|
|
19180
|
+
function coveredPositions(table) {
|
|
19181
|
+
const covered = /* @__PURE__ */ new Set();
|
|
19182
|
+
for (let r = 0; r < table.rows; r++) {
|
|
19183
|
+
for (let c = 0; c < table.cols; c++) {
|
|
19184
|
+
if (covered.has(`${r},${c}`)) continue;
|
|
19185
|
+
const cell = table.cells[r]?.[c];
|
|
19186
|
+
if (!cell) continue;
|
|
19187
|
+
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
19188
|
+
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
19189
|
+
if (dr === 0 && dc === 0) continue;
|
|
19190
|
+
if (r + dr < table.rows && c + dc < table.cols) covered.add(`${r + dr},${c + dc}`);
|
|
19191
|
+
}
|
|
19192
|
+
}
|
|
19193
|
+
c += cell.colSpan - 1;
|
|
19194
|
+
}
|
|
19195
|
+
}
|
|
19196
|
+
return covered;
|
|
19197
|
+
}
|
|
19047
19198
|
function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
|
|
19048
19199
|
if (table.cols < 2) return;
|
|
19200
|
+
const covered = coveredPositions(table);
|
|
19049
19201
|
for (let r = 0; r < table.rows; r++) {
|
|
19050
|
-
for (let c = 0; c < table.cols
|
|
19202
|
+
for (let c = 0; c < table.cols; c++) {
|
|
19203
|
+
if (covered.has(`${r},${c}`)) continue;
|
|
19051
19204
|
const labelCell = table.cells[r][c];
|
|
19052
|
-
|
|
19053
|
-
if (!labelCell || !valueCell) continue;
|
|
19205
|
+
if (!labelCell) continue;
|
|
19054
19206
|
if (!isLabelCell(labelCell.text)) continue;
|
|
19207
|
+
let vc = c + labelCell.colSpan;
|
|
19208
|
+
while (vc < table.cols && covered.has(`${r},${vc}`)) vc++;
|
|
19209
|
+
if (vc >= table.cols) continue;
|
|
19210
|
+
const valueCell = table.cells[r][vc];
|
|
19211
|
+
if (!valueCell) continue;
|
|
19055
19212
|
if (isKeywordLabel(valueCell.text)) continue;
|
|
19056
19213
|
const normalizedCellLabel = normalizeLabel(labelCell.text);
|
|
19057
19214
|
if (!normalizedCellLabel) continue;
|
|
19058
19215
|
const matchKey = findMatchingKey(normalizedCellLabel, values);
|
|
19059
19216
|
if (matchKey === void 0) continue;
|
|
19060
|
-
const newValue = values.
|
|
19061
|
-
if (
|
|
19217
|
+
const newValue = values.consume(matchKey);
|
|
19218
|
+
if (newValue === void 0) continue;
|
|
19219
|
+
if (patternFilledCells?.has(valueCell)) {
|
|
19062
19220
|
valueCell.text = newValue + " " + valueCell.text;
|
|
19063
19221
|
} else {
|
|
19064
19222
|
valueCell.text = newValue;
|
|
@@ -19081,14 +19239,16 @@ function fillTable(table, values, filled, matchedLabels, patternFilledCells) {
|
|
|
19081
19239
|
if (!allLabels) return;
|
|
19082
19240
|
for (let r = 1; r < table.rows; r++) {
|
|
19083
19241
|
for (let c = 0; c < table.cols; c++) {
|
|
19242
|
+
if (covered.has(`${r},${c}`)) continue;
|
|
19084
19243
|
const headerCell = headerRow[c];
|
|
19085
19244
|
const valueCell = table.cells[r]?.[c];
|
|
19086
19245
|
if (!headerCell || !valueCell) continue;
|
|
19087
19246
|
const headerLabel = normalizeLabel(headerCell.text);
|
|
19088
19247
|
const matchKey = findMatchingKey(headerLabel, values);
|
|
19089
19248
|
if (matchKey === void 0) continue;
|
|
19090
|
-
if (matchedLabels.has(matchKey)) continue;
|
|
19091
|
-
const newValue = values.
|
|
19249
|
+
if (!values.isArray(matchKey) && matchedLabels.has(matchKey)) continue;
|
|
19250
|
+
const newValue = values.consume(matchKey);
|
|
19251
|
+
if (newValue === void 0) continue;
|
|
19092
19252
|
valueCell.text = newValue;
|
|
19093
19253
|
matchedLabels.add(matchKey);
|
|
19094
19254
|
filled.push({
|
|
@@ -19109,7 +19269,8 @@ function fillInlineFields(text, values, filled, matchedLabels) {
|
|
|
19109
19269
|
for (const seg of segments) {
|
|
19110
19270
|
const matchKey = findMatchingKey(normalizeLabel(seg.label), values);
|
|
19111
19271
|
if (matchKey === void 0) continue;
|
|
19112
|
-
const newValue = values.
|
|
19272
|
+
const newValue = values.consume(matchKey);
|
|
19273
|
+
if (newValue === void 0) continue;
|
|
19113
19274
|
matchedLabels.add(matchKey);
|
|
19114
19275
|
filled.push({ label: seg.label.trim(), value: newValue, row: -1, col: -1 });
|
|
19115
19276
|
out += text.slice(pos, seg.valueStart);
|
|
@@ -19216,6 +19377,7 @@ function scanSectionXml(xml, sectionIndex) {
|
|
|
19216
19377
|
const paraStack = [];
|
|
19217
19378
|
const tableStack = [];
|
|
19218
19379
|
const rowStack = [];
|
|
19380
|
+
const trStartStack = [];
|
|
19219
19381
|
const cellStack = [];
|
|
19220
19382
|
let pendingT = null;
|
|
19221
19383
|
const ctrlSubStack = [];
|
|
@@ -19280,11 +19442,17 @@ function scanSectionXml(xml, sectionIndex) {
|
|
|
19280
19442
|
} else if (local2 === "tr") {
|
|
19281
19443
|
const row = rowStack[rowStack.length - 1];
|
|
19282
19444
|
const table = tableStack[tableStack.length - 1];
|
|
19283
|
-
if (row && table && row.length > 0)
|
|
19445
|
+
if (row && table && row.length > 0) {
|
|
19446
|
+
table.rows.push(row);
|
|
19447
|
+
const trStart = trStartStack[trStartStack.length - 1];
|
|
19448
|
+
if (trStart >= 0) table.rowRanges.push({ start: trStart, end: m.index + full.length });
|
|
19449
|
+
}
|
|
19284
19450
|
if (rowStack.length > 0) rowStack[rowStack.length - 1] = [];
|
|
19451
|
+
if (trStartStack.length > 0) trStartStack[trStartStack.length - 1] = -1;
|
|
19285
19452
|
} else if (local2 === "tbl") {
|
|
19286
19453
|
const table = tableStack.pop();
|
|
19287
19454
|
rowStack.pop();
|
|
19455
|
+
trStartStack.pop();
|
|
19288
19456
|
if (table) {
|
|
19289
19457
|
finalizeTable(table);
|
|
19290
19458
|
if (!table.topLevel) {
|
|
@@ -19327,6 +19495,7 @@ function scanSectionXml(xml, sectionIndex) {
|
|
|
19327
19495
|
const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
|
|
19328
19496
|
if (!isNaN(ca)) cell.colAddr = ca;
|
|
19329
19497
|
if (!isNaN(ra)) cell.rowAddr = ra;
|
|
19498
|
+
cell.addrTagRange = { start: m.index, end: m.index + full.length };
|
|
19330
19499
|
}
|
|
19331
19500
|
} else if (local === "cellSpan") {
|
|
19332
19501
|
const cell = cellStack[cellStack.length - 1];
|
|
@@ -19377,6 +19546,7 @@ function scanSectionXml(xml, sectionIndex) {
|
|
|
19377
19546
|
start: m.index,
|
|
19378
19547
|
topLevel: false,
|
|
19379
19548
|
rows: [],
|
|
19549
|
+
rowRanges: [],
|
|
19380
19550
|
cellByAnchor: /* @__PURE__ */ new Map()
|
|
19381
19551
|
};
|
|
19382
19552
|
stack.pop();
|
|
@@ -19384,9 +19554,11 @@ function scanSectionXml(xml, sectionIndex) {
|
|
|
19384
19554
|
stack.push({ local, qname, contentStart });
|
|
19385
19555
|
tableStack.push(table);
|
|
19386
19556
|
rowStack.push([]);
|
|
19557
|
+
trStartStack.push(-1);
|
|
19387
19558
|
if (table.topLevel) tables.push(table);
|
|
19388
19559
|
} else if (local === "tr") {
|
|
19389
19560
|
if (rowStack.length > 0) rowStack[rowStack.length - 1] = [];
|
|
19561
|
+
if (trStartStack.length > 0) trStartStack[trStartStack.length - 1] = m.index;
|
|
19390
19562
|
} else if (local === "tc") {
|
|
19391
19563
|
cellStack.push({ colSpan: 1, rowSpan: 1, paragraphs: [], tables: [] });
|
|
19392
19564
|
} else if (local === "cellAddr" || local === "cellSpan") {
|
|
@@ -19397,6 +19569,7 @@ function scanSectionXml(xml, sectionIndex) {
|
|
|
19397
19569
|
const ra = parseInt(getAttr2(attrsRaw, "rowAddr") || "", 10);
|
|
19398
19570
|
if (!isNaN(ca)) cell.colAddr = ca;
|
|
19399
19571
|
if (!isNaN(ra)) cell.rowAddr = ra;
|
|
19572
|
+
cell.addrTagRange = { start: m.index, end: contentStart };
|
|
19400
19573
|
} else {
|
|
19401
19574
|
const cs = parseInt(getAttr2(attrsRaw, "colSpan") || "1", 10);
|
|
19402
19575
|
const rs = parseInt(getAttr2(attrsRaw, "rowSpan") || "1", 10);
|
|
@@ -19789,6 +19962,7 @@ async function fillHwpx(hwpxBuffer, values) {
|
|
|
19789
19962
|
throw new KordocError("HWPX\uC5D0\uC11C \uC139\uC158 \uD30C\uC77C\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
19790
19963
|
}
|
|
19791
19964
|
const normalizedValues = normalizeValues(values);
|
|
19965
|
+
const cursor = new ValueCursor(normalizedValues);
|
|
19792
19966
|
const matchedLabels = /* @__PURE__ */ new Set();
|
|
19793
19967
|
const filled = [];
|
|
19794
19968
|
const failedKeys = /* @__PURE__ */ new Set();
|
|
@@ -19824,7 +19998,7 @@ async function fillHwpx(hwpxBuffer, values) {
|
|
|
19824
19998
|
for (const cell of row) {
|
|
19825
19999
|
for (const para of cell.paragraphs) {
|
|
19826
20000
|
const text = matchText(para);
|
|
19827
|
-
const result = fillInCellPatterns(text,
|
|
20001
|
+
const result = fillInCellPatterns(text, cursor, matchedLabels);
|
|
19828
20002
|
if (!result) continue;
|
|
19829
20003
|
const l = led(para);
|
|
19830
20004
|
if (l.fullText !== void 0) continue;
|
|
@@ -19858,21 +20032,30 @@ async function fillHwpx(hwpxBuffer, values) {
|
|
|
19858
20032
|
if (isKeywordLabel(cellLabelText(valueCell))) continue;
|
|
19859
20033
|
const normalizedCellLabel = normalizeLabel(labelText);
|
|
19860
20034
|
if (!normalizedCellLabel) continue;
|
|
19861
|
-
const matchKey = findMatchingKey(normalizedCellLabel,
|
|
20035
|
+
const matchKey = findMatchingKey(normalizedCellLabel, cursor);
|
|
19862
20036
|
if (matchKey === void 0) continue;
|
|
19863
|
-
const newValue = normalizedValues.get(matchKey);
|
|
19864
20037
|
if (patternApplied.has(valueCell)) {
|
|
19865
20038
|
const target = valueCell.paragraphs.find((p) => p.tRanges.length > 0) ?? valueCell.paragraphs[0];
|
|
19866
20039
|
if (!target) continue;
|
|
19867
20040
|
const l = led(target);
|
|
19868
|
-
if (l.fullText
|
|
19869
|
-
|
|
19870
|
-
|
|
19871
|
-
|
|
19872
|
-
|
|
20041
|
+
if (l.fullText !== void 0) continue;
|
|
20042
|
+
const newValue = cursor.consume(matchKey);
|
|
20043
|
+
if (newValue === void 0) continue;
|
|
20044
|
+
l.ranges.push({ start: 0, end: 0, replacement: newValue + " " });
|
|
20045
|
+
l.filledIdx.push(filled.length);
|
|
20046
|
+
l.matchKeys.push(matchKey);
|
|
20047
|
+
matchedLabels.add(matchKey);
|
|
20048
|
+
filled.push({
|
|
20049
|
+
label: labelText.trim().replace(/[::]\s*$/, ""),
|
|
20050
|
+
value: newValue,
|
|
20051
|
+
row: rowIdx,
|
|
20052
|
+
col: colIdx
|
|
20053
|
+
});
|
|
19873
20054
|
} else {
|
|
19874
20055
|
const paras = valueCell.paragraphs;
|
|
19875
20056
|
if (paras.length === 0) continue;
|
|
20057
|
+
const newValue = cursor.consume(matchKey);
|
|
20058
|
+
if (newValue === void 0) continue;
|
|
19876
20059
|
const l0 = led(paras[0]);
|
|
19877
20060
|
l0.fullText = newValue;
|
|
19878
20061
|
l0.ranges = [];
|
|
@@ -19883,14 +20066,14 @@ async function fillHwpx(hwpxBuffer, values) {
|
|
|
19883
20066
|
lk.fullText = "";
|
|
19884
20067
|
lk.ranges = [];
|
|
19885
20068
|
}
|
|
20069
|
+
matchedLabels.add(matchKey);
|
|
20070
|
+
filled.push({
|
|
20071
|
+
label: labelText.trim().replace(/[::]\s*$/, ""),
|
|
20072
|
+
value: newValue,
|
|
20073
|
+
row: rowIdx,
|
|
20074
|
+
col: colIdx
|
|
20075
|
+
});
|
|
19886
20076
|
}
|
|
19887
|
-
matchedLabels.add(matchKey);
|
|
19888
|
-
filled.push({
|
|
19889
|
-
label: labelText.trim().replace(/[::]\s*$/, ""),
|
|
19890
|
-
value: newValue,
|
|
19891
|
-
row: rowIdx,
|
|
19892
|
-
col: colIdx
|
|
19893
|
-
});
|
|
19894
20077
|
}
|
|
19895
20078
|
}
|
|
19896
20079
|
if (table.rows.length >= 2) {
|
|
@@ -19904,10 +20087,11 @@ async function fillHwpx(hwpxBuffer, values) {
|
|
|
19904
20087
|
const dataCells = table.rows[rowIdx];
|
|
19905
20088
|
for (let colIdx = 0; colIdx < Math.min(headerCells.length, dataCells.length); colIdx++) {
|
|
19906
20089
|
const headerLabel = normalizeLabel(cellLabelText(headerCells[colIdx]));
|
|
19907
|
-
const matchKey = findMatchingKey(headerLabel,
|
|
20090
|
+
const matchKey = findMatchingKey(headerLabel, cursor);
|
|
19908
20091
|
if (matchKey === void 0) continue;
|
|
19909
|
-
if (matchedLabels.has(matchKey)) continue;
|
|
19910
|
-
const newValue =
|
|
20092
|
+
if (!cursor.isArray(matchKey) && matchedLabels.has(matchKey)) continue;
|
|
20093
|
+
const newValue = cursor.consume(matchKey);
|
|
20094
|
+
if (newValue === void 0) continue;
|
|
19911
20095
|
const paras = dataCells[colIdx].paragraphs;
|
|
19912
20096
|
if (paras.length === 0) continue;
|
|
19913
20097
|
const l0 = led(paras[0]);
|
|
@@ -19937,9 +20121,10 @@ async function fillHwpx(hwpxBuffer, values) {
|
|
|
19937
20121
|
if (existing?.fullText !== void 0) continue;
|
|
19938
20122
|
const text = matchText(para);
|
|
19939
20123
|
for (const seg of scanInlineSegments(text)) {
|
|
19940
|
-
const matchKey = findMatchingKey(normalizeLabel(seg.label),
|
|
20124
|
+
const matchKey = findMatchingKey(normalizeLabel(seg.label), cursor);
|
|
19941
20125
|
if (matchKey === void 0) continue;
|
|
19942
|
-
const newValue =
|
|
20126
|
+
const newValue = cursor.consume(matchKey);
|
|
20127
|
+
if (newValue === void 0) continue;
|
|
19943
20128
|
const replacement = seg.valueStart === seg.valueEnd ? padInsertion(text, seg.valueStart, newValue) : newValue;
|
|
19944
20129
|
const l = led(para);
|
|
19945
20130
|
l.ranges.push({ start: seg.valueStart, end: seg.valueEnd, replacement });
|
|
@@ -19994,6 +20179,7 @@ async function fillHwpx(hwpxBuffer, values) {
|
|
|
19994
20179
|
splices.push(...paraSplices);
|
|
19995
20180
|
}
|
|
19996
20181
|
if (splices.length > 0) {
|
|
20182
|
+
splices.push(...allLinesegRemovalSplices(xml));
|
|
19997
20183
|
replacements.set(sectionPaths[si], encoder.encode(applySplices(xml, splices)));
|
|
19998
20184
|
}
|
|
19999
20185
|
}
|
|
@@ -20013,6 +20199,245 @@ async function fillHwpx(hwpxBuffer, values) {
|
|
|
20013
20199
|
// src/hwpx/generator.ts
|
|
20014
20200
|
import JSZip6 from "jszip";
|
|
20015
20201
|
|
|
20202
|
+
// src/hwpx/text-metrics.ts
|
|
20203
|
+
var ASCII_W = [
|
|
20204
|
+
300,
|
|
20205
|
+
320,
|
|
20206
|
+
320,
|
|
20207
|
+
610,
|
|
20208
|
+
610,
|
|
20209
|
+
830,
|
|
20210
|
+
724,
|
|
20211
|
+
320,
|
|
20212
|
+
320,
|
|
20213
|
+
320,
|
|
20214
|
+
550,
|
|
20215
|
+
550,
|
|
20216
|
+
320,
|
|
20217
|
+
550,
|
|
20218
|
+
320,
|
|
20219
|
+
550,
|
|
20220
|
+
// 0x20-0x2F
|
|
20221
|
+
550,
|
|
20222
|
+
550,
|
|
20223
|
+
550,
|
|
20224
|
+
550,
|
|
20225
|
+
550,
|
|
20226
|
+
550,
|
|
20227
|
+
550,
|
|
20228
|
+
550,
|
|
20229
|
+
550,
|
|
20230
|
+
550,
|
|
20231
|
+
320,
|
|
20232
|
+
320,
|
|
20233
|
+
550,
|
|
20234
|
+
550,
|
|
20235
|
+
550,
|
|
20236
|
+
550,
|
|
20237
|
+
// 0x30-0x3F
|
|
20238
|
+
830,
|
|
20239
|
+
706,
|
|
20240
|
+
605,
|
|
20241
|
+
685,
|
|
20242
|
+
719,
|
|
20243
|
+
627,
|
|
20244
|
+
617,
|
|
20245
|
+
683,
|
|
20246
|
+
734,
|
|
20247
|
+
305,
|
|
20248
|
+
315,
|
|
20249
|
+
660,
|
|
20250
|
+
605,
|
|
20251
|
+
839,
|
|
20252
|
+
734,
|
|
20253
|
+
732,
|
|
20254
|
+
// 0x40-0x4F
|
|
20255
|
+
603,
|
|
20256
|
+
705,
|
|
20257
|
+
660,
|
|
20258
|
+
627,
|
|
20259
|
+
664,
|
|
20260
|
+
731,
|
|
20261
|
+
706,
|
|
20262
|
+
910,
|
|
20263
|
+
705,
|
|
20264
|
+
705,
|
|
20265
|
+
626,
|
|
20266
|
+
320,
|
|
20267
|
+
550,
|
|
20268
|
+
320,
|
|
20269
|
+
550,
|
|
20270
|
+
550,
|
|
20271
|
+
// 0x50-0x5F
|
|
20272
|
+
320,
|
|
20273
|
+
569,
|
|
20274
|
+
597,
|
|
20275
|
+
552,
|
|
20276
|
+
597,
|
|
20277
|
+
536,
|
|
20278
|
+
356,
|
|
20279
|
+
562,
|
|
20280
|
+
635,
|
|
20281
|
+
287,
|
|
20282
|
+
288,
|
|
20283
|
+
582,
|
|
20284
|
+
287,
|
|
20285
|
+
907,
|
|
20286
|
+
635,
|
|
20287
|
+
588,
|
|
20288
|
+
// 0x60-0x6F
|
|
20289
|
+
597,
|
|
20290
|
+
579,
|
|
20291
|
+
478,
|
|
20292
|
+
496,
|
|
20293
|
+
356,
|
|
20294
|
+
635,
|
|
20295
|
+
563,
|
|
20296
|
+
720,
|
|
20297
|
+
542,
|
|
20298
|
+
543,
|
|
20299
|
+
486,
|
|
20300
|
+
320,
|
|
20301
|
+
320,
|
|
20302
|
+
320,
|
|
20303
|
+
550,
|
|
20304
|
+
0
|
|
20305
|
+
// 0x70-0x7E(+DEL)
|
|
20306
|
+
];
|
|
20307
|
+
var SYM_W = {
|
|
20308
|
+
160: 300,
|
|
20309
|
+
163: 568,
|
|
20310
|
+
165: 707,
|
|
20311
|
+
167: 498,
|
|
20312
|
+
171: 440,
|
|
20313
|
+
172: 564,
|
|
20314
|
+
176: 291,
|
|
20315
|
+
177: 798,
|
|
20316
|
+
182: 606,
|
|
20317
|
+
183: 320,
|
|
20318
|
+
187: 440,
|
|
20319
|
+
215: 617,
|
|
20320
|
+
247: 678,
|
|
20321
|
+
8211: 625,
|
|
20322
|
+
8212: 875,
|
|
20323
|
+
8213: 875,
|
|
20324
|
+
8216: 320,
|
|
20325
|
+
8217: 320,
|
|
20326
|
+
8220: 480,
|
|
20327
|
+
8221: 480,
|
|
20328
|
+
8224: 558,
|
|
20329
|
+
8225: 438,
|
|
20330
|
+
8229: 640,
|
|
20331
|
+
8230: 960,
|
|
20332
|
+
8240: 988,
|
|
20333
|
+
8242: 335,
|
|
20334
|
+
8243: 474,
|
|
20335
|
+
8251: 770,
|
|
20336
|
+
8364: 656,
|
|
20337
|
+
9756: 1012,
|
|
20338
|
+
9758: 1012
|
|
20339
|
+
};
|
|
20340
|
+
function charWidthEm1000(cp) {
|
|
20341
|
+
if (cp >= 32 && cp <= 126) return ASCII_W[cp - 32];
|
|
20342
|
+
const sym = SYM_W[cp];
|
|
20343
|
+
if (sym !== void 0) return sym;
|
|
20344
|
+
if (cp >= 44032 && cp <= 55203) return 970;
|
|
20345
|
+
if (cp >= 4352 && cp <= 4607) return 970;
|
|
20346
|
+
if (cp >= 12593 && cp <= 12686) return 970;
|
|
20347
|
+
if (cp >= 19968 && cp <= 40959 || cp >= 63744 && cp <= 64255) return 1e3;
|
|
20348
|
+
if (cp >= 12296 && cp <= 12305 || cp >= 12308 && cp <= 12315) return 500;
|
|
20349
|
+
if (cp === 12288) return 970;
|
|
20350
|
+
if (cp >= 8592 && cp <= 8959) return 970;
|
|
20351
|
+
if (cp >= 9312 && cp <= 9471) return 970;
|
|
20352
|
+
if (cp >= 9632 && cp <= 9983) return 970;
|
|
20353
|
+
if (cp >= 12800 && cp <= 13311) return 970;
|
|
20354
|
+
if (cp >= 65281 && cp <= 65376) return 970;
|
|
20355
|
+
return cp >= 11904 ? 970 : 550;
|
|
20356
|
+
}
|
|
20357
|
+
var SPACE_EM_FIXED = 500;
|
|
20358
|
+
var SPACE_EM_FONT = 300;
|
|
20359
|
+
function measureTextWidth(text, height, ratioPct, opts) {
|
|
20360
|
+
const spaceEm = opts?.spaceEm ?? SPACE_EM_FIXED;
|
|
20361
|
+
const spacing = opts?.spacingPct ?? 0;
|
|
20362
|
+
let em = 0;
|
|
20363
|
+
for (const ch of text) {
|
|
20364
|
+
const cp = ch.codePointAt(0);
|
|
20365
|
+
const w = cp === 32 ? spaceEm : charWidthEm1000(cp);
|
|
20366
|
+
em += w * (1 + spacing / 100);
|
|
20367
|
+
}
|
|
20368
|
+
return em / 1e3 * height * (ratioPct / 100);
|
|
20369
|
+
}
|
|
20370
|
+
var FORBID_START = /* @__PURE__ */ new Set([..."!%),.:;?]}\xA2\xB0\u2032\u2033\u2103\u3009\u300B\u300D\u300F\u3011\u3015!%),.:;?]}\u20A9~\u2026\xB7\u3001\u3002\u3003"]);
|
|
20371
|
+
var FORBID_END = /* @__PURE__ */ new Set([..."$([{\xA3\xA5\u3008\u300A\u300C\u300E\u3010\u3014$([{\u20A9"]);
|
|
20372
|
+
function simulateWrap(text, firstWidth, contWidth, height, ratioPct, mode = "keep", opts) {
|
|
20373
|
+
const EPS = 0.5;
|
|
20374
|
+
const spaceEm = opts?.spaceEm ?? SPACE_EM_FIXED;
|
|
20375
|
+
const spacing = opts?.spacingPct ?? 0;
|
|
20376
|
+
const k = height * ratioPct / 100 / 1e3;
|
|
20377
|
+
const cwCp = (cp) => (cp === 32 ? spaceEm : charWidthEm1000(cp)) * (1 + spacing / 100) * k;
|
|
20378
|
+
const charW = (ch) => cwCp(ch.codePointAt(0));
|
|
20379
|
+
const rangeW = (from, to) => {
|
|
20380
|
+
let w = 0;
|
|
20381
|
+
for (const ch of text.slice(from, to)) w += charW(ch);
|
|
20382
|
+
return w;
|
|
20383
|
+
};
|
|
20384
|
+
const units = text.match(mode === "keep" ? / +|[^ ]+/g : / +|[^ ]/g) ?? [];
|
|
20385
|
+
const starts = [0];
|
|
20386
|
+
let lineW = 0;
|
|
20387
|
+
let avail = firstWidth;
|
|
20388
|
+
let pos = 0;
|
|
20389
|
+
const lineStart = () => starts[starts.length - 1];
|
|
20390
|
+
const breakBefore = (unitPos, w) => {
|
|
20391
|
+
let bp = unitPos;
|
|
20392
|
+
const u = text[unitPos];
|
|
20393
|
+
if (u !== void 0 && FORBID_START.has(u) && bp - 1 > lineStart() && text[bp - 1] !== " ") bp--;
|
|
20394
|
+
while (bp - 1 > lineStart() && FORBID_END.has(text[bp - 1])) bp--;
|
|
20395
|
+
if (bp <= lineStart()) bp = unitPos;
|
|
20396
|
+
starts.push(bp);
|
|
20397
|
+
avail = contWidth;
|
|
20398
|
+
lineW = rangeW(bp, unitPos) + w;
|
|
20399
|
+
};
|
|
20400
|
+
for (const u of units) {
|
|
20401
|
+
if (u[0] === " ") {
|
|
20402
|
+
lineW += charW(" ") * u.length;
|
|
20403
|
+
pos += u.length;
|
|
20404
|
+
continue;
|
|
20405
|
+
}
|
|
20406
|
+
const w = rangeW(pos, pos + u.length);
|
|
20407
|
+
if (lineW + w <= avail + EPS) {
|
|
20408
|
+
lineW += w;
|
|
20409
|
+
pos += u.length;
|
|
20410
|
+
continue;
|
|
20411
|
+
}
|
|
20412
|
+
if (lineW === 0 || w > contWidth + EPS) {
|
|
20413
|
+
let sub = 0;
|
|
20414
|
+
for (const ch of u) {
|
|
20415
|
+
const c = charW(ch);
|
|
20416
|
+
if (lineW + c > avail + EPS && lineW > 0) breakBefore(pos + sub, 0);
|
|
20417
|
+
lineW += c;
|
|
20418
|
+
sub += ch.length;
|
|
20419
|
+
}
|
|
20420
|
+
pos += u.length;
|
|
20421
|
+
continue;
|
|
20422
|
+
}
|
|
20423
|
+
breakBefore(pos, w);
|
|
20424
|
+
pos += u.length;
|
|
20425
|
+
}
|
|
20426
|
+
return { lines: starts.length, starts, lastLineWidth: lineW };
|
|
20427
|
+
}
|
|
20428
|
+
function simulateWrapKeepWord(text, firstWidth, contWidth, height, ratioPct, opts) {
|
|
20429
|
+
return simulateWrap(text, firstWidth, contWidth, height, ratioPct, "keep", opts);
|
|
20430
|
+
}
|
|
20431
|
+
function fitRatioForFewerLines(text, firstWidth, contWidth, height, baseRatio, minRatio, opts) {
|
|
20432
|
+
const base = simulateWrap(text, firstWidth, contWidth, height, baseRatio, "keep", opts);
|
|
20433
|
+
if (base.lines < 2) return null;
|
|
20434
|
+
for (let r = baseRatio - 1; r >= minRatio; r--) {
|
|
20435
|
+
const sim = simulateWrap(text, firstWidth, contWidth, height, r, "keep", opts);
|
|
20436
|
+
if (sim.lines < base.lines) return r;
|
|
20437
|
+
}
|
|
20438
|
+
return null;
|
|
20439
|
+
}
|
|
20440
|
+
|
|
20016
20441
|
// src/hwpx/gongmun.ts
|
|
20017
20442
|
var OFFICIAL_MARGINS = { top: 20, bottom: 10, left: 20, right: 20 };
|
|
20018
20443
|
var PRESET_DEFAULTS = {
|
|
@@ -20048,6 +20473,7 @@ function resolveGongmun(opts) {
|
|
|
20048
20473
|
const preset = normalizeGongmunPreset(opts.preset);
|
|
20049
20474
|
const d = PRESET_DEFAULTS[preset];
|
|
20050
20475
|
const bodyPt = opts.bodyPt ?? d.bodyPt;
|
|
20476
|
+
const autoFitMinRatio = opts.autoFit === false ? null : typeof opts.autoFit === "object" ? Math.min(Math.max(opts.autoFit.minRatio ?? 90, 50), 99) : 90;
|
|
20051
20477
|
return {
|
|
20052
20478
|
preset,
|
|
20053
20479
|
bodyFont: opts.bodyFont ?? "myeongjo",
|
|
@@ -20055,7 +20481,8 @@ function resolveGongmun(opts) {
|
|
|
20055
20481
|
lineSpacing: opts.lineSpacing ?? d.lineSpacing,
|
|
20056
20482
|
numbering: opts.numbering ?? d.numbering,
|
|
20057
20483
|
margins: opts.margins ?? OFFICIAL_MARGINS,
|
|
20058
|
-
centerTitle: opts.centerTitle ?? true
|
|
20484
|
+
centerTitle: opts.centerTitle ?? true,
|
|
20485
|
+
autoFitMinRatio
|
|
20059
20486
|
};
|
|
20060
20487
|
}
|
|
20061
20488
|
var HANGUL_INITIALS = [0, 2, 3, 5, 6, 7, 9, 11, 12, 14, 15, 16, 17, 18];
|
|
@@ -20098,11 +20525,14 @@ function standardMarker(depth, n) {
|
|
|
20098
20525
|
function reportMarker(depth) {
|
|
20099
20526
|
return REPORT_BULLETS[Math.min(depth, REPORT_BULLETS.length - 1)];
|
|
20100
20527
|
}
|
|
20528
|
+
function markerWidth(marker, bodyHeight) {
|
|
20529
|
+
let em = SPACE_EM_FIXED;
|
|
20530
|
+
for (const c of marker) em += charWidthEm1000(c.codePointAt(0));
|
|
20531
|
+
return Math.round(em / 1e3 * bodyHeight);
|
|
20532
|
+
}
|
|
20101
20533
|
function levelIndent(depth, bodyHeight, numbering) {
|
|
20102
|
-
const
|
|
20103
|
-
|
|
20104
|
-
const hang = Math.round((markerTa + 1) * ta);
|
|
20105
|
-
return { left: Math.round(depth * bodyHeight), indent: -hang };
|
|
20534
|
+
const marker = numbering === "report" ? reportMarker(depth) : standardMarker(depth, 0);
|
|
20535
|
+
return { left: Math.round(depth * bodyHeight), indent: -markerWidth(marker, bodyHeight) };
|
|
20106
20536
|
}
|
|
20107
20537
|
function computeSuppression(depths) {
|
|
20108
20538
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -20138,77 +20568,53 @@ function mmToHwpunit(mm) {
|
|
|
20138
20568
|
return Math.round(mm * 7200 / 25.4);
|
|
20139
20569
|
}
|
|
20140
20570
|
|
|
20141
|
-
// src/
|
|
20142
|
-
|
|
20143
|
-
|
|
20144
|
-
|
|
20145
|
-
|
|
20146
|
-
|
|
20147
|
-
|
|
20148
|
-
var NS_OCF = "urn:oasis:names:tc:opendocument:xmlns:container";
|
|
20149
|
-
var CHAR_NORMAL = 0;
|
|
20150
|
-
var CHAR_BOLD = 1;
|
|
20151
|
-
var CHAR_ITALIC = 2;
|
|
20152
|
-
var CHAR_BOLD_ITALIC = 3;
|
|
20153
|
-
var CHAR_CODE = 4;
|
|
20154
|
-
var CHAR_H1 = 5;
|
|
20155
|
-
var CHAR_H2 = 6;
|
|
20156
|
-
var CHAR_H3 = 7;
|
|
20157
|
-
var CHAR_H4 = 8;
|
|
20158
|
-
var CHAR_TABLE_HEADER = 9;
|
|
20159
|
-
var CHAR_QUOTE = 10;
|
|
20160
|
-
var PARA_NORMAL = 0;
|
|
20161
|
-
var PARA_H1 = 1;
|
|
20162
|
-
var PARA_H2 = 2;
|
|
20163
|
-
var PARA_H3 = 3;
|
|
20164
|
-
var PARA_H4 = 4;
|
|
20165
|
-
var PARA_CODE = 5;
|
|
20166
|
-
var PARA_QUOTE = 6;
|
|
20167
|
-
var PARA_LIST = 7;
|
|
20168
|
-
var DEFAULT_TEXT_COLOR = "#000000";
|
|
20169
|
-
function resolveTheme(theme) {
|
|
20170
|
-
return {
|
|
20171
|
-
h1: theme?.headingColors?.[1] ?? DEFAULT_TEXT_COLOR,
|
|
20172
|
-
h2: theme?.headingColors?.[2] ?? DEFAULT_TEXT_COLOR,
|
|
20173
|
-
h3: theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,
|
|
20174
|
-
h4: theme?.headingColors?.[4] ?? theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,
|
|
20175
|
-
body: theme?.bodyColor ?? DEFAULT_TEXT_COLOR,
|
|
20176
|
-
quote: theme?.quoteColor ?? DEFAULT_TEXT_COLOR,
|
|
20177
|
-
/** quoteColor가 명시되었는지 — blockquote charPr 분기에 사용 (baseline 호환) */
|
|
20178
|
-
hasQuoteOption: theme?.quoteColor !== void 0,
|
|
20179
|
-
tableHeader: theme?.tableHeaderColor ?? theme?.bodyColor ?? DEFAULT_TEXT_COLOR,
|
|
20180
|
-
tableHeaderBold: !!theme?.tableHeaderBold
|
|
20181
|
-
};
|
|
20571
|
+
// src/diff/text-diff.ts
|
|
20572
|
+
function similarity(a, b) {
|
|
20573
|
+
if (a === b) return 1;
|
|
20574
|
+
if (!a || !b) return 0;
|
|
20575
|
+
const maxLen = Math.max(a.length, b.length);
|
|
20576
|
+
if (maxLen === 0) return 1;
|
|
20577
|
+
return 1 - levenshtein(a, b) / maxLen;
|
|
20182
20578
|
}
|
|
20183
|
-
|
|
20184
|
-
|
|
20185
|
-
const gongmun = options?.gongmun ? resolveGongmun(options.gongmun) : null;
|
|
20186
|
-
const blocks = parseMarkdownToBlocks(markdown);
|
|
20187
|
-
const sectionXml = blocksToSectionXml(blocks, theme, gongmun);
|
|
20188
|
-
const zip = new JSZip6();
|
|
20189
|
-
zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
|
|
20190
|
-
zip.file("META-INF/container.xml", generateContainerXml());
|
|
20191
|
-
zip.file("Contents/content.hpf", generateManifest());
|
|
20192
|
-
zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun));
|
|
20193
|
-
zip.file("Contents/section0.xml", sectionXml);
|
|
20194
|
-
zip.file("Preview/PrvText.txt", buildPrvText(blocks));
|
|
20195
|
-
return await zip.generateAsync({ type: "arraybuffer" });
|
|
20579
|
+
function normalizedSimilarity(a, b) {
|
|
20580
|
+
return similarity(normalize(a), normalize(b));
|
|
20196
20581
|
}
|
|
20197
|
-
function
|
|
20198
|
-
|
|
20199
|
-
|
|
20200
|
-
|
|
20201
|
-
|
|
20202
|
-
|
|
20203
|
-
|
|
20204
|
-
|
|
20205
|
-
if (
|
|
20582
|
+
function normalize(s) {
|
|
20583
|
+
return s.replace(/\s+/g, " ").trim();
|
|
20584
|
+
}
|
|
20585
|
+
var MAX_LEVENSHTEIN_LEN = 1e4;
|
|
20586
|
+
function levenshtein(a, b) {
|
|
20587
|
+
if (a.length + b.length > MAX_LEVENSHTEIN_LEN) {
|
|
20588
|
+
const sampleLen = Math.min(500, a.length, b.length);
|
|
20589
|
+
let diffs = 0;
|
|
20590
|
+
for (let i = 0; i < sampleLen; i++) if (a[i] !== b[i]) diffs++;
|
|
20591
|
+
const sampleRate = sampleLen > 0 ? diffs / sampleLen : 1;
|
|
20592
|
+
return Math.abs(a.length - b.length) + Math.round(Math.min(a.length, b.length) * sampleRate);
|
|
20206
20593
|
}
|
|
20207
|
-
|
|
20594
|
+
if (a.length > b.length) [a, b] = [b, a];
|
|
20595
|
+
const m = a.length;
|
|
20596
|
+
const n = b.length;
|
|
20597
|
+
let prev = Array.from({ length: m + 1 }, (_, i) => i);
|
|
20598
|
+
let curr = new Array(m + 1);
|
|
20599
|
+
for (let j = 1; j <= n; j++) {
|
|
20600
|
+
curr[0] = j;
|
|
20601
|
+
for (let i = 1; i <= m; i++) {
|
|
20602
|
+
if (a[i - 1] === b[j - 1]) {
|
|
20603
|
+
curr[i] = prev[i - 1];
|
|
20604
|
+
} else {
|
|
20605
|
+
curr[i] = 1 + Math.min(prev[i - 1], prev[i], curr[i - 1]);
|
|
20606
|
+
}
|
|
20607
|
+
}
|
|
20608
|
+
;
|
|
20609
|
+
[prev, curr] = [curr, prev];
|
|
20610
|
+
}
|
|
20611
|
+
return prev[m];
|
|
20208
20612
|
}
|
|
20209
|
-
|
|
20613
|
+
|
|
20614
|
+
// src/roundtrip/markdown-units.ts
|
|
20615
|
+
function splitMarkdownUnits(md2) {
|
|
20210
20616
|
const lines = md2.split("\n");
|
|
20211
|
-
const
|
|
20617
|
+
const units = [];
|
|
20212
20618
|
let i = 0;
|
|
20213
20619
|
while (i < lines.length) {
|
|
20214
20620
|
const line = lines[i];
|
|
@@ -20216,66 +20622,523 @@ function parseMarkdownToBlocks(md2) {
|
|
|
20216
20622
|
i++;
|
|
20217
20623
|
continue;
|
|
20218
20624
|
}
|
|
20219
|
-
|
|
20220
|
-
|
|
20221
|
-
|
|
20222
|
-
|
|
20223
|
-
|
|
20224
|
-
|
|
20225
|
-
|
|
20226
|
-
|
|
20625
|
+
if (line.trim().startsWith("<table>")) {
|
|
20626
|
+
const collected2 = [];
|
|
20627
|
+
let depth = 0;
|
|
20628
|
+
while (i < lines.length) {
|
|
20629
|
+
const l = lines[i];
|
|
20630
|
+
collected2.push(l);
|
|
20631
|
+
depth += (l.match(/<table>/g) || []).length;
|
|
20632
|
+
depth -= (l.match(/<\/table>/g) || []).length;
|
|
20227
20633
|
i++;
|
|
20634
|
+
if (depth <= 0) break;
|
|
20228
20635
|
}
|
|
20229
|
-
|
|
20230
|
-
blocks.push({ type: "code_block", text: codeLines.join("\n"), lang });
|
|
20231
|
-
continue;
|
|
20232
|
-
}
|
|
20233
|
-
if (/^(\*{3,}|-{3,}|_{3,})\s*$/.test(line.trim())) {
|
|
20234
|
-
blocks.push({ type: "hr" });
|
|
20235
|
-
i++;
|
|
20236
|
-
continue;
|
|
20237
|
-
}
|
|
20238
|
-
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
20239
|
-
if (headingMatch) {
|
|
20240
|
-
blocks.push({ type: "heading", text: headingMatch[2].trim(), level: headingMatch[1].length });
|
|
20241
|
-
i++;
|
|
20636
|
+
units.push({ kind: "html-table", raw: collected2.join("\n"), lines: collected2 });
|
|
20242
20637
|
continue;
|
|
20243
20638
|
}
|
|
20244
20639
|
if (line.trimStart().startsWith("|")) {
|
|
20245
|
-
const
|
|
20640
|
+
const collected2 = [];
|
|
20246
20641
|
while (i < lines.length && lines[i].trimStart().startsWith("|")) {
|
|
20247
|
-
|
|
20248
|
-
if (/^[\s|:\-]+$/.test(row)) {
|
|
20249
|
-
i++;
|
|
20250
|
-
continue;
|
|
20251
|
-
}
|
|
20252
|
-
const cells = row.split("|").slice(1, -1).map((c) => c.trim());
|
|
20253
|
-
if (cells.length > 0) tableRows.push(cells);
|
|
20642
|
+
collected2.push(lines[i]);
|
|
20254
20643
|
i++;
|
|
20255
20644
|
}
|
|
20256
|
-
|
|
20645
|
+
units.push({ kind: "gfm-table", raw: collected2.join("\n"), lines: collected2 });
|
|
20257
20646
|
continue;
|
|
20258
20647
|
}
|
|
20259
|
-
if (line.
|
|
20260
|
-
|
|
20261
|
-
|
|
20262
|
-
quoteLines.push(lines[i].replace(/^>\s?/, ""));
|
|
20263
|
-
i++;
|
|
20264
|
-
}
|
|
20265
|
-
for (const ql of quoteLines) {
|
|
20266
|
-
blocks.push({ type: "blockquote", text: ql.trim() || "" });
|
|
20267
|
-
}
|
|
20648
|
+
if (/^-{3,}\s*$/.test(line.trim())) {
|
|
20649
|
+
units.push({ kind: "separator", raw: line.trim(), lines: [line.trim()] });
|
|
20650
|
+
i++;
|
|
20268
20651
|
continue;
|
|
20269
20652
|
}
|
|
20270
|
-
|
|
20271
|
-
|
|
20272
|
-
const indent = Math.floor(listMatch[1].length / 2);
|
|
20273
|
-
const ordered = /\d/.test(listMatch[2]);
|
|
20274
|
-
blocks.push({ type: "list_item", text: listMatch[3].trim(), ordered, indent });
|
|
20653
|
+
if (/^!\[image\]\([^)]*\)\s*$/.test(line.trim())) {
|
|
20654
|
+
units.push({ kind: "image", raw: line.trim(), lines: [line.trim()] });
|
|
20275
20655
|
i++;
|
|
20276
20656
|
continue;
|
|
20277
20657
|
}
|
|
20278
|
-
|
|
20658
|
+
const collected = [];
|
|
20659
|
+
while (i < lines.length && lines[i].trim() && !lines[i].trimStart().startsWith("|") && !lines[i].trim().startsWith("<table>")) {
|
|
20660
|
+
collected.push(lines[i].trim());
|
|
20661
|
+
i++;
|
|
20662
|
+
}
|
|
20663
|
+
units.push({ kind: "text", raw: collected.join("\n"), lines: collected });
|
|
20664
|
+
}
|
|
20665
|
+
return units;
|
|
20666
|
+
}
|
|
20667
|
+
function alignUnits(a, b) {
|
|
20668
|
+
const m = a.length, n = b.length;
|
|
20669
|
+
if (m * n > 4e6) {
|
|
20670
|
+
const result2 = [];
|
|
20671
|
+
let pre = 0;
|
|
20672
|
+
while (pre < m && pre < n && a[pre] === b[pre]) {
|
|
20673
|
+
result2.push([pre, pre]);
|
|
20674
|
+
pre++;
|
|
20675
|
+
}
|
|
20676
|
+
let suf = 0;
|
|
20677
|
+
while (suf < m - pre && suf < n - pre && a[m - 1 - suf] === b[n - 1 - suf]) suf++;
|
|
20678
|
+
const aMid = m - pre - suf, bMid = n - pre - suf;
|
|
20679
|
+
if (aMid === bMid) {
|
|
20680
|
+
for (let i2 = 0; i2 < aMid; i2++) result2.push([pre + i2, pre + i2]);
|
|
20681
|
+
} else {
|
|
20682
|
+
for (let i2 = 0; i2 < aMid; i2++) result2.push([pre + i2, null]);
|
|
20683
|
+
for (let j2 = 0; j2 < bMid; j2++) result2.push([null, pre + j2]);
|
|
20684
|
+
}
|
|
20685
|
+
for (let s = suf - 1; s >= 0; s--) result2.push([m - 1 - s, n - 1 - s]);
|
|
20686
|
+
return result2;
|
|
20687
|
+
}
|
|
20688
|
+
const dp = Array.from({ length: m + 1 }, () => new Int32Array(n + 1));
|
|
20689
|
+
for (let i2 = 1; i2 <= m; i2++) {
|
|
20690
|
+
for (let j2 = 1; j2 <= n; j2++) {
|
|
20691
|
+
dp[i2][j2] = a[i2 - 1] === b[j2 - 1] ? dp[i2 - 1][j2 - 1] + 1 : Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
20692
|
+
}
|
|
20693
|
+
}
|
|
20694
|
+
const matches = [];
|
|
20695
|
+
let i = m, j = n;
|
|
20696
|
+
while (i > 0 && j > 0) {
|
|
20697
|
+
if (a[i - 1] === b[j - 1] && dp[i][j] === dp[i - 1][j - 1] + 1) {
|
|
20698
|
+
matches.push([i - 1, j - 1]);
|
|
20699
|
+
i--;
|
|
20700
|
+
j--;
|
|
20701
|
+
} else if (dp[i - 1][j] >= dp[i][j - 1]) i--;
|
|
20702
|
+
else j--;
|
|
20703
|
+
}
|
|
20704
|
+
matches.reverse();
|
|
20705
|
+
const result = [];
|
|
20706
|
+
let ai = 0, bi = 0;
|
|
20707
|
+
const flushGap = (aEnd, bEnd) => {
|
|
20708
|
+
if (aEnd - ai === bEnd - bi) {
|
|
20709
|
+
while (ai < aEnd) result.push([ai++, bi++]);
|
|
20710
|
+
return;
|
|
20711
|
+
}
|
|
20712
|
+
while (ai < aEnd && bi < bEnd) {
|
|
20713
|
+
const sim = normalizedSimilarity(a[ai], b[bi]);
|
|
20714
|
+
if (sim >= 0.4) {
|
|
20715
|
+
if (aEnd - ai > bEnd - bi && bestSimInRange(a, ai + 1, ai + (aEnd - ai) - (bEnd - bi), b[bi]) > sim) {
|
|
20716
|
+
result.push([ai++, null]);
|
|
20717
|
+
} else if (bEnd - bi > aEnd - ai && bestSimInRange(b, bi + 1, bi + (bEnd - bi) - (aEnd - ai), a[ai]) > sim) {
|
|
20718
|
+
result.push([null, bi++]);
|
|
20719
|
+
} else {
|
|
20720
|
+
result.push([ai++, bi++]);
|
|
20721
|
+
}
|
|
20722
|
+
} else if (aEnd - ai >= bEnd - bi) result.push([ai++, null]);
|
|
20723
|
+
else result.push([null, bi++]);
|
|
20724
|
+
}
|
|
20725
|
+
while (ai < aEnd) result.push([ai++, null]);
|
|
20726
|
+
while (bi < bEnd) result.push([null, bi++]);
|
|
20727
|
+
};
|
|
20728
|
+
for (const [pi, pj] of matches) {
|
|
20729
|
+
flushGap(pi, pj);
|
|
20730
|
+
result.push([ai++, bi++]);
|
|
20731
|
+
}
|
|
20732
|
+
flushGap(m, n);
|
|
20733
|
+
return result;
|
|
20734
|
+
}
|
|
20735
|
+
function bestSimInRange(arr, from, to, target) {
|
|
20736
|
+
let best = 0;
|
|
20737
|
+
for (let k = from; k <= to && k < arr.length; k++) {
|
|
20738
|
+
const s = normalizedSimilarity(arr[k], target);
|
|
20739
|
+
if (s > best) best = s;
|
|
20740
|
+
}
|
|
20741
|
+
return best;
|
|
20742
|
+
}
|
|
20743
|
+
function escapeGfm(text) {
|
|
20744
|
+
return text.replace(/~/g, "\\~");
|
|
20745
|
+
}
|
|
20746
|
+
var HWP_SHAPE_ALT_TEXT_RE = /(?:모서리가 둥근 |둥근 )?(?:사각형|직사각형|정사각형|원|타원|삼각형|이등변 삼각형|직각 삼각형|선|직선|곡선|화살표|굵은 화살표|이중 화살표|오각형|육각형|팔각형|별|[4-8]점별|십자|십자형|구름|구름형|마름모|도넛|평행사변형|사다리꼴|부채꼴|호|반원|물결|번개|하트|빗금|블록 화살표|수식|표|그림|개체|그리기\s?개체|묶음\s?개체|글상자|수식\s?개체|OLE\s?개체)\s?입니다\.?/g;
|
|
20747
|
+
function sanitizeText(text) {
|
|
20748
|
+
let result = mapPuaText(text).replace(/[\u{F0000}-\u{FFFFD}]/gu, "").replace(HWP_SHAPE_ALT_TEXT_RE, "").replace(/ +/g, " ").trim();
|
|
20749
|
+
if (result.length <= 30 && result.includes(" ")) {
|
|
20750
|
+
const tokens = result.split(" ");
|
|
20751
|
+
const koreanSingleCharCount = tokens.filter((t) => t.length === 1 && /[가-ㄱ-ㆎ]/.test(t)).length;
|
|
20752
|
+
if (tokens.length >= 3 && koreanSingleCharCount / tokens.length >= 0.7) {
|
|
20753
|
+
result = tokens.join("");
|
|
20754
|
+
}
|
|
20755
|
+
}
|
|
20756
|
+
return result;
|
|
20757
|
+
}
|
|
20758
|
+
function normForMatch(text) {
|
|
20759
|
+
return sanitizeText(text).replace(/\s+/g, " ").trim();
|
|
20760
|
+
}
|
|
20761
|
+
function unescapeGfm(text) {
|
|
20762
|
+
return text.replace(/\\~/g, "~");
|
|
20763
|
+
}
|
|
20764
|
+
function summarize(text) {
|
|
20765
|
+
const t = text.replace(/\s+/g, " ").trim();
|
|
20766
|
+
return t.length > 80 ? t.slice(0, 77) + "..." : t;
|
|
20767
|
+
}
|
|
20768
|
+
function replicateGfmTable(table) {
|
|
20769
|
+
const { cells, rows: numRows, cols: numCols } = table;
|
|
20770
|
+
if (numRows === 0 || numCols === 0) return null;
|
|
20771
|
+
if (numRows === 1 && numCols === 1) return null;
|
|
20772
|
+
if (numCols === 1) return null;
|
|
20773
|
+
const display = Array.from({ length: numRows }, (_, r) => Array.from({ length: numCols }, (_2, c) => ({ text: "", gridR: r, gridC: c })));
|
|
20774
|
+
const skip = /* @__PURE__ */ new Set();
|
|
20775
|
+
for (let r = 0; r < numRows; r++) {
|
|
20776
|
+
for (let c = 0; c < numCols; c++) {
|
|
20777
|
+
if (skip.has(`${r},${c}`)) continue;
|
|
20778
|
+
const cell = cells[r]?.[c];
|
|
20779
|
+
if (!cell) continue;
|
|
20780
|
+
display[r][c] = {
|
|
20781
|
+
text: escapeGfm(sanitizeText(cell.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>"),
|
|
20782
|
+
gridR: r,
|
|
20783
|
+
gridC: c
|
|
20784
|
+
};
|
|
20785
|
+
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
20786
|
+
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
20787
|
+
if (dr === 0 && dc === 0) continue;
|
|
20788
|
+
if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
|
|
20789
|
+
}
|
|
20790
|
+
}
|
|
20791
|
+
c += cell.colSpan - 1;
|
|
20792
|
+
}
|
|
20793
|
+
}
|
|
20794
|
+
const uniqueRows = [];
|
|
20795
|
+
let pendingLabelRow = null;
|
|
20796
|
+
for (let r = 0; r < display.length; r++) {
|
|
20797
|
+
const row = display[r];
|
|
20798
|
+
if (row.every((cell) => cell.text === "")) continue;
|
|
20799
|
+
const nonEmptyCols = row.filter((cell) => cell.text !== "");
|
|
20800
|
+
const hasSkipInRow = row.some((_, c) => skip.has(`${r},${c}`));
|
|
20801
|
+
if (!hasSkipInRow && nonEmptyCols.length === 1 && row[0].text !== "" && row.slice(1).every((c) => c.text === "")) {
|
|
20802
|
+
if (pendingLabelRow) uniqueRows.push(pendingLabelRow);
|
|
20803
|
+
pendingLabelRow = row;
|
|
20804
|
+
continue;
|
|
20805
|
+
}
|
|
20806
|
+
if (pendingLabelRow) {
|
|
20807
|
+
if (row[0].text === "") row[0] = pendingLabelRow[0];
|
|
20808
|
+
else uniqueRows.push(pendingLabelRow);
|
|
20809
|
+
pendingLabelRow = null;
|
|
20810
|
+
}
|
|
20811
|
+
uniqueRows.push(row);
|
|
20812
|
+
}
|
|
20813
|
+
if (pendingLabelRow) uniqueRows.push(pendingLabelRow);
|
|
20814
|
+
return uniqueRows.length > 0 ? uniqueRows : null;
|
|
20815
|
+
}
|
|
20816
|
+
function parseGfmTable(lines) {
|
|
20817
|
+
const rows = [];
|
|
20818
|
+
for (const line of lines) {
|
|
20819
|
+
const trimmed = line.trim();
|
|
20820
|
+
if (!trimmed.startsWith("|")) continue;
|
|
20821
|
+
const cells = trimmed.split(/(?<!\\)\|/).slice(1, -1).map((c) => c.trim());
|
|
20822
|
+
if (cells.length === 0) continue;
|
|
20823
|
+
if (cells.every((c) => /^:?-{3,}:?$/.test(c))) continue;
|
|
20824
|
+
rows.push(cells);
|
|
20825
|
+
}
|
|
20826
|
+
return rows;
|
|
20827
|
+
}
|
|
20828
|
+
function unescapeGfmCell(text) {
|
|
20829
|
+
return text.replace(/<br\s*\/?>/gi, "\n").replace(/\\\|/g, "|").replace(/\\~/g, "~");
|
|
20830
|
+
}
|
|
20831
|
+
function replicateCellInnerHtml(cell) {
|
|
20832
|
+
if (cell.blocks?.length) {
|
|
20833
|
+
return cell.blocks.map((b) => {
|
|
20834
|
+
if (b.type === "table" && b.table) {
|
|
20835
|
+
const cap = b.table.caption ? sanitizeText(b.table.caption) : "";
|
|
20836
|
+
return (cap ? cap + "<br>" : "") + replicateTableToHtml(b.table);
|
|
20837
|
+
}
|
|
20838
|
+
if (b.type === "image" && b.text) return `<img src="${b.text}" alt="image">`;
|
|
20839
|
+
const t = sanitizeText(b.text ?? "");
|
|
20840
|
+
return t ? t.replace(/\n/g, "<br>") : "";
|
|
20841
|
+
}).filter(Boolean).join("<br>");
|
|
20842
|
+
}
|
|
20843
|
+
return sanitizeText(cell.text).replace(/\n/g, "<br>");
|
|
20844
|
+
}
|
|
20845
|
+
function replicateTableToHtml(table) {
|
|
20846
|
+
const rows = replicateHtmlTable(table);
|
|
20847
|
+
const lines = ["<table>"];
|
|
20848
|
+
for (let r = 0; r < rows.length; r++) {
|
|
20849
|
+
const tag = rows[r].tag;
|
|
20850
|
+
const rowHtml = rows[r].cells.map((cell) => {
|
|
20851
|
+
const attrs = [];
|
|
20852
|
+
if (cell.colSpan > 1) attrs.push(`colspan="${cell.colSpan}"`);
|
|
20853
|
+
if (cell.rowSpan > 1) attrs.push(`rowspan="${cell.rowSpan}"`);
|
|
20854
|
+
const attrStr = attrs.length ? " " + attrs.join(" ") : "";
|
|
20855
|
+
return `<${tag}${attrStr}>${cell.inner}</${tag}>`;
|
|
20856
|
+
});
|
|
20857
|
+
if (rowHtml.length) lines.push(`<tr>${rowHtml.join("")}</tr>`);
|
|
20858
|
+
}
|
|
20859
|
+
lines.push("</table>");
|
|
20860
|
+
return lines.join("\n");
|
|
20861
|
+
}
|
|
20862
|
+
function replicateHtmlTable(table) {
|
|
20863
|
+
const { cells, rows: numRows, cols: numCols } = table;
|
|
20864
|
+
const skip = /* @__PURE__ */ new Set();
|
|
20865
|
+
const result = [];
|
|
20866
|
+
for (let r = 0; r < numRows; r++) {
|
|
20867
|
+
const tag = r === 0 ? "th" : "td";
|
|
20868
|
+
const rowCells = [];
|
|
20869
|
+
for (let c = 0; c < numCols; c++) {
|
|
20870
|
+
if (skip.has(`${r},${c}`)) continue;
|
|
20871
|
+
const cell = cells[r]?.[c];
|
|
20872
|
+
if (!cell) continue;
|
|
20873
|
+
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
20874
|
+
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
20875
|
+
if (dr === 0 && dc === 0) continue;
|
|
20876
|
+
if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
|
|
20877
|
+
}
|
|
20878
|
+
}
|
|
20879
|
+
rowCells.push({
|
|
20880
|
+
inner: replicateCellInnerHtml(cell),
|
|
20881
|
+
colSpan: cell.colSpan,
|
|
20882
|
+
rowSpan: cell.rowSpan,
|
|
20883
|
+
gridR: r,
|
|
20884
|
+
gridC: c
|
|
20885
|
+
});
|
|
20886
|
+
}
|
|
20887
|
+
if (rowCells.length) result.push({ tag, cells: rowCells });
|
|
20888
|
+
}
|
|
20889
|
+
return result;
|
|
20890
|
+
}
|
|
20891
|
+
function parseHtmlTable(raw) {
|
|
20892
|
+
const re = /<(\/?)(table|tr|td|th)((?:"[^"]*"|'[^']*'|[^>"'])*?)>/gi;
|
|
20893
|
+
let depth = 0;
|
|
20894
|
+
let currentRow = null;
|
|
20895
|
+
let cellStart = -1;
|
|
20896
|
+
let cellInfo = null;
|
|
20897
|
+
const rows = [];
|
|
20898
|
+
let m;
|
|
20899
|
+
while ((m = re.exec(raw)) !== null) {
|
|
20900
|
+
const isClose = m[1] === "/";
|
|
20901
|
+
const tag = m[2].toLowerCase();
|
|
20902
|
+
const attrs = m[3] || "";
|
|
20903
|
+
if (tag === "table") {
|
|
20904
|
+
depth += isClose ? -1 : 1;
|
|
20905
|
+
if (depth < 0) return null;
|
|
20906
|
+
continue;
|
|
20907
|
+
}
|
|
20908
|
+
if (depth !== 1) continue;
|
|
20909
|
+
if (tag === "tr") {
|
|
20910
|
+
if (!isClose) currentRow = [];
|
|
20911
|
+
else if (currentRow) {
|
|
20912
|
+
rows.push({ tag: rows.length === 0 ? "th" : "td", cells: currentRow });
|
|
20913
|
+
currentRow = null;
|
|
20914
|
+
}
|
|
20915
|
+
} else {
|
|
20916
|
+
if (!isClose) {
|
|
20917
|
+
const cs = parseInt(attrs.match(/colspan\s*=\s*"(\d+)"/i)?.[1] || "1", 10);
|
|
20918
|
+
const rs = parseInt(attrs.match(/rowspan\s*=\s*"(\d+)"/i)?.[1] || "1", 10);
|
|
20919
|
+
cellStart = m.index + m[0].length;
|
|
20920
|
+
cellInfo = { colSpan: isNaN(cs) ? 1 : cs, rowSpan: isNaN(rs) ? 1 : rs };
|
|
20921
|
+
} else if (cellStart >= 0 && cellInfo && currentRow) {
|
|
20922
|
+
currentRow.push({ inner: raw.slice(cellStart, m.index), colSpan: cellInfo.colSpan, rowSpan: cellInfo.rowSpan });
|
|
20923
|
+
cellStart = -1;
|
|
20924
|
+
cellInfo = null;
|
|
20925
|
+
}
|
|
20926
|
+
}
|
|
20927
|
+
}
|
|
20928
|
+
if (depth !== 0) return null;
|
|
20929
|
+
return rows;
|
|
20930
|
+
}
|
|
20931
|
+
var AUTONUM_PREFIX_RE = /^(?:[0-90-9a-zA-Z가-힣]{1,6}[.)\]:]|[([][0-90-9a-zA-Z가-힣]{1,6}[)\]][.:]?|[ⅰ-ⅹⅠ-Ⅹ①-⑮][.)\]:]?)$/u;
|
|
20932
|
+
function htmlCellInnerToLines(inner) {
|
|
20933
|
+
let hadNonText = false;
|
|
20934
|
+
let work = inner;
|
|
20935
|
+
if (/<table[\s>]/i.test(work)) {
|
|
20936
|
+
hadNonText = true;
|
|
20937
|
+
work = removeNestedTables(work);
|
|
20938
|
+
}
|
|
20939
|
+
if (/<img\s/i.test(work)) {
|
|
20940
|
+
hadNonText = true;
|
|
20941
|
+
work = work.replace(/<img\s(?:"[^"]*"|'[^']*'|[^>"'])*?>/gi, "");
|
|
20942
|
+
}
|
|
20943
|
+
const lines = work.split(/<br\s*\/?>/gi).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
20944
|
+
return { lines, hadNonText };
|
|
20945
|
+
}
|
|
20946
|
+
function extractTopLevelTables(html) {
|
|
20947
|
+
const result = [];
|
|
20948
|
+
let depth = 0;
|
|
20949
|
+
let start = -1;
|
|
20950
|
+
const re = /<(\/?)table(?:[\s>]|>)/gi;
|
|
20951
|
+
let m;
|
|
20952
|
+
while ((m = re.exec(html)) !== null) {
|
|
20953
|
+
if (m[1] !== "/") {
|
|
20954
|
+
if (depth === 0) start = m.index;
|
|
20955
|
+
depth++;
|
|
20956
|
+
} else {
|
|
20957
|
+
depth--;
|
|
20958
|
+
if (depth === 0 && start >= 0) {
|
|
20959
|
+
result.push(html.slice(start, m.index + m[0].length));
|
|
20960
|
+
start = -1;
|
|
20961
|
+
}
|
|
20962
|
+
if (depth < 0) depth = 0;
|
|
20963
|
+
}
|
|
20964
|
+
}
|
|
20965
|
+
return result;
|
|
20966
|
+
}
|
|
20967
|
+
function removeNestedTables(html) {
|
|
20968
|
+
let result = "";
|
|
20969
|
+
let depth = 0;
|
|
20970
|
+
const re = /<(\/?)table(?:[\s>]|>)/gi;
|
|
20971
|
+
let last = 0;
|
|
20972
|
+
let m;
|
|
20973
|
+
while ((m = re.exec(html)) !== null) {
|
|
20974
|
+
if (m[1] !== "/") {
|
|
20975
|
+
if (depth === 0) result += html.slice(last, m.index);
|
|
20976
|
+
depth++;
|
|
20977
|
+
} else {
|
|
20978
|
+
depth--;
|
|
20979
|
+
if (depth === 0) last = m.index + m[0].length;
|
|
20980
|
+
if (depth < 0) depth = 0;
|
|
20981
|
+
}
|
|
20982
|
+
}
|
|
20983
|
+
if (depth === 0) result += html.slice(last);
|
|
20984
|
+
return result;
|
|
20985
|
+
}
|
|
20986
|
+
|
|
20987
|
+
// src/hwpx/generator.ts
|
|
20988
|
+
var NS_SECTION = "http://www.hancom.co.kr/hwpml/2011/section";
|
|
20989
|
+
var NS_PARA = "http://www.hancom.co.kr/hwpml/2011/paragraph";
|
|
20990
|
+
var NS_HEAD = "http://www.hancom.co.kr/hwpml/2011/head";
|
|
20991
|
+
var NS_CORE = "http://www.hancom.co.kr/hwpml/2011/core";
|
|
20992
|
+
var NS_OPF = "http://www.idpf.org/2007/opf/";
|
|
20993
|
+
var NS_HPF = "http://www.hancom.co.kr/schema/2011/hpf";
|
|
20994
|
+
var NS_OCF = "urn:oasis:names:tc:opendocument:xmlns:container";
|
|
20995
|
+
var CHAR_NORMAL = 0;
|
|
20996
|
+
var CHAR_BOLD = 1;
|
|
20997
|
+
var CHAR_ITALIC = 2;
|
|
20998
|
+
var CHAR_BOLD_ITALIC = 3;
|
|
20999
|
+
var CHAR_CODE = 4;
|
|
21000
|
+
var CHAR_H1 = 5;
|
|
21001
|
+
var CHAR_H2 = 6;
|
|
21002
|
+
var CHAR_H3 = 7;
|
|
21003
|
+
var CHAR_H4 = 8;
|
|
21004
|
+
var CHAR_TABLE_HEADER = 9;
|
|
21005
|
+
var CHAR_QUOTE = 10;
|
|
21006
|
+
var PARA_NORMAL = 0;
|
|
21007
|
+
var PARA_H1 = 1;
|
|
21008
|
+
var PARA_H2 = 2;
|
|
21009
|
+
var PARA_H3 = 3;
|
|
21010
|
+
var PARA_H4 = 4;
|
|
21011
|
+
var PARA_CODE = 5;
|
|
21012
|
+
var PARA_QUOTE = 6;
|
|
21013
|
+
var PARA_LIST = 7;
|
|
21014
|
+
var DEFAULT_TEXT_COLOR = "#000000";
|
|
21015
|
+
function resolveTheme(theme) {
|
|
21016
|
+
return {
|
|
21017
|
+
h1: theme?.headingColors?.[1] ?? DEFAULT_TEXT_COLOR,
|
|
21018
|
+
h2: theme?.headingColors?.[2] ?? DEFAULT_TEXT_COLOR,
|
|
21019
|
+
h3: theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,
|
|
21020
|
+
h4: theme?.headingColors?.[4] ?? theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,
|
|
21021
|
+
body: theme?.bodyColor ?? DEFAULT_TEXT_COLOR,
|
|
21022
|
+
quote: theme?.quoteColor ?? DEFAULT_TEXT_COLOR,
|
|
21023
|
+
/** quoteColor가 명시되었는지 — blockquote charPr 분기에 사용 (baseline 호환) */
|
|
21024
|
+
hasQuoteOption: theme?.quoteColor !== void 0,
|
|
21025
|
+
tableHeader: theme?.tableHeaderColor ?? theme?.bodyColor ?? DEFAULT_TEXT_COLOR,
|
|
21026
|
+
tableHeaderBold: !!theme?.tableHeaderBold
|
|
21027
|
+
};
|
|
21028
|
+
}
|
|
21029
|
+
async function markdownToHwpx(markdown, options) {
|
|
21030
|
+
const theme = resolveTheme(options?.theme);
|
|
21031
|
+
const gongmun = options?.gongmun ? resolveGongmun(options.gongmun) : null;
|
|
21032
|
+
const blocks = parseMarkdownToBlocks(markdown);
|
|
21033
|
+
const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
|
|
21034
|
+
const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
|
|
21035
|
+
const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit);
|
|
21036
|
+
const zip = new JSZip6();
|
|
21037
|
+
zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
|
|
21038
|
+
zip.file("META-INF/container.xml", generateContainerXml());
|
|
21039
|
+
zip.file("Contents/content.hpf", generateManifest());
|
|
21040
|
+
zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun, fit?.variants ?? []));
|
|
21041
|
+
zip.file("Contents/section0.xml", sectionXml);
|
|
21042
|
+
zip.file("Preview/PrvText.txt", buildPrvText(blocks));
|
|
21043
|
+
return await zip.generateAsync({ type: "arraybuffer" });
|
|
21044
|
+
}
|
|
21045
|
+
function buildPrvText(blocks) {
|
|
21046
|
+
const lines = [];
|
|
21047
|
+
let bytes = 0;
|
|
21048
|
+
for (const b of blocks) {
|
|
21049
|
+
let text = b.text || (b.rows ? b.rows.map((r) => r.join(" ")).join("\n") : "");
|
|
21050
|
+
if (b.type === "html_table") text = text.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
21051
|
+
if (!text) continue;
|
|
21052
|
+
lines.push(text);
|
|
21053
|
+
bytes += text.length * 3;
|
|
21054
|
+
if (bytes > 1024) break;
|
|
21055
|
+
}
|
|
21056
|
+
return lines.join("\n").slice(0, 1024);
|
|
21057
|
+
}
|
|
21058
|
+
function parseMarkdownToBlocks(md2) {
|
|
21059
|
+
const lines = md2.split("\n");
|
|
21060
|
+
const blocks = [];
|
|
21061
|
+
let i = 0;
|
|
21062
|
+
while (i < lines.length) {
|
|
21063
|
+
const line = lines[i];
|
|
21064
|
+
if (!line.trim()) {
|
|
21065
|
+
i++;
|
|
21066
|
+
continue;
|
|
21067
|
+
}
|
|
21068
|
+
const fenceMatch = line.match(/^(`{3,}|~{3,})(.*)$/);
|
|
21069
|
+
if (fenceMatch) {
|
|
21070
|
+
const fence = fenceMatch[1];
|
|
21071
|
+
const lang = fenceMatch[2].trim();
|
|
21072
|
+
const codeLines = [];
|
|
21073
|
+
i++;
|
|
21074
|
+
while (i < lines.length && !lines[i].startsWith(fence)) {
|
|
21075
|
+
codeLines.push(lines[i]);
|
|
21076
|
+
i++;
|
|
21077
|
+
}
|
|
21078
|
+
if (i < lines.length) i++;
|
|
21079
|
+
blocks.push({ type: "code_block", text: codeLines.join("\n"), lang });
|
|
21080
|
+
continue;
|
|
21081
|
+
}
|
|
21082
|
+
if (/^(\*{3,}|-{3,}|_{3,})\s*$/.test(line.trim())) {
|
|
21083
|
+
blocks.push({ type: "hr" });
|
|
21084
|
+
i++;
|
|
21085
|
+
continue;
|
|
21086
|
+
}
|
|
21087
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
21088
|
+
if (headingMatch) {
|
|
21089
|
+
blocks.push({ type: "heading", text: headingMatch[2].trim(), level: headingMatch[1].length });
|
|
21090
|
+
i++;
|
|
21091
|
+
continue;
|
|
21092
|
+
}
|
|
21093
|
+
if (/^<table[\s>]/i.test(line.trimStart())) {
|
|
21094
|
+
const htmlLines = [];
|
|
21095
|
+
let depth = 0;
|
|
21096
|
+
while (i < lines.length) {
|
|
21097
|
+
const l = lines[i];
|
|
21098
|
+
htmlLines.push(l);
|
|
21099
|
+
depth += (l.match(/<table[\s>]/gi) ?? []).length;
|
|
21100
|
+
depth -= (l.match(/<\/table>/gi) ?? []).length;
|
|
21101
|
+
i++;
|
|
21102
|
+
if (depth <= 0) break;
|
|
21103
|
+
}
|
|
21104
|
+
blocks.push({ type: "html_table", text: htmlLines.join("\n") });
|
|
21105
|
+
continue;
|
|
21106
|
+
}
|
|
21107
|
+
if (line.trimStart().startsWith("|")) {
|
|
21108
|
+
const tableRows = [];
|
|
21109
|
+
while (i < lines.length && lines[i].trimStart().startsWith("|")) {
|
|
21110
|
+
const row = lines[i];
|
|
21111
|
+
if (/^[\s|:\-]+$/.test(row)) {
|
|
21112
|
+
i++;
|
|
21113
|
+
continue;
|
|
21114
|
+
}
|
|
21115
|
+
const cells = row.split("|").slice(1, -1).map((c) => c.trim());
|
|
21116
|
+
if (cells.length > 0) tableRows.push(cells);
|
|
21117
|
+
i++;
|
|
21118
|
+
}
|
|
21119
|
+
if (tableRows.length > 0) blocks.push({ type: "table", rows: tableRows });
|
|
21120
|
+
continue;
|
|
21121
|
+
}
|
|
21122
|
+
if (line.trimStart().startsWith("> ")) {
|
|
21123
|
+
const quoteLines = [];
|
|
21124
|
+
while (i < lines.length && (lines[i].trimStart().startsWith("> ") || lines[i].trimStart().startsWith(">"))) {
|
|
21125
|
+
quoteLines.push(lines[i].replace(/^>\s?/, ""));
|
|
21126
|
+
i++;
|
|
21127
|
+
}
|
|
21128
|
+
for (const ql of quoteLines) {
|
|
21129
|
+
blocks.push({ type: "blockquote", text: ql.trim() || "" });
|
|
21130
|
+
}
|
|
21131
|
+
continue;
|
|
21132
|
+
}
|
|
21133
|
+
const listMatch = line.match(/^(\s*)([-*+]|\d+[.)]) (.+)$/);
|
|
21134
|
+
if (listMatch) {
|
|
21135
|
+
const indent = Math.floor(listMatch[1].length / 2);
|
|
21136
|
+
const ordered = /\d/.test(listMatch[2]);
|
|
21137
|
+
blocks.push({ type: "list_item", text: listMatch[3].trim(), ordered, indent });
|
|
21138
|
+
i++;
|
|
21139
|
+
continue;
|
|
21140
|
+
}
|
|
21141
|
+
blocks.push({ type: "paragraph", text: line.trim() });
|
|
20279
21142
|
i++;
|
|
20280
21143
|
}
|
|
20281
21144
|
return blocks;
|
|
@@ -20322,18 +21185,19 @@ function spanToCharPrId(span) {
|
|
|
20322
21185
|
function escapeXml(text) {
|
|
20323
21186
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
20324
21187
|
}
|
|
20325
|
-
function generateRuns(text, defaultCharPr = CHAR_NORMAL) {
|
|
21188
|
+
function generateRuns(text, defaultCharPr = CHAR_NORMAL, mapCharId) {
|
|
20326
21189
|
const spans = parseInlineMarkdown(text);
|
|
20327
21190
|
return spans.map((span) => {
|
|
20328
|
-
|
|
21191
|
+
let charId = span.code || span.bold || span.italic ? spanToCharPrId(span) : defaultCharPr;
|
|
21192
|
+
if (mapCharId) charId = mapCharId(charId);
|
|
20329
21193
|
return `<hp:run charPrIDRef="${charId}"><hp:t>${escapeXml(span.text)}</hp:t></hp:run>`;
|
|
20330
21194
|
}).join("");
|
|
20331
21195
|
}
|
|
20332
|
-
function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL) {
|
|
21196
|
+
function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL, mapCharId) {
|
|
20333
21197
|
if (paraPrId === PARA_CODE) {
|
|
20334
21198
|
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_CODE}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`;
|
|
20335
21199
|
}
|
|
20336
|
-
const runs = generateRuns(text, charPrId);
|
|
21200
|
+
const runs = generateRuns(text, charPrId, mapCharId);
|
|
20337
21201
|
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0">${runs}</hp:p>`;
|
|
20338
21202
|
}
|
|
20339
21203
|
function headingParaPrId(level) {
|
|
@@ -20373,7 +21237,7 @@ function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_C
|
|
|
20373
21237
|
const boldAttr = bold ? ` bold="1"` : "";
|
|
20374
21238
|
const italicAttr = italic ? ` italic="1"` : "";
|
|
20375
21239
|
const effFont = bold ? 2 : fontId;
|
|
20376
|
-
return ` <hh:charPr id="${id}" height="${height}" textColor="${textColor}" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="
|
|
21240
|
+
return ` <hh:charPr id="${id}" height="${height}" textColor="${textColor}" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="1"${boldAttr}${italicAttr}>
|
|
20377
21241
|
<hh:fontRef hangul="${effFont}" latin="${effFont}" hanja="${effFont}" japanese="${effFont}" other="${effFont}" symbol="${effFont}" user="${effFont}"/>
|
|
20378
21242
|
<hh:ratio hangul="${ratioPct}" latin="${ratioPct}" hanja="${ratioPct}" japanese="100" other="100" symbol="100" user="100"/>
|
|
20379
21243
|
<hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
|
|
@@ -20392,13 +21256,58 @@ function paraPr(id, opts = {}) {
|
|
|
20392
21256
|
<hh:autoSpacing eAsianEng="0" eAsianNum="0"/>
|
|
20393
21257
|
<hh:margin><hc:intent value="${indent}" unit="HWPUNIT"/><hc:left value="${left}" unit="HWPUNIT"/><hc:right value="0" unit="HWPUNIT"/><hc:prev value="${spaceBefore}" unit="HWPUNIT"/><hc:next value="${spaceAfter}" unit="HWPUNIT"/></hh:margin>
|
|
20394
21258
|
<hh:lineSpacing type="PERCENT" value="${lineSpacing}"/>
|
|
20395
|
-
<hh:border borderFillIDRef="
|
|
21259
|
+
<hh:border borderFillIDRef="1" offsetLeft="0" offsetRight="0" offsetTop="0" offsetBottom="0" connect="0" ignoreMargin="0"/>
|
|
20396
21260
|
</hh:paraPr>`;
|
|
20397
21261
|
}
|
|
20398
21262
|
var GONGMUN_LIST_BASE = 8;
|
|
20399
21263
|
var GONGMUN_LIST_LEVELS = 8;
|
|
20400
21264
|
var GONGMUN_CENTER = GONGMUN_LIST_BASE + GONGMUN_LIST_LEVELS;
|
|
20401
|
-
|
|
21265
|
+
var CHAR_VARIANT_BASE = 11;
|
|
21266
|
+
var GONGMUN_BODY_RATIO = 95;
|
|
21267
|
+
function plainRenderText(text) {
|
|
21268
|
+
return parseInlineMarkdown(text).map((s) => s.text).join("");
|
|
21269
|
+
}
|
|
21270
|
+
function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
|
|
21271
|
+
const minRatio = gongmun.autoFitMinRatio;
|
|
21272
|
+
if (minRatio === null || minRatio >= GONGMUN_BODY_RATIO) return null;
|
|
21273
|
+
const pageW = 59528 - mmToHwpunit(gongmun.margins.left) - mmToHwpunit(gongmun.margins.right);
|
|
21274
|
+
const ratioByBlock = /* @__PURE__ */ new Map();
|
|
21275
|
+
const variants = [];
|
|
21276
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
21277
|
+
const block = blocks[i];
|
|
21278
|
+
let text;
|
|
21279
|
+
let firstW;
|
|
21280
|
+
let contW;
|
|
21281
|
+
if (block.type === "list_item" && gongmunList.has(i)) {
|
|
21282
|
+
const { marker, depth } = gongmunList.get(i);
|
|
21283
|
+
const content = plainRenderText(block.text || "");
|
|
21284
|
+
text = marker ? `${marker} ${content}` : content;
|
|
21285
|
+
const { left, indent } = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering);
|
|
21286
|
+
firstW = pageW - left - Math.max(indent, 0);
|
|
21287
|
+
contW = pageW - left - Math.max(-indent, 0);
|
|
21288
|
+
} else if (block.type === "paragraph") {
|
|
21289
|
+
const raw = (block.text || "").trim();
|
|
21290
|
+
if (/^<center>[\s\S]*<\/center>$/i.test(raw)) continue;
|
|
21291
|
+
text = plainRenderText(raw);
|
|
21292
|
+
firstW = contW = pageW;
|
|
21293
|
+
} else {
|
|
21294
|
+
continue;
|
|
21295
|
+
}
|
|
21296
|
+
if (!text) continue;
|
|
21297
|
+
const r = fitRatioForFewerLines(text, firstW, contW, gongmun.bodyHeight, GONGMUN_BODY_RATIO, minRatio);
|
|
21298
|
+
if (r === null) continue;
|
|
21299
|
+
ratioByBlock.set(i, r);
|
|
21300
|
+
if (!variants.includes(r)) variants.push(r);
|
|
21301
|
+
}
|
|
21302
|
+
return ratioByBlock.size > 0 ? { ratioByBlock, variants } : null;
|
|
21303
|
+
}
|
|
21304
|
+
function variantMapper(fit, blockIdx) {
|
|
21305
|
+
const r = fit.ratioByBlock.get(blockIdx);
|
|
21306
|
+
if (r === void 0) return void 0;
|
|
21307
|
+
const vi = fit.variants.indexOf(r);
|
|
21308
|
+
return (id) => id >= 0 && id <= 3 ? CHAR_VARIANT_BASE + vi * 4 + id : id;
|
|
21309
|
+
}
|
|
21310
|
+
function buildCharProperties(theme, gongmun, ratioVariants = []) {
|
|
20402
21311
|
let body = 1e3, code = 900, h1 = 1800, h2 = 1400, h3 = 1200, h4 = 1100;
|
|
20403
21312
|
if (gongmun) {
|
|
20404
21313
|
body = gongmun.bodyHeight;
|
|
@@ -20408,7 +21317,7 @@ function buildCharProperties(theme, gongmun) {
|
|
|
20408
21317
|
h3 = body;
|
|
20409
21318
|
h4 = Math.max(body - 100, 1300);
|
|
20410
21319
|
}
|
|
20411
|
-
const bodyRatio = gongmun ?
|
|
21320
|
+
const bodyRatio = gongmun ? GONGMUN_BODY_RATIO : 100;
|
|
20412
21321
|
const rows = [
|
|
20413
21322
|
charPr(0, body, false, false, 0, theme.body, bodyRatio),
|
|
20414
21323
|
charPr(1, body, true, false, 0, theme.body, bodyRatio),
|
|
@@ -20422,6 +21331,14 @@ function buildCharProperties(theme, gongmun) {
|
|
|
20422
21331
|
charPr(CHAR_TABLE_HEADER, body, theme.tableHeaderBold, false, 0, theme.tableHeader),
|
|
20423
21332
|
charPr(CHAR_QUOTE, body, false, true, 0, theme.quote)
|
|
20424
21333
|
];
|
|
21334
|
+
for (const r of ratioVariants) {
|
|
21335
|
+
rows.push(
|
|
21336
|
+
charPr(rows.length, body, false, false, 0, theme.body, r),
|
|
21337
|
+
charPr(rows.length + 1, body, true, false, 0, theme.body, r),
|
|
21338
|
+
charPr(rows.length + 2, body, false, true, 0, theme.body, r),
|
|
21339
|
+
charPr(rows.length + 3, body, true, true, 0, theme.body, r)
|
|
21340
|
+
);
|
|
21341
|
+
}
|
|
20425
21342
|
return `<hh:charProperties itemCnt="${rows.length}">
|
|
20426
21343
|
${rows.join("\n")}
|
|
20427
21344
|
</hh:charProperties>`;
|
|
@@ -20464,9 +21381,9 @@ ${base2.join("\n")}
|
|
|
20464
21381
|
${base.join("\n")}
|
|
20465
21382
|
</hh:paraProperties>`;
|
|
20466
21383
|
}
|
|
20467
|
-
function generateHeaderXml(theme, gongmun) {
|
|
21384
|
+
function generateHeaderXml(theme, gongmun, ratioVariants = []) {
|
|
20468
21385
|
const bodyFace = gongmun?.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD568\uCD08\uB86C\uBC14\uD0D5";
|
|
20469
|
-
const charPropsXml = buildCharProperties(theme, gongmun);
|
|
21386
|
+
const charPropsXml = buildCharProperties(theme, gongmun, ratioVariants);
|
|
20470
21387
|
const paraPropsXml = buildParaProperties(gongmun);
|
|
20471
21388
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
20472
21389
|
<hh:head xmlns:hh="${NS_HEAD}" xmlns:hp="${NS_PARA}" xmlns:hc="${NS_CORE}" version="1.4" secCnt="1">
|
|
@@ -20522,25 +21439,21 @@ function generateHeaderXml(theme, gongmun) {
|
|
|
20522
21439
|
</hh:fontface>
|
|
20523
21440
|
</hh:fontfaces>
|
|
20524
21441
|
<hh:borderFills itemCnt="2">
|
|
20525
|
-
<hh:borderFill id="
|
|
21442
|
+
<hh:borderFill id="1" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
|
|
20526
21443
|
<hh:slash type="NONE" Crooked="0" isCounter="0"/>
|
|
20527
21444
|
<hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
|
|
20528
21445
|
<hh:leftBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
20529
21446
|
<hh:rightBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
20530
21447
|
<hh:topBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
20531
21448
|
<hh:bottomBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
20532
|
-
<hh:diagonal type="NONE" width="0.1 mm" color="#000000"/>
|
|
20533
|
-
<hh:fillInfo/>
|
|
20534
21449
|
</hh:borderFill>
|
|
20535
|
-
<hh:borderFill id="
|
|
21450
|
+
<hh:borderFill id="2" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
|
|
20536
21451
|
<hh:slash type="NONE" Crooked="0" isCounter="0"/>
|
|
20537
21452
|
<hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
|
|
20538
21453
|
<hh:leftBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
20539
21454
|
<hh:rightBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
20540
21455
|
<hh:topBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
20541
21456
|
<hh:bottomBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
20542
|
-
<hh:diagonal type="NONE" width="0.1 mm" color="#000000"/>
|
|
20543
|
-
<hh:fillInfo/>
|
|
20544
21457
|
</hh:borderFill>
|
|
20545
21458
|
</hh:borderFills>
|
|
20546
21459
|
${charPropsXml}
|
|
@@ -20587,14 +21500,74 @@ function generateTable(rows, theme) {
|
|
|
20587
21500
|
const tdElements = cells.map((cell, colIdx) => {
|
|
20588
21501
|
const runs = generateRuns(cell, headerCharPr);
|
|
20589
21502
|
const p = `<hp:p paraPrIDRef="0" styleIDRef="0">${runs}</hp:p>`;
|
|
20590
|
-
return `<hp:tc name="" header="${isHeaderRow ? 1 : 0}" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="
|
|
21503
|
+
return `<hp:tc name="" header="${isHeaderRow ? 1 : 0}" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="2"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="TOP" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">${p}</hp:subList><hp:cellAddr colAddr="${colIdx}" rowAddr="${rowIdx}"/><hp:cellSpan colSpan="1" rowSpan="1"/><hp:cellSz width="${cellW}" height="${cellH}"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
|
|
20591
21504
|
}).join("");
|
|
20592
21505
|
return `<hp:tr>${tdElements}</hp:tr>`;
|
|
20593
21506
|
}).join("");
|
|
20594
21507
|
const tblInner = `<hp:sz width="${tblW}" widthRelTo="ABSOLUTE" height="${tblH}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="0" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:inMargin left="510" right="510" top="141" bottom="141"/>` + trElements;
|
|
20595
|
-
const tbl = `<hp:tbl id="${tblId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="0" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="
|
|
21508
|
+
const tbl = `<hp:tbl id="${tblId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="0" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="2" noShading="0">${tblInner}</hp:tbl>`;
|
|
20596
21509
|
return `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${tbl}</hp:run></hp:p>`;
|
|
20597
21510
|
}
|
|
21511
|
+
function layoutHtmlRows(rows) {
|
|
21512
|
+
const occupied = /* @__PURE__ */ new Set();
|
|
21513
|
+
const placed = [];
|
|
21514
|
+
let colCnt = 0;
|
|
21515
|
+
for (let r = 0; r < rows.length; r++) {
|
|
21516
|
+
let c = 0;
|
|
21517
|
+
for (const cell of rows[r].cells) {
|
|
21518
|
+
while (occupied.has(`${r},${c}`)) c++;
|
|
21519
|
+
const colSpan = Math.max(1, cell.colSpan);
|
|
21520
|
+
const rowSpan = Math.max(1, cell.rowSpan);
|
|
21521
|
+
placed.push({ r, c, colSpan, rowSpan, inner: cell.inner, isHeader: rows[r].tag === "th" });
|
|
21522
|
+
for (let dr = 0; dr < rowSpan; dr++) {
|
|
21523
|
+
for (let dc = 0; dc < colSpan; dc++) occupied.add(`${r + dr},${c + dc}`);
|
|
21524
|
+
}
|
|
21525
|
+
c += colSpan;
|
|
21526
|
+
colCnt = Math.max(colCnt, c);
|
|
21527
|
+
}
|
|
21528
|
+
}
|
|
21529
|
+
return { placed, rowCnt: rows.length, colCnt };
|
|
21530
|
+
}
|
|
21531
|
+
function unescapeHtml(s) {
|
|
21532
|
+
return s.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&");
|
|
21533
|
+
}
|
|
21534
|
+
function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3) {
|
|
21535
|
+
const rows = parseHtmlTable(rawHtml);
|
|
21536
|
+
if (!rows || rows.length === 0) return null;
|
|
21537
|
+
const { placed, rowCnt, colCnt } = layoutHtmlRows(rows);
|
|
21538
|
+
if (rowCnt === 0 || colCnt === 0) return null;
|
|
21539
|
+
const colW = Math.floor(totalWidth / colCnt);
|
|
21540
|
+
const cellH = 1500;
|
|
21541
|
+
const tblW = colW * colCnt;
|
|
21542
|
+
const tblId = nextTableId();
|
|
21543
|
+
const useHeaderStyle = theme.tableHeader !== theme.body || theme.tableHeaderBold;
|
|
21544
|
+
const tcXmls = placed.map((cell) => {
|
|
21545
|
+
const headerCharPr = cell.isHeader && useHeaderStyle ? CHAR_TABLE_HEADER : CHAR_NORMAL;
|
|
21546
|
+
const { lines } = htmlCellInnerToLines(cell.inner);
|
|
21547
|
+
const paras = lines.map(
|
|
21548
|
+
(line) => `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="${headerCharPr}"><hp:t>${escapeXml(unescapeHtml(line))}</hp:t></hp:run></hp:p>`
|
|
21549
|
+
);
|
|
21550
|
+
let nestedH = 0;
|
|
21551
|
+
for (const nested of extractTopLevelTables(cell.inner)) {
|
|
21552
|
+
const nestedXml = generateHtmlTableXml(nested, theme, Math.max(colW * cell.colSpan - 1020, 4e3));
|
|
21553
|
+
if (nestedXml) {
|
|
21554
|
+
paras.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${nestedXml}</hp:run></hp:p>`);
|
|
21555
|
+
nestedH += (nested.match(/<tr[\s>]/gi) ?? []).length * cellH + 300;
|
|
21556
|
+
}
|
|
21557
|
+
}
|
|
21558
|
+
if (paras.length === 0) {
|
|
21559
|
+
paras.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="${headerCharPr}"><hp:t></hp:t></hp:run></hp:p>`);
|
|
21560
|
+
}
|
|
21561
|
+
const cellHeight = Math.max(cellH * cell.rowSpan, Math.max(lines.length, 1) * 800 + nestedH);
|
|
21562
|
+
return `<hp:tc name="" header="${cell.isHeader ? 1 : 0}" hasMargin="0" protect="0" editable="1" dirty="0" borderFillIDRef="2"><hp:subList id="" textDirection="HORIZONTAL" lineWrap="BREAK" vertAlign="TOP" linkListIDRef="0" linkListNextIDRef="0" textWidth="0" textHeight="0" hasTextRef="0" hasNumRef="0">${paras.join("")}</hp:subList><hp:cellAddr colAddr="${cell.c}" rowAddr="${cell.r}"/><hp:cellSpan colSpan="${cell.colSpan}" rowSpan="${cell.rowSpan}"/><hp:cellSz width="${colW * cell.colSpan}" height="${cellHeight}"/><hp:cellMargin left="141" right="141" top="141" bottom="141"/></hp:tc>`;
|
|
21563
|
+
});
|
|
21564
|
+
const trXmls = [];
|
|
21565
|
+
for (let r = 0; r < rowCnt; r++) {
|
|
21566
|
+
const rowTcs = tcXmls.filter((_, i) => placed[i].r === r);
|
|
21567
|
+
trXmls.push(`<hp:tr>${rowTcs.join("")}</hp:tr>`);
|
|
21568
|
+
}
|
|
21569
|
+
return `<hp:tbl id="${tblId}" zOrder="0" numberingType="TABLE" pageBreak="CELL" repeatHeader="0" rowCnt="${rowCnt}" colCnt="${colCnt}" cellSpacing="0" borderFillIDRef="2" noShading="0"><hp:sz width="${tblW}" widthRelTo="ABSOLUTE" height="${cellH * rowCnt}" heightRelTo="ABSOLUTE" protect="0"/><hp:pos treatAsChar="1" affectLSpacing="0" flowWithText="0" allowOverlap="0" holdAnchorAndSO="0" vertRelTo="PARA" horzRelTo="PARA" vertAlign="TOP" horzAlign="LEFT" vertOffset="0" horzOffset="0"/><hp:outMargin left="0" right="0" top="0" bottom="0"/><hp:inMargin left="510" right="510" top="141" bottom="141"/>` + trXmls.join("") + `</hp:tbl>`;
|
|
21570
|
+
}
|
|
20598
21571
|
function precomputeGongmunList(blocks, gongmun) {
|
|
20599
21572
|
const result = /* @__PURE__ */ new Map();
|
|
20600
21573
|
let i = 0;
|
|
@@ -20618,12 +21591,11 @@ function precomputeGongmunList(blocks, gongmun) {
|
|
|
20618
21591
|
}
|
|
20619
21592
|
return result;
|
|
20620
21593
|
}
|
|
20621
|
-
function blocksToSectionXml(blocks, theme, gongmun) {
|
|
21594
|
+
function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null) {
|
|
20622
21595
|
const paraXmls = [];
|
|
20623
21596
|
let isFirst = true;
|
|
20624
21597
|
const orderedCounters = {};
|
|
20625
21598
|
let prevWasOrdered = false;
|
|
20626
|
-
const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
|
|
20627
21599
|
for (let blockIdx = 0; blockIdx < blocks.length; blockIdx++) {
|
|
20628
21600
|
const block = blocks[blockIdx];
|
|
20629
21601
|
let xml = "";
|
|
@@ -20645,7 +21617,7 @@ function blocksToSectionXml(blocks, theme, gongmun) {
|
|
|
20645
21617
|
if (ctr) {
|
|
20646
21618
|
xml = generateParagraph(ctr[1].trim(), GONGMUN_CENTER);
|
|
20647
21619
|
} else {
|
|
20648
|
-
xml = generateParagraph(block.text || "");
|
|
21620
|
+
xml = generateParagraph(block.text || "", PARA_NORMAL, CHAR_NORMAL, fit ? variantMapper(fit, blockIdx) : void 0);
|
|
20649
21621
|
}
|
|
20650
21622
|
break;
|
|
20651
21623
|
}
|
|
@@ -20669,7 +21641,7 @@ function blocksToSectionXml(blocks, theme, gongmun) {
|
|
|
20669
21641
|
const content = block.text || "";
|
|
20670
21642
|
const text = marker2 ? `${marker2} ${content}` : content;
|
|
20671
21643
|
const listCharPr = gongmun.numbering === "report" && depth === 0 ? CHAR_BOLD : CHAR_NORMAL;
|
|
20672
|
-
xml = generateParagraph(text, GONGMUN_LIST_BASE + depth, listCharPr);
|
|
21644
|
+
xml = generateParagraph(text, GONGMUN_LIST_BASE + depth, listCharPr, fit ? variantMapper(fit, blockIdx) : void 0);
|
|
20673
21645
|
break;
|
|
20674
21646
|
}
|
|
20675
21647
|
const indent = block.indent || 0;
|
|
@@ -20692,80 +21664,52 @@ function blocksToSectionXml(blocks, theme, gongmun) {
|
|
|
20692
21664
|
xml = generateParagraph(indentPrefix + marker + (block.text || ""), PARA_LIST);
|
|
20693
21665
|
break;
|
|
20694
21666
|
}
|
|
20695
|
-
case "hr":
|
|
20696
|
-
xml = `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0"><hp:t>\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500</hp:t></hp:run></hp:p>`;
|
|
20697
|
-
break;
|
|
20698
|
-
case "table":
|
|
20699
|
-
if (block.rows) {
|
|
20700
|
-
if (isFirst) {
|
|
20701
|
-
const secRun = `<hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run>`;
|
|
20702
|
-
paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
|
|
20703
|
-
isFirst = false;
|
|
20704
|
-
}
|
|
20705
|
-
xml = generateTable(block.rows, theme);
|
|
20706
|
-
}
|
|
20707
|
-
break;
|
|
20708
|
-
|
|
20709
|
-
|
|
20710
|
-
|
|
20711
|
-
|
|
20712
|
-
|
|
20713
|
-
|
|
20714
|
-
|
|
20715
|
-
|
|
20716
|
-
|
|
20717
|
-
|
|
20718
|
-
|
|
20719
|
-
|
|
20720
|
-
|
|
20721
|
-
|
|
20722
|
-
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
20723
|
-
<hs:sec xmlns:hs="${NS_SECTION}" xmlns:hp="${NS_PARA}">
|
|
20724
|
-
${paraXmls.join("\n ")}
|
|
20725
|
-
</hs:sec>`;
|
|
20726
|
-
}
|
|
20727
|
-
|
|
20728
|
-
// src/diff/text-diff.ts
|
|
20729
|
-
function similarity(a, b) {
|
|
20730
|
-
if (a === b) return 1;
|
|
20731
|
-
if (!a || !b) return 0;
|
|
20732
|
-
const maxLen = Math.max(a.length, b.length);
|
|
20733
|
-
if (maxLen === 0) return 1;
|
|
20734
|
-
return 1 - levenshtein(a, b) / maxLen;
|
|
20735
|
-
}
|
|
20736
|
-
function normalizedSimilarity(a, b) {
|
|
20737
|
-
return similarity(normalize(a), normalize(b));
|
|
20738
|
-
}
|
|
20739
|
-
function normalize(s) {
|
|
20740
|
-
return s.replace(/\s+/g, " ").trim();
|
|
20741
|
-
}
|
|
20742
|
-
var MAX_LEVENSHTEIN_LEN = 1e4;
|
|
20743
|
-
function levenshtein(a, b) {
|
|
20744
|
-
if (a.length + b.length > MAX_LEVENSHTEIN_LEN) {
|
|
20745
|
-
const sampleLen = Math.min(500, a.length, b.length);
|
|
20746
|
-
let diffs = 0;
|
|
20747
|
-
for (let i = 0; i < sampleLen; i++) if (a[i] !== b[i]) diffs++;
|
|
20748
|
-
const sampleRate = sampleLen > 0 ? diffs / sampleLen : 1;
|
|
20749
|
-
return Math.abs(a.length - b.length) + Math.round(Math.min(a.length, b.length) * sampleRate);
|
|
20750
|
-
}
|
|
20751
|
-
if (a.length > b.length) [a, b] = [b, a];
|
|
20752
|
-
const m = a.length;
|
|
20753
|
-
const n = b.length;
|
|
20754
|
-
let prev = Array.from({ length: m + 1 }, (_, i) => i);
|
|
20755
|
-
let curr = new Array(m + 1);
|
|
20756
|
-
for (let j = 1; j <= n; j++) {
|
|
20757
|
-
curr[0] = j;
|
|
20758
|
-
for (let i = 1; i <= m; i++) {
|
|
20759
|
-
if (a[i - 1] === b[j - 1]) {
|
|
20760
|
-
curr[i] = prev[i - 1];
|
|
20761
|
-
} else {
|
|
20762
|
-
curr[i] = 1 + Math.min(prev[i - 1], prev[i], curr[i - 1]);
|
|
21667
|
+
case "hr":
|
|
21668
|
+
xml = `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0"><hp:t>\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500</hp:t></hp:run></hp:p>`;
|
|
21669
|
+
break;
|
|
21670
|
+
case "table":
|
|
21671
|
+
if (block.rows) {
|
|
21672
|
+
if (isFirst) {
|
|
21673
|
+
const secRun = `<hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run>`;
|
|
21674
|
+
paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
|
|
21675
|
+
isFirst = false;
|
|
21676
|
+
}
|
|
21677
|
+
xml = generateTable(block.rows, theme);
|
|
21678
|
+
}
|
|
21679
|
+
break;
|
|
21680
|
+
case "html_table": {
|
|
21681
|
+
const tbl = generateHtmlTableXml(block.text || "", theme);
|
|
21682
|
+
if (tbl) {
|
|
21683
|
+
if (isFirst) {
|
|
21684
|
+
const secRun = `<hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run>`;
|
|
21685
|
+
paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
|
|
21686
|
+
isFirst = false;
|
|
21687
|
+
}
|
|
21688
|
+
xml = `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${tbl}</hp:run></hp:p>`;
|
|
21689
|
+
} else {
|
|
21690
|
+
const plain = (block.text || "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
21691
|
+
xml = plain ? generateParagraph(plain) : "";
|
|
21692
|
+
}
|
|
21693
|
+
break;
|
|
20763
21694
|
}
|
|
20764
21695
|
}
|
|
20765
|
-
;
|
|
20766
|
-
|
|
21696
|
+
if (!xml) continue;
|
|
21697
|
+
if (isFirst && block.type !== "table") {
|
|
21698
|
+
xml = xml.replace(
|
|
21699
|
+
/<hp:run charPrIDRef="(\d+)">/,
|
|
21700
|
+
`<hp:run charPrIDRef="$1">${generateSecPr(gongmun)}`
|
|
21701
|
+
);
|
|
21702
|
+
isFirst = false;
|
|
21703
|
+
}
|
|
21704
|
+
paraXmls.push(xml);
|
|
20767
21705
|
}
|
|
20768
|
-
|
|
21706
|
+
if (paraXmls.length === 0) {
|
|
21707
|
+
paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run></hp:p>`);
|
|
21708
|
+
}
|
|
21709
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
21710
|
+
<hs:sec xmlns:hs="${NS_SECTION}" xmlns:hp="${NS_PARA}">
|
|
21711
|
+
${paraXmls.join("\n ")}
|
|
21712
|
+
</hs:sec>`;
|
|
20769
21713
|
}
|
|
20770
21714
|
|
|
20771
21715
|
// src/diff/compare.ts
|
|
@@ -20885,320 +21829,251 @@ function diffTableCells(a, b) {
|
|
|
20885
21829
|
const maxRows = Math.max(a.rows, b.rows);
|
|
20886
21830
|
const maxCols = Math.max(a.cols, b.cols);
|
|
20887
21831
|
const result = [];
|
|
20888
|
-
for (let r = 0; r < maxRows; r++) {
|
|
20889
|
-
const row = [];
|
|
20890
|
-
for (let c = 0; c < maxCols; c++) {
|
|
20891
|
-
const cellA = r < a.rows && c < a.cols ? a.cells[r][c].text : void 0;
|
|
20892
|
-
const cellB = r < b.rows && c < b.cols ? b.cells[r][c].text : void 0;
|
|
20893
|
-
let type;
|
|
20894
|
-
if (cellA === void 0) type = "added";
|
|
20895
|
-
else if (cellB === void 0) type = "removed";
|
|
20896
|
-
else if (cellA === cellB) type = "unchanged";
|
|
20897
|
-
else type = "modified";
|
|
20898
|
-
row.push({ type, before: cellA, after: cellB });
|
|
20899
|
-
}
|
|
20900
|
-
result.push(row);
|
|
20901
|
-
}
|
|
20902
|
-
return result;
|
|
20903
|
-
}
|
|
20904
|
-
|
|
20905
|
-
// src/roundtrip/patcher.ts
|
|
20906
|
-
import JSZip7 from "jszip";
|
|
20907
|
-
|
|
20908
|
-
// src/roundtrip/markdown-units.ts
|
|
20909
|
-
function splitMarkdownUnits(md2) {
|
|
20910
|
-
const lines = md2.split("\n");
|
|
20911
|
-
const units = [];
|
|
20912
|
-
let i = 0;
|
|
20913
|
-
while (i < lines.length) {
|
|
20914
|
-
const line = lines[i];
|
|
20915
|
-
if (!line.trim()) {
|
|
20916
|
-
i++;
|
|
20917
|
-
continue;
|
|
20918
|
-
}
|
|
20919
|
-
if (line.trim().startsWith("<table>")) {
|
|
20920
|
-
const collected2 = [];
|
|
20921
|
-
let depth = 0;
|
|
20922
|
-
while (i < lines.length) {
|
|
20923
|
-
const l = lines[i];
|
|
20924
|
-
collected2.push(l);
|
|
20925
|
-
depth += (l.match(/<table>/g) || []).length;
|
|
20926
|
-
depth -= (l.match(/<\/table>/g) || []).length;
|
|
20927
|
-
i++;
|
|
20928
|
-
if (depth <= 0) break;
|
|
20929
|
-
}
|
|
20930
|
-
units.push({ kind: "html-table", raw: collected2.join("\n"), lines: collected2 });
|
|
20931
|
-
continue;
|
|
20932
|
-
}
|
|
20933
|
-
if (line.trimStart().startsWith("|")) {
|
|
20934
|
-
const collected2 = [];
|
|
20935
|
-
while (i < lines.length && lines[i].trimStart().startsWith("|")) {
|
|
20936
|
-
collected2.push(lines[i]);
|
|
20937
|
-
i++;
|
|
20938
|
-
}
|
|
20939
|
-
units.push({ kind: "gfm-table", raw: collected2.join("\n"), lines: collected2 });
|
|
20940
|
-
continue;
|
|
20941
|
-
}
|
|
20942
|
-
if (/^-{3,}\s*$/.test(line.trim())) {
|
|
20943
|
-
units.push({ kind: "separator", raw: line.trim(), lines: [line.trim()] });
|
|
20944
|
-
i++;
|
|
20945
|
-
continue;
|
|
20946
|
-
}
|
|
20947
|
-
if (/^!\[image\]\([^)]*\)\s*$/.test(line.trim())) {
|
|
20948
|
-
units.push({ kind: "image", raw: line.trim(), lines: [line.trim()] });
|
|
20949
|
-
i++;
|
|
20950
|
-
continue;
|
|
20951
|
-
}
|
|
20952
|
-
const collected = [];
|
|
20953
|
-
while (i < lines.length && lines[i].trim() && !lines[i].trimStart().startsWith("|") && !lines[i].trim().startsWith("<table>")) {
|
|
20954
|
-
collected.push(lines[i].trim());
|
|
20955
|
-
i++;
|
|
20956
|
-
}
|
|
20957
|
-
units.push({ kind: "text", raw: collected.join("\n"), lines: collected });
|
|
20958
|
-
}
|
|
20959
|
-
return units;
|
|
20960
|
-
}
|
|
20961
|
-
function escapeGfm(text) {
|
|
20962
|
-
return text.replace(/~/g, "\\~");
|
|
20963
|
-
}
|
|
20964
|
-
var HWP_SHAPE_ALT_TEXT_RE = /(?:모서리가 둥근 |둥근 )?(?:사각형|직사각형|정사각형|원|타원|삼각형|이등변 삼각형|직각 삼각형|선|직선|곡선|화살표|굵은 화살표|이중 화살표|오각형|육각형|팔각형|별|[4-8]점별|십자|십자형|구름|구름형|마름모|도넛|평행사변형|사다리꼴|부채꼴|호|반원|물결|번개|하트|빗금|블록 화살표|수식|표|그림|개체|그리기\s?개체|묶음\s?개체|글상자|수식\s?개체|OLE\s?개체)\s?입니다\.?/g;
|
|
20965
|
-
function sanitizeText(text) {
|
|
20966
|
-
let result = mapPuaText(text).replace(/[\u{F0000}-\u{FFFFD}]/gu, "").replace(HWP_SHAPE_ALT_TEXT_RE, "").replace(/ +/g, " ").trim();
|
|
20967
|
-
if (result.length <= 30 && result.includes(" ")) {
|
|
20968
|
-
const tokens = result.split(" ");
|
|
20969
|
-
const koreanSingleCharCount = tokens.filter((t) => t.length === 1 && /[가-ㄱ-ㆎ]/.test(t)).length;
|
|
20970
|
-
if (tokens.length >= 3 && koreanSingleCharCount / tokens.length >= 0.7) {
|
|
20971
|
-
result = tokens.join("");
|
|
20972
|
-
}
|
|
20973
|
-
}
|
|
20974
|
-
return result;
|
|
20975
|
-
}
|
|
20976
|
-
function normForMatch(text) {
|
|
20977
|
-
return sanitizeText(text).replace(/\s+/g, " ").trim();
|
|
20978
|
-
}
|
|
20979
|
-
function unescapeGfm(text) {
|
|
20980
|
-
return text.replace(/\\~/g, "~");
|
|
20981
|
-
}
|
|
20982
|
-
function summarize(text) {
|
|
20983
|
-
const t = text.replace(/\s+/g, " ").trim();
|
|
20984
|
-
return t.length > 80 ? t.slice(0, 77) + "..." : t;
|
|
20985
|
-
}
|
|
20986
|
-
function replicateGfmTable(table) {
|
|
20987
|
-
const { cells, rows: numRows, cols: numCols } = table;
|
|
20988
|
-
if (numRows === 0 || numCols === 0) return null;
|
|
20989
|
-
if (numRows === 1 && numCols === 1) return null;
|
|
20990
|
-
if (numCols === 1) return null;
|
|
20991
|
-
const display = Array.from({ length: numRows }, (_, r) => Array.from({ length: numCols }, (_2, c) => ({ text: "", gridR: r, gridC: c })));
|
|
20992
|
-
const skip = /* @__PURE__ */ new Set();
|
|
20993
|
-
for (let r = 0; r < numRows; r++) {
|
|
20994
|
-
for (let c = 0; c < numCols; c++) {
|
|
20995
|
-
if (skip.has(`${r},${c}`)) continue;
|
|
20996
|
-
const cell = cells[r]?.[c];
|
|
20997
|
-
if (!cell) continue;
|
|
20998
|
-
display[r][c] = {
|
|
20999
|
-
text: escapeGfm(sanitizeText(cell.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>"),
|
|
21000
|
-
gridR: r,
|
|
21001
|
-
gridC: c
|
|
21002
|
-
};
|
|
21003
|
-
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
21004
|
-
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
21005
|
-
if (dr === 0 && dc === 0) continue;
|
|
21006
|
-
if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
|
|
21007
|
-
}
|
|
21008
|
-
}
|
|
21009
|
-
c += cell.colSpan - 1;
|
|
21010
|
-
}
|
|
21011
|
-
}
|
|
21012
|
-
const uniqueRows = [];
|
|
21013
|
-
let pendingLabelRow = null;
|
|
21014
|
-
for (let r = 0; r < display.length; r++) {
|
|
21015
|
-
const row = display[r];
|
|
21016
|
-
if (row.every((cell) => cell.text === "")) continue;
|
|
21017
|
-
const nonEmptyCols = row.filter((cell) => cell.text !== "");
|
|
21018
|
-
const hasSkipInRow = row.some((_, c) => skip.has(`${r},${c}`));
|
|
21019
|
-
if (!hasSkipInRow && nonEmptyCols.length === 1 && row[0].text !== "" && row.slice(1).every((c) => c.text === "")) {
|
|
21020
|
-
if (pendingLabelRow) uniqueRows.push(pendingLabelRow);
|
|
21021
|
-
pendingLabelRow = row;
|
|
21022
|
-
continue;
|
|
21023
|
-
}
|
|
21024
|
-
if (pendingLabelRow) {
|
|
21025
|
-
if (row[0].text === "") row[0] = pendingLabelRow[0];
|
|
21026
|
-
else uniqueRows.push(pendingLabelRow);
|
|
21027
|
-
pendingLabelRow = null;
|
|
21028
|
-
}
|
|
21029
|
-
uniqueRows.push(row);
|
|
21030
|
-
}
|
|
21031
|
-
if (pendingLabelRow) uniqueRows.push(pendingLabelRow);
|
|
21032
|
-
return uniqueRows.length > 0 ? uniqueRows : null;
|
|
21033
|
-
}
|
|
21034
|
-
function parseGfmTable(lines) {
|
|
21035
|
-
const rows = [];
|
|
21036
|
-
for (const line of lines) {
|
|
21037
|
-
const trimmed = line.trim();
|
|
21038
|
-
if (!trimmed.startsWith("|")) continue;
|
|
21039
|
-
const cells = trimmed.split(/(?<!\\)\|/).slice(1, -1).map((c) => c.trim());
|
|
21040
|
-
if (cells.length === 0) continue;
|
|
21041
|
-
if (cells.every((c) => /^:?-{3,}:?$/.test(c))) continue;
|
|
21042
|
-
rows.push(cells);
|
|
21043
|
-
}
|
|
21044
|
-
return rows;
|
|
21045
|
-
}
|
|
21046
|
-
function unescapeGfmCell(text) {
|
|
21047
|
-
return text.replace(/<br\s*\/?>/gi, "\n").replace(/\\\|/g, "|").replace(/\\~/g, "~");
|
|
21048
|
-
}
|
|
21049
|
-
function replicateCellInnerHtml(cell) {
|
|
21050
|
-
if (cell.blocks?.length) {
|
|
21051
|
-
return cell.blocks.map((b) => {
|
|
21052
|
-
if (b.type === "table" && b.table) {
|
|
21053
|
-
const cap = b.table.caption ? sanitizeText(b.table.caption) : "";
|
|
21054
|
-
return (cap ? cap + "<br>" : "") + replicateTableToHtml(b.table);
|
|
21055
|
-
}
|
|
21056
|
-
if (b.type === "image" && b.text) return `<img src="${b.text}" alt="image">`;
|
|
21057
|
-
const t = sanitizeText(b.text ?? "");
|
|
21058
|
-
return t ? t.replace(/\n/g, "<br>") : "";
|
|
21059
|
-
}).filter(Boolean).join("<br>");
|
|
21060
|
-
}
|
|
21061
|
-
return sanitizeText(cell.text).replace(/\n/g, "<br>");
|
|
21062
|
-
}
|
|
21063
|
-
function replicateTableToHtml(table) {
|
|
21064
|
-
const rows = replicateHtmlTable(table);
|
|
21065
|
-
const lines = ["<table>"];
|
|
21066
|
-
for (let r = 0; r < rows.length; r++) {
|
|
21067
|
-
const tag = rows[r].tag;
|
|
21068
|
-
const rowHtml = rows[r].cells.map((cell) => {
|
|
21069
|
-
const attrs = [];
|
|
21070
|
-
if (cell.colSpan > 1) attrs.push(`colspan="${cell.colSpan}"`);
|
|
21071
|
-
if (cell.rowSpan > 1) attrs.push(`rowspan="${cell.rowSpan}"`);
|
|
21072
|
-
const attrStr = attrs.length ? " " + attrs.join(" ") : "";
|
|
21073
|
-
return `<${tag}${attrStr}>${cell.inner}</${tag}>`;
|
|
21074
|
-
});
|
|
21075
|
-
if (rowHtml.length) lines.push(`<tr>${rowHtml.join("")}</tr>`);
|
|
21076
|
-
}
|
|
21077
|
-
lines.push("</table>");
|
|
21078
|
-
return lines.join("\n");
|
|
21079
|
-
}
|
|
21080
|
-
function replicateHtmlTable(table) {
|
|
21081
|
-
const { cells, rows: numRows, cols: numCols } = table;
|
|
21082
|
-
const skip = /* @__PURE__ */ new Set();
|
|
21083
|
-
const result = [];
|
|
21084
|
-
for (let r = 0; r < numRows; r++) {
|
|
21085
|
-
const tag = r === 0 ? "th" : "td";
|
|
21086
|
-
const rowCells = [];
|
|
21087
|
-
for (let c = 0; c < numCols; c++) {
|
|
21088
|
-
if (skip.has(`${r},${c}`)) continue;
|
|
21089
|
-
const cell = cells[r]?.[c];
|
|
21090
|
-
if (!cell) continue;
|
|
21091
|
-
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
21092
|
-
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
21093
|
-
if (dr === 0 && dc === 0) continue;
|
|
21094
|
-
if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
|
|
21095
|
-
}
|
|
21096
|
-
}
|
|
21097
|
-
rowCells.push({
|
|
21098
|
-
inner: replicateCellInnerHtml(cell),
|
|
21099
|
-
colSpan: cell.colSpan,
|
|
21100
|
-
rowSpan: cell.rowSpan,
|
|
21101
|
-
gridR: r,
|
|
21102
|
-
gridC: c
|
|
21103
|
-
});
|
|
21832
|
+
for (let r = 0; r < maxRows; r++) {
|
|
21833
|
+
const row = [];
|
|
21834
|
+
for (let c = 0; c < maxCols; c++) {
|
|
21835
|
+
const cellA = r < a.rows && c < a.cols ? a.cells[r][c].text : void 0;
|
|
21836
|
+
const cellB = r < b.rows && c < b.cols ? b.cells[r][c].text : void 0;
|
|
21837
|
+
let type;
|
|
21838
|
+
if (cellA === void 0) type = "added";
|
|
21839
|
+
else if (cellB === void 0) type = "removed";
|
|
21840
|
+
else if (cellA === cellB) type = "unchanged";
|
|
21841
|
+
else type = "modified";
|
|
21842
|
+
row.push({ type, before: cellA, after: cellB });
|
|
21104
21843
|
}
|
|
21105
|
-
|
|
21844
|
+
result.push(row);
|
|
21106
21845
|
}
|
|
21107
21846
|
return result;
|
|
21108
21847
|
}
|
|
21109
|
-
|
|
21110
|
-
|
|
21111
|
-
|
|
21112
|
-
|
|
21113
|
-
|
|
21114
|
-
|
|
21115
|
-
|
|
21116
|
-
|
|
21117
|
-
|
|
21118
|
-
|
|
21119
|
-
|
|
21120
|
-
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
|
|
21124
|
-
|
|
21848
|
+
|
|
21849
|
+
// src/roundtrip/patcher.ts
|
|
21850
|
+
import JSZip7 from "jszip";
|
|
21851
|
+
|
|
21852
|
+
// src/roundtrip/table-rows.ts
|
|
21853
|
+
var ROW_OBJECT_RE = /<(?:[A-Za-z0-9_]+:)?(?:tbl|pic|equation|ole|container|shape|drawingObject|drawText|video|chart|fieldBegin|fieldEnd|ctrl)\b/;
|
|
21854
|
+
var TAG_AT_RE = /<[A-Za-z0-9_:]+(?:"[^"]*"|'[^']*'|[^>"'])*>/y;
|
|
21855
|
+
function patchTableRows(input) {
|
|
21856
|
+
const { table, scanTable, ctx, skip, origKeys, editedKeys } = input;
|
|
21857
|
+
const xml = ctx.scans[scanTable.sectionIndex]?.xml;
|
|
21858
|
+
if (!xml) return skip("\uC139\uC158 XML \uB9E4\uD551 \uC2E4\uD328");
|
|
21859
|
+
const numRows = table.rows;
|
|
21860
|
+
if (origKeys.length !== numRows) return skip("\uD45C \uD589 \uC88C\uD45C \uBD88\uC77C\uCE58 \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
|
|
21861
|
+
if (scanTable.rows.length !== numRows || scanTable.rowRanges.length !== numRows) {
|
|
21862
|
+
return skip("\uD45C \uD589 \uAD6C\uC870 \uC88C\uD45C \uBD88\uC77C\uCE58 (\uBE48 \uD589/\uBCD1\uD569 \uC18C\uC2E4) \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
|
|
21863
|
+
}
|
|
21864
|
+
for (let r = 0; r < numRows; r++) {
|
|
21865
|
+
if (scanTable.rows[r].some((c) => c.rowAddr !== r)) {
|
|
21866
|
+
return skip("\uD589 \uC8FC\uC18C \uBE44\uC5F0\uC18D \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
|
|
21125
21867
|
}
|
|
21126
|
-
|
|
21127
|
-
|
|
21128
|
-
|
|
21129
|
-
|
|
21130
|
-
|
|
21131
|
-
|
|
21868
|
+
}
|
|
21869
|
+
const allCells = scanTable.rows.flat();
|
|
21870
|
+
const explicitAddr = (c) => !!c.addrTagRange && /\browAddr\s*=\s*"/.test(xml.slice(c.addrTagRange.start, c.addrTagRange.end));
|
|
21871
|
+
const explicitCount = allCells.filter(explicitAddr).length;
|
|
21872
|
+
if (explicitCount !== 0 && explicitCount !== allCells.length) {
|
|
21873
|
+
return skip("\uC140 \uC8FC\uC18C(cellAddr) \uD45C\uAE30 \uD63C\uC7AC \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
|
|
21874
|
+
}
|
|
21875
|
+
const hasExplicitAddr = explicitCount > 0;
|
|
21876
|
+
const pairs = alignUnits(origKeys, editedKeys);
|
|
21877
|
+
const seq = [];
|
|
21878
|
+
let lastOrig = -1;
|
|
21879
|
+
for (const [oi, ei] of pairs) {
|
|
21880
|
+
if (oi !== null && ei !== null) {
|
|
21881
|
+
seq.push({ kind: "keep", oi, ei });
|
|
21882
|
+
lastOrig = oi;
|
|
21883
|
+
} else if (oi !== null) {
|
|
21884
|
+
seq.push({ kind: "del", oi });
|
|
21885
|
+
lastOrig = oi;
|
|
21886
|
+
} else if (ei !== null) seq.push({ kind: "ins", ei, insertAt: lastOrig + 1 });
|
|
21887
|
+
}
|
|
21888
|
+
const dels = seq.filter((e) => e.kind === "del");
|
|
21889
|
+
const inss = seq.filter((e) => e.kind === "ins");
|
|
21890
|
+
const keeps = seq.filter((e) => e.kind === "keep");
|
|
21891
|
+
if (dels.length === 0 && inss.length === 0) {
|
|
21892
|
+
return skip("\uD45C \uD589 \uC815\uB82C \uC2E4\uD328 \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
|
|
21893
|
+
}
|
|
21894
|
+
if (keeps.length + inss.length === 0) return skip("\uBAA8\uB4E0 \uD589 \uC0AD\uC81C\uB294 \uBBF8\uC9C0\uC6D0");
|
|
21895
|
+
if (keeps.length === 0) return skip("\uD589 \uC804\uBA74 \uAD50\uCCB4 \u2014 \uC11C\uC2DD \uAE30\uC900 \uD589\uC774 \uC5C6\uC5B4 \uBBF8\uC9C0\uC6D0");
|
|
21896
|
+
const spans = allCells.filter((c) => (c.rowSpan ?? 1) > 1);
|
|
21897
|
+
for (const d of dels) {
|
|
21898
|
+
if (spans.some((s) => s.rowAddr <= d.oi && s.rowAddr + s.rowSpan > d.oi)) {
|
|
21899
|
+
return skip(`\uD45C ${d.oi + 1}\uD589 \uC0AD\uC81C\uAC00 \uC138\uB85C \uBCD1\uD569\uACFC \uACB9\uCE68 \u2014 \uBBF8\uC9C0\uC6D0`);
|
|
21900
|
+
}
|
|
21901
|
+
}
|
|
21902
|
+
for (const ins of inss) {
|
|
21903
|
+
const p = ins.insertAt;
|
|
21904
|
+
if (spans.some((s) => s.rowAddr < p && s.rowAddr + s.rowSpan > p)) {
|
|
21905
|
+
return skip("\uD589 \uC0BD\uC785 \uC704\uCE58\uAC00 \uC138\uB85C \uBCD1\uD569 \uB0B4\uBD80 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
21906
|
+
}
|
|
21907
|
+
}
|
|
21908
|
+
for (const d of dels) {
|
|
21909
|
+
const rr = scanTable.rowRanges[d.oi];
|
|
21910
|
+
if (ROW_OBJECT_RE.test(xml.slice(rr.start, rr.end))) {
|
|
21911
|
+
return skip(`\uD45C ${d.oi + 1}\uD589\uC5D0 \uAC1C\uCCB4(\uC911\uCCA9\uD45C/\uC774\uBBF8\uC9C0/\uD544\uB4DC) \uD3EC\uD568 \u2014 \uD589 \uC0AD\uC81C \uBBF8\uC9C0\uC6D0`);
|
|
21912
|
+
}
|
|
21913
|
+
}
|
|
21914
|
+
const keptSet = new Set(keeps.map((k) => k.oi));
|
|
21915
|
+
const insertPlans = [];
|
|
21916
|
+
for (const ins of inss) {
|
|
21917
|
+
const p = ins.insertAt;
|
|
21918
|
+
const kept = [...keptSet].sort((a, b) => a - b);
|
|
21919
|
+
let template = -1;
|
|
21920
|
+
for (const k of kept) {
|
|
21921
|
+
if (k < p) template = k;
|
|
21922
|
+
}
|
|
21923
|
+
if (template <= 0 && p >= 1) {
|
|
21924
|
+
const following = kept.find((k) => k >= 1);
|
|
21925
|
+
if (following !== void 0) template = following;
|
|
21926
|
+
}
|
|
21927
|
+
if (template < 0) template = kept[0];
|
|
21928
|
+
const cells = input.editedCells(ins.ei);
|
|
21929
|
+
if (!cells) return skip("\uC0BD\uC785 \uD589\uC5D0 \uC774\uBBF8\uC9C0/\uC911\uCCA9\uD45C \uD3EC\uD568 \u2014 \uD589 \uCD94\uAC00 \uBBF8\uC9C0\uC6D0");
|
|
21930
|
+
for (const cell of cells) {
|
|
21931
|
+
const unstable = cell.lines.find((l) => sanitizeText(l) !== l);
|
|
21932
|
+
if (unstable !== void 0) return skip("\uC0BD\uC785 \uD589\uC5D0 \uACF5\uBC31 \uC815\uADDC\uD654 \uBD88\uC548\uC815 \uD14D\uC2A4\uD2B8 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
21933
|
+
}
|
|
21934
|
+
const tmplCells = scanTable.rows[template];
|
|
21935
|
+
const rr = scanTable.rowRanges[template];
|
|
21936
|
+
if (ROW_OBJECT_RE.test(xml.slice(rr.start, rr.end))) {
|
|
21937
|
+
return skip("\uC11C\uC2DD \uAE30\uC900 \uD589\uC5D0 \uAC1C\uCCB4(\uC911\uCCA9\uD45C/\uC774\uBBF8\uC9C0/\uD544\uB4DC) \uD3EC\uD568 \u2014 \uD589 \uCD94\uAC00 \uBBF8\uC9C0\uC6D0");
|
|
21938
|
+
}
|
|
21939
|
+
if (tmplCells.some((c) => c.rowSpan > 1)) return skip("\uC11C\uC2DD \uAE30\uC900 \uD589\uC5D0 \uC138\uB85C \uBCD1\uD569 \u2014 \uD589 \uCD94\uAC00 \uBBF8\uC9C0\uC6D0");
|
|
21940
|
+
const tmplWidth = tmplCells.reduce((s, c) => s + c.colSpan, 0);
|
|
21941
|
+
if (tmplWidth !== table.cols) return skip("\uC11C\uC2DD \uAE30\uC900 \uD589\uC774 \uACA9\uC790 \uC804\uCCB4\uB97C \uB36E\uC9C0 \uC54A\uC74C \u2014 \uD589 \uCD94\uAC00 \uBBF8\uC9C0\uC6D0");
|
|
21942
|
+
if (cells.length !== tmplCells.length) {
|
|
21943
|
+
return skip(`\uC0BD\uC785 \uD589 \uC140 \uC218(${cells.length}) \u2260 \uAE30\uC900 \uD589 \uC140 \uC218(${tmplCells.length}) \u2014 \uBBF8\uC9C0\uC6D0`);
|
|
21944
|
+
}
|
|
21945
|
+
for (let i = 0; i < cells.length; i++) {
|
|
21946
|
+
if (cells[i].rowSpan !== 1 || cells[i].colSpan !== tmplCells[i].colSpan) {
|
|
21947
|
+
return skip("\uC0BD\uC785 \uD589 \uBCD1\uD569 \uAD6C\uC870\uAC00 \uAE30\uC900 \uD589\uACFC \uB2E4\uB984 \u2014 \uBBF8\uC9C0\uC6D0");
|
|
21132
21948
|
}
|
|
21133
|
-
}
|
|
21134
|
-
|
|
21135
|
-
|
|
21136
|
-
|
|
21137
|
-
|
|
21138
|
-
|
|
21139
|
-
|
|
21140
|
-
|
|
21141
|
-
|
|
21142
|
-
|
|
21949
|
+
}
|
|
21950
|
+
insertPlans.push({ entry: ins, template, cells });
|
|
21951
|
+
}
|
|
21952
|
+
const net = inss.length - dels.length;
|
|
21953
|
+
TAG_AT_RE.lastIndex = scanTable.start;
|
|
21954
|
+
const tblOpen = TAG_AT_RE.exec(xml);
|
|
21955
|
+
if (!tblOpen || tblOpen.index !== scanTable.start) return skip("\uD45C \uC5EC\uB294 \uD0DC\uADF8 \uD574\uC11D \uC2E4\uD328");
|
|
21956
|
+
const rowCntM = tblOpen[0].match(/\browCnt\s*=\s*"(\d+)"/);
|
|
21957
|
+
if (!rowCntM || rowCntM.index === void 0) return skip("\uD45C rowCnt \uC18D\uC131 \uC5C6\uC74C \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
|
|
21958
|
+
if (parseInt(rowCntM[1], 10) !== numRows) return skip("rowCnt\uC640 \uC2E4\uC81C \uD589 \uC218 \uBD88\uC77C\uCE58 \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
|
|
21959
|
+
const finalIndex = /* @__PURE__ */ new Map();
|
|
21960
|
+
{
|
|
21961
|
+
let fi = 0;
|
|
21962
|
+
for (const e of seq) {
|
|
21963
|
+
if (e.kind !== "del") finalIndex.set(e, fi++);
|
|
21964
|
+
}
|
|
21965
|
+
}
|
|
21966
|
+
const splices = [];
|
|
21967
|
+
let applied = 0;
|
|
21968
|
+
for (const d of dels) {
|
|
21969
|
+
const rr = scanTable.rowRanges[d.oi];
|
|
21970
|
+
splices.push({ start: rr.start, end: rr.end, replacement: "" });
|
|
21971
|
+
applied++;
|
|
21972
|
+
}
|
|
21973
|
+
const fragmentsByAnchor = /* @__PURE__ */ new Map();
|
|
21974
|
+
let heightDelta = 0;
|
|
21975
|
+
for (const plan of insertPlans) {
|
|
21976
|
+
const finalRow = finalIndex.get(plan.entry);
|
|
21977
|
+
const fragment = buildRowFragment(xml, scanTable, plan.template, plan.cells, finalRow, hasExplicitAddr, ctx);
|
|
21978
|
+
if (fragment === null) return skip("\uD589 \uBCF5\uC81C \uC2E4\uD328 (\uC140 \uBB38\uB2E8 \uAD6C\uC870 \uBBF8\uC9C0\uC6D0)");
|
|
21979
|
+
const p = plan.entry.insertAt;
|
|
21980
|
+
const anchor = p === 0 ? scanTable.rowRanges[0].start : scanTable.rowRanges[p - 1].end;
|
|
21981
|
+
let list = fragmentsByAnchor.get(anchor);
|
|
21982
|
+
if (!list) fragmentsByAnchor.set(anchor, list = []);
|
|
21983
|
+
list.push(fragment);
|
|
21984
|
+
heightDelta += rowHeightOf(fragment);
|
|
21985
|
+
applied++;
|
|
21986
|
+
}
|
|
21987
|
+
for (const [anchor, fragments] of fragmentsByAnchor) {
|
|
21988
|
+
splices.push({ start: anchor, end: anchor, replacement: fragments.join("") });
|
|
21989
|
+
}
|
|
21990
|
+
for (const d of dels) {
|
|
21991
|
+
const rr = scanTable.rowRanges[d.oi];
|
|
21992
|
+
heightDelta -= rowHeightOf(xml.slice(rr.start, rr.end));
|
|
21993
|
+
}
|
|
21994
|
+
if (hasExplicitAddr) {
|
|
21995
|
+
for (const k of keeps) {
|
|
21996
|
+
const fi = finalIndex.get(k);
|
|
21997
|
+
if (fi === k.oi) continue;
|
|
21998
|
+
for (const cell of scanTable.rows[k.oi]) {
|
|
21999
|
+
const sp = rowAddrRewrite(xml, cell, fi);
|
|
22000
|
+
if (sp) splices.push(sp);
|
|
21143
22001
|
}
|
|
21144
22002
|
}
|
|
21145
22003
|
}
|
|
21146
|
-
|
|
21147
|
-
|
|
21148
|
-
}
|
|
21149
|
-
function htmlCellInnerToLines(inner) {
|
|
21150
|
-
let hadNonText = false;
|
|
21151
|
-
let work = inner;
|
|
21152
|
-
if (/<table[\s>]/i.test(work)) {
|
|
21153
|
-
hadNonText = true;
|
|
21154
|
-
work = removeNestedTables(work);
|
|
22004
|
+
{
|
|
22005
|
+
const valStart = scanTable.start + rowCntM.index + rowCntM[0].indexOf('"') + 1;
|
|
22006
|
+
splices.push({ start: valStart, end: valStart + rowCntM[1].length, replacement: String(numRows + net) });
|
|
21155
22007
|
}
|
|
21156
|
-
if (
|
|
21157
|
-
|
|
21158
|
-
|
|
22008
|
+
if (heightDelta !== 0) {
|
|
22009
|
+
const sp = tableSzHeightSplice(xml, scanTable, tblOpen[0].length, heightDelta);
|
|
22010
|
+
if (sp) splices.push(sp);
|
|
21159
22011
|
}
|
|
21160
|
-
|
|
21161
|
-
|
|
22012
|
+
ctx.sectionSplices[scanTable.sectionIndex].push(...splices);
|
|
22013
|
+
for (const k of keeps) {
|
|
22014
|
+
if (origKeys[k.oi] !== editedKeys[k.ei]) applied += input.patchMatched(k.oi, k.ei);
|
|
22015
|
+
}
|
|
22016
|
+
return applied;
|
|
21162
22017
|
}
|
|
21163
|
-
|
|
21164
|
-
|
|
21165
|
-
|
|
21166
|
-
|
|
21167
|
-
const
|
|
21168
|
-
|
|
21169
|
-
|
|
21170
|
-
|
|
21171
|
-
|
|
21172
|
-
|
|
21173
|
-
|
|
21174
|
-
|
|
21175
|
-
|
|
21176
|
-
|
|
21177
|
-
|
|
21178
|
-
}
|
|
21179
|
-
|
|
22018
|
+
var FRAG_OPEN = "<hp:tbl>";
|
|
22019
|
+
var FRAG_CLOSE = "</hp:tbl>";
|
|
22020
|
+
function buildRowFragment(xml, scanTable, template, cells, finalRow, hasExplicitAddr, ctx) {
|
|
22021
|
+
const rr = scanTable.rowRanges[template];
|
|
22022
|
+
const wrapped = FRAG_OPEN + xml.slice(rr.start, rr.end) + FRAG_CLOSE;
|
|
22023
|
+
const scan = scanSectionXml(wrapped, 0);
|
|
22024
|
+
const row = scan.tables[0]?.rows[0];
|
|
22025
|
+
if (!row || row.length !== cells.length) return null;
|
|
22026
|
+
const splices = allLinesegRemovalSplices(wrapped);
|
|
22027
|
+
for (let i = 0; i < cells.length; i++) {
|
|
22028
|
+
const paras = row[i].paragraphs;
|
|
22029
|
+
let lines = cells[i].lines;
|
|
22030
|
+
if (lines.length > 0 && paras.length === 0) return null;
|
|
22031
|
+
if (lines.length > paras.length) {
|
|
22032
|
+
lines = [...lines.slice(0, paras.length - 1), lines.slice(paras.length - 1).join(" ")];
|
|
22033
|
+
ctx.skipped.push({ reason: "\uC0BD\uC785 \uD589 \uC140\uC758 \uC904 \uC218\uAC00 \uBB38\uB2E8 \uC218 \uCD08\uACFC \u2014 \uB9C8\uC9C0\uB9C9 \uBB38\uB2E8\uC5D0 \uBCD1\uD569 \uC801\uC6A9", after: summarize(cells[i].lines.join(" ")), partial: true });
|
|
22034
|
+
}
|
|
22035
|
+
for (let p = 0; p < paras.length; p++) {
|
|
22036
|
+
const sp = buildParagraphSplices(paras[p], lines[p] ?? "", wrapped);
|
|
22037
|
+
if (sp === null) return null;
|
|
22038
|
+
splices.push(...sp);
|
|
22039
|
+
}
|
|
22040
|
+
if (hasExplicitAddr) {
|
|
22041
|
+
const sp = rowAddrRewrite(wrapped, row[i], finalRow);
|
|
22042
|
+
if (sp) splices.push(sp);
|
|
21180
22043
|
}
|
|
21181
22044
|
}
|
|
21182
|
-
|
|
22045
|
+
const patched = applySplices(wrapped, splices);
|
|
22046
|
+
return patched.slice(FRAG_OPEN.length, patched.length - FRAG_CLOSE.length);
|
|
21183
22047
|
}
|
|
21184
|
-
function
|
|
21185
|
-
|
|
21186
|
-
|
|
21187
|
-
const
|
|
21188
|
-
|
|
21189
|
-
|
|
21190
|
-
|
|
21191
|
-
|
|
21192
|
-
|
|
21193
|
-
|
|
21194
|
-
|
|
21195
|
-
|
|
21196
|
-
|
|
21197
|
-
|
|
21198
|
-
}
|
|
22048
|
+
function rowAddrRewrite(xml, cell, newRow) {
|
|
22049
|
+
if (!cell.addrTagRange) return null;
|
|
22050
|
+
const tag = xml.slice(cell.addrTagRange.start, cell.addrTagRange.end);
|
|
22051
|
+
const m = tag.match(/\browAddr\s*=\s*"(\d+)"/);
|
|
22052
|
+
if (!m || m.index === void 0) return null;
|
|
22053
|
+
if (parseInt(m[1], 10) === newRow) return null;
|
|
22054
|
+
const valStart = cell.addrTagRange.start + m.index + m[0].indexOf('"') + 1;
|
|
22055
|
+
return { start: valStart, end: valStart + m[1].length, replacement: String(newRow) };
|
|
22056
|
+
}
|
|
22057
|
+
function rowHeightOf(fragment) {
|
|
22058
|
+
let max = 0;
|
|
22059
|
+
for (const m of fragment.matchAll(/<(?:[A-Za-z0-9_]+:)?cellSz\b(?:"[^"]*"|'[^']*'|[^>"'])*>/g)) {
|
|
22060
|
+
const h = m[0].match(/\bheight\s*=\s*"(\d+)"/);
|
|
22061
|
+
if (h) max = Math.max(max, parseInt(h[1], 10));
|
|
21199
22062
|
}
|
|
21200
|
-
|
|
21201
|
-
|
|
22063
|
+
return max;
|
|
22064
|
+
}
|
|
22065
|
+
function tableSzHeightSplice(xml, scanTable, tblOpenLen, delta) {
|
|
22066
|
+
const from = scanTable.start + tblOpenLen;
|
|
22067
|
+
const to = scanTable.rowRanges[0]?.start ?? from;
|
|
22068
|
+
const slice = xml.slice(from, to);
|
|
22069
|
+
const szM = slice.match(/<(?:[A-Za-z0-9_]+:)?sz\b(?:"[^"]*"|'[^']*'|[^>"'])*>/);
|
|
22070
|
+
if (!szM || szM.index === void 0) return null;
|
|
22071
|
+
const hM = szM[0].match(/\bheight\s*=\s*"(\d+)"/);
|
|
22072
|
+
if (!hM || hM.index === void 0) return null;
|
|
22073
|
+
const oldH = parseInt(hM[1], 10);
|
|
22074
|
+
const newH = Math.max(0, oldH + delta);
|
|
22075
|
+
const valStart = from + szM.index + hM.index + hM[0].indexOf('"') + 1;
|
|
22076
|
+
return { start: valStart, end: valStart + hM[1].length, replacement: String(newH) };
|
|
21202
22077
|
}
|
|
21203
22078
|
|
|
21204
22079
|
// src/roundtrip/table-patch.ts
|
|
@@ -21210,37 +22085,89 @@ function patchGfmTable(table, scanTable, orig, edited, ctx, skip) {
|
|
|
21210
22085
|
if (replica.length !== origRows.length || replica.some((row, r) => row.length !== origRows[r].length || row.some((c, j) => c.text !== origRows[r][j]))) {
|
|
21211
22086
|
return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
21212
22087
|
}
|
|
21213
|
-
if (editedRows.length !== origRows.length)
|
|
22088
|
+
if (editedRows.length !== origRows.length) {
|
|
22089
|
+
return patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx, skip);
|
|
22090
|
+
}
|
|
21214
22091
|
let applied = 0;
|
|
21215
22092
|
for (let r = 0; r < origRows.length; r++) {
|
|
21216
|
-
|
|
21217
|
-
|
|
22093
|
+
applied += patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, r, ctx, skip);
|
|
22094
|
+
}
|
|
22095
|
+
return applied;
|
|
22096
|
+
}
|
|
22097
|
+
function patchGfmRowPair(table, scanTable, origRows, editedRows, replica, r, er, ctx, skip) {
|
|
22098
|
+
if (editedRows[er].length !== origRows[r].length) {
|
|
22099
|
+
skip(`\uD45C ${r + 1}\uD589 \uC5F4 \uC218 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0`);
|
|
22100
|
+
return 0;
|
|
22101
|
+
}
|
|
22102
|
+
let applied = 0;
|
|
22103
|
+
for (let c = 0; c < origRows[r].length; c++) {
|
|
22104
|
+
if (origRows[r][c] === editedRows[er][c]) continue;
|
|
22105
|
+
const { gridR, gridC } = replica[r][c];
|
|
22106
|
+
const origTokens = extractCellTokens(origRows[r][c]);
|
|
22107
|
+
const editedTokens = extractCellTokens(editedRows[er][c]);
|
|
22108
|
+
if (origTokens !== editedTokens) {
|
|
22109
|
+
skip("\uC140 \uB0B4 \uC774\uBBF8\uC9C0 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
21218
22110
|
continue;
|
|
21219
22111
|
}
|
|
21220
|
-
|
|
21221
|
-
|
|
21222
|
-
|
|
21223
|
-
|
|
21224
|
-
|
|
21225
|
-
|
|
21226
|
-
|
|
21227
|
-
|
|
21228
|
-
|
|
21229
|
-
|
|
21230
|
-
const origLines = unescapeGfmCell(stripCellTokens(origRows[r][c])).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
21231
|
-
const n = applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, origRows[r][c], editedRows[r][c], origLines.length);
|
|
21232
|
-
if (n > 0 && origTokens) {
|
|
21233
|
-
ctx.skipped.push({
|
|
21234
|
-
reason: "\uC140 \uB0B4 \uC774\uBBF8\uC9C0\xB7\uD14D\uC2A4\uD2B8 \uD63C\uC7AC \u2014 \uD14D\uC2A4\uD2B8\uB9CC \uC801\uC6A9 (\uC774\uBBF8\uC9C0 \uC778\uC811 \uBC30\uCE58\uB294 <br> \uBD84\uB9AC\uB85C \uC7AC\uD604\uB428)",
|
|
21235
|
-
before: summarize(origRows[r][c]),
|
|
21236
|
-
after: summarize(editedRows[r][c])
|
|
21237
|
-
});
|
|
21238
|
-
}
|
|
21239
|
-
applied += n;
|
|
22112
|
+
const newLines = unescapeGfmCell(stripCellTokens(editedRows[er][c])).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
22113
|
+
const origLines = unescapeGfmCell(stripCellTokens(origRows[r][c])).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
22114
|
+
const n = applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, origRows[r][c], editedRows[er][c], origLines.length);
|
|
22115
|
+
if (n > 0 && origTokens) {
|
|
22116
|
+
ctx.skipped.push({
|
|
22117
|
+
reason: "\uC140 \uB0B4 \uC774\uBBF8\uC9C0\xB7\uD14D\uC2A4\uD2B8 \uD63C\uC7AC \u2014 \uD14D\uC2A4\uD2B8\uB9CC \uC801\uC6A9 (\uC774\uBBF8\uC9C0 \uC778\uC811 \uBC30\uCE58\uB294 <br> \uBD84\uB9AC\uB85C \uC7AC\uD604\uB428)",
|
|
22118
|
+
before: summarize(origRows[r][c]),
|
|
22119
|
+
after: summarize(editedRows[er][c]),
|
|
22120
|
+
partial: true
|
|
22121
|
+
});
|
|
21240
22122
|
}
|
|
22123
|
+
applied += n;
|
|
21241
22124
|
}
|
|
21242
22125
|
return applied;
|
|
21243
22126
|
}
|
|
22127
|
+
function patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx, skip) {
|
|
22128
|
+
if (replica.length !== table.rows || replica.some((row, r) => row.some((c) => c.gridR !== r))) {
|
|
22129
|
+
return skip("\uD45C \uB80C\uB354 \uD589\uACFC \uACA9\uC790 \uD589 \uBD88\uC77C\uCE58 (\uBE48 \uD589/\uBCD1\uD569) \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
|
|
22130
|
+
}
|
|
22131
|
+
if (table.cells.some((row) => row.some((c) => c && (c.colSpan > 1 || c.rowSpan > 1)))) {
|
|
22132
|
+
return skip("\uBCD1\uD569 \uC140 \uD45C \u2014 GFM \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
|
|
22133
|
+
}
|
|
22134
|
+
if (!gfmRenderStable(editedRows, table.cols)) {
|
|
22135
|
+
return skip("\uD589 \uBCC0\uACBD \uACB0\uACFC\uAC00 \uD45C \uB80C\uB354\uC5D0\uC11C \uBCC0\uD615\uB428 (\uBE48 \uD589/\uCCAB \uC5F4 \uC804\uD30C/\uC5F4 \uC218 \uBD88\uC77C\uCE58) \u2014 \uBBF8\uC9C0\uC6D0");
|
|
22136
|
+
}
|
|
22137
|
+
const key = (row) => row.join("\0");
|
|
22138
|
+
return patchTableRows({
|
|
22139
|
+
table,
|
|
22140
|
+
scanTable,
|
|
22141
|
+
ctx,
|
|
22142
|
+
skip,
|
|
22143
|
+
origKeys: origRows.map(key),
|
|
22144
|
+
editedKeys: editedRows.map(key),
|
|
22145
|
+
editedCells: (ei) => {
|
|
22146
|
+
const cells = [];
|
|
22147
|
+
for (const cellMd of editedRows[ei]) {
|
|
22148
|
+
if (extractCellTokens(cellMd)) return null;
|
|
22149
|
+
const lines = unescapeGfmCell(cellMd).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
22150
|
+
cells.push({ lines, colSpan: 1, rowSpan: 1 });
|
|
22151
|
+
}
|
|
22152
|
+
return cells;
|
|
22153
|
+
},
|
|
22154
|
+
patchMatched: (oi, ei) => patchGfmRowPair(table, scanTable, origRows, editedRows, replica, oi, ei, ctx, skip)
|
|
22155
|
+
});
|
|
22156
|
+
}
|
|
22157
|
+
function gfmRenderStable(editedRows, cols) {
|
|
22158
|
+
const sim = {
|
|
22159
|
+
rows: editedRows.length,
|
|
22160
|
+
cols,
|
|
22161
|
+
hasHeader: editedRows.length > 1,
|
|
22162
|
+
cells: editedRows.map((row) => {
|
|
22163
|
+
const padded = row.length < cols ? [...row, ...Array(cols - row.length).fill("")] : row;
|
|
22164
|
+
return padded.map((md2) => ({ text: unescapeGfmCell(md2), colSpan: 1, rowSpan: 1 }));
|
|
22165
|
+
})
|
|
22166
|
+
};
|
|
22167
|
+
const replica = replicateGfmTable(sim);
|
|
22168
|
+
if (!replica || replica.length !== editedRows.length) return false;
|
|
22169
|
+
return replica.every((row, r) => row.length === editedRows[r].length && row.every((c, j) => c.text === editedRows[r][j]));
|
|
22170
|
+
}
|
|
21244
22171
|
function patchHtmlTable(table, scanTable, orig, edited, ctx, skip) {
|
|
21245
22172
|
return patchHtmlTableRaw(table, scanTable, orig.raw, edited.raw, ctx, skip, 0);
|
|
21246
22173
|
}
|
|
@@ -21254,46 +22181,77 @@ function patchHtmlTableRaw(table, scanTable, origRaw, editedRaw, ctx, skip, dept
|
|
|
21254
22181
|
}
|
|
21255
22182
|
const editedRows = parseHtmlTable(editedRaw);
|
|
21256
22183
|
if (!editedRows) return skip("\uD3B8\uC9D1\uB41C HTML \uD45C \uD30C\uC2F1 \uC2E4\uD328");
|
|
21257
|
-
if (editedRows.length !== replica.length)
|
|
22184
|
+
if (editedRows.length !== replica.length) {
|
|
22185
|
+
return patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, depth);
|
|
22186
|
+
}
|
|
21258
22187
|
let applied = 0;
|
|
21259
22188
|
for (let r = 0; r < replica.length; r++) {
|
|
21260
|
-
|
|
21261
|
-
|
|
22189
|
+
applied += patchHtmlRowPair(table, scanTable, replica, editedRows, r, r, ctx, skip, depth);
|
|
22190
|
+
}
|
|
22191
|
+
return applied;
|
|
22192
|
+
}
|
|
22193
|
+
function patchHtmlRowPair(table, scanTable, replica, editedRows, r, er, ctx, skip, depth) {
|
|
22194
|
+
if (editedRows[er].cells.length !== replica[r].cells.length) {
|
|
22195
|
+
skip(`\uD45C ${r + 1}\uD589 \uC140 \uC218 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0`);
|
|
22196
|
+
return 0;
|
|
22197
|
+
}
|
|
22198
|
+
let applied = 0;
|
|
22199
|
+
for (let c = 0; c < replica[r].cells.length; c++) {
|
|
22200
|
+
const oc = replica[r].cells[c];
|
|
22201
|
+
const ec = editedRows[er].cells[c];
|
|
22202
|
+
if (oc.colSpan !== ec.colSpan || oc.rowSpan !== ec.rowSpan) {
|
|
22203
|
+
skip(`\uC140 \uBCD1\uD569(colspan/rowspan) \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0`);
|
|
21262
22204
|
continue;
|
|
21263
22205
|
}
|
|
21264
|
-
|
|
21265
|
-
|
|
21266
|
-
|
|
21267
|
-
|
|
21268
|
-
|
|
22206
|
+
if (oc.inner === ec.inner) continue;
|
|
22207
|
+
const origContent = htmlCellInnerToLines(oc.inner);
|
|
22208
|
+
const editedContent = htmlCellInnerToLines(ec.inner);
|
|
22209
|
+
if (origContent.hadNonText || editedContent.hadNonText) {
|
|
22210
|
+
if (extractImgTags(oc.inner) !== extractImgTags(ec.inner)) {
|
|
22211
|
+
skip("\uC140 \uB0B4 \uC774\uBBF8\uC9C0 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
21269
22212
|
continue;
|
|
21270
22213
|
}
|
|
21271
|
-
|
|
21272
|
-
const
|
|
21273
|
-
|
|
21274
|
-
|
|
21275
|
-
|
|
21276
|
-
skip("\uC140 \uB0B4 \uC774\uBBF8\uC9C0 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
21277
|
-
continue;
|
|
21278
|
-
}
|
|
21279
|
-
const origTables = extractTopLevelTables(oc.inner);
|
|
21280
|
-
const editedTables = extractTopLevelTables(ec.inner);
|
|
21281
|
-
if (origTables.length !== editedTables.length) {
|
|
21282
|
-
skip("\uC140 \uB0B4 \uC911\uCCA9\uD45C \uCD94\uAC00/\uC0AD\uC81C\uB294 \uBBF8\uC9C0\uC6D0");
|
|
21283
|
-
continue;
|
|
21284
|
-
}
|
|
21285
|
-
if (origTables.join("\n") !== editedTables.join("\n")) {
|
|
21286
|
-
applied += patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth);
|
|
21287
|
-
}
|
|
22214
|
+
const origTables = extractTopLevelTables(oc.inner);
|
|
22215
|
+
const editedTables = extractTopLevelTables(ec.inner);
|
|
22216
|
+
if (origTables.length !== editedTables.length) {
|
|
22217
|
+
skip("\uC140 \uB0B4 \uC911\uCCA9\uD45C \uCD94\uAC00/\uC0AD\uC81C\uB294 \uBBF8\uC9C0\uC6D0");
|
|
22218
|
+
continue;
|
|
21288
22219
|
}
|
|
21289
|
-
if (
|
|
21290
|
-
|
|
21291
|
-
applied += applyCellEdit(table, scanTable, oc.gridR, oc.gridC, newLines, ctx, oc.inner, ec.inner, origContent.lines.length);
|
|
22220
|
+
if (origTables.join("\n") !== editedTables.join("\n")) {
|
|
22221
|
+
applied += patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth);
|
|
21292
22222
|
}
|
|
21293
22223
|
}
|
|
22224
|
+
if (origContent.lines.join("\n") !== editedContent.lines.join("\n")) {
|
|
22225
|
+
const newLines = editedContent.lines.map((l) => unescapeGfm(l));
|
|
22226
|
+
applied += applyCellEdit(table, scanTable, oc.gridR, oc.gridC, newLines, ctx, oc.inner, ec.inner, origContent.lines.length);
|
|
22227
|
+
}
|
|
21294
22228
|
}
|
|
21295
22229
|
return applied;
|
|
21296
22230
|
}
|
|
22231
|
+
function patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, depth) {
|
|
22232
|
+
if (replica.length !== table.rows || replica.some((row, r) => row.cells.some((c) => c.gridR !== r))) {
|
|
22233
|
+
return skip("\uD45C \uB80C\uB354 \uD589\uACFC \uACA9\uC790 \uD589 \uBD88\uC77C\uCE58 (\uBCD1\uD569 \uC18C\uC2E4 \uD589) \u2014 \uD589 \uCD94\uAC00/\uC0AD\uC81C \uBBF8\uC9C0\uC6D0");
|
|
22234
|
+
}
|
|
22235
|
+
const key = (row) => row.cells.map((c) => `${c.colSpan}x${c.rowSpan}:${c.inner}`).join("\0");
|
|
22236
|
+
return patchTableRows({
|
|
22237
|
+
table,
|
|
22238
|
+
scanTable,
|
|
22239
|
+
ctx,
|
|
22240
|
+
skip,
|
|
22241
|
+
origKeys: replica.map(key),
|
|
22242
|
+
editedKeys: editedRows.map(key),
|
|
22243
|
+
editedCells: (ei) => {
|
|
22244
|
+
const cells = [];
|
|
22245
|
+
for (const cell of editedRows[ei].cells) {
|
|
22246
|
+
const content = htmlCellInnerToLines(cell.inner);
|
|
22247
|
+
if (content.hadNonText) return null;
|
|
22248
|
+
cells.push({ lines: content.lines.map((l) => unescapeGfm(l)), colSpan: cell.colSpan, rowSpan: cell.rowSpan });
|
|
22249
|
+
}
|
|
22250
|
+
return cells;
|
|
22251
|
+
},
|
|
22252
|
+
patchMatched: (oi, ei) => patchHtmlRowPair(table, scanTable, replica, editedRows, oi, ei, ctx, skip, depth)
|
|
22253
|
+
});
|
|
22254
|
+
}
|
|
21297
22255
|
function patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth) {
|
|
21298
22256
|
const irCell = table.cells[oc.gridR]?.[oc.gridC];
|
|
21299
22257
|
const scanCell = scanTable.cellByAnchor.get(`${oc.gridR},${oc.gridC}`);
|
|
@@ -21393,7 +22351,7 @@ function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, af
|
|
|
21393
22351
|
splices.push(...sp);
|
|
21394
22352
|
sectionIndex = target.sectionIndex;
|
|
21395
22353
|
if (newLines.length > 1) {
|
|
21396
|
-
ctx.skipped.push({ reason: "\uC140 \uB0B4 \uC904 \uCD94\uAC00\uB294 \uBB38\uB2E8 \uC0DD\uC131 \uBBF8\uC9C0\uC6D0 \u2014 \uD55C \uBB38\uB2E8\uC73C\uB85C \uBCD1\uD569 \uC801\uC6A9", after: summarize(after) });
|
|
22354
|
+
ctx.skipped.push({ reason: "\uC140 \uB0B4 \uC904 \uCD94\uAC00\uB294 \uBB38\uB2E8 \uC0DD\uC131 \uBBF8\uC9C0\uC6D0 \u2014 \uD55C \uBB38\uB2E8\uC73C\uB85C \uBCD1\uD569 \uC801\uC6A9", after: summarize(after), partial: true });
|
|
21397
22355
|
}
|
|
21398
22356
|
} else {
|
|
21399
22357
|
const assigned = [];
|
|
@@ -21405,7 +22363,9 @@ function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, af
|
|
|
21405
22363
|
}
|
|
21406
22364
|
}
|
|
21407
22365
|
if (newLines.length > nonEmpty.length) {
|
|
21408
|
-
ctx.skipped.push({ reason: "\uC140 \uB0B4 \uC904 \uCD94\uAC00\uB294 \uBB38\uB2E8 \uC0DD\uC131 \uBBF8\uC9C0\uC6D0 \u2014 \uB9C8\uC9C0\uB9C9 \uBB38\uB2E8\uC5D0 \uBCD1\uD569 \uC801\uC6A9", after: summarize(after) });
|
|
22366
|
+
ctx.skipped.push({ reason: "\uC140 \uB0B4 \uC904 \uCD94\uAC00\uB294 \uBB38\uB2E8 \uC0DD\uC131 \uBBF8\uC9C0\uC6D0 \u2014 \uB9C8\uC9C0\uB9C9 \uBB38\uB2E8\uC5D0 \uBCD1\uD569 \uC801\uC6A9", after: summarize(after), partial: true });
|
|
22367
|
+
} else if (newLines.length < nonEmpty.length && nonEmpty.length > 1) {
|
|
22368
|
+
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 });
|
|
21409
22369
|
}
|
|
21410
22370
|
for (let i = 0; i < nonEmpty.length; i++) {
|
|
21411
22371
|
if (assigned[i] === nonEmpty[i].text || normForMatch(assigned[i]) === normForMatch(nonEmpty[i].text)) continue;
|
|
@@ -21578,7 +22538,8 @@ async function patchHwpx(original, editedMarkdown, options) {
|
|
|
21578
22538
|
try {
|
|
21579
22539
|
for (let i = 0; i < scans.length; i++) {
|
|
21580
22540
|
if (sectionSplices[i].length === 0) continue;
|
|
21581
|
-
sectionSplices[i].
|
|
22541
|
+
const claimed = sectionSplices[i].filter((s) => s.end > s.start);
|
|
22542
|
+
sectionSplices[i].push(...allLinesegRemovalSplices(scans[i].xml).filter((ls) => !claimed.some((c) => ls.start >= c.start && ls.end <= c.end)));
|
|
21582
22543
|
const newXml = applySplices(scans[i].xml, sectionSplices[i]);
|
|
21583
22544
|
replacements.set(sectionPaths[i], encoder.encode(newXml));
|
|
21584
22545
|
}
|
|
@@ -21646,82 +22607,6 @@ function buildTableOrdinals(blocks) {
|
|
|
21646
22607
|
}
|
|
21647
22608
|
return map;
|
|
21648
22609
|
}
|
|
21649
|
-
function alignUnits(a, b) {
|
|
21650
|
-
const m = a.length, n = b.length;
|
|
21651
|
-
if (m * n > 4e6) {
|
|
21652
|
-
const result2 = [];
|
|
21653
|
-
let pre = 0;
|
|
21654
|
-
while (pre < m && pre < n && a[pre] === b[pre]) {
|
|
21655
|
-
result2.push([pre, pre]);
|
|
21656
|
-
pre++;
|
|
21657
|
-
}
|
|
21658
|
-
let suf = 0;
|
|
21659
|
-
while (suf < m - pre && suf < n - pre && a[m - 1 - suf] === b[n - 1 - suf]) suf++;
|
|
21660
|
-
const aMid = m - pre - suf, bMid = n - pre - suf;
|
|
21661
|
-
if (aMid === bMid) {
|
|
21662
|
-
for (let i2 = 0; i2 < aMid; i2++) result2.push([pre + i2, pre + i2]);
|
|
21663
|
-
} else {
|
|
21664
|
-
for (let i2 = 0; i2 < aMid; i2++) result2.push([pre + i2, null]);
|
|
21665
|
-
for (let j2 = 0; j2 < bMid; j2++) result2.push([null, pre + j2]);
|
|
21666
|
-
}
|
|
21667
|
-
for (let s = suf - 1; s >= 0; s--) result2.push([m - 1 - s, n - 1 - s]);
|
|
21668
|
-
return result2;
|
|
21669
|
-
}
|
|
21670
|
-
const dp = Array.from({ length: m + 1 }, () => new Int32Array(n + 1));
|
|
21671
|
-
for (let i2 = 1; i2 <= m; i2++) {
|
|
21672
|
-
for (let j2 = 1; j2 <= n; j2++) {
|
|
21673
|
-
dp[i2][j2] = a[i2 - 1] === b[j2 - 1] ? dp[i2 - 1][j2 - 1] + 1 : Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
|
|
21674
|
-
}
|
|
21675
|
-
}
|
|
21676
|
-
const matches = [];
|
|
21677
|
-
let i = m, j = n;
|
|
21678
|
-
while (i > 0 && j > 0) {
|
|
21679
|
-
if (a[i - 1] === b[j - 1] && dp[i][j] === dp[i - 1][j - 1] + 1) {
|
|
21680
|
-
matches.push([i - 1, j - 1]);
|
|
21681
|
-
i--;
|
|
21682
|
-
j--;
|
|
21683
|
-
} else if (dp[i - 1][j] >= dp[i][j - 1]) i--;
|
|
21684
|
-
else j--;
|
|
21685
|
-
}
|
|
21686
|
-
matches.reverse();
|
|
21687
|
-
const result = [];
|
|
21688
|
-
let ai = 0, bi = 0;
|
|
21689
|
-
const flushGap = (aEnd, bEnd) => {
|
|
21690
|
-
if (aEnd - ai === bEnd - bi) {
|
|
21691
|
-
while (ai < aEnd) result.push([ai++, bi++]);
|
|
21692
|
-
return;
|
|
21693
|
-
}
|
|
21694
|
-
while (ai < aEnd && bi < bEnd) {
|
|
21695
|
-
const sim = normalizedSimilarity(a[ai], b[bi]);
|
|
21696
|
-
if (sim >= 0.4) {
|
|
21697
|
-
if (aEnd - ai > bEnd - bi && bestSimInRange(a, ai + 1, ai + (aEnd - ai) - (bEnd - bi), b[bi]) > sim) {
|
|
21698
|
-
result.push([ai++, null]);
|
|
21699
|
-
} else if (bEnd - bi > aEnd - ai && bestSimInRange(b, bi + 1, bi + (bEnd - bi) - (aEnd - ai), a[ai]) > sim) {
|
|
21700
|
-
result.push([null, bi++]);
|
|
21701
|
-
} else {
|
|
21702
|
-
result.push([ai++, bi++]);
|
|
21703
|
-
}
|
|
21704
|
-
} else if (aEnd - ai >= bEnd - bi) result.push([ai++, null]);
|
|
21705
|
-
else result.push([null, bi++]);
|
|
21706
|
-
}
|
|
21707
|
-
while (ai < aEnd) result.push([ai++, null]);
|
|
21708
|
-
while (bi < bEnd) result.push([null, bi++]);
|
|
21709
|
-
};
|
|
21710
|
-
for (const [pi, pj] of matches) {
|
|
21711
|
-
flushGap(pi, pj);
|
|
21712
|
-
result.push([ai++, bi++]);
|
|
21713
|
-
}
|
|
21714
|
-
flushGap(m, n);
|
|
21715
|
-
return result;
|
|
21716
|
-
}
|
|
21717
|
-
function bestSimInRange(arr, from, to, target) {
|
|
21718
|
-
let best = 0;
|
|
21719
|
-
for (let k = from; k <= to && k < arr.length; k++) {
|
|
21720
|
-
const s = normalizedSimilarity(arr[k], target);
|
|
21721
|
-
if (s > best) best = s;
|
|
21722
|
-
}
|
|
21723
|
-
return best;
|
|
21724
|
-
}
|
|
21725
22610
|
function resolveParagraphMappings(blocks, scans) {
|
|
21726
22611
|
const buckets = /* @__PURE__ */ new Map();
|
|
21727
22612
|
for (const scan of scans) {
|
|
@@ -21864,7 +22749,7 @@ function patchParagraphUnit(block, orig, edited, ctx, skip) {
|
|
|
21864
22749
|
const origPrefix = block.text.split(" ", 1)[0];
|
|
21865
22750
|
const sp = newPlain.indexOf(" ");
|
|
21866
22751
|
const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain;
|
|
21867
|
-
if (newFirst === origPrefix ||
|
|
22752
|
+
if (newFirst === origPrefix || AUTONUM_PREFIX_RE.test(newFirst)) {
|
|
21868
22753
|
newPlain = sp > 0 ? newPlain.slice(sp + 1) : "";
|
|
21869
22754
|
} else {
|
|
21870
22755
|
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) });
|
|
@@ -22607,7 +23492,7 @@ function patchParagraph(block, orig, edited, ctx, skip) {
|
|
|
22607
23492
|
const origPrefix = block.text.split(" ", 1)[0];
|
|
22608
23493
|
const sp = newPlain.indexOf(" ");
|
|
22609
23494
|
const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain;
|
|
22610
|
-
if (newFirst === origPrefix ||
|
|
23495
|
+
if (newFirst === origPrefix || AUTONUM_PREFIX_RE.test(newFirst)) {
|
|
22611
23496
|
newPlain = sp > 0 ? newPlain.slice(sp + 1) : "";
|
|
22612
23497
|
} else {
|
|
22613
23498
|
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) });
|
|
@@ -22672,9 +23557,6 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
|
|
|
22672
23557
|
}
|
|
22673
23558
|
return applied;
|
|
22674
23559
|
}
|
|
22675
|
-
function extractImgTags5(inner) {
|
|
22676
|
-
return (inner.match(/<img\s(?:"[^"]*"|'[^']*'|[^>"'])*?>/gi) || []).join(" ");
|
|
22677
|
-
}
|
|
22678
23560
|
function patchHtmlCells5(table, scanTable, orig, edited, ctx, skip) {
|
|
22679
23561
|
if (replicateTableToHtml(table) !== orig.raw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
22680
23562
|
const replica = replicateHtmlTable(table);
|
|
@@ -22702,7 +23584,7 @@ function patchHtmlCells5(table, scanTable, orig, edited, ctx, skip) {
|
|
|
22702
23584
|
const origContent = htmlCellInnerToLines(oc.inner);
|
|
22703
23585
|
const editedContent = htmlCellInnerToLines(ec.inner);
|
|
22704
23586
|
if (origContent.hadNonText || editedContent.hadNonText) {
|
|
22705
|
-
if (
|
|
23587
|
+
if (extractImgTags(oc.inner) !== extractImgTags(ec.inner)) {
|
|
22706
23588
|
skip("\uC140 \uB0B4 \uC774\uBBF8\uC9C0 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
22707
23589
|
continue;
|
|
22708
23590
|
}
|
|
@@ -22793,7 +23675,9 @@ function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, a
|
|
|
22793
23675
|
}
|
|
22794
23676
|
}
|
|
22795
23677
|
if (newLines.length > nonEmpty.length) {
|
|
22796
|
-
ctx.skipped.push({ reason: "\uC140 \uB0B4 \uC904 \uCD94\uAC00\uB294 \uBB38\uB2E8 \uC0DD\uC131 \uBBF8\uC9C0\uC6D0 \u2014 \uB9C8\uC9C0\uB9C9 \uBB38\uB2E8\uC5D0 \uBCD1\uD569 \uC801\uC6A9", after: summarize(after) });
|
|
23678
|
+
ctx.skipped.push({ reason: "\uC140 \uB0B4 \uC904 \uCD94\uAC00\uB294 \uBB38\uB2E8 \uC0DD\uC131 \uBBF8\uC9C0\uC6D0 \u2014 \uB9C8\uC9C0\uB9C9 \uBB38\uB2E8\uC5D0 \uBCD1\uD569 \uC801\uC6A9", after: summarize(after), partial: true });
|
|
23679
|
+
} else if (newLines.length < nonEmpty.length && nonEmpty.length > 1) {
|
|
23680
|
+
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 });
|
|
22797
23681
|
}
|
|
22798
23682
|
let staged = 0;
|
|
22799
23683
|
for (let i = 0; i < nonEmpty.length; i++) {
|
|
@@ -23168,6 +24052,7 @@ var HwpxSession = class _HwpxSession {
|
|
|
23168
24052
|
try {
|
|
23169
24053
|
for (let s = 0; s < st.scans.length; s++) {
|
|
23170
24054
|
if (sectionSplices[s].length === 0) continue;
|
|
24055
|
+
sectionSplices[s].push(...allLinesegRemovalSplices(st.scans[s].xml));
|
|
23171
24056
|
replacements.set(st.sectionPaths[s], encoder.encode(applySplices(st.scans[s].xml, sectionSplices[s])));
|
|
23172
24057
|
}
|
|
23173
24058
|
} catch (err) {
|
|
@@ -23224,7 +24109,7 @@ var HwpxSession = class _HwpxSession {
|
|
|
23224
24109
|
const origPrefix = block.text.split(" ", 1)[0];
|
|
23225
24110
|
const sp = newPlain.indexOf(" ");
|
|
23226
24111
|
const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain;
|
|
23227
|
-
if (newFirst === origPrefix ||
|
|
24112
|
+
if (newFirst === origPrefix || AUTONUM_PREFIX_RE.test(newFirst)) {
|
|
23228
24113
|
newPlain = sp > 0 ? newPlain.slice(sp + 1) : "";
|
|
23229
24114
|
} else {
|
|
23230
24115
|
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) });
|
|
@@ -23518,7 +24403,7 @@ async function parseHwp(buffer, options) {
|
|
|
23518
24403
|
async function parsePdf(buffer, options) {
|
|
23519
24404
|
let parsePdfDocument;
|
|
23520
24405
|
try {
|
|
23521
|
-
const mod = await import("./parser-
|
|
24406
|
+
const mod = await import("./parser-ZHJFQR44.js");
|
|
23522
24407
|
parsePdfDocument = mod.parsePdfDocument;
|
|
23523
24408
|
} catch {
|
|
23524
24409
|
return {
|
|
@@ -23610,12 +24495,16 @@ async function fillForm(input, values, outputFormat = "markdown") {
|
|
|
23610
24495
|
export {
|
|
23611
24496
|
HwpxSession,
|
|
23612
24497
|
PRESET_ALIAS,
|
|
24498
|
+
SPACE_EM_FIXED,
|
|
24499
|
+
SPACE_EM_FONT,
|
|
23613
24500
|
VERSION,
|
|
24501
|
+
ValueCursor,
|
|
23614
24502
|
applySplices,
|
|
23615
24503
|
blocksToMarkdown,
|
|
23616
24504
|
blocksToPdf,
|
|
23617
24505
|
buildParagraphSplices,
|
|
23618
24506
|
buildRangeSplices,
|
|
24507
|
+
charWidthEm1000,
|
|
23619
24508
|
compare,
|
|
23620
24509
|
detectFormat,
|
|
23621
24510
|
detectOle2Format,
|
|
@@ -23626,6 +24515,7 @@ export {
|
|
|
23626
24515
|
fillForm,
|
|
23627
24516
|
fillFormFields,
|
|
23628
24517
|
fillHwpx,
|
|
24518
|
+
fitRatioForFewerLines,
|
|
23629
24519
|
inferFieldType,
|
|
23630
24520
|
isHwpxFile,
|
|
23631
24521
|
isLabelCell,
|
|
@@ -23634,6 +24524,7 @@ export {
|
|
|
23634
24524
|
isZipFile,
|
|
23635
24525
|
markdownToHwpx,
|
|
23636
24526
|
markdownToPdf,
|
|
24527
|
+
measureTextWidth,
|
|
23637
24528
|
normalizeGongmunPreset,
|
|
23638
24529
|
openHwpxDocument,
|
|
23639
24530
|
parse,
|
|
@@ -23649,6 +24540,8 @@ export {
|
|
|
23649
24540
|
patchHwpx,
|
|
23650
24541
|
patchHwpxBlocks,
|
|
23651
24542
|
renderHtml,
|
|
23652
|
-
scanSectionXml
|
|
24543
|
+
scanSectionXml,
|
|
24544
|
+
simulateWrap,
|
|
24545
|
+
simulateWrapKeepWord
|
|
23653
24546
|
};
|
|
23654
24547
|
//# sourceMappingURL=index.js.map
|