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
|
@@ -4,21 +4,24 @@
|
|
|
4
4
|
* Fetches author information from ORCID public API
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
export interface OrcidProfile {
|
|
8
|
+
orcid: string;
|
|
9
|
+
name: string;
|
|
10
|
+
affiliation: string;
|
|
11
|
+
email: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
7
14
|
/**
|
|
8
15
|
* Validate ORCID format (0000-0000-0000-0000)
|
|
9
|
-
* @param {string} orcid
|
|
10
|
-
* @returns {boolean}
|
|
11
16
|
*/
|
|
12
|
-
export function isValidOrcid(orcid) {
|
|
17
|
+
export function isValidOrcid(orcid: string): boolean {
|
|
13
18
|
return /^(\d{4}-){3}\d{3}[\dX]$/i.test(orcid);
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
/**
|
|
17
22
|
* Clean ORCID input (removes URLs, whitespace)
|
|
18
|
-
* @param {string} input
|
|
19
|
-
* @returns {string}
|
|
20
23
|
*/
|
|
21
|
-
export function cleanOrcid(input) {
|
|
24
|
+
export function cleanOrcid(input: string): string {
|
|
22
25
|
if (!input) return '';
|
|
23
26
|
|
|
24
27
|
// Remove URL prefix if present
|
|
@@ -32,10 +35,8 @@ export function cleanOrcid(input) {
|
|
|
32
35
|
|
|
33
36
|
/**
|
|
34
37
|
* Fetch author info from ORCID public API
|
|
35
|
-
* @param {string} orcid
|
|
36
|
-
* @returns {Promise<{name: string, affiliation: string, email: string, works: number}>}
|
|
37
38
|
*/
|
|
38
|
-
export async function fetchOrcidProfile(orcid) {
|
|
39
|
+
export async function fetchOrcidProfile(orcid: string): Promise<OrcidProfile> {
|
|
39
40
|
const cleanId = cleanOrcid(orcid);
|
|
40
41
|
|
|
41
42
|
if (!isValidOrcid(cleanId)) {
|
|
@@ -57,7 +58,7 @@ export async function fetchOrcidProfile(orcid) {
|
|
|
57
58
|
throw new Error(`ORCID API error: ${response.status}`);
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
const data = await response.json();
|
|
61
|
+
const data = await response.json() as any;
|
|
61
62
|
|
|
62
63
|
// Extract name
|
|
63
64
|
const nameData = data.name;
|
|
@@ -79,7 +80,7 @@ export async function fetchOrcidProfile(orcid) {
|
|
|
79
80
|
// Extract email (if public)
|
|
80
81
|
let email = '';
|
|
81
82
|
const emails = data.emails?.email || [];
|
|
82
|
-
const primaryEmail = emails.find(e => e.primary) || emails[0];
|
|
83
|
+
const primaryEmail = emails.find((e: any) => e.primary) || emails[0];
|
|
83
84
|
if (primaryEmail?.email) {
|
|
84
85
|
email = primaryEmail.email;
|
|
85
86
|
}
|
|
@@ -94,10 +95,8 @@ export async function fetchOrcidProfile(orcid) {
|
|
|
94
95
|
|
|
95
96
|
/**
|
|
96
97
|
* Fetch work count from ORCID
|
|
97
|
-
* @param {string} orcid
|
|
98
|
-
* @returns {Promise<number>}
|
|
99
98
|
*/
|
|
100
|
-
export async function fetchOrcidWorkCount(orcid) {
|
|
99
|
+
export async function fetchOrcidWorkCount(orcid: string): Promise<number> {
|
|
101
100
|
const cleanId = cleanOrcid(orcid);
|
|
102
101
|
|
|
103
102
|
if (!isValidOrcid(cleanId)) {
|
|
@@ -116,17 +115,15 @@ export async function fetchOrcidWorkCount(orcid) {
|
|
|
116
115
|
return 0;
|
|
117
116
|
}
|
|
118
117
|
|
|
119
|
-
const data = await response.json();
|
|
118
|
+
const data = await response.json() as any;
|
|
120
119
|
return data.group?.length || 0;
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
/**
|
|
124
123
|
* Format author for YAML
|
|
125
|
-
* @param {object} profile
|
|
126
|
-
* @returns {string}
|
|
127
124
|
*/
|
|
128
|
-
export function formatAuthorYaml(profile) {
|
|
129
|
-
const lines = [];
|
|
125
|
+
export function formatAuthorYaml(profile: OrcidProfile): string {
|
|
126
|
+
const lines: string[] = [];
|
|
130
127
|
lines.push(` - name: ${profile.name}`);
|
|
131
128
|
if (profile.affiliation) {
|
|
132
129
|
lines.push(` affiliation: ${profile.affiliation}`);
|
|
@@ -140,10 +137,8 @@ export function formatAuthorYaml(profile) {
|
|
|
140
137
|
|
|
141
138
|
/**
|
|
142
139
|
* Generate ORCID badge markdown
|
|
143
|
-
* @param {string} orcid
|
|
144
|
-
* @returns {string}
|
|
145
140
|
*/
|
|
146
|
-
export function getOrcidBadge(orcid) {
|
|
141
|
+
export function getOrcidBadge(orcid: string): string {
|
|
147
142
|
const cleanId = cleanOrcid(orcid);
|
|
148
143
|
return `[](https://orcid.org/${cleanId})`;
|
|
149
144
|
}
|
|
@@ -47,15 +47,35 @@ export const SIMPLE_MARGIN_PREAMBLE = `
|
|
|
47
47
|
}
|
|
48
48
|
`;
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Options for converting comments to margin notes
|
|
52
|
+
*/
|
|
53
|
+
export interface CommentConversionOptions {
|
|
54
|
+
useTodonotes?: boolean;
|
|
55
|
+
stripResolved?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Result of comment conversion
|
|
60
|
+
*/
|
|
61
|
+
export interface CommentConversionResult {
|
|
62
|
+
markdown: string;
|
|
63
|
+
commentCount: number;
|
|
64
|
+
preamble: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
50
67
|
/**
|
|
51
68
|
* Convert CriticMarkup comments to LaTeX margin notes
|
|
52
69
|
* {>>Author: comment text<<} -> \margincomment{Author: comment text}
|
|
53
70
|
*
|
|
54
|
-
* @param
|
|
55
|
-
* @param
|
|
56
|
-
* @returns
|
|
71
|
+
* @param markdown - Markdown with CriticMarkup comments
|
|
72
|
+
* @param options - { useTodonotes: boolean, stripResolved: boolean }
|
|
73
|
+
* @returns Converted markdown with comment count and preamble
|
|
57
74
|
*/
|
|
58
|
-
export function convertCommentsToMarginNotes(
|
|
75
|
+
export function convertCommentsToMarginNotes(
|
|
76
|
+
markdown: string,
|
|
77
|
+
options: CommentConversionOptions = {}
|
|
78
|
+
): CommentConversionResult {
|
|
59
79
|
const { useTodonotes = true, stripResolved = true } = options;
|
|
60
80
|
|
|
61
81
|
let commentCount = 0;
|
|
@@ -77,7 +97,7 @@ export function convertCommentsToMarginNotes(markdown, options = {}) {
|
|
|
77
97
|
|
|
78
98
|
if (useTodonotes) {
|
|
79
99
|
// Check if content has author prefix (Author: text)
|
|
80
|
-
const authorMatch = escaped.match(/^([^:]+):\s*(
|
|
100
|
+
const authorMatch = escaped.match(/^([^:]+):\s*([\s\S]+)$/);
|
|
81
101
|
if (authorMatch) {
|
|
82
102
|
const [, author, text] = authorMatch;
|
|
83
103
|
return `\\reviewercomment{${author}}{${text}}`;
|
|
@@ -99,10 +119,10 @@ export function convertCommentsToMarginNotes(markdown, options = {}) {
|
|
|
99
119
|
|
|
100
120
|
/**
|
|
101
121
|
* Escape LaTeX special characters
|
|
102
|
-
* @param
|
|
103
|
-
* @returns
|
|
122
|
+
* @param text - Text to escape
|
|
123
|
+
* @returns Escaped text
|
|
104
124
|
*/
|
|
105
|
-
function escapeLatex(text) {
|
|
125
|
+
function escapeLatex(text: string): string {
|
|
106
126
|
return text
|
|
107
127
|
.replace(/\\/g, '\\textbackslash{}')
|
|
108
128
|
.replace(/([#$%&_{}])/g, '\\$1')
|
|
@@ -111,16 +131,24 @@ function escapeLatex(text) {
|
|
|
111
131
|
.replace(/\n/g, ' '); // Replace newlines with spaces
|
|
112
132
|
}
|
|
113
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Result of track changes conversion
|
|
136
|
+
*/
|
|
137
|
+
export interface TrackChangesResult {
|
|
138
|
+
markdown: string;
|
|
139
|
+
preamble: string;
|
|
140
|
+
}
|
|
141
|
+
|
|
114
142
|
/**
|
|
115
143
|
* Convert track changes to visible LaTeX formatting
|
|
116
144
|
* {++inserted++} -> \textcolor{green}{inserted}
|
|
117
145
|
* {--deleted--} -> \textcolor{red}{\sout{deleted}}
|
|
118
146
|
* {~~old~>new~~} -> \textcolor{red}{\sout{old}}\textcolor{green}{new}
|
|
119
147
|
*
|
|
120
|
-
* @param
|
|
121
|
-
* @returns
|
|
148
|
+
* @param markdown - Markdown with track changes
|
|
149
|
+
* @returns Converted markdown and preamble
|
|
122
150
|
*/
|
|
123
|
-
export function convertTrackChangesToLatex(markdown) {
|
|
151
|
+
export function convertTrackChangesToLatex(markdown: string): TrackChangesResult {
|
|
124
152
|
let result = markdown;
|
|
125
153
|
|
|
126
154
|
// Insertions: {++text++} -> green text
|
|
@@ -149,12 +177,21 @@ export function convertTrackChangesToLatex(markdown) {
|
|
|
149
177
|
return { markdown: result, preamble };
|
|
150
178
|
}
|
|
151
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Options for combined preamble
|
|
182
|
+
*/
|
|
183
|
+
export interface PreambleOptions {
|
|
184
|
+
comments?: boolean;
|
|
185
|
+
trackChanges?: boolean;
|
|
186
|
+
useTodonotes?: boolean;
|
|
187
|
+
}
|
|
188
|
+
|
|
152
189
|
/**
|
|
153
190
|
* Get combined preamble for comments and track changes
|
|
154
|
-
* @param
|
|
155
|
-
* @returns
|
|
191
|
+
* @param options - { comments: boolean, trackChanges: boolean, useTodonotes: boolean }
|
|
192
|
+
* @returns Combined LaTeX preamble
|
|
156
193
|
*/
|
|
157
|
-
export function getCombinedPreamble(options = {}) {
|
|
194
|
+
export function getCombinedPreamble(options: PreambleOptions = {}): string {
|
|
158
195
|
const { comments = true, trackChanges = false, useTodonotes = true } = options;
|
|
159
196
|
|
|
160
197
|
let preamble = '';
|
|
@@ -180,15 +217,36 @@ export function getCombinedPreamble(options = {}) {
|
|
|
180
217
|
return preamble;
|
|
181
218
|
}
|
|
182
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Options for preparing markdown for annotated PDF
|
|
222
|
+
*/
|
|
223
|
+
export interface AnnotatedPdfOptions {
|
|
224
|
+
showTrackChanges?: boolean;
|
|
225
|
+
useTodonotes?: boolean;
|
|
226
|
+
stripResolved?: boolean;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Result of preparing markdown for annotated PDF
|
|
231
|
+
*/
|
|
232
|
+
export interface AnnotatedPdfResult {
|
|
233
|
+
markdown: string;
|
|
234
|
+
preamble: string;
|
|
235
|
+
commentCount: number;
|
|
236
|
+
}
|
|
237
|
+
|
|
183
238
|
/**
|
|
184
239
|
* Prepare markdown for PDF with visible comments
|
|
185
240
|
* Converts comments to margin notes and optionally shows track changes
|
|
186
241
|
*
|
|
187
|
-
* @param
|
|
188
|
-
* @param
|
|
189
|
-
* @returns
|
|
242
|
+
* @param markdown - Markdown content
|
|
243
|
+
* @param options - { showTrackChanges: boolean, useTodonotes: boolean }
|
|
244
|
+
* @returns Converted markdown with preamble and comment count
|
|
190
245
|
*/
|
|
191
|
-
export function prepareMarkdownForAnnotatedPdf(
|
|
246
|
+
export function prepareMarkdownForAnnotatedPdf(
|
|
247
|
+
markdown: string,
|
|
248
|
+
options: AnnotatedPdfOptions = {}
|
|
249
|
+
): AnnotatedPdfResult {
|
|
192
250
|
const { showTrackChanges = false, useTodonotes = true, stripResolved = true } = options;
|
|
193
251
|
|
|
194
252
|
let result = markdown;
|
|
@@ -22,13 +22,82 @@ const COMMENT_TYPES = [
|
|
|
22
22
|
'Popup', // Popup comments (attached to other annotations)
|
|
23
23
|
];
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Raw PDF annotation extracted from pdf-lib
|
|
27
|
+
*/
|
|
28
|
+
export interface PdfAnnotation {
|
|
29
|
+
type: string;
|
|
30
|
+
page: number;
|
|
31
|
+
contents: string;
|
|
32
|
+
author: string;
|
|
33
|
+
date: string;
|
|
34
|
+
rect: number[];
|
|
35
|
+
quadPoints: number[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* PDF comment converted to CriticMarkup format
|
|
40
|
+
*/
|
|
41
|
+
export interface PdfComment {
|
|
42
|
+
author: string;
|
|
43
|
+
text: string;
|
|
44
|
+
page: number;
|
|
45
|
+
type: string;
|
|
46
|
+
date?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* PDF annotation with extracted highlighted text
|
|
51
|
+
*/
|
|
52
|
+
export interface PdfAnnotationWithText extends PdfAnnotation {
|
|
53
|
+
highlightedText: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Options for PDF extraction
|
|
58
|
+
*/
|
|
59
|
+
export interface ExtractOptions {
|
|
60
|
+
timeout?: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Options for markdown insertion
|
|
65
|
+
*/
|
|
66
|
+
export interface InsertOptions {
|
|
67
|
+
sectionPerPage?: boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Statistics about PDF comments
|
|
72
|
+
*/
|
|
73
|
+
export interface PdfCommentStats {
|
|
74
|
+
total: number;
|
|
75
|
+
byType: Record<string, number>;
|
|
76
|
+
byAuthor: Record<string, number>;
|
|
77
|
+
byPage: Record<number, number>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Text item from pdfjs-dist
|
|
82
|
+
*/
|
|
83
|
+
interface PdfTextItem {
|
|
84
|
+
str: string;
|
|
85
|
+
x: number;
|
|
86
|
+
y: number;
|
|
87
|
+
width: number;
|
|
88
|
+
height: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
25
91
|
/**
|
|
26
92
|
* Extract raw annotations from a PDF file
|
|
27
|
-
* @param
|
|
28
|
-
* @param
|
|
29
|
-
* @returns
|
|
93
|
+
* @param pdfPath - Path to PDF file
|
|
94
|
+
* @param options - { timeout: number (ms) }
|
|
95
|
+
* @returns Array of PDF annotations
|
|
30
96
|
*/
|
|
31
|
-
export async function extractPdfAnnotations(
|
|
97
|
+
export async function extractPdfAnnotations(
|
|
98
|
+
pdfPath: string,
|
|
99
|
+
options: ExtractOptions = {}
|
|
100
|
+
): Promise<PdfAnnotation[]> {
|
|
32
101
|
const { timeout = 30000 } = options;
|
|
33
102
|
|
|
34
103
|
// Validate file exists
|
|
@@ -36,32 +105,34 @@ export async function extractPdfAnnotations(pdfPath, options = {}) {
|
|
|
36
105
|
throw new Error(`File not found: ${pdfPath}`);
|
|
37
106
|
}
|
|
38
107
|
|
|
39
|
-
let pdfBytes;
|
|
108
|
+
let pdfBytes: Buffer;
|
|
40
109
|
try {
|
|
41
110
|
pdfBytes = fs.readFileSync(pdfPath);
|
|
42
111
|
} catch (err) {
|
|
43
|
-
|
|
112
|
+
const error = err as Error;
|
|
113
|
+
throw new Error(`Cannot read PDF file: ${error.message}`);
|
|
44
114
|
}
|
|
45
115
|
|
|
46
116
|
// Create a promise that rejects after timeout
|
|
47
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
117
|
+
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
48
118
|
setTimeout(() => reject(new Error(`PDF extraction timed out after ${timeout / 1000}s`)), timeout);
|
|
49
119
|
});
|
|
50
120
|
|
|
51
|
-
let pdfDoc;
|
|
121
|
+
let pdfDoc: PDFDocument;
|
|
52
122
|
try {
|
|
53
123
|
pdfDoc = await Promise.race([
|
|
54
124
|
PDFDocument.load(pdfBytes, { ignoreEncryption: true }),
|
|
55
125
|
timeoutPromise,
|
|
56
126
|
]);
|
|
57
127
|
} catch (err) {
|
|
58
|
-
|
|
59
|
-
|
|
128
|
+
const error = err as Error;
|
|
129
|
+
if (error.message.includes('timed out')) {
|
|
130
|
+
throw error;
|
|
60
131
|
}
|
|
61
|
-
throw new Error(`Invalid or corrupted PDF file: ${
|
|
132
|
+
throw new Error(`Invalid or corrupted PDF file: ${error.message}`);
|
|
62
133
|
}
|
|
63
134
|
|
|
64
|
-
const annotations = [];
|
|
135
|
+
const annotations: PdfAnnotation[] = [];
|
|
65
136
|
const pages = pdfDoc.getPages();
|
|
66
137
|
|
|
67
138
|
for (let pageNum = 0; pageNum < pages.length; pageNum++) {
|
|
@@ -74,7 +145,7 @@ export async function extractPdfAnnotations(pdfPath, options = {}) {
|
|
|
74
145
|
|
|
75
146
|
for (const annotRef of annotRefs) {
|
|
76
147
|
try {
|
|
77
|
-
const annot = annotRef.dict || annotRef;
|
|
148
|
+
const annot = (annotRef as any).dict || annotRef;
|
|
78
149
|
if (!annot) continue;
|
|
79
150
|
|
|
80
151
|
// Get annotation type
|
|
@@ -98,11 +169,11 @@ export async function extractPdfAnnotations(pdfPath, options = {}) {
|
|
|
98
169
|
|
|
99
170
|
// Extract rectangle (position on page)
|
|
100
171
|
const rectObj = annot.get(pdfDoc.context.obj('Rect'));
|
|
101
|
-
const rect = rectObj?.asArray?.()?.map(n => n?.asNumber?.() || 0) || [0, 0, 0, 0];
|
|
172
|
+
const rect = rectObj?.asArray?.()?.map((n: any) => n?.asNumber?.() || 0) || [0, 0, 0, 0];
|
|
102
173
|
|
|
103
174
|
// Extract QuadPoints for highlights (the actual text bounds)
|
|
104
175
|
const quadObj = annot.get(pdfDoc.context.obj('QuadPoints'));
|
|
105
|
-
const quadPoints = quadObj?.asArray?.()?.map(n => n?.asNumber?.() || 0) || [];
|
|
176
|
+
const quadPoints = quadObj?.asArray?.()?.map((n: any) => n?.asNumber?.() || 0) || [];
|
|
106
177
|
|
|
107
178
|
// Skip empty annotations
|
|
108
179
|
if (!contents.trim() && subtype !== 'StrikeOut') continue;
|
|
@@ -135,10 +206,10 @@ export async function extractPdfAnnotations(pdfPath, options = {}) {
|
|
|
135
206
|
|
|
136
207
|
/**
|
|
137
208
|
* Parse PDF date string (D:YYYYMMDDHHmmSS format)
|
|
138
|
-
* @param
|
|
139
|
-
* @returns
|
|
209
|
+
* @param dateStr - PDF date string
|
|
210
|
+
* @returns ISO date string
|
|
140
211
|
*/
|
|
141
|
-
function parsePdfDate(dateStr) {
|
|
212
|
+
function parsePdfDate(dateStr: string): string {
|
|
142
213
|
if (!dateStr) return '';
|
|
143
214
|
|
|
144
215
|
// Remove D: prefix and timezone info
|
|
@@ -156,10 +227,10 @@ function parsePdfDate(dateStr) {
|
|
|
156
227
|
|
|
157
228
|
/**
|
|
158
229
|
* Clean PDF string (remove parentheses, decode escape sequences)
|
|
159
|
-
* @param
|
|
160
|
-
* @returns
|
|
230
|
+
* @param str - Raw PDF string
|
|
231
|
+
* @returns Cleaned string
|
|
161
232
|
*/
|
|
162
|
-
function cleanPdfString(str) {
|
|
233
|
+
function cleanPdfString(str: string): string {
|
|
163
234
|
if (!str) return '';
|
|
164
235
|
|
|
165
236
|
return str
|
|
@@ -176,10 +247,10 @@ function cleanPdfString(str) {
|
|
|
176
247
|
|
|
177
248
|
/**
|
|
178
249
|
* Convert PDF annotations to CriticMarkup comments
|
|
179
|
-
* @param
|
|
180
|
-
* @returns
|
|
250
|
+
* @param annotations - From extractPdfAnnotations
|
|
251
|
+
* @returns Array of PDF comments
|
|
181
252
|
*/
|
|
182
|
-
export function annotationsToComments(annotations) {
|
|
253
|
+
export function annotationsToComments(annotations: PdfAnnotation[]): PdfComment[] {
|
|
183
254
|
return annotations
|
|
184
255
|
.filter(a => a.contents.trim())
|
|
185
256
|
.map(a => ({
|
|
@@ -193,10 +264,10 @@ export function annotationsToComments(annotations) {
|
|
|
193
264
|
|
|
194
265
|
/**
|
|
195
266
|
* Extract comments from PDF and format for display
|
|
196
|
-
* @param
|
|
197
|
-
* @returns
|
|
267
|
+
* @param pdfPath - Path to PDF file
|
|
268
|
+
* @returns Array of PDF comments
|
|
198
269
|
*/
|
|
199
|
-
export async function extractPdfComments(pdfPath) {
|
|
270
|
+
export async function extractPdfComments(pdfPath: string): Promise<PdfComment[]> {
|
|
200
271
|
const annotations = await extractPdfAnnotations(pdfPath);
|
|
201
272
|
return annotationsToComments(annotations);
|
|
202
273
|
}
|
|
@@ -206,32 +277,36 @@ export async function extractPdfComments(pdfPath) {
|
|
|
206
277
|
* Since PDFs don't have direct text anchors like Word, we use page numbers
|
|
207
278
|
* and append comments to the end of corresponding sections
|
|
208
279
|
*
|
|
209
|
-
* @param
|
|
210
|
-
* @param
|
|
211
|
-
* @param
|
|
212
|
-
* @returns
|
|
280
|
+
* @param markdown - The markdown content
|
|
281
|
+
* @param comments - Comments from extractPdfComments
|
|
282
|
+
* @param options - { sectionPerPage: boolean }
|
|
283
|
+
* @returns Markdown with comments inserted
|
|
213
284
|
*/
|
|
214
|
-
export function insertPdfCommentsIntoMarkdown(
|
|
285
|
+
export function insertPdfCommentsIntoMarkdown(
|
|
286
|
+
markdown: string,
|
|
287
|
+
comments: PdfComment[],
|
|
288
|
+
options: InsertOptions = {}
|
|
289
|
+
): string {
|
|
215
290
|
if (comments.length === 0) return markdown;
|
|
216
291
|
|
|
217
292
|
// Group comments by page
|
|
218
|
-
const commentsByPage = new Map();
|
|
293
|
+
const commentsByPage = new Map<number, PdfComment[]>();
|
|
219
294
|
for (const c of comments) {
|
|
220
295
|
if (!commentsByPage.has(c.page)) {
|
|
221
296
|
commentsByPage.set(c.page, []);
|
|
222
297
|
}
|
|
223
|
-
commentsByPage.get(c.page)
|
|
298
|
+
commentsByPage.get(c.page)!.push(c);
|
|
224
299
|
}
|
|
225
300
|
|
|
226
301
|
// Strategy: Append all comments at the end with page references
|
|
227
302
|
// This is the safest approach since we can't reliably map PDF positions to markdown
|
|
228
303
|
const lines = markdown.split('\n');
|
|
229
|
-
const commentBlock = [];
|
|
304
|
+
const commentBlock: string[] = [];
|
|
230
305
|
|
|
231
306
|
commentBlock.push('');
|
|
232
307
|
commentBlock.push('<!-- PDF Comments -->');
|
|
233
308
|
|
|
234
|
-
for (const [page, pageComments] of commentsByPage) {
|
|
309
|
+
for (const [page, pageComments] of Array.from(commentsByPage.entries())) {
|
|
235
310
|
for (const c of pageComments) {
|
|
236
311
|
const authorPrefix = c.author ? `${c.author}: ` : '';
|
|
237
312
|
const pageRef = `[p.${page}]`;
|
|
@@ -244,15 +319,15 @@ export function insertPdfCommentsIntoMarkdown(markdown, comments, options = {})
|
|
|
244
319
|
|
|
245
320
|
/**
|
|
246
321
|
* Format PDF comments for CLI display
|
|
247
|
-
* @param
|
|
248
|
-
* @returns
|
|
322
|
+
* @param comments - Array of PDF comments
|
|
323
|
+
* @returns Formatted string
|
|
249
324
|
*/
|
|
250
|
-
export function formatPdfComments(comments) {
|
|
325
|
+
export function formatPdfComments(comments: PdfComment[]): string {
|
|
251
326
|
if (comments.length === 0) {
|
|
252
327
|
return 'No comments found in PDF.';
|
|
253
328
|
}
|
|
254
329
|
|
|
255
|
-
const lines = [];
|
|
330
|
+
const lines: string[] = [];
|
|
256
331
|
let currentPage = 0;
|
|
257
332
|
|
|
258
333
|
for (const c of comments) {
|
|
@@ -272,10 +347,10 @@ export function formatPdfComments(comments) {
|
|
|
272
347
|
|
|
273
348
|
/**
|
|
274
349
|
* Get icon for annotation type
|
|
275
|
-
* @param
|
|
276
|
-
* @returns
|
|
350
|
+
* @param type - Annotation type
|
|
351
|
+
* @returns Icon string
|
|
277
352
|
*/
|
|
278
|
-
function getTypeIcon(type) {
|
|
353
|
+
function getTypeIcon(type: string): string {
|
|
279
354
|
switch (type) {
|
|
280
355
|
case 'Text': return '📝'; // Sticky note
|
|
281
356
|
case 'FreeText': return '💬'; // Text box
|
|
@@ -289,11 +364,11 @@ function getTypeIcon(type) {
|
|
|
289
364
|
|
|
290
365
|
/**
|
|
291
366
|
* Get statistics about PDF comments
|
|
292
|
-
* @param
|
|
293
|
-
* @returns
|
|
367
|
+
* @param comments - Array of PDF comments
|
|
368
|
+
* @returns Statistics object
|
|
294
369
|
*/
|
|
295
|
-
export function getPdfCommentStats(comments) {
|
|
296
|
-
const stats = {
|
|
370
|
+
export function getPdfCommentStats(comments: PdfComment[]): PdfCommentStats {
|
|
371
|
+
const stats: PdfCommentStats = {
|
|
297
372
|
total: comments.length,
|
|
298
373
|
byType: {},
|
|
299
374
|
byAuthor: {},
|
|
@@ -311,12 +386,12 @@ export function getPdfCommentStats(comments) {
|
|
|
311
386
|
|
|
312
387
|
/**
|
|
313
388
|
* Extract text content from a PDF page
|
|
314
|
-
* @param
|
|
315
|
-
* @returns
|
|
389
|
+
* @param page - pdfjs page object
|
|
390
|
+
* @returns Array of text items with positions
|
|
316
391
|
*/
|
|
317
|
-
async function getPageTextItems(page) {
|
|
392
|
+
async function getPageTextItems(page: any): Promise<PdfTextItem[]> {
|
|
318
393
|
const textContent = await page.getTextContent();
|
|
319
|
-
return textContent.items.map(item => ({
|
|
394
|
+
return textContent.items.map((item: any) => ({
|
|
320
395
|
str: item.str,
|
|
321
396
|
x: item.transform[4],
|
|
322
397
|
y: item.transform[5],
|
|
@@ -328,12 +403,12 @@ async function getPageTextItems(page) {
|
|
|
328
403
|
/**
|
|
329
404
|
* Check if a point is inside a quadrilateral defined by QuadPoints
|
|
330
405
|
* QuadPoints format: [x1,y1, x2,y2, x3,y3, x4,y4] for each quad
|
|
331
|
-
* @param
|
|
332
|
-
* @param
|
|
333
|
-
* @param
|
|
334
|
-
* @returns
|
|
406
|
+
* @param x - X coordinate
|
|
407
|
+
* @param y - Y coordinate
|
|
408
|
+
* @param quad - 8 numbers defining corners
|
|
409
|
+
* @returns True if point is inside quad
|
|
335
410
|
*/
|
|
336
|
-
function isPointInQuad(x, y, quad) {
|
|
411
|
+
function isPointInQuad(x: number, y: number, quad: number[]): boolean {
|
|
337
412
|
if (quad.length < 8) return false;
|
|
338
413
|
|
|
339
414
|
// Get bounding box from quad points
|
|
@@ -349,11 +424,14 @@ function isPointInQuad(x, y, quad) {
|
|
|
349
424
|
|
|
350
425
|
/**
|
|
351
426
|
* Extract highlighted text from a PDF using QuadPoints
|
|
352
|
-
* @param
|
|
353
|
-
* @param
|
|
354
|
-
* @returns
|
|
427
|
+
* @param pdfPath - Path to PDF file
|
|
428
|
+
* @param annotations - Annotations with quadPoints from extractPdfAnnotations
|
|
429
|
+
* @returns Annotations with highlighted text extracted
|
|
355
430
|
*/
|
|
356
|
-
export async function extractHighlightedText(
|
|
431
|
+
export async function extractHighlightedText(
|
|
432
|
+
pdfPath: string,
|
|
433
|
+
annotations: PdfAnnotation[]
|
|
434
|
+
): Promise<PdfAnnotationWithText[]> {
|
|
357
435
|
const pdfBytes = fs.readFileSync(pdfPath);
|
|
358
436
|
const data = new Uint8Array(pdfBytes);
|
|
359
437
|
|
|
@@ -362,7 +440,7 @@ export async function extractHighlightedText(pdfPath, annotations) {
|
|
|
362
440
|
const loadingTask = getDocument({ data, useSystemFonts: true });
|
|
363
441
|
const pdfDoc = await loadingTask.promise;
|
|
364
442
|
|
|
365
|
-
const results = [];
|
|
443
|
+
const results: PdfAnnotationWithText[] = [];
|
|
366
444
|
|
|
367
445
|
for (const annot of annotations) {
|
|
368
446
|
// Only process text markup annotations (Highlight, Underline, StrikeOut, Squiggly)
|
|
@@ -381,13 +459,13 @@ export async function extractHighlightedText(pdfPath, annotations) {
|
|
|
381
459
|
const textItems = await getPageTextItems(page);
|
|
382
460
|
|
|
383
461
|
// Split quadPoints into individual quads (8 numbers each)
|
|
384
|
-
const quads = [];
|
|
462
|
+
const quads: number[][] = [];
|
|
385
463
|
for (let i = 0; i < annot.quadPoints.length; i += 8) {
|
|
386
464
|
quads.push(annot.quadPoints.slice(i, i + 8));
|
|
387
465
|
}
|
|
388
466
|
|
|
389
467
|
// Find text items that fall within any of the quads
|
|
390
|
-
const matchedText = [];
|
|
468
|
+
const matchedText: string[] = [];
|
|
391
469
|
for (const item of textItems) {
|
|
392
470
|
// Check if text item center is in any quad
|
|
393
471
|
const centerX = item.x + (item.width || 0) / 2;
|
|
@@ -416,23 +494,23 @@ export async function extractHighlightedText(pdfPath, annotations) {
|
|
|
416
494
|
|
|
417
495
|
/**
|
|
418
496
|
* Extract annotations with highlighted text in one call
|
|
419
|
-
* @param
|
|
420
|
-
* @returns
|
|
497
|
+
* @param pdfPath - Path to PDF file
|
|
498
|
+
* @returns Annotations with highlighted text
|
|
421
499
|
*/
|
|
422
|
-
export async function extractPdfAnnotationsWithText(pdfPath) {
|
|
500
|
+
export async function extractPdfAnnotationsWithText(pdfPath: string): Promise<PdfAnnotationWithText[]> {
|
|
423
501
|
const annotations = await extractPdfAnnotations(pdfPath);
|
|
424
502
|
return extractHighlightedText(pdfPath, annotations);
|
|
425
503
|
}
|
|
426
504
|
|
|
427
505
|
/**
|
|
428
506
|
* Format annotation with highlighted text for display
|
|
429
|
-
* @param
|
|
430
|
-
* @returns
|
|
507
|
+
* @param annot - Annotation with highlightedText
|
|
508
|
+
* @returns Formatted string
|
|
431
509
|
*/
|
|
432
|
-
export function formatAnnotationWithText(annot) {
|
|
510
|
+
export function formatAnnotationWithText(annot: PdfAnnotationWithText): string {
|
|
433
511
|
const typeIcon = getTypeIcon(annot.type);
|
|
434
512
|
const author = annot.author || 'Unknown';
|
|
435
|
-
const parts = [`${typeIcon} [${author}]`];
|
|
513
|
+
const parts: string[] = [`${typeIcon} [${author}]`];
|
|
436
514
|
|
|
437
515
|
if (annot.highlightedText) {
|
|
438
516
|
parts.push(`"${annot.highlightedText}"`);
|