kordoc 4.23.1 → 4.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -53
- package/dist/{-6U2DXAP7.js → -TSN4SWFV.js} +13 -11
- package/dist/{chunk-RJZQLUGW.js → chunk-2SMANR76.js} +4 -4
- package/dist/{chunk-CU7WLAPQ.js → chunk-4BCQ3FQS.js} +134 -15
- package/dist/chunk-4BCQ3FQS.js.map +1 -0
- package/dist/{chunk-TSKGMN46.cjs → chunk-4VNIEHWM.cjs} +23 -23
- package/dist/chunk-4VNIEHWM.cjs.map +1 -0
- package/dist/{chunk-H7K2FTV2.js → chunk-5EP6VFP5.js} +3 -3
- package/dist/{chunk-PWHYNFTN.cjs → chunk-5QBTJ4LA.cjs} +6 -6
- package/dist/chunk-5QBTJ4LA.cjs.map +1 -0
- package/dist/{chunk-FDRIJEES.js → chunk-6H7D4QTM.js} +2 -2
- package/dist/{chunk-UZZGT6XI.js → chunk-AJ3DJSO6.js} +4 -4
- package/dist/{chunk-KPCGYMQK.js → chunk-B77K6J3U.js} +2 -2
- package/dist/{chunk-B4WJQMSZ.js → chunk-BIVO2GMU.js} +2 -2
- package/dist/{chunk-QV367L5S.js → chunk-G7SKCXQG.js} +2 -2
- package/dist/chunk-GS7T56RP.cjs.map +1 -1
- package/dist/{chunk-KRK65GHM.js → chunk-HP24FYLJ.js} +4 -4
- package/dist/chunk-J55UQC5H.cjs.map +1 -1
- package/dist/{chunk-27HAGR4H.cjs → chunk-JSI5T77E.cjs} +24 -24
- package/dist/chunk-JSI5T77E.cjs.map +1 -0
- package/dist/{chunk-Q2SOQOWP.cjs → chunk-KGOVG47P.cjs} +3 -3
- package/dist/chunk-KGOVG47P.cjs.map +1 -0
- package/dist/{chunk-K6CTZQZW.js → chunk-L2OJUIII.js} +2 -2
- package/dist/{chunk-5BGQOKZS.js → chunk-LBPUPT6S.js} +6 -6
- package/dist/{chunk-EEM4AJTY.js → chunk-LEL5UBGR.js} +2 -2
- package/dist/{chunk-XBTFGKMR.js → chunk-LEUS275C.js} +2 -2
- package/dist/{chunk-KMHHSOSR.js → chunk-MI25BZSU.js} +2 -2
- package/dist/{chunk-KWBPDHFT.js → chunk-NAPPGU3W.js} +2 -2
- package/dist/{chunk-4RQYUDGT.cjs → chunk-RIQVVWVF.cjs} +3 -3
- package/dist/chunk-RIQVVWVF.cjs.map +1 -0
- package/dist/{chunk-SSKZ2KL2.js → chunk-RS2Q64N5.js} +2 -2
- package/dist/{chunk-YPTW52ZJ.js → chunk-RVKOFZAT.js} +2 -2
- package/dist/{chunk-SQS4D55F.js → chunk-SWCO5NP6.js} +3 -3
- package/dist/chunk-TK3FDAEE.cjs.map +1 -1
- package/dist/{chunk-T63JP3GD.cjs → chunk-TYXXTWPH.cjs} +2 -2
- package/dist/chunk-TYXXTWPH.cjs.map +1 -0
- package/dist/{chunk-IMS56622.js → chunk-V2GW3M2F.js} +2 -2
- package/dist/{chunk-DE7ETARS.js → chunk-W4P3QPSB.js} +2 -2
- package/dist/{chunk-Q6T5BIWZ.js → chunk-WYYUWBTS.js} +2 -2
- package/dist/{chunk-WG43OZYN.js → chunk-YE4T2P6F.js} +2 -2
- package/dist/{chunk-ZC3WNCZV.js → chunk-ZR3BPESP.js} +3 -3
- package/dist/chunks-HPPVNSBT.js +10 -0
- package/dist/cli.js +68 -30
- package/dist/cli.js.map +1 -1
- package/dist/{formula-6FPGJ7PI.cjs → formula-5DGAZK6N.cjs} +9 -9
- package/dist/formula-5DGAZK6N.cjs.map +1 -0
- package/dist/{formula-73LPYA6R.js → formula-6J26PNHL.js} +4 -4
- package/dist/{formula-L3RKXO2Z.js → formula-PNZX2ZAZ.js} +3 -3
- package/dist/{image-ocr-4IW435IF.cjs → image-ocr-I4PGBAJ7.cjs} +17 -17
- package/dist/image-ocr-I4PGBAJ7.cjs.map +1 -0
- package/dist/{image-ocr-R42ZVGCH.js → image-ocr-RPHNFU7I.js} +6 -6
- package/dist/{image-ocr-37S4CHFI.js → image-ocr-UNTKJLQL.js} +9 -9
- package/dist/index.cjs +707 -588
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -1
- package/dist/index.d.ts +47 -1
- package/dist/index.js +129 -10
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +53 -37
- package/dist/mcp.js.map +1 -1
- package/dist/{model-bundle-L3TZDQJF.js → model-bundle-ZSDEJFA7.js} +5 -5
- package/dist/{models-2IDIYAGL.js → models-JS66XYKO.js} +5 -5
- package/dist/page-range-QHHFTL7X.cjs.map +1 -1
- package/dist/{parse-worker-v2-NVI6YJN6.js → parse-worker-v2-JHPEY3MI.js} +58 -15
- package/dist/parse-worker-v2-JHPEY3MI.js.map +1 -0
- package/dist/{parser-7BDTFYHE.js → parser-N64TUIWU.js} +9 -9
- package/dist/{parser-M7HKGKEN.cjs → parser-NMV5GTKC.cjs} +157 -157
- package/dist/parser-NMV5GTKC.cjs.map +1 -0
- package/dist/{parser-KHVN5B3I.js → parser-YKATDDQV.js} +12 -12
- package/dist/pdf-ocr-JXK752RC.cjs +31 -0
- package/dist/pdf-ocr-JXK752RC.cjs.map +1 -0
- package/dist/{pdf-ocr-EYDE264W.js → pdf-ocr-KTKR2JQH.js} +9 -9
- package/dist/{pdf-ocr-XFMBTHEE.js → pdf-ocr-W3LDJYCA.js} +6 -6
- package/dist/{profile-io-FDA5PEW2.js → profile-io-JRODOL7A.js} +3 -3
- package/dist/{rasterize-NR6JJSJV.js → rasterize-2DMR7RGP.js} +3 -3
- package/dist/{redact-doc-K74LDR3O.js → redact-doc-TC6QSTPM.js} +11 -11
- package/dist/{render-RM5BAYGB.js → render-WEUU5EDS.js} +7 -7
- package/dist/seal-LSALFURW.js +10 -0
- package/dist/{setup-M4RKKK3P.js → setup-LKJKGMKJ.js} +3 -3
- package/dist/visual-PHZHJRY5.js +21 -0
- package/dist/{watch-ZWD4LADV.js → watch-HHFVXB3G.js} +12 -12
- package/package.json +1 -1
- package/dist/chunk-27HAGR4H.cjs.map +0 -1
- package/dist/chunk-4RQYUDGT.cjs.map +0 -1
- package/dist/chunk-CU7WLAPQ.js.map +0 -1
- package/dist/chunk-PWHYNFTN.cjs.map +0 -1
- package/dist/chunk-Q2SOQOWP.cjs.map +0 -1
- package/dist/chunk-T63JP3GD.cjs.map +0 -1
- package/dist/chunk-TSKGMN46.cjs.map +0 -1
- package/dist/chunks-FPFZZPUE.js +0 -10
- package/dist/formula-6FPGJ7PI.cjs.map +0 -1
- package/dist/image-ocr-4IW435IF.cjs.map +0 -1
- package/dist/parse-worker-v2-NVI6YJN6.js.map +0 -1
- package/dist/parser-M7HKGKEN.cjs.map +0 -1
- package/dist/pdf-ocr-HUL7G577.cjs +0 -31
- package/dist/pdf-ocr-HUL7G577.cjs.map +0 -1
- package/dist/seal-LRVVOPOD.js +0 -10
- package/dist/visual-WTFQPXO2.js +0 -21
- /package/dist/{-6U2DXAP7.js.map → -TSN4SWFV.js.map} +0 -0
- /package/dist/{chunk-RJZQLUGW.js.map → chunk-2SMANR76.js.map} +0 -0
- /package/dist/{chunk-H7K2FTV2.js.map → chunk-5EP6VFP5.js.map} +0 -0
- /package/dist/{chunk-FDRIJEES.js.map → chunk-6H7D4QTM.js.map} +0 -0
- /package/dist/{chunk-UZZGT6XI.js.map → chunk-AJ3DJSO6.js.map} +0 -0
- /package/dist/{chunk-KPCGYMQK.js.map → chunk-B77K6J3U.js.map} +0 -0
- /package/dist/{chunk-B4WJQMSZ.js.map → chunk-BIVO2GMU.js.map} +0 -0
- /package/dist/{chunk-QV367L5S.js.map → chunk-G7SKCXQG.js.map} +0 -0
- /package/dist/{chunk-KRK65GHM.js.map → chunk-HP24FYLJ.js.map} +0 -0
- /package/dist/{chunk-K6CTZQZW.js.map → chunk-L2OJUIII.js.map} +0 -0
- /package/dist/{chunk-5BGQOKZS.js.map → chunk-LBPUPT6S.js.map} +0 -0
- /package/dist/{chunk-EEM4AJTY.js.map → chunk-LEL5UBGR.js.map} +0 -0
- /package/dist/{chunk-XBTFGKMR.js.map → chunk-LEUS275C.js.map} +0 -0
- /package/dist/{chunk-KMHHSOSR.js.map → chunk-MI25BZSU.js.map} +0 -0
- /package/dist/{chunk-KWBPDHFT.js.map → chunk-NAPPGU3W.js.map} +0 -0
- /package/dist/{chunk-SSKZ2KL2.js.map → chunk-RS2Q64N5.js.map} +0 -0
- /package/dist/{chunk-YPTW52ZJ.js.map → chunk-RVKOFZAT.js.map} +0 -0
- /package/dist/{chunk-SQS4D55F.js.map → chunk-SWCO5NP6.js.map} +0 -0
- /package/dist/{chunk-IMS56622.js.map → chunk-V2GW3M2F.js.map} +0 -0
- /package/dist/{chunk-DE7ETARS.js.map → chunk-W4P3QPSB.js.map} +0 -0
- /package/dist/{chunk-Q6T5BIWZ.js.map → chunk-WYYUWBTS.js.map} +0 -0
- /package/dist/{chunk-WG43OZYN.js.map → chunk-YE4T2P6F.js.map} +0 -0
- /package/dist/{chunk-ZC3WNCZV.js.map → chunk-ZR3BPESP.js.map} +0 -0
- /package/dist/{chunks-FPFZZPUE.js.map → chunks-HPPVNSBT.js.map} +0 -0
- /package/dist/{formula-73LPYA6R.js.map → formula-6J26PNHL.js.map} +0 -0
- /package/dist/{formula-L3RKXO2Z.js.map → formula-PNZX2ZAZ.js.map} +0 -0
- /package/dist/{image-ocr-R42ZVGCH.js.map → image-ocr-RPHNFU7I.js.map} +0 -0
- /package/dist/{image-ocr-37S4CHFI.js.map → image-ocr-UNTKJLQL.js.map} +0 -0
- /package/dist/{model-bundle-L3TZDQJF.js.map → model-bundle-ZSDEJFA7.js.map} +0 -0
- /package/dist/{models-2IDIYAGL.js.map → models-JS66XYKO.js.map} +0 -0
- /package/dist/{parser-7BDTFYHE.js.map → parser-N64TUIWU.js.map} +0 -0
- /package/dist/{parser-KHVN5B3I.js.map → parser-YKATDDQV.js.map} +0 -0
- /package/dist/{pdf-ocr-EYDE264W.js.map → pdf-ocr-KTKR2JQH.js.map} +0 -0
- /package/dist/{pdf-ocr-XFMBTHEE.js.map → pdf-ocr-W3LDJYCA.js.map} +0 -0
- /package/dist/{profile-io-FDA5PEW2.js.map → profile-io-JRODOL7A.js.map} +0 -0
- /package/dist/{rasterize-NR6JJSJV.js.map → rasterize-2DMR7RGP.js.map} +0 -0
- /package/dist/{redact-doc-K74LDR3O.js.map → redact-doc-TC6QSTPM.js.map} +0 -0
- /package/dist/{render-RM5BAYGB.js.map → render-WEUU5EDS.js.map} +0 -0
- /package/dist/{seal-LRVVOPOD.js.map → seal-LSALFURW.js.map} +0 -0
- /package/dist/{setup-M4RKKK3P.js.map → setup-LKJKGMKJ.js.map} +0 -0
- /package/dist/{visual-WTFQPXO2.js.map → visual-PHZHJRY5.js.map} +0 -0
- /package/dist/{watch-ZWD4LADV.js.map → watch-HHFVXB3G.js.map} +0 -0
package/README.md
CHANGED
|
@@ -11,16 +11,16 @@ HWP 3.x·5.x, HWPX, HWPML, PDF, XLS·XLSX, DOCX, PPTX, PNG·JPG·WebP를 Markdow
|
|
|
11
11
|
|
|
12
12
|
[English](README-EN.md) · [상세 사용법](docs/usage.md) · [벤치마크](docs/benchmarks.md) · [변경 이력](CHANGELOG.md)
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
- 🇰🇷 **한국 공문서 표 구조 100%** — 원본 HWPX 2,429문서의 보이는 표 **10,461개 전부 구조 일치**. [4.22.0 검증](docs/benchmarks.md)
|
|
14
|
+

