kordoc 4.23.0 → 4.24.0

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 (126) hide show
  1. package/README.md +3 -1
  2. package/dist/{-YNDBG7XO.js → -VEOO4BOM.js} +13 -11
  3. package/dist/{chunk-4AI32TFY.js → chunk-3M2BIQLZ.js} +2 -2
  4. package/dist/{chunk-2EVBM5NZ.js → chunk-4VPN5MHS.js} +2 -2
  5. package/dist/{chunk-VRIHNSYF.js → chunk-55DOBEGD.js} +2 -2
  6. package/dist/{chunk-2URKNOOQ.js → chunk-6YDPTTIY.js} +2 -2
  7. package/dist/{chunk-4XLDFJGY.js → chunk-CKCJU42Y.js} +6 -6
  8. package/dist/{chunk-5NBUT7GX.js → chunk-DBPDAG7N.js} +2 -2
  9. package/dist/{chunk-M6QZYQRH.cjs → chunk-DKWEZWCF.cjs} +3 -3
  10. package/dist/{chunk-M6QZYQRH.cjs.map → chunk-DKWEZWCF.cjs.map} +1 -1
  11. package/dist/{chunk-QO4PT3NN.js → chunk-DM5YPONO.js} +2 -2
  12. package/dist/{chunk-KLVN3EW7.cjs → chunk-DZT3CHNZ.cjs} +3 -3
  13. package/dist/{chunk-KLVN3EW7.cjs.map → chunk-DZT3CHNZ.cjs.map} +1 -1
  14. package/dist/{chunk-LJSKKGWU.js → chunk-EN3PK6OT.js} +2 -2
  15. package/dist/{chunk-6BUW4PJ3.js → chunk-ENCAYXDI.js} +4 -4
  16. package/dist/{chunk-I22NWH6W.cjs → chunk-FHFPQ6MX.cjs} +24 -24
  17. package/dist/{chunk-I22NWH6W.cjs.map → chunk-FHFPQ6MX.cjs.map} +1 -1
  18. package/dist/{chunk-W67KQWMU.js → chunk-G4HWEM6Q.js} +4 -4
  19. package/dist/{chunk-MSUBZT53.js → chunk-GEY6ZMXH.js} +177 -17
  20. package/dist/chunk-GEY6ZMXH.js.map +1 -0
  21. package/dist/{chunk-MA4NIAYO.js → chunk-H5PDQ66I.js} +3 -3
  22. package/dist/{chunk-5KLO56CJ.cjs → chunk-HOXHBG4C.cjs} +2 -2
  23. package/dist/{chunk-5KLO56CJ.cjs.map → chunk-HOXHBG4C.cjs.map} +1 -1
  24. package/dist/{chunk-IOBVLL5A.cjs → chunk-IHNIPVPJ.cjs} +6 -6
  25. package/dist/{chunk-IOBVLL5A.cjs.map → chunk-IHNIPVPJ.cjs.map} +1 -1
  26. package/dist/{chunk-YFCE7J37.js → chunk-IZYYKE5F.js} +2 -2
  27. package/dist/{chunk-2CHTPRDU.js → chunk-O2SLKE4L.js} +2 -2
  28. package/dist/{chunk-QXIZ5XSB.cjs → chunk-OHDGEGDJ.cjs} +23 -23
  29. package/dist/{chunk-QXIZ5XSB.cjs.map → chunk-OHDGEGDJ.cjs.map} +1 -1
  30. package/dist/{chunk-TFXWP5QI.js → chunk-OJISMR2Z.js} +2 -2
  31. package/dist/{chunk-67DVZL4W.js → chunk-P35SCAJN.js} +2 -2
  32. package/dist/{chunk-GZFL6UOS.js → chunk-P6FNIU5P.js} +2 -2
  33. package/dist/{chunk-A5HW2Z5T.js → chunk-PX6X4YOR.js} +4 -4
  34. package/dist/{chunk-XCSWST2A.js → chunk-SRUBDR3Z.js} +3 -3
  35. package/dist/{chunk-Y3LLNEU3.js → chunk-XLY5ZJRP.js} +2 -2
  36. package/dist/{chunk-UIZYWW3J.js → chunk-Z5G6QNVH.js} +2 -2
  37. package/dist/{chunk-S7B74SOM.js → chunk-Z62PHCSU.js} +3 -3
  38. package/dist/{chunk-6O2AUXFB.js → chunk-ZGNHJCDR.js} +2 -2
  39. package/dist/chunks-LV5EJBZ4.js +10 -0
  40. package/dist/cli.js +57 -30
  41. package/dist/cli.js.map +1 -1
  42. package/dist/{formula-ZULPRKJR.js → formula-4GRNVWIQ.js} +4 -4
  43. package/dist/{formula-JASN5ELL.js → formula-6Y467S4R.js} +3 -3
  44. package/dist/{formula-Z7JPTFAV.cjs → formula-R3OWFGCZ.cjs} +9 -9
  45. package/dist/{formula-Z7JPTFAV.cjs.map → formula-R3OWFGCZ.cjs.map} +1 -1
  46. package/dist/{image-ocr-IYFAHFQH.js → image-ocr-CGJJCD4E.js} +9 -9
  47. package/dist/{image-ocr-MJVZFMXW.cjs → image-ocr-EBKG45KF.cjs} +17 -17
  48. package/dist/{image-ocr-MJVZFMXW.cjs.map → image-ocr-EBKG45KF.cjs.map} +1 -1
  49. package/dist/{image-ocr-2ZWU6O5O.js → image-ocr-ZLL66KNO.js} +6 -6
  50. package/dist/index.cjs +847 -687
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +47 -1
  53. package/dist/index.d.ts +47 -1
  54. package/dist/index.js +172 -12
  55. package/dist/index.js.map +1 -1
  56. package/dist/mcp.js +40 -27
  57. package/dist/mcp.js.map +1 -1
  58. package/dist/{model-bundle-FD5ORLT4.js → model-bundle-RD4KSNTB.js} +5 -5
  59. package/dist/{models-CNXDF4BB.js → models-OLGCZBXI.js} +5 -5
  60. package/dist/{parse-worker-v2-GZIAKU6M.js → parse-worker-v2-YZY2GQY5.js} +51 -15
  61. package/dist/parse-worker-v2-YZY2GQY5.js.map +1 -0
  62. package/dist/{parser-MTUCDPDX.cjs → parser-DX4I3GT7.cjs} +157 -157
  63. package/dist/{parser-MTUCDPDX.cjs.map → parser-DX4I3GT7.cjs.map} +1 -1
  64. package/dist/{parser-OQ4FLNBE.js → parser-IHCFHLHN.js} +12 -12
  65. package/dist/{parser-WTOPH3C2.js → parser-J22QBXPP.js} +9 -9
  66. package/dist/{pdf-ocr-V346MK77.js → pdf-ocr-H2247ZZH.js} +6 -6
  67. package/dist/{pdf-ocr-IBZRT65M.js → pdf-ocr-TYIH23RP.js} +9 -9
  68. package/dist/pdf-ocr-WU7SZHWM.cjs +31 -0
  69. package/dist/{pdf-ocr-EW34T34R.cjs.map → pdf-ocr-WU7SZHWM.cjs.map} +1 -1
  70. package/dist/{profile-io-UFTSKMWU.js → profile-io-GH3TYTNJ.js} +3 -3
  71. package/dist/{rasterize-SXIF5J5K.js → rasterize-7TFTVFMB.js} +3 -3
  72. package/dist/{redact-doc-P6XQ6B6U.js → redact-doc-DSSQOO3A.js} +11 -11
  73. package/dist/{render-QW56QMUE.js → render-NKXZQINI.js} +7 -7
  74. package/dist/seal-JIVSSI3Z.js +10 -0
  75. package/dist/{setup-RIZUPKAE.js → setup-JVLMX2TH.js} +3 -3
  76. package/dist/visual-BKVZN6HP.js +21 -0
  77. package/dist/{watch-TAHHXY7Z.js → watch-5RZVHAKI.js} +12 -12
  78. package/package.json +1 -1
  79. package/dist/chunk-MSUBZT53.js.map +0 -1
  80. package/dist/chunks-LX2EPPSD.js +0 -10
  81. package/dist/parse-worker-v2-GZIAKU6M.js.map +0 -1
  82. package/dist/pdf-ocr-EW34T34R.cjs +0 -31
  83. package/dist/seal-HMXHWFBA.js +0 -10
  84. package/dist/visual-X7OFXY4M.js +0 -21
  85. /package/dist/{-YNDBG7XO.js.map → -VEOO4BOM.js.map} +0 -0
  86. /package/dist/{chunk-4AI32TFY.js.map → chunk-3M2BIQLZ.js.map} +0 -0
  87. /package/dist/{chunk-2EVBM5NZ.js.map → chunk-4VPN5MHS.js.map} +0 -0
  88. /package/dist/{chunk-VRIHNSYF.js.map → chunk-55DOBEGD.js.map} +0 -0
  89. /package/dist/{chunk-2URKNOOQ.js.map → chunk-6YDPTTIY.js.map} +0 -0
  90. /package/dist/{chunk-4XLDFJGY.js.map → chunk-CKCJU42Y.js.map} +0 -0
  91. /package/dist/{chunk-5NBUT7GX.js.map → chunk-DBPDAG7N.js.map} +0 -0
  92. /package/dist/{chunk-QO4PT3NN.js.map → chunk-DM5YPONO.js.map} +0 -0
  93. /package/dist/{chunk-LJSKKGWU.js.map → chunk-EN3PK6OT.js.map} +0 -0
  94. /package/dist/{chunk-6BUW4PJ3.js.map → chunk-ENCAYXDI.js.map} +0 -0
  95. /package/dist/{chunk-W67KQWMU.js.map → chunk-G4HWEM6Q.js.map} +0 -0
  96. /package/dist/{chunk-MA4NIAYO.js.map → chunk-H5PDQ66I.js.map} +0 -0
  97. /package/dist/{chunk-YFCE7J37.js.map → chunk-IZYYKE5F.js.map} +0 -0
  98. /package/dist/{chunk-2CHTPRDU.js.map → chunk-O2SLKE4L.js.map} +0 -0
  99. /package/dist/{chunk-TFXWP5QI.js.map → chunk-OJISMR2Z.js.map} +0 -0
  100. /package/dist/{chunk-67DVZL4W.js.map → chunk-P35SCAJN.js.map} +0 -0
  101. /package/dist/{chunk-GZFL6UOS.js.map → chunk-P6FNIU5P.js.map} +0 -0
  102. /package/dist/{chunk-A5HW2Z5T.js.map → chunk-PX6X4YOR.js.map} +0 -0
  103. /package/dist/{chunk-XCSWST2A.js.map → chunk-SRUBDR3Z.js.map} +0 -0
  104. /package/dist/{chunk-Y3LLNEU3.js.map → chunk-XLY5ZJRP.js.map} +0 -0
  105. /package/dist/{chunk-UIZYWW3J.js.map → chunk-Z5G6QNVH.js.map} +0 -0
  106. /package/dist/{chunk-S7B74SOM.js.map → chunk-Z62PHCSU.js.map} +0 -0
  107. /package/dist/{chunk-6O2AUXFB.js.map → chunk-ZGNHJCDR.js.map} +0 -0
  108. /package/dist/{chunks-LX2EPPSD.js.map → chunks-LV5EJBZ4.js.map} +0 -0
  109. /package/dist/{formula-ZULPRKJR.js.map → formula-4GRNVWIQ.js.map} +0 -0
  110. /package/dist/{formula-JASN5ELL.js.map → formula-6Y467S4R.js.map} +0 -0
  111. /package/dist/{image-ocr-IYFAHFQH.js.map → image-ocr-CGJJCD4E.js.map} +0 -0
  112. /package/dist/{image-ocr-2ZWU6O5O.js.map → image-ocr-ZLL66KNO.js.map} +0 -0
  113. /package/dist/{model-bundle-FD5ORLT4.js.map → model-bundle-RD4KSNTB.js.map} +0 -0
  114. /package/dist/{models-CNXDF4BB.js.map → models-OLGCZBXI.js.map} +0 -0
  115. /package/dist/{parser-OQ4FLNBE.js.map → parser-IHCFHLHN.js.map} +0 -0
  116. /package/dist/{parser-WTOPH3C2.js.map → parser-J22QBXPP.js.map} +0 -0
  117. /package/dist/{pdf-ocr-IBZRT65M.js.map → pdf-ocr-H2247ZZH.js.map} +0 -0
  118. /package/dist/{pdf-ocr-V346MK77.js.map → pdf-ocr-TYIH23RP.js.map} +0 -0
  119. /package/dist/{profile-io-UFTSKMWU.js.map → profile-io-GH3TYTNJ.js.map} +0 -0
  120. /package/dist/{rasterize-SXIF5J5K.js.map → rasterize-7TFTVFMB.js.map} +0 -0
  121. /package/dist/{redact-doc-P6XQ6B6U.js.map → redact-doc-DSSQOO3A.js.map} +0 -0
  122. /package/dist/{render-QW56QMUE.js.map → render-NKXZQINI.js.map} +0 -0
  123. /package/dist/{seal-HMXHWFBA.js.map → seal-JIVSSI3Z.js.map} +0 -0
  124. /package/dist/{setup-RIZUPKAE.js.map → setup-JVLMX2TH.js.map} +0 -0
  125. /package/dist/{visual-X7OFXY4M.js.map → visual-BKVZN6HP.js.map} +0 -0
  126. /package/dist/{watch-TAHHXY7Z.js.map → watch-5RZVHAKI.js.map} +0 -0
