@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.
Files changed (132) hide show
  1. package/README.md +3 -0
  2. package/dist/handlers/filesystem-handlers.js +58 -11
  3. package/dist/handlers/history-handlers.d.ts +7 -0
  4. package/dist/handlers/history-handlers.js +33 -1
  5. package/dist/remote-device/remote-channel.d.ts +8 -3
  6. package/dist/remote-device/remote-channel.js +68 -21
  7. package/dist/search-manager.d.ts +13 -0
  8. package/dist/search-manager.js +146 -0
  9. package/dist/server.js +56 -4
  10. package/dist/test-docx.d.ts +1 -0
  11. package/dist/tools/docx/builders/image.d.ts +14 -0
  12. package/dist/tools/docx/builders/image.js +84 -0
  13. package/dist/tools/docx/builders/index.d.ts +9 -3
  14. package/dist/tools/docx/builders/index.js +9 -3
  15. package/dist/tools/docx/builders/paragraph.d.ts +12 -0
  16. package/dist/tools/docx/builders/paragraph.js +29 -0
  17. package/dist/tools/docx/builders/table.d.ts +10 -0
  18. package/dist/tools/docx/builders/table.js +138 -0
  19. package/dist/tools/docx/builders/utils.d.ts +5 -0
  20. package/dist/tools/docx/builders/utils.js +18 -0
  21. package/dist/tools/docx/constants.d.ts +28 -32
  22. package/dist/tools/docx/constants.js +56 -52
  23. package/dist/tools/docx/create.d.ts +21 -0
  24. package/dist/tools/docx/create.js +386 -0
  25. package/dist/tools/docx/dom.d.ts +139 -0
  26. package/dist/tools/docx/dom.js +448 -0
  27. package/dist/tools/docx/index.d.ts +8 -12
  28. package/dist/tools/docx/index.js +8 -14
  29. package/dist/tools/docx/modify.d.ts +28 -0
  30. package/dist/tools/docx/modify.js +271 -0
  31. package/dist/tools/docx/ops/delete-paragraph-at-body-index.d.ts +11 -0
  32. package/dist/tools/docx/ops/delete-paragraph-at-body-index.js +23 -0
  33. package/dist/tools/docx/ops/header-replace-text-exact.d.ts +13 -0
  34. package/dist/tools/docx/ops/header-replace-text-exact.js +55 -0
  35. package/dist/tools/docx/ops/index.d.ts +17 -0
  36. package/dist/tools/docx/ops/index.js +70 -0
  37. package/dist/tools/docx/ops/insert-image-after-text.d.ts +24 -0
  38. package/dist/tools/docx/ops/insert-image-after-text.js +128 -0
  39. package/dist/tools/docx/ops/insert-paragraph-after-text.d.ts +12 -0
  40. package/dist/tools/docx/ops/insert-paragraph-after-text.js +74 -0
  41. package/dist/tools/docx/ops/insert-table-after-text.d.ts +19 -0
  42. package/dist/tools/docx/ops/insert-table-after-text.js +57 -0
  43. package/dist/tools/docx/ops/replace-hyperlink-url.d.ts +12 -0
  44. package/dist/tools/docx/ops/replace-hyperlink-url.js +37 -0
  45. package/dist/tools/docx/ops/replace-paragraph-at-body-index.d.ts +9 -0
  46. package/dist/tools/docx/ops/replace-paragraph-at-body-index.js +25 -0
  47. package/dist/tools/docx/ops/replace-paragraph-text-exact.d.ts +21 -0
  48. package/dist/tools/docx/ops/replace-paragraph-text-exact.js +36 -0
  49. package/dist/tools/docx/ops/replace-table-cell-text.d.ts +25 -0
  50. package/dist/tools/docx/ops/replace-table-cell-text.js +85 -0
  51. package/dist/tools/docx/ops/set-color-for-paragraph-exact.d.ts +9 -0
  52. package/dist/tools/docx/ops/set-color-for-paragraph-exact.js +24 -0
  53. package/dist/tools/docx/ops/set-color-for-style.d.ts +13 -0
  54. package/dist/tools/docx/ops/set-color-for-style.js +31 -0
  55. package/dist/tools/docx/ops/set-paragraph-style-at-body-index.d.ts +8 -0
  56. package/dist/tools/docx/ops/set-paragraph-style-at-body-index.js +57 -0
  57. package/dist/tools/docx/ops/table-set-cell-text.d.ts +9 -0
  58. package/dist/tools/docx/ops/table-set-cell-text.js +40 -0
  59. package/dist/tools/docx/read.d.ts +27 -0
  60. package/dist/tools/docx/read.js +308 -0
  61. package/dist/tools/docx/relationships.d.ts +22 -0
  62. package/dist/tools/docx/relationships.js +76 -0
  63. package/dist/tools/docx/types.d.ts +202 -103
  64. package/dist/tools/docx/types.js +2 -5
  65. package/dist/tools/docx/validate.d.ts +33 -0
  66. package/dist/tools/docx/validate.js +49 -0
  67. package/dist/tools/docx/write.d.ts +17 -0
  68. package/dist/tools/docx/write.js +88 -0
  69. package/dist/tools/docx/xml-view-test.d.ts +1 -0
  70. package/dist/tools/docx/xml-view-test.js +63 -0
  71. package/dist/tools/docx/xml-view.d.ts +56 -0
  72. package/dist/tools/docx/xml-view.js +169 -0
  73. package/dist/tools/docx/zip.d.ts +21 -0
  74. package/dist/tools/docx/zip.js +35 -0
  75. package/dist/tools/edit.js +57 -27
  76. package/dist/tools/schemas.d.ts +13 -0
  77. package/dist/tools/schemas.js +6 -1
  78. package/dist/types.d.ts +10 -0
  79. package/dist/ui/contracts.d.ts +14 -0
  80. package/dist/ui/contracts.js +18 -0
  81. package/dist/ui/file-preview/index.html +16 -0
  82. package/dist/ui/file-preview/preview-runtime.js +13983 -0
  83. package/dist/ui/file-preview/shared/preview-file-types.d.ts +5 -0
  84. package/dist/ui/file-preview/shared/preview-file-types.js +57 -0
  85. package/dist/ui/file-preview/src/app.d.ts +4 -0
  86. package/dist/ui/file-preview/src/app.js +800 -0
  87. package/dist/ui/file-preview/src/components/code-viewer.d.ts +6 -0
  88. package/dist/ui/file-preview/src/components/code-viewer.js +73 -0
  89. package/dist/ui/file-preview/src/components/highlighting.d.ts +2 -0
  90. package/dist/ui/file-preview/src/components/highlighting.js +54 -0
  91. package/dist/ui/file-preview/src/components/html-renderer.d.ts +9 -0
  92. package/dist/ui/file-preview/src/components/html-renderer.js +63 -0
  93. package/dist/ui/file-preview/src/components/markdown-renderer.d.ts +1 -0
  94. package/dist/ui/file-preview/src/components/markdown-renderer.js +21 -0
  95. package/dist/ui/file-preview/src/components/toolbar.d.ts +6 -0
  96. package/dist/ui/file-preview/src/components/toolbar.js +75 -0
  97. package/dist/ui/file-preview/src/image-preview.d.ts +3 -0
  98. package/dist/ui/file-preview/src/image-preview.js +21 -0
  99. package/dist/ui/file-preview/src/main.d.ts +1 -0
  100. package/dist/ui/file-preview/src/main.js +5 -0
  101. package/dist/ui/file-preview/src/types.d.ts +1 -0
  102. package/dist/ui/file-preview/src/types.js +1 -0
  103. package/dist/ui/file-preview/styles.css +764 -0
  104. package/dist/ui/resources.d.ts +21 -0
  105. package/dist/ui/resources.js +72 -0
  106. package/dist/ui/shared/escape-html.d.ts +4 -0
  107. package/dist/ui/shared/escape-html.js +11 -0
  108. package/dist/ui/shared/host-lifecycle.d.ts +16 -0
  109. package/dist/ui/shared/host-lifecycle.js +35 -0
  110. package/dist/ui/shared/rpc-client.d.ts +14 -0
  111. package/dist/ui/shared/rpc-client.js +72 -0
  112. package/dist/ui/shared/theme-adaptation.d.ts +10 -0
  113. package/dist/ui/shared/theme-adaptation.js +118 -0
  114. package/dist/ui/shared/tool-header.d.ts +9 -0
  115. package/dist/ui/shared/tool-header.js +25 -0
  116. package/dist/ui/shared/tool-shell.d.ts +16 -0
  117. package/dist/ui/shared/tool-shell.js +65 -0
  118. package/dist/ui/shared/widget-state.d.ts +28 -0
  119. package/dist/ui/shared/widget-state.js +60 -0
  120. package/dist/utils/capture.d.ts +1 -0
  121. package/dist/utils/capture.js +176 -8
  122. package/dist/utils/files/base.d.ts +3 -1
  123. package/dist/utils/files/docx.d.ts +28 -22
  124. package/dist/utils/files/docx.js +630 -196
  125. package/dist/utils/files/factory.d.ts +6 -5
  126. package/dist/utils/files/factory.js +18 -6
  127. package/dist/utils/files/text.js +9 -1
  128. package/dist/utils/system-info.js +1 -1
  129. package/dist/utils/usageTracker.js +5 -0
  130. package/dist/version.d.ts +1 -1
  131. package/dist/version.js +1 -1
  132. package/package.json +6 -2
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
- import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListPromptsRequestSchema, InitializeRequestSchema, LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, } from "@modelcontextprotocol/sdk/types.js";
2
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, ListPromptsRequestSchema, InitializeRequestSchema, LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, } from "@modelcontextprotocol/sdk/types.js";
3
3
  import { zodToJsonSchema } from "zod-to-json-schema";
