@wonderwhy-er/desktop-commander 0.2.38 → 0.2.40

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 (263) hide show
  1. package/README.md +53 -2
  2. package/dist/handlers/filesystem-handlers.d.ts +5 -0
  3. package/dist/handlers/filesystem-handlers.js +14 -2
  4. package/dist/remote-device/desktop-commander-integration.js +1 -1
  5. package/dist/search-manager.js +31 -38
  6. package/dist/server.js +9 -4
  7. package/dist/terminal-manager.js +4 -2
  8. package/dist/tools/edit.js +34 -1
  9. package/dist/tools/filesystem.js +91 -3
  10. package/dist/tools/improved-process-tools.js +2 -1
  11. package/dist/ui/config-editor/config-editor-runtime.js +65 -14096
  12. package/dist/ui/config-editor/styles.css +2 -1
  13. package/dist/ui/file-preview/preview-runtime.js +435 -26533
  14. package/dist/ui/file-preview/shared/preview-file-types.d.ts +1 -1
  15. package/dist/ui/file-preview/src/app.d.ts +1 -5
  16. package/dist/ui/file-preview/src/app.js +384 -534
  17. package/dist/ui/file-preview/src/components/markdown-renderer.js +47 -9
  18. package/dist/ui/file-preview/src/directory-controller.d.ts +8 -0
  19. package/dist/ui/file-preview/src/directory-controller.js +233 -0
  20. package/dist/ui/file-preview/src/document-layout.d.ts +20 -0
  21. package/dist/ui/file-preview/src/document-layout.js +109 -0
  22. package/dist/ui/file-preview/src/document-outline.d.ts +17 -0
  23. package/dist/ui/file-preview/src/document-outline.js +97 -0
  24. package/dist/ui/file-preview/src/document-workspace.d.ts +19 -0
  25. package/dist/ui/file-preview/src/document-workspace.js +33 -0
  26. package/dist/ui/file-preview/src/file-type-handlers.d.ts +10 -0
  27. package/dist/ui/file-preview/src/file-type-handlers.js +98 -0
  28. package/dist/ui/file-preview/src/host/external-actions.d.ts +19 -0
  29. package/dist/ui/file-preview/src/host/external-actions.js +94 -0
  30. package/dist/ui/file-preview/src/host/selection-context.d.ts +9 -0
  31. package/dist/ui/file-preview/src/host/selection-context.js +106 -0
  32. package/dist/ui/file-preview/src/markdown/conflict-dialog.d.ts +40 -0
  33. package/dist/ui/file-preview/src/markdown/conflict-dialog.js +163 -0
  34. package/dist/ui/file-preview/src/markdown/controller.d.ts +44 -0
  35. package/dist/ui/file-preview/src/markdown/controller.js +1040 -0
  36. package/dist/ui/file-preview/src/markdown/editor.d.ts +131 -0
  37. package/dist/ui/file-preview/src/markdown/editor.js +1479 -0
  38. package/dist/ui/file-preview/src/markdown/linking.d.ts +16 -0
  39. package/dist/ui/file-preview/src/markdown/linking.js +228 -0
  40. package/dist/ui/file-preview/src/markdown/outline.d.ts +2 -0
  41. package/dist/ui/file-preview/src/markdown/outline.js +16 -0
  42. package/dist/ui/file-preview/src/markdown/parser.d.ts +30 -0
  43. package/dist/ui/file-preview/src/markdown/parser.js +38 -0
  44. package/dist/ui/file-preview/src/markdown/preview.d.ts +1 -0
  45. package/dist/ui/file-preview/src/markdown/preview.js +20 -0
  46. package/dist/ui/file-preview/src/markdown/slugify.d.ts +3 -0
  47. package/dist/ui/file-preview/src/markdown/slugify.js +31 -0
  48. package/dist/ui/file-preview/src/markdown/utils.d.ts +1 -0
  49. package/dist/ui/file-preview/src/markdown/utils.js +15 -0
  50. package/dist/ui/file-preview/src/model.d.ts +35 -0
  51. package/dist/ui/file-preview/src/panel-actions.d.ts +17 -0
  52. package/dist/ui/file-preview/src/panel-actions.js +182 -0
  53. package/dist/ui/file-preview/src/path-utils.d.ts +6 -0
  54. package/dist/ui/file-preview/src/path-utils.js +64 -0
  55. package/dist/ui/file-preview/src/payload-utils.d.ts +11 -0
  56. package/dist/ui/file-preview/src/payload-utils.js +94 -0
  57. package/dist/ui/file-preview/styles.css +1066 -233
  58. package/dist/ui/shared/widget-state.d.ts +6 -1
  59. package/dist/ui/shared/widget-state.js +102 -4
  60. package/dist/utils/capture.js +1 -1
  61. package/dist/utils/files/base.d.ts +2 -0
  62. package/dist/utils/open-browser.js +1 -1
  63. package/dist/utils/toolHistory.d.ts +13 -0
  64. package/dist/utils/toolHistory.js +65 -0
  65. package/dist/version.d.ts +1 -1
  66. package/dist/version.js +1 -1
  67. package/package.json +12 -1
  68. package/dist/data/spec-kit-prompts.json +0 -123
  69. package/dist/handlers/macos-control-handlers.d.ts +0 -16
  70. package/dist/handlers/macos-control-handlers.js +0 -81
  71. package/dist/handlers/node-handlers.d.ts +0 -6
  72. package/dist/handlers/node-handlers.js +0 -73
  73. package/dist/handlers/test-crash-handler.d.ts +0 -11
  74. package/dist/handlers/test-crash-handler.js +0 -26
  75. package/dist/http-index.d.ts +0 -45
  76. package/dist/http-index.js +0 -51
  77. package/dist/http-server-auto-tunnel.js +0 -667
  78. package/dist/http-server-named-tunnel.d.ts +0 -2
  79. package/dist/http-server-named-tunnel.js +0 -167
  80. package/dist/http-server-tunnel.d.ts +0 -2
  81. package/dist/http-server-tunnel.js +0 -111
  82. package/dist/http-server.d.ts +0 -2
  83. package/dist/http-server.js +0 -270
  84. package/dist/index-oauth.d.ts +0 -2
  85. package/dist/index-oauth.js +0 -201
  86. package/dist/lib.d.ts +0 -10
  87. package/dist/lib.js +0 -10
  88. package/dist/oauth/auth-middleware.d.ts +0 -20
  89. package/dist/oauth/auth-middleware.js +0 -62
  90. package/dist/oauth/index.d.ts +0 -3
  91. package/dist/oauth/index.js +0 -3
  92. package/dist/oauth/oauth-manager.d.ts +0 -80
  93. package/dist/oauth/oauth-manager.js +0 -179
  94. package/dist/oauth/oauth-routes.d.ts +0 -3
  95. package/dist/oauth/oauth-routes.js +0 -377
  96. package/dist/oauth/provider.d.ts +0 -22
  97. package/dist/oauth/provider.js +0 -124
  98. package/dist/oauth/server.d.ts +0 -18
  99. package/dist/oauth/server.js +0 -160
  100. package/dist/oauth/types.d.ts +0 -54
  101. package/dist/oauth/types.js +0 -2
  102. package/dist/remote-device/templates/auth-success.d.ts +0 -1
  103. package/dist/remote-device/templates/auth-success.js +0 -30
  104. package/dist/setup.log +0 -275
  105. package/dist/test-docx.d.ts +0 -1
  106. package/dist/test-setup.js +0 -14
  107. package/dist/tools/docx/builders/html-builder.d.ts +0 -17
  108. package/dist/tools/docx/builders/html-builder.js +0 -92
  109. package/dist/tools/docx/builders/image.d.ts +0 -14
  110. package/dist/tools/docx/builders/image.js +0 -84
  111. package/dist/tools/docx/builders/index.d.ts +0 -11
  112. package/dist/tools/docx/builders/index.js +0 -11
  113. package/dist/tools/docx/builders/markdown-builder.d.ts +0 -2
  114. package/dist/tools/docx/builders/markdown-builder.js +0 -260
  115. package/dist/tools/docx/builders/paragraph.d.ts +0 -12
  116. package/dist/tools/docx/builders/paragraph.js +0 -29
  117. package/dist/tools/docx/builders/table.d.ts +0 -10
  118. package/dist/tools/docx/builders/table.js +0 -138
  119. package/dist/tools/docx/builders/utils.d.ts +0 -5
  120. package/dist/tools/docx/builders/utils.js +0 -18
  121. package/dist/tools/docx/constants.d.ts +0 -32
  122. package/dist/tools/docx/constants.js +0 -61
  123. package/dist/tools/docx/converters/markdown-to-html.d.ts +0 -17
  124. package/dist/tools/docx/converters/markdown-to-html.js +0 -111
  125. package/dist/tools/docx/create.d.ts +0 -21
  126. package/dist/tools/docx/create.js +0 -386
  127. package/dist/tools/docx/dom.d.ts +0 -139
  128. package/dist/tools/docx/dom.js +0 -448
  129. package/dist/tools/docx/errors.d.ts +0 -28
  130. package/dist/tools/docx/errors.js +0 -48
  131. package/dist/tools/docx/extractors/images.d.ts +0 -14
  132. package/dist/tools/docx/extractors/images.js +0 -40
  133. package/dist/tools/docx/extractors/metadata.d.ts +0 -14
  134. package/dist/tools/docx/extractors/metadata.js +0 -64
  135. package/dist/tools/docx/extractors/sections.d.ts +0 -14
  136. package/dist/tools/docx/extractors/sections.js +0 -61
  137. package/dist/tools/docx/html.d.ts +0 -17
  138. package/dist/tools/docx/html.js +0 -111
  139. package/dist/tools/docx/index.d.ts +0 -10
  140. package/dist/tools/docx/index.js +0 -10
  141. package/dist/tools/docx/markdown.d.ts +0 -84
  142. package/dist/tools/docx/markdown.js +0 -507
  143. package/dist/tools/docx/modify.d.ts +0 -28
  144. package/dist/tools/docx/modify.js +0 -271
  145. package/dist/tools/docx/operations/handlers/index.d.ts +0 -39
  146. package/dist/tools/docx/operations/handlers/index.js +0 -152
  147. package/dist/tools/docx/operations/html-manipulator.d.ts +0 -24
  148. package/dist/tools/docx/operations/html-manipulator.js +0 -352
  149. package/dist/tools/docx/operations/index.d.ts +0 -14
  150. package/dist/tools/docx/operations/index.js +0 -61
  151. package/dist/tools/docx/operations/operation-handlers.d.ts +0 -3
  152. package/dist/tools/docx/operations/operation-handlers.js +0 -67
  153. package/dist/tools/docx/operations/preprocessor.d.ts +0 -14
  154. package/dist/tools/docx/operations/preprocessor.js +0 -44
  155. package/dist/tools/docx/operations/xml-replacer.d.ts +0 -9
  156. package/dist/tools/docx/operations/xml-replacer.js +0 -35
  157. package/dist/tools/docx/operations.d.ts +0 -13
  158. package/dist/tools/docx/operations.js +0 -13
  159. package/dist/tools/docx/ops/delete-paragraph-at-body-index.d.ts +0 -11
  160. package/dist/tools/docx/ops/delete-paragraph-at-body-index.js +0 -23
  161. package/dist/tools/docx/ops/header-replace-text-exact.d.ts +0 -13
  162. package/dist/tools/docx/ops/header-replace-text-exact.js +0 -55
  163. package/dist/tools/docx/ops/index.d.ts +0 -17
  164. package/dist/tools/docx/ops/index.js +0 -70
  165. package/dist/tools/docx/ops/insert-image-after-text.d.ts +0 -24
  166. package/dist/tools/docx/ops/insert-image-after-text.js +0 -128
  167. package/dist/tools/docx/ops/insert-paragraph-after-text.d.ts +0 -12
  168. package/dist/tools/docx/ops/insert-paragraph-after-text.js +0 -74
  169. package/dist/tools/docx/ops/insert-table-after-text.d.ts +0 -19
  170. package/dist/tools/docx/ops/insert-table-after-text.js +0 -57
  171. package/dist/tools/docx/ops/replace-hyperlink-url.d.ts +0 -12
  172. package/dist/tools/docx/ops/replace-hyperlink-url.js +0 -37
  173. package/dist/tools/docx/ops/replace-paragraph-at-body-index.d.ts +0 -9
  174. package/dist/tools/docx/ops/replace-paragraph-at-body-index.js +0 -25
  175. package/dist/tools/docx/ops/replace-paragraph-text-exact.d.ts +0 -21
  176. package/dist/tools/docx/ops/replace-paragraph-text-exact.js +0 -36
  177. package/dist/tools/docx/ops/replace-table-cell-text.d.ts +0 -25
  178. package/dist/tools/docx/ops/replace-table-cell-text.js +0 -85
  179. package/dist/tools/docx/ops/set-color-for-paragraph-exact.d.ts +0 -9
  180. package/dist/tools/docx/ops/set-color-for-paragraph-exact.js +0 -24
  181. package/dist/tools/docx/ops/set-color-for-style.d.ts +0 -13
  182. package/dist/tools/docx/ops/set-color-for-style.js +0 -31
  183. package/dist/tools/docx/ops/set-paragraph-style-at-body-index.d.ts +0 -8
  184. package/dist/tools/docx/ops/set-paragraph-style-at-body-index.js +0 -57
  185. package/dist/tools/docx/ops/table-set-cell-text.d.ts +0 -9
  186. package/dist/tools/docx/ops/table-set-cell-text.js +0 -40
  187. package/dist/tools/docx/parsers/image-extractor.d.ts +0 -18
  188. package/dist/tools/docx/parsers/image-extractor.js +0 -61
  189. package/dist/tools/docx/parsers/index.d.ts +0 -9
  190. package/dist/tools/docx/parsers/index.js +0 -9
  191. package/dist/tools/docx/parsers/paragraph-parser.d.ts +0 -2
  192. package/dist/tools/docx/parsers/paragraph-parser.js +0 -88
  193. package/dist/tools/docx/parsers/table-parser.d.ts +0 -9
  194. package/dist/tools/docx/parsers/table-parser.js +0 -72
  195. package/dist/tools/docx/parsers/xml-parser.d.ts +0 -25
  196. package/dist/tools/docx/parsers/xml-parser.js +0 -71
  197. package/dist/tools/docx/parsers/zip-reader.d.ts +0 -23
  198. package/dist/tools/docx/parsers/zip-reader.js +0 -52
  199. package/dist/tools/docx/read.d.ts +0 -27
  200. package/dist/tools/docx/read.js +0 -308
  201. package/dist/tools/docx/relationships.d.ts +0 -22
  202. package/dist/tools/docx/relationships.js +0 -76
  203. package/dist/tools/docx/structure.d.ts +0 -25
  204. package/dist/tools/docx/structure.js +0 -102
  205. package/dist/tools/docx/styled-html-parser.d.ts +0 -23
  206. package/dist/tools/docx/styled-html-parser.js +0 -1262
  207. package/dist/tools/docx/types.d.ts +0 -213
  208. package/dist/tools/docx/types.js +0 -5
  209. package/dist/tools/docx/utils/escaping.d.ts +0 -13
  210. package/dist/tools/docx/utils/escaping.js +0 -26
  211. package/dist/tools/docx/utils/images.d.ts +0 -9
  212. package/dist/tools/docx/utils/images.js +0 -26
  213. package/dist/tools/docx/utils/index.d.ts +0 -12
  214. package/dist/tools/docx/utils/index.js +0 -17
  215. package/dist/tools/docx/utils/markdown.d.ts +0 -13
  216. package/dist/tools/docx/utils/markdown.js +0 -32
  217. package/dist/tools/docx/utils/paths.d.ts +0 -15
  218. package/dist/tools/docx/utils/paths.js +0 -27
  219. package/dist/tools/docx/utils/versioning.d.ts +0 -25
  220. package/dist/tools/docx/utils/versioning.js +0 -55
  221. package/dist/tools/docx/utils.d.ts +0 -101
  222. package/dist/tools/docx/utils.js +0 -299
  223. package/dist/tools/docx/validate.d.ts +0 -33
  224. package/dist/tools/docx/validate.js +0 -49
  225. package/dist/tools/docx/validators.d.ts +0 -13
  226. package/dist/tools/docx/validators.js +0 -40
  227. package/dist/tools/docx/write.d.ts +0 -17
  228. package/dist/tools/docx/write.js +0 -88
  229. package/dist/tools/docx/xml-view-test.d.ts +0 -1
  230. package/dist/tools/docx/xml-view-test.js +0 -63
  231. package/dist/tools/docx/xml-view.d.ts +0 -56
  232. package/dist/tools/docx/xml-view.js +0 -169
  233. package/dist/tools/docx/zip.d.ts +0 -21
  234. package/dist/tools/docx/zip.js +0 -35
  235. package/dist/tools/macos-control/ax-adapter.d.ts +0 -55
  236. package/dist/tools/macos-control/ax-adapter.js +0 -438
  237. package/dist/tools/macos-control/cdp-adapter.d.ts +0 -23
  238. package/dist/tools/macos-control/cdp-adapter.js +0 -402
  239. package/dist/tools/macos-control/orchestrator.d.ts +0 -77
  240. package/dist/tools/macos-control/orchestrator.js +0 -136
  241. package/dist/tools/macos-control/role-aliases.d.ts +0 -5
  242. package/dist/tools/macos-control/role-aliases.js +0 -34
  243. package/dist/tools/macos-control/types.d.ts +0 -129
  244. package/dist/tools/macos-control/types.js +0 -1
  245. package/dist/tools/pdf-processor.d.ts +0 -1
  246. package/dist/tools/pdf-processor.js +0 -3
  247. package/dist/tools/search.d.ts +0 -32
  248. package/dist/tools/search.js +0 -202
  249. package/dist/ui/file-preview/src/components/toolbar.d.ts +0 -6
  250. package/dist/ui/file-preview/src/components/toolbar.js +0 -75
  251. package/dist/ui/shared/host-lifecycle.d.ts +0 -16
  252. package/dist/ui/shared/host-lifecycle.js +0 -35
  253. package/dist/ui/shared/rpc-client.d.ts +0 -14
  254. package/dist/ui/shared/rpc-client.js +0 -72
  255. package/dist/ui/shared/theme-adaptation.d.ts +0 -10
  256. package/dist/ui/shared/theme-adaptation.js +0 -118
  257. package/dist/ui/shared/tool-header.d.ts +0 -9
  258. package/dist/ui/shared/tool-header.js +0 -25
  259. package/dist/utils/crash-logger.d.ts +0 -18
  260. package/dist/utils/crash-logger.js +0 -44
  261. package/dist/utils/dedent.d.ts +0 -8
  262. package/dist/utils/dedent.js +0 -38
  263. /package/dist/{http-server-auto-tunnel.d.ts → ui/file-preview/src/model.js} +0 -0
