kordoc 4.12.2 → 4.12.3

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 (121) hide show
  1. package/README.md +12 -1
  2. package/dist/{-EZH6NKTE.js → -FWGDIOV4.js} +8 -8
  3. package/dist/{chunk-OEYECZGV.js → chunk-2DAFWDV2.js} +9 -5
  4. package/dist/chunk-2DAFWDV2.js.map +1 -0
  5. package/dist/{chunk-5RPYBC2Q.js → chunk-3KQOI6R6.js} +27 -2
  6. package/dist/chunk-3KQOI6R6.js.map +1 -0
  7. package/dist/{chunk-DBGEUDBY.js → chunk-6L3B44DH.js} +2 -2
  8. package/dist/{chunk-ONNAHSPV.cjs → chunk-7BIXTQZ3.cjs} +14 -10
  9. package/dist/chunk-7BIXTQZ3.cjs.map +1 -0
  10. package/dist/{chunk-IOJX4Q63.js → chunk-B63QEHYL.js} +3 -3
  11. package/dist/{chunk-JCMBQC5N.js → chunk-BAZMKQZW.js} +2 -2
  12. package/dist/{chunk-V5BUPZ6I.cjs → chunk-BOATAEXU.cjs} +7 -4
  13. package/dist/chunk-BOATAEXU.cjs.map +1 -0
  14. package/dist/{chunk-KX7IYCCZ.js → chunk-CKYDP34A.js} +3 -3
  15. package/dist/{chunk-7XUXSDH5.js → chunk-DUGUCM7K.js} +9 -5
  16. package/dist/chunk-DUGUCM7K.js.map +1 -0
  17. package/dist/{chunk-2LKYJ4G3.cjs → chunk-FFITS3NY.cjs} +6 -6
  18. package/dist/{chunk-2LKYJ4G3.cjs.map → chunk-FFITS3NY.cjs.map} +1 -1
  19. package/dist/{chunk-2B7OIEJJ.js → chunk-HB56YANA.js} +5 -2
  20. package/dist/chunk-HB56YANA.js.map +1 -0
  21. package/dist/{chunk-2HBYWA5X.js → chunk-IC6HHXFL.js} +2 -2
  22. package/dist/{chunk-LD2K4K5V.js → chunk-INFYDSZL.js} +111 -22
  23. package/dist/chunk-INFYDSZL.js.map +1 -0
  24. package/dist/{chunk-62IU4NV3.cjs → chunk-ISCI5LKN.cjs} +2 -2
  25. package/dist/{chunk-62IU4NV3.cjs.map → chunk-ISCI5LKN.cjs.map} +1 -1
  26. package/dist/{chunk-XXDZ2KTW.js → chunk-KLO6RHX2.js} +2 -2
  27. package/dist/{chunk-MUYU4JI5.js → chunk-KRE2SREV.js} +2 -2
  28. package/dist/{chunk-QBCMFNHS.js → chunk-OJDMMZ5Z.js} +2 -2
  29. package/dist/{chunk-UL2MDA5C.js → chunk-PL4V523B.js} +3 -3
  30. package/dist/{chunk-FBLMVHDK.js → chunk-PUZZFYLV.js} +2 -2
  31. package/dist/{chunk-2LO525TL.js → chunk-SJEPQOVW.js} +2 -2
  32. package/dist/{chunk-QM2RSJ2S.js → chunk-TWKXX343.js} +3 -3
  33. package/dist/{chunk-2LPBIW2B.cjs → chunk-W3H2H55O.cjs} +3 -3
  34. package/dist/{chunk-2LPBIW2B.cjs.map → chunk-W3H2H55O.cjs.map} +1 -1
  35. package/dist/{chunk-FVBR7SC3.js → chunk-YBZJMAE2.js} +2 -2
  36. package/dist/{chunk-Q6ETEJFK.js → chunk-ZASGH5EN.js} +5 -2
  37. package/dist/chunk-ZASGH5EN.js.map +1 -0
  38. package/dist/chunks-VICNQMNE.js +10 -0
  39. package/dist/cli.js +30 -23
  40. package/dist/cli.js.map +1 -1
  41. package/dist/{formula-NW33S4TA.js → formula-R7IWAAYR.js} +3 -3
  42. package/dist/{formula-6RQX4NMJ.js → formula-YJWKEPUK.js} +4 -4
  43. package/dist/{formula-NBEO6CFC.cjs → formula-ZYHUXTK5.cjs} +9 -9
  44. package/dist/{formula-NBEO6CFC.cjs.map → formula-ZYHUXTK5.cjs.map} +1 -1
  45. package/dist/{image-ocr-V4KY373B.cjs → image-ocr-6O6ZXKUD.cjs} +11 -11
  46. package/dist/{image-ocr-V4KY373B.cjs.map → image-ocr-6O6ZXKUD.cjs.map} +1 -1
  47. package/dist/{image-ocr-SO56VETS.js → image-ocr-G4JVF2UH.js} +7 -7
  48. package/dist/{image-ocr-CAVU2TNZ.js → image-ocr-OLTSKQWD.js} +5 -5
  49. package/dist/index.cjs +455 -366
  50. package/dist/index.cjs.map +1 -1
  51. package/dist/index.d.cts +17 -0
  52. package/dist/index.d.ts +17 -0
  53. package/dist/index.js +107 -18
  54. package/dist/index.js.map +1 -1
  55. package/dist/mcp.js +20 -17
  56. package/dist/mcp.js.map +1 -1
  57. package/dist/{model-bundle-EIJF34DR.js → model-bundle-IFD2D5CW.js} +5 -5
  58. package/dist/{models-6V4CPQXC.js → models-FJ3IUNTB.js} +5 -5
  59. package/dist/{parser-OBHNXEQM.js → parser-I7TC35V6.js} +31 -10
  60. package/dist/parser-I7TC35V6.js.map +1 -0
  61. package/dist/{parser-GIREMEPD.js → parser-JRT3B6OK.js} +31 -10
  62. package/dist/parser-JRT3B6OK.js.map +1 -0
  63. package/dist/{parser-OMT25WH2.cjs → parser-YLLIYOIZ.cjs} +59 -38
  64. package/dist/parser-YLLIYOIZ.cjs.map +1 -0
  65. package/dist/pdf-ocr-ADUP2LPU.cjs +14 -0
  66. package/dist/{pdf-ocr-TFYVK4FI.cjs.map → pdf-ocr-ADUP2LPU.cjs.map} +1 -1
  67. package/dist/pdf-ocr-ATJTB2B3.js +13 -0
  68. package/dist/pdf-ocr-P75KSZFV.js +16 -0
  69. package/dist/{profile-io-PZVMM66V.js → profile-io-BPJQQZLQ.js} +3 -3
  70. package/dist/{rasterize-NRWP2C6L.js → rasterize-ALCNU53T.js} +2 -2
  71. package/dist/render-MDLTQUUV.js +10 -0
  72. package/dist/seal-K4K3KPE3.js +10 -0
  73. package/dist/{setup-V55AJP6H.js → setup-O2DALZKF.js} +3 -3
  74. package/dist/{watch-7CQSMDDP.js → watch-GPWYJAS2.js} +9 -9
  75. package/package.json +1 -1
  76. package/dist/chunk-2B7OIEJJ.js.map +0 -1
  77. package/dist/chunk-5RPYBC2Q.js.map +0 -1
  78. package/dist/chunk-7XUXSDH5.js.map +0 -1
  79. package/dist/chunk-LD2K4K5V.js.map +0 -1
  80. package/dist/chunk-OEYECZGV.js.map +0 -1
  81. package/dist/chunk-ONNAHSPV.cjs.map +0 -1
  82. package/dist/chunk-Q6ETEJFK.js.map +0 -1
  83. package/dist/chunk-V5BUPZ6I.cjs.map +0 -1
  84. package/dist/chunks-TT7ZE5QQ.js +0 -10
  85. package/dist/parser-GIREMEPD.js.map +0 -1
  86. package/dist/parser-OBHNXEQM.js.map +0 -1
  87. package/dist/parser-OMT25WH2.cjs.map +0 -1
  88. package/dist/pdf-ocr-IRXQ5GBM.js +0 -13
  89. package/dist/pdf-ocr-SL4GCOGS.js +0 -16
  90. package/dist/pdf-ocr-TFYVK4FI.cjs +0 -14
  91. package/dist/render-V5ZPTZQ7.js +0 -10
  92. package/dist/seal-LVG2DGAB.js +0 -10
  93. /package/dist/{-EZH6NKTE.js.map → -FWGDIOV4.js.map} +0 -0
  94. /package/dist/{chunk-DBGEUDBY.js.map → chunk-6L3B44DH.js.map} +0 -0
  95. /package/dist/{chunk-IOJX4Q63.js.map → chunk-B63QEHYL.js.map} +0 -0
  96. /package/dist/{chunk-JCMBQC5N.js.map → chunk-BAZMKQZW.js.map} +0 -0
  97. /package/dist/{chunk-KX7IYCCZ.js.map → chunk-CKYDP34A.js.map} +0 -0
  98. /package/dist/{chunk-2HBYWA5X.js.map → chunk-IC6HHXFL.js.map} +0 -0
  99. /package/dist/{chunk-XXDZ2KTW.js.map → chunk-KLO6RHX2.js.map} +0 -0
  100. /package/dist/{chunk-MUYU4JI5.js.map → chunk-KRE2SREV.js.map} +0 -0
  101. /package/dist/{chunk-QBCMFNHS.js.map → chunk-OJDMMZ5Z.js.map} +0 -0
  102. /package/dist/{chunk-UL2MDA5C.js.map → chunk-PL4V523B.js.map} +0 -0
  103. /package/dist/{chunk-FBLMVHDK.js.map → chunk-PUZZFYLV.js.map} +0 -0
  104. /package/dist/{chunk-2LO525TL.js.map → chunk-SJEPQOVW.js.map} +0 -0
  105. /package/dist/{chunk-QM2RSJ2S.js.map → chunk-TWKXX343.js.map} +0 -0
  106. /package/dist/{chunk-FVBR7SC3.js.map → chunk-YBZJMAE2.js.map} +0 -0
  107. /package/dist/{chunks-TT7ZE5QQ.js.map → chunks-VICNQMNE.js.map} +0 -0
  108. /package/dist/{formula-NW33S4TA.js.map → formula-R7IWAAYR.js.map} +0 -0
  109. /package/dist/{formula-6RQX4NMJ.js.map → formula-YJWKEPUK.js.map} +0 -0
  110. /package/dist/{image-ocr-SO56VETS.js.map → image-ocr-G4JVF2UH.js.map} +0 -0
  111. /package/dist/{image-ocr-CAVU2TNZ.js.map → image-ocr-OLTSKQWD.js.map} +0 -0
  112. /package/dist/{model-bundle-EIJF34DR.js.map → model-bundle-IFD2D5CW.js.map} +0 -0
  113. /package/dist/{models-6V4CPQXC.js.map → models-FJ3IUNTB.js.map} +0 -0
  114. /package/dist/{pdf-ocr-IRXQ5GBM.js.map → pdf-ocr-ATJTB2B3.js.map} +0 -0
  115. /package/dist/{pdf-ocr-SL4GCOGS.js.map → pdf-ocr-P75KSZFV.js.map} +0 -0
  116. /package/dist/{profile-io-PZVMM66V.js.map → profile-io-BPJQQZLQ.js.map} +0 -0
  117. /package/dist/{rasterize-NRWP2C6L.js.map → rasterize-ALCNU53T.js.map} +0 -0
  118. /package/dist/{render-V5ZPTZQ7.js.map → render-MDLTQUUV.js.map} +0 -0
  119. /package/dist/{seal-LVG2DGAB.js.map → seal-K4K3KPE3.js.map} +0 -0
  120. /package/dist/{setup-V55AJP6H.js.map → setup-O2DALZKF.js.map} +0 -0
  121. /package/dist/{watch-7CQSMDDP.js.map → watch-GPWYJAS2.js.map} +0 -0
