docrev 0.9.18 → 0.10.1

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.
Files changed (134) hide show
  1. package/.gitattributes +1 -1
  2. package/CHANGELOG.md +173 -149
  3. package/PLAN-tables-and-postprocess.md +850 -850
  4. package/README.md +431 -406
  5. package/bin/rev.js +11 -11
  6. package/bin/rev.ts +145 -145
  7. package/completions/rev.bash +127 -127
  8. package/completions/rev.ps1 +210 -210
  9. package/completions/rev.zsh +207 -207
  10. package/dist/lib/build.d.ts +8 -0
  11. package/dist/lib/build.d.ts.map +1 -1
  12. package/dist/lib/build.js +62 -6
  13. package/dist/lib/build.js.map +1 -1
  14. package/dist/lib/commands/context.d.ts +1 -1
  15. package/dist/lib/commands/context.d.ts.map +1 -1
  16. package/dist/lib/commands/context.js +1 -1
  17. package/dist/lib/commands/context.js.map +1 -1
  18. package/dist/lib/commands/sections.js +7 -7
  19. package/dist/lib/commands/sections.js.map +1 -1
  20. package/dist/lib/commands/sync.d.ts.map +1 -1
  21. package/dist/lib/commands/sync.js +15 -14
  22. package/dist/lib/commands/sync.js.map +1 -1
  23. package/dist/lib/commands/utilities.js +164 -164
  24. package/dist/lib/commands/verify-anchors.js +6 -6
  25. package/dist/lib/commands/verify-anchors.js.map +1 -1
  26. package/dist/lib/commands/word-tools.js +8 -8
  27. package/dist/lib/grammar.js +3 -3
  28. package/dist/lib/macro-filter.lua +201 -0
  29. package/dist/lib/macros.d.ts +102 -0
  30. package/dist/lib/macros.d.ts.map +1 -0
  31. package/dist/lib/macros.js +218 -0
  32. package/dist/lib/macros.js.map +1 -0
  33. package/dist/lib/pdf-comments.js +44 -44
  34. package/dist/lib/plugins.js +57 -57
  35. package/dist/lib/pptx-color-filter.lua +37 -0
  36. package/dist/lib/pptx-themes.js +115 -115
  37. package/dist/lib/schema.d.ts.map +1 -1
  38. package/dist/lib/schema.js +34 -0
  39. package/dist/lib/schema.js.map +1 -1
  40. package/dist/lib/sections.d.ts +35 -0
  41. package/dist/lib/sections.d.ts.map +1 -1
  42. package/dist/lib/sections.js +81 -0
  43. package/dist/lib/sections.js.map +1 -1
  44. package/dist/lib/spelling.js +2 -2
  45. package/dist/lib/templates.js +387 -387
  46. package/dist/lib/themes.js +51 -51
  47. package/eslint.config.js +27 -27
  48. package/lib/anchor-match.ts +276 -276
  49. package/lib/annotations.ts +644 -644
  50. package/lib/build.ts +1766 -1694
  51. package/lib/citations.ts +160 -160
  52. package/lib/commands/build.ts +855 -855
  53. package/lib/commands/citations.ts +515 -515
  54. package/lib/commands/comments.ts +1050 -1050
  55. package/lib/commands/context.ts +176 -174
  56. package/lib/commands/core.ts +309 -309
  57. package/lib/commands/doi.ts +435 -435
  58. package/lib/commands/file-ops.ts +372 -372
  59. package/lib/commands/history.ts +320 -320
  60. package/lib/commands/index.ts +87 -87
  61. package/lib/commands/init.ts +259 -259
  62. package/lib/commands/merge-resolve.ts +378 -378
  63. package/lib/commands/preview.ts +178 -178
  64. package/lib/commands/project-info.ts +244 -244
  65. package/lib/commands/quality.ts +517 -517
  66. package/lib/commands/response.ts +454 -454
  67. package/lib/commands/section-boundaries.ts +82 -82
  68. package/lib/commands/sections.ts +451 -451
  69. package/lib/commands/sync.ts +709 -706
  70. package/lib/commands/text-ops.ts +449 -449
  71. package/lib/commands/utilities.ts +448 -448
  72. package/lib/commands/verify-anchors.ts +272 -272
  73. package/lib/commands/word-tools.ts +340 -340
  74. package/lib/comment-realign.ts +517 -517
  75. package/lib/config.ts +84 -84
  76. package/lib/crossref.ts +781 -781
  77. package/lib/csl.ts +191 -191
  78. package/lib/dependencies.ts +98 -98
  79. package/lib/diff-engine.ts +465 -465
  80. package/lib/doi-cache.ts +115 -115
  81. package/lib/doi.ts +897 -897
  82. package/lib/equations.ts +506 -506
  83. package/lib/errors.ts +346 -346
  84. package/lib/format.ts +541 -541
  85. package/lib/git.ts +326 -326
  86. package/lib/grammar.ts +303 -303
  87. package/lib/image-registry.ts +180 -180
  88. package/lib/import.ts +911 -911
  89. package/lib/journals.ts +543 -543
  90. package/lib/macro-filter.lua +201 -0
  91. package/lib/macros.ts +273 -0
  92. package/lib/merge.ts +633 -633
  93. package/lib/orcid.ts +144 -144
  94. package/lib/pdf-comments.ts +263 -263
  95. package/lib/pdf-import.ts +524 -524
  96. package/lib/plugins.ts +362 -362
  97. package/lib/postprocess.ts +188 -188
  98. package/lib/pptx-color-filter.lua +37 -37
  99. package/lib/pptx-template.ts +469 -469
  100. package/lib/pptx-themes.ts +483 -483
  101. package/lib/protect-restore.ts +520 -520
  102. package/lib/rate-limiter.ts +94 -94
  103. package/lib/response.ts +197 -197
  104. package/lib/restore-references.ts +240 -240
  105. package/lib/review.ts +327 -327
  106. package/lib/schema.ts +488 -454
  107. package/lib/scientific-words.ts +73 -73
  108. package/lib/sections.ts +425 -335
  109. package/lib/slides.ts +756 -756
  110. package/lib/spelling.ts +334 -334
  111. package/lib/templates.ts +526 -526
  112. package/lib/themes.ts +742 -742
  113. package/lib/trackchanges.ts +247 -247
  114. package/lib/tui.ts +450 -450
  115. package/lib/types.ts +550 -550
  116. package/lib/undo.ts +250 -250
  117. package/lib/utils.ts +69 -69
  118. package/lib/variables.ts +179 -179
  119. package/lib/word-extraction.ts +806 -806
  120. package/lib/word.ts +643 -643
  121. package/lib/wordcomments.ts +840 -840
  122. package/package.json +137 -137
  123. package/scripts/postbuild.js +47 -28
  124. package/skill/REFERENCE.md +539 -539
  125. package/skill/SKILL.md +295 -295
  126. package/tsconfig.json +26 -26
  127. package/types/index.d.ts +525 -525
  128. package/issues.md +0 -180
  129. package/site/assets/extra.css +0 -208
  130. package/site/commands.html +0 -926
  131. package/site/configuration.html +0 -469
  132. package/site/index.html +0 -288
  133. package/site/troubleshooting.html +0 -461
  134. package/site/workflow.html +0 -518
