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.
- package/.claude/settings.local.json +9 -0
- package/PLAN-tables-and-postprocess.md +850 -0
- package/README.md +33 -0
- package/bin/rev.js +12 -131
- package/bin/rev.ts +145 -0
- package/dist/bin/rev.d.ts +9 -0
- package/dist/bin/rev.d.ts.map +1 -0
- package/dist/bin/rev.js +118 -0
- package/dist/bin/rev.js.map +1 -0
- package/dist/lib/annotations.d.ts +91 -0
- package/dist/lib/annotations.d.ts.map +1 -0
- package/dist/lib/annotations.js +554 -0
- package/dist/lib/annotations.js.map +1 -0
- package/dist/lib/build.d.ts +171 -0
- package/dist/lib/build.d.ts.map +1 -0
- package/dist/lib/build.js +755 -0
- package/dist/lib/build.js.map +1 -0
- package/dist/lib/citations.d.ts +34 -0
- package/dist/lib/citations.d.ts.map +1 -0
- package/dist/lib/citations.js +140 -0
- package/dist/lib/citations.js.map +1 -0
- package/dist/lib/commands/build.d.ts +13 -0
- package/dist/lib/commands/build.d.ts.map +1 -0
- package/dist/lib/commands/build.js +678 -0
- package/dist/lib/commands/build.js.map +1 -0
- package/dist/lib/commands/citations.d.ts +11 -0
- package/dist/lib/commands/citations.d.ts.map +1 -0
- package/dist/lib/commands/citations.js +428 -0
- package/dist/lib/commands/citations.js.map +1 -0
- package/dist/lib/commands/comments.d.ts +11 -0
- package/dist/lib/commands/comments.d.ts.map +1 -0
- package/dist/lib/commands/comments.js +883 -0
- package/dist/lib/commands/comments.js.map +1 -0
- package/dist/lib/commands/context.d.ts +35 -0
- package/dist/lib/commands/context.d.ts.map +1 -0
- package/dist/lib/commands/context.js +59 -0
- package/dist/lib/commands/context.js.map +1 -0
- package/dist/lib/commands/core.d.ts +11 -0
- package/dist/lib/commands/core.d.ts.map +1 -0
- package/dist/lib/commands/core.js +246 -0
- package/dist/lib/commands/core.js.map +1 -0
- package/dist/lib/commands/doi.d.ts +11 -0
- package/dist/lib/commands/doi.d.ts.map +1 -0
- package/dist/lib/commands/doi.js +373 -0
- package/dist/lib/commands/doi.js.map +1 -0
- package/dist/lib/commands/history.d.ts +11 -0
- package/dist/lib/commands/history.d.ts.map +1 -0
- package/dist/lib/commands/history.js +245 -0
- package/dist/lib/commands/history.js.map +1 -0
- package/dist/lib/commands/index.d.ts +28 -0
- package/dist/lib/commands/index.d.ts.map +1 -0
- package/dist/lib/commands/index.js +35 -0
- package/dist/lib/commands/index.js.map +1 -0
- package/dist/lib/commands/init.d.ts +11 -0
- package/dist/lib/commands/init.d.ts.map +1 -0
- package/dist/lib/commands/init.js +209 -0
- package/dist/lib/commands/init.js.map +1 -0
- package/dist/lib/commands/response.d.ts +11 -0
- package/dist/lib/commands/response.d.ts.map +1 -0
- package/dist/lib/commands/response.js +317 -0
- package/dist/lib/commands/response.js.map +1 -0
- package/dist/lib/commands/sections.d.ts +11 -0
- package/dist/lib/commands/sections.d.ts.map +1 -0
- package/dist/lib/commands/sections.js +1071 -0
- package/dist/lib/commands/sections.js.map +1 -0
- package/dist/lib/commands/utilities.d.ts +19 -0
- package/dist/lib/commands/utilities.d.ts.map +1 -0
- package/dist/lib/commands/utilities.js +2009 -0
- package/dist/lib/commands/utilities.js.map +1 -0
- package/dist/lib/comment-realign.d.ts +50 -0
- package/dist/lib/comment-realign.d.ts.map +1 -0
- package/dist/lib/comment-realign.js +372 -0
- package/dist/lib/comment-realign.js.map +1 -0
- package/dist/lib/config.d.ts +41 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +76 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/crossref.d.ts +108 -0
- package/dist/lib/crossref.d.ts.map +1 -0
- package/dist/lib/crossref.js +597 -0
- package/dist/lib/crossref.js.map +1 -0
- package/dist/lib/dependencies.d.ts +30 -0
- package/dist/lib/dependencies.d.ts.map +1 -0
- package/dist/lib/dependencies.js +95 -0
- package/dist/lib/dependencies.js.map +1 -0
- package/dist/lib/doi-cache.d.ts +29 -0
- package/dist/lib/doi-cache.d.ts.map +1 -0
- package/dist/lib/doi-cache.js +104 -0
- package/dist/lib/doi-cache.js.map +1 -0
- package/dist/lib/doi.d.ts +65 -0
- package/dist/lib/doi.d.ts.map +1 -0
- package/dist/lib/doi.js +710 -0
- package/dist/lib/doi.js.map +1 -0
- package/dist/lib/equations.d.ts +61 -0
- package/dist/lib/equations.d.ts.map +1 -0
- package/dist/lib/equations.js +445 -0
- package/dist/lib/equations.js.map +1 -0
- package/dist/lib/errors.d.ts +60 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +303 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/format.d.ts +104 -0
- package/dist/lib/format.d.ts.map +1 -0
- package/dist/lib/format.js +416 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/git.d.ts +88 -0
- package/dist/lib/git.d.ts.map +1 -0
- package/dist/lib/git.js +304 -0
- package/dist/lib/git.js.map +1 -0
- package/dist/lib/grammar.d.ts +62 -0
- package/dist/lib/grammar.d.ts.map +1 -0
- package/dist/lib/grammar.js +244 -0
- package/dist/lib/grammar.js.map +1 -0
- package/dist/lib/image-registry.d.ts +68 -0
- package/dist/lib/image-registry.d.ts.map +1 -0
- package/dist/lib/image-registry.js +112 -0
- package/dist/lib/image-registry.js.map +1 -0
- package/dist/lib/import.d.ts +184 -0
- package/dist/lib/import.d.ts.map +1 -0
- package/dist/lib/import.js +1581 -0
- package/dist/lib/import.js.map +1 -0
- package/dist/lib/journals.d.ts +55 -0
- package/dist/lib/journals.d.ts.map +1 -0
- package/dist/lib/journals.js +417 -0
- package/dist/lib/journals.js.map +1 -0
- package/dist/lib/merge.d.ts +138 -0
- package/dist/lib/merge.d.ts.map +1 -0
- package/dist/lib/merge.js +603 -0
- package/dist/lib/merge.js.map +1 -0
- package/dist/lib/orcid.d.ts +36 -0
- package/dist/lib/orcid.d.ts.map +1 -0
- package/dist/lib/orcid.js +117 -0
- package/dist/lib/orcid.js.map +1 -0
- package/dist/lib/pdf-comments.d.ts +95 -0
- package/dist/lib/pdf-comments.d.ts.map +1 -0
- package/dist/lib/pdf-comments.js +192 -0
- package/dist/lib/pdf-comments.js.map +1 -0
- package/dist/lib/pdf-import.d.ts +118 -0
- package/dist/lib/pdf-import.d.ts.map +1 -0
- package/dist/lib/pdf-import.js +397 -0
- package/dist/lib/pdf-import.js.map +1 -0
- package/dist/lib/plugins.d.ts +76 -0
- package/dist/lib/plugins.d.ts.map +1 -0
- package/dist/lib/plugins.js +235 -0
- package/dist/lib/plugins.js.map +1 -0
- package/dist/lib/postprocess.d.ts +42 -0
- package/dist/lib/postprocess.d.ts.map +1 -0
- package/dist/lib/postprocess.js +138 -0
- package/dist/lib/postprocess.js.map +1 -0
- package/dist/lib/pptx-template.d.ts +59 -0
- package/dist/lib/pptx-template.d.ts.map +1 -0
- package/dist/lib/pptx-template.js +613 -0
- package/dist/lib/pptx-template.js.map +1 -0
- package/dist/lib/pptx-themes.d.ts +80 -0
- package/dist/lib/pptx-themes.d.ts.map +1 -0
- package/dist/lib/pptx-themes.js +818 -0
- package/dist/lib/pptx-themes.js.map +1 -0
- package/dist/lib/protect-restore.d.ts +137 -0
- package/dist/lib/protect-restore.d.ts.map +1 -0
- package/dist/lib/protect-restore.js +394 -0
- package/dist/lib/protect-restore.js.map +1 -0
- package/dist/lib/rate-limiter.d.ts +27 -0
- package/dist/lib/rate-limiter.d.ts.map +1 -0
- package/dist/lib/rate-limiter.js +79 -0
- package/dist/lib/rate-limiter.js.map +1 -0
- package/dist/lib/response.d.ts +41 -0
- package/dist/lib/response.d.ts.map +1 -0
- package/dist/lib/response.js +150 -0
- package/dist/lib/response.js.map +1 -0
- package/dist/lib/review.d.ts +35 -0
- package/dist/lib/review.d.ts.map +1 -0
- package/dist/lib/review.js +263 -0
- package/dist/lib/review.js.map +1 -0
- package/dist/lib/schema.d.ts +66 -0
- package/dist/lib/schema.d.ts.map +1 -0
- package/dist/lib/schema.js +339 -0
- package/dist/lib/schema.js.map +1 -0
- package/dist/lib/scientific-words.d.ts +6 -0
- package/dist/lib/scientific-words.d.ts.map +1 -0
- package/dist/lib/scientific-words.js +66 -0
- package/dist/lib/scientific-words.js.map +1 -0
- package/dist/lib/sections.d.ts +40 -0
- package/dist/lib/sections.d.ts.map +1 -0
- package/dist/lib/sections.js +288 -0
- package/dist/lib/sections.js.map +1 -0
- package/dist/lib/slides.d.ts +86 -0
- package/dist/lib/slides.d.ts.map +1 -0
- package/dist/lib/slides.js +676 -0
- package/dist/lib/slides.js.map +1 -0
- package/dist/lib/spelling.d.ts +76 -0
- package/dist/lib/spelling.d.ts.map +1 -0
- package/dist/lib/spelling.js +272 -0
- package/dist/lib/spelling.js.map +1 -0
- package/dist/lib/templates.d.ts +30 -0
- package/dist/lib/templates.d.ts.map +1 -0
- package/dist/lib/templates.js +504 -0
- package/dist/lib/templates.js.map +1 -0
- package/dist/lib/themes.d.ts +85 -0
- package/dist/lib/themes.d.ts.map +1 -0
- package/dist/lib/themes.js +652 -0
- package/dist/lib/themes.js.map +1 -0
- package/dist/lib/trackchanges.d.ts +51 -0
- package/dist/lib/trackchanges.d.ts.map +1 -0
- package/dist/lib/trackchanges.js +202 -0
- package/dist/lib/trackchanges.js.map +1 -0
- package/dist/lib/tui.d.ts +76 -0
- package/dist/lib/tui.d.ts.map +1 -0
- package/dist/lib/tui.js +377 -0
- package/dist/lib/tui.js.map +1 -0
- package/dist/lib/types.d.ts +447 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +6 -0
- package/dist/lib/types.js.map +1 -0
- package/dist/lib/undo.d.ts +57 -0
- package/dist/lib/undo.d.ts.map +1 -0
- package/dist/lib/undo.js +185 -0
- package/dist/lib/undo.js.map +1 -0
- package/dist/lib/utils.d.ts +16 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +40 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/variables.d.ts +42 -0
- package/dist/lib/variables.d.ts.map +1 -0
- package/dist/lib/variables.js +141 -0
- package/dist/lib/variables.js.map +1 -0
- package/dist/lib/word.d.ts +80 -0
- package/dist/lib/word.d.ts.map +1 -0
- package/dist/lib/word.js +360 -0
- package/dist/lib/word.js.map +1 -0
- package/dist/lib/wordcomments.d.ts +51 -0
- package/dist/lib/wordcomments.d.ts.map +1 -0
- package/dist/lib/wordcomments.js +587 -0
- package/dist/lib/wordcomments.js.map +1 -0
- package/eslint.config.js +27 -0
- package/lib/annotations.ts +622 -0
- package/lib/apply-buildup-colors.py +88 -0
- package/lib/build.ts +1013 -0
- package/lib/{citations.js → citations.ts} +38 -27
- package/lib/commands/{build.js → build.ts} +80 -27
- package/lib/commands/{citations.js → citations.ts} +36 -18
- package/lib/commands/{comments.js → comments.ts} +187 -54
- package/lib/commands/{context.js → context.ts} +18 -8
- package/lib/commands/{core.js → core.ts} +34 -20
- package/lib/commands/{doi.js → doi.ts} +32 -16
- package/lib/commands/{history.js → history.ts} +25 -12
- package/lib/commands/{index.js → index.ts} +9 -5
- package/lib/commands/{init.js → init.ts} +20 -8
- package/lib/commands/{response.js → response.ts} +47 -20
- package/lib/commands/{sections.js → sections.ts} +273 -68
- package/lib/commands/{utilities.js → utilities.ts} +338 -158
- package/lib/{comment-realign.js → comment-realign.ts} +117 -45
- package/lib/config.ts +84 -0
- package/lib/{crossref.js → crossref.ts} +213 -138
- package/lib/dependencies.ts +106 -0
- package/lib/doi-cache.ts +115 -0
- package/lib/{doi.js → doi.ts} +115 -281
- package/lib/{equations.js → equations.ts} +60 -64
- package/lib/{errors.js → errors.ts} +56 -48
- package/lib/{format.js → format.ts} +137 -63
- package/lib/{git.js → git.ts} +66 -63
- package/lib/{grammar.js → grammar.ts} +45 -32
- package/lib/image-registry.ts +180 -0
- package/lib/import.ts +2060 -0
- package/lib/journals.ts +505 -0
- package/lib/{merge.js → merge.ts} +185 -135
- package/lib/{orcid.js → orcid.ts} +17 -22
- package/lib/{pdf-comments.js → pdf-comments.ts} +76 -18
- package/lib/{pdf-import.js → pdf-import.ts} +148 -70
- package/lib/{plugins.js → plugins.ts} +82 -39
- package/lib/postprocess.ts +188 -0
- package/lib/pptx-color-filter.lua +37 -0
- package/lib/pptx-template.ts +625 -0
- package/lib/pptx-themes/academic.pptx +0 -0
- package/lib/pptx-themes/corporate.pptx +0 -0
- package/lib/pptx-themes/dark.pptx +0 -0
- package/lib/pptx-themes/default.pptx +0 -0
- package/lib/pptx-themes/minimal.pptx +0 -0
- package/lib/pptx-themes/plant.pptx +0 -0
- package/lib/pptx-themes.ts +896 -0
- package/lib/protect-restore.ts +516 -0
- package/lib/rate-limiter.ts +94 -0
- package/lib/{response.js → response.ts} +36 -21
- package/lib/{review.js → review.ts} +53 -43
- package/lib/{schema.js → schema.ts} +70 -25
- package/lib/{sections.js → sections.ts} +71 -76
- package/lib/slides.ts +793 -0
- package/lib/{spelling.js → spelling.ts} +43 -59
- package/lib/{templates.js → templates.ts} +20 -17
- package/lib/themes.ts +742 -0
- package/lib/{trackchanges.js → trackchanges.ts} +52 -23
- package/lib/types.ts +509 -0
- package/lib/{undo.js → undo.ts} +75 -52
- package/lib/utils.ts +41 -0
- package/lib/{variables.js → variables.ts} +60 -54
- package/lib/word.ts +428 -0
- package/lib/{wordcomments.js → wordcomments.ts} +94 -40
- package/package.json +15 -5
- package/skill/REFERENCE.md +67 -0
- package/tsconfig.json +26 -0
- package/lib/annotations.js +0 -414
- package/lib/build.js +0 -639
- package/lib/config.js +0 -79
- package/lib/import.js +0 -1145
- package/lib/journals.js +0 -629
- package/lib/word.js +0 -225
- /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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
82
|
+
const part = parts[i];
|
|
83
|
+
if (part && part.trim()) {
|
|
81
84
|
equations.push({
|
|
82
85
|
type: 'display',
|
|
83
|
-
content:
|
|
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
|
-
|
|
91
|
-
|
|
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
|
-
|
|
114
|
-
|
|
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)
|
|
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(
|
|
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(
|
|
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: []
|
|
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(
|
|
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
|
|
12
|
-
* @param
|
|
13
|
-
* @returns
|
|
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
|
|
31
|
-
* @returns
|
|
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
|
|
79
|
-
* @returns
|
|
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
|
|
137
|
-
* @param
|
|
138
|
-
* @returns
|
|
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
|
|
184
|
-
* @returns
|
|
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
|
|
222
|
-
* @param
|
|
223
|
-
* @returns
|
|
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
|
|
269
|
-
* @param
|
|
270
|
-
* @param
|
|
271
|
-
* @returns
|
|
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
|
|
319
|
-
* @param
|
|
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
|
|
329
|
-
* @param
|
|
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}`,
|