kordoc 3.18.1 → 4.0.1
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 +768 -752
- package/dist/{-V66QW3WA.js → -O3AWNVPH.js} +16 -8
- package/dist/{chunk-2IBFK5ZO.js → chunk-33OUI7HC.js} +2 -2
- package/dist/chunk-33OUI7HC.js.map +1 -0
- package/dist/{chunk-UHYPUIRH.js → chunk-3H3CVOZ3.js} +2 -2
- package/dist/chunk-3H3CVOZ3.js.map +1 -0
- package/dist/{chunk-MEPHGCPQ.js → chunk-5CJGKKMZ.js} +1 -1
- package/dist/chunk-5CJGKKMZ.js.map +1 -0
- package/dist/{chunk-QMJJI6TD.js → chunk-C5ABJ7PB.js} +6 -4
- package/dist/chunk-C5ABJ7PB.js.map +1 -0
- package/dist/chunk-DCZVOIEO.cjs.map +1 -1
- package/dist/{chunk-UNV7F3FK.js → chunk-EH2KYFFO.js} +2 -2
- package/dist/chunk-EH2KYFFO.js.map +1 -0
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-NZJAXMN7.js → chunk-JMLK6NTW.js} +3 -3
- package/dist/chunk-JMLK6NTW.js.map +1 -0
- package/dist/chunk-MOL7MDBG.js +0 -0
- package/dist/{chunk-R2H34FY5.cjs → chunk-NIZXIVEI.cjs} +2 -2
- package/dist/chunk-NIZXIVEI.cjs.map +1 -0
- package/dist/{chunk-7K5P4RNT.js → chunk-SHVV3BD6.js} +1652 -588
- package/dist/chunk-SHVV3BD6.js.map +1 -0
- package/dist/{chunk-4RGDFDQ2.js → chunk-YEC7VG6O.js} +8 -2
- package/dist/chunk-YEC7VG6O.js.map +1 -0
- package/dist/cli.js +76 -16
- package/dist/cli.js.map +1 -1
- package/dist/{detect-RI2MQ33K.js → detect-PJZMUL2Z.js} +2 -2
- package/dist/formula-5NKVS2LR.cjs.map +1 -1
- package/dist/formula-JCNF43NE.js +0 -0
- package/dist/index.cjs +2036 -966
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +110 -9
- package/dist/index.d.ts +110 -9
- package/dist/index.js +1811 -741
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +60 -17
- package/dist/mcp.js.map +1 -1
- package/dist/page-range-737B4EZW.js +0 -0
- package/dist/page-range-P7SDW6LR.cjs.map +1 -1
- package/dist/{parser-XEY5MRGV.cjs → parser-44OPXZMP.cjs} +15 -15
- package/dist/parser-44OPXZMP.cjs.map +1 -0
- package/dist/{parser-JBBA5A5E.js → parser-G433UZMX.js} +3 -3
- package/dist/parser-G433UZMX.js.map +1 -0
- package/dist/{parser-DOBK652H.js → parser-ZOMDHCA7.js} +4 -4
- package/dist/parser-ZOMDHCA7.js.map +1 -0
- package/dist/{provider-G4C2V2PD.cjs → provider-5K7O3Z2O.cjs} +1 -1
- package/dist/provider-5K7O3Z2O.cjs.map +1 -0
- package/dist/{provider-AKROB7WQ.js → provider-7H4CPZYS.js} +1 -1
- package/dist/provider-7H4CPZYS.js.map +1 -0
- package/dist/{provider-4ZJKV3DC.js → provider-H4WWSPOV.js} +1 -1
- package/dist/provider-H4WWSPOV.js.map +1 -0
- package/dist/render-SQVQBORJ.js +10 -0
- package/dist/seal-6E26L45Z.js +10 -0
- package/dist/setup-57FB3LSP.js +0 -0
- package/dist/{watch-2MNRQWGV.js → watch-UYT3ZCBM.js} +8 -8
- package/dist/watch-UYT3ZCBM.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-2IBFK5ZO.js.map +0 -1
- package/dist/chunk-4RGDFDQ2.js.map +0 -1
- package/dist/chunk-7K5P4RNT.js.map +0 -1
- package/dist/chunk-MEPHGCPQ.js.map +0 -1
- package/dist/chunk-NZJAXMN7.js.map +0 -1
- package/dist/chunk-QMJJI6TD.js.map +0 -1
- package/dist/chunk-R2H34FY5.cjs.map +0 -1
- package/dist/chunk-UHYPUIRH.js.map +0 -1
- package/dist/chunk-UNV7F3FK.js.map +0 -1
- package/dist/parser-DOBK652H.js.map +0 -1
- package/dist/parser-JBBA5A5E.js.map +0 -1
- package/dist/parser-XEY5MRGV.cjs.map +0 -1
- package/dist/provider-4ZJKV3DC.js.map +0 -1
- package/dist/provider-AKROB7WQ.js.map +0 -1
- package/dist/provider-G4C2V2PD.cjs.map +0 -1
- package/dist/render-VX4H2S4F.js +0 -10
- package/dist/seal-6Z6H4YXN.js +0 -10
- package/dist/watch-2MNRQWGV.js.map +0 -1
- /package/dist/{-V66QW3WA.js.map → -O3AWNVPH.js.map} +0 -0
- /package/dist/{detect-RI2MQ33K.js.map → detect-PJZMUL2Z.js.map} +0 -0
- /package/dist/{render-VX4H2S4F.js.map → render-SQVQBORJ.js.map} +0 -0
- /package/dist/{seal-6Z6H4YXN.js.map → seal-6E26L45Z.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
KordocError
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EH2KYFFO.js";
|
|
5
5
|
|
|
6
6
|
// src/hwpx/parser-shared.ts
|
|
7
7
|
import { DOMParser } from "@xmldom/xmldom";
|
|
@@ -180,6 +180,12 @@ function parseParaGeom(el) {
|
|
|
180
180
|
g.spaceBefore = v("prev");
|
|
181
181
|
g.spaceAfter = v("next");
|
|
182
182
|
}
|
|
183
|
+
const bs = findDeep(el, "breakSetting");
|
|
184
|
+
if (bs) {
|
|
185
|
+
const nl = bs.getAttribute("breakNonLatinWord");
|
|
186
|
+
if (nl === "BREAK_WORD") g.wrapMode = "keep";
|
|
187
|
+
else if (nl === "KEEP_WORD") g.wrapMode = "charAll";
|
|
188
|
+
}
|
|
183
189
|
return g;
|
|
184
190
|
}
|
|
185
191
|
function parseRenderStyles(headXml) {
|
|
@@ -258,4 +264,4 @@ export {
|
|
|
258
264
|
DEFAULT_CHAR,
|
|
259
265
|
parseRenderStyles
|
|
260
266
|
};
|
|
261
|
-
//# sourceMappingURL=chunk-
|
|
267
|
+
//# sourceMappingURL=chunk-YEC7VG6O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hwpx/parser-shared.ts","../src/render/head-styles.ts"],"sourcesContent":["/**\r\n * HWPX 파서 공유 상수/타입/유틸 (parser.ts에서 분리).\r\n * ZIP 한도, 섹션 공유 상태(SectionShared), walk 컨텍스트(WalkCtx), XML 유틸.\r\n */\r\n\r\nimport { DOMParser } from \"@xmldom/xmldom\"\r\nimport { KordocError } from \"../utils.js\"\r\nimport type { CellContext, IRBlock, ParseWarning } from \"../types.js\"\r\n// WalkCtx.styleMap 타입 참조 — 타입 전용이라 styles.ts와의 순환은 컴파일 시 소거됨\r\nimport type { HwpxStyleMap } from \"./styles.js\"\r\n\r\nexport const MAX_DECOMPRESS_SIZE = 100 * 1024 * 1024\r\n/** 손상 ZIP 복구 시 최대 엔트리 수 */\r\nexport const MAX_ZIP_ENTRIES = 500\r\n\r\n/** colSpan/rowSpan을 안전한 범위로 클램핑 */\r\nexport function clampSpan(val: number, max: number): number {\r\n return Math.max(1, Math.min(val, max))\r\n}\r\n\r\n/** XML DOM 재귀 최대 깊이 — 악성 파일의 스택 오버플로 방지.\r\n * 좌표계가 다른 hwp5 MAX_NEST_DEPTH(8, 표 중첩 단계)·filler/소스맵 16\r\n * (표 중첩 단계)과 달리 이건 \"XML 요소\" 깊이라 표 1단이 여러 depth를\r\n * 소모한다 — 상수 통일 금지 (의미가 다름) */\r\nexport const MAX_XML_DEPTH = 200\r\n\r\n/** 셀 컨텍스트 확장 — 중첩표/이미지/다중문단 블록과 제목셀 여부를 IRCell로 전달 (v3.0) */\r\nexport interface CellCtxEx extends CellContext {\r\n blocks?: IRBlock[]\r\n /** 중첩표/이미지 등 구조 콘텐츠 존재 — true일 때만 IRCell.blocks로 attach */\r\n hasStructure?: boolean\r\n isHeader?: boolean\r\n}\r\n\r\nexport interface TableState {\r\n rows: CellContext[][]\r\n currentRow: CellContext[]\r\n cell: CellCtxEx | null\r\n /** hp:caption 텍스트 — IRTable.caption으로 전달 (v3.0) */\r\n caption?: string\r\n}\r\n\r\n/** 섹션 간 공유 상태 — 자동번호 카운터, 머리말/꼬리말, 변경추적 */\r\nexport interface SectionShared {\r\n /** numbering id → 레벨별(1..10) 카운터. 0 = 미사용(start값으로 초기화) */\r\n numState: Map<string, number[]>\r\n pageText: { headers: string[]; footers: string[] }\r\n track: { deleteDepth: number; warned: boolean }\r\n}\r\n\r\nexport function createSectionShared(): SectionShared {\r\n return { numState: new Map(), pageText: { headers: [], footers: [] }, track: { deleteDepth: 0, warned: false } }\r\n}\r\n\r\n/** walk 함수들이 공유하는 파싱 컨텍스트 — 개별 optional 파라미터를 하나로 묶어 시그니처 안정화 */\r\nexport interface WalkCtx {\r\n styleMap?: HwpxStyleMap\r\n warnings?: ParseWarning[]\r\n sectionNum?: number\r\n shared: SectionShared\r\n /** secPr outlineShapeIDRef — 개요(OUTLINE) 문단이 사용하는 numbering id */\r\n outlineNumId?: string\r\n}\r\n\r\n/** xmldom DOMParser 생성 — onError 콜백으로 malformed XML 경고 수집 */\r\nexport function createXmlParser(warnings?: ParseWarning[]): DOMParser {\r\n return new DOMParser({\r\n onError(level: \"warn\" | \"error\" | \"fatalError\", msg: string) {\r\n if (level === \"fatalError\") throw new KordocError(`XML 파싱 실패: ${msg}`)\r\n warnings?.push({ code: \"MALFORMED_XML\", message: `XML ${level === \"warn\" ? \"경고\" : \"오류\"}: ${msg}` })\r\n },\r\n })\r\n}\r\n\r\n/** 수집된 머리말/꼬리말을 본문 앞/뒤 문단으로 배치 */\r\nexport function applyPageText(blocks: IRBlock[], shared: SectionShared): void {\r\n const { headers, footers } = shared.pageText\r\n if (headers.length > 0) {\r\n blocks.unshift(...headers.map(t => ({ type: \"paragraph\" as const, text: t, pageNumber: 1 })))\r\n }\r\n if (footers.length > 0) {\r\n blocks.push(...footers.map(t => ({ type: \"paragraph\" as const, text: t })))\r\n }\r\n}\r\n\r\n/** 자식 중 지정된 localName(접두사 제거)을 가진 첫 번째 Element 반환 */\r\nexport function findChildByLocalName(parent: Element, name: string): Element | null {\r\n const children = parent.childNodes\r\n if (!children) return null\r\n for (let i = 0; i < children.length; i++) {\r\n const ch = children[i] as Element\r\n if (ch.nodeType !== 1) continue\r\n const tag = (ch.tagName || ch.localName || \"\").replace(/^[^:]+:/, \"\")\r\n if (tag === name) return ch\r\n }\r\n return null\r\n}\r\n\r\n/** 노드 내 모든 텍스트를 재귀적으로 추출 */\r\nexport function extractTextFromNode(node: Node): string {\r\n let result = \"\"\r\n const children = node.childNodes\r\n if (!children) return result\r\n for (let i = 0; i < children.length; i++) {\r\n const child = children[i]\r\n if (child.nodeType === 3) result += child.textContent || \"\"\r\n else if (child.nodeType === 1) result += extractTextFromNode(child)\r\n }\r\n return result.trim()\r\n}\r\n","/**\r\n * 레이아웃 보존 렌더 — header.xml 스타일 테이블 (charPr/paraPr/borderFill).\r\n * 파서 IR과 무관하게 렌더에 필요한 속성만 추출한다.\r\n */\r\n\r\nimport { createXmlParser, findChildByLocalName } from \"../hwpx/parser-shared.js\"\r\n\r\nexport interface RenderCharStyle {\r\n /** 글자 크기 (1/100pt — 1000 = 10pt) */\r\n height: number\r\n bold: boolean\r\n italic: boolean\r\n underline: boolean\r\n /** #RRGGBB — 검정이면 undefined */\r\n color?: string\r\n /** 장평 % */\r\n ratio: number\r\n /** 자간 % */\r\n spacing: number\r\n /** CSS font-family 스택 — charPr fontRef(hangul)에서 해석. 없으면 root 기본 폴백 */\r\n fontFamily?: string\r\n}\r\n\r\nexport type ParaAlign = \"JUSTIFY\" | \"LEFT\" | \"RIGHT\" | \"CENTER\" | \"DISTRIBUTE\" | \"DISTRIBUTE_SPACE\"\r\n\r\n/** reflow(Tier-2)용 문단 기하 — 줄간격·여백. paraPr `<hh:margin>`·`<hh:lineSpacing>`은\r\n * `<hp:switch>/<hp:case>` 안(손자)이라 재귀 탐색으로 뽑는다. 단위 HWPUNIT. */\r\nexport interface RenderParaGeom {\r\n /** PERCENT(기본 160=160%) / FIXED / BETWEEN_LINES / AT_LEAST */\r\n lineSpacingType: string\r\n lineSpacingValue: number\r\n /** 왼쪽 들여쓰기(HWPUNIT) */\r\n marginLeft: number\r\n marginRight: number\r\n /** 첫 줄 들여쓰기/내어쓰기 — 음수=둘째 줄부터 더 들어감(hanging) */\r\n marginIntent: number\r\n /** 문단 위 간격(prev) */\r\n spaceBefore: number\r\n /** 문단 아래 간격(next) */\r\n spaceAfter: number\r\n /** breakSetting의 한글 줄나눔 — 'keep'(어절)/'charAll'(글자). 없으면 호출자 모드.\r\n * 주의: 저장 속성 의미는 이름과 반대 — breakNonLatinWord \"BREAK_WORD\"=어절,\r\n * \"KEEP_WORD\"=글자 (한글 COM 실렌더 실측) */\r\n wrapMode?: \"keep\" | \"charAll\"\r\n}\r\n\r\nexport const DEFAULT_PARA_GEOM: RenderParaGeom = {\r\n lineSpacingType: \"PERCENT\", lineSpacingValue: 160,\r\n marginLeft: 0, marginRight: 0, marginIntent: 0, spaceBefore: 0, spaceAfter: 0,\r\n}\r\n\r\nexport interface RenderBorderEdge {\r\n /** SOLID/DASH/DOT… — NONE은 edge 자체를 생략 */\r\n type: string\r\n /** pt 단위 굵기 */\r\n widthPt: number\r\n color: string\r\n}\r\n\r\nexport interface RenderBorderFill {\r\n left?: RenderBorderEdge\r\n right?: RenderBorderEdge\r\n top?: RenderBorderEdge\r\n bottom?: RenderBorderEdge\r\n /** 배경색 #RRGGBB (없으면 undefined) */\r\n fill?: string\r\n}\r\n\r\nexport interface RenderStyles {\r\n charPr: Map<string, RenderCharStyle>\r\n paraAlign: Map<string, ParaAlign>\r\n /** reflow용 문단 기하 (줄간격·여백) — id별 */\r\n paraGeom: Map<string, RenderParaGeom>\r\n borderFill: Map<string, RenderBorderFill>\r\n}\r\n\r\nexport const DEFAULT_CHAR: RenderCharStyle = { height: 1000, bold: false, italic: false, underline: false, ratio: 100, spacing: 0 }\r\n\r\n// ─── 글꼴 매핑 (HWP fontfaces face → CSS font-family 스택) ──────────────\r\n//\r\n// HWPX charPr 는 <hh:fontRef hangul=\"N\">으로 fontfaces 테이블의 실제 글꼴명을 가리킨다.\r\n// 렌더는 이 글꼴명을 SVG <text font-family>로 내보내 뷰어(WebView2/브라우저)가 원본과\r\n// 같은 글꼴로 그리게 한다. 미설치 글꼴은 계열(명조=serif / 고딕=sans) 폴백으로 수렴시켜\r\n// 최소한 획 계열(바탕↔돋움)은 원본과 일치시킨다 — 공문서 제목 고딕이 바탕체로 나오던 회귀 해소.\r\n\r\n/** 자주 쓰는 글꼴의 별칭 스택 (한글명↔영문 시스템명 병기 — 뷰어 OS별 등록명 차이 흡수) */\r\nconst FONT_ALIASES: Record<string, string> = {\r\n \"함초롬바탕\": \"'HCR Batang','함초롬바탕','한컴바탕'\",\r\n \"한컴바탕\": \"'HCR Batang','함초롬바탕','한컴바탕'\",\r\n \"함초롬돋움\": \"'HCR Dotum','함초롬돋움','한컴돋움'\",\r\n \"한컴돋움\": \"'HCR Dotum','함초롬돋움','한컴돋움'\",\r\n \"맑은 고딕\": \"'Malgun Gothic','맑은 고딕'\",\r\n \"맑은고딕\": \"'Malgun Gothic','맑은 고딕'\",\r\n \"굴림\": \"'Gulim','굴림'\",\r\n \"굴림체\": \"'GulimChe','굴림체','Gulim'\",\r\n \"돋움\": \"'Dotum','돋움'\",\r\n \"돋움체\": \"'DotumChe','돋움체','Dotum'\",\r\n \"바탕\": \"'Batang','바탕'\",\r\n \"바탕체\": \"'BatangChe','바탕체','Batang'\",\r\n \"궁서\": \"'Gungsuh','궁서'\",\r\n \"궁서체\": \"'GungsuhChe','궁서체','Gungsuh'\",\r\n \"나눔고딕\": \"'NanumGothic','나눔고딕'\",\r\n \"나눔명조\": \"'NanumMyeongjo','나눔명조'\",\r\n \"맑은 고딕 Semilight\": \"'Malgun Gothic Semilight','맑은 고딕'\",\r\n}\r\n\r\n/** 명조/바탕 계열(serif) 여부 — 아니면 고딕/돋움(sans)으로 본다 */\r\nfunction isSerifFace(face: string): boolean {\r\n return /바탕|명조|Batang|Myeong|Mincho|궁서|Gungsuh|Serif|신명|순명|Song|송/i.test(face)\r\n}\r\n\r\n/** CSS font-family 토큰 인용 — 영숫자·하이픈만이면 무인용, 그 외(공백·한글)는 작은따옴표 */\r\nfunction cssQuote(name: string): string {\r\n return /^[A-Za-z0-9_-]+$/.test(name) ? name : `'${name.replace(/['\"\\\\]/g, \"\")}'`\r\n}\r\n\r\n/**\r\n * HWP 글꼴명 → CSS font-family 스택. 정확한 글꼴 먼저, 이어서 계열 폴백(명조=serif /\r\n * 고딕=sans, 각 한국어 렌더 가능 글꼴 포함)을 붙여 미설치 시에도 획 계열을 보존한다.\r\n */\r\nexport function hwpFaceToCssStack(face: string | null | undefined): string {\r\n const trimmed = (face ?? \"\").trim()\r\n if (!trimmed) return \"\"\r\n const generic = isSerifFace(trimmed)\r\n ? \"'HCR Batang','Batang','Noto Serif KR',serif\"\r\n : \"'Malgun Gothic','HCR Dotum','Noto Sans KR',sans-serif\"\r\n const head = FONT_ALIASES[trimmed] ?? cssQuote(trimmed)\r\n return `${head},${generic}`\r\n}\r\n\r\n/** fontfaces 테이블에서 HANGUL 그룹의 font id → 글꼴명 맵 (없으면 첫 그룹) */\r\nfunction collectHangulFonts(root: Element): Map<string, string> {\r\n const map = new Map<string, string>()\r\n const findFaces = (el: Element, depth: number): Element | null => {\r\n if (depth > 24) return null\r\n for (const ch of Array.from(el.childNodes)) {\r\n if (ch.nodeType !== 1) continue\r\n const e = ch as Element\r\n if ((e.tagName || \"\").replace(/^[^:]+:/, \"\") === \"fontfaces\") return e\r\n const f = findFaces(e, depth + 1)\r\n if (f) return f\r\n }\r\n return null\r\n }\r\n const faces = findFaces(root, 0)\r\n if (!faces) return map\r\n let group: Element | null = null\r\n let firstGroup: Element | null = null\r\n for (const ch of Array.from(faces.childNodes)) {\r\n if (ch.nodeType !== 1) continue\r\n const e = ch as Element\r\n if ((e.tagName || \"\").replace(/^[^:]+:/, \"\") !== \"fontface\") continue\r\n if (!firstGroup) firstGroup = e\r\n if ((e.getAttribute(\"lang\") ?? \"\").toUpperCase() === \"HANGUL\") { group = e; break }\r\n }\r\n group = group ?? firstGroup\r\n if (!group) return map\r\n for (const ch of Array.from(group.childNodes)) {\r\n if (ch.nodeType !== 1) continue\r\n const e = ch as Element\r\n if ((e.tagName || \"\").replace(/^[^:]+:/, \"\") !== \"font\") continue\r\n const id = e.getAttribute(\"id\")\r\n const face = e.getAttribute(\"face\")\r\n if (id != null && face) map.set(id, face)\r\n }\r\n return map\r\n}\r\n\r\n/** \"0.12 mm\" / \"0.5 mm\" → pt */\r\nfunction borderWidthPt(v: string | null | undefined): number {\r\n const n = parseFloat(v ?? \"\")\r\n if (!Number.isFinite(n)) return 0.34\r\n return n * 2.834645 // mm → pt\r\n}\r\n\r\nfunction parseEdge(el: Element | null): RenderBorderEdge | undefined {\r\n if (!el) return undefined\r\n const type = el.getAttribute(\"type\") ?? \"NONE\"\r\n if (type === \"NONE\") return undefined\r\n return { type, widthPt: borderWidthPt(el.getAttribute(\"width\")), color: el.getAttribute(\"color\") ?? \"#000000\" }\r\n}\r\n\r\n/** 서브트리에서 localName이 일치하는 첫 요소를 재귀 탐색 (switch/case 래핑 대응) */\r\nfunction findDeep(el: Element, name: string, depth = 0): Element | null {\r\n if (depth > 32) return null\r\n const children = el.childNodes\r\n if (!children) return null\r\n for (let i = 0; i < children.length; i++) {\r\n const ch = children[i]\r\n if (ch.nodeType !== 1) continue\r\n const e = ch as Element\r\n if ((e.tagName || \"\").replace(/^[^:]+:/, \"\") === name) return e\r\n const found = findDeep(e, name, depth + 1)\r\n if (found) return found\r\n }\r\n return null\r\n}\r\n\r\n/** paraPr 요소 → 문단 기하 (margin·lineSpacing은 hp:switch/case 안이라 재귀 탐색) */\r\nfunction parseParaGeom(el: Element): RenderParaGeom {\r\n const g: RenderParaGeom = { ...DEFAULT_PARA_GEOM }\r\n const ls = findDeep(el, \"lineSpacing\")\r\n if (ls) {\r\n g.lineSpacingType = ls.getAttribute(\"type\") ?? \"PERCENT\"\r\n g.lineSpacingValue = Number(ls.getAttribute(\"value\")) || 160\r\n }\r\n const margin = findDeep(el, \"margin\")\r\n if (margin) {\r\n const v = (n: string): number => {\r\n const c = findDeep(margin, n)\r\n return c ? Number(c.getAttribute(\"value\")) || 0 : 0\r\n }\r\n g.marginLeft = v(\"left\")\r\n g.marginRight = v(\"right\")\r\n g.marginIntent = v(\"intent\")\r\n g.spaceBefore = v(\"prev\")\r\n g.spaceAfter = v(\"next\")\r\n }\r\n const bs = findDeep(el, \"breakSetting\")\r\n if (bs) {\r\n // 속성 의미 역전 주의(위 RenderParaGeom.wrapMode 주석): BREAK_WORD=어절, KEEP_WORD=글자\r\n const nl = bs.getAttribute(\"breakNonLatinWord\")\r\n if (nl === \"BREAK_WORD\") g.wrapMode = \"keep\"\r\n else if (nl === \"KEEP_WORD\") g.wrapMode = \"charAll\"\r\n }\r\n return g\r\n}\r\n\r\n/** header.xml(구버전 head.xml) → 렌더용 스타일 맵 */\r\nexport function parseRenderStyles(headXml: string): RenderStyles {\r\n const styles: RenderStyles = { charPr: new Map(), paraAlign: new Map(), paraGeom: new Map(), borderFill: new Map() }\r\n const doc = createXmlParser().parseFromString(headXml, \"text/xml\")\r\n const root = doc.documentElement as unknown as Element | null\r\n if (!root) return styles\r\n\r\n // fontfaces(HANGUL) 선파싱 — charPr fontRef 해석에 쓴다\r\n const hangulFonts = collectHangulFonts(root)\r\n\r\n const walk = (el: Element): void => {\r\n const tag = (el.tagName || \"\").replace(/^[^:]+:/, \"\")\r\n if (tag === \"charPr\") {\r\n const id = el.getAttribute(\"id\")\r\n if (id != null) {\r\n const ratioEl = findChildByLocalName(el, \"ratio\")\r\n const spacingEl = findChildByLocalName(el, \"spacing\")\r\n const underlineEl = findChildByLocalName(el, \"underline\")\r\n const textColor = el.getAttribute(\"textColor\")\r\n const fontRef = findChildByLocalName(el, \"fontRef\")\r\n const fontId = fontRef?.getAttribute(\"hangul\") ?? fontRef?.getAttribute(\"latin\")\r\n const face = fontId != null ? hangulFonts.get(fontId) : undefined\r\n styles.charPr.set(id, {\r\n height: Number(el.getAttribute(\"height\")) || 1000,\r\n bold: findChildByLocalName(el, \"bold\") != null,\r\n italic: findChildByLocalName(el, \"italic\") != null,\r\n underline: underlineEl != null && (underlineEl.getAttribute(\"type\") ?? \"NONE\") !== \"NONE\",\r\n color: textColor && textColor !== \"#000000\" && textColor.toLowerCase() !== \"none\" ? textColor : undefined,\r\n ratio: Number(ratioEl?.getAttribute(\"hangul\")) || 100,\r\n spacing: Number(spacingEl?.getAttribute(\"hangul\")) || 0,\r\n fontFamily: face ? hwpFaceToCssStack(face) : undefined,\r\n })\r\n }\r\n } else if (tag === \"paraPr\") {\r\n const id = el.getAttribute(\"id\")\r\n if (id != null) {\r\n const align = findChildByLocalName(el, \"align\")\r\n styles.paraAlign.set(id, (align?.getAttribute(\"horizontal\") as ParaAlign) || \"JUSTIFY\")\r\n styles.paraGeom.set(id, parseParaGeom(el))\r\n }\r\n } else if (tag === \"borderFill\") {\r\n const id = el.getAttribute(\"id\")\r\n if (id != null) {\r\n const bf: RenderBorderFill = {\r\n left: parseEdge(findChildByLocalName(el, \"leftBorder\")),\r\n right: parseEdge(findChildByLocalName(el, \"rightBorder\")),\r\n top: parseEdge(findChildByLocalName(el, \"topBorder\")),\r\n bottom: parseEdge(findChildByLocalName(el, \"bottomBorder\")),\r\n }\r\n const fillBrush = findChildByLocalName(el, \"fillBrush\")\r\n const winBrush = fillBrush ? findChildByLocalName(fillBrush, \"winBrush\") : null\r\n const face = winBrush?.getAttribute(\"faceColor\")\r\n if (face && face.toLowerCase() !== \"none\") bf.fill = face\r\n styles.borderFill.set(id, bf)\r\n }\r\n }\r\n const children = el.childNodes\r\n for (let i = 0; i < children.length; i++) {\r\n const ch = children[i]\r\n if (ch.nodeType === 1) walk(ch as Element)\r\n }\r\n }\r\n walk(root)\r\n return styles\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -4,25 +4,28 @@ import {
|
|
|
4
4
|
extractFormFields,
|
|
5
5
|
fillFormFields,
|
|
6
6
|
fillHwpx,
|
|
7
|
+
gongmunLintWarnings,
|
|
8
|
+
lintGongmunText,
|
|
7
9
|
markdownToHwpx,
|
|
8
|
-
parse
|
|
9
|
-
|
|
10
|
+
parse,
|
|
11
|
+
unknownFontWarnings
|
|
12
|
+
} from "./chunk-SHVV3BD6.js";
|
|
10
13
|
import {
|
|
11
14
|
blocksToMarkdown
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-33OUI7HC.js";
|
|
13
16
|
import {
|
|
14
17
|
detectFormat,
|
|
15
18
|
detectZipFormat
|
|
16
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-5CJGKKMZ.js";
|
|
17
20
|
import "./chunk-MOL7MDBG.js";
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
21
|
+
import "./chunk-JMLK6NTW.js";
|
|
22
|
+
import "./chunk-C5ABJ7PB.js";
|
|
23
|
+
import "./chunk-YEC7VG6O.js";
|
|
21
24
|
import {
|
|
22
25
|
VERSION,
|
|
23
26
|
sanitizeError,
|
|
24
27
|
toArrayBuffer
|
|
25
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-EH2KYFFO.js";
|
|
26
29
|
|
|
27
30
|
// src/cli.ts
|
|
28
31
|
import { readFileSync, writeFileSync, mkdirSync, statSync } from "fs";
|
|
@@ -130,7 +133,7 @@ program.command("watch <dir>").description("\uB514\uB809\uD1A0\uB9AC \uAC10\uC2D
|
|
|
130
133
|
if (command.getOptionValueSource("format") === "default" && program.getOptionValueSource("format") === "cli") {
|
|
131
134
|
opts.format = rootOpts.format;
|
|
132
135
|
}
|
|
133
|
-
const { watchDirectory } = await import("./watch-
|
|
136
|
+
const { watchDirectory } = await import("./watch-UYT3ZCBM.js");
|
|
134
137
|
await watchDirectory({
|
|
135
138
|
dir,
|
|
136
139
|
outDir: opts.outDir,
|
|
@@ -287,7 +290,7 @@ program.command("fill <template>").description("\uC11C\uC2DD \uBB38\uC11C\uC758
|
|
|
287
290
|
});
|
|
288
291
|
program.command("seal <file>").description('\uB3C4\uC7A5/\uC11C\uBA85 \uC774\uBBF8\uC9C0\uB97C \uC575\uCEE4 \uBB38\uAD6C \uC704\uC5D0 \uBD80\uC720 \uBC30\uCE58 (\uD45C/\uD398\uC774\uC9C0 \uBD88\uD655\uC7A5) \u2014 kordoc seal \uC2E0\uCCAD\uC11C.hwpx --image \uB3C4\uC7A5.png --anchor "(\uC778)" -o \uACB0\uACFC.hwpx').requiredOption("--image <path>", "\uB3C4\uC7A5/\uC11C\uBA85 \uC774\uBBF8\uC9C0 (\uD22C\uBA85 \uBC30\uACBD PNG \uAD8C\uC7A5)").option("--anchor <text>", "\uC575\uCEE4 \uBB38\uAD6C", "(\uC778)").option("-n, --occurrence <num>", "\uAC19\uC740 \uC575\uCEE4\uAC00 \uC5EC\uB7FF\uC77C \uB54C 0-based \uC120\uD0DD", "0").option("--size-mm <num>", "\uB3C4\uC7A5 \uD55C \uBCC0 \uD06C\uAE30 mm (\uAE30\uBCF8: \uC904\uB192\uC774\xD71.6, 7~18 \uD074\uB7A8\uD504)").option("--mode <mode>", "overlap(\uBB38\uAD6C \uC704 \uACB9\uCE68) | right(\uC624\uB978\uCABD \uC606) | auto", "auto").option("--dx <mm>", "x \uBBF8\uC138\uC870\uC815 mm", "0").option("--dy <mm>", "y \uBBF8\uC138\uC870\uC815 mm", "0").option("-o, --output <path>", "\uCD9C\uB825 \uACBD\uB85C (\uAE30\uBCF8: <\uC785\uB825>.sealed.hwpx)").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (file, opts) => {
|
|
289
292
|
try {
|
|
290
|
-
const { placeSealHwpx, detectFormat: detectFormat2 } = await import("./-
|
|
293
|
+
const { placeSealHwpx, detectFormat: detectFormat2 } = await import("./-O3AWNVPH.js");
|
|
291
294
|
const rootOpts = program.opts();
|
|
292
295
|
const output = opts.output ?? rootOpts.output;
|
|
293
296
|
const silent = opts.silent ?? rootOpts.silent;
|
|
@@ -356,7 +359,7 @@ program.command("seal <file>").description('\uB3C4\uC7A5/\uC11C\uBA85 \uC774\uBB
|
|
|
356
359
|
});
|
|
357
360
|
program.command("patch <original> <edited>").description("\uC11C\uC2DD \uBCF4\uC874 \uB77C\uC6B4\uB4DC\uD2B8\uB9BD \uD328\uCE58 \u2014 \uD3B8\uC9D1\uB41C \uB9C8\uD06C\uB2E4\uC6B4\uC744 \uC6D0\uBCF8 HWPX/HWP\uC5D0 in-place \uBC18\uC601 (kordoc patch \uC6D0\uBCF8.hwpx \uD3B8\uC9D1.md -o \uCD9C\uB825.hwpx)").option("-o, --output <path>", "\uCD9C\uB825 \uACBD\uB85C (\uAE30\uBCF8: <\uC6D0\uBCF8>.patched.hwpx|.hwp)").option("--no-verify", "\uD328\uCE58 \uD6C4 \uC7AC\uD30C\uC2F1 \uC790\uB3D9 \uAC80\uC99D \uC0DD\uB7B5").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (original, edited, opts) => {
|
|
358
361
|
try {
|
|
359
|
-
const { patchHwpx, patchHwp, detectFormat: detectFormat2 } = await import("./-
|
|
362
|
+
const { patchHwpx, patchHwp, detectFormat: detectFormat2 } = await import("./-O3AWNVPH.js");
|
|
360
363
|
const rootOpts = program.opts();
|
|
361
364
|
const output = opts.output ?? rootOpts.output;
|
|
362
365
|
const silent = opts.silent ?? rootOpts.silent;
|
|
@@ -397,7 +400,7 @@ program.command("patch <original> <edited>").description("\uC11C\uC2DD \uBCF4\uC
|
|
|
397
400
|
});
|
|
398
401
|
program.command("validate <file>").description("HWPX \uAD6C\uC870 \uAC80\uC99D \u2014 ZIP\xB7mimetype\xB7\uD544\uC218 \uD30C\uC77C\xB7XML \uC6F0\uD3FC\uB4DC\xB7secCnt\xB7manifest \uCC38\uC870 (\uD55C\uCEF4\uB3C5\uC2A4 \uAC70\uBD80 \uC694\uC778 \uC0AC\uC804 \uCC28\uB2E8)").option("--json", "\uACB0\uACFC\uB97C JSON\uC73C\uB85C stdout\uC5D0 \uCD9C\uB825").action(async (file, opts) => {
|
|
399
402
|
try {
|
|
400
|
-
const { validateHwpx } = await import("./-
|
|
403
|
+
const { validateHwpx } = await import("./-O3AWNVPH.js");
|
|
401
404
|
const buf = new Uint8Array(readFileSync(resolve(file)));
|
|
402
405
|
const result = await validateHwpx(buf);
|
|
403
406
|
if (opts.json) {
|
|
@@ -420,7 +423,7 @@ program.command("validate <file>").description("HWPX \uAD6C\uC870 \uAC80\uC99D \
|
|
|
420
423
|
process.exit(1);
|
|
421
424
|
}
|
|
422
425
|
});
|
|
423
|
-
program.command("generate <markdown>").alias("gen").description("\uB9C8\uD06C\uB2E4\uC6B4 \u2192 \uACF5\uBB38\uC11C HWPX \uC0DD\uC131 \u2014 kordoc generate \uBCF4\uACE0\uC11C.md -o \uBCF4\uACE0\uC11C.hwpx --preset \uBCF4\uACE0\uC11C (markdown\uC5D0 '-' \uC9C0\uC815 \uC2DC stdin)").option("-o, --output <path>", "\uCD9C\uB825 HWPX \uACBD\uB85C (\uAE30\uBCF8: <\uC785\uB825>.hwpx)").option("--preset <name>", "\uACF5\uBB38\uC11C \uD504\uB9AC\uC14B: \uAE30\uC548\uBB38(official)\xB7\uBCF4\uACE0\uC11C(report)\xB7\uACC4\uD68D\uC11C(plan)\xB7\uD1B5\uC9C0(notice)\xB7\uD68C\uC758\uB85D(minutes)", "\uAE30\uC548\uBB38").option("--font <type>", "\uBCF8\uBB38 \uAE00\uAF34: myeongjo(\uD568\uCD08\uB86C\uBC14\uD0D5) \uB610\uB294 gothic(\uB9D1\uC740 \uACE0\uB515)").option("--pt <size>", "\uBCF8\uBB38 \uAE00\uC790 \uD06C\uAE30(pt)").option("--line-spacing <percent>", "\uBCF8\uBB38 \uC904\uAC04\uACA9(%)").option("--plain", "\uACF5\uBB38\uC11C \uBAA8\uB4DC \uB044\uAE30 (\uBC94\uC6A9 \uB9C8\uD06C\uB2E4\uC6B4 \uBCC0\uD658)").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (markdown, opts) => {
|
|
426
|
+
program.command("generate <markdown>").alias("gen").description("\uB9C8\uD06C\uB2E4\uC6B4 \u2192 \uACF5\uBB38\uC11C HWPX \uC0DD\uC131 \u2014 kordoc generate \uBCF4\uACE0\uC11C.md -o \uBCF4\uACE0\uC11C.hwpx --preset \uBCF4\uACE0\uC11C (markdown\uC5D0 '-' \uC9C0\uC815 \uC2DC stdin)").option("-o, --output <path>", "\uCD9C\uB825 HWPX \uACBD\uB85C (\uAE30\uBCF8: <\uC785\uB825>.hwpx)").option("--preset <name>", "\uACF5\uBB38\uC11C \uD504\uB9AC\uC14B: \uAE30\uC548\uBB38(official)\xB7\uBCF4\uACE0\uC11C(report)\xB7\uACC4\uD68D\uC11C(plan)\xB7\uD1B5\uC9C0(notice)\xB7\uD68C\uC758\uB85D(minutes)\xB7\uAC1C\uC870\uC2DD(gaejosik \u2014 \uD45C\uC9C0\xB7\uBAA9\uCC28\xB7\uC7A5\uD5E4\uB354 \uC790\uB3D9)", "\uAE30\uC548\uBB38").option("--font <type>", "\uBCF8\uBB38 \uAE00\uAF34: myeongjo(\uD568\uCD08\uB86C\uBC14\uD0D5) \uB610\uB294 gothic(\uB9D1\uC740 \uACE0\uB515)").option("--pt <size>", "\uBCF8\uBB38 \uAE00\uC790 \uD06C\uAE30(pt)").option("--line-spacing <percent>", "\uBCF8\uBB38 \uC904\uAC04\uACA9(%)").option("--org <name>", "\uD45C\uC9C0 \uAE30\uAD00\uBA85 (\uAC1C\uC870\uC2DD \uD504\uB9AC\uC14B)").option("--date <date>", "\uD45C\uC9C0 \uB0A0\uC9DC (\uAC1C\uC870\uC2DD \uD504\uB9AC\uC14B, \uAE30\uBCF8 \uC624\uB298 \u2014 'YYYY. M. D.')").option("--toc", "\uBAA9\uCC28 \uD398\uC774\uC9C0 \uAC15\uC81C \uCF1C\uAE30 (\uAC1C\uC870\uC2DD \uC678 \uD504\uB9AC\uC14B\uC5D0\uC11C\uB3C4 h2 \uBAA9\uB85D\uC73C\uB85C \uC0DD\uC131)").option("--no-toc", "\uBAA9\uCC28 \uD398\uC774\uC9C0 \uB044\uAE30 (\uAC1C\uC870\uC2DD \uD504\uB9AC\uC14B \uAE30\uBCF8 \uCF1C\uC9D0)").option("--cover", "\uD45C\uC9C0 \uD398\uC774\uC9C0 \uAC15\uC81C \uCF1C\uAE30 (\uAC1C\uC870\uC2DD \uC678 \uD504\uB9AC\uC14B\uC5D0\uC11C\uB3C4 \uCCAB h1\uC744 \uD45C\uC9C0\uB85C)").option("--no-cover", "\uD45C\uC9C0 \uD398\uC774\uC9C0 \uB044\uAE30 (\uAC1C\uC870\uC2DD \uD504\uB9AC\uC14B \uAE30\uBCF8 \uCF1C\uC9D0)").option("--approval <labels>", "\uACB0\uC7AC\uB780 \uC9C1\uC704 \uB77C\uBCA8 (\uC27C\uD45C \uAD6C\uBD84, \uC608: \uB2F4\uB2F9,\uD300\uC7A5,\uACFC\uC7A5) \u2014 \uBB38\uC11C \uCD5C\uC0C1\uB2E8 \uC6B0\uCE21").option("--page-numbers", "\uCABD\uBC88\uD638 \uAC15\uC81C \uCF1C\uAE30 (\uD558\uB2E8 \uC911\uC559 '- 1 -')").option("--no-page-numbers", "\uCABD\uBC88\uD638 \uB044\uAE30 (\uAC1C\uC870\uC2DD\xB7\uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C \uAE30\uBCF8 \uCF1C\uC9D0)").option("--end-mark", "\uBCF8\uBB38 \uB05D '\uB05D.' \uD45C\uC2DC \uAC15\uC81C \uCF1C\uAE30").option("--no-end-mark", "'\uB05D.' \uD45C\uC2DC \uB044\uAE30 (\uAE30\uC548\uBB38 \uAE30\uBCF8 \uCF1C\uC9D0)").option("--no-body-title-box", "\uBCF8\uBB38 \uCCAB \uD398\uC774\uC9C0 \uC81C\uBAA9 \uBC18\uBCF5 \uBC15\uC2A4 \uB044\uAE30 (\uAC1C\uC870\uC2DD+\uD45C\uC9C0 \uAE30\uBCF8 \uCF1C\uC9D0)").option("--h2-marker <type>", "h2 \uC139\uC158 \uC81C\uBAA9 \uB9D0\uBA38\uB9AC: box(\u25A1 \u2014 \uBCF4\uACE0\uC11C\xB7\uACC4\uD68D\uC11C \uAE30\uBCF8)\xB7number(1. \u2014 \uACF5\uACE0\uBB38 \uAD00\uD589)\xB7none").option("--fonts <spec>", "\uC694\uC18C\uBCC4 \uAE00\uAF34 \uC624\uBC84\uB77C\uC774\uB4DC: body=\uB098\uB214\uBA85\uC870,heading=\uB098\uB214\uACE0\uB515,ref=\uD55C\uC591\uC911\uACE0\uB515,table=\uB9D1\uC740 \uACE0\uB515").option("--sizes <spec>", "\uAC1C\uC870\uC2DD \uC694\uC18C\uBCC4 \uD06C\uAE30(pt): dae=16,cham=13,table=12,coverTitle=30 \u2026").option("--plain", "\uACF5\uBB38\uC11C \uBAA8\uB4DC \uB044\uAE30 (\uBC94\uC6A9 \uB9C8\uD06C\uB2E4\uC6B4 \uBCC0\uD658)").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (markdown, opts) => {
|
|
424
427
|
try {
|
|
425
428
|
const rootOpts = program.opts();
|
|
426
429
|
const output = opts.output ?? rootOpts.output;
|
|
@@ -438,11 +441,31 @@ program.command("generate <markdown>").alias("gen").description("\uB9C8\uD06C\uB
|
|
|
438
441
|
if (!opts.plain) {
|
|
439
442
|
const preset = PRESET_ALIAS[String(opts.preset).trim()];
|
|
440
443
|
if (!preset) {
|
|
441
|
-
process.stderr.write(`[kordoc] \uC54C \uC218 \uC5C6\uB294 \uD504\uB9AC\uC14B: ${opts.preset} (\uAE30\uC548\uBB38/\uBCF4\uACE0\uC11C/\uACC4\uD68D\uC11C/\uD1B5\uC9C0/\uD68C\uC758\uB85D)
|
|
444
|
+
process.stderr.write(`[kordoc] \uC54C \uC218 \uC5C6\uB294 \uD504\uB9AC\uC14B: ${opts.preset} (\uAE30\uC548\uBB38/\uBCF4\uACE0\uC11C/\uACC4\uD68D\uC11C/\uD1B5\uC9C0/\uD68C\uC758\uB85D/\uAC1C\uC870\uC2DD)
|
|
442
445
|
`);
|
|
443
446
|
process.exit(1);
|
|
444
447
|
}
|
|
445
448
|
gongmun = { preset };
|
|
449
|
+
if (opts.cover === false) {
|
|
450
|
+
gongmun.cover = false;
|
|
451
|
+
} else if (opts.org || opts.date) {
|
|
452
|
+
gongmun.cover = { ...opts.org ? { org: opts.org } : {}, ...opts.date ? { date: opts.date } : {} };
|
|
453
|
+
} else if (opts.cover === true) {
|
|
454
|
+
gongmun.cover = true;
|
|
455
|
+
}
|
|
456
|
+
if (opts.toc !== void 0) gongmun.toc = opts.toc;
|
|
457
|
+
if (opts.approval) gongmun.approval = String(opts.approval).split(",").map((s) => s.trim()).filter(Boolean);
|
|
458
|
+
if (opts.pageNumbers !== void 0) gongmun.pageNumbers = opts.pageNumbers;
|
|
459
|
+
if (opts.endMark !== void 0) gongmun.endMark = opts.endMark;
|
|
460
|
+
if (opts.bodyTitleBox === false) gongmun.bodyTitleBox = false;
|
|
461
|
+
if (opts.h2Marker) {
|
|
462
|
+
if (!["box", "number", "none"].includes(opts.h2Marker)) {
|
|
463
|
+
process.stderr.write(`[kordoc] --h2-marker \uB294 box/number/none
|
|
464
|
+
`);
|
|
465
|
+
process.exit(1);
|
|
466
|
+
}
|
|
467
|
+
gongmun.h2Marker = opts.h2Marker;
|
|
468
|
+
}
|
|
446
469
|
if (opts.font) {
|
|
447
470
|
if (opts.font !== "myeongjo" && opts.font !== "gothic") {
|
|
448
471
|
process.stderr.write(`[kordoc] --font \uC740 myeongjo \uB610\uB294 gothic
|
|
@@ -453,6 +476,21 @@ program.command("generate <markdown>").alias("gen").description("\uB9C8\uD06C\uB
|
|
|
453
476
|
}
|
|
454
477
|
if (opts.pt) gongmun.bodyPt = Number(opts.pt);
|
|
455
478
|
if (opts.lineSpacing) gongmun.lineSpacing = Number(opts.lineSpacing);
|
|
479
|
+
const parseKv = (spec) => Object.fromEntries(spec.split(",").map((p) => p.split("=").map((s) => s.trim())).filter((kv) => kv.length === 2 && kv[0] && kv[1]));
|
|
480
|
+
if (opts.fonts) gongmun.fonts = parseKv(String(opts.fonts));
|
|
481
|
+
if (opts.sizes) {
|
|
482
|
+
gongmun.sizes = Object.fromEntries(
|
|
483
|
+
Object.entries(parseKv(String(opts.sizes))).map(([k, v]) => [k, Number(v)]).filter(([, v]) => Number.isFinite(v))
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
if (gongmun?.fonts && !silent) {
|
|
488
|
+
for (const w of unknownFontWarnings(gongmun.fonts)) process.stderr.write(`[kordoc] ${w}
|
|
489
|
+
`);
|
|
490
|
+
}
|
|
491
|
+
if (gongmun && !silent) {
|
|
492
|
+
for (const w of gongmunLintWarnings(md, 5)) process.stderr.write(`[kordoc] \u26A0 ${w}
|
|
493
|
+
`);
|
|
456
494
|
}
|
|
457
495
|
const buf = await markdownToHwpx(md, gongmun ? { gongmun } : void 0);
|
|
458
496
|
const outPath = resolve(output ?? (markdown === "-" ? `${baseName}.hwpx` : markdown.replace(/\.(md|markdown|txt)$/i, "") + ".hwpx"));
|
|
@@ -469,12 +507,34 @@ program.command("generate <markdown>").alias("gen").description("\uB9C8\uD06C\uB
|
|
|
469
507
|
process.exit(1);
|
|
470
508
|
}
|
|
471
509
|
});
|
|
510
|
+
program.command("lint <file>").description("\uACF5\uBB38\uC11C \uD45C\uAE30\uBC95 \uAC80\uC218 \u2014 \uB0A0\uC9DC\xB7\uC2DC\uAC04\xB7\uAE08\uC561\xB7\uBD99\uC784 \uB4F1 \uD589\uC815\uC5C5\uBB34\uC6B4\uC601 \uD3B8\uB78C \uD45C\uAE30\uBC95 (md/txt, '-'=stdin). error \uC788\uC73C\uBA74 exit 1").option("--json", "JSON \uCD9C\uB825").action((file, opts) => {
|
|
511
|
+
try {
|
|
512
|
+
const text = file === "-" ? readFileSync(0, "utf-8") : readFileSync(resolve(file), "utf-8");
|
|
513
|
+
const findings = lintGongmunText(text);
|
|
514
|
+
const errors = findings.filter((f) => f.severity === "error").length;
|
|
515
|
+
if (opts.json) {
|
|
516
|
+
process.stdout.write(JSON.stringify({ findings, summary: { total: findings.length, errors, ok: errors === 0 } }, null, 2) + "\n");
|
|
517
|
+
} else {
|
|
518
|
+
process.stdout.write(`[kordoc] \uD45C\uAE30\uBC95 \uAC80\uC218: \uC704\uBC18 ${findings.length}\uAC74 (error ${errors}, warning ${findings.length - errors})
|
|
519
|
+
`);
|
|
520
|
+
for (const f of findings) {
|
|
521
|
+
process.stdout.write(` L${f.line} [${f.severity}] ${f.rule}: "${f.match}" \u2014 ${f.message}${f.suggest ? ` \u2192 ${f.suggest}` : ""}
|
|
522
|
+
`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
process.exit(errors > 0 ? 1 : 0);
|
|
526
|
+
} catch (err) {
|
|
527
|
+
process.stderr.write(`[kordoc] \uC624\uB958: ${sanitizeError(err)}
|
|
528
|
+
`);
|
|
529
|
+
process.exit(1);
|
|
530
|
+
}
|
|
531
|
+
});
|
|
472
532
|
program.command("render <file>").description("\uB808\uC774\uC544\uC6C3 \uBCF4\uC874 \uB80C\uB354 \u2014 \uD55C\uCEF4 \uC800\uC7A5 HWPX\uC758 \uC870\uD310 \uCE90\uC2DC\uB97C SVG\uB85C (\uC804\uCCB4 \uD398\uC774\uC9C0 \uC138\uB85C \uC2A4\uD0DD) \u2014 kordoc render \uBB38\uC11C.hwpx -o \uBB38\uC11C.svg").option("-o, --output <path>", "\uCD9C\uB825 SVG \uACBD\uB85C (\uAE30\uBCF8: <\uC785\uB825>.svg)").option("--highlight <terms>", "\uAC80\uC0C9\uC5B4 \uD615\uAD11\uD39C (\uC27C\uD45C \uAD6C\uBD84)").option("--reflow", "\uC870\uD310 \uCE90\uC2DC \uC5C6\uB294 HWPX\uB3C4 \uC21C\uC218 TS \uC870\uD310\uC73C\uB85C \uB80C\uB354 (markdownToHwpx \uC0B0\uCD9C\uBB3C\xB7\uD3B8\uC9D1\uBCF8)").option("--reflow-mode <mode>", "reflow \uC904\uBC14\uAFC8 \uBAA8\uB4DC: keep(\uC5B4\uC808) | charAll(\uAE00\uC790)", "keep").option("--silent", "\uC9C4\uD589 \uBA54\uC2DC\uC9C0 \uC228\uAE30\uAE30").action(async (file, opts) => {
|
|
473
533
|
try {
|
|
474
534
|
const rootOpts = program.opts();
|
|
475
535
|
const output = opts.output ?? rootOpts.output;
|
|
476
536
|
const silent = opts.silent ?? rootOpts.silent;
|
|
477
|
-
const { renderHwpxToSvg } = await import("./render-
|
|
537
|
+
const { renderHwpxToSvg } = await import("./render-SQVQBORJ.js");
|
|
478
538
|
const absPath = resolve(file);
|
|
479
539
|
const buffer = readFileSync(absPath);
|
|
480
540
|
const highlights = opts.highlight ? String(opts.highlight).split(",") : void 0;
|
|
@@ -496,7 +556,7 @@ program.command("render <file>").description("\uB808\uC774\uC544\uC6C3 \uBCF4\uC
|
|
|
496
556
|
});
|
|
497
557
|
program.command("render-worker").description("persistent \uB80C\uB354 \uC6CC\uCEE4 \u2014 stdin NDJSON \uC694\uCCAD \u2192 \uC870\uD310 SVG \uD30C\uC77C \uCD9C\uB825 (\uD504\uB85C\uC138\uC2A4 \uC720\uC9C0, \uCF5C\uB4DC\uC2A4\uD0C0\uD2B8 \uC81C\uAC70)").action(async () => {
|
|
498
558
|
const { createInterface } = await import("readline");
|
|
499
|
-
const { renderHwpxToSvg } = await import("./render-
|
|
559
|
+
const { renderHwpxToSvg } = await import("./render-SQVQBORJ.js");
|
|
500
560
|
const rl = createInterface({ input: process.stdin });
|
|
501
561
|
const write = (o) => void process.stdout.write(JSON.stringify(o) + "\n");
|
|
502
562
|
write({ ready: true, version: VERSION });
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["/** kordoc CLI — 모두 파싱해버리겠다 */\n\nimport { readFileSync, writeFileSync, mkdirSync, statSync } from \"fs\"\nimport { basename, dirname, resolve, extname } from \"path\"\nimport { Command } from \"commander\"\nimport { parse, detectFormat, detectZipFormat, fillFormFields, extractFormFields, blocksToMarkdown, markdownToHwpx, fillHwpx, PRESET_ALIAS } 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(\"--formula-ocr\", \"PDF 수식 OCR 활성화 (MFD+MFR ONNX, 첫 사용 시 모델 ~155MB 자동 다운로드)\")\n .option(\"--dedupe-headers\", \"HWP5 레이아웃 표 페이지 반복 러닝 헤더 중복 제거 (기본 off — 붙임별 재번호 오삭제 주의)\")\n .option(\"--inline-images\", \"이미지를 base64 data URI 로 마크다운에 인라인 (BMP→PNG 압축, HWP5 전용 — 인라인된 경우만 파일 미저장, 그 외 포맷은 저장 유지)\")\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 = { filePath: absPath }\n if (opts.pages) parseOptions.pages = opts.pages as string\n if (opts.headerFooter === false) parseOptions.removeHeaderFooter = false\n if (opts.formulaOcr) parseOptions.formulaOcr = true\n if (opts.dedupeHeaders) parseOptions.dedupeRunningHeaders = true\n if (opts.inlineImages) parseOptions.inlineImages = true\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 // 이미지 인라인은 HWP5 경로에서만 실제로 일어난다(parser.ts). 그 외 포맷(HWPX/DOCX 등)은\n // --inline-images 를 줘도 인라인되지 않으므로, 이미지 저장/경로접두사를 생략하면 참조가\n // 깨지고(dangling) 바이트가 유실된다 → 실제 인라인된 경우에만 생략한다.\n const imagesInlined = opts.inlineImages && result.fileType === \"hwp\"\n // --out-dir 시 이미지 참조 경로에 images/ 접두사 추가 (인라인 모드에선 이미지가 마크다운에 임베드되므로 건너뜀)\n // <img src> 는 병합/중첩 표 셀 경로(table/builder.ts) — 마크다운 문법과 함께 둘 다 바꿔야 참조가 안 깨진다\n if (opts.outDir && result.images?.length && !imagesInlined) {\n markdown = markdown\n .replace(/!\\[image\\]\\(image_/g, \"\n .replace(/(<img\\b[^>]*\\bsrc=\")image_/g, \"$1images/image_\")\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 시) — 실제 인라인된 경우(HWP5)에만 미저장, 그 외엔 저장 유지\n const saveImages = (dir: string) => {\n if (!result.images?.length || imagesInlined) 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, command: Command) => {\n // 루트 커맨드의 동명 옵션(-d/--out-dir·-p/--pages·--format·--silent)이 서브커맨드 뒤에서도 루트로 흡수되는 commander 동작 보완\n const rootOpts = program.opts()\n opts.outDir ??= rootOpts.outDir\n opts.pages ??= rootOpts.pages\n opts.silent ??= rootOpts.silent\n if (command.getOptionValueSource(\"format\") === \"default\" && program.getOptionValueSource(\"format\") === \"cli\") {\n opts.format = rootOpts.format\n }\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\n .command(\"fill <template>\")\n .description(\"서식 문서의 빈칸을 채워서 출력 — kordoc fill 신청서.hwpx -f '성명=홍길동,전화=010-1234-5678' -o 결과.hwpx\")\n .option(\"-f, --fields <pairs>\", \"채울 필드 (key=value 쉼표 구분 또는 JSON)\")\n .option(\"-j, --json <path>\", \"채울 필드 JSON 파일 경로\")\n .option(\"-o, --output <path>\", \"출력 파일 경로 (확장자로 포맷 결정: .md, .hwpx)\")\n .option(\"--format <type>\", \"출력 포맷: hwpx-preserve (기본, 원본 스타일 보존), hwpx, markdown\", \"hwpx-preserve\")\n .option(\"--dry-run\", \"채우지 않고 서식 필드 목록만 출력\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (template: string, opts, command: Command) => {\n try {\n // 루트 커맨드의 동명 옵션(-o/--output·--format·--silent)이 서브커맨드 뒤에서도 루트로 흡수되는 commander 동작 보완\n const rootOpts = program.opts()\n opts.output ??= rootOpts.output\n opts.silent ??= rootOpts.silent\n if (command.getOptionValueSource(\"format\") === \"default\" && program.getOptionValueSource(\"format\") === \"cli\") {\n opts.format = rootOpts.format\n }\n const absPath = resolve(template)\n const fileSize = statSync(absPath).size\n if (fileSize > 500 * 1024 * 1024) {\n process.stderr.write(`[kordoc] 파일이 너무 큽니다 (${(fileSize / 1024 / 1024).toFixed(1)}MB)\\n`)\n process.exit(1)\n }\n\n const buffer = readFileSync(absPath)\n const arrayBuffer = toArrayBuffer(buffer)\n\n if (!opts.silent) process.stderr.write(`[kordoc] ${basename(absPath)} 파싱 중...\\n`)\n\n // --dry-run: 필드 목록만 출력\n if (opts.dryRun) {\n const result = await parse(arrayBuffer)\n if (!result.success) {\n process.stderr.write(`[kordoc] 파싱 실패: ${result.error}\\n`)\n process.exit(1)\n }\n const formInfo = extractFormFields(result.blocks)\n if (formInfo.fields.length === 0) {\n process.stderr.write(`[kordoc] 서식 필드를 찾을 수 없습니다.\\n`)\n process.exit(1)\n }\n process.stdout.write(JSON.stringify(formInfo, null, 2) + \"\\n\")\n return\n }\n\n // 필드 값 파싱\n let values: Record<string, string> = {}\n if (opts.json) {\n const jsonPath = resolve(opts.json)\n const jsonContent = readFileSync(jsonPath, \"utf-8\")\n values = JSON.parse(jsonContent)\n } else if (opts.fields) {\n const fieldsStr: string = opts.fields\n if (fieldsStr.startsWith(\"{\")) {\n values = JSON.parse(fieldsStr)\n } else {\n // \"key1=value1,key2=value2\" 파싱 — 값에 쉼표가 있을 수 있으므로\n // '=' 앞의 키를 기준으로 분리 (쉼표+한글/영문+= 패턴)\n const pairs = fieldsStr.split(/,(?=[가-힣A-Za-z][가-힣A-Za-z\\s]*=)/)\n for (const pair of pairs) {\n const eqIdx = pair.indexOf(\"=\")\n if (eqIdx > 0) {\n const key = pair.slice(0, eqIdx).trim()\n const val = pair.slice(eqIdx + 1).trim()\n values[key] = val\n }\n }\n }\n } else {\n process.stderr.write(`[kordoc] 채울 필드를 지정해주세요 (-f 또는 -j 옵션)\\n`)\n process.exit(1)\n }\n\n // 출력 포맷 결정\n let outputFormat = opts.format as string\n if (opts.output) {\n const ext = extname(opts.output).toLowerCase()\n if (ext === \".hwpx\") outputFormat = outputFormat === \"markdown\" ? \"hwpx-preserve\" : outputFormat\n else if (ext === \".md\") outputFormat = \"markdown\"\n }\n\n // ─── hwpx-preserve: 원본 ZIP 직접 수정 ───\n if (outputFormat === \"hwpx-preserve\") {\n const format = detectFormat(arrayBuffer)\n let isHwpx = format === \"hwpx\"\n if (isHwpx) {\n const zipFormat = await detectZipFormat(arrayBuffer)\n isHwpx = zipFormat === \"hwpx\"\n }\n if (!isHwpx) {\n if (!opts.silent) process.stderr.write(`[kordoc] HWPX가 아니므로 hwpx 모드로 전환합니다\\n`)\n outputFormat = \"hwpx\"\n } else {\n const hwpxResult = await fillHwpx(arrayBuffer, values)\n if (!opts.silent) {\n process.stderr.write(`[kordoc] ${hwpxResult.filled.length}개 필드 채움 (원본 스타일 보존)\\n`)\n if (hwpxResult.unmatched.length > 0) {\n process.stderr.write(`[kordoc] ⚠️ 매칭 실패: ${hwpxResult.unmatched.join(\", \")}\\n`)\n }\n }\n if (opts.output) {\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\n writeFileSync(resolve(opts.output), Buffer.from(hwpxResult.buffer))\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\n } else {\n process.stdout.write(Buffer.from(hwpxResult.buffer))\n }\n return\n }\n }\n\n // ─── 일반 경로: parse → fill → output ───\n const result = await parse(arrayBuffer)\n if (!result.success) {\n process.stderr.write(`[kordoc] 파싱 실패: ${result.error}\\n`)\n process.exit(1)\n }\n\n const formInfo = extractFormFields(result.blocks)\n if (!opts.silent) {\n process.stderr.write(`[kordoc] 서식 필드 ${formInfo.fields.length}개 감지 (확신도 ${(formInfo.confidence * 100).toFixed(0)}%)\\n`)\n }\n\n const fillResult = fillFormFields(result.blocks, values)\n if (!opts.silent) {\n process.stderr.write(`[kordoc] ${fillResult.filled.length}개 필드 채움\\n`)\n if (fillResult.unmatched.length > 0) {\n process.stderr.write(`[kordoc] ⚠️ 매칭 실패: ${fillResult.unmatched.join(\", \")}\\n`)\n }\n }\n\n const markdown = blocksToMarkdown(fillResult.blocks)\n\n if (outputFormat === \"hwpx\") {\n const hwpxBuffer = await markdownToHwpx(markdown)\n if (opts.output) {\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\n writeFileSync(resolve(opts.output), Buffer.from(hwpxBuffer))\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\n } else {\n process.stdout.write(Buffer.from(hwpxBuffer))\n }\n } else {\n if (opts.output) {\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\n writeFileSync(resolve(opts.output), markdown, \"utf-8\")\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\n } else {\n process.stdout.write(markdown + \"\\n\")\n }\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\nprogram\n .command(\"seal <file>\")\n .description('도장/서명 이미지를 앵커 문구 위에 부유 배치 (표/페이지 불확장) — kordoc seal 신청서.hwpx --image 도장.png --anchor \"(인)\" -o 결과.hwpx')\n .requiredOption(\"--image <path>\", \"도장/서명 이미지 (투명 배경 PNG 권장)\")\n .option(\"--anchor <text>\", \"앵커 문구\", \"(인)\")\n .option(\"-n, --occurrence <num>\", \"같은 앵커가 여럿일 때 0-based 선택\", \"0\")\n .option(\"--size-mm <num>\", \"도장 한 변 크기 mm (기본: 줄높이×1.6, 7~18 클램프)\")\n .option(\"--mode <mode>\", \"overlap(문구 위 겹침) | right(오른쪽 옆) | auto\", \"auto\")\n .option(\"--dx <mm>\", \"x 미세조정 mm\", \"0\")\n .option(\"--dy <mm>\", \"y 미세조정 mm\", \"0\")\n .option(\"-o, --output <path>\", \"출력 경로 (기본: <입력>.sealed.hwpx)\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const { placeSealHwpx, detectFormat } = await import(\"./index.js\")\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n const mode = String(opts.mode).toLowerCase()\n if (![\"overlap\", \"right\", \"auto\"].includes(mode)) {\n process.stderr.write(`[kordoc] --mode 는 overlap/right/auto 중 하나여야 합니다\\n`)\n process.exit(1)\n }\n const buf = new Uint8Array(readFileSync(resolve(file)))\n if (detectFormat(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer) !== \"hwpx\") {\n process.stderr.write(`[kordoc] seal 은 HWPX 전용입니다 (HWP 5.x 바이너리는 미지원)\\n`)\n process.exit(1)\n }\n const imgPath = resolve(opts.image)\n const imgSize = statSync(imgPath).size\n if (imgSize > 500 * 1024 * 1024) {\n process.stderr.write(`[kordoc] 도장 이미지가 너무 큽니다 (${(imgSize / 1024 / 1024).toFixed(0)}MB)\\n`)\n process.exit(1)\n }\n const image = new Uint8Array(readFileSync(imgPath))\n const ext = extname(opts.image).slice(1).toLowerCase() || \"png\"\n // --size-mm 검증 — 비숫자·음수가 NaN/음수로 XML 속성에 그대로 기록되던 것 차단 (MCP zod 동등)\n let sizeMm: number | undefined\n if (opts.sizeMm != null) {\n const n = Number(opts.sizeMm)\n if (!Number.isFinite(n) || n <= 0) {\n process.stderr.write(`[kordoc] --size-mm 은 양수여야 합니다: ${opts.sizeMm}\\n`)\n process.exit(1)\n }\n sizeMm = n\n }\n const result = await placeSealHwpx(\n buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer,\n [{\n anchor: opts.anchor,\n occurrence: Number(opts.occurrence) || 0,\n image,\n ext: ext as \"png\" | \"jpg\" | \"jpeg\" | \"bmp\" | \"gif\",\n sizeMm,\n mode: mode as \"overlap\" | \"right\" | \"auto\",\n dxMm: Number(opts.dx) || 0,\n dyMm: Number(opts.dy) || 0,\n }],\n )\n const outPath = resolve(output ?? file.replace(/\\.hwpx$/i, \"\") + \".sealed.hwpx\")\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, Buffer.from(result.buffer))\n if (!silent) {\n for (const p of result.placed) {\n process.stderr.write(`[kordoc] 도장 배치: \"${p.anchor}\" #${p.occurrence} → ${p.mode} (${p.posXMm}mm, ${p.posYMm}mm, ${p.sizeMm}mm) [${p.entry}]\\n`)\n for (const w of p.warnings ?? []) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\n }\n process.stderr.write(`[kordoc] → ${outPath}\\n`)\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\nprogram\n .command(\"patch <original> <edited>\")\n .description(\"서식 보존 라운드트립 패치 — 편집된 마크다운을 원본 HWPX/HWP에 in-place 반영 (kordoc patch 원본.hwpx 편집.md -o 출력.hwpx)\")\n .option(\"-o, --output <path>\", \"출력 경로 (기본: <원본>.patched.hwpx|.hwp)\")\n .option(\"--no-verify\", \"패치 후 재파싱 자동 검증 생략\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (original: string, edited: string, opts) => {\n try {\n const { patchHwpx, patchHwp, detectFormat } = await import(\"./index.js\")\n // 루트 커맨드의 동명 옵션(-o/--silent)이 서브커맨드 옵션을 가로채는 commander 동작 보완\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n const originalBuf = new Uint8Array(readFileSync(resolve(original)))\n const editedMarkdown = readFileSync(resolve(edited), \"utf-8\")\n\n const format = detectFormat(originalBuf.buffer as ArrayBuffer)\n const result = format === \"hwp\"\n ? await patchHwp(originalBuf, editedMarkdown, { verify: opts.verify !== false })\n : await patchHwpx(originalBuf, editedMarkdown, { verify: opts.verify !== false })\n if (!result.success || !result.data) {\n process.stderr.write(`[kordoc] 패치 실패: ${result.error ?? \"알 수 없는 오류\"}\\n`)\n process.exit(1)\n }\n\n const ext = format === \"hwp\" ? \".hwp\" : \".hwpx\"\n const outPath = resolve(output ?? original.replace(/\\.hwpx?$/i, \"\") + \".patched\" + ext)\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, result.data)\n\n if (!silent) {\n process.stderr.write(`[kordoc] ${result.applied}개 변경 적용 (원본 서식 보존) → ${outPath}\\n`)\n for (const s of result.skipped) {\n process.stderr.write(`[kordoc] ⚠️ SKIP: ${s.reason}${s.before ? ` | ${s.before}` : \"\"}\\n`)\n }\n if (result.verification) {\n const v = result.verification.stats\n const residual = v.added + v.removed + v.modified\n process.stderr.write(residual === 0\n ? `[kordoc] ✓ 검증: 편집 마크다운과 재파싱 결과 완전 일치 (${v.unchanged}블록)\\n`\n : `[kordoc] ⚠️ 검증 잔차: 수정 ${v.modified}, 추가 ${v.added}, 삭제 ${v.removed} (미지원 변경은 skip 목록 참조)\\n`)\n }\n }\n if (result.skipped.length > 0) process.exitCode = 2\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\nprogram\n .command(\"validate <file>\")\n .description(\"HWPX 구조 검증 — ZIP·mimetype·필수 파일·XML 웰폼드·secCnt·manifest 참조 (한컴독스 거부 요인 사전 차단)\")\n .option(\"--json\", \"결과를 JSON으로 stdout에 출력\")\n .action(async (file: string, opts) => {\n try {\n const { validateHwpx } = await import(\"./index.js\")\n const buf = new Uint8Array(readFileSync(resolve(file)))\n const result = await validateHwpx(buf)\n if (opts.json) {\n process.stdout.write(JSON.stringify(result, null, 2) + \"\\n\")\n } else if (result.ok) {\n process.stderr.write(`[kordoc] ✓ 구조 검증 통과 (엔트리 ${result.entryCount}개): ${file}\\n`)\n } else {\n process.stderr.write(`[kordoc] ✗ 구조 문제 ${result.issues.length}건: ${file}\\n`)\n for (const i of result.issues) {\n process.stderr.write(`[kordoc] - ${i.path ? `${i.path}: ` : \"\"}${i.message}\\n`)\n }\n }\n if (!result.ok) process.exit(1)\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\n// 공문서 프리셋 별칭(한글/영문) → 내부 preset 키 — gongmun.ts와 공용(PRESET_ALIAS)\n\nprogram\n .command(\"generate <markdown>\")\n .alias(\"gen\")\n .description(\"마크다운 → 공문서 HWPX 생성 — kordoc generate 보고서.md -o 보고서.hwpx --preset 보고서 (markdown에 '-' 지정 시 stdin)\")\n .option(\"-o, --output <path>\", \"출력 HWPX 경로 (기본: <입력>.hwpx)\")\n .option(\"--preset <name>\", \"공문서 프리셋: 기안문(official)·보고서(report)·계획서(plan)·통지(notice)·회의록(minutes)\", \"기안문\")\n .option(\"--font <type>\", \"본문 글꼴: myeongjo(함초롬바탕) 또는 gothic(맑은 고딕)\")\n .option(\"--pt <size>\", \"본문 글자 크기(pt)\")\n .option(\"--line-spacing <percent>\", \"본문 줄간격(%)\")\n .option(\"--plain\", \"공문서 모드 끄기 (범용 마크다운 변환)\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (markdown: string, opts) => {\n try {\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n\n // 입력: '-' 이면 stdin, 아니면 파일\n let md: string\n let baseName = \"document\"\n if (markdown === \"-\") {\n md = readFileSync(0, \"utf-8\")\n } else {\n const inPath = resolve(markdown)\n md = readFileSync(inPath, \"utf-8\")\n baseName = basename(inPath).replace(/\\.(md|markdown|txt)$/i, \"\")\n }\n\n // 공문서 옵션 구성\n let gongmun: import(\"./index.js\").GongmunOptions | undefined\n if (!opts.plain) {\n const preset = PRESET_ALIAS[String(opts.preset).trim()]\n if (!preset) {\n process.stderr.write(`[kordoc] 알 수 없는 프리셋: ${opts.preset} (기안문/보고서/계획서/통지/회의록)\\n`)\n process.exit(1)\n }\n gongmun = { preset }\n if (opts.font) {\n if (opts.font !== \"myeongjo\" && opts.font !== \"gothic\") {\n process.stderr.write(`[kordoc] --font 은 myeongjo 또는 gothic\\n`)\n process.exit(1)\n }\n gongmun.bodyFont = opts.font\n }\n if (opts.pt) gongmun.bodyPt = Number(opts.pt)\n if (opts.lineSpacing) gongmun.lineSpacing = Number(opts.lineSpacing)\n }\n\n const buf = await markdownToHwpx(md, gongmun ? { gongmun } : undefined)\n const outPath = resolve(output ?? (markdown === \"-\" ? `${baseName}.hwpx` : markdown.replace(/\\.(md|markdown|txt)$/i, \"\") + \".hwpx\"))\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, Buffer.from(buf))\n\n if (!silent) {\n const mode = gongmun ? `공문서:${gongmun.preset}` : \"범용\"\n process.stderr.write(`[kordoc] HWPX 생성 (${mode}) → ${outPath}\\n`)\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\nprogram\n .command(\"render <file>\")\n .description(\"레이아웃 보존 렌더 — 한컴 저장 HWPX의 조판 캐시를 SVG로 (전체 페이지 세로 스택) — kordoc render 문서.hwpx -o 문서.svg\")\n .option(\"-o, --output <path>\", \"출력 SVG 경로 (기본: <입력>.svg)\")\n .option(\"--highlight <terms>\", \"검색어 형광펜 (쉼표 구분)\")\n .option(\"--reflow\", \"조판 캐시 없는 HWPX도 순수 TS 조판으로 렌더 (markdownToHwpx 산출물·편집본)\")\n .option(\"--reflow-mode <mode>\", \"reflow 줄바꿈 모드: keep(어절) | charAll(글자)\", \"keep\")\n .option(\"--silent\", \"진행 메시지 숨기기\")\n .action(async (file: string, opts) => {\n try {\n const rootOpts = program.opts()\n const output: string | undefined = opts.output ?? rootOpts.output\n const silent: boolean = opts.silent ?? rootOpts.silent\n const { renderHwpxToSvg } = await import(\"./render/index.js\")\n const absPath = resolve(file)\n const buffer = readFileSync(absPath)\n const highlights = opts.highlight ? String(opts.highlight).split(\",\") : undefined\n const result = await renderHwpxToSvg(toArrayBuffer(buffer), { highlights, reflow: opts.reflow, reflowMode: opts.reflowMode })\n const outPath = resolve(output ?? file.replace(/\\.hwpx$/i, \"\") + \".svg\")\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, result.svg, \"utf-8\")\n if (!silent) {\n process.stderr.write(`[kordoc] 렌더 (${result.pageCount}페이지, ${result.width}x${result.height}pt, 텍스트 ${result.stats.texts}·이미지 ${result.stats.images}·표 ${result.stats.tables}) → ${outPath}\\n`)\n for (const w of result.warnings) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\n }\n } catch (err) {\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\nprogram\n .command(\"render-worker\")\n .description(\"persistent 렌더 워커 — stdin NDJSON 요청 → 조판 SVG 파일 출력 (프로세스 유지, 콜드스타트 제거)\")\n .action(async () => {\n // 프로토콜(NDJSON, 한 줄=한 요청/응답):\n // 요청 {\"id\":1,\"file\":\"a.hwpx\",\"out\":\"a.svg\",\"reflow\":true,\"highlight\":[\"term\"]}\n // 응답 {\"id\":1,\"ok\":true,\"out\":\"a.svg\",\"width\":..,\"height\":..,\"pageCount\":..,\"stats\":{..},\"warnings\":[..]}\n // {\"cmd\":\"quit\"} 로 종료. 모듈은 최초 1회만 로드 → 이후 요청은 콜드스타트 없음.\n const { createInterface } = await import(\"node:readline\")\n const { renderHwpxToSvg } = await import(\"./render/index.js\")\n const rl = createInterface({ input: process.stdin })\n const write = (o: unknown): void => void process.stdout.write(JSON.stringify(o) + \"\\n\")\n write({ ready: true, version: VERSION })\n for await (const line of rl) {\n const t = line.trim()\n if (!t) continue\n let req: { id?: number; cmd?: string; file?: string; out?: string; reflow?: boolean; reflowMode?: string; highlight?: string[] }\n // 비JSON 라인도 응답은 낸다 — 무음 삼킴이면 id 대기 클라이언트가 영구 행\n try { req = JSON.parse(t) } catch { write({ ok: false, error: \"잘못된 JSON 라인\" }); continue }\n if (req === null || typeof req !== \"object\") { write({ ok: false, error: \"JSON 객체가 아닙니다\" }); continue }\n if (req.cmd === \"quit\") { rl.close(); break }\n const id = req.id\n try {\n if (!req.file || !req.out) throw new Error(\"file·out 필수\")\n const buffer = readFileSync(resolve(req.file))\n const result = await renderHwpxToSvg(toArrayBuffer(buffer), {\n highlights: req.highlight, reflow: req.reflow, reflowMode: req.reflowMode as \"keep\" | \"charAll\" | undefined,\n })\n const outPath = resolve(req.out)\n mkdirSync(dirname(outPath), { recursive: true })\n writeFileSync(outPath, result.svg, \"utf-8\")\n write({ id, ok: true, out: outPath, width: result.width, height: result.height, pageCount: result.pageCount, stats: result.stats, warnings: result.warnings })\n } catch (err) {\n write({ id, ok: false, error: sanitizeError(err) })\n }\n }\n })\n\nprogram\n .command(\"mcp\")\n .description(\"MCP 서버 실행 (Claude / Cursor / Windsurf 연동)\")\n .action(async () => {\n await import(\"./mcp.js\")\n })\n\nprogram\n .command(\"setup\")\n .description(\"대화형 설치 마법사 — AI 클라이언트 자동 등록 (Mac/Win/Linux)\")\n .action(async () => {\n const { runSetup } = await import(\"./setup.js\")\n await runSetup()\n })\n\nprogram\n .command(\"check-formula-models\")\n .description(\"PDF 수식 OCR 모델(MFD + MFR + tokenizer, ~155MB) 상태 확인 — 없거나 SHA 불일치면 다운로드\")\n .option(\"--status-only\", \"상태만 JSON 으로 출력 (다운로드 안 함)\")\n .action(async (opts) => {\n try {\n const { getFormulaModelStatus, ensureFormulaModels, getFormulaModelsDir } = await import(\n \"./pdf/formula/index.js\"\n )\n const dir = getFormulaModelsDir()\n if (opts.statusOnly) {\n const status = await getFormulaModelStatus()\n process.stdout.write(\n JSON.stringify(\n {\n modelsDir: dir,\n allReady: status.every((s) => s.verified),\n models: status.map((s) => ({\n name: s.spec.name,\n filename: s.spec.filename,\n sizeMb: s.spec.sizeMb,\n exists: s.exists,\n verified: s.verified,\n invalidReason: s.invalidReason,\n path: s.localPath,\n })),\n },\n null,\n 2,\n ) + \"\\n\",\n )\n return\n }\n process.stderr.write(`[kordoc-formula] 캐시 디렉토리: ${dir}\\n`)\n await ensureFormulaModels((p) => {\n if (p.phase === \"download\" && p.total) {\n const pct = Math.floor((p.downloaded / p.total) * 100)\n process.stderr.write(\n `\\r[kordoc-formula] ${p.spec.name} ${pct}% (${(p.downloaded / 1024 / 1024).toFixed(1)}/${(p.total / 1024 / 1024).toFixed(1)}MB)`,\n )\n if (p.downloaded >= p.total) process.stderr.write(\"\\n\")\n } else if (p.phase === \"verify\") {\n process.stderr.write(`[kordoc-formula] ${p.spec.name} SHA-256 검증 중...\\n`)\n } else if (p.phase === \"done\") {\n process.stderr.write(`[kordoc-formula] ${p.spec.name} 준비 완료\\n`)\n } else if (p.phase === \"skip\") {\n process.stderr.write(`[kordoc-formula] ${p.spec.name} 이미 존재 (skip)\\n`)\n }\n })\n process.stdout.write(\"ok\\n\")\n } catch (err) {\n process.stderr.write(`[kordoc] 수식 모델 준비 실패: ${sanitizeError(err)}\\n`)\n process.exit(1)\n }\n })\n\nprogram.parse()\n"],"mappings":"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","names":["result","formInfo","detectFormat"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["/** kordoc CLI — 모두 파싱해버리겠다 */\r\n\r\nimport { readFileSync, writeFileSync, mkdirSync, statSync } from \"fs\"\r\nimport { basename, dirname, resolve, extname } from \"path\"\r\nimport { Command } from \"commander\"\r\nimport { parse, detectFormat, detectZipFormat, fillFormFields, extractFormFields, blocksToMarkdown, markdownToHwpx, fillHwpx, PRESET_ALIAS, unknownFontWarnings, lintGongmunText, gongmunLintWarnings } from \"./index.js\"\r\nimport type { ParseOptions } from \"./types.js\"\r\nimport { VERSION, toArrayBuffer, sanitizeError } from \"./utils.js\"\r\n\r\nconst program = new Command()\r\n\r\nprogram\r\n .name(\"kordoc\")\r\n .description(\"모두 파싱해버리겠다 — HWP, HWPX, PDF, XLSX, DOCX → Markdown\")\r\n .version(VERSION)\r\n .argument(\"<files...>\", \"변환할 파일 경로 (HWP, HWPX, PDF, XLSX, DOCX)\")\r\n .option(\"-o, --output <path>\", \"출력 파일 경로 (단일 파일 시)\")\r\n .option(\"-d, --out-dir <dir>\", \"출력 디렉토리 (다중 파일 시)\")\r\n .option(\"-p, --pages <range>\", \"페이지/섹션 범위 (예: 1-3, 1,3,5)\")\r\n .option(\"--format <type>\", \"출력 형식: markdown (기본) 또는 json\", \"markdown\")\r\n .option(\"--no-header-footer\", \"PDF 머리글/바닥글 자동 제거\")\r\n .option(\"--formula-ocr\", \"PDF 수식 OCR 활성화 (MFD+MFR ONNX, 첫 사용 시 모델 ~155MB 자동 다운로드)\")\r\n .option(\"--dedupe-headers\", \"HWP5 레이아웃 표 페이지 반복 러닝 헤더 중복 제거 (기본 off — 붙임별 재번호 오삭제 주의)\")\r\n .option(\"--inline-images\", \"이미지를 base64 data URI 로 마크다운에 인라인 (BMP→PNG 압축, HWP5 전용 — 인라인된 경우만 파일 미저장, 그 외 포맷은 저장 유지)\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (files: string[], opts) => {\r\n const validFormats = [\"markdown\", \"json\"]\r\n if (!validFormats.includes(opts.format)) {\r\n process.stderr.write(`[kordoc] 지원하지 않는 형식: ${opts.format} (markdown 또는 json)\\n`)\r\n process.exit(1)\r\n }\r\n for (let fi = 0; fi < files.length; fi++) {\r\n const filePath = files[fi]\r\n const absPath = resolve(filePath)\r\n const fileName = basename(absPath)\r\n const filePrefix = files.length > 1 ? `[${fi + 1}/${files.length}] ` : \"\"\r\n\r\n try {\r\n const fileSize = statSync(absPath).size\r\n if (fileSize > 500 * 1024 * 1024) {\r\n process.stderr.write(`\\n[kordoc] SKIP: ${fileName} — 파일이 너무 큽니다 (${(fileSize / 1024 / 1024).toFixed(1)}MB)\\n`)\r\n process.exitCode = 1\r\n continue\r\n }\r\n const buffer = readFileSync(absPath)\r\n const arrayBuffer = toArrayBuffer(buffer)\r\n const format = detectFormat(arrayBuffer)\r\n\r\n if (!opts.silent) {\r\n process.stderr.write(`[kordoc] ${filePrefix}${fileName} (${format}) ...`)\r\n }\r\n\r\n const parseOptions: ParseOptions = { filePath: absPath }\r\n if (opts.pages) parseOptions.pages = opts.pages as string\r\n if (opts.headerFooter === false) parseOptions.removeHeaderFooter = false\r\n if (opts.formulaOcr) parseOptions.formulaOcr = true\r\n if (opts.dedupeHeaders) parseOptions.dedupeRunningHeaders = true\r\n if (opts.inlineImages) parseOptions.inlineImages = true\r\n if (!opts.silent) {\r\n parseOptions.onProgress = (current: number, total: number) => {\r\n process.stderr.write(`\\r[kordoc] ${filePrefix}${fileName} (${format}) [${current}/${total}]`)\r\n }\r\n }\r\n const result = await parse(arrayBuffer, parseOptions)\r\n\r\n if (!result.success) {\r\n process.stderr.write(` FAIL\\n`)\r\n process.stderr.write(` → ${result.error}\\n`)\r\n process.exitCode = 1\r\n continue\r\n }\r\n\r\n if (!opts.silent) process.stderr.write(` OK\\n`)\r\n\r\n let markdown = result.markdown\r\n // 이미지 인라인은 HWP5 경로에서만 실제로 일어난다(parser.ts). 그 외 포맷(HWPX/DOCX 등)은\r\n // --inline-images 를 줘도 인라인되지 않으므로, 이미지 저장/경로접두사를 생략하면 참조가\r\n // 깨지고(dangling) 바이트가 유실된다 → 실제 인라인된 경우에만 생략한다.\r\n const imagesInlined = opts.inlineImages && result.fileType === \"hwp\"\r\n // --out-dir 시 이미지 참조 경로에 images/ 접두사 추가 (인라인 모드에선 이미지가 마크다운에 임베드되므로 건너뜀)\r\n // <img src> 는 병합/중첩 표 셀 경로(table/builder.ts) — 마크다운 문법과 함께 둘 다 바꿔야 참조가 안 깨진다\r\n if (opts.outDir && result.images?.length && !imagesInlined) {\r\n markdown = markdown\r\n .replace(/!\\[image\\]\\(image_/g, \"\r\n .replace(/(<img\\b[^>]*\\bsrc=\")image_/g, \"$1images/image_\")\r\n }\r\n const output = opts.format === \"json\"\r\n ? JSON.stringify(result, (_key, value) =>\r\n value instanceof Uint8Array ? Buffer.from(value).toString(\"base64\") : value\r\n , 2)\r\n : markdown\r\n\r\n // 이미지 저장 (--out-dir 또는 --output 시) — 실제 인라인된 경우(HWP5)에만 미저장, 그 외엔 저장 유지\r\n const saveImages = (dir: string) => {\r\n if (!result.images?.length || imagesInlined) return\r\n const imgDir = resolve(dir, \"images\")\r\n mkdirSync(imgDir, { recursive: true })\r\n for (const img of result.images) {\r\n writeFileSync(resolve(imgDir, img.filename), img.data)\r\n }\r\n if (!opts.silent) process.stderr.write(` → ${result.images.length}개 이미지 → ${imgDir}\\n`)\r\n }\r\n\r\n if (opts.output && files.length === 1) {\r\n writeFileSync(opts.output, output, \"utf-8\")\r\n if (!opts.silent) process.stderr.write(` → ${opts.output}\\n`)\r\n saveImages(resolve(opts.output, \"..\"))\r\n } else if (opts.outDir) {\r\n mkdirSync(opts.outDir, { recursive: true })\r\n const outExt = opts.format === \"json\" ? \".json\" : \".md\"\r\n const outPath = resolve(opts.outDir, fileName.replace(/\\.[^.]+$/, outExt))\r\n writeFileSync(outPath, output, \"utf-8\")\r\n if (!opts.silent) process.stderr.write(` → ${outPath}\\n`)\r\n saveImages(opts.outDir)\r\n } else {\r\n process.stdout.write(output + \"\\n\")\r\n }\r\n } catch (err) {\r\n process.stderr.write(`\\n[kordoc] ERROR: ${fileName} — ${sanitizeError(err)}\\n`)\r\n process.exitCode = 1\r\n }\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"watch <dir>\")\r\n .description(\"디렉토리 감시 — 새 문서 자동 변환\")\r\n .option(\"--webhook <url>\", \"결과 전송 웹훅 URL\")\r\n .option(\"-d, --out-dir <dir>\", \"변환 결과 출력 디렉토리\")\r\n .option(\"-p, --pages <range>\", \"페이지/섹션 범위\")\r\n .option(\"--format <type>\", \"출력 형식: markdown 또는 json\", \"markdown\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (dir: string, opts, command: Command) => {\r\n // 루트 커맨드의 동명 옵션(-d/--out-dir·-p/--pages·--format·--silent)이 서브커맨드 뒤에서도 루트로 흡수되는 commander 동작 보완\r\n const rootOpts = program.opts()\r\n opts.outDir ??= rootOpts.outDir\r\n opts.pages ??= rootOpts.pages\r\n opts.silent ??= rootOpts.silent\r\n if (command.getOptionValueSource(\"format\") === \"default\" && program.getOptionValueSource(\"format\") === \"cli\") {\r\n opts.format = rootOpts.format\r\n }\r\n const { watchDirectory } = await import(\"./watch.js\")\r\n await watchDirectory({\r\n dir,\r\n outDir: opts.outDir,\r\n webhook: opts.webhook,\r\n format: opts.format,\r\n pages: opts.pages,\r\n silent: opts.silent,\r\n })\r\n })\r\n\r\nprogram\r\n .command(\"fill <template>\")\r\n .description(\"서식 문서의 빈칸을 채워서 출력 — kordoc fill 신청서.hwpx -f '성명=홍길동,전화=010-1234-5678' -o 결과.hwpx\")\r\n .option(\"-f, --fields <pairs>\", \"채울 필드 (key=value 쉼표 구분 또는 JSON)\")\r\n .option(\"-j, --json <path>\", \"채울 필드 JSON 파일 경로\")\r\n .option(\"-o, --output <path>\", \"출력 파일 경로 (확장자로 포맷 결정: .md, .hwpx)\")\r\n .option(\"--format <type>\", \"출력 포맷: hwpx-preserve (기본, 원본 스타일 보존), hwpx, markdown\", \"hwpx-preserve\")\r\n .option(\"--dry-run\", \"채우지 않고 서식 필드 목록만 출력\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (template: string, opts, command: Command) => {\r\n try {\r\n // 루트 커맨드의 동명 옵션(-o/--output·--format·--silent)이 서브커맨드 뒤에서도 루트로 흡수되는 commander 동작 보완\r\n const rootOpts = program.opts()\r\n opts.output ??= rootOpts.output\r\n opts.silent ??= rootOpts.silent\r\n if (command.getOptionValueSource(\"format\") === \"default\" && program.getOptionValueSource(\"format\") === \"cli\") {\r\n opts.format = rootOpts.format\r\n }\r\n const absPath = resolve(template)\r\n const fileSize = statSync(absPath).size\r\n if (fileSize > 500 * 1024 * 1024) {\r\n process.stderr.write(`[kordoc] 파일이 너무 큽니다 (${(fileSize / 1024 / 1024).toFixed(1)}MB)\\n`)\r\n process.exit(1)\r\n }\r\n\r\n const buffer = readFileSync(absPath)\r\n const arrayBuffer = toArrayBuffer(buffer)\r\n\r\n if (!opts.silent) process.stderr.write(`[kordoc] ${basename(absPath)} 파싱 중...\\n`)\r\n\r\n // --dry-run: 필드 목록만 출력\r\n if (opts.dryRun) {\r\n const result = await parse(arrayBuffer)\r\n if (!result.success) {\r\n process.stderr.write(`[kordoc] 파싱 실패: ${result.error}\\n`)\r\n process.exit(1)\r\n }\r\n const formInfo = extractFormFields(result.blocks)\r\n if (formInfo.fields.length === 0) {\r\n process.stderr.write(`[kordoc] 서식 필드를 찾을 수 없습니다.\\n`)\r\n process.exit(1)\r\n }\r\n process.stdout.write(JSON.stringify(formInfo, null, 2) + \"\\n\")\r\n return\r\n }\r\n\r\n // 필드 값 파싱\r\n let values: Record<string, string> = {}\r\n if (opts.json) {\r\n const jsonPath = resolve(opts.json)\r\n const jsonContent = readFileSync(jsonPath, \"utf-8\")\r\n values = JSON.parse(jsonContent)\r\n } else if (opts.fields) {\r\n const fieldsStr: string = opts.fields\r\n if (fieldsStr.startsWith(\"{\")) {\r\n values = JSON.parse(fieldsStr)\r\n } else {\r\n // \"key1=value1,key2=value2\" 파싱 — 값에 쉼표가 있을 수 있으므로\r\n // '=' 앞의 키를 기준으로 분리 (쉼표+한글/영문+= 패턴)\r\n const pairs = fieldsStr.split(/,(?=[가-힣A-Za-z][가-힣A-Za-z\\s]*=)/)\r\n for (const pair of pairs) {\r\n const eqIdx = pair.indexOf(\"=\")\r\n if (eqIdx > 0) {\r\n const key = pair.slice(0, eqIdx).trim()\r\n const val = pair.slice(eqIdx + 1).trim()\r\n values[key] = val\r\n }\r\n }\r\n }\r\n } else {\r\n process.stderr.write(`[kordoc] 채울 필드를 지정해주세요 (-f 또는 -j 옵션)\\n`)\r\n process.exit(1)\r\n }\r\n\r\n // 출력 포맷 결정\r\n let outputFormat = opts.format as string\r\n if (opts.output) {\r\n const ext = extname(opts.output).toLowerCase()\r\n if (ext === \".hwpx\") outputFormat = outputFormat === \"markdown\" ? \"hwpx-preserve\" : outputFormat\r\n else if (ext === \".md\") outputFormat = \"markdown\"\r\n }\r\n\r\n // ─── hwpx-preserve: 원본 ZIP 직접 수정 ───\r\n if (outputFormat === \"hwpx-preserve\") {\r\n const format = detectFormat(arrayBuffer)\r\n let isHwpx = format === \"hwpx\"\r\n if (isHwpx) {\r\n const zipFormat = await detectZipFormat(arrayBuffer)\r\n isHwpx = zipFormat === \"hwpx\"\r\n }\r\n if (!isHwpx) {\r\n if (!opts.silent) process.stderr.write(`[kordoc] HWPX가 아니므로 hwpx 모드로 전환합니다\\n`)\r\n outputFormat = \"hwpx\"\r\n } else {\r\n const hwpxResult = await fillHwpx(arrayBuffer, values)\r\n if (!opts.silent) {\r\n process.stderr.write(`[kordoc] ${hwpxResult.filled.length}개 필드 채움 (원본 스타일 보존)\\n`)\r\n if (hwpxResult.unmatched.length > 0) {\r\n process.stderr.write(`[kordoc] ⚠️ 매칭 실패: ${hwpxResult.unmatched.join(\", \")}\\n`)\r\n }\r\n }\r\n if (opts.output) {\r\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\r\n writeFileSync(resolve(opts.output), Buffer.from(hwpxResult.buffer))\r\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\r\n } else {\r\n process.stdout.write(Buffer.from(hwpxResult.buffer))\r\n }\r\n return\r\n }\r\n }\r\n\r\n // ─── 일반 경로: parse → fill → output ───\r\n const result = await parse(arrayBuffer)\r\n if (!result.success) {\r\n process.stderr.write(`[kordoc] 파싱 실패: ${result.error}\\n`)\r\n process.exit(1)\r\n }\r\n\r\n const formInfo = extractFormFields(result.blocks)\r\n if (!opts.silent) {\r\n process.stderr.write(`[kordoc] 서식 필드 ${formInfo.fields.length}개 감지 (확신도 ${(formInfo.confidence * 100).toFixed(0)}%)\\n`)\r\n }\r\n\r\n const fillResult = fillFormFields(result.blocks, values)\r\n if (!opts.silent) {\r\n process.stderr.write(`[kordoc] ${fillResult.filled.length}개 필드 채움\\n`)\r\n if (fillResult.unmatched.length > 0) {\r\n process.stderr.write(`[kordoc] ⚠️ 매칭 실패: ${fillResult.unmatched.join(\", \")}\\n`)\r\n }\r\n }\r\n\r\n const markdown = blocksToMarkdown(fillResult.blocks)\r\n\r\n if (outputFormat === \"hwpx\") {\r\n const hwpxBuffer = await markdownToHwpx(markdown)\r\n if (opts.output) {\r\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\r\n writeFileSync(resolve(opts.output), Buffer.from(hwpxBuffer))\r\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\r\n } else {\r\n process.stdout.write(Buffer.from(hwpxBuffer))\r\n }\r\n } else {\r\n if (opts.output) {\r\n mkdirSync(dirname(resolve(opts.output)), { recursive: true })\r\n writeFileSync(resolve(opts.output), markdown, \"utf-8\")\r\n if (!opts.silent) process.stderr.write(`[kordoc] → ${resolve(opts.output)}\\n`)\r\n } else {\r\n process.stdout.write(markdown + \"\\n\")\r\n }\r\n }\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"seal <file>\")\r\n .description('도장/서명 이미지를 앵커 문구 위에 부유 배치 (표/페이지 불확장) — kordoc seal 신청서.hwpx --image 도장.png --anchor \"(인)\" -o 결과.hwpx')\r\n .requiredOption(\"--image <path>\", \"도장/서명 이미지 (투명 배경 PNG 권장)\")\r\n .option(\"--anchor <text>\", \"앵커 문구\", \"(인)\")\r\n .option(\"-n, --occurrence <num>\", \"같은 앵커가 여럿일 때 0-based 선택\", \"0\")\r\n .option(\"--size-mm <num>\", \"도장 한 변 크기 mm (기본: 줄높이×1.6, 7~18 클램프)\")\r\n .option(\"--mode <mode>\", \"overlap(문구 위 겹침) | right(오른쪽 옆) | auto\", \"auto\")\r\n .option(\"--dx <mm>\", \"x 미세조정 mm\", \"0\")\r\n .option(\"--dy <mm>\", \"y 미세조정 mm\", \"0\")\r\n .option(\"-o, --output <path>\", \"출력 경로 (기본: <입력>.sealed.hwpx)\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (file: string, opts) => {\r\n try {\r\n const { placeSealHwpx, detectFormat } = await import(\"./index.js\")\r\n const rootOpts = program.opts()\r\n const output: string | undefined = opts.output ?? rootOpts.output\r\n const silent: boolean = opts.silent ?? rootOpts.silent\r\n const mode = String(opts.mode).toLowerCase()\r\n if (![\"overlap\", \"right\", \"auto\"].includes(mode)) {\r\n process.stderr.write(`[kordoc] --mode 는 overlap/right/auto 중 하나여야 합니다\\n`)\r\n process.exit(1)\r\n }\r\n const buf = new Uint8Array(readFileSync(resolve(file)))\r\n if (detectFormat(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer) !== \"hwpx\") {\r\n process.stderr.write(`[kordoc] seal 은 HWPX 전용입니다 (HWP 5.x 바이너리는 미지원)\\n`)\r\n process.exit(1)\r\n }\r\n const imgPath = resolve(opts.image)\r\n const imgSize = statSync(imgPath).size\r\n if (imgSize > 500 * 1024 * 1024) {\r\n process.stderr.write(`[kordoc] 도장 이미지가 너무 큽니다 (${(imgSize / 1024 / 1024).toFixed(0)}MB)\\n`)\r\n process.exit(1)\r\n }\r\n const image = new Uint8Array(readFileSync(imgPath))\r\n const ext = extname(opts.image).slice(1).toLowerCase() || \"png\"\r\n // --size-mm 검증 — 비숫자·음수가 NaN/음수로 XML 속성에 그대로 기록되던 것 차단 (MCP zod 동등)\r\n let sizeMm: number | undefined\r\n if (opts.sizeMm != null) {\r\n const n = Number(opts.sizeMm)\r\n if (!Number.isFinite(n) || n <= 0) {\r\n process.stderr.write(`[kordoc] --size-mm 은 양수여야 합니다: ${opts.sizeMm}\\n`)\r\n process.exit(1)\r\n }\r\n sizeMm = n\r\n }\r\n const result = await placeSealHwpx(\r\n buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength) as ArrayBuffer,\r\n [{\r\n anchor: opts.anchor,\r\n occurrence: Number(opts.occurrence) || 0,\r\n image,\r\n ext: ext as \"png\" | \"jpg\" | \"jpeg\" | \"bmp\" | \"gif\",\r\n sizeMm,\r\n mode: mode as \"overlap\" | \"right\" | \"auto\",\r\n dxMm: Number(opts.dx) || 0,\r\n dyMm: Number(opts.dy) || 0,\r\n }],\r\n )\r\n const outPath = resolve(output ?? file.replace(/\\.hwpx$/i, \"\") + \".sealed.hwpx\")\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, Buffer.from(result.buffer))\r\n if (!silent) {\r\n for (const p of result.placed) {\r\n process.stderr.write(`[kordoc] 도장 배치: \"${p.anchor}\" #${p.occurrence} → ${p.mode} (${p.posXMm}mm, ${p.posYMm}mm, ${p.sizeMm}mm) [${p.entry}]\\n`)\r\n for (const w of p.warnings ?? []) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\r\n }\r\n process.stderr.write(`[kordoc] → ${outPath}\\n`)\r\n }\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"patch <original> <edited>\")\r\n .description(\"서식 보존 라운드트립 패치 — 편집된 마크다운을 원본 HWPX/HWP에 in-place 반영 (kordoc patch 원본.hwpx 편집.md -o 출력.hwpx)\")\r\n .option(\"-o, --output <path>\", \"출력 경로 (기본: <원본>.patched.hwpx|.hwp)\")\r\n .option(\"--no-verify\", \"패치 후 재파싱 자동 검증 생략\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (original: string, edited: string, opts) => {\r\n try {\r\n const { patchHwpx, patchHwp, detectFormat } = await import(\"./index.js\")\r\n // 루트 커맨드의 동명 옵션(-o/--silent)이 서브커맨드 옵션을 가로채는 commander 동작 보완\r\n const rootOpts = program.opts()\r\n const output: string | undefined = opts.output ?? rootOpts.output\r\n const silent: boolean = opts.silent ?? rootOpts.silent\r\n const originalBuf = new Uint8Array(readFileSync(resolve(original)))\r\n const editedMarkdown = readFileSync(resolve(edited), \"utf-8\")\r\n\r\n const format = detectFormat(originalBuf.buffer as ArrayBuffer)\r\n const result = format === \"hwp\"\r\n ? await patchHwp(originalBuf, editedMarkdown, { verify: opts.verify !== false })\r\n : await patchHwpx(originalBuf, editedMarkdown, { verify: opts.verify !== false })\r\n if (!result.success || !result.data) {\r\n process.stderr.write(`[kordoc] 패치 실패: ${result.error ?? \"알 수 없는 오류\"}\\n`)\r\n process.exit(1)\r\n }\r\n\r\n const ext = format === \"hwp\" ? \".hwp\" : \".hwpx\"\r\n const outPath = resolve(output ?? original.replace(/\\.hwpx?$/i, \"\") + \".patched\" + ext)\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, result.data)\r\n\r\n if (!silent) {\r\n process.stderr.write(`[kordoc] ${result.applied}개 변경 적용 (원본 서식 보존) → ${outPath}\\n`)\r\n for (const s of result.skipped) {\r\n process.stderr.write(`[kordoc] ⚠️ SKIP: ${s.reason}${s.before ? ` | ${s.before}` : \"\"}\\n`)\r\n }\r\n if (result.verification) {\r\n const v = result.verification.stats\r\n const residual = v.added + v.removed + v.modified\r\n process.stderr.write(residual === 0\r\n ? `[kordoc] ✓ 검증: 편집 마크다운과 재파싱 결과 완전 일치 (${v.unchanged}블록)\\n`\r\n : `[kordoc] ⚠️ 검증 잔차: 수정 ${v.modified}, 추가 ${v.added}, 삭제 ${v.removed} (미지원 변경은 skip 목록 참조)\\n`)\r\n }\r\n }\r\n if (result.skipped.length > 0) process.exitCode = 2\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"validate <file>\")\r\n .description(\"HWPX 구조 검증 — ZIP·mimetype·필수 파일·XML 웰폼드·secCnt·manifest 참조 (한컴독스 거부 요인 사전 차단)\")\r\n .option(\"--json\", \"결과를 JSON으로 stdout에 출력\")\r\n .action(async (file: string, opts) => {\r\n try {\r\n const { validateHwpx } = await import(\"./index.js\")\r\n const buf = new Uint8Array(readFileSync(resolve(file)))\r\n const result = await validateHwpx(buf)\r\n if (opts.json) {\r\n process.stdout.write(JSON.stringify(result, null, 2) + \"\\n\")\r\n } else if (result.ok) {\r\n process.stderr.write(`[kordoc] ✓ 구조 검증 통과 (엔트리 ${result.entryCount}개): ${file}\\n`)\r\n } else {\r\n process.stderr.write(`[kordoc] ✗ 구조 문제 ${result.issues.length}건: ${file}\\n`)\r\n for (const i of result.issues) {\r\n process.stderr.write(`[kordoc] - ${i.path ? `${i.path}: ` : \"\"}${i.message}\\n`)\r\n }\r\n }\r\n if (!result.ok) process.exit(1)\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\n// 공문서 프리셋 별칭(한글/영문) → 내부 preset 키 — gongmun.ts와 공용(PRESET_ALIAS)\r\n\r\nprogram\r\n .command(\"generate <markdown>\")\r\n .alias(\"gen\")\r\n .description(\"마크다운 → 공문서 HWPX 생성 — kordoc generate 보고서.md -o 보고서.hwpx --preset 보고서 (markdown에 '-' 지정 시 stdin)\")\r\n .option(\"-o, --output <path>\", \"출력 HWPX 경로 (기본: <입력>.hwpx)\")\r\n .option(\"--preset <name>\", \"공문서 프리셋: 기안문(official)·보고서(report)·계획서(plan)·통지(notice)·회의록(minutes)·개조식(gaejosik — 표지·목차·장헤더 자동)\", \"기안문\")\r\n .option(\"--font <type>\", \"본문 글꼴: myeongjo(함초롬바탕) 또는 gothic(맑은 고딕)\")\r\n .option(\"--pt <size>\", \"본문 글자 크기(pt)\")\r\n .option(\"--line-spacing <percent>\", \"본문 줄간격(%)\")\r\n .option(\"--org <name>\", \"표지 기관명 (개조식 프리셋)\")\r\n .option(\"--date <date>\", \"표지 날짜 (개조식 프리셋, 기본 오늘 — 'YYYY. M. D.')\")\r\n .option(\"--toc\", \"목차 페이지 강제 켜기 (개조식 외 프리셋에서도 h2 목록으로 생성)\")\r\n .option(\"--no-toc\", \"목차 페이지 끄기 (개조식 프리셋 기본 켜짐)\")\r\n .option(\"--cover\", \"표지 페이지 강제 켜기 (개조식 외 프리셋에서도 첫 h1을 표지로)\")\r\n .option(\"--no-cover\", \"표지 페이지 끄기 (개조식 프리셋 기본 켜짐)\")\r\n .option(\"--approval <labels>\", \"결재란 직위 라벨 (쉼표 구분, 예: 담당,팀장,과장) — 문서 최상단 우측\")\r\n .option(\"--page-numbers\", \"쪽번호 강제 켜기 (하단 중앙 '- 1 -')\")\r\n .option(\"--no-page-numbers\", \"쪽번호 끄기 (개조식·보고서·계획서 기본 켜짐)\")\r\n .option(\"--end-mark\", \"본문 끝 '끝.' 표시 강제 켜기\")\r\n .option(\"--no-end-mark\", \"'끝.' 표시 끄기 (기안문 기본 켜짐)\")\r\n .option(\"--no-body-title-box\", \"본문 첫 페이지 제목 반복 박스 끄기 (개조식+표지 기본 켜짐)\")\r\n .option(\"--h2-marker <type>\", \"h2 섹션 제목 말머리: box(□ — 보고서·계획서 기본)·number(1. — 공고문 관행)·none\")\r\n .option(\"--fonts <spec>\", \"요소별 글꼴 오버라이드: body=나눔명조,heading=나눔고딕,ref=한양중고딕,table=맑은 고딕\")\r\n .option(\"--sizes <spec>\", \"개조식 요소별 크기(pt): dae=16,cham=13,table=12,coverTitle=30 …\")\r\n .option(\"--plain\", \"공문서 모드 끄기 (범용 마크다운 변환)\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (markdown: string, opts) => {\r\n try {\r\n const rootOpts = program.opts()\r\n const output: string | undefined = opts.output ?? rootOpts.output\r\n const silent: boolean = opts.silent ?? rootOpts.silent\r\n\r\n // 입력: '-' 이면 stdin, 아니면 파일\r\n let md: string\r\n let baseName = \"document\"\r\n if (markdown === \"-\") {\r\n md = readFileSync(0, \"utf-8\")\r\n } else {\r\n const inPath = resolve(markdown)\r\n md = readFileSync(inPath, \"utf-8\")\r\n baseName = basename(inPath).replace(/\\.(md|markdown|txt)$/i, \"\")\r\n }\r\n\r\n // 공문서 옵션 구성\r\n let gongmun: import(\"./index.js\").GongmunOptions | undefined\r\n if (!opts.plain) {\r\n const preset = PRESET_ALIAS[String(opts.preset).trim()]\r\n if (!preset) {\r\n process.stderr.write(`[kordoc] 알 수 없는 프리셋: ${opts.preset} (기안문/보고서/계획서/통지/회의록/개조식)\\n`)\r\n process.exit(1)\r\n }\r\n gongmun = { preset }\r\n // 표지: --no-cover가 최우선, org/date 지정 시 객체(=켜짐), --cover는 강제 켜기.\r\n // 미지정이면 프리셋 기본(개조식만 켜짐 — resolveGongmun)\r\n if (opts.cover === false) {\r\n gongmun.cover = false\r\n } else if (opts.org || opts.date) {\r\n gongmun.cover = { ...(opts.org ? { org: opts.org } : {}), ...(opts.date ? { date: opts.date } : {}) }\r\n } else if (opts.cover === true) {\r\n gongmun.cover = true\r\n }\r\n // 목차: --toc/--no-toc 명시 시에만 전달 (미지정이면 프리셋 기본)\r\n if (opts.toc !== undefined) gongmun.toc = opts.toc\r\n if (opts.approval) gongmun.approval = String(opts.approval).split(\",\").map((s: string) => s.trim()).filter(Boolean)\r\n if (opts.pageNumbers !== undefined) gongmun.pageNumbers = opts.pageNumbers\r\n if (opts.endMark !== undefined) gongmun.endMark = opts.endMark\r\n if (opts.bodyTitleBox === false) gongmun.bodyTitleBox = false\r\n if (opts.h2Marker) {\r\n if (![\"box\", \"number\", \"none\"].includes(opts.h2Marker)) {\r\n process.stderr.write(`[kordoc] --h2-marker 는 box/number/none\\n`)\r\n process.exit(1)\r\n }\r\n gongmun.h2Marker = opts.h2Marker\r\n }\r\n if (opts.font) {\r\n if (opts.font !== \"myeongjo\" && opts.font !== \"gothic\") {\r\n process.stderr.write(`[kordoc] --font 은 myeongjo 또는 gothic\\n`)\r\n process.exit(1)\r\n }\r\n gongmun.bodyFont = opts.font\r\n }\r\n if (opts.pt) gongmun.bodyPt = Number(opts.pt)\r\n if (opts.lineSpacing) gongmun.lineSpacing = Number(opts.lineSpacing)\r\n // \"key=value,key=value\" 스펙 파싱 — 값에 쉼표가 없는 폰트명·숫자만 지원\r\n const parseKv = (spec: string): Record<string, string> =>\r\n Object.fromEntries(spec.split(\",\").map((p) => p.split(\"=\").map((s) => s.trim())).filter((kv) => kv.length === 2 && kv[0] && kv[1]))\r\n if (opts.fonts) gongmun.fonts = parseKv(String(opts.fonts))\r\n if (opts.sizes) {\r\n gongmun.sizes = Object.fromEntries(\r\n Object.entries(parseKv(String(opts.sizes))).map(([k, v]) => [k, Number(v)]).filter(([, v]) => Number.isFinite(v as number)),\r\n )\r\n }\r\n }\r\n\r\n // 폰트 오버라이드 오타·미설치 경고 (A2) — 생성은 진행\r\n if (gongmun?.fonts && !silent) {\r\n for (const w of unknownFontWarnings(gongmun.fonts)) process.stderr.write(`[kordoc] ${w}\\n`)\r\n }\r\n // 공문서 표기법 검수 (편람 기준, 조언용) — 생성은 진행, stderr 경고만\r\n if (gongmun && !silent) {\r\n for (const w of gongmunLintWarnings(md, 5)) process.stderr.write(`[kordoc] ⚠ ${w}\\n`)\r\n }\r\n\r\n const buf = await markdownToHwpx(md, gongmun ? { gongmun } : undefined)\r\n const outPath = resolve(output ?? (markdown === \"-\" ? `${baseName}.hwpx` : markdown.replace(/\\.(md|markdown|txt)$/i, \"\") + \".hwpx\"))\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, Buffer.from(buf))\r\n\r\n if (!silent) {\r\n const mode = gongmun ? `공문서:${gongmun.preset}` : \"범용\"\r\n process.stderr.write(`[kordoc] HWPX 생성 (${mode}) → ${outPath}\\n`)\r\n }\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"lint <file>\")\r\n .description(\"공문서 표기법 검수 — 날짜·시간·금액·붙임 등 행정업무운영 편람 표기법 (md/txt, '-'=stdin). error 있으면 exit 1\")\r\n .option(\"--json\", \"JSON 출력\")\r\n .action((file: string, opts) => {\r\n try {\r\n const text = file === \"-\" ? readFileSync(0, \"utf-8\") : readFileSync(resolve(file), \"utf-8\")\r\n const findings = lintGongmunText(text)\r\n const errors = findings.filter((f) => f.severity === \"error\").length\r\n if (opts.json) {\r\n process.stdout.write(JSON.stringify({ findings, summary: { total: findings.length, errors, ok: errors === 0 } }, null, 2) + \"\\n\")\r\n } else {\r\n process.stdout.write(`[kordoc] 표기법 검수: 위반 ${findings.length}건 (error ${errors}, warning ${findings.length - errors})\\n`)\r\n for (const f of findings) {\r\n process.stdout.write(` L${f.line} [${f.severity}] ${f.rule}: \"${f.match}\" — ${f.message}${f.suggest ? ` → ${f.suggest}` : \"\"}\\n`)\r\n }\r\n }\r\n process.exit(errors > 0 ? 1 : 0)\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"render <file>\")\r\n .description(\"레이아웃 보존 렌더 — 한컴 저장 HWPX의 조판 캐시를 SVG로 (전체 페이지 세로 스택) — kordoc render 문서.hwpx -o 문서.svg\")\r\n .option(\"-o, --output <path>\", \"출력 SVG 경로 (기본: <입력>.svg)\")\r\n .option(\"--highlight <terms>\", \"검색어 형광펜 (쉼표 구분)\")\r\n .option(\"--reflow\", \"조판 캐시 없는 HWPX도 순수 TS 조판으로 렌더 (markdownToHwpx 산출물·편집본)\")\r\n .option(\"--reflow-mode <mode>\", \"reflow 줄바꿈 모드: keep(어절) | charAll(글자)\", \"keep\")\r\n .option(\"--silent\", \"진행 메시지 숨기기\")\r\n .action(async (file: string, opts) => {\r\n try {\r\n const rootOpts = program.opts()\r\n const output: string | undefined = opts.output ?? rootOpts.output\r\n const silent: boolean = opts.silent ?? rootOpts.silent\r\n const { renderHwpxToSvg } = await import(\"./render/index.js\")\r\n const absPath = resolve(file)\r\n const buffer = readFileSync(absPath)\r\n const highlights = opts.highlight ? String(opts.highlight).split(\",\") : undefined\r\n const result = await renderHwpxToSvg(toArrayBuffer(buffer), { highlights, reflow: opts.reflow, reflowMode: opts.reflowMode })\r\n const outPath = resolve(output ?? file.replace(/\\.hwpx$/i, \"\") + \".svg\")\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, result.svg, \"utf-8\")\r\n if (!silent) {\r\n process.stderr.write(`[kordoc] 렌더 (${result.pageCount}페이지, ${result.width}x${result.height}pt, 텍스트 ${result.stats.texts}·이미지 ${result.stats.images}·표 ${result.stats.tables}) → ${outPath}\\n`)\r\n for (const w of result.warnings) process.stderr.write(`[kordoc] ⚠️ ${w}\\n`)\r\n }\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 오류: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"render-worker\")\r\n .description(\"persistent 렌더 워커 — stdin NDJSON 요청 → 조판 SVG 파일 출력 (프로세스 유지, 콜드스타트 제거)\")\r\n .action(async () => {\r\n // 프로토콜(NDJSON, 한 줄=한 요청/응답):\r\n // 요청 {\"id\":1,\"file\":\"a.hwpx\",\"out\":\"a.svg\",\"reflow\":true,\"highlight\":[\"term\"]}\r\n // 응답 {\"id\":1,\"ok\":true,\"out\":\"a.svg\",\"width\":..,\"height\":..,\"pageCount\":..,\"stats\":{..},\"warnings\":[..]}\r\n // {\"cmd\":\"quit\"} 로 종료. 모듈은 최초 1회만 로드 → 이후 요청은 콜드스타트 없음.\r\n const { createInterface } = await import(\"node:readline\")\r\n const { renderHwpxToSvg } = await import(\"./render/index.js\")\r\n const rl = createInterface({ input: process.stdin })\r\n const write = (o: unknown): void => void process.stdout.write(JSON.stringify(o) + \"\\n\")\r\n write({ ready: true, version: VERSION })\r\n for await (const line of rl) {\r\n const t = line.trim()\r\n if (!t) continue\r\n let req: { id?: number; cmd?: string; file?: string; out?: string; reflow?: boolean; reflowMode?: string; highlight?: string[] }\r\n // 비JSON 라인도 응답은 낸다 — 무음 삼킴이면 id 대기 클라이언트가 영구 행\r\n try { req = JSON.parse(t) } catch { write({ ok: false, error: \"잘못된 JSON 라인\" }); continue }\r\n if (req === null || typeof req !== \"object\") { write({ ok: false, error: \"JSON 객체가 아닙니다\" }); continue }\r\n if (req.cmd === \"quit\") { rl.close(); break }\r\n const id = req.id\r\n try {\r\n if (!req.file || !req.out) throw new Error(\"file·out 필수\")\r\n const buffer = readFileSync(resolve(req.file))\r\n const result = await renderHwpxToSvg(toArrayBuffer(buffer), {\r\n highlights: req.highlight, reflow: req.reflow, reflowMode: req.reflowMode as \"keep\" | \"charAll\" | undefined,\r\n })\r\n const outPath = resolve(req.out)\r\n mkdirSync(dirname(outPath), { recursive: true })\r\n writeFileSync(outPath, result.svg, \"utf-8\")\r\n write({ id, ok: true, out: outPath, width: result.width, height: result.height, pageCount: result.pageCount, stats: result.stats, warnings: result.warnings })\r\n } catch (err) {\r\n write({ id, ok: false, error: sanitizeError(err) })\r\n }\r\n }\r\n })\r\n\r\nprogram\r\n .command(\"mcp\")\r\n .description(\"MCP 서버 실행 (Claude / Cursor / Windsurf 연동)\")\r\n .action(async () => {\r\n await import(\"./mcp.js\")\r\n })\r\n\r\nprogram\r\n .command(\"setup\")\r\n .description(\"대화형 설치 마법사 — AI 클라이언트 자동 등록 (Mac/Win/Linux)\")\r\n .action(async () => {\r\n const { runSetup } = await import(\"./setup.js\")\r\n await runSetup()\r\n })\r\n\r\nprogram\r\n .command(\"check-formula-models\")\r\n .description(\"PDF 수식 OCR 모델(MFD + MFR + tokenizer, ~155MB) 상태 확인 — 없거나 SHA 불일치면 다운로드\")\r\n .option(\"--status-only\", \"상태만 JSON 으로 출력 (다운로드 안 함)\")\r\n .action(async (opts) => {\r\n try {\r\n const { getFormulaModelStatus, ensureFormulaModels, getFormulaModelsDir } = await import(\r\n \"./pdf/formula/index.js\"\r\n )\r\n const dir = getFormulaModelsDir()\r\n if (opts.statusOnly) {\r\n const status = await getFormulaModelStatus()\r\n process.stdout.write(\r\n JSON.stringify(\r\n {\r\n modelsDir: dir,\r\n allReady: status.every((s) => s.verified),\r\n models: status.map((s) => ({\r\n name: s.spec.name,\r\n filename: s.spec.filename,\r\n sizeMb: s.spec.sizeMb,\r\n exists: s.exists,\r\n verified: s.verified,\r\n invalidReason: s.invalidReason,\r\n path: s.localPath,\r\n })),\r\n },\r\n null,\r\n 2,\r\n ) + \"\\n\",\r\n )\r\n return\r\n }\r\n process.stderr.write(`[kordoc-formula] 캐시 디렉토리: ${dir}\\n`)\r\n await ensureFormulaModels((p) => {\r\n if (p.phase === \"download\" && p.total) {\r\n const pct = Math.floor((p.downloaded / p.total) * 100)\r\n process.stderr.write(\r\n `\\r[kordoc-formula] ${p.spec.name} ${pct}% (${(p.downloaded / 1024 / 1024).toFixed(1)}/${(p.total / 1024 / 1024).toFixed(1)}MB)`,\r\n )\r\n if (p.downloaded >= p.total) process.stderr.write(\"\\n\")\r\n } else if (p.phase === \"verify\") {\r\n process.stderr.write(`[kordoc-formula] ${p.spec.name} SHA-256 검증 중...\\n`)\r\n } else if (p.phase === \"done\") {\r\n process.stderr.write(`[kordoc-formula] ${p.spec.name} 준비 완료\\n`)\r\n } else if (p.phase === \"skip\") {\r\n process.stderr.write(`[kordoc-formula] ${p.spec.name} 이미 존재 (skip)\\n`)\r\n }\r\n })\r\n process.stdout.write(\"ok\\n\")\r\n } catch (err) {\r\n process.stderr.write(`[kordoc] 수식 모델 준비 실패: ${sanitizeError(err)}\\n`)\r\n process.exit(1)\r\n }\r\n })\r\n\r\nprogram.parse()\r\n"],"mappings":"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","names":["result","formInfo","detectFormat"]}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
isOldHwpFile,
|
|
10
10
|
isPdfFile,
|
|
11
11
|
isZipFile
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-5CJGKKMZ.js";
|
|
13
13
|
export {
|
|
14
14
|
detectFormat,
|
|
15
15
|
detectOle2Format,
|
|
@@ -21,4 +21,4 @@ export {
|
|
|
21
21
|
isPdfFile,
|
|
22
22
|
isZipFile
|
|
23
23
|
};
|
|
24
|
-
//# sourceMappingURL=detect-
|
|
24
|
+
//# sourceMappingURL=detect-PJZMUL2Z.js.map
|