hwpkit-dev 0.0.2 → 0.0.5

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 (42) hide show
  1. package/ .npmignore +4 -1
  2. package/README.md +44 -7
  3. package/dist/index.d.mts +46 -16
  4. package/dist/index.d.ts +46 -16
  5. package/dist/index.js +3964 -1227
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +3964 -1227
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +2 -1
  10. package/playground/index.html +346 -0
  11. package/playground/main.ts +302 -0
  12. package/playground/vite.config.ts +16 -0
  13. package/src/contract/decoder.ts +1 -0
  14. package/src/contract/encoder.ts +6 -1
  15. package/src/core/BaseDecoder.ts +118 -0
  16. package/src/core/BaseEncoder.ts +146 -0
  17. package/src/decoders/docx/DocxDecoder.ts +743 -151
  18. package/src/decoders/html/HtmlDecoder.ts +366 -0
  19. package/src/decoders/hwp/HwpScanner.ts +478 -193
  20. package/src/decoders/hwpx/HwpxDecoder.ts +796 -297
  21. package/src/decoders/md/MdDecoder.ts +4 -4
  22. package/src/encoders/docx/DocxEncoder.ts +549 -240
  23. package/src/encoders/html/HtmlEncoder.ts +17 -19
  24. package/src/encoders/hwp/HwpEncoder.ts +1643 -890
  25. package/src/encoders/hwpx/HwpxEncoder.ts +1626 -472
  26. package/src/encoders/hwpx/constants.ts +148 -0
  27. package/src/encoders/hwpx/utils.ts +198 -0
  28. package/src/encoders/md/MdEncoder.ts +20 -15
  29. package/src/model/builders.ts +4 -4
  30. package/src/model/doc-props.ts +24 -10
  31. package/src/model/doc-tree.ts +13 -5
  32. package/src/pipeline/Pipeline.ts +7 -3
  33. package/src/pipeline/registry.ts +13 -2
  34. package/src/safety/StyleBridge.ts +51 -6
  35. package/src/toolkit/ArchiveKit.ts +56 -0
  36. package/src/toolkit/StyleMapper.ts +221 -0
  37. package/src/toolkit/UnitConverter.ts +138 -0
  38. package/src/toolkit/XmlKit.ts +0 -5
  39. package/hwp-analyze.ts +0 -90
  40. package/inspect-doc.ts +0 -57
  41. package/output_test.hwp +0 -0
  42. package/test-docx-to-hwp.ts +0 -45
package/ .npmignore CHANGED
@@ -9,4 +9,7 @@ dist
9
9
  tests
10
10
  data
11
11
  playground
12
- CLAUDE.*
12
+ CLAUDE.*
13
+ .c
14
+ Tester.so.c
15
+ *.hwp
package/README.md CHANGED
@@ -23,13 +23,14 @@
23
23
 
24
24
  ## 변환 지원 현황
25
25
 
26
- | 입력 \ 출력 | HWPX | DOCX | Markdown |
27
- |------------|:----:|:----:|:--------:|
28
- | **HWPX** | - | O | O |
29
- | **HWP** | O | O | O |
30
- | **DOCX** | O | - | O |
31
- | **Markdown** | O | O | - |
32
-
26
+ | 입력 \ 출력 | HWPX | HWP | DOCX |
27
+ |------------|:----:|:----:|:------:|
28
+ | **HWPX** | O | X | O |
29
+ | **HWP** | O | X | O |
30
+ | **DOCX** | O | X | O |
31
+ | **Markdown** |O | X ||
32
+
33
+ > 한글 2022기준 hwpx는 정상적으로 열림
33
34
  ---
34
35
 
35
36
  ## 설치
@@ -113,6 +114,42 @@ const doc = buildRoot({ title: '제목' }, [
113
114
  ]);
