@wonderwhy-er/desktop-commander 0.2.34 → 0.2.35

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 (78) hide show
  1. package/dist/tools/docx/builders/html-builder.d.ts +17 -0
  2. package/dist/tools/docx/builders/html-builder.js +92 -0
  3. package/dist/tools/docx/builders/index.d.ts +5 -0
  4. package/dist/tools/docx/builders/index.js +5 -0
  5. package/dist/tools/docx/builders/markdown-builder.d.ts +2 -0
  6. package/dist/tools/docx/builders/markdown-builder.js +260 -0
  7. package/dist/tools/docx/constants.d.ts +36 -0
  8. package/dist/tools/docx/constants.js +57 -0
  9. package/dist/tools/docx/converters/markdown-to-html.d.ts +17 -0
  10. package/dist/tools/docx/converters/markdown-to-html.js +111 -0
  11. package/dist/tools/docx/errors.d.ts +28 -0
  12. package/dist/tools/docx/errors.js +48 -0
  13. package/dist/tools/docx/extractors/images.d.ts +14 -0
  14. package/dist/tools/docx/extractors/images.js +40 -0
  15. package/dist/tools/docx/extractors/metadata.d.ts +14 -0
  16. package/dist/tools/docx/extractors/metadata.js +64 -0
  17. package/dist/tools/docx/extractors/sections.d.ts +14 -0
  18. package/dist/tools/docx/extractors/sections.js +61 -0
  19. package/dist/tools/docx/html.d.ts +17 -0
  20. package/dist/tools/docx/html.js +111 -0
  21. package/dist/tools/docx/index.d.ts +14 -0
  22. package/dist/tools/docx/index.js +16 -0
  23. package/dist/tools/docx/markdown.d.ts +84 -0
  24. package/dist/tools/docx/markdown.js +507 -0
  25. package/dist/tools/docx/operations/handlers/index.d.ts +39 -0
  26. package/dist/tools/docx/operations/handlers/index.js +152 -0
  27. package/dist/tools/docx/operations/html-manipulator.d.ts +24 -0
  28. package/dist/tools/docx/operations/html-manipulator.js +352 -0
  29. package/dist/tools/docx/operations/index.d.ts +14 -0
  30. package/dist/tools/docx/operations/index.js +61 -0
  31. package/dist/tools/docx/operations/operation-handlers.d.ts +3 -0
  32. package/dist/tools/docx/operations/operation-handlers.js +67 -0
  33. package/dist/tools/docx/operations/preprocessor.d.ts +14 -0
  34. package/dist/tools/docx/operations/preprocessor.js +44 -0
  35. package/dist/tools/docx/operations/xml-replacer.d.ts +9 -0
  36. package/dist/tools/docx/operations/xml-replacer.js +35 -0
  37. package/dist/tools/docx/operations.d.ts +13 -0
  38. package/dist/tools/docx/operations.js +13 -0
  39. package/dist/tools/docx/parsers/image-extractor.d.ts +18 -0
  40. package/dist/tools/docx/parsers/image-extractor.js +61 -0
  41. package/dist/tools/docx/parsers/index.d.ts +9 -0
  42. package/dist/tools/docx/parsers/index.js +9 -0
  43. package/dist/tools/docx/parsers/paragraph-parser.d.ts +2 -0
  44. package/dist/tools/docx/parsers/paragraph-parser.js +88 -0
  45. package/dist/tools/docx/parsers/table-parser.d.ts +9 -0
  46. package/dist/tools/docx/parsers/table-parser.js +72 -0
  47. package/dist/tools/docx/parsers/xml-parser.d.ts +25 -0
  48. package/dist/tools/docx/parsers/xml-parser.js +71 -0
  49. package/dist/tools/docx/parsers/zip-reader.d.ts +23 -0
  50. package/dist/tools/docx/parsers/zip-reader.js +52 -0
  51. package/dist/tools/docx/structure.d.ts +25 -0
  52. package/dist/tools/docx/structure.js +102 -0
  53. package/dist/tools/docx/styled-html-parser.d.ts +23 -0
  54. package/dist/tools/docx/styled-html-parser.js +1262 -0
  55. package/dist/tools/docx/types.d.ts +114 -0
  56. package/dist/tools/docx/types.js +8 -0
  57. package/dist/tools/docx/utils/escaping.d.ts +13 -0
  58. package/dist/tools/docx/utils/escaping.js +26 -0
  59. package/dist/tools/docx/utils/images.d.ts +9 -0
  60. package/dist/tools/docx/utils/images.js +26 -0
  61. package/dist/tools/docx/utils/index.d.ts +12 -0
  62. package/dist/tools/docx/utils/index.js +17 -0
  63. package/dist/tools/docx/utils/markdown.d.ts +13 -0
  64. package/dist/tools/docx/utils/markdown.js +32 -0
  65. package/dist/tools/docx/utils/paths.d.ts +15 -0
  66. package/dist/tools/docx/utils/paths.js +27 -0
  67. package/dist/tools/docx/utils/versioning.d.ts +25 -0
  68. package/dist/tools/docx/utils/versioning.js +55 -0
  69. package/dist/tools/docx/utils.d.ts +101 -0
  70. package/dist/tools/docx/utils.js +299 -0
  71. package/dist/tools/docx/validators.d.ts +13 -0
  72. package/dist/tools/docx/validators.js +40 -0
  73. package/dist/utils/capture.js +4 -4
  74. package/dist/utils/files/docx.d.ts +41 -0
  75. package/dist/utils/files/docx.js +245 -0
  76. package/dist/version.d.ts +1 -1
  77. package/dist/version.js +1 -1
  78. package/package.json +1 -1