package/dist/index.d.cts CHANGED
@@ -781,6 +781,15 @@ type GongmunNumbering = "standard" | "report" | "gaejosik";
781
781
  type GongmunFont = "myeongjo" | "gothic";
782
782
  /** 프리셋 입력값 — 영문 키 또는 한글 별칭(기안문·보고서·계획서·통지·회의록 등) */
783
783
  type GongmunPresetInput = GongmunPreset | "기안문" | "시행문" | "공문" | "공문서" | "보고서" | "계획서" | "계획" | "통지" | "알림" | "안내" | "회의록" | "개조식" | "개조식보고서" | "정부보고서" | "정부표준개조식보고서" | "보도자료";
784
+ /** 항목부호 단계 하나의 타이포 — 셋 다 선택(미지정=본문 계열 유지) */
785
+ interface GongmunLevelStyle {
786
+ /** 글꼴명 (예: HY견고딕·한컴돋움·휴먼명조) */
787
+ font?: string;
788
+ /** 글자 크기 pt (6~60) */
789
+ pt?: number;
790
+ /** 굵게 */
791
+ bold?: boolean;
792
+ }
784
793
  /** 공문서 모드 옵션 (전부 선택 — 프리셋 기본값을 개별 override) */
785
794
  interface GongmunOptions {
786
795
  /** 문서 종류 프리셋(영문 키 또는 한글 별칭). 기본 'official'(일반 기안문) */
@@ -834,6 +843,14 @@ interface GongmunOptions {
834
843
  };
835
844
  /** 개조식 요소별 글자 크기(pt) 오버라이드 — 미지정 요소는 bodyPt 비례 기본값 */
836
845
  sizes?: GaejosikSizeOverrides;
846
+ /**
847
+ * 항목부호 단계별 위계 타이포(v4.12.3) — depth(0~7)마다 글꼴·크기(pt)·굵기를 지정한다.
848
+ * 실측(실결재 기안문 206 + 보고서 337건): 법정 8단계(1. 가. 1))는 본문과 동일이 90%라 기본은
849
+ * 무변경, □/ㅇ/- 계열 전자결재 기안문은 □=HY견고딕 +2~3pt bold·ㅇ=한컴돋움 bold·-=휴먼명조가
850
+ * 지배 관행이다(docs/gongmunseo-reference.md 2.7). 지정한 단계만 바뀌고 나머지는 본문 계열.
851
+ * 개조식·보고서의 실측 □(HY헤드라인M)·보도자료 각주보다 우선한다(명시 옵션).
852
+ */
853
+ levels?: Record<number | string, GongmunLevelStyle>;
837
854
  /** 쪽번호(하단 중앙 "- 1 -", 표지·목차는 카운트 제외). 기본: 개조식·보고서·계획서 켜짐 */
838
855
  pageNumbers?: boolean;
839
856
  /** 본문 끝 2타+"끝." 표시(행정업무규정). 기본: 기안문(official)만 켜짐 */
package/dist/index.d.ts CHANGED
@@ -781,6 +781,15 @@ type GongmunNumbering = "standard" | "report" | "gaejosik";
781
781
  type GongmunFont = "myeongjo" | "gothic";
782
782
  /** 프리셋 입력값 — 영문 키 또는 한글 별칭(기안문·보고서·계획서·통지·회의록 등) */
783
783
  type GongmunPresetInput = GongmunPreset | "기안문" | "시행문" | "공문" | "공문서" | "보고서" | "계획서" | "계획" | "통지" | "알림" | "안내" | "회의록" | "개조식" | "개조식보고서" | "정부보고서" | "정부표준개조식보고서" | "보도자료";
784
+ /** 항목부호 단계 하나의 타이포 — 셋 다 선택(미지정=본문 계열 유지) */
785
+ interface GongmunLevelStyle {
786
+ /** 글꼴명 (예: HY견고딕·한컴돋움·휴먼명조) */
787
+ font?: string;
788
+ /** 글자 크기 pt (6~60) */
789
+ pt?: number;
790
+ /** 굵게 */
791
+ bold?: boolean;
792
+ }
784
793
  /** 공문서 모드 옵션 (전부 선택 — 프리셋 기본값을 개별 override) */
785
794
  interface GongmunOptions {
786
795
  /** 문서 종류 프리셋(영문 키 또는 한글 별칭). 기본 'official'(일반 기안문) */
@@ -834,6 +843,14 @@ interface GongmunOptions {
834
843
  };
835
844
  /** 개조식 요소별 글자 크기(pt) 오버라이드 — 미지정 요소는 bodyPt 비례 기본값 */
836
845
  sizes?: GaejosikSizeOverrides;
846
+ /**
847
+ * 항목부호 단계별 위계 타이포(v4.12.3) — depth(0~7)마다 글꼴·크기(pt)·굵기를 지정한다.
848
+ * 실측(실결재 기안문 206 + 보고서 337건): 법정 8단계(1. 가. 1))는 본문과 동일이 90%라 기본은
849
+ * 무변경, □/ㅇ/- 계열 전자결재 기안문은 □=HY견고딕 +2~3pt bold·ㅇ=한컴돋움 bold·-=휴먼명조가
850
+ * 지배 관행이다(docs/gongmunseo-reference.md 2.7). 지정한 단계만 바뀌고 나머지는 본문 계열.
851
+ * 개조식·보고서의 실측 □(HY헤드라인M)·보도자료 각주보다 우선한다(명시 옵션).
852
+ */
853
+ levels?: Record<number | string, GongmunLevelStyle>;
837
854
  /** 쪽번호(하단 중앙 "- 1 -", 표지·목차는 카운트 제외). 기본: 개조식·보고서·계획서 켜짐 */
838
855
  pageNumbers?: boolean;
839
856
  /** 본문 끝 2타+"끝." 표시(행정업무규정). 기본: 기안문(official)만 켜짐 */
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  flattenLayoutTables,
9
9
  inlineImagesIntoMarkdown,
10
10
  mapPuaText
11
- } from "./chunk-2B7OIEJJ.js";
11
+ } from "./chunk-HB56YANA.js";
12
12
  import {
13
13
  parsePageRange
14
14
  } from "./chunk-GE43BE46.js";
