kordoc 2.2.1 → 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/LICENSE +21 -21
- package/dist/{chunk-MUAWCQDY.js → chunk-5Y2Q3BRW.js} +1 -1
- package/dist/chunk-5Y2Q3BRW.js.map +1 -0
- package/dist/{chunk-3TBUDJDE.js → chunk-MOL7MDBG.js} +1 -1
- package/dist/chunk-MOL7MDBG.js.map +1 -0
- package/dist/{chunk-FINXMRCH.js → chunk-R34CFFNV.js} +5 -5
- package/dist/chunk-R34CFFNV.js.map +1 -0
- package/dist/cli.js +4 -4
- package/dist/cli.js.map +1 -1
- package/dist/{detect-63IGCXTH.js → detect-GYK3HKD5.js} +2 -2
- package/dist/index.cjs +235 -41
- 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 +235 -41
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +4 -4
- package/dist/mcp.js.map +1 -1
- package/dist/page-range-737B4EZW.js +8 -0
- package/dist/{watch-Q6L4UBTC.js → watch-VNJDVUVQ.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-3TBUDJDE.js.map +0 -1
- package/dist/chunk-FINXMRCH.js.map +0 -1
- package/dist/chunk-MUAWCQDY.js.map +0 -1
- package/dist/page-range-OF5I4PQY.js +0 -8
- /package/dist/{detect-63IGCXTH.js.map → detect-GYK3HKD5.js.map} +0 -0
- /package/dist/{page-range-OF5I4PQY.js.map → page-range-737B4EZW.js.map} +0 -0
- /package/dist/{watch-Q6L4UBTC.js.map → watch-VNJDVUVQ.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
parse,
|
|
5
5
|
sanitizeError,
|
|
6
6
|
toArrayBuffer
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-R34CFFNV.js";
|
|
8
8
|
import {
|
|
9
9
|
detectFormat
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-5Y2Q3BRW.js";
|
|
11
|
+
import "./chunk-MOL7MDBG.js";
|
|
12
12
|
|
|
13
13
|
// src/cli.ts
|
|
14
14
|
import { readFileSync, writeFileSync, mkdirSync, statSync } from "fs";
|
|
@@ -105,7 +105,7 @@ program.name("kordoc").description("\uBAA8\uB450 \uD30C\uC2F1\uD574\uBC84\uB9AC\
|
|
|
105
105
|
}
|
|
106
106
|
});
|
|
107
107
|
program.command("watch <dir>").description("\uB514\uB809\uD1A0\uB9AC \uAC10\uC2DC \u2014 \uC0C8 \uBB38\uC11C \uC790\uB3D9 \uBCC0\uD658").option("--webhook <url>", "\uACB0\uACFC \uC804\uC1A1 \uC6F9\uD6C5 URL").option("-d, --out-dir <dir>", "\uBCC0\uD658 \uACB0\uACFC \uCD9C\uB825 \uB514\uB809\uD1A0\uB9AC").option("-p, --pages <range>", "\uD398\uC774\uC9C0/\uC139\uC158 \uBC94\uC704").option("--format <type>", "\uCD9C\uB825 \uD615\uC2DD: markdown \uB610\uB294 json", "markdown").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (dir, opts) => {
|
|
108
|
-
const { watchDirectory } = await import("./watch-
|
|
108
|
+
const { watchDirectory } = await import("./watch-VNJDVUVQ.js");
|
|
109
109
|
await watchDirectory({
|
|
110
110
|
dir,
|
|
111
111
|
outDir: opts.outDir,
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["/** kordoc CLI — 모두 파싱해버리겠다 */\
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["/** kordoc CLI — 모두 파싱해버리겠다 */\n\nimport { readFileSync, writeFileSync, mkdirSync, statSync } from \"fs\"\nimport { basename, resolve } from \"path\"\nimport { Command } from \"commander\"\nimport { parse, detectFormat } from \"./index.js\"\nimport type { ParseOptions } from \"./types.js\"\nimport { VERSION, toArrayBuffer, sanitizeError } from \"./utils.js\"\n\nconst program = new Command()\n\nprogram\n .name(\"kordoc\")\n .description(\"모두 파싱해버리겠다 — HWP, HWPX, PDF, XLSX, DOCX → Markdown\")\n .version(VERSION)\n .argument(\"<files...>\", \"변환할 파일 경로 (HWP, HWPX, PDF, XLSX, DOCX)\")\n .option(\"-o, --output <path>\", \"출력 파일 경로 (단일 파일 시)\")\n .option(\"-d, --out-dir <dir>\", \"출력 디렉토리 (다중 파일 시)\")\n .option(\"-p, --pages <range>\", \"페이지/섹션 범위 (예: 1-3, 1,3,5)\")\n .option(\"--format <type>\", \"출력 형식: markdown (기본) 또는 json\", \"markdown\")\n .option(\"--no-header-footer\", \"PDF 머리글/바닥글 자동 제거\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (files: string[], opts) => {\n const validFormats = [\"markdown\", \"json\"]\n if (!validFormats.includes(opts.format)) {\n process.stderr.write(`[kordoc] 지원하지 않는 형식: ${opts.format} (markdown 또는 json)\\n`)\n process.exit(1)\n }\n for (let fi = 0; fi < files.length; fi++) {\n const filePath = files[fi]\n const absPath = resolve(filePath)\n const fileName = basename(absPath)\n const filePrefix = files.length > 1 ? `[${fi + 1}/${files.length}] ` : \"\"\n\n try {\n const fileSize = statSync(absPath).size\n if (fileSize > 500 * 1024 * 1024) {\n process.stderr.write(`\\n[kordoc] SKIP: ${fileName} — 파일이 너무 큽니다 (${(fileSize / 1024 / 1024).toFixed(1)}MB)\\n`)\n process.exitCode = 1\n continue\n }\n const buffer = readFileSync(absPath)\n const arrayBuffer = toArrayBuffer(buffer)\n const format = detectFormat(arrayBuffer)\n\n if (!opts.silent) {\n process.stderr.write(`[kordoc] ${filePrefix}${fileName} (${format}) ...`)\n }\n\n const parseOptions: ParseOptions = {}\n if (opts.pages) parseOptions.pages = opts.pages as string\n if (opts.headerFooter === false) parseOptions.removeHeaderFooter = false\n if (!opts.silent) {\n parseOptions.onProgress = (current: number, total: number) => {\n process.stderr.write(`\\r[kordoc] ${filePrefix}${fileName} (${format}) [${current}/${total}]`)\n }\n }\n const result = await parse(arrayBuffer, parseOptions)\n\n if (!result.success) {\n process.stderr.write(` FAIL\\n`)\n process.stderr.write(` → ${result.error}\\n`)\n process.exitCode = 1\n continue\n }\n\n if (!opts.silent) process.stderr.write(` OK\\n`)\n\n let markdown = result.markdown\n // --out-dir 시 이미지 참조 경로에 images/ 접두사 추가\n if (opts.outDir && result.images?.length) {\n markdown = markdown.replace(/!\\[image\\]\\(image_/g, \"\n }\n const output = opts.format === \"json\"\n ? JSON.stringify(result, (_key, value) =>\n value instanceof Uint8Array ? Buffer.from(value).toString(\"base64\") : value\n , 2)\n : markdown\n\n // 이미지 저장 (--out-dir 또는 --output 시)\n const saveImages = (dir: string) => {\n if (!result.images?.length) return\n const imgDir = resolve(dir, \"images\")\n mkdirSync(imgDir, { recursive: true })\n for (const img of result.images) {\n writeFileSync(resolve(imgDir, img.filename), img.data)\n }\n if (!opts.silent) process.stderr.write(` → ${result.images.length}개 이미지 → ${imgDir}\\n`)\n }\n\n if (opts.output && files.length === 1) {\n writeFileSync(opts.output, output, \"utf-8\")\n if (!opts.silent) process.stderr.write(` → ${opts.output}\\n`)\n saveImages(resolve(opts.output, \"..\"))\n } else if (opts.outDir) {\n mkdirSync(opts.outDir, { recursive: true })\n const outExt = opts.format === \"json\" ? \".json\" : \".md\"\n const outPath = resolve(opts.outDir, fileName.replace(/\\.[^.]+$/, outExt))\n writeFileSync(outPath, output, \"utf-8\")\n if (!opts.silent) process.stderr.write(` → ${outPath}\\n`)\n saveImages(opts.outDir)\n } else {\n process.stdout.write(output + \"\\n\")\n }\n } catch (err) {\n process.stderr.write(`\\n[kordoc] ERROR: ${fileName} — ${sanitizeError(err)}\\n`)\n process.exitCode = 1\n }\n }\n })\n\nprogram\n .command(\"watch <dir>\")\n .description(\"디렉토리 감시 — 새 문서 자동 변환\")\n .option(\"--webhook <url>\", \"결과 전송 웹훅 URL\")\n .option(\"-d, --out-dir <dir>\", \"변환 결과 출력 디렉토리\")\n .option(\"-p, --pages <range>\", \"페이지/섹션 범위\")\n .option(\"--format <type>\", \"출력 형식: markdown 또는 json\", \"markdown\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (dir: string, opts) => {\n const { watchDirectory } = await import(\"./watch.js\")\n await watchDirectory({\n dir,\n outDir: opts.outDir,\n webhook: opts.webhook,\n format: opts.format,\n pages: opts.pages,\n silent: opts.silent,\n })\n })\n\nprogram.parse()\n"],"mappings":";;;;;;;;;;;;;AAEA,SAAS,cAAc,eAAe,WAAW,gBAAgB;AACjE,SAAS,UAAU,eAAe;AAClC,SAAS,eAAe;AAKxB,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,QAAQ,EACb,YAAY,2GAAoD,EAChE,QAAQ,OAAO,EACf,SAAS,cAAc,2EAAwC,EAC/D,OAAO,uBAAuB,2EAAoB,EAClD,OAAO,uBAAuB,0EAAmB,EACjD,OAAO,uBAAuB,mEAA2B,EACzD,OAAO,mBAAmB,wEAAgC,UAAU,EACpE,OAAO,sBAAsB,qEAAmB,EAChD,OAAO,YAAY,oDAAY,EAC/B,OAAO,OAAO,OAAiB,SAAS;AACvC,QAAM,eAAe,CAAC,YAAY,MAAM;AACxC,MAAI,CAAC,aAAa,SAAS,KAAK,MAAM,GAAG;AACvC,YAAQ,OAAO,MAAM,gEAAwB,KAAK,MAAM;AAAA,CAAuB;AAC/E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,WAAS,KAAK,GAAG,KAAK,MAAM,QAAQ,MAAM;AACxC,UAAM,WAAW,MAAM,EAAE;AACzB,UAAM,UAAU,QAAQ,QAAQ;AAChC,UAAM,WAAW,SAAS,OAAO;AACjC,UAAM,aAAa,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,IAAI,MAAM,MAAM,OAAO;AAEvE,QAAI;AACF,YAAM,WAAW,SAAS,OAAO,EAAE;AACnC,UAAI,WAAW,MAAM,OAAO,MAAM;AAChC,gBAAQ,OAAO,MAAM;AAAA,iBAAoB,QAAQ,gEAAmB,WAAW,OAAO,MAAM,QAAQ,CAAC,CAAC;AAAA,CAAO;AAC7G,gBAAQ,WAAW;AACnB;AAAA,MACF;AACA,YAAM,SAAS,aAAa,OAAO;AACnC,YAAM,cAAc,cAAc,MAAM;AACxC,YAAM,SAAS,aAAa,WAAW;AAEvC,UAAI,CAAC,KAAK,QAAQ;AAChB,gBAAQ,OAAO,MAAM,YAAY,UAAU,GAAG,QAAQ,KAAK,MAAM,OAAO;AAAA,MAC1E;AAEA,YAAM,eAA6B,CAAC;AACpC,UAAI,KAAK,MAAO,cAAa,QAAQ,KAAK;AAC1C,UAAI,KAAK,iBAAiB,MAAO,cAAa,qBAAqB;AACnE,UAAI,CAAC,KAAK,QAAQ;AAChB,qBAAa,aAAa,CAAC,SAAiB,UAAkB;AAC5D,kBAAQ,OAAO,MAAM,cAAc,UAAU,GAAG,QAAQ,KAAK,MAAM,MAAM,OAAO,IAAI,KAAK,GAAG;AAAA,QAC9F;AAAA,MACF;AACA,YAAM,SAAS,MAAM,MAAM,aAAa,YAAY;AAEpD,UAAI,CAAC,OAAO,SAAS;AACnB,gBAAQ,OAAO,MAAM;AAAA,CAAS;AAC9B,gBAAQ,OAAO,MAAM,YAAO,OAAO,KAAK;AAAA,CAAI;AAC5C,gBAAQ,WAAW;AACnB;AAAA,MACF;AAEA,UAAI,CAAC,KAAK,OAAQ,SAAQ,OAAO,MAAM;AAAA,CAAO;AAE9C,UAAI,WAAW,OAAO;AAEtB,UAAI,KAAK,UAAU,OAAO,QAAQ,QAAQ;AACxC,mBAAW,SAAS,QAAQ,uBAAuB,wBAAwB;AAAA,MAC7E;AACA,YAAM,SAAS,KAAK,WAAW,SAC3B,KAAK;AAAA,QAAU;AAAA,QAAQ,CAAC,MAAM,UAC5B,iBAAiB,aAAa,OAAO,KAAK,KAAK,EAAE,SAAS,QAAQ,IAAI;AAAA,QACtE;AAAA,MAAC,IACH;AAGJ,YAAM,aAAa,CAAC,QAAgB;AAClC,YAAI,CAAC,OAAO,QAAQ,OAAQ;AAC5B,cAAM,SAAS,QAAQ,KAAK,QAAQ;AACpC,kBAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AACrC,mBAAW,OAAO,OAAO,QAAQ;AAC/B,wBAAc,QAAQ,QAAQ,IAAI,QAAQ,GAAG,IAAI,IAAI;AAAA,QACvD;AACA,YAAI,CAAC,KAAK,OAAQ,SAAQ,OAAO,MAAM,YAAO,OAAO,OAAO,MAAM,oCAAW,MAAM;AAAA,CAAI;AAAA,MACzF;AAEA,UAAI,KAAK,UAAU,MAAM,WAAW,GAAG;AACrC,sBAAc,KAAK,QAAQ,QAAQ,OAAO;AAC1C,YAAI,CAAC,KAAK,OAAQ,SAAQ,OAAO,MAAM,YAAO,KAAK,MAAM;AAAA,CAAI;AAC7D,mBAAW,QAAQ,KAAK,QAAQ,IAAI,CAAC;AAAA,MACvC,WAAW,KAAK,QAAQ;AACtB,kBAAU,KAAK,QAAQ,EAAE,WAAW,KAAK,CAAC;AAC1C,cAAM,SAAS,KAAK,WAAW,SAAS,UAAU;AAClD,cAAM,UAAU,QAAQ,KAAK,QAAQ,SAAS,QAAQ,YAAY,MAAM,CAAC;AACzE,sBAAc,SAAS,QAAQ,OAAO;AACtC,YAAI,CAAC,KAAK,OAAQ,SAAQ,OAAO,MAAM,YAAO,OAAO;AAAA,CAAI;AACzD,mBAAW,KAAK,MAAM;AAAA,MACxB,OAAO;AACL,gBAAQ,OAAO,MAAM,SAAS,IAAI;AAAA,MACpC;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,OAAO,MAAM;AAAA,kBAAqB,QAAQ,WAAM,cAAc,GAAG,CAAC;AAAA,CAAI;AAC9E,cAAQ,WAAW;AAAA,IACrB;AAAA,EACF;AACF,CAAC;AAEH,QACG,QAAQ,aAAa,EACrB,YAAY,4FAAsB,EAClC,OAAO,mBAAmB,4CAAc,EACxC,OAAO,uBAAuB,iEAAe,EAC7C,OAAO,uBAAuB,8CAAW,EACzC,OAAO,mBAAmB,yDAA2B,UAAU,EAC/D,OAAO,YAAY,oDAAY,EAC/B,OAAO,OAAO,KAAa,SAAS;AACnC,QAAM,EAAE,eAAe,IAAI,MAAM,OAAO,qBAAY;AACpD,QAAM,eAAe;AAAA,IACnB;AAAA,IACA,QAAQ,KAAK;AAAA,IACb,SAAS,KAAK;AAAA,IACd,QAAQ,KAAK;AAAA,IACb,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,EACf,CAAC;AACH,CAAC;AAEH,QAAQ,MAAM;","names":[]}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
isOldHwpFile,
|
|
7
7
|
isPdfFile,
|
|
8
8
|
isZipFile
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-5Y2Q3BRW.js";
|
|
10
10
|
export {
|
|
11
11
|
detectFormat,
|
|
12
12
|
detectZipFormat,
|
|
@@ -15,4 +15,4 @@ export {
|
|
|
15
15
|
isPdfFile,
|
|
16
16
|
isZipFile
|
|
17
17
|
};
|
|
18
|
-
//# sourceMappingURL=detect-
|
|
18
|
+
//# sourceMappingURL=detect-GYK3HKD5.js.map
|
package/dist/index.cjs
CHANGED
|
@@ -183,7 +183,7 @@ var import_zlib = require("zlib");
|
|
|
183
183
|
var import_xmldom = require("@xmldom/xmldom");
|
|
184
184
|
|
|
185
185
|
// src/utils.ts
|
|
186
|
-
var VERSION = true ? "2.2.
|
|
186
|
+
var VERSION = true ? "2.2.2" : "0.0.0-dev";
|
|
187
187
|
function toArrayBuffer(buf) {
|
|
188
188
|
if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {
|
|
189
189
|
return buf.buffer;
|
|
@@ -6306,6 +6306,23 @@ var NS_HEAD = "http://www.hancom.co.kr/hwpml/2011/head";
|
|
|
6306
6306
|
var NS_OPF = "http://www.idpf.org/2007/opf/";
|
|
6307
6307
|
var NS_HPF = "http://www.hancom.co.kr/schema/2011/hpf";
|
|
6308
6308
|
var NS_OCF = "urn:oasis:names:tc:opendocument:xmlns:container";
|
|
6309
|
+
var CHAR_NORMAL = 0;
|
|
6310
|
+
var CHAR_BOLD = 1;
|
|
6311
|
+
var CHAR_ITALIC = 2;
|
|
6312
|
+
var CHAR_BOLD_ITALIC = 3;
|
|
6313
|
+
var CHAR_CODE = 4;
|
|
6314
|
+
var CHAR_H1 = 5;
|
|
6315
|
+
var CHAR_H2 = 6;
|
|
6316
|
+
var CHAR_H3 = 7;
|
|
6317
|
+
var CHAR_H4 = 8;
|
|
6318
|
+
var PARA_NORMAL = 0;
|
|
6319
|
+
var PARA_H1 = 1;
|
|
6320
|
+
var PARA_H2 = 2;
|
|
6321
|
+
var PARA_H3 = 3;
|
|
6322
|
+
var PARA_H4 = 4;
|
|
6323
|
+
var PARA_CODE = 5;
|
|
6324
|
+
var PARA_QUOTE = 6;
|
|
6325
|
+
var PARA_LIST = 7;
|
|
6309
6326
|
async function markdownToHwpx(markdown) {
|
|
6310
6327
|
const blocks = parseMarkdownToBlocks(markdown);
|
|
6311
6328
|
const sectionXml = blocksToSectionXml(blocks);
|
|
@@ -6327,6 +6344,25 @@ function parseMarkdownToBlocks(md) {
|
|
|
6327
6344
|
i++;
|
|
6328
6345
|
continue;
|
|
6329
6346
|
}
|
|
6347
|
+
const fenceMatch = line.match(/^(`{3,}|~{3,})(.*)$/);
|
|
6348
|
+
if (fenceMatch) {
|
|
6349
|
+
const fence = fenceMatch[1];
|
|
6350
|
+
const lang = fenceMatch[2].trim();
|
|
6351
|
+
const codeLines = [];
|
|
6352
|
+
i++;
|
|
6353
|
+
while (i < lines.length && !lines[i].startsWith(fence)) {
|
|
6354
|
+
codeLines.push(lines[i]);
|
|
6355
|
+
i++;
|
|
6356
|
+
}
|
|
6357
|
+
if (i < lines.length) i++;
|
|
6358
|
+
blocks.push({ type: "code_block", text: codeLines.join("\n"), lang });
|
|
6359
|
+
continue;
|
|
6360
|
+
}
|
|
6361
|
+
if (/^(\*{3,}|-{3,}|_{3,})\s*$/.test(line.trim())) {
|
|
6362
|
+
blocks.push({ type: "hr" });
|
|
6363
|
+
i++;
|
|
6364
|
+
continue;
|
|
6365
|
+
}
|
|
6330
6366
|
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
6331
6367
|
if (headingMatch) {
|
|
6332
6368
|
blocks.push({ type: "heading", text: headingMatch[2].trim(), level: headingMatch[1].length });
|
|
@@ -6345,19 +6381,101 @@ function parseMarkdownToBlocks(md) {
|
|
|
6345
6381
|
if (cells.length > 0) tableRows.push(cells);
|
|
6346
6382
|
i++;
|
|
6347
6383
|
}
|
|
6348
|
-
if (tableRows.length > 0) {
|
|
6349
|
-
|
|
6384
|
+
if (tableRows.length > 0) blocks.push({ type: "table", rows: tableRows });
|
|
6385
|
+
continue;
|
|
6386
|
+
}
|
|
6387
|
+
if (line.trimStart().startsWith("> ")) {
|
|
6388
|
+
const quoteLines = [];
|
|
6389
|
+
while (i < lines.length && (lines[i].trimStart().startsWith("> ") || lines[i].trimStart().startsWith(">"))) {
|
|
6390
|
+
quoteLines.push(lines[i].replace(/^>\s?/, ""));
|
|
6391
|
+
i++;
|
|
6392
|
+
}
|
|
6393
|
+
for (const ql of quoteLines) {
|
|
6394
|
+
blocks.push({ type: "blockquote", text: ql.trim() || "" });
|
|
6350
6395
|
}
|
|
6351
6396
|
continue;
|
|
6352
6397
|
}
|
|
6398
|
+
const listMatch = line.match(/^(\s*)([-*+]|\d+[.)]) (.+)$/);
|
|
6399
|
+
if (listMatch) {
|
|
6400
|
+
const indent = Math.floor(listMatch[1].length / 2);
|
|
6401
|
+
const ordered = /\d/.test(listMatch[2]);
|
|
6402
|
+
blocks.push({ type: "list_item", text: listMatch[3].trim(), ordered, indent });
|
|
6403
|
+
i++;
|
|
6404
|
+
continue;
|
|
6405
|
+
}
|
|
6353
6406
|
blocks.push({ type: "paragraph", text: line.trim() });
|
|
6354
6407
|
i++;
|
|
6355
6408
|
}
|
|
6356
6409
|
return blocks;
|
|
6357
6410
|
}
|
|
6411
|
+
function parseInlineMarkdown(text) {
|
|
6412
|
+
text = text.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1");
|
|
6413
|
+
text = text.replace(/\[([^\]]*)\]\(([^)]*)\)/g, (_, t, u) => t || u);
|
|
6414
|
+
text = text.replace(/~~([^~]+)~~/g, "$1");
|
|
6415
|
+
const spans = [];
|
|
6416
|
+
const regex = /(`[^`]+`|\*{3}[^*]+\*{3}|\*{2}[^*]+\*{2}|\*[^*]+\*|_{2}[^_]+_{2}|_[^_]+_)/g;
|
|
6417
|
+
let lastIdx = 0;
|
|
6418
|
+
for (const match of text.matchAll(regex)) {
|
|
6419
|
+
const idx = match.index;
|
|
6420
|
+
if (idx > lastIdx) {
|
|
6421
|
+
spans.push({ text: text.slice(lastIdx, idx), bold: false, italic: false, code: false });
|
|
6422
|
+
}
|
|
6423
|
+
const raw = match[0];
|
|
6424
|
+
if (raw.startsWith("`")) {
|
|
6425
|
+
spans.push({ text: raw.slice(1, -1), bold: false, italic: false, code: true });
|
|
6426
|
+
} else if (raw.startsWith("***") || raw.startsWith("___")) {
|
|
6427
|
+
spans.push({ text: raw.slice(3, -3), bold: true, italic: true, code: false });
|
|
6428
|
+
} else if (raw.startsWith("**") || raw.startsWith("__")) {
|
|
6429
|
+
spans.push({ text: raw.slice(2, -2), bold: true, italic: false, code: false });
|
|
6430
|
+
} else {
|
|
6431
|
+
spans.push({ text: raw.slice(1, -1), bold: false, italic: true, code: false });
|
|
6432
|
+
}
|
|
6433
|
+
lastIdx = idx + raw.length;
|
|
6434
|
+
}
|
|
6435
|
+
if (lastIdx < text.length) {
|
|
6436
|
+
spans.push({ text: text.slice(lastIdx), bold: false, italic: false, code: false });
|
|
6437
|
+
}
|
|
6438
|
+
if (spans.length === 0) {
|
|
6439
|
+
spans.push({ text, bold: false, italic: false, code: false });
|
|
6440
|
+
}
|
|
6441
|
+
return spans;
|
|
6442
|
+
}
|
|
6443
|
+
function spanToCharPrId(span) {
|
|
6444
|
+
if (span.code) return CHAR_CODE;
|
|
6445
|
+
if (span.bold && span.italic) return CHAR_BOLD_ITALIC;
|
|
6446
|
+
if (span.bold) return CHAR_BOLD;
|
|
6447
|
+
if (span.italic) return CHAR_ITALIC;
|
|
6448
|
+
return CHAR_NORMAL;
|
|
6449
|
+
}
|
|
6358
6450
|
function escapeXml(text) {
|
|
6359
6451
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
6360
6452
|
}
|
|
6453
|
+
function generateRuns(text, defaultCharPr = CHAR_NORMAL) {
|
|
6454
|
+
const spans = parseInlineMarkdown(text);
|
|
6455
|
+
return spans.map((span) => {
|
|
6456
|
+
const charId = span.code || span.bold || span.italic ? spanToCharPrId(span) : defaultCharPr;
|
|
6457
|
+
return `<hp:run charPrIDRef="${charId}"><hp:t>${escapeXml(span.text)}</hp:t></hp:run>`;
|
|
6458
|
+
}).join("");
|
|
6459
|
+
}
|
|
6460
|
+
function generateParagraph(text, paraPrId = PARA_NORMAL, charPrId = CHAR_NORMAL) {
|
|
6461
|
+
if (paraPrId === PARA_CODE) {
|
|
6462
|
+
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0"><hp:run charPrIDRef="${CHAR_CODE}"><hp:t>${escapeXml(text)}</hp:t></hp:run></hp:p>`;
|
|
6463
|
+
}
|
|
6464
|
+
const runs = generateRuns(text, charPrId);
|
|
6465
|
+
return `<hp:p paraPrIDRef="${paraPrId}" styleIDRef="0">${runs}</hp:p>`;
|
|
6466
|
+
}
|
|
6467
|
+
function headingParaPrId(level) {
|
|
6468
|
+
if (level === 1) return PARA_H1;
|
|
6469
|
+
if (level === 2) return PARA_H2;
|
|
6470
|
+
if (level === 3) return PARA_H3;
|
|
6471
|
+
return PARA_H4;
|
|
6472
|
+
}
|
|
6473
|
+
function headingCharPrId(level) {
|
|
6474
|
+
if (level === 1) return CHAR_H1;
|
|
6475
|
+
if (level === 2) return CHAR_H2;
|
|
6476
|
+
if (level === 3) return CHAR_H3;
|
|
6477
|
+
return CHAR_H4;
|
|
6478
|
+
}
|
|
6361
6479
|
function generateContainerXml() {
|
|
6362
6480
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
6363
6481
|
<ocf:container xmlns:ocf="${NS_OCF}" xmlns:hpf="${NS_HPF}">
|
|
@@ -6379,21 +6497,50 @@ function generateManifest() {
|
|
|
6379
6497
|
</opf:spine>
|
|
6380
6498
|
</opf:package>`;
|
|
6381
6499
|
}
|
|
6500
|
+
function charPr(id, height, bold, italic, fontId = 0) {
|
|
6501
|
+
const boldAttr = bold ? ` bold="1"` : "";
|
|
6502
|
+
const italicAttr = italic ? ` italic="1"` : "";
|
|
6503
|
+
return ` <hh:charPr id="${id}" height="${height}" textColor="#000000" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="0"${boldAttr}${italicAttr}>
|
|
6504
|
+
<hh:fontRef hangul="${fontId}" latin="${fontId}" hanja="${fontId}" japanese="${fontId}" other="${fontId}" symbol="${fontId}" user="${fontId}"/>
|
|
6505
|
+
<hh:ratio hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
|
|
6506
|
+
<hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
|
|
6507
|
+
<hh:relSz hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
|
|
6508
|
+
<hh:offset hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
|
|
6509
|
+
</hh:charPr>`;
|
|
6510
|
+
}
|
|
6511
|
+
function paraPr(id, opts = {}) {
|
|
6512
|
+
const { align = "JUSTIFY", spaceBefore = 0, spaceAfter = 0, lineSpacing = 160, indent = 0 } = opts;
|
|
6513
|
+
return ` <hh:paraPr id="${id}" tabPrIDRef="0" condense="0" fontLineHeight="0" snapToGrid="1" suppressLineNumbers="0" checked="0" textDir="AUTO">
|
|
6514
|
+
<hh:align horizontal="${align}" vertical="BASELINE"/>
|
|
6515
|
+
<hh:heading type="NONE" idRef="0" level="0"/>
|
|
6516
|
+
<hh:breakSetting breakLatinWord="KEEP_WORD" breakNonLatinWord="BREAK_WORD" widowOrphan="0" keepWithNext="0" keepLines="0" pageBreakBefore="0" lineWrap="BREAK"/>
|
|
6517
|
+
<hh:autoSpacing eAsianEng="0" eAsianNum="0"/>
|
|
6518
|
+
<hh:margin indent="${indent}" left="0" right="0" prev="${spaceBefore}" next="${spaceAfter}"/>
|
|
6519
|
+
<hh:lineSpacing type="PERCENT" value="${lineSpacing}"/>
|
|
6520
|
+
<hh:border borderFillIDRef="0" offsetLeft="0" offsetRight="0" offsetTop="0" offsetBottom="0" connect="0" ignoreMargin="0"/>
|
|
6521
|
+
</hh:paraPr>`;
|
|
6522
|
+
}
|
|
6382
6523
|
function generateHeaderXml() {
|
|
6383
6524
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
6384
6525
|
<hh:head xmlns:hh="${NS_HEAD}" xmlns:hp="${NS_PARA}" version="1.4" secCnt="1">
|
|
6385
6526
|
<hh:beginNum page="1" footnote="1" endnote="1" pic="1" tbl="1" equation="1"/>
|
|
6386
6527
|
<hh:refList>
|
|
6387
6528
|
<hh:fontfaces itemCnt="7">
|
|
6388
|
-
<hh:fontface lang="HANGUL" fontCnt="
|
|
6529
|
+
<hh:fontface lang="HANGUL" fontCnt="2">
|
|
6389
6530
|
<hh:font id="0" face="\uD568\uCD08\uB86C\uBC14\uD0D5" type="TTF" isEmbedded="0">
|
|
6390
6531
|
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
6391
6532
|
</hh:font>
|
|
6533
|
+
<hh:font id="1" face="\uD568\uCD08\uB86C\uB3CB\uC6C0" type="TTF" isEmbedded="0">
|
|
6534
|
+
<hh:typeInfo familyType="FCAT_GOTHIC" weight="6" proportion="4" contrast="0" strokeVariation="1" armStyle="1" letterform="1" midline="1" xHeight="1"/>
|
|
6535
|
+
</hh:font>
|
|
6392
6536
|
</hh:fontface>
|
|
6393
|
-
<hh:fontface lang="LATIN" fontCnt="
|
|
6537
|
+
<hh:fontface lang="LATIN" fontCnt="2">
|
|
6394
6538
|
<hh:font id="0" face="Times New Roman" type="TTF" isEmbedded="0">
|
|
6395
6539
|
<hh:typeInfo familyType="FCAT_OLDSTYLE" weight="5" proportion="4" contrast="2" strokeVariation="0" armStyle="0" letterform="0" midline="0" xHeight="4"/>
|
|
6396
6540
|
</hh:font>
|
|
6541
|
+
<hh:font id="1" face="Consolas" type="TTF" isEmbedded="0">
|
|
6542
|
+
<hh:typeInfo familyType="FCAT_MODERN" weight="5" proportion="0" contrast="0" strokeVariation="0" armStyle="0" letterform="0" midline="0" xHeight="0"/>
|
|
6543
|
+
</hh:font>
|
|
6397
6544
|
</hh:fontface>
|
|
6398
6545
|
<hh:fontface lang="HANJA" fontCnt="1">
|
|
6399
6546
|
<hh:font id="0" face="\uD568\uCD08\uB86C\uBC14\uD0D5" type="TTF" isEmbedded="0">
|
|
@@ -6425,34 +6572,37 @@ function generateHeaderXml() {
|
|
|
6425
6572
|
<hh:borderFill id="0" threeD="0" shadow="0" centerLine="0" breakCellSeparateLine="0">
|
|
6426
6573
|
<hh:slash type="NONE" Crooked="0" isCounter="0"/>
|
|
6427
6574
|
<hh:backSlash type="NONE" Crooked="0" isCounter="0"/>
|
|
6428
|
-
<hh:leftBorder type="NONE" width="0.1mm" color="
|
|
6429
|
-
<hh:rightBorder type="NONE" width="0.1mm" color="
|
|
6430
|
-
<hh:topBorder type="NONE" width="0.1mm" color="
|
|
6431
|
-
<hh:bottomBorder type="NONE" width="0.1mm" color="
|
|
6432
|
-
<hh:diagonal type="NONE" width="0.1mm" color="
|
|
6575
|
+
<hh:leftBorder type="NONE" width="0.1mm" color="#000000"/>
|
|
6576
|
+
<hh:rightBorder type="NONE" width="0.1mm" color="#000000"/>
|
|
6577
|
+
<hh:topBorder type="NONE" width="0.1mm" color="#000000"/>
|
|
6578
|
+
<hh:bottomBorder type="NONE" width="0.1mm" color="#000000"/>
|
|
6579
|
+
<hh:diagonal type="NONE" width="0.1mm" color="#000000"/>
|
|
6433
6580
|
<hh:fillInfo/>
|
|
6434
6581
|
</hh:borderFill>
|
|
6435
6582
|
</hh:borderFills>
|
|
6436
|
-
<hh:charProperties itemCnt="
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6583
|
+
<hh:charProperties itemCnt="9">
|
|
6584
|
+
${charPr(0, 1e3, false, false)}
|
|
6585
|
+
${charPr(1, 1e3, true, false)}
|
|
6586
|
+
${charPr(2, 1e3, false, true)}
|
|
6587
|
+
${charPr(3, 1e3, true, true)}
|
|
6588
|
+
${charPr(4, 900, false, false, 1)}
|
|
6589
|
+
${charPr(5, 1800, true, false, 1)}
|
|
6590
|
+
${charPr(6, 1400, true, false, 1)}
|
|
6591
|
+
${charPr(7, 1200, true, false, 1)}
|
|
6592
|
+
${charPr(8, 1100, true, false, 1)}
|
|
6444
6593
|
</hh:charProperties>
|
|
6445
6594
|
<hh:tabProperties itemCnt="0"/>
|
|
6446
6595
|
<hh:numberings itemCnt="0"/>
|
|
6447
6596
|
<hh:bullets itemCnt="0"/>
|
|
6448
|
-
<hh:paraProperties itemCnt="
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6597
|
+
<hh:paraProperties itemCnt="8">
|
|
6598
|
+
${paraPr(0)}
|
|
6599
|
+
${paraPr(1, { align: "LEFT", spaceBefore: 800, spaceAfter: 200, lineSpacing: 180 })}
|
|
6600
|
+
${paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: 170 })}
|
|
6601
|
+
${paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: 160 })}
|
|
6602
|
+
${paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: 160 })}
|
|
6603
|
+
${paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400 })}
|
|
6604
|
+
${paraPr(6, { align: "LEFT", lineSpacing: 150, indent: 600 })}
|
|
6605
|
+
${paraPr(7, { align: "LEFT", lineSpacing: 160, indent: 600 })}
|
|
6456
6606
|
</hh:paraProperties>
|
|
6457
6607
|
<hh:styles itemCnt="1">
|
|
6458
6608
|
<hh:style id="0" type="PARA" name="\uBC14\uD0D5\uAE00" engName="Normal" paraPrIDRef="0" charPrIDRef="0" nextStyleIDRef="0" langIDRef="1042" lockForm="0"/>
|
|
@@ -6461,34 +6611,78 @@ function generateHeaderXml() {
|
|
|
6461
6611
|
<hh:compatibleDocument targetProgram="HWP2018"/>
|
|
6462
6612
|
</hh:head>`;
|
|
6463
6613
|
}
|
|
6464
|
-
function
|
|
6465
|
-
return `<hp:
|
|
6614
|
+
function generateSecPr() {
|
|
6615
|
+
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>`;
|
|
6466
6616
|
}
|
|
6467
6617
|
function generateTable(rows) {
|
|
6468
6618
|
const trElements = rows.map((row) => {
|
|
6469
|
-
const tdElements = row.map(
|
|
6470
|
-
|
|
6471
|
-
|
|
6619
|
+
const tdElements = row.map((cell) => {
|
|
6620
|
+
const runs = generateRuns(cell);
|
|
6621
|
+
return `<hp:tc><hp:cellSpan colSpan="1" rowSpan="1"/><hp:p paraPrIDRef="0" styleIDRef="0">${runs}</hp:p></hp:tc>`;
|
|
6622
|
+
}).join("");
|
|
6472
6623
|
return `<hp:tr>${tdElements}</hp:tr>`;
|
|
6473
6624
|
}).join("");
|
|
6474
6625
|
return `<hp:tbl>${trElements}</hp:tbl>`;
|
|
6475
6626
|
}
|
|
6476
6627
|
function blocksToSectionXml(blocks) {
|
|
6477
|
-
const
|
|
6628
|
+
const paraXmls = [];
|
|
6629
|
+
let isFirst = true;
|
|
6630
|
+
for (const block of blocks) {
|
|
6631
|
+
let xml = "";
|
|
6478
6632
|
switch (block.type) {
|
|
6479
|
-
case "heading":
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6633
|
+
case "heading": {
|
|
6634
|
+
const pId = headingParaPrId(block.level || 1);
|
|
6635
|
+
const cId = headingCharPrId(block.level || 1);
|
|
6636
|
+
xml = generateParagraph(block.text || "", pId, cId);
|
|
6637
|
+
break;
|
|
6638
|
+
}
|
|
6483
6639
|
case "paragraph":
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6640
|
+
xml = generateParagraph(block.text || "");
|
|
6641
|
+
break;
|
|
6642
|
+
case "code_block": {
|
|
6643
|
+
const codeLines = (block.text || "").split("\n");
|
|
6644
|
+
xml = codeLines.map((line) => generateParagraph(line || " ", PARA_CODE)).join("\n ");
|
|
6645
|
+
break;
|
|
6646
|
+
}
|
|
6647
|
+
case "blockquote":
|
|
6648
|
+
xml = generateParagraph(block.text || "", PARA_QUOTE);
|
|
6649
|
+
break;
|
|
6650
|
+
case "list_item": {
|
|
6651
|
+
const marker = block.ordered ? `${(block.indent || 0) + 1}. ` : "\xB7 ";
|
|
6652
|
+
const indentPrefix = " ".repeat(block.indent || 0);
|
|
6653
|
+
xml = generateParagraph(indentPrefix + marker + (block.text || ""), PARA_LIST);
|
|
6654
|
+
break;
|
|
6655
|
+
}
|
|
6656
|
+
case "hr":
|
|
6657
|
+
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>`;
|
|
6658
|
+
break;
|
|
6659
|
+
case "table":
|
|
6660
|
+
if (block.rows) {
|
|
6661
|
+
if (isFirst) {
|
|
6662
|
+
const secRun = `<hp:run charPrIDRef="0">${generateSecPr()}<hp:t></hp:t></hp:run>`;
|
|
6663
|
+
paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0">${secRun}</hp:p>`);
|
|
6664
|
+
isFirst = false;
|
|
6665
|
+
}
|
|
6666
|
+
xml = generateTable(block.rows);
|
|
6667
|
+
}
|
|
6668
|
+
break;
|
|
6487
6669
|
}
|
|
6488
|
-
|
|
6670
|
+
if (!xml) continue;
|
|
6671
|
+
if (isFirst && block.type !== "table") {
|
|
6672
|
+
xml = xml.replace(
|
|
6673
|
+
/<hp:run charPrIDRef="(\d+)">/,
|
|
6674
|
+
`<hp:run charPrIDRef="$1">${generateSecPr()}`
|
|
6675
|
+
);
|
|
6676
|
+
isFirst = false;
|
|
6677
|
+
}
|
|
6678
|
+
paraXmls.push(xml);
|
|
6679
|
+
}
|
|
6680
|
+
if (paraXmls.length === 0) {
|
|
6681
|
+
paraXmls.push(`<hp:p paraPrIDRef="0" styleIDRef="0"><hp:run charPrIDRef="0">${generateSecPr()}<hp:t></hp:t></hp:run></hp:p>`);
|
|
6682
|
+
}
|
|
6489
6683
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
|
6490
6684
|
<hs:sec xmlns:hs="${NS_SECTION}" xmlns:hp="${NS_PARA}">
|
|
6491
|
-
${
|
|
6685
|
+
${paraXmls.join("\n ")}
|
|
6492
6686
|
</hs:sec>`;
|
|
6493
6687
|
}
|
|
6494
6688
|
|