4
4
  import { getSystemInfo, getOSSpecificGuidance, getPathGuidance, getDevelopmentToolGuidance } from './utils/system-info.js';
5
5
  // Get system information once at startup
@@ -21,6 +21,8 @@ import { handleWelcomePageOnboarding } from './utils/welcome-onboarding.js';
21
21
  import { VERSION } from './version.js';
22
22
  import { capture, capture_call_tool } from "./utils/capture.js";
23
23
  import { logToStderr, logger } from './utils/logger.js';
24
+ import { buildUiToolMeta, FILE_PREVIEW_RESOURCE_URI } from './ui/contracts.js';
25
+ import { listUiResources, readUiResource } from './ui/resources.js';
24
26
  // Store startup messages to send after initialization
25
27
  const deferredMessages = [];
26
28
  function deferLog(level, message) {
@@ -47,11 +49,18 @@ export const server = new Server({
47
49
  });
48
50
  // Add handler for resources/list method
49
51
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
50
- // Return an empty list of resources
51
52
  return {
52
- resources: [],
53
+ resources: listUiResources(),
53
54
  };
54
55
  });
56
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
57
+ const { uri } = request.params;
58
+ const response = await readUiResource(uri);
59
+ if (response) {
60
+ return response;
61
+ }
62
+ throw new Error(`Unknown resource URI: ${uri}`);
63
+ });
55
64
  // Add handler for prompts/list method
