@wonderwhy-er/desktop-commander 0.2.35 → 0.2.36

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 (115) hide show
  1. package/README.md +2 -0
  2. package/dist/handlers/filesystem-handlers.js +58 -11
  3. package/dist/handlers/history-handlers.d.ts +7 -0
  4. package/dist/handlers/history-handlers.js +33 -1
  5. package/dist/server.js +30 -4
  6. package/dist/tools/docx/builders/image.d.ts +14 -0
  7. package/dist/tools/docx/builders/image.js +84 -0
  8. package/dist/tools/docx/builders/index.d.ts +9 -3
  9. package/dist/tools/docx/builders/index.js +9 -3
  10. package/dist/tools/docx/builders/paragraph.d.ts +12 -0
  11. package/dist/tools/docx/builders/paragraph.js +29 -0
  12. package/dist/tools/docx/builders/table.d.ts +8 -0
  13. package/dist/tools/docx/builders/table.js +94 -0
  14. package/dist/tools/docx/builders/utils.d.ts +5 -0
  15. package/dist/tools/docx/builders/utils.js +18 -0
  16. package/dist/tools/docx/constants.d.ts +28 -32
  17. package/dist/tools/docx/constants.js +56 -52
  18. package/dist/tools/docx/create.d.ts +21 -0
  19. package/dist/tools/docx/create.js +386 -0
  20. package/dist/tools/docx/dom.d.ts +66 -0
  21. package/dist/tools/docx/dom.js +228 -0
  22. package/dist/tools/docx/index.d.ts +8 -12
  23. package/dist/tools/docx/index.js +8 -14
  24. package/dist/tools/docx/modify.d.ts +28 -0
  25. package/dist/tools/docx/modify.js +271 -0
  26. package/dist/tools/docx/ops/delete-paragraph-at-body-index.d.ts +11 -0
  27. package/dist/tools/docx/ops/delete-paragraph-at-body-index.js +23 -0
  28. package/dist/tools/docx/ops/header-replace-text-exact.d.ts +13 -0
  29. package/dist/tools/docx/ops/header-replace-text-exact.js +55 -0
  30. package/dist/tools/docx/ops/index.d.ts +17 -0
  31. package/dist/tools/docx/ops/index.js +67 -0
  32. package/dist/tools/docx/ops/insert-image-after-text.d.ts +24 -0
  33. package/dist/tools/docx/ops/insert-image-after-text.js +128 -0
  34. package/dist/tools/docx/ops/insert-paragraph-after-text.d.ts +12 -0
  35. package/dist/tools/docx/ops/insert-paragraph-after-text.js +74 -0
  36. package/dist/tools/docx/ops/insert-table-after-text.d.ts +19 -0
  37. package/dist/tools/docx/ops/insert-table-after-text.js +57 -0
  38. package/dist/tools/docx/ops/replace-hyperlink-url.d.ts +12 -0
  39. package/dist/tools/docx/ops/replace-hyperlink-url.js +37 -0
  40. package/dist/tools/docx/ops/replace-paragraph-at-body-index.d.ts +9 -0
  41. package/dist/tools/docx/ops/replace-paragraph-at-body-index.js +25 -0
  42. package/dist/tools/docx/ops/replace-paragraph-text-exact.d.ts +9 -0
  43. package/dist/tools/docx/ops/replace-paragraph-text-exact.js +21 -0
  44. package/dist/tools/docx/ops/set-color-for-paragraph-exact.d.ts +8 -0
  45. package/dist/tools/docx/ops/set-color-for-paragraph-exact.js +23 -0
  46. package/dist/tools/docx/ops/set-color-for-style.d.ts +9 -0
  47. package/dist/tools/docx/ops/set-color-for-style.js +27 -0
  48. package/dist/tools/docx/ops/set-paragraph-style-at-body-index.d.ts +8 -0
  49. package/dist/tools/docx/ops/set-paragraph-style-at-body-index.js +57 -0
  50. package/dist/tools/docx/ops/table-set-cell-text.d.ts +9 -0
  51. package/dist/tools/docx/ops/table-set-cell-text.js +72 -0
  52. package/dist/tools/docx/read.d.ts +27 -0
  53. package/dist/tools/docx/read.js +188 -0
  54. package/dist/tools/docx/relationships.d.ts +22 -0
  55. package/dist/tools/docx/relationships.js +76 -0
  56. package/dist/tools/docx/types.d.ts +174 -104
  57. package/dist/tools/docx/types.js +2 -5
  58. package/dist/tools/docx/validate.d.ts +33 -0
  59. package/dist/tools/docx/validate.js +49 -0
  60. package/dist/tools/docx/write.d.ts +17 -0
  61. package/dist/tools/docx/write.js +88 -0
  62. package/dist/tools/docx/zip.d.ts +21 -0
  63. package/dist/tools/docx/zip.js +35 -0
  64. package/dist/tools/schemas.d.ts +13 -0
  65. package/dist/tools/schemas.js +5 -0
  66. package/dist/types.d.ts +10 -0
  67. package/dist/ui/contracts.d.ts +14 -0
  68. package/dist/ui/contracts.js +18 -0
  69. package/dist/ui/file-preview/index.html +16 -0
  70. package/dist/ui/file-preview/preview-runtime.js +13977 -0
  71. package/dist/ui/file-preview/shared/preview-file-types.d.ts +5 -0
  72. package/dist/ui/file-preview/shared/preview-file-types.js +57 -0
  73. package/dist/ui/file-preview/src/app.d.ts +4 -0
  74. package/dist/ui/file-preview/src/app.js +800 -0
  75. package/dist/ui/file-preview/src/components/code-viewer.d.ts +6 -0
  76. package/dist/ui/file-preview/src/components/code-viewer.js +73 -0
  77. package/dist/ui/file-preview/src/components/highlighting.d.ts +2 -0
  78. package/dist/ui/file-preview/src/components/highlighting.js +54 -0
  79. package/dist/ui/file-preview/src/components/html-renderer.d.ts +9 -0
  80. package/dist/ui/file-preview/src/components/html-renderer.js +63 -0
  81. package/dist/ui/file-preview/src/components/markdown-renderer.d.ts +1 -0
  82. package/dist/ui/file-preview/src/components/markdown-renderer.js +21 -0
  83. package/dist/ui/file-preview/src/components/toolbar.d.ts +6 -0
  84. package/dist/ui/file-preview/src/components/toolbar.js +75 -0
  85. package/dist/ui/file-preview/src/image-preview.d.ts +3 -0
  86. package/dist/ui/file-preview/src/image-preview.js +21 -0
  87. package/dist/ui/file-preview/src/main.d.ts +1 -0
  88. package/dist/ui/file-preview/src/main.js +5 -0
  89. package/dist/ui/file-preview/src/types.d.ts +1 -0
  90. package/dist/ui/file-preview/src/types.js +1 -0
  91. package/dist/ui/file-preview/styles.css +764 -0
  92. package/dist/ui/resources.d.ts +21 -0
  93. package/dist/ui/resources.js +72 -0
  94. package/dist/ui/shared/escape-html.d.ts +4 -0
  95. package/dist/ui/shared/escape-html.js +11 -0
  96. package/dist/ui/shared/host-lifecycle.d.ts +16 -0
  97. package/dist/ui/shared/host-lifecycle.js +35 -0
  98. package/dist/ui/shared/rpc-client.d.ts +14 -0
  99. package/dist/ui/shared/rpc-client.js +72 -0
  100. package/dist/ui/shared/theme-adaptation.d.ts +10 -0
  101. package/dist/ui/shared/theme-adaptation.js +118 -0
  102. package/dist/ui/shared/tool-header.d.ts +9 -0
  103. package/dist/ui/shared/tool-header.js +25 -0
  104. package/dist/ui/shared/tool-shell.d.ts +16 -0
  105. package/dist/ui/shared/tool-shell.js +65 -0
  106. package/dist/ui/shared/widget-state.d.ts +28 -0
  107. package/dist/ui/shared/widget-state.js +60 -0
  108. package/dist/utils/capture.d.ts +1 -0
  109. package/dist/utils/capture.js +6 -0
  110. package/dist/utils/files/docx.d.ts +8 -15
  111. package/dist/utils/files/docx.js +76 -176
  112. package/dist/utils/files/text.js +9 -1
  113. package/dist/version.d.ts +1 -1
  114. package/dist/version.js +1 -1
  115. package/package.json +5 -2