package/dist/index.d.cts CHANGED
@@ -1732,6 +1732,52 @@ interface LintSuiteResult {
1732
1732
  }
1733
1733
  declare function runLintSuite(text: string, opts?: LintSuiteOptions): LintSuiteResult;
1734
1734
 
1735
+ /**
1736
+ * 블록 단위 검수 — 문단·표 칸을 id 가 붙은 블록으로 받아, 지적을 "블록 id + 블록 안 글자 위치"로 돌려준다.
1737
+ *
1738
+ * 열린 문서를 고치는 도구(한/글 실시간 편집 kordoc-auto, 내장 편집기 kordoc-ai)는 문서를 마크다운 줄로 펼쳤다가 줄·글자
1739
+ * 위치를 다시 문단·칸으로 되짚어야 했다. 그 펼치기·되짚기를 여기 한곳에 둔다:
1740
+ * - 문단은 한 줄. 마크다운 구조(펜스·제목·표·인용)로 읽히는 줄은 앞에 \ 를 붙여 글자로 읽게 하고 위치를 그만큼 민다
1741
+ * - 표는 GFM 표(앞뒤 빈 줄, 머리행 뒤 구분 줄). 칸 글의 | 는 같은 길이의 전각 막대로, 줄바꿈은 빈칸으로(길이 불변)
1742
+ * - 칸이 하나뿐인 표(요약 상자·글 상자)는 데이터 표가 아니라 본문 — 표 줄로 쓰면 표 칸 예외(쉬운 말·쌍점)가 적용돼 놓친다
1743
+ * 위치는 모두 UTF-16 단위(자바스크립트 문자열 위치)다.
1744
+ */
1745
+
1746
+ interface LintBlock {
1747
+ /** 호출 쪽이 정한 블록 id (문단·칸 위치를 되찾는 열쇠) */
1748
+ id: string;
1749
+ /** 문단 글 또는 칸 글 */
1750
+ text: string;
1751
+ /** 표 칸이면 표 id 와 0부터 센 행·열 — 같은 표 id 의 칸들이 한 표로 묶인다 */
1752
+ table?: {
1753
+ id: string;
1754
+ row: number;
1755
+ col: number;
1756
+ };
1757
+ }
1758
+ interface BlockFinding {
1759
+ /** 걸린 블록 id — 블록을 정할 수 없는 지적(문서 단위)은 null */
1760
+ block: string | null;
1761
+ /** 블록 글 안 위치(0부터, UTF-16) — 블록 전체에 걸린 지적(문체 등)은 null */
1762
+ offset: number | null;
1763
+ /** match 길이(UTF-16) */
1764
+ length: number;
1765
+ category: "notation" | "munche" | "slop" | "logic" | "budget";
1766
+ rule: string;
1767
+ severity: "error" | "warning";
1768
+ match: string;
1769
+ message: string;
1770
+ suggest?: string;
1771
+ }
1772
+ interface LintBlocksResult {
1773
+ findings: BlockFinding[];
1774
+ /** 표에서 찾지 못한 본문 수치(확인 목록) — numbers 를 켰을 때 */
1775
+ numbers?: LintSuiteResult["numbers"];
1776
+ summary: LintSuiteResult["summary"];
1777
+ }
1778
+ /** 블록 단위 검수 — 검수 판정은 runLintSuite(CLI·MCP 와 같음), 위치만 블록으로 */
1779
+ declare function lintBlocks(blocks: readonly LintBlock[], opts?: LintSuiteOptions): LintBlocksResult;
1780
+
1735
1781
  /**
1736
1782
  * 한글 조판 텍스트 폭 계산 — 함초롬바탕(HCR Batang) 실측 advance 테이블
1737
1783
  *
@@ -2760,4 +2806,4 @@ interface FillFormOutput {
2760
2806
  */
