kordoc 2.2.0 → 2.2.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 +318 -302
- package/dist/{chunk-LYFG7AUT.js → chunk-R34CFFNV.js} +12 -9
- package/dist/chunk-R34CFFNV.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/index.cjs +245 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -9
- package/dist/index.d.ts +3 -9
- package/dist/index.js +245 -48
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +1 -1
- package/dist/{watch-Q5OXA73S.js → watch-VNJDVUVQ.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-LYFG7AUT.js.map +0 -1
- /package/dist/{watch-Q5OXA73S.js.map → watch-VNJDVUVQ.js.map} +0 -0
package/dist/index.d.cts
CHANGED
|
@@ -234,20 +234,14 @@ declare function diffBlocks(blocksA: IRBlock[], blocksB: IRBlock[]): DiffResult;
|
|
|
234
234
|
declare function extractFormFields(blocks: IRBlock[]): FormResult;
|
|
235
235
|
|
|
236
236
|
/**
|
|
237
|
-
* Markdown → HWPX 역변환
|
|
237
|
+
* Markdown → HWPX 역변환
|
|
238
238
|
*
|
|
239
|
-
* 지원: 단락,
|
|
239
|
+
* 지원: 헤딩(h1~h6), 단락, 볼드, 이탤릭, 인라인코드, 코드블록,
|
|
240
|
+
* 순서/비순서 리스트, 수평선, 인용문, 테이블
|
|
240
241
|
* jszip으로 HWPX ZIP 패키징.
|
|
241
242
|
*/
|
|
242
243
|
/**
|
|
243
244
|
* 마크다운 텍스트를 HWPX (ArrayBuffer)로 변환.
|
|
244
|
-
*
|
|
245
|
-
* @example
|
|
246
|
-
* ```ts
|
|
247
|
-
* import { markdownToHwpx } from "kordoc"
|
|
248
|
-
* const hwpxBuffer = await markdownToHwpx("# 제목\n\n본문 텍스트")
|
|
249
|
-
* writeFileSync("output.hwpx", Buffer.from(hwpxBuffer))
|
|
250
|
-
* ```
|
|
251
245
|
*/
|
|
252
246
|
declare function markdownToHwpx(markdown: string): Promise<ArrayBuffer>;
|
|
253
247
|
|
package/dist/index.d.ts
CHANGED
|
@@ -234,20 +234,14 @@ declare function diffBlocks(blocksA: IRBlock[], blocksB: IRBlock[]): DiffResult;
|
|
|
234
234
|
declare function extractFormFields(blocks: IRBlock[]): FormResult;
|
|
235
235
|
|
|
236
236
|
/**
|
|
237
|
-
* Markdown → HWPX 역변환
|
|
237
|
+
* Markdown → HWPX 역변환
|
|
238
238
|
*
|
|
239
|
-
* 지원: 단락,
|
|
239
|
+
* 지원: 헤딩(h1~h6), 단락, 볼드, 이탤릭, 인라인코드, 코드블록,
|
|
240
|
+
* 순서/비순서 리스트, 수평선, 인용문, 테이블
|
|
240
241
|
* jszip으로 HWPX ZIP 패키징.
|
|
241
242
|
*/
|
|
242
243
|
/**
|
|
243
244
|
* 마크다운 텍스트를 HWPX (ArrayBuffer)로 변환.
|
|
244
|
-
*
|
|
245
|
-
* @example
|
|
246
|
-
* ```ts
|
|
247
|
-
* import { markdownToHwpx } from "kordoc"
|
|
248
|
-
* const hwpxBuffer = await markdownToHwpx("# 제목\n\n본문 텍스트")
|
|
249
|
-
* writeFileSync("output.hwpx", Buffer.from(hwpxBuffer))
|
|
250
|
-
* ```
|
|
251
245
|
*/
|
|
252
246
|
declare function markdownToHwpx(markdown: string): Promise<ArrayBuffer>;
|
|
253
247
|
|
package/dist/index.js
CHANGED
|
@@ -139,7 +139,7 @@ import { inflateRawSync } from "zlib";
|
|
|
139
139
|
import { DOMParser } from "@xmldom/xmldom";
|
|
140
140
|
|
|
141
141
|
// src/utils.ts
|
|
142
|
-
var VERSION = true ? "2.2.
|
|
142
|
+
var VERSION = true ? "2.2.2" : "0.0.0-dev";
|
|
143
143
|
function toArrayBuffer(buf) {
|
|
144
144
|
if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {
|
|
145
145
|
return buf.buffer;
|
|
@@ -328,9 +328,12 @@ function trimAndReturn(grid, numRows, maxCols) {
|
|
|
328
328
|
}
|
|
329
329
|
function convertTableToText(rows) {
|
|
330
330
|
return rows.map(
|
|
331
|
-
(row) => row.map((c) => c.text.trim().replace(/\n/g, " ")).filter(Boolean).join("
|
|
331
|
+
(row) => row.map((c) => c.text.trim().replace(/\n/g, " ").replace(/\|/g, "\\|")).filter(Boolean).join(" / ")
|
|
332
332
|
).filter(Boolean).join("\n");
|
|
333
333
|
}
|
|
334
|
+
function escapeGfm(text) {
|
|
335
|
+
return text.replace(/~/g, "\\~");
|
|
336
|
+
}
|
|
334
337
|
var HWP_SHAPE_ALT_TEXT_RE = /(?:모서리가 둥근 |둥근 )?(?:사각형|직사각형|정사각형|원|타원|삼각형|이등변 삼각형|직각 삼각형|선|직선|곡선|화살표|굵은 화살표|이중 화살표|오각형|육각형|팔각형|별|[4-8]점별|십자|십자형|구름|구름형|마름모|도넛|평행사변형|사다리꼴|부채꼴|호|반원|물결|번개|하트|빗금|블록 화살표|수식|표|그림|개체|그리기\s?개체|묶음\s?개체|글상자|수식\s?개체|OLE\s?개체)\s?입니다\.?/g;
|
|
335
338
|
function sanitizeText(text) {
|
|
336
339
|
let result = text.replace(/[\u{F0000}-\u{FFFFD}]/gu, "").replace(HWP_SHAPE_ALT_TEXT_RE, "").replace(/ +/g, " ").trim();
|
|
@@ -440,7 +443,7 @@ function blocksToMarkdown(blocks) {
|
|
|
440
443
|
if (block.footnoteText) {
|
|
441
444
|
text += ` (\uC8FC: ${block.footnoteText})`;
|
|
442
445
|
}
|
|
443
|
-
lines.push(text);
|
|
446
|
+
lines.push(escapeGfm(text), "");
|
|
444
447
|
} else if (block.type === "table" && block.table) {
|
|
445
448
|
if (lines.length > 0 && lines[lines.length - 1] !== "") {
|
|
446
449
|
lines.push("");
|
|
@@ -463,13 +466,13 @@ function tableToMarkdown(table) {
|
|
|
463
466
|
return content.split(/\n/).map((line) => {
|
|
464
467
|
const trimmed = line.trim();
|
|
465
468
|
if (!trimmed) return "";
|
|
466
|
-
if (/^\d+\.\s/.test(trimmed)) return `**${trimmed}**`;
|
|
467
|
-
if (/^[가-힣]\.\s/.test(trimmed)) return ` ${trimmed}`;
|
|
468
|
-
return trimmed;
|
|
469
|
+
if (/^\d+\.\s/.test(trimmed)) return `**${escapeGfm(trimmed)}**`;
|
|
470
|
+
if (/^[가-힣]\.\s/.test(trimmed)) return ` ${escapeGfm(trimmed)}`;
|
|
471
|
+
return escapeGfm(trimmed);
|
|
469
472
|
}).filter(Boolean).join("\n");
|
|
470
473
|
}
|
|
471
474
|
if (numCols === 1 && numRows >= 2) {
|
|
472
|
-
return cells.map((row) => sanitizeText(row[0].text).replace(/\n/g, " ")).filter(Boolean).join("\n");
|
|
475
|
+
return cells.map((row) => escapeGfm(sanitizeText(row[0].text)).replace(/\n/g, " ")).filter(Boolean).join("\n");
|
|
473
476
|
}
|
|
474
477
|
const display = Array.from({ length: numRows }, () => Array(numCols).fill(""));
|
|
475
478
|
const skip = /* @__PURE__ */ new Set();
|
|
@@ -478,7 +481,7 @@ function tableToMarkdown(table) {
|
|
|
478
481
|
if (skip.has(`${r},${c}`)) continue;
|
|
479
482
|
const cell = cells[r]?.[c];
|
|
480
483
|
if (!cell) continue;
|
|
481
|
-
display[r][c] = sanitizeText(cell.text).replace(/\n/g, "<br>");
|
|
484
|
+
display[r][c] = escapeGfm(sanitizeText(cell.text)).replace(/\|/g, "\\|").replace(/\n/g, "<br>");
|
|
482
485
|
for (let dr = 0; dr < cell.rowSpan; dr++) {
|
|
483
486
|
for (let dc = 0; dc < cell.colSpan; dc++) {
|
|
484
487
|
if (dr === 0 && dc === 0) continue;
|
|
@@ -6258,6 +6261,23 @@ var NS_HEAD = "http://www.hancom.co.kr/hwpml/2011/head";
|
|
|
6258
6261
|
var NS_OPF = "http://www.idpf.org/2007/opf/";
|
|
6259
6262
|
var NS_HPF = "http://www.hancom.co.kr/schema/2011/hpf";
|
|
6260
6263
|
var NS_OCF = "urn:oasis:names:tc:opendocument:xmlns:container";
|
|
6264
|
+
var CHAR_NORMAL = 0;
|
|
6265
|
+
var CHAR_BOLD = 1;
|
|
6266
|
+
var CHAR_ITALIC = 2;
|
|
6267
|
+
var CHAR_BOLD_ITALIC = 3;
|
|
6268
|
+
var CHAR_CODE = 4;
|
|
6269
|
+
var CHAR_H1 = 5;
|
|
6270
|
+
var CHAR_H2 = 6;
|
|
6271
|
+
var CHAR_H3 = 7;
|
|
6272
|
+
var CHAR_H4 = 8;
|
|
6273
|
+
var PARA_NORMAL = 0;
|
|
6274
|
+
var PARA_H1 = 1;
|
|
6275
|
+
var PARA_H2 = 2;
|
|
6276
|
+
var PARA_H3 = 3;
|
|
6277
|
+
var PARA_H4 = 4;
|
|
6278
|
+
var PARA_CODE = 5;
|
|
6279
|
+
var PARA_QUOTE = 6;
|
|
6280
|
+
var PARA_LIST = 7;
|
|
6261
6281
|
async function markdownToHwpx(markdown) {
|
|
6262
6282
|
const blocks = parseMarkdownToBlocks(markdown);
|
|
6263
6283
|
const sectionXml = blocksToSectionXml(blocks);
|
|
@@ -6279,6 +6299,25 @@ function parseMarkdownToBlocks(md) {
|
|
|
6279
6299
|
i++;
|
|
6280
6300
|
continue;
|
|
6281
6301
|
}
|
|
6302
|
+
const fenceMatch = line.match(/^(`{3,}|~{3,})(.*)$/);
|
|
6303
|
+
if (fenceMatch) {
|
|
6304
|
+
const fence = fenceMatch[1];
|
|
6305
|
+
const lang = fenceMatch[2].trim();
|
|
6306
|
+
const codeLines = [];
|
|
6307
|
+
i++;
|
|
6308
|
+
while (i < lines.length && !lines[i].startsWith(fence)) {
|
|
6309
|
+
codeLines.push(lines[i]);
|
|
6310
|
+
i++;
|
|
6311
|
+
}
|
|
6312
|
+
if (i < lines.length) i++;
|
|
6313
|
+
blocks.push({ type: "code_block", text: codeLines.join("\n"), lang });
|
|
6314
|
+
continue;
|
|
6315
|
+
}
|
|
6316
|
+
if (/^(\*{3,}|-{3,}|_{3,})\s*$/.test(line.trim())) {
|
|
6317
|
+
blocks.push({ type: "hr" });
|
|
6318
|
+
i++;
|
|
6319
|
+
continue;
|
|
6320
|
+
}
|
|
6282
6321
|
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
6283
6322
|
if (headingMatch) {
|
|
6284
6323
|
blocks.push({ type: "heading", text: headingMatch[2].trim(), level: headingMatch[1].length });
|
|
@@ -6297,19 +6336,101 @@ function parseMarkdownToBlocks(md) {
|
|
|
6297
6336
|
if (cells.length > 0) tableRows.push(cells);
|
|
6298
6337
|
i++;
|
|
6299
6338
|
}
|
|
6300
|
-
if (tableRows.length > 0) {
|
|
6301
|
-
|
|
6339
|
+
if (tableRows.length > 0) blocks.push({ type: "table", rows: tableRows });
|
|
6340
|
+
continue;
|
|
6341
|
+
}
|
|
6342
|
+
if (line.trimStart().startsWith("> ")) {
|
|
6343
|
+
const quoteLines = [];
|
|
6344
|
+
while (i < lines.length && (lines[i].trimStart().startsWith("> ") || lines[i].trimStart().startsWith(">"))) {
|
|
6345
|
+
quoteLines.push(lines[i].replace(/^>\s?/, ""));
|
|
6346
|
+
i++;
|
|
6347
|
+
}
|
|
6348
|
+
for (const ql of quoteLines) {
|
|
6349
|
+
blocks.push({ type: "blockquote", text: ql.trim() || "" });
|
|
6302
6350
|
}
|
|
6303
6351
|
continue;
|
|
6304
6352
|
}
|
|
6353
|
+
const listMatch = line.match(/^(\s*)([-*+]|\d+[.)]) (.+)$/);
|
|
6354
|
+
if (listMatch) {
|
|
6355
|
+
const indent = Math.floor(listMatch[1].length / 2);
|
|
6356
|
+
const ordered = /\d/.test(listMatch[2]);
|
|
6357
|
+
blocks.push({ type: "list_item", text: listMatch[3].trim(), ordered, indent });
|
|
6358
|
+
i++;
|
|
6359
|
+
continue;
|
|
6360
|
+
}
|
|
6305
6361
|
blocks.push({ type: "paragraph", text: line.trim() });
|
|
6306
6362
|
i++;
|
|
6307
6363
|
}
|
|
6308
6364
|
return blocks;
|
|
6309
6365
|
}
|
|
6366
|
+
function parseInlineMarkdown(text) {
|
|
6367
|
+
text = text.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1");
|
|
6368
|
+
text = text.replace(/\[([^\]]*)\]\(([^)]*)\)/g, (_, t, u) => t || u);
|
|
6369
|
+
text = text.replace(/~~([^~]+)~~/g, "$1");
|
|
6370
|
+
const spans = [];
|
|
6371
|
+
const regex = /(`[^`]+`|\*{3}[^*]+\*{3}|\*{2}[^*]+\*{2}|\*[^*]+\*|_{2}[^_]+_{2}|_[^_]+_)/g;
|
|
6372
|
+
let lastIdx = 0;
|
|
6373
|
+
for (const match of text.matchAll(regex)) {
|
|
6374
|
+
const idx = match.index;
|
|
6375
|
+
if (idx > lastIdx) {
|
|
6376
|
+
spans.push({ text: text.slice(lastIdx, idx), bold: false, italic: false, code: false });
|
|
6377
|
+
}
|
|
6378
|
+
const raw = match[0];
|
|
6379
|
+
if (raw.startsWith("`")) {
|
|
6380
|
+
spans.push({ text: raw.slice(1, -1), bold: false, italic: false, code: true });
|
|
6381
|
+
} else if (raw.startsWith("***") || raw.startsWith("___")) {
|
|
6382
|
+
spans.push({ text: raw.slice(3, -3), bold: true, italic: true, code: false });
|
|
6383
|
+
} else if (raw.startsWith("**") || raw.startsWith("__")) {
|
|
6384
|
+
spans.push({ text: raw.slice(2, -2), bold: true, italic: false, code: false });
|
|
6385
|
+
} else {
|
|
6386
|
+
spans.push({ text: raw.slice(1, -1), bold: false, italic: true, code: false });
|
|
6387
|
+
}
|
|
6388
|
+
lastIdx = idx + raw.length;
|
|
6389
|
+
}
|
|
6390
|
+
if (lastIdx < text.length) {
|
|
6391
|
+
spans.push({ text: text.slice(lastIdx), bold: false, italic: false, code: false });
|
|
6392
|
+
}
|
|
6393
|
+
if (spans.length === 0) {
|
|
6394
|
+
spans.push({ text, bold: false, italic: false, code: false });
|
|
6395
|
+
}
|
|
6396
|
+
return spans;
|
|
6397
|
+
}
|
|
6398
|
+
function spanToCharPrId(span) {
|
|
6399
|
+
if (span.code) return CHAR_CODE;
|
|
6400
|
+
if (span.bold && span.italic) return CHAR_BOLD_ITALIC;
|
|
6401
|
+
if (span.bold) return CHAR_BOLD;
|
|
6402
|
+
if (span.italic) return CHAR_ITALIC;
|
|
6403
|
+
return CHAR_NORMAL;
|
|
6404
|
+
}
|
|
6310
6405
|
function escapeXml(text) {
|
|
6311
6406
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
6312
6407
|
}
|
|
6408
|
+
function generateRuns(text, defaultCharPr = CHAR_NORMAL) {
|
|
6409
|
+
const spans = parseInlineMarkdown(text);
|
|
6410
|
+
return spans.map((span) => {
|
|
6411
|
+
const charId = span.code || span.bold || span.italic ? spanToCharPrId(span) : defaultCharPr;
|
|
6412
|
+
return `<hp:run charPrIDRef="${charId}"><hp:t>${escapeXml(span.text)}</hp:t></hp:run>`;
|
|
6413
|
+
}).join("");
|
|
6414
|
+
}
|
|
6415
|
+
function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL) {
|
|
6416
|
+
if (paraPrId === PARA_CODE) {
|
|
6417
|
+
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_CODE}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`;
|
|
6418
|
+
}
|
|
6419
|
+
const runs = generateRuns(text, charPrId);
|
|
6420
|
+
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0">${runs}</hp:p>`;
|
|
6421
|
+
}
|
|
6422
|
+
function headingParaPrId(level) {
|
|
6423
|
+
if (level === 1) return PARA_H1;
|
|
6424
|
+
if (level === 2) return PARA_H2;
|
|
6425
|
+
if (level === 3) return PARA_H3;
|
|
6426
|
+
return PARA_H4;
|
|
6427
|
+
}
|
|
6428
|
+
function headingCharPrId(level) {
|
|
6429
|
+
if (level === 1) return CHAR_H1;
|
|
6430
|
+
if (level === 2) return CHAR_H2;
|
|
6431
|
+
if (level === 3) return CHAR_H3;
|
|
6432
|
+
return CHAR_H4;
|
|
6433
|
+
}
|
|
6313
6434
|
function generateContainerXml() {
|
|
6314
6435
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
6315
6436
|
<ocf:container xmlns:ocf="${NS_OCF}" xmlns:hpf="${NS_HPF}">
|
|
@@ -6331,21 +6452,50 @@ function generateManifest() {
|
|
|
6331
6452
|
</opf:spine>
|
|
6332
6453
|
</opf:package>`;
|
|
6333
6454
|
}
|
|
6455
|
+
function charPr(id, height, bold, italic, fontId = 0) {
|
|
6456
|
+
const boldAttr = bold ? ` bold="1"` : "";
|
|
6457
|
+
const italicAttr = italic ? ` italic="1"` : "";
|
|
6458
|
+
return ` <hh:charPr id="${id}" height="${height}" textColor="#000000" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="0"${boldAttr}${italicAttr}>
|
|
6459
|
+
<hh:fontRef hangul="${fontId}" latin="${fontId}" hanja="${fontId}" japanese="${fontId}" other="${fontId}" symbol="${fontId}" user="${fontId}"/>
|
|
6460
|
+
<hh:ratio hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
|
|
6461
|
+
<hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
|
|
6462
|
+
<hh:relSz hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
|
|
6463
|
+
<hh:offset hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
|
|
6464
|
+
</hh:charPr>`;
|
|
6465
|
+
}
|
|
6466
|
+
function paraPr(id, opts = {}) {
|
|
6467
|
+
const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0 } = opts;
|
|
6468
|
+
return ` <hh:paraPr id="${id}" tabPrIDRef="0" condense="0" fontLineHeight="0" snapToGrid="1" suppressLineNumbers="0" checked="0" textDir="AUTO">
|
|
6469
|
+
<hh:align horizontal="${align}" vertical="BASELINE"/>
|
|
6470
|
+
<hh:heading type="NONE" idRef="0" level="0"/>
|
|
6471
|
+
<hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="BREAK_WORD" widowOrphan="0" keepWithNext="0" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/>
|
|
6472
|
+
<hh:autoSpacing eAsianEng="0" eAsianNum="0"/>
|
|
6473
|
+
<hh:margin indent="${indent}" left="0" right="0" prev="${spaceBefore}" next="${spaceAfter}"/>
|
|
6474
|
+
<hh:lineSpacing type="PERCENT" value="${lineSpacing}"/>
|
|
6475
|
+
<hh:border borderFillIDRef="0" offsetLeft="0" offsetRight="0" offsetTop="0" offsetBottom="0" connect="0" ignoreMargin="0"/>
|
|
6476
|
+
</hh:paraPr>`;
|
|
6477
|
+
}
|
|
6334
6478
|
function generateHeaderXml() {
|
|
6335
6479
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
6336
6480
|
<hh:head xmlns:hh="${NS_HEAD}" xmlns:hp="${NS_PARA}" version="1.4" secCnt="1">
|
|
6337
6481
|
<hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/>
|
|
6338
6482
|
<hh:refList>
|
|
6339
6483
|
<hh:fontfaces itemCnt="7">
|
|
6340
|
-
<hh:fontface lang="HANGUL" fontCnt="
|
|
6484
|
+
<hh:fontface lang="HANGUL" fontCnt="2">
|
|
6341
6485
|
<hh:font id="0" face="\uD568\uCD08\uB86C\uBC14\uD0D5" type="TTF" isEmbedded="0">
|
|
6342
6486
|
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
6343
6487
|
</hh:font>
|
|
6488
|
+
<hh:font id="1" face="\uD568\uCD08\uB86C\uB3CB\uC6C0" type="TTF" isEmbedded="0">
|
|
6489
|
+
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
6490
|
+
</hh:font>
|
|
6344
6491
|
</hh:fontface>
|
|
6345
|
-
<hh:fontface lang="LATIN" fontCnt="
|
|
6492
|
+
<hh:fontface lang="LATIN" fontCnt="2">
|
|
6346
6493
|
<hh:font id="0" face="Times New Roman" type="TTF" isEmbedded="0">
|
|
6347
6494
|
<hh:typeInfo familyType="FCAT_OLDSTYLE" weight="5" proportion="4" contrast="2" strokeVariation="0" armStyle="0" letterform="0" midline="0" xHeight="4"/>
|
|
6348
6495
|
</hh:font>
|
|
6496
|
+
<hh:font id="1" face="Consolas" type="TTF" isEmbedded="0">
|
|
6497
|
+
<hh:typeInfo familyType="FCAT_MODERN" weight="5" proportion="0" contrast="0" strokeVariation="0" armStyle="0" letterform="0" midline="0" xHeight="0"/>
|
|
6498
|
+
</hh:font>
|
|
6349
6499
|
</hh:fontface>
|
|
6350
6500
|
<hh:fontface lang="HANJA" fontCnt="1">
|
|
6351
6501
|
<hh:font id="0" face="\uD568\uCD08\uB86C\uBC14\uD0D5" type="TTF" isEmbedded="0">
|
|
@@ -6377,34 +6527,37 @@ function generateHeaderXml() {
|
|
|
6377
6527
|
<hh:borderFill id="0" threeD="0" shadow="0" centerLine="0" breakCellSeparateLine="0">
|
|
6378
6528
|
<hh:slash type="NONE" Crooked="0" isCounter="0"/>
|
|
6379
6529
|
<hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
|
|
6380
|
-
<hh:leftBorder type="NONE" width="0.1mm" color="
|
|
6381
|
-
<hh:rightBorder type="NONE" width="0.1mm" color="
|
|
6382
|
-
<hh:topBorder type="NONE" width="0.1mm" color="
|
|
6383
|
-
<hh:bottomBorder type="NONE" width="0.1mm" color="
|
|
6384
|
-
<hh:diagonal type="NONE" width="0.1mm" color="
|
|
6530
|
+
<hh:leftBorder type="NONE" width="0.1mm" color="#000000"/>
|
|
6531
|
+
<hh:rightBorder type="NONE" width="0.1mm" color="#000000"/>
|
|
6532
|
+
<hh:topBorder type="NONE" width="0.1mm" color="#000000"/>
|
|
6533
|
+
<hh:bottomBorder type="NONE" width="0.1mm" color="#000000"/>
|
|
6534
|
+
<hh:diagonal type="NONE" width="0.1mm" color="#000000"/>
|
|
6385
6535
|
<hh:fillInfo/>
|
|
6386
6536
|
</hh:borderFill>
|
|
6387
6537
|
</hh:borderFills>
|
|
6388
|
-
<hh:charProperties itemCnt="
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6538
|
+
<hh:charProperties itemCnt="9">
|
|
6539
|
+
${charPr(0, 1e3, false, false)}
|
|
6540
|
+
${charPr(1, 1e3, true, false)}
|
|
6541
|
+
${charPr(2, 1e3, false, true)}
|
|
6542
|
+
${charPr(3, 1e3, true, true)}
|
|
6543
|
+
${charPr(4, 900, false, false, 1)}
|
|
6544
|
+
${charPr(5, 1800, true, false, 1)}
|
|
6545
|
+
${charPr(6, 1400, true, false, 1)}
|
|
6546
|
+
${charPr(7, 1200, true, false, 1)}
|
|
6547
|
+
${charPr(8, 1100, true, false, 1)}
|
|
6396
6548
|
</hh:charProperties>
|
|
6397
6549
|
<hh:tabProperties itemCnt="0"/>
|
|
6398
6550
|
<hh:numberings itemCnt="0"/>
|
|
6399
6551
|
<hh:bullets itemCnt="0"/>
|
|
6400
|
-
<hh:paraProperties itemCnt="
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6552
|
+
<hh:paraProperties itemCnt="8">
|
|
6553
|
+
${paraPr(0)}
|
|
6554
|
+
${paraPr(1, { align: "LEFT", spaceBefore: 800, spaceAfter: 200, lineSpacing: 180 })}
|
|
6555
|
+
${paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: 170 })}
|
|
6556
|
+
${paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: 160 })}
|
|
6557
|
+
${paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: 160 })}
|
|
6558
|
+
${paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400 })}
|
|
6559
|
+
${paraPr(6, { align: "LEFT", lineSpacing: 150, indent: 600 })}
|
|
6560
|
+
${paraPr(7, { align: "LEFT", lineSpacing: 160, indent: 600 })}
|
|
6408
6561
|
</hh:paraProperties>
|
|
6409
6562
|
<hh:styles itemCnt="1">
|
|
6410
6563
|
<hh:style id="0" type="PARA" name="\uBC14\uD0D5\uAE00" engName="Normal" paraPrIDRef="0" charPrIDRef="0" nextStyleIDRef="0" langIDRef="1042" lockForm="0"/>
|
|
@@ -6413,34 +6566,78 @@ function generateHeaderXml() {
|
|
|
6413
6566
|
<hh:compatibleDocument targetProgram="HWP2018"/>
|
|
6414
6567
|
</hh:head>`;
|
|
6415
6568
|
}
|
|
6416
|
-
function
|
|
6417
|
-
return `<hp:
|
|
6569
|
+
function generateSecPr() {
|
|
6570
|
+
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="2835" footer="2835" gutter="0" left="5670" right="4252" top="8504" bottom="4252"/></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>`;
|
|
6418
6571
|
}
|
|
6419
6572
|
function generateTable(rows) {
|
|
6420
6573
|
const trElements = rows.map((row) => {
|
|
6421
|
-
const tdElements = row.map(
|
|
6422
|
-
|
|
6423
|
-
|
|
6574
|
+
const tdElements = row.map((cell) => {
|
|
6575
|
+
const runs = generateRuns(cell);
|
|
6576
|
+
return `<hp:tc><hp:cellSpan colSpan="1" rowSpan="1"/><hp:p paraPrIDRef="0" styleIDRef="0">${runs}</hp:p></hp:tc>`;
|
|
6577
|
+
}).join("");
|
|
6424
6578
|
return `<hp:tr>${tdElements}</hp:tr>`;
|
|
6425
6579
|
}).join("");
|
|
6426
6580
|
return `<hp:tbl>${trElements}</hp:tbl>`;
|
|
6427
6581
|
}
|
|
6428
6582
|
function blocksToSectionXml(blocks) {
|
|
6429
|
-
const
|
|
6583
|
+
const paraXmls = [];
|
|
6584
|
+
let isFirst = true;
|
|
6585
|
+
for (const block of blocks) {
|
|
6586
|
+
let xml = "";
|
|
6430
6587
|
switch (block.type) {
|
|
6431
|
-
case "heading":
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6588
|
+
case "heading": {
|
|
6589
|
+
const pId = headingParaPrId(block.level || 1);
|
|
6590
|
+
const cId = headingCharPrId(block.level || 1);
|
|
6591
|
+
xml = generateParagraph(block.text || "", pId, cId);
|
|
6592
|
+
break;
|
|
6593
|
+
}
|
|
6435
6594
|
case "paragraph":
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6595
|
+
xml = generateParagraph(block.text || "");
|
|
6596
|
+
break;
|
|
6597
|
+
case "code_block": {
|
|
6598
|
+
const codeLines = (block.text || "").split("\n");
|
|
6599
|
+
xml = codeLines.map((line) => generateParagraph(line || " ", PARA_CODE)).join("\n ");
|
|
6600
|
+
break;
|
|
6601
|
+
}
|
|
6602
|
+
case "blockquote":
|
|
6603
|
+
xml = generateParagraph(block.text || "", PARA_QUOTE);
|
|
6604
|
+
break;
|
|
6605
|
+
case "list_item": {
|
|
6606
|
+
const marker = block.ordered ? `${(block.indent || 0) + 1}. ` : "\xB7 ";
|
|
6607
|
+
const indentPrefix = " ".repeat(block.indent || 0);
|
|
6608
|
+
xml = generateParagraph(indentPrefix + marker + (block.text || ""), PARA_LIST);
|
|
6609
|
+
break;
|
|
6610
|
+
}
|
|
6611
|
+
case "hr":
|
|
6612
|
+
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>`;
|
|
6613
|
+
break;
|
|
6614
|
+
case "table":
|
|
6615
|
+
if (block.rows) {
|
|
6616
|
+
if (isFirst) {
|
|
6617
|
+
const secRun = `<hp:run charPrIDRef="0">${generateSecPr()}<hp:t></hp:t></hp:run>`;
|
|
6618
|
+
paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
|
|
6619
|
+
isFirst = false;
|
|
6620
|
+
}
|
|
6621
|
+
xml = generateTable(block.rows);
|
|
6622
|
+
}
|
|
6623
|
+
break;
|
|
6439
6624
|
}
|
|
6440
|
-
|
|
6625
|
+
if (!xml) continue;
|
|
6626
|
+
if (isFirst && block.type !== "table") {
|
|
6627
|
+
xml = xml.replace(
|
|
6628
|
+
/<hp:run charPrIDRef="(\d+)">/,
|
|
6629
|
+
`<hp:run charPrIDRef="$1">${generateSecPr()}`
|
|
6630
|
+
);
|
|
6631
|
+
isFirst = false;
|
|
6632
|
+
}
|
|
6633
|
+
paraXmls.push(xml);
|
|
6634
|
+
}
|
|
6635
|
+
if (paraXmls.length === 0) {
|
|
6636
|
+
paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${generateSecPr()}<hp:t></hp:t></hp:run></hp:p>`);
|
|
6637
|
+
}
|
|
6441
6638
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
6442
6639
|
<hs:sec xmlns:hs="${NS_SECTION}" xmlns:hp="${NS_PARA}">
|
|
6443
|
-
${
|
|
6640
|
+
${paraXmls.join("\n ")}
|
|
6444
6641
|
</hs:sec>`;
|
|
6445
6642
|
}
|
|
6446
6643
|
|