114
115
  ```
115
116
 
117
+ ### 스타일 적용
118
+
119
+ ```typescript
120
+ // 텍스트 스타일
121
+ buildSpan('스타일 적용 텍스트', {
122
+ font: 'Malgun Gothic', // 글꼴
123
+ pt: 14, // 글자 크기 (pt)
124
+ b: true, // 볼드
125
+ i: true, // 이탤릭
126
+ u: true, // 밑줄
127
+ s: true, // 취소선
128
+ color: 'FF0000', // 글색 (hex, BGR)
129
+ bg: 'FFFF00' // 형광펜 (hex, BGR)
130
+ });
131
+
132
+ // 표 정렬 및 선 스타일
133
+ buildGrid(rows, {
134
+ align: 'center', // 표 정렬: 'left' | 'center' | 'right'
135
+ defaultStroke: { // 기본 선 스타일
136
+ kind: 'solid', // 선 종류: 'solid' | 'double' | 'dash' | 'dot'
137
+ pt: 1, // 선 굵기 (pt)
138
+ color: '000000' // 선 색상 (hex, BGR)
139
+ },
140
+ colWidths: [100, 100] // 열 너비 (pt)
141
+ });
142
+
143
+ // 개별 셀의 선 스타일
144
+ buildCell(content, {
145
+ top: { kind: 'double', pt: 2, color: '0000FF' }, // 상단 선
146
+ bot: { kind: 'dash', pt: 1.5, color: 'FF0000' }, // 하단 선
147
+ left: { kind: 'dot', pt: 1, color: '00FF00' }, // 좌측 선
148
+ right: { kind: 'solid', pt: 3, color: 'FFFF00' }, // 우측 선
149
+ bg: 'FFFFFF' // 셀 배경색
150
+ });
151
+ ```
152
+
116
153
  ### 트리 순회
117
154
 
118
155
  ```typescript
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- type Align = 'left' | 'center' | 'right' | 'justify';
2
- type ImgWrap = 'inline' | 'square' | 'tight' | 'through' | 'none' | 'behind' | 'front';
1
+ type Align = 'left' | 'center' | 'right' | 'justify' | 'distribute' | 'distribute_space';
2
+ type ImgWrap = 'inline' | 'square' | 'tight' | 'through' | 'none' | 'behind' | 'front' | 'topAndBottom';
3
3
  type ImgHorzAlign = 'left' | 'center' | 'right';
4
4
  type ImgVertAlign = 'top' | 'center' | 'bottom';
5
5
  type ImgHorzRelTo = 'margin' | 'column' | 'page' | 'para';
@@ -21,7 +21,7 @@ interface ImgLayout {
21
21
  }
22
22
  type VAlign = 'top' | 'mid' | 'bot';
23
23
  type Heading = 1 | 2 | 3 | 4 | 5 | 6;
