docx-kit 0.1.0 → 0.2.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.
package/README.md CHANGED
@@ -5,7 +5,19 @@
5
5
  [![NPM DOWNLOADS](https://img.shields.io/npm/dy/docx-kit.svg)](https://www.npmjs.com/package/docx-kit)
6
6
  [![LICENSE](https://img.shields.io/github/license/ntnyq/docx-kit.svg)](https://github.com/ntnyq/docx-kit/blob/main/LICENSE)
7
7
 
8
- TypeScript library for generating Word (.docx) documents easily with rich content, styles, and intuitive, customizable API.
8
+ **CSS-like DOCX API Kit** Type-safe, plugin-extensible Word document generation for Node.js and the browser.
9
+
10
+ Built on top of [docx](https://github.com/dolanmiu/docx) (docxjs), docx-kit adds:
11
+
12
+ 📖 **Documentation:** [https://docx-kit.ntnyq.dev](https://docx-kit.ntnyq.dev)
13
+
14
+ - **CSS-like stylesheet** with class names and cascade resolution
15
+ - **Plugin architecture** with type-safe registration and 12 built-in plugins
16
+ - **Fluent builder API** (h1–h6, p, table, image, pageBreak, bulletList, numberedList, hyperlink, section, plugin)
17
+ - **Unit system** with CSS unit support (pt, px, mm, cm, in, %)
18
+ - **Platform-specific entry points** for Node.js and browser
19
+
20
+ ---
9
21
 
10
22
  ## Install
11
23
 
@@ -21,6 +33,513 @@ yarn add docx-kit
21
33
  pnpm add docx-kit
22
34
  ```
23
35
 
36
+ ---
37
+
38
+ ## Quick Start
39
+
40
+ ```ts
41
+ import { createDocx, defineStyles } from 'docx-kit'
42
+
43
+ const styles = defineStyles({
44
+ accent: { color: '#2563eb', fontWeight: 'bold' },
45
+ muted: { color: '#6b7280', fontSize: 10 },
46
+ highlight: { highlight: 'yellow' },
47
+ })
48
+
49
+ const doc = createDocx({ styles })
50
+ .h1('Hello, docx-kit!')
51
+ .p('This is a paragraph with default styling.')
52
+ .p('This text is accented.', { className: 'accent' })
53
+ .p('Highlighted text.', { className: 'highlight' })
54
+ .bulletList([
55
+ 'Bullet lists',
56
+ 'Numbered lists',
57
+ 'Hyperlinks',
58
+ ])
59
+ .numberedList([
60
+ 'Install docx-kit',
61
+ 'Define your styles',
62
+ 'Generate your document',
63
+ ])
64
+ .hyperlink('https://github.com/ntnyq/docx-kit', 'Visit docx-kit')
65
+ .table({
66
+ columns: [
67
+ { key: 'name', title: 'Name', width: '60%' },
68
+ { key: 'value', title: 'Value', width: '40%' },
69
+ ],
70
+ data: [
71
+ { name: 'Revenue', value: '$1.2M' },
72
+ { name: 'Growth', value: '+15%' },
73
+ ],
74
+ })
75
+
76
+ await doc.save('report.docx') // Node.js
77
+ // or
78
+ const blob = await doc.toBlob() // Browser
79
+
80
+ ```
81
+
82
+ ---
83
+
84
+ ## API
85
+
86
+ ### `createDocx(config?)` → `DocxBuilder`
87
+
88
+ The primary entry point. Returns a fluent builder for chaining content.
89
+
90
+ ```ts
91
+ import { createDocx } from 'docx-kit'
92
+
93
+ const doc = createDocx({
94
+ page: {
95
+ size: 'A4',
96
+ orientation: 'landscape',
97
+ margin: '2cm 2.5cm',
98
+ },
99
+ styles: { /* ... */ },
100
+ defaults: {
101
+ text: { fontFamily: 'Arial', fontSize: 11 },
102
+ paragraph: { lineHeight: 1.5 },
103
+ },
104
+ metadata: {
105
+ title: 'Annual Report',
106
+ creator: 'Alice',
107
+ subject: 'Finance',
108
+ keywords: ['report', '2024'],
109
+ },
110
+ })
111
+ ```
112
+
113
+ ### Builder Methods
114
+
115
+ | Method | Description |
116
+ |--------|-------------|
117
+ | `.h1(text, opts?)` | Level-1 heading |
118
+ | `.h2(text, opts?)` | Level-2 heading |
119
+ | `.h3(text, opts?)` | Level-3 heading |
120
+ | `.h4(text, opts?)` | Level-4 heading |
121
+ | `.h5(text, opts?)` | Level-5 heading |
122
+ | `.h6(text, opts?)` | Level-6 heading |
123
+ | `.p(text, opts?)` | Paragraph |
124
+ | `.bulletList(items, opts?)` | Bullet list |
125
+ | `.numberedList(items, opts?)` | Numbered list |
126
+ | `.hyperlink(url, text, opts?)` | Hyperlink |
127
+ | `.table({ columns, data, ... })` | Table with header row |
128
+ | `.image({ data, width?, height?, ... })` | Image (inline or floating) |
129
+ | `.pageBreak()` | Forced page break |
130
+ | `.section(config?)` | Start a new document section |
131
+ | `.plugin(name, options, style?)` | Invoke a registered plugin |
132
+ | `.use(plugin)` | Register a plugin |
133
+ | `.add(node)` | Add a raw DSL node |
134
+
135
+ ### Export Methods
136
+
137
+ ```ts
138
+ await doc.toBlob() // → Blob (browser & Node.js)
139
+ await doc.toUint8Array() // → Uint8Array
140
+ await doc.toBuffer() // → Uint8Array (alias, NOT Node.js Buffer)
141
+ await doc.toBase64() // → base64 string
142
+ await doc.save('f.docx') // → writes to disk (Node.js only)
143
+ await doc.toDocument() // → raw docx Document (for further manipulation)
144
+ doc.toJSON() // → plain object (debug / AI serialization)
145
+ ```
146
+
147
+ ### DSL Nodes (via `.add()`)
148
+
149
+ | Node Type | Fields |
150
+ |-----------|--------|
151
+ | `{ type: 'heading', level: 1-6, text, className?, id?, style? }` | Heading |
152
+ | `{ type: 'paragraph', text?, children?, className?, id?, style? }` | Paragraph |
153
+ | `{ type: 'bulletList', items, bullet?, level?, className?, style? }` | Bullet list |
154
+ | `{ type: 'numberedList', items, numberingFormat?, start?, level?, className?, style? }` | Numbered list |
155
+ | `{ type: 'hyperlink', url, children, className?, style? }` | Hyperlink |
156
+ | `{ type: 'image', data, width?, height?, alt?, floating? }` | Image |
157
+ | `{ type: 'pageBreak' }` | Page break |
158
+ | `{ type: 'sectionBreak', config? }` | Section boundary (internal) |
159
+ | `{ type: 'table', columns, data, bordered?, striped?, header? }` | Table |
160
+ | `{ type: 'plugin', name, options }` | Plugin invocation |
161
+
162
+ ### Table API
163
+
164
+ ```ts
165
+ doc.table({
166
+ columns: [
167
+ { key: 'name', title: 'Name', width: '60%', align: 'left' },
168
+ { key: 'value', title: 'Value', width: '40%', align: 'right' },
169
+ ],
170
+ data: [
171
+ { name: 'Revenue', value: '$1.2M' },
172
+ { name: 'Growth', value: '+15%' },
173
+ ],
174
+ bordered: true,
175
+ striped: true,
176
+ header: true,
177
+ headerCellStyle: { fontWeight: 'bold' },
178
+ cellStyle: { fontSize: 10 },
179
+ })
180
+ ```
181
+
182
+ Advanced: custom renderers per column:
183
+
184
+ ```ts
185
+ .columns([
186
+ {
187
+ key: 'value',
188
+ title: 'Value',
189
+ render: (val, row, idx) =>
190
+ Number.parseFloat(val) > 0
191
+ ? [{ type: 'text', text: `+${val}`, style: { color: '#16a34a' } }]
192
+ : val,
193
+ },
194
+ ])
195
+ ```
196
+
197
+ ### Image API
198
+
199
+ ```ts
200
+ doc.image({
201
+ data: arrayBuffer, // string | Uint8Array | ArrayBuffer | Blob
202
+ width: 200, // px (bare number = px)
203
+ height: 150,
204
+ alt: 'A descriptive text',
205
+ floating: { // optional
206
+ wrap: 'square',
207
+ x: '10pt',
208
+ y: '20pt',
209
+ },
210
+ })
211
+ ```
212
+
213
+ ### Style System
214
+
215
+ Define styles with `defineStyles()` and reference them via `className`:
216
+
217
+ ```ts
218
+ import { defineStyles } from 'docx-kit'
219
+
220
+ const styles = defineStyles({
221
+ accent: {
222
+ color: '#2563eb',
223
+ fontWeight: 'bold',
224
+ fontSize: 14,
225
+ },
226
+ warning: {
227
+ color: '#dc2626',
228
+ backgroundColor: '#fef2f2',
229
+ borderLeft: { color: '#dc2626', style: 'single', width: 3 },
230
+ },
231
+ })
232
+ ```
233
+
234
+ **Style properties** (38 total):
235
+
236
+ | Category | Properties |
237
+ |----------|------------|
238
+ | **Text** | `fontFamily`, `fontSize`, `fontWeight`, `fontStyle`, `color`, `underline`, `strike`, `allCaps`, `backgroundColor` |
239
+ | **Spacing** | `letterSpacing`, `lineHeight` |
240
+ | **Margins** | `margin`, `marginTop`, `marginRight`, `marginBottom`, `marginLeft` |
241
+ | **Padding** | `padding` |
242
+ | **Alignment** | `textAlign`, `textIndent`, `verticalAlign` |
243
+ | **Borders** | `border`, `borderTop`, `borderRight`, `borderBottom`, `borderLeft` |
244
+ | **Layout** | `width`, `height` |
245
+ | **Escape** | `docx` — merge directly into docxjs options |
246
+
247
+ Style cascade: `defaults → stylesheet class(es) → inline style`. Multiple class names are supported (`className: 'accent warning'` or `['accent', 'warning']`).
248
+
249
+ ### BorderRule
250
+
251
+ ```ts
252
+ type BorderRule = {
253
+ color?: string // hex color
254
+ style?: 'dashed' | 'dotted' | 'double' | 'none' | 'single'
255
+ width?: number // pt (bare number = pt)
256
+ }
257
+ ```
258
+
259
+ ### Unit System
260
+
261
+ All size values accept CSS-like units:
262
+
263
+ ```ts
264
+ type UnitValue = number | `${number}%` | `${number}cm` | `${number}in` | `${number}mm` | `${number}pt` | `${number}px`
265
+ ```
266
+
267
+ Bare numbers are context-dependent: `pt` for fonts/spacing/borders, `px` for images.
268
+
269
+ ### Page Configuration
270
+
271
+ ```ts
272
+ type PageConfig = {
273
+ size?: 'A3' | 'A4' | 'Legal' | 'Letter' | { width: UnitValue; height: UnitValue }
274
+ orientation?: 'portrait' | 'landscape'
275
+ margin?: UnitValue | [topBottom, leftRight] | [top, right, bottom, left] // CSS shorthand
276
+ }
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Multi-Section Documents
282
+
283
+ Use `.section(config?)` to split a document into independent sections, each with
284
+ its own page size, orientation, margins, headers, and footers.
285
+
286
+ ```ts
287
+ import { createDocx } from 'docx-kit'
288
+
289
+ const doc = createDocx()
290
+ .h1('Section 1 — A4 Portrait')
291
+ .p('This is the first section.')
292
+
293
+ // Start a new section in A3 landscape
294
+ .section({ page: { size: 'A3', orientation: 'landscape' } })
295
+ .h1('Section 2 — A3 Landscape')
296
+ .p('This section uses a different page size.')
297
+
298
+ // Section with custom headers and footers
299
+ .section({
300
+ header: {
301
+ default: { children: ['Chapter 3', 'Confidential'] },
302
+ first: { children: ['Title Page'] },
303
+ },
304
+ footer: {
305
+ default: { children: ['Page 3'] },
306
+ },
307
+ })
308
+ .h1('Section 3 — With Headers')
309
+ .p('This section has headers and footers.')
310
+ ```
311
+
312
+ ### SectionConfig
313
+
314
+ ```ts
315
+ type SectionConfig = {
316
+ page?: PageConfig // Section-level page size/orientation/margin override
317
+ header?: HeaderFooterConfig
318
+ footer?: HeaderFooterConfig
319
+ }
320
+ ```
321
+
322
+ ### HeaderFooterConfig
323
+
324
+ ```ts
325
+ type HeaderFooterConfig = {
326
+ default?: HeaderFooterContent // Appears on all pages
327
+ first?: HeaderFooterContent // First page only (overrides default)
328
+ even?: HeaderFooterContent // Even pages only (overrides default)
329
+ }
330
+
331
+ type HeaderFooterContent = {
332
+ children: string[] // Each string → one Paragraph line
333
+ }
334
+ ```
335
+
336
+ ---
337
+
338
+ ## Plugins
339
+
340
+ docx-kit ships with **12 built-in plugins**. Each plugin is registered via `.use()` and invoked with `.plugin(name, options)`.
341
+
342
+ | Plugin | Node Name | Description | Docs |
343
+ |--------|-----------|-------------|------|
344
+ | [Callout](#) | `callout` | Colored info / warning / success / danger boxes | [→](https://docx-kit.ntnyq.dev/plugins/callout) |
345
+ | [Code Block](#) | `codeBlock` | Syntax-highlighted code blocks with line numbers | [→](https://docx-kit.ntnyq.dev/plugins/code-block) |
346
+ | [Cover Page](#) | `coverPage` | Professional title page | [→](https://docx-kit.ntnyq.dev/plugins/cover-page) |
347
+ | [Data Table](#) | `dataTable` | Auto-inferred table from object arrays | [→](https://docx-kit.ntnyq.dev/plugins/data-table) |
348
+ | [ECharts](#) | `echarts` | ECharts charts as embedded images | [→](https://docx-kit.ntnyq.dev/plugins/echarts) |
349
+ | [Meeting Minutes](#) | `meetingMinutes` | Structured meeting notes with agenda table | [→](https://docx-kit.ntnyq.dev/plugins/meeting-minutes) |
350
+ | [Page Number](#) | `pageNumber` | Page number field for headers/footers | [→](https://docx-kit.ntnyq.dev/plugins/page-number) |
351
+ | [Property Table](#) | `propertyTable` | Key-value pair styled table | [→](https://docx-kit.ntnyq.dev/plugins/property-table) |
352
+ | [QR Code](#) | `qrcode` | QR code images from text or URLs | [→](https://docx-kit.ntnyq.dev/plugins/qrcode) |
353
+ | [Signature Block](#) | `signatureBlock` | Signature lines for contracts | [→](https://docx-kit.ntnyq.dev/plugins/signature-block) |
354
+ | [Timeline](#) | `timeline` | Chronological timeline as a styled table | [→](https://docx-kit.ntnyq.dev/plugins/timeline) |
355
+ | [Watermark](#) | `watermark` | Text watermark for document branding | [→](https://docx-kit.ntnyq.dev/plugins/watermark) |
356
+
357
+ 📖 **Full plugin documentation:** [https://docx-kit.ntnyq.dev/plugins/](https://docx-kit.ntnyq.dev/plugins/)
358
+
359
+ ### Quick Example
360
+
361
+ ```ts
362
+ import { createDocx, calloutPlugin, dataTablePlugin } from 'docx-kit'
363
+
364
+ const doc = createDocx()
365
+ .use(calloutPlugin())
366
+ .use(dataTablePlugin())
367
+ .h1('Report')
368
+ .plugin('callout', { type: 'info', content: 'System status: OK' })
369
+ .plugin('dataTable', {
370
+ data: [
371
+ { name: 'Alice', role: 'Engineer' },
372
+ { name: 'Bob', role: 'Designer' },
373
+ ],
374
+ })
375
+ ```
376
+
377
+ ### Custom Plugins
378
+
379
+ ```ts
380
+ import { definePlugin } from 'docx-kit'
381
+
382
+ const myPlugin = definePlugin({
383
+ name: 'signature' as const,
384
+ setup: () => { /* one-time init */ },
385
+ render: (options, ctx) => {
386
+ return new ctx.constructor.Paragraph({ ... })
387
+ },
388
+ })
389
+ ```
390
+
391
+ ---
392
+
393
+ ## AI-Friendly Entry Point
394
+
395
+ Use `renderDocx()` to generate documents from JSON — ideal for AI / LLM output:
396
+
397
+ ```ts
398
+ import { renderDocx } from 'docx-kit'
399
+
400
+ const blob = await renderDocx({
401
+ content: [
402
+ { type: 'heading', level: 1, text: 'AI-Generated Report' },
403
+ { type: 'paragraph', text: 'Generated automatically from structured data.' },
404
+ { type: 'table', columns: [
405
+ { key: 'name', title: 'Name' },
406
+ { key: 'value', title: 'Value' },
407
+ ], data: [{ name: 'Foo', value: 'Bar' }] },
408
+ ],
409
+ styles: { accent: { color: '#2563eb', fontWeight: 'bold' } },
410
+ })
411
+ ```
412
+
413
+ ---
414
+
415
+ ## Platform Entry Points
416
+
417
+ | Entry | Import | Purpose |
418
+ |-------|--------|---------|
419
+ | Main | `'docx-kit'` | Universal — Builder, styles, plugins, all types |
420
+ | Node.js | `'docx-kit/node'` | `saveDocument()` for file-system write |
421
+ | Browser | `'docx-kit/browser'` | `normalizeImageData()`, `dataUrlToUint8Array()` |
422
+
423
+ ---
424
+
425
+ ## Exports
426
+
427
+ ### Functions
428
+
429
+ | Export | Signature |
430
+ |--------|-----------|
431
+ | `createDocx` | `(config?: DocxKitConfig) => DocxBuilder` |
432
+ | `renderDocx` | `(schema: DocxSchema) => Promise<Blob>` |
433
+ | `defineStyles` | `<T>(styles: T) => T` |
434
+ | `definePlugin` | `<N,O>(plugin: DocxPlugin<N,O>) => DocxPlugin<N,O>` |
435
+ | `qrcodePlugin` | `() => DocxPlugin<'qrcode', QRCodePluginOptions>` |
436
+ | `echartsPlugin` | `() => DocxPlugin<'echarts', EChartsPluginOptions>` |
437
+ | `calloutPlugin` | `() => DocxPlugin<'callout', CalloutOptions>` |
438
+ | `codeBlockPlugin` | `() => DocxPlugin<'codeBlock', CodeBlockOptions>` |
439
+ | `coverPagePlugin` | `() => DocxPlugin<'coverPage', CoverPageOptions>` |
440
+ | `dataTablePlugin` | `() => DocxPlugin<'dataTable', DataTableOptions>` |
441
+ | `meetingMinutesPlugin` | `() => DocxPlugin<'meetingMinutes', MeetingMinutesOptions>` |
442
+ | `pageNumberPlugin` | `() => DocxPlugin<'pageNumber', PageNumberOptions>` |
443
+ | `propertyTablePlugin` | `() => DocxPlugin<'propertyTable', PropertyTableOptions>` |
444
+ | `signatureBlockPlugin` | `() => DocxPlugin<'signatureBlock', SignatureBlockOptions>` |
445
+ | `timelinePlugin` | `() => DocxPlugin<'timeline', TimelineOptions>` |
446
+ | `watermarkPlugin` | `() => DocxPlugin<'watermark', WatermarkOptions>` |
447
+ | `dataUrlToUint8Array` | `(dataUrl: string) => Uint8Array \| Promise<Uint8Array>` |
448
+
449
+ ### Types
450
+
451
+ | Type | Category |
452
+ |------|----------|
453
+ | `DocxBuilder`, `DocxSchema` | Builder |
454
+ | `BlockNode`, `HeadingNode`, `ParagraphNode`, `BulletListNode`, `NumberedListNode`, `HyperlinkNode`, `ImageNode`, `TableNode`, `PageBreakNode`, `SectionBreakNode`, `PluginNode`, `TextNode`, `BulletItem`, `InlineNode` | DSL |
455
+ | `DocxStyleRule`, `StyleSheet`, `BorderRule`, `BorderStyle`, `FontWeight`, `TextAlign`, `VerticalAlign` | Style |
456
+ | `DocxKitConfig`, `PageConfig`, `PageSize`, `Orientation`, `DocxTheme`, `SectionConfig`, `HeaderFooterConfig`, `HeaderFooterContent` | Config |
457
+ | `DocxPlugin`, `PluginRegistry`, `PluginRenderContext` | Plugin |
458
+ | `QRCodePluginOptions`, `EChartsPluginOptions`, `CalloutOptions`, `CodeBlockOptions`, `CoverPageOptions`, `DataTableOptions`, `ColAlign`, `ColFormat`, `PropertyTableOptions`, `PropertyItem`, `MeetingMinutesOptions`, `AgendaItem`, `PageNumberOptions`, `SignatureBlockOptions`, `SignatureParty`, `TimelineOptions`, `TimelineEvent`, `WatermarkOptions` | Plugin options |
459
+ | `ClassName`, `BaseNode`, `TableColumn` | Utility types |
460
+ | `DocxKitError`, `ERROR_CODES`, `ErrorCode` | Errors |
461
+ | `UnitValue` | Units |
462
+
463
+ ---
464
+
465
+ ## Errors
466
+
467
+ All errors extend `DocxKitError` with `code` and `cause`:
468
+
469
+ | Code | Description |
470
+ |------|-------------|
471
+ | `EXPORT_FAILED` | Packaging/export failed |
472
+ | `IMAGE_INVALID_DATA` | Image data is null or empty |
473
+ | `PLUGIN_NOT_REGISTERED` | Plugin name not found in register |
474
+ | `PLUGIN_RENDER_FAILED` | Plugin render() threw |
475
+ | `STYLE_UNKNOWN_CLASS` | className not found in stylesheet |
476
+ | `TABLE_INVALID_COLUMNS` | Table columns is empty |
477
+ | `UNKNOWN_NODE_TYPE` | Unrecognized node type |
478
+
479
+ ---
480
+
481
+ ## Project Structure
482
+
483
+ ```
484
+ src/
485
+ ├── builder/ # DocxBuilder class + createDocx/renderDocx factories
486
+ ├── compiler/ # Node → docxjs object compilation
487
+ │ ├── compileDocument.ts # Top-level document assembly
488
+ │ ├── compileNode.ts # Node type dispatcher
489
+ │ ├── compileStyle.ts # Style → docxjs option mapping
490
+ │ └── units.ts # Unit conversion (CSS → twips)
491
+ ├── dsl/
492
+ │ └── nodes.ts # All node type definitions
493
+ ├── style/
494
+ │ └── normalizeStyle.ts # Style cascade resolution
495
+ ├── types/
496
+ │ ├── document.ts # DocxKitConfig, PageConfig, DocxTheme
497
+ │ ├── plugin.ts # DocxPlugin, PluginRenderContext
498
+ │ ├── style.ts # DocxStyleRule, BorderRule, etc.
499
+ │ └── utility.ts # UnitValue, LiteralUnion, HexColor
500
+ ├── renderer/
501
+ │ └── pack.ts # Export wrappers (packToBlob, etc.)
502
+ ├── plugins/
503
+ │ ├── callout/ # Built-in Callout plugin
504
+ │ ├── code-block/ # Built-in Code Block plugin
505
+ │ ├── cover-page/ # Built-in Cover Page plugin
506
+ │ ├── data-table/ # Built-in Data Table plugin
507
+ │ ├── echarts/ # Built-in ECharts plugin
508
+ │ ├── meeting-minutes/ # Built-in Meeting Minutes plugin
509
+ │ ├── page-number/ # Built-in Page Number plugin
510
+ │ ├── property-table/ # Built-in Property Table plugin
511
+ │ ├── qrcode/ # Built-in QRCode plugin
512
+ │ ├── signature-block/ # Built-in Signature Block plugin
513
+ │ ├── timeline/ # Built-in Timeline plugin
514
+ │ └── watermark/ # Built-in Watermark plugin
515
+ ├── node/
516
+ │ ├── fs.ts # saveDocument (Node.js only)
517
+ │ └── dataUrl.ts # Node.js data URL decoder
518
+ ├── browser/
519
+ │ └── dom.ts # Browser helpers
520
+ ├── utils/
521
+ │ ├── dataUrl.ts # Shared data URL utilities
522
+ │ └── image.ts # Image factory helpers
523
+ ├── errors.ts # DocxKitError + error codes
524
+ ├── index.ts # Main entry point
525
+ ├── node.ts # Node.js entry point
526
+ └── browser.ts # Browser entry point
527
+ ```
528
+
529
+ ---
530
+
531
+ ## Feature Gap Analysis
532
+
533
+ See [docs/reports/docx-kit-gap-analysis.md](./docs/reports/docx-kit-gap-analysis.md) for a comprehensive comparison with `dolanmiu/docx` v9.7.1. Key gaps:
534
+
535
+ | Priority | Status | Missing Features |
536
+ |----------|--------|-----------------|
537
+ | **P0** | ✅ Done | Numbering/bullet lists, numbered lists, multiple sections, headers & footers |
538
+ | **P1** | Open | Hyperlinks, text highlighting, super/subscript, cell merging, page numbers, paragraph borders, cell shading |
539
+ | **P2** | Open | Bookmarks, TOC, table style presets, tab stops, keep-with-next, page borders, RTL, character spacing |
540
+
541
+ ---
542
+
24
543
  ## License
25
544
 
26
545
  [MIT](./LICENSE) License © 2025-PRESENT [ntnyq](https://github.com/ntnyq)