@@ -0,0 +1,17 @@
1
+ /**
2
+ * HTML → DOCX Conversion (html-to-docx)
3
+ *
4
+ * Converts processed HTML content into a DOCX buffer, injecting the original
5
+ * document's default font and font size so unstyled text keeps its appearance.
6
+ *
7
+ * @module docx/builders/html-builder
8
+ */
9
+ import type { DocxBuildOptions } from '../types.js';
10
+ /**
11
+ * Create a DOCX Buffer from HTML content.
12
+ *
13
+ * @param html - HTML content to convert
14
+ * @param options - Build options (baseDir, documentDefaults, etc.)
15
+ * @returns DOCX file as a Buffer
16
+ */
17
+ export declare function createDocxFromHtml(html: string, options?: DocxBuildOptions): Promise<Buffer>;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * HTML → DOCX Conversion (html-to-docx)
3
+ *
4
+ * Converts processed HTML content into a DOCX buffer, injecting the original
5
+ * document's default font and font size so unstyled text keeps its appearance.
6
+ *
7
+ * @module docx/builders/html-builder
8
+ */
9
+ import { createRequire } from 'module';
10
+ import { DocxError, DocxErrorCode, withErrorContext } from '../errors.js';
11
+ import { DEFAULT_BUILD_OPTIONS, HTML_WRAPPER_TEMPLATE } from '../constants.js';
12
+ const require = createRequire(import.meta.url);
13
+ const HTMLtoDOCX = require('html-to-docx');
14
+ // ─── HTML Structure Helpers ──────────────────────────────────────────────────
15
+ /** Build a `<style>` tag with the original document's default font/size as CSS `body` rules. */
16
+ function buildDefaultStyleTag(defaults) {
17
+ if (!defaults)
18
+ return '';
19
+ const rules = [];
20
+ if (defaults.font)
21
+ rules.push(`font-family: '${defaults.font}'`);
22
+ if (defaults.fontSize)
23
+ rules.push(`font-size: ${defaults.fontSize}pt`);
24
+ if (rules.length === 0)
25
+ return '';
26
+ return `<style>body { ${rules.join('; ')}; }</style>`;
27
+ }
28
+ /**
29
+ * Ensure the HTML has a proper structure (DOCTYPE, `<html>`, `<head>`, `<body>`).
30
+ * Injects the document-default CSS into `<head>` when available.
31
+ */
32
+ function ensureHtmlStructure(html, defaults) {
33
+ const trimmed = html.trim();
34
+ const styleTag = buildDefaultStyleTag(defaults);
35
+ if (!trimmed) {
36
+ const wrapped = HTML_WRAPPER_TEMPLATE.split('{content}').join('');
37
+ return styleTag ? wrapped.replace('</head>', `${styleTag}\n</head>`) : wrapped;
38
+ }
39
+ const lower = trimmed.toLowerCase();
40
+ const hasDoctype = lower.startsWith('<!doctype');
41
+ const hasHtml = lower.includes('<html');
42
+ const hasBody = lower.includes('<body');
43
+ // Already complete — inject styles only
44
+ if (hasDoctype && hasHtml && hasBody) {
45
+ if (styleTag && trimmed.includes('</head>')) {
46
+ return trimmed.replace('</head>', `${styleTag}\n</head>`);
47
+ }
48
+ return trimmed;
49
+ }
50
+ // Partial structure — add DOCTYPE, inject styles
51
+ if (hasHtml || hasBody) {
52
+ const result = `<!DOCTYPE html>\n${trimmed}`;
53
+ return styleTag && result.includes('</head>')
54
+ ? result.replace('</head>', `${styleTag}\n</head>`)
55
+ : result;
56
+ }
57
+ // Plain fragment — wrap fully
58
+ // Use split/join instead of replace to avoid $-pattern interpretation in base64 data URLs
59
+ const wrapped = HTML_WRAPPER_TEMPLATE.split('{content}').join(trimmed);
60
+ return styleTag ? wrapped.replace('</head>', `${styleTag}\n</head>`) : wrapped;
61
+ }
62
+ // ─── Public API ──────────────────────────────────────────────────────────────
63
+ /**
64
+ * Create a DOCX Buffer from HTML content.
65
+ *
66
+ * @param html - HTML content to convert
67
+ * @param options - Build options (baseDir, documentDefaults, etc.)
68
+ * @returns DOCX file as a Buffer
69
+ */
70
+ export async function createDocxFromHtml(html, options = {}) {
71
+ return withErrorContext(async () => {
72
+ if (!html?.trim()) {
73
+ throw new DocxError('HTML content cannot be empty', DocxErrorCode.DOCX_CREATE_FAILED, { htmlLength: 0 });
74
+ }
75
+ const defaults = options.documentDefaults;
76
+ const processedHtml = ensureHtmlStructure(html, defaults);
77
+ const docxOptions = {
78
+ table: { row: { cantSplit: true } },
79
+ footer: DEFAULT_BUILD_OPTIONS.footer,
80
+ pageNumber: DEFAULT_BUILD_OPTIONS.pageNumber,
81
+ font: defaults?.font || DEFAULT_BUILD_OPTIONS.font,
82
+ fontSize: defaults?.fontSize || DEFAULT_BUILD_OPTIONS.fontSize,
83
+ orientation: DEFAULT_BUILD_OPTIONS.orientation,
84
+ margins: { ...DEFAULT_BUILD_OPTIONS.margins },
85
+ };
86
+ const docxBuffer = await HTMLtoDOCX(processedHtml, null, docxOptions);
87
+ if (!docxBuffer || docxBuffer.length === 0) {
88
+ throw new DocxError('Failed to generate DOCX: empty buffer', DocxErrorCode.DOCX_CREATE_FAILED, { htmlLength: html.length });
89
+ }
90
+ return Buffer.from(docxBuffer);
91
+ }, DocxErrorCode.DOCX_CREATE_FAILED, { htmlLength: html.length });
92
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * DOCX Builders
3
+ * Centralized exports for all building utilities
4
+ */
5
+ export * from './markdown-builder.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * DOCX Builders
3
+ * Centralized exports for all building utilities
4
+ */
5
+ export * from './markdown-builder.js';
@@ -0,0 +1,2 @@
1
+ import type { DocxBuildOptions } from '../types.js';
2
+ export declare function createDocxFromMarkdown(markdown: string, options?: DocxBuildOptions): Promise<Buffer>;
@@ -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,36 @@
1
+ /**
2
+ * DOCX Constants
3
+ *
4
+ * Centralised constants shared across the DOCX module.
5
+ *
6
+ * @module docx/constants
7
+ */
8
+ export declare const DEFAULT_CONVERSION_OPTIONS: {
9
+ readonly includeImages: true;
10
+ readonly preserveFormatting: true;
11
+ readonly styleMap: readonly string[];
12
+ };
13
+ export declare const DEFAULT_BUILD_OPTIONS: {
14
+ readonly font: "Calibri";
15
+ readonly fontSize: 11;
16
+ readonly orientation: "portrait";
17
+ readonly margins: {
18
+ readonly top: 1440;
19
+ readonly right: 1440;
20
+ readonly bottom: 1440;
21
+ readonly left: 1440;
22
+ readonly header: 720;
23
+ readonly footer: 720;
24
+ readonly gutter: 0;
25
+ };
26
+ readonly footer: true;
27
+ readonly pageNumber: false;
28
+ };
29
+ export declare const DOCX_NAMESPACES: {
30
+ readonly DUBLIN_CORE: "dc";
31
+ readonly CUSTOM_PROPERTIES: "cp";
32
+ readonly DCTERMS: "dcterms";
33
+ };
34
+ export declare const CORE_PROPERTIES_PATH = "docProps/core.xml";
35
+ export declare const IMAGE_MIME_TYPES: Readonly<Record<string, string>>;
36
+ export declare const HTML_WRAPPER_TEMPLATE = "<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"UTF-8\">\n</head>\n<body>\n{content}\n</body>\n</html>";
@@ -0,0 +1,57 @@
1
+ /**
2
+ * DOCX Constants
3
+ *
4
+ * Centralised constants shared across the DOCX module.
5
+ *
6
+ * @module docx/constants
7
+ */
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,
30
+ };
31
+ // ─── DOCX Internal XML Namespaces ────────────────────────────────────────────
32
+ export const DOCX_NAMESPACES = {
33
+ DUBLIN_CORE: 'dc',
34
+ CUSTOM_PROPERTIES: 'cp',
35
+ DCTERMS: 'dcterms',
36
+ };
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',
47
+ };
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,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
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * DOCX Error Handling
3
+ *
4
+ * Centralised error class and async error-wrapping utility.
5
+ *
6
+ * @module docx/errors
7
+ */
8
+ export declare class DocxError extends Error {
9
+ readonly code: string;
10
+ readonly context?: Record<string, unknown> | undefined;
11
+ constructor(message: string, code: string, context?: Record<string, unknown> | undefined);
12
+ toJSON(): Record<string, unknown>;
13
+ }
14
+ export declare enum DocxErrorCode {
15
+ INVALID_DOCX = "INVALID_DOCX",
16
+ INVALID_PATH = "INVALID_PATH",
17
+ OPERATION_FAILED = "OPERATION_FAILED",
18
+ UNKNOWN_OPERATION = "UNKNOWN_OPERATION",
19
+ UNSUPPORTED_OPERATION = "UNSUPPORTED_OPERATION",
20
+ DOCX_CREATE_FAILED = "DOCX_CREATE_FAILED",
21
+ DOCX_EDIT_FAILED = "DOCX_EDIT_FAILED",
22
+ DOCX_READ_FAILED = "DOCX_READ_FAILED",
23
+ INVALID_IMAGE_FILE = "INVALID_IMAGE_FILE",
24
+ INVALID_IMAGE_DATA_URL = "INVALID_IMAGE_DATA_URL",
25
+ GET_INFO_FAILED = "GET_INFO_FAILED"
26
+ }
27
+ /** Wrap an async operation — re-throws existing DocxErrors, wraps everything else. */
28
+ export declare function withErrorContext<T>(operation: () => Promise<T>, errorCode: DocxErrorCode | string, context?: Record<string, unknown>): Promise<T>;