@wonderwhy-er/desktop-commander 0.2.34 → 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.
- package/README.md +2 -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/server.js +30 -4
- package/dist/tools/docx/builders/html-builder.d.ts +17 -0
- package/dist/tools/docx/builders/html-builder.js +92 -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 +11 -0
- package/dist/tools/docx/builders/index.js +11 -0
- package/dist/tools/docx/builders/markdown-builder.d.ts +2 -0
- package/dist/tools/docx/builders/markdown-builder.js +260 -0
- 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 +8 -0
- package/dist/tools/docx/builders/table.js +94 -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 +32 -0
- package/dist/tools/docx/constants.js +61 -0
- package/dist/tools/docx/converters/markdown-to-html.d.ts +17 -0
- package/dist/tools/docx/converters/markdown-to-html.js +111 -0
- package/dist/tools/docx/create.d.ts +21 -0
- package/dist/tools/docx/create.js +386 -0
- package/dist/tools/docx/dom.d.ts +66 -0
- package/dist/tools/docx/dom.js +228 -0
- package/dist/tools/docx/errors.d.ts +28 -0
- package/dist/tools/docx/errors.js +48 -0
- package/dist/tools/docx/extractors/images.d.ts +14 -0
- package/dist/tools/docx/extractors/images.js +40 -0
- package/dist/tools/docx/extractors/metadata.d.ts +14 -0
- package/dist/tools/docx/extractors/metadata.js +64 -0
- package/dist/tools/docx/extractors/sections.d.ts +14 -0
- package/dist/tools/docx/extractors/sections.js +61 -0
- package/dist/tools/docx/html.d.ts +17 -0
- package/dist/tools/docx/html.js +111 -0
- package/dist/tools/docx/index.d.ts +10 -0
- package/dist/tools/docx/index.js +10 -0
- package/dist/tools/docx/markdown.d.ts +84 -0
- package/dist/tools/docx/markdown.js +507 -0
- package/dist/tools/docx/modify.d.ts +28 -0
- package/dist/tools/docx/modify.js +271 -0
- package/dist/tools/docx/operations/handlers/index.d.ts +39 -0
- package/dist/tools/docx/operations/handlers/index.js +152 -0
- package/dist/tools/docx/operations/html-manipulator.d.ts +24 -0
- package/dist/tools/docx/operations/html-manipulator.js +352 -0
- package/dist/tools/docx/operations/index.d.ts +14 -0
- package/dist/tools/docx/operations/index.js +61 -0
- package/dist/tools/docx/operations/operation-handlers.d.ts +3 -0
- package/dist/tools/docx/operations/operation-handlers.js +67 -0
- package/dist/tools/docx/operations/preprocessor.d.ts +14 -0
- package/dist/tools/docx/operations/preprocessor.js +44 -0
- package/dist/tools/docx/operations/xml-replacer.d.ts +9 -0
- package/dist/tools/docx/operations/xml-replacer.js +35 -0
- package/dist/tools/docx/operations.d.ts +13 -0
- package/dist/tools/docx/operations.js +13 -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 +67 -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 +9 -0
- package/dist/tools/docx/ops/replace-paragraph-text-exact.js +21 -0
- package/dist/tools/docx/ops/set-color-for-paragraph-exact.d.ts +8 -0
- package/dist/tools/docx/ops/set-color-for-paragraph-exact.js +23 -0
- package/dist/tools/docx/ops/set-color-for-style.d.ts +9 -0
- package/dist/tools/docx/ops/set-color-for-style.js +27 -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 +72 -0
- package/dist/tools/docx/parsers/image-extractor.d.ts +18 -0
- package/dist/tools/docx/parsers/image-extractor.js +61 -0
- package/dist/tools/docx/parsers/index.d.ts +9 -0
- package/dist/tools/docx/parsers/index.js +9 -0
- package/dist/tools/docx/parsers/paragraph-parser.d.ts +2 -0
- package/dist/tools/docx/parsers/paragraph-parser.js +88 -0
- package/dist/tools/docx/parsers/table-parser.d.ts +9 -0
- package/dist/tools/docx/parsers/table-parser.js +72 -0
- package/dist/tools/docx/parsers/xml-parser.d.ts +25 -0
- package/dist/tools/docx/parsers/xml-parser.js +71 -0
- package/dist/tools/docx/parsers/zip-reader.d.ts +23 -0
- package/dist/tools/docx/parsers/zip-reader.js +52 -0
- package/dist/tools/docx/read.d.ts +27 -0
- package/dist/tools/docx/read.js +188 -0
- package/dist/tools/docx/relationships.d.ts +22 -0
- package/dist/tools/docx/relationships.js +76 -0
- package/dist/tools/docx/structure.d.ts +25 -0
- package/dist/tools/docx/structure.js +102 -0
- package/dist/tools/docx/styled-html-parser.d.ts +23 -0
- package/dist/tools/docx/styled-html-parser.js +1262 -0
- package/dist/tools/docx/types.d.ts +184 -0
- package/dist/tools/docx/types.js +5 -0
- package/dist/tools/docx/utils/escaping.d.ts +13 -0
- package/dist/tools/docx/utils/escaping.js +26 -0
- package/dist/tools/docx/utils/images.d.ts +9 -0
- package/dist/tools/docx/utils/images.js +26 -0
- package/dist/tools/docx/utils/index.d.ts +12 -0
- package/dist/tools/docx/utils/index.js +17 -0
- package/dist/tools/docx/utils/markdown.d.ts +13 -0
- package/dist/tools/docx/utils/markdown.js +32 -0
- package/dist/tools/docx/utils/paths.d.ts +15 -0
- package/dist/tools/docx/utils/paths.js +27 -0
- package/dist/tools/docx/utils/versioning.d.ts +25 -0
- package/dist/tools/docx/utils/versioning.js +55 -0
- package/dist/tools/docx/utils.d.ts +101 -0
- package/dist/tools/docx/utils.js +299 -0
- package/dist/tools/docx/validate.d.ts +33 -0
- package/dist/tools/docx/validate.js +49 -0
- package/dist/tools/docx/validators.d.ts +13 -0
- package/dist/tools/docx/validators.js +40 -0
- package/dist/tools/docx/write.d.ts +17 -0
- package/dist/tools/docx/write.js +88 -0
- package/dist/tools/docx/zip.d.ts +21 -0
- package/dist/tools/docx/zip.js +35 -0
- package/dist/tools/schemas.d.ts +13 -0
- package/dist/tools/schemas.js +5 -0
- 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 +13977 -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 +10 -4
- package/dist/utils/files/docx.d.ts +34 -0
- package/dist/utils/files/docx.js +145 -0
- package/dist/utils/files/text.js +9 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
import * as docx from 'docx';
|
|
5
|
+
const { AlignmentType, Document, HeadingLevel, Paragraph, Table, TableCell, TableRow, TextRun, WidthType, Packer, } = docx;
|
|
6
|
+
import { DocxErrorCode, withErrorContext } from '../errors.js';
|
|
7
|
+
import { normalizeLineEndings, prepareImageForDocx, createImageRun, } from '../utils.js';
|
|
8
|
+
export async function createDocxFromMarkdown(markdown, options = {}) {
|
|
9
|
+
return withErrorContext(async () => {
|
|
10
|
+
const children = [];
|
|
11
|
+
const baseDir = options.baseDir;
|
|
12
|
+
const lines = normalizeLineEndings(markdown).split('\n');
|
|
13
|
+
let i = 0;
|
|
14
|
+
while (i < lines.length) {
|
|
15
|
+
const rawLine = lines[i];
|
|
16
|
+
const line = rawLine.trimEnd();
|
|
17
|
+
// Skip empty lines
|
|
18
|
+
if (!line.trim()) {
|
|
19
|
+
i++;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
// 1) Markdown table detection
|
|
23
|
+
const isHeader = isTableHeaderLine(line);
|
|
24
|
+
const hasSeparator = i + 1 < lines.length && isTableSeparatorLine(lines[i + 1]);
|
|
25
|
+
if (isHeader && hasSeparator) {
|
|
26
|
+
const tableLines = [line];
|
|
27
|
+
i++;
|
|
28
|
+
tableLines.push(lines[i]); // Add separator line
|
|
29
|
+
i++;
|
|
30
|
+
// Collect all subsequent table rows
|
|
31
|
+
while (i < lines.length) {
|
|
32
|
+
const nextLine = lines[i].trim();
|
|
33
|
+
if (!nextLine || !isTableRowLine(nextLine)) {
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
tableLines.push(nextLine);
|
|
37
|
+
i++;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const table = createTableFromMarkdown(tableLines);
|
|
41
|
+
children.push(table);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error('[DOCX Build] Failed to create table:', error);
|
|
45
|
+
// Fallback: add table lines as plain text
|
|
46
|
+
for (const tableLine of tableLines) {
|
|
47
|
+
children.push(new Paragraph({ text: tableLine }));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
// 2) Images
|
|
53
|
+
const imageMatch = line.match(/!\[([^\]]*)\]\(([^)]+)\)/);
|
|
54
|
+
if (imageMatch) {
|
|
55
|
+
const altText = imageMatch[1] || '';
|
|
56
|
+
const src = imageMatch[2];
|
|
57
|
+
try {
|
|
58
|
+
const imageData = await prepareImageForDocx(src, altText, baseDir);
|
|
59
|
+
const imageRun = createImageRun(imageData);
|
|
60
|
+
const paragraph = new Paragraph({
|
|
61
|
+
children: [imageRun],
|
|
62
|
+
alignment: AlignmentType.CENTER,
|
|
63
|
+
});
|
|
64
|
+
children.push(paragraph);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
console.warn(`Failed to embed image ${src}:`, error);
|
|
68
|
+
children.push(new Paragraph({
|
|
69
|
+
text: `[Image: ${altText || src}]`,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
i++;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
// 3) Headings
|
|
76
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
77
|
+
if (headingMatch) {
|
|
78
|
+
const level = headingMatch[1].length;
|
|
79
|
+
const text = headingMatch[2].trim();
|
|
80
|
+
const textRuns = parseInlineFormatting(text);
|
|
81
|
+
const heading = new Paragraph({
|
|
82
|
+
children: textRuns,
|
|
83
|
+
heading: getHeadingLevel(level),
|
|
84
|
+
});
|
|
85
|
+
children.push(heading);
|
|
86
|
+
i++;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
// 4) Regular paragraphs
|
|
90
|
+
const textRuns = parseInlineFormatting(rawLine);
|
|
91
|
+
const paragraph = new Paragraph({
|
|
92
|
+
children: textRuns,
|
|
93
|
+
});
|
|
94
|
+
children.push(paragraph);
|
|
95
|
+
i++;
|
|
96
|
+
}
|
|
97
|
+
const doc = new Document({
|
|
98
|
+
sections: [{
|
|
99
|
+
properties: {},
|
|
100
|
+
children: children,
|
|
101
|
+
}],
|
|
102
|
+
});
|
|
103
|
+
return await Packer.toBuffer(doc);
|
|
104
|
+
}, DocxErrorCode.DOCX_CREATE_FAILED, { markdownLength: markdown.length });
|
|
105
|
+
}
|
|
106
|
+
// ============================================================================
|
|
107
|
+
// Helper Functions
|
|
108
|
+
// ============================================================================
|
|
109
|
+
function isTableHeaderLine(line) {
|
|
110
|
+
const trimmed = line.trim();
|
|
111
|
+
if (!trimmed.includes('|'))
|
|
112
|
+
return false;
|
|
113
|
+
const startsWithPipe = trimmed.startsWith('|');
|
|
114
|
+
const endsWithPipe = trimmed.endsWith('|');
|
|
115
|
+
const pipeCount = (trimmed.match(/\|/g) || []).length;
|
|
116
|
+
if (startsWithPipe && endsWithPipe) {
|
|
117
|
+
return pipeCount >= 2;
|
|
118
|
+
}
|
|
119
|
+
return pipeCount >= 1;
|
|
120
|
+
}
|
|
121
|
+
function isTableSeparatorLine(line) {
|
|
122
|
+
const trimmed = line.trim();
|
|
123
|
+
if (!trimmed.includes('|'))
|
|
124
|
+
return false;
|
|
125
|
+
let content = trimmed;
|
|
126
|
+
if (content.startsWith('|'))
|
|
127
|
+
content = content.substring(1);
|
|
128
|
+
if (content.endsWith('|'))
|
|
129
|
+
content = content.substring(0, content.length - 1);
|
|
130
|
+
const parts = content.split('|');
|
|
131
|
+
let validParts = 0;
|
|
132
|
+
for (const part of parts) {
|
|
133
|
+
const cleaned = part.trim();
|
|
134
|
+
if (cleaned.length === 0)
|
|
135
|
+
continue;
|
|
136
|
+
if (/^:?-+:?$/.test(cleaned)) {
|
|
137
|
+
validParts++;
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return validParts > 0;
|
|
144
|
+
}
|
|
145
|
+
function isTableRowLine(line) {
|
|
146
|
+
const trimmed = line.trim();
|
|
147
|
+
if (!trimmed.includes('|'))
|
|
148
|
+
return false;
|
|
149
|
+
if (isTableSeparatorLine(trimmed))
|
|
150
|
+
return false;
|
|
151
|
+
const pipeCount = (trimmed.match(/\|/g) || []).length;
|
|
152
|
+
return pipeCount >= 1;
|
|
153
|
+
}
|
|
154
|
+
function splitTableRow(line) {
|
|
155
|
+
const trimmed = line.trim();
|
|
156
|
+
let withoutBorders = trimmed;
|
|
157
|
+
if (withoutBorders.startsWith('|')) {
|
|
158
|
+
withoutBorders = withoutBorders.substring(1);
|
|
159
|
+
}
|
|
160
|
+
if (withoutBorders.endsWith('|')) {
|
|
161
|
+
withoutBorders = withoutBorders.substring(0, withoutBorders.length - 1);
|
|
162
|
+
}
|
|
163
|
+
return withoutBorders.split('|').map(cell => cell.trim());
|
|
164
|
+
}
|
|
165
|
+
function createTableFromMarkdown(lines) {
|
|
166
|
+
if (lines.length < 2) {
|
|
167
|
+
return new Table({ rows: [] });
|
|
168
|
+
}
|
|
169
|
+
const headerCells = splitTableRow(lines[0]);
|
|
170
|
+
const rows = [];
|
|
171
|
+
// Header row
|
|
172
|
+
rows.push(new TableRow({
|
|
173
|
+
children: headerCells.map((cell) => {
|
|
174
|
+
const textRuns = parseInlineFormatting(cell.trim());
|
|
175
|
+
textRuns.forEach(run => {
|
|
176
|
+
run.bold = true;
|
|
177
|
+
});
|
|
178
|
+
return new TableCell({
|
|
179
|
+
children: [
|
|
180
|
+
new Paragraph({
|
|
181
|
+
children: textRuns,
|
|
182
|
+
alignment: AlignmentType.CENTER,
|
|
183
|
+
}),
|
|
184
|
+
],
|
|
185
|
+
});
|
|
186
|
+
}),
|
|
187
|
+
}));
|
|
188
|
+
// Data rows (skip separator at index 1)
|
|
189
|
+
for (let i = 2; i < lines.length; i++) {
|
|
190
|
+
const cells = splitTableRow(lines[i]);
|
|
191
|
+
rows.push(new TableRow({
|
|
192
|
+
children: cells.map((cell) => {
|
|
193
|
+
const textRuns = parseInlineFormatting(cell.trim());
|
|
194
|
+
return new TableCell({
|
|
195
|
+
children: [
|
|
196
|
+
new Paragraph({
|
|
197
|
+
children: textRuns,
|
|
198
|
+
}),
|
|
199
|
+
],
|
|
200
|
+
});
|
|
201
|
+
}),
|
|
202
|
+
}));
|
|
203
|
+
}
|
|
204
|
+
return new Table({
|
|
205
|
+
width: { size: 100, type: WidthType.PERCENTAGE },
|
|
206
|
+
rows,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function parseInlineFormatting(text) {
|
|
210
|
+
const runs = [];
|
|
211
|
+
let currentText = '';
|
|
212
|
+
let i = 0;
|
|
213
|
+
while (i < text.length) {
|
|
214
|
+
// Check for **bold**
|
|
215
|
+
if (text.substring(i, i + 2) === '**') {
|
|
216
|
+
if (currentText) {
|
|
217
|
+
runs.push(new TextRun({ text: currentText }));
|
|
218
|
+
currentText = '';
|
|
219
|
+
}
|
|
220
|
+
const closeIndex = text.indexOf('**', i + 2);
|
|
221
|
+
if (closeIndex !== -1) {
|
|
222
|
+
const boldText = text.substring(i + 2, closeIndex);
|
|
223
|
+
runs.push(new TextRun({ text: boldText, bold: true }));
|
|
224
|
+
i = closeIndex + 2;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Check for *italic*
|
|
229
|
+
if (text[i] === '*' && text[i + 1] !== '*') {
|
|
230
|
+
if (currentText) {
|
|
231
|
+
runs.push(new TextRun({ text: currentText }));
|
|
232
|
+
currentText = '';
|
|
233
|
+
}
|
|
234
|
+
const closeIndex = text.indexOf('*', i + 1);
|
|
235
|
+
if (closeIndex !== -1) {
|
|
236
|
+
const italicText = text.substring(i + 1, closeIndex);
|
|
237
|
+
runs.push(new TextRun({ text: italicText, italics: true }));
|
|
238
|
+
i = closeIndex + 1;
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
currentText += text[i];
|
|
243
|
+
i++;
|
|
244
|
+
}
|
|
245
|
+
if (currentText) {
|
|
246
|
+
runs.push(new TextRun({ text: currentText }));
|
|
247
|
+
}
|
|
248
|
+
return runs.length > 0 ? runs : [new TextRun({ text: text })];
|
|
249
|
+
}
|
|
250
|
+
function getHeadingLevel(level) {
|
|
251
|
+
const levelMap = {
|
|
252
|
+
1: HeadingLevel.HEADING_1,
|
|
253
|
+
2: HeadingLevel.HEADING_2,
|
|
254
|
+
3: HeadingLevel.HEADING_3,
|
|
255
|
+
4: HeadingLevel.HEADING_4,
|
|
256
|
+
5: HeadingLevel.HEADING_5,
|
|
257
|
+
6: HeadingLevel.HEADING_6,
|
|
258
|
+
};
|
|
259
|
+
return levelMap[level] ?? HeadingLevel.HEADING_1;
|
|
260
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paragraph builder — creates w:p elements with optional styles.
|
|
3
|
+
*/
|
|
4
|
+
import type { DocxContentParagraph } from '../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Build a paragraph element from content structure.
|
|
7
|
+
*
|
|
8
|
+
* @param doc The XML document
|
|
9
|
+
* @param item The paragraph content item
|
|
10
|
+
* @returns A w:p element
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildParagraph(doc: Document, item: DocxContentParagraph): Element;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paragraph builder — creates w:p elements with optional styles.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Build a paragraph element from content structure.
|
|
6
|
+
*
|
|
7
|
+
* @param doc The XML document
|
|
8
|
+
* @param item The paragraph content item
|
|
9
|
+
* @returns A w:p element
|
|
10
|
+
*/
|
|
11
|
+
export function buildParagraph(doc, item) {
|
|
12
|
+
const p = doc.createElement('w:p');
|
|
13
|
+
// Set style if provided
|
|
14
|
+
if (item.style) {
|
|
15
|
+
const pPr = doc.createElement('w:pPr');
|
|
16
|
+
const pStyle = doc.createElement('w:pStyle');
|
|
17
|
+
pStyle.setAttribute('w:val', item.style);
|
|
18
|
+
pPr.appendChild(pStyle);
|
|
19
|
+
p.appendChild(pPr);
|
|
20
|
+
}
|
|
21
|
+
// Add text run
|
|
22
|
+
const r = doc.createElement('w:r');
|
|
23
|
+
const t = doc.createElement('w:t');
|
|
24
|
+
t.setAttribute('xml:space', 'preserve');
|
|
25
|
+
t.textContent = item.text;
|
|
26
|
+
r.appendChild(t);
|
|
27
|
+
p.appendChild(r);
|
|
28
|
+
return p;
|
|
29
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table builder — creates w:tbl elements with headers, rows, and styling.
|
|
3
|
+
*/
|
|
4
|
+
import type { DocxContentTable, InsertTableOp } from '../types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Build a table element from content structure or operation.
|
|
7
|
+
*/
|
|
8
|
+
export declare function buildTable(doc: Document, spec: DocxContentTable | InsertTableOp): Element;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table builder — creates w:tbl elements with headers, rows, and styling.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Build a table element from content structure or operation.
|
|
6
|
+
*/
|
|
7
|
+
export function buildTable(doc, spec) {
|
|
8
|
+
const tbl = doc.createElement('w:tbl');
|
|
9
|
+
// Table properties
|
|
10
|
+
const tblPr = doc.createElement('w:tblPr');
|
|
11
|
+
if (spec.style) {
|
|
12
|
+
const tblStyle = doc.createElement('w:tblStyle');
|
|
13
|
+
tblStyle.setAttribute('w:val', spec.style);
|
|
14
|
+
tblPr.appendChild(tblStyle);
|
|
15
|
+
}
|
|
16
|
+
const tblW = doc.createElement('w:tblW');
|
|
17
|
+
tblW.setAttribute('w:w', '0');
|
|
18
|
+
tblW.setAttribute('w:type', 'auto');
|
|
19
|
+
tblPr.appendChild(tblW);
|
|
20
|
+
// Table borders
|
|
21
|
+
const tblBorders = doc.createElement('w:tblBorders');
|
|
22
|
+
for (const side of ['top', 'left', 'bottom', 'right', 'insideH', 'insideV']) {
|
|
23
|
+
const border = doc.createElement(`w:${side}`);
|
|
24
|
+
border.setAttribute('w:val', 'single');
|
|
25
|
+
border.setAttribute('w:sz', '4');
|
|
26
|
+
border.setAttribute('w:space', '0');
|
|
27
|
+
border.setAttribute('w:color', '000000');
|
|
28
|
+
tblBorders.appendChild(border);
|
|
29
|
+
}
|
|
30
|
+
tblPr.appendChild(tblBorders);
|
|
31
|
+
tbl.appendChild(tblPr);
|
|
32
|
+
// Table grid
|
|
33
|
+
const colCount = spec.headers
|
|
34
|
+
? spec.headers.length
|
|
35
|
+
: spec.rows.length > 0
|
|
36
|
+
? spec.rows[0].length
|
|
37
|
+
: 0;
|
|
38
|
+
if (colCount > 0) {
|
|
39
|
+
const tblGrid = doc.createElement('w:tblGrid');
|
|
40
|
+
for (let c = 0; c < colCount; c++) {
|
|
41
|
+
const gridCol = doc.createElement('w:gridCol');
|
|
42
|
+
const w = spec.colWidths?.[c] ?? Math.floor(9000 / colCount);
|
|
43
|
+
gridCol.setAttribute('w:w', String(w));
|
|
44
|
+
tblGrid.appendChild(gridCol);
|
|
45
|
+
}
|
|
46
|
+
tbl.appendChild(tblGrid);
|
|
47
|
+
}
|
|
48
|
+
// Helper to build a cell
|
|
49
|
+
const buildCell = (text, isHeader, widthTwips) => {
|
|
50
|
+
const tc = doc.createElement('w:tc');
|
|
51
|
+
if (widthTwips) {
|
|
52
|
+
const tcPr = doc.createElement('w:tcPr');
|
|
53
|
+
const tcW = doc.createElement('w:tcW');
|
|
54
|
+
tcW.setAttribute('w:w', String(widthTwips));
|
|
55
|
+
tcW.setAttribute('w:type', 'dxa');
|
|
56
|
+
tcPr.appendChild(tcW);
|
|
57
|
+
tc.appendChild(tcPr);
|
|
58
|
+
}
|
|
59
|
+
const p = doc.createElement('w:p');
|
|
60
|
+
const r = doc.createElement('w:r');
|
|
61
|
+
if (isHeader) {
|
|
62
|
+
const rPr = doc.createElement('w:rPr');
|
|
63
|
+
const b = doc.createElement('w:b');
|
|
64
|
+
rPr.appendChild(b);
|
|
65
|
+
r.appendChild(rPr);
|
|
66
|
+
}
|
|
67
|
+
const t = doc.createElement('w:t');
|
|
68
|
+
t.setAttribute('xml:space', 'preserve');
|
|
69
|
+
t.textContent = text;
|
|
70
|
+
r.appendChild(t);
|
|
71
|
+
p.appendChild(r);
|
|
72
|
+
tc.appendChild(p);
|
|
73
|
+
return tc;
|
|
74
|
+
};
|
|
75
|
+
// Header row
|
|
76
|
+
if (spec.headers && spec.headers.length > 0) {
|
|
77
|
+
const tr = doc.createElement('w:tr');
|
|
78
|
+
for (let i = 0; i < spec.headers.length; i++) {
|
|
79
|
+
const width = spec.colWidths?.[i];
|
|
80
|
+
tr.appendChild(buildCell(spec.headers[i], true, width));
|
|
81
|
+
}
|
|
82
|
+
tbl.appendChild(tr);
|
|
83
|
+
}
|
|
84
|
+
// Data rows
|
|
85
|
+
for (const row of spec.rows) {
|
|
86
|
+
const tr = doc.createElement('w:tr');
|
|
87
|
+
for (let i = 0; i < row.length; i++) {
|
|
88
|
+
const width = spec.colWidths?.[i];
|
|
89
|
+
tr.appendChild(buildCell(row[i], false, width));
|
|
90
|
+
}
|
|
91
|
+
tbl.appendChild(tr);
|
|
92
|
+
}
|
|
93
|
+
return tbl;
|
|
94
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XML escaping utilities.
|
|
3
|
+
*/
|
|
4
|
+
export function escapeXml(s) {
|
|
5
|
+
return s
|
|
6
|
+
.replace(/&/g, '&')
|
|
7
|
+
.replace(/</g, '<')
|
|
8
|
+
.replace(/>/g, '>')
|
|
9
|
+
.replace(/"/g, '"')
|
|
10
|
+
.replace(/'/g, ''');
|
|
11
|
+
}
|
|
12
|
+
export function escapeXmlAttr(s) {
|
|
13
|
+
return s
|
|
14
|
+
.replace(/&/g, '&')
|
|
15
|
+
.replace(/"/g, '"')
|
|
16
|
+
.replace(/</g, '<')
|
|
17
|
+
.replace(/>/g, '>');
|
|
18
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOCX constants — shared values used across the module.
|
|
3
|
+
*/
|
|
4
|
+
export declare const IMAGE_MIME_TYPES: Record<string, string>;
|
|
5
|
+
export declare function getMimeType(ext: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Convert pixels to EMU (English Metric Units).
|
|
8
|
+
* 1 inch = 914400 EMU, 1 px ≈ 9525 EMU (at 96 DPI)
|
|
9
|
+
*/
|
|
10
|
+
export declare const PX_TO_EMU = 9525;
|
|
11
|
+
export declare function pixelsToEmu(px: number): number;
|
|
12
|
+
export declare const NAMESPACES: {
|
|
13
|
+
readonly W: "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
|
|
14
|
+
readonly WP: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
|
|
15
|
+
readonly A: "http://schemas.openxmlformats.org/drawingml/2006/main";
|
|
16
|
+
readonly PIC: "http://schemas.openxmlformats.org/drawingml/2006/picture";
|
|
17
|
+
readonly R: "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
18
|
+
readonly RELS: "http://schemas.openxmlformats.org/package/2006/relationships";
|
|
19
|
+
};
|
|
20
|
+
export declare const DEFAULT_IMAGE_WIDTH = 300;
|
|
21
|
+
export declare const DEFAULT_IMAGE_HEIGHT = 200;
|
|
22
|
+
export declare const DOCX_PATHS: {
|
|
23
|
+
readonly CONTENT_TYPES: "[Content_Types].xml";
|
|
24
|
+
readonly DOCUMENT_XML: "word/document.xml";
|
|
25
|
+
readonly DOCUMENT_RELS: "word/_rels/document.xml.rels";
|
|
26
|
+
readonly ROOT_RELS: "_rels/.rels";
|
|
27
|
+
readonly STYLES_XML: "word/styles.xml";
|
|
28
|
+
readonly SETTINGS_XML: "word/settings.xml";
|
|
29
|
+
readonly WEB_SETTINGS_XML: "word/webSettings.xml";
|
|
30
|
+
readonly FONT_TABLE_XML: "word/fontTable.xml";
|
|
31
|
+
readonly MEDIA_FOLDER: "word/media";
|
|
32
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOCX constants — shared values used across the module.
|
|
3
|
+
*/
|
|
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',
|
|
17
|
+
};
|
|
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',
|
|
42
|
+
};
|
|
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',
|
|
61
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown → HTML Converter
|
|
3
|
+
*
|
|
4
|
+
* Provides markdown-to-HTML conversion for DOCX content operations
|
|
5
|
+
* (appendMarkdown, insertTable with markdown input, etc.).
|
|
6
|
+
*
|
|
7
|
+
* @module docx/converters/markdown-to-html
|
|
8
|
+
*/
|
|
9
|
+
/** Convert basic markdown text to HTML. */
|
|
10
|
+
export declare function markdownToHtml(markdown: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Convert a markdown table to an HTML `<table>` with inline CSS borders.
|
|
13
|
+
* html-to-docx needs explicit border styles — without them, tables are invisible in Word.
|
|
14
|
+
*/
|
|
15
|
+
export declare function markdownTableToHtml(markdown: string): string;
|
|
16
|
+
/** Build a markdown table string from a 2-D rows array (first row = header). */
|
|
17
|
+
export declare function buildMarkdownTableFromRows(rows: string[][]): string;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown → HTML Converter
|
|
3
|
+
*
|
|
4
|
+
* Provides markdown-to-HTML conversion for DOCX content operations
|
|
5
|
+
* (appendMarkdown, insertTable with markdown input, etc.).
|
|
6
|
+
*
|
|
7
|
+
* @module docx/converters/markdown-to-html
|
|
8
|
+
*/
|
|
9
|
+
import { escapeHtml } from '../utils/escaping.js';
|
|
10
|
+
// ─── Markdown → HTML ─────────────────────────────────────────────────────────
|
|
11
|
+
/** Convert basic markdown text to HTML. */
|
|
12
|
+
export function markdownToHtml(markdown) {
|
|
13
|
+
if (!markdown?.trim())
|
|
14
|
+
return '';
|
|
15
|
+
let html = markdown.trim();
|
|
16
|
+
// Headings (h6 → h1 to avoid partial matches)
|
|
17
|
+
html = html.replace(/^######\s+(.+)$/gm, '<h6>$1</h6>');
|
|
18
|
+
html = html.replace(/^#####\s+(.+)$/gm, '<h5>$1</h5>');
|
|
19
|
+
html = html.replace(/^####\s+(.+)$/gm, '<h4>$1</h4>');
|
|
20
|
+
html = html.replace(/^###\s+(.+)$/gm, '<h3>$1</h3>');
|
|
21
|
+
html = html.replace(/^##\s+(.+)$/gm, '<h2>$1</h2>');
|
|
22
|
+
html = html.replace(/^#\s+(.+)$/gm, '<h1>$1</h1>');
|
|
23
|
+
// Bold (before italic to avoid conflicts)
|
|
24
|
+
html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
|
|
25
|
+
html = html.replace(/__(.+?)__/g, '<strong>$1</strong>');
|
|
26
|
+
// Italic
|
|
27
|
+
html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
|
|
28
|
+
html = html.replace(/_(.+?)_/g, '<em>$1</em>');
|
|
29
|
+
// Images & links
|
|
30
|
+
html = html.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, '<img src="$2" alt="$1" />');
|
|
31
|
+
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
|
|
32
|
+
// Inline code
|
|
33
|
+
html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
34
|
+
// Paragraphs (double-newline separated)
|
|
35
|
+
return html
|
|
36
|
+
.split(/\n\n+/)
|
|
37
|
+
.map((p) => p.trim())
|
|
38
|
+
.filter(Boolean)
|
|
39
|
+
.map((p) => {
|
|
40
|
+
// Don't wrap blocks that are already complete HTML elements
|
|
41
|
+
if (p.startsWith('<') && p.endsWith('>'))
|
|
42
|
+
return p.replace(/\n/g, '<br>');
|
|
43
|
+
return `<p>${p.replace(/\n/g, '<br>')}</p>`;
|
|
44
|
+
})
|
|
45
|
+
.join('\n');
|
|
46
|
+
}
|
|
47
|
+
// ─── Markdown Table → HTML ───────────────────────────────────────────────────
|
|
48
|
+
/** Parse a single markdown table row into cell values. */
|
|
49
|
+
function parseTableRow(row) {
|
|
50
|
+
return row.replace(/^\|/, '').replace(/\|$/, '').split('|').map((c) => c.trim());
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Convert a markdown table to an HTML `<table>` with inline CSS borders.
|
|
54
|
+
* html-to-docx needs explicit border styles — without them, tables are invisible in Word.
|
|
55
|
+
*/
|
|
56
|
+
export function markdownTableToHtml(markdown) {
|
|
57
|
+
if (!markdown?.trim())
|
|
58
|
+
return '';
|
|
59
|
+
const lines = markdown
|
|
60
|
+
.trim()
|
|
61
|
+
.split('\n')
|
|
62
|
+
.map((l) => l.trim())
|
|
63
|
+
.filter(Boolean);
|
|
64
|
+
if (lines.length < 2)
|
|
65
|
+
return '';
|
|
66
|
+
const headerCells = parseTableRow(lines[0]);
|
|
67
|
+
if (headerCells.length === 0)
|
|
68
|
+
return '';
|
|
69
|
+
const dataRows = lines.slice(2).map(parseTableRow);
|
|
70
|
+
const BORDER = 'border:1px solid #000;';
|
|
71
|
+
const CELL = `${BORDER} padding:6px 10px;`;
|
|
72
|
+
const HEADER = `${CELL} background-color:#f2f2f2; font-weight:bold;`;
|
|
73
|
+
let html = `<table style="border-collapse:collapse; width:100%; ${BORDER}">\n`;
|
|
74
|
+
html += ' <thead>\n <tr>\n';
|
|
75
|
+
for (const cell of headerCells) {
|
|
76
|
+
html += ` <th style="${HEADER}">${escapeHtml(cell)}</th>\n`;
|
|
77
|
+
}
|
|
78
|
+
html += ' </tr>\n </thead>\n';
|
|
79
|
+
if (dataRows.length > 0) {
|
|
80
|
+
html += ' <tbody>\n';
|
|
81
|
+
for (const row of dataRows) {
|
|
82
|
+
html += ' <tr>\n';
|
|
83
|
+
for (const cell of row) {
|
|
84
|
+
html += ` <td style="${CELL}">${escapeHtml(cell)}</td>\n`;
|
|
85
|
+
}
|
|
86
|
+
html += ' </tr>\n';
|
|
87
|
+
}
|
|
88
|
+
html += ' </tbody>\n';
|
|
89
|
+
}
|
|
90
|
+
return html + '</table>';
|
|
91
|
+
}
|
|
92
|
+
// ─── Rows Array → Markdown Table ─────────────────────────────────────────────
|
|
93
|
+
/** Build a markdown table string from a 2-D rows array (first row = header). */
|
|
94
|
+
export function buildMarkdownTableFromRows(rows) {
|
|
95
|
+
if (!rows?.length)
|
|
96
|
+
return '';
|
|
97
|
+
const header = rows[0];
|
|
98
|
+
if (!header?.length)
|
|
99
|
+
return '';
|
|
100
|
+
const lines = [
|
|
101
|
+
`| ${header.join(' | ')} |`,
|
|
102
|
+
`| ${header.map(() => '---').join(' | ')} |`,
|
|
103
|
+
];
|
|
104
|
+
for (const row of rows.slice(1)) {
|
|
105
|
+
const padded = [...row];
|
|
106
|
+
while (padded.length < header.length)
|
|
107
|
+
padded.push('');
|
|
108
|
+
lines.push(`| ${padded.slice(0, header.length).join(' | ')} |`);
|
|
109
|
+
}
|
|
110
|
+
return lines.join('\n');
|
|
111
|
+
}
|