hwpkit-dev 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/ .npmignore +4 -2
  2. package/README.md +39 -2
  3. package/dist/index.d.mts +41 -14
  4. package/dist/index.d.ts +41 -14
  5. package/dist/index.js +3553 -1159
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +3553 -1159
  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 +325 -157
  20. package/src/decoders/hwpx/HwpxDecoder.ts +785 -297
  21. package/src/decoders/md/MdDecoder.ts +4 -4
  22. package/src/encoders/docx/DocxEncoder.ts +504 -240
  23. package/src/encoders/html/HtmlEncoder.ts +17 -19
  24. package/src/encoders/hwp/HwpEncoder.ts +1466 -859
  25. package/src/encoders/hwpx/HwpxEncoder.ts +1477 -469
  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 +19 -5
  31. package/src/model/doc-tree.ts +12 -4
  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/test-styling.ts +210 -0
  40. package/hwp-analyze.ts +0 -90
  41. package/inspect-doc.ts +0 -57
  42. package/output_test.hwp +0 -0
  43. package/test-docx-to-hwp.ts +0 -45
package/ .npmignore CHANGED
@@ -1,5 +1,4 @@
1
1
  node_modules
2
- dist
3
2
  *.hml
4
3
  *.hml.md
5
4
  *.hwpx
@@ -9,4 +8,7 @@ dist
9
8
  tests
10
9
  data
11
10
  playground
12
- CLAUDE.*
11
+ CLAUDE.*
12
+ .c
13
+ Tester.so.c
14
+ *.hwp
package/README.md CHANGED
@@ -26,10 +26,11 @@
26
26
  | 입력 \ 출력 | HWPX | DOCX | Markdown |
27
27
  |------------|:----:|:----:|:--------:|
28
28
  | **HWPX** | - | O | O |
29
- | **HWP** | O | O | O |
29
+ | **HWP** | | O | O |
30
30
  | **DOCX** | O | - | O |
31
- | **Markdown** | O | O | - |
31
+ | **Markdown** | | | - |
32
32
 
33
+ > 한글 소프트웨어서는 작동이 안됨 (수정중)
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
1
  type Align = 'left' | 'center' | 'right' | 'justify';
