docrev 0.9.11 → 0.9.14
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 -9
- package/.gitattributes +1 -1
- package/CHANGELOG.md +149 -149
- package/PLAN-tables-and-postprocess.md +850 -850
- package/README.md +391 -391
- package/bin/rev.js +11 -11
- package/bin/rev.ts +145 -145
- package/completions/rev.bash +127 -127
- package/completions/rev.ps1 +210 -210
- package/completions/rev.zsh +207 -207
- package/dev_notes/stress2/build_adversarial.ts +186 -186
- package/dev_notes/stress2/drift_matcher.ts +62 -62
- package/dev_notes/stress2/probe_anchors.ts +35 -35
- package/dev_notes/stress2/project/discussion.before.md +3 -3
- package/dev_notes/stress2/project/discussion.md +3 -3
- package/dev_notes/stress2/project/methods.before.md +20 -20
- package/dev_notes/stress2/project/methods.md +20 -20
- package/dev_notes/stress2/project/rev.yaml +5 -5
- package/dev_notes/stress2/project/sections.yaml +4 -4
- package/dev_notes/stress2/sections.yaml +5 -5
- package/dev_notes/stress2/trace_placement.ts +50 -50
- package/dev_notes/stresstest_boundaries.ts +27 -27
- package/dev_notes/stresstest_drift_apply.ts +43 -43
- package/dev_notes/stresstest_drift_compare.ts +43 -43
- package/dev_notes/stresstest_drift_v2.ts +54 -54
- package/dev_notes/stresstest_inspect.ts +54 -54
- package/dev_notes/stresstest_pstyle.ts +55 -55
- package/dev_notes/stresstest_section_debug.ts +23 -23
- package/dev_notes/stresstest_split.ts +70 -70
- package/dev_notes/stresstest_trace.ts +19 -19
- package/dev_notes/stresstest_verify_no_overwrite.ts +40 -40
- package/dist/lib/build.d.ts +50 -1
- package/dist/lib/build.d.ts.map +1 -1
- package/dist/lib/build.js +80 -30
- package/dist/lib/build.js.map +1 -1
- package/dist/lib/commands/build.d.ts.map +1 -1
- package/dist/lib/commands/build.js +38 -5
- package/dist/lib/commands/build.js.map +1 -1
- package/dist/lib/commands/utilities.js +164 -164
- package/dist/lib/commands/word-tools.js +8 -8
- package/dist/lib/grammar.js +3 -3
- package/dist/lib/import.d.ts.map +1 -1
- package/dist/lib/import.js +146 -24
- package/dist/lib/import.js.map +1 -1
- package/dist/lib/pdf-comments.js +44 -44
- package/dist/lib/plugins.js +57 -57
- package/dist/lib/pptx-themes.js +115 -115
- package/dist/lib/spelling.js +2 -2
- package/dist/lib/templates.js +387 -387
- package/dist/lib/themes.js +51 -51
- package/dist/lib/types.d.ts +20 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/word-extraction.d.ts +6 -0
- package/dist/lib/word-extraction.d.ts.map +1 -1
- package/dist/lib/word-extraction.js +46 -3
- package/dist/lib/word-extraction.js.map +1 -1
- package/dist/lib/wordcomments.d.ts.map +1 -1
- package/dist/lib/wordcomments.js +23 -5
- package/dist/lib/wordcomments.js.map +1 -1
- package/eslint.config.js +27 -27
- package/lib/anchor-match.ts +276 -276
- package/lib/annotations.ts +644 -644
- package/lib/build.ts +1300 -1227
- package/lib/citations.ts +160 -160
- package/lib/commands/build.ts +833 -801
- package/lib/commands/citations.ts +515 -515
- package/lib/commands/comments.ts +1050 -1050
- package/lib/commands/context.ts +174 -174
- package/lib/commands/core.ts +309 -309
- package/lib/commands/doi.ts +435 -435
- package/lib/commands/file-ops.ts +372 -372
- package/lib/commands/history.ts +320 -320
- package/lib/commands/index.ts +87 -87
- package/lib/commands/init.ts +259 -259
- package/lib/commands/merge-resolve.ts +378 -378
- package/lib/commands/preview.ts +178 -178
- package/lib/commands/project-info.ts +244 -244
- package/lib/commands/quality.ts +517 -517
- package/lib/commands/response.ts +454 -454
- package/lib/commands/section-boundaries.ts +82 -82
- package/lib/commands/sections.ts +451 -451
- package/lib/commands/sync.ts +706 -706
- package/lib/commands/text-ops.ts +449 -449
- package/lib/commands/utilities.ts +448 -448
- package/lib/commands/verify-anchors.ts +272 -272
- package/lib/commands/word-tools.ts +340 -340
- package/lib/comment-realign.ts +517 -517
- package/lib/config.ts +84 -84
- package/lib/crossref.ts +781 -781
- package/lib/csl.ts +191 -191
- package/lib/dependencies.ts +98 -98
- package/lib/diff-engine.ts +465 -465
- package/lib/doi-cache.ts +115 -115
- package/lib/doi.ts +897 -897
- package/lib/equations.ts +506 -506
- package/lib/errors.ts +346 -346
- package/lib/format.ts +541 -541
- package/lib/git.ts +326 -326
- package/lib/grammar.ts +303 -303
- package/lib/image-registry.ts +180 -180
- package/lib/import.ts +911 -792
- package/lib/journals.ts +543 -543
- package/lib/merge.ts +633 -633
- package/lib/orcid.ts +144 -144
- package/lib/pdf-comments.ts +263 -263
- package/lib/pdf-import.ts +524 -524
- package/lib/plugins.ts +362 -362
- package/lib/postprocess.ts +188 -188
- package/lib/pptx-color-filter.lua +37 -37
- package/lib/pptx-template.ts +469 -469
- package/lib/pptx-themes.ts +483 -483
- package/lib/protect-restore.ts +520 -520
- package/lib/rate-limiter.ts +94 -94
- package/lib/response.ts +197 -197
- package/lib/restore-references.ts +240 -240
- package/lib/review.ts +327 -327
- package/lib/schema.ts +417 -417
- package/lib/scientific-words.ts +73 -73
- package/lib/sections.ts +335 -335
- package/lib/slides.ts +756 -756
- package/lib/spelling.ts +334 -334
- package/lib/templates.ts +526 -526
- package/lib/themes.ts +742 -742
- package/lib/trackchanges.ts +247 -247
- package/lib/tui.ts +450 -450
- package/lib/types.ts +550 -530
- package/lib/undo.ts +250 -250
- package/lib/utils.ts +69 -69
- package/lib/variables.ts +179 -179
- package/lib/word-extraction.ts +806 -759
- package/lib/word.ts +643 -643
- package/lib/wordcomments.ts +817 -798
- package/package.json +137 -137
- package/scripts/postbuild.js +28 -28
- package/skill/REFERENCE.md +431 -431
- package/skill/SKILL.md +258 -258
- package/tsconfig.json +26 -26
- package/types/index.d.ts +525 -525
package/lib/variables.ts
CHANGED
|
@@ -1,179 +1,179 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Template variable substitution for rev
|
|
3
|
-
*
|
|
4
|
-
* Supported variables:
|
|
5
|
-
* {{date}} - Current date (YYYY-MM-DD)
|
|
6
|
-
* {{date:format}} - Custom date format (e.g., {{date:MMMM D, YYYY}})
|
|
7
|
-
* {{version}} - Version from rev.yaml
|
|
8
|
-
* {{word_count}} - Total word count
|
|
9
|
-
* {{author}} - First author name
|
|
10
|
-
* {{authors}} - All authors (comma-separated)
|
|
11
|
-
* {{title}} - Document title
|
|
12
|
-
* {{year}} - Current year
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import * as fs from 'fs';
|
|
16
|
-
import { countWords } from './utils.js';
|
|
17
|
-
import type { Author } from './types.js';
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Format date with simple pattern
|
|
21
|
-
*/
|
|
22
|
-
function formatDate(date: Date, format: string = 'YYYY-MM-DD'): string {
|
|
23
|
-
const months = [
|
|
24
|
-
'January',
|
|
25
|
-
'February',
|
|
26
|
-
'March',
|
|
27
|
-
'April',
|
|
28
|
-
'May',
|
|
29
|
-
'June',
|
|
30
|
-
'July',
|
|
31
|
-
'August',
|
|
32
|
-
'September',
|
|
33
|
-
'October',
|
|
34
|
-
'November',
|
|
35
|
-
'December',
|
|
36
|
-
];
|
|
37
|
-
const monthsShort = [
|
|
38
|
-
'Jan',
|
|
39
|
-
'Feb',
|
|
40
|
-
'Mar',
|
|
41
|
-
'Apr',
|
|
42
|
-
'May',
|
|
43
|
-
'Jun',
|
|
44
|
-
'Jul',
|
|
45
|
-
'Aug',
|
|
46
|
-
'Sep',
|
|
47
|
-
'Oct',
|
|
48
|
-
'Nov',
|
|
49
|
-
'Dec',
|
|
50
|
-
];
|
|
51
|
-
|
|
52
|
-
const year = date.getFullYear();
|
|
53
|
-
const month = date.getMonth();
|
|
54
|
-
const day = date.getDate();
|
|
55
|
-
|
|
56
|
-
// Use placeholders to avoid replacement conflicts (e.g., D in December)
|
|
57
|
-
const monthFull = months[month] || '';
|
|
58
|
-
const monthShort = monthsShort[month] || '';
|
|
59
|
-
return format
|
|
60
|
-
.replace('YYYY', '\x00YEAR\x00')
|
|
61
|
-
.replace('MMMM', '\x00MONTHFULL\x00')
|
|
62
|
-
.replace('MMM', '\x00MONTHSHORT\x00')
|
|
63
|
-
.replace('MM', '\x00MONTHNUM\x00')
|
|
64
|
-
.replace('DD', '\x00DAYPAD\x00')
|
|
65
|
-
.replace(/\bD\b/, '\x00DAY\x00')
|
|
66
|
-
.replace('\x00YEAR\x00', year.toString())
|
|
67
|
-
.replace('\x00MONTHFULL\x00', monthFull)
|
|
68
|
-
.replace('\x00MONTHSHORT\x00', monthShort)
|
|
69
|
-
.replace('\x00MONTHNUM\x00', (month + 1).toString().padStart(2, '0'))
|
|
70
|
-
.replace('\x00DAYPAD\x00', day.toString().padStart(2, '0'))
|
|
71
|
-
.replace('\x00DAY\x00', day.toString());
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Get first author name from authors array
|
|
76
|
-
*/
|
|
77
|
-
function getFirstAuthor(authors: Author[] | string | undefined): string {
|
|
78
|
-
if (!authors || (Array.isArray(authors) && authors.length === 0)) return '';
|
|
79
|
-
|
|
80
|
-
const first = Array.isArray(authors) ? authors[0] : authors;
|
|
81
|
-
|
|
82
|
-
if (!first) return '';
|
|
83
|
-
if (typeof first === 'string') return first;
|
|
84
|
-
if (first.name) return first.name;
|
|
85
|
-
|
|
86
|
-
return '';
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Get all author names
|
|
91
|
-
*/
|
|
92
|
-
function getAllAuthors(authors: Author[] | string | undefined): string {
|
|
93
|
-
if (!authors) return '';
|
|
94
|
-
if (typeof authors === 'string') return authors;
|
|
95
|
-
|
|
96
|
-
return authors
|
|
97
|
-
.map((a) => (typeof a === 'string' ? a : (a.name || '')))
|
|
98
|
-
.filter(Boolean)
|
|
99
|
-
.join(', ');
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Options for variable processing
|
|
104
|
-
*/
|
|
105
|
-
interface ProcessVariablesOptions {
|
|
106
|
-
sectionContents?: string[];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Config object (minimal subset needed for variables)
|
|
111
|
-
*/
|
|
112
|
-
interface Config {
|
|
113
|
-
version?: string;
|
|
114
|
-
title?: string;
|
|
115
|
-
authors?: Author[] | string;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Process template variables in text
|
|
120
|
-
*/
|
|
121
|
-
export function processVariables(
|
|
122
|
-
text: string,
|
|
123
|
-
config: Config = {},
|
|
124
|
-
options: ProcessVariablesOptions = {}
|
|
125
|
-
): string {
|
|
126
|
-
const now = new Date();
|
|
127
|
-
let result = text;
|
|
128
|
-
|
|
129
|
-
// Calculate word count from sections if provided
|
|
130
|
-
let wordCount = 0;
|
|
131
|
-
if (options.sectionContents) {
|
|
132
|
-
for (const content of options.sectionContents) {
|
|
133
|
-
wordCount += countWords(content);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// {{date}} - Current date
|
|
138
|
-
result = result.replace(/\{\{date\}\}/g, formatDate(now));
|
|
139
|
-
|
|
140
|
-
// {{date:format}} - Custom date format
|
|
141
|
-
result = result.replace(/\{\{date:([^}]+)\}\}/g, (match, format) => {
|
|
142
|
-
return formatDate(now, format);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// {{year}} - Current year
|
|
146
|
-
result = result.replace(/\{\{year\}\}/g, now.getFullYear().toString());
|
|
147
|
-
|
|
148
|
-
// {{version}} - From config
|
|
149
|
-
result = result.replace(/\{\{version\}\}/g, config.version || '');
|
|
150
|
-
|
|
151
|
-
// {{title}} - Document title
|
|
152
|
-
result = result.replace(/\{\{title\}\}/g, config.title || '');
|
|
153
|
-
|
|
154
|
-
// {{author}} - First author
|
|
155
|
-
result = result.replace(/\{\{author\}\}/g, getFirstAuthor(config.authors));
|
|
156
|
-
|
|
157
|
-
// {{authors}} - All authors
|
|
158
|
-
result = result.replace(/\{\{authors\}\}/g, getAllAuthors(config.authors));
|
|
159
|
-
|
|
160
|
-
// {{word_count}} - Total word count
|
|
161
|
-
result = result.replace(/\{\{word_count\}\}/g, wordCount.toLocaleString());
|
|
162
|
-
|
|
163
|
-
return result;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Check if text contains any template variables
|
|
168
|
-
*/
|
|
169
|
-
export function hasVariables(text: string): boolean {
|
|
170
|
-
return /\{\{[^}]+\}\}/.test(text);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* List all variables found in text
|
|
175
|
-
*/
|
|
176
|
-
export function findVariables(text: string): string[] {
|
|
177
|
-
const matches = text.match(/\{\{([^}]+)\}\}/g) || [];
|
|
178
|
-
return [...new Set(matches.map((m) => m.slice(2, -2)))];
|
|
179
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Template variable substitution for rev
|
|
3
|
+
*
|
|
4
|
+
* Supported variables:
|
|
5
|
+
* {{date}} - Current date (YYYY-MM-DD)
|
|
6
|
+
* {{date:format}} - Custom date format (e.g., {{date:MMMM D, YYYY}})
|
|
7
|
+
* {{version}} - Version from rev.yaml
|
|
8
|
+
* {{word_count}} - Total word count
|
|
9
|
+
* {{author}} - First author name
|
|
10
|
+
* {{authors}} - All authors (comma-separated)
|
|
11
|
+
* {{title}} - Document title
|
|
12
|
+
* {{year}} - Current year
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import * as fs from 'fs';
|
|
16
|
+
import { countWords } from './utils.js';
|
|
17
|
+
import type { Author } from './types.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Format date with simple pattern
|
|
21
|
+
*/
|
|
22
|
+
function formatDate(date: Date, format: string = 'YYYY-MM-DD'): string {
|
|
23
|
+
const months = [
|
|
24
|
+
'January',
|
|
25
|
+
'February',
|
|
26
|
+
'March',
|
|
27
|
+
'April',
|
|
28
|
+
'May',
|
|
29
|
+
'June',
|
|
30
|
+
'July',
|
|
31
|
+
'August',
|
|
32
|
+
'September',
|
|
33
|
+
'October',
|
|
34
|
+
'November',
|
|
35
|
+
'December',
|
|
36
|
+
];
|
|
37
|
+
const monthsShort = [
|
|
38
|
+
'Jan',
|
|
39
|
+
'Feb',
|
|
40
|
+
'Mar',
|
|
41
|
+
'Apr',
|
|
42
|
+
'May',
|
|
43
|
+
'Jun',
|
|
44
|
+
'Jul',
|
|
45
|
+
'Aug',
|
|
46
|
+
'Sep',
|
|
47
|
+
'Oct',
|
|
48
|
+
'Nov',
|
|
49
|
+
'Dec',
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const year = date.getFullYear();
|
|
53
|
+
const month = date.getMonth();
|
|
54
|
+
const day = date.getDate();
|
|
55
|
+
|
|
56
|
+
// Use placeholders to avoid replacement conflicts (e.g., D in December)
|
|
57
|
+
const monthFull = months[month] || '';
|
|
58
|
+
const monthShort = monthsShort[month] || '';
|
|
59
|
+
return format
|
|
60
|
+
.replace('YYYY', '\x00YEAR\x00')
|
|
61
|
+
.replace('MMMM', '\x00MONTHFULL\x00')
|
|
62
|
+
.replace('MMM', '\x00MONTHSHORT\x00')
|
|
63
|
+
.replace('MM', '\x00MONTHNUM\x00')
|
|
64
|
+
.replace('DD', '\x00DAYPAD\x00')
|
|
65
|
+
.replace(/\bD\b/, '\x00DAY\x00')
|
|
66
|
+
.replace('\x00YEAR\x00', year.toString())
|
|
67
|
+
.replace('\x00MONTHFULL\x00', monthFull)
|
|
68
|
+
.replace('\x00MONTHSHORT\x00', monthShort)
|
|
69
|
+
.replace('\x00MONTHNUM\x00', (month + 1).toString().padStart(2, '0'))
|
|
70
|
+
.replace('\x00DAYPAD\x00', day.toString().padStart(2, '0'))
|
|
71
|
+
.replace('\x00DAY\x00', day.toString());
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get first author name from authors array
|
|
76
|
+
*/
|
|
77
|
+
function getFirstAuthor(authors: Author[] | string | undefined): string {
|
|
78
|
+
if (!authors || (Array.isArray(authors) && authors.length === 0)) return '';
|
|
79
|
+
|
|
80
|
+
const first = Array.isArray(authors) ? authors[0] : authors;
|
|
81
|
+
|
|
82
|
+
if (!first) return '';
|
|
83
|
+
if (typeof first === 'string') return first;
|
|
84
|
+
if (first.name) return first.name;
|
|
85
|
+
|
|
86
|
+
return '';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get all author names
|
|
91
|
+
*/
|
|
92
|
+
function getAllAuthors(authors: Author[] | string | undefined): string {
|
|
93
|
+
if (!authors) return '';
|
|
94
|
+
if (typeof authors === 'string') return authors;
|
|
95
|
+
|
|
96
|
+
return authors
|
|
97
|
+
.map((a) => (typeof a === 'string' ? a : (a.name || '')))
|
|
98
|
+
.filter(Boolean)
|
|
99
|
+
.join(', ');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Options for variable processing
|
|
104
|
+
*/
|
|
105
|
+
interface ProcessVariablesOptions {
|
|
106
|
+
sectionContents?: string[];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Config object (minimal subset needed for variables)
|
|
111
|
+
*/
|
|
112
|
+
interface Config {
|
|
113
|
+
version?: string;
|
|
114
|
+
title?: string;
|
|
115
|
+
authors?: Author[] | string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Process template variables in text
|
|
120
|
+
*/
|
|
121
|
+
export function processVariables(
|
|
122
|
+
text: string,
|
|
123
|
+
config: Config = {},
|
|
124
|
+
options: ProcessVariablesOptions = {}
|
|
125
|
+
): string {
|
|
126
|
+
const now = new Date();
|
|
127
|
+
let result = text;
|
|
128
|
+
|
|
129
|
+
// Calculate word count from sections if provided
|
|
130
|
+
let wordCount = 0;
|
|
131
|
+
if (options.sectionContents) {
|
|
132
|
+
for (const content of options.sectionContents) {
|
|
133
|
+
wordCount += countWords(content);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// {{date}} - Current date
|
|
138
|
+
result = result.replace(/\{\{date\}\}/g, formatDate(now));
|
|
139
|
+
|
|
140
|
+
// {{date:format}} - Custom date format
|
|
141
|
+
result = result.replace(/\{\{date:([^}]+)\}\}/g, (match, format) => {
|
|
142
|
+
return formatDate(now, format);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// {{year}} - Current year
|
|
146
|
+
result = result.replace(/\{\{year\}\}/g, now.getFullYear().toString());
|
|
147
|
+
|
|
148
|
+
// {{version}} - From config
|
|
149
|
+
result = result.replace(/\{\{version\}\}/g, config.version || '');
|
|
150
|
+
|
|
151
|
+
// {{title}} - Document title
|
|
152
|
+
result = result.replace(/\{\{title\}\}/g, config.title || '');
|
|
153
|
+
|
|
154
|
+
// {{author}} - First author
|
|
155
|
+
result = result.replace(/\{\{author\}\}/g, getFirstAuthor(config.authors));
|
|
156
|
+
|
|
157
|
+
// {{authors}} - All authors
|
|
158
|
+
result = result.replace(/\{\{authors\}\}/g, getAllAuthors(config.authors));
|
|
159
|
+
|
|
160
|
+
// {{word_count}} - Total word count
|
|
161
|
+
result = result.replace(/\{\{word_count\}\}/g, wordCount.toLocaleString());
|
|
162
|
+
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Check if text contains any template variables
|
|
168
|
+
*/
|
|
169
|
+
export function hasVariables(text: string): boolean {
|
|
170
|
+
return /\{\{[^}]+\}\}/.test(text);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* List all variables found in text
|
|
175
|
+
*/
|
|
176
|
+
export function findVariables(text: string): string[] {
|
|
177
|
+
const matches = text.match(/\{\{([^}]+)\}\}/g) || [];
|
|
178
|
+
return [...new Set(matches.map((m) => m.slice(2, -2)))];
|
|
179
|
+
}
|