56
65
  server.setRequestHandler(ListPromptsRequestSchema, async () => {
57
66
  // Return an empty list of prompts
@@ -233,10 +242,24 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
233
242
  - PDF: Extracts text content as markdown with page structure
234
243
  * offset/length work as page pagination (0-based)
235
244
  * Includes embedded images when available
245
+ - DOCX (.docx): Two modes depending on parameters:
246
+ * DEFAULT (no offset/length): Returns a text-bearing outline — shows paragraphs with text,
247
+ tables with cell content, styles, image refs. Skips shapes/drawings/SVG noise.
248
+ Each element shows its body index [0], [1], etc.
249
+ * WITH offset/length: Returns raw pretty-printed XML with line pagination.
250
+ Use this to drill into specific sections or see the actual XML for editing.
251
+ * EDITING WORKFLOW: 1) read_file to get outline, 2) read_file with offset/length
252
+ to see raw XML around what you want to edit, 3) edit_block with old_string/new_string
253
+ using XML fragments copied from the read output.
254
+ * IMPORTANT: offset MUST be non-zero to get raw XML (use offset=1 to start from line 1).
255
+ offset=0 always returns the outline regardless of length.
256
+ * For BULK changes (translation, mass replacements): use start_process with Python
257
+ zipfile module to find/replace all <w:t> elements at once.
236
258
 
