docrev 0.8.1 → 0.8.5

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 (306) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/PLAN-tables-and-postprocess.md +850 -0
  3. package/README.md +33 -0
  4. package/bin/rev.js +12 -131
  5. package/bin/rev.ts +145 -0
  6. package/dist/bin/rev.d.ts +9 -0
  7. package/dist/bin/rev.d.ts.map +1 -0
  8. package/dist/bin/rev.js +118 -0
  9. package/dist/bin/rev.js.map +1 -0
  10. package/dist/lib/annotations.d.ts +91 -0
  11. package/dist/lib/annotations.d.ts.map +1 -0
  12. package/dist/lib/annotations.js +554 -0
  13. package/dist/lib/annotations.js.map +1 -0
  14. package/dist/lib/build.d.ts +171 -0
  15. package/dist/lib/build.d.ts.map +1 -0
  16. package/dist/lib/build.js +755 -0
  17. package/dist/lib/build.js.map +1 -0
  18. package/dist/lib/citations.d.ts +34 -0
  19. package/dist/lib/citations.d.ts.map +1 -0
  20. package/dist/lib/citations.js +140 -0
  21. package/dist/lib/citations.js.map +1 -0
  22. package/dist/lib/commands/build.d.ts +13 -0
  23. package/dist/lib/commands/build.d.ts.map +1 -0
  24. package/dist/lib/commands/build.js +678 -0
  25. package/dist/lib/commands/build.js.map +1 -0
  26. package/dist/lib/commands/citations.d.ts +11 -0
  27. package/dist/lib/commands/citations.d.ts.map +1 -0
  28. package/dist/lib/commands/citations.js +428 -0
  29. package/dist/lib/commands/citations.js.map +1 -0
  30. package/dist/lib/commands/comments.d.ts +11 -0
  31. package/dist/lib/commands/comments.d.ts.map +1 -0
  32. package/dist/lib/commands/comments.js +883 -0
  33. package/dist/lib/commands/comments.js.map +1 -0
  34. package/dist/lib/commands/context.d.ts +35 -0
  35. package/dist/lib/commands/context.d.ts.map +1 -0
  36. package/dist/lib/commands/context.js +59 -0
  37. package/dist/lib/commands/context.js.map +1 -0
  38. package/dist/lib/commands/core.d.ts +11 -0
  39. package/dist/lib/commands/core.d.ts.map +1 -0
  40. package/dist/lib/commands/core.js +246 -0
  41. package/dist/lib/commands/core.js.map +1 -0
  42. package/dist/lib/commands/doi.d.ts +11 -0
  43. package/dist/lib/commands/doi.d.ts.map +1 -0
  44. package/dist/lib/commands/doi.js +373 -0
  45. package/dist/lib/commands/doi.js.map +1 -0
  46. package/dist/lib/commands/history.d.ts +11 -0
  47. package/dist/lib/commands/history.d.ts.map +1 -0
  48. package/dist/lib/commands/history.js +245 -0
  49. package/dist/lib/commands/history.js.map +1 -0
  50. package/dist/lib/commands/index.d.ts +28 -0
  51. package/dist/lib/commands/index.d.ts.map +1 -0
  52. package/dist/lib/commands/index.js +35 -0
  53. package/dist/lib/commands/index.js.map +1 -0
  54. package/dist/lib/commands/init.d.ts +11 -0
  55. package/dist/lib/commands/init.d.ts.map +1 -0
  56. package/dist/lib/commands/init.js +209 -0
  57. package/dist/lib/commands/init.js.map +1 -0
  58. package/dist/lib/commands/response.d.ts +11 -0
  59. package/dist/lib/commands/response.d.ts.map +1 -0
  60. package/dist/lib/commands/response.js +317 -0
  61. package/dist/lib/commands/response.js.map +1 -0
  62. package/dist/lib/commands/sections.d.ts +11 -0
  63. package/dist/lib/commands/sections.d.ts.map +1 -0
  64. package/dist/lib/commands/sections.js +1071 -0
  65. package/dist/lib/commands/sections.js.map +1 -0
  66. package/dist/lib/commands/utilities.d.ts +19 -0
  67. package/dist/lib/commands/utilities.d.ts.map +1 -0
  68. package/dist/lib/commands/utilities.js +2009 -0
  69. package/dist/lib/commands/utilities.js.map +1 -0
  70. package/dist/lib/comment-realign.d.ts +50 -0
  71. package/dist/lib/comment-realign.d.ts.map +1 -0
  72. package/dist/lib/comment-realign.js +372 -0
  73. package/dist/lib/comment-realign.js.map +1 -0
  74. package/dist/lib/config.d.ts +41 -0
  75. package/dist/lib/config.d.ts.map +1 -0
  76. package/dist/lib/config.js +76 -0
  77. package/dist/lib/config.js.map +1 -0
  78. package/dist/lib/crossref.d.ts +108 -0
  79. package/dist/lib/crossref.d.ts.map +1 -0
  80. package/dist/lib/crossref.js +597 -0
  81. package/dist/lib/crossref.js.map +1 -0
  82. package/dist/lib/dependencies.d.ts +30 -0
  83. package/dist/lib/dependencies.d.ts.map +1 -0
  84. package/dist/lib/dependencies.js +95 -0
  85. package/dist/lib/dependencies.js.map +1 -0
  86. package/dist/lib/doi-cache.d.ts +29 -0
  87. package/dist/lib/doi-cache.d.ts.map +1 -0
  88. package/dist/lib/doi-cache.js +104 -0
  89. package/dist/lib/doi-cache.js.map +1 -0
  90. package/dist/lib/doi.d.ts +65 -0
  91. package/dist/lib/doi.d.ts.map +1 -0
  92. package/dist/lib/doi.js +710 -0
  93. package/dist/lib/doi.js.map +1 -0
  94. package/dist/lib/equations.d.ts +61 -0
  95. package/dist/lib/equations.d.ts.map +1 -0
  96. package/dist/lib/equations.js +445 -0
  97. package/dist/lib/equations.js.map +1 -0
  98. package/dist/lib/errors.d.ts +60 -0
  99. package/dist/lib/errors.d.ts.map +1 -0
  100. package/dist/lib/errors.js +303 -0
  101. package/dist/lib/errors.js.map +1 -0
  102. package/dist/lib/format.d.ts +104 -0
  103. package/dist/lib/format.d.ts.map +1 -0
  104. package/dist/lib/format.js +416 -0
  105. package/dist/lib/format.js.map +1 -0
  106. package/dist/lib/git.d.ts +88 -0
  107. package/dist/lib/git.d.ts.map +1 -0
  108. package/dist/lib/git.js +304 -0
  109. package/dist/lib/git.js.map +1 -0
  110. package/dist/lib/grammar.d.ts +62 -0
  111. package/dist/lib/grammar.d.ts.map +1 -0
  112. package/dist/lib/grammar.js +244 -0
  113. package/dist/lib/grammar.js.map +1 -0
  114. package/dist/lib/image-registry.d.ts +68 -0
  115. package/dist/lib/image-registry.d.ts.map +1 -0
  116. package/dist/lib/image-registry.js +112 -0
  117. package/dist/lib/image-registry.js.map +1 -0
  118. package/dist/lib/import.d.ts +184 -0
  119. package/dist/lib/import.d.ts.map +1 -0
  120. package/dist/lib/import.js +1581 -0
  121. package/dist/lib/import.js.map +1 -0
  122. package/dist/lib/journals.d.ts +55 -0
  123. package/dist/lib/journals.d.ts.map +1 -0
  124. package/dist/lib/journals.js +417 -0
  125. package/dist/lib/journals.js.map +1 -0
  126. package/dist/lib/merge.d.ts +138 -0
  127. package/dist/lib/merge.d.ts.map +1 -0
  128. package/dist/lib/merge.js +603 -0
  129. package/dist/lib/merge.js.map +1 -0
  130. package/dist/lib/orcid.d.ts +36 -0
  131. package/dist/lib/orcid.d.ts.map +1 -0
  132. package/dist/lib/orcid.js +117 -0
  133. package/dist/lib/orcid.js.map +1 -0
  134. package/dist/lib/pdf-comments.d.ts +95 -0
  135. package/dist/lib/pdf-comments.d.ts.map +1 -0
  136. package/dist/lib/pdf-comments.js +192 -0
  137. package/dist/lib/pdf-comments.js.map +1 -0
  138. package/dist/lib/pdf-import.d.ts +118 -0
  139. package/dist/lib/pdf-import.d.ts.map +1 -0
  140. package/dist/lib/pdf-import.js +397 -0
  141. package/dist/lib/pdf-import.js.map +1 -0
  142. package/dist/lib/plugins.d.ts +76 -0
  143. package/dist/lib/plugins.d.ts.map +1 -0
  144. package/dist/lib/plugins.js +235 -0
  145. package/dist/lib/plugins.js.map +1 -0
  146. package/dist/lib/postprocess.d.ts +42 -0
  147. package/dist/lib/postprocess.d.ts.map +1 -0
  148. package/dist/lib/postprocess.js +138 -0
  149. package/dist/lib/postprocess.js.map +1 -0
  150. package/dist/lib/pptx-template.d.ts +59 -0
  151. package/dist/lib/pptx-template.d.ts.map +1 -0
  152. package/dist/lib/pptx-template.js +613 -0
  153. package/dist/lib/pptx-template.js.map +1 -0
  154. package/dist/lib/pptx-themes.d.ts +80 -0
  155. package/dist/lib/pptx-themes.d.ts.map +1 -0
  156. package/dist/lib/pptx-themes.js +818 -0
  157. package/dist/lib/pptx-themes.js.map +1 -0
  158. package/dist/lib/protect-restore.d.ts +137 -0
  159. package/dist/lib/protect-restore.d.ts.map +1 -0
  160. package/dist/lib/protect-restore.js +394 -0
  161. package/dist/lib/protect-restore.js.map +1 -0
  162. package/dist/lib/rate-limiter.d.ts +27 -0
  163. package/dist/lib/rate-limiter.d.ts.map +1 -0
  164. package/dist/lib/rate-limiter.js +79 -0
  165. package/dist/lib/rate-limiter.js.map +1 -0
  166. package/dist/lib/response.d.ts +41 -0
  167. package/dist/lib/response.d.ts.map +1 -0
  168. package/dist/lib/response.js +150 -0
  169. package/dist/lib/response.js.map +1 -0
  170. package/dist/lib/review.d.ts +35 -0
  171. package/dist/lib/review.d.ts.map +1 -0
  172. package/dist/lib/review.js +263 -0
  173. package/dist/lib/review.js.map +1 -0
  174. package/dist/lib/schema.d.ts +66 -0
  175. package/dist/lib/schema.d.ts.map +1 -0
  176. package/dist/lib/schema.js +339 -0
  177. package/dist/lib/schema.js.map +1 -0
  178. package/dist/lib/scientific-words.d.ts +6 -0
  179. package/dist/lib/scientific-words.d.ts.map +1 -0
  180. package/dist/lib/scientific-words.js +66 -0
  181. package/dist/lib/scientific-words.js.map +1 -0
  182. package/dist/lib/sections.d.ts +40 -0
  183. package/dist/lib/sections.d.ts.map +1 -0
  184. package/dist/lib/sections.js +288 -0
  185. package/dist/lib/sections.js.map +1 -0
  186. package/dist/lib/slides.d.ts +86 -0
  187. package/dist/lib/slides.d.ts.map +1 -0
  188. package/dist/lib/slides.js +676 -0
  189. package/dist/lib/slides.js.map +1 -0
  190. package/dist/lib/spelling.d.ts +76 -0
  191. package/dist/lib/spelling.d.ts.map +1 -0
  192. package/dist/lib/spelling.js +272 -0
  193. package/dist/lib/spelling.js.map +1 -0
  194. package/dist/lib/templates.d.ts +30 -0
  195. package/dist/lib/templates.d.ts.map +1 -0
  196. package/dist/lib/templates.js +504 -0
  197. package/dist/lib/templates.js.map +1 -0
  198. package/dist/lib/themes.d.ts +85 -0
  199. package/dist/lib/themes.d.ts.map +1 -0
  200. package/dist/lib/themes.js +652 -0
  201. package/dist/lib/themes.js.map +1 -0
  202. package/dist/lib/trackchanges.d.ts +51 -0
  203. package/dist/lib/trackchanges.d.ts.map +1 -0
  204. package/dist/lib/trackchanges.js +202 -0
  205. package/dist/lib/trackchanges.js.map +1 -0
  206. package/dist/lib/tui.d.ts +76 -0
  207. package/dist/lib/tui.d.ts.map +1 -0
  208. package/dist/lib/tui.js +377 -0
  209. package/dist/lib/tui.js.map +1 -0
  210. package/dist/lib/types.d.ts +447 -0
  211. package/dist/lib/types.d.ts.map +1 -0
  212. package/dist/lib/types.js +6 -0
  213. package/dist/lib/types.js.map +1 -0
  214. package/dist/lib/undo.d.ts +57 -0
  215. package/dist/lib/undo.d.ts.map +1 -0
  216. package/dist/lib/undo.js +185 -0
  217. package/dist/lib/undo.js.map +1 -0
  218. package/dist/lib/utils.d.ts +16 -0
  219. package/dist/lib/utils.d.ts.map +1 -0
  220. package/dist/lib/utils.js +40 -0
  221. package/dist/lib/utils.js.map +1 -0
  222. package/dist/lib/variables.d.ts +42 -0
  223. package/dist/lib/variables.d.ts.map +1 -0
  224. package/dist/lib/variables.js +141 -0
  225. package/dist/lib/variables.js.map +1 -0
  226. package/dist/lib/word.d.ts +80 -0
  227. package/dist/lib/word.d.ts.map +1 -0
  228. package/dist/lib/word.js +360 -0
  229. package/dist/lib/word.js.map +1 -0
  230. package/dist/lib/wordcomments.d.ts +51 -0
  231. package/dist/lib/wordcomments.d.ts.map +1 -0
  232. package/dist/lib/wordcomments.js +587 -0
  233. package/dist/lib/wordcomments.js.map +1 -0
  234. package/eslint.config.js +27 -0
  235. package/lib/annotations.ts +622 -0
  236. package/lib/apply-buildup-colors.py +88 -0
  237. package/lib/build.ts +1013 -0
  238. package/lib/{citations.js → citations.ts} +38 -27
  239. package/lib/commands/{build.js → build.ts} +80 -27
  240. package/lib/commands/{citations.js → citations.ts} +36 -18
  241. package/lib/commands/{comments.js → comments.ts} +187 -54
  242. package/lib/commands/{context.js → context.ts} +18 -8
  243. package/lib/commands/{core.js → core.ts} +34 -20
  244. package/lib/commands/{doi.js → doi.ts} +32 -16
  245. package/lib/commands/{history.js → history.ts} +25 -12
  246. package/lib/commands/{index.js → index.ts} +9 -5
  247. package/lib/commands/{init.js → init.ts} +20 -8
  248. package/lib/commands/{response.js → response.ts} +47 -20
  249. package/lib/commands/{sections.js → sections.ts} +273 -68
  250. package/lib/commands/{utilities.js → utilities.ts} +338 -158
  251. package/lib/{comment-realign.js → comment-realign.ts} +117 -45
  252. package/lib/config.ts +84 -0
  253. package/lib/{crossref.js → crossref.ts} +213 -138
  254. package/lib/dependencies.ts +106 -0
  255. package/lib/doi-cache.ts +115 -0
  256. package/lib/{doi.js → doi.ts} +115 -281
  257. package/lib/{equations.js → equations.ts} +60 -64
  258. package/lib/{errors.js → errors.ts} +56 -48
  259. package/lib/{format.js → format.ts} +137 -63
  260. package/lib/{git.js → git.ts} +66 -63
  261. package/lib/{grammar.js → grammar.ts} +45 -32
  262. package/lib/image-registry.ts +180 -0
  263. package/lib/import.ts +2060 -0
  264. package/lib/journals.ts +505 -0
  265. package/lib/{merge.js → merge.ts} +185 -135
  266. package/lib/{orcid.js → orcid.ts} +17 -22
  267. package/lib/{pdf-comments.js → pdf-comments.ts} +76 -18
  268. package/lib/{pdf-import.js → pdf-import.ts} +148 -70
  269. package/lib/{plugins.js → plugins.ts} +82 -39
  270. package/lib/postprocess.ts +188 -0
  271. package/lib/pptx-color-filter.lua +37 -0
  272. package/lib/pptx-template.ts +625 -0
  273. package/lib/pptx-themes/academic.pptx +0 -0
  274. package/lib/pptx-themes/corporate.pptx +0 -0
  275. package/lib/pptx-themes/dark.pptx +0 -0
  276. package/lib/pptx-themes/default.pptx +0 -0
  277. package/lib/pptx-themes/minimal.pptx +0 -0
  278. package/lib/pptx-themes/plant.pptx +0 -0
  279. package/lib/pptx-themes.ts +896 -0
  280. package/lib/protect-restore.ts +516 -0
  281. package/lib/rate-limiter.ts +94 -0
  282. package/lib/{response.js → response.ts} +36 -21
  283. package/lib/{review.js → review.ts} +53 -43
  284. package/lib/{schema.js → schema.ts} +70 -25
  285. package/lib/{sections.js → sections.ts} +71 -76
  286. package/lib/slides.ts +793 -0
  287. package/lib/{spelling.js → spelling.ts} +43 -59
  288. package/lib/{templates.js → templates.ts} +20 -17
  289. package/lib/themes.ts +742 -0
  290. package/lib/{trackchanges.js → trackchanges.ts} +52 -23
  291. package/lib/types.ts +509 -0
  292. package/lib/{undo.js → undo.ts} +75 -52
  293. package/lib/utils.ts +41 -0
  294. package/lib/{variables.js → variables.ts} +60 -54
  295. package/lib/word.ts +428 -0
  296. package/lib/{wordcomments.js → wordcomments.ts} +94 -40
  297. package/package.json +15 -5
  298. package/skill/REFERENCE.md +67 -0
  299. package/tsconfig.json +26 -0
  300. package/lib/annotations.js +0 -414
  301. package/lib/build.js +0 -639
  302. package/lib/config.js +0 -79
  303. package/lib/import.js +0 -1145
  304. package/lib/journals.js +0 -629
  305. package/lib/word.js +0 -225
  306. /package/lib/{scientific-words.js → scientific-words.ts} +0 -0
