word-to-markdown 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "{}"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright {yyyy} {name of copyright owner}
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # Word to Markdown
2
+
3
+ Convert Word documents to beautiful Markdown. Via command line or in your browser. An even better version of the original [`word-to-markdown`](https://github.com/benbalter/word-to-markdown).
4
+
5
+ Try it in your browser at [word2md.com](https://word2md.com), or use it from the command line — no clone required:
6
+
7
+ ```console
8
+ npx word-to-markdown input.docx > output.md
9
+ ```
10
+
11
+ ## Supports
12
+
13
+ - Paragraphs
14
+ - Numbered lists
15
+ - Bullet lists
16
+ - Nested Lists
17
+ - Headings
18
+ - Lists
19
+ - Tables
20
+ - Footnotes and endnotes
21
+ - Images
22
+ - Bold, italics, underlines, strikethrough, superscript and subscript.
23
+ - Links
24
+ - Line breaks
25
+ - Text boxes
26
+ - Comments
27
+
28
+ ## How is this different from the original?
29
+
30
+ _TL;DR: This project is a complete rewrite, using modern tools and libraries, and is much faster and more reliable. The output should be the same or better. [Feedback welcome!](https://github.com/benbalter/word-to-markdown-js/issues/new)_
31
+
32
+ ## A note on privacy
33
+
34
+ Word to Markdown is designed with privacy as a core principle. The application operates entirely client-side:
35
+
36
+ - **Complete client-side processing**: When using the web interface, all document conversion happens locally in your browser using JavaScript. Your documents never leave your computer.
37
+ - **No server uploads**: When using the web interface, files are processed entirely on your device. No document content is ever transmitted to any server.
38
+ - **No personal data collection**: The application does not collect, store, or transmit any personal information or document contents.
39
+ - **Privacy-first analytics**: The hosted version at word2md.com uses only privacy-centric Cloudflare Analytics for anonymous usage statistics. No Google Analytics or user tracking.
40
+ - **Self-hosting option**: For maximum privacy, you can run the application locally or self-host it without any analytics whatsoever.
41
+
42
+ Whether you use the command line tool, run it locally in your browser, or use the hosted version, your documents and privacy are protected.
43
+
44
+ ## Command line
45
+
46
+ Run it directly with `npx` (downloads and runs the latest published version):
47
+
48
+ ```console
49
+ npx word-to-markdown path/to/your/file.docx > output.md
50
+ ```
51
+
52
+ Or install it globally to get the `w2m` command:
53
+
54
+ ```console
55
+ npm install -g word-to-markdown
56
+ w2m path/to/your/file.docx > output.md
57
+ ```
58
+
59
+ ## Use as a library
60
+
61
+ ```console
62
+ npm install word-to-markdown
63
+ ```
64
+
65
+ ```js
66
+ import convert, { convertWithWarnings } from 'word-to-markdown';
67
+
68
+ // Just the Markdown:
69
+ const markdown = await convert('path/to/your/file.docx');
70
+
71
+ // Markdown plus any document warnings (e.g. encryption, sensitivity labels):
72
+ const { markdown, warnings } = await convertWithWarnings(
73
+ 'path/to/your/file.docx',
74
+ );
75
+ ```
76
+
77
+ In the browser, pass an `ArrayBuffer` instead of a file path.
78
+
79
+ ## Running Locally
80
+
81
+ ### Get set up
82
+
83
+ 1. Clone the repo
84
+ 2. Run `npm install`
85
+
86
+ ### Command line (from source)
87
+
88
+ Run `npm run build:js` once, then `node build/cli.js path/to/your/file.docx`.
89
+
90
+ ### Run the site locally
91
+
92
+ `npm run dev` starts the Astro dev server. To preview a production build, run
93
+ `npm run build` followed by `npm run preview`.
94
+
95
+ ## Self-Hosting
96
+
97
+ To self-host the static site using Docker Compose:
98
+
99
+ 1. Clone the repository
100
+ 2. Run `npm install && npm run build`
101
+ 3. Run `docker-compose up -d`
102
+ 4. Access at http://localhost:3000
103
+
104
+ ## More context
105
+
106
+ See the README of [the original Word to Markdown](https://github.com/benbalter/word-to-markdown?tab=readme-ov-file#the-problem) for the project's motivation.
107
+
108
+ ### The old way
109
+
110
+ [The Original](https://github.com/benbalter/word-to-markdown) Word to Markdown is 10 years old. The conversion process was as follows:
111
+
112
+ 1. Use [LibreOffice](https://www.libreoffice.org/) to convert the Word document to HTML.
113
+ 2. Use a bunch of RegEx to clean up the HTML
114
+ 3. User [Premailer](https://github.com/premailer/premailer) to inline the CSS
115
+ 4. Use [Nokogiri](https://nokogiri.org) to manipulate the HTML further
116
+ 5. Use [Reverse Markdown](https://github.com/xijo/reverse_markdown) to convert the HTML to Markdown
117
+ 6. Use a bunch of RegEx to clean up the Markdown
118
+
119
+ Not only did this process require installing and shelling out to a huge binary (LibreOffice), but it was very fragile, and key projects like Reverse Markdown are no longer maintained. I tried experimenting with Pandoc, but it had many of the same limitation.
120
+
121
+ ### The new way
122
+
123
+ 1. Use [Mammoth.js](https://github.com/mwilliamson/mammoth.js/) to convert the Word document to HTML.
124
+ 2. Use [Turndown](https://github.com/mixmark-io/turndown) to convert the HTML to Markdown.
125
+ 3. Use [Markdownlint](https://github.com/DavidAnson/markdownlint) to clean up the Markdown.
126
+
127
+ All three of these projects are actively maintained and heavily used, and allows us to convert the document faster, and entirely in JavaScript. Heck, I think theoretically, this could run in the browser for added privacy.
128
+
129
+ It's still in beta, but so far, I've found the output to be better, with much less manual cleanup required. Notice something is off? Please [open an issue](https://github.com/benbalter/word-to-markdown-js/issues/new).
130
+
131
+ One note: This project does not yet attempt to guess heading levels based on font size. It could, but it's not yet implemented.
package/build/cli.js ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ import { __awaiter } from "tslib";
3
+ import { Command } from 'commander';
4
+ import { convertWithWarnings, UnsupportedFileError, FileNotFoundError, InvalidFileError, FilePermissionError, ConversionError, } from './main.js';
5
+ const program = new Command();
6
+ program.name('w2m');
7
+ program.description('Convert Word documents to beautiful Markdown');
8
+ program
9
+ .command('convert', { isDefault: true })
10
+ .argument('<file>', 'The Word document to convert')
11
+ .action((file) => __awaiter(void 0, void 0, void 0, function* () {
12
+ try {
13
+ const result = yield convertWithWarnings(file);
14
+ // Display warnings to stderr if any
15
+ if (result.warnings.length > 0) {
16
+ result.warnings.forEach((warning) => {
17
+ console.error(warning);
18
+ });
19
+ console.error(''); // Empty line for separation
20
+ }
21
+ // Output markdown to stdout
22
+ console.log(result.markdown);
23
+ }
24
+ catch (error) {
25
+ // Handle our custom errors with user-friendly messages
26
+ if (error instanceof UnsupportedFileError ||
27
+ error instanceof FileNotFoundError ||
28
+ error instanceof InvalidFileError ||
29
+ error instanceof FilePermissionError ||
30
+ error instanceof ConversionError) {
31
+ console.error(`Error: ${error.message}`);
32
+ process.exit(1);
33
+ }
34
+ // Handle unexpected errors (including non-Error objects)
35
+ console.error('Error:', error instanceof Error ? error.message : String(error));
36
+ process.exit(1);
37
+ }
38
+ }));
39
+ program.parse();
40
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,GAChB,MAAM,WAAW,CAAC;AAEnB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAC9B,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACpB,OAAO,CAAC,WAAW,CAAC,8CAA8C,CAAC,CAAC;AACpE,OAAO;KACJ,OAAO,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;KACvC,QAAQ,CAAC,QAAQ,EAAE,8BAA8B,CAAC;KAClD,MAAM,CAAC,CAAO,IAAI,EAAE,EAAE;IACrB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAE/C,oCAAoC;QACpC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBAClC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC,CAAC,CAAC;YACH,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,4BAA4B;QACjD,CAAC;QAED,4BAA4B;QAC5B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,uDAAuD;QACvD,IACE,KAAK,YAAY,oBAAoB;YACrC,KAAK,YAAY,iBAAiB;YAClC,KAAK,YAAY,gBAAgB;YACjC,KAAK,YAAY,mBAAmB;YACpC,KAAK,YAAY,eAAe,EAChC,CAAC;YACD,OAAO,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,yDAAyD;QACzD,OAAO,CAAC,KAAK,CACX,QAAQ,EACR,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAA,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
package/build/main.js ADDED
@@ -0,0 +1,519 @@
1
+ import { __awaiter } from "tslib";
2
+ import TurndownService from '@joplin/turndown';
3
+ import * as turndownPluginGfm from '@joplin/turndown-plugin-gfm';
4
+ import * as mammoth from 'mammoth';
5
+ import * as markdownlint from 'markdownlint/sync';
6
+ import { applyFixes } from 'markdownlint';
7
+ import { parse } from 'node-html-parser';
8
+ import * as prettier from 'prettier';
9
+ import * as prettierMarkdown from 'prettier/plugins/markdown';
10
+ import JSZip from 'jszip';
11
+ import fs from 'fs/promises';
12
+ import path from 'path';
13
+ // Custom error class for unsupported file formats
14
+ export class UnsupportedFileError extends Error {
15
+ constructor(message) {
16
+ super(message);
17
+ this.name = 'UnsupportedFileError';
18
+ }
19
+ }
20
+ // Custom error class for file not found
21
+ export class FileNotFoundError extends Error {
22
+ constructor(filePath) {
23
+ const location = filePath ? `: "${filePath}"` : '';
24
+ super(`File not found${location}. Please check that the file exists and the path is correct.`);
25
+ this.name = 'FileNotFoundError';
26
+ }
27
+ }
28
+ // Custom error class for invalid/corrupted files
29
+ export class InvalidFileError extends Error {
30
+ constructor(filePath) {
31
+ const location = filePath ? `: "${filePath}"` : '';
32
+ super(`Invalid file${location}. The file is not a valid .docx file or is corrupted. Please ensure the file is a valid Microsoft Word document (.docx format).`);
33
+ this.name = 'InvalidFileError';
34
+ }
35
+ }
36
+ // Custom error class for permission errors
37
+ export class FilePermissionError extends Error {
38
+ constructor(filePath) {
39
+ const location = filePath ? `: "${filePath}"` : '';
40
+ super(`Permission denied${location}. Cannot read the file. Please check file permissions.`);
41
+ this.name = 'FilePermissionError';
42
+ }
43
+ }
44
+ // Custom error class for general conversion errors
45
+ export class ConversionError extends Error {
46
+ constructor(message, originalError) {
47
+ super(message);
48
+ this.name = 'ConversionError';
49
+ // Capture stack trace if available (Node.js/V8 specific)
50
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
51
+ const ErrorWithCapture = Error;
52
+ if (typeof ErrorWithCapture.captureStackTrace === 'function') {
53
+ ErrorWithCapture.captureStackTrace(this, this.constructor);
54
+ }
55
+ if (originalError) {
56
+ // Use standard error chaining for better debugging tool support
57
+ this.cause = originalError;
58
+ }
59
+ }
60
+ }
61
+ const defaultTurndownOptions = {
62
+ headingStyle: 'atx',
63
+ codeBlockStyle: 'fenced',
64
+ bulletListMarker: '-',
65
+ };
66
+ // Check if a file path has a .doc extension (unsupported format)
67
+ export function validateFileExtension(filePath) {
68
+ // Use manual extension parsing (works in both Node.js and browser)
69
+ const filename = filePath.toLowerCase();
70
+ const lastDotIndex = filename.lastIndexOf('.');
71
+ const ext = lastDotIndex !== -1 ? filename.substring(lastDotIndex) : '';
72
+ if (ext === '.doc') {
73
+ throw new UnsupportedFileError('This tool only supports .docx files, not .doc files. Please save your document as a .docx file and try again.');
74
+ }
75
+ }
76
+ // Validates that a file path is safe to use (Node.js only)
77
+ // Prevents path traversal attacks by checking for parent directory references
78
+ function validateFilePath(filePath) {
79
+ // Check for path traversal attempts
80
+ if (filePath.includes('..')) {
81
+ throw new Error('Invalid file path: path traversal not allowed');
82
+ }
83
+ // Resolve to absolute path to check for traversal
84
+ // Note: This uses the path module which is Node.js-only, but this function
85
+ // is only called in Node.js contexts (CLI, server, direct API use with file paths)
86
+ const resolvedPath = path.resolve(filePath);
87
+ // Check for absolute paths to dangerous system directories (Unix-like systems)
88
+ const dangerousPaths = ['/etc/', '/sys/', '/proc/', '/root/', '/boot/'];
89
+ for (const dangerousPath of dangerousPaths) {
90
+ if (resolvedPath.startsWith(dangerousPath)) {
91
+ throw new Error('Invalid file path: access to system directories not allowed');
92
+ }
93
+ }
94
+ // Check for Windows system directories
95
+ const windowsDangerousPaths = ['C:\\Windows\\', 'C:\\Program Files\\'];
96
+ for (const dangerousPath of windowsDangerousPaths) {
97
+ if (resolvedPath.toUpperCase().startsWith(dangerousPath.toUpperCase())) {
98
+ throw new Error('Invalid file path: access to system directories not allowed');
99
+ }
100
+ }
101
+ }
102
+ // Map of common HTML entities to decode
103
+ const decodeMap = {
104
+ '&amp;': '&',
105
+ // Don't decode &lt; and &gt; in our custom decoder
106
+ // Let Turndown handle them appropriately based on context
107
+ '&quot;': '"',
108
+ '&#39;': "'",
109
+ '&#x27;': "'",
110
+ '&apos;': "'",
111
+ '&nbsp;': ' ',
112
+ '&copy;': '©',
113
+ '&reg;': '®',
114
+ '&trade;': '™',
115
+ '&hellip;': '…',
116
+ '&mdash;': '—',
117
+ '&ndash;': '–',
118
+ '&lsquo;': '\u2018',
119
+ '&rsquo;': '\u2019',
120
+ '&ldquo;': '\u201C',
121
+ '&rdquo;': '\u201D',
122
+ };
123
+ // Maximum iterations for decoding nested HTML entities to prevent infinite loops
124
+ const MAX_DECODE_ITERATIONS = 10;
125
+ // Decode HTML entities in text content
126
+ function decodeHtmlEntities(html) {
127
+ function decodeOnce(text) {
128
+ // Use a more specific regex pattern to avoid catastrophic backtracking
129
+ // Match: & followed by either:
130
+ // - a-zA-Z letters (for named entities like &amp;, &nbsp;, etc.)
131
+ // - # followed by digits (for numeric entities like &#169;)
132
+ // - #[xX] followed by hex digits (for hex entities like &#x27; or &#X27;)
133
+ // All terminated with a semicolon
134
+ return text.replace(/&(?:[a-zA-Z]+|#\d+|#[xX][0-9a-fA-F]+);/g, (entity) => {
135
+ // Handle named entities
136
+ if (decodeMap[entity]) {
137
+ return decodeMap[entity];
138
+ }
139
+ // Handle numeric entities &#123;
140
+ const numericMatch = entity.match(/^&#(\d+);$/);
141
+ if (numericMatch) {
142
+ return String.fromCharCode(parseInt(numericMatch[1], 10));
143
+ }
144
+ // Handle hex entities &#x1A;
145
+ const hexMatch = entity.match(/^&#x([0-9a-fA-F]+);$/i);
146
+ if (hexMatch) {
147
+ return String.fromCharCode(parseInt(hexMatch[1], 16));
148
+ }
149
+ // Return original if not recognized
150
+ return entity;
151
+ });
152
+ }
153
+ // Keep decoding until no more entities are found (handles double/triple encoding)
154
+ let decoded = html;
155
+ let prevDecoded;
156
+ let iterations = 0;
157
+ do {
158
+ prevDecoded = decoded;
159
+ decoded = decodeOnce(decoded);
160
+ iterations++;
161
+ } while (decoded !== prevDecoded &&
162
+ decoded.includes('&') &&
163
+ iterations < MAX_DECODE_ITERATIONS);
164
+ return decoded;
165
+ }
166
+ // Turndown will add an empty header if the first row
167
+ // of the table isn't `<th>` elements. This function
168
+ // converts the first row of a table to `<th>` elements
169
+ // so that it renders correctly in Markdown.
170
+ // Common unicode bullets that might appear in Word documents - compiled once
171
+ const unicodeBullets = ['•', '◦', '▪', '▫', '‣', '⁃', '∙', '·'];
172
+ const bulletRegex = new RegExp(`^\\s*[${unicodeBullets.map((b) => b.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('')}]\\s*`);
173
+ // Process HTML in a single pass: convert table headers and remove unicode bullets
174
+ // This is more efficient than parsing the HTML twice
175
+ function processHtml(html) {
176
+ const root = parse(html);
177
+ // Process tables - convert first row to table headers
178
+ root.querySelectorAll('table').forEach((table) => {
179
+ const firstRow = table.querySelector('tr');
180
+ if (!firstRow)
181
+ return;
182
+ // If first row already has TH elements, leave it alone
183
+ if (firstRow.querySelector('th'))
184
+ return;
185
+ // Check if first row is empty or has only empty cells
186
+ const cells = firstRow.querySelectorAll('td');
187
+ const isEmpty = cells.length === 0 || cells.every((cell) => { var _a; return !((_a = cell.textContent) === null || _a === void 0 ? void 0 : _a.trim()); });
188
+ if (isEmpty) {
189
+ // Remove empty first row and find the first non-empty row to convert
190
+ firstRow.remove();
191
+ const nextRow = table.querySelector('tr');
192
+ if (nextRow) {
193
+ nextRow.querySelectorAll('td').forEach((cell) => {
194
+ cell.tagName = 'th';
195
+ });
196
+ }
197
+ }
198
+ else {
199
+ // Convert first row TD elements to TH
200
+ cells.forEach((cell) => {
201
+ cell.tagName = 'th';
202
+ });
203
+ }
204
+ });
205
+ // Process lists - remove unicode bullets from unnumbered list items
206
+ root.querySelectorAll('ul li').forEach((listItem) => {
207
+ // Get the text content and remove unicode bullets from the beginning
208
+ const textContent = listItem.innerHTML;
209
+ const cleanedContent = textContent.replace(bulletRegex, '');
210
+ if (cleanedContent !== textContent) {
211
+ listItem.innerHTML = cleanedContent;
212
+ }
213
+ });
214
+ return root.toString();
215
+ }
216
+ // Reusable TurndownService instance to avoid recreating it for each conversion
217
+ let turndownServiceInstance = null;
218
+ function getTurndownService(options = {}) {
219
+ // Create a new instance if options are provided, otherwise reuse the singleton
220
+ if (Object.keys(options).length > 0) {
221
+ const service = new TurndownService(Object.assign(Object.assign({}, options), defaultTurndownOptions));
222
+ service.use(turndownPluginGfm.gfm);
223
+ return service;
224
+ }
225
+ if (!turndownServiceInstance) {
226
+ turndownServiceInstance = new TurndownService(defaultTurndownOptions);
227
+ turndownServiceInstance.use(turndownPluginGfm.gfm);
228
+ }
229
+ return turndownServiceInstance;
230
+ }
231
+ // Convert HTML to GitHub-flavored Markdown
232
+ export function htmlToMd(html, options = {}) {
233
+ // Decode HTML entities before conversion
234
+ const decodedHtml = decodeHtmlEntities(html);
235
+ const turndownService = getTurndownService(options);
236
+ return turndownService.turndown(decodedHtml).trim();
237
+ }
238
+ // Pre-compiled regex patterns for better performance
239
+ const numberedListRegex = /^(\s*)(\d+)\.\s/gm;
240
+ const nonBreakingSpacesRegex = /[\u00A0\u2007\u202F\u2060\uFEFF]/g;
241
+ const smartQuotesRegex = /[\u201C\u201D\u2018\u2019\u2013\u2014]/g;
242
+ // Map for non-breaking space replacements
243
+ const nonBreakingSpaceMap = {
244
+ '\u00A0': ' ', // Non-breaking space
245
+ '\u2007': ' ', // Figure space
246
+ '\u202F': ' ', // Narrow no-break space
247
+ '\u2060': '', // Word joiner (zero-width non-breaking space)
248
+ '\uFEFF': '', // Zero-width no-break space (BOM)
249
+ };
250
+ // Map for smart quote replacements
251
+ const smartQuoteMap = {
252
+ '\u201C': '"', // Left double quotation mark
253
+ '\u201D': '"', // Right double quotation mark
254
+ '\u2018': "'", // Left single quotation mark
255
+ '\u2019': "'", // Right single quotation mark
256
+ '\u2013': '-', // En dash
257
+ '\u2014': '-', // Em dash
258
+ };
259
+ // Convert numbered lists to bullet lists
260
+ function convertNumberedListsToBullets(md) {
261
+ // Replace numbered list items with bullet list items
262
+ // This regex matches lines that start with optional whitespace, a number, a dot, and a space
263
+ return md.replace(numberedListRegex, '$1- ');
264
+ }
265
+ // Remove unicode non-breaking spaces and convert smart quotes to ASCII in a single pass
266
+ function normalizeText(md) {
267
+ return md
268
+ .replace(nonBreakingSpacesRegex, (char) => nonBreakingSpaceMap[char])
269
+ .replace(smartQuotesRegex, (char) => smartQuoteMap[char]);
270
+ }
271
+ // Lint the Markdown and correct any issues
272
+ function lint(md) {
273
+ const lintResult = markdownlint.lint({ strings: { md } });
274
+ return applyFixes(md, lintResult['md']).trim();
275
+ }
276
+ // Format the Markdown with Prettier
277
+ function prettify(md) {
278
+ return __awaiter(this, void 0, void 0, function* () {
279
+ const formatted = yield prettier.format(md, {
280
+ parser: 'markdown',
281
+ plugins: [prettierMarkdown],
282
+ });
283
+ return formatted.trim();
284
+ });
285
+ }
286
+ // Extract document properties from a .docx file
287
+ export function extractDocumentProperties(input) {
288
+ return __awaiter(this, void 0, void 0, function* () {
289
+ const properties = {};
290
+ try {
291
+ let arrayBuffer;
292
+ if (typeof input === 'string') {
293
+ // Validate the file path to prevent path traversal attacks
294
+ validateFilePath(input);
295
+ // Read file from path and convert to ArrayBuffer
296
+ const fileBuffer = yield fs.readFile(input);
297
+ const slicedBuffer = fileBuffer.buffer.slice(fileBuffer.byteOffset, fileBuffer.byteOffset + fileBuffer.byteLength);
298
+ // Ensure we have an ArrayBuffer (not SharedArrayBuffer)
299
+ // In practice, Node.js Buffer.buffer returns an ArrayBuffer, but TypeScript
300
+ // can't guarantee this, so we handle both cases
301
+ if (slicedBuffer instanceof ArrayBuffer) {
302
+ arrayBuffer = slicedBuffer;
303
+ }
304
+ else {
305
+ // Convert SharedArrayBuffer to ArrayBuffer by copying the data
306
+ const uint8Array = new Uint8Array(slicedBuffer);
307
+ const newArrayBuffer = new ArrayBuffer(uint8Array.byteLength);
308
+ new Uint8Array(newArrayBuffer).set(uint8Array);
309
+ arrayBuffer = newArrayBuffer;
310
+ }
311
+ }
312
+ else {
313
+ arrayBuffer = input;
314
+ }
315
+ const zip = yield JSZip.loadAsync(arrayBuffer);
316
+ // Check for encryption - encrypted files have EncryptionInfo and EncryptedPackage
317
+ const encryptionInfo = zip.file('EncryptionInfo');
318
+ if (encryptionInfo) {
319
+ properties.encryption = true;
320
+ }
321
+ // Try to read core properties
322
+ const corePropsFile = zip.file('docProps/core.xml');
323
+ if (corePropsFile) {
324
+ const coreXml = yield corePropsFile.async('string');
325
+ // Look for keywords that might indicate sensitivity/confidentiality
326
+ if (coreXml.toLowerCase().includes('confidential') ||
327
+ coreXml.toLowerCase().includes('sensitive')) {
328
+ properties.confidentiality = 'detected in core properties';
329
+ }
330
+ }
331
+ // Try to read custom properties
332
+ const customPropsFile = zip.file('docProps/custom.xml');
333
+ if (customPropsFile) {
334
+ const customXml = yield customPropsFile.async('string');
335
+ const customXmlLower = customXml.toLowerCase();
336
+ // Use regex patterns to detect sensitivity/confidentiality properties
337
+ // We use regex instead of full XML parsing for performance and simplicity,
338
+ // as we only need to detect the presence of specific property names, not extract values
339
+ // Pattern matches common sensitivity/confidentiality property names:
340
+ // - "Sensitivity" (standard Office property)
341
+ // - "MSIP_Label_*" (Microsoft Information Protection labels)
342
+ // - Any property with "confidential" or "sensitive" in the name
343
+ // We only check for the property name attribute existence, not the full element content,
344
+ // to avoid potential catastrophic backtracking on large/malformed XML
345
+ const sensitivityPattern = /<property[^>]*\bname="(?:Sensitivity|MSIP_Label_[^"]*|[^"]*(?:confidential|sensitive)[^"]*)"[^>]*>/gi;
346
+ const hasSensitivityProperty = sensitivityPattern.test(customXml);
347
+ const hasConfidentialText = customXmlLower.includes('confidential');
348
+ const hasMSIPLabel = customXmlLower.includes('msip_label');
349
+ if (hasSensitivityProperty || hasMSIPLabel) {
350
+ properties.sensitivity = 'detected in custom properties';
351
+ }
352
+ if (hasConfidentialText) {
353
+ properties.confidentiality = 'detected in custom properties';
354
+ }
355
+ }
356
+ // Check for document protection
357
+ const settingsFile = zip.file('word/settings.xml');
358
+ if (settingsFile) {
359
+ const settingsXml = yield settingsFile.async('string');
360
+ if (settingsXml.includes('<w:documentProtection') ||
361
+ settingsXml.includes('<w:writeProtection')) {
362
+ properties.protection = true;
363
+ }
364
+ }
365
+ }
366
+ catch (error) {
367
+ // If we can't extract properties, just continue without them
368
+ // This might happen with encrypted, corrupted, or non-standard .docx files
369
+ // We log the error in development mode but don't fail the conversion
370
+ if (process.env.NODE_ENV === 'development') {
371
+ console.warn('Failed to extract document properties:', error);
372
+ }
373
+ }
374
+ return properties;
375
+ });
376
+ }
377
+ // Generate warnings based on document properties
378
+ export function generateWarnings(properties) {
379
+ const warnings = [];
380
+ if (properties.encryption) {
381
+ warnings.push('Warning: This document appears to be encrypted. Conversion may not include all content or may fail entirely.');
382
+ }
383
+ if (properties.sensitivity) {
384
+ warnings.push(`Warning: This document has sensitivity labels (${properties.sensitivity}). Please ensure you have permission to convert and share this content.`);
385
+ }
386
+ if (properties.confidentiality) {
387
+ warnings.push(`Warning: This document contains confidentiality markers (${properties.confidentiality}). Please verify that conversion is authorized.`);
388
+ }
389
+ if (properties.protection) {
390
+ warnings.push('Warning: This document has editing restrictions enabled. Some content may not convert properly.');
391
+ }
392
+ return warnings;
393
+ }
394
+ // Converts a Word document to crisp, clean Markdown with warnings
395
+ export function convertWithWarnings(input_1) {
396
+ return __awaiter(this, arguments, void 0, function* (input, options = {}) {
397
+ // Normalize input so that the underlying .docx content is read at most once
398
+ let mammothInput;
399
+ let propertiesInput = input;
400
+ if (typeof input === 'string') {
401
+ // Validate file extension for file path inputs
402
+ validateFileExtension(input);
403
+ // Validate the file path to prevent path traversal attacks
404
+ validateFilePath(input);
405
+ // Read the file once and share the buffer between
406
+ // property extraction and Mammoth conversion to avoid
407
+ // redundant disk reads for large documents
408
+ const fileBuffer = yield fs.readFile(input);
409
+ const slicedBuffer = fileBuffer.buffer.slice(fileBuffer.byteOffset, fileBuffer.byteOffset + fileBuffer.byteLength);
410
+ // Ensure we have an ArrayBuffer (not SharedArrayBuffer) for property extraction
411
+ let arrayBuffer;
412
+ if (slicedBuffer instanceof ArrayBuffer) {
413
+ arrayBuffer = slicedBuffer;
414
+ }
415
+ else {
416
+ // Convert SharedArrayBuffer to ArrayBuffer by copying the data
417
+ const uint8Array = new Uint8Array(slicedBuffer);
418
+ const newArrayBuffer = new ArrayBuffer(uint8Array.byteLength);
419
+ new Uint8Array(newArrayBuffer).set(uint8Array);
420
+ arrayBuffer = newArrayBuffer;
421
+ }
422
+ propertiesInput = arrayBuffer;
423
+ mammothInput = { buffer: fileBuffer };
424
+ }
425
+ else {
426
+ propertiesInput = input;
427
+ // In Node.js, mammoth expects { buffer }, in browser it expects { arrayBuffer }
428
+ // Check for Buffer availability to determine the environment
429
+ if (typeof Buffer !== 'undefined') {
430
+ mammothInput = { buffer: Buffer.from(input) };
431
+ }
432
+ else {
433
+ mammothInput = { arrayBuffer: input };
434
+ }
435
+ }
436
+ // Extract document properties to check for confidentiality flags
437
+ const properties = yield extractDocumentProperties(propertiesInput);
438
+ const warnings = generateWarnings(properties);
439
+ const mammothResult = yield mammoth.convertToHtml(mammothInput, options.mammoth);
440
+ const processedHtml = processHtml(mammothResult.value);
441
+ const md = htmlToMd(processedHtml, options.turndown);
442
+ const mdWithBullets = convertNumberedListsToBullets(md);
443
+ const normalizedMd = normalizeText(mdWithBullets);
444
+ const cleanedMd = lint(normalizedMd);
445
+ const formattedMd = yield prettify(cleanedMd);
446
+ return {
447
+ markdown: formattedMd,
448
+ warnings,
449
+ };
450
+ });
451
+ }
452
+ // Converts a Word document to crisp, clean Markdown
453
+ export default function convert(input_1) {
454
+ return __awaiter(this, arguments, void 0, function* (input, options = {}) {
455
+ let inputObj;
456
+ let filePath;
457
+ try {
458
+ if (typeof input === 'string') {
459
+ filePath = input;
460
+ // Validate file extension for file path inputs
461
+ validateFileExtension(input);
462
+ inputObj = { path: input };
463
+ }
464
+ else {
465
+ inputObj = { arrayBuffer: input };
466
+ }
467
+ const mammothResult = yield mammoth.convertToHtml(inputObj, options.mammoth);
468
+ const processedHtml = processHtml(mammothResult.value);
469
+ const md = htmlToMd(processedHtml, options.turndown);
470
+ const mdWithBullets = convertNumberedListsToBullets(md);
471
+ const normalizedMd = normalizeText(mdWithBullets);
472
+ const cleanedMd = lint(normalizedMd);
473
+ const formattedMd = yield prettify(cleanedMd);
474
+ return formattedMd;
475
+ }
476
+ catch (error) {
477
+ // Re-throw our custom errors as-is
478
+ if (error instanceof UnsupportedFileError ||
479
+ error instanceof FileNotFoundError ||
480
+ error instanceof InvalidFileError ||
481
+ error instanceof FilePermissionError ||
482
+ error instanceof ConversionError) {
483
+ throw error;
484
+ }
485
+ // Handle specific error types from underlying libraries
486
+ const errorMessage = error instanceof Error ? error.message : String(error);
487
+ const errorCode = error && typeof error === 'object' && 'code' in error
488
+ ? error.code
489
+ : undefined;
490
+ // File not found errors (only occur with file path inputs)
491
+ if (errorCode === 'ENOENT') {
492
+ throw new FileNotFoundError(filePath);
493
+ }
494
+ // Permission errors (only occur with file path inputs)
495
+ if (errorCode === 'EACCES' || errorCode === 'EPERM') {
496
+ throw new FilePermissionError(filePath);
497
+ }
498
+ // Invalid .docx file errors (from JSZip or mammoth during file parsing)
499
+ // These patterns typically come from JSZip/mammoth when parsing the file structure.
500
+ // While there's a small theoretical risk of matching document content in unusual
501
+ // scenarios (e.g., embedded error messages), these specific technical phrases are
502
+ // highly unlikely to appear in normal document content.
503
+ if (errorMessage.includes('end of central directory') || // JSZip: invalid ZIP structure
504
+ errorMessage.includes('zip file') || // JSZip: not a valid ZIP
505
+ errorMessage.includes('Corrupted zip') || // JSZip: corrupted ZIP file
506
+ errorMessage.includes('End of data reached') || // JSZip: truncated file
507
+ errorMessage.includes('Could not find file') // mammoth: missing required file in .docx
508
+ ) {
509
+ // Note: For ArrayBuffer inputs (e.g., web uploads), filePath will be undefined,
510
+ // so the error message won't include the original filename. The web interface
511
+ // could be enhanced to pass the filename separately if needed.
512
+ throw new InvalidFileError(filePath);
513
+ }
514
+ // Wrap other errors with a general conversion error
515
+ throw new ConversionError('An error occurred while converting the document. Please ensure the file is a valid .docx file and try again.', error instanceof Error ? error : undefined);
516
+ }
517
+ });
518
+ }
519
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,103 @@
1
+ {
2
+ "name": "word-to-markdown",
3
+ "version": "0.1.0",
4
+ "description": "Convert Word documents to beautiful Markdown.",
5
+ "type": "module",
6
+ "keywords": [
7
+ "word",
8
+ "docx",
9
+ "markdown",
10
+ "convert",
11
+ "converter",
12
+ "mammoth",
13
+ "turndown",
14
+ "cli"
15
+ ],
16
+ "homepage": "https://word2md.com",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/benbalter/word-to-markdown-js.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/benbalter/word-to-markdown-js/issues"
23
+ },
24
+ "engines": {
25
+ "node": ">= 22.13"
26
+ },
27
+ "devDependencies": {
28
+ "@astrojs/check": "^0.9.9",
29
+ "@astrojs/sitemap": "^3.7.3",
30
+ "@eslint/js": "^9.39.4",
31
+ "@nuasite/checks": "^0.46.1",
32
+ "@playwright/test": "^1.61.0",
33
+ "@tailwindcss/typography": "^0.5.20",
34
+ "@tailwindcss/vite": "^4.3.1",
35
+ "@types/jest": "~30.0",
36
+ "@types/node": "~26",
37
+ "@types/turndown": "^5.0.6",
38
+ "astro": "^7.0.0",
39
+ "eslint": "^9.39.4",
40
+ "eslint-config-prettier": "~10.1",
41
+ "eslint-plugin-jest": "~29.15",
42
+ "globals": "^17.7.0",
43
+ "jest": "~30.4",
44
+ "jest-util": "~30.4",
45
+ "playwright": "^1.61.0",
46
+ "tailwindcss": "^4.3.1",
47
+ "ts-api-utils": "~2.5",
48
+ "ts-jest": "~29.4",
49
+ "typescript": "^6.0.3",
50
+ "typescript-eslint": "^8.62.0"
51
+ },
52
+ "scripts": {
53
+ "fix": "eslint --fix . && prettier --write .",
54
+ "dev": "astro dev",
55
+ "build": "npm run build:js && npm run build:site",
56
+ "build:js": "tsc",
57
+ "build:site": "astro check --minimumSeverity error && astro build",
58
+ "preview": "astro preview",
59
+ "lint": "eslint . && prettier --check .",
60
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest --coverage",
61
+ "test:e2e": "playwright test",
62
+ "test:e2e:headed": "playwright test --headed",
63
+ "test:e2e:debug": "playwright test --debug",
64
+ "all": "npm run fix && npm run test && npm run build && npm run check-builds",
65
+ "check-builds": "./scripts/check-builds.sh",
66
+ "prepack": "rm -rf build && npm run build:js"
67
+ },
68
+ "author": "Ben Balter <ben@balter.com>",
69
+ "license": "ISC",
70
+ "dependencies": {
71
+ "@joplin/turndown": "^4.0.85",
72
+ "@joplin/turndown-plugin-gfm": "^1.0.67",
73
+ "clipboard": "^2.0.11",
74
+ "commander": "^15.0.0",
75
+ "jszip": "^3.10.1",
76
+ "mammoth": "^1.12.0",
77
+ "markdownlint": "^0.41.0",
78
+ "node-html-parser": "^7.0.1",
79
+ "prettier": "~3.8",
80
+ "rehype-sanitize": "^6.0.0",
81
+ "rehype-stringify": "^10.0.1",
82
+ "remark-gfm": "^4.0.1",
83
+ "remark-parse": "^11.0.0",
84
+ "remark-rehype": "^11.1.2",
85
+ "tslib": "~2.8",
86
+ "unified": "^11.0.5",
87
+ "url": "^0.11.4"
88
+ },
89
+ "volta": {
90
+ "node": "22.13.0"
91
+ },
92
+ "bin": {
93
+ "w2m": "build/cli.js",
94
+ "word-to-markdown": "build/cli.js"
95
+ },
96
+ "main": "build/main.js",
97
+ "files": [
98
+ "build/cli.js",
99
+ "build/cli.js.map",
100
+ "build/main.js",
101
+ "build/main.js.map"
102
+ ]
103
+ }