237
259
  ${PATH_GUIDANCE}
238
260
  ${CMD_PREFIX_DESCRIPTION}`,
239
261
  inputSchema: zodToJsonSchema(ReadFileArgsSchema),
262
+ _meta: buildUiToolMeta(FILE_PREVIEW_RESOURCE_URI, true),
240
263
  annotations: {
241
264
  title: "Read File or URL",
242
265
  readOnlyHint: true,
@@ -269,6 +292,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
269
292
  Write or append to file contents.
270
293
 
271
294
  IMPORTANT: DO NOT use this tool to create PDF files. Use 'write_pdf' for all PDF creation tasks.
295
+ DO NOT use this tool to edit DOCX files. Use 'edit_block' with old_string/new_string instead.
296
+ To CREATE a new DOCX, use write_file with .docx extension — text content with markdown headings (#, ##, ###) is converted to styled DOCX paragraphs.
272
297
 
273
298
  CHUNKING IS STANDARD PRACTICE: Always write files in chunks of 25-30 lines maximum.
274
299
  This is the normal, recommended way to write files - not an emergency measure.
@@ -647,6 +672,17 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
647
672
  - new_string: Replacement text
648
673
  - expected_replacements: Optional number of replacements (default: 1)
649
674
 
675
+ DOCX FILES (.docx) - XML Find/Replace mode:
676
+ Takes same parameters as text files (old_string, new_string, expected_replacements).
677
+ Operates on the pretty-printed XML inside the DOCX — the same XML you see from
678
+ read_file with offset/length. Copy XML fragments from read output as old_string.
679
+ After editing, the XML is repacked into a valid DOCX.
680
+ Also searches headers/footers if not found in document body.
681
+ Examples:
682
+ - Replace text: old_string="<w:t>Old Text</w:t>" new_string="<w:t>New Text</w:t>"
683
+ - Change style: old_string='<w:pStyle w:val="Normal"/>' new_string='<w:pStyle w:val="Heading1"/>'
684
+ - Add content: include surrounding XML context in old_string, add new elements in new_string
685
+
650
686
  By default, replaces only ONE occurrence of the search text.
651
687
  To replace multiple occurrences, provide expected_replacements with
652
688
  the exact number of matches expected.
@@ -1179,6 +1215,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1179
1215
  };
1180
1216
  }
1181
1217
  break;
1218
+ case "track_ui_event":
1219
+ try {
1220
+ result = await handlers.handleTrackUiEvent(args);
1221
+ }
1222
+ catch (error) {
1223
+ capture('server_request_error', { message: `Error in track_ui_event handler: ${error}` });
1224
+ result = {
1225
+ content: [{ type: "text", text: `Error: Failed to track UI event` }],
1226
+ isError: true,
1227
+ };
1228
+ }
1229
+ break;
1182
1230
  case "give_feedback_to_desktop_commander":
1183
1231
  try {
1184
1232
  result = await giveFeedbackToDesktopCommander(args);
@@ -1265,12 +1313,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1265
1313
  // Add tool call to history (exclude only get_recent_tool_calls to prevent recursion)
1266
1314
  const duration = Date.now() - startTime;
1267
1315
  const EXCLUDED_TOOLS = [
1268
- 'get_recent_tool_calls'
1316
+ 'get_recent_tool_calls',
1317
+ 'track_ui_event'
1269
1318
  ];
1270
1319
  if (!EXCLUDED_TOOLS.includes(name)) {
1271
1320
  toolHistory.addCall(name, args, result, duration);
1272
1321
  }
1273
1322
  // Track success or failure based on result
1323
+ if (name === 'track_ui_event') {
1324
+ return result;
1325
+ }
1274
1326
  if (result.isError) {
1275
1327
  await usageTracker.trackFailure(name);
1276
1328
  console.log(`[FEEDBACK DEBUG] Tool ${name} failed, not checking feedback`);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Image builder — creates w:drawing elements and manages image relationships.
3
+ */
4
+ import PizZip from 'pizzip';
5
+ import type { DocxContentImage, InsertImageOp } from '../types.js';
6
+ /**
7
+ * Build an image element and add it to the ZIP archive.
8
+ *
9
+ * @param doc The XML document
10
+ * @param zip The DOCX ZIP archive
11
+ * @param spec The image specification (from content or operation)
12
+ * @returns A w:p element containing the image drawing
13
+ */
14
+ export declare function buildImageElement(doc: Document, zip: PizZip, spec: DocxContentImage | InsertImageOp): Promise<Element>;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Image builder — creates w:drawing elements and manages image relationships.
3
+ */
4
+ import fs from 'fs/promises';
5
+ import path from 'path';
6
+ import { DOMParser } from '@xmldom/xmldom';
7
+ import { addImageRelationship, ensureContentType } from '../relationships.js';
8
+ import { escapeXmlAttr } from './utils.js';
9
+ import { pixelsToEmu, DEFAULT_IMAGE_WIDTH, DEFAULT_IMAGE_HEIGHT, NAMESPACES } from '../constants.js';
10
+ /**
11
+ * Build an image element and add it to the ZIP archive.
12
+ *
13
+ * @param doc The XML document
14
+ * @param zip The DOCX ZIP archive
15
+ * @param spec The image specification (from content or operation)
16
+ * @returns A w:p element containing the image drawing
17
+ */
18
+ export async function buildImageElement(doc, zip, spec) {
19
+ // Validate image exists
20
+ try {
21
+ await fs.access(spec.imagePath);
22
+ }
23
+ catch {
24
+ throw new Error(`Image file not found: ${spec.imagePath}`);
25
+ }
26
+ // Read image
27
+ const imgBuffer = await fs.readFile(spec.imagePath);
28
+ const ext = path.extname(spec.imagePath).toLowerCase();
29
+ const baseName = path.basename(spec.imagePath);
30
+ // Find next available media filename
31
+ let mediaIndex = 1;
32
+ while (zip.file(`word/media/image${mediaIndex}${ext}`)) {
33
+ mediaIndex++;
34
+ }
35
+ const mediaFileName = `image${mediaIndex}${ext}`;
36
+ // Add image to ZIP
37
+ zip.file(`word/media/${mediaFileName}`, imgBuffer);
38
+ // Add relationship
39
+ const rId = addImageRelationship(zip, mediaFileName);
40
+ // Ensure Content_Types entry
41
+ ensureContentType(zip, ext);
42
+ // Compute dimensions (EMU)
43
+ const widthPx = spec.width ?? DEFAULT_IMAGE_WIDTH;
44
+ const heightPx = spec.height ?? DEFAULT_IMAGE_HEIGHT;
45
+ const widthEmu = pixelsToEmu(widthPx);
46
+ const heightEmu = pixelsToEmu(heightPx);
47
+ // Build drawing XML
48
+ const altText = spec.altText ?? baseName;
49
+ const drawingXmlStr = buildDrawingXml(rId, widthEmu, heightEmu, altText, mediaFileName);
50
+ // Parse drawing XML into a paragraph
51
+ const drawingFragment = new DOMParser().parseFromString(`<w:p xmlns:w="${NAMESPACES.W}">` +
52
+ `<w:r>${drawingXmlStr}</w:r></w:p>`, 'application/xml');
53
+ return doc.importNode(drawingFragment.documentElement, true);
54
+ }
55
+ /**
56
+ * Build the inline w:drawing XML for an image reference.
57
+ */
58
+ function buildDrawingXml(rId, widthEmu, heightEmu, altText, fileName) {
59
+ return (`<w:drawing xmlns:w="${NAMESPACES.W}">` +
60
+ `<wp:inline distT="0" distB="0" distL="0" distR="0" ` +
61
+ `xmlns:wp="${NAMESPACES.WP}">` +
62
+ `<wp:extent cx="${widthEmu}" cy="${heightEmu}"/>` +
63
+ `<wp:docPr id="1" name="${fileName}" descr="${escapeXmlAttr(altText)}"/>` +
64
+ `<a:graphic xmlns:a="${NAMESPACES.A}">` +
65
+ `<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">` +
66
+ `<pic:pic xmlns:pic="${NAMESPACES.PIC}">` +
67
+ `<pic:nvPicPr>` +
68
+ `<pic:cNvPr id="0" name="${fileName}" descr="${escapeXmlAttr(altText)}"/>` +
69
+ `<pic:cNvPicPr/>` +
70
+ `</pic:nvPicPr>` +
71
+ `<pic:blipFill>` +
72
+ `<a:blip r:embed="${rId}" xmlns:r="${NAMESPACES.R}"/>` +
73
+ `<a:stretch><a:fillRect/></a:stretch>` +
74
+ `</pic:blipFill>` +
75
+ `<pic:spPr>` +
76
+ `<a:xfrm><a:off x="0" y="0"/><a:ext cx="${widthEmu}" cy="${heightEmu}"/></a:xfrm>` +
77
+ `<a:prstGeom prst="rect"><a:avLst/></a:prstGeom>` +
78
+ `</pic:spPr>` +
79
+ `</pic:pic>` +
80
+ `</a:graphicData>` +
81
+ `</a:graphic>` +
82
+ `</wp:inline>` +
83
+ `</w:drawing>`);
84
+ }
@@ -1,5 +1,11 @@
1
1
  /**
2
- * DOCX Builders
3
- * Centralized exports for all building utilities
2
+ * DOCX element builders — Single Responsibility: build XML elements
3
+ * for paragraphs, tables, and images.
4
+ *
5
+ * These builders are shared between create.ts and ops/ modules to
6
+ * eliminate code duplication and ensure consistency.
4
7
  */