@@ -1,263 +1,263 @@
1
- /**
2
- * PDF comment rendering for dual export
3
- *
4
- * Converts CriticMarkup comments to LaTeX margin notes for PDF output
5
- */
6
-
7
- import { escapeLatex } from './utils.js';
8
-
9
- /**
10
- * LaTeX preamble for margin comments
11
- * Uses todonotes package with custom styling
12
- */
13
- export const MARGIN_NOTES_PREAMBLE = `
14
- % Margin notes for comments
15
- \\usepackage[colorinlistoftodos,textsize=scriptsize]{todonotes}
16
- \\usepackage{xcolor}
17
-
18
- % Define comment colors by author
19
- \\definecolor{commentblue}{RGB}{59, 130, 246}
20
- \\definecolor{commentgreen}{RGB}{34, 197, 94}
21
- \\definecolor{commentorange}{RGB}{249, 115, 22}
22
- \\definecolor{commentpurple}{RGB}{168, 85, 247}
23
- \\definecolor{commentgray}{RGB}{107, 114, 128}
24
-
25
- % Custom margin note command
26
- \\newcommand{\\margincomment}[2][]{%
27
- \\todo[linecolor=commentblue,backgroundcolor=commentblue!10,bordercolor=commentblue,size=\\scriptsize,#1]{#2}%
28
- }
29
-
30
- % Author-specific commands
31
- \\newcommand{\\reviewercomment}[2]{%
32
- \\todo[linecolor=commentgreen,backgroundcolor=commentgreen!10,bordercolor=commentgreen,size=\\scriptsize]{\\textbf{#1:} #2}%
33
- }
34
-
35
- % Increase margin for notes (if needed)
36
- % \\setlength{\\marginparwidth}{2.5cm}
37
- `;
38
-
39
- /**
40
- * Simpler preamble using marginpar (no extra packages needed)
41
- */
42
- export const SIMPLE_MARGIN_PREAMBLE = `
43
- % Simple margin notes for comments
44
- \\usepackage{xcolor}
45
- \\definecolor{commentcolor}{RGB}{59, 130, 246}
46
-
47
- \\newcommand{\\margincomment}[1]{%
48
- \\marginpar{\\raggedright\\scriptsize\\textcolor{commentcolor}{#1}}%
49
- }
50
- `;
51
-
52
- /**
53
- * Options for converting comments to margin notes
54
- */
55
- export interface CommentConversionOptions {
56
- useTodonotes?: boolean;
57
- stripResolved?: boolean;
58
- }
59
-
60
- /**
61
- * Result of comment conversion
62
- */
63
- export interface CommentConversionResult {
64
- markdown: string;
65
- commentCount: number;
66
- preamble: string;
67
- }
68
-
69
- /**
70
- * Convert CriticMarkup comments to LaTeX margin notes
71
- * {>>Author: comment text<<} -> \margincomment{Author: comment text}
72
- *
73
- * @param markdown - Markdown with CriticMarkup comments
74
- * @param options - { useTodonotes: boolean, stripResolved: boolean }
75
- * @returns Converted markdown with comment count and preamble
76
- */
77
- export function convertCommentsToMarginNotes(
78
- markdown: string,
79
- options: CommentConversionOptions = {}
80
- ): CommentConversionResult {
81
- const { useTodonotes = true, stripResolved = true } = options;
82
-
83
- let commentCount = 0;
84
-
85
- // Pattern for CriticMarkup comments: {>>author: text<<} or {>>text<<}
86
- // Also handle resolved comments: {>>✓ author: text<<}
87
- const commentPattern = /\{>>(✓\s*)?([^<]+)<<\}/g;
88
-
89
- const converted = markdown.replace(commentPattern, (match, resolved, content) => {
90
- // Skip resolved comments if requested
91
- if (resolved && stripResolved) {
92
- return '';
93
- }
94
-
95
- commentCount++;
96
-
97
- // Escape LaTeX special characters
98
- const escaped = escapeLatex(content.trim());
99
-
100
- if (useTodonotes) {
101
- // Check if content has author prefix (Author: text)
102
- const authorMatch = escaped.match(/^([^:]+):\s*([\s\S]+)$/);
103
- if (authorMatch) {
104
- const [, author, text] = authorMatch;
105
- return `\\reviewercomment{${author}}{${text}}`;
106
- }
107
- return `\\margincomment{${escaped}}`;
108
- } else {
109
- return `\\margincomment{${escaped}}`;
110
- }
111
- });
112
-
113
- const preamble = useTodonotes ? MARGIN_NOTES_PREAMBLE : SIMPLE_MARGIN_PREAMBLE;
114
-
115
- return {
116
- markdown: converted,
117
- commentCount,
118
- preamble,
119
- };
120
- }
121
-
122
- /**
123
- * Result of track changes conversion
124
- */
125
- export interface TrackChangesResult {
126
- markdown: string;
127
- preamble: string;
128
- }
129
-
130
- /**
131
- * Convert track changes to visible LaTeX formatting
132
- * {++inserted++} -> \textcolor{green}{inserted}
133
- * {--deleted--} -> \textcolor{red}{\sout{deleted}}
134
- * {~~old~>new~~} -> \textcolor{red}{\sout{old}}\textcolor{green}{new}
135
- *
136
- * @param markdown - Markdown with track changes
137
- * @returns Converted markdown and preamble
138
- */
139
- export function convertTrackChangesToLatex(markdown: string): TrackChangesResult {
140
- let result = markdown;
141
-
142
- // Insertions: {++text++} -> green text
143
- result = result.replace(/\{\+\+([^+]+)\+\+\}/g, (match, text) => {
144
- return `\\textcolor{green}{${escapeLatex(text)}}`;
145
- });
146
-
147
- // Deletions: {--text--} -> red strikethrough
148
- result = result.replace(/\{--([^-]+)--\}/g, (match, text) => {
149
- return `\\textcolor{red}{\\sout{${escapeLatex(text)}}}`;
150
- });
151
-
152
- // Substitutions: {~~old~>new~~} -> red strikethrough + green new
153
- result = result.replace(/\{~~([^~]+)~>([^~]+)~~\}/g, (match, oldText, newText) => {
154
- return `\\textcolor{red}{\\sout{${escapeLatex(oldText)}}}\\textcolor{green}{${escapeLatex(newText)}}`;
155
- });
156
-
157
- const preamble = `
158
- % Track changes visualization
159
- \\usepackage{xcolor}
160
- \\usepackage[normalem]{ulem}
161
- \\definecolor{green}{RGB}{34, 197, 94}
162
- \\definecolor{red}{RGB}{239, 68, 68}
163
- `;
164
-
165
- return { markdown: result, preamble };
166
- }
167
-
168
- /**
169
- * Options for combined preamble
170
- */
171
- export interface PreambleOptions {
172
- comments?: boolean;
173
- trackChanges?: boolean;
174
- useTodonotes?: boolean;
175
- }
176
-
177
- /**
178
- * Get combined preamble for comments and track changes
179
- * @param options - { comments: boolean, trackChanges: boolean, useTodonotes: boolean }
180
- * @returns Combined LaTeX preamble
181
- */
182
- export function getCombinedPreamble(options: PreambleOptions = {}): string {
183
- const { comments = true, trackChanges = false, useTodonotes = true } = options;
184
-
185
- let preamble = '';
186
-
187
- if (comments) {
188
- preamble += useTodonotes ? MARGIN_NOTES_PREAMBLE : SIMPLE_MARGIN_PREAMBLE;
189
- }
190
-
191
- if (trackChanges) {
192
- preamble += `
193
- % Track changes visualization
194
- \\usepackage[normalem]{ulem}
195
- `;
196
- if (!comments) {
197
- preamble += `\\usepackage{xcolor}\n`;
198
- }
199
- preamble += `
200
- \\definecolor{insertgreen}{RGB}{34, 197, 94}
201
- \\definecolor{deletered}{RGB}{239, 68, 68}
202
- `;
203
- }
204
-
205
- return preamble;
206
- }
207
-
208
- /**
209
- * Options for preparing markdown for annotated PDF
210
- */
211
- export interface AnnotatedPdfOptions {
212
- showTrackChanges?: boolean;
213
- useTodonotes?: boolean;
214
- stripResolved?: boolean;
215
- }
216
-
217
- /**
218
- * Result of preparing markdown for annotated PDF
219
- */
220
- export interface AnnotatedPdfResult {
221
- markdown: string;
222
- preamble: string;
223
- commentCount: number;
224
- }
225
-
226
- /**
227
- * Prepare markdown for PDF with visible comments
228
- * Converts comments to margin notes and optionally shows track changes
229
- *
230
- * @param markdown - Markdown content
231
- * @param options - { showTrackChanges: boolean, useTodonotes: boolean }
232
- * @returns Converted markdown with preamble and comment count
233
- */
234
- export function prepareMarkdownForAnnotatedPdf(
235
- markdown: string,
236
- options: AnnotatedPdfOptions = {}
237
- ): AnnotatedPdfResult {
238
- const { showTrackChanges = false, useTodonotes = true, stripResolved = true } = options;
239
-
240
- let result = markdown;
241
- let preamble = '';
242
- let commentCount = 0;
243
-
244
- // Convert comments to margin notes
245
- const commentResult = convertCommentsToMarginNotes(result, { useTodonotes, stripResolved });
246
- result = commentResult.markdown;
247
- commentCount = commentResult.commentCount;
248
- preamble += commentResult.preamble;
249
-
250
- // Optionally show track changes
251
- if (showTrackChanges) {
252
- const trackResult = convertTrackChangesToLatex(result);
253
- result = trackResult.markdown;
254
- // Add ulem package if not already in todonotes preamble
255
- if (!useTodonotes) {
256
- preamble += trackResult.preamble;
257
- } else {
258
- preamble += `\\usepackage[normalem]{ulem}\n`;
259
- }
260
- }
261
-
262
- return { markdown: result, preamble, commentCount };
263
- }
1
+ /**
2
+ * PDF comment rendering for dual export
3
+ *
4
+ * Converts CriticMarkup comments to LaTeX margin notes for PDF output
5
+ */
6
+
7
+ import { escapeLatex } from './utils.js';
8
+
9
+ /**
10
+ * LaTeX preamble for margin comments
11
+ * Uses todonotes package with custom styling
12
+ */
13
+ export const MARGIN_NOTES_PREAMBLE = `
14
+ % Margin notes for comments
15
+ \\usepackage[colorinlistoftodos,textsize=scriptsize]{todonotes}
16
+ \\usepackage{xcolor}
17
+
18
+ % Define comment colors by author
19
+ \\definecolor{commentblue}{RGB}{59, 130, 246}
20
+ \\definecolor{commentgreen}{RGB}{34, 197, 94}
21
+ \\definecolor{commentorange}{RGB}{249, 115, 22}
22
+ \\definecolor{commentpurple}{RGB}{168, 85, 247}
23
+ \\definecolor{commentgray}{RGB}{107, 114, 128}
24
+
25
+ % Custom margin note command
26
+ \\newcommand{\\margincomment}[2][]{%
27
+ \\todo[linecolor=commentblue,backgroundcolor=commentblue!10,bordercolor=commentblue,size=\\scriptsize,#1]{#2}%
28
+ }
29
+
30
+ % Author-specific commands
31
+ \\newcommand{\\reviewercomment}[2]{%
32
+ \\todo[linecolor=commentgreen,backgroundcolor=commentgreen!10,bordercolor=commentgreen,size=\\scriptsize]{\\textbf{#1:} #2}%
33
+ }
34
+
35
+ % Increase margin for notes (if needed)
36
+ % \\setlength{\\marginparwidth}{2.5cm}
37
+ `;
38
+
39
+ /**
40
+ * Simpler preamble using marginpar (no extra packages needed)
41
+ */
42
+ export const SIMPLE_MARGIN_PREAMBLE = `
43
+ % Simple margin notes for comments
44
+ \\usepackage{xcolor}
45
+ \\definecolor{commentcolor}{RGB}{59, 130, 246}
46
+
47
+ \\newcommand{\\margincomment}[1]{%
48
+ \\marginpar{\\raggedright\\scriptsize\\textcolor{commentcolor}{#1}}%
49
+ }
50
+ `;
51
+
52
+ /**
53
+ * Options for converting comments to margin notes
54
+ */
55
+ export interface CommentConversionOptions {
56
+ useTodonotes?: boolean;
57
+ stripResolved?: boolean;
58
+ }
59
+
60
+ /**
61
+ * Result of comment conversion
62
+ */
63
+ export interface CommentConversionResult {
64
+ markdown: string;
65
+ commentCount: number;
66
+ preamble: string;
67
+ }
68
+
69
+ /**
70
+ * Convert CriticMarkup comments to LaTeX margin notes
71
+ * {>>Author: comment text<<} -> \margincomment{Author: comment text}
72
+ *
73
+ * @param markdown - Markdown with CriticMarkup comments
74
+ * @param options - { useTodonotes: boolean, stripResolved: boolean }
75
+ * @returns Converted markdown with comment count and preamble
76
+ */
77
+ export function convertCommentsToMarginNotes(
78
+ markdown: string,
79
+ options: CommentConversionOptions = {}
80
+ ): CommentConversionResult {
81
+ const { useTodonotes = true, stripResolved = true } = options;
82
+
83
+ let commentCount = 0;
84
+
85
+ // Pattern for CriticMarkup comments: {>>author: text<<} or {>>text<<}
86
+ // Also handle resolved comments: {>>✓ author: text<<}
87
+ const commentPattern = /\{>>(✓\s*)?([^<]+)<<\}/g;
88
+
89
+ const converted = markdown.replace(commentPattern, (match, resolved, content) => {
90
+ // Skip resolved comments if requested
91
+ if (resolved && stripResolved) {
92
+ return '';
93
+ }
94
+
95
+ commentCount++;
96
+
97
+ // Escape LaTeX special characters
98
+ const escaped = escapeLatex(content.trim());
99
+
100
+ if (useTodonotes) {
101
+ // Check if content has author prefix (Author: text)
102
+ const authorMatch = escaped.match(/^([^:]+):\s*([\s\S]+)$/);
103
+ if (authorMatch) {
104
+ const [, author, text] = authorMatch;
105
+ return `\\reviewercomment{${author}}{${text}}`;
106
+ }
107
+ return `\\margincomment{${escaped}}`;
108
+ } else {
109
+ return `\\margincomment{${escaped}}`;
110
+ }
111
+ });
112
+
113
+ const preamble = useTodonotes ? MARGIN_NOTES_PREAMBLE : SIMPLE_MARGIN_PREAMBLE;
114
+
115
+ return {
116
+ markdown: converted,
117
+ commentCount,
118
+ preamble,
119
+ };
120
+ }
121
+
122
+ /**
123
+ * Result of track changes conversion
124
+ */
125
+ export interface TrackChangesResult {
126
+ markdown: string;
127
+ preamble: string;
128
+ }
129
+
130
+ /**
131
+ * Convert track changes to visible LaTeX formatting
132
+ * {++inserted++} -> \textcolor{green}{inserted}
133
+ * {--deleted--} -> \textcolor{red}{\sout{deleted}}
134
+ * {~~old~>new~~} -> \textcolor{red}{\sout{old}}\textcolor{green}{new}
135
+ *
136
+ * @param markdown - Markdown with track changes
137
+ * @returns Converted markdown and preamble
138
+ */
139
+ export function convertTrackChangesToLatex(markdown: string): TrackChangesResult {
140
+ let result = markdown;
141
+
142
+ // Insertions: {++text++} -> green text
143
+ result = result.replace(/\{\+\+([^+]+)\+\+\}/g, (match, text) => {
144
+ return `\\textcolor{green}{${escapeLatex(text)}}`;
145
+ });
146
+
147
+ // Deletions: {--text--} -> red strikethrough
148
+ result = result.replace(/\{--([^-]+)--\}/g, (match, text) => {
149
+ return `\\textcolor{red}{\\sout{${escapeLatex(text)}}}`;
150
+ });
151
+
152
+ // Substitutions: {~~old~>new~~} -> red strikethrough + green new
153
+ result = result.replace(/\{~~([^~]+)~>([^~]+)~~\}/g, (match, oldText, newText) => {
154
+ return `\\textcolor{red}{\\sout{${escapeLatex(oldText)}}}\\textcolor{green}{${escapeLatex(newText)}}`;
155
+ });
156
+
157
+ const preamble = `
158
+ % Track changes visualization
159
+ \\usepackage{xcolor}
160
+ \\usepackage[normalem]{ulem}
161
+ \\definecolor{green}{RGB}{34, 197, 94}
162
+ \\definecolor{red}{RGB}{239, 68, 68}
163
+ `;
164
+
165
+ return { markdown: result, preamble };
166
+ }
167
+
168
+ /**
169
+ * Options for combined preamble
170
+ */
171
+ export interface PreambleOptions {
172
+ comments?: boolean;
173
+ trackChanges?: boolean;
174
+ useTodonotes?: boolean;
175
+ }
176
+
177
+ /**
178
+ * Get combined preamble for comments and track changes
179
+ * @param options - { comments: boolean, trackChanges: boolean, useTodonotes: boolean }
180
+ * @returns Combined LaTeX preamble
181
+ */
182
+ export function getCombinedPreamble(options: PreambleOptions = {}): string {
183
+ const { comments = true, trackChanges = false, useTodonotes = true } = options;
184
+
185
+ let preamble = '';
186
+
187
+ if (comments) {
188
+ preamble += useTodonotes ? MARGIN_NOTES_PREAMBLE : SIMPLE_MARGIN_PREAMBLE;
189
+ }
190
+
191
+ if (trackChanges) {
192
+ preamble += `
193
+ % Track changes visualization
194
+ \\usepackage[normalem]{ulem}
195
+ `;
196
+ if (!comments) {
197
+ preamble += `\\usepackage{xcolor}\n`;
198
+ }
199
+ preamble += `
200
+ \\definecolor{insertgreen}{RGB}{34, 197, 94}
201
+ \\definecolor{deletered}{RGB}{239, 68, 68}
202
+ `;
203
+ }
204
+
205
+ return preamble;
206
+ }
207
+
208
+ /**
209
+ * Options for preparing markdown for annotated PDF
210
+ */
211
+ export interface AnnotatedPdfOptions {
212
+ showTrackChanges?: boolean;
213
+ useTodonotes?: boolean;
214
+ stripResolved?: boolean;
215
+ }
216
+
217
+ /**
218
+ * Result of preparing markdown for annotated PDF
219
+ */
220
+ export interface AnnotatedPdfResult {
221
+ markdown: string;
222
+ preamble: string;
223
+ commentCount: number;
224
+ }
225
+
226
+ /**
227
+ * Prepare markdown for PDF with visible comments
228
+ * Converts comments to margin notes and optionally shows track changes
229
+ *
230
+ * @param markdown - Markdown content
231
+ * @param options - { showTrackChanges: boolean, useTodonotes: boolean }
232
+ * @returns Converted markdown with preamble and comment count
233
+ */
234
+ export function prepareMarkdownForAnnotatedPdf(
235
+ markdown: string,
236
+ options: AnnotatedPdfOptions = {}
237
+ ): AnnotatedPdfResult {
238
+ const { showTrackChanges = false, useTodonotes = true, stripResolved = true } = options;
239
+
240
+ let result = markdown;
241
+ let preamble = '';
242
+ let commentCount = 0;
243
+
244
+ // Convert comments to margin notes
245
+ const commentResult = convertCommentsToMarginNotes(result, { useTodonotes, stripResolved });
246
+ result = commentResult.markdown;
247
+ commentCount = commentResult.commentCount;
248
+ preamble += commentResult.preamble;
249
+
250
+ // Optionally show track changes
251
+ if (showTrackChanges) {
252
+ const trackResult = convertTrackChangesToLatex(result);
253
+ result = trackResult.markdown;
254
+ // Add ulem package if not already in todonotes preamble
255
+ if (!useTodonotes) {
256
+ preamble += trackResult.preamble;
257
+ } else {
258
+ preamble += `\\usepackage[normalem]{ulem}\n`;
259
+ }
260
+ }
261
+
262
+ return { markdown: result, preamble, commentCount };
263
+ }