@wonderwhy-er/desktop-commander 0.2.35 → 0.2.37
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 +3 -0
- package/dist/handlers/filesystem-handlers.js +58 -11
- package/dist/handlers/history-handlers.d.ts +7 -0
- package/dist/handlers/history-handlers.js +33 -1
- package/dist/remote-device/remote-channel.d.ts +8 -3
- package/dist/remote-device/remote-channel.js +68 -21
- package/dist/search-manager.d.ts +13 -0
- package/dist/search-manager.js +146 -0
- package/dist/server.js +56 -4
- package/dist/test-docx.d.ts +1 -0
- package/dist/tools/docx/builders/image.d.ts +14 -0
- package/dist/tools/docx/builders/image.js +84 -0
- package/dist/tools/docx/builders/index.d.ts +9 -3
- package/dist/tools/docx/builders/index.js +9 -3
- package/dist/tools/docx/builders/paragraph.d.ts +12 -0
- package/dist/tools/docx/builders/paragraph.js +29 -0
- package/dist/tools/docx/builders/table.d.ts +10 -0
- package/dist/tools/docx/builders/table.js +138 -0
- package/dist/tools/docx/builders/utils.d.ts +5 -0
- package/dist/tools/docx/builders/utils.js +18 -0
- package/dist/tools/docx/constants.d.ts +28 -32
- package/dist/tools/docx/constants.js +56 -52
- package/dist/tools/docx/create.d.ts +21 -0
- package/dist/tools/docx/create.js +386 -0
- package/dist/tools/docx/dom.d.ts +139 -0
- package/dist/tools/docx/dom.js +448 -0
- package/dist/tools/docx/index.d.ts +8 -12
- package/dist/tools/docx/index.js +8 -14
- package/dist/tools/docx/modify.d.ts +28 -0
- package/dist/tools/docx/modify.js +271 -0
- package/dist/tools/docx/ops/delete-paragraph-at-body-index.d.ts +11 -0
- package/dist/tools/docx/ops/delete-paragraph-at-body-index.js +23 -0
- package/dist/tools/docx/ops/header-replace-text-exact.d.ts +13 -0
- package/dist/tools/docx/ops/header-replace-text-exact.js +55 -0
- package/dist/tools/docx/ops/index.d.ts +17 -0
- package/dist/tools/docx/ops/index.js +70 -0
- package/dist/tools/docx/ops/insert-image-after-text.d.ts +24 -0
- package/dist/tools/docx/ops/insert-image-after-text.js +128 -0
- package/dist/tools/docx/ops/insert-paragraph-after-text.d.ts +12 -0
- package/dist/tools/docx/ops/insert-paragraph-after-text.js +74 -0
- package/dist/tools/docx/ops/insert-table-after-text.d.ts +19 -0
- package/dist/tools/docx/ops/insert-table-after-text.js +57 -0
- package/dist/tools/docx/ops/replace-hyperlink-url.d.ts +12 -0
- package/dist/tools/docx/ops/replace-hyperlink-url.js +37 -0
- package/dist/tools/docx/ops/replace-paragraph-at-body-index.d.ts +9 -0
- package/dist/tools/docx/ops/replace-paragraph-at-body-index.js +25 -0
- package/dist/tools/docx/ops/replace-paragraph-text-exact.d.ts +21 -0
- package/dist/tools/docx/ops/replace-paragraph-text-exact.js +36 -0
- package/dist/tools/docx/ops/replace-table-cell-text.d.ts +25 -0
- package/dist/tools/docx/ops/replace-table-cell-text.js +85 -0
- package/dist/tools/docx/ops/set-color-for-paragraph-exact.d.ts +9 -0
- package/dist/tools/docx/ops/set-color-for-paragraph-exact.js +24 -0
- package/dist/tools/docx/ops/set-color-for-style.d.ts +13 -0
- package/dist/tools/docx/ops/set-color-for-style.js +31 -0
- package/dist/tools/docx/ops/set-paragraph-style-at-body-index.d.ts +8 -0
- package/dist/tools/docx/ops/set-paragraph-style-at-body-index.js +57 -0
- package/dist/tools/docx/ops/table-set-cell-text.d.ts +9 -0
- package/dist/tools/docx/ops/table-set-cell-text.js +40 -0
- package/dist/tools/docx/read.d.ts +27 -0
- package/dist/tools/docx/read.js +308 -0
- package/dist/tools/docx/relationships.d.ts +22 -0
- package/dist/tools/docx/relationships.js +76 -0
- package/dist/tools/docx/types.d.ts +202 -103
- package/dist/tools/docx/types.js +2 -5
- package/dist/tools/docx/validate.d.ts +33 -0
- package/dist/tools/docx/validate.js +49 -0
- package/dist/tools/docx/write.d.ts +17 -0
- package/dist/tools/docx/write.js +88 -0
- package/dist/tools/docx/xml-view-test.d.ts +1 -0
- package/dist/tools/docx/xml-view-test.js +63 -0
- package/dist/tools/docx/xml-view.d.ts +56 -0
- package/dist/tools/docx/xml-view.js +169 -0
- package/dist/tools/docx/zip.d.ts +21 -0
- package/dist/tools/docx/zip.js +35 -0
- package/dist/tools/edit.js +57 -27
- package/dist/tools/schemas.d.ts +13 -0
- package/dist/tools/schemas.js +6 -1
- package/dist/types.d.ts +10 -0
- package/dist/ui/contracts.d.ts +14 -0
- package/dist/ui/contracts.js +18 -0
- package/dist/ui/file-preview/index.html +16 -0
- package/dist/ui/file-preview/preview-runtime.js +13983 -0
- package/dist/ui/file-preview/shared/preview-file-types.d.ts +5 -0
- package/dist/ui/file-preview/shared/preview-file-types.js +57 -0
- package/dist/ui/file-preview/src/app.d.ts +4 -0
- package/dist/ui/file-preview/src/app.js +800 -0
- package/dist/ui/file-preview/src/components/code-viewer.d.ts +6 -0
- package/dist/ui/file-preview/src/components/code-viewer.js +73 -0
- package/dist/ui/file-preview/src/components/highlighting.d.ts +2 -0
- package/dist/ui/file-preview/src/components/highlighting.js +54 -0
- package/dist/ui/file-preview/src/components/html-renderer.d.ts +9 -0
- package/dist/ui/file-preview/src/components/html-renderer.js +63 -0
- package/dist/ui/file-preview/src/components/markdown-renderer.d.ts +1 -0
- package/dist/ui/file-preview/src/components/markdown-renderer.js +21 -0
- package/dist/ui/file-preview/src/components/toolbar.d.ts +6 -0
- package/dist/ui/file-preview/src/components/toolbar.js +75 -0
- package/dist/ui/file-preview/src/image-preview.d.ts +3 -0
- package/dist/ui/file-preview/src/image-preview.js +21 -0
- package/dist/ui/file-preview/src/main.d.ts +1 -0
- package/dist/ui/file-preview/src/main.js +5 -0
- package/dist/ui/file-preview/src/types.d.ts +1 -0
- package/dist/ui/file-preview/src/types.js +1 -0
- package/dist/ui/file-preview/styles.css +764 -0
- package/dist/ui/resources.d.ts +21 -0
- package/dist/ui/resources.js +72 -0
- package/dist/ui/shared/escape-html.d.ts +4 -0
- package/dist/ui/shared/escape-html.js +11 -0
- package/dist/ui/shared/host-lifecycle.d.ts +16 -0
- package/dist/ui/shared/host-lifecycle.js +35 -0
- package/dist/ui/shared/rpc-client.d.ts +14 -0
- package/dist/ui/shared/rpc-client.js +72 -0
- package/dist/ui/shared/theme-adaptation.d.ts +10 -0
- package/dist/ui/shared/theme-adaptation.js +118 -0
- package/dist/ui/shared/tool-header.d.ts +9 -0
- package/dist/ui/shared/tool-header.js +25 -0
- package/dist/ui/shared/tool-shell.d.ts +16 -0
- package/dist/ui/shared/tool-shell.js +65 -0
- package/dist/ui/shared/widget-state.d.ts +28 -0
- package/dist/ui/shared/widget-state.js +60 -0
- package/dist/utils/capture.d.ts +1 -0
- package/dist/utils/capture.js +176 -8
- package/dist/utils/files/base.d.ts +3 -1
- package/dist/utils/files/docx.d.ts +28 -22
- package/dist/utils/files/docx.js +630 -196
- package/dist/utils/files/factory.d.ts +6 -5
- package/dist/utils/files/factory.js +18 -6
- package/dist/utils/files/text.js +9 -1
- package/dist/utils/system-info.js +1 -1
- package/dist/utils/usageTracker.js +5 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -2
|
@@ -1,57 +1,61 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* DOCX
|
|
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
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
//
|
|
38
|
-
|
|
39
|
-
//
|
|
40
|
-
export const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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,139 @@
|
|
|
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
|
+
* Return ALL top‑level tables that are logically in the body, including those
|
|
28
|
+
* wrapped in structured document tags (w:sdt / w:sdtContent).
|
|
29
|
+
*
|
|
30
|
+
* Previous logic only saw tables that were direct children of <w:body>. That
|
|
31
|
+
* meant tables inside SDTs were invisible to table operations and readDocxOutline.
|
|
32
|
+
* This helper walks the body tree and collects any <w:tbl> that appears as a
|
|
33
|
+
* *first‑class* block (we do not recurse into tables themselves, so nested
|
|
34
|
+
* tables are not double‑counted).
|
|
35
|
+
*/
|
|
36
|
+
export declare function getAllBodyTables(body: Element): Element[];
|
|
37
|
+
/**
|
|
38
|
+
* Build a compact signature string from the body children array.
|
|
39
|
+
* Maps each node's qualified name to a short local name:
|
|
40
|
+
* w:p → p, w:tbl → tbl, w:sdt → sdt, w:sectPr → sectPr, …
|
|
41
|
+
* Returns e.g. "p,tbl,p,p,sectPr".
|
|
42
|
+
*/
|
|
43
|
+
export declare function bodySignature(children: Element[]): string;
|
|
44
|
+
/** Concatenate text from every <w:t> descendant of a paragraph. */
|
|
45
|
+
export declare function getParagraphText(p: Element): string;
|
|
46
|
+
/** Read the style id from w:pPr/w:pStyle/@w:val, or null if absent. */
|
|
47
|
+
export declare function getParagraphStyle(p: Element): string | null;
|
|
48
|
+
/**
|
|
49
|
+
* Extract all text content from a table cell (w:tc).
|
|
50
|
+
* Returns the concatenated text from all paragraphs in the cell.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getCellText(tc: Element): string;
|
|
53
|
+
/**
|
|
54
|
+
* Extract all rows from a table (w:tbl).
|
|
55
|
+
* Returns an array of rows, where each row is an array of cell text strings.
|
|
56
|
+
* First row is treated as header if it exists.
|
|
57
|
+
*/
|
|
58
|
+
export declare function getTableContent(tbl: Element): {
|
|
59
|
+
headers?: string[];
|
|
60
|
+
rows: string[][];
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Get table style from w:tblPr/w:tblStyle/@w:val, or null if absent.
|
|
64
|
+
*/
|
|
65
|
+
export declare function getTableStyle(tbl: Element): string | null;
|
|
66
|
+
/**
|
|
67
|
+
* Extract image reference from a w:drawing element.
|
|
68
|
+
* Returns the relationship ID (rId) and media file path if found.
|
|
69
|
+
*/
|
|
70
|
+
export declare function getImageReference(drawing: Element): {
|
|
71
|
+
rId: string | null;
|
|
72
|
+
mediaPath: string | null;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Replace the text of a paragraph with minimal DOM changes.
|
|
76
|
+
* Sets the FIRST w:t to `text`, clears every subsequent w:t.
|
|
77
|
+
* Sets xml:space="preserve" so leading/trailing spaces survive.
|
|
78
|
+
* Does NOT remove/recreate runs or remove paragraph properties.
|
|
79
|
+
*
|
|
80
|
+
* WARNING: This function does NOT preserve multiple runs with different styles.
|
|
81
|
+
* Use setParagraphTextPreservingStyles() for cells with multiple styled runs.
|
|
82
|
+
*/
|
|
83
|
+
export declare function setParagraphTextMinimal(p: Element, text: string): void;
|
|
84
|
+
/**
|
|
85
|
+
* Replace paragraph text while preserving all run styles.
|
|
86
|
+
*
|
|
87
|
+
* This function preserves the structure of all runs (w:r) and their
|
|
88
|
+
* properties (w:rPr), distributing the new text across existing runs.
|
|
89
|
+
*
|
|
90
|
+
* Strategy:
|
|
91
|
+
* 1. Collect all runs with their properties
|
|
92
|
+
* 2. Distribute new text across runs (preserving run count and styles)
|
|
93
|
+
* 3. If new text is longer, extend the last run
|
|
94
|
+
* 4. If new text is shorter, clear excess runs but keep their structure
|
|
95
|
+
*/
|
|
96
|
+
export declare function setParagraphTextPreservingStyles(p: Element, text: string): void;
|
|
97
|
+
/**
|
|
98
|
+
* Replace cell text while preserving ALL paragraphs and their styles.
|
|
99
|
+
*
|
|
100
|
+
* This function works at the cell level:
|
|
101
|
+
* - Preserves ALL paragraphs in the cell (doesn't remove any)
|
|
102
|
+
* - Updates text in the first paragraph while preserving its styles
|
|
103
|
+
* - Keeps all other paragraphs intact with their original text and styles
|
|
104
|
+
*
|
|
105
|
+
* This ensures that cells with multiple paragraphs (each with different
|
|
106
|
+
* styles, font sizes, etc.) maintain their structure after text replacement.
|
|
107
|
+
*
|
|
108
|
+
* Example: If a cell has:
|
|
109
|
+
* - Paragraph 1: "LAWN AND LANDSCAPE" (Heading1 style, large font, red color)
|
|
110
|
+
* - Paragraph 2: "Take your weekends back..." (Normal style, smaller font, black color)
|
|
111
|
+
*
|
|
112
|
+
* Replacing with "EARTH AND MOUNTAIN" will:
|
|
113
|
+
* - Update paragraph 1 to "EARTH AND MOUNTAIN" (preserving Heading1 style, large font, red color)
|
|
114
|
+
* - Keep paragraph 2 completely intact with its original text and style
|
|
115
|
+
*/
|
|
116
|
+
export declare function setCellTextPreservingStyles(tc: Element, text: string): void;
|
|
117
|
+
/**
|
|
118
|
+
* Ensure a <w:r> element has w:rPr/w:color[@w:val=hex].
|
|
119
|
+
* Creates w:rPr and w:color if they don't exist.
|
|
120
|
+
* Only touches the colour — leaves every other run property intact.
|
|
121
|
+
*/
|
|
122
|
+
export declare function ensureRunColor(run: Element, hex: string): void;
|
|
123
|
+
/**
|
|
124
|
+
* Apply run-level colour to every <w:r> in a paragraph.
|
|
125
|
+
*/
|
|
126
|
+
export declare function colorParagraphRuns(p: Element, color: string): void;
|
|
127
|
+
/**
|
|
128
|
+
* Apply bold / italic / color to every <w:r> in a paragraph.
|
|
129
|
+
* Preserves all existing w:rPr children; only modifies specified props.
|
|
130
|
+
*/
|
|
131
|
+
export declare function styleParagraphRuns(p: Element, style: {
|
|
132
|
+
color?: string;
|
|
133
|
+
bold?: boolean;
|
|
134
|
+
italic?: boolean;
|
|
135
|
+
}): void;
|
|
136
|
+
/** Count direct w:tbl children of body. */
|
|
137
|
+
export declare function countTables(children: Element[]): number;
|
|
138
|
+
/** Count <w:drawing> descendants (rough image count). */
|
|
139
|
+
export declare function countImages(body: Element): number;
|