2
- type ImgWrap = 'inline' | 'square' | 'tight' | 'through' | 'none' | 'behind' | 'front';
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,10 +37,15 @@ interface TextProps {
37
37
  interface ParaProps {
38
38
  align?: Align;
39
39
  heading?: Heading;
40
+ styleId?: string;
40
41
  indentPt?: number;
42
+ indentRightPt?: number;
43
+ firstLineIndentPt?: number;
44
+ leftMargin?: number;
41
45
  spaceBefore?: number;
42
46
  spaceAfter?: number;
43
47
  lineHeight?: number;
48
+ lineHeightFixed?: number;
44
49
  listLv?: number;
45
50
  listOrd?: boolean;
46
51
  listMark?: string;
@@ -57,6 +62,10 @@ interface CellProps {
57
62
  right?: Stroke;
58
63
  bg?: string;
59
64
  padPt?: number;
65
+ padT?: number;
66
+ padB?: number;
67
+ padL?: number;
68
+ padR?: number;
60
69
  align?: Align;
61
70
  va?: VAlign;
62
71
  isHeader?: boolean;
@@ -75,6 +84,7 @@ interface GridProps {
75
84
  defaultStroke?: Stroke;
76
85
  look?: TableLook;
77
86
  headerRow?: boolean;
87
+ align?: Align;
78
88
  }
79
89
  interface PageDims {
80
90
  wPt: number;
@@ -84,6 +94,8 @@ interface PageDims {
84
94
  ml: number;
85
95
  mr: number;
86
96
  orient?: 'portrait' | 'landscape';
97
+ headerPt?: number;
98
+ footerPt?: number;
87
99
  }
88
100
  interface DocMeta {
89
101
  title?: string;
@@ -93,6 +105,8 @@ interface DocMeta {
93
105
  keywords?: string;
94
106
  created?: string;
95
107
  modified?: string;
108
+ zoom?: number;
109
+ viewMode?: string;
96
110
  }
97
111
  declare const A4: PageDims;
98
112
  declare const A4_LANDSCAPE: PageDims;
@@ -141,14 +155,14 @@ interface LinkNode {
141
155
  interface ParaNode {
142
156
  tag: 'para';
143
157
  props: ParaProps;
144
- kids: (SpanNode | ImgNode | LinkNode)[];
158
+ kids: (SpanNode | ImgNode | LinkNode | GridNode)[];
145
159
  }
146
160
  interface CellNode {
147
161
  tag: 'cell';
148
162
  cs: number;
149
163
  rs: number;
150
164
  props: CellProps;
151
- kids: ParaNode[];
165
+ kids: (ParaNode | GridNode)[];
152
166
  }
153
167
  interface RowNode {
154
168
  tag: 'row';
@@ -165,8 +179,16 @@ interface SheetNode {
165
179
  tag: 'sheet';
166
180
  dims: PageDims;
167
181
  kids: ContentNode[];
168
- header?: ParaNode[];
169
- footer?: ParaNode[];
182
+ headers?: {
183
+ default?: ParaNode[];
184
+ first?: ParaNode[];
185
+ even?: ParaNode[];
186
+ };
187
+ footers?: {
188
+ default?: ParaNode[];
189
+ first?: ParaNode[];
190
+ even?: ParaNode[];
191
+ };
170
192
  }
171
193
  interface DocRoot {
172
194
  tag: 'root';
@@ -189,14 +211,19 @@ interface Fail {
189
211
  declare function succeed<T>(data: T, warns?: string[]): Ok<T>;
190
212
  declare function fail(error: string, warns?: string[]): Fail;
191
213
 
192
- interface Decoder {
214
+ interface EncoderOptions {
215
+ [key: string]: any;
216
+ }
217
+ interface Encoder {
193
218
  readonly format: string;
194
- decode(data: Uint8Array): Promise<Outcome<DocRoot>>;
219
+ readonly aliases?: string[];
220
+ encode(doc: DocRoot, options?: EncoderOptions): Promise<Outcome<Uint8Array>>;
195
221
  }
196
222
 
197
- interface Encoder {
223
+ interface Decoder {
198
224
  readonly format: string;
199
- encode(doc: DocRoot): Promise<Outcome<Uint8Array>>;
225
+ readonly aliases?: string[];
226
+ decode(data: Uint8Array): Promise<Outcome<DocRoot>>;
200
227
  }
201
228
 
202
229
  declare class Pipeline {
@@ -208,7 +235,7 @@ declare class Pipeline {
208
235
  /** File/Blob 비동기 입력 */
209
236
  static openAsync(input: File | Blob | Uint8Array | string, fmt?: string): Promise<Pipeline>;
210
237
  /** 목표 포맷으로 변환 */
211
- to(targetFmt: string): Promise<Outcome<Uint8Array>>;
238
+ to(targetFmt: string, options?: EncoderOptions): Promise<Outcome<Uint8Array>>;
212
239
  /** DocRoot만 추출 (인코딩 없이) */
213
240
  inspect(): Promise<Outcome<DocRoot>>;
214
241
  }
@@ -227,8 +254,8 @@ declare const registry: FormatRegistry;
227
254
 
228
255
  declare function buildRoot(meta?: DocMeta, kids?: SheetNode[]): DocRoot;
229
256
  declare function buildSheet(kids?: ContentNode[], dims?: PageDims, opts?: {
230
- header?: ParaNode[];
231
- footer?: ParaNode[];
257
+ headers?: SheetNode["headers"];
258
+ footers?: SheetNode["footers"];
232
259
  }): SheetNode;
233
260
  declare function buildPageNum(format?: PageNumNode['format']): PageNumNode;
234
261
  declare function buildBr(): BrNode;
@@ -238,7 +265,7 @@ declare function buildSpan(content: string, props?: TextProps): SpanNode;
238
265
  declare function buildImg(b64: string, mime: ImgNode['mime'], w: number, h: number, alt?: string, layout?: ImgLayout): ImgNode;
239
266
  declare function buildGrid(kids: RowNode[], props?: GridProps): GridNode;
240
267
  declare function buildRow(kids: CellNode[], heightPt?: number): RowNode;
241
- declare function buildCell(kids: ParaNode[], opts?: {
268
+ declare function buildCell(kids: (ParaNode | GridNode)[], opts?: {
242
269
  cs?: number;
243
270
  rs?: number;
244
271
  props?: CellProps;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  type Align = 'left' | 'center' | 'right' | 'justify';
2
- type ImgWrap = 'inline' | 'square' | 'tight' | 'through' | 'none' | 'behind' | 'front';
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,10 +37,15 @@ interface TextProps {
37
37
  interface ParaProps {
38
38
  align?: Align;
39
39
  heading?: Heading;
40
+ styleId?: string;
40
41
  indentPt?: number;
42
+ indentRightPt?: number;
43
+ firstLineIndentPt?: number;
44
+ leftMargin?: number;
41
45
  spaceBefore?: number;
42
46
  spaceAfter?: number;
43
47
  lineHeight?: number;
48
+ lineHeightFixed?: number;
44
49
  listLv?: number;
45
50
  listOrd?: boolean;
46
51
  listMark?: string;
@@ -57,6 +62,10 @@ interface CellProps {
57
62
  right?: Stroke;
58
63
  bg?: string;
59
64
  padPt?: number;
65
+ padT?: number;
66
+ padB?: number;
67
+ padL?: number;
68
+ padR?: number;
60
69
  align?: Align;
61
70
  va?: VAlign;
62
71
  isHeader?: boolean;
@@ -75,6 +84,7 @@ interface GridProps {
75
84
  defaultStroke?: Stroke;
76
85
  look?: TableLook;
77
86
  headerRow?: boolean;
87
+ align?: Align;
78
88
  }
79
89
  interface PageDims {
80
90
  wPt: number;
@@ -84,6 +94,8 @@ interface PageDims {
84
94
  ml: number;
85
95
  mr: number;
86
96
  orient?: 'portrait' | 'landscape';
97
+ headerPt?: number;
98
+ footerPt?: number;
87
99
  }
88
100
  interface DocMeta {
89
101
  title?: string;
@@ -93,6 +105,8 @@ interface DocMeta {
93
105
  keywords?: string;
94
106
  created?: string;
95
107
  modified?: string;
108
+ zoom?: number;
109
+ viewMode?: string;
96
110
  }
97
111
  declare const A4: PageDims;
98
112
  declare const A4_LANDSCAPE: PageDims;
@@ -141,14 +155,14 @@ interface LinkNode {
141
155
  interface ParaNode {
142
156
  tag: 'para';
143
157
  props: ParaProps;
144
- kids: (SpanNode | ImgNode | LinkNode)[];
158
+ kids: (SpanNode | ImgNode | LinkNode | GridNode)[];
145
159
  }
146
160
  interface CellNode {
147
161
  tag: 'cell';
148
162
  cs: number;
149
163
  rs: number;
150
164
  props: CellProps;
151
- kids: ParaNode[];
165
+ kids: (ParaNode | GridNode)[];
152
166
  }
153
167
  interface RowNode {
154
168
  tag: 'row';
@@ -165,8 +179,16 @@ interface SheetNode {
165
179
  tag: 'sheet';
166
180
  dims: PageDims;
167
181
  kids: ContentNode[];
168
- header?: ParaNode[];
169
- footer?: ParaNode[];
182
+ headers?: {
183
+ default?: ParaNode[];
184
+ first?: ParaNode[];
185
+ even?: ParaNode[];
186
+ };
187
+ footers?: {
188
+ default?: ParaNode[];
189
+ first?: ParaNode[];
190
+ even?: ParaNode[];
191
+ };
170
192
  }
171
193
  interface DocRoot {
172
194
  tag: 'root';
@@ -189,14 +211,19 @@ interface Fail {
189
211
  declare function succeed<T>(data: T, warns?: string[]): Ok<T>;
190
212
  declare function fail(error: string, warns?: string[]): Fail;
191
213
 
192
- interface Decoder {
214
+ interface EncoderOptions {
215
+ [key: string]: any;
216
+ }
217
+ interface Encoder {
193
218
  readonly format: string;
194
- decode(data: Uint8Array): Promise<Outcome<DocRoot>>;
219
+ readonly aliases?: string[];
220
+ encode(doc: DocRoot, options?: EncoderOptions): Promise<Outcome<Uint8Array>>;
195
221
  }
196
222
 
197
- interface Encoder {
223
+ interface Decoder {
198
224
  readonly format: string;
199
- encode(doc: DocRoot): Promise<Outcome<Uint8Array>>;
225
+ readonly aliases?: string[];
226
+ decode(data: Uint8Array): Promise<Outcome<DocRoot>>;
200
227
  }
201
228
 
202
229
  declare class Pipeline {
@@ -208,7 +235,7 @@ declare class Pipeline {
208
235
  /** File/Blob 비동기 입력 */
209
236
  static openAsync(input: File | Blob | Uint8Array | string, fmt?: string): Promise<Pipeline>;
210
237
  /** 목표 포맷으로 변환 */
211
- to(targetFmt: string): Promise<Outcome<Uint8Array>>;
238
+ to(targetFmt: string, options?: EncoderOptions): Promise<Outcome<Uint8Array>>;
212
239
  /** DocRoot만 추출 (인코딩 없이) */
213
240
  inspect(): Promise<Outcome<DocRoot>>;
214
241
  }
@@ -227,8 +254,8 @@ declare const registry: FormatRegistry;
227
254
 
228
255
  declare function buildRoot(meta?: DocMeta, kids?: SheetNode[]): DocRoot;
229
256
  declare function buildSheet(kids?: ContentNode[], dims?: PageDims, opts?: {
230
- header?: ParaNode[];
231
- footer?: ParaNode[];
257
+ headers?: SheetNode["headers"];
258
+ footers?: SheetNode["footers"];
232
259
  }): SheetNode;
233
260
  declare function buildPageNum(format?: PageNumNode['format']): PageNumNode;
234
261
  declare function buildBr(): BrNode;
@@ -238,7 +265,7 @@ declare function buildSpan(content: string, props?: TextProps): SpanNode;
238
265
  declare function buildImg(b64: string, mime: ImgNode['mime'], w: number, h: number, alt?: string, layout?: ImgLayout): ImgNode;
239
266
  declare function buildGrid(kids: RowNode[], props?: GridProps): GridNode;
240
267
  declare function buildRow(kids: CellNode[], heightPt?: number): RowNode;
241
- declare function buildCell(kids: ParaNode[], opts?: {
268
+ declare function buildCell(kids: (ParaNode | GridNode)[], opts?: {
242
269
  cs?: number;
243
270
  rs?: number;
244
271
  props?: CellProps;