docrev 0.9.4 → 0.9.6

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 (141) hide show
  1. package/dist/lib/commands/comments.d.ts.map +1 -1
  2. package/dist/lib/commands/comments.js +19 -27
  3. package/dist/lib/commands/comments.js.map +1 -1
  4. package/dist/lib/commands/context.d.ts +1 -0
  5. package/dist/lib/commands/context.d.ts.map +1 -1
  6. package/dist/lib/commands/context.js +1 -2
  7. package/dist/lib/commands/context.js.map +1 -1
  8. package/dist/lib/commands/file-ops.d.ts +11 -0
  9. package/dist/lib/commands/file-ops.d.ts.map +1 -0
  10. package/dist/lib/commands/file-ops.js +301 -0
  11. package/dist/lib/commands/file-ops.js.map +1 -0
  12. package/dist/lib/commands/index.d.ts +9 -1
  13. package/dist/lib/commands/index.d.ts.map +1 -1
  14. package/dist/lib/commands/index.js +17 -1
  15. package/dist/lib/commands/index.js.map +1 -1
  16. package/dist/lib/commands/merge-resolve.d.ts +12 -0
  17. package/dist/lib/commands/merge-resolve.d.ts.map +1 -0
  18. package/dist/lib/commands/merge-resolve.js +318 -0
  19. package/dist/lib/commands/merge-resolve.js.map +1 -0
  20. package/dist/lib/commands/preview.d.ts +11 -0
  21. package/dist/lib/commands/preview.d.ts.map +1 -0
  22. package/dist/lib/commands/preview.js +138 -0
  23. package/dist/lib/commands/preview.js.map +1 -0
  24. package/dist/lib/commands/project-info.d.ts +11 -0
  25. package/dist/lib/commands/project-info.d.ts.map +1 -0
  26. package/dist/lib/commands/project-info.js +187 -0
  27. package/dist/lib/commands/project-info.js.map +1 -0
  28. package/dist/lib/commands/quality.d.ts +11 -0
  29. package/dist/lib/commands/quality.d.ts.map +1 -0
  30. package/dist/lib/commands/quality.js +384 -0
  31. package/dist/lib/commands/quality.js.map +1 -0
  32. package/dist/lib/commands/sections.d.ts +3 -2
  33. package/dist/lib/commands/sections.d.ts.map +1 -1
  34. package/dist/lib/commands/sections.js +4 -723
  35. package/dist/lib/commands/sections.js.map +1 -1
  36. package/dist/lib/commands/sync.d.ts +11 -0
  37. package/dist/lib/commands/sync.d.ts.map +1 -0
  38. package/dist/lib/commands/sync.js +441 -0
  39. package/dist/lib/commands/sync.js.map +1 -0
  40. package/dist/lib/commands/text-ops.d.ts +11 -0
  41. package/dist/lib/commands/text-ops.d.ts.map +1 -0
  42. package/dist/lib/commands/text-ops.js +357 -0
  43. package/dist/lib/commands/text-ops.js.map +1 -0
  44. package/dist/lib/commands/utilities.d.ts +2 -4
  45. package/dist/lib/commands/utilities.d.ts.map +1 -1
  46. package/dist/lib/commands/utilities.js +3 -1605
  47. package/dist/lib/commands/utilities.js.map +1 -1
  48. package/dist/lib/commands/word-tools.d.ts +11 -0
  49. package/dist/lib/commands/word-tools.d.ts.map +1 -0
  50. package/dist/lib/commands/word-tools.js +272 -0
  51. package/dist/lib/commands/word-tools.js.map +1 -0
  52. package/dist/lib/comment-realign.d.ts.map +1 -1
  53. package/dist/lib/comment-realign.js +0 -7
  54. package/dist/lib/comment-realign.js.map +1 -1
  55. package/dist/lib/dependencies.d.ts.map +1 -1
  56. package/dist/lib/dependencies.js +11 -23
  57. package/dist/lib/dependencies.js.map +1 -1
  58. package/dist/lib/diff-engine.d.ts +25 -0
  59. package/dist/lib/diff-engine.d.ts.map +1 -0
  60. package/dist/lib/diff-engine.js +354 -0
  61. package/dist/lib/diff-engine.js.map +1 -0
  62. package/dist/lib/git.d.ts.map +1 -1
  63. package/dist/lib/git.js +18 -28
  64. package/dist/lib/git.js.map +1 -1
  65. package/dist/lib/import.d.ts +37 -117
  66. package/dist/lib/import.d.ts.map +1 -1
  67. package/dist/lib/import.js +10 -1039
  68. package/dist/lib/import.js.map +1 -1
  69. package/dist/lib/merge.d.ts.map +1 -1
  70. package/dist/lib/merge.js +29 -117
  71. package/dist/lib/merge.js.map +1 -1
  72. package/dist/lib/pdf-comments.d.ts.map +1 -1
  73. package/dist/lib/pdf-comments.js +1 -13
  74. package/dist/lib/pdf-comments.js.map +1 -1
  75. package/dist/lib/pptx-themes.d.ts.map +1 -1
  76. package/dist/lib/pptx-themes.js +0 -403
  77. package/dist/lib/pptx-themes.js.map +1 -1
  78. package/dist/lib/protect-restore.d.ts.map +1 -1
  79. package/dist/lib/protect-restore.js +34 -36
  80. package/dist/lib/protect-restore.js.map +1 -1
  81. package/dist/lib/restore-references.d.ts +35 -0
  82. package/dist/lib/restore-references.d.ts.map +1 -0
  83. package/dist/lib/restore-references.js +188 -0
  84. package/dist/lib/restore-references.js.map +1 -0
  85. package/dist/lib/slides.d.ts.map +1 -1
  86. package/dist/lib/slides.js +0 -35
  87. package/dist/lib/slides.js.map +1 -1
  88. package/dist/lib/trackchanges.d.ts.map +1 -1
  89. package/dist/lib/trackchanges.js +1 -11
  90. package/dist/lib/trackchanges.js.map +1 -1
  91. package/dist/lib/tui.d.ts +36 -45
  92. package/dist/lib/tui.d.ts.map +1 -1
  93. package/dist/lib/tui.js +92 -108
  94. package/dist/lib/tui.js.map +1 -1
  95. package/dist/lib/undo.d.ts +3 -4
  96. package/dist/lib/undo.d.ts.map +1 -1
  97. package/dist/lib/undo.js +0 -7
  98. package/dist/lib/undo.js.map +1 -1
  99. package/dist/lib/utils.d.ts +12 -0
  100. package/dist/lib/utils.d.ts.map +1 -1
  101. package/dist/lib/utils.js +26 -0
  102. package/dist/lib/utils.js.map +1 -1
  103. package/dist/lib/word-extraction.d.ts +77 -0
  104. package/dist/lib/word-extraction.d.ts.map +1 -0
  105. package/dist/lib/word-extraction.js +515 -0
  106. package/dist/lib/word-extraction.js.map +1 -0
  107. package/dist/lib/wordcomments.d.ts.map +1 -1
  108. package/dist/lib/wordcomments.js +1 -8
  109. package/dist/lib/wordcomments.js.map +1 -1
  110. package/dist/package.json +137 -0
  111. package/lib/commands/comments.ts +20 -25
  112. package/lib/commands/context.ts +1 -2
  113. package/lib/commands/file-ops.ts +372 -0
  114. package/lib/commands/index.ts +24 -0
  115. package/lib/commands/merge-resolve.ts +378 -0
  116. package/lib/commands/preview.ts +178 -0
  117. package/lib/commands/project-info.ts +244 -0
  118. package/lib/commands/quality.ts +517 -0
  119. package/lib/commands/sections.ts +3 -857
  120. package/lib/commands/sync.ts +536 -0
  121. package/lib/commands/text-ops.ts +449 -0
  122. package/lib/commands/utilities.ts +62 -2066
  123. package/lib/commands/word-tools.ts +340 -0
  124. package/lib/comment-realign.ts +0 -8
  125. package/lib/dependencies.ts +12 -20
  126. package/lib/diff-engine.ts +465 -0
  127. package/lib/git.ts +24 -31
  128. package/lib/import.ts +78 -1348
  129. package/lib/merge.ts +42 -132
  130. package/lib/pdf-comments.ts +2 -14
  131. package/lib/pptx-themes.ts +0 -413
  132. package/lib/protect-restore.ts +48 -44
  133. package/lib/restore-references.ts +240 -0
  134. package/lib/slides.ts +0 -37
  135. package/lib/trackchanges.ts +1 -12
  136. package/lib/{tui.js → tui.ts} +139 -126
  137. package/lib/undo.ts +3 -12
  138. package/lib/utils.ts +28 -0
  139. package/lib/word-extraction.ts +666 -0
  140. package/lib/wordcomments.ts +1 -9
  141. package/package.json +1 -1
