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
|
@@ -6,14 +6,33 @@
|
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
|
|
9
|
+
interface Reply {
|
|
10
|
+
author: string;
|
|
11
|
+
text: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface CommentWithReplies {
|
|
15
|
+
author: string;
|
|
16
|
+
text: string;
|
|
17
|
+
replies: Reply[];
|
|
18
|
+
context: string;
|
|
19
|
+
file: string;
|
|
20
|
+
line: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface ResponseOptions {
|
|
24
|
+
title?: string;
|
|
25
|
+
authorName?: string;
|
|
26
|
+
includeContext?: boolean;
|
|
27
|
+
includeLocation?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
9
30
|
/**
|
|
10
31
|
* Parse a comment with potential replies
|
|
11
32
|
* Format: {>>Author: comment<<} {>>Reply Author: reply<<}
|
|
12
|
-
* @param {string} text
|
|
13
|
-
* @returns {Array<{author: string, text: string, replies: Array, context: string, file: string, line: number}>}
|
|
14
33
|
*/
|
|
15
|
-
export function parseCommentsWithReplies(text, file = '') {
|
|
16
|
-
const comments = [];
|
|
34
|
+
export function parseCommentsWithReplies(text: string, file: string = ''): CommentWithReplies[] {
|
|
35
|
+
const comments: CommentWithReplies[] = [];
|
|
17
36
|
const lines = text.split('\n');
|
|
18
37
|
|
|
19
38
|
// Pattern for comments: {>>Author: text<<}
|
|
@@ -21,6 +40,7 @@ export function parseCommentsWithReplies(text, file = '') {
|
|
|
21
40
|
|
|
22
41
|
for (let lineNum = 0; lineNum < lines.length; lineNum++) {
|
|
23
42
|
const line = lines[lineNum];
|
|
43
|
+
if (!line) continue;
|
|
24
44
|
const matches = [...line.matchAll(commentPattern)];
|
|
25
45
|
|
|
26
46
|
if (matches.length === 0) continue;
|
|
@@ -31,13 +51,14 @@ export function parseCommentsWithReplies(text, file = '') {
|
|
|
31
51
|
|
|
32
52
|
// First match is the original comment, rest are replies
|
|
33
53
|
const [first, ...rest] = matches;
|
|
54
|
+
if (!first || !first[1] || !first[2]) continue;
|
|
34
55
|
|
|
35
56
|
comments.push({
|
|
36
57
|
author: first[1].trim(),
|
|
37
58
|
text: first[2].trim(),
|
|
38
59
|
replies: rest.map(m => ({
|
|
39
|
-
author: m[1]
|
|
40
|
-
text: m[2]
|
|
60
|
+
author: m[1]?.trim() || '',
|
|
61
|
+
text: m[2]?.trim() || '',
|
|
41
62
|
})),
|
|
42
63
|
context,
|
|
43
64
|
file,
|
|
@@ -50,18 +71,16 @@ export function parseCommentsWithReplies(text, file = '') {
|
|
|
50
71
|
|
|
51
72
|
/**
|
|
52
73
|
* Group comments by reviewer
|
|
53
|
-
* @param {Array} comments
|
|
54
|
-
* @returns {Map<string, Array>}
|
|
55
74
|
*/
|
|
56
|
-
export function groupByReviewer(comments) {
|
|
57
|
-
const grouped = new Map();
|
|
75
|
+
export function groupByReviewer(comments: CommentWithReplies[]): Map<string, CommentWithReplies[]> {
|
|
76
|
+
const grouped = new Map<string, CommentWithReplies[]>();
|
|
58
77
|
|
|
59
78
|
for (const comment of comments) {
|
|
60
79
|
const reviewer = comment.author;
|
|
61
80
|
if (!grouped.has(reviewer)) {
|
|
62
81
|
grouped.set(reviewer, []);
|
|
63
82
|
}
|
|
64
|
-
grouped.get(reviewer)
|
|
83
|
+
grouped.get(reviewer)!.push(comment);
|
|
65
84
|
}
|
|
66
85
|
|
|
67
86
|
return grouped;
|
|
@@ -69,11 +88,8 @@ export function groupByReviewer(comments) {
|
|
|
69
88
|
|
|
70
89
|
/**
|
|
71
90
|
* Generate response letter in Markdown format
|
|
72
|
-
* @param {Array} comments - All comments from all files
|
|
73
|
-
* @param {object} options
|
|
74
|
-
* @returns {string}
|
|
75
91
|
*/
|
|
76
|
-
export function generateResponseLetter(comments, options = {}) {
|
|
92
|
+
export function generateResponseLetter(comments: CommentWithReplies[], options: ResponseOptions = {}): string {
|
|
77
93
|
const {
|
|
78
94
|
title = 'Response to Reviewers',
|
|
79
95
|
authorName = 'Author',
|
|
@@ -81,7 +97,7 @@ export function generateResponseLetter(comments, options = {}) {
|
|
|
81
97
|
includeLocation = true,
|
|
82
98
|
} = options;
|
|
83
99
|
|
|
84
|
-
const lines = [];
|
|
100
|
+
const lines: string[] = [];
|
|
85
101
|
lines.push(`# ${title}`);
|
|
86
102
|
lines.push('');
|
|
87
103
|
lines.push(`We thank the reviewers for their constructive feedback. Below we address each comment.`);
|
|
@@ -105,12 +121,13 @@ export function generateResponseLetter(comments, options = {}) {
|
|
|
105
121
|
if (reviewer.toLowerCase() === authorName.toLowerCase()) continue;
|
|
106
122
|
if (reviewer.toLowerCase() === 'claude') continue;
|
|
107
123
|
|
|
108
|
-
const reviewerComments = grouped.get(reviewer)
|
|
124
|
+
const reviewerComments = grouped.get(reviewer)!;
|
|
109
125
|
lines.push(`## ${reviewer}`);
|
|
110
126
|
lines.push('');
|
|
111
127
|
|
|
112
128
|
for (let i = 0; i < reviewerComments.length; i++) {
|
|
113
129
|
const c = reviewerComments[i];
|
|
130
|
+
if (!c) continue;
|
|
114
131
|
|
|
115
132
|
lines.push(`### Comment ${i + 1}`);
|
|
116
133
|
if (includeLocation) {
|
|
@@ -164,11 +181,9 @@ export function generateResponseLetter(comments, options = {}) {
|
|
|
164
181
|
|
|
165
182
|
/**
|
|
166
183
|
* Collect comments from multiple files
|
|
167
|
-
* @param {string[]} files - Array of file paths
|
|
168
|
-
* @returns {Array}
|
|
169
184
|
*/
|
|
170
|
-
export function collectComments(files) {
|
|
171
|
-
const allComments = [];
|
|
185
|
+
export function collectComments(files: string[]): CommentWithReplies[] {
|
|
186
|
+
const allComments: CommentWithReplies[] = [];
|
|
172
187
|
|
|
173
188
|
for (const file of files) {
|
|
174
189
|
if (!fs.existsSync(file)) continue;
|
|
@@ -4,45 +4,65 @@
|
|
|
4
4
|
|
|
5
5
|
import * as readline from 'readline';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
+
import type { Annotation, Comment } from './types.js';
|
|
7
8
|
import { getTrackChanges, getComments, applyDecision } from './annotations.js';
|
|
8
9
|
|
|
10
|
+
interface ReviewResult {
|
|
11
|
+
text: string;
|
|
12
|
+
accepted: number;
|
|
13
|
+
rejected: number;
|
|
14
|
+
skipped: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface CommentReviewOptions {
|
|
18
|
+
author?: string;
|
|
19
|
+
addReply?: (text: string, comment: Comment, author: string, replyText: string) => string;
|
|
20
|
+
setCommentStatus?: (text: string, comment: Comment, resolved: boolean) => string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface CommentReviewResult {
|
|
24
|
+
text: string;
|
|
25
|
+
resolved: number;
|
|
26
|
+
replied: number;
|
|
27
|
+
skipped: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
9
30
|
/**
|
|
10
31
|
* Format an annotation for display
|
|
11
|
-
* @param {object} annotation
|
|
12
|
-
* @param {number} index
|
|
13
|
-
* @param {number} total
|
|
14
|
-
* @returns {string}
|
|
15
32
|
*/
|
|
16
|
-
function formatAnnotation(annotation, index, total) {
|
|
33
|
+
function formatAnnotation(annotation: Annotation, index: number, total: number): string {
|
|
17
34
|
const header = chalk.dim(`─── Change ${index + 1}/${total} (line ${annotation.line}) ───`);
|
|
18
35
|
|
|
19
|
-
let action;
|
|
20
|
-
let display;
|
|
36
|
+
let action: string;
|
|
37
|
+
let display: string;
|
|
21
38
|
|
|
22
39
|
switch (annotation.type) {
|
|
23
40
|
case 'insert':
|
|
24
41
|
action = chalk.green(`+ Insert: "${annotation.content}"`);
|
|
25
42
|
display =
|
|
26
|
-
chalk.dim(annotation.before) +
|
|
43
|
+
chalk.dim(annotation.before || '') +
|
|
27
44
|
chalk.green.bold(`[${annotation.content}]`) +
|
|
28
|
-
chalk.dim(annotation.after);
|
|
45
|
+
chalk.dim(annotation.after || '');
|
|
29
46
|
break;
|
|
30
47
|
case 'delete':
|
|
31
48
|
action = chalk.red(`- Delete: "${annotation.content}"`);
|
|
32
49
|
display =
|
|
33
|
-
chalk.dim(annotation.before) +
|
|
50
|
+
chalk.dim(annotation.before || '') +
|
|
34
51
|
chalk.red.strikethrough(`[${annotation.content}]`) +
|
|
35
|
-
chalk.dim(annotation.after);
|
|
52
|
+
chalk.dim(annotation.after || '');
|
|
36
53
|
break;
|
|
37
54
|
case 'substitute':
|
|
38
55
|
action = chalk.yellow(`~ Change: "${annotation.content}" → "${annotation.replacement}"`);
|
|
39
56
|
display =
|
|
40
|
-
chalk.dim(annotation.before) +
|
|
57
|
+
chalk.dim(annotation.before || '') +
|
|
41
58
|
chalk.red.strikethrough(`[${annotation.content}]`) +
|
|
42
59
|
chalk.dim(' → ') +
|
|
43
60
|
chalk.green.bold(`[${annotation.replacement}]`) +
|
|
44
|
-
chalk.dim(annotation.after);
|
|
61
|
+
chalk.dim(annotation.after || '');
|
|
45
62
|
break;
|
|
63
|
+
default:
|
|
64
|
+
action = chalk.gray(`? Unknown: "${annotation.content}"`);
|
|
65
|
+
display = chalk.dim(annotation.before || '') + chalk.gray(`[${annotation.content}]`) + chalk.dim(annotation.after || '');
|
|
46
66
|
}
|
|
47
67
|
|
|
48
68
|
return `\n${header}\n\n ${action}\n\n ${display}\n`;
|
|
@@ -50,11 +70,8 @@ function formatAnnotation(annotation, index, total) {
|
|
|
50
70
|
|
|
51
71
|
/**
|
|
52
72
|
* Prompt for a single keypress
|
|
53
|
-
* @param {string} prompt
|
|
54
|
-
* @param {string[]} validKeys
|
|
55
|
-
* @returns {Promise<string>}
|
|
56
73
|
*/
|
|
57
|
-
function promptKey(prompt, validKeys) {
|
|
74
|
+
function promptKey(prompt: string, validKeys: string[]): Promise<string> {
|
|
58
75
|
return new Promise((resolve) => {
|
|
59
76
|
const rl = readline.createInterface({
|
|
60
77
|
input: process.stdin,
|
|
@@ -69,7 +86,7 @@ function promptKey(prompt, validKeys) {
|
|
|
69
86
|
|
|
70
87
|
process.stdout.write(prompt);
|
|
71
88
|
|
|
72
|
-
process.stdin.once('data', (key) => {
|
|
89
|
+
process.stdin.once('data', (key: Buffer) => {
|
|
73
90
|
const char = key.toString().toLowerCase();
|
|
74
91
|
|
|
75
92
|
if (process.stdin.isTTY) {
|
|
@@ -95,10 +112,8 @@ function promptKey(prompt, validKeys) {
|
|
|
95
112
|
|
|
96
113
|
/**
|
|
97
114
|
* Run interactive review session
|
|
98
|
-
* @param {string} text
|
|
99
|
-
* @returns {Promise<{text: string, accepted: number, rejected: number, skipped: number}>}
|
|
100
115
|
*/
|
|
101
|
-
export async function interactiveReview(text) {
|
|
116
|
+
export async function interactiveReview(text: string): Promise<ReviewResult> {
|
|
102
117
|
const changes = getTrackChanges(text);
|
|
103
118
|
const comments = getComments(text);
|
|
104
119
|
|
|
@@ -119,6 +134,7 @@ export async function interactiveReview(text) {
|
|
|
119
134
|
|
|
120
135
|
for (let i = 0; i < changes.length; i++) {
|
|
121
136
|
const change = changes[i];
|
|
137
|
+
if (!change) continue;
|
|
122
138
|
console.log(formatAnnotation(change, i, changes.length));
|
|
123
139
|
|
|
124
140
|
const prompt = chalk.dim('[a]ccept [r]eject [s]kip | accept [A]ll reject a[L]l [q]uit: ');
|
|
@@ -132,7 +148,8 @@ export async function interactiveReview(text) {
|
|
|
132
148
|
case 'A':
|
|
133
149
|
// Accept all remaining
|
|
134
150
|
for (let j = i; j < changes.length; j++) {
|
|
135
|
-
|
|
151
|
+
const ch = changes[j];
|
|
152
|
+
if (ch) currentText = applyDecision(currentText, ch, true);
|
|
136
153
|
}
|
|
137
154
|
accepted += changes.length - i;
|
|
138
155
|
console.log(chalk.green(`\nAccepted all ${changes.length - i} remaining changes.`));
|
|
@@ -142,7 +159,8 @@ export async function interactiveReview(text) {
|
|
|
142
159
|
case 'L':
|
|
143
160
|
// Reject all remaining
|
|
144
161
|
for (let j = i; j < changes.length; j++) {
|
|
145
|
-
|
|
162
|
+
const ch = changes[j];
|
|
163
|
+
if (ch) currentText = applyDecision(currentText, ch, false);
|
|
146
164
|
}
|
|
147
165
|
rejected += changes.length - i;
|
|
148
166
|
console.log(chalk.red(`\nRejected all ${changes.length - i} remaining changes.`));
|
|
@@ -179,9 +197,8 @@ export async function interactiveReview(text) {
|
|
|
179
197
|
|
|
180
198
|
/**
|
|
181
199
|
* List all comments
|
|
182
|
-
* @param {string} text
|
|
183
200
|
*/
|
|
184
|
-
export function listComments(text) {
|
|
201
|
+
export function listComments(text: string): void {
|
|
185
202
|
const comments = getComments(text);
|
|
186
203
|
|
|
187
204
|
if (comments.length === 0) {
|
|
@@ -193,15 +210,16 @@ export function listComments(text) {
|
|
|
193
210
|
|
|
194
211
|
for (let i = 0; i < comments.length; i++) {
|
|
195
212
|
const c = comments[i];
|
|
213
|
+
if (!c) continue;
|
|
196
214
|
const author = c.author || 'Anonymous';
|
|
197
215
|
const header = chalk.blue(`[${i + 1}] ${author}`) + chalk.dim(` (line ${c.line})`);
|
|
198
216
|
|
|
199
217
|
console.log(header);
|
|
200
218
|
console.log(` ${c.content}`);
|
|
201
219
|
console.log(
|
|
202
|
-
chalk.dim(` Context: ...${c.before.slice(-25)}`) +
|
|
220
|
+
chalk.dim(` Context: ...${(c.before || '').slice(-25)}`) +
|
|
203
221
|
chalk.yellow('*') +
|
|
204
|
-
chalk.dim(`${c.after.slice(0, 25)}...`)
|
|
222
|
+
chalk.dim(`${(c.after || '').slice(0, 25)}...`)
|
|
205
223
|
);
|
|
206
224
|
console.log();
|
|
207
225
|
}
|
|
@@ -209,12 +227,8 @@ export function listComments(text) {
|
|
|
209
227
|
|
|
210
228
|
/**
|
|
211
229
|
* Format a comment for interactive display
|
|
212
|
-
* @param {object} comment
|
|
213
|
-
* @param {number} index
|
|
214
|
-
* @param {number} total
|
|
215
|
-
* @returns {string}
|
|
216
230
|
*/
|
|
217
|
-
function formatComment(comment, index, total) {
|
|
231
|
+
function formatComment(comment: Comment, index: number, total: number): string {
|
|
218
232
|
const statusIcon = comment.resolved ? chalk.green('✓') : chalk.yellow('○');
|
|
219
233
|
const author = comment.author || 'Anonymous';
|
|
220
234
|
const header = chalk.dim(`─── Comment ${index + 1}/${total} (line ${comment.line}) ───`);
|
|
@@ -227,16 +241,10 @@ function formatComment(comment, index, total) {
|
|
|
227
241
|
|
|
228
242
|
/**
|
|
229
243
|
* Run interactive comment review session
|
|
230
|
-
* @param {string} text
|
|
231
|
-
* @param {object} options
|
|
232
|
-
* @param {string} options.author - Author name for replies
|
|
233
|
-
* @param {Function} options.addReply - Function to add reply to comment
|
|
234
|
-
* @param {Function} options.setCommentStatus - Function to set comment status
|
|
235
|
-
* @returns {Promise<{text: string, resolved: number, replied: number, skipped: number}>}
|
|
236
244
|
*/
|
|
237
|
-
export async function interactiveCommentReview(text, options = {}) {
|
|
245
|
+
export async function interactiveCommentReview(text: string, options: CommentReviewOptions = {}): Promise<CommentReviewResult> {
|
|
238
246
|
const { author = 'Author', addReply, setCommentStatus } = options;
|
|
239
|
-
const comments = getComments(text, { pendingOnly: true });
|
|
247
|
+
const comments = getComments(text, { pendingOnly: true }) as Comment[];
|
|
240
248
|
|
|
241
249
|
if (comments.length === 0) {
|
|
242
250
|
console.log(chalk.green('No pending comments found.'));
|
|
@@ -252,6 +260,7 @@ export async function interactiveCommentReview(text, options = {}) {
|
|
|
252
260
|
|
|
253
261
|
for (let i = 0; i < comments.length; i++) {
|
|
254
262
|
const comment = comments[i];
|
|
263
|
+
if (!comment) continue;
|
|
255
264
|
console.log(formatComment(comment, i, comments.length));
|
|
256
265
|
|
|
257
266
|
const prompt = chalk.dim('[r]eply [m]ark resolved [s]kip | resolve [A]ll [q]uit: ');
|
|
@@ -265,8 +274,9 @@ export async function interactiveCommentReview(text, options = {}) {
|
|
|
265
274
|
case 'A':
|
|
266
275
|
// Resolve all remaining
|
|
267
276
|
for (let j = i; j < comments.length; j++) {
|
|
268
|
-
|
|
269
|
-
|
|
277
|
+
const c = comments[j];
|
|
278
|
+
if (setCommentStatus && c) {
|
|
279
|
+
currentText = setCommentStatus(currentText, c, true);
|
|
270
280
|
}
|
|
271
281
|
}
|
|
272
282
|
resolved += comments.length - i;
|
|
@@ -288,7 +298,7 @@ export async function interactiveCommentReview(text, options = {}) {
|
|
|
288
298
|
input: process.stdin,
|
|
289
299
|
output: process.stdout,
|
|
290
300
|
});
|
|
291
|
-
const replyText = await new Promise((resolve) => {
|
|
301
|
+
const replyText = await new Promise<string>((resolve) => {
|
|
292
302
|
rl.question(chalk.cyan(' Reply: '), resolve);
|
|
293
303
|
});
|
|
294
304
|
rl.close();
|
|
@@ -2,10 +2,59 @@
|
|
|
2
2
|
* JSON Schema validation for rev.yaml configuration
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Validation error
|
|
7
|
+
*/
|
|
8
|
+
interface ValidationError {
|
|
9
|
+
path: string;
|
|
10
|
+
message: string;
|
|
11
|
+
value?: unknown;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Validation warning
|
|
16
|
+
*/
|
|
17
|
+
interface ValidationWarning {
|
|
18
|
+
path: string;
|
|
19
|
+
message: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Validation result
|
|
24
|
+
*/
|
|
25
|
+
interface ValidationResult {
|
|
26
|
+
valid: boolean;
|
|
27
|
+
errors: ValidationError[];
|
|
28
|
+
warnings: ValidationWarning[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* JSON Schema type
|
|
33
|
+
*/
|
|
34
|
+
interface Schema {
|
|
35
|
+
$schema?: string;
|
|
36
|
+
title?: string;
|
|
37
|
+
description?: string;
|
|
38
|
+
type?: string;
|
|
39
|
+
properties?: Record<string, Schema>;
|
|
40
|
+
required?: string[];
|
|
41
|
+
items?: Schema;
|
|
42
|
+
oneOf?: Schema[];
|
|
43
|
+
enum?: string[];
|
|
44
|
+
pattern?: string;
|
|
45
|
+
format?: string;
|
|
46
|
+
minimum?: number;
|
|
47
|
+
maximum?: number;
|
|
48
|
+
minItems?: number;
|
|
49
|
+
maxItems?: number;
|
|
50
|
+
additionalProperties?: boolean;
|
|
51
|
+
default?: unknown;
|
|
52
|
+
}
|
|
53
|
+
|
|
5
54
|
/**
|
|
6
55
|
* JSON Schema for rev.yaml
|
|
7
56
|
*/
|
|
8
|
-
export const revYamlSchema = {
|
|
57
|
+
export const revYamlSchema: Schema = {
|
|
9
58
|
$schema: 'http://json-schema.org/draft-07/schema#',
|
|
10
59
|
title: 'rev.yaml configuration',
|
|
11
60
|
description: 'Configuration file for docrev document workflow',
|
|
@@ -134,13 +183,9 @@ export const revYamlSchema = {
|
|
|
134
183
|
|
|
135
184
|
/**
|
|
136
185
|
* Validate a value against a simple schema
|
|
137
|
-
* @param {*} value - Value to validate
|
|
138
|
-
* @param {object} schema - JSON Schema
|
|
139
|
-
* @param {string} path - Current path for error messages
|
|
140
|
-
* @returns {object[]} Array of validation errors
|
|
141
186
|
*/
|
|
142
|
-
function validateValue(value, schema, path = '') {
|
|
143
|
-
const errors = [];
|
|
187
|
+
function validateValue(value: unknown, schema: Schema, path = ''): ValidationError[] {
|
|
188
|
+
const errors: ValidationError[] = [];
|
|
144
189
|
|
|
145
190
|
// Handle oneOf
|
|
146
191
|
if (schema.oneOf) {
|
|
@@ -228,23 +273,24 @@ function validateValue(value, schema, path = '') {
|
|
|
228
273
|
}
|
|
229
274
|
if (schema.items) {
|
|
230
275
|
value.forEach((item, index) => {
|
|
231
|
-
errors.push(...validateValue(item, schema.items
|
|
276
|
+
errors.push(...validateValue(item, schema.items!, `${path}[${index}]`));
|
|
232
277
|
});
|
|
233
278
|
}
|
|
234
279
|
}
|
|
235
280
|
|
|
236
281
|
// Object validation
|
|
237
282
|
if (schema.type === 'object' && typeof value === 'object' && value !== null) {
|
|
283
|
+
const obj = value as Record<string, unknown>;
|
|
238
284
|
if (schema.properties) {
|
|
239
285
|
for (const [key, propSchema] of Object.entries(schema.properties)) {
|
|
240
|
-
if (
|
|
241
|
-
errors.push(...validateValue(
|
|
286
|
+
if (obj[key] !== undefined) {
|
|
287
|
+
errors.push(...validateValue(obj[key], propSchema, path ? `${path}.${key}` : key));
|
|
242
288
|
}
|
|
243
289
|
}
|
|
244
290
|
}
|
|
245
291
|
if (schema.required) {
|
|
246
292
|
for (const key of schema.required) {
|
|
247
|
-
if (
|
|
293
|
+
if (obj[key] === undefined) {
|
|
248
294
|
errors.push({
|
|
249
295
|
path: path ? `${path}.${key}` : key,
|
|
250
296
|
message: `Required property "${key}" is missing`,
|
|
@@ -260,29 +306,28 @@ function validateValue(value, schema, path = '') {
|
|
|
260
306
|
|
|
261
307
|
/**
|
|
262
308
|
* Validate rev.yaml configuration
|
|
263
|
-
* @param {object} config - Parsed configuration object
|
|
264
|
-
* @returns {{ valid: boolean, errors: object[], warnings: object[] }}
|
|
265
309
|
*/
|
|
266
|
-
export function validateConfig(config) {
|
|
310
|
+
export function validateConfig(config: Record<string, unknown>): ValidationResult {
|
|
267
311
|
const errors = validateValue(config, revYamlSchema);
|
|
268
|
-
const warnings = [];
|
|
312
|
+
const warnings: ValidationWarning[] = [];
|
|
269
313
|
|
|
270
314
|
// Additional semantic validations
|
|
271
|
-
if (config.sections && config.sections.length === 0) {
|
|
315
|
+
if (config.sections && Array.isArray(config.sections) && config.sections.length === 0) {
|
|
272
316
|
warnings.push({
|
|
273
317
|
path: 'sections',
|
|
274
318
|
message: 'No sections specified - build will auto-detect .md files',
|
|
275
319
|
});
|
|
276
320
|
}
|
|
277
321
|
|
|
278
|
-
if (config.bibliography && !config.bibliography.endsWith('.bib')) {
|
|
322
|
+
if (config.bibliography && typeof config.bibliography === 'string' && !config.bibliography.endsWith('.bib')) {
|
|
279
323
|
warnings.push({
|
|
280
324
|
path: 'bibliography',
|
|
281
325
|
message: 'Bibliography file should have .bib extension',
|
|
282
326
|
});
|
|
283
327
|
}
|
|
284
328
|
|
|
285
|
-
|
|
329
|
+
const pdf = config.pdf as { linestretch?: number } | undefined;
|
|
330
|
+
if (pdf?.linestretch && (pdf.linestretch < 1 || pdf.linestretch > 3)) {
|
|
286
331
|
warnings.push({
|
|
287
332
|
path: 'pdf.linestretch',
|
|
288
333
|
message: 'Line stretch values outside 1-3 range may produce unexpected results',
|
|
@@ -290,7 +335,7 @@ export function validateConfig(config) {
|
|
|
290
335
|
}
|
|
291
336
|
|
|
292
337
|
// Check for common typos
|
|
293
|
-
const knownKeys = Object.keys(revYamlSchema.properties);
|
|
338
|
+
const knownKeys = Object.keys(revYamlSchema.properties || {});
|
|
294
339
|
for (const key of Object.keys(config)) {
|
|
295
340
|
if (key.startsWith('_')) continue; // Internal keys
|
|
296
341
|
if (!knownKeys.includes(key)) {
|
|
@@ -316,12 +361,12 @@ export function validateConfig(config) {
|
|
|
316
361
|
|
|
317
362
|
/**
|
|
318
363
|
* Format validation results for display
|
|
319
|
-
* @param {{ valid: boolean, errors: object[], warnings: object[] }} result
|
|
320
|
-
* @param {object} chalk - Chalk instance for coloring
|
|
321
|
-
* @returns {string}
|
|
322
364
|
*/
|
|
323
|
-
export function formatValidationResult(
|
|
324
|
-
|
|
365
|
+
export function formatValidationResult(
|
|
366
|
+
result: ValidationResult,
|
|
367
|
+
chalk: { red: (s: string) => string; yellow: (s: string) => string; green: (s: string) => string }
|
|
368
|
+
): string {
|
|
369
|
+
const lines: string[] = [];
|
|
325
370
|
|
|
326
371
|
if (result.errors.length > 0) {
|
|
327
372
|
lines.push(chalk.red('Configuration errors:'));
|
|
@@ -348,7 +393,7 @@ export function formatValidationResult(result, chalk) {
|
|
|
348
393
|
/**
|
|
349
394
|
* Levenshtein distance for typo detection
|
|
350
395
|
*/
|
|
351
|
-
function levenshtein(a, b) {
|
|
396
|
+
function levenshtein(a: string, b: string): number {
|
|
352
397
|
const matrix = Array(b.length + 1)
|
|
353
398
|
.fill(null)
|
|
354
399
|
.map(() => Array(a.length + 1).fill(null));
|