2761
2807
  declare function fillForm(input: string | ArrayBuffer | Buffer, values: Record<string, FillInput>, outputFormat?: FillOutputFormat): Promise<FillFormOutput>;
2762
2808
 
2763
- export { AGENCY_COMMON_NAME, type AgencyFont, type AgencyPressStyle, type AgencyReportStyle, type AgencyStyle, BUILTIN_TEMPLATES, type BlockCapability, type BlockCapabilityInfo, type BlockDiff, type BlockEdit, type BlockSourceRef, type BorderDef, type BorderFillDef, type BoundingBox, type BuiltinTemplate, type CellCapability, type CellContext, type CellDiff, type CellProfile, type CharPrDef, type ChunkOptions, type ClassifyContext, type ClickHereField, DEFAULT_REDACT_RULES, type DiffChangeType, type DiffResult, type DocChunk, type DocumentMetadata, type DocumentQualitySummary, type ErrorCode, type ExtractRegionOptions, type ExtractTableVisualOptions, type ExtractedImage, type ExtractedTable, type ExtractedTableCrop, type FileType, type FillFormOutput, type FillInput, type FillOutputFormat, type FillResult, type FillValue, type FormField, type FormFieldSchema, type FormFieldType, type FormResult, type FormSchemaResult, type FormatProfile, type GongmunFont, type GongmunGateAxis, type GongmunGateFinding, type GongmunGateResult, type GongmunLintFinding, type GongmunNumbering, type GongmunOptions, type GongmunPreset, type GongmunPresetInput, type HwpxFillResult, HwpxSession, type HwpxTheme, type IRBlock, type IRBlockType, type IRCell, type IRTable, type ImageData, type InlineStyle, type LintSuiteOptions, type LintSuiteResult, type MarkdownOptions, type MarkdownToHwpxOptions, type MeasureOptions, type MuncheLineKind, type MuncheLintFinding, type OcrLine, type OcrModelFile, type OcrPageLines, type OcrProvider, type OutlineItem, PRESET_ALIAS, type PageBBox, type PageMargin, type PageMarkdown, type PageOptions, type PageQuality, type ParseFailure, type ParseOptions, type ParseResult, type ParseSuccess, type ParseWarning, type PatchOptions, type PatchResult, type PatchSkip, type PlaceSealResult, type PrintOptions, type PrintPreset, type RedactHit, type RedactOptions, type RedactRule, type RedactTextResult, type RegionAsset, type RenderAsset, type RenderDocumentOptions, type RenderDocumentResult, type RenderFormat, type RenderObjectType, type RenderRegion, type RenderScene, type RenderSourceFormat, type RenderSvgOptions, type RenderSvgResult, SPACE_EM_FIXED, SPACE_EM_FONT, type ScanCell, type ScanParaKind, type ScanParagraph, type ScanTable, type ScenePage, type SceneRenderOptions, type SceneRenderResult, type SealOp, type SealPlacement, type SectionScan, type SpliceEdit, type TRange, type TableProfile, type TableRepresentation, type TableVisualPolicy, type TotalRowPosition, VERSION, type ValidateIssue, type ValidateResult, ValueCursor, type WarningCode, type WatchOptions, type WrapMode, type WrapResult, agencyNames, agencyStyle, applySplices, blocksToChunks, blocksToMarkdown, blocksToPages, blocksToPdf, buildParagraphSplices, buildRangeSplices, charWidthEm1000, chooseTableRepresentation, classifyTable, classifyTableTree, collectTableBlocks, compare, detectFormat, detectOle2Format, detectZipFormat, diffBlocks, extractClickHereFields, extractFormFields, extractFormSchema, extractRenderedRegions, extractTables, fillForm, fillFormFields, fillHwpx, fillWithUniqueGuard, fitRatioForFewerLines, flattenLayoutTables, formatFillValue, formatGateFinding, gongmunGate, gongmunLintWarnings, hasStructuredCellContent, hwpxToProfile, incompatibleGongmunWarnings, inferFieldType, isHwpxFile, isKnownFont, isLabelCell, isOldHwpFile, isPdfFile, isZipFile, lintBudgetText, lintGongmunText, lintLogicText, lintMuncheText, lintSlopText, logicLintWarnings, markdownToHwpx, markdownToPdf, measureTextWidth, muncheLintWarnings, normalizeGongmunPreset, openHwpxDocument, parse, parseDocx, parseHwp, parseHwp3, parseHwpml, parseHwpx, parseImage, parsePdf, parsePptx, parseXls, parseXlsx, patchHwp, patchHwpx, patchHwpxBlocks, placeSealHwpx, placeTotalRow, readBuiltinTemplate, readBuiltinTemplateSample, redactMarkdown, redactText, renderDocument, renderDocumentToScene, renderHtml, renderHwp5Pages, renderHwpxToSvg, renderSceneToHtml, resolveBuiltinTemplate, runLintSuite, scanSectionXml, simulateWrap, simulateWrapKeepWord, slopLintWarnings, unknownFontWarnings, usesGaejosikMunche, usesLogicStructure, validateHwpx };
2809
+ export { AGENCY_COMMON_NAME, type AgencyFont, type AgencyPressStyle, type AgencyReportStyle, type AgencyStyle, BUILTIN_TEMPLATES, type BlockCapability, type BlockCapabilityInfo, type BlockDiff, type BlockEdit, type BlockFinding, type BlockSourceRef, type BorderDef, type BorderFillDef, type BoundingBox, type BuiltinTemplate, type CellCapability, type CellContext, type CellDiff, type CellProfile, type CharPrDef, type ChunkOptions, type ClassifyContext, type ClickHereField, DEFAULT_REDACT_RULES, type DiffChangeType, type DiffResult, type DocChunk, type DocumentMetadata, type DocumentQualitySummary, type ErrorCode, type ExtractRegionOptions, type ExtractTableVisualOptions, type ExtractedImage, type ExtractedTable, type ExtractedTableCrop, type FileType, type FillFormOutput, type FillInput, type FillOutputFormat, type FillResult, type FillValue, type FormField, type FormFieldSchema, type FormFieldType, type FormResult, type FormSchemaResult, type FormatProfile, type GongmunFont, type GongmunGateAxis, type GongmunGateFinding, type GongmunGateResult, type GongmunLintFinding, type GongmunNumbering, type GongmunOptions, type GongmunPreset, type GongmunPresetInput, type HwpxFillResult, HwpxSession, type HwpxTheme, type IRBlock, type IRBlockType, type IRCell, type IRTable, type ImageData, type InlineStyle, type LintBlock, type LintBlocksResult, type LintSuiteOptions, type LintSuiteResult, type MarkdownOptions, type MarkdownToHwpxOptions, type MeasureOptions, type MuncheLineKind, type MuncheLintFinding, type OcrLine, type OcrModelFile, type OcrPageLines, type OcrProvider, type OutlineItem, PRESET_ALIAS, type PageBBox, type PageMargin, type PageMarkdown, type PageOptions, type PageQuality, type ParseFailure, type ParseOptions, type ParseResult, type ParseSuccess, type ParseWarning, type PatchOptions, type PatchResult, type PatchSkip, type PlaceSealResult, type PrintOptions, type PrintPreset, type RedactHit, type RedactOptions, type RedactRule, type RedactTextResult, type RegionAsset, type RenderAsset, type RenderDocumentOptions, type RenderDocumentResult, type RenderFormat, type RenderObjectType, type RenderRegion, type RenderScene, type RenderSourceFormat, type RenderSvgOptions, type RenderSvgResult, SPACE_EM_FIXED, SPACE_EM_FONT, type ScanCell, type ScanParaKind, type ScanParagraph, type ScanTable, type ScenePage, type SceneRenderOptions, type SceneRenderResult, type SealOp, type SealPlacement, type SectionScan, type SpliceEdit, type TRange, type TableProfile, type TableRepresentation, type TableVisualPolicy, type TotalRowPosition, VERSION, type ValidateIssue, type ValidateResult, ValueCursor, type WarningCode, type WatchOptions, type WrapMode, type WrapResult, agencyNames, agencyStyle, applySplices, blocksToChunks, blocksToMarkdown, blocksToPages, blocksToPdf, buildParagraphSplices, buildRangeSplices, charWidthEm1000, chooseTableRepresentation, classifyTable, classifyTableTree, collectTableBlocks, compare, detectFormat, detectOle2Format, detectZipFormat, diffBlocks, extractClickHereFields, extractFormFields, extractFormSchema, extractRenderedRegions, extractTables, fillForm, fillFormFields, fillHwpx, fillWithUniqueGuard, fitRatioForFewerLines, flattenLayoutTables, formatFillValue, formatGateFinding, gongmunGate, gongmunLintWarnings, hasStructuredCellContent, hwpxToProfile, incompatibleGongmunWarnings, inferFieldType, isHwpxFile, isKnownFont, isLabelCell, isOldHwpFile, isPdfFile, isZipFile, lintBlocks, lintBudgetText, lintGongmunText, lintLogicText, lintMuncheText, lintSlopText, logicLintWarnings, markdownToHwpx, markdownToPdf, measureTextWidth, muncheLintWarnings, normalizeGongmunPreset, openHwpxDocument, parse, parseDocx, parseHwp, parseHwp3, parseHwpml, parseHwpx, parseImage, parsePdf, parsePptx, parseXls, parseXlsx, patchHwp, patchHwpx, patchHwpxBlocks, placeSealHwpx, placeTotalRow, readBuiltinTemplate, readBuiltinTemplateSample, redactMarkdown, redactText, renderDocument, renderDocumentToScene, renderHtml, renderHwp5Pages, renderHwpxToSvg, renderSceneToHtml, resolveBuiltinTemplate, runLintSuite, scanSectionXml, simulateWrap, simulateWrapKeepWord, slopLintWarnings, unknownFontWarnings, usesGaejosikMunche, usesLogicStructure, validateHwpx };
package/dist/index.d.ts CHANGED
@@ -1732,6 +1732,52 @@ interface LintSuiteResult {
1732
1732
  }
