kordoc 3.5.4 → 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/{-KX7VLNW5.js → -7UC4ZWBS.js} +21 -5
- package/dist/{chunk-WEAP42T3.js → chunk-IJJMVTU5.js} +2 -2
- package/dist/chunk-IJJMVTU5.js.map +1 -0
- package/dist/{chunk-VEB43O2L.js → chunk-MEVKYW55.js} +2 -2
- package/dist/chunk-MEVKYW55.js.map +1 -0
- package/dist/{chunk-DK2IE43H.js → chunk-NXRABCWW.js} +1584 -701
- package/dist/chunk-NXRABCWW.js.map +1 -0
- package/dist/{chunk-XZTDYOZV.cjs → chunk-QZCP3UWU.cjs} +2 -2
- package/dist/{chunk-XZTDYOZV.cjs.map → chunk-QZCP3UWU.cjs.map} +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.cjs +1783 -900
- 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 +1584 -701
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +3 -3
- package/dist/{parser-W5TBEAVX.js → parser-DR5CTZ74.js} +2 -2
- package/dist/{parser-CPTBEGQP.cjs → parser-RFLPUZ7P.cjs} +14 -14
- package/dist/{parser-CPTBEGQP.cjs.map → parser-RFLPUZ7P.cjs.map} +1 -1
- package/dist/{parser-XT65AEDJ.js → parser-ZHJFQR44.js} +2 -2
- package/dist/{watch-VOSNRZAY.js → watch-UIX447QV.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-DK2IE43H.js.map +0 -1
- package/dist/chunk-VEB43O2L.js.map +0 -1
- package/dist/chunk-WEAP42T3.js.map +0 -1
- /package/dist/{-KX7VLNW5.js.map → -7UC4ZWBS.js.map} +0 -0
- /package/dist/{parser-W5TBEAVX.js.map → parser-DR5CTZ74.js.map} +0 -0
- /package/dist/{parser-XT65AEDJ.js.map → parser-ZHJFQR44.js.map} +0 -0
- /package/dist/{watch-VOSNRZAY.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,17 +20525,10 @@ function standardMarker(depth, n) {
|
|
|
20098
20525
|
function reportMarker(depth) {
|
|
20099
20526
|
return REPORT_BULLETS[Math.min(depth, REPORT_BULLETS.length - 1)];
|
|
20100
20527
|
}
|
|
20101
|
-
var MARKER_FULLWIDTH = "\u2460\u2461\u2462\u2463\u2464\u2465\u2466\u2467\u2468\u2469\u246A\u246B\u246C\u246D\u246E\u246F\u2470\u2471\u2472\u2473\u326E\u326F\u3270\u3271\u3272\u3273\u3274\u3275\u3276\u3277\u3278\u3279\u327A\u327B\u25A1\u25CB\u25E6\u25AA\u25C7\u25B3\u25B6\u318D";
|
|
20102
20528
|
function markerWidth(marker, bodyHeight) {
|
|
20103
|
-
|
|
20104
|
-
|
|
20105
|
-
|
|
20106
|
-
if (/[가-힣]/.test(c) || MARKER_FULLWIDTH.includes(c)) w += bodyHeight;
|
|
20107
|
-
else if (c === "." || c === ",") w += Math.round(bodyHeight * 0.25);
|
|
20108
|
-
else if (c === "(" || c === ")") w += Math.round(bodyHeight * 0.45);
|
|
20109
|
-
else w += Math.round(ta);
|
|
20110
|
-
}
|
|
20111
|
-
return Math.round(w + ta);
|
|
20529
|
+
let em = SPACE_EM_FIXED;
|
|
20530
|
+
for (const c of marker) em += charWidthEm1000(c.codePointAt(0));
|
|
20531
|
+
return Math.round(em / 1e3 * bodyHeight);
|
|
20112
20532
|
}
|
|
20113
20533
|
function levelIndent(depth, bodyHeight, numbering) {
|
|
20114
20534
|
const marker = numbering === "report" ? reportMarker(depth) : standardMarker(depth, 0);
|
|
@@ -20148,77 +20568,53 @@ function mmToHwpunit(mm) {
|
|
|
20148
20568
|
return Math.round(mm * 7200 / 25.4);
|
|
20149
20569
|
}
|
|
20150
20570
|
|
|
20151
|
-
// src/
|
|
20152
|
-
|
|
20153
|
-
|
|
20154
|
-
|
|
20155
|
-
|
|
20156
|
-
|
|
20157
|
-
|
|
20158
|
-
var NS_OCF = "urn:oasis:names:tc:opendocument:xmlns:container";
|
|
20159
|
-
var CHAR_NORMAL = 0;
|
|
20160
|
-
var CHAR_BOLD = 1;
|
|
20161
|
-
var CHAR_ITALIC = 2;
|
|
20162
|
-
var CHAR_BOLD_ITALIC = 3;
|
|
20163
|
-
var CHAR_CODE = 4;
|
|
20164
|
-
var CHAR_H1 = 5;
|
|
20165
|
-
var CHAR_H2 = 6;
|
|
20166
|
-
var CHAR_H3 = 7;
|
|
20167
|
-
var CHAR_H4 = 8;
|
|
20168
|
-
var CHAR_TABLE_HEADER = 9;
|
|
20169
|
-
var CHAR_QUOTE = 10;
|
|
20170
|
-
var PARA_NORMAL = 0;
|
|
20171
|
-
var PARA_H1 = 1;
|
|
20172
|
-
var PARA_H2 = 2;
|
|
20173
|
-
var PARA_H3 = 3;
|
|
20174
|
-
var PARA_H4 = 4;
|
|
20175
|
-
var PARA_CODE = 5;
|
|
20176
|
-
var PARA_QUOTE = 6;
|
|
20177
|
-
var PARA_LIST = 7;
|
|
20178
|
-
var DEFAULT_TEXT_COLOR = "#000000";
|
|
20179
|
-
function resolveTheme(theme) {
|
|
20180
|
-
return {
|
|
20181
|
-
h1: theme?.headingColors?.[1] ?? DEFAULT_TEXT_COLOR,
|
|
20182
|
-
h2: theme?.headingColors?.[2] ?? DEFAULT_TEXT_COLOR,
|
|
20183
|
-
h3: theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,
|
|
20184
|
-
h4: theme?.headingColors?.[4] ?? theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,
|
|
20185
|
-
body: theme?.bodyColor ?? DEFAULT_TEXT_COLOR,
|
|
20186
|
-
quote: theme?.quoteColor ?? DEFAULT_TEXT_COLOR,
|
|
20187
|
-
/** quoteColor가 명시되었는지 — blockquote charPr 분기에 사용 (baseline 호환) */
|
|
20188
|
-
hasQuoteOption: theme?.quoteColor !== void 0,
|
|
20189
|
-
tableHeader: theme?.tableHeaderColor ?? theme?.bodyColor ?? DEFAULT_TEXT_COLOR,
|
|
20190
|
-
tableHeaderBold: !!theme?.tableHeaderBold
|
|
20191
|
-
};
|
|
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;
|
|
20192
20578
|
}
|
|
20193
|
-
|
|
20194
|
-
|
|
20195
|
-
const gongmun = options?.gongmun ? resolveGongmun(options.gongmun) : null;
|
|
20196
|
-
const blocks = parseMarkdownToBlocks(markdown);
|
|
20197
|
-
const sectionXml = blocksToSectionXml(blocks, theme, gongmun);
|
|
20198
|
-
const zip = new JSZip6();
|
|
20199
|
-
zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
|
|
20200
|
-
zip.file("META-INF/container.xml", generateContainerXml());
|
|
20201
|
-
zip.file("Contents/content.hpf", generateManifest());
|
|
20202
|
-
zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun));
|
|
20203
|
-
zip.file("Contents/section0.xml", sectionXml);
|
|
20204
|
-
zip.file("Preview/PrvText.txt", buildPrvText(blocks));
|
|
20205
|
-
return await zip.generateAsync({ type: "arraybuffer" });
|
|
20579
|
+
function normalizedSimilarity(a, b) {
|
|
20580
|
+
return similarity(normalize(a), normalize(b));
|
|
20206
20581
|
}
|
|
20207
|
-
function
|
|
20208
|
-
|
|
20209
|
-
|
|
20210
|
-
|
|
20211
|
-
|
|
20212
|
-
|
|
20213
|
-
|
|
20214
|
-
|
|
20215
|
-
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);
|
|
20216
20593
|
}
|
|
20217
|
-
|
|
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];
|
|
20218
20612
|
}
|
|
20219
|
-
|
|
20613
|
+
|
|
20614
|
+
// src/roundtrip/markdown-units.ts
|
|
20615
|
+
function splitMarkdownUnits(md2) {
|
|
20220
20616
|
const lines = md2.split("\n");
|
|
20221
|
-
const
|
|
20617
|
+
const units = [];
|
|
20222
20618
|
let i = 0;
|
|
20223
20619
|
while (i < lines.length) {
|
|
20224
20620
|
const line = lines[i];
|
|
@@ -20226,66 +20622,523 @@ function parseMarkdownToBlocks(md2) {
|
|
|
20226
20622
|
i++;
|
|
20227
20623
|
continue;
|
|
20228
20624
|
}
|
|
20229
|
-
|
|
20230
|
-
|
|
20231
|
-
|
|
20232
|
-
|
|
20233
|
-
|
|
20234
|
-
|
|
20235
|
-
|
|
20236
|
-
|
|
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;
|
|
20237
20633
|
i++;
|
|
20634
|
+
if (depth <= 0) break;
|
|
20238
20635
|
}
|
|
20239
|
-
|
|
20240
|
-
blocks.push({ type: "code_block", text: codeLines.join("\n"), lang });
|
|
20241
|
-
continue;
|
|
20242
|
-
}
|
|
20243
|
-
if (/^(\*{3,}|-{3,}|_{3,})\s*$/.test(line.trim())) {
|
|
20244
|
-
blocks.push({ type: "hr" });
|
|
20245
|
-
i++;
|
|
20246
|
-
continue;
|
|
20247
|
-
}
|
|
20248
|
-
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
20249
|
-
if (headingMatch) {
|
|
20250
|
-
blocks.push({ type: "heading", text: headingMatch[2].trim(), level: headingMatch[1].length });
|
|
20251
|
-
i++;
|
|
20636
|
+
units.push({ kind: "html-table", raw: collected2.join("\n"), lines: collected2 });
|
|
20252
20637
|
continue;
|
|
20253
20638
|
}
|
|
20254
20639
|
if (line.trimStart().startsWith("|")) {
|
|
20255
|
-
const
|
|
20640
|
+
const collected2 = [];
|
|
20256
20641
|
while (i < lines.length && lines[i].trimStart().startsWith("|")) {
|
|
20257
|
-
|
|
20258
|
-
if (/^[\s|:\-]+$/.test(row)) {
|
|
20259
|
-
i++;
|
|
20260
|
-
continue;
|
|
20261
|
-
}
|
|
20262
|
-
const cells = row.split("|").slice(1, -1).map((c) => c.trim());
|
|
20263
|
-
if (cells.length > 0) tableRows.push(cells);
|
|
20642
|
+
collected2.push(lines[i]);
|
|
20264
20643
|
i++;
|
|
20265
20644
|
}
|
|
20266
|
-
|
|
20645
|
+
units.push({ kind: "gfm-table", raw: collected2.join("\n"), lines: collected2 });
|
|
20267
20646
|
continue;
|
|
20268
20647
|
}
|
|
20269
|
-
if (line.
|
|
20270
|
-
|
|
20271
|
-
|
|
20272
|
-
quoteLines.push(lines[i].replace(/^>\s?/, ""));
|
|
20273
|
-
i++;
|
|
20274
|
-
}
|
|
20275
|
-
for (const ql of quoteLines) {
|
|
20276
|
-
blocks.push({ type: "blockquote", text: ql.trim() || "" });
|
|
20277
|
-
}
|
|
20648
|
+
if (/^-{3,}\s*$/.test(line.trim())) {
|
|
20649
|
+
units.push({ kind: "separator", raw: line.trim(), lines: [line.trim()] });
|
|
20650
|
+
i++;
|
|
20278
20651
|
continue;
|
|
20279
20652
|
}
|
|
20280
|
-
|
|
20281
|
-
|
|
20282
|
-
const indent = Math.floor(listMatch[1].length / 2);
|
|
20283
|
-
const ordered = /\d/.test(listMatch[2]);
|
|
20284
|
-
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()] });
|
|
20285
20655
|
i++;
|
|
20286
20656
|
continue;
|
|
20287
20657
|
}
|
|
20288
|
-
|
|
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() });
|
|
20289
21142
|
i++;
|
|
20290
21143
|
}
|
|
20291
21144
|
return blocks;
|
|
@@ -20332,18 +21185,19 @@ function spanToCharPrId(span) {
|
|
|
20332
21185
|
function escapeXml(text) {
|
|
20333
21186
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
20334
21187
|
}
|
|
20335
|
-
function generateRuns(text, defaultCharPr = CHAR_NORMAL) {
|
|
21188
|
+
function generateRuns(text, defaultCharPr = CHAR_NORMAL, mapCharId) {
|
|
20336
21189
|
const spans = parseInlineMarkdown(text);
|
|
20337
21190
|
return spans.map((span) => {
|
|
20338
|
-
|
|
21191
|
+
let charId = span.code || span.bold || span.italic ? spanToCharPrId(span) : defaultCharPr;
|
|
21192
|
+
if (mapCharId) charId = mapCharId(charId);
|
|
20339
21193
|
return `<hp:run charPrIDRef="${charId}"><hp:t>${escapeXml(span.text)}</hp:t></hp:run>`;
|
|
20340
21194
|
}).join("");
|
|
20341
21195
|
}
|
|
20342
|
-
function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL) {
|
|
21196
|
+
function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL, mapCharId) {
|
|
20343
21197
|
if (paraPrId === PARA_CODE) {
|
|
20344
21198
|
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_CODE}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`;
|
|
20345
21199
|
}
|
|
20346
|
-
const runs = generateRuns(text, charPrId);
|
|
21200
|
+
const runs = generateRuns(text, charPrId, mapCharId);
|
|
20347
21201
|
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0">${runs}</hp:p>`;
|
|
20348
21202
|
}
|
|
20349
21203
|
function headingParaPrId(level) {
|
|
@@ -20383,7 +21237,7 @@ function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_C
|
|
|
20383
21237
|
const boldAttr = bold ? ` bold="1"` : "";
|
|
20384
21238
|
const italicAttr = italic ? ` italic="1"` : "";
|
|
20385
21239
|
const effFont = bold ? 2 : fontId;
|
|
20386
|
-
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}>
|
|
20387
21241
|
<hh:fontRef hangul="${effFont}" latin="${effFont}" hanja="${effFont}" japanese="${effFont}" other="${effFont}" symbol="${effFont}" user="${effFont}"/>
|
|
20388
21242
|
<hh:ratio hangul="${ratioPct}" latin="${ratioPct}" hanja="${ratioPct}" japanese="100" other="100" symbol="100" user="100"/>
|
|
20389
21243
|
<hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
|
|
@@ -20402,13 +21256,58 @@ function paraPr(id, opts = {}) {
|
|
|
20402
21256
|
<hh:autoSpacing eAsianEng="0" eAsianNum="0"/>
|
|
20403
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>
|
|
20404
21258
|
<hh:lineSpacing type="PERCENT" value="${lineSpacing}"/>
|
|
20405
|
-
<hh:border borderFillIDRef="
|
|
21259
|
+
<hh:border borderFillIDRef="1" offsetLeft="0" offsetRight="0" offsetTop="0" offsetBottom="0" connect="0" ignoreMargin="0"/>
|
|
20406
21260
|
</hh:paraPr>`;
|
|
20407
21261
|
}
|
|
20408
21262
|
var GONGMUN_LIST_BASE = 8;
|
|
20409
21263
|
var GONGMUN_LIST_LEVELS = 8;
|
|
20410
21264
|
var GONGMUN_CENTER = GONGMUN_LIST_BASE + GONGMUN_LIST_LEVELS;
|
|
20411
|
-
|
|
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 = []) {
|
|
20412
21311
|
let body = 1e3, code = 900, h1 = 1800, h2 = 1400, h3 = 1200, h4 = 1100;
|
|
20413
21312
|
if (gongmun) {
|
|
20414
21313
|
body = gongmun.bodyHeight;
|
|
@@ -20418,7 +21317,7 @@ function buildCharProperties(theme, gongmun) {
|
|
|
20418
21317
|
h3 = body;
|
|
20419
21318
|
h4 = Math.max(body - 100, 1300);
|
|
20420
21319
|
}
|
|
20421
|
-
const bodyRatio = gongmun ?
|
|
21320
|
+
const bodyRatio = gongmun ? GONGMUN_BODY_RATIO : 100;
|
|
20422
21321
|
const rows = [
|
|
20423
21322
|
charPr(0, body, false, false, 0, theme.body, bodyRatio),
|
|
20424
21323
|
charPr(1, body, true, false, 0, theme.body, bodyRatio),
|
|
@@ -20432,6 +21331,14 @@ function buildCharProperties(theme, gongmun) {
|
|
|
20432
21331
|
charPr(CHAR_TABLE_HEADER, body, theme.tableHeaderBold, false, 0, theme.tableHeader),
|
|
20433
21332
|
charPr(CHAR_QUOTE, body, false, true, 0, theme.quote)
|
|
20434
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
|
+
}
|
|
20435
21342
|
return `<hh:charProperties itemCnt="${rows.length}">
|
|
20436
21343
|
${rows.join("\n")}
|
|
20437
21344
|
</hh:charProperties>`;
|
|
@@ -20474,9 +21381,9 @@ ${base2.join("\n")}
|
|
|
20474
21381
|
${base.join("\n")}
|
|
20475
21382
|
</hh:paraProperties>`;
|
|
20476
21383
|
}
|
|
20477
|
-
function generateHeaderXml(theme, gongmun) {
|
|
21384
|
+
function generateHeaderXml(theme, gongmun, ratioVariants = []) {
|
|
20478
21385
|
const bodyFace = gongmun?.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD568\uCD08\uB86C\uBC14\uD0D5";
|
|
20479
|
-
const charPropsXml = buildCharProperties(theme, gongmun);
|
|
21386
|
+
const charPropsXml = buildCharProperties(theme, gongmun, ratioVariants);
|
|
20480
21387
|
const paraPropsXml = buildParaProperties(gongmun);
|
|
20481
21388
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
20482
21389
|
<hh:head xmlns:hh="${NS_HEAD}" xmlns:hp="${NS_PARA}" xmlns:hc="${NS_CORE}" version="1.4" secCnt="1">
|
|
@@ -20532,25 +21439,21 @@ function generateHeaderXml(theme, gongmun) {
|
|
|
20532
21439
|
</hh:fontface>
|
|
20533
21440
|
</hh:fontfaces>
|
|
20534
21441
|
<hh:borderFills itemCnt="2">
|
|
20535
|
-
<hh:borderFill id="
|
|
21442
|
+
<hh:borderFill id="1" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
|
|
20536
21443
|
<hh:slash type="NONE" Crooked="0" isCounter="0"/>
|
|
20537
21444
|
<hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
|
|
20538
21445
|
<hh:leftBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
20539
21446
|
<hh:rightBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
20540
21447
|
<hh:topBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
20541
21448
|
<hh:bottomBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
20542
|
-
<hh:diagonal type="NONE" width="0.1 mm" color="#000000"/>
|
|
20543
|
-
<hh:fillInfo/>
|
|
20544
21449
|
</hh:borderFill>
|
|
20545
|
-
<hh:borderFill id="
|
|
21450
|
+
<hh:borderFill id="2" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
|
|
20546
21451
|
<hh:slash type="NONE" Crooked="0" isCounter="0"/>
|
|
20547
21452
|
<hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
|
|
20548
21453
|
<hh:leftBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
20549
21454
|
<hh:rightBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
20550
21455
|
<hh:topBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
20551
21456
|
<hh:bottomBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
20552
|
-
<hh:diagonal type="NONE" width="0.1 mm" color="#000000"/>
|
|
20553
|
-
<hh:fillInfo/>
|
|
20554
21457
|
</hh:borderFill>
|
|
20555
21458
|
</hh:borderFills>
|
|
20556
21459
|
${charPropsXml}
|
|
@@ -20597,14 +21500,74 @@ function generateTable(rows, theme) {
|
|
|
20597
21500
|
const tdElements = cells.map((cell, colIdx) => {
|
|
20598
21501
|
const runs = generateRuns(cell, headerCharPr);
|
|
20599
21502
|
const p = `<hp:p paraPrIDRef="0" styleIDRef="0">${runs}</hp:p>`;
|
|
20600
|
-
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>`;
|
|
20601
21504
|
}).join("");
|
|
20602
21505
|
return `<hp:tr>${tdElements}</hp:tr>`;
|
|
20603
21506
|
}).join("");
|
|
20604
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;
|
|
20605
|
-
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>`;
|
|
20606
21509
|
return `<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${tbl}</hp:run></hp:p>`;
|
|
20607
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
|
+
}
|
|
20608
21571
|
function precomputeGongmunList(blocks, gongmun) {
|
|
20609
21572
|
const result = /* @__PURE__ */ new Map();
|
|
20610
21573
|
let i = 0;
|
|
@@ -20628,12 +21591,11 @@ function precomputeGongmunList(blocks, gongmun) {
|
|
|
20628
21591
|
}
|
|
20629
21592
|
return result;
|
|
20630
21593
|
}
|
|
20631
|
-
function blocksToSectionXml(blocks, theme, gongmun) {
|
|
21594
|
+
function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null) {
|
|
20632
21595
|
const paraXmls = [];
|
|
20633
21596
|
let isFirst = true;
|
|
20634
21597
|
const orderedCounters = {};
|
|
20635
21598
|
let prevWasOrdered = false;
|
|
20636
|
-
const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
|
|
20637
21599
|
for (let blockIdx = 0; blockIdx < blocks.length; blockIdx++) {
|
|
20638
21600
|
const block = blocks[blockIdx];
|
|
20639
21601
|
let xml = "";
|
|
@@ -20655,7 +21617,7 @@ function blocksToSectionXml(blocks, theme, gongmun) {
|
|
|
20655
21617
|
if (ctr) {
|
|
20656
21618
|
xml = generateParagraph(ctr[1].trim(), GONGMUN_CENTER);
|
|
20657
21619
|
} else {
|
|
20658
|
-
xml = generateParagraph(block.text || "");
|
|
21620
|
+
xml = generateParagraph(block.text || "", PARA_NORMAL, CHAR_NORMAL, fit ? variantMapper(fit, blockIdx) : void 0);
|
|
20659
21621
|
}
|
|
20660
21622
|
break;
|
|
20661
21623
|
}
|
|
@@ -20679,7 +21641,7 @@ function blocksToSectionXml(blocks, theme, gongmun) {
|
|
|
20679
21641
|
const content = block.text || "";
|
|
20680
21642
|
const text = marker2 ? `${marker2} ${content}` : content;
|
|
20681
21643
|
const listCharPr = gongmun.numbering === "report" && depth === 0 ? CHAR_BOLD : CHAR_NORMAL;
|
|
20682
|
-
xml = generateParagraph(text, GONGMUN_LIST_BASE + depth, listCharPr);
|
|
21644
|
+
xml = generateParagraph(text, GONGMUN_LIST_BASE + depth, listCharPr, fit ? variantMapper(fit, blockIdx) : void 0);
|
|
20683
21645
|
break;
|
|
20684
21646
|
}
|
|
20685
21647
|
const indent = block.indent || 0;
|
|
@@ -20702,80 +21664,52 @@ function blocksToSectionXml(blocks, theme, gongmun) {
|
|
|
20702
21664
|
xml = generateParagraph(indentPrefix + marker + (block.text || ""), PARA_LIST);
|
|
20703
21665
|
break;
|
|
20704
21666
|
}
|
|
20705
|
-
case "hr":
|
|
20706
|
-
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>`;
|
|
20707
|
-
break;
|
|
20708
|
-
case "table":
|
|
20709
|
-
if (block.rows) {
|
|
20710
|
-
if (isFirst) {
|
|
20711
|
-
const secRun = `<hp:run charPrIDRef="0">${generateSecPr(gongmun)}<hp:t></hp:t></hp:run>`;
|
|
20712
|
-
paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
|
|
20713
|
-
isFirst = false;
|
|
20714
|
-
}
|
|
20715
|
-
xml = generateTable(block.rows, theme);
|
|
20716
|
-
}
|
|
20717
|
-
break;
|
|
20718
|
-
|
|
20719
|
-
|
|
20720
|
-
|
|
20721
|
-
|
|
20722
|
-
|
|
20723
|
-
|
|
20724
|
-
|
|
20725
|
-
|
|
20726
|
-
|
|
20727
|
-
|
|
20728
|
-
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
|
|
20732
|
-
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
20733
|
-
<hs:sec xmlns:hs="${NS_SECTION}" xmlns:hp="${NS_PARA}">
|
|
20734
|
-
${paraXmls.join("\n ")}
|
|
20735
|
-
</hs:sec>`;
|
|
20736
|
-
}
|
|
20737
|
-
|
|
20738
|
-
// src/diff/text-diff.ts
|
|
20739
|
-
function similarity(a, b) {
|
|
20740
|
-
if (a === b) return 1;
|
|
20741
|
-
if (!a || !b) return 0;
|
|
20742
|
-
const maxLen = Math.max(a.length, b.length);
|
|
20743
|
-
if (maxLen === 0) return 1;
|
|
20744
|
-
return 1 - levenshtein(a, b) / maxLen;
|
|
20745
|
-
}
|
|
20746
|
-
function normalizedSimilarity(a, b) {
|
|
20747
|
-
return similarity(normalize(a), normalize(b));
|
|
20748
|
-
}
|
|
20749
|
-
function normalize(s) {
|
|
20750
|
-
return s.replace(/\s+/g, " ").trim();
|
|
20751
|
-
}
|
|
20752
|
-
var MAX_LEVENSHTEIN_LEN = 1e4;
|
|
20753
|
-
function levenshtein(a, b) {
|
|
20754
|
-
if (a.length + b.length > MAX_LEVENSHTEIN_LEN) {
|
|
20755
|
-
const sampleLen = Math.min(500, a.length, b.length);
|
|
20756
|
-
let diffs = 0;
|
|
20757
|
-
for (let i = 0; i < sampleLen; i++) if (a[i] !== b[i]) diffs++;
|
|
20758
|
-
const sampleRate = sampleLen > 0 ? diffs / sampleLen : 1;
|
|
20759
|
-
return Math.abs(a.length - b.length) + Math.round(Math.min(a.length, b.length) * sampleRate);
|
|
20760
|
-
}
|
|
20761
|
-
if (a.length > b.length) [a, b] = [b, a];
|
|
20762
|
-
const m = a.length;
|
|
20763
|
-
const n = b.length;
|
|
20764
|
-
let prev = Array.from({ length: m + 1 }, (_, i) => i);
|
|
20765
|
-
let curr = new Array(m + 1);
|
|
20766
|
-
for (let j = 1; j <= n; j++) {
|
|
20767
|
-
curr[0] = j;
|
|
20768
|
-
for (let i = 1; i <= m; i++) {
|
|
20769
|
-
if (a[i - 1] === b[j - 1]) {
|
|
20770
|
-
curr[i] = prev[i - 1];
|
|
20771
|
-
} else {
|
|
20772
|
-
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;
|
|
20773
21694
|
}
|
|
20774
21695
|
}
|
|
20775
|
-
;
|
|
20776
|
-
|
|
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);
|
|
20777
21705
|
}
|
|
20778
|
-
|
|
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>`;
|
|
20779
21713
|
}
|
|
20780
21714
|
|
|
20781
21715
|
// src/diff/compare.ts
|
|
@@ -20895,320 +21829,251 @@ function diffTableCells(a, b) {
|
|
|
20895
21829
|
const maxRows = Math.max(a.rows, b.rows);
|
|
20896
21830
|
const maxCols = Math.max(a.cols, b.cols);
|
|
20897
21831
|
const result = [];
|
|
20898
|
-
for (let r = 0; r < maxRows; r++) {
|
|
20899
|
-
const row = [];
|
|
20900
|
-
for (let c = 0; c < maxCols; c++) {
|
|
20901
|
-
const cellA = r < a.rows && c < a.cols ? a.cells[r][c].text : void 0;
|
|
20902
|
-
const cellB = r < b.rows && c < b.cols ? b.cells[r][c].text : void 0;
|
|
20903
|
-
let type;
|
|
20904
|
-
if (cellA === void 0) type = "added";
|
|
20905
|
-
else if (cellB === void 0) type = "removed";
|
|
20906
|
-
else if (cellA === cellB) type = "unchanged";
|
|
20907
|
-
else type = "modified";
|
|
20908
|
-
row.push({ type, before: cellA, after: cellB });
|
|
20909
|
-
}
|
|
20910
|
-
result.push(row);
|
|
20911
|
-
}
|
|
20912
|
-
return result;
|
|
20913
|
-
}
|
|
20914
|
-
|
|
20915
|
-
// src/roundtrip/patcher.ts
|
|
20916
|
-
import JSZip7 from "jszip";
|
|
20917
|
-
|
|
20918
|
-
// src/roundtrip/markdown-units.ts
|
|
20919
|
-
function splitMarkdownUnits(md2) {
|
|
20920
|
-
const lines = md2.split("\n");
|
|
20921
|
-
const units = [];
|
|
20922
|
-
let i = 0;
|
|
20923
|
-
while (i < lines.length) {
|
|
20924
|
-
const line = lines[i];
|
|
20925
|
-
if (!line.trim()) {
|
|
20926
|
-
i++;
|
|
20927
|
-
continue;
|
|
20928
|
-
}
|
|
20929
|
-
if (line.trim().startsWith("<table>")) {
|
|
20930
|
-
const collected2 = [];
|
|
20931
|
-
let depth = 0;
|
|
20932
|
-
while (i < lines.length) {
|
|
20933
|
-
const l = lines[i];
|
|
20934
|
-
collected2.push(l);
|
|
20935
|
-
depth += (l.match(/<table>/g) || []).length;
|
|
20936
|
-
depth -= (l.match(/<\/table>/g) || []).length;
|
|
20937
|
-
i++;
|
|
20938
|
-
if (depth <= 0) break;
|
|
20939
|
-
}
|
|
20940
|
-
units.push({ kind: "html-table", raw: collected2.join("\n"), lines: collected2 });
|
|
20941
|
-
continue;
|
|
20942
|
-
}
|
|
20943
|
-
if (line.trimStart().startsWith("|")) {
|
|
20944
|
-
const collected2 = [];
|
|
20945
|
-
while (i < lines.length && lines[i].trimStart().startsWith("|")) {
|
|
20946
|
-
collected2.push(lines[i]);
|
|
20947
|
-
i++;
|
|
20948
|
-
}
|
|
20949
|
-
units.push({ kind: "gfm-table", raw: collected2.join("\n"), lines: collected2 });
|
|
20950
|
-
continue;
|
|
20951
|
-
}
|
|
20952
|
-
if (/^-{3,}\s*$/.test(line.trim())) {
|
|
20953
|
-
units.push({ kind: "separator", raw: line.trim(), lines: [line.trim()] });
|
|
20954
|
-
i++;
|
|
20955
|
-
continue;
|
|
20956
|
-
}
|
|
20957
|
-
if (/^!\[image\]\([^)]*\)\s*$/.test(line.trim())) {
|
|
20958
|
-
units.push({ kind: "image", raw: line.trim(), lines: [line.trim()] });
|
|
20959
|
-
i++;
|
|
20960
|
-
continue;
|
|
20961
|
-
}
|
|
20962
|
-
const collected = [];
|
|
20963
|
-
while (i < lines.length && lines[i].trim() && !lines[i].trimStart().startsWith("|") && !lines[i].trim().startsWith("<table>")) {
|
|
20964
|
-
collected.push(lines[i].trim());
|
|
20965
|
-
i++;
|
|
20966
|
-
}
|
|
20967
|
-
units.push({ kind: "text", raw: collected.join("\n"), lines: collected });
|
|
20968
|
-
}
|
|
20969
|
-
return units;
|
|
20970
|
-
}
|
|
20971
|
-
function escapeGfm(text) {
|
|
20972
|
-
return text.replace(/~/g, "\\~");
|
|
20973
|
-
}
|
|
20974
|
-
var HWP_SHAPE_ALT_TEXT_RE = /(?:모서리가 둥근 |둥근 )?(?:사각형|직사각형|정사각형|원|타원|삼각형|이등변 삼각형|직각 삼각형|선|직선|곡선|화살표|굵은 화살표|이중 화살표|오각형|육각형|팔각형|별|[4-8]점별|십자|십자형|구름|구름형|마름모|도넛|평행사변형|사다리꼴|부채꼴|호|반원|물결|번개|하트|빗금|블록 화살표|수식|표|그림|개체|그리기\s?개체|묶음\s?개체|글상자|수식\s?개체|OLE\s?개체)\s?입니다\.?/g;
|
|
20975
|
-
function sanitizeText(text) {
|
|
20976
|
-
let result = mapPuaText(text).replace(/[\u{F0000}-\u{FFFFD}]/gu, "").replace(HWP_SHAPE_ALT_TEXT_RE, "").replace(/ +/g, " ").trim();
|
|
20977
|
-
if (result.length <= 30 && result.includes(" ")) {
|
|
20978
|
-
const tokens = result.split(" ");
|
|
20979
|
-
const koreanSingleCharCount = tokens.filter((t) => t.length === 1 && /[가-ㄱ-ㆎ]/.test(t)).length;
|
|
20980
|
-
if (tokens.length >= 3 && koreanSingleCharCount / tokens.length >= 0.7) {
|
|
20981
|
-
result = tokens.join("");
|
|
20982
|
-
}
|
|
20983
|
-
}
|
|
20984
|
-
return result;
|
|
20985
|
-
}
|
|
20986
|
-
function normForMatch(text) {
|
|
20987
|
-
return sanitizeText(text).replace(/\s+/g, " ").trim();
|
|
20988
|
-
}
|
|
20989
|
-
function unescapeGfm(text) {
|
|
20990
|
-
return text.replace(/\\~/g, "~");
|
|
20991
|
-
}
|
|
20992
|
-
function summarize(text) {
|
|
20993
|
-
const t = text.replace(/\s+/g, " ").trim();
|
|
20994
|
-
return t.length > 80 ? t.slice(0, 77) + "..." : t;
|
|
20995
|
-
}
|
|
20996
|
-
function replicateGfmTable(table) {
|
|
20997
|
-
const { cells, rows: numRows, cols: numCols } = table;
|
|
20998
|
-
if (numRows === 0 || numCols === 0) return null;
|
|
20999
|
-
if (numRows === 1 && numCols === 1) return null;
|
|
21000
|
-
if (numCols === 1) return null;
|
|
21001
|
-
const display = Array.from({ length: numRows }, (_, r) => Array.from({ length: numCols }, (_2, c) => ({ text: "", gridR: r, gridC: c })));
|
|
21002
|
-
const skip = /* @__PURE__ */ new Set();
|
|
21003
|
-
for (let r = 0; r < numRows; r++) {
|
|
21004
|
-
for (let c = 0; c < numCols; c++) {
|
|
21005
|
-
if (skip.has(`${r},${c}`)) continue;
|
|
21006
|
-
const cell = cells[r]?.[c];
|
|
21007
|
-
if (!cell) continue;
|
|
21008
|
-
display[r][c] = {
|
|
21009
|
-
text: escapeGfm(sanitizeText(cell.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>"),
|
|
21010
|
-
gridR: r,
|
|
21011
|
-
gridC: c
|
|
21012
|
-
};
|
|
21013
|
-
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
21014
|
-
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
21015
|
-
if (dr === 0 && dc === 0) continue;
|
|
21016
|
-
if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
|
|
21017
|
-
}
|
|
21018
|
-
}
|
|
21019
|
-
c += cell.colSpan - 1;
|
|
21020
|
-
}
|
|
21021
|
-
}
|
|
21022
|
-
const uniqueRows = [];
|
|
21023
|
-
let pendingLabelRow = null;
|
|
21024
|
-
for (let r = 0; r < display.length; r++) {
|
|
21025
|
-
const row = display[r];
|
|
21026
|
-
if (row.every((cell) => cell.text === "")) continue;
|
|
21027
|
-
const nonEmptyCols = row.filter((cell) => cell.text !== "");
|
|
21028
|
-
const hasSkipInRow = row.some((_, c) => skip.has(`${r},${c}`));
|
|
21029
|
-
if (!hasSkipInRow && nonEmptyCols.length === 1 && row[0].text !== "" && row.slice(1).every((c) => c.text === "")) {
|
|
21030
|
-
if (pendingLabelRow) uniqueRows.push(pendingLabelRow);
|
|
21031
|
-
pendingLabelRow = row;
|
|
21032
|
-
continue;
|
|
21033
|
-
}
|
|
21034
|
-
if (pendingLabelRow) {
|
|
21035
|
-
if (row[0].text === "") row[0] = pendingLabelRow[0];
|
|
21036
|
-
else uniqueRows.push(pendingLabelRow);
|
|
21037
|
-
pendingLabelRow = null;
|
|
21038
|
-
}
|
|
21039
|
-
uniqueRows.push(row);
|
|
21040
|
-
}
|
|
21041
|
-
if (pendingLabelRow) uniqueRows.push(pendingLabelRow);
|
|
21042
|
-
return uniqueRows.length > 0 ? uniqueRows : null;
|
|
21043
|
-
}
|
|
21044
|
-
function parseGfmTable(lines) {
|
|
21045
|
-
const rows = [];
|
|
21046
|
-
for (const line of lines) {
|
|
21047
|
-
const trimmed = line.trim();
|
|
21048
|
-
if (!trimmed.startsWith("|")) continue;
|
|
21049
|
-
const cells = trimmed.split(/(?<!\\)\|/).slice(1, -1).map((c) => c.trim());
|
|
21050
|
-
if (cells.length === 0) continue;
|
|
21051
|
-
if (cells.every((c) => /^:?-{3,}:?$/.test(c))) continue;
|
|
21052
|
-
rows.push(cells);
|
|
21053
|
-
}
|
|
21054
|
-
return rows;
|
|
21055
|
-
}
|
|
21056
|
-
function unescapeGfmCell(text) {
|
|
21057
|
-
return text.replace(/<br\s*\/?>/gi, "\n").replace(/\\\|/g, "|").replace(/\\~/g, "~");
|
|
21058
|
-
}
|
|
21059
|
-
function replicateCellInnerHtml(cell) {
|
|
21060
|
-
if (cell.blocks?.length) {
|
|
21061
|
-
return cell.blocks.map((b) => {
|
|
21062
|
-
if (b.type === "table" && b.table) {
|
|
21063
|
-
const cap = b.table.caption ? sanitizeText(b.table.caption) : "";
|
|
21064
|
-
return (cap ? cap + "<br>" : "") + replicateTableToHtml(b.table);
|
|
21065
|
-
}
|
|
21066
|
-
if (b.type === "image" && b.text) return `<img src="${b.text}" alt="image">`;
|
|
21067
|
-
const t = sanitizeText(b.text ?? "");
|
|
21068
|
-
return t ? t.replace(/\n/g, "<br>") : "";
|
|
21069
|
-
}).filter(Boolean).join("<br>");
|
|
21070
|
-
}
|
|
21071
|
-
return sanitizeText(cell.text).replace(/\n/g, "<br>");
|
|
21072
|
-
}
|
|
21073
|
-
function replicateTableToHtml(table) {
|
|
21074
|
-
const rows = replicateHtmlTable(table);
|
|
21075
|
-
const lines = ["<table>"];
|
|
21076
|
-
for (let r = 0; r < rows.length; r++) {
|
|
21077
|
-
const tag = rows[r].tag;
|
|
21078
|
-
const rowHtml = rows[r].cells.map((cell) => {
|
|
21079
|
-
const attrs = [];
|
|
21080
|
-
if (cell.colSpan > 1) attrs.push(`colspan="${cell.colSpan}"`);
|
|
21081
|
-
if (cell.rowSpan > 1) attrs.push(`rowspan="${cell.rowSpan}"`);
|
|
21082
|
-
const attrStr = attrs.length ? " " + attrs.join(" ") : "";
|
|
21083
|
-
return `<${tag}${attrStr}>${cell.inner}</${tag}>`;
|
|
21084
|
-
});
|
|
21085
|
-
if (rowHtml.length) lines.push(`<tr>${rowHtml.join("")}</tr>`);
|
|
21086
|
-
}
|
|
21087
|
-
lines.push("</table>");
|
|
21088
|
-
return lines.join("\n");
|
|
21089
|
-
}
|
|
21090
|
-
function replicateHtmlTable(table) {
|
|
21091
|
-
const { cells, rows: numRows, cols: numCols } = table;
|
|
21092
|
-
const skip = /* @__PURE__ */ new Set();
|
|
21093
|
-
const result = [];
|
|
21094
|
-
for (let r = 0; r < numRows; r++) {
|
|
21095
|
-
const tag = r === 0 ? "th" : "td";
|
|
21096
|
-
const rowCells = [];
|
|
21097
|
-
for (let c = 0; c < numCols; c++) {
|
|
21098
|
-
if (skip.has(`${r},${c}`)) continue;
|
|
21099
|
-
const cell = cells[r]?.[c];
|
|
21100
|
-
if (!cell) continue;
|
|
21101
|
-
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
21102
|
-
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
21103
|
-
if (dr === 0 && dc === 0) continue;
|
|
21104
|
-
if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
|
|
21105
|
-
}
|
|
21106
|
-
}
|
|
21107
|
-
rowCells.push({
|
|
21108
|
-
inner: replicateCellInnerHtml(cell),
|
|
21109
|
-
colSpan: cell.colSpan,
|
|
21110
|
-
rowSpan: cell.rowSpan,
|
|
21111
|
-
gridR: r,
|
|
21112
|
-
gridC: c
|
|
21113
|
-
});
|
|
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 });
|
|
21114
21843
|
}
|
|
21115
|
-
|
|
21844
|
+
result.push(row);
|
|
21116
21845
|
}
|
|
21117
21846
|
return result;
|
|
21118
21847
|
}
|
|
21119
|
-
|
|
21120
|
-
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
|
|
21124
|
-
|
|
21125
|
-
|
|
21126
|
-
|
|
21127
|
-
|
|
21128
|
-
|
|
21129
|
-
|
|
21130
|
-
|
|
21131
|
-
|
|
21132
|
-
|
|
21133
|
-
|
|
21134
|
-
|
|
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");
|
|
21135
21867
|
}
|
|
21136
|
-
|
|
21137
|
-
|
|
21138
|
-
|
|
21139
|
-
|
|
21140
|
-
|
|
21141
|
-
|
|
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");
|
|
21142
21948
|
}
|
|
21143
|
-
}
|
|
21144
|
-
|
|
21145
|
-
|
|
21146
|
-
|
|
21147
|
-
|
|
21148
|
-
|
|
21149
|
-
|
|
21150
|
-
|
|
21151
|
-
|
|
21152
|
-
|
|
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);
|
|
21153
22001
|
}
|
|
21154
22002
|
}
|
|
21155
22003
|
}
|
|
21156
|
-
|
|
21157
|
-
|
|
21158
|
-
}
|
|
21159
|
-
function htmlCellInnerToLines(inner) {
|
|
21160
|
-
let hadNonText = false;
|
|
21161
|
-
let work = inner;
|
|
21162
|
-
if (/<table[\s>]/i.test(work)) {
|
|
21163
|
-
hadNonText = true;
|
|
21164
|
-
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) });
|
|
21165
22007
|
}
|
|
21166
|
-
if (
|
|
21167
|
-
|
|
21168
|
-
|
|
22008
|
+
if (heightDelta !== 0) {
|
|
22009
|
+
const sp = tableSzHeightSplice(xml, scanTable, tblOpen[0].length, heightDelta);
|
|
22010
|
+
if (sp) splices.push(sp);
|
|
21169
22011
|
}
|
|
21170
|
-
|
|
21171
|
-
|
|
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;
|
|
21172
22017
|
}
|
|
21173
|
-
|
|
21174
|
-
|
|
21175
|
-
|
|
21176
|
-
|
|
21177
|
-
const
|
|
21178
|
-
|
|
21179
|
-
|
|
21180
|
-
|
|
21181
|
-
|
|
21182
|
-
|
|
21183
|
-
|
|
21184
|
-
|
|
21185
|
-
|
|
21186
|
-
|
|
21187
|
-
|
|
21188
|
-
}
|
|
21189
|
-
|
|
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);
|
|
21190
22043
|
}
|
|
21191
22044
|
}
|
|
21192
|
-
|
|
22045
|
+
const patched = applySplices(wrapped, splices);
|
|
22046
|
+
return patched.slice(FRAG_OPEN.length, patched.length - FRAG_CLOSE.length);
|
|
21193
22047
|
}
|
|
21194
|
-
function
|
|
21195
|
-
|
|
21196
|
-
|
|
21197
|
-
const
|
|
21198
|
-
|
|
21199
|
-
|
|
21200
|
-
|
|
21201
|
-
|
|
21202
|
-
|
|
21203
|
-
|
|
21204
|
-
|
|
21205
|
-
|
|
21206
|
-
|
|
21207
|
-
|
|
21208
|
-
}
|
|
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));
|
|
21209
22062
|
}
|
|
21210
|
-
|
|
21211
|
-
|
|
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) };
|
|
21212
22077
|
}
|
|
21213
22078
|
|
|
21214
22079
|
// src/roundtrip/table-patch.ts
|
|
@@ -21220,37 +22085,89 @@ function patchGfmTable(table, scanTable, orig, edited, ctx, skip) {
|
|
|
21220
22085
|
if (replica.length !== origRows.length || replica.some((row, r) => row.length !== origRows[r].length || row.some((c, j) => c.text !== origRows[r][j]))) {
|
|
21221
22086
|
return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
21222
22087
|
}
|
|
21223
|
-
if (editedRows.length !== origRows.length)
|
|
22088
|
+
if (editedRows.length !== origRows.length) {
|
|
22089
|
+
return patchGfmTableRows(table, scanTable, origRows, editedRows, replica, ctx, skip);
|
|
22090
|
+
}
|
|
21224
22091
|
let applied = 0;
|
|
21225
22092
|
for (let r = 0; r < origRows.length; r++) {
|
|
21226
|
-
|
|
21227
|
-
|
|
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");
|
|
21228
22110
|
continue;
|
|
21229
22111
|
}
|
|
21230
|
-
|
|
21231
|
-
|
|
21232
|
-
|
|
21233
|
-
|
|
21234
|
-
|
|
21235
|
-
|
|
21236
|
-
|
|
21237
|
-
|
|
21238
|
-
|
|
21239
|
-
|
|
21240
|
-
const origLines = unescapeGfmCell(stripCellTokens(origRows[r][c])).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
21241
|
-
const n = applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, origRows[r][c], editedRows[r][c], origLines.length);
|
|
21242
|
-
if (n > 0 && origTokens) {
|
|
21243
|
-
ctx.skipped.push({
|
|
21244
|
-
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)",
|
|
21245
|
-
before: summarize(origRows[r][c]),
|
|
21246
|
-
after: summarize(editedRows[r][c])
|
|
21247
|
-
});
|
|
21248
|
-
}
|
|
21249
|
-
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
|
+
});
|
|
21250
22122
|
}
|
|
22123
|
+
applied += n;
|
|
21251
22124
|
}
|
|
21252
22125
|
return applied;
|
|
21253
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
|
+
}
|
|
21254
22171
|
function patchHtmlTable(table, scanTable, orig, edited, ctx, skip) {
|
|
21255
22172
|
return patchHtmlTableRaw(table, scanTable, orig.raw, edited.raw, ctx, skip, 0);
|
|
21256
22173
|
}
|
|
@@ -21264,46 +22181,77 @@ function patchHtmlTableRaw(table, scanTable, origRaw, editedRaw, ctx, skip, dept
|
|
|
21264
22181
|
}
|
|
21265
22182
|
const editedRows = parseHtmlTable(editedRaw);
|
|
21266
22183
|
if (!editedRows) return skip("\uD3B8\uC9D1\uB41C HTML \uD45C \uD30C\uC2F1 \uC2E4\uD328");
|
|
21267
|
-
if (editedRows.length !== replica.length)
|
|
22184
|
+
if (editedRows.length !== replica.length) {
|
|
22185
|
+
return patchHtmlTableRows(table, scanTable, replica, editedRows, ctx, skip, depth);
|
|
22186
|
+
}
|
|
21268
22187
|
let applied = 0;
|
|
21269
22188
|
for (let r = 0; r < replica.length; r++) {
|
|
21270
|
-
|
|
21271
|
-
|
|
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`);
|
|
21272
22204
|
continue;
|
|
21273
22205
|
}
|
|
21274
|
-
|
|
21275
|
-
|
|
21276
|
-
|
|
21277
|
-
|
|
21278
|
-
|
|
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");
|
|
21279
22212
|
continue;
|
|
21280
22213
|
}
|
|
21281
|
-
|
|
21282
|
-
const
|
|
21283
|
-
|
|
21284
|
-
|
|
21285
|
-
|
|
21286
|
-
skip("\uC140 \uB0B4 \uC774\uBBF8\uC9C0 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
21287
|
-
continue;
|
|
21288
|
-
}
|
|
21289
|
-
const origTables = extractTopLevelTables(oc.inner);
|
|
21290
|
-
const editedTables = extractTopLevelTables(ec.inner);
|
|
21291
|
-
if (origTables.length !== editedTables.length) {
|
|
21292
|
-
skip("\uC140 \uB0B4 \uC911\uCCA9\uD45C \uCD94\uAC00/\uC0AD\uC81C\uB294 \uBBF8\uC9C0\uC6D0");
|
|
21293
|
-
continue;
|
|
21294
|
-
}
|
|
21295
|
-
if (origTables.join("\n") !== editedTables.join("\n")) {
|
|
21296
|
-
applied += patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth);
|
|
21297
|
-
}
|
|
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;
|
|
21298
22219
|
}
|
|
21299
|
-
if (
|
|
21300
|
-
|
|
21301
|
-
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);
|
|
21302
22222
|
}
|
|
21303
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
|
+
}
|
|
21304
22228
|
}
|
|
21305
22229
|
return applied;
|
|
21306
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
|
+
}
|
|
21307
22255
|
function patchNestedTables(table, scanTable, oc, origTables, editedTables, ctx, skip, depth) {
|
|
21308
22256
|
const irCell = table.cells[oc.gridR]?.[oc.gridC];
|
|
21309
22257
|
const scanCell = scanTable.cellByAnchor.get(`${oc.gridR},${oc.gridC}`);
|
|
@@ -21403,7 +22351,7 @@ function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, af
|
|
|
21403
22351
|
splices.push(...sp);
|
|
21404
22352
|
sectionIndex = target.sectionIndex;
|
|
21405
22353
|
if (newLines.length > 1) {
|
|
21406
|
-
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 });
|
|
21407
22355
|
}
|
|
21408
22356
|
} else {
|
|
21409
22357
|
const assigned = [];
|
|
@@ -21415,7 +22363,9 @@ function applyCellEdit(table, scanTable, gridR, gridC, newLines, ctx, before, af
|
|
|
21415
22363
|
}
|
|
21416
22364
|
}
|
|
21417
22365
|
if (newLines.length > nonEmpty.length) {
|
|
21418
|
-
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 });
|
|
21419
22369
|
}
|
|
21420
22370
|
for (let i = 0; i < nonEmpty.length; i++) {
|
|
21421
22371
|
if (assigned[i] === nonEmpty[i].text || normForMatch(assigned[i]) === normForMatch(nonEmpty[i].text)) continue;
|
|
@@ -21588,7 +22538,8 @@ async function patchHwpx(original, editedMarkdown, options) {
|
|
|
21588
22538
|
try {
|
|
21589
22539
|
for (let i = 0; i < scans.length; i++) {
|
|
21590
22540
|
if (sectionSplices[i].length === 0) continue;
|
|
21591
|
-
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)));
|
|
21592
22543
|
const newXml = applySplices(scans[i].xml, sectionSplices[i]);
|
|
21593
22544
|
replacements.set(sectionPaths[i], encoder.encode(newXml));
|
|
21594
22545
|
}
|
|
@@ -21656,82 +22607,6 @@ function buildTableOrdinals(blocks) {
|
|
|
21656
22607
|
}
|
|
21657
22608
|
return map;
|
|
21658
22609
|
}
|
|
21659
|
-
function alignUnits(a, b) {
|
|
21660
|
-
const m = a.length, n = b.length;
|
|
21661
|
-
if (m * n > 4e6) {
|
|
21662
|
-
const result2 = [];
|
|
21663
|
-
let pre = 0;
|
|
21664
|
-
while (pre < m && pre < n && a[pre] === b[pre]) {
|
|
21665
|
-
result2.push([pre, pre]);
|
|
21666
|
-
pre++;
|
|
21667
|
-
}
|
|
21668
|
-
let suf = 0;
|
|
21669
|
-
while (suf < m - pre && suf < n - pre && a[m - 1 - suf] === b[n - 1 - suf]) suf++;
|
|
21670
|
-
const aMid = m - pre - suf, bMid = n - pre - suf;
|
|
21671
|
-
if (aMid === bMid) {
|
|
21672
|
-
for (let i2 = 0; i2 < aMid; i2++) result2.push([pre + i2, pre + i2]);
|
|
21673
|
-
} else {
|
|
21674
|
-
for (let i2 = 0; i2 < aMid; i2++) result2.push([pre + i2, null]);
|
|
21675
|
-
for (let j2 = 0; j2 < bMid; j2++) result2.push([null, pre + j2]);
|
|
21676
|
-
}
|
|
21677
|
-
for (let s = suf - 1; s >= 0; s--) result2.push([m - 1 - s, n - 1 - s]);
|
|
21678
|
-
return result2;
|
|
21679
|
-
}
|
|
21680
|
-
const dp = Array.from({ length: m + 1 }, () => new Int32Array(n + 1));
|
|
21681
|
-
for (let i2 = 1; i2 <= m; i2++) {
|
|
21682
|
-
for (let j2 = 1; j2 <= n; j2++) {
|
|
21683
|
-
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]);
|
|
21684
|
-
}
|
|
21685
|
-
}
|
|
21686
|
-
const matches = [];
|
|
21687
|
-
let i = m, j = n;
|
|
21688
|
-
while (i > 0 && j > 0) {
|
|
21689
|
-
if (a[i - 1] === b[j - 1] && dp[i][j] === dp[i - 1][j - 1] + 1) {
|
|
21690
|
-
matches.push([i - 1, j - 1]);
|
|
21691
|
-
i--;
|
|
21692
|
-
j--;
|
|
21693
|
-
} else if (dp[i - 1][j] >= dp[i][j - 1]) i--;
|
|
21694
|
-
else j--;
|
|
21695
|
-
}
|
|
21696
|
-
matches.reverse();
|
|
21697
|
-
const result = [];
|
|
21698
|
-
let ai = 0, bi = 0;
|
|
21699
|
-
const flushGap = (aEnd, bEnd) => {
|
|
21700
|
-
if (aEnd - ai === bEnd - bi) {
|
|
21701
|
-
while (ai < aEnd) result.push([ai++, bi++]);
|
|
21702
|
-
return;
|
|
21703
|
-
}
|
|
21704
|
-
while (ai < aEnd && bi < bEnd) {
|
|
21705
|
-
const sim = normalizedSimilarity(a[ai], b[bi]);
|
|
21706
|
-
if (sim >= 0.4) {
|
|
21707
|
-
if (aEnd - ai > bEnd - bi && bestSimInRange(a, ai + 1, ai + (aEnd - ai) - (bEnd - bi), b[bi]) > sim) {
|
|
21708
|
-
result.push([ai++, null]);
|
|
21709
|
-
} else if (bEnd - bi > aEnd - ai && bestSimInRange(b, bi + 1, bi + (bEnd - bi) - (aEnd - ai), a[ai]) > sim) {
|
|
21710
|
-
result.push([null, bi++]);
|
|
21711
|
-
} else {
|
|
21712
|
-
result.push([ai++, bi++]);
|
|
21713
|
-
}
|
|
21714
|
-
} else if (aEnd - ai >= bEnd - bi) result.push([ai++, null]);
|
|
21715
|
-
else result.push([null, bi++]);
|
|
21716
|
-
}
|
|
21717
|
-
while (ai < aEnd) result.push([ai++, null]);
|
|
21718
|
-
while (bi < bEnd) result.push([null, bi++]);
|
|
21719
|
-
};
|
|
21720
|
-
for (const [pi, pj] of matches) {
|
|
21721
|
-
flushGap(pi, pj);
|
|
21722
|
-
result.push([ai++, bi++]);
|
|
21723
|
-
}
|
|
21724
|
-
flushGap(m, n);
|
|
21725
|
-
return result;
|
|
21726
|
-
}
|
|
21727
|
-
function bestSimInRange(arr, from, to, target) {
|
|
21728
|
-
let best = 0;
|
|
21729
|
-
for (let k = from; k <= to && k < arr.length; k++) {
|
|
21730
|
-
const s = normalizedSimilarity(arr[k], target);
|
|
21731
|
-
if (s > best) best = s;
|
|
21732
|
-
}
|
|
21733
|
-
return best;
|
|
21734
|
-
}
|
|
21735
22610
|
function resolveParagraphMappings(blocks, scans) {
|
|
21736
22611
|
const buckets = /* @__PURE__ */ new Map();
|
|
21737
22612
|
for (const scan of scans) {
|
|
@@ -21874,7 +22749,7 @@ function patchParagraphUnit(block, orig, edited, ctx, skip) {
|
|
|
21874
22749
|
const origPrefix = block.text.split(" ", 1)[0];
|
|
21875
22750
|
const sp = newPlain.indexOf(" ");
|
|
21876
22751
|
const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain;
|
|
21877
|
-
if (newFirst === origPrefix ||
|
|
22752
|
+
if (newFirst === origPrefix || AUTONUM_PREFIX_RE.test(newFirst)) {
|
|
21878
22753
|
newPlain = sp > 0 ? newPlain.slice(sp + 1) : "";
|
|
21879
22754
|
} else {
|
|
21880
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) });
|
|
@@ -22617,7 +23492,7 @@ function patchParagraph(block, orig, edited, ctx, skip) {
|
|
|
22617
23492
|
const origPrefix = block.text.split(" ", 1)[0];
|
|
22618
23493
|
const sp = newPlain.indexOf(" ");
|
|
22619
23494
|
const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain;
|
|
22620
|
-
if (newFirst === origPrefix ||
|
|
23495
|
+
if (newFirst === origPrefix || AUTONUM_PREFIX_RE.test(newFirst)) {
|
|
22621
23496
|
newPlain = sp > 0 ? newPlain.slice(sp + 1) : "";
|
|
22622
23497
|
} else {
|
|
22623
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) });
|
|
@@ -22682,9 +23557,6 @@ function patchGfmCells(scanTable, orig, edited, ctx, skip) {
|
|
|
22682
23557
|
}
|
|
22683
23558
|
return applied;
|
|
22684
23559
|
}
|
|
22685
|
-
function extractImgTags5(inner) {
|
|
22686
|
-
return (inner.match(/<img\s(?:"[^"]*"|'[^']*'|[^>"'])*?>/gi) || []).join(" ");
|
|
22687
|
-
}
|
|
22688
23560
|
function patchHtmlCells5(table, scanTable, orig, edited, ctx, skip) {
|
|
22689
23561
|
if (replicateTableToHtml(table) !== orig.raw) return skip("\uD45C \uC88C\uD45C \uC7AC\uD604 \uBD88\uC77C\uCE58 \u2014 \uB9E4\uD551 \uC2E0\uB8B0 \uBD88\uAC00");
|
|
22690
23562
|
const replica = replicateHtmlTable(table);
|
|
@@ -22712,7 +23584,7 @@ function patchHtmlCells5(table, scanTable, orig, edited, ctx, skip) {
|
|
|
22712
23584
|
const origContent = htmlCellInnerToLines(oc.inner);
|
|
22713
23585
|
const editedContent = htmlCellInnerToLines(ec.inner);
|
|
22714
23586
|
if (origContent.hadNonText || editedContent.hadNonText) {
|
|
22715
|
-
if (
|
|
23587
|
+
if (extractImgTags(oc.inner) !== extractImgTags(ec.inner)) {
|
|
22716
23588
|
skip("\uC140 \uB0B4 \uC774\uBBF8\uC9C0 \uBCC0\uACBD\uC740 \uBBF8\uC9C0\uC6D0");
|
|
22717
23589
|
continue;
|
|
22718
23590
|
}
|
|
@@ -22803,7 +23675,9 @@ function applyCellEdit5(table, scanTable, gridR, gridC, newLines, ctx, before, a
|
|
|
22803
23675
|
}
|
|
22804
23676
|
}
|
|
22805
23677
|
if (newLines.length > nonEmpty.length) {
|
|
22806
|
-
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 });
|
|
22807
23681
|
}
|
|
22808
23682
|
let staged = 0;
|
|
22809
23683
|
for (let i = 0; i < nonEmpty.length; i++) {
|
|
@@ -23178,6 +24052,7 @@ var HwpxSession = class _HwpxSession {
|
|
|
23178
24052
|
try {
|
|
23179
24053
|
for (let s = 0; s < st.scans.length; s++) {
|
|
23180
24054
|
if (sectionSplices[s].length === 0) continue;
|
|
24055
|
+
sectionSplices[s].push(...allLinesegRemovalSplices(st.scans[s].xml));
|
|
23181
24056
|
replacements.set(st.sectionPaths[s], encoder.encode(applySplices(st.scans[s].xml, sectionSplices[s])));
|
|
23182
24057
|
}
|
|
23183
24058
|
} catch (err) {
|
|
@@ -23234,7 +24109,7 @@ var HwpxSession = class _HwpxSession {
|
|
|
23234
24109
|
const origPrefix = block.text.split(" ", 1)[0];
|
|
23235
24110
|
const sp = newPlain.indexOf(" ");
|
|
23236
24111
|
const newFirst = sp > 0 ? newPlain.slice(0, sp) : newPlain;
|
|
23237
|
-
if (newFirst === origPrefix ||
|
|
24112
|
+
if (newFirst === origPrefix || AUTONUM_PREFIX_RE.test(newFirst)) {
|
|
23238
24113
|
newPlain = sp > 0 ? newPlain.slice(sp + 1) : "";
|
|
23239
24114
|
} else {
|
|
23240
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) });
|
|
@@ -23528,7 +24403,7 @@ async function parseHwp(buffer, options) {
|
|
|
23528
24403
|
async function parsePdf(buffer, options) {
|
|
23529
24404
|
let parsePdfDocument;
|
|
23530
24405
|
try {
|
|
23531
|
-
const mod = await import("./parser-
|
|
24406
|
+
const mod = await import("./parser-ZHJFQR44.js");
|
|
23532
24407
|
parsePdfDocument = mod.parsePdfDocument;
|
|
23533
24408
|
} catch {
|
|
23534
24409
|
return {
|
|
@@ -23620,12 +24495,16 @@ async function fillForm(input, values, outputFormat = "markdown") {
|
|
|
23620
24495
|
export {
|
|
23621
24496
|
HwpxSession,
|
|
23622
24497
|
PRESET_ALIAS,
|
|
24498
|
+
SPACE_EM_FIXED,
|
|
24499
|
+
SPACE_EM_FONT,
|
|
23623
24500
|
VERSION,
|
|
24501
|
+
ValueCursor,
|
|
23624
24502
|
applySplices,
|
|
23625
24503
|
blocksToMarkdown,
|
|
23626
24504
|
blocksToPdf,
|
|
23627
24505
|
buildParagraphSplices,
|
|
23628
24506
|
buildRangeSplices,
|
|
24507
|
+
charWidthEm1000,
|
|
23629
24508
|
compare,
|
|
23630
24509
|
detectFormat,
|
|
23631
24510
|
detectOle2Format,
|
|
@@ -23636,6 +24515,7 @@ export {
|
|
|
23636
24515
|
fillForm,
|
|
23637
24516
|
fillFormFields,
|
|
23638
24517
|
fillHwpx,
|
|
24518
|
+
fitRatioForFewerLines,
|
|
23639
24519
|
inferFieldType,
|
|
23640
24520
|
isHwpxFile,
|
|
23641
24521
|
isLabelCell,
|
|
@@ -23644,6 +24524,7 @@ export {
|
|
|
23644
24524
|
isZipFile,
|
|
23645
24525
|
markdownToHwpx,
|
|
23646
24526
|
markdownToPdf,
|
|
24527
|
+
measureTextWidth,
|
|
23647
24528
|
normalizeGongmunPreset,
|
|
23648
24529
|
openHwpxDocument,
|
|
23649
24530
|
parse,
|
|
@@ -23659,6 +24540,8 @@ export {
|
|
|
23659
24540
|
patchHwpx,
|
|
23660
24541
|
patchHwpxBlocks,
|
|
23661
24542
|
renderHtml,
|
|
23662
|
-
scanSectionXml
|
|
24543
|
+
scanSectionXml,
|
|
24544
|
+
simulateWrap,
|
|
24545
|
+
simulateWrapKeepWord
|
|
23663
24546
|
};
|
|
23664
24547
|
//# sourceMappingURL=index.js.map
|