docrev 0.9.13 → 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 +38 -1
- package/dist/lib/build.d.ts.map +1 -1
- package/dist/lib/build.js +68 -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/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/eslint.config.js +27 -27
- package/lib/anchor-match.ts +276 -276
- package/lib/annotations.ts +644 -644
- package/lib/build.ts +1300 -1251
- 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 -911
- 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 -550
- package/lib/undo.ts +250 -250
- package/lib/utils.ts +69 -69
- package/lib/variables.ts +179 -179
- package/lib/word-extraction.ts +806 -806
- package/lib/word.ts +643 -643
- package/lib/wordcomments.ts +817 -817
- 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/orcid.ts
CHANGED
|
@@ -1,144 +1,144 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ORCID integration for author metadata
|
|
3
|
-
*
|
|
4
|
-
* Fetches author information from ORCID public API
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export interface OrcidProfile {
|
|
8
|
-
orcid: string;
|
|
9
|
-
name: string;
|
|
10
|
-
affiliation: string;
|
|
11
|
-
email: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Validate ORCID format (0000-0000-0000-0000)
|
|
16
|
-
*/
|
|
17
|
-
export function isValidOrcid(orcid: string): boolean {
|
|
18
|
-
return /^(\d{4}-){3}\d{3}[\dX]$/i.test(orcid);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Clean ORCID input (removes URLs, whitespace)
|
|
23
|
-
*/
|
|
24
|
-
export function cleanOrcid(input: string): string {
|
|
25
|
-
if (!input) return '';
|
|
26
|
-
|
|
27
|
-
// Remove URL prefix if present
|
|
28
|
-
let clean = input.trim()
|
|
29
|
-
.replace(/^https?:\/\/(www\.)?orcid\.org\//i, '')
|
|
30
|
-
.replace(/^orcid\.org\//i, '')
|
|
31
|
-
.trim();
|
|
32
|
-
|
|
33
|
-
return clean;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Fetch author info from ORCID public API
|
|
38
|
-
*/
|
|
39
|
-
export async function fetchOrcidProfile(orcid: string): Promise<OrcidProfile> {
|
|
40
|
-
const cleanId = cleanOrcid(orcid);
|
|
41
|
-
|
|
42
|
-
if (!isValidOrcid(cleanId)) {
|
|
43
|
-
throw new Error(`Invalid ORCID format: ${orcid}`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const url = `https://pub.orcid.org/v3.0/${cleanId}/person`;
|
|
47
|
-
|
|
48
|
-
const response = await fetch(url, {
|
|
49
|
-
headers: {
|
|
50
|
-
'Accept': 'application/json',
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
if (!response.ok) {
|
|
55
|
-
if (response.status === 404) {
|
|
56
|
-
throw new Error(`ORCID not found: ${cleanId}`);
|
|
57
|
-
}
|
|
58
|
-
throw new Error(`ORCID API error: ${response.status}`);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const data = await response.json() as any;
|
|
62
|
-
|
|
63
|
-
// Extract name
|
|
64
|
-
const nameData = data.name;
|
|
65
|
-
let name = '';
|
|
66
|
-
if (nameData) {
|
|
67
|
-
const given = nameData['given-names']?.value || '';
|
|
68
|
-
const family = nameData['family-name']?.value || '';
|
|
69
|
-
name = `${given} ${family}`.trim();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Extract primary affiliation
|
|
73
|
-
let affiliation = '';
|
|
74
|
-
const affiliations = data.employments?.['affiliation-group'] || [];
|
|
75
|
-
if (affiliations.length > 0) {
|
|
76
|
-
const primary = affiliations[0]?.summaries?.[0]?.['employment-summary'];
|
|
77
|
-
affiliation = primary?.organization?.name || '';
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Extract email (if public)
|
|
81
|
-
let email = '';
|
|
82
|
-
const emails = data.emails?.email || [];
|
|
83
|
-
const primaryEmail = emails.find((e: any) => e.primary) || emails[0];
|
|
84
|
-
if (primaryEmail?.email) {
|
|
85
|
-
email = primaryEmail.email;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
orcid: cleanId,
|
|
90
|
-
name,
|
|
91
|
-
affiliation,
|
|
92
|
-
email,
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Fetch work count from ORCID
|
|
98
|
-
*/
|
|
99
|
-
export async function fetchOrcidWorkCount(orcid: string): Promise<number> {
|
|
100
|
-
const cleanId = cleanOrcid(orcid);
|
|
101
|
-
|
|
102
|
-
if (!isValidOrcid(cleanId)) {
|
|
103
|
-
throw new Error(`Invalid ORCID format: ${orcid}`);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const url = `https://pub.orcid.org/v3.0/${cleanId}/works`;
|
|
107
|
-
|
|
108
|
-
const response = await fetch(url, {
|
|
109
|
-
headers: {
|
|
110
|
-
'Accept': 'application/json',
|
|
111
|
-
},
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
if (!response.ok) {
|
|
115
|
-
return 0;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const data = await response.json() as any;
|
|
119
|
-
return data.group?.length || 0;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Format author for YAML
|
|
124
|
-
*/
|
|
125
|
-
export function formatAuthorYaml(profile: OrcidProfile): string {
|
|
126
|
-
const lines: string[] = [];
|
|
127
|
-
lines.push(` - name: ${profile.name}`);
|
|
128
|
-
if (profile.affiliation) {
|
|
129
|
-
lines.push(` affiliation: ${profile.affiliation}`);
|
|
130
|
-
}
|
|
131
|
-
if (profile.email) {
|
|
132
|
-
lines.push(` email: ${profile.email}`);
|
|
133
|
-
}
|
|
134
|
-
lines.push(` orcid: ${profile.orcid}`);
|
|
135
|
-
return lines.join('\n');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Generate ORCID badge markdown
|
|
140
|
-
*/
|
|
141
|
-
export function getOrcidBadge(orcid: string): string {
|
|
142
|
-
const cleanId = cleanOrcid(orcid);
|
|
143
|
-
return `[](https://orcid.org/${cleanId})`;
|
|
144
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* ORCID integration for author metadata
|
|
3
|
+
*
|
|
4
|
+
* Fetches author information from ORCID public API
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface OrcidProfile {
|
|
8
|
+
orcid: string;
|
|
9
|
+
name: string;
|
|
10
|
+
affiliation: string;
|
|
11
|
+
email: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Validate ORCID format (0000-0000-0000-0000)
|
|
16
|
+
*/
|
|
17
|
+
export function isValidOrcid(orcid: string): boolean {
|
|
18
|
+
return /^(\d{4}-){3}\d{3}[\dX]$/i.test(orcid);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Clean ORCID input (removes URLs, whitespace)
|
|
23
|
+
*/
|
|
24
|
+
export function cleanOrcid(input: string): string {
|
|
25
|
+
if (!input) return '';
|
|
26
|
+
|
|
27
|
+
// Remove URL prefix if present
|
|
28
|
+
let clean = input.trim()
|
|
29
|
+
.replace(/^https?:\/\/(www\.)?orcid\.org\//i, '')
|
|
30
|
+
.replace(/^orcid\.org\//i, '')
|
|
31
|
+
.trim();
|
|
32
|
+
|
|
33
|
+
return clean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Fetch author info from ORCID public API
|
|
38
|
+
*/
|
|
39
|
+
export async function fetchOrcidProfile(orcid: string): Promise<OrcidProfile> {
|
|
40
|
+
const cleanId = cleanOrcid(orcid);
|
|
41
|
+
|
|
42
|
+
if (!isValidOrcid(cleanId)) {
|
|
43
|
+
throw new Error(`Invalid ORCID format: ${orcid}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const url = `https://pub.orcid.org/v3.0/${cleanId}/person`;
|
|
47
|
+
|
|
48
|
+
const response = await fetch(url, {
|
|
49
|
+
headers: {
|
|
50
|
+
'Accept': 'application/json',
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (!response.ok) {
|
|
55
|
+
if (response.status === 404) {
|
|
56
|
+
throw new Error(`ORCID not found: ${cleanId}`);
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`ORCID API error: ${response.status}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const data = await response.json() as any;
|
|
62
|
+
|
|
63
|
+
// Extract name
|
|
64
|
+
const nameData = data.name;
|
|
65
|
+
let name = '';
|
|
66
|
+
if (nameData) {
|
|
67
|
+
const given = nameData['given-names']?.value || '';
|
|
68
|
+
const family = nameData['family-name']?.value || '';
|
|
69
|
+
name = `${given} ${family}`.trim();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Extract primary affiliation
|
|
73
|
+
let affiliation = '';
|
|
74
|
+
const affiliations = data.employments?.['affiliation-group'] || [];
|
|
75
|
+
if (affiliations.length > 0) {
|
|
76
|
+
const primary = affiliations[0]?.summaries?.[0]?.['employment-summary'];
|
|
77
|
+
affiliation = primary?.organization?.name || '';
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Extract email (if public)
|
|
81
|
+
let email = '';
|
|
82
|
+
const emails = data.emails?.email || [];
|
|
83
|
+
const primaryEmail = emails.find((e: any) => e.primary) || emails[0];
|
|
84
|
+
if (primaryEmail?.email) {
|
|
85
|
+
email = primaryEmail.email;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
orcid: cleanId,
|
|
90
|
+
name,
|
|
91
|
+
affiliation,
|
|
92
|
+
email,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Fetch work count from ORCID
|
|
98
|
+
*/
|
|
99
|
+
export async function fetchOrcidWorkCount(orcid: string): Promise<number> {
|
|
100
|
+
const cleanId = cleanOrcid(orcid);
|
|
101
|
+
|
|
102
|
+
if (!isValidOrcid(cleanId)) {
|
|
103
|
+
throw new Error(`Invalid ORCID format: ${orcid}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const url = `https://pub.orcid.org/v3.0/${cleanId}/works`;
|
|
107
|
+
|
|
108
|
+
const response = await fetch(url, {
|
|
109
|
+
headers: {
|
|
110
|
+
'Accept': 'application/json',
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const data = await response.json() as any;
|
|
119
|
+
return data.group?.length || 0;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Format author for YAML
|
|
124
|
+
*/
|
|
125
|
+
export function formatAuthorYaml(profile: OrcidProfile): string {
|
|
126
|
+
const lines: string[] = [];
|
|
127
|
+
lines.push(` - name: ${profile.name}`);
|
|
128
|
+
if (profile.affiliation) {
|
|
129
|
+
lines.push(` affiliation: ${profile.affiliation}`);
|
|
130
|
+
}
|
|
131
|
+
if (profile.email) {
|
|
132
|
+
lines.push(` email: ${profile.email}`);
|
|
133
|
+
}
|
|
134
|
+
lines.push(` orcid: ${profile.orcid}`);
|
|
135
|
+
return lines.join('\n');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Generate ORCID badge markdown
|
|
140
|
+
*/
|
|
141
|
+
export function getOrcidBadge(orcid: string): string {
|
|
142
|
+
const cleanId = cleanOrcid(orcid);
|
|
143
|
+
return `[](https://orcid.org/${cleanId})`;
|
|
144
|
+
}
|