@@ -14,13 +14,14 @@ import { exec } from 'child_process';
14
14
  import { promisify } from 'util';
15
15
  import AdmZip from 'adm-zip';
16
16
  import { parseString } from 'xml2js';
17
+ import type { Equation, EquationStats, WordEquationResult } from './types.js';
17
18
 
18
19
  const execAsync = promisify(exec);
19
20
  const parseXml = promisify(parseString);
20
21
 
21
22
  // Dynamic import for mathml-to-latex (ESM)
22
- let MathMLToLaTeX = null;
23
- async function getMathMLConverter() {
23
+ let MathMLToLaTeX: any = null;
24
+ async function getMathMLConverter(): Promise<any> {
24
25
  if (!MathMLToLaTeX) {
25
26
  try {
26
27
  const module = await import('mathml-to-latex');
@@ -34,12 +35,9 @@ async function getMathMLConverter() {
34
35
 
35
36
  /**
36
37
  * Extract all equations from markdown text
37
- * @param {string} text
38
- * @param {string} file - Source file name
39
- * @returns {Array<{type: 'inline'|'display', content: string, line: number, file: string}>}
40
38
  */
41
- export function extractEquations(text, file = '') {
42
- const equations = [];
39
+ export function extractEquations(text: string, file: string = ''): Equation[] {
40
+ const equations: Equation[] = [];
43
41
  const lines = text.split('\n');
44
42
 
45
43
  let inDisplayMath = false;
@@ -48,6 +46,7 @@ export function extractEquations(text, file = '') {
48
46
 
49
47
  for (let lineNum = 0; lineNum < lines.length; lineNum++) {
50
48
  const line = lines[lineNum];
49
+ if (!line) continue;
51
50
 
52
51
  // Skip code blocks
53
52
  if (line.trim().startsWith('```')) continue;
@@ -55,16 +54,19 @@ export function extractEquations(text, file = '') {
55
54
  // Handle inline math ($...$) in a segment of text
56
55
  // Careful not to match $$ or escaped \$
57
56
  const inlinePattern = /(?<![\$\\])\$(?!\$)([^$\n]+)\$(?!\$)/g;
58
- const extractInline = (segment) => {
57
+ const extractInline = (segment: string): void => {
59
58
  let match;
60
59
  inlinePattern.lastIndex = 0;
61
60
  while ((match = inlinePattern.exec(segment)) !== null) {
62
- equations.push({
63
- type: 'inline',
64
- content: match[1].trim(),
65
- line: lineNum + 1,
66
- file,
67
- });
61
+ const content = match[1];
62
+ if (content) {
63
+ equations.push({
64
+ type: 'inline',
65
+ content: content.trim(),
66
+ line: lineNum + 1,
67
+ file,
68
+ });
69
+ }
68
70
  }
69
71
  };
70
72
 
@@ -75,24 +77,26 @@ export function extractEquations(text, file = '') {
75
77
  if (!inDisplayMath && parts.length >= 3) {
76
78
  // Single-line display math: $$content$$
77
79
  // Also extract inline math from surrounding text
78
- extractInline(parts[0]); // Text before $$
80
+ if (parts[0]) extractInline(parts[0]); // Text before $$
79
81
  for (let i = 1; i < parts.length; i += 2) {
80
- if (parts[i].trim()) {
82
+ const part = parts[i];
83
+ if (part && part.trim()) {
81
84
  equations.push({
82
85
  type: 'display',
83
- content: parts[i].trim(),
86
+ content: part.trim(),
84
87
  line: lineNum + 1,
85
88
  file,
86
89
  });
87
90
  }
88
91
  }
89
92
  // Extract inline from text after the last $$
90
- if (parts.length % 2 === 1 && parts[parts.length - 1]) {
91
- extractInline(parts[parts.length - 1]);
93
+ const lastPart = parts[parts.length - 1];
94
+ if (parts.length % 2 === 1 && lastPart) {
95
+ extractInline(lastPart);
92
96
  }
93
97
  } else if (!inDisplayMath) {
94
98
  // Start of multi-line display math
95
- extractInline(parts[0]); // Text before $$
99
+ if (parts[0]) extractInline(parts[0]); // Text before $$
96
100
  inDisplayMath = true;
97
101
  displayMathStart = lineNum + 1;
98
102
  displayMathContent = parts[1] || '';
@@ -110,8 +114,9 @@ export function extractEquations(text, file = '') {
110
114
  }
111
115
  displayMathContent = '';
112
116
  // Text after $$ on closing line
113
- if (parts[1]) {
114
- extractInline(parts[1]);
117
+ const afterPart = parts[1];
118
+ if (afterPart) {
119
+ extractInline(afterPart);
115
120
  }
116
121
  }
117
122
  continue;
@@ -132,11 +137,9 @@ export function extractEquations(text, file = '') {
132
137
  /**
133
138
  * Generate a markdown document with numbered equations
134
139
  * Useful for creating an equation reference sheet
135
- * @param {Array} equations
136
- * @returns {string}
137
140
  */
138
- export function generateEquationSheet(equations) {
139
- const lines = [];
141
+ export function generateEquationSheet(equations: Equation[]): string {
142
+ const lines: string[] = [];
140
143
  lines.push('# Equations');
141
144
  lines.push('');
142
145
 
@@ -144,12 +147,12 @@ export function generateEquationSheet(equations) {
144
147
  let inlineNum = 0;
145
148
 
146
149
  // Group by file
147
- const byFile = new Map();
150
+ const byFile = new Map<string, Equation[]>();
148
151
  for (const eq of equations) {
149
152
  if (!byFile.has(eq.file)) {
150
153
  byFile.set(eq.file, []);
151
154
  }
152
- byFile.get(eq.file).push(eq);
155
+ byFile.get(eq.file)!.push(eq);
153
156
  }
154
157
 
155
158
  for (const [file, fileEqs] of byFile) {
@@ -183,14 +186,18 @@ export function generateEquationSheet(equations) {
183
186
  return lines.join('\n');
184
187
  }
185
188
 
189
+ interface ConvertToWordOptions {
190
+ preserveLatex?: boolean;
191
+ }
192
+
186
193
  /**
187
194
  * Convert markdown with equations to Word using pandoc
188
- * @param {string} inputPath - Input markdown file
189
- * @param {string} outputPath - Output docx file
190
- * @param {object} options
191
- * @returns {Promise<{success: boolean, message: string}>}
192
195
  */
193
- export async function convertToWord(inputPath, outputPath, options = {}) {
196
+ export async function convertToWord(
197
+ inputPath: string,
198
+ outputPath: string,
199
+ options: ConvertToWordOptions = {}
200
+ ): Promise<{ success: boolean; message: string }> {
194
201
  const { preserveLatex = false } = options;
195
202
 
196
203
  // Check pandoc is available
@@ -217,18 +224,18 @@ export async function convertToWord(inputPath, outputPath, options = {}) {
217
224
  try {
218
225
  await execAsync(args.join(' '));
219
226
  return { success: true, message: `Created ${outputPath}` };
220
- } catch (err) {
227
+ } catch (err: any) {
221
228
  return { success: false, message: err.message };
222
229
  }
223
230
  }
224
231
 
225
232
  /**
226
233
  * Create a simple equations-only document
227
- * @param {string} inputPath - Source markdown
228
- * @param {string} outputPath - Output path (md or docx)
229
- * @returns {Promise<{success: boolean, message: string, stats: object}>}
230
234
  */
231
- export async function createEquationsDoc(inputPath, outputPath) {
235
+ export async function createEquationsDoc(
236
+ inputPath: string,
237
+ outputPath: string
238
+ ): Promise<{ success: boolean; message: string; stats: { display: number; inline: number } | null }> {
232
239
  if (!fs.existsSync(inputPath)) {
233
240
  return { success: false, message: `File not found: ${inputPath}`, stats: null };
234
241
  }
@@ -264,13 +271,11 @@ export async function createEquationsDoc(inputPath, outputPath) {
264
271
 
265
272
  /**
266
273
  * Get equation statistics for a file or directory
267
- * @param {string[]} files
268
- * @returns {object}
269
274
  */
270
- export function getEquationStats(files) {
275
+ export function getEquationStats(files: string[]): EquationStats {
271
276
  let totalDisplay = 0;
272
277
  let totalInline = 0;
273
- const byFile = [];
278
+ const byFile: Array<{ file: string; display: number; inline: number }> = [];
274
279
 
275
280
  for (const file of files) {
276
281
  if (!fs.existsSync(file)) continue;
@@ -299,11 +304,8 @@ export function getEquationStats(files) {
299
304
  /**
300
305
  * Extract equations from a Word document using Pandoc
301
306
  * Converts OMML (Office Math Markup) to LaTeX
302
- *
303
- * @param {string} docxPath - Path to Word document
304
- * @returns {Promise<{success: boolean, equations: Array<{type: string, latex: string, position: number}>, error?: string}>}
305
307
  */
306
- export async function extractEquationsFromWord(docxPath) {
308
+ export async function extractEquationsFromWord(docxPath: string): Promise<WordEquationResult> {
307
309
  if (!fs.existsSync(docxPath)) {
308
310
  return { success: false, equations: [], error: `File not found: ${docxPath}` };
309
311
  }
@@ -336,11 +338,8 @@ export async function extractEquationsFromWord(docxPath) {
336
338
  /**
337
339
  * Direct OMML extraction from Word document (fallback if Pandoc fails)
338
340
  * Parses document.xml for <m:oMath> elements and attempts conversion
339
- *
340
- * @param {string} docxPath
341
- * @returns {Promise<{success: boolean, equations: Array, error?: string}>}
342
341
  */
343
- async function extractEquationsFromWordDirect(docxPath) {
342
+ async function extractEquationsFromWordDirect(docxPath: string): Promise<WordEquationResult> {
344
343
  try {
345
344
  const zip = new AdmZip(docxPath);
346
345
  const documentEntry = zip.getEntry('word/document.xml');
@@ -356,15 +355,16 @@ async function extractEquationsFromWordDirect(docxPath) {
356
355
  const matches = documentXml.match(ommlPattern) || [];
357
356
 
358
357
  if (matches.length === 0) {
359
- return { success: true, equations: [], message: 'No equations found' };
358
+ return { success: true, equations: [] };
360
359
  }
361
360
 
362
361
  // Try to convert OMML to LaTeX via MathML intermediate
363
362
  const Converter = await getMathMLConverter();
364
- const equations = [];
363
+ const equations: WordEquationResult['equations'] = [];
365
364
 
366
365
  for (let i = 0; i < matches.length; i++) {
367
366
  const omml = matches[i];
367
+ if (!omml) continue;
368
368
 
369
369
  // Attempt OMML → MathML → LaTeX conversion
370
370
  // Note: This is a simplified approach; full OMML→MathML requires XSLT
@@ -391,7 +391,7 @@ async function extractEquationsFromWordDirect(docxPath) {
391
391
  }
392
392
 
393
393
  return { success: true, equations };
394
- } catch (err) {
394
+ } catch (err: any) {
395
395
  return { success: false, equations: [], error: err.message };
396
396
  }
397
397
  }
@@ -399,19 +399,15 @@ async function extractEquationsFromWordDirect(docxPath) {
399
399
  /**
400
400
  * Check if OMML represents display math (equation on its own line)
401
401
  */
402
- function isDisplayMath(omml) {
402
+ function isDisplayMath(omml: string): boolean {
403
403
  return omml.includes('<m:oMathPara') || omml.includes('m:jc');
404
404
  }
405
405
 
406
406
  /**
407
407
  * Convert OMML to LaTeX (simplified approach)
408
408
  * For complex equations, Pandoc method is more reliable
409
- *
410
- * @param {string} omml - OMML XML string
411
- * @param {Function} Converter - MathMLToLaTeX converter
412
- * @returns {Promise<string|null>}
413
409
  */
414
- async function ommlToLatex(omml, Converter) {
410
+ async function ommlToLatex(omml: string, Converter: any): Promise<string | null> {
415
411
  if (!Converter) return null;
416
412
 
417
413
  // Extract key elements from OMML and build approximate MathML
@@ -433,7 +429,7 @@ async function ommlToLatex(omml, Converter) {
433
429
  * Convert OMML to MathML (simplified)
434
430
  * Maps common OMML elements to MathML equivalents
435
431
  */
436
- function ommlToMathML(omml) {
432
+ function ommlToMathML(omml: string): string | null {
437
433
  // Remove namespace prefixes for easier parsing
438
434
  let xml = omml
439
435
  .replace(/<m:/g, '<')
@@ -442,7 +438,7 @@ function ommlToMathML(omml) {
442
438
  .replace(/<\/w:/g, '</w_');
443
439
 
444
440
  // Map OMML elements to MathML
445
- const mappings = [
441
+ const mappings: Array<[RegExp, string]> = [
446
442
  [/<oMath[^>]*>/gi, '<math xmlns="http://www.w3.org/1998/Math/MathML">'],
447
443
  [/<\/oMath>/gi, '</math>'],
448
444
  [/<r>/gi, '<mi>'],
@@ -487,10 +483,10 @@ function ommlToMathML(omml) {
487
483
 
488
484
  /**
489
485
  * Get equation summary from Word document
490
- * @param {string} docxPath
491
- * @returns {Promise<{count: number, display: number, inline: number, converted: number}>}
492
486
  */
493
- export async function getWordEquationStats(docxPath) {
487
+ export async function getWordEquationStats(
488
+ docxPath: string
489
+ ): Promise<{ count: number; display: number; inline: number; converted: number; error?: string }> {
494
490
  const result = await extractEquationsFromWord(docxPath);
495
491
 
496
492
  if (!result.success) {
@@ -3,16 +3,21 @@
3
3
  */
4
4
 
5
5
  import chalk from 'chalk';
6
- import path from 'path';
7
- import fs from 'fs';
6
+ import * as path from 'path';
7
+ import * as fs from 'fs';
8
+
9
+ interface BuildContext {
10
+ bibPath?: string;
11
+ format?: string;
12
+ }
8
13
 
9
14
  /**
10
15
  * Format an error message with optional suggestions
11
- * @param {string} message - Main error message
12
- * @param {string[]} suggestions - Actionable suggestions
13
- * @returns {string}
16
+ * @param message - Main error message
17
+ * @param suggestions - Actionable suggestions
18
+ * @returns Formatted error string
14
19
  */
15
- export function formatError(message, suggestions = []) {
20
+ export function formatError(message: string, suggestions: string[] = []): string {
16
21
  const lines = [chalk.red(`Error: ${message}`)];
17
22
 
18
23
  if (suggestions.length > 0) {
@@ -27,11 +32,11 @@ export function formatError(message, suggestions = []) {
27
32
 
28
33
  /**
29
34
  * Get actionable suggestions for file not found errors
30
- * @param {string} filePath - The file path that wasn't found
31
- * @returns {string[]}
35
+ * @param filePath - The file path that wasn't found
36
+ * @returns Array of suggestions
32
37
  */
33
- export function getFileNotFoundSuggestions(filePath) {
34
- const suggestions = [];
38
+ export function getFileNotFoundSuggestions(filePath: string): string[] {
39
+ const suggestions: string[] = [];
35
40
  const ext = path.extname(filePath).toLowerCase();
36
41
  const dir = path.dirname(filePath);
37
42
  const base = path.basename(filePath);
@@ -75,11 +80,11 @@ export function getFileNotFoundSuggestions(filePath) {
75
80
 
76
81
  /**
77
82
  * Get actionable suggestions for dependency errors
78
- * @param {string} dependency - The missing dependency
79
- * @returns {string[]}
83
+ * @param dependency - The missing dependency
84
+ * @returns Array of suggestions
80
85
  */
81
- export function getDependencySuggestions(dependency) {
82
- const suggestions = [];
86
+ export function getDependencySuggestions(dependency: string): string[] {
87
+ const suggestions: string[] = [];
83
88
  const platform = process.platform;
84
89
 
85
90
  switch (dependency.toLowerCase()) {
@@ -133,12 +138,12 @@ export function getDependencySuggestions(dependency) {
133
138
 
134
139
  /**
135
140
  * Get actionable suggestions for configuration errors
136
- * @param {string} field - The problematic config field
137
- * @param {string} issue - What's wrong with it
138
- * @returns {string[]}
141
+ * @param field - The problematic config field
142
+ * @param issue - What's wrong with it
143
+ * @returns Array of suggestions
139
144
  */
140
- export function getConfigSuggestions(field, issue) {
141
- const suggestions = [];
145
+ export function getConfigSuggestions(field: string, issue: string): string[] {
146
+ const suggestions: string[] = [];
142
147
 
143
148
  switch (field) {
144
149
  case 'bibliography':
@@ -180,11 +185,11 @@ export function getConfigSuggestions(field, issue) {
180
185
 
181
186
  /**
182
187
  * Get suggestions for comment/annotation errors
183
- * @param {string} issue - The issue type
184
- * @returns {string[]}
188
+ * @param issue - The issue type
189
+ * @returns Array of suggestions
185
190
  */
186
- export function getAnnotationSuggestions(issue) {
187
- const suggestions = [];
191
+ export function getAnnotationSuggestions(issue: string): string[] {
192
+ const suggestions: string[] = [];
188
193
 
189
194
  switch (issue) {
190
195
  case 'no_comments':
@@ -218,12 +223,12 @@ export function getAnnotationSuggestions(issue) {
218
223
 
219
224
  /**
220
225
  * Get suggestions for build errors
221
- * @param {string} issue - The build issue
222
- * @param {object} context - Additional context
223
- * @returns {string[]}
226
+ * @param issue - The build issue
227
+ * @param context - Additional context
228
+ * @returns Array of suggestions
224
229
  */
225
- export function getBuildSuggestions(issue, context = {}) {
226
- const suggestions = [];
230
+ export function getBuildSuggestions(issue: string, context: BuildContext = {}): string[] {
231
+ const suggestions: string[] = [];
227
232
 
228
233
  switch (issue) {
229
234
  case 'no_sections':
@@ -265,12 +270,12 @@ export function getBuildSuggestions(issue, context = {}) {
265
270
 
266
271
  /**
267
272
  * Find similar filenames using Levenshtein distance
268
- * @param {string} target - Target filename
269
- * @param {string[]} candidates - Available filenames
270
- * @param {number} limit - Max results
271
- * @returns {string[]}
273
+ * @param target - Target filename
274
+ * @param candidates - Available filenames
275
+ * @param limit - Max results
276
+ * @returns Array of similar filenames
272
277
  */
273
- function findSimilarFiles(target, candidates, limit = 3) {
278
+ function findSimilarFiles(target: string, candidates: string[], limit: number = 3): string[] {
274
279
  const scored = candidates
275
280
  .map(c => ({ name: c, distance: levenshtein(target.toLowerCase(), c.toLowerCase()) }))
276
281
  .filter(c => c.distance <= 3) // Only reasonably similar
@@ -281,54 +286,57 @@ function findSimilarFiles(target, candidates, limit = 3) {
281
286
 
282
287
  /**
283
288
  * Simple Levenshtein distance
289
+ * @param a - First string
290
+ * @param b - Second string
291
+ * @returns Edit distance
284
292
  */
285
- function levenshtein(a, b) {
293
+ function levenshtein(a: string, b: string): number {
286
294
  if (a.length === 0) return b.length;
287
295
  if (b.length === 0) return a.length;
288
296
 
289
- const matrix = [];
297
+ const matrix: number[][] = [];
290
298
 
291
299
  for (let i = 0; i <= b.length; i++) {
292
300
  matrix[i] = [i];
293
301
  }
294
302
 
295
303
  for (let j = 0; j <= a.length; j++) {
296
- matrix[0][j] = j;
304
+ matrix[0]![j] = j;
297
305
  }
298
306
 
299
307
  for (let i = 1; i <= b.length; i++) {
300
308
  for (let j = 1; j <= a.length; j++) {
301
309
  if (b.charAt(i - 1) === a.charAt(j - 1)) {
302
- matrix[i][j] = matrix[i - 1][j - 1];
310
+ matrix[i]![j] = matrix[i - 1]![j - 1]!;
303
311
  } else {
304
- matrix[i][j] = Math.min(
305
- matrix[i - 1][j - 1] + 1,
306
- matrix[i][j - 1] + 1,
307
- matrix[i - 1][j] + 1
312
+ matrix[i]![j] = Math.min(
313
+ matrix[i - 1]![j - 1]! + 1,
314
+ matrix[i]![j - 1]! + 1,
315
+ matrix[i - 1]![j]! + 1
308
316
  );
309
317
  }
310
318
  }
311
319
  }
312
320
 
313
- return matrix[b.length][a.length];
321
+ return matrix[b.length]![a.length]!;
314
322
  }
315
323
 
316
324
  /**
317
325
  * Print error and exit
318
- * @param {string} message - Error message
319
- * @param {string[]} suggestions - Suggestions
326
+ * @param message - Error message
327
+ * @param suggestions - Suggestions
320
328
  */
321
- export function exitWithError(message, suggestions = []) {
329
+ export function exitWithError(message: string, suggestions: string[] = []): never {
322
330
  console.error(formatError(message, suggestions));
323
331
  process.exit(1);
324
332
  }
325
333
 
326
334
  /**
327
335
  * Validate file exists with helpful error
328
- * @param {string} filePath - File to check
329
- * @param {string} fileType - Type description for error message
336
+ * @param filePath - File to check
337
+ * @param fileType - Type description for error message
330
338
  */
331
- export function requireFile(filePath, fileType = 'File') {
339
+ export function requireFile(filePath: string, fileType: string = 'File'): void {
332
340
  if (!fs.existsSync(filePath)) {
333
341
  exitWithError(
334
342
  `${fileType} not found: ${filePath}`,