1733
1733
  declare function runLintSuite(text: string, opts?: LintSuiteOptions): LintSuiteResult;
1734
1734
 
1735
+ /**
1736
+ * 블록 단위 검수 — 문단·표 칸을 id 가 붙은 블록으로 받아, 지적을 "블록 id + 블록 안 글자 위치"로 돌려준다.
1737
+ *
1738
+ * 열린 문서를 고치는 도구(한/글 실시간 편집 kordoc-auto, 내장 편집기 kordoc-ai)는 문서를 마크다운 줄로 펼쳤다가 줄·글자
1739
+ * 위치를 다시 문단·칸으로 되짚어야 했다. 그 펼치기·되짚기를 여기 한곳에 둔다:
1740
+ * - 문단은 한 줄. 마크다운 구조(펜스·제목·표·인용)로 읽히는 줄은 앞에 \ 를 붙여 글자로 읽게 하고 위치를 그만큼 민다
1741
+ * - 표는 GFM 표(앞뒤 빈 줄, 머리행 뒤 구분 줄). 칸 글의 | 는 같은 길이의 전각 막대로, 줄바꿈은 빈칸으로(길이 불변)
1742
+ * - 칸이 하나뿐인 표(요약 상자·글 상자)는 데이터 표가 아니라 본문 — 표 줄로 쓰면 표 칸 예외(쉬운 말·쌍점)가 적용돼 놓친다
1743
+ * 위치는 모두 UTF-16 단위(자바스크립트 문자열 위치)다.
1744
+ */
1745
+
1746
+ interface LintBlock {
1747
+ /** 호출 쪽이 정한 블록 id (문단·칸 위치를 되찾는 열쇠) */
1748
+ id: string;
1749
+ /** 문단 글 또는 칸 글 */
1750
+ text: string;
1751
+ /** 표 칸이면 표 id 와 0부터 센 행·열 — 같은 표 id 의 칸들이 한 표로 묶인다 */
1752
+ table?: {
1753
+ id: string;
1754
+ row: number;
1755
+ col: number;
1756
+ };
1757
+ }
1758
+ interface BlockFinding {
1759
+ /** 걸린 블록 id — 블록을 정할 수 없는 지적(문서 단위)은 null */
1760
+ block: string | null;
1761
+ /** 블록 글 안 위치(0부터, UTF-16) — 블록 전체에 걸린 지적(문체 등)은 null */
1762
+ offset: number | null;
1763
+ /** match 길이(UTF-16) */
1764
+ length: number;
1765
+ category: "notation" | "munche" | "slop" | "logic" | "budget";
1766
+ rule: string;
1767
+ severity: "error" | "warning";
1768
+ match: string;
1769
+ message: string;
1770
+ suggest?: string;
1771
+ }
1772
+ interface LintBlocksResult {
1773
+ findings: BlockFinding[];
1774
+ /** 표에서 찾지 못한 본문 수치(확인 목록) — numbers 를 켰을 때 */
1775
+ numbers?: LintSuiteResult["numbers"];
1776
+ summary: LintSuiteResult["summary"];
1777
+ }
1778
+ /** 블록 단위 검수 — 검수 판정은 runLintSuite(CLI·MCP 와 같음), 위치만 블록으로 */
1779
+ declare function lintBlocks(blocks: readonly LintBlock[], opts?: LintSuiteOptions): LintBlocksResult;
1780
+
1735
1781
  /**
1736
1782
  * 한글 조판 텍스트 폭 계산 — 함초롬바탕(HCR Batang) 실측 advance 테이블
1737
1783
  *
@@ -2760,4 +2806,4 @@ interface FillFormOutput {
2760
2806
  */