@@ -29,7 +29,7 @@ import {
29
29
  sanitizeHref,
30
30
  stripDtd,
31
31
  toArrayBuffer
32
- } from "./chunk-MUYU4JI5.js";
32
+ } from "./chunk-KRE2SREV.js";
33
33
 
34
34
  // src/index.ts
35
35
  import { readFile } from "fs/promises";
@@ -2785,8 +2785,9 @@ function appendParaText(state, data, resolveControl) {
2785
2785
  case CHAR_PARA:
2786
2786
  break;
2787
2787
  // 문단 끝
2788
+ // 하이픈(24)은 한컴이 그리지 않는다 — 한컴 PDF·rhwp export-hwpx 모두 "60g/㎡"(licbyl2 17855137,
2789
+ // 전 코퍼스 유일 출현). 실렌더가 진실이므로 방출하지 않는다 (v4.12.3, 종전 "-")
2788
2790
  case CHAR_HYPHEN:
2789
- result += "-";
2790
2791
  break;
2791
2792
  case CHAR_NBSP:
2792
2793
  result += "\xA0";
@@ -23055,6 +23056,36 @@ function validateGongmunOptions(opts) {
23055
23056
  if (opts.approval && opts.approval.length > 6) {
23056
23057
  throw new KordocError("approval must contain at most 6 labels");
23057
23058
  }
23059
+ if (opts.levels) {
23060
+ for (const [key, st] of Object.entries(opts.levels)) {
23061
+ const depth = Number(key);
23062
+ if (!Number.isInteger(depth) || depth < 0 || depth >= GONGMUN_LEVEL_COUNT) {
23063
+ throw new KordocError(`levels: depth must be an integer between 0 and ${GONGMUN_LEVEL_COUNT - 1} (got "${key}")`);
23064
+ }
23065
+ if (!st || typeof st !== "object") throw new KordocError(`levels.${key} must be an object {font, pt, bold}`);
23066
+ if (st.pt !== void 0) assertFiniteRange(`levels.${key}.pt`, st.pt, 6, 60);
23067
+ if (st.font !== void 0 && (typeof st.font !== "string" || !st.font.trim())) {
23068
+ throw new KordocError(`levels.${key}.font must be a non-empty string`);
23069
+ }
23070
+ }
23071
+ }
23072
+ }
23073
+ var GONGMUN_LEVEL_COUNT = 8;
23074
+ function resolveLevels(levels, bodyHeight) {
23075
+ if (!levels) return null;
23076
+ const out = {};
23077
+ for (const [key, st] of Object.entries(levels)) {
23078
+ if (st.font === void 0 && st.pt === void 0 && st.bold === void 0) continue;
23079
+ out[Number(key)] = {
23080
+ font: st.font?.trim() || null,
23081
+ height: st.pt !== void 0 ? Math.round(st.pt * 100) : bodyHeight,
23082
+ bold: !!st.bold
23083
+ };
23084
+ }
23085
+ return Object.keys(out).length > 0 ? out : null;
23086
+ }
23087
+ function levelMarkerHeight(g, depth) {
23088
+ return g.levels?.[depth]?.height ?? g.bodyHeight;
23058
23089
  }
23059
23090
  function incompatibleGongmunWarnings(opts) {
23060
23091
  const warns = [];
@@ -23099,6 +23130,7 @@ function resolveGongmun(opts) {
23099
23130
  toc: preset !== "press" && (opts.toc ?? gaejosik),
23100
23131
  fonts: opts.fonts ?? {},
23101
23132
  sizes: opts.sizes ?? {},
23133
+ levels: resolveLevels(opts.levels, Math.round(bodyPt * 100)),
23102
23134
  // 쪽번호 — 보고서 계열 관행(실측: 2_보고서 양식·추진계획·공고문 전부 하단 중앙)
23103
23135
  pageNumbers: opts.pageNumbers ?? (gaejosik || preset === "report" || preset === "plan"),
23104
23136
  // 머리말·꼬리말 — 실측: 보고서 계열 15mm(GT3·t2·춘천·브라더), 공고·보도 10mm,
@@ -23157,10 +23189,10 @@ function markerWidth(marker, bodyHeight) {
23157
23189
  for (const c of marker) em += charWidthEm1000(c.codePointAt(0));
23158
23190
  return Math.round(em / 1e3 * bodyHeight);
23159
23191
  }
23160
- function levelIndent(depth, bodyHeight, numbering, sizes = {}, bullet2 = "\u25CB", asteriskThird = false) {
23192
+ function levelIndent(depth, bodyHeight, numbering, sizes = {}, bullet2 = "\u25CB", asteriskThird = false, markerHeight = bodyHeight) {
23161
23193
  if (numbering === "gaejosik") return gaejosikLevelIndent(depth, bodyHeight, sizes, bullet2);
23162
23194
  const marker = numbering === "report" ? reportMarker(depth, bullet2, asteriskThird) : standardMarker(depth, 0);
23163
- return { left: Math.round(depth * bodyHeight), indent: -markerWidth(marker, bodyHeight) };
23195
+ return { left: Math.round(depth * bodyHeight), indent: -markerWidth(marker, markerHeight) };
23164
23196
  }
23165
23197
  function computeSuppression(depths) {
23166
23198
  const counts = /* @__PURE__ */ new Map();
@@ -23253,13 +23285,13 @@ function headingCharPrId(level) {
23253
23285
  if (level === 3) return CHAR_H3;
23254
23286
  return CHAR_H4;
23255
23287
  }
23256
- function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_COLOR, ratioPct = 100) {
23288
+ function charPr(id, height, bold, italic, fontId = 0, textColor = DEFAULT_TEXT_COLOR, ratioPct = 100, restFont = fontId) {
23257
23289
  const boldAttr = bold ? ` bold="1"` : "";
23258
23290
  const italicAttr = italic ? ` italic="1"` : "";
23259
23291
  const effFont = fontId;
23260
23292
  const boldEl = bold ? `<hh:bold/>` : "";
23261
23293
  return ` <hh:charPr id="${id}" height="${height}" textColor="${escapeXml(textColor)}" shadeColor="none" useFontSpace="0" useKerning="0" symMark="NONE" borderFillIDRef="1"${boldAttr}${italicAttr}>
23262
- <hh:fontRef hangul="${effFont}" latin="${effFont}" hanja="${effFont}" japanese="${effFont}" other="${effFont}" symbol="${effFont}" user="${effFont}"/>
23294
+ <hh:fontRef hangul="${effFont}" latin="${effFont}" hanja="${restFont}" japanese="${restFont}" other="${restFont}" symbol="${restFont}" user="${restFont}"/>
23263
23295
  <hh:ratio hangul="${ratioPct}" latin="${ratioPct}" hanja="${ratioPct}" japanese="100" other="100" symbol="100" user="100"/>
23264
23296
  <hh:spacing hangul="0" latin="0" hanja="0" japanese="0" other="0" symbol="0" user="0"/>
23265
23297
  <hh:relSz hangul="100" latin="100" hanja="100" japanese="100" other="100" symbol="100" user="100"/>
@@ -23975,7 +24007,7 @@ ${base2.join("\n")}
23975
24007
  ];
23976
24008
  const listAlign = gongmun.numbering === "gaejosik" || gongmun.numbering === "report" ? "LEFT" : "JUSTIFY";
23977
24009
  for (let d = 0; d < GONGMUN_LIST_LEVELS; d++) {
23978
- const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset));
24010
+ const { left, indent } = levelIndent(d, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset), levelMarkerHeight(gongmun, d));
23979
24011
  const sectionGap = gongmun.numbering === "gaejosik" || gongmun.numbering === "report" ? gaejosikSpaceBefore(d, gongmun.bodyHeight) : 0;
23980
24012
  const keepNext = (gongmun.numbering === "gaejosik" || gongmun.numbering === "report") && d === 0;
23981
24013
  base.push(paraPr(GONGMUN_LIST_BASE + d, { align: listAlign, lineSpacing: ls, left, indent, spaceBefore: sectionGap, keepWord: true, keepWithNext: keepNext }));
@@ -24404,6 +24436,7 @@ function computeGongmunFitPlan(blocks, gongmun, gongmunList) {
24404
24436
  if (block.type === "list_item" && gongmunList.items.has(i)) {
24405
24437
  const { marker, depth, indentVariant } = gongmunList.items.get(i);
24406
24438
  if (gongmun.numbering === "gaejosik" && (depth === 0 || (block.text || "").trimStart().startsWith("\u203B"))) continue;
24439
+ if (gongmun.levels?.[depth]) continue;
24407
24440
  const content = plainRenderText(block.text || "");
24408
24441
  text = marker ? `${marker} ${content}` : content;
24409
24442
  const li = levelIndent(depth, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset));
@@ -24469,8 +24502,9 @@ function precomputeGongmunList(blocks, gongmun) {
24469
24502
  const variantIdx = /* @__PURE__ */ new Map();
24470
24503
  const variantOf = (marker, depth) => {
24471
24504
  if (!marker || gongmun.numbering !== "standard") return void 0;
24472
- const w = markerWidth(marker, gongmun.bodyHeight);
24473
- const rep = -levelIndent(depth, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset)).indent;
24505
+ const h = levelMarkerHeight(gongmun, depth);
24506
+ const w = markerWidth(marker, h);
24507
+ const rep = -levelIndent(depth, gongmun.bodyHeight, gongmun.numbering, gongmun.sizes, gongmun.bullet2, usesAsteriskThird(gongmun.preset), h).indent;
24474
24508
  if (w === rep) return void 0;
24475
24509
  const key = `${depth}:${w}`;
24476
24510
  let vi = variantIdx.get(key);
@@ -26649,6 +26683,11 @@ function renderListItem(block, blockIdx, ctx) {
26649
26683
  mapId = void 0;
26650
26684
  }
26651
26685
  }
26686
+ const lv = ctx.levelIds?.[depth];
26687
+ if (lv) {
26688
+ listCharPr = lv.normal;
26689
+ mapId = (id) => id === CHAR_BOLD ? lv.bold : id === CHAR_NORMAL ? lv.normal : id;
26690
+ }
26652
26691
  return generateParagraph(text, listParaPr, listCharPr, mapId);
26653
26692
  }
26654
26693
  const indent = block.indent || 0;
@@ -26709,7 +26748,7 @@ function appendPostamble(blocks, ctx) {
26709
26748
  paraXmls.push(...buildPressContact(gongmun, dfIds, tableStyle.totalWidth, bfReg));
26710
26749
  }
26711
26750
  }
26712
- function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null, chartParts = null, bfReg = null, remap = null, dfIds = null, images = null, page = null) {
26751
+ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? precomputeGongmunList(blocks, gongmun) : null, fit = null, chartParts = null, bfReg = null, remap = null, dfIds = null, images = null, page = null, levelIds = null) {
26713
26752
  resetTableIds();
26714
26753
  resetGjTableIds();
26715
26754
  resetExtraTableIds();
@@ -26725,6 +26764,7 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
26725
26764
  remap,
26726
26765
  dfIds,
26727
26766
  images,
26767
+ levelIds,
26728
26768
  gaejosik: gongmun?.preset === "gaejosik",
26729
26769
  measured,
26730
26770
  richAssets,
@@ -26829,6 +26869,41 @@ function blocksToSectionXml(blocks, theme, gongmun, gongmunList = gongmun ? prec
26829
26869
  </hs:sec>`;
26830
26870
  }
26831
26871
 
26872
+ // src/hwpx/gen-levels.ts
26873
+ function levelDepths(g) {
26874
+ return g.levels ? Object.keys(g.levels).map(Number).sort((a, b) => a - b) : [];
26875
+ }
26876
+ function levelFontFaces(g) {
26877
+ const out = [];
26878
+ for (const d of levelDepths(g)) {
26879
+ const f = g.levels[d].font;
26880
+ if (f && !out.includes(f)) out.push(f);
26881
+ }
26882
+ return out;
26883
+ }
26884
+ function levelCharIds(g, base) {
26885
+ const depths = levelDepths(g);
26886
+ if (depths.length === 0) return null;
26887
+ const ids = {};
26888
+ depths.forEach((d, i) => {
26889
+ ids[d] = { normal: base + i * 2, bold: base + i * 2 + 1 };
26890
+ });
26891
+ return ids;
26892
+ }
26893
+ function levelCharPrXmls(g, base, fontBase, bodyFontId) {
26894
+ const ids = levelCharIds(g, base);
26895
+ if (!ids) return [];
26896
+ const faces = levelFontFaces(g);
26897
+ const out = [];
26898
+ for (const d of levelDepths(g)) {
26899
+ const st = g.levels[d];
26900
+ const fontId = st.font ? fontBase + faces.indexOf(st.font) : bodyFontId;
26901
+ out.push(charPr(ids[d].normal, st.height, st.bold, false, fontId, void 0, GONGMUN_BODY_RATIO, bodyFontId));
26902
+ out.push(charPr(ids[d].bold, st.height, true, false, fontId, void 0, GONGMUN_BODY_RATIO, bodyFontId));
26903
+ }
26904
+ return out;
26905
+ }
26906
+
26832
26907
  // src/hwpx/generator.ts
26833
26908
  async function markdownToHwpx(markdown, options) {
26834
26909
  const theme = resolveTheme(options?.theme);
@@ -26848,10 +26923,15 @@ async function markdownToHwpx(markdown, options) {
26848
26923
  const dfActive = !!gongmun && docframeActive(gongmun);
26849
26924
  const dfBase = charVariantBase(richAssets, !!gongmun) + (fit?.variants?.length ?? 0) * 4 + (remap?.charPrXmls.length ?? 0);
26850
26925
  const dfIds = dfActive ? docframeIds(dfBase) : null;
26926
+ const dfXmls = dfActive ? docframeCharPrXmls(dfBase, richAssets) : [];
26927
+ const lvBase = dfBase + dfXmls.length;
26928
+ const lvIds = gongmun ? levelCharIds(gongmun, lvBase) : null;
26929
+ const lvFonts = gongmun ? levelFontFaces(gongmun) : [];
26930
+ const lvXmls = gongmun ? levelCharPrXmls(gongmun, lvBase, staticFontNext(gongmun) + (remap?.fontFaces.length ?? 0), richAssets ? 4 : 0) : [];
26851
26931
  const chartParts = [];
26852
26932
  const supplied = options?.images ? new Map(Object.entries(options.images).map(([k, v]) => [k, v instanceof Uint8Array ? v : new Uint8Array(v)])) : void 0;
26853
26933
  const images = new ImageRegistry(supplied);
26854
- const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts, bfReg, remap, dfIds, images, page);
26934
+ const sectionXml = blocksToSectionXml(blocks, theme, gongmun, gongmunList, fit, chartParts, bfReg, remap, dfIds, images, page, lvIds);
26855
26935
  if (remap && remap.tables.length > 0) {
26856
26936
  const unused = remap.tables.filter((t) => !t.used).length;
26857
26937
  if (unused === remap.tables.length) {
@@ -26869,9 +26949,9 @@ async function markdownToHwpx(markdown, options) {
26869
26949
  gongmun,
26870
26950
  fit?.variants ?? [],
26871
26951
  extraBorderFills,
26872
- [...remap?.charPrXmls ?? [], ...dfActive ? docframeCharPrXmls(dfBase, richAssets) : []],
26952
+ [...remap?.charPrXmls ?? [], ...dfXmls, ...lvXmls],
26873
26953
  gongmunList?.indentVariants ?? [],
26874
- remap?.fontFaces ?? []
26954
+ [...remap?.fontFaces ?? [], ...lvFonts]
26875
26955
  ));
26876
26956
  zip.file("Contents/section0.xml", sectionXml);
26877
26957
  for (const part of chartParts) zip.file(part.name, part.xml);
@@ -28023,10 +28103,12 @@ var DISCRIM_FIXES = [
28023
28103
  var DISCRIM_RE = new RegExp(DISCRIM_FIXES.map(([w]) => w).sort((a, b) => b.length - a.length).join("|"), "g");
28024
28104
  var RULES = [
28025
28105
  // 날짜 ─ 온점 뒤 한 칸, 0 패딩 금지, 연도 4자리, 끝 마침표
28106
+ // 법령 연혁 표기 `<개정 2012.2.14>`·`삭제 <2016.2.29.>`·`[시행일:2017.9.8.]` 는 법제처 정본 형식(별지서식 표제) —
28107
+ // 편람 날짜 규칙 대상이 아니다 (v4.12.3: 서식 595건 DATE 156건 전부 이 꼴, 기안문 0건)
28026
28108
  {
28027
28109
  code: "DATE_NO_SPACE",
28028
28110
  severity: "error",
28029
- pattern: /\b\d{4}\.\d{1,2}\.\d{1,2}\.?/g,
28111
+ pattern: /(?<!<(?:개정|신설|전문개정|전부개정|일부개정|제정)\s*)(?<!삭제\s*<)(?<!시행일\s*:\s*)\b\d{4}\.\d{1,2}\.\d{1,2}\.?/g,
28030
28112
  message: "\uB0A0\uC9DC \uC628\uC810 \uB4A4\uC5D0 \uD55C \uCE78\uC529 \uB744\uC6CC\uC57C \uD568",
28031
28113
  suggest: "\uC608) 2025. 1. 6."
28032
28114
  },
@@ -28112,10 +28194,15 @@ var RULES = [
28112
28194
  suggest: "\uC608) \uC5C5\uBB34 \uD611\uC57D(MOU)"
28113
28195
  },
28114
28196
  // 쌍점 — URL(https:// 등)·시각(13:20)은 제외
28197
+ // 편람: 쌍점은 앞말에 붙이고 뒤는 1타(원장: 김갑동). 표 셀은 제외(skipTable) — 법정 별지서식
28198
+ // 자체가 "성 명 :"·"주 소 :" 라벨 셀을 쓰므로 서식 라벨은 이 규칙의 대상이 아니다(v4.12.3 실측:
28199
+ // 서식 595건의 표 셀 801건 전부 라벨, 기안문 206건은 본문 414건이 "일 시 : 값" 꼴 — 편람상 위반).
28200
+ // 뒤 글자에서 `<`(HTML 태그)·`*`·`_`(마크다운 강조 닫힘)는 제외 — "성명:</td>"·"과정:** 붙임" 오탐
28115
28201
  {
28116
28202
  code: "COLON_SPACE",
28117
28203
  severity: "warning",
28118
- pattern: /\S\s+:(?!\/\/)|\S:(?!\/\/)[^\s\d]/g,
28204
+ skipTable: true,
28205
+ pattern: /\S\s+:(?!\/\/)|\S:(?!\/\/)[^\s\d<*_]/g,
28119
28206
  message: "\uC30D\uC810\uC740 \uC55E\uB9D0\uC5D0 \uBD99\uC774\uACE0 \uB4A4\uB294 \uD55C \uCE78 \uB744\uC6C0",
28120
28207
  suggest: "\uC608) \uC6D0\uC7A5: \uAE40\uAC11\uB3D9"
28121
28208
  },
@@ -28195,7 +28282,9 @@ function lintGongmunText(text, opts) {
28195
28282
  continue;
28196
28283
  }
28197
28284
  if (fenceMarker !== null) continue;
28285
+ const tableLine = /^\s*\|/.test(line) || /<t[dhr][\s>]/i.test(line);
28198
28286
  for (const r of RULES) {
28287
+ if (r.skipTable && tableLine) continue;
28199
28288
  r.pattern.lastIndex = 0;
28200
28289
  for (const m of line.matchAll(r.pattern)) {
28201
28290
  findings.push({
@@ -32474,7 +32563,7 @@ async function dispatch(format, buffer, opts) {
32474
32563
  }
32475
32564
  async function parseImage(buffer, options) {
32476
32565
  try {
32477
- const { parseImageDocument } = await import("./image-ocr-CAVU2TNZ.js");
32566
+ const { parseImageDocument } = await import("./image-ocr-OLTSKQWD.js");
32478
32567
  const { blocks, warnings } = await parseImageDocument(buffer, options);
32479
32568
  return {
32480
32569
  success: true,
@@ -32533,7 +32622,7 @@ async function parseHwp(buffer, options) {
32533
32622
  async function parsePdf(buffer, options) {
32534
32623
  let parsePdfDocument;
32535
32624
  try {
32536
- const mod = await import("./parser-GIREMEPD.js");
32625
+ const mod = await import("./parser-JRT3B6OK.js");
32537
32626
  parsePdfDocument = mod.parsePdfDocument;
32538
32627
  } catch {
32539
32628
  return {