5
- export * from './markdown-builder.js';
8
+ export { buildParagraph } from './paragraph.js';
9
+ export { buildTable } from './table.js';
10
+ export { buildImageElement } from './image.js';
11
+ export { escapeXml, escapeXmlAttr } from './utils.js';
@@ -1,5 +1,11 @@
1
1
  /**
2
- * DOCX Builders
3
- * Centralized exports for all building utilities
2
+ * DOCX element builders — Single Responsibility: build XML elements
3
+ * for paragraphs, tables, and images.
4
+ *
5
+ * These builders are shared between create.ts and ops/ modules to
6
+ * eliminate code duplication and ensure consistency.
4
7
  */
5
- export * from './markdown-builder.js';
8
+ export { buildParagraph } from './paragraph.js';
9
+ export { buildTable } from './table.js';
10
+ export { buildImageElement } from './image.js';
11
+ export { escapeXml, escapeXmlAttr } from './utils.js';
@@ -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,10 @@
1
+ /**
2
+ * Table builder — creates w:tbl elements with headers, rows, and styling.
3
+ * Supports multiple paragraphs per cell with different styles.
4
+ */
5
+ import type { DocxContentTable, InsertTableOp } from '../types.js';
6
+ /**
7
+ * Build a table element from content structure or operation.
8
+ * Supports cells with multiple paragraphs, each with its own style.
9
+ */
10
+ export declare function buildTable(doc: Document, spec: DocxContentTable | InsertTableOp): Element;
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Table builder — creates w:tbl elements with headers, rows, and styling.
3
+ * Supports multiple paragraphs per cell with different styles.
4
+ */
5
+ import { buildParagraph } from './paragraph.js';
6
+ /**
7
+ * Build a table element from content structure or operation.
8
+ * Supports cells with multiple paragraphs, each with its own style.
9
+ */
10
+ export function buildTable(doc, spec) {
11
+ const tbl = doc.createElement('w:tbl');
12
+ // Table properties
13
+ const tblPr = doc.createElement('w:tblPr');
14
+ if (spec.style) {
15
+ const tblStyle = doc.createElement('w:tblStyle');
16
+ tblStyle.setAttribute('w:val', spec.style);
17
+ tblPr.appendChild(tblStyle);
18
+ }
19
+ const tblW = doc.createElement('w:tblW');
20
+ tblW.setAttribute('w:w', '0');
21
+ tblW.setAttribute('w:type', 'auto');
22
+ tblPr.appendChild(tblW);
23
+ // Table borders
24
+ const tblBorders = doc.createElement('w:tblBorders');
25
+ for (const side of ['top', 'left', 'bottom', 'right', 'insideH', 'insideV']) {
26
+ const border = doc.createElement(`w:${side}`);
27
+ border.setAttribute('w:val', 'single');
28
+ border.setAttribute('w:sz', '4');
29
+ border.setAttribute('w:space', '0');
30
+ border.setAttribute('w:color', '000000');
31
+ tblBorders.appendChild(border);
32
+ }
33
+ tblPr.appendChild(tblBorders);
34
+ tbl.appendChild(tblPr);
35
+ // Determine column count
36
+ const colCount = spec.headers
37
+ ? spec.headers.length
38
+ : spec.rows.length > 0
39
+ ? spec.rows[0].length
40
+ : 0;
41
+ // Table grid
42
+ if (colCount > 0) {
43
+ const tblGrid = doc.createElement('w:tblGrid');
44
+ for (let c = 0; c < colCount; c++) {
45
+ const gridCol = doc.createElement('w:gridCol');
46
+ const w = spec.colWidths?.[c] ?? Math.floor(9000 / colCount);
47
+ gridCol.setAttribute('w:w', String(w));
48
+ tblGrid.appendChild(gridCol);
49
+ }
50
+ tbl.appendChild(tblGrid);
51
+ }
52
+ /**
53
+ * Build a cell from content.
54
+ * Content can be:
55
+ * - A string: creates one paragraph with that text
56
+ * - An array of DocxContentParagraph: creates multiple paragraphs, each with its own style
57
+ */
58
+ const buildCell = (content, isHeader, widthTwips) => {
59
+ const tc = doc.createElement('w:tc');
60
+ // Cell properties (width)
61
+ if (widthTwips) {
62
+ const tcPr = doc.createElement('w:tcPr');
63
+ const tcW = doc.createElement('w:tcW');
64
+ tcW.setAttribute('w:w', String(widthTwips));
65
+ tcW.setAttribute('w:type', 'dxa');
66
+ tcPr.appendChild(tcW);
67
+ tc.appendChild(tcPr);
68
+ }
69
+ // Handle content: string or array of paragraphs
70
+ if (typeof content === 'string') {
71
+ // Simple case: single paragraph
72
+ const p = doc.createElement('w:p');
73
+ const r = doc.createElement('w:r');
74
+ // Header cells get bold
75
+ if (isHeader) {
76
+ const rPr = doc.createElement('w:rPr');
77
+ const b = doc.createElement('w:b');
78
+ rPr.appendChild(b);
79
+ r.appendChild(rPr);
80
+ }
81
+ const t = doc.createElement('w:t');
82
+ t.setAttribute('xml:space', 'preserve');
83
+ t.textContent = content;
84
+ r.appendChild(t);
85
+ p.appendChild(r);
86
+ tc.appendChild(p);
87
+ }
88
+ else {
89
+ // Complex case: multiple paragraphs with different styles
90
+ for (const paraSpec of content) {
91
+ const p = buildParagraph(doc, paraSpec);
92
+ // If header and first paragraph, ensure bold on runs
93
+ if (isHeader) {
94
+ const runs = p.getElementsByTagName('w:r');
95
+ for (let i = 0; i < runs.length; i++) {
96
+ const run = runs.item(i);
97
+ let rPr = run.getElementsByTagName('w:rPr').item(0);
98
+ if (!rPr) {
99
+ rPr = doc.createElement('w:rPr');
100
+ if (run.firstChild) {
101
+ run.insertBefore(rPr, run.firstChild);
102
+ }
103
+ else {
104
+ run.appendChild(rPr);
105
+ }
106
+ }
107
+ // Add bold if not already present
108
+ if (!rPr.getElementsByTagName('w:b').length) {
109
+ const b = doc.createElement('w:b');
110
+ rPr.appendChild(b);
111
+ }
112
+ }
113
+ }
114
+ tc.appendChild(p);
115
+ }
116
+ }
117
+ return tc;
118
+ };
119
+ // Header row
120
+ if (spec.headers && spec.headers.length > 0) {
121
+ const tr = doc.createElement('w:tr');
122
+ for (let i = 0; i < spec.headers.length; i++) {
123
+ const width = spec.colWidths?.[i];
124
+ tr.appendChild(buildCell(spec.headers[i], true, width));
125
+ }
126
+ tbl.appendChild(tr);
127
+ }
128
+ // Data rows
129
+ for (const row of spec.rows) {
130
+ const tr = doc.createElement('w:tr');
131
+ for (let i = 0; i < row.length; i++) {
132
+ const width = spec.colWidths?.[i];
133
+ tr.appendChild(buildCell(row[i], false, width));
134
+ }
135
+ tbl.appendChild(tr);
136
+ }
137
+ return tbl;
138
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * XML escaping utilities.
3
+ */
4
+ export declare function escapeXml(s: string): string;
5
+ export declare function escapeXmlAttr(s: string): string;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * XML escaping utilities.
3
+ */
4
+ export function escapeXml(s) {
5
+ return s
6
+ .replace(/&/g, '&amp;')
7
+ .replace(/</g, '&lt;')
8
+ .replace(/>/g, '&gt;')
9
+ .replace(/"/g, '&quot;')
10
+ .replace(/'/g, '&apos;');
11
+ }
12
+ export function escapeXmlAttr(s) {
13
+ return s
14
+ .replace(/&/g, '&amp;')
15
+ .replace(/"/g, '&quot;')
16
+ .replace(/</g, '&lt;')
17
+ .replace(/>/g, '&gt;');
18
+ }
@@ -1,36 +1,32 @@
1
1
  /**
2
- * DOCX Constants
3
- *
4
- * Centralised constants shared across the DOCX module.
5
- *
6
- * @module docx/constants
2
+ * DOCX constants — shared values used across the module.
7
3
  */
8
- 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;
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";
28
19
  };
29
- export declare const DOCX_NAMESPACES: {
30
- readonly DUBLIN_CORE: "dc";
31
- readonly CUSTOM_PROPERTIES: "cp";
32
- readonly DCTERMS: "dcterms";
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";
33
32
  };
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>";