2761
2807
  declare function fillForm(input: string | ArrayBuffer | Buffer, values: Record<string, FillInput>, outputFormat?: FillOutputFormat): Promise<FillFormOutput>;
2762
2808
 
2763
- export { AGENCY_COMMON_NAME, type AgencyFont, type AgencyPressStyle, type AgencyReportStyle, type AgencyStyle, BUILTIN_TEMPLATES, type BlockCapability, type BlockCapabilityInfo, type BlockDiff, type BlockEdit, type BlockSourceRef, type BorderDef, type BorderFillDef, type BoundingBox, type BuiltinTemplate, type CellCapability, type CellContext, type CellDiff, type CellProfile, type CharPrDef, type ChunkOptions, type ClassifyContext, type ClickHereField, DEFAULT_REDACT_RULES, type DiffChangeType, type DiffResult, type DocChunk, type DocumentMetadata, type DocumentQualitySummary, type ErrorCode, type ExtractRegionOptions, type ExtractTableVisualOptions, type ExtractedImage, type ExtractedTable, type ExtractedTableCrop, type FileType, type FillFormOutput, type FillInput, type FillOutputFormat, type FillResult, type FillValue, type FormField, type FormFieldSchema, type FormFieldType, type FormResult, type FormSchemaResult, type FormatProfile, type GongmunFont, type GongmunGateAxis, type GongmunGateFinding, type GongmunGateResult, type GongmunLintFinding, type GongmunNumbering, type GongmunOptions, type GongmunPreset, type GongmunPresetInput, type HwpxFillResult, HwpxSession, type HwpxTheme, type IRBlock, type IRBlockType, type IRCell, type IRTable, type ImageData, type InlineStyle, type LintSuiteOptions, type LintSuiteResult, type MarkdownOptions, type MarkdownToHwpxOptions, type MeasureOptions, type MuncheLineKind, type MuncheLintFinding, type OcrLine, type OcrModelFile, type OcrPageLines, type OcrProvider, type OutlineItem, PRESET_ALIAS, type PageBBox, type PageMargin, type PageMarkdown, type PageOptions, type PageQuality, type ParseFailure, type ParseOptions, type ParseResult, type ParseSuccess, type ParseWarning, type PatchOptions, type PatchResult, type PatchSkip, type PlaceSealResult, type PrintOptions, type PrintPreset, type RedactHit, type RedactOptions, type RedactRule, type RedactTextResult, type RegionAsset, type RenderAsset, type RenderDocumentOptions, type RenderDocumentResult, type RenderFormat, type RenderObjectType, type RenderRegion, type RenderScene, type RenderSourceFormat, type RenderSvgOptions, type RenderSvgResult, SPACE_EM_FIXED, SPACE_EM_FONT, type ScanCell, type ScanParaKind, type ScanParagraph, type ScanTable, type ScenePage, type SceneRenderOptions, type SceneRenderResult, type SealOp, type SealPlacement, type SectionScan, type SpliceEdit, type TRange, type TableProfile, type TableRepresentation, type TableVisualPolicy, type TotalRowPosition, VERSION, type ValidateIssue, type ValidateResult, ValueCursor, type WarningCode, type WatchOptions, type WrapMode, type WrapResult, agencyNames, agencyStyle, applySplices, blocksToChunks, blocksToMarkdown, blocksToPages, blocksToPdf, buildParagraphSplices, buildRangeSplices, charWidthEm1000, chooseTableRepresentation, classifyTable, classifyTableTree, collectTableBlocks, compare, detectFormat, detectOle2Format, detectZipFormat, diffBlocks, extractClickHereFields, extractFormFields, extractFormSchema, extractRenderedRegions, extractTables, fillForm, fillFormFields, fillHwpx, fillWithUniqueGuard, fitRatioForFewerLines, flattenLayoutTables, formatFillValue, formatGateFinding, gongmunGate, gongmunLintWarnings, hasStructuredCellContent, hwpxToProfile, incompatibleGongmunWarnings, inferFieldType, isHwpxFile, isKnownFont, isLabelCell, isOldHwpFile, isPdfFile, isZipFile, lintBudgetText, lintGongmunText, lintLogicText, lintMuncheText, lintSlopText, logicLintWarnings, markdownToHwpx, markdownToPdf, measureTextWidth, muncheLintWarnings, normalizeGongmunPreset, openHwpxDocument, parse, parseDocx, parseHwp, parseHwp3, parseHwpml, parseHwpx, parseImage, parsePdf, parsePptx, parseXls, parseXlsx, patchHwp, patchHwpx, patchHwpxBlocks, placeSealHwpx, placeTotalRow, readBuiltinTemplate, readBuiltinTemplateSample, redactMarkdown, redactText, renderDocument, renderDocumentToScene, renderHtml, renderHwp5Pages, renderHwpxToSvg, renderSceneToHtml, resolveBuiltinTemplate, runLintSuite, scanSectionXml, simulateWrap, simulateWrapKeepWord, slopLintWarnings, unknownFontWarnings, usesGaejosikMunche, usesLogicStructure, validateHwpx };
2809
+ export { AGENCY_COMMON_NAME, type AgencyFont, type AgencyPressStyle, type AgencyReportStyle, type AgencyStyle, BUILTIN_TEMPLATES, type BlockCapability, type BlockCapabilityInfo, type BlockDiff, type BlockEdit, type BlockFinding, type BlockSourceRef, type BorderDef, type BorderFillDef, type BoundingBox, type BuiltinTemplate, type CellCapability, type CellContext, type CellDiff, type CellProfile, type CharPrDef, type ChunkOptions, type ClassifyContext, type ClickHereField, DEFAULT_REDACT_RULES, type DiffChangeType, type DiffResult, type DocChunk, type DocumentMetadata, type DocumentQualitySummary, type ErrorCode, type ExtractRegionOptions, type ExtractTableVisualOptions, type ExtractedImage, type ExtractedTable, type ExtractedTableCrop, type FileType, type FillFormOutput, type FillInput, type FillOutputFormat, type FillResult, type FillValue, type FormField, type FormFieldSchema, type FormFieldType, type FormResult, type FormSchemaResult, type FormatProfile, type GongmunFont, type GongmunGateAxis, type GongmunGateFinding, type GongmunGateResult, type GongmunLintFinding, type GongmunNumbering, type GongmunOptions, type GongmunPreset, type GongmunPresetInput, type HwpxFillResult, HwpxSession, type HwpxTheme, type IRBlock, type IRBlockType, type IRCell, type IRTable, type ImageData, type InlineStyle, type LintBlock, type LintBlocksResult, type LintSuiteOptions, type LintSuiteResult, type MarkdownOptions, type MarkdownToHwpxOptions, type MeasureOptions, type MuncheLineKind, type MuncheLintFinding, type OcrLine, type OcrModelFile, type OcrPageLines, type OcrProvider, type OutlineItem, PRESET_ALIAS, type PageBBox, type PageMargin, type PageMarkdown, type PageOptions, type PageQuality, type ParseFailure, type ParseOptions, type ParseResult, type ParseSuccess, type ParseWarning, type PatchOptions, type PatchResult, type PatchSkip, type PlaceSealResult, type PrintOptions, type PrintPreset, type RedactHit, type RedactOptions, type RedactRule, type RedactTextResult, type RegionAsset, type RenderAsset, type RenderDocumentOptions, type RenderDocumentResult, type RenderFormat, type RenderObjectType, type RenderRegion, type RenderScene, type RenderSourceFormat, type RenderSvgOptions, type RenderSvgResult, SPACE_EM_FIXED, SPACE_EM_FONT, type ScanCell, type ScanParaKind, type ScanParagraph, type ScanTable, type ScenePage, type SceneRenderOptions, type SceneRenderResult, type SealOp, type SealPlacement, type SectionScan, type SpliceEdit, type TRange, type TableProfile, type TableRepresentation, type TableVisualPolicy, type TotalRowPosition, VERSION, type ValidateIssue, type ValidateResult, ValueCursor, type WarningCode, type WatchOptions, type WrapMode, type WrapResult, agencyNames, agencyStyle, applySplices, blocksToChunks, blocksToMarkdown, blocksToPages, blocksToPdf, buildParagraphSplices, buildRangeSplices, charWidthEm1000, chooseTableRepresentation, classifyTable, classifyTableTree, collectTableBlocks, compare, detectFormat, detectOle2Format, detectZipFormat, diffBlocks, extractClickHereFields, extractFormFields, extractFormSchema, extractRenderedRegions, extractTables, fillForm, fillFormFields, fillHwpx, fillWithUniqueGuard, fitRatioForFewerLines, flattenLayoutTables, formatFillValue, formatGateFinding, gongmunGate, gongmunLintWarnings, hasStructuredCellContent, hwpxToProfile, incompatibleGongmunWarnings, inferFieldType, isHwpxFile, isKnownFont, isLabelCell, isOldHwpFile, isPdfFile, isZipFile, lintBlocks, lintBudgetText, lintGongmunText, lintLogicText, lintMuncheText, lintSlopText, logicLintWarnings, markdownToHwpx, markdownToPdf, measureTextWidth, muncheLintWarnings, normalizeGongmunPreset, openHwpxDocument, parse, parseDocx, parseHwp, parseHwp3, parseHwpml, parseHwpx, parseImage, parsePdf, parsePptx, parseXls, parseXlsx, patchHwp, patchHwpx, patchHwpxBlocks, placeSealHwpx, placeTotalRow, readBuiltinTemplate, readBuiltinTemplateSample, redactMarkdown, redactText, renderDocument, renderDocumentToScene, renderHtml, renderHwp5Pages, renderHwpxToSvg, renderSceneToHtml, resolveBuiltinTemplate, runLintSuite, scanSectionXml, simulateWrap, simulateWrapKeepWord, slopLintWarnings, unknownFontWarnings, usesGaejosikMunche, usesLogicStructure, validateHwpx };
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  blocksToPages,
3
3
  bmpToPng,