24
- type StrokeKind = 'solid' | 'dash' | 'dot' | 'double' | 'none';
24
+ type StrokeKind = 'solid' | 'dash' | 'dot' | 'double' | 'none' | 'dashDot' | 'dashDotDot' | 'wave';
25
25
  interface TextProps {
26
26
  b?: boolean;
27
27
  i?: boolean;
@@ -37,13 +37,21 @@ interface TextProps {
37
37
  interface ParaProps {
38
38
  align?: Align;
39
39
  heading?: Heading;
40
+ styleId?: string;
41
+ hwpStyleId?: number;
40
42
  indentPt?: number;
43
+ indentRightPt?: number;
44
+ firstLineIndentPt?: number;
45
+ leftMargin?: number;
41
46
  spaceBefore?: number;
42
47
  spaceAfter?: number;
43
48
  lineHeight?: number;
49
+ lineHeightFixed?: number;
44
50
  listLv?: number;
45
51
  listOrd?: boolean;
46
52
  listMark?: string;
53
+ verAlign?: 'baseline' | 'top' | 'center' | 'bottom';
54
+ lineWrap?: 'break' | 'squeeze' | 'keep';
47
55
  }
48
56
  interface Stroke {
49
57
  kind: StrokeKind;
@@ -57,6 +65,10 @@ interface CellProps {
57
65
  right?: Stroke;
58
66
  bg?: string;
59
67
  padPt?: number;
68
+ padT?: number;
69
+ padB?: number;
70
+ padL?: number;
71
+ padR?: number;
60
72
  align?: Align;
61
73
  va?: VAlign;
62
74
  isHeader?: boolean;
@@ -75,6 +87,7 @@ interface GridProps {
75
87
  defaultStroke?: Stroke;
76
88
  look?: TableLook;
77
89
  headerRow?: boolean;
90
+ align?: Align;
78
91
  }
79
92
  interface PageDims {
80
93
  wPt: number;
@@ -84,6 +97,8 @@ interface PageDims {
84
97
  ml: number;
85
98
  mr: number;
86
99
  orient?: 'portrait' | 'landscape';
100
+ headerPt?: number;
101
+ footerPt?: number;
87
102
  }
88
103
  interface DocMeta {
89
104
  title?: string;
@@ -93,6 +108,8 @@ interface DocMeta {
93
108
  keywords?: string;
94
109
  created?: string;
95
110
  modified?: string;
111
+ zoom?: number;
112
+ viewMode?: string;
96
113
  }
97
114
  declare const A4: PageDims;
98
115
  declare const A4_LANDSCAPE: PageDims;
@@ -117,7 +134,7 @@ interface PbNode {
117
134
  }
118
135
  interface PageNumNode {
119
136
  tag: 'pagenum';
120
- format?: 'decimal' | 'roman' | 'romanCaps';
137
+ format?: 'decimal' | 'roman' | 'romanCaps' | 'total';
121
138
  }
122
139
  interface ImgNode {
123
140
  tag: 'img';
@@ -141,14 +158,14 @@ interface LinkNode {
141
158
  interface ParaNode {
142
159
  tag: 'para';
143
160
  props: ParaProps;
144
- kids: (SpanNode | ImgNode | LinkNode)[];
161
+ kids: (SpanNode | ImgNode | LinkNode | GridNode | PageNumNode)[];
145
162
  }
146
163
  interface CellNode {
147
164
  tag: 'cell';
148
165
  cs: number;
149
166
  rs: number;
150
167
  props: CellProps;
151
- kids: ParaNode[];
168
+ kids: (ParaNode | GridNode)[];
152
169
  }
153
170
  interface RowNode {
154
171
  tag: 'row';
@@ -165,8 +182,16 @@ interface SheetNode {
165
182
  tag: 'sheet';
166
183
  dims: PageDims;
167
184
  kids: ContentNode[];
168
- header?: ParaNode[];
169
- footer?: ParaNode[];
185
+ headers?: {
186
+ default?: ParaNode[];
187
+ first?: ParaNode[];
188
+ even?: ParaNode[];
189
+ };
190
+ footers?: {
191
+ default?: ParaNode[];
192
+ first?: ParaNode[];
193
+ even?: ParaNode[];
194
+ };
170
195
  }
171
196
  interface DocRoot {
172
197
  tag: 'root';
@@ -189,14 +214,19 @@ interface Fail {
189
214
  declare function succeed<T>(data: T, warns?: string[]): Ok<T>;
190
215
  declare function fail(error: string, warns?: string[]): Fail;
191
216
 
192
- interface Decoder {
217
+ interface EncoderOptions {
218
+ [key: string]: any;
219
+ }
220
+ interface Encoder {
193
221
  readonly format: string;
194
- decode(data: Uint8Array): Promise<Outcome<DocRoot>>;
222
+ readonly aliases?: string[];
223
+ encode(doc: DocRoot, options?: EncoderOptions): Promise<Outcome<Uint8Array>>;
195
224
  }
196
225
 
197
- interface Encoder {
226
+ interface Decoder {
198
227
  readonly format: string;
199
- encode(doc: DocRoot): Promise<Outcome<Uint8Array>>;
228
+ readonly aliases?: string[];
229
+ decode(data: Uint8Array): Promise<Outcome<DocRoot>>;
200
230
  }
201
231
 
202
232
  declare class Pipeline {
@@ -208,7 +238,7 @@ declare class Pipeline {
208
238
  /** File/Blob 비동기 입력 */
209
239
  static openAsync(input: File | Blob | Uint8Array | string, fmt?: string): Promise<Pipeline>;
210
240
  /** 목표 포맷으로 변환 */
211
- to(targetFmt: string): Promise<Outcome<Uint8Array>>;
241
+ to(targetFmt: string, options?: EncoderOptions): Promise<Outcome<Uint8Array>>;
212
242
  /** DocRoot만 추출 (인코딩 없이) */
213
243
  inspect(): Promise<Outcome<DocRoot>>;
214
244
  }
@@ -227,8 +257,8 @@ declare const registry: FormatRegistry;
227
257
 
228
258
  declare function buildRoot(meta?: DocMeta, kids?: SheetNode[]): DocRoot;
229
259
  declare function buildSheet(kids?: ContentNode[], dims?: PageDims, opts?: {
230
- header?: ParaNode[];
231
- footer?: ParaNode[];
260
+ headers?: SheetNode["headers"];
261
+ footers?: SheetNode["footers"];
232
262
  }): SheetNode;
233
263
  declare function buildPageNum(format?: PageNumNode['format']): PageNumNode;
234
264
  declare function buildBr(): BrNode;
@@ -238,7 +268,7 @@ declare function buildSpan(content: string, props?: TextProps): SpanNode;
238
268
  declare function buildImg(b64: string, mime: ImgNode['mime'], w: number, h: number, alt?: string, layout?: ImgLayout): ImgNode;
239
269
  declare function buildGrid(kids: RowNode[], props?: GridProps): GridNode;
240
270
  declare function buildRow(kids: CellNode[], heightPt?: number): RowNode;
241
- declare function buildCell(kids: ParaNode[], opts?: {
271
+ declare function buildCell(kids: (ParaNode | GridNode)[], opts?: {
242
272
  cs?: number;
243
273
  rs?: number;
244
274
  props?: CellProps;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- type Align = 'left' | 'center' | 'right' | 'justify';
2
- type ImgWrap = 'inline' | 'square' | 'tight' | 'through' | 'none' | 'behind' | 'front';
1
+ type Align = 'left' | 'center' | 'right' | 'justify' | 'distribute' | 'distribute_space';
2
+ type ImgWrap = 'inline' | 'square' | 'tight' | 'through' | 'none' | 'behind' | 'front' | 'topAndBottom';
3
3
  type ImgHorzAlign = 'left' | 'center' | 'right';
4
4
  type ImgVertAlign = 'top' | 'center' | 'bottom';
5
5
  type ImgHorzRelTo = 'margin' | 'column' | 'page' | 'para';
@@ -21,7 +21,7 @@ interface ImgLayout {
21
21
  }
22
22
  type VAlign = 'top' | 'mid' | 'bot';
23
23
  type Heading = 1 | 2 | 3 | 4 | 5 | 6;
24
- type StrokeKind = 'solid' | 'dash' | 'dot' | 'double' | 'none';
24
+ type StrokeKind = 'solid' | 'dash' | 'dot' | 'double' | 'none' | 'dashDot' | 'dashDotDot' | 'wave';
25
25
  interface TextProps {
26
26
  b?: boolean;
27
27
  i?: boolean;
@@ -37,13 +37,21 @@ interface TextProps {
37
37
  interface ParaProps {
38
38
  align?: Align;
39
39
  heading?: Heading;
40
+ styleId?: string;
41
+ hwpStyleId?: number;
40
42
  indentPt?: number;
43
+ indentRightPt?: number;
44
+ firstLineIndentPt?: number;
45
+ leftMargin?: number;
41
46
  spaceBefore?: number;
42
47
  spaceAfter?: number;
43
48
  lineHeight?: number;
49
+ lineHeightFixed?: number;
44
50
  listLv?: number;
45
51
  listOrd?: boolean;
46
52
  listMark?: string;
53
+ verAlign?: 'baseline' | 'top' | 'center' | 'bottom';
54
+ lineWrap?: 'break' | 'squeeze' | 'keep';
47
55
  }
48
56
  interface Stroke {
49
57
  kind: StrokeKind;
@@ -57,6 +65,10 @@ interface CellProps {
57
65
  right?: Stroke;
58
66
  bg?: string;
59
67
  padPt?: number;
68
+ padT?: number;
69
+ padB?: number;
70
+ padL?: number;
71
+ padR?: number;
60
72
  align?: Align;
61
73
  va?: VAlign;
62
74
  isHeader?: boolean;
@@ -75,6 +87,7 @@ interface GridProps {
75
87
  defaultStroke?: Stroke;
76
88
  look?: TableLook;
77
89
  headerRow?: boolean;
90
+ align?: Align;
78
91
  }
79
92
  interface PageDims {
80
93
  wPt: number;
@@ -84,6 +97,8 @@ interface PageDims {
84
97
  ml: number;
85
98
  mr: number;
86
99
  orient?: 'portrait' | 'landscape';
100
+ headerPt?: number;
101
+ footerPt?: number;
87
102
  }
88
103
  interface DocMeta {
89
104
  title?: string;
@@ -93,6 +108,8 @@ interface DocMeta {
93
108
  keywords?: string;
94
109
  created?: string;
95
110
  modified?: string;
111
+ zoom?: number;
112
+ viewMode?: string;
96
113
  }
97
114
  declare const A4: PageDims;
98
115
  declare const A4_LANDSCAPE: PageDims;
@@ -117,7 +134,7 @@ interface PbNode {
117
134
  }
118
135
  interface PageNumNode {
119
136
  tag: 'pagenum';
120
- format?: 'decimal' | 'roman' | 'romanCaps';
137
+ format?: 'decimal' | 'roman' | 'romanCaps' | 'total';
121
138
  }
122
139
  interface ImgNode {
123
140
  tag: 'img';
@@ -141,14 +158,14 @@ interface LinkNode {
141
158
  interface ParaNode {
142
159
  tag: 'para';
143
160
  props: ParaProps;
144
- kids: (SpanNode | ImgNode | LinkNode)[];
161
+ kids: (SpanNode | ImgNode | LinkNode | GridNode | PageNumNode)[];
145
162
  }
146
163
  interface CellNode {
147
164
  tag: 'cell';
148
165
  cs: number;
149
166
  rs: number;
150
167
  props: CellProps;
151
- kids: ParaNode[];
168
+ kids: (ParaNode | GridNode)[];
152
169
  }
153
170
  interface RowNode {
154
171
  tag: 'row';
@@ -165,8 +182,16 @@ interface SheetNode {
165
182
  tag: 'sheet';
166
183
  dims: PageDims;
167
184
  kids: ContentNode[];
168
- header?: ParaNode[];
169
- footer?: ParaNode[];
185
+ headers?: {
186
+ default?: ParaNode[];
187
+ first?: ParaNode[];
188
+ even?: ParaNode[];
189
+ };
190
+ footers?: {
191
+ default?: ParaNode[];
192
+ first?: ParaNode[];
193
+ even?: ParaNode[];
194
+ };
170
195
  }
171
196
  interface DocRoot {
172
197
  tag: 'root';
@@ -189,14 +214,19 @@ interface Fail {
189
214
  declare function succeed<T>(data: T, warns?: string[]): Ok<T>;
190
215
  declare function fail(error: string, warns?: string[]): Fail;
191
216
 
192
- interface Decoder {
217
+ interface EncoderOptions {
218
+ [key: string]: any;
219
+ }
220
+ interface Encoder {
193
221
  readonly format: string;
194
- decode(data: Uint8Array): Promise<Outcome<DocRoot>>;
222
+ readonly aliases?: string[];
223
+ encode(doc: DocRoot, options?: EncoderOptions): Promise<Outcome<Uint8Array>>;
195
224
  }
196
225
 
197
- interface Encoder {
226
+ interface Decoder {
198
227
  readonly format: string;
199
- encode(doc: DocRoot): Promise<Outcome<Uint8Array>>;
228
+ readonly aliases?: string[];
229
+ decode(data: Uint8Array): Promise<Outcome<DocRoot>>;
200
230
  }
201
231
 
202
232
  declare class Pipeline {
@@ -208,7 +238,7 @@ declare class Pipeline {
208
238
  /** File/Blob 비동기 입력 */
209
239
  static openAsync(input: File | Blob | Uint8Array | string, fmt?: string): Promise<Pipeline>;
210
240
  /** 목표 포맷으로 변환 */
211
- to(targetFmt: string): Promise<Outcome<Uint8Array>>;
241
+ to(targetFmt: string, options?: EncoderOptions): Promise<Outcome<Uint8Array>>;
212
242
  /** DocRoot만 추출 (인코딩 없이) */
213
243
  inspect(): Promise<Outcome<DocRoot>>;
214
244
  }
@@ -227,8 +257,8 @@ declare const registry: FormatRegistry;
227
257
 
228
258
  declare function buildRoot(meta?: DocMeta, kids?: SheetNode[]): DocRoot;
229
259
  declare function buildSheet(kids?: ContentNode[], dims?: PageDims, opts?: {
230
- header?: ParaNode[];
231
- footer?: ParaNode[];
260
+ headers?: SheetNode["headers"];
261
+ footers?: SheetNode["footers"];
232
262
  }): SheetNode;
233
263
  declare function buildPageNum(format?: PageNumNode['format']): PageNumNode;
234
264
  declare function buildBr(): BrNode;
@@ -238,7 +268,7 @@ declare function buildSpan(content: string, props?: TextProps): SpanNode;
238
268
  declare function buildImg(b64: string, mime: ImgNode['mime'], w: number, h: number, alt?: string, layout?: ImgLayout): ImgNode;
239
269
  declare function buildGrid(kids: RowNode[], props?: GridProps): GridNode;
240
270
  declare function buildRow(kids: CellNode[], heightPt?: number): RowNode;
241
- declare function buildCell(kids: ParaNode[], opts?: {
271
+ declare function buildCell(kids: (ParaNode | GridNode)[], opts?: {
242
272
  cs?: number;
243
273
  rs?: number;
244
274
  props?: CellProps;