hwp-convert 1.0.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 (53) hide show
  1. package/CHANGELOG.md +185 -0
  2. package/LICENSE +25 -0
  3. package/NOTICE +23 -0
  4. package/README.md +338 -0
  5. package/dist/browser/hwp-convert.browser.mjs +20677 -0
  6. package/dist/browser/hwp-convert.browser.mjs.map +7 -0
  7. package/dist/cli.d.ts +2 -0
  8. package/dist/cli.js +267 -0
  9. package/dist/index.d.ts +5 -0
  10. package/dist/index.js +5 -0
  11. package/dist/lib/errors.d.ts +9 -0
  12. package/dist/lib/errors.js +18 -0
  13. package/dist/lib/hwp/binData.d.ts +15 -0
  14. package/dist/lib/hwp/binData.js +64 -0
  15. package/dist/lib/hwp/bodyText.d.ts +31 -0
  16. package/dist/lib/hwp/bodyText.js +208 -0
  17. package/dist/lib/hwp/byteReader.d.ts +40 -0
  18. package/dist/lib/hwp/byteReader.js +116 -0
  19. package/dist/lib/hwp/cfbReader.d.ts +44 -0
  20. package/dist/lib/hwp/cfbReader.js +134 -0
  21. package/dist/lib/hwp/control.d.ts +17 -0
  22. package/dist/lib/hwp/control.js +290 -0
  23. package/dist/lib/hwp/converter.d.ts +22 -0
  24. package/dist/lib/hwp/converter.js +41 -0
  25. package/dist/lib/hwp/docInfo.d.ts +26 -0
  26. package/dist/lib/hwp/docInfo.js +396 -0
  27. package/dist/lib/hwp/fileHeader.d.ts +42 -0
  28. package/dist/lib/hwp/fileHeader.js +66 -0
  29. package/dist/lib/hwp/htmlReader.d.ts +17 -0
  30. package/dist/lib/hwp/htmlReader.js +602 -0
  31. package/dist/lib/hwp/hwpxBuilder.d.ts +19 -0
  32. package/dist/lib/hwp/hwpxBuilder.js +633 -0
  33. package/dist/lib/hwp/index.d.ts +68 -0
  34. package/dist/lib/hwp/index.js +149 -0
  35. package/dist/lib/hwp/mdReader.d.ts +16 -0
  36. package/dist/lib/hwp/mdReader.js +485 -0
  37. package/dist/lib/hwp/mdWriter.d.ts +23 -0
  38. package/dist/lib/hwp/mdWriter.js +182 -0
  39. package/dist/lib/hwp/owpml.d.ts +33 -0
  40. package/dist/lib/hwp/owpml.js +86 -0
  41. package/dist/lib/hwp/record.d.ts +24 -0
  42. package/dist/lib/hwp/record.js +59 -0
  43. package/dist/lib/hwp/tags.d.ts +115 -0
  44. package/dist/lib/hwp/tags.js +217 -0
  45. package/dist/lib/hwp/types.d.ts +214 -0
  46. package/dist/lib/hwp/types.js +5 -0
  47. package/dist/lib/hwpxReader.d.ts +60 -0
  48. package/dist/lib/hwpxReader.js +1104 -0
  49. package/dist/lib/types.d.ts +47 -0
  50. package/dist/lib/types.js +1 -0
  51. package/dist/lib/writer.d.ts +19 -0
  52. package/dist/lib/writer.js +149 -0
  53. package/package.json +94 -0