4
4
  inlineImagesIntoMarkdown
5
- } from "./chunk-67DVZL4W.js";
5
+ } from "./chunk-P35SCAJN.js";
6
6
  import {
7
7
  parsePageRange
8
8
  } from "./chunk-V4BH5SRQ.js";
@@ -43,7 +43,7 @@ import {
43
43
  validateOcrOptions,
44
44
  visibleText,
45
45
  wrapScript
46
- } from "./chunk-2URKNOOQ.js";
46
+ } from "./chunk-6YDPTTIY.js";
47
47
  import {
48
48
  KordocError,
49
49
  OPTIONAL_DEP_INSTALL_HINT,
@@ -61,7 +61,7 @@ import {
61
61
  toArrayBuffer,
62
62
  unescapeHtml,
63
63
  unzipLimitBytes
64
- } from "./chunk-Y3LLNEU3.js";
64
+ } from "./chunk-XLY5ZJRP.js";
65
65
 
66
66
  // src/plain-markdown.ts
67
67
  function toPlainMarkdown(md2) {
@@ -24620,7 +24620,7 @@ var MIN_SIDE = 24;
24620
24620
  async function ocrEmbeddedImages(blocks, options, warnings) {
24621
24621
  const ocr = options?.ocr;
24622
24622
  if (ocr !== true && ocr !== "force" && typeof ocr !== "function") return false;
24623
- const { parseImageDocument } = await import("./image-ocr-2ZWU6O5O.js");
24623
+ const { parseImageDocument } = await import("./image-ocr-ZLL66KNO.js");
24624
24624
  let inserted = false, unreadable = 0;
24625
24625
  let failed = null;
24626
24626
  const walk = async (list, depth) => {
@@ -43371,27 +43371,35 @@ function gridFromHtml(html) {
43371
43371
  return { rowCnt: rows.length, colCnt, cells };
43372
43372
  }
43373
43373
  function splitContact(line) {
43374
- if (/[||]/.test(line)) return line.split(/\s*[||]\s*/).map((s) => s.trim()).filter(Boolean);
43375
43374
  const out = [];
43376
43375
  let rest = line.trim();
43377
43376
  const d = /^\(?\d{4}\.\s*\d{1,2}\.\s*\d{1,2}\.?(?:\s*\([^)]{0,20}\))?\)?[,,]?/u.exec(rest);
43378
43377
  if (d) {
43379
43378
  out.push(d[0].replace(/[,,]$/, ""));
43380
- rest = rest.slice(d[0].length).trim();
43379
+ rest = rest.slice(d[0].length).replace(/^\s*[||]?\s*/, "").trim();
43381
43380
  }
43381
+ if (/[||]/.test(rest)) return [...out, ...rest.split(/\s*[||]\s*/).map((s) => s.trim()).filter(Boolean)];
43382
43382
  out.push(...rest.split(/(?<=☎\s{0,3}[\d-]{1,20})[\s,,]+/u).map((s) => s.trim()).filter(Boolean));
43383
43383
  return out;
43384
43384
  }
43385
43385
  function fillCells(xml, edits) {
43386
- return applySplices(xml, edits.filter((e) => e.cell.paras.length).map(({ cell: cell2, lines, post }) => {
43386
+ return applySplices(xml, edits.filter((e) => e.cell.paras.length).map(({ cell: cell2, lines, post, raw }) => {
43387
43387
  const first = xml.slice(cell2.paras[0].start, cell2.paras[0].end);
43388
+ const direct = raw?.(first);
43388
43389
  return {
43389
43390
  start: cell2.paras[0].start,
43390
43391
  end: cell2.paras[cell2.paras.length - 1].end,
43391
- replacement: (lines.length ? lines : [""]).map((l) => post ? post(fillParagraph(first, l)) : fillParagraph(first, l)).join("")
43392
+ replacement: direct ?? (lines.length ? lines : [""]).map((l) => post ? post(fillParagraph(first, l)) : fillParagraph(first, l)).join("")
43392
43393
  };
43393
43394
  }));
43394
43395
  }
43396
+ function replaceCellValue(pXml, oldValue, newValue) {
43397
+ const needle = escapeTextXml(oldValue);
43398
+ const at = pXml.indexOf(needle);
43399
+ if (!oldValue || at < 0 || pXml.indexOf(needle, at + 1) >= 0) return null;
43400
+ if (pXml.lastIndexOf("<", at) > pXml.lastIndexOf(">", at)) return null;
43401
+ return pXml.slice(0, at) + bodyText(newValue) + pXml.slice(at + needle.length);
43402
+ }
43395
43403
  function defaultPara(text) {
43396
43404
  return `<hp:p id="0" paraPrIDRef="0" styleIDRef="0" pageBreak="0" columnBreak="0" merged="0"><hp:run charPrIDRef="0">${text ? `<hp:t>${bodyText(text)}</hp:t>` : ""}</hp:run></hp:p>`;
43397
43405
  }
@@ -43554,11 +43562,38 @@ function titleXml(ctx, title, contact) {
43554
43562
  }
43555
43563
  function assignContacts(ctx, slots, contact) {
43556
43564
  const texts = matchContactPieces(slots.map((c) => c.text), contact);
43557
- return slots.map((cell2, i) => ({ cell: cell2, lines: [texts[i]], post: (p) => undistribute(ctx, p) }));
43565
+ const kept = slots.filter((c, i) => contact && texts[i] && texts[i] === c.text).map((c) => c.text.trim());
43566
+ if (kept.length) ctx.warnings.push(`template: \uC6D0\uACE0\uC5D0 \uC5C6\uB294 \uB2F4\uB2F9 \uC904 \uCE78\uC740 \uACAC\uBCF8 \uADF8\uB300\uB85C \uB460 \u2014 ${kept.join(", ")}`);
43567
+ if (slots.length === 1) return [{ cell: slots[0], lines: [texts[0]], post: (p) => undistribute(ctx, p) }];
43568
+ return slots.flatMap((cell2, i) => {
43569
+ const next = texts[i];
43570
+ if (next === cell2.text) return [];
43571
+ const before2 = LABELLED_RE.exec(cell2.text.trim()), after2 = LABELLED_RE.exec(next.trim());
43572
+ const swap = before2 && after2 && before2[1].trim() === after2[1].trim() ? [before2[3], after2[3]] : !before2 && !after2 && DATE_IN_RE.test(cell2.text) && next ? [cell2.text.trim(), next.trim()] : null;
43573
+ return [{ cell: cell2, lines: [next], ...swap ? { raw: (first) => replaceCellValue(first, swap[0], swap[1]) } : {} }];
43574
+ });
43575
+ }
43576
+ var LABELLED_RE = /^(.+?)([\s ]*[::][\s ]*)(\S.*)$/u;
43577
+ function parseContactPiece(piece) {
43578
+ const m = LABELLED_RE.exec(piece.trim());
43579
+ if (m) {
43580
+ const kw = ROLE_KW_RE.exec(m[1])?.[1];
43581
+ return kw ? { kw, label: m[1].trim(), value: m[3].trim() } : null;
43582
+ }
43583
+ const k = ROLE_KW_RE.exec(piece);
43584
+ if (!k) return null;
43585
+ const end = (k.index ?? 0) + k[1].length;
43586
+ const value = piece.slice(end).trim();
43587
+ return value ? { kw: k[1], label: piece.slice(0, end).trim(), value } : null;
43558
43588
  }
43589
+ var STAFF_KW = /* @__PURE__ */ new Set(["\uB2F4\uB2F9", "\uC8FC\uBB34\uAD00"]);
43559
43590
  function matchContactPieces(slotTexts, contact) {
43560
43591
  const out = slotTexts.map(() => "");
43561
43592
  if (!contact || !slotTexts.length) return out;
43593
+ if (slotTexts.length > 1) {
43594
+ const done = matchRoleSlots(slotTexts, splitContact(contact));
43595
+ if (done) return done;
43596
+ }
43562
43597
  const pieces = slotTexts.length === 1 ? [splitContact(contact).join(" ")] : splitContact(contact);
43563
43598
  const free = slotTexts.map((_, i) => i);
43564
43599
  const take = (pred) => {
@@ -43579,6 +43614,28 @@ function matchContactPieces(slotTexts, contact) {
43579
43614
  }
43580
43615
  return out;
43581
43616
  }
43617
+ function matchRoleSlots(slotTexts, pieces) {
43618
+ const slots = slotTexts.map((t) => {
43619
+ const date = DATE_IN_RE.test(t) && !ROLE_KW_RE.test(t);
43620
+ const m = LABELLED_RE.exec(t.trim());
43621
+ return { date, kw: m ? ROLE_KW_RE.exec(m[1])?.[1] ?? null : null, label: m?.[1].trim() ?? "", sep: m?.[2] ?? " : " };
43622
+ });
43623
+ if (slots.some((s) => !s.date && !s.kw)) return null;
43624
+ const out = slotTexts.slice();
43625
+ for (const piece of pieces) {
43626
+ if (DATE_RE.test(piece)) {
43627
+ const i2 = slots.findIndex((s) => s.date);
43628
+ if (i2 >= 0) out[i2] = piece;
43629
+ continue;
43630
+ }
43631
+ const entry = parseContactPiece(piece);
43632
+ if (!entry) return null;
43633
+ const i = slots.findIndex((s) => s.kw === entry.kw);
43634
+ if (i < 0) return null;
43635
+ out[i] = `${STAFF_KW.has(entry.kw) ? slots[i].label : entry.label}${slots[i].sep}${entry.value}`;
43636
+ }
43637
+ return out;
43638
+ }
43582
43639
  function contactXml(ctx, contact) {
43583
43640
  const proto = ctx.scan.protos.get("contact");
43584
43641
  if (!proto) return bodyPara(ctx, contact);
@@ -45337,10 +45394,13 @@ var RULES = [
45337
45394
  // 숫자 런 첫머리에서만 시작 — 아니면 긴 숫자 줄에서 시작 자리마다 런을 다시 훑어 이차 폭주(숫자 5만 자 2.9초)
45338
45395
  // "359,600천원"·"1,200천원" 처럼 쉼표를 둔 수 뒤 천원은 예산서 단위 표기(단위: 천원)라 줄임말이 아니다 —
45339
45396
  // 쉼표 묶음 뒤(앞이 숫자·쉼표)는 건너뛴다. 걸리는 것은 "3천원"·"1500천원" 같은 쉼표 없는 수
45397
+ // 표 칸("금액(천원)" 열)·산출근거 곱셈 줄("× … = 900천원")의 천원도 예산서 단위 표기다 — 건너뛴다
45340
45398
  {
45341
45399
  code: "MONEY_CHEONWON",
45342
45400
  severity: "error",
45343
45401
  pattern: /(?<![\d,])\d+\s*천\s*원/g,
45402
+ skipTable: true,
45403
+ check: (m) => /[×✕]|\s=\s/.test(m.input ?? "") ? null : "",
45344
45404
  message: "\uAE08\uC561\uC740 '\uCC9C\uC6D0'\uC73C\uB85C \uC904\uC774\uC9C0 \uC54A\uACE0 \uC544\uB77C\uBE44\uC544 \uC22B\uC790\uB85C",
45345
45405
  suggest: "\uC608) 345,000\uC6D0"
45346
45406
  },
@@ -46315,7 +46375,8 @@ function checkCalc(line, no, out) {
46315
46375
  rule: "BUDGET_CALC_MISMATCH",
46316
46376
  severity: "error",
46317
46377
  message: "\uC0B0\uCD9C\uADFC\uAC70 \uACF1\uC148 \uACB0\uACFC\uAC00 \uC801\uC740 \uAE08\uC561\uACFC \uB2E4\uB984",
46318
- suggest: `${m[1].trim()} = ${fmt(expected)}${m[3]}`
46378
+ // "원래 식 → 바른 식" — 그대로 바꿔 넣을 수 있는 꼴(편집 도구가 바로 반영)
46379
+ suggest: `${m[0]} \u2192 ${m[1].trim()} = ${fmt(expected)}${m[3]}`
46319
46380
  });
46320
46381
  }
46321
46382
  }
@@ -46625,6 +46686,104 @@ function runLintSuite(text, opts = {}) {
46625
46686
  };
46626
46687
  }
46627
46688
 
46689
+ // src/hwpx/lint-blocks.ts
46690
+ var MARKDOWN_STRUCTURE = /^\s*(?:```|~~~|#|\||>)/;
46691
+ var safeLine = (text) => text.replace(/[\r\n]/g, " ");
46692
+ var safeCell = (text) => safeLine(text).replace(/\|/g, "\uFF5C");
46693
+ function blocksToLines(blocks) {
46694
+ const lines = [];
46695
+ const paragraph = (block) => {
46696
+ const text = safeLine(block.text);
46697
+ const prefix = MARKDOWN_STRUCTURE.test(text) ? "\\" : "";
46698
+ lines.push({ text: prefix + text, segments: [{ start: prefix.length, length: text.length, block: block.id }] });
46699
+ };
46700
+ const tables = /* @__PURE__ */ new Map();
46701
+ for (const b of blocks) if (b.table) (tables.get(b.table.id) ?? tables.set(b.table.id, []).get(b.table.id)).push(b);
46702
+ const emitted = /* @__PURE__ */ new Set();
46703
+ for (const b of blocks) {
46704
+ if (!b.table) {
46705
+ paragraph(b);
46706
+ continue;
46707
+ }
46708
+ if (emitted.has(b.table.id)) continue;
46709
+ emitted.add(b.table.id);
46710
+ const cells = tables.get(b.table.id);
46711
+ if (cells.length === 1) {
46712
+ paragraph(cells[0]);
46713
+ continue;
46714
+ }
46715
+ const rows = cells.reduce((n, c) => Math.max(n, c.table.row + 1), 0);
46716
+ const cols = cells.reduce((n, c) => Math.max(n, c.table.col + 1), 0);
46717
+ const at = new Map(cells.map((c) => [`${c.table.row},${c.table.col}`, c]));
46718
+ lines.push({ text: "", segments: [] });
46719
+ for (let r = 0; r < rows; r++) {
46720
+ let text = "|";
46721
+ const segments = [];
46722
+ for (let c = 0; c < cols; c++) {
46723
+ text += " ";
46724
+ const cell2 = at.get(`${r},${c}`);
46725
+ if (cell2) {
46726
+ const t = safeCell(cell2.text);
46727
+ segments.push({ start: text.length, length: t.length, block: cell2.id });
46728
+ text += t;
46729
+ }
46730
+ text += " |";
46731
+ }
46732
+ lines.push({ text, segments });
46733
+ if (r === 0) lines.push({ text: "|" + " --- |".repeat(cols), segments: [] });
46734
+ }
46735
+ lines.push({ text: "", segments: [] });
46736
+ }
46737
+ return lines;
46738
+ }
46739
+ function locate(lines, f) {
46740
+ const line = lines[f.line - 1];
46741
+ if (!line) return { block: null, offset: null };
46742
+ if (f.column !== void 0) {
46743
+ const at = f.column - 1;
46744
+ const seg2 = line.segments.find((s) => at >= s.start && at < s.start + Math.max(1, s.length)) ?? line.segments.find((s) => line.text.indexOf(f.match, s.start) >= s.start && line.text.indexOf(f.match, s.start) < s.start + s.length);
46745
+ if (seg2) {
46746
+ const found = line.text.indexOf(f.match, Math.max(seg2.start, at));
46747
+ const start = found >= seg2.start && found < seg2.start + seg2.length ? found : at;
46748
+ return { block: seg2.block, offset: Math.min(Math.max(0, start - seg2.start), seg2.length) };
46749
+ }
46750
+ return { block: null, offset: null };
46751
+ }
46752
+ if (line.segments.length !== 1) return { block: null, offset: null };
46753
+ const seg = line.segments[0];
46754
+ const body = line.text.slice(seg.start, seg.start + seg.length);
46755
+ const first = f.match ? body.indexOf(f.match) : -1;
46756
+ const unique = first >= 0 && body.indexOf(f.match, first + 1) < 0;
46757
+ return { block: seg.block, offset: unique ? first : null };
46758
+ }
46759
+ function lintBlocks(blocks, opts = {}) {
46760
+ const lines = blocksToLines(blocks);
46761
+ const suite = runLintSuite(lines.map((l) => l.text).join("\n") + "\n", opts);
46762
+ const findings = [];
46763
+ const take = (category, list) => {
46764
+ for (const f of list ?? []) {
46765
+ const { block, offset } = locate(lines, f);
46766
+ findings.push({
46767
+ block,
46768
+ offset,
46769
+ length: f.match.length,
46770
+ category,
46771
+ rule: f.rule,
46772
+ severity: f.severity,
46773
+ match: f.match,
46774
+ message: f.message,
46775
+ ...f.suggest ? { suggest: f.suggest } : {}
46776
+ });
46777
+ }
46778
+ };
46779
+ take("notation", suite.findings);
46780
+ take("munche", suite.munche);
46781
+ take("slop", suite.slop);
46782
+ take("logic", suite.logic);
46783
+ take("budget", suite.budget);
46784
+ return { findings, ...suite.numbers ? { numbers: suite.numbers } : {}, summary: suite.summary };
46785
+ }
46786
+
46628
46787
  // src/roundtrip/patcher.ts
46629
46788
  import JSZip13 from "jszip";
46630
46789
 
@@ -57382,7 +57541,7 @@ function scriptsOff(r, off) {
57382
57541
  }
57383
57542
  async function parseImage(buffer, options) {
57384
57543
  try {
57385
- const { parseImageDocument } = await import("./image-ocr-2ZWU6O5O.js");
57544
+ const { parseImageDocument } = await import("./image-ocr-ZLL66KNO.js");
57386
57545
  const { blocks, warnings, lines } = await parseImageDocument(buffer, options);
57387
57546
  stripScriptTags({ blocks });
57388
57547
  return {
@@ -57446,7 +57605,7 @@ async function parseHwp(buffer, options) {
57446
57605
  async function parsePdf(buffer, options) {
57447
57606
  let parsePdfDocument;
57448
57607
  try {
57449
- const mod = await import("./parser-WTOPH3C2.js");
57608
+ const mod = await import("./parser-J22QBXPP.js");
57450
57609
  parsePdfDocument = mod.parsePdfDocument;
57451
57610
  } catch {
57452
57611
  return {
@@ -57597,6 +57756,7 @@ export {
57597
57756
  isOldHwpFile,
57598
57757
  isPdfFile,
57599
57758
  isZipFile,
57759
+ lintBlocks,
57600
57760
  lintBudgetText,
57601
57761
  lintGongmunText,
57602
57762
  lintLogicText,