kordoc 4.0.0 → 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.
Files changed (44) hide show
  1. package/dist/{-URVKBXYK.js → -O3AWNVPH.js} +11 -7
  2. package/dist/{chunk-7ETIIYGI.js → chunk-33OUI7HC.js} +2 -2
  3. package/dist/{chunk-IA5UZZKV.js → chunk-3H3CVOZ3.js} +2 -2
  4. package/dist/{chunk-JUJEKFUF.js → chunk-C5ABJ7PB.js} +3 -3
  5. package/dist/{chunk-ZKG6SBHV.js → chunk-EH2KYFFO.js} +2 -2
  6. package/dist/{chunk-THZVBYHE.js → chunk-JMLK6NTW.js} +3 -3
  7. package/dist/{chunk-EBSCV3JC.cjs → chunk-NIZXIVEI.cjs} +2 -2
  8. package/dist/{chunk-EBSCV3JC.cjs.map → chunk-NIZXIVEI.cjs.map} +1 -1
  9. package/dist/{chunk-PGWAF755.js → chunk-SHVV3BD6.js} +200 -40
  10. package/dist/chunk-SHVV3BD6.js.map +1 -0
  11. package/dist/{chunk-DVUNWK6W.js → chunk-YEC7VG6O.js} +2 -2
  12. package/dist/cli.js +49 -13
  13. package/dist/cli.js.map +1 -1
  14. package/dist/index.cjs +446 -286
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +38 -4
  17. package/dist/index.d.ts +38 -4
  18. package/dist/index.js +195 -35
  19. package/dist/index.js.map +1 -1
  20. package/dist/mcp.js +17 -13
  21. package/dist/mcp.js.map +1 -1
  22. package/dist/{parser-6TV6JKHF.cjs → parser-44OPXZMP.cjs} +14 -14
  23. package/dist/{parser-6TV6JKHF.cjs.map → parser-44OPXZMP.cjs.map} +1 -1
  24. package/dist/{parser-NXHY37WH.js → parser-G433UZMX.js} +2 -2
  25. package/dist/{parser-LHUO6UUA.js → parser-ZOMDHCA7.js} +3 -3
  26. package/dist/render-SQVQBORJ.js +10 -0
  27. package/dist/seal-6E26L45Z.js +10 -0
  28. package/dist/{watch-PNXTAWDR.js → watch-UYT3ZCBM.js} +7 -7
  29. package/package.json +1 -1
  30. package/dist/chunk-PGWAF755.js.map +0 -1
  31. package/dist/render-T5O6QHBJ.js +0 -10
  32. package/dist/seal-7KNR5WFH.js +0 -10
  33. /package/dist/{-URVKBXYK.js.map → -O3AWNVPH.js.map} +0 -0
  34. /package/dist/{chunk-7ETIIYGI.js.map → chunk-33OUI7HC.js.map} +0 -0
  35. /package/dist/{chunk-IA5UZZKV.js.map → chunk-3H3CVOZ3.js.map} +0 -0
  36. /package/dist/{chunk-JUJEKFUF.js.map → chunk-C5ABJ7PB.js.map} +0 -0
  37. /package/dist/{chunk-ZKG6SBHV.js.map → chunk-EH2KYFFO.js.map} +0 -0
  38. /package/dist/{chunk-THZVBYHE.js.map → chunk-JMLK6NTW.js.map} +0 -0
  39. /package/dist/{chunk-DVUNWK6W.js.map → chunk-YEC7VG6O.js.map} +0 -0
  40. /package/dist/{parser-NXHY37WH.js.map → parser-G433UZMX.js.map} +0 -0
  41. /package/dist/{parser-LHUO6UUA.js.map → parser-ZOMDHCA7.js.map} +0 -0
  42. /package/dist/{render-T5O6QHBJ.js.map → render-SQVQBORJ.js.map} +0 -0
  43. /package/dist/{seal-7KNR5WFH.js.map → seal-6E26L45Z.js.map} +0 -0
  44. /package/dist/{watch-PNXTAWDR.js.map → watch-UYT3ZCBM.js.map} +0 -0