@@ -0,0 +1,26 @@
1
+ /**
2
+ * DocInfo 스트림 파싱 — 1차 포팅.
3
+ *
4
+ * 1차 범위: BIN_DATA, FACE_NAME, CHAR_SHAPE, PARA_SHAPE, STYLE.
5
+ * BORDER_FILL/NUMBERING/BULLET/TAB_DEF 등은 2차 단계.
6
+ *
7
+ * 원작: rhwp/src/parser/doc_info.rs (MIT, Edward Kim)
8
+ */
9
+ import type { HwpDocInfo } from "./types.js";
10
+ export declare class DocInfoError extends Error {
11
+ constructor(msg: string);
12
+ }
13
+ export interface DocProperties {
14
+ sectionCount: number;
15
+ pageStartNum: number;
16
+ footnoteStartNum: number;
17
+ endnoteStartNum: number;
18
+ pictureStartNum: number;
19
+ tableStartNum: number;
20
+ equationStartNum: number;
21
+ }
22
+ export interface DocInfoParseResult {
23
+ docInfo: HwpDocInfo;
24
+ docProperties: DocProperties;
25
+ }
26
+ export declare function parseDocInfo(data: Uint8Array): DocInfoParseResult;
@@ -0,0 +1,396 @@
1
+ /**
2
+ * DocInfo 스트림 파싱 — 1차 포팅.
3
+ *
4
+ * 1차 범위: BIN_DATA, FACE_NAME, CHAR_SHAPE, PARA_SHAPE, STYLE.
5
+ * BORDER_FILL/NUMBERING/BULLET/TAB_DEF 등은 2차 단계.
6
+ *
7
+ * 원작: rhwp/src/parser/doc_info.rs (MIT, Edward Kim)
8
+ */
9
+ import { ByteReader } from "./byteReader.js";
10
+ import { readAllRecords } from "./record.js";
11
+ import { HWPTAG_DOCUMENT_PROPERTIES, HWPTAG_ID_MAPPINGS, HWPTAG_BIN_DATA, HWPTAG_FACE_NAME, HWPTAG_BORDER_FILL, HWPTAG_CHAR_SHAPE, HWPTAG_TAB_DEF, HWPTAG_NUMBERING, HWPTAG_BULLET, HWPTAG_PARA_SHAPE, HWPTAG_STYLE, } from "./tags.js";
12
+ export class DocInfoError extends Error {
13
+ constructor(msg) {
14
+ super(msg);
15
+ this.name = "DocInfoError";
16
+ }
17
+ }
18
+ const DEFAULT_DOC_PROPS = {
19
+ sectionCount: 1,
20
+ pageStartNum: 1,
21
+ footnoteStartNum: 1,
22
+ endnoteStartNum: 1,
23
+ pictureStartNum: 1,
24
+ tableStartNum: 1,
25
+ equationStartNum: 1,
26
+ };
27
+ export function parseDocInfo(data) {
28
+ const records = readAllRecords(data);
29
+ const binData = [];
30
+ const fontFaces = Array.from({ length: 7 }, () => []);
31
+ const charShapes = [];
32
+ const paraShapes = [];
33
+ const styles = [];
34
+ const borderFills = [];
35
+ const numberings = [];
36
+ const bullets = [];
37
+ const tabDefs = [];
38
+ let docProps = { ...DEFAULT_DOC_PROPS };
39
+ let idMappings = null;
40
+ let currentLang = 0;
41
+ const langConsumed = [0, 0, 0, 0, 0, 0, 0];
42
+ for (const rec of records) {
43
+ switch (rec.tagId) {
44
+ case HWPTAG_DOCUMENT_PROPERTIES:
45
+ docProps = parseDocumentProperties(rec.data);
46
+ break;
47
+ case HWPTAG_ID_MAPPINGS:
48
+ idMappings = parseIdMappings(rec.data);
49
+ break;
50
+ case HWPTAG_BIN_DATA:
51
+ binData.push(parseBinData(rec.data));
52
+ break;
53
+ case HWPTAG_FACE_NAME: {
54
+ const font = parseFaceName(rec.data);
55
+ if (idMappings) {
56
+ while (currentLang < 7 &&
57
+ langConsumed[currentLang] >= idMappings.fontCounts[currentLang]) {
58
+ currentLang++;
59
+ }
60
+ if (currentLang < 7) {
61
+ fontFaces[currentLang].push(font);
62
+ langConsumed[currentLang]++;
63
+ }
64
+ else {
65
+ fontFaces[6].push(font);
66
+ }
67
+ }
68
+ else {
69
+ fontFaces[0].push(font);
70
+ }
71
+ break;
72
+ }
73
+ case HWPTAG_BORDER_FILL:
74
+ borderFills.push(parseBorderFill(rec.data));
75
+ break;
76
+ case HWPTAG_CHAR_SHAPE:
77
+ charShapes.push(parseCharShape(rec.data));
78
+ break;
79
+ case HWPTAG_TAB_DEF:
80
+ tabDefs.push(parseTabDef(rec.data));
81
+ break;
82
+ case HWPTAG_NUMBERING:
83
+ numberings.push(parseNumbering(rec.data));
84
+ break;
85
+ case HWPTAG_BULLET:
86
+ bullets.push(parseBullet(rec.data));
87
+ break;
88
+ case HWPTAG_PARA_SHAPE:
89
+ paraShapes.push(parseParaShape(rec.data));
90
+ break;
91
+ case HWPTAG_STYLE:
92
+ styles.push(parseStyle(rec.data));
93
+ break;
94
+ default:
95
+ break;
96
+ }
97
+ }
98
+ return {
99
+ docInfo: {
100
+ fontFaces,
101
+ charShapes,
102
+ paraShapes,
103
+ styles,
104
+ binData,
105
+ borderFills,
106
+ numberings,
107
+ bullets,
108
+ tabDefs,
109
+ },
110
+ docProperties: docProps,
111
+ };
112
+ }
113
+ function parseBorderFill(data) {
114
+ const r = new ByteReader(data);
115
+ const attr = r.remaining() >= 2 ? r.readU16() : 0;
116
+ // 4면 테두리: 좌/우/상/하 인터리브 — { type u8, width u8, color u32 }
117
+ const readBorder = () => {
118
+ if (r.remaining() < 6) {
119
+ return { lineType: 1, widthIndex: 0, color: 0 };
120
+ }
121
+ const lineType = r.readU8();
122
+ const widthIndex = r.readU8();
123
+ const color = r.readColorRef();
124
+ return { lineType, widthIndex, color };
125
+ };
126
+ const borders = [
127
+ readBorder(),
128
+ readBorder(),
129
+ readBorder(),
130
+ readBorder(),
131
+ ];
132
+ // 대각선
133
+ let diagonal = { diagonalType: 0, widthIndex: 0, color: 0 };
134
+ if (r.remaining() >= 6) {
135
+ diagonal = {
136
+ diagonalType: r.readU8(),
137
+ widthIndex: r.readU8(),
138
+ color: r.readColorRef(),
139
+ };
140
+ }
141
+ // 채우기: u32 fillType 비트마스크 + 종류별 데이터
142
+ let fill;
143
+ if (r.remaining() >= 4) {
144
+ const fillType = r.readU32();
145
+ if (fillType === 0) {
146
+ // 채우기 없음: hwplib 기준 4바이트 추가 skip
147
+ if (r.remaining() >= 4)
148
+ r.skip(4);
149
+ }
150
+ else if ((fillType & 0x01) !== 0) {
151
+ // solid
152
+ if (r.remaining() >= 12) {
153
+ fill = {
154
+ backgroundColor: r.readColorRef(),
155
+ patternColor: r.readColorRef(),
156
+ patternType: r.readI32(),
157
+ };
158
+ }
159
+ // gradient/image 는 1차 포팅에서 무시 (이후 바이트 무시)
160
+ }
161
+ }
162
+ return { attr, borders, diagonal, fill };
163
+ }
164
+ function parseTabDef(data) {
165
+ const r = new ByteReader(data);
166
+ const attr = r.remaining() >= 4 ? r.readU32() : 0;
167
+ return {
168
+ attr,
169
+ autoTabLeft: (attr & 0x01) !== 0,
170
+ autoTabRight: (attr & 0x02) !== 0,
171
+ };
172
+ }
173
+ function parseNumbering(data) {
174
+ const r = new ByteReader(data);
175
+ const levelFormats = ["", "", "", "", "", "", ""];
176
+ // 7 레벨 × { attr(u32) + widthAdjust(i16) + textDistance(i16) + charShapeId(u32) + formatLen(u16) + WCHAR[formatLen] }
177
+ for (let level = 0; level < 7; level++) {
178
+ if (r.remaining() < 12)
179
+ break;
180
+ r.readU32(); // attr
181
+ r.readI16(); // widthAdjust
182
+ r.readI16(); // textDistance
183
+ r.readU32(); // charShapeId
184
+ if (r.remaining() < 2)
185
+ break;
186
+ const formatLen = r.readU16();
187
+ if (formatLen > 0 && r.remaining() >= formatLen * 2) {
188
+ try {
189
+ levelFormats[level] = r.readUtf16(formatLen);
190
+ }
191
+ catch {
192
+ // skip
193
+ }
194
+ }
195
+ }
196
+ const startNumber = r.remaining() >= 2 ? r.readU16() : 1;
197
+ return { startNumber, levelFormats };
198
+ }
199
+ function parseBullet(data) {
200
+ const r = new ByteReader(data);
201
+ // attr(u32) + widthAdjust(i16) + textDistance(i16) + charShapeId(u32)
202
+ if (r.remaining() < 12)
203
+ return { bulletChar: "●" };
204
+ r.readU32();
205
+ r.readI16();
206
+ r.readI16();
207
+ r.readU32();
208
+ if (r.remaining() < 2)
209
+ return { bulletChar: "●" };
210
+ const bulletCharCode = r.readU16();
211
+ const bulletChar = bulletCharCode > 0 ? String.fromCharCode(bulletCharCode) : "●";
212
+ return { bulletChar };
213
+ }
214
+ function parseIdMappings(data) {
215
+ const r = new ByteReader(data);
216
+ const safe = (n) => (r.remaining() >= 4 ? r.readU32() : n);
217
+ return {
218
+ binDataCount: safe(0),
219
+ fontCounts: [safe(0), safe(0), safe(0), safe(0), safe(0), safe(0), safe(0)],
220
+ borderFillCount: safe(0),
221
+ charShapeCount: safe(0),
222
+ tabDefCount: safe(0),
223
+ numberingCount: safe(0),
224
+ bulletCount: safe(0),
225
+ paraShapeCount: safe(0),
226
+ styleCount: safe(0),
227
+ };
228
+ }
229
+ function parseDocumentProperties(data) {
230
+ const r = new ByteReader(data);
231
+ const safe = (n) => (r.remaining() >= 2 ? r.readU16() : n);
232
+ return {
233
+ sectionCount: safe(1),
234
+ pageStartNum: safe(1),
235
+ footnoteStartNum: safe(1),
236
+ endnoteStartNum: safe(1),
237
+ pictureStartNum: safe(1),
238
+ tableStartNum: safe(1),
239
+ equationStartNum: safe(1),
240
+ };
241
+ }
242
+ function parseBinData(data) {
243
+ const r = new ByteReader(data);
244
+ const attr = r.readU16();
245
+ const typeBits = attr & 0x000f;
246
+ let type;
247
+ switch (typeBits) {
248
+ case 0:
249
+ type = "link";
250
+ break;
251
+ case 1:
252
+ type = "embedding";
253
+ break;
254
+ case 2:
255
+ type = "storage";
256
+ break;
257
+ default:
258
+ type = "link";
259
+ break;
260
+ }
261
+ if (type === "link") {
262
+ // absPath, relPath — 1차 포팅에서는 무시
263
+ safeReadHwpString(r);
264
+ safeReadHwpString(r);
265
+ return { storageId: 0, type };
266
+ }
267
+ const storageId = r.remaining() >= 2 ? r.readU16() : 0;
268
+ const extension = safeReadHwpString(r);
269
+ return { storageId, extension, type };
270
+ }
271
+ function parseFaceName(data) {
272
+ const r = new ByteReader(data);
273
+ const attr = r.readU8();
274
+ const name = safeReadHwpString(r) ?? "";
275
+ let substituteName;
276
+ if ((attr & 0x80) !== 0) {
277
+ substituteName = safeReadHwpString(r);
278
+ }
279
+ return { name, substituteName };
280
+ }
281
+ function parseCharShape(data) {
282
+ const r = new ByteReader(data);
283
+ const fontIds = [];
284
+ for (let i = 0; i < 7; i++)
285
+ fontIds.push(r.readU16());
286
+ // ratios u8x7
287
+ for (let i = 0; i < 7; i++)
288
+ r.readU8();
289
+ // spacings i8x7
290
+ for (let i = 0; i < 7; i++)
291
+ r.readI8();
292
+ // relativeSizes u8x7
293
+ for (let i = 0; i < 7; i++)
294
+ r.readU8();
295
+ // charOffsets i8x7
296
+ for (let i = 0; i < 7; i++)
297
+ r.readI8();
298
+ const baseSize = r.readI32();
299
+ const attr = r.readU32();
300
+ // shadow_offset_x, shadow_offset_y (i8 x 2)
301
+ r.readI8();
302
+ r.readI8();
303
+ const textColor = r.readColorRef();
304
+ const underlineColor = r.readColorRef();
305
+ const shadeColor = r.readColorRef();
306
+ const shadowColor = r.readColorRef();
307
+ return {
308
+ faceNameIds: {
309
+ hangul: fontIds[0],
310
+ latin: fontIds[1],
311
+ hanja: fontIds[2],
312
+ japanese: fontIds[3],
313
+ other: fontIds[4],
314
+ symbol: fontIds[5],
315
+ user: fontIds[6],
316
+ },
317
+ baseSize,
318
+ property: attr,
319
+ textColor,
320
+ shadeColor,
321
+ underlineColor,
322
+ shadowColor,
323
+ bold: (attr & 0x02) !== 0,
324
+ italic: (attr & 0x01) !== 0,
325
+ underline: ((attr >>> 2) & 0x03) !== 0,
326
+ strikeout: ((attr >>> 18) & 0x07) > 1,
327
+ };
328
+ }
329
+ function parseParaShape(data) {
330
+ const r = new ByteReader(data);
331
+ const attr1 = r.readU32();
332
+ const leftMargin = r.readI32();
333
+ const rightMargin = r.readI32();
334
+ const indent = r.readI32();
335
+ const prevSpacing = r.readI32();
336
+ const nextSpacing = r.readI32();
337
+ const lineSpacing = r.readI32();
338
+ const alignBits = (attr1 >>> 2) & 0x07;
339
+ let alignment;
340
+ switch (alignBits) {
341
+ case 0:
342
+ alignment = "justify";
343
+ break;
344
+ case 1:
345
+ alignment = "left";
346
+ break;
347
+ case 2:
348
+ alignment = "right";
349
+ break;
350
+ case 3:
351
+ alignment = "center";
352
+ break;
353
+ case 4:
354
+ alignment = "distribute";
355
+ break;
356
+ case 5:
357
+ alignment = "distributeSpace";
358
+ break;
359
+ default:
360
+ alignment = "unknown";
361
+ }
362
+ return {
363
+ alignment,
364
+ property: attr1,
365
+ leftMargin,
366
+ rightMargin,
367
+ indent,
368
+ prevSpacing,
369
+ nextSpacing,
370
+ lineSpacing,
371
+ };
372
+ }
373
+ function parseStyle(data) {
374
+ const r = new ByteReader(data);
375
+ const name = safeReadHwpString(r) ?? "";
376
+ const engName = safeReadHwpString(r);
377
+ // properties u8, next u8, lang u8 — 일단 skip
378
+ if (r.remaining() >= 3) {
379
+ r.readU8();
380
+ r.readU8();
381
+ r.readU8();
382
+ }
383
+ const paraShapeId = r.remaining() >= 2 ? r.readU16() : 0;
384
+ const charShapeId = r.remaining() >= 2 ? r.readU16() : 0;
385
+ return { name, engName, paraShapeId, charShapeId };
386
+ }
387
+ function safeReadHwpString(r) {
388
+ if (r.remaining() < 2)
389
+ return undefined;
390
+ try {
391
+ return r.readHwpString();
392
+ }
393
+ catch {
394
+ return undefined;
395
+ }
396
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * HWP FileHeader 스트림 (256바이트, 비압축).
3
+ * 0..31 : 시그니처 "HWP Document File" + NULL 패딩
4
+ * 32..35 : 버전 (revision, build, minor, major) — LE
5
+ * 36..39 : 속성 플래그 (u32 LE)
6
+ * 40.. : 예약
7
+ *
8
+ * 원작: rhwp/src/parser/header.rs (MIT, Copyright (c) 2025-2026 Edward Kim)
9
+ */
10
+ export declare const HWP_SIGNATURE = "HWP Document File";
11
+ export declare const FILE_HEADER_SIZE = 256;
12
+ export interface HwpVersion {
13
+ major: number;
14
+ minor: number;
15
+ build: number;
16
+ revision: number;
17
+ }
18
+ export declare function versionToString(v: HwpVersion): string;
19
+ export declare function isVersionSupported(v: HwpVersion): boolean;
20
+ export interface FileHeaderFlags {
21
+ raw: number;
22
+ compressed: boolean;
23
+ encrypted: boolean;
24
+ distribution: boolean;
25
+ script: boolean;
26
+ drm: boolean;
27
+ xmlTemplate: boolean;
28
+ documentHistory: boolean;
29
+ digitalSignature: boolean;
30
+ publicKeyEncrypted: boolean;
31
+ modifiedCertificate: boolean;
32
+ prepareDistribution: boolean;
33
+ }
34
+ export declare function parseFlags(raw: number): FileHeaderFlags;
35
+ export interface FileHeader {
36
+ version: HwpVersion;
37
+ flags: FileHeaderFlags;
38
+ }
39
+ export declare class HwpHeaderError extends Error {
40
+ constructor(msg: string);
41
+ }
42
+ export declare function parseFileHeader(data: Uint8Array): FileHeader;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * HWP FileHeader 스트림 (256바이트, 비압축).
3
+ * 0..31 : 시그니처 "HWP Document File" + NULL 패딩
4
+ * 32..35 : 버전 (revision, build, minor, major) — LE
5
+ * 36..39 : 속성 플래그 (u32 LE)
6
+ * 40.. : 예약
7
+ *
8
+ * 원작: rhwp/src/parser/header.rs (MIT, Copyright (c) 2025-2026 Edward Kim)
9
+ */
10
+ export const HWP_SIGNATURE = "HWP Document File";
11
+ export const FILE_HEADER_SIZE = 256;
12
+ export function versionToString(v) {
13
+ return `${v.major}.${v.minor}.${v.build}.${v.revision}`;
14
+ }
15
+ export function isVersionSupported(v) {
16
+ return v.major === 5 && (v.minor === 0 || v.minor === 1);
17
+ }
18
+ export function parseFlags(raw) {
19
+ return {
20
+ raw,
21
+ compressed: (raw & 0x001) !== 0,
22
+ encrypted: (raw & 0x002) !== 0,
23
+ distribution: (raw & 0x004) !== 0,
24
+ script: (raw & 0x008) !== 0,
25
+ drm: (raw & 0x010) !== 0,
26
+ xmlTemplate: (raw & 0x020) !== 0,
27
+ documentHistory: (raw & 0x040) !== 0,
28
+ digitalSignature: (raw & 0x080) !== 0,
29
+ publicKeyEncrypted: (raw & 0x100) !== 0,
30
+ modifiedCertificate: (raw & 0x200) !== 0,
31
+ prepareDistribution: (raw & 0x400) !== 0,
32
+ };
33
+ }
34
+ export class HwpHeaderError extends Error {
35
+ constructor(msg) {
36
+ super(msg);
37
+ this.name = "HwpHeaderError";
38
+ }
39
+ }
40
+ const ASCII = new TextDecoder("ascii");
41
+ export function parseFileHeader(data) {
42
+ if (data.byteLength < FILE_HEADER_SIZE) {
43
+ throw new HwpHeaderError(`FileHeader 크기 부족: ${data.byteLength} (최소 ${FILE_HEADER_SIZE})`);
44
+ }
45
+ // 시그니처 (0..31, NULL 종료)
46
+ const sigArea = data.subarray(0, 32);
47
+ let sigEnd = sigArea.indexOf(0);
48
+ if (sigEnd === -1)
49
+ sigEnd = 32;
50
+ const sig = ASCII.decode(sigArea.subarray(0, sigEnd));
51
+ if (!sig.startsWith(HWP_SIGNATURE)) {
52
+ throw new HwpHeaderError(`HWP 시그니처가 일치하지 않습니다: "${sig}"`);
53
+ }
54
+ // 버전 (revision, build, minor, major)
55
+ const version = {
56
+ revision: data[32],
57
+ build: data[33],
58
+ minor: data[34],
59
+ major: data[35],
60
+ };
61
+ // 플래그
62
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
63
+ const flagsRaw = view.getUint32(36, true);
64
+ const flags = parseFlags(flagsRaw);
65
+ return { version, flags };
66
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * HTML → HwpDocument IR.
3
+ *
4
+ * `htmlparser2` 로 SAX 파싱 → 트리 구축 → IR 변환.
5
+ * - p, div, h1~h6 → paragraph (heading 은 굵게 + 큰 사이즈)
6
+ * - strong/b, em/i → 굵게/기울임 run
7
+ * - br → 줄바꿈
8
+ * - ul/ol/li → "- " / "1. " prefix paragraph
9
+ * - table/thead/tbody/tr/th/td → HwpTableControl
10
+ * - img → HwpPictureControl (src 가 data: URI 일 때만)
11
+ * - blockquote → "> " prefix paragraph
12
+ * - code/pre → 모노스페이스
13
+ * - a → 텍스트만 (URL 미보존)
14
+ * - 기타 (style/script/head 등) → 무시
15
+ */
16
+ import type { HwpDocument, ConvertOptions } from "./types.js";
17
+ export declare function htmlToHwpDocument(html: string, options?: ConvertOptions): HwpDocument;