@@ -1,299 +0,0 @@
1
- /**
2
- * DOCX Utility Functions
3
- * Helper functions for DOCX operations, validation, and data transformation
4
- */
5
- import fs from 'fs/promises';
6
- import path from 'path';
7
- // Import types from docx for image handling
8
- // @ts-ignore - docx library has incomplete type definitions but exports exist at runtime
9
- import * as docx from 'docx';
10
- const { ImageRun, } = docx;
11
- import { DocxError, DocxErrorCode, withErrorContext } from './errors.js';
12
- /**
13
- * Check if a string is a valid data URL
14
- */
15
- export function isDataUrl(src) {
16
- return src.startsWith('data:') && src.includes('base64,');
17
- }
18
- /**
19
- * Check if a source is a URL (http/https)
20
- */
21
- export function isUrl(src) {
22
- return src.startsWith('http://') || src.startsWith('https://');
23
- }
24
- /**
25
- * Parse data URL into buffer
26
- * @returns Buffer if successful, null if invalid
27
- */
28
- export function parseDataUrl(dataUrl) {
29
- try {
30
- const match = dataUrl.match(/^data:([^;]+);base64,(.+)$/);
31
- if (!match)
32
- return null;
33
- return Buffer.from(match[2], 'base64');
34
- }
35
- catch {
36
- return null;
37
- }
38
- }
39
- /**
40
- * Resolve image path relative to base directory
41
- */
42
- export function resolveImagePath(imagePath, baseDir) {
43
- if (path.isAbsolute(imagePath) || isUrl(imagePath) || isDataUrl(imagePath)) {
44
- return imagePath;
45
- }
46
- if (!baseDir) {
47
- return path.resolve(imagePath);
48
- }
49
- return path.join(baseDir, imagePath);
50
- }
51
- /**
52
- * Check if a file exists
53
- */
54
- export async function fileExists(filePath) {
55
- try {
56
- await fs.access(filePath);
57
- return true;
58
- }
59
- catch {
60
- return false;
61
- }
62
- }
63
- /**
64
- * Validate image file
65
- */
66
- export async function validateImageFile(imagePath) {
67
- if (isDataUrl(imagePath)) {
68
- const buffer = parseDataUrl(imagePath);
69
- if (!buffer) {
70
- return { valid: false, error: 'Invalid data URL format' };
71
- }
72
- return { valid: true };
73
- }
74
- if (isUrl(imagePath)) {
75
- // For URLs, we'll validate during fetch
76
- return { valid: true };
77
- }
78
- const exists = await fileExists(imagePath);
79
- if (!exists) {
80
- return { valid: false, error: `Image file not found: ${imagePath}` };
81
- }
82
- // Check file extension
83
- const ext = path.extname(imagePath).toLowerCase();
84
- const validExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.svg'];
85
- if (!validExtensions.includes(ext)) {
86
- return { valid: false, error: `Unsupported image format: ${ext}` };
87
- }
88
- return { valid: true };
89
- }
90
- /**
91
- * Escape special regex characters for literal string matching
92
- */
93
- export function escapeRegExp(str) {
94
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
95
- }
96
- /**
97
- * Validate markdown table format
98
- */
99
- export function isValidMarkdownTable(markdown) {
100
- const lines = markdown.trim().split('\n');
101
- if (lines.length < 2)
102
- return false;
103
- // Check header row
104
- const headerLine = lines[0].trim();
105
- if (!headerLine.startsWith('|') || !headerLine.endsWith('|'))
106
- return false;
107
- // Check separator row
108
- const separatorLine = lines[1].trim();
109
- if (!separatorLine.startsWith('|') || !separatorLine.endsWith('|'))
110
- return false;
111
- // Verify separator contains dashes
112
- const separatorPattern = /^(\|\s*:?-{2,}\s*:?\s*)+\|$/;
113
- if (!separatorPattern.test(separatorLine))
114
- return false;
115
- return true;
116
- }
117
- /**
118
- * Build a markdown table from a 2D array of rows
119
- */
120
- export function buildMarkdownTableFromRows(rows) {
121
- if (!rows || rows.length === 0) {
122
- return '';
123
- }
124
- const header = rows[0];
125
- const dataRows = rows.slice(1);
126
- const headerLine = `| ${header.join(' | ')} |`;
127
- const separatorLine = `| ${header.map(() => '---').join(' | ')} |`;
128
- const dataLines = dataRows.map((r) => `| ${r.join(' | ')} |`);
129
- return [headerLine, separatorLine, ...dataLines].join('\n');
130
- }
131
- /**
132
- * Parse markdown table into 2D array
133
- */
134
- export function parseMarkdownTable(markdown) {
135
- if (!isValidMarkdownTable(markdown)) {
136
- return null;
137
- }
138
- const lines = markdown.trim().split('\n');
139
- const rows = [];
140
- for (let i = 0; i < lines.length; i++) {
141
- // Skip separator line
142
- if (i === 1)
143
- continue;
144
- const line = lines[i].trim();
145
- const cells = line
146
- .replace(/^\|/, '')
147
- .replace(/\|$/, '')
148
- .split('|')
149
- .map(cell => cell.trim());
150
- rows.push(cells);
151
- }
152
- return rows;
153
- }
154
- /**
155
- * Get MIME type from file extension or data URL
156
- */
157
- export function getMimeType(source) {
158
- if (isDataUrl(source)) {
159
- const match = source.match(/^data:([^;]+);/);
160
- return match ? match[1] : null;
161
- }
162
- const ext = path.extname(source).toLowerCase();
163
- const mimeTypes = {
164
- '.png': 'image/png',
165
- '.jpg': 'image/jpeg',
166
- '.jpeg': 'image/jpeg',
167
- '.gif': 'image/gif',
168
- '.bmp': 'image/bmp',
169
- '.webp': 'image/webp',
170
- '.svg': 'image/svg+xml',
171
- };
172
- return mimeTypes[ext] || null;
173
- }
174
- /**
175
- * Format file size in human-readable format
176
- */
177
- export function formatFileSize(bytes) {
178
- if (bytes === 0)
179
- return '0 Bytes';
180
- const k = 1024;
181
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
182
- const i = Math.floor(Math.log(bytes) / Math.log(k));
183
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
184
- }
185
- /**
186
- * Normalize line endings to \n
187
- */
188
- export function normalizeLineEndings(text) {
189
- return text.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
190
- }
191
- /**
192
- * Split markdown into lines, preserving empty lines
193
- */
194
- export function splitMarkdownLines(markdown) {
195
- return normalizeLineEndings(markdown).split('\n');
196
- }
197
- /**
198
- * Validate DOCX file path
199
- */
200
- export function isDocxPath(filePath) {
201
- return filePath.toLowerCase().endsWith('.docx');
202
- }
203
- /**
204
- * Extract file name without extension
205
- */
206
- export function getFileNameWithoutExtension(filePath) {
207
- const basename = path.basename(filePath);
208
- return basename.replace(/\.docx$/i, '');
209
- }
210
- // Re-export error handling from errors module
211
- export { DocxError, DocxErrorCode, withErrorContext } from './errors.js';
212
- /**
213
- * Load and prepare an image for DOCX embedding
214
- * Handles both local files and data URLs
215
- *
216
- * @param imagePath - Path to image file or data URL
217
- * @param altText - Alternative text for the image
218
- * @param baseDir - Base directory for resolving relative paths
219
- * @returns Prepared image data ready for embedding
220
- */
221
- export async function prepareImageForDocx(imagePath, altText = '', baseDir) {
222
- return withErrorContext(async () => {
223
- let buffer;
224
- let mimeType = 'image/png'; // Default
225
- // Handle data URL
226
- if (isDataUrl(imagePath)) {
227
- const parsed = parseDataUrl(imagePath);
228
- if (!parsed) {
229
- throw new DocxError('Invalid data URL format', DocxErrorCode.INVALID_IMAGE_DATA_URL, { imagePath: imagePath.substring(0, 50) });
230
- }
231
- buffer = parsed;
232
- // Extract MIME type from data URL
233
- const mimeMatch = imagePath.match(/^data:([^;]+);/);
234
- if (mimeMatch) {
235
- mimeType = mimeMatch[1];
236
- }
237
- }
238
- else {
239
- // Handle file path
240
- const resolved = resolveImagePath(imagePath, baseDir);
241
- // Validate image file
242
- const validation = await validateImageFile(resolved);
243
- if (!validation.valid) {
244
- throw new DocxError(validation.error || 'Invalid image file', DocxErrorCode.INVALID_IMAGE_FILE, { imagePath: resolved });
245
- }
246
- // Read image file
247
- try {
248
- buffer = await fs.readFile(resolved);
249
- }
250
- catch (error) {
251
- throw new DocxError(`Failed to read image file: ${error instanceof Error ? error.message : String(error)}`, DocxErrorCode.IMAGE_READ_FAILED, { imagePath: resolved });
252
- }
253
- // Determine MIME type from file extension
254
- const ext = path.extname(resolved).toLowerCase();
255
- const mimeTypes = {
256
- '.png': 'image/png',
257
- '.jpg': 'image/jpeg',
258
- '.jpeg': 'image/jpeg',
259
- '.gif': 'image/gif',
260
- '.bmp': 'image/bmp',
261
- '.webp': 'image/webp',
262
- };
263
- mimeType = mimeTypes[ext] || 'image/png';
264
- }
265
- return {
266
- buffer,
267
- altText: altText || path.basename(imagePath),
268
- mimeType,
269
- // Default dimensions - can be customized
270
- width: 600,
271
- height: 400,
272
- };
273
- }, DocxErrorCode.IMAGE_PREPARATION_FAILED, { imagePath });
274
- }
275
- /**
276
- * Create an ImageRun instance for embedding in DOCX paragraphs
277
- * This is a lower-level utility for direct image insertion
278
- *
279
- * @param imageData - Prepared image data
280
- * @returns ImageRun instance ready to be added to a paragraph
281
- */
282
- export function createImageRun(imageData) {
283
- try {
284
- return new ImageRun({
285
- data: imageData.buffer,
286
- transformation: {
287
- width: imageData.width || 600,
288
- height: imageData.height || 400,
289
- },
290
- altText: {
291
- title: imageData.altText,
292
- description: imageData.altText,
293
- },
294
- });
295
- }
296
- catch (error) {
297
- throw new DocxError(`Failed to create image run: ${error instanceof Error ? error.message : String(error)}`, DocxErrorCode.IMAGE_RUN_CREATION_FAILED);
298
- }
299
- }
@@ -1,33 +0,0 @@
1
- /**
2
- * Invariant validation for DOCX write operations.
3
- *
4
- * Single Responsibility: capture a structural snapshot of w:body and
5
- * compare before / after snapshots to guarantee no accidental breakage.
6
- */
7
- import type { BodySnapshot } from './types.js';
8
- export interface ValidationOptions {
9
- /**
10
- * Expected change in w:body direct child count.
11
- * Positive = inserts, negative = deletes.
12
- * Default 0 (no structural changes expected).
13
- */
14
- expectedChildDelta?: number;
15
- /**
16
- * Expected change in w:tbl count.
17
- * Default 0 (no table additions/removals expected).
18
- */
19
- expectedTableDelta?: number;
20
- }
21
- /** Take a snapshot of the body's structural invariants. */
22
- export declare function captureSnapshot(body: Element): BodySnapshot;
23
- /**
24
- * Compare before / after snapshots.
25
- * Throws a descriptive error if any invariant has been violated,
26
- * preventing the output file from being written.
27
- *
28
- * When `expectedChildDelta` is non-zero (structural ops like insert or
29
- * delete), signature validation is skipped because the body structure
30
- * is *expected* to change. Child count is still validated against
31
- * the expected delta, and table count must remain unchanged.
32
- */
33
- export declare function validateInvariants(before: BodySnapshot, after: BodySnapshot, options?: ValidationOptions): void;
@@ -1,49 +0,0 @@
1
- /**
2
- * Invariant validation for DOCX write operations.
3
- *
4
- * Single Responsibility: capture a structural snapshot of w:body and
5
- * compare before / after snapshots to guarantee no accidental breakage.
6
- */
7
- import { getBodyChildren, bodySignature, countTables } from './dom.js';
8
- // ─── Capture ─────────────────────────────────────────────────────────
9
- /** Take a snapshot of the body's structural invariants. */
10
- export function captureSnapshot(body) {
11
- const children = getBodyChildren(body);
12
- return {
13
- bodyChildCount: children.length,
14
- tableCount: countTables(children),
15
- signature: bodySignature(children),
16
- };
17
- }
18
- // ─── Validate ────────────────────────────────────────────────────────
19
- /**
20
- * Compare before / after snapshots.
21
- * Throws a descriptive error if any invariant has been violated,
22
- * preventing the output file from being written.
23
- *
24
- * When `expectedChildDelta` is non-zero (structural ops like insert or
25
- * delete), signature validation is skipped because the body structure
26
- * is *expected* to change. Child count is still validated against
27
- * the expected delta, and table count must remain unchanged.
28
- */
29
- export function validateInvariants(before, after, options) {
30
- const delta = options?.expectedChildDelta ?? 0;
31
- const tableDelta = options?.expectedTableDelta ?? 0;
32
- const expectedChildCount = before.bodyChildCount + delta;
33
- const expectedTableCount = before.tableCount + tableDelta;
34
- const errors = [];
35
- if (expectedChildCount !== after.bodyChildCount) {
36
- errors.push(`Body child count mismatch: expected ${expectedChildCount} (before ${before.bodyChildCount} + delta ${delta}), got ${after.bodyChildCount}`);
37
- }
38
- if (expectedTableCount !== after.tableCount) {
39
- errors.push(`Table count mismatch: expected ${expectedTableCount} (before ${before.tableCount} + delta ${tableDelta}), got ${after.tableCount}`);
40
- }
41
- // Only enforce signature stability when no structural ops changed the body
42
- if (delta === 0 && before.signature !== after.signature) {
43
- errors.push(`Body signature changed:\n before: ${before.signature}\n after: ${after.signature}`);
44
- }
45
- if (errors.length > 0) {
46
- throw new Error('DOCX structural validation failed — output NOT written.\n' +
47
- errors.join('\n'));
48
- }
49
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * DOCX Validation Utilities
3
- *
4
- * Input validation for paths, operations arrays, and image dimensions.
5
- *
6
- * @module docx/validators
7
- */
8
- /** Validate that a DOCX file path is a non-empty string ending in `.docx`. */
9
- export declare function validateDocxPath(path: string): void;
10
- /** Validate that an operations array is a non-empty array. */
11
- export declare function validateOperations(operations: unknown[]): void;
12
- /** Validate optional image width and height (must be positive and finite). */
13
- export declare function validateImageDimensions(width?: number, height?: number): void;
@@ -1,40 +0,0 @@
1
- /**
2
- * DOCX Validation Utilities
3
- *
4
- * Input validation for paths, operations arrays, and image dimensions.
5
- *
6
- * @module docx/validators
7
- */
8
- import { DocxError, DocxErrorCode } from './errors.js';
9
- import { isDocxPath } from './utils/paths.js';
10
- /** Validate that a DOCX file path is a non-empty string ending in `.docx`. */
11
- export function validateDocxPath(path) {
12
- if (!path || typeof path !== 'string') {
13
- throw new DocxError('DOCX path must be a non-empty string', DocxErrorCode.INVALID_PATH, { path });
14
- }
15
- const normalised = path.trim();
16
- if (!normalised) {
17
- throw new DocxError('DOCX path cannot be empty', DocxErrorCode.INVALID_PATH, { path });
18
- }
19
- if (!isDocxPath(normalised)) {
20
- throw new DocxError('Invalid DOCX path: must end with .docx', DocxErrorCode.INVALID_PATH, { path: normalised });
21
- }
22
- }
23
- /** Validate that an operations array is a non-empty array. */
24
- export function validateOperations(operations) {
25
- if (!Array.isArray(operations)) {
26
- throw new DocxError('Operations must be an array', DocxErrorCode.OPERATION_FAILED, { operations });
27
- }
28
- if (operations.length === 0) {
29
- throw new DocxError('Operations array cannot be empty', DocxErrorCode.OPERATION_FAILED, { operations });
30
- }
31
- }
32
- /** Validate optional image width and height (must be positive and finite). */
33
- export function validateImageDimensions(width, height) {
34
- if (width !== undefined && (typeof width !== 'number' || width <= 0 || !Number.isFinite(width))) {
35
- throw new DocxError('Image width must be a positive finite number', DocxErrorCode.INVALID_IMAGE_FILE, { width });
36
- }
37
- if (height !== undefined && (typeof height !== 'number' || height <= 0 || !Number.isFinite(height))) {
38
- throw new DocxError('Image height must be a positive finite number', DocxErrorCode.INVALID_IMAGE_FILE, { height });
39
- }
40
- }
@@ -1,17 +0,0 @@
1
- /**
2
- * writeDocxPatched - the patch-based "update" orchestrator.
3
- *
4
- * Single Responsibility: coordinate the full update pipeline:
5
- * 1. Open DOCX ZIP
6
- * 2. Parse word/document.xml
7
- * 3. Snapshot before
8
- * 4. Apply operations (pass zip for ops that touch auxiliary files)
9
- * 5. Snapshot after
10
- * 6. Validate invariants (accounting for structural deltas)
11
- * 7. Serialize and save
12
- *
13
- * Each step delegates to a single-purpose module, keeping this file
14
- * a pure orchestrator with no direct DOM/XML/ZIP logic.
15
- */
16
- import type { DocxOp, WriteDocxResult } from './types.js';
17
- export declare function writeDocxPatched(inputPath: string, outputPath: string, ops: DocxOp[]): Promise<WriteDocxResult>;
@@ -1,88 +0,0 @@
1
- /**
2
- * writeDocxPatched - the patch-based "update" orchestrator.
3
- *
4
- * Single Responsibility: coordinate the full update pipeline:
5
- * 1. Open DOCX ZIP
6
- * 2. Parse word/document.xml
7
- * 3. Snapshot before
8
- * 4. Apply operations (pass zip for ops that touch auxiliary files)
9
- * 5. Snapshot after
10
- * 6. Validate invariants (accounting for structural deltas)
11
- * 7. Serialize and save
12
- *
13
- * Each step delegates to a single-purpose module, keeping this file
14
- * a pure orchestrator with no direct DOM/XML/ZIP logic.
15
- */
16
- import { loadDocxZip, getDocumentXml, saveDocxZip } from './zip.js';
17
- import { parseXml, serializeXml, getBody } from './dom.js';
18
- import { captureSnapshot, validateInvariants } from './validate.js';
19
- import { applyOp } from './ops/index.js';
20
- /** Structural op types that add/remove body children. */
21
- const STRUCTURAL_INSERT_OPS = new Set([
22
- 'insert_paragraph_after_text',
23
- 'insert_table',
24
- 'insert_image',
25
- ]);
26
- const STRUCTURAL_DELETE_OPS = new Set(['delete_paragraph_at_body_index']);
27
- export async function writeDocxPatched(inputPath, outputPath, ops) {
28
- // 1. Load ZIP
29
- const zip = await loadDocxZip(inputPath);
30
- // 2. Parse document.xml
31
- const xmlStr = getDocumentXml(zip);
32
- const doc = parseXml(xmlStr);
33
- const body = getBody(doc);
34
- // 3. Before-snapshot
35
- const before = captureSnapshot(body);
36
- // 4. Apply ops — pass zip for ops that modify auxiliary files
37
- const results = [];
38
- const warnings = [];
39
- for (const op of ops) {
40
- try {
41
- const result = applyOp(body, op, zip);
42
- results.push(result);
43
- if (result.status === 'skipped') {
44
- warnings.push(`Op ${op.type} skipped: ${result.reason ?? 'unknown'}`);
45
- }
46
- }
47
- catch (err) {
48
- const msg = err instanceof Error ? err.message : String(err);
49
- warnings.push(`Op ${op.type} failed: ${msg}`);
50
- results.push({
51
- op,
52
- status: 'skipped',
53
- matched: 0,
54
- reason: `error: ${msg}`,
55
- });
56
- }
57
- }
58
- // 5. Compute expected structural delta from applied ops
59
- let expectedChildDelta = 0;
60
- let expectedTableDelta = 0;
61
- for (const r of results) {
62
- if (r.status !== 'applied')
63
- continue;
64
- if (STRUCTURAL_INSERT_OPS.has(r.op.type))
65
- expectedChildDelta += 1;
66
- if (STRUCTURAL_DELETE_OPS.has(r.op.type))
67
- expectedChildDelta -= 1;
68
- if (r.op.type === 'insert_table')
69
- expectedTableDelta += 1;
70
- }
71
- // 6. After-snapshot
72
- const after = captureSnapshot(body);
73
- // 7. Validate — throws if structural invariants are broken
74
- validateInvariants(before, after, { expectedChildDelta, expectedTableDelta });
75
- // 8. Serialize and save (document.xml + any zip-level changes)
76
- const newXml = serializeXml(doc);
77
- await saveDocxZip(zip, newXml, outputPath);
78
- // 9. Build stats
79
- const stats = {
80
- tablesBefore: before.tableCount,
81
- tablesAfter: after.tableCount,
82
- bodyChildrenBefore: before.bodyChildCount,
83
- bodyChildrenAfter: after.bodyChildCount,
84
- bodySignatureBefore: before.signature,
85
- bodySignatureAfter: after.signature,
86
- };
87
- return { outputPath, results, stats, warnings };
88
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,63 +0,0 @@
1
- /**
2
- * Quick test: extract XML, show context, then edit a checkbox.
3
- */
4
- import { extractDocxXml, editDocxXml } from './xml-view.js';
5
- async function main() {
6
- const input = '/Users/eduardsruzga/Downloads/dcox/Wedding Photo Checklist.docx';
7
- const output = '/Users/eduardsruzga/Downloads/dcox/Wedding Photo Checklist - XML Edit Test.docx';
8
- // 1. Extract and show stats
9
- const view = await extractDocxXml(input);
10
- console.log(`Extracted XML: ${view.lineCount} lines, ${view.rawSize} raw chars`);
11
- // 2. Show context around "Bride hairstyling" with EXACT indentation
12
- const lines = view.xml.split('\n');
13
- for (let i = 0; i < lines.length; i++) {
14
- if (lines[i].includes('Bride hairstyling')) {
15
- console.log(`\nFound "Bride hairstyling" at line ${i + 1}:`);
16
- for (let j = Math.max(0, i - 20); j <= Math.min(lines.length - 1, i + 5); j++) {
17
- console.log(`${String(j + 1).padStart(4)}|${lines[j]}`);
18
- }
19
- // 3. Build the old/new strings from ACTUAL lines
20
- // The ☐ should be around line i-20 to i-15
21
- // Find it by scanning backwards
22
- let checkboxLine = -1;
23
- for (let j = i - 1; j >= Math.max(0, i - 25); j--) {
24
- if (lines[j].includes('☐')) {
25
- checkboxLine = j;
26
- break;
27
- }
28
- }
29
- console.log(`\nCheckbox ☐ found at line ${checkboxLine + 1}: "${lines[checkboxLine]}"`);
30
- // Use just enough context: the checkbox line + next line to make it unique
31
- const oldStr = lines[checkboxLine];
32
- const newStr = oldStr.replace('☐', '☑');
33
- console.log(`\nold: "${oldStr}"`);
34
- console.log(`new: "${newStr}"`);
35
- // Check uniqueness
36
- const matches = lines.filter(l => l === oldStr).length;
37
- console.log(`Exact line matches in document: ${matches}`);
38
- if (matches > 1) {
39
- // Expand context until we get exactly 1 match
40
- for (let ctx = 3; ctx <= 30; ctx++) {
41
- const contextOld = lines.slice(checkboxLine, checkboxLine + ctx).join('\n');
42
- const contextMatches = view.xml.split(contextOld).length - 1;
43
- if (contextMatches === 1) {
44
- console.log(`\nUnique match found with ${ctx}-line context`);
45
- const contextNew = contextOld.replace('☐', '☑');
46
- const result = await editDocxXml(input, output, contextOld, contextNew);
47
- console.log(`Edit result:`, result);
48
- break;
49
- }
50
- else {
51
- console.log(`${ctx} lines of context: ${contextMatches} matches`);
52
- }
53
- }
54
- }
55
- else {
56
- const result = await editDocxXml(input, output, oldStr, newStr);
57
- console.log(`\nEdit result:`, result);
58
- }
59
- break;
60
- }
61
- }
62
- }
63
- main().catch(console.error);
@@ -1,56 +0,0 @@
1
- /**
2
- * DOCX XML View
3
- *
4
- * Exposes word/document.xml from a DOCX file as pretty-printed XML that can be
5
- * read with offset/length pagination and edited with find/replace, just like a
6
- * text file. All formatting is preserved because we operate on the actual XML.
7
- *
8
- * Round-trip: DOCX → unzip → pretty-print → edit → compact → repack → DOCX
9
- */
10
- /**
11
- * Pretty-print XML by splitting tags onto separate lines with indentation.
12
- *
13
- * Preserves content inside text nodes exactly. Self-closing tags, inline
14
- * open+close tags (e.g. <w:t>text</w:t>), and pure closing tags are all
15
- * handled so that compact→pretty→compact is lossless.
16
- */
17
- export declare function prettyPrintXml(xml: string): string;
18
- /**
19
- * Compact pretty-printed XML back to a single line.
20
- *
21
- * CRITICAL: Must not introduce or remove whitespace inside <w:t> text nodes
22
- * or break xml:space="preserve" semantics. We achieve this by only stripping
23
- * leading indentation (which we added) and joining lines. The original XML
24
- * had no newlines between tags, so this restores the original form.
25
- */
26
- export declare function compactXml(prettyXml: string): string;
27
- export interface DocxXmlReadResult {
28
- /** Pretty-printed XML content */
29
- content: string;
30
- /** Total number of lines */
31
- lineCount: number;
32
- /** Source DOCX path */
33
- path: string;
34
- /** Size of the raw (compact) XML in chars */
35
- rawSize: number;
36
- }
37
- /**
38
- * Read the document.xml from a DOCX as pretty-printed, line-based XML.
39
- * Supports offset/length pagination just like text file reading.
40
- */
41
- export declare function readDocxXml(filePath: string, offset?: number, length?: number): Promise<DocxXmlReadResult>;
42
- /**
43
- * Apply a find/replace edit to a DOCX file's XML and write a new DOCX.
44
- *
45
- * The edit operates on the pretty-printed XML so that line-based context
46
- * from read_file can be used directly as the search string. After editing,
47
- * the XML is compacted back and repacked into the DOCX zip.
48
- *
49
- * @returns result with status, match count, and output path
50
- */
51
- export declare function editDocxXml(inputPath: string, outputPath: string, oldStr: string, newStr: string, expectedReplacements?: number): Promise<{
52
- status: 'applied' | 'no_match' | 'unexpected_count';
53
- matchCount: number;
54
- outputPath: string;
55
- message?: string;
56
- }>;