@@ -11,7 +11,7 @@ import {
11
11
  dedupeRunningHeaders,
12
12
  flattenLayoutTables,
13
13
  mapPuaText
14
- } from "./chunk-7ETIIYGI.js";
14
+ } from "./chunk-33OUI7HC.js";
15
15
  import {
16
16
  detectFormat,
17
17
  detectOle2Format,
@@ -32,14 +32,14 @@ import {
32
32
  paraTextPureT,
33
33
  patchZipEntries,
34
34
  scanSectionXml
35
- } from "./chunk-THZVBYHE.js";
35
+ } from "./chunk-JMLK6NTW.js";
36
36
  import {
37
37
  SPACE_EM_FIXED,
38
38
  charWidthEm1000,
39
39
  fitRatioForFewerLines,
40
40
  measureTextWidth,
41
41
  simulateWrap
42
- } from "./chunk-JUJEKFUF.js";
42
+ } from "./chunk-C5ABJ7PB.js";
43
43
  import {
44
44
  MAX_DECOMPRESS_SIZE,
45
45
  MAX_XML_DEPTH,
@@ -50,7 +50,7 @@ import {
50
50
  createXmlParser,
51
51
  extractTextFromNode,
52
52
  findChildByLocalName
53
- } from "./chunk-DVUNWK6W.js";
53
+ } from "./chunk-YEC7VG6O.js";
54
54
  import {
55
55
  KordocError,
56
56
  classifyError,
@@ -61,7 +61,7 @@ import {
61
61
  sanitizeHref,
62
62
  stripDtd,
63
63
  toArrayBuffer
64
- } from "./chunk-ZKG6SBHV.js";
64
+ } from "./chunk-EH2KYFFO.js";
65
65
 
66
66
  // src/index.ts
67
67
  import { readFile } from "fs/promises";
@@ -19746,7 +19746,7 @@ async function fillHwpx(hwpxBuffer, values, blockedLabels) {
19746
19746
  import JSZip6 from "jszip";
19747
19747
 
19748
19748
  // src/hwpx/gaejosik.ts
19749
- var GAEJOSIK_BULLETS = ["\u25A1", "\u25CB", "\u2015", "\u318D"];
19749
+ var GAEJOSIK_BULLETS = ["\u25A1", "\u25CB", "-", "\u318D"];
19750
19750
  function gaejosikMarker(depth) {
19751
19751
  return GAEJOSIK_BULLETS[Math.min(depth, GAEJOSIK_BULLETS.length - 1)];
19752
19752
  }
@@ -19893,6 +19893,9 @@ function normalizeGongmunPreset(preset) {
19893
19893
  if (!preset) return "official";
19894
19894
  return PRESET_ALIAS[preset.trim()] ?? "official";
19895
19895
  }
19896
+ function usesReportFonts(preset) {
19897
+ return preset === "gaejosik" || preset === "report" || preset === "plan";
19898
+ }
19896
19899
  function resolveGongmun(opts) {
19897
19900
  const preset = normalizeGongmunPreset(opts.preset);
19898
19901
  const d = PRESET_DEFAULTS[preset];
@@ -19921,7 +19924,9 @@ function resolveGongmun(opts) {
19921
19924
  endMark: opts.endMark ?? preset === "official",
19922
19925
  approval: opts.approval && opts.approval.length > 0 ? opts.approval : null,
19923
19926
  // 본문 제목박스 — 실측(GT3·GT12): 목차 뒤 본문 시작에 제목 반복. 표지 켜진 개조식 기본
19924
- bodyTitleBox: opts.bodyTitleBox ?? (gaejosik && coverOn)
19927
+ bodyTitleBox: opts.bodyTitleBox ?? (gaejosik && coverOn),
19928
+ // h2 말머리 — 실측 보고서 양식(부처별 3종)의 섹션 제목이 곧 □ 대항목 (QA-2)
19929
+ h2Marker: opts.h2Marker ?? (preset === "report" || preset === "plan" ? "box" : "none")
19925
19930
  };
19926
19931
  }
19927
19932
  var HANGUL_INITIALS = [0, 2, 3, 5, 6, 7, 9, 11, 12, 14, 15, 16, 17, 18];
@@ -20066,10 +20071,10 @@ function headingCharPrId(level) {
20066
20071
  if (level === 3) return CHAR_H3;
20067
20072
  return CHAR_H4;
20068
20073
  }
20069
- function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_COLOR, ratioPct = 100, keepFontOnBold = false) {
20074
+ function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_COLOR, ratioPct = 100) {
20070
20075
  const boldAttr = bold ? ` bold="1"` : "";
20071
20076
  const italicAttr = italic ? ` italic="1"` : "";
20072
- const effFont = bold && !keepFontOnBold ? 2 : fontId;
20077
+ const effFont = fontId;
20073
20078
  const boldEl = bold ? `<hh:bold/>` : "";
20074
20079
  return ` <hh:charPr id="${id}" height="${height}" textColor="${textColor}" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="1"${boldAttr}${italicAttr}>
20075
20080
  <hh:fontRef hangul="${effFont}" latin="${effFont}" hanja="${effFont}" japanese="${effFont}" other="${effFont}" symbol="${effFont}" user="${effFont}"/>
@@ -20160,8 +20165,8 @@ function pageHidingCtrl(hideHeader = false) {
20160
20165
  return `<hp:ctrl><hp:pageHiding hideHeader="${hideHeader ? 1 : 0}" hideFooter="0" hideMasterPage="0" hideBorder="0" hideFill="0" hidePageNum="1"/></hp:ctrl>`;
20161
20166
  }
20162
20167
  var CHAR_VARIANT_BASE = 11;
20163
- function charVariantBase(gaejosik) {
20164
- return gaejosik ? CHAR_VARIANT_BASE + GJ_CHAR_COUNT : CHAR_VARIANT_BASE;
20168
+ function charVariantBase(measured) {
20169
+ return measured ? CHAR_VARIANT_BASE + GJ_CHAR_COUNT : CHAR_VARIANT_BASE;
20165
20170
  }
20166
20171
  var GONGMUN_BODY_RATIO = 95;
20167
20172
 
@@ -20409,7 +20414,7 @@ function generateManifest(chartParts = []) {
20409
20414
  </opf:package>`;
20410
20415
  }