|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
<sub>같은 법령 별표 한 건을 HWP·HWPX·PDF·스캔 이미지로 넣은 실제 출력입니다. 네 경우 모두 병합 칸(`rowspan`·`colspan`)을 같은 짜임의 표로 읽습니다. 스캔 이미지는 OCR이 자동으로 켜집니다.</sub>
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
- 📊 **PDF 공개 벤치 종합 0.964**: opendataloader-bench 200문서, 공개 리더보드 12개 파서보다 높은 점수(4.22.14 측정). [측정 조건](docs/benchmarks.md#pdf--markdown--opendataloader-bench)
|
|
19
|
+
- 🇰🇷 **한국 공문서 표 구조 100%**: 원본 HWPX 2,424문서의 보이는 표 **10,342개 전부 구조 일치**. [검증 결과](#검증-결과)
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
쓸모 있었다면 GitHub ⭐ 하나 눌러주세요. 다른 사람이 이 도구를 찾는 데 도움이 됩니다.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
영상: [공개 벤치 측정 과정](https://youtu.be/9kRbwiTRQLs)(2026-09-27 판, 1분 31초) · [양식 일괄 채우기 시연](https://youtu.be/Q13GmgDcIw0)
|
|
24
24
|
|
|
25
25
|
## 설치
|
|
26
26
|
|
|
@@ -38,7 +38,7 @@ CLI는 설치 없이 `npx kordoc`으로 실행할 수 있습니다. PDF·OCR 의
|
|
|
38
38
|
npx -y kordoc setup
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
Claude Desktop·Claude Code·Cursor·Codex 등 설치된 클라이언트에 MCP를 등록합니다. 클라이언트를 재시작하면
|
|
41
|
+
Claude Desktop·Claude Code·Cursor·Codex 등 설치된 클라이언트에 MCP를 등록합니다. 클라이언트를 재시작하면 파싱·비교·생성·검수·렌더 등 **18개 도구**를 사용할 수 있습니다.
|
|
42
42
|
|
|
43
43
|
Claude Code 플러그인:
|
|
44
44
|
|
|
@@ -60,12 +60,11 @@ npx kordoc 문서.pdf --format json --pages 1-3
|
|
|
60
60
|
npx kordoc 스캔본.pdf --ocr -o 스캔본.md
|
|
61
61
|
npx kordoc generate 보고서.md --preset 보고서 -o 보고서.hwpx
|
|
62
62
|
npx kordoc fill --template gian -j 값.json -o 기안문.hwpx
|
|
63
|
+
npx kordoc lint 보고서.hwpx --gate --preset 보고서
|
|
63
64
|
```
|
|
64
65
|
|
|
65
66
|
`--jobs`는 파일 단위 병렬 변환이며 메모리 사용도 늘어납니다. [병렬 변환 안내](docs/parallel-batch.md)
|
|
66
67
|
|
|
67
|
-
보고서·계획서·개조식·서울방침은 `#` 제목 바로 뒤 인용문(`> …하고자 함`)이 요약 상자가 됩니다(개조식은 표지가 있을 때(기본) 본문 첫 쪽 제목 상자 아래 — `cover:false` 면 첫 `#` 이 장 머리라 인용문은 ※ 참고). 보고 목적 한 문장(쉼표 허용) 3줄 이내로 쓰고, 넘거나 두 문장 이상이면 경고합니다. 업무보고는 `> ▪ …` 인용문이 자리와 관계없이 성과 요약 상자가 됩니다.
|
|
68
|
-
|
|
69
68
|
### JavaScript / TypeScript
|
|
70
69
|
|
|
71
70
|
```typescript
|
|
@@ -91,12 +90,13 @@ await writeFile("보고서.hwpx", Buffer.from(hwpx))
|
|
|
91
90
|
| 작업 | 기능 |
|
|
92
91
|
| --- | --- |
|
|
93
92
|
| 읽기 | 문서 → Markdown·IR·쪽별 본문·RAG 청크, 로컬 OCR |
|
|
94
|
-
| 비교·편집 | 블록·셀 단위 비교, HWPX·HWP 서식 보존
|
|
95
|
-
| 작성 | Markdown → HWPX, 공문서
|
|
93
|
+
| 비교·편집 | 블록·셀 단위 비교, HWPX·HWP 서식 보존 패치, 견본 서식 그대로 새 내용 쓰기 |
|
|
94
|
+
| 작성 | Markdown → HWPX, 공문서 프리셋·부서 서식 견본(`--template`), 표·수식·차트 |
|
|
96
95
|
| 양식 | 필드·누름틀 채우기, 표준 기안문 2종, 도장 날인 |
|
|
97
|
-
|
|
|
96
|
+
| 검수 | 표기법·공공언어, 구성·AI 문체 게이트, 예산 산출근거 검산, 열린 문서 블록 단위 검수(`lint-blocks`) |
|
|
97
|
+
| 보기·보안 | HWPX·HWP 미리보기·영역 추출, 개인정보 마스킹 |
|
|
98
98
|
|
|
99
|
-
서식 보존 패치용 Markdown은 `--keep-layout-tables`로 추출합니다.
|
|
99
|
+
서식 보존 패치용 Markdown은 `--keep-layout-tables`로 추출합니다. 적용하지 못한 편집은 건너뛴 사유로 보고합니다. [서식 보존 편집](docs/usage.md#서식-보존-편집) · [CLI 전체](docs/usage.md#-cli)
|
|
100
100
|
|
|
101
101
|
## 검증 결과
|
|
102
102
|
|
|
@@ -113,53 +113,23 @@ await writeFile("보고서.hwpx", Buffer.from(hwpx))
|
|
|
113
113
|
| 법령 별표 | 272건 · 346표 | HWP **346/346**, PDF **342/346 · 98.84%** |
|
|
114
114
|
| PDF 전체 | 1,911문서 중 1,729건 채점 | 글 커버리지 **99.80%** |
|
|
115
115
|
| OCR | 53문서 · 102쪽 | CER **0.0409** · 글자 재현율 **99.02%** |
|
|
116
|
+
| opendataloader-bench | PDF 200문서 | 종합 기본값 **0.964** · OCR 끔 **0.939** |
|
|
116
117
|
|
|
117
|
-
표 구조 점수와 셀 내용·화면 재현은 별도 지표입니다. 중첩표 100%는 위 101표에 한정하며 전체 PDF·조판의 완전 일치를 뜻하지 않습니다. 채점 범위·제외
|
|
118
|
-
|
|
119
|
-
**4.22.15 (2026-10-19)**: "이 서식대로 써줘" 요청을 어느 AI 에서든 같은 경로로 처리합니다. 견본을 `--keep-layout-tables` 로 읽어 내용만 새로 쓴 뒤 `patch` 하면, 늘어난 줄은 같은 항목 부호(□·ㅇ·-) 견본 문단을 복제해 같은 들여쓰기·글꼴·굵기로 들어가고 지운 줄은 문단째 빠집니다. 같은 견본·같은 요청으로 Codex 를 돌려 보니 종전엔 새 내용을 원본 문단 자리에 억지로 맞춰 ○ 줄 서식이 어긋났고, 개선 뒤엔 줄 수가 달라도 견본 서식 그대로 나왔습니다. [사용법](docs/usage.md#서식-보존-편집)
|
|
120
|
-
|
|
121
|
-
**4.22.14 개선 검증(2026-10-19)**: 4.22.13과 같은 채점기·코퍼스로 다시 잰 결과 파서 출력(opendataloader-bench 네 모드·PDF 글·표·별표·OCR·기타 포맷·왕복·생성)은 문서별로 4.22.13과 같고, 렌더(한컴 PDF 짝) 글 조각 위치(1.5pt 안) **86,051/90,433→86,508/90,518**, 쪽 수 **1,421→1,423/1,431**로 개선했습니다. 조판 저장본 대조는 두 줄 이상 문단 **24,940→24,941/25,187**입니다. 칸 안 표가 든 칸 높이, 한컴이 첫 쪽 조각만 적은 표의 쪽 넘김, 줄 끝 글자 자간, 구역 첫 문단의 줄 시작(앞면·뒷면 서식 표), 한컴 사용자 기호(글머리 가운데점 등) 폭을 바로잡았습니다. [상세](docs/benchmarks.md)
|
|
122
|
-
|
|
123
|
-
빈 행을 접을 때 기존 논리 격자 안의 병합 모서리 셀을 보존합니다. 재현 PDF의 번호 기호 6종은 복원했으며, HTML 선 출력과 미등록 글꼴 기호는 [남은 한계](docs/parsing-loss-reproductions.md)로 기록했습니다.
|
|
124
|
-
|
|
125
|
-
외부 PDF 벤치 **opendataloader-bench 200문서**는 4.22.14 배포 후보의 동일 코퍼스 재검증에서 기본값 종합 **0.964**, OCR 끔 **0.939**입니다. [옵션별 결과와 재현 방법](docs/benchmarks.md#pdf--markdown--opendataloader-bench)
|
|
118
|
+
표 구조 점수와 셀 내용·화면 재현은 별도 지표입니다. 중첩표 100%는 위 101표에 한정하며 전체 PDF·조판의 완전 일치를 뜻하지 않습니다. 채점 범위·제외 기준·옵션별 수치·재현 방법은 [벤치마크 상세](docs/benchmarks.md)에 있습니다.
|
|
126
119
|
|
|
127
120
|
## 최근 업데이트
|
|
128
121
|
|
|
129
|
-
최신 배포: **[4.
|
|
122
|
+
최신 배포: **[4.24.1](https://github.com/chrisryugj/kordoc/releases/tag/v4.24.1)** · 2026-10-21
|
|
130
123
|
|
|
131
124
|
| 버전 | 주요 변경 |
|
|
132
125
|
| --- | --- |
|
|
133
|
-
| 4.
|
|
134
|
-
| 4.
|
|
135
|
-
| 4.
|
|
136
|
-
| 4.
|
|
137
|
-
| 4.22.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
| 4.22.13 | 쪽 넘김·칸 안 표 렌더 보정 — 꼬리말 0 쪽 번호, 갈라 저장한 칸이 있는 표의 넘침 여유 해제, 첫 줄도 안 드는 갈라 저장 행은 다음 쪽, 칸 안 표에 밀린 줄, 쪽을 넘는 칸 안 표(한컴 PDF 글 조각 위치 85,968 → 86,051, 그림 3,869 → 3,872, 쪽 수 1,413 → 1,421) — 파서 출력·조판 지표는 4.22.12와 같음 |
|
|
141
|
-
| 4.22.12 | 글상자 렌더 보정 — 지금 크기(curSz)·쪽 좌표 캐시 재조판·글 영역 폭 없는 글상자·옛한글 자모 폭, 제 표에 밀린 쪽 나누기 문단, 같은 너비 행 없는 표의 가장 긴 길 열 경계(한컴 PDF 글 조각 위치 85,837 → 85,968, 그림 3,866 → 3,869) — 파서 출력·조판 지표는 4.22.11과 같음 |
|
|
142
|
-
| 4.22.11 | 렌더 보정 — 갈린 칸 안 표의 이어진 쪽 시작·갈린 행 마지막 조각의 개체 바닥·여러 행 칸 내용 높이·갈린 가운데 칸 마지막 조각 정렬(한컴 PDF 글 조각 위치 85,496 → 85,837), 빈 문단 그림이 쪽 아래로 밀리던 4.21.31 회귀 수정 — 파서 출력·조판은 4.22.10과 같음 |
|
|
143
|
-
| 4.22.10 | MCP `parse_document` OCR 모델 인수(#165), 렌더 표 보정 — 행마다 다른 칸 너비의 열 경계·병합 칸 행 성장·갈라 저장한 칸·쪽 바닥 첫 행·갈린 가운데 칸 다음 쪽 조각(한컴 PDF 글 조각 위치 84,468 → 85,496, 쪽 수 1,410 → 1,413) — 파서 출력·조판은 4.22.9와 같음 |
|
|
144
|
-
| 4.22.9 | 굴림체·돋움체 반각 기호 폭·글머리표 예약 폭 조판 보정(본문 첫 줄 위치 76,676 → 76,729, 표 칸 205,007 → 205,015), 렌더의 갈라 저장한 가운데 칸·행 단위 표 쪽 넘김·개체 뒤 자동 탭 보정(한컴 PDF 글 조각 위치 82,816 → 84,468) — 파서 출력은 4.22.8과 같음 |
|
|
145
|
-
| 4.22.8 | PDF 표 아래 캡션 순서·한 단 본문의 가짜 2단 기각·그림 영역 OCR 지도 표 오판 정리(ODL 기본값 0.96305 → 0.96367), 칸 높이 고정 표 나눔·Wingdings 기호 폭·표만 든 줄 높이 조판 보정 — 본문 첫 줄 위치 76,631 → 76,676, 표 칸 205,005 → 205,007 |
|
|
146
|
-
| 4.22.7 | 단어 안 밑줄·빈칸 선의 불필요한 이스케이프 정리(ODL 기본값 0.96291 → 0.96305), 쪽에서 갈리는 표의 캡션·문단 위 여백, 한글 2024 초기 빌드 글머리표 공백 압축 — 본문 첫 줄 위치 76,525 → 76,631, 표 칸 204,958 → 205,005(문서별 하락 0) |
|
|
147
|
-
| 4.22.6 | 손글씨 OCR 모델 프리셋(#164), 글자 겹치기 원 번호·한컴 번호 PUA 를 HWPX·HWP·PDF 에서 같게, PDF 한컴 글꼴 기호 복원, 칸 나눔 표·종이 기준 그림·옮긴 문단 조판 보정 — 본문 첫 줄 위치 76,443 → 76,525, 표 칸 204,869 → 204,958 |
|
|
148
|
-
| 4.22.5 | 0폭 탭·기호 폭·글머리표 예약·표 분할·줄 높이 보정, PDF 부분 셀 병합·본문 절 제목·누락 기호 복원 |
|
|
149
|
-
| 4.22.4 | 그림·테두리·공백·세로쓰기 기준선·따옴표 조판 보정, PDF 글머리 칸·주석·양식 제목·쪽 경계 목록 행 복원 |
|
|
150
|
-
| 4.22.3 | 넘친 표 점유 높이·그림 옆 줄 조각·선택 하이픈 조판 개선, PDF 감싸개 안 표 이어짐과 반복 자료행 복원, 빈 행을 접을 때 병합 모서리 셀 보존 |
|
|
151
|
-
| 4.22.2 | 부분 편집 문단 위치·그림 어울림·고정폭 빈칸 조판 개선, PDF 독립 제목·번호 행 보존 및 연락처·음영 행 내용 복원 |
|
|
152
|
-
| 4.22.1 | 텍스트층 PDF의 그림 영역 OCR에서 회전 보정·고해상도 재인식 좌표 혼합 수정. 전체 스캔의 기울기 보정 유지 |
|
|
153
|
-
| 4.22.0 | PDF 중첩표 94/101 → 101/101, 쪽 경계 셀·HWP 캡션·표 칸 안 각주 보존. OCR 줄 좌표·모델 선택 추가, 수식 OCR 설치 경량화 |
|
|
154
|
-
| 4.21.33 | 미주 단 흐름, 갈리는 표의 각주, 칸 간격 — 본문 줄 위치 일치 95.9% → 97.5%, 표 칸 99.5% → 99.7% |
|
|
155
|
-
| 4.21.32 | 렌더·reflow 쪽 배치 개선 — 쪽을 넘는 표 칸과 떠 있는 개체. 표 칸 줄 위치 일치 97.4% → 99.5%, 본문 87.2% → 95.9% |
|
|
156
|
-
| 4.21.31 | 렌더·reflow 조판 일치, 각주 안 표 구조 보존(#149), 인라인 수식 옵션(#150), 보안 점검 반영 |
|
|
157
|
-
| 4.21.23 | HWP·HWPX 그림 속 글 OCR(`ocr: true`, #143) |
|
|
158
|
-
| 4.21.0 | 중앙부처 기관 서식 `--agency`, 보도자료 담당 표 |
|
|
159
|
-
|
|
160
|
-
OCR 줄의 상자·신뢰도는 `--ocr --ocr-lines --format json`으로 받습니다. `--ocr-det`·`--ocr-det-long-side`로 검출 모델과 해상도를 선택할 수 있습니다. [OCR 줄·모델 사용법](docs/usage.md#ocr-줄모델-선택)
|
|
161
|
-
|
|
162
|
-
버전별 상세는 [변경 이력](CHANGELOG.md)에 있습니다.
|
|
126
|
+
| 4.24.1 | 검수 수정: 블록 검수 희소 표 메모리 폭주·천원 규칙 이차 시간·예산 검산(목록 줄·소계(A)·비율 행), `generate --template` 견본 덮어쓰기 차단 |
|
|
127
|
+
| 4.24.0 | 블록 단위 검수 `lintBlocks`: 열린 문서의 문단·표 칸을 블록으로 넘기면 지적을 블록 id·블록 안 위치로 돌려줌(CLI `lint-blocks`, MCP `lint_document`, 워커, Python SDK) |
|
|
128
|
+
| 4.23.1 | 견본 생성 제목표 결재선 칸을 직위별로, 산출근거 줄·표 칸 천원 단위 오탐 제거 |
|
|
129
|
+
| 4.23.0 | 부서 서식 견본으로 새 문서 생성(`generate --template`), 예산 문서 검수(`lint --budget`), MCP `lint_document` |
|
|
130
|
+
| 4.22.18 | kordoc 생성 보고서의 제목 틀·장 띠·요약 상자 패치, 변경 추적 HWP 패치 결과가 한글에 보이지 않던 문제 |
|
|
131
|
+
|
|
132
|
+
이전 버전과 상세 내용은 [변경 이력](CHANGELOG.md)에 있습니다.
|
|
163
133
|
|
|
164
134
|
## 자주 묻는 질문
|
|
165
135
|
|
|
@@ -175,6 +145,9 @@ OCR 줄의 상자·신뢰도는 `--ocr --ocr-lines --format json`으로 받습
|
|
|
175
145
|
**Q. RAG 색인용으로 쓸 수 있나요?**
|
|
176
146
|
`--format chunks`가 제목 경로를 붙인 구조 청크와 독립 표 청크를 냅니다. 표를 HTML 없이 받으려면 `--table-format gfm`(API는 `tableFormat: "gfm"`)을 씁니다. Python·Java에서는 [Python SDK](sdk/python/README.md)·[Java SDK](sdk/java/README.md)로 부릅니다.
|
|
177
147
|
|
|
148
|
+
**Q. OCR 줄 좌표나 다른 모델이 필요하면?**
|
|
149
|
+
`--ocr --ocr-lines --format json`이 줄별 상자·신뢰도를 내고, `--ocr-det`·`--ocr-det-long-side`로 검출 모델과 해상도를 고릅니다. [OCR 줄·모델 선택](docs/usage.md#ocr-줄모델-선택)
|
|
150
|
+
|
|
178
151
|
## 문서·보안
|
|
179
152
|
|
|
180
153
|
- [상세 사용법](docs/usage.md): 전체 CLI·MCP 도구·API·지원 포맷
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
hwpxToProfile,
|
|
24
24
|
incompatibleGongmunWarnings,
|
|
25
25
|
isKnownFont,
|
|
26
|
+
lintBlocks,
|
|
26
27
|
lintBudgetText,
|
|
27
28
|
lintGongmunText,
|
|
28
29
|
lintLogicText,
|
|
@@ -57,10 +58,10 @@ import {
|
|
|
57
58
|
usesGaejosikMunche,
|
|
58
59
|
usesLogicStructure,
|
|
59
60
|
validateHwpx
|
|
60
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-4BCQ3FQS.js";
|
|
61
62
|
import {
|
|
62
63
|
blocksToChunks
|
|
63
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-MI25BZSU.js";
|
|
64
65
|
import {
|
|
65
66
|
SPACE_EM_FIXED,
|
|
66
67
|
SPACE_EM_FONT,
|
|
@@ -85,20 +86,20 @@ import {
|
|
|
85
86
|
renderSceneToHtml,
|
|
86
87
|
simulateWrap,
|
|
87
88
|
simulateWrapKeepWord
|
|
88
|
-
} from "./chunk-
|
|
89
|
-
import "./chunk-
|
|
89
|
+
} from "./chunk-LBPUPT6S.js";
|
|
90
|
+
import "./chunk-LEL5UBGR.js";
|
|
90
91
|
import {
|
|
91
92
|
blocksToPages
|
|
92
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-RS2Q64N5.js";
|
|
93
94
|
import "./chunk-VKVDMH7X.js";
|
|
94
95
|
import "./chunk-VQFA55IC.js";
|
|
95
96
|
import "./chunk-BYMPPVT3.js";
|
|
96
|
-
import "./chunk-
|
|
97
|
+
import "./chunk-W4P3QPSB.js";
|
|
97
98
|
import {
|
|
98
99
|
blocksToMarkdown,
|
|
99
100
|
flattenLayoutTables,
|
|
100
101
|
hasStructuredCellContent
|
|
101
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-BIVO2GMU.js";
|
|
102
103
|
import {
|
|
103
104
|
ValueCursor,
|
|
104
105
|
applySplices,
|
|
@@ -112,11 +113,11 @@ import {
|
|
|
112
113
|
isLabelCell,
|
|
113
114
|
placeSealHwpx,
|
|
114
115
|
scanSectionXml
|
|
115
|
-
} from "./chunk-
|
|
116
|
-
import "./chunk-
|
|
116
|
+
} from "./chunk-5EP6VFP5.js";
|
|
117
|
+
import "./chunk-L2OJUIII.js";
|
|
117
118
|
import {
|
|
118
119
|
VERSION
|
|
119
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-YE4T2P6F.js";
|
|
120
121
|
import {
|
|
121
122
|
DEFAULT_REDACT_RULES,
|
|
122
123
|
redactMarkdown,
|
|
@@ -176,6 +177,7 @@ export {
|
|
|
176
177
|
isOldHwpFile,
|
|
177
178
|
isPdfFile,
|
|
178
179
|
isZipFile,
|
|
180
|
+
lintBlocks,
|
|
179
181
|
lintBudgetText,
|
|
180
182
|
lintGongmunText,
|
|
181
183
|
lintLogicText,
|
|
@@ -225,4 +227,4 @@ export {
|
|
|
225
227
|
usesLogicStructure,
|
|
226
228
|
validateHwpx
|
|
227
229
|
};
|
|
228
|
-
//# sourceMappingURL=-
|
|
230
|
+
//# sourceMappingURL=-TSN4SWFV.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
UNRULED_REGION_TABLES,
|
|
7
7
|
extractPageBlocksWithLines
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ZR3BPESP.js";
|
|
9
9
|
import {
|
|
10
10
|
validateOcrOptions
|
|
11
11
|
} from "./chunk-BYMPPVT3.js";
|
|
@@ -16,11 +16,11 @@ import {
|
|
|
16
16
|
ocrSourcePath,
|
|
17
17
|
parseCharacterDict,
|
|
18
18
|
resolveOcrModels
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-V2GW3M2F.js";
|
|
20
20
|
import {
|
|
21
21
|
KordocError,
|
|
22
22
|
OPTIONAL_DEP_INSTALL_HINT
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-YE4T2P6F.js";
|
|
24
24
|
|
|
25
25
|
// src/ocr/ruling-lines.ts
|
|
26
26
|
var INK_LUMA_MAX = 205;
|
|
@@ -2215,4 +2215,4 @@ export {
|
|
|
2215
2215
|
groupOcrLines,
|
|
2216
2216
|
ocrItemsToBlocks
|
|
2217
2217
|
};
|
|
2218
|
-
//# sourceMappingURL=chunk-
|
|
2218
|
+
//# sourceMappingURL=chunk-2SMANR76.js.map
|
|
@@ -51,10 +51,10 @@ import {
|
|
|
51
51
|
resolveParaHeading,
|
|
52
52
|
simulateWrap,
|
|
53
53
|
takeTocLeaders
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-LBPUPT6S.js";
|
|
55
55
|
import {
|
|
56
56
|
blocksToPages
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-RS2Q64N5.js";
|
|
58
58
|
import {
|
|
59
59
|
bmpToPng,
|
|
60
60
|
inlineImagesIntoMarkdown
|
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
tidyScriptTags,
|
|
77
77
|
unframeLayoutTables,
|
|
78
78
|
wrapScript
|
|
79
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-W4P3QPSB.js";
|
|
80
80
|
import {
|
|
81
81
|
MAX_COLS,
|
|
82
82
|
MAX_ROWS,
|
|
@@ -99,7 +99,7 @@ import {
|
|
|
99
99
|
noteTableHtml,
|
|
100
100
|
sanitizeText,
|
|
101
101
|
visibleText
|
|
102
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-BIVO2GMU.js";
|
|
103
103
|
import {
|
|
104
104
|
ANNOTATION_BLANK_RE,
|
|
105
105
|
ValueCursor,
|
|
@@ -132,7 +132,7 @@ import {
|
|
|
132
132
|
resolveUnmatched,
|
|
133
133
|
scanInlineSegments,
|
|
134
134
|
scanSectionXml
|
|
135
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-5EP6VFP5.js";
|
|
136
136
|
import {
|
|
137
137
|
MAX_DECOMPRESS_SIZE,
|
|
138
138
|
MAX_XML_DEPTH,
|
|
@@ -149,7 +149,7 @@ import {
|
|
|
149
149
|
localName,
|
|
150
150
|
rawTextContent,
|
|
151
151
|
readZipEntry
|
|
152
|
-
} from "./chunk-
|
|
152
|
+
} from "./chunk-L2OJUIII.js";
|
|
153
153
|
import {
|
|
154
154
|
KordocError,
|
|
155
155
|
classifyError,
|
|
@@ -165,7 +165,7 @@ import {
|
|
|
165
165
|
toArrayBuffer,
|
|
166
166
|
unescapeHtml,
|
|
167
167
|
unzipLimitBytes
|
|
168
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-YE4T2P6F.js";
|
|
169
169
|
|
|
170
170
|
// src/table/visual.ts
|
|
171
171
|
import { readFile as readFile2 } from "fs/promises";
|
|
@@ -19329,7 +19329,7 @@ var MIN_SIDE = 24;
|
|
|
19329
19329
|
async function ocrEmbeddedImages(blocks, options, warnings) {
|
|
19330
19330
|
const ocr = options?.ocr;
|
|
19331
19331
|
if (ocr !== true && ocr !== "force" && typeof ocr !== "function") return false;
|
|
19332
|
-
const { parseImageDocument } = await import("./image-ocr-
|
|
19332
|
+
const { parseImageDocument } = await import("./image-ocr-UNTKJLQL.js");
|
|
19333
19333
|
let inserted = false, unreadable = 0;
|
|
19334
19334
|
let failed = null;
|
|
19335
19335
|
const walk = async (list, depth) => {
|
|
@@ -28501,6 +28501,11 @@ function scheduleLineYear(m) {
|
|
|
28501
28501
|
const before = (m.input ?? "").slice(Math.max(0, at - 40), at);
|
|
28502
28502
|
return SCHEDULE_LEADER.test(before) ? null : "";
|
|
28503
28503
|
}
|
|
28504
|
+
var calcLineCache;
|
|
28505
|
+
function isCalcLine(line) {
|
|
28506
|
+
if (calcLineCache?.line !== line) calcLineCache = { line, calc: /[×✕]|\s=\s/.test(line) };
|
|
28507
|
+
return calcLineCache.calc;
|
|
28508
|
+
}
|
|
28504
28509
|
var WEEKDAYS = "\uC77C\uC6D4\uD654\uC218\uBAA9\uAE08\uD1A0";
|
|
28505
28510
|
function weekdayCheck(m) {
|
|
28506
28511
|
const [y, mo, d] = [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
@@ -28611,7 +28616,7 @@ var RULES = [
|
|
|
28611
28616
|
severity: "error",
|
|
28612
28617
|
pattern: /(?<![\d,])\d+\s*천\s*원/g,
|
|
28613
28618
|
skipTable: true,
|
|
28614
|
-
check: (m) =>
|
|
28619
|
+
check: (m) => isCalcLine(m.input ?? "") ? null : "",
|
|
28615
28620
|
message: "\uAE08\uC561\uC740 '\uCC9C\uC6D0'\uC73C\uB85C \uC904\uC774\uC9C0 \uC54A\uACE0 \uC544\uB77C\uBE44\uC544 \uC22B\uC790\uB85C",
|
|
28616
28621
|
suggest: "\uC608) 345,000\uC6D0"
|
|
28617
28622
|
},
|
|
@@ -29544,7 +29549,7 @@ var NUM = String.raw`\d[\d,]*(?:\.\d+)?`;
|
|
|
29544
29549
|
var MUL = String.raw`[×xX*✕]`;
|
|
29545
29550
|
var FACTOR = String.raw`${NUM}\s{0,2}(?:%|[가-힣]{1,3})?`;
|
|
29546
29551
|
var CALC_RE = new RegExp(
|
|
29547
|
-
String.raw`(?<![\d,.])(?<![
|
|
29552
|
+
String.raw`(?<![\d,.])(?<![+−×xX✕]\s{0,8})(?<!\S\s{0,8}[\-*]\s{0,8})(${FACTOR}(?:\s{0,3}${MUL}\s{0,3}${FACTOR}){1,8})\s{0,3}=\s{0,3}(${NUM})\s{0,2}(원|천원|만원|백만원|억원)`,
|
|
29548
29553
|
"g"
|
|
29549
29554
|
);
|
|
29550
29555
|
var FACTOR_RE = new RegExp(String.raw`(${NUM})\s{0,2}(%|[가-힣]{1,3})?`, "g");
|
|
@@ -29591,8 +29596,9 @@ function checkCalc(line, no, out) {
|
|
|
29591
29596
|
});
|
|
29592
29597
|
}
|
|
29593
29598
|
}
|
|
29594
|
-
var SUBTOTAL_RE = /^소\s
|
|
29599
|
+
var SUBTOTAL_RE = /^소\s*계\s*(?:\([^)]{1,10}\))?$/;
|
|
29595
29600
|
var NON_ADDITIVE_HEAD = /률|율|비율|%|단가|평균/;
|
|
29601
|
+
var NON_ADDITIVE_ROW = /^(?:구성비|비중|평균|단가|환율|[가-힣]{0,4}(?:비율|증감률|증감율|집행률|집행율|달성률|달성율))(?:\(%\))?$/;
|
|
29596
29602
|
var plainCell = (c) => c.replace(/[*_`]/g, "").trim();
|
|
29597
29603
|
function cellNum(c) {
|
|
29598
29604
|
const t = plainCell(c);
|
|
@@ -29632,7 +29638,7 @@ function checkTable(rows, out) {
|
|
|
29632
29638
|
});
|
|
29633
29639
|
}
|
|
29634
29640
|
const subs = body.filter((r) => SUBTOTAL_RE.test(label(r)));
|
|
29635
|
-
const parts = subs.length ? subs : body.filter((r) => r !== total);
|
|
29641
|
+
const parts = subs.length ? subs : body.filter((r) => r !== total && !NON_ADDITIVE_ROW.test(label(r).replace(/\s+/g, "")));
|
|
29636
29642
|
for (let c = 0; c < cols; c++) {
|
|
29637
29643
|
const cell2 = plainCell(total.cells[c] ?? "");
|
|
29638
29644
|
if (cell2 === "" || cell2 === "-" || cell2 === "\u2013" || NON_ADDITIVE_HEAD.test(plainCell(rows[0].cells[c] ?? ""))) continue;
|
|
@@ -29897,6 +29903,118 @@ function runLintSuite(text, opts = {}) {
|
|
|
29897
29903
|
};
|
|
29898
29904
|
}
|
|
29899
29905
|
|
|
29906
|
+
// src/hwpx/lint-blocks.ts
|
|
29907
|
+
var MARKDOWN_STRUCTURE = /^\s*(?:```|~~~|#|\||>)/;
|
|
29908
|
+
var safeLine = (text) => text.replace(/[\r\n]/g, " ");
|
|
29909
|
+
var safeCell = (text) => safeLine(text).replace(/\|/g, "\uFF5C");
|
|
29910
|
+
var MAX_DENSE_CELLS = 1e5;
|
|
29911
|
+
function blocksToLines(blocks) {
|
|
29912
|
+
const lines = [];
|
|
29913
|
+
const paragraph = (block) => {
|
|
29914
|
+
const text = safeLine(block.text);
|
|
29915
|
+
const prefix = MARKDOWN_STRUCTURE.test(text) ? "\\" : "";
|
|
29916
|
+
lines.push({ text: prefix + text, segments: [{ start: prefix.length, length: text.length, block: block.id }] });
|
|
29917
|
+
};
|
|
29918
|
+
const tables = /* @__PURE__ */ new Map();
|
|
29919
|
+
for (const b of blocks) if (b.table) (tables.get(b.table.id) ?? tables.set(b.table.id, []).get(b.table.id)).push(b);
|
|
29920
|
+
const emitted = /* @__PURE__ */ new Set();
|
|
29921
|
+
for (const b of blocks) {
|
|
29922
|
+
if (!b.table) {
|
|
29923
|
+
paragraph(b);
|
|
29924
|
+
continue;
|
|
29925
|
+
}
|
|
29926
|
+
if (emitted.has(b.table.id)) continue;
|
|
29927
|
+
emitted.add(b.table.id);
|
|
29928
|
+
const cells = tables.get(b.table.id);
|
|
29929
|
+
if (cells.length === 1) {
|
|
29930
|
+
paragraph(cells[0]);
|
|
29931
|
+
continue;
|
|
29932
|
+
}
|
|
29933
|
+
const rows = cells.reduce((n, c) => Math.max(n, c.table.row + 1), 0);
|
|
29934
|
+
const cols = cells.reduce((n, c) => Math.max(n, c.table.col + 1), 0);
|
|
29935
|
+
const range = (n) => Array.from({ length: n }, (_, i) => i);
|
|
29936
|
+
const used = (k) => [...new Set(cells.map((c) => c.table[k]))].sort((a, b2) => a - b2);
|
|
29937
|
+
const dense = rows * cols <= Math.max(MAX_DENSE_CELLS, cells.length * 4);
|
|
29938
|
+
const rowNos = dense ? range(rows) : used("row");
|
|
29939
|
+
const colNos = dense ? range(cols) : used("col");
|
|
29940
|
+
const at = /* @__PURE__ */ new Map();
|
|
29941
|
+
for (const c of cells) {
|
|
29942
|
+
const key = `${c.table.row},${c.table.col}`;
|
|
29943
|
+
const before = at.get(key);
|
|
29944
|
+
if (before) paragraph(before);
|
|
29945
|
+
at.set(key, c);
|
|
29946
|
+
}
|
|
29947
|
+
lines.push({ text: "", segments: [] });
|
|
29948
|
+
for (const [ri, r] of rowNos.entries()) {
|
|
29949
|
+
let text = "|";
|
|
29950
|
+
const segments = [];
|
|
29951
|
+
for (const c of colNos) {
|
|
29952
|
+
text += " ";
|
|
29953
|
+
const cell2 = at.get(`${r},${c}`);
|
|
29954
|
+
if (cell2) {
|
|
29955
|
+
const t = safeCell(cell2.text);
|
|
29956
|
+
segments.push({ start: text.length, length: t.length, block: cell2.id });
|
|
29957
|
+
text += t;
|
|
29958
|
+
}
|
|
29959
|
+
text += " |";
|
|
29960
|
+
}
|
|
29961
|
+
lines.push({ text, segments });
|
|
29962
|
+
if (ri === 0) lines.push({ text: "|" + " --- |".repeat(colNos.length), segments: [] });
|
|
29963
|
+
}
|
|
29964
|
+
lines.push({ text: "", segments: [] });
|
|
29965
|
+
}
|
|
29966
|
+
return lines;
|
|
29967
|
+
}
|
|
29968
|
+
function locate(lines, f) {
|
|
29969
|
+
const line = lines[f.line - 1];
|
|
29970
|
+
if (!line) return { block: null, offset: null };
|
|
29971
|
+
if (f.column !== void 0) {
|
|
29972
|
+
const at = f.column - 1;
|
|
29973
|
+
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);
|
|
29974
|
+
if (seg2) {
|
|
29975
|
+
const found = line.text.indexOf(f.match, Math.max(seg2.start, at));
|
|
29976
|
+
const start = found >= seg2.start && found < seg2.start + seg2.length ? found : at;
|
|
29977
|
+
const offset = Math.min(Math.max(0, start - seg2.start), seg2.length);
|
|
29978
|
+
return { block: seg2.block, offset, room: seg2.length - offset };
|
|
29979
|
+
}
|
|
29980
|
+
return { block: null, offset: null };
|
|
29981
|
+
}
|
|
29982
|
+
if (line.segments.length !== 1) return { block: null, offset: null };
|
|
29983
|
+
const seg = line.segments[0];
|
|
29984
|
+
const body = line.text.slice(seg.start, seg.start + seg.length);
|
|
29985
|
+
const first = f.match ? body.indexOf(f.match) : -1;
|
|
29986
|
+
const unique = first >= 0 && body.indexOf(f.match, first + 1) < 0;
|
|
29987
|
+
return { block: seg.block, offset: unique ? first : null, ...unique ? { room: seg.length - first } : {} };
|
|
29988
|
+
}
|
|
29989
|
+
function lintBlocks(blocks, opts = {}) {
|
|
29990
|
+
const lines = blocksToLines(blocks);
|
|
29991
|
+
const suite = runLintSuite(lines.map((l) => l.text).join("\n") + "\n", opts);
|
|
29992
|
+
const findings = [];
|
|
29993
|
+
const take = (category, list) => {
|
|
29994
|
+
for (const f of list ?? []) {
|
|
29995
|
+
const { block, offset, room } = locate(lines, f);
|
|
29996
|
+
const length = room === void 0 ? f.match.length : Math.min(f.match.length, room);
|
|
29997
|
+
findings.push({
|
|
29998
|
+
block,
|
|
29999
|
+
offset,
|
|
30000
|
+
length,
|
|
30001
|
+
category,
|
|
30002
|
+
rule: f.rule,
|
|
30003
|
+
severity: f.severity,
|
|
30004
|
+
match: f.match,
|
|
30005
|
+
message: f.message,
|
|
30006
|
+
...f.suggest ? { suggest: f.suggest } : {}
|
|
30007
|
+
});
|
|
30008
|
+
}
|
|
30009
|
+
};
|
|
30010
|
+
take("notation", suite.findings);
|
|
30011
|
+
take("munche", suite.munche);
|
|
30012
|
+
take("slop", suite.slop);
|
|
30013
|
+
take("logic", suite.logic);
|
|
30014
|
+
take("budget", suite.budget);
|
|
30015
|
+
return { findings, ...suite.numbers ? { numbers: suite.numbers } : {}, summary: suite.summary };
|
|
30016
|
+
}
|
|
30017
|
+
|
|
29900
30018
|
// src/roundtrip/patcher.ts
|
|
29901
30019
|
import JSZip11 from "jszip";
|
|
29902
30020
|
|
|
@@ -32941,7 +33059,7 @@ function scriptsOff(r, off) {
|
|
|
32941
33059
|
}
|
|
32942
33060
|
async function parseImage(buffer, options) {
|
|
32943
33061
|
try {
|
|
32944
|
-
const { parseImageDocument } = await import("./image-ocr-
|
|
33062
|
+
const { parseImageDocument } = await import("./image-ocr-UNTKJLQL.js");
|
|
32945
33063
|
const { blocks, warnings, lines } = await parseImageDocument(buffer, options);
|
|
32946
33064
|
stripScriptTags({ blocks });
|
|
32947
33065
|
return {
|
|
@@ -33005,7 +33123,7 @@ async function parseHwp(buffer, options) {
|
|
|
33005
33123
|
async function parsePdf(buffer, options) {
|
|
33006
33124
|
let parsePdfDocument;
|
|
33007
33125
|
try {
|
|
33008
|
-
const mod = await import("./parser-
|
|
33126
|
+
const mod = await import("./parser-YKATDDQV.js");
|
|
33009
33127
|
parsePdfDocument = mod.parsePdfDocument;
|
|
33010
33128
|
} catch {
|
|
33011
33129
|
return {
|
|
@@ -33214,6 +33332,7 @@ export {
|
|
|
33214
33332
|
formatGateFinding,
|
|
33215
33333
|
lintBudgetText,
|
|
33216
33334
|
runLintSuite,
|
|
33335
|
+
lintBlocks,
|
|
33217
33336
|
replaceOleStream,
|
|
33218
33337
|
wipeFreeSectors,
|
|
33219
33338
|
patchHwp,
|
|
@@ -33237,4 +33356,4 @@ export {
|
|
|
33237
33356
|
parseHwpml,
|
|
33238
33357
|
fillForm
|
|
33239
33358
|
};
|
|
33240
|
-
//# sourceMappingURL=chunk-
|
|
33359
|
+
//# sourceMappingURL=chunk-4BCQ3FQS.js.map
|