@@ -1,57 +1,61 @@
1
1
  /**
2
- * DOCX Constants
3
- *
4
- * Centralised constants shared across the DOCX module.
5
- *
6
- * @module docx/constants
2
+ * DOCX constants — shared values used across the module.
7
3
  */
8
- // ─── Conversion Defaults ─────────────────────────────────────────────────────
9
- export const DEFAULT_CONVERSION_OPTIONS = {
10
- includeImages: true,
11
- preserveFormatting: true,
12
- styleMap: [],
13
- };
14
- // ─── Build (html-to-docx) Defaults ──────────────────────────────────────────
15
- export const DEFAULT_BUILD_OPTIONS = {
16
- font: 'Calibri',
17
- fontSize: 11,
18
- orientation: 'portrait',
19
- margins: {
20
- top: 1440,
21
- right: 1440,
22
- bottom: 1440,
23
- left: 1440,
24
- header: 720,
25
- footer: 720,
26
- gutter: 0,
27
- },
28
- footer: true,
29
- pageNumber: false,
4
+ // ═══════════════════════════════════════════════════════════════════════
5
+ // Image MIME types
6
+ // ═══════════════════════════════════════════════════════════════════════
7
+ export const IMAGE_MIME_TYPES = {
8
+ '.png': 'image/png',
9
+ '.jpg': 'image/jpeg',
10
+ '.jpeg': 'image/jpeg',
11
+ '.gif': 'image/gif',
12
+ '.bmp': 'image/bmp',
13
+ '.tiff': 'image/tiff',
14
+ '.tif': 'image/tiff',
15
+ '.svg': 'image/svg+xml',
16
+ '.webp': 'image/webp',
30
17
  };
31
- // ─── DOCX Internal XML Namespaces ────────────────────────────────────────────
32
- export const DOCX_NAMESPACES = {
33
- DUBLIN_CORE: 'dc',
34
- CUSTOM_PROPERTIES: 'cp',
35
- DCTERMS: 'dcterms',
18
+ export function getMimeType(ext) {
19
+ return IMAGE_MIME_TYPES[ext.toLowerCase()] ?? 'application/octet-stream';
20
+ }
21
+ // ═══════════════════════════════════════════════════════════════════════
22
+ // EMU conversion (English Metric Units)
23
+ // ═══════════════════════════════════════════════════════════════════════
24
+ /**
25
+ * Convert pixels to EMU (English Metric Units).
26
+ * 1 inch = 914400 EMU, 1 px ≈ 9525 EMU (at 96 DPI)
27
+ */
28
+ export const PX_TO_EMU = 9525;
29
+ export function pixelsToEmu(px) {
30
+ return px * PX_TO_EMU;
31
+ }
32
+ // ═══════════════════════════════════════════════════════════════════════
33
+ // XML namespaces
34
+ // ═══════════════════════════════════════════════════════════════════════
35
+ export const NAMESPACES = {
36
+ W: 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
37
+ WP: 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',
38
+ A: 'http://schemas.openxmlformats.org/drawingml/2006/main',
39
+ PIC: 'http://schemas.openxmlformats.org/drawingml/2006/picture',
40
+ R: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
41
+ RELS: 'http://schemas.openxmlformats.org/package/2006/relationships',
36
42
  };
37
- // ─── DOCX Archive Paths ─────────────────────────────────────────────────────
38
- export const CORE_PROPERTIES_PATH = 'docProps/core.xml';
39
- // ─── Image MIME Types (extension → MIME) ─────────────────────────────────────
40
- export const IMAGE_MIME_TYPES = {
41
- jpg: 'image/jpeg',
42
- jpeg: 'image/jpeg',
43
- gif: 'image/gif',
44
- bmp: 'image/bmp',
45
- webp: 'image/webp',
46
- png: 'image/png',
43
+ // ═══════════════════════════════════════════════════════════════════════
44
+ // Default values
45
+ // ═══════════════════════════════════════════════════════════════════════
46
+ export const DEFAULT_IMAGE_WIDTH = 300;
47
+ export const DEFAULT_IMAGE_HEIGHT = 200;
48
+ // ═══════════════════════════════════════════════════════════════════════
49
+ // File paths
50
+ // ═══════════════════════════════════════════════════════════════════════
51
+ export const DOCX_PATHS = {
52
+ CONTENT_TYPES: '[Content_Types].xml',
53
+ DOCUMENT_XML: 'word/document.xml',
54
+ DOCUMENT_RELS: 'word/_rels/document.xml.rels',
55
+ ROOT_RELS: '_rels/.rels',
56
+ STYLES_XML: 'word/styles.xml',
57
+ SETTINGS_XML: 'word/settings.xml',
58
+ WEB_SETTINGS_XML: 'word/webSettings.xml',
59
+ FONT_TABLE_XML: 'word/fontTable.xml',
60
+ MEDIA_FOLDER: 'word/media',
47
61
  };
48
- // ─── HTML Wrapper Template ───────────────────────────────────────────────────
49
- export const HTML_WRAPPER_TEMPLATE = `<!DOCTYPE html>
50
- <html>
51
- <head>
52
- <meta charset="UTF-8">
53
- </head>
54
- <body>
55
- {content}
56
- </body>
57
- </html>`;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * createDocxNew - Create a brand-new professional DOCX file from scratch.
3
+ *
4
+ * Single Responsibility: Build a complete, professional DOCX structure
5
+ * with proper styles, document defaults, and content from styled DOM structure.
6
+ *
7
+ * This function does NOT read any existing files - it creates everything
8
+ * from scratch with a professional structure.
9
+ */
10
+ import type { DocxContentStructure, WriteDocxResult } from './types.js';
11
+ /**
12
+ * Create a new professional DOCX file from content structure.
13
+ *
14
+ * This function creates a complete DOCX structure from scratch with:
15
+ * - Professional styles (Normal, Heading1-9, ListParagraph, TableGrid)
16
+ * - Document defaults (Calibri font, proper spacing)
17
+ * - Complete ZIP structure
18
+ *
19
+ * Then builds content from the provided structure.
20
+ */
21
+ export declare function createDocxNew(outputPath: string, content: DocxContentStructure): Promise<WriteDocxResult>;
@@ -0,0 +1,386 @@
1
+ /**
2
+ * createDocxNew - Create a brand-new professional DOCX file from scratch.
3
+ *
4
+ * Single Responsibility: Build a complete, professional DOCX structure
5
+ * with proper styles, document defaults, and content from styled DOM structure.
6
+ *
7
+ * This function does NOT read any existing files - it creates everything
8
+ * from scratch with a professional structure.
9
+ */
10
+ import fs from 'fs/promises';
11
+ import PizZip from 'pizzip';
12
+ import { parseXml, serializeXml, getBody } from './dom.js';
13
+ import { buildParagraph, buildTable, buildImageElement } from './builders/index.js';
14
+ /**
15
+ * Create a professional DOCX ZIP structure with:
16
+ * - Complete styles.xml (Normal, Heading1-9, etc.)
17
+ * - Document defaults (fonts, spacing, colors)
18
+ * - Proper relationships
19
+ * - Content types
20
+ * - Empty document body ready for content
21
+ */
22
+ function createProfessionalDocxZip() {
23
+ const zip = new PizZip();
24
+ // ─── [Content_Types].xml ──────────────────────────────────────────
25
+ zip.file('[Content_Types].xml', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
26
+ <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
27
+ <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
28
+ <Default Extension="xml" ContentType="application/xml"/>
29
+ <Default Extension="png" ContentType="image/png"/>
30
+ <Default Extension="jpg" ContentType="image/jpeg"/>
31
+ <Default Extension="jpeg" ContentType="image/jpeg"/>
32
+ <Default Extension="gif" ContentType="image/gif"/>
33
+ <Default Extension="bmp" ContentType="image/bmp"/>
34
+ <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
35
+ <Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
36
+ </Types>`);
37
+ // ─── _rels/.rels ──────────────────────────────────────────────────
38
+ zip.folder('_rels')?.file('.rels', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
39
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
40
+ <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
41
+ </Relationships>`);
42
+ // ─── word/_rels/document.xml.rels ────────────────────────────────
43
+ zip.folder('word')?.folder('_rels')?.file('document.xml.rels', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
44
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
45
+ </Relationships>`);
46
+ // ─── word/styles.xml ───────────────────────────────────────────────
47
+ zip.file('word/styles.xml', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
48
+ <w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
49
+ <!-- Document Defaults -->
50
+ <w:docDefaults>
51
+ <w:rPrDefault>
52
+ <w:rPr>
53
+ <w:rFonts w:ascii="Calibri" w:hAnsi="Calibri" w:eastAsia="Calibri" w:cs="Calibri"/>
54
+ <w:sz w:val="22"/>
55
+ <w:szCs w:val="22"/>
56
+ <w:color w:val="000000"/>
57
+ </w:rPr>
58
+ </w:rPrDefault>
59
+ <w:pPrDefault>
60
+ <w:pPr>
61
+ <w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
62
+ </w:pPr>
63
+ </w:pPrDefault>
64
+ </w:docDefaults>
65
+
66
+ <!-- Normal Style -->
67
+ <w:style w:type="paragraph" w:styleId="Normal">
68
+ <w:name w:val="Normal"/>
69
+ <w:qFormat/>
70
+ <w:pPr>
71
+ <w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
72
+ </w:pPr>
73
+ <w:rPr>
74
+ <w:rFonts w:ascii="Calibri" w:hAnsi="Calibri" w:eastAsia="Calibri" w:cs="Calibri"/>
75
+ <w:sz w:val="22"/>
76
+ <w:szCs w:val="22"/>
77
+ <w:color w:val="000000"/>
78
+ </w:rPr>
79
+ </w:style>
80
+
81
+ <!-- Heading Styles -->
82
+ <w:style w:type="paragraph" w:styleId="Heading1">
83
+ <w:name w:val="Heading 1"/>
84
+ <w:basedOn w:val="Normal"/>
85
+ <w:next w:val="Normal"/>
86
+ <w:qFormat/>
87
+ <w:pPr>
88
+ <w:keepNext/>
89
+ <w:spacing w:before="480" w:after="0"/>
90
+ <w:outlineLvl w:val="0"/>
91
+ </w:pPr>
92
+ <w:rPr>
93
+ <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" w:eastAsia="Calibri Light" w:cs="Calibri Light"/>
94
+ <w:b/>
95
+ <w:bCs/>
96
+ <w:sz w:val="32"/>
97
+ <w:szCs w:val="32"/>
98
+ <w:color w:val="2F5496"/>
99
+ </w:rPr>
100
+ </w:style>
101
+
102
+ <w:style w:type="paragraph" w:styleId="Heading2">
103
+ <w:name w:val="Heading 2"/>
104
+ <w:basedOn w:val="Normal"/>
105
+ <w:next w:val="Normal"/>
106
+ <w:qFormat/>
107
+ <w:pPr>
108
+ <w:keepNext/>
109
+ <w:spacing w:before="240" w:after="0"/>
110
+ <w:outlineLvl w:val="1"/>
111
+ </w:pPr>
112
+ <w:rPr>
113
+ <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" w:eastAsia="Calibri Light" w:cs="Calibri Light"/>
114
+ <w:b/>
115
+ <w:bCs/>
116
+ <w:sz w:val="28"/>
117
+ <w:szCs w:val="28"/>
118
+ <w:color w:val="2F5496"/>
119
+ </w:rPr>
120
+ </w:style>
121
+
122
+ <w:style w:type="paragraph" w:styleId="Heading3">
123
+ <w:name w:val="Heading 3"/>
124
+ <w:basedOn w:val="Normal"/>
125
+ <w:next w:val="Normal"/>
126
+ <w:qFormat/>
127
+ <w:pPr>
128
+ <w:keepNext/>
129
+ <w:spacing w:before="240" w:after="0"/>
130
+ <w:outlineLvl w:val="2"/>
131
+ </w:pPr>
132
+ <w:rPr>
133
+ <w:b/>
134
+ <w:bCs/>
135
+ <w:sz w:val="24"/>
136
+ <w:szCs w:val="24"/>
137
+ <w:color w:val="1F3763"/>
138
+ </w:rPr>
139
+ </w:style>
140
+
141
+ <w:style w:type="paragraph" w:styleId="Heading4">
142
+ <w:name w:val="Heading 4"/>
143
+ <w:basedOn w:val="Normal"/>
144
+ <w:next w:val="Normal"/>
145
+ <w:qFormat/>
146
+ <w:pPr>
147
+ <w:keepNext/>
148
+ <w:spacing w:before="240" w:after="0"/>
149
+ <w:outlineLvl w:val="3"/>
150
+ </w:pPr>
151
+ <w:rPr>
152
+ <w:b/>
153
+ <w:bCs/>
154
+ <w:sz w:val="22"/>
155
+ <w:szCs w:val="22"/>
156
+ <w:color w:val="1F3763"/>
157
+ </w:rPr>
158
+ </w:style>
159
+
160
+ <w:style w:type="paragraph" w:styleId="Heading5">
161
+ <w:name w:val="Heading 5"/>
162
+ <w:basedOn w:val="Normal"/>
163
+ <w:next w:val="Normal"/>
164
+ <w:qFormat/>
165
+ <w:pPr>
166
+ <w:keepNext/>
167
+ <w:spacing w:before="240" w:after="0"/>
168
+ <w:outlineLvl w:val="4"/>
169
+ </w:pPr>
170
+ <w:rPr>
171
+ <w:b/>
172
+ <w:bCs/>
173
+ <w:sz w:val="22"/>
174
+ <w:szCs w:val="22"/>
175
+ <w:color w:val="1F3763"/>
176
+ </w:rPr>
177
+ </w:style>
178
+
179
+ <w:style w:type="paragraph" w:styleId="Heading6">
180
+ <w:name w:val="Heading 6"/>
181
+ <w:basedOn w:val="Normal"/>
182
+ <w:next w:val="Normal"/>
183
+ <w:qFormat/>
184
+ <w:pPr>
185
+ <w:keepNext/>
186
+ <w:spacing w:before="240" w:after="0"/>
187
+ <w:outlineLvl w:val="5"/>
188
+ </w:pPr>
189
+ <w:rPr>
190
+ <w:b/>
191
+ <w:bCs/>
192
+ <w:sz w:val="22"/>
193
+ <w:szCs w:val="22"/>
194
+ <w:color w:val="1F3763"/>
195
+ </w:rPr>
196
+ </w:style>
197
+
198
+ <w:style w:type="paragraph" w:styleId="Heading7">
199
+ <w:name w:val="Heading 7"/>
200
+ <w:basedOn w:val="Normal"/>
201
+ <w:next w:val="Normal"/>
202
+ <w:qFormat/>
203
+ <w:pPr>
204
+ <w:keepNext/>
205
+ <w:spacing w:before="240" w:after="0"/>
206
+ <w:outlineLvl w:val="6"/>
207
+ </w:pPr>
208
+ <w:rPr>
209
+ <w:b/>
210
+ <w:bCs/>
211
+ <w:sz w:val="22"/>
212
+ <w:szCs w:val="22"/>
213
+ <w:color w:val="1F3763"/>
214
+ </w:rPr>
215
+ </w:style>
216
+
217
+ <w:style w:type="paragraph" w:styleId="Heading8">
218
+ <w:name w:val="Heading 8"/>
219
+ <w:basedOn w:val="Normal"/>
220
+ <w:next w:val="Normal"/>
221
+ <w:qFormat/>
222
+ <w:pPr>
223
+ <w:keepNext/>
224
+ <w:spacing w:before="240" w:after="0"/>
225
+ <w:outlineLvl w:val="7"/>
226
+ </w:pPr>
227
+ <w:rPr>
228
+ <w:b/>
229
+ <w:bCs/>
230
+ <w:sz w:val="22"/>
231
+ <w:szCs w:val="22"/>
232
+ <w:color w:val="1F3763"/>
233
+ </w:rPr>
234
+ </w:style>
235
+
236
+ <w:style w:type="paragraph" w:styleId="Heading9">
237
+ <w:name w:val="Heading 9"/>
238
+ <w:basedOn w:val="Normal"/>
239
+ <w:next w:val="Normal"/>
240
+ <w:qFormat/>
241
+ <w:pPr>
242
+ <w:keepNext/>
243
+ <w:spacing w:before="240" w:after="0"/>
244
+ <w:outlineLvl w:val="8"/>
245
+ </w:pPr>
246
+ <w:rPr>
247
+ <w:b/>
248
+ <w:bCs/>
249
+ <w:sz w:val="22"/>
250
+ <w:szCs w:val="22"/>
251
+ <w:color w:val="1F3763"/>
252
+ </w:rPr>
253
+ </w:style>
254
+
255
+ <!-- List Styles -->
256
+ <w:style w:type="paragraph" w:styleId="ListParagraph">
257
+ <w:name w:val="List Paragraph"/>
258
+ <w:basedOn w:val="Normal"/>
259
+ <w:qFormat/>
260
+ <w:pPr>
261
+ <w:ind w:left="720"/>
262
+ </w:pPr>
263
+ </w:style>
264
+
265
+ <!-- Table Styles -->
266
+ <w:style w:type="table" w:styleId="TableGrid">
267
+ <w:name w:val="Table Grid"/>
268
+ <w:basedOn w:val="NormalTable"/>
269
+ <w:qFormat/>
270
+ <w:tblPr>
271
+ <w:tblBorders>
272
+ <w:top w:val="single" w:sz="4" w:space="0" w:color="000000"/>
273
+ <w:left w:val="single" w:sz="4" w:space="0" w:color="000000"/>
274
+ <w:bottom w:val="single" w:sz="4" w:space="0" w:color="000000"/>
275
+ <w:right w:val="single" w:sz="4" w:space="0" w:color="000000"/>
276
+ <w:insideH w:val="single" w:sz="4" w:space="0" w:color="000000"/>
277
+ <w:insideV w:val="single" w:sz="4" w:space="0" w:color="000000"/>
278
+ </w:tblBorders>
279
+ </w:tblPr>
280
+ </w:style>
281
+ </w:styles>`);
282
+ // ─── word/document.xml ─────────────────────────────────────────────
283
+ zip.file('word/document.xml', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
284
+ <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
285
+ <w:body>
286
+ </w:body>
287
+ </w:document>`);
288
+ // ─── word/settings.xml ────────────────────────────────────────────
289
+ zip.file('word/settings.xml', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
290
+ <w:settings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
291
+ <w:defaultTabStop w:val="720"/>
292
+ <w:compat>
293
+ <w:compatSetting w:name="compatibilityMode" w:uri="http://schemas.microsoft.com/office/word" w:val="15"/>
294
+ </w:compat>
295
+ </w:settings>`);
296
+ // ─── word/webSettings.xml ────────────────────────────────────────
297
+ zip.file('word/webSettings.xml', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
298
+ <w:webSettings xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
299
+ <w:optimizeForBrowser/>
300
+ </w:webSettings>`);
301
+ // ─── word/fontTable.xml ───────────────────────────────────────────
302
+ zip.file('word/fontTable.xml', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
303
+ <w:fonts xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
304
+ <w:font w:name="Calibri">
305
+ <w:panose1 w:val="020F0502020204030204"/>
306
+ <w:charset w:val="00"/>
307
+ <w:family w:val="swiss"/>
308
+ <w:pitch w:val="variable"/>
309
+ <w:sig w:usb0="E00002FF" w:usb1="4000ACFF" w:usb2="00000001" w:usb3="00000000" w:csb0="0000019F" w:csb1="00000000"/>
310
+ </w:font>
311
+ <w:font w:name="Calibri Light">
312
+ <w:panose1 w:val="020F0302020204030204"/>
313
+ <w:charset w:val="00"/>
314
+ <w:family w:val="swiss"/>
315
+ <w:pitch w:val="variable"/>
316
+ <w:sig w:usb0="E00002FF" w:usb1="4000ACFF" w:usb2="00000001" w:usb3="00000000" w:csb0="0000019F" w:csb1="00000000"/>
317
+ </w:font>
318
+ <w:font w:name="Times New Roman">
319
+ <w:panose1 w:val="02020603050405020304"/>
320
+ <w:charset w:val="00"/>
321
+ <w:family w:val="roman"/>
322
+ <w:pitch w:val="variable"/>
323
+ <w:sig w:usb0="E0002AFF" w:usb1="C0007841" w:usb2="00000009" w:usb3="00000000" w:csb0="000001FF" w:csb1="00000000"/>
324
+ </w:font>
325
+ </w:fonts>`);
326
+ // ─── Create media folder ───────────────────────────────────────────
327
+ zip.folder('word')?.folder('media');
328
+ return zip;
329
+ }
330
+ // ─── Content builders are now in ./builders/index.js ───────────────────
331
+ /**
332
+ * Create a new professional DOCX file from content structure.
333
+ *
334
+ * This function creates a complete DOCX structure from scratch with:
335
+ * - Professional styles (Normal, Heading1-9, ListParagraph, TableGrid)
336
+ * - Document defaults (Calibri font, proper spacing)
337
+ * - Complete ZIP structure
338
+ *
339
+ * Then builds content from the provided structure.
340
+ */
341
+ export async function createDocxNew(outputPath, content) {
342
+ // 1. Create professional DOCX ZIP structure
343
+ const zip = createProfessionalDocxZip();
344
+ // 2. Parse empty document.xml
345
+ const xmlStr = zip.file('word/document.xml').asText();
346
+ const doc = parseXml(xmlStr);
347
+ const body = getBody(doc);
348
+ // 3. Build content from structure
349
+ let tableCount = 0;
350
+ for (const item of content.items) {
351
+ if (item.type === 'paragraph') {
352
+ const p = buildParagraph(doc, item);
353
+ body.appendChild(p);
354
+ }
355
+ else if (item.type === 'table') {
356
+ const tbl = buildTable(doc, item);
357
+ body.appendChild(tbl);
358
+ tableCount++;
359
+ }
360
+ else if (item.type === 'image') {
361
+ const imgP = await buildImageElement(doc, zip, item);
362
+ body.appendChild(imgP);
363
+ }
364
+ }
365
+ // 4. Serialize and save
366
+ const newXml = serializeXml(doc);
367
+ zip.file('word/document.xml', newXml);
368
+ const buf = zip.generate({ type: 'nodebuffer' });
369
+ await fs.writeFile(outputPath, buf);
370
+ // 5. Build stats
371
+ const bodyChildCount = content.items.length;
372
+ const stats = {
373
+ tablesBefore: 0,
374
+ tablesAfter: tableCount,
375
+ bodyChildrenBefore: 0,
376
+ bodyChildrenAfter: bodyChildCount,
377
+ bodySignatureBefore: '',
378
+ bodySignatureAfter: '', // Could compute if needed
379
+ };
380
+ return {
381
+ outputPath,
382
+ results: [], // No ops were applied
383
+ stats,
384
+ warnings: [],
385
+ };
386
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * DOM utilities for DOCX XML manipulation.
3
+ *
4
+ * Single Responsibility: XML parsing, navigation, and minimal element
5
+ * mutation. No file I/O — every function works on in-memory DOM nodes.
6
+ *
7
+ * Uses @xmldom/xmldom for parsing and serialisation so that the
8
+ * document-order of nodes is always preserved.
9
+ */
10
+ export declare function parseXml(xmlStr: string): Document;
11
+ export declare function serializeXml(doc: Document): string;
12
+ /**
13
+ * Convert any NodeList / HTMLCollection-like object into a real array.
14
+ */
15
+ export declare function nodeListToArray<T extends Node = Node>(nl: NodeListOf<T> | NodeList | {
16
+ length: number;
17
+ item(index: number): T | null;
18
+ }): T[];
19
+ /** Return the single <w:body> element from a parsed document.xml DOM. */
20
+ export declare function getBody(doc: Document): Element;
21
+ /**
22
+ * Return ALL direct element children of w:body **in document order**.
23
+ * Includes w:p, w:tbl, w:sdt, w:sectPr, etc.
24
+ */
25
+ export declare function getBodyChildren(body: Element): Element[];
26
+ /**
27
+ * Build a compact signature string from the body children array.
28
+ * Maps each node's qualified name to a short local name:
29
+ * w:p → p, w:tbl → tbl, w:sdt → sdt, w:sectPr → sectPr, …
30
+ * Returns e.g. "p,tbl,p,p,sectPr".
31
+ */
32
+ export declare function bodySignature(children: Element[]): string;
33
+ /** Concatenate text from every <w:t> descendant of a paragraph. */
34
+ export declare function getParagraphText(p: Element): string;
35
+ /** Read the style id from w:pPr/w:pStyle/@w:val, or null if absent. */
36
+ export declare function getParagraphStyle(p: Element): string | null;
37
+ /**
38
+ * Replace the text of a paragraph with minimal DOM changes.
39
+ * Sets the FIRST w:t to `text`, clears every subsequent w:t.
40
+ * Sets xml:space="preserve" so leading/trailing spaces survive.
41
+ * Does NOT recreate runs or remove paragraph properties.
42
+ */
43
+ export declare function setParagraphTextMinimal(p: Element, text: string): void;
44
+ /**
45
+ * Ensure a <w:r> element has w:rPr/w:color[@w:val=hex].
46
+ * Creates w:rPr and w:color if they don't exist.
47
+ * Only touches the colour — leaves every other run property intact.
48
+ */
49
+ export declare function ensureRunColor(run: Element, hex: string): void;
50
+ /**
51
+ * Apply run-level colour to every <w:r> in a paragraph.
52
+ */
53
+ export declare function colorParagraphRuns(p: Element, color: string): void;
54
+ /**
55
+ * Apply bold / italic / color to every <w:r> in a paragraph.
56
+ * Preserves all existing w:rPr children; only modifies specified props.
57
+ */
58
+ export declare function styleParagraphRuns(p: Element, style: {
59
+ color?: string;
60
+ bold?: boolean;
61
+ italic?: boolean;
62
+ }): void;
63
+ /** Count direct w:tbl children of body. */
64
+ export declare function countTables(children: Element[]): number;
65
+ /** Count <w:drawing> descendants (rough image count). */
66
+ export declare function countImages(body: Element): number;