20411
20416
  function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls = []) {
20412
- const gaejosik = gongmun?.preset === "gaejosik";
20417
+ const measured = !!gongmun && usesReportFonts(gongmun.preset);
20413
20418
  let body = 1e3, code = 900, h1 = 1800, h2 = 1400, h3 = 1200, h4 = 1100;
20414
20419
  if (gongmun) {
20415
20420
  body = gongmun.bodyHeight;
@@ -20419,7 +20424,9 @@ function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls
20419
20424
  h3 = body;
20420
20425
  h4 = Math.max(body - 100, 1300);
20421
20426
  }
20422
- const bodyFont = gaejosik ? 4 : 0;
20427
+ const bodyFont = measured ? 4 : 0;
20428
+ const hFont = measured ? 3 : 1;
20429
+ const hBold = !measured;
20423
20430
  const bodyRatio = gongmun ? GONGMUN_BODY_RATIO : 100;
20424
20431
  const rows = [
20425
20432
  charPr(0, body, false, false, bodyFont, theme.body, bodyRatio),
@@ -20427,25 +20434,25 @@ function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls
20427
20434
  charPr(2, body, false, true, bodyFont, theme.body, bodyRatio),
20428
20435
  charPr(3, body, true, true, bodyFont, theme.body, bodyRatio),
20429
20436
  charPr(4, code, false, false, 1),
20430
- charPr(5, h1, true, false, 1, theme.h1),
20431
- charPr(6, h2, true, false, 1, theme.h2),
20432
- charPr(7, h3, true, false, 1, theme.h3),
20433
- charPr(8, h4, true, false, 1, theme.h4),
20437
+ charPr(5, h1, hBold, false, hFont, theme.h1),
20438
+ charPr(6, h2, hBold, false, hFont, theme.h2),
20439
+ charPr(7, h3, hBold, false, hFont, theme.h3),
20440
+ charPr(8, h4, hBold, false, hFont, theme.h4),
20434
20441
  charPr(CHAR_TABLE_HEADER, body, theme.tableHeaderBold, false, bodyFont, theme.tableHeader),
20435
20442
  charPr(CHAR_QUOTE, body, false, true, bodyFont, theme.quote)
20436
20443
  ];
20437
- if (gaejosik) {
20444
+ if (measured) {
20438
20445
  const sz = gaejosikSizes(body, gongmun.sizes);
20439
20446
  rows.push(
20440
20447
  charPr(11, sz.dae, false, false, 3),
20441
20448
  // □ HY헤드라인M
20442
- charPr(12, sz.dae, true, false, 3, "#000000", 100, true),
20449
+ charPr(12, sz.dae, true, false, 3),
20443
20450
  // □ bold
20444
20451
  charPr(13, sz.cham, false, false, 5),
20445
20452
  // ※ 한양중고딕
20446
- charPr(14, sz.cham, true, false, 5, "#000000", 100, true),
20453
+ charPr(14, sz.cham, true, false, 5),
20447
20454
  // ※ bold
20448
- charPr(15, sz.chapter, true, false, 4, "#FFFFFF", 100, true),
20455
+ charPr(15, sz.chapter, true, false, 4, "#FFFFFF"),
20449
20456
  // 장 로마숫자(흰)
20450
20457
  charPr(16, sz.chapter, false, false, 3),
20451
20458
  // 장 제목
@@ -20453,15 +20460,15 @@ function buildCharProperties(theme, gongmun, ratioVariants = [], extraCharPrXmls
20453
20460
  // 표지 제목
20454
20461
  charPr(18, sz.coverSub, false, false, 3),
20455
20462
  // 표지 날짜·기관명
20456
- charPr(19, sz.tocLabel, true, false, 3, "#000000", 100, true),
20463
+ charPr(19, sz.tocLabel, true, false, 3),
20457
20464
  // 목 차
20458
- charPr(20, sz.tocRoman, true, false, 6, "#000000", 100, true),
20465
+ charPr(20, sz.tocRoman, true, false, 6),
20459
20466
  // 목차 로마숫자(한양신명조)
20460
20467
  charPr(21, sz.tocItem, false, false, 3),
20461
20468
  // 목차 항목
20462
20469
  charPr(22, sz.table, false, false, 7),
20463
20470
  // 표 셀(맑은 고딕 12pt)
20464
- charPr(23, sz.table, true, false, 7, "#000000", 100, true),
20471
+ charPr(23, sz.table, true, false, 7),
20465
20472
  // 표 셀 bold
20466
20473
  charPr(24, sz.bar, false, false, 4),
20467
20474
  // 표지 바 셀 빈 문단(6pt)
@@ -20500,10 +20507,11 @@ ${base2.join("\n")}
20500
20507
  }
20501
20508
  const ls = gongmun.lineSpacing;
20502
20509
  const titleAlign = gongmun.centerTitle ? "CENTER" : "LEFT";
20510
+ const h2Geom = gongmun.h2Marker !== "none" ? { spaceBefore: Math.round(gongmun.bodyHeight * 2), spaceAfter: 0, indent: -markerWidth(gongmun.h2Marker === "box" ? "\u25A1" : "1.", 1600) } : { spaceBefore: 600, spaceAfter: 150 };
20503
20511
  const base = [
20504
20512
  paraPr(0, { lineSpacing: ls, keepWord: true }),
20505
20513
  paraPr(1, { align: titleAlign, spaceBefore: 400, spaceAfter: 400, lineSpacing: ls, keepWord: true }),
20506
- paraPr(2, { align: "LEFT", spaceBefore: 600, spaceAfter: 150, lineSpacing: ls, keepWord: true }),
20514
+ paraPr(2, { align: "LEFT", ...h2Geom, lineSpacing: ls, keepWord: true }),
20507
20515
  paraPr(3, { align: "LEFT", spaceBefore: 400, spaceAfter: 100, lineSpacing: ls, keepWord: true }),
20508
20516
  paraPr(4, { align: "LEFT", spaceBefore: 300, spaceAfter: 100, lineSpacing: ls, keepWord: true }),
20509
20517
  paraPr(5, { align: "LEFT", lineSpacing: 130, indent: 400, keepWord: true }),
@@ -20532,6 +20540,11 @@ ${base2.join("\n")}
20532
20540
  // 표지 장식 바 셀 빈 문단 — 저줄간격(실측 71%)으로 바 높이 818 안에 수납
20533
20541
  paraPr(GJ_PARA_BAR, { align: "CENTER", lineSpacing: 70, keepWord: true })
20534
20542
  );
20543
+ } else if (usesReportFonts(gongmun.preset)) {
20544
+ const cham = gaejosikChamIndent(gongmun.bodyHeight, gongmun.sizes);
20545
+ base.push(
20546
+ paraPr(GJ_PARA_CHAM, { align: "JUSTIFY", lineSpacing: ls, left: cham.left, indent: cham.indent, spaceBefore: gaejosikSpaceBefore(3, gongmun.bodyHeight), keepWord: true })
20547
+ );
20535
20548
  }
20536
20549
  return `<hh:paraProperties itemCnt="${base.length}">
20537
20550
  ${base.join("\n")}
@@ -20554,14 +20567,15 @@ function fontEntry(id, face, weight = 6) {
20554
20567
  </hh:font>`;
20555
20568
  }
20556
20569
  function buildFontFaces(gongmun, bodyFace) {
20557
- if (gongmun?.preset === "gaejosik") {
20570
+ if (gongmun && usesReportFonts(gongmun.preset)) {
20558
20571
  const ov = gongmun.fonts;
20572
+ const bodyDefault = gongmun.preset !== "gaejosik" && gongmun.bodyFont === "gothic" ? "\uB9D1\uC740 \uACE0\uB515" : "\uD734\uBA3C\uBA85\uC870";
20559
20573
  const faces = [
20560
20574
  "\uD568\uCD08\uB86C\uBC14\uD0D5",
20561
20575
  "\uD568\uCD08\uB86C\uB3CB\uC6C0",
20562
20576
  "HY\uACAC\uACE0\uB515",
20563
20577
  ov.heading ?? "HY\uD5E4\uB4DC\uB77C\uC778M",
20564
- ov.body ?? "\uD734\uBA3C\uBA85\uC870",
20578
+ ov.body ?? bodyDefault,
20565
20579
  ov.ref ?? "\uD55C\uC591\uC911\uACE0\uB515",
20566
20580
  "\uD55C\uC591\uC2E0\uBA85\uC870",
20567
20581
  ov.table ?? "\uB9D1\uC740 \uACE0\uB515"
@@ -22236,12 +22250,13 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22236
22250
  const orderedCounters = {};
22237
22251
  let prevWasOrdered = false;
22238
22252
  const gaejosik = gongmun?.preset === "gaejosik";
22239
- const vBase = charVariantBase(gaejosik);
22253
+ const measured = !!gongmun && usesReportFonts(gongmun.preset);
22254
+ const vBase = charVariantBase(measured);
22240
22255
  const tableStyle = gongmun ? {
22241
22256
  totalWidth: mmToHwpunit(210 - gongmun.margins.left - gongmun.margins.right),
22242
- charPr: gaejosik ? GJ_CHAR_TABLE : CHAR_NORMAL,
22243
- boldCharPr: gaejosik ? GJ_CHAR_TABLE_BOLD : CHAR_BOLD,
22244
- charHeight: gaejosik ? gaejosikSizes(gongmun.bodyHeight, gongmun.sizes).table : gongmun.bodyHeight,
22257
+ charPr: measured ? GJ_CHAR_TABLE : CHAR_NORMAL,
22258
+ boldCharPr: measured ? GJ_CHAR_TABLE_BOLD : CHAR_BOLD,
22259
+ charHeight: measured ? gaejosikSizes(gongmun.bodyHeight, gongmun.sizes).table : gongmun.bodyHeight,
22245
22260
  headerBf: gongmunTableHeaderBf(gaejosik),
22246
22261
  centerParaPr: GONGMUN_CENTER,
22247
22262
  tblCenterParaPr: GONGMUN_TBL_CENTER,
@@ -22251,6 +22266,7 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22251
22266
  } : null;
22252
22267
  const chamMap = (id) => id === CHAR_BOLD ? GJ_CHAR_CHAM_BOLD : id;
22253
22268
  let chapterNo = 0;
22269
+ let h2Seq = 0;
22254
22270
  let coverH1Idx = -1;
22255
22271
  let pendingPageBreak = false;
22256
22272
  let pendingNewNum = false;
@@ -22304,7 +22320,7 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22304
22320
  switch (block.type) {
22305
22321
  case "heading": {
22306
22322
  if (gongmun && blockIdx === titleBoxH1Idx && tableStyle && bfReg) {
22307
- xml = buildTitleBox((block.text || "").trim(), CHAR_H1, tableStyle.totalWidth, bfReg);
22323
+ xml = buildTitleBox((block.text || "").trim(), measured ? GJ_CHAR_BODY_TITLE : CHAR_H1, tableStyle.totalWidth, bfReg);
22308
22324
  break;
22309
22325
  }
22310
22326
  if (gaejosik) {
@@ -22328,11 +22344,16 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22328
22344
  const pId = headingParaPrId(block.level || 1);
22329
22345
  const cId = headingCharPrId(block.level || 1);
22330
22346
  const styleId = gongmun ? Math.min(block.level || 1, 4) : 0;
22331
- xml = generateParagraph(block.text || "", pId, cId, void 0, styleId);
22347
+ let hText = block.text || "";
22348
+ if (gongmun && (block.level || 1) === 2 && gongmun.h2Marker !== "none") {
22349
+ const title = stripChapterNumber(hText);
22350
+ hText = gongmun.h2Marker === "box" ? `\u25A1 ${title}` : `${++h2Seq}. ${title}`;
22351
+ }
22352
+ xml = generateParagraph(hText, pId, cId, void 0, styleId);
22332
22353
  break;
22333
22354
  }
22334
22355
  case "paragraph": {
22335
- if (gaejosik && (block.text || "").trimStart().startsWith("\u203B")) {
22356
+ if (measured && (block.text || "").trimStart().startsWith("\u203B")) {
22336
22357
  xml = generateParagraph((block.text || "").trim(), GJ_PARA_CHAM, GJ_CHAR_CHAM, chamMap);
22337
22358
  break;
22338
22359
  }
@@ -22377,7 +22398,7 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22377
22398
  break;
22378
22399
  }
22379
22400
  case "blockquote": {
22380
- if (gaejosik) {
22401
+ if (measured) {
22381
22402
  const t = (block.text || "").trim();
22382
22403
  if (t) xml = generateParagraph(t.startsWith("\u203B") ? t : `\u203B ${t}`, GJ_PARA_CHAM, GJ_CHAR_CHAM, chamMap);
22383
22404
  break;
@@ -22395,14 +22416,14 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
22395
22416
  const depth = info?.depth ?? 0;
22396
22417
  const marker2 = info?.marker ?? "";
22397
22418
  const content = block.text || "";
22398
- if (gaejosik && content.trimStart().startsWith("\u203B")) {
22419
+ if (measured && content.trimStart().startsWith("\u203B")) {
22399
22420
  xml = generateParagraph(content.trim(), GJ_PARA_CHAM, GJ_CHAR_CHAM, chamMap);
22400
22421
  break;
22401
22422
  }
22402
22423
  const text = marker2 ? `${marker2} ${content}` : content;
22403
22424
  let listCharPr = gongmun.numbering === "report" && depth === 0 ? CHAR_BOLD : CHAR_NORMAL;
22404
22425
  let mapId = fit ? variantMapper(fit, blockIdx, vBase) : void 0;
22405
- if (gaejosik && depth === 0) {
22426
+ if (measured && depth === 0 && gongmun.numbering !== "standard") {
22406
22427
  listCharPr = GJ_CHAR_DAE;
22407
22428
  mapId = (id) => id === CHAR_BOLD ? GJ_CHAR_DAE_BOLD : id;
22408
22429
  }
@@ -22498,11 +22519,12 @@ async function markdownToHwpx(markdown, options) {
22498
22519
  const theme = resolveTheme(options?.theme);
22499
22520
  const gongmun = options?.gongmun ? resolveGongmun(options.gongmun) : null;
22500
22521
  const gaejosik = gongmun?.preset === "gaejosik";
22522
+ const measured = !!gongmun && usesReportFonts(gongmun.preset);
22501
22523
  const blocks = parseMarkdownToBlocks(markdown);
22502
22524
  const gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null;
22503
22525
  const fit = gongmun && gongmunList ? computeGongmunFitPlan(blocks, gongmun, gongmunList) : null;
22504
22526
  const staticBfEnd = gongmun ? gaejosik ? 11 : 4 : 3;
22505
- const remap = options?.profile ? buildProfileRemap(options.profile, charVariantBase(gaejosik) + (fit?.variants?.length ?? 0) * 4, staticBfEnd) : null;
22527
+ const remap = options?.profile ? buildProfileRemap(options.profile, charVariantBase(measured) + (fit?.variants?.length ?? 0) * 4, staticBfEnd) : null;
22506
22528
  const bfReg = gongmun ? new TableBfRegistry(staticBfEnd + (remap?.borderFillXmls.length ?? 0)) : null;
22507
22529
  const chartParts = [];
22508
22530
  const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts, bfReg, remap);
@@ -23003,6 +23025,142 @@ function unknownFontWarnings(fonts) {
23003
23025
  return warnings;
23004
23026
  }
23005
23027
 
23028
+ // src/hwpx/gongmun-lint.ts
23029
+ var RULES = [
23030
+ // 날짜 ─ 온점 뒤 한 칸, 0 패딩 금지, 연도 4자리, 끝 마침표
23031
+ {
23032
+ code: "DATE_NO_SPACE",
23033
+ severity: "error",
23034
+ pattern: /\b\d{4}\.\d{1,2}\.\d{1,2}\.?/g,
23035
+ message: "\uB0A0\uC9DC \uC628\uC810 \uB4A4\uC5D0 \uD55C \uCE78\uC529 \uB744\uC6CC\uC57C \uD568",
23036
+ suggest: "\uC608) 2025. 1. 6."
23037
+ },
23038
+ {
23039
+ code: "DATE_ZERO_PAD",
23040
+ severity: "error",
23041
+ pattern: /\b\d{4}\.\s*0\d\.|\.\s*0\d\./g,
23042
+ message: "\uC6D4\xB7\uC77C \uC55E\uC758 '0'\uC740 \uD45C\uAE30\uD558\uC9C0 \uC54A\uC74C",
23043
+ suggest: "\uC608) 2025. 1. 6. (2025. 01. 06. \u2715)"
23044
+ },
23045
+ {
23046
+ code: "DATE_2DIGIT_YR",
23047
+ severity: "error",
23048
+ pattern: /(?<!\d)['’]\d{2}\.\s*\d/g,
23049
+ message: "\uC5F0\uB3C4\uB294 \uB124 \uC790\uB9AC\uB85C \uD45C\uAE30('24 \u2715)",
23050
+ suggest: "\uC608) 2025. 1. 6."
23051
+ },
23052
+ {
23053
+ code: "DATE_NO_END_DOT",
23054
+ severity: "warning",
23055
+ pattern: /\b\d{4}\.\s\d{1,2}\.\s\d{1,2}(?!\s*[.\d(])/g,
23056
+ message: "\uB0A0\uC9DC\uC758 '\uC77C' \uB2E4\uC74C\uC5D0 \uB9C8\uCE68\uD45C(.)\uB97C \uCC0D\uC5B4\uC57C \uD568",
23057
+ suggest: "\uC608) 2025. 1. 6."
23058
+ },
23059
+ // 시간 ─ 24시각제, 쌍점 붙여쓰기
23060
+ {
23061
+ code: "TIME_AMPM",
23062
+ severity: "error",
23063
+ pattern: /(오전|오후|아침|밤|낮)\s*\d{1,2}\s*시/g,
23064
+ message: "24\uC2DC\uAC01\uC81C \uC22B\uC790\uB85C \uD45C\uAE30(\uC624\uC804/\uC624\uD6C4 \uC0AC\uC6A9 \uC548 \uD568)",
23065
+ suggest: "\uC608) 09:00, 15:30"
23066
+ },
23067
+ {
23068
+ code: "TIME_24H",
23069
+ severity: "warning",
23070
+ pattern: /(?<!\d)24\s*시(?!각)/g,
23071
+ message: "'24\uC2DC'\uBCF4\uB2E4 \uC775\uC77C 00:00 \uB610\uB294 '18:00\uAE4C\uC9C0' \uAD8C\uC7A5",
23072
+ suggest: "\uC608) 18:00"
23073
+ },
23074
+ {
23075
+ code: "TIME_COLON_SP",
23076
+ severity: "error",
23077
+ pattern: /\b\d{1,2}\s+:\s*\d{2}\b|\b\d{1,2}:\s+\d{2}\b/g,
23078
+ message: "\uC2DC\uC640 \uBD84 \uC0AC\uC774 \uC30D\uC810\uC740 \uC591\uCABD\uC744 \uBD99\uC5EC \uC500",
23079
+ suggest: "\uC608) 13:20"
23080
+ },
23081
+ // 금액 ─ '천원' 금지, 금+숫자 붙여쓰기
23082
+ {
23083
+ code: "MONEY_CHEONWON",
23084
+ severity: "error",
23085
+ pattern: /\d+\s*천\s*원/g,
23086
+ message: "\uAE08\uC561\uC740 '\uCC9C\uC6D0'\uC73C\uB85C \uC904\uC774\uC9C0 \uC54A\uACE0 \uC544\uB77C\uBE44\uC544 \uC22B\uC790\uB85C",
23087
+ suggest: "\uC608) 345,000\uC6D0"
23088
+ },
23089
+ {
23090
+ code: "MONEY_GEUM_SP",
23091
+ severity: "warning",
23092
+ pattern: /금\s+\d/g,
23093
+ message: "'\uAE08'\uACFC \uC22B\uC790 \uC0AC\uC774\uB294 \uBD99\uC5EC \uC4F0\uB294 \uAC83\uC774 \uC6D0\uCE59",
23094
+ suggest: "\uC608) \uAE08113,560\uC6D0"
23095
+ },
23096
+ // 붙임 ─ 쌍점 금지(2타 띄움)
23097
+ {
23098
+ code: "BUNIM_COLON",
23099
+ severity: "error",
23100
+ pattern: /붙\s*임\s*:/g,
23101
+ message: "'\uBD99\uC784' \uB2E4\uC74C\uC5D0 \uC30D\uC810(:)\uC744 \uBD99\uC774\uC9C0 \uC54A\uC74C(2\uD0C0 \uB744\uC6C0)",
23102
+ suggest: "\uC608) \uBD99\uC784 \uACC4\uD68D\uC11C 1\uBD80."
23103
+ },
23104
+ // 표기 ─ 물결표+까지 중복, 한글 먼저, 쌍점 띄어쓰기
23105
+ {
23106
+ code: "KKAJI_DUP",
23107
+ severity: "error",
23108
+ pattern: /[∼~~][^\n]{0,20}?까지/g,
23109
+ message: "\uBB3C\uACB0\uD45C(\u223C)\uC640 '\uAE4C\uC9C0'\uB97C \uD568\uAED8 \uC4F0\uC9C0 \uC54A\uC74C",
23110
+ suggest: "\uC608) 2. 20.\u223C2. 24."
23111
+ },
23112
+ {
23113
+ code: "FOREIGN_FIRST",
23114
+ severity: "warning",
23115
+ pattern: /\b[A-Z]{2,5}\s*\([가-힣]/g,
23116
+ message: "\uD55C\uAE00\uC744 \uBA3C\uC800 \uC4F0\uACE0 \uAD04\uD638 \uC548\uC5D0 \uC678\uAD6D\uC5B4\uB97C \uBCD1\uAE30",
23117
+ suggest: "\uC608) \uC5C5\uBB34 \uD611\uC57D(MOU)"
23118
+ },
23119
+ // 쌍점 — URL(https:// 등)·시각(13:20)은 제외
23120
+ {
23121
+ code: "COLON_SPACE",
23122
+ severity: "warning",
23123
+ pattern: /\S\s+:\S|\S:(?!\/\/)[^\s\d]/g,
23124
+ message: "\uC30D\uC810\uC740 \uC55E\uB9D0\uC5D0 \uBD99\uC774\uACE0 \uB4A4\uB294 \uD55C \uCE78 \uB744\uC6C0",
23125
+ suggest: "\uC608) \uC6D0\uC7A5: \uAE40\uAC11\uB3D9"
23126
+ }
23127
+ ];
23128
+ function lintGongmunText(text) {
23129
+ const findings = [];
23130
+ let inFence = false;
23131
+ const lines = text.split(/\r?\n/);
23132
+ for (let i = 0; i < lines.length; i++) {
23133
+ const line = lines[i];
23134
+ if (/^\s*(```|~~~)/.test(line)) {
23135
+ inFence = !inFence;
23136
+ continue;
23137
+ }
23138
+ if (inFence) continue;
23139
+ for (const r of RULES) {
23140
+ r.pattern.lastIndex = 0;
23141
+ for (const m of line.matchAll(r.pattern)) {
23142
+ findings.push({
23143
+ line: i + 1,
23144
+ match: m[0].trim(),
23145
+ rule: r.code,
23146
+ severity: r.severity,
23147
+ message: r.message,
23148
+ suggest: r.suggest
23149
+ });
23150
+ }
23151
+ }
23152
+ }
23153
+ return findings;
23154
+ }
23155
+ function gongmunLintWarnings(text, limit = 10) {
23156
+ const findings = lintGongmunText(text);
23157
+ const shown = findings.slice(0, limit).map(
23158
+ (f) => `\uD45C\uAE30\uBC95 [${f.rule}] L${f.line} "${f.match}" \u2014 ${f.message}${f.suggest ? ` (${f.suggest})` : ""}`
23159
+ );
23160
+ if (findings.length > limit) shown.push(`\uD45C\uAE30\uBC95 \uACBD\uACE0 ${findings.length - limit}\uAC74 \uB354 \uC788\uC74C \u2014 kordoc lint\uB85C \uC804\uCCB4 \uD655\uC778`);
23161
+ return shown;
23162
+ }
23163
+
23006
23164
  // src/roundtrip/patcher.ts
23007
23165
  import JSZip8 from "jszip";
23008
23166
 
@@ -25734,7 +25892,7 @@ async function parseHwp(buffer, options) {
25734
25892
  async function parsePdf(buffer, options) {
25735
25893
  let parsePdfDocument;
25736
25894
  try {
25737
- const mod = await import("./parser-LHUO6UUA.js");
25895
+ const mod = await import("./parser-ZOMDHCA7.js");
25738
25896
  parsePdfDocument = mod.parsePdfDocument;
25739
25897
  } catch {
25740
25898
  return {
@@ -25844,6 +26002,8 @@ export {
25844
26002
  hwpxToProfile,
25845
26003
  isKnownFont,
25846
26004
  unknownFontWarnings,
26005
+ lintGongmunText,
26006
+ gongmunLintWarnings,
25847
26007
  patchHwpx,
25848
26008
  patchHwp,
25849
26009
  validateHwpx,
@@ -25864,4 +26024,4 @@ export {
25864
26024
  parseHwpml,
25865
26025
  fillForm
25866
26026
  };
25867
- //# sourceMappingURL=chunk-PGWAF755.js.map
26027
+ //# sourceMappingURL=chunk-SHVV3BD6.js.map