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
|
@@ -7,10 +7,78 @@ import * as fs from 'fs';
|
|
|
7
7
|
import AdmZip from 'adm-zip';
|
|
8
8
|
import { parseStringPromise } from 'xml2js';
|
|
9
9
|
|
|
10
|
+
interface CommentData {
|
|
11
|
+
author: string;
|
|
12
|
+
text: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface CommentWithPosition {
|
|
16
|
+
id: string;
|
|
17
|
+
position: number;
|
|
18
|
+
author: string;
|
|
19
|
+
text: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface Paragraph {
|
|
23
|
+
text: string;
|
|
24
|
+
comments: CommentWithPosition[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface MdParagraph {
|
|
28
|
+
text: string;
|
|
29
|
+
start: number;
|
|
30
|
+
end: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface ParagraphMatch {
|
|
34
|
+
index: number;
|
|
35
|
+
score: number;
|
|
36
|
+
paragraph: MdParagraph;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface WordContext {
|
|
40
|
+
before: string[];
|
|
41
|
+
after: string[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface CommentInsertion {
|
|
45
|
+
position: number;
|
|
46
|
+
text: string;
|
|
47
|
+
commentText: string;
|
|
48
|
+
hasReplies: boolean;
|
|
49
|
+
debug: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface RealignOptions {
|
|
53
|
+
dryRun?: boolean;
|
|
54
|
+
author?: string;
|
|
55
|
+
replyAuthor?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface RealignResult {
|
|
59
|
+
success: boolean;
|
|
60
|
+
dryRun?: boolean;
|
|
61
|
+
insertions: number;
|
|
62
|
+
matched?: number;
|
|
63
|
+
unmatched?: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface RealignMarkdownOptions {
|
|
67
|
+
author?: string;
|
|
68
|
+
replyAuthor?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface RealignMarkdownResult {
|
|
72
|
+
success: boolean;
|
|
73
|
+
markdown: string;
|
|
74
|
+
insertions: number;
|
|
75
|
+
error?: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
10
78
|
/**
|
|
11
79
|
* Extract paragraphs with their full text and comment positions from DOCX
|
|
12
80
|
*/
|
|
13
|
-
export async function extractParagraphsWithComments(docxPath) {
|
|
81
|
+
export async function extractParagraphsWithComments(docxPath: string): Promise<Paragraph[]> {
|
|
14
82
|
const zip = new AdmZip(docxPath);
|
|
15
83
|
const doc = zip.readAsText('word/document.xml');
|
|
16
84
|
const commentsXml = zip.readAsText('word/comments.xml');
|
|
@@ -21,13 +89,13 @@ export async function extractParagraphsWithComments(docxPath) {
|
|
|
21
89
|
if (!commentNodes) return [];
|
|
22
90
|
|
|
23
91
|
const nodes = Array.isArray(commentNodes) ? commentNodes : [commentNodes];
|
|
24
|
-
const commentData = {};
|
|
92
|
+
const commentData: Record<string, CommentData> = {};
|
|
25
93
|
|
|
26
94
|
for (const c of nodes) {
|
|
27
|
-
const id = c
|
|
28
|
-
const author = c
|
|
95
|
+
const id = c.$?.['w:id'] ?? '';
|
|
96
|
+
const author = c.$?.['w:author'] ?? 'Unknown';
|
|
29
97
|
let text = '';
|
|
30
|
-
const extractT = (n) => {
|
|
98
|
+
const extractT = (n: any): void => {
|
|
31
99
|
if (!n) return;
|
|
32
100
|
if (n['w:t']) {
|
|
33
101
|
const t = n['w:t'];
|
|
@@ -45,7 +113,7 @@ export async function extractParagraphsWithComments(docxPath) {
|
|
|
45
113
|
}
|
|
46
114
|
|
|
47
115
|
// Extract paragraphs with comments
|
|
48
|
-
const paragraphs = [];
|
|
116
|
+
const paragraphs: Paragraph[] = [];
|
|
49
117
|
const paraPattern = /<w:p\b[^>]*>([\s\S]*?)<\/w:p>/g;
|
|
50
118
|
let match;
|
|
51
119
|
|
|
@@ -55,7 +123,7 @@ export async function extractParagraphsWithComments(docxPath) {
|
|
|
55
123
|
|
|
56
124
|
// Build paragraph text and track comment positions
|
|
57
125
|
let text = '';
|
|
58
|
-
const comments = [];
|
|
126
|
+
const comments: CommentWithPosition[] = [];
|
|
59
127
|
|
|
60
128
|
const tokenPattern = /<w:t[^>]*>([^<]*)<\/w:t>|<w:commentRangeStart[^>]*w:id="(\d+)"[^>]*\/?>/g;
|
|
61
129
|
let tokenMatch;
|
|
@@ -88,14 +156,14 @@ export async function extractParagraphsWithComments(docxPath) {
|
|
|
88
156
|
/**
|
|
89
157
|
* Find best matching paragraph in markdown for a reference paragraph
|
|
90
158
|
*/
|
|
91
|
-
function findMatchingParagraph(refText, mdParagraphs) {
|
|
159
|
+
function findMatchingParagraph(refText: string, mdParagraphs: MdParagraph[]): ParagraphMatch | null {
|
|
92
160
|
// Normalize for comparison
|
|
93
|
-
const normalize = (s) => s.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
161
|
+
const normalize = (s: string): string => s.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
94
162
|
const refNorm = normalize(refText);
|
|
95
163
|
|
|
96
164
|
if (refNorm.length < 20) return null;
|
|
97
165
|
|
|
98
|
-
let bestMatch = null;
|
|
166
|
+
let bestMatch: ParagraphMatch | null = null;
|
|
99
167
|
let bestScore = 0;
|
|
100
168
|
|
|
101
169
|
for (let i = 0; i < mdParagraphs.length; i++) {
|
|
@@ -122,20 +190,23 @@ function findMatchingParagraph(refText, mdParagraphs) {
|
|
|
122
190
|
/**
|
|
123
191
|
* Extract paragraphs from markdown (split by blank lines)
|
|
124
192
|
*/
|
|
125
|
-
function parseMdParagraphs(markdown) {
|
|
126
|
-
const paragraphs = [];
|
|
193
|
+
function parseMdParagraphs(markdown: string): MdParagraph[] {
|
|
194
|
+
const paragraphs: MdParagraph[] = [];
|
|
127
195
|
const parts = markdown.split(/\n\n+/);
|
|
128
196
|
|
|
129
197
|
let pos = 0;
|
|
130
198
|
for (const part of parts) {
|
|
131
199
|
const trimmed = part.trim();
|
|
132
200
|
if (trimmed) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
201
|
+
const partStart = markdown.indexOf(part, pos);
|
|
202
|
+
if (partStart !== -1) {
|
|
203
|
+
paragraphs.push({
|
|
204
|
+
text: trimmed,
|
|
205
|
+
start: partStart,
|
|
206
|
+
end: partStart + part.length,
|
|
207
|
+
});
|
|
208
|
+
pos = partStart + part.length;
|
|
209
|
+
}
|
|
139
210
|
}
|
|
140
211
|
}
|
|
141
212
|
|
|
@@ -145,7 +216,7 @@ function parseMdParagraphs(markdown) {
|
|
|
145
216
|
/**
|
|
146
217
|
* Strip existing comments from a specific author
|
|
147
218
|
*/
|
|
148
|
-
function stripAuthorComments(text, author) {
|
|
219
|
+
function stripAuthorComments(text: string, author: string): string {
|
|
149
220
|
const pattern = new RegExp(`\\s*\\{>>${author}:[^<]*<<\\}`, 'g');
|
|
150
221
|
return text.replace(pattern, '');
|
|
151
222
|
}
|
|
@@ -153,7 +224,7 @@ function stripAuthorComments(text, author) {
|
|
|
153
224
|
/**
|
|
154
225
|
* Normalize text for matching (remove citations, extra whitespace)
|
|
155
226
|
*/
|
|
156
|
-
function normalizeForMatching(text) {
|
|
227
|
+
function normalizeForMatching(text: string): string {
|
|
157
228
|
return text
|
|
158
229
|
// Remove Word citation placeholders
|
|
159
230
|
.replace(/\(\s*\$+\s*\)/g, '')
|
|
@@ -174,7 +245,7 @@ function normalizeForMatching(text) {
|
|
|
174
245
|
/**
|
|
175
246
|
* Find the word at or near a position in text
|
|
176
247
|
*/
|
|
177
|
-
function getWordAtPosition(text, pos) {
|
|
248
|
+
function getWordAtPosition(text: string, pos: number): WordContext {
|
|
178
249
|
const before = text.slice(Math.max(0, pos - 30), pos);
|
|
179
250
|
const after = text.slice(pos, pos + 30);
|
|
180
251
|
|
|
@@ -192,7 +263,7 @@ function getWordAtPosition(text, pos) {
|
|
|
192
263
|
* Find position in markdown paragraph matching reference position
|
|
193
264
|
* Uses the anchor word (word immediately before the comment) for precise matching
|
|
194
265
|
*/
|
|
195
|
-
function findMdPosition(refText, refPos, mdText) {
|
|
266
|
+
function findMdPosition(refText: string, refPos: number, mdText: string): number {
|
|
196
267
|
// Get the word(s) immediately before the comment position in reference
|
|
197
268
|
const refWords = getWordAtPosition(refText, refPos);
|
|
198
269
|
const normalizedMd = normalizeForMatching(mdText);
|
|
@@ -218,7 +289,7 @@ function findMdPosition(refText, refPos, mdText) {
|
|
|
218
289
|
|
|
219
290
|
if (matches.length === 1) {
|
|
220
291
|
// Unique match - use this position
|
|
221
|
-
const matchEnd = matches[0].index + matches[0][0].length;
|
|
292
|
+
const matchEnd = matches[0].index! + matches[0][0].length;
|
|
222
293
|
// Map back to original markdown position
|
|
223
294
|
const ratio = matchEnd / Math.max(normalizedMd.length, 1);
|
|
224
295
|
return Math.round(ratio * mdText.length);
|
|
@@ -228,7 +299,7 @@ function findMdPosition(refText, refPos, mdText) {
|
|
|
228
299
|
if (afterWords.length > 0) {
|
|
229
300
|
const afterPattern = afterWords[0].toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
230
301
|
for (const match of matches) {
|
|
231
|
-
const matchEnd = match.index + match[0].length;
|
|
302
|
+
const matchEnd = match.index! + match[0].length;
|
|
232
303
|
const afterContext = normalizedMd.slice(matchEnd, matchEnd + 50);
|
|
233
304
|
if (afterContext.includes(afterPattern)) {
|
|
234
305
|
const ratio = matchEnd / Math.max(normalizedMd.length, 1);
|
|
@@ -237,7 +308,7 @@ function findMdPosition(refText, refPos, mdText) {
|
|
|
237
308
|
}
|
|
238
309
|
}
|
|
239
310
|
// Fall back to first match
|
|
240
|
-
const matchEnd = matches[0].index + matches[0][0].length;
|
|
311
|
+
const matchEnd = matches[0].index! + matches[0][0].length;
|
|
241
312
|
const ratio = matchEnd / Math.max(normalizedMd.length, 1);
|
|
242
313
|
return Math.round(ratio * mdText.length);
|
|
243
314
|
}
|
|
@@ -252,8 +323,8 @@ function findMdPosition(refText, refPos, mdText) {
|
|
|
252
323
|
* Extract reply comments that follow a parent comment
|
|
253
324
|
* Returns map of parent comment text -> array of reply texts
|
|
254
325
|
*/
|
|
255
|
-
function extractReplies(markdown, parentAuthor, replyAuthor) {
|
|
256
|
-
const replies = new Map();
|
|
326
|
+
function extractReplies(markdown: string, parentAuthor: string, replyAuthor: string): Map<string, string[]> {
|
|
327
|
+
const replies = new Map<string, string[]>();
|
|
257
328
|
const pattern = new RegExp(
|
|
258
329
|
`\\{>>${parentAuthor}:\\s*([^<]+)<<\\}((?:\\s*\\{>>${replyAuthor}:[^<]+<<\\})*)`,
|
|
259
330
|
'g'
|
|
@@ -266,7 +337,7 @@ function extractReplies(markdown, parentAuthor, replyAuthor) {
|
|
|
266
337
|
|
|
267
338
|
if (replyBlock) {
|
|
268
339
|
const replyPattern = new RegExp(`\\{>>${replyAuthor}:\\s*([^<]+)<<\\}`, 'g');
|
|
269
|
-
const replyTexts = [];
|
|
340
|
+
const replyTexts: string[] = [];
|
|
270
341
|
let replyMatch;
|
|
271
342
|
while ((replyMatch = replyPattern.exec(replyBlock)) !== null) {
|
|
272
343
|
replyTexts.push(replyMatch[1].trim());
|
|
@@ -282,11 +353,12 @@ function extractReplies(markdown, parentAuthor, replyAuthor) {
|
|
|
282
353
|
|
|
283
354
|
/**
|
|
284
355
|
* Realign comments from reference DOCX to markdown
|
|
285
|
-
* @param {string} docxPath - Reference DOCX with correctly positioned comments
|
|
286
|
-
* @param {string} markdownPath - Markdown to realign
|
|
287
|
-
* @param {object} options - {dryRun: boolean, author: string, replyAuthor: string}
|
|
288
356
|
*/
|
|
289
|
-
export async function realignComments(
|
|
357
|
+
export async function realignComments(
|
|
358
|
+
docxPath: string,
|
|
359
|
+
markdownPath: string,
|
|
360
|
+
options: RealignOptions = {}
|
|
361
|
+
): Promise<RealignResult> {
|
|
290
362
|
const { dryRun = false, author = 'Guy Colling', replyAuthor = 'Gilles Colling' } = options;
|
|
291
363
|
|
|
292
364
|
// Read original markdown to extract replies before stripping
|
|
@@ -313,7 +385,7 @@ export async function realignComments(docxPath, markdownPath, options = {}) {
|
|
|
313
385
|
const mdParagraphs = parseMdParagraphs(markdown);
|
|
314
386
|
|
|
315
387
|
// Track insertions (position, text) - will insert from end to start
|
|
316
|
-
const insertions = [];
|
|
388
|
+
const insertions: CommentInsertion[] = [];
|
|
317
389
|
let matched = 0;
|
|
318
390
|
let unmatched = 0;
|
|
319
391
|
|
|
@@ -334,8 +406,8 @@ export async function realignComments(docxPath, markdownPath, options = {}) {
|
|
|
334
406
|
|
|
335
407
|
for (const comment of authorComments) {
|
|
336
408
|
// Find corresponding position in markdown paragraph
|
|
337
|
-
const mdPos = findMdPosition(refPara.text, comment.position, mdPara
|
|
338
|
-
const absolutePos = mdPara
|
|
409
|
+
const mdPos = findMdPosition(refPara.text, comment.position, mdPara?.text ?? '');
|
|
410
|
+
const absolutePos = (mdPara?.start ?? 0) + mdPos;
|
|
339
411
|
|
|
340
412
|
// Build comment mark with any replies
|
|
341
413
|
let commentMark = ` {>>${comment.author}: ${comment.text}<<}`;
|
|
@@ -354,7 +426,7 @@ export async function realignComments(docxPath, markdownPath, options = {}) {
|
|
|
354
426
|
text: commentMark,
|
|
355
427
|
commentText: comment.text.slice(0, 30),
|
|
356
428
|
hasReplies: !!replyTexts,
|
|
357
|
-
debug: `"${mdPara
|
|
429
|
+
debug: `"${(mdPara?.text ?? '').slice(Math.max(0, mdPos - 20), mdPos)}|HERE|${(mdPara?.text ?? '').slice(mdPos, mdPos + 20)}"`,
|
|
358
430
|
});
|
|
359
431
|
}
|
|
360
432
|
}
|
|
@@ -386,12 +458,12 @@ export async function realignComments(docxPath, markdownPath, options = {}) {
|
|
|
386
458
|
|
|
387
459
|
/**
|
|
388
460
|
* Realign comments in markdown string (in-memory, doesn't write to file)
|
|
389
|
-
* @param {string} docxPath - Reference DOCX with correctly positioned comments
|
|
390
|
-
* @param {string} markdown - Markdown content to realign
|
|
391
|
-
* @param {object} options - {author: string, replyAuthor: string}
|
|
392
|
-
* @returns {Promise<{success: boolean, markdown: string, insertions: number}>}
|
|
393
461
|
*/
|
|
394
|
-
export async function realignMarkdown(
|
|
462
|
+
export async function realignMarkdown(
|
|
463
|
+
docxPath: string,
|
|
464
|
+
markdown: string,
|
|
465
|
+
options: RealignMarkdownOptions = {}
|
|
466
|
+
): Promise<RealignMarkdownResult> {
|
|
395
467
|
const { author = 'Guy Colling', replyAuthor = 'Gilles Colling' } = options;
|
|
396
468
|
|
|
397
469
|
try {
|
|
@@ -411,7 +483,7 @@ export async function realignMarkdown(docxPath, markdown, options = {}) {
|
|
|
411
483
|
const mdParagraphs = parseMdParagraphs(result);
|
|
412
484
|
|
|
413
485
|
// Track insertions
|
|
414
|
-
const insertions = [];
|
|
486
|
+
const insertions: Array<{ position: number; text: string }> = [];
|
|
415
487
|
|
|
416
488
|
for (const refPara of refWithComments) {
|
|
417
489
|
const match = findMatchingParagraph(refPara.text, mdParagraphs);
|
|
@@ -421,8 +493,8 @@ export async function realignMarkdown(docxPath, markdown, options = {}) {
|
|
|
421
493
|
const authorComments = refPara.comments.filter((c) => c.author === author);
|
|
422
494
|
|
|
423
495
|
for (const comment of authorComments) {
|
|
424
|
-
const mdPos = findMdPosition(refPara.text, comment.position, mdPara
|
|
425
|
-
const absolutePos = mdPara
|
|
496
|
+
const mdPos = findMdPosition(refPara.text, comment.position, mdPara?.text ?? '');
|
|
497
|
+
const absolutePos = (mdPara?.start ?? 0) + mdPos;
|
|
426
498
|
|
|
427
499
|
let commentMark = ` {>>${comment.author}: ${comment.text}<<}`;
|
|
428
500
|
|
|
@@ -447,7 +519,7 @@ export async function realignMarkdown(docxPath, markdown, options = {}) {
|
|
|
447
519
|
}
|
|
448
520
|
|
|
449
521
|
return { success: true, markdown: result, insertions: insertions.length };
|
|
450
|
-
} catch (err) {
|
|
522
|
+
} catch (err: any) {
|
|
451
523
|
return { success: false, markdown, insertions: 0, error: err.message };
|
|
452
524
|
}
|
|
453
525
|
}
|
package/lib/config.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User configuration management
|
|
3
|
+
* Stores user preferences in ~/.revrc
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { UserConfig } from './types.js';
|
|
7
|
+
import * as fs from 'fs';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import * as os from 'os';
|
|
10
|
+
|
|
11
|
+
const CONFIG_PATH = path.join(os.homedir(), '.revrc');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Load user config
|
|
15
|
+
* @returns User configuration object
|
|
16
|
+
*/
|
|
17
|
+
export function loadUserConfig(): UserConfig {
|
|
18
|
+
try {
|
|
19
|
+
if (fs.existsSync(CONFIG_PATH)) {
|
|
20
|
+
const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
|
|
21
|
+
return JSON.parse(content) as UserConfig;
|
|
22
|
+
}
|
|
23
|
+
} catch (e) {
|
|
24
|
+
if (process.env.DEBUG) {
|
|
25
|
+
const error = e as Error;
|
|
26
|
+
console.warn('config: Failed to parse ~/.revrc:', error.message);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Save user config
|
|
34
|
+
* @param config - User configuration to save
|
|
35
|
+
*/
|
|
36
|
+
export function saveUserConfig(config: UserConfig): void {
|
|
37
|
+
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get user name
|
|
42
|
+
* @returns User name or null if not set
|
|
43
|
+
*/
|
|
44
|
+
export function getUserName(): string | null {
|
|
45
|
+
const config = loadUserConfig();
|
|
46
|
+
return config.userName || null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Set user name
|
|
51
|
+
* @param name - User name to set
|
|
52
|
+
*/
|
|
53
|
+
export function setUserName(name: string): void {
|
|
54
|
+
const config = loadUserConfig();
|
|
55
|
+
config.userName = name;
|
|
56
|
+
saveUserConfig(config);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get config file path
|
|
61
|
+
* @returns Absolute path to config file
|
|
62
|
+
*/
|
|
63
|
+
export function getConfigPath(): string {
|
|
64
|
+
return CONFIG_PATH;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get default sections for new projects
|
|
69
|
+
* @returns Array of section names or null if not set
|
|
70
|
+
*/
|
|
71
|
+
export function getDefaultSections(): string[] | null {
|
|
72
|
+
const config = loadUserConfig();
|
|
73
|
+
return config.defaultSections || null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Set default sections for new projects
|
|
78
|
+
* @param sections - Array of section names (without .md extension)
|
|
79
|
+
*/
|
|
80
|
+
export function setDefaultSections(sections: string[]): void {
|
|
81
|
+
const config = loadUserConfig();
|
|
82
|
+
config.defaultSections = sections;
|
|
83
|
+
saveUserConfig(config);
|
|
84
|
+
}
|