package/lib/merge.ts CHANGED
@@ -178,18 +178,15 @@ export async function checkBaseMatch(basePath: string, reviewerPath: string): Pr
178
178
  }
179
179
 
180
180
  /**
181
- * Extract changes from a Word document compared to original
182
- * Uses sentence-level diffing for better conflict detection
183
- * @param originalText - Original text (from base document)
184
- * @param wordText - Text extracted from reviewer's Word doc
181
+ * Extract changes from diffs between original and modified text
182
+ * @param diffs - Array of diff changes
185
183
  * @param reviewer - Reviewer identifier
186
184
  */
187
- export function extractChanges(originalText: string, wordText: string, reviewer: string): ReviewerChange[] {
185
+ function extractChangesFromDiffs(
186
+ diffs: Array<{ added?: boolean; removed?: boolean; value: string }>,
187
+ reviewer: string,
188
+ ): ReviewerChange[] {
188
189
  const changes: ReviewerChange[] = [];
189
-
190
- // Use sentence-level diff for better granularity
191
- const diffs = diffSentences(originalText, wordText);
192
-
193
190
  let originalPos = 0;
194
191
  let i = 0;
195
192
 
@@ -198,11 +195,9 @@ export function extractChanges(originalText: string, wordText: string, reviewer:
198
195
  if (!part) break;
199
196
 
200
197
  if (!part.added && !part.removed) {
201
- // Unchanged
202
198
  originalPos += part.value.length;
203
199
  i++;
204
200
  } else if (part.removed && diffs[i + 1]?.added) {
205
- // Replacement: removed followed by added
206
201
  const nextPart = diffs[i + 1];
207
202
  if (!nextPart) break;
208
203
  changes.push({
@@ -216,7 +211,6 @@ export function extractChanges(originalText: string, wordText: string, reviewer:
216
211
  originalPos += part.value.length;
217
212
  i += 2;
218
213
  } else if (part.removed) {
219
- // Pure deletion
220
214
  changes.push({
221
215
  reviewer,
222
216
  type: 'delete',
@@ -228,7 +222,6 @@ export function extractChanges(originalText: string, wordText: string, reviewer:
228
222
  originalPos += part.value.length;
229
223
  i++;
230
224
  } else if (part.added) {
231
- // Pure insertion
232
225
  changes.push({
233
226
  reviewer,
234
227
  type: 'insert',
@@ -244,61 +237,22 @@ export function extractChanges(originalText: string, wordText: string, reviewer:
244
237
  return changes;
245
238
  }
246
239
 
240
+ /**
241
+ * Extract changes from a Word document compared to original
242
+ * Uses sentence-level diffing for better conflict detection
243
+ * @param originalText - Original text (from base document)
244
+ * @param wordText - Text extracted from reviewer's Word doc
245
+ * @param reviewer - Reviewer identifier
246
+ */
247
+ export function extractChanges(originalText: string, wordText: string, reviewer: string): ReviewerChange[] {
248
+ return extractChangesFromDiffs(diffSentences(originalText, wordText), reviewer);
249
+ }
250
+
247
251
  /**
248
252
  * Extract changes using word-level diff (more fine-grained)
249
253
  */
250
254
  export function extractChangesWordLevel(originalText: string, wordText: string, reviewer: string): ReviewerChange[] {
251
- const changes: ReviewerChange[] = [];
252
- const diffs = diffWords(originalText, wordText);
253
-
254
- let originalPos = 0;
255
- let i = 0;
256
-
257
- while (i < diffs.length) {
258
- const part = diffs[i];
259
- if (!part) break;
260
-
261
- if (!part.added && !part.removed) {
262
- originalPos += part.value.length;
263
- i++;
264
- } else if (part.removed && diffs[i + 1]?.added) {
265
- const nextPart = diffs[i + 1];
266
- if (!nextPart) break;
267
- changes.push({
268
- reviewer,
269
- type: 'replace',
270
- start: originalPos,
271
- end: originalPos + part.value.length,
272
- oldText: part.value,
273
- newText: nextPart.value,
274
- });
275
- originalPos += part.value.length;
276
- i += 2;
277
- } else if (part.removed) {
278
- changes.push({
279
- reviewer,
280
- type: 'delete',
281
- start: originalPos,
282
- end: originalPos + part.value.length,
283
- oldText: part.value,
284
- newText: '',
285
- });
286
- originalPos += part.value.length;
287
- i++;
288
- } else if (part.added) {
289
- changes.push({
290
- reviewer,
291
- type: 'insert',
292
- start: originalPos,
293
- end: originalPos,
294
- oldText: '',
295
- newText: part.value,
296
- });
297
- i++;
298
- }
299
- }
300
-
301
- return changes;
255
+ return extractChangesFromDiffs(diffWords(originalText, wordText), reviewer);
302
256
  }
303
257
 
304
258
  /**
@@ -563,23 +517,15 @@ export function clearConflicts(projectDir: string): void {
563
517
  }
564
518
 
565
519
  /**
566
- * Merge multiple Word documents using three-way merge
520
+ * Core merge logic: extract changes from reviewer docs, detect conflicts, apply annotations
567
521
  */
568
- export async function mergeThreeWay(
569
- basePath: string,
522
+ async function mergeReviewerDocsCore(
523
+ baseText: string,
570
524
  reviewerDocs: ReviewerDoc[],
571
- options: MergeOptions = {}
572
- ): Promise<MergeResult & { baseText: string }> {
525
+ options: MergeOptions = {},
526
+ ): Promise<MergeResult> {
573
527
  const { diffLevel = 'sentence' } = options;
574
528
 
575
- if (!fs.existsSync(basePath)) {
576
- throw new Error(`Base document not found: ${basePath}`);
577
- }
578
-
579
- // Extract text from base document
580
- const { text: baseText } = await extractFromWord(basePath);
581
-
582
- // Extract changes from each reviewer relative to base
583
529
  const allChanges: ReviewerChange[][] = [];
584
530
  const allComments: ReviewerComment[] = [];
585
531
 
@@ -590,14 +536,12 @@ export async function mergeThreeWay(
590
536
 
591
537
  const { text: wordText } = await extractFromWord(doc.path);
592
538
 
593
- // Choose diff level
594
539
  const changes = diffLevel === 'word'
595
540
  ? extractChangesWordLevel(baseText, wordText, doc.name)
596
541
  : extractChanges(baseText, wordText, doc.name);
597
542
 
598
543
  allChanges.push(changes);
599
544
 
600
- // Also extract comments
601
545
  try {
602
546
  const comments = await extractWordComments(doc.path);
603
547
  allComments.push(...comments.map(c => ({ ...c, reviewer: doc.name })));
@@ -609,13 +553,10 @@ export async function mergeThreeWay(
609
553
  }
610
554
  }
611
555
 
612
- // Detect conflicts
613
556
  const { conflicts, nonConflicting } = detectConflicts(allChanges);
614
557
 
615
- // Apply non-conflicting changes as annotations
616
558
  let merged = applyChangesAsAnnotations(baseText, nonConflicting);
617
559
 
618
- // Add comments with reviewer attribution
619
560
  for (const comment of allComments) {
620
561
  merged += `\n{>>${comment.reviewer}: ${comment.text}<<}`;
621
562
  }
@@ -628,7 +569,24 @@ export async function mergeThreeWay(
628
569
  comments: allComments.length,
629
570
  };
630
571
 
631
- return { merged, conflicts, stats, baseText, originalText: baseText };
572
+ return { merged, conflicts, stats, originalText: baseText };
573
+ }
574
+
575
+ /**
576
+ * Merge multiple Word documents using three-way merge
577
+ */
578
+ export async function mergeThreeWay(
579
+ basePath: string,
580
+ reviewerDocs: ReviewerDoc[],
581
+ options: MergeOptions = {}
582
+ ): Promise<MergeResult & { baseText: string }> {
583
+ if (!fs.existsSync(basePath)) {
584
+ throw new Error(`Base document not found: ${basePath}`);
585
+ }
586
+
587
+ const { text: baseText } = await extractFromWord(basePath);
588
+ const result = await mergeReviewerDocsCore(baseText, reviewerDocs, options);
589
+ return { ...result, baseText };
632
590
  }
633
591
 
634
592
  /**
@@ -640,60 +598,12 @@ export async function mergeReviewerDocs(
640
598
  reviewerDocs: ReviewerDoc[],
641
599
  options: MergeOptions = {}
642
600
  ): Promise<MergeResult> {
643
- const { autoResolve = false } = options;
644
-
645
601
  if (!fs.existsSync(originalPath)) {
646
602
  throw new Error(`Original file not found: ${originalPath}`);
647
603
  }
648
604
 
649
605
  const originalText = fs.readFileSync(originalPath, 'utf-8');
650
-
651
- // Extract changes from each reviewer
652
- const allChanges: ReviewerChange[][] = [];
653
- const allComments: ReviewerComment[] = [];
654
-
655
- for (const doc of reviewerDocs) {
656
- if (!fs.existsSync(doc.path)) {
657
- throw new Error(`Reviewer file not found: ${doc.path}`);
658
- }
659
-
660
- const { text: wordText } = await extractFromWord(doc.path);
661
- const changes = extractChanges(originalText, wordText, doc.name);
662
- allChanges.push(changes);
663
-
664
- // Also extract comments
665
- try {
666
- const comments = await extractWordComments(doc.path);
667
- allComments.push(...comments.map(c => ({ ...c, reviewer: doc.name })));
668
- } catch (e) {
669
- if (process.env.DEBUG) {
670
- const error = e as Error;
671
- console.warn(`merge: Failed to extract comments:`, error.message);
672
- }
673
- }
674
- }
675
-
676
- // Detect conflicts
677
- const { conflicts, nonConflicting } = detectConflicts(allChanges);
678
-
679
- // Apply non-conflicting changes as annotations
680
- let merged = applyChangesAsAnnotations(originalText, nonConflicting);
681
-
682
- // Add comments
683
- for (const comment of allComments) {
684
- // Append comments at the end for now (position tracking is complex)
685
- merged += `\n{>>${comment.reviewer}: ${comment.text}<<}`;
686
- }
687
-
688
- const stats = {
689
- reviewers: reviewerDocs.length,
690
- totalChanges: allChanges.flat().length,
691
- nonConflicting: nonConflicting.length,
692
- conflicts: conflicts.length,
693
- comments: allComments.length,
694
- };
695
-
696
- return { merged, conflicts, stats, originalText };
606
+ return mergeReviewerDocsCore(originalText, reviewerDocs, options);
697
607
  }
698
608
 
699
609
  /**
@@ -4,6 +4,8 @@
4
4
  * Converts CriticMarkup comments to LaTeX margin notes for PDF output
5
5
  */
6
6
 
7
+ import { escapeLatex } from './utils.js';
8
+
7
9
  /**
8
10
  * LaTeX preamble for margin comments
9
11
  * Uses todonotes package with custom styling
@@ -117,20 +119,6 @@ export function convertCommentsToMarginNotes(
117
119
  };
118
120
  }
119
121
 
120
- /**
121
- * Escape LaTeX special characters
122
- * @param text - Text to escape
123
- * @returns Escaped text
124
- */
125
- function escapeLatex(text: string): string {
126
- return text
127
- .replace(/\\/g, '\\textbackslash{}')
128
- .replace(/([#$%&_{}])/g, '\\$1')
129
- .replace(/\^/g, '\\textasciicircum{}')
130
- .replace(/~/g, '\\textasciitilde{}')
131
- .replace(/\n/g, ' '); // Replace newlines with spaces
132
- }
133
-
134
122
  /**
135
123
  * Result of track changes conversion
136
124
  */