kordoc 3.8.1 → 3.8.2
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 +5 -0
- package/dist/{-LD4BZDDJ.js → -FEHSMPVO.js} +3 -3
- package/dist/{chunk-PELBIL4K.js → chunk-553VTUVP.js} +2 -2
- package/dist/{chunk-KT2BCHXI.js → chunk-DP37KF2X.js} +834 -822
- package/dist/chunk-DP37KF2X.js.map +1 -0
- package/dist/{chunk-IFYJFWD2.js → chunk-JHZUFBUV.js} +2 -2
- package/dist/{chunk-LFCS3UVG.cjs → chunk-YBPNKFJW.cjs} +2 -2
- package/dist/{chunk-LFCS3UVG.cjs.map → chunk-YBPNKFJW.cjs.map} +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.cjs +946 -934
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -8
- package/dist/index.d.ts +17 -8
- package/dist/index.js +833 -821
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +3 -3
- package/dist/{parser-FFEBMLSH.js → parser-KNQDRLZQ.js} +60 -20
- package/dist/parser-KNQDRLZQ.js.map +1 -0
- package/dist/{parser-XEDROIM7.js → parser-NR2TYGO3.js} +60 -20
- package/dist/parser-NR2TYGO3.js.map +1 -0
- package/dist/{parser-IXK5V7YG.cjs → parser-NS4ZPD7B.cjs} +77 -35
- package/dist/parser-NS4ZPD7B.cjs.map +1 -0
- package/dist/{watch-MAWCDNFI.js → watch-XCWADLPU.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-KT2BCHXI.js.map +0 -1
- package/dist/parser-FFEBMLSH.js.map +0 -1
- package/dist/parser-IXK5V7YG.cjs.map +0 -1
- package/dist/parser-XEDROIM7.js.map +0 -1
- /package/dist/{-LD4BZDDJ.js.map → -FEHSMPVO.js.map} +0 -0
- /package/dist/{chunk-PELBIL4K.js.map → chunk-553VTUVP.js.map} +0 -0
- /package/dist/{chunk-IFYJFWD2.js.map → chunk-JHZUFBUV.js.map} +0 -0
- /package/dist/{watch-MAWCDNFI.js.map → watch-XCWADLPU.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-553VTUVP.js";
|
|
23
23
|
import {
|
|
24
24
|
parsePageRange
|
|
25
25
|
} from "./chunk-GE43BE46.js";
|
|
@@ -20622,53 +20622,112 @@ function mmToHwpunit(mm) {
|
|
|
20622
20622
|
return Math.round(mm * 7200 / 25.4);
|
|
20623
20623
|
}
|
|
20624
20624
|
|
|
20625
|
-
// src/
|
|
20626
|
-
|
|
20627
|
-
|
|
20628
|
-
|
|
20629
|
-
|
|
20630
|
-
|
|
20631
|
-
|
|
20625
|
+
// src/hwpx/gen-ids.ts
|
|
20626
|
+
var NS_SECTION = "http://www.hancom.co.kr/hwpml/2011/section";
|
|
20627
|
+
var NS_PARA = "http://www.hancom.co.kr/hwpml/2011/paragraph";
|
|
20628
|
+
var NS_HEAD = "http://www.hancom.co.kr/hwpml/2011/head";
|
|
20629
|
+
var NS_CORE = "http://www.hancom.co.kr/hwpml/2011/core";
|
|
20630
|
+
var NS_OPF = "http://www.idpf.org/2007/opf/";
|
|
20631
|
+
var NS_HPF = "http://www.hancom.co.kr/schema/2011/hpf";
|
|
20632
|
+
var NS_OCF = "urn:oasis:names:tc:opendocument:xmlns:container";
|
|
20633
|
+
var CHAR_NORMAL = 0;
|
|
20634
|
+
var CHAR_BOLD = 1;
|
|
20635
|
+
var CHAR_ITALIC = 2;
|
|
20636
|
+
var CHAR_BOLD_ITALIC = 3;
|
|
20637
|
+
var CHAR_CODE = 4;
|
|
20638
|
+
var CHAR_H1 = 5;
|
|
20639
|
+
var CHAR_H2 = 6;
|
|
20640
|
+
var CHAR_H3 = 7;
|
|
20641
|
+
var CHAR_H4 = 8;
|
|
20642
|
+
var CHAR_TABLE_HEADER = 9;
|
|
20643
|
+
var CHAR_QUOTE = 10;
|
|
20644
|
+
var PARA_NORMAL = 0;
|
|
20645
|
+
var PARA_H1 = 1;
|
|
20646
|
+
var PARA_H2 = 2;
|
|
20647
|
+
var PARA_H3 = 3;
|
|
20648
|
+
var PARA_H4 = 4;
|
|
20649
|
+
var PARA_CODE = 5;
|
|
20650
|
+
var PARA_QUOTE = 6;
|
|
20651
|
+
var PARA_LIST = 7;
|
|
20652
|
+
var DEFAULT_TEXT_COLOR = "#000000";
|
|
20653
|
+
function resolveTheme(theme) {
|
|
20654
|
+
return {
|
|
20655
|
+
h1: theme?.headingColors?.[1] ?? DEFAULT_TEXT_COLOR,
|
|
20656
|
+
h2: theme?.headingColors?.[2] ?? DEFAULT_TEXT_COLOR,
|
|
20657
|
+
h3: theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,
|
|
20658
|
+
h4: theme?.headingColors?.[4] ?? theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,
|
|
20659
|
+
body: theme?.bodyColor ?? DEFAULT_TEXT_COLOR,
|
|
20660
|
+
quote: theme?.quoteColor ?? DEFAULT_TEXT_COLOR,
|
|
20661
|
+
/** quoteColor가 명시되었는지 — blockquote charPr 분기에 사용 (baseline 호환) */
|
|
20662
|
+
hasQuoteOption: theme?.quoteColor !== void 0,
|
|
20663
|
+
tableHeader: theme?.tableHeaderColor ?? theme?.bodyColor ?? DEFAULT_TEXT_COLOR,
|
|
20664
|
+
tableHeaderBold: !!theme?.tableHeaderBold
|
|
20665
|
+
};
|
|
20632
20666
|
}
|
|
20633
|
-
function
|
|
20634
|
-
return
|
|
20667
|
+
function escapeXml(text) {
|
|
20668
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
20635
20669
|
}
|
|
20636
|
-
function
|
|
20637
|
-
|
|
20670
|
+
function headingParaPrId(level) {
|
|
20671
|
+
if (level === 1) return PARA_H1;
|
|
20672
|
+
if (level === 2) return PARA_H2;
|
|
20673
|
+
if (level === 3) return PARA_H3;
|
|
20674
|
+
return PARA_H4;
|
|
20638
20675
|
}
|
|
20639
|
-
|
|
20640
|
-
|
|
20641
|
-
if (
|
|
20642
|
-
|
|
20643
|
-
|
|
20644
|
-
|
|
20645
|
-
|
|
20646
|
-
|
|
20647
|
-
|
|
20648
|
-
|
|
20649
|
-
|
|
20650
|
-
|
|
20651
|
-
|
|
20652
|
-
|
|
20653
|
-
|
|
20654
|
-
|
|
20655
|
-
|
|
20656
|
-
|
|
20657
|
-
|
|
20658
|
-
|
|
20659
|
-
|
|
20660
|
-
|
|
20661
|
-
|
|
20662
|
-
|
|
20663
|
-
|
|
20664
|
-
|
|
20665
|
-
|
|
20676
|
+
function headingCharPrId(level) {
|
|
20677
|
+
if (level === 1) return CHAR_H1;
|
|
20678
|
+
if (level === 2) return CHAR_H2;
|
|
20679
|
+
if (level === 3) return CHAR_H3;
|
|
20680
|
+
return CHAR_H4;
|
|
20681
|
+
}
|
|
20682
|
+
function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_COLOR, ratioPct = 100) {
|
|
20683
|
+
const boldAttr = bold ? ` bold="1"` : "";
|
|
20684
|
+
const italicAttr = italic ? ` italic="1"` : "";
|
|
20685
|
+
const effFont = bold ? 2 : fontId;
|
|
20686
|
+
return ` <hh:charPr id="${id}" height="${height}" textColor="${textColor}" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="1"${boldAttr}${italicAttr}>
|
|
20687
|
+
<hh:fontRef hangul="${effFont}" latin="${effFont}" hanja="${effFont}" japanese="${effFont}" other="${effFont}" symbol="${effFont}" user="${effFont}"/>
|
|
20688
|
+
<hh:ratio hangul="${ratioPct}" latin="${ratioPct}" hanja="${ratioPct}" japanese="100" other="100" symbol="100" user="100"/>
|
|
20689
|
+
<hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
|
|
20690
|
+
<hh:relSz hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
|
|
20691
|
+
<hh:offset hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
|
|
20692
|
+
</hh:charPr>`;
|
|
20693
|
+
}
|
|
20694
|
+
function paraPr(id, opts = {}) {
|
|
20695
|
+
const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0, left = 0, keepWord = false } = opts;
|
|
20696
|
+
const breakNonLatin = keepWord ? "KEEP_WORD" : "BREAK_WORD";
|
|
20697
|
+
const snapGrid = keepWord ? "0" : "1";
|
|
20698
|
+
return ` <hh:paraPr id="${id}" tabPrIDRef="0" condense="0" fontLineHeight="0" snapToGrid="${snapGrid}" suppressLineNumbers="0" checked="0" textDir="AUTO">
|
|
20699
|
+
<hh:align horizontal="${align}" vertical="BASELINE"/>
|
|
20700
|
+
<hh:heading type="NONE" idRef="0" level="0"/>
|
|
20701
|
+
<hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="${breakNonLatin}" widowOrphan="0" keepWithNext="0" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/>
|
|
20702
|
+
<hh:autoSpacing eAsianEng="0" eAsianNum="0"/>
|
|
20703
|
+
<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>
|
|
20704
|
+
<hh:lineSpacing type="PERCENT" value="${lineSpacing}"/>
|
|
20705
|
+
<hh:border borderFillIDRef="1" offsetLeft="0" offsetRight="0" offsetTop="0" offsetBottom="0" connect="0" ignoreMargin="0"/>
|
|
20706
|
+
</hh:paraPr>`;
|
|
20666
20707
|
}
|
|
20708
|
+
var GONGMUN_LIST_BASE = 8;
|
|
20709
|
+
var GONGMUN_LIST_LEVELS = 8;
|
|
20710
|
+
var GONGMUN_CENTER = GONGMUN_LIST_BASE + GONGMUN_LIST_LEVELS;
|
|
20711
|
+
var CHAR_VARIANT_BASE = 11;
|
|
20712
|
+
var GONGMUN_BODY_RATIO = 95;
|
|
20667
20713
|
|
|
20668
|
-
// src/
|
|
20669
|
-
function
|
|
20714
|
+
// src/hwpx/md-runs.ts
|
|
20715
|
+
function buildPrvText(blocks) {
|
|
20716
|
+
const lines = [];
|
|
20717
|
+
let bytes = 0;
|
|
20718
|
+
for (const b of blocks) {
|
|
20719
|
+
let text = b.text || (b.rows ? b.rows.map((r) => r.join(" ")).join("\n") : "");
|
|
20720
|
+
if (b.type === "html_table") text = text.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
20721
|
+
if (!text) continue;
|
|
20722
|
+
lines.push(text);
|
|
20723
|
+
bytes += text.length * 3;
|
|
20724
|
+
if (bytes > 1024) break;
|
|
20725
|
+
}
|
|
20726
|
+
return lines.join("\n").slice(0, 1024);
|
|
20727
|
+
}
|
|
20728
|
+
function parseMarkdownToBlocks(md2) {
|
|
20670
20729
|
const lines = md2.split("\n");
|
|
20671
|
-
const
|
|
20730
|
+
const blocks = [];
|
|
20672
20731
|
let i = 0;
|
|
20673
20732
|
while (i < lines.length) {
|
|
20674
20733
|
const line = lines[i];
|
|
@@ -20676,442 +20735,451 @@ function splitMarkdownUnits(md2) {
|
|
|
20676
20735
|
i++;
|
|
20677
20736
|
continue;
|
|
20678
20737
|
}
|
|
20679
|
-
|
|
20680
|
-
|
|
20738
|
+
const fenceMatch = line.match(/^(`{3,}|~{3,})(.*)$/);
|
|
20739
|
+
if (fenceMatch) {
|
|
20740
|
+
const fence = fenceMatch[1];
|
|
20741
|
+
const lang = fenceMatch[2].trim();
|
|
20742
|
+
const codeLines = [];
|
|
20743
|
+
i++;
|
|
20744
|
+
while (i < lines.length && !lines[i].startsWith(fence)) {
|
|
20745
|
+
codeLines.push(lines[i]);
|
|
20746
|
+
i++;
|
|
20747
|
+
}
|
|
20748
|
+
if (i < lines.length) i++;
|
|
20749
|
+
blocks.push({ type: "code_block", text: codeLines.join("\n"), lang });
|
|
20750
|
+
continue;
|
|
20751
|
+
}
|
|
20752
|
+
if (/^(\*{3,}|-{3,}|_{3,})\s*$/.test(line.trim())) {
|
|
20753
|
+
blocks.push({ type: "hr" });
|
|
20754
|
+
i++;
|
|
20755
|
+
continue;
|
|
20756
|
+
}
|
|
20757
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
20758
|
+
if (headingMatch) {
|
|
20759
|
+
blocks.push({ type: "heading", text: headingMatch[2].trim(), level: headingMatch[1].length });
|
|
20760
|
+
i++;
|
|
20761
|
+
continue;
|
|
20762
|
+
}
|
|
20763
|
+
if (/^<table[\s>]/i.test(line.trimStart())) {
|
|
20764
|
+
const htmlLines = [];
|
|
20681
20765
|
let depth = 0;
|
|
20682
20766
|
while (i < lines.length) {
|
|
20683
20767
|
const l = lines[i];
|
|
20684
|
-
|
|
20685
|
-
depth += (l.match(/<table
|
|
20686
|
-
depth -= (l.match(/<\/table>/
|
|
20768
|
+
htmlLines.push(l);
|
|
20769
|
+
depth += (l.match(/<table[\s>]/gi) ?? []).length;
|
|
20770
|
+
depth -= (l.match(/<\/table>/gi) ?? []).length;
|
|
20687
20771
|
i++;
|
|
20688
20772
|
if (depth <= 0) break;
|
|
20689
20773
|
}
|
|
20690
|
-
|
|
20774
|
+
blocks.push({ type: "html_table", text: htmlLines.join("\n") });
|
|
20691
20775
|
continue;
|
|
20692
20776
|
}
|
|
20693
20777
|
if (line.trimStart().startsWith("|")) {
|
|
20694
|
-
const
|
|
20778
|
+
const tableRows = [];
|
|
20695
20779
|
while (i < lines.length && lines[i].trimStart().startsWith("|")) {
|
|
20696
|
-
|
|
20780
|
+
const row = lines[i];
|
|
20781
|
+
if (/^[\s|:\-]+$/.test(row)) {
|
|
20782
|
+
i++;
|
|
20783
|
+
continue;
|
|
20784
|
+
}
|
|
20785
|
+
const cells = row.split("|").slice(1, -1).map((c) => c.trim());
|
|
20786
|
+
if (cells.length > 0) tableRows.push(cells);
|
|
20697
20787
|
i++;
|
|
20698
20788
|
}
|
|
20699
|
-
|
|
20789
|
+
if (tableRows.length > 0) blocks.push({ type: "table", rows: tableRows });
|
|
20700
20790
|
continue;
|
|
20701
20791
|
}
|
|
20702
|
-
if (
|
|
20703
|
-
|
|
20704
|
-
i
|
|
20792
|
+
if (line.trimStart().startsWith("> ")) {
|
|
20793
|
+
const quoteLines = [];
|
|
20794
|
+
while (i < lines.length && (lines[i].trimStart().startsWith("> ") || lines[i].trimStart().startsWith(">"))) {
|
|
20795
|
+
quoteLines.push(lines[i].replace(/^>\s?/, ""));
|
|
20796
|
+
i++;
|
|
20797
|
+
}
|
|
20798
|
+
for (const ql of quoteLines) {
|
|
20799
|
+
blocks.push({ type: "blockquote", text: ql.trim() || "" });
|
|
20800
|
+
}
|
|
20705
20801
|
continue;
|
|
20706
20802
|
}
|
|
20707
|
-
|
|
20708
|
-
|
|
20803
|
+
const listMatch = line.match(/^(\s*)([-*+]|\d+[.)]) (.+)$/);
|
|
20804
|
+
if (listMatch) {
|
|
20805
|
+
const indent = Math.floor(listMatch[1].length / 2);
|
|
20806
|
+
const ordered = /\d/.test(listMatch[2]);
|
|
20807
|
+
blocks.push({ type: "list_item", text: listMatch[3].trim(), ordered, indent });
|
|
20709
20808
|
i++;
|
|
20710
20809
|
continue;
|
|
20711
20810
|
}
|
|
20712
|
-
|
|
20713
|
-
|
|
20714
|
-
collected.push(lines[i].trim());
|
|
20715
|
-
i++;
|
|
20716
|
-
}
|
|
20717
|
-
units.push({ kind: "text", raw: collected.join("\n"), lines: collected });
|
|
20811
|
+
blocks.push({ type: "paragraph", text: line.trim() });
|
|
20812
|
+
i++;
|
|
20718
20813
|
}
|
|
20719
|
-
return
|
|
20814
|
+
return blocks;
|
|
20720
20815
|
}
|
|
20721
|
-
function
|
|
20722
|
-
|
|
20723
|
-
|
|
20724
|
-
|
|
20725
|
-
|
|
20726
|
-
|
|
20727
|
-
|
|
20728
|
-
|
|
20816
|
+
function parseInlineMarkdown(text) {
|
|
20817
|
+
text = text.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1");
|
|
20818
|
+
text = text.replace(/\[([^\]]*)\]\(([^)]*)\)/g, (_, t, u) => t || u);
|
|
20819
|
+
text = text.replace(/~~([^~]+)~~/g, "$1");
|
|
20820
|
+
const spans = [];
|
|
20821
|
+
const regex = /(`[^`]+`|\*{3}[^*]+\*{3}|\*{2}[^*]+\*{2}|\*[^*]+\*|_{2}[^_]+_{2}|_[^_]+_)/g;
|
|
20822
|
+
let lastIdx = 0;
|
|
20823
|
+
for (const match of text.matchAll(regex)) {
|
|
20824
|
+
const idx = match.index;
|
|
20825
|
+
if (idx > lastIdx) {
|
|
20826
|
+
spans.push({ text: text.slice(lastIdx, idx), bold: false, italic: false, code: false });
|
|
20729
20827
|
}
|
|
20730
|
-
|
|
20731
|
-
|
|
20732
|
-
|
|
20733
|
-
if (
|
|
20734
|
-
|
|
20828
|
+
const raw = match[0];
|
|
20829
|
+
if (raw.startsWith("`")) {
|
|
20830
|
+
spans.push({ text: raw.slice(1, -1), bold: false, italic: false, code: true });
|
|
20831
|
+
} else if (raw.startsWith("***") || raw.startsWith("___")) {
|
|
20832
|
+
spans.push({ text: raw.slice(3, -3), bold: true, italic: true, code: false });
|
|
20833
|
+
} else if (raw.startsWith("**") || raw.startsWith("__")) {
|
|
20834
|
+
spans.push({ text: raw.slice(2, -2), bold: true, italic: false, code: false });
|
|
20735
20835
|
} else {
|
|
20736
|
-
|
|
20737
|
-
for (let j2 = 0; j2 < bMid; j2++) result2.push([null, pre + j2]);
|
|
20836
|
+
spans.push({ text: raw.slice(1, -1), bold: false, italic: true, code: false });
|
|
20738
20837
|
}
|
|
20739
|
-
|
|
20740
|
-
return result2;
|
|
20838
|
+
lastIdx = idx + raw.length;
|
|
20741
20839
|
}
|
|
20742
|
-
|
|
20743
|
-
|
|
20744
|
-
for (let j2 = 1; j2 <= n; j2++) {
|
|
20745
|
-
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]);
|
|
20746
|
-
}
|
|
20747
|
-
}
|
|
20748
|
-
const matches = [];
|
|
20749
|
-
let i = m, j = n;
|
|
20750
|
-
while (i > 0 && j > 0) {
|
|
20751
|
-
if (a[i - 1] === b[j - 1] && dp[i][j] === dp[i - 1][j - 1] + 1) {
|
|
20752
|
-
matches.push([i - 1, j - 1]);
|
|
20753
|
-
i--;
|
|
20754
|
-
j--;
|
|
20755
|
-
} else if (dp[i - 1][j] >= dp[i][j - 1]) i--;
|
|
20756
|
-
else j--;
|
|
20840
|
+
if (lastIdx < text.length) {
|
|
20841
|
+
spans.push({ text: text.slice(lastIdx), bold: false, italic: false, code: false });
|
|
20757
20842
|
}
|
|
20758
|
-
|
|
20759
|
-
|
|
20760
|
-
let ai = 0, bi = 0;
|
|
20761
|
-
const flushGap = (aEnd, bEnd) => {
|
|
20762
|
-
if (aEnd - ai === bEnd - bi) {
|
|
20763
|
-
while (ai < aEnd) result.push([ai++, bi++]);
|
|
20764
|
-
return;
|
|
20765
|
-
}
|
|
20766
|
-
while (ai < aEnd && bi < bEnd) {
|
|
20767
|
-
const sim = normalizedSimilarity(a[ai], b[bi]);
|
|
20768
|
-
if (sim >= 0.4) {
|
|
20769
|
-
if (aEnd - ai > bEnd - bi && bestSimInRange(a, ai + 1, ai + (aEnd - ai) - (bEnd - bi), b[bi]) > sim) {
|
|
20770
|
-
result.push([ai++, null]);
|
|
20771
|
-
} else if (bEnd - bi > aEnd - ai && bestSimInRange(b, bi + 1, bi + (bEnd - bi) - (aEnd - ai), a[ai]) > sim) {
|
|
20772
|
-
result.push([null, bi++]);
|
|
20773
|
-
} else {
|
|
20774
|
-
result.push([ai++, bi++]);
|
|
20775
|
-
}
|
|
20776
|
-
} else if (aEnd - ai >= bEnd - bi) result.push([ai++, null]);
|
|
20777
|
-
else result.push([null, bi++]);
|
|
20778
|
-
}
|
|
20779
|
-
while (ai < aEnd) result.push([ai++, null]);
|
|
20780
|
-
while (bi < bEnd) result.push([null, bi++]);
|
|
20781
|
-
};
|
|
20782
|
-
for (const [pi, pj] of matches) {
|
|
20783
|
-
flushGap(pi, pj);
|
|
20784
|
-
result.push([ai++, bi++]);
|
|
20843
|
+
if (spans.length === 0) {
|
|
20844
|
+
spans.push({ text, bold: false, italic: false, code: false });
|
|
20785
20845
|
}
|
|
20786
|
-
|
|
20787
|
-
return result;
|
|
20846
|
+
return spans;
|
|
20788
20847
|
}
|
|
20789
|
-
function
|
|
20790
|
-
|
|
20791
|
-
|
|
20792
|
-
|
|
20793
|
-
|
|
20794
|
-
|
|
20795
|
-
return best;
|
|
20848
|
+
function spanToCharPrId(span) {
|
|
20849
|
+
if (span.code) return CHAR_CODE;
|
|
20850
|
+
if (span.bold && span.italic) return CHAR_BOLD_ITALIC;
|
|
20851
|
+
if (span.bold) return CHAR_BOLD;
|
|
20852
|
+
if (span.italic) return CHAR_ITALIC;
|
|
20853
|
+
return CHAR_NORMAL;
|
|
20796
20854
|
}
|
|
20797
|
-
function
|
|
20798
|
-
|
|
20855
|
+
function generateRuns(text, defaultCharPr = CHAR_NORMAL, mapCharId) {
|
|
20856
|
+
const spans = parseInlineMarkdown(text);
|
|
20857
|
+
return spans.map((span) => {
|
|
20858
|
+
let charId = span.code || span.bold || span.italic ? spanToCharPrId(span) : defaultCharPr;
|
|
20859
|
+
if (mapCharId) charId = mapCharId(charId);
|
|
20860
|
+
return `<hp:run charPrIDRef="${charId}"><hp:t>${escapeXml(span.text)}</hp:t></hp:run>`;
|
|
20861
|
+
}).join("");
|
|
20799
20862
|
}
|
|
20800
|
-
|
|
20801
|
-
|
|
20802
|
-
|
|
20803
|
-
if (result.length <= 30 && result.includes(" ")) {
|
|
20804
|
-
const tokens = result.split(" ");
|
|
20805
|
-
const koreanSingleCharCount = tokens.filter((t) => t.length === 1 && /[가-ㄱ-ㆎ]/.test(t)).length;
|
|
20806
|
-
if (tokens.length >= 3 && koreanSingleCharCount / tokens.length >= 0.7) {
|
|
20807
|
-
result = tokens.join("");
|
|
20808
|
-
}
|
|
20863
|
+
function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL, mapCharId) {
|
|
20864
|
+
if (paraPrId === PARA_CODE) {
|
|
20865
|
+
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_CODE}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`;
|
|
20809
20866
|
}
|
|
20810
|
-
|
|
20811
|
-
}
|
|
20812
|
-
function normForMatch(text) {
|
|
20813
|
-
return sanitizeText(text).replace(/\s+/g, " ").trim();
|
|
20867
|
+
const runs = generateRuns(text, charPrId, mapCharId);
|
|
20868
|
+
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0">${runs}</hp:p>`;
|
|
20814
20869
|
}
|
|
20815
|
-
|
|
20816
|
-
|
|
20870
|
+
|
|
20871
|
+
// src/hwpx/gen-header.ts
|
|
20872
|
+
function generateContainerXml() {
|
|
20873
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
20874
|
+
<ocf:container xmlns:ocf="${NS_OCF}" xmlns:hpf="${NS_HPF}">
|
|
20875
|
+
<ocf:rootfiles>
|
|
20876
|
+
<ocf:rootfile full-path="Contents/content.hpf" media-type="application/hwpml-package+xml"/>
|
|
20877
|
+
</ocf:rootfiles>
|
|
20878
|
+
</ocf:container>`;
|
|
20817
20879
|
}
|
|
20818
|
-
function
|
|
20819
|
-
|
|
20820
|
-
|
|
20880
|
+
function generateManifest() {
|
|
20881
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
20882
|
+
<opf:package xmlns:opf="${NS_OPF}" xmlns:hpf="${NS_HPF}" xmlns:hh="${NS_HEAD}">
|
|
20883
|
+
<opf:manifest>
|
|
20884
|
+
<opf:item id="header" href="Contents/header.xml" media-type="application/xml"/>
|
|
20885
|
+
<opf:item id="section0" href="Contents/section0.xml" media-type="application/xml"/>
|
|
20886
|
+
</opf:manifest>
|
|
20887
|
+
<opf:spine>
|
|
20888
|
+
<opf:itemref idref="header" linear="no"/>
|
|
20889
|
+
<opf:itemref idref="section0" linear="yes"/>
|
|
20890
|
+
</opf:spine>
|
|
20891
|
+
</opf:package>`;
|
|
20821
20892
|
}
|
|
20822
|
-
function
|
|
20823
|
-
|
|
20824
|
-
if (
|
|
20825
|
-
|
|
20826
|
-
|
|
20827
|
-
|
|
20828
|
-
|
|
20829
|
-
|
|
20830
|
-
|
|
20831
|
-
if (skip.has(`${r},${c}`)) continue;
|
|
20832
|
-
const cell = cells[r]?.[c];
|
|
20833
|
-
if (!cell) continue;
|
|
20834
|
-
display[r][c] = {
|
|
20835
|
-
text: escapeGfm(sanitizeText(cell.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>"),
|
|
20836
|
-
gridR: r,
|
|
20837
|
-
gridC: c
|
|
20838
|
-
};
|
|
20839
|
-
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
20840
|
-
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
20841
|
-
if (dr === 0 && dc === 0) continue;
|
|
20842
|
-
if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
|
|
20843
|
-
}
|
|
20844
|
-
}
|
|
20845
|
-
c += cell.colSpan - 1;
|
|
20846
|
-
}
|
|
20893
|
+
function buildCharProperties(theme, gongmun, ratioVariants = []) {
|
|
20894
|
+
let body = 1e3, code = 900, h1 = 1800, h2 = 1400, h3 = 1200, h4 = 1100;
|
|
20895
|
+
if (gongmun) {
|
|
20896
|
+
body = gongmun.bodyHeight;
|
|
20897
|
+
code = Math.max(body - 200, 900);
|
|
20898
|
+
h1 = gongmun.preset === "report" || gongmun.preset === "plan" ? 2e3 : 1700;
|
|
20899
|
+
h2 = 1600;
|
|
20900
|
+
h3 = body;
|
|
20901
|
+
h4 = Math.max(body - 100, 1300);
|
|
20847
20902
|
}
|
|
20848
|
-
const
|
|
20849
|
-
|
|
20850
|
-
|
|
20851
|
-
|
|
20852
|
-
|
|
20853
|
-
|
|
20854
|
-
|
|
20855
|
-
|
|
20856
|
-
|
|
20857
|
-
|
|
20858
|
-
|
|
20859
|
-
|
|
20860
|
-
|
|
20861
|
-
|
|
20862
|
-
|
|
20863
|
-
|
|
20864
|
-
|
|
20865
|
-
|
|
20903
|
+
const bodyRatio = gongmun ? GONGMUN_BODY_RATIO : 100;
|
|
20904
|
+
const rows = [
|
|
20905
|
+
charPr(0, body, false, false, 0, theme.body, bodyRatio),
|
|
20906
|
+
charPr(1, body, true, false, 0, theme.body, bodyRatio),
|
|
20907
|
+
charPr(2, body, false, true, 0, theme.body, bodyRatio),
|
|
20908
|
+
charPr(3, body, true, true, 0, theme.body, bodyRatio),
|
|
20909
|
+
charPr(4, code, false, false, 1),
|
|
20910
|
+
charPr(5, h1, true, false, 1, theme.h1),
|
|
20911
|
+
charPr(6, h2, true, false, 1, theme.h2),
|
|
20912
|
+
charPr(7, h3, true, false, 1, theme.h3),
|
|
20913
|
+
charPr(8, h4, true, false, 1, theme.h4),
|
|
20914
|
+
charPr(CHAR_TABLE_HEADER, body, theme.tableHeaderBold, false, 0, theme.tableHeader),
|
|
20915
|
+
charPr(CHAR_QUOTE, body, false, true, 0, theme.quote)
|
|
20916
|
+
];
|
|
20917
|
+
for (const r of ratioVariants) {
|
|
20918
|
+
rows.push(
|
|
20919
|
+
charPr(rows.length, body, false, false, 0, theme.body, r),
|
|
20920
|
+
charPr(rows.length + 1, body, true, false, 0, theme.body, r),
|
|
20921
|
+
charPr(rows.length + 2, body, false, true, 0, theme.body, r),
|
|
20922
|
+
charPr(rows.length + 3, body, true, true, 0, theme.body, r)
|
|
20923
|
+
);
|
|
20866
20924
|
}
|
|
20867
|
-
|
|
20868
|
-
|
|
20925
|
+
return `<hh:charProperties itemCnt="${rows.length}">
|
|
20926
|
+
${rows.join("\n")}
|
|
20927
|
+
</hh:charProperties>`;
|
|
20869
20928
|
}
|
|
20870
|
-
function
|
|
20871
|
-
|
|
20872
|
-
|
|
20873
|
-
|
|
20874
|
-
|
|
20875
|
-
|
|
20876
|
-
|
|
20877
|
-
|
|
20878
|
-
|
|
20929
|
+
function buildParaProperties(gongmun) {
|
|
20930
|
+
if (!gongmun) {
|
|
20931
|
+
const base2 = [
|
|
20932
|
+
paraPr(0),
|
|
20933
|
+
paraPr(1, { align: "LEFT", spaceBefore: 800, spaceAfter: 200, lineSpacing: 180 }),
|
|
20934
|
+
paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: 170 }),
|
|
20935
|
+
paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: 160 }),
|
|
20936
|
+
paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: 160 }),
|
|
20937
|
+
paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400 }),
|
|
20938
|
+
paraPr(6, { align: "LEFT", lineSpacing: 150, indent: 600 }),
|
|
20939
|
+
paraPr(7, { align: "LEFT", lineSpacing: 160, indent: 600 })
|
|
20940
|
+
];
|
|
20941
|
+
return `<hh:paraProperties itemCnt="${base2.length}">
|
|
20942
|
+
${base2.join("\n")}
|
|
20943
|
+
</hh:paraProperties>`;
|
|
20879
20944
|
}
|
|
20880
|
-
|
|
20881
|
-
|
|
20882
|
-
|
|
20883
|
-
|
|
20884
|
-
}
|
|
20885
|
-
|
|
20886
|
-
|
|
20887
|
-
|
|
20888
|
-
|
|
20889
|
-
|
|
20890
|
-
|
|
20891
|
-
|
|
20892
|
-
|
|
20893
|
-
|
|
20894
|
-
|
|
20895
|
-
|
|
20945
|
+
const ls = gongmun.lineSpacing;
|
|
20946
|
+
const titleAlign = gongmun.centerTitle ? "CENTER" : "LEFT";
|
|
20947
|
+
const base = [
|
|
20948
|
+
paraPr(0, { lineSpacing: ls, keepWord: true }),
|
|
20949
|
+
paraPr(1, { align: titleAlign, spaceBefore: 400, spaceAfter: 400, lineSpacing: ls, keepWord: true }),
|
|
20950
|
+
paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: ls, keepWord: true }),
|
|
20951
|
+
paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: ls, keepWord: true }),
|
|
20952
|
+
paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: ls, keepWord: true }),
|
|
20953
|
+
paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400, keepWord: true }),
|
|
20954
|
+
paraPr(6, { align: "LEFT", lineSpacing: ls, indent: 600, keepWord: true }),
|
|
20955
|
+
paraPr(7, { align: "LEFT", lineSpacing: ls, indent: 600, keepWord: true })
|
|
20956
|
+
];
|
|
20957
|
+
for (let d = 0; d < GONGMUN_LIST_LEVELS; d++) {
|
|
20958
|
+
const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering);
|
|
20959
|
+
const sectionGap = gongmun.numbering === "report" && d === 0 ? Math.round(gongmun.bodyHeight * 0.5) : 0;
|
|
20960
|
+
base.push(paraPr(GONGMUN_LIST_BASE + d, { align: "JUSTIFY", lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true }));
|
|
20896
20961
|
}
|
|
20897
|
-
|
|
20962
|
+
base.push(paraPr(GONGMUN_CENTER, { align: "CENTER", lineSpacing: ls, keepWord: true }));
|
|
20963
|
+
return `<hh:paraProperties itemCnt="${base.length}">
|
|
20964
|
+
${base.join("\n")}
|
|
20965
|
+
</hh:paraProperties>`;
|
|
20898
20966
|
}
|
|
20899
|
-
function
|
|
20900
|
-
const
|
|
20901
|
-
const
|
|
20902
|
-
|
|
20903
|
-
|
|
20904
|
-
|
|
20905
|
-
|
|
20906
|
-
|
|
20907
|
-
|
|
20908
|
-
|
|
20909
|
-
|
|
20910
|
-
|
|
20911
|
-
|
|
20912
|
-
|
|
20913
|
-
|
|
20914
|
-
|
|
20967
|
+
function generateHeaderXml(theme, gongmun, ratioVariants = []) {
|
|
20968
|
+
const bodyFace = gongmun?.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD568\uCD08\uB86C\uBC14\uD0D5";
|
|
20969
|
+
const charPropsXml = buildCharProperties(theme, gongmun, ratioVariants);
|
|
20970
|
+
const paraPropsXml = buildParaProperties(gongmun);
|
|
20971
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
20972
|
+
<hh:head xmlns:hh="${NS_HEAD}" xmlns:hp="${NS_PARA}" xmlns:hc="${NS_CORE}" version="1.4" secCnt="1">
|
|
20973
|
+
<hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/>
|
|
20974
|
+
<hh:refList>
|
|
20975
|
+
<hh:fontfaces itemCnt="7">
|
|
20976
|
+
<hh:fontface lang="HANGUL" fontCnt="3">
|
|
20977
|
+
<hh:font id="0" face="${bodyFace}" type="TTF" isEmbedded="0">
|
|
20978
|
+
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
20979
|
+
</hh:font>
|
|
20980
|
+
<hh:font id="1" face="\uD568\uCD08\uB86C\uB3CB\uC6C0" type="TTF" isEmbedded="0">
|
|
20981
|
+
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
20982
|
+
</hh:font>
|
|
20983
|
+
<hh:font id="2" face="HY\uACAC\uACE0\uB515" type="TTF" isEmbedded="0">
|
|
20984
|
+
<hh:typeInfo familyType="FCAT_GOTHIC" weight="9" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
20985
|
+
</hh:font>
|
|
20986
|
+
</hh:fontface>
|
|
20987
|
+
<hh:fontface lang="LATIN" fontCnt="3">
|
|
20988
|
+
<hh:font id="0" face="Times New Roman" type="TTF" isEmbedded="0">
|
|
20989
|
+
<hh:typeInfo familyType="FCAT_OLDSTYLE" weight="5" proportion="4" contrast="2" strokeVariation="0" armStyle="0" letterform="0" midline="0" xHeight="4"/>
|
|
20990
|
+
</hh:font>
|
|
20991
|
+
<hh:font id="1" face="Consolas" type="TTF" isEmbedded="0">
|
|
20992
|
+
<hh:typeInfo familyType="FCAT_MODERN" weight="5" proportion="0" contrast="0" strokeVariation="0" armStyle="0" letterform="0" midline="0" xHeight="0"/>
|
|
20993
|
+
</hh:font>
|
|
20994
|
+
<hh:font id="2" face="Arial Black" type="TTF" isEmbedded="0">
|
|
20995
|
+
<hh:typeInfo familyType="FCAT_GOTHIC" weight="9" proportion="0" contrast="0" strokeVariation="0" armStyle="0" letterform="0" midline="0" xHeight="0"/>
|
|
20996
|
+
</hh:font>
|
|
20997
|
+
</hh:fontface>
|
|
20998
|
+
<hh:fontface lang="HANJA" fontCnt="1">
|
|
20999
|
+
<hh:font id="0" face="\uD568\uCD08\uB86C\uBC14\uD0D5" type="TTF" isEmbedded="0">
|
|
21000
|
+
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
21001
|
+
</hh:font>
|
|
21002
|
+
</hh:fontface>
|
|
21003
|
+
<hh:fontface lang="JAPANESE" fontCnt="1">
|
|
21004
|
+
<hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
|
|
21005
|
+
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
21006
|
+
</hh:font>
|
|
21007
|
+
</hh:fontface>
|
|
21008
|
+
<hh:fontface lang="OTHER" fontCnt="1">
|
|
21009
|
+
<hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
|
|
21010
|
+
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
21011
|
+
</hh:font>
|
|
21012
|
+
</hh:fontface>
|
|
21013
|
+
<hh:fontface lang="SYMBOL" fontCnt="1">
|
|
21014
|
+
<hh:font id="0" face="Symbol" type="TTF" isEmbedded="0">
|
|
21015
|
+
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
21016
|
+
</hh:font>
|
|
21017
|
+
</hh:fontface>
|
|
21018
|
+
<hh:fontface lang="USER" fontCnt="1">
|
|
21019
|
+
<hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
|
|
21020
|
+
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
21021
|
+
</hh:font>
|
|
21022
|
+
</hh:fontface>
|
|
21023
|
+
</hh:fontfaces>
|
|
21024
|
+
<hh:borderFills itemCnt="2">
|
|
21025
|
+
<hh:borderFill id="1" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
|
|
21026
|
+
<hh:slash type="NONE" Crooked="0" isCounter="0"/>
|
|
21027
|
+
<hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
|
|
21028
|
+
<hh:leftBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
21029
|
+
<hh:rightBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
21030
|
+
<hh:topBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
21031
|
+
<hh:bottomBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
21032
|
+
</hh:borderFill>
|
|
21033
|
+
<hh:borderFill id="2" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
|
|
21034
|
+
<hh:slash type="NONE" Crooked="0" isCounter="0"/>
|
|
21035
|
+
<hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
|
|
21036
|
+
<hh:leftBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
21037
|
+
<hh:rightBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
21038
|
+
<hh:topBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
21039
|
+
<hh:bottomBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
21040
|
+
</hh:borderFill>
|
|
21041
|
+
</hh:borderFills>
|
|
21042
|
+
${charPropsXml}
|
|
21043
|
+
<hh:tabProperties itemCnt="0"/>
|
|
21044
|
+
<hh:numberings itemCnt="0"/>
|
|
21045
|
+
<hh:bullets itemCnt="0"/>
|
|
21046
|
+
${paraPropsXml}
|
|
21047
|
+
<hh:styles itemCnt="1">
|
|
21048
|
+
<hh:style id="0" type="PARA" name="\uBC14\uD0D5\uAE00" engName="Normal" paraPrIDRef="0" charPrIDRef="0" nextStyleIDRef="0" langIDRef="1042" lockForm="0"/>
|
|
21049
|
+
</hh:styles>
|
|
21050
|
+
</hh:refList>
|
|
21051
|
+
<hh:compatibleDocument targetProgram="HWP2018"><hh:layoutCompatibility/></hh:compatibleDocument>
|
|
21052
|
+
</hh:head>`;
|
|
20915
21053
|
}
|
|
20916
|
-
|
|
20917
|
-
|
|
20918
|
-
|
|
20919
|
-
|
|
20920
|
-
|
|
20921
|
-
|
|
20922
|
-
|
|
20923
|
-
|
|
20924
|
-
|
|
20925
|
-
|
|
20926
|
-
|
|
20927
|
-
|
|
20928
|
-
|
|
20929
|
-
|
|
20930
|
-
|
|
20931
|
-
|
|
20932
|
-
|
|
20933
|
-
|
|
20934
|
-
|
|
20935
|
-
|
|
20936
|
-
|
|
20937
|
-
|
|
20938
|
-
|
|
20939
|
-
|
|
21054
|
+
|
|
21055
|
+
// src/hwpx/gen-gongmun-fit.ts
|
|
21056
|
+
function plainRenderText(text) {
|
|
21057
|
+
return parseInlineMarkdown(text).map((s) => s.text).join("");
|
|
21058
|
+
}
|
|
21059
|
+
function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
|
|
21060
|
+
const minRatio = gongmun.autoFitMinRatio;
|
|
21061
|
+
if (minRatio === null || minRatio >= GONGMUN_BODY_RATIO) return null;
|
|
21062
|
+
const pageW = 59528 - mmToHwpunit(gongmun.margins.left) - mmToHwpunit(gongmun.margins.right);
|
|
21063
|
+
const ratioByBlock = /* @__PURE__ */ new Map();
|
|
21064
|
+
const variants = [];
|
|
21065
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
21066
|
+
const block = blocks[i];
|
|
21067
|
+
let text;
|
|
21068
|
+
let firstW;
|
|
21069
|
+
let contW;
|
|
21070
|
+
if (block.type === "list_item" && gongmunList.has(i)) {
|
|
21071
|
+
const { marker, depth } = gongmunList.get(i);
|
|
21072
|
+
const content = plainRenderText(block.text || "");
|
|
21073
|
+
text = marker ? `${marker} ${content}` : content;
|
|
21074
|
+
const { left, indent } = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering);
|
|
21075
|
+
firstW = pageW - left - Math.max(indent, 0);
|
|
21076
|
+
contW = pageW - left - Math.max(-indent, 0);
|
|
21077
|
+
} else if (block.type === "paragraph") {
|
|
21078
|
+
const raw = (block.text || "").trim();
|
|
21079
|
+
if (/^<center>[\s\S]*<\/center>$/i.test(raw)) continue;
|
|
21080
|
+
text = plainRenderText(raw);
|
|
21081
|
+
firstW = contW = pageW;
|
|
21082
|
+
} else {
|
|
21083
|
+
continue;
|
|
20940
21084
|
}
|
|
20941
|
-
if (
|
|
21085
|
+
if (!text) continue;
|
|
21086
|
+
const r = fitRatioForFewerLines(text, firstW, contW, gongmun.bodyHeight, GONGMUN_BODY_RATIO, minRatio);
|
|
21087
|
+
if (r === null) continue;
|
|
21088
|
+
ratioByBlock.set(i, r);
|
|
21089
|
+
if (!variants.includes(r)) variants.push(r);
|
|
20942
21090
|
}
|
|
20943
|
-
return
|
|
21091
|
+
return ratioByBlock.size > 0 ? { ratioByBlock, variants } : null;
|
|
20944
21092
|
}
|
|
20945
|
-
function
|
|
20946
|
-
const
|
|
20947
|
-
|
|
20948
|
-
|
|
20949
|
-
|
|
20950
|
-
|
|
20951
|
-
|
|
20952
|
-
|
|
20953
|
-
|
|
20954
|
-
|
|
20955
|
-
|
|
20956
|
-
|
|
20957
|
-
if (tag === "table") {
|
|
20958
|
-
depth += isClose ? -1 : 1;
|
|
20959
|
-
if (depth < 0) return null;
|
|
21093
|
+
function variantMapper(fit, blockIdx) {
|
|
21094
|
+
const r = fit.ratioByBlock.get(blockIdx);
|
|
21095
|
+
if (r === void 0) return void 0;
|
|
21096
|
+
const vi = fit.variants.indexOf(r);
|
|
21097
|
+
return (id) => id >= 0 && id <= 3 ? CHAR_VARIANT_BASE + vi * 4 + id : id;
|
|
21098
|
+
}
|
|
21099
|
+
function precomputeGongmunList(blocks, gongmun) {
|
|
21100
|
+
const result = /* @__PURE__ */ new Map();
|
|
21101
|
+
let i = 0;
|
|
21102
|
+
while (i < blocks.length) {
|
|
21103
|
+
if (blocks[i].type !== "list_item") {
|
|
21104
|
+
i++;
|
|
20960
21105
|
continue;
|
|
20961
21106
|
}
|
|
20962
|
-
|
|
20963
|
-
|
|
20964
|
-
|
|
20965
|
-
|
|
20966
|
-
|
|
20967
|
-
|
|
21107
|
+
const run = [];
|
|
21108
|
+
while (i < blocks.length) {
|
|
21109
|
+
const t = blocks[i].type;
|
|
21110
|
+
if (t === "list_item") {
|
|
21111
|
+
run.push(i);
|
|
21112
|
+
i++;
|
|
21113
|
+
continue;
|
|
20968
21114
|
}
|
|
20969
|
-
|
|
20970
|
-
|
|
20971
|
-
|
|
20972
|
-
|
|
20973
|
-
|
|
20974
|
-
|
|
20975
|
-
|
|
20976
|
-
currentRow.push({ inner: raw.slice(cellStart, m.index), colSpan: cellInfo.colSpan, rowSpan: cellInfo.rowSpan });
|
|
20977
|
-
cellStart = -1;
|
|
20978
|
-
cellInfo = null;
|
|
21115
|
+
if (t === "table" || t === "html_table") {
|
|
21116
|
+
let j = i + 1;
|
|
21117
|
+
while (j < blocks.length && (blocks[j].type === "table" || blocks[j].type === "html_table")) j++;
|
|
21118
|
+
if (j < blocks.length && blocks[j].type === "list_item") {
|
|
21119
|
+
i = j;
|
|
21120
|
+
continue;
|
|
21121
|
+
}
|
|
20979
21122
|
}
|
|
21123
|
+
break;
|
|
20980
21124
|
}
|
|
21125
|
+
const depths = run.map((bi) => Math.min(Math.max(blocks[bi].indent || 0, 0), GONGMUN_LIST_LEVELS - 1));
|
|
21126
|
+
const suppress = gongmun.numbering === "standard" ? computeSuppression(depths) : depths.map(() => false);
|
|
21127
|
+
const numberer = new GongmunNumberer(gongmun.numbering);
|
|
21128
|
+
run.forEach((bi, k) => {
|
|
21129
|
+
const marker = numberer.next(depths[k], suppress[k]);
|
|
21130
|
+
result.set(bi, { marker, depth: depths[k] });
|
|
21131
|
+
});
|
|
20981
21132
|
}
|
|
20982
|
-
|
|
20983
|
-
return rows;
|
|
21133
|
+
return result;
|
|
20984
21134
|
}
|
|
20985
|
-
|
|
20986
|
-
|
|
20987
|
-
|
|
20988
|
-
|
|
20989
|
-
if (
|
|
20990
|
-
|
|
20991
|
-
|
|
20992
|
-
|
|
20993
|
-
if (/<img\s/i.test(work)) {
|
|
20994
|
-
hadNonText = true;
|
|
20995
|
-
work = work.replace(/<img\s(?:"[^"]*"|'[^']*'|[^>"'])*?>/gi, "");
|
|
20996
|
-
}
|
|
20997
|
-
const lines = work.split(/<br\s*\/?>/gi).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
20998
|
-
return { lines, hadNonText };
|
|
21135
|
+
|
|
21136
|
+
// src/diff/text-diff.ts
|
|
21137
|
+
function similarity(a, b) {
|
|
21138
|
+
if (a === b) return 1;
|
|
21139
|
+
if (!a || !b) return 0;
|
|
21140
|
+
const maxLen = Math.max(a.length, b.length);
|
|
21141
|
+
if (maxLen === 0) return 1;
|
|
21142
|
+
return 1 - levenshtein(a, b) / maxLen;
|
|
20999
21143
|
}
|
|
21000
|
-
function
|
|
21001
|
-
|
|
21002
|
-
let depth = 0;
|
|
21003
|
-
let start = -1;
|
|
21004
|
-
const re = /<(\/?)table(?:[\s>]|>)/gi;
|
|
21005
|
-
let m;
|
|
21006
|
-
while ((m = re.exec(html)) !== null) {
|
|
21007
|
-
if (m[1] !== "/") {
|
|
21008
|
-
if (depth === 0) start = m.index;
|
|
21009
|
-
depth++;
|
|
21010
|
-
} else {
|
|
21011
|
-
depth--;
|
|
21012
|
-
if (depth === 0 && start >= 0) {
|
|
21013
|
-
result.push(html.slice(start, m.index + m[0].length));
|
|
21014
|
-
start = -1;
|
|
21015
|
-
}
|
|
21016
|
-
if (depth < 0) depth = 0;
|
|
21017
|
-
}
|
|
21018
|
-
}
|
|
21019
|
-
return result;
|
|
21144
|
+
function normalizedSimilarity(a, b) {
|
|
21145
|
+
return similarity(normalize(a), normalize(b));
|
|
21020
21146
|
}
|
|
21021
|
-
function
|
|
21022
|
-
|
|
21023
|
-
|
|
21024
|
-
|
|
21025
|
-
|
|
21026
|
-
|
|
21027
|
-
|
|
21028
|
-
|
|
21029
|
-
|
|
21030
|
-
|
|
21031
|
-
|
|
21032
|
-
|
|
21033
|
-
|
|
21034
|
-
|
|
21147
|
+
function normalize(s) {
|
|
21148
|
+
return s.replace(/\s+/g, " ").trim();
|
|
21149
|
+
}
|
|
21150
|
+
var MAX_LEVENSHTEIN_LEN = 1e4;
|
|
21151
|
+
function levenshtein(a, b) {
|
|
21152
|
+
if (a.length + b.length > MAX_LEVENSHTEIN_LEN) {
|
|
21153
|
+
const sampleLen = Math.min(500, a.length, b.length);
|
|
21154
|
+
let diffs = 0;
|
|
21155
|
+
for (let i = 0; i < sampleLen; i++) if (a[i] !== b[i]) diffs++;
|
|
21156
|
+
const sampleRate = sampleLen > 0 ? diffs / sampleLen : 1;
|
|
21157
|
+
return Math.abs(a.length - b.length) + Math.round(Math.min(a.length, b.length) * sampleRate);
|
|
21158
|
+
}
|
|
21159
|
+
if (a.length > b.length) [a, b] = [b, a];
|
|
21160
|
+
const m = a.length;
|
|
21161
|
+
const n = b.length;
|
|
21162
|
+
let prev = Array.from({ length: m + 1 }, (_, i) => i);
|
|
21163
|
+
let curr = new Array(m + 1);
|
|
21164
|
+
for (let j = 1; j <= n; j++) {
|
|
21165
|
+
curr[0] = j;
|
|
21166
|
+
for (let i = 1; i <= m; i++) {
|
|
21167
|
+
if (a[i - 1] === b[j - 1]) {
|
|
21168
|
+
curr[i] = prev[i - 1];
|
|
21169
|
+
} else {
|
|
21170
|
+
curr[i] = 1 + Math.min(prev[i - 1], prev[i], curr[i - 1]);
|
|
21171
|
+
}
|
|
21035
21172
|
}
|
|
21173
|
+
;
|
|
21174
|
+
[prev, curr] = [curr, prev];
|
|
21036
21175
|
}
|
|
21037
|
-
|
|
21038
|
-
return result;
|
|
21176
|
+
return prev[m];
|
|
21039
21177
|
}
|
|
21040
21178
|
|
|
21041
|
-
// src/
|
|
21042
|
-
|
|
21043
|
-
var NS_PARA = "http://www.hancom.co.kr/hwpml/2011/paragraph";
|
|
21044
|
-
var NS_HEAD = "http://www.hancom.co.kr/hwpml/2011/head";
|
|
21045
|
-
var NS_CORE = "http://www.hancom.co.kr/hwpml/2011/core";
|
|
21046
|
-
var NS_OPF = "http://www.idpf.org/2007/opf/";
|
|
21047
|
-
var NS_HPF = "http://www.hancom.co.kr/schema/2011/hpf";
|
|
21048
|
-
var NS_OCF = "urn:oasis:names:tc:opendocument:xmlns:container";
|
|
21049
|
-
var CHAR_NORMAL = 0;
|
|
21050
|
-
var CHAR_BOLD = 1;
|
|
21051
|
-
var CHAR_ITALIC = 2;
|
|
21052
|
-
var CHAR_BOLD_ITALIC = 3;
|
|
21053
|
-
var CHAR_CODE = 4;
|
|
21054
|
-
var CHAR_H1 = 5;
|
|
21055
|
-
var CHAR_H2 = 6;
|
|
21056
|
-
var CHAR_H3 = 7;
|
|
21057
|
-
var CHAR_H4 = 8;
|
|
21058
|
-
var CHAR_TABLE_HEADER = 9;
|
|
21059
|
-
var CHAR_QUOTE = 10;
|
|
21060
|
-
var PARA_NORMAL = 0;
|
|
21061
|
-
var PARA_H1 = 1;
|
|
21062
|
-
var PARA_H2 = 2;
|
|
21063
|
-
var PARA_H3 = 3;
|
|
21064
|
-
var PARA_H4 = 4;
|
|
21065
|
-
var PARA_CODE = 5;
|
|
21066
|
-
var PARA_QUOTE = 6;
|
|
21067
|
-
var PARA_LIST = 7;
|
|
21068
|
-
var DEFAULT_TEXT_COLOR = "#000000";
|
|
21069
|
-
function resolveTheme(theme) {
|
|
21070
|
-
return {
|
|
21071
|
-
h1: theme?.headingColors?.[1] ?? DEFAULT_TEXT_COLOR,
|
|
21072
|
-
h2: theme?.headingColors?.[2] ?? DEFAULT_TEXT_COLOR,
|
|
21073
|
-
h3: theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,
|
|
21074
|
-
h4: theme?.headingColors?.[4] ?? theme?.headingColors?.[3] ?? DEFAULT_TEXT_COLOR,
|
|
21075
|
-
body: theme?.bodyColor ?? DEFAULT_TEXT_COLOR,
|
|
21076
|
-
quote: theme?.quoteColor ?? DEFAULT_TEXT_COLOR,
|
|
21077
|
-
/** quoteColor가 명시되었는지 — blockquote charPr 분기에 사용 (baseline 호환) */
|
|
21078
|
-
hasQuoteOption: theme?.quoteColor !== void 0,
|
|
21079
|
-
tableHeader: theme?.tableHeaderColor ?? theme?.bodyColor ?? DEFAULT_TEXT_COLOR,
|
|
21080
|
-
tableHeaderBold: !!theme?.tableHeaderBold
|
|
21081
|
-
};
|
|
21082
|
-
}
|
|
21083
|
-
async function markdownToHwpx(markdown, options) {
|
|
21084
|
-
const theme = resolveTheme(options?.theme);
|
|
21085
|
-
const gongmun = options?.gongmun ? resolveGongmun(options.gongmun) : null;
|
|
21086
|
-
const blocks = parseMarkdownToBlocks(markdown);
|
|
21087
|
-
const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
|
|
21088
|
-
const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
|
|
21089
|
-
const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit);
|
|
21090
|
-
const zip = new JSZip7();
|
|
21091
|
-
zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
|
|
21092
|
-
zip.file("META-INF/container.xml", generateContainerXml());
|
|
21093
|
-
zip.file("Contents/content.hpf", generateManifest());
|
|
21094
|
-
zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun, fit?.variants ?? []));
|
|
21095
|
-
zip.file("Contents/section0.xml", sectionXml);
|
|
21096
|
-
zip.file("Preview/PrvText.txt", buildPrvText(blocks));
|
|
21097
|
-
return await zip.generateAsync({ type: "arraybuffer" });
|
|
21098
|
-
}
|
|
21099
|
-
function buildPrvText(blocks) {
|
|
21100
|
-
const lines = [];
|
|
21101
|
-
let bytes = 0;
|
|
21102
|
-
for (const b of blocks) {
|
|
21103
|
-
let text = b.text || (b.rows ? b.rows.map((r) => r.join(" ")).join("\n") : "");
|
|
21104
|
-
if (b.type === "html_table") text = text.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
21105
|
-
if (!text) continue;
|
|
21106
|
-
lines.push(text);
|
|
21107
|
-
bytes += text.length * 3;
|
|
21108
|
-
if (bytes > 1024) break;
|
|
21109
|
-
}
|
|
21110
|
-
return lines.join("\n").slice(0, 1024);
|
|
21111
|
-
}
|
|
21112
|
-
function parseMarkdownToBlocks(md2) {
|
|
21179
|
+
// src/roundtrip/markdown-units.ts
|
|
21180
|
+
function splitMarkdownUnits(md2) {
|
|
21113
21181
|
const lines = md2.split("\n");
|
|
21114
|
-
const
|
|
21182
|
+
const units = [];
|
|
21115
21183
|
let i = 0;
|
|
21116
21184
|
while (i < lines.length) {
|
|
21117
21185
|
const line = lines[i];
|
|
@@ -21119,420 +21187,369 @@ function parseMarkdownToBlocks(md2) {
|
|
|
21119
21187
|
i++;
|
|
21120
21188
|
continue;
|
|
21121
21189
|
}
|
|
21122
|
-
|
|
21123
|
-
|
|
21124
|
-
const fence = fenceMatch[1];
|
|
21125
|
-
const lang = fenceMatch[2].trim();
|
|
21126
|
-
const codeLines = [];
|
|
21127
|
-
i++;
|
|
21128
|
-
while (i < lines.length && !lines[i].startsWith(fence)) {
|
|
21129
|
-
codeLines.push(lines[i]);
|
|
21130
|
-
i++;
|
|
21131
|
-
}
|
|
21132
|
-
if (i < lines.length) i++;
|
|
21133
|
-
blocks.push({ type: "code_block", text: codeLines.join("\n"), lang });
|
|
21134
|
-
continue;
|
|
21135
|
-
}
|
|
21136
|
-
if (/^(\*{3,}|-{3,}|_{3,})\s*$/.test(line.trim())) {
|
|
21137
|
-
blocks.push({ type: "hr" });
|
|
21138
|
-
i++;
|
|
21139
|
-
continue;
|
|
21140
|
-
}
|
|
21141
|
-
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
21142
|
-
if (headingMatch) {
|
|
21143
|
-
blocks.push({ type: "heading", text: headingMatch[2].trim(), level: headingMatch[1].length });
|
|
21144
|
-
i++;
|
|
21145
|
-
continue;
|
|
21146
|
-
}
|
|
21147
|
-
if (/^<table[\s>]/i.test(line.trimStart())) {
|
|
21148
|
-
const htmlLines = [];
|
|
21190
|
+
if (line.trim().startsWith("<table>")) {
|
|
21191
|
+
const collected2 = [];
|
|
21149
21192
|
let depth = 0;
|
|
21150
21193
|
while (i < lines.length) {
|
|
21151
21194
|
const l = lines[i];
|
|
21152
|
-
|
|
21153
|
-
depth += (l.match(/<table
|
|
21154
|
-
depth -= (l.match(/<\/table>/
|
|
21195
|
+
collected2.push(l);
|
|
21196
|
+
depth += (l.match(/<table>/g) || []).length;
|
|
21197
|
+
depth -= (l.match(/<\/table>/g) || []).length;
|
|
21155
21198
|
i++;
|
|
21156
21199
|
if (depth <= 0) break;
|
|
21157
21200
|
}
|
|
21158
|
-
|
|
21201
|
+
units.push({ kind: "html-table", raw: collected2.join("\n"), lines: collected2 });
|
|
21159
21202
|
continue;
|
|
21160
21203
|
}
|
|
21161
21204
|
if (line.trimStart().startsWith("|")) {
|
|
21162
|
-
const
|
|
21205
|
+
const collected2 = [];
|
|
21163
21206
|
while (i < lines.length && lines[i].trimStart().startsWith("|")) {
|
|
21164
|
-
|
|
21165
|
-
if (/^[\s|:\-]+$/.test(row)) {
|
|
21166
|
-
i++;
|
|
21167
|
-
continue;
|
|
21168
|
-
}
|
|
21169
|
-
const cells = row.split("|").slice(1, -1).map((c) => c.trim());
|
|
21170
|
-
if (cells.length > 0) tableRows.push(cells);
|
|
21207
|
+
collected2.push(lines[i]);
|
|
21171
21208
|
i++;
|
|
21172
21209
|
}
|
|
21173
|
-
|
|
21210
|
+
units.push({ kind: "gfm-table", raw: collected2.join("\n"), lines: collected2 });
|
|
21174
21211
|
continue;
|
|
21175
21212
|
}
|
|
21176
|
-
if (line.
|
|
21177
|
-
|
|
21178
|
-
|
|
21179
|
-
quoteLines.push(lines[i].replace(/^>\s?/, ""));
|
|
21180
|
-
i++;
|
|
21181
|
-
}
|
|
21182
|
-
for (const ql of quoteLines) {
|
|
21183
|
-
blocks.push({ type: "blockquote", text: ql.trim() || "" });
|
|
21184
|
-
}
|
|
21213
|
+
if (/^-{3,}\s*$/.test(line.trim())) {
|
|
21214
|
+
units.push({ kind: "separator", raw: line.trim(), lines: [line.trim()] });
|
|
21215
|
+
i++;
|
|
21185
21216
|
continue;
|
|
21186
21217
|
}
|
|
21187
|
-
|
|
21188
|
-
|
|
21189
|
-
const indent = Math.floor(listMatch[1].length / 2);
|
|
21190
|
-
const ordered = /\d/.test(listMatch[2]);
|
|
21191
|
-
blocks.push({ type: "list_item", text: listMatch[3].trim(), ordered, indent });
|
|
21218
|
+
if (/^!\[image\]\([^)]*\)\s*$/.test(line.trim())) {
|
|
21219
|
+
units.push({ kind: "image", raw: line.trim(), lines: [line.trim()] });
|
|
21192
21220
|
i++;
|
|
21193
21221
|
continue;
|
|
21194
21222
|
}
|
|
21195
|
-
|
|
21196
|
-
i
|
|
21223
|
+
const collected = [];
|
|
21224
|
+
while (i < lines.length && lines[i].trim() && !lines[i].trimStart().startsWith("|") && !lines[i].trim().startsWith("<table>")) {
|
|
21225
|
+
collected.push(lines[i].trim());
|
|
21226
|
+
i++;
|
|
21227
|
+
}
|
|
21228
|
+
units.push({ kind: "text", raw: collected.join("\n"), lines: collected });
|
|
21197
21229
|
}
|
|
21198
|
-
return
|
|
21230
|
+
return units;
|
|
21199
21231
|
}
|
|
21200
|
-
function
|
|
21201
|
-
|
|
21202
|
-
|
|
21203
|
-
|
|
21204
|
-
|
|
21205
|
-
|
|
21206
|
-
|
|
21207
|
-
|
|
21208
|
-
const idx = match.index;
|
|
21209
|
-
if (idx > lastIdx) {
|
|
21210
|
-
spans.push({ text: text.slice(lastIdx, idx), bold: false, italic: false, code: false });
|
|
21232
|
+
function alignUnits(a, b) {
|
|
21233
|
+
const m = a.length, n = b.length;
|
|
21234
|
+
if (m * n > 4e6) {
|
|
21235
|
+
const result2 = [];
|
|
21236
|
+
let pre = 0;
|
|
21237
|
+
while (pre < m && pre < n && a[pre] === b[pre]) {
|
|
21238
|
+
result2.push([pre, pre]);
|
|
21239
|
+
pre++;
|
|
21211
21240
|
}
|
|
21212
|
-
|
|
21213
|
-
|
|
21214
|
-
|
|
21215
|
-
|
|
21216
|
-
|
|
21217
|
-
} else if (raw.startsWith("**") || raw.startsWith("__")) {
|
|
21218
|
-
spans.push({ text: raw.slice(2, -2), bold: true, italic: false, code: false });
|
|
21241
|
+
let suf = 0;
|
|
21242
|
+
while (suf < m - pre && suf < n - pre && a[m - 1 - suf] === b[n - 1 - suf]) suf++;
|
|
21243
|
+
const aMid = m - pre - suf, bMid = n - pre - suf;
|
|
21244
|
+
if (aMid === bMid) {
|
|
21245
|
+
for (let i2 = 0; i2 < aMid; i2++) result2.push([pre + i2, pre + i2]);
|
|
21219
21246
|
} else {
|
|
21220
|
-
|
|
21247
|
+
for (let i2 = 0; i2 < aMid; i2++) result2.push([pre + i2, null]);
|
|
21248
|
+
for (let j2 = 0; j2 < bMid; j2++) result2.push([null, pre + j2]);
|
|
21221
21249
|
}
|
|
21222
|
-
|
|
21250
|
+
for (let s = suf - 1; s >= 0; s--) result2.push([m - 1 - s, n - 1 - s]);
|
|
21251
|
+
return result2;
|
|
21223
21252
|
}
|
|
21224
|
-
|
|
21225
|
-
|
|
21253
|
+
const dp = Array.from({ length: m + 1 }, () => new Int32Array(n + 1));
|
|
21254
|
+
for (let i2 = 1; i2 <= m; i2++) {
|
|
21255
|
+
for (let j2 = 1; j2 <= n; j2++) {
|
|
21256
|
+
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]);
|
|
21257
|
+
}
|
|
21226
21258
|
}
|
|
21227
|
-
|
|
21228
|
-
|
|
21259
|
+
const matches = [];
|
|
21260
|
+
let i = m, j = n;
|
|
21261
|
+
while (i > 0 && j > 0) {
|
|
21262
|
+
if (a[i - 1] === b[j - 1] && dp[i][j] === dp[i - 1][j - 1] + 1) {
|
|
21263
|
+
matches.push([i - 1, j - 1]);
|
|
21264
|
+
i--;
|
|
21265
|
+
j--;
|
|
21266
|
+
} else if (dp[i - 1][j] >= dp[i][j - 1]) i--;
|
|
21267
|
+
else j--;
|
|
21229
21268
|
}
|
|
21230
|
-
|
|
21231
|
-
|
|
21232
|
-
|
|
21233
|
-
|
|
21234
|
-
|
|
21235
|
-
|
|
21236
|
-
|
|
21237
|
-
|
|
21269
|
+
matches.reverse();
|
|
21270
|
+
const result = [];
|
|
21271
|
+
let ai = 0, bi = 0;
|
|
21272
|
+
const flushGap = (aEnd, bEnd) => {
|
|
21273
|
+
if (aEnd - ai === bEnd - bi) {
|
|
21274
|
+
while (ai < aEnd) result.push([ai++, bi++]);
|
|
21275
|
+
return;
|
|
21276
|
+
}
|
|
21277
|
+
while (ai < aEnd && bi < bEnd) {
|
|
21278
|
+
const sim = normalizedSimilarity(a[ai], b[bi]);
|
|
21279
|
+
if (sim >= 0.4) {
|
|
21280
|
+
if (aEnd - ai > bEnd - bi && bestSimInRange(a, ai + 1, ai + (aEnd - ai) - (bEnd - bi), b[bi]) > sim) {
|
|
21281
|
+
result.push([ai++, null]);
|
|
21282
|
+
} else if (bEnd - bi > aEnd - ai && bestSimInRange(b, bi + 1, bi + (bEnd - bi) - (aEnd - ai), a[ai]) > sim) {
|
|
21283
|
+
result.push([null, bi++]);
|
|
21284
|
+
} else {
|
|
21285
|
+
result.push([ai++, bi++]);
|
|
21286
|
+
}
|
|
21287
|
+
} else if (aEnd - ai >= bEnd - bi) result.push([ai++, null]);
|
|
21288
|
+
else result.push([null, bi++]);
|
|
21289
|
+
}
|
|
21290
|
+
while (ai < aEnd) result.push([ai++, null]);
|
|
21291
|
+
while (bi < bEnd) result.push([null, bi++]);
|
|
21292
|
+
};
|
|
21293
|
+
for (const [pi, pj] of matches) {
|
|
21294
|
+
flushGap(pi, pj);
|
|
21295
|
+
result.push([ai++, bi++]);
|
|
21296
|
+
}
|
|
21297
|
+
flushGap(m, n);
|
|
21298
|
+
return result;
|
|
21238
21299
|
}
|
|
21239
|
-
function
|
|
21240
|
-
|
|
21300
|
+
function bestSimInRange(arr, from, to, target) {
|
|
21301
|
+
let best = 0;
|
|
21302
|
+
for (let k = from; k <= to && k < arr.length; k++) {
|
|
21303
|
+
const s = normalizedSimilarity(arr[k], target);
|
|
21304
|
+
if (s > best) best = s;
|
|
21305
|
+
}
|
|
21306
|
+
return best;
|
|
21241
21307
|
}
|
|
21242
|
-
function
|
|
21243
|
-
|
|
21244
|
-
return spans.map((span) => {
|
|
21245
|
-
let charId = span.code || span.bold || span.italic ? spanToCharPrId(span) : defaultCharPr;
|
|
21246
|
-
if (mapCharId) charId = mapCharId(charId);
|
|
21247
|
-
return `<hp:run charPrIDRef="${charId}"><hp:t>${escapeXml(span.text)}</hp:t></hp:run>`;
|
|
21248
|
-
}).join("");
|
|
21308
|
+
function escapeGfm(text) {
|
|
21309
|
+
return text.replace(/~/g, "\\~");
|
|
21249
21310
|
}
|
|
21250
|
-
|
|
21251
|
-
|
|
21252
|
-
|
|
21311
|
+
var HWP_SHAPE_ALT_TEXT_RE = /(?:모서리가 둥근 |둥근 )?(?:사각형|직사각형|정사각형|원|타원|삼각형|이등변 삼각형|직각 삼각형|선|직선|곡선|화살표|굵은 화살표|이중 화살표|오각형|육각형|팔각형|별|[4-8]점별|십자|십자형|구름|구름형|마름모|도넛|평행사변형|사다리꼴|부채꼴|호|반원|물결|번개|하트|빗금|블록 화살표|수식|표|그림|개체|그리기\s?개체|묶음\s?개체|글상자|수식\s?개체|OLE\s?개체)\s?입니다\.?/g;
|
|
21312
|
+
function sanitizeText(text) {
|
|
21313
|
+
let result = mapPuaText(text).replace(/[\u{F0000}-\u{FFFFD}]/gu, "").replace(HWP_SHAPE_ALT_TEXT_RE, "").replace(/ +/g, " ").trim();
|
|
21314
|
+
if (result.length <= 30 && result.includes(" ")) {
|
|
21315
|
+
const tokens = result.split(" ");
|
|
21316
|
+
const koreanSingleCharCount = tokens.filter((t) => t.length === 1 && /[가-ㄱ-ㆎ]/.test(t)).length;
|
|
21317
|
+
if (tokens.length >= 3 && koreanSingleCharCount / tokens.length >= 0.7) {
|
|
21318
|
+
result = tokens.join("");
|
|
21319
|
+
}
|
|
21253
21320
|
}
|
|
21254
|
-
|
|
21255
|
-
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0">${runs}</hp:p>`;
|
|
21256
|
-
}
|
|
21257
|
-
function headingParaPrId(level) {
|
|
21258
|
-
if (level === 1) return PARA_H1;
|
|
21259
|
-
if (level === 2) return PARA_H2;
|
|
21260
|
-
if (level === 3) return PARA_H3;
|
|
21261
|
-
return PARA_H4;
|
|
21321
|
+
return result;
|
|
21262
21322
|
}
|
|
21263
|
-
function
|
|
21264
|
-
|
|
21265
|
-
if (level === 2) return CHAR_H2;
|
|
21266
|
-
if (level === 3) return CHAR_H3;
|
|
21267
|
-
return CHAR_H4;
|
|
21323
|
+
function normForMatch(text) {
|
|
21324
|
+
return sanitizeText(text).replace(/\s+/g, " ").trim();
|
|
21268
21325
|
}
|
|
21269
|
-
function
|
|
21270
|
-
return
|
|
21271
|
-
<ocf:container xmlns:ocf="${NS_OCF}" xmlns:hpf="${NS_HPF}">
|
|
21272
|
-
<ocf:rootfiles>
|
|
21273
|
-
<ocf:rootfile full-path="Contents/content.hpf" media-type="application/hwpml-package+xml"/>
|
|
21274
|
-
</ocf:rootfiles>
|
|
21275
|
-
</ocf:container>`;
|
|
21326
|
+
function unescapeGfm(text) {
|
|
21327
|
+
return text.replace(/\\~/g, "~");
|
|
21276
21328
|
}
|
|
21277
|
-
function
|
|
21278
|
-
|
|
21279
|
-
|
|
21280
|
-
<opf:manifest>
|
|
21281
|
-
<opf:item id="header" href="Contents/header.xml" media-type="application/xml"/>
|
|
21282
|
-
<opf:item id="section0" href="Contents/section0.xml" media-type="application/xml"/>
|
|
21283
|
-
</opf:manifest>
|
|
21284
|
-
<opf:spine>
|
|
21285
|
-
<opf:itemref idref="header" linear="no"/>
|
|
21286
|
-
<opf:itemref idref="section0" linear="yes"/>
|
|
21287
|
-
</opf:spine>
|
|
21288
|
-
</opf:package>`;
|
|
21329
|
+
function summarize(text) {
|
|
21330
|
+
const t = text.replace(/\s+/g, " ").trim();
|
|
21331
|
+
return t.length > 80 ? t.slice(0, 77) + "..." : t;
|
|
21289
21332
|
}
|
|
21290
|
-
function
|
|
21291
|
-
const
|
|
21292
|
-
|
|
21293
|
-
|
|
21294
|
-
|
|
21295
|
-
|
|
21296
|
-
|
|
21297
|
-
|
|
21298
|
-
|
|
21299
|
-
|
|
21300
|
-
|
|
21333
|
+
function replicateGfmTable(table) {
|
|
21334
|
+
const { cells, rows: numRows, cols: numCols } = table;
|
|
21335
|
+
if (numRows === 0 || numCols === 0) return null;
|
|
21336
|
+
if (numRows === 1 && numCols === 1) return null;
|
|
21337
|
+
if (numCols === 1) return null;
|
|
21338
|
+
const display = Array.from({ length: numRows }, (_, r) => Array.from({ length: numCols }, (_2, c) => ({ text: "", gridR: r, gridC: c })));
|
|
21339
|
+
const skip = /* @__PURE__ */ new Set();
|
|
21340
|
+
for (let r = 0; r < numRows; r++) {
|
|
21341
|
+
for (let c = 0; c < numCols; c++) {
|
|
21342
|
+
if (skip.has(`${r},${c}`)) continue;
|
|
21343
|
+
const cell = cells[r]?.[c];
|
|
21344
|
+
if (!cell) continue;
|
|
21345
|
+
display[r][c] = {
|
|
21346
|
+
text: escapeGfm(sanitizeText(cell.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>"),
|
|
21347
|
+
gridR: r,
|
|
21348
|
+
gridC: c
|
|
21349
|
+
};
|
|
21350
|
+
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
21351
|
+
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
21352
|
+
if (dr === 0 && dc === 0) continue;
|
|
21353
|
+
if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
|
|
21354
|
+
}
|
|
21355
|
+
}
|
|
21356
|
+
c += cell.colSpan - 1;
|
|
21357
|
+
}
|
|
21358
|
+
}
|
|
21359
|
+
const uniqueRows = [];
|
|
21360
|
+
let pendingLabelRow = null;
|
|
21361
|
+
for (let r = 0; r < display.length; r++) {
|
|
21362
|
+
const row = display[r];
|
|
21363
|
+
if (row.every((cell) => cell.text === "")) continue;
|
|
21364
|
+
const nonEmptyCols = row.filter((cell) => cell.text !== "");
|
|
21365
|
+
const hasSkipInRow = row.some((_, c) => skip.has(`${r},${c}`));
|
|
21366
|
+
if (!hasSkipInRow && nonEmptyCols.length === 1 && row[0].text !== "" && row.slice(1).every((c) => c.text === "")) {
|
|
21367
|
+
if (pendingLabelRow) uniqueRows.push(pendingLabelRow);
|
|
21368
|
+
pendingLabelRow = row;
|
|
21369
|
+
continue;
|
|
21370
|
+
}
|
|
21371
|
+
if (pendingLabelRow) {
|
|
21372
|
+
if (row[0].text === "") row[0] = pendingLabelRow[0];
|
|
21373
|
+
else uniqueRows.push(pendingLabelRow);
|
|
21374
|
+
pendingLabelRow = null;
|
|
21375
|
+
}
|
|
21376
|
+
uniqueRows.push(row);
|
|
21377
|
+
}
|
|
21378
|
+
if (pendingLabelRow) uniqueRows.push(pendingLabelRow);
|
|
21379
|
+
return uniqueRows.length > 0 ? uniqueRows : null;
|
|
21301
21380
|
}
|
|
21302
|
-
function
|
|
21303
|
-
const
|
|
21304
|
-
const
|
|
21305
|
-
|
|
21306
|
-
|
|
21307
|
-
|
|
21308
|
-
|
|
21309
|
-
|
|
21310
|
-
|
|
21311
|
-
|
|
21312
|
-
|
|
21313
|
-
<hh:border borderFillIDRef="1" offsetLeft="0" offsetRight="0" offsetTop="0" offsetBottom="0" connect="0" ignoreMargin="0"/>
|
|
21314
|
-
</hh:paraPr>`;
|
|
21381
|
+
function parseGfmTable(lines) {
|
|
21382
|
+
const rows = [];
|
|
21383
|
+
for (const line of lines) {
|
|
21384
|
+
const trimmed = line.trim();
|
|
21385
|
+
if (!trimmed.startsWith("|")) continue;
|
|
21386
|
+
const cells = trimmed.split(/(?<!\\)\|/).slice(1, -1).map((c) => c.trim());
|
|
21387
|
+
if (cells.length === 0) continue;
|
|
21388
|
+
if (cells.every((c) => /^:?-{3,}:?$/.test(c))) continue;
|
|
21389
|
+
rows.push(cells);
|
|
21390
|
+
}
|
|
21391
|
+
return rows;
|
|
21315
21392
|
}
|
|
21316
|
-
|
|
21317
|
-
|
|
21318
|
-
var GONGMUN_CENTER = GONGMUN_LIST_BASE + GONGMUN_LIST_LEVELS;
|
|
21319
|
-
var CHAR_VARIANT_BASE = 11;
|
|
21320
|
-
var GONGMUN_BODY_RATIO = 95;
|
|
21321
|
-
function plainRenderText(text) {
|
|
21322
|
-
return parseInlineMarkdown(text).map((s) => s.text).join("");
|
|
21393
|
+
function unescapeGfmCell(text) {
|
|
21394
|
+
return text.replace(/<br\s*\/?>/gi, "\n").replace(/\\\|/g, "|").replace(/\\~/g, "~");
|
|
21323
21395
|
}
|
|
21324
|
-
function
|
|
21325
|
-
|
|
21326
|
-
|
|
21327
|
-
|
|
21328
|
-
|
|
21329
|
-
|
|
21330
|
-
|
|
21331
|
-
|
|
21332
|
-
|
|
21333
|
-
|
|
21334
|
-
|
|
21335
|
-
if (block.type === "list_item" && gongmunList.has(i)) {
|
|
21336
|
-
const { marker, depth } = gongmunList.get(i);
|
|
21337
|
-
const content = plainRenderText(block.text || "");
|
|
21338
|
-
text = marker ? `${marker} ${content}` : content;
|
|
21339
|
-
const { left, indent } = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering);
|
|
21340
|
-
firstW = pageW - left - Math.max(indent, 0);
|
|
21341
|
-
contW = pageW - left - Math.max(-indent, 0);
|
|
21342
|
-
} else if (block.type === "paragraph") {
|
|
21343
|
-
const raw = (block.text || "").trim();
|
|
21344
|
-
if (/^<center>[\s\S]*<\/center>$/i.test(raw)) continue;
|
|
21345
|
-
text = plainRenderText(raw);
|
|
21346
|
-
firstW = contW = pageW;
|
|
21347
|
-
} else {
|
|
21348
|
-
continue;
|
|
21349
|
-
}
|
|
21350
|
-
if (!text) continue;
|
|
21351
|
-
const r = fitRatioForFewerLines(text, firstW, contW, gongmun.bodyHeight, GONGMUN_BODY_RATIO, minRatio);
|
|
21352
|
-
if (r === null) continue;
|
|
21353
|
-
ratioByBlock.set(i, r);
|
|
21354
|
-
if (!variants.includes(r)) variants.push(r);
|
|
21396
|
+
function replicateCellInnerHtml(cell) {
|
|
21397
|
+
if (cell.blocks?.length) {
|
|
21398
|
+
return cell.blocks.map((b) => {
|
|
21399
|
+
if (b.type === "table" && b.table) {
|
|
21400
|
+
const cap = b.table.caption ? sanitizeText(b.table.caption) : "";
|
|
21401
|
+
return (cap ? cap + "<br>" : "") + replicateTableToHtml(b.table);
|
|
21402
|
+
}
|
|
21403
|
+
if (b.type === "image" && b.text) return `<img src="${b.text}" alt="image">`;
|
|
21404
|
+
const t = sanitizeText(b.text ?? "");
|
|
21405
|
+
return t ? t.replace(/\n/g, "<br>") : "";
|
|
21406
|
+
}).filter(Boolean).join("<br>");
|
|
21355
21407
|
}
|
|
21356
|
-
return
|
|
21408
|
+
return sanitizeText(cell.text).replace(/\n/g, "<br>");
|
|
21357
21409
|
}
|
|
21358
|
-
function
|
|
21359
|
-
const
|
|
21360
|
-
|
|
21361
|
-
|
|
21362
|
-
|
|
21410
|
+
function replicateTableToHtml(table) {
|
|
21411
|
+
const rows = replicateHtmlTable(table);
|
|
21412
|
+
const lines = ["<table>"];
|
|
21413
|
+
for (let r = 0; r < rows.length; r++) {
|
|
21414
|
+
const tag = rows[r].tag;
|
|
21415
|
+
const rowHtml = rows[r].cells.map((cell) => {
|
|
21416
|
+
const attrs = [];
|
|
21417
|
+
if (cell.colSpan > 1) attrs.push(`colspan="${cell.colSpan}"`);
|
|
21418
|
+
if (cell.rowSpan > 1) attrs.push(`rowspan="${cell.rowSpan}"`);
|
|
21419
|
+
const attrStr = attrs.length ? " " + attrs.join(" ") : "";
|
|
21420
|
+
return `<${tag}${attrStr}>${cell.inner}</${tag}>`;
|
|
21421
|
+
});
|
|
21422
|
+
if (rowHtml.length) lines.push(`<tr>${rowHtml.join("")}</tr>`);
|
|
21423
|
+
}
|
|
21424
|
+
lines.push("</table>");
|
|
21425
|
+
return lines.join("\n");
|
|
21363
21426
|
}
|
|
21364
|
-
function
|
|
21365
|
-
|
|
21366
|
-
|
|
21367
|
-
|
|
21368
|
-
|
|
21369
|
-
|
|
21370
|
-
|
|
21371
|
-
|
|
21372
|
-
|
|
21427
|
+
function replicateHtmlTable(table) {
|
|
21428
|
+
const { cells, rows: numRows, cols: numCols } = table;
|
|
21429
|
+
const skip = /* @__PURE__ */ new Set();
|
|
21430
|
+
const result = [];
|
|
21431
|
+
for (let r = 0; r < numRows; r++) {
|
|
21432
|
+
const tag = r === 0 ? "th" : "td";
|
|
21433
|
+
const rowCells = [];
|
|
21434
|
+
for (let c = 0; c < numCols; c++) {
|
|
21435
|
+
if (skip.has(`${r},${c}`)) continue;
|
|
21436
|
+
const cell = cells[r]?.[c];
|
|
21437
|
+
if (!cell) continue;
|
|
21438
|
+
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
21439
|
+
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
21440
|
+
if (dr === 0 && dc === 0) continue;
|
|
21441
|
+
if (r + dr < numRows && c + dc < numCols) skip.add(`${r + dr},${c + dc}`);
|
|
21442
|
+
}
|
|
21443
|
+
}
|
|
21444
|
+
rowCells.push({
|
|
21445
|
+
inner: replicateCellInnerHtml(cell),
|
|
21446
|
+
colSpan: cell.colSpan,
|
|
21447
|
+
rowSpan: cell.rowSpan,
|
|
21448
|
+
gridR: r,
|
|
21449
|
+
gridC: c
|
|
21450
|
+
});
|
|
21451
|
+
}
|
|
21452
|
+
if (rowCells.length) result.push({ tag, cells: rowCells });
|
|
21373
21453
|
}
|
|
21374
|
-
|
|
21375
|
-
|
|
21376
|
-
|
|
21377
|
-
|
|
21378
|
-
|
|
21379
|
-
|
|
21380
|
-
|
|
21381
|
-
|
|
21382
|
-
|
|
21383
|
-
|
|
21384
|
-
|
|
21385
|
-
|
|
21386
|
-
|
|
21387
|
-
|
|
21388
|
-
|
|
21389
|
-
|
|
21390
|
-
|
|
21391
|
-
|
|
21392
|
-
|
|
21393
|
-
|
|
21394
|
-
)
|
|
21454
|
+
return result;
|
|
21455
|
+
}
|
|
21456
|
+
function parseHtmlTable(raw) {
|
|
21457
|
+
const re = /<(\/?)(table|tr|td|th)((?:"[^"]*"|'[^']*'|[^>"'])*?)>/gi;
|
|
21458
|
+
let depth = 0;
|
|
21459
|
+
let currentRow = null;
|
|
21460
|
+
let cellStart = -1;
|
|
21461
|
+
let cellInfo = null;
|
|
21462
|
+
const rows = [];
|
|
21463
|
+
let m;
|
|
21464
|
+
while ((m = re.exec(raw)) !== null) {
|
|
21465
|
+
const isClose = m[1] === "/";
|
|
21466
|
+
const tag = m[2].toLowerCase();
|
|
21467
|
+
const attrs = m[3] || "";
|
|
21468
|
+
if (tag === "table") {
|
|
21469
|
+
depth += isClose ? -1 : 1;
|
|
21470
|
+
if (depth < 0) return null;
|
|
21471
|
+
continue;
|
|
21472
|
+
}
|
|
21473
|
+
if (depth !== 1) continue;
|
|
21474
|
+
if (tag === "tr") {
|
|
21475
|
+
if (!isClose) currentRow = [];
|
|
21476
|
+
else if (currentRow) {
|
|
21477
|
+
rows.push({ tag: rows.length === 0 ? "th" : "td", cells: currentRow });
|
|
21478
|
+
currentRow = null;
|
|
21479
|
+
}
|
|
21480
|
+
} else {
|
|
21481
|
+
if (!isClose) {
|
|
21482
|
+
const cs = parseInt(attrs.match(/colspan\s*=\s*"(\d+)"/i)?.[1] || "1", 10);
|
|
21483
|
+
const rs = parseInt(attrs.match(/rowspan\s*=\s*"(\d+)"/i)?.[1] || "1", 10);
|
|
21484
|
+
cellStart = m.index + m[0].length;
|
|
21485
|
+
cellInfo = { colSpan: isNaN(cs) ? 1 : cs, rowSpan: isNaN(rs) ? 1 : rs };
|
|
21486
|
+
} else if (cellStart >= 0 && cellInfo && currentRow) {
|
|
21487
|
+
currentRow.push({ inner: raw.slice(cellStart, m.index), colSpan: cellInfo.colSpan, rowSpan: cellInfo.rowSpan });
|
|
21488
|
+
cellStart = -1;
|
|
21489
|
+
cellInfo = null;
|
|
21490
|
+
}
|
|
21491
|
+
}
|
|
21395
21492
|
}
|
|
21396
|
-
return
|
|
21397
|
-
|
|
21398
|
-
</hh:charProperties>`;
|
|
21493
|
+
if (depth !== 0) return null;
|
|
21494
|
+
return rows;
|
|
21399
21495
|
}
|
|
21400
|
-
|
|
21401
|
-
|
|
21402
|
-
|
|
21403
|
-
|
|
21404
|
-
|
|
21405
|
-
|
|
21406
|
-
|
|
21407
|
-
paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: 160 }),
|
|
21408
|
-
paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400 }),
|
|
21409
|
-
paraPr(6, { align: "LEFT", lineSpacing: 150, indent: 600 }),
|
|
21410
|
-
paraPr(7, { align: "LEFT", lineSpacing: 160, indent: 600 })
|
|
21411
|
-
];
|
|
21412
|
-
return `<hh:paraProperties itemCnt="${base2.length}">
|
|
21413
|
-
${base2.join("\n")}
|
|
21414
|
-
</hh:paraProperties>`;
|
|
21496
|
+
var AUTONUM_PREFIX_RE = /^(?:[0-90-9a-zA-Z가-힣]{1,6}[.)\]:]|[([][0-90-9a-zA-Z가-힣]{1,6}[)\]][.:]?|[ⅰ-ⅹⅠ-Ⅹ①-⑮][.)\]:]?)$/u;
|
|
21497
|
+
function htmlCellInnerToLines(inner) {
|
|
21498
|
+
let hadNonText = false;
|
|
21499
|
+
let work = inner;
|
|
21500
|
+
if (/<table[\s>]/i.test(work)) {
|
|
21501
|
+
hadNonText = true;
|
|
21502
|
+
work = removeNestedTables(work);
|
|
21415
21503
|
}
|
|
21416
|
-
|
|
21417
|
-
|
|
21418
|
-
|
|
21419
|
-
paraPr(0, { lineSpacing: ls, keepWord: true }),
|
|
21420
|
-
paraPr(1, { align: titleAlign, spaceBefore: 400, spaceAfter: 400, lineSpacing: ls, keepWord: true }),
|
|
21421
|
-
paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: ls, keepWord: true }),
|
|
21422
|
-
paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: ls, keepWord: true }),
|
|
21423
|
-
paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: ls, keepWord: true }),
|
|
21424
|
-
paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400, keepWord: true }),
|
|
21425
|
-
paraPr(6, { align: "LEFT", lineSpacing: ls, indent: 600, keepWord: true }),
|
|
21426
|
-
paraPr(7, { align: "LEFT", lineSpacing: ls, indent: 600, keepWord: true })
|
|
21427
|
-
];
|
|
21428
|
-
for (let d = 0; d < GONGMUN_LIST_LEVELS; d++) {
|
|
21429
|
-
const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering);
|
|
21430
|
-
const sectionGap = gongmun.numbering === "report" && d === 0 ? Math.round(gongmun.bodyHeight * 0.5) : 0;
|
|
21431
|
-
base.push(paraPr(GONGMUN_LIST_BASE + d, { align: "JUSTIFY", lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true }));
|
|
21504
|
+
if (/<img\s/i.test(work)) {
|
|
21505
|
+
hadNonText = true;
|
|
21506
|
+
work = work.replace(/<img\s(?:"[^"]*"|'[^']*'|[^>"'])*?>/gi, "");
|
|
21432
21507
|
}
|
|
21433
|
-
|
|
21434
|
-
return
|
|
21435
|
-
${base.join("\n")}
|
|
21436
|
-
</hh:paraProperties>`;
|
|
21508
|
+
const lines = work.split(/<br\s*\/?>/gi).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
21509
|
+
return { lines, hadNonText };
|
|
21437
21510
|
}
|
|
21438
|
-
function
|
|
21439
|
-
const
|
|
21440
|
-
|
|
21441
|
-
|
|
21442
|
-
|
|
21443
|
-
|
|
21444
|
-
|
|
21445
|
-
|
|
21446
|
-
|
|
21447
|
-
|
|
21448
|
-
|
|
21449
|
-
|
|
21450
|
-
|
|
21451
|
-
|
|
21452
|
-
|
|
21453
|
-
|
|
21454
|
-
|
|
21455
|
-
|
|
21456
|
-
|
|
21457
|
-
|
|
21458
|
-
<hh:fontface lang="LATIN" fontCnt="3">
|
|
21459
|
-
<hh:font id="0" face="Times New Roman" type="TTF" isEmbedded="0">
|
|
21460
|
-
<hh:typeInfo familyType="FCAT_OLDSTYLE" weight="5" proportion="4" contrast="2" strokeVariation="0" armStyle="0" letterform="0" midline="0" xHeight="4"/>
|
|
21461
|
-
</hh:font>
|
|
21462
|
-
<hh:font id="1" face="Consolas" type="TTF" isEmbedded="0">
|
|
21463
|
-
<hh:typeInfo familyType="FCAT_MODERN" weight="5" proportion="0" contrast="0" strokeVariation="0" armStyle="0" letterform="0" midline="0" xHeight="0"/>
|
|
21464
|
-
</hh:font>
|
|
21465
|
-
<hh:font id="2" face="Arial Black" type="TTF" isEmbedded="0">
|
|
21466
|
-
<hh:typeInfo familyType="FCAT_GOTHIC" weight="9" proportion="0" contrast="0" strokeVariation="0" armStyle="0" letterform="0" midline="0" xHeight="0"/>
|
|
21467
|
-
</hh:font>
|
|
21468
|
-
</hh:fontface>
|
|
21469
|
-
<hh:fontface lang="HANJA" fontCnt="1">
|
|
21470
|
-
<hh:font id="0" face="\uD568\uCD08\uB86C\uBC14\uD0D5" type="TTF" isEmbedded="0">
|
|
21471
|
-
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
21472
|
-
</hh:font>
|
|
21473
|
-
</hh:fontface>
|
|
21474
|
-
<hh:fontface lang="JAPANESE" fontCnt="1">
|
|
21475
|
-
<hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
|
|
21476
|
-
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
21477
|
-
</hh:font>
|
|
21478
|
-
</hh:fontface>
|
|
21479
|
-
<hh:fontface lang="OTHER" fontCnt="1">
|
|
21480
|
-
<hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
|
|
21481
|
-
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
21482
|
-
</hh:font>
|
|
21483
|
-
</hh:fontface>
|
|
21484
|
-
<hh:fontface lang="SYMBOL" fontCnt="1">
|
|
21485
|
-
<hh:font id="0" face="Symbol" type="TTF" isEmbedded="0">
|
|
21486
|
-
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
21487
|
-
</hh:font>
|
|
21488
|
-
</hh:fontface>
|
|
21489
|
-
<hh:fontface lang="USER" fontCnt="1">
|
|
21490
|
-
<hh:font id="0" face="\uAD74\uB9BC" type="TTF" isEmbedded="0">
|
|
21491
|
-
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="0" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
21492
|
-
</hh:font>
|
|
21493
|
-
</hh:fontface>
|
|
21494
|
-
</hh:fontfaces>
|
|
21495
|
-
<hh:borderFills itemCnt="2">
|
|
21496
|
-
<hh:borderFill id="1" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
|
|
21497
|
-
<hh:slash type="NONE" Crooked="0" isCounter="0"/>
|
|
21498
|
-
<hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
|
|
21499
|
-
<hh:leftBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
21500
|
-
<hh:rightBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
21501
|
-
<hh:topBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
21502
|
-
<hh:bottomBorder type="NONE" width="0.1 mm" color="#000000"/>
|
|
21503
|
-
</hh:borderFill>
|
|
21504
|
-
<hh:borderFill id="2" threeD="0" shadow="0" centerLine="NONE" breakCellSeparateLine="0">
|
|
21505
|
-
<hh:slash type="NONE" Crooked="0" isCounter="0"/>
|
|
21506
|
-
<hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
|
|
21507
|
-
<hh:leftBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
21508
|
-
<hh:rightBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
21509
|
-
<hh:topBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
21510
|
-
<hh:bottomBorder type="SOLID" width="0.12 mm" color="#000000"/>
|
|
21511
|
-
</hh:borderFill>
|
|
21512
|
-
</hh:borderFills>
|
|
21513
|
-
${charPropsXml}
|
|
21514
|
-
<hh:tabProperties itemCnt="0"/>
|
|
21515
|
-
<hh:numberings itemCnt="0"/>
|
|
21516
|
-
<hh:bullets itemCnt="0"/>
|
|
21517
|
-
${paraPropsXml}
|
|
21518
|
-
<hh:styles itemCnt="1">
|
|
21519
|
-
<hh:style id="0" type="PARA" name="\uBC14\uD0D5\uAE00" engName="Normal" paraPrIDRef="0" charPrIDRef="0" nextStyleIDRef="0" langIDRef="1042" lockForm="0"/>
|
|
21520
|
-
</hh:styles>
|
|
21521
|
-
</hh:refList>
|
|
21522
|
-
<hh:compatibleDocument targetProgram="HWP2018"><hh:layoutCompatibility/></hh:compatibleDocument>
|
|
21523
|
-
</hh:head>`;
|
|
21511
|
+
function extractTopLevelTables(html) {
|
|
21512
|
+
const result = [];
|
|
21513
|
+
let depth = 0;
|
|
21514
|
+
let start = -1;
|
|
21515
|
+
const re = /<(\/?)table(?:[\s>]|>)/gi;
|
|
21516
|
+
let m;
|
|
21517
|
+
while ((m = re.exec(html)) !== null) {
|
|
21518
|
+
if (m[1] !== "/") {
|
|
21519
|
+
if (depth === 0) start = m.index;
|
|
21520
|
+
depth++;
|
|
21521
|
+
} else {
|
|
21522
|
+
depth--;
|
|
21523
|
+
if (depth === 0 && start >= 0) {
|
|
21524
|
+
result.push(html.slice(start, m.index + m[0].length));
|
|
21525
|
+
start = -1;
|
|
21526
|
+
}
|
|
21527
|
+
if (depth < 0) depth = 0;
|
|
21528
|
+
}
|
|
21529
|
+
}
|
|
21530
|
+
return result;
|
|
21524
21531
|
}
|
|
21525
|
-
function
|
|
21526
|
-
|
|
21527
|
-
|
|
21528
|
-
|
|
21529
|
-
|
|
21530
|
-
|
|
21531
|
-
|
|
21532
|
-
|
|
21533
|
-
|
|
21534
|
-
|
|
21532
|
+
function removeNestedTables(html) {
|
|
21533
|
+
let result = "";
|
|
21534
|
+
let depth = 0;
|
|
21535
|
+
const re = /<(\/?)table(?:[\s>]|>)/gi;
|
|
21536
|
+
let last = 0;
|
|
21537
|
+
let m;
|
|
21538
|
+
while ((m = re.exec(html)) !== null) {
|
|
21539
|
+
if (m[1] !== "/") {
|
|
21540
|
+
if (depth === 0) result += html.slice(last, m.index);
|
|
21541
|
+
depth++;
|
|
21542
|
+
} else {
|
|
21543
|
+
depth--;
|
|
21544
|
+
if (depth === 0) last = m.index + m[0].length;
|
|
21545
|
+
if (depth < 0) depth = 0;
|
|
21546
|
+
}
|
|
21547
|
+
}
|
|
21548
|
+
if (depth === 0) result += html.slice(last);
|
|
21549
|
+
return result;
|
|
21535
21550
|
}
|
|
21551
|
+
|
|
21552
|
+
// src/hwpx/gen-table.ts
|
|
21536
21553
|
var TABLE_ID_BASE = 1e3;
|
|
21537
21554
|
var tableIdCounter = TABLE_ID_BASE;
|
|
21538
21555
|
function nextTableId() {
|
|
@@ -21622,41 +21639,18 @@ function generateHtmlTableXml(rawHtml, theme, totalWidth = 44e3) {
|
|
|
21622
21639
|
}
|
|
21623
21640
|
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>`;
|
|
21624
21641
|
}
|
|
21625
|
-
|
|
21626
|
-
|
|
21627
|
-
|
|
21628
|
-
|
|
21629
|
-
|
|
21630
|
-
|
|
21631
|
-
|
|
21632
|
-
|
|
21633
|
-
|
|
21634
|
-
|
|
21635
|
-
|
|
21636
|
-
|
|
21637
|
-
run.push(i);
|
|
21638
|
-
i++;
|
|
21639
|
-
continue;
|
|
21640
|
-
}
|
|
21641
|
-
if (t === "table" || t === "html_table") {
|
|
21642
|
-
let j = i + 1;
|
|
21643
|
-
while (j < blocks.length && (blocks[j].type === "table" || blocks[j].type === "html_table")) j++;
|
|
21644
|
-
if (j < blocks.length && blocks[j].type === "list_item") {
|
|
21645
|
-
i = j;
|
|
21646
|
-
continue;
|
|
21647
|
-
}
|
|
21648
|
-
}
|
|
21649
|
-
break;
|
|
21650
|
-
}
|
|
21651
|
-
const depths = run.map((bi) => Math.min(Math.max(blocks[bi].indent || 0, 0), GONGMUN_LIST_LEVELS - 1));
|
|
21652
|
-
const suppress = gongmun.numbering === "standard" ? computeSuppression(depths) : depths.map(() => false);
|
|
21653
|
-
const numberer = new GongmunNumberer(gongmun.numbering);
|
|
21654
|
-
run.forEach((bi, k) => {
|
|
21655
|
-
const marker = numberer.next(depths[k], suppress[k]);
|
|
21656
|
-
result.set(bi, { marker, depth: depths[k] });
|
|
21657
|
-
});
|
|
21658
|
-
}
|
|
21659
|
-
return result;
|
|
21642
|
+
|
|
21643
|
+
// src/hwpx/gen-section.ts
|
|
21644
|
+
function generateSecPr(gongmun) {
|
|
21645
|
+
const m = gongmun ? {
|
|
21646
|
+
top: mmToHwpunit(gongmun.margins.top),
|
|
21647
|
+
bottom: mmToHwpunit(gongmun.margins.bottom),
|
|
21648
|
+
left: mmToHwpunit(gongmun.margins.left),
|
|
21649
|
+
right: mmToHwpunit(gongmun.margins.right),
|
|
21650
|
+
header: 0,
|
|
21651
|
+
footer: 0
|
|
21652
|
+
} : { top: 8504, bottom: 4252, left: 5670, right: 4252, header: 2835, footer: 2835 };
|
|
21653
|
+
return `<hp:secPr textDirection="HORIZONTAL" spaceColumns="1134" tabStop="8000" outlineShapeIDRef="0" memoShapeIDRef="0" textVerticalWidthHead="0" masterPageCnt="0"><hp:grid lineGrid="0" charGrid="0" wonggojiFormat="0"/><hp:startNum pageStartsOn="BOTH" page="0" pic="0" tbl="0" equation="0"/><hp:visibility hideFirstHeader="0" hideFirstFooter="0" hideFirstMasterPage="0" border="SHOW_ALL" fill="SHOW_ALL" hideFirstPageNum="0" hideFirstEmptyLine="0" showLineNumber="0"/><hp:pagePr landscape="WIDELY" width="59528" height="84188" gutterType="LEFT_ONLY"><hp:margin header="${m.header}" footer="${m.footer}" gutter="0" left="${m.left}" right="${m.right}" top="${m.top}" bottom="${m.bottom}"/></hp:pagePr><hp:footNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar=")" supscript="0"/><hp:noteLine length="-1" type="SOLID" width="0.12 mm" color="#000000"/><hp:noteSpacing betweenNotes="283" belowLine="567" aboveLine="850"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="EACH_COLUMN" beneathText="0"/></hp:footNotePr><hp:endNotePr><hp:autoNumFormat type="DIGIT" userChar="" prefixChar="" suffixChar=")" supscript="0"/><hp:noteLine length="14692344" type="SOLID" width="0.12 mm" color="#000000"/><hp:noteSpacing betweenNotes="0" belowLine="567" aboveLine="850"/><hp:numbering type="CONTINUOUS" newNum="1"/><hp:placement place="END_OF_DOCUMENT" beneathText="0"/></hp:endNotePr></hp:secPr>`;
|
|
21660
21654
|
}
|
|
21661
21655
|
function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null) {
|
|
21662
21656
|
const paraXmls = [];
|
|
@@ -21779,6 +21773,24 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
|
|
|
21779
21773
|
</hs:sec>`;
|
|
21780
21774
|
}
|
|
21781
21775
|
|
|
21776
|
+
// src/hwpx/generator.ts
|
|
21777
|
+
async function markdownToHwpx(markdown, options) {
|
|
21778
|
+
const theme = resolveTheme(options?.theme);
|
|
21779
|
+
const gongmun = options?.gongmun ? resolveGongmun(options.gongmun) : null;
|
|
21780
|
+
const blocks = parseMarkdownToBlocks(markdown);
|
|
21781
|
+
const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
|
|
21782
|
+
const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
|
|
21783
|
+
const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit);
|
|
21784
|
+
const zip = new JSZip7();
|
|
21785
|
+
zip.file("mimetype", "application/hwp+zip", { compression: "STORE" });
|
|
21786
|
+
zip.file("META-INF/container.xml", generateContainerXml());
|
|
21787
|
+
zip.file("Contents/content.hpf", generateManifest());
|
|
21788
|
+
zip.file("Contents/header.xml", generateHeaderXml(theme, gongmun, fit?.variants ?? []));
|
|
21789
|
+
zip.file("Contents/section0.xml", sectionXml);
|
|
21790
|
+
zip.file("Preview/PrvText.txt", buildPrvText(blocks));
|
|
21791
|
+
return await zip.generateAsync({ type: "arraybuffer" });
|
|
21792
|
+
}
|
|
21793
|
+
|
|
21782
21794
|
// src/diff/compare.ts
|
|
21783
21795
|
var SIMILARITY_THRESHOLD = 0.4;
|
|
21784
21796
|
async function compare(bufferA, bufferB, options) {
|
|
@@ -24503,7 +24515,7 @@ async function parseHwp(buffer, options) {
|
|
|
24503
24515
|
async function parsePdf(buffer, options) {
|
|
24504
24516
|
let parsePdfDocument;
|
|
24505
24517
|
try {
|
|
24506
|
-
const mod = await import("./parser-
|
|
24518
|
+
const mod = await import("./parser-NR2TYGO3.js");
|
|
24507
24519
|
parsePdfDocument = mod.parsePdfDocument;
|
|
24508
24520
|
} catch {
|
|
24509
24521
|
return {
|