docrev 0.11.3 → 0.12.0
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/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/dist/bin/rev.js +29 -21
- package/dist/bin/rev.js.map +1 -1
- package/dist/lib/build.d.ts +43 -0
- package/dist/lib/build.d.ts.map +1 -1
- package/dist/lib/build.js +175 -5
- package/dist/lib/build.js.map +1 -1
- package/dist/lib/commands/build.d.ts.map +1 -1
- package/dist/lib/commands/build.js +39 -125
- package/dist/lib/commands/build.js.map +1 -1
- package/dist/lib/commands/comments.js +3 -3
- package/dist/lib/commands/comments.js.map +1 -1
- package/dist/lib/commands/context.d.ts +12 -1
- package/dist/lib/commands/context.d.ts.map +1 -1
- package/dist/lib/commands/context.js +34 -1
- package/dist/lib/commands/context.js.map +1 -1
- package/dist/lib/commands/merge-resolve.js +1 -1
- package/dist/lib/commands/merge-resolve.js.map +1 -1
- package/dist/lib/commands/quality.js +2 -2
- package/dist/lib/commands/quality.js.map +1 -1
- package/dist/lib/commands/sections.js +1 -1
- package/dist/lib/commands/sections.js.map +1 -1
- package/dist/lib/commands/text-ops.js +1 -1
- package/dist/lib/commands/text-ops.js.map +1 -1
- package/dist/lib/commands/utilities.d.ts.map +1 -1
- package/dist/lib/commands/utilities.js +5 -2
- package/dist/lib/commands/utilities.js.map +1 -1
- package/dist/lib/commands/word-tools.js +2 -2
- package/dist/lib/commands/word-tools.js.map +1 -1
- package/dist/lib/crossref.d.ts.map +1 -1
- package/dist/lib/crossref.js +12 -41
- package/dist/lib/crossref.js.map +1 -1
- package/dist/lib/csl.d.ts.map +1 -1
- package/dist/lib/csl.js +14 -22
- package/dist/lib/csl.js.map +1 -1
- package/dist/lib/diff-engine.js +1 -1
- package/dist/lib/diff-engine.js.map +1 -1
- package/dist/lib/equations.d.ts.map +1 -1
- package/dist/lib/equations.js +12 -3
- package/dist/lib/equations.js.map +1 -1
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +1 -30
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/image-registry.d.ts.map +1 -1
- package/dist/lib/image-registry.js +4 -0
- package/dist/lib/image-registry.js.map +1 -1
- package/dist/lib/import.d.ts +1 -1
- package/dist/lib/import.d.ts.map +1 -1
- package/dist/lib/import.js +1 -1
- package/dist/lib/import.js.map +1 -1
- package/dist/lib/input.d.ts +0 -11
- package/dist/lib/input.d.ts.map +1 -1
- package/dist/lib/input.js +0 -35
- package/dist/lib/input.js.map +1 -1
- package/dist/lib/merge.d.ts.map +1 -1
- package/dist/lib/merge.js +9 -1
- package/dist/lib/merge.js.map +1 -1
- package/dist/lib/ooxml.d.ts +22 -0
- package/dist/lib/ooxml.d.ts.map +1 -1
- package/dist/lib/ooxml.js +130 -0
- package/dist/lib/ooxml.js.map +1 -1
- package/dist/lib/orcid.d.ts.map +1 -1
- package/dist/lib/orcid.js +16 -7
- package/dist/lib/orcid.js.map +1 -1
- package/dist/lib/plugins.d.ts.map +1 -1
- package/dist/lib/plugins.js +8 -4
- package/dist/lib/plugins.js.map +1 -1
- package/dist/lib/protect-restore.d.ts.map +1 -1
- package/dist/lib/protect-restore.js +7 -5
- package/dist/lib/protect-restore.js.map +1 -1
- package/dist/lib/restore-references.d.ts.map +1 -1
- package/dist/lib/restore-references.js +25 -3
- package/dist/lib/restore-references.js.map +1 -1
- package/dist/lib/schema.d.ts.map +1 -1
- package/dist/lib/schema.js +1 -19
- package/dist/lib/schema.js.map +1 -1
- package/dist/lib/slides.js +1 -1
- package/dist/lib/slides.js.map +1 -1
- package/dist/lib/spelling.js +1 -1
- package/dist/lib/spelling.js.map +1 -1
- package/dist/lib/tui.js +0 -1
- package/dist/lib/tui.js.map +1 -1
- package/dist/lib/utils.d.ts +14 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +41 -0
- package/dist/lib/utils.js.map +1 -1
- package/dist/lib/word-extraction.d.ts +5 -5
- package/dist/lib/word-extraction.d.ts.map +1 -1
- package/dist/lib/word-extraction.js +25 -106
- package/dist/lib/word-extraction.js.map +1 -1
- package/dist/lib/word.d.ts +14 -38
- package/dist/lib/word.d.ts.map +1 -1
- package/dist/lib/word.js +24 -179
- package/dist/lib/word.js.map +1 -1
- package/dist/lib/wordcomments.d.ts.map +1 -1
- package/dist/lib/wordcomments.js +9 -7
- package/dist/lib/wordcomments.js.map +1 -1
- package/package.json +17 -6
- package/.gitattributes +0 -1
- package/PLAN-tables-and-postprocess.md +0 -850
- package/bin/rev.ts +0 -145
- package/docs-src/build.py +0 -113
- package/docs-src/extra.css +0 -208
- package/docs-src/md-to-html.lua +0 -6
- package/docs-src/template.html +0 -116
- package/eslint.config.js +0 -27
- package/lib/anchor-match.ts +0 -307
- package/lib/annotations.ts +0 -695
- package/lib/build.ts +0 -2047
- package/lib/citations.ts +0 -160
- package/lib/commands/build.ts +0 -885
- package/lib/commands/citations.ts +0 -515
- package/lib/commands/comments.ts +0 -1077
- package/lib/commands/context.ts +0 -185
- package/lib/commands/core.ts +0 -328
- package/lib/commands/doi.ts +0 -451
- package/lib/commands/file-ops.ts +0 -372
- package/lib/commands/history.ts +0 -320
- package/lib/commands/index.ts +0 -87
- package/lib/commands/init.ts +0 -259
- package/lib/commands/merge-resolve.ts +0 -378
- package/lib/commands/preview.ts +0 -178
- package/lib/commands/project-info.ts +0 -244
- package/lib/commands/quality.ts +0 -517
- package/lib/commands/response.ts +0 -454
- package/lib/commands/section-boundaries.ts +0 -82
- package/lib/commands/sections.ts +0 -451
- package/lib/commands/sync.ts +0 -689
- package/lib/commands/text-ops.ts +0 -449
- package/lib/commands/utilities.ts +0 -448
- package/lib/commands/verify-anchors.ts +0 -272
- package/lib/commands/word-tools.ts +0 -340
- package/lib/comment-realign.ts +0 -99
- package/lib/config.ts +0 -84
- package/lib/crossref.ts +0 -781
- package/lib/csl.ts +0 -191
- package/lib/dependencies.ts +0 -132
- package/lib/diff-engine.ts +0 -465
- package/lib/doi-cache.ts +0 -115
- package/lib/doi.ts +0 -879
- package/lib/equations.ts +0 -506
- package/lib/errors.ts +0 -350
- package/lib/format.ts +0 -541
- package/lib/git.ts +0 -326
- package/lib/grammar.ts +0 -303
- package/lib/image-registry.ts +0 -180
- package/lib/import.ts +0 -932
- package/lib/input.ts +0 -174
- package/lib/journals.ts +0 -543
- package/lib/macro-filter.lua +0 -201
- package/lib/macros.ts +0 -273
- package/lib/merge.ts +0 -633
- package/lib/ooxml.ts +0 -768
- package/lib/orcid.ts +0 -144
- package/lib/pdf-comments.ts +0 -263
- package/lib/pdf-import.ts +0 -524
- package/lib/plugins.ts +0 -362
- package/lib/postprocess.ts +0 -188
- package/lib/pptx-color-filter.lua +0 -37
- package/lib/pptx-template.ts +0 -469
- 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 +0 -483
- package/lib/protect-restore.ts +0 -520
- package/lib/rate-limiter.ts +0 -127
- package/lib/response.ts +0 -200
- package/lib/restore-references.ts +0 -240
- package/lib/review.ts +0 -327
- package/lib/schema.ts +0 -494
- package/lib/scientific-words.ts +0 -73
- package/lib/sections.ts +0 -428
- package/lib/slides.ts +0 -756
- package/lib/spelling.ts +0 -334
- package/lib/templates.ts +0 -526
- package/lib/themes.ts +0 -742
- package/lib/trackchanges.ts +0 -166
- package/lib/tui.ts +0 -450
- package/lib/types.ts +0 -546
- package/lib/undo.ts +0 -250
- package/lib/utils.ts +0 -69
- package/lib/variables.ts +0 -179
- package/lib/word-extraction.ts +0 -525
- package/lib/word.ts +0 -526
- package/lib/wordcomments.ts +0 -789
- package/mkdocs.yml +0 -64
- package/scripts/postbuild.js +0 -47
- package/tsconfig.json +0 -26
- package/types/index.d.ts +0 -531
package/lib/undo.ts
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* In-session undo stack for comment/annotation operations
|
|
3
|
-
*
|
|
4
|
-
* Provides undo/redo functionality during interactive sessions
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
interface StackEntry {
|
|
8
|
-
state: string | object;
|
|
9
|
-
description: string;
|
|
10
|
-
timestamp: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface HistoryEntry {
|
|
14
|
-
description: string;
|
|
15
|
-
current: boolean;
|
|
16
|
-
index: number;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface StackInfo {
|
|
20
|
-
position: number;
|
|
21
|
-
size: number;
|
|
22
|
-
undoSteps: number;
|
|
23
|
-
redoSteps: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
interface UndoStack {
|
|
27
|
-
push(state: string | object, description?: string): void;
|
|
28
|
-
undo(): StackEntry | null;
|
|
29
|
-
redo(): StackEntry | null;
|
|
30
|
-
current(): StackEntry | null;
|
|
31
|
-
canUndo(): boolean;
|
|
32
|
-
canRedo(): boolean;
|
|
33
|
-
info(): StackInfo;
|
|
34
|
-
history(limit?: number): HistoryEntry[];
|
|
35
|
-
getStack(): StackEntry[];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface DocumentChange {
|
|
39
|
-
text: string;
|
|
40
|
-
description: string;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface DocumentSession {
|
|
44
|
-
getText(): string;
|
|
45
|
-
applyChange(newText: string, description: string): void;
|
|
46
|
-
undo(): DocumentChange | null;
|
|
47
|
-
redo(): DocumentChange | null;
|
|
48
|
-
canUndo(): boolean;
|
|
49
|
-
canRedo(): boolean;
|
|
50
|
-
info(): StackInfo;
|
|
51
|
-
history(limit?: number): HistoryEntry[];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Create an undo stack
|
|
56
|
-
*/
|
|
57
|
-
export function createUndoStack(maxSize: number = 50): UndoStack {
|
|
58
|
-
const stack: StackEntry[] = [];
|
|
59
|
-
let position = -1;
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
/**
|
|
63
|
-
* Push a new state onto the stack
|
|
64
|
-
*/
|
|
65
|
-
push(state: string | object, description: string = ''): void {
|
|
66
|
-
// Remove any states after current position (for redo)
|
|
67
|
-
if (position < stack.length - 1) {
|
|
68
|
-
stack.splice(position + 1);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Add new state
|
|
72
|
-
stack.push({
|
|
73
|
-
state: typeof state === 'string' ? state : JSON.parse(JSON.stringify(state)),
|
|
74
|
-
description,
|
|
75
|
-
timestamp: Date.now(),
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// Enforce max size
|
|
79
|
-
while (stack.length > maxSize) {
|
|
80
|
-
stack.shift();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
position = stack.length - 1;
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Undo to previous state
|
|
88
|
-
*/
|
|
89
|
-
undo(): StackEntry | null {
|
|
90
|
-
if (position <= 0) {
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
position--;
|
|
95
|
-
return stack[position] || null;
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Redo to next state
|
|
100
|
-
*/
|
|
101
|
-
redo(): StackEntry | null {
|
|
102
|
-
if (position >= stack.length - 1) {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
position++;
|
|
107
|
-
return stack[position] || null;
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Get current state
|
|
112
|
-
*/
|
|
113
|
-
current(): StackEntry | null {
|
|
114
|
-
if (position < 0 || position >= stack.length) {
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
return stack[position] || null;
|
|
118
|
-
},
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Check if undo is available
|
|
122
|
-
*/
|
|
123
|
-
canUndo(): boolean {
|
|
124
|
-
return position > 0;
|
|
125
|
-
},
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Check if redo is available
|
|
129
|
-
*/
|
|
130
|
-
canRedo(): boolean {
|
|
131
|
-
return position < stack.length - 1;
|
|
132
|
-
},
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Get stack info
|
|
136
|
-
*/
|
|
137
|
-
info(): StackInfo {
|
|
138
|
-
return {
|
|
139
|
-
position,
|
|
140
|
-
size: stack.length,
|
|
141
|
-
undoSteps: position,
|
|
142
|
-
redoSteps: stack.length - position - 1,
|
|
143
|
-
};
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Get history of changes
|
|
148
|
-
*/
|
|
149
|
-
history(limit: number = 10): HistoryEntry[] {
|
|
150
|
-
const start = Math.max(0, position - Math.floor(limit / 2));
|
|
151
|
-
const end = Math.min(stack.length, start + limit);
|
|
152
|
-
|
|
153
|
-
return stack.slice(start, end).map((item, i) => ({
|
|
154
|
-
description: item.description,
|
|
155
|
-
current: start + i === position,
|
|
156
|
-
index: start + i,
|
|
157
|
-
}));
|
|
158
|
-
},
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Get the full stack (for debugging)
|
|
162
|
-
*/
|
|
163
|
-
getStack(): StackEntry[] {
|
|
164
|
-
return [...stack];
|
|
165
|
-
},
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Create a document session with undo support
|
|
171
|
-
*/
|
|
172
|
-
export function createDocumentSession(initialText: string): DocumentSession {
|
|
173
|
-
const undoStack = createUndoStack();
|
|
174
|
-
|
|
175
|
-
// Save initial state
|
|
176
|
-
undoStack.push(initialText, 'Initial state');
|
|
177
|
-
|
|
178
|
-
return {
|
|
179
|
-
/**
|
|
180
|
-
* Get current text
|
|
181
|
-
*/
|
|
182
|
-
getText(): string {
|
|
183
|
-
const current = undoStack.current();
|
|
184
|
-
return current ? current.state as string : initialText;
|
|
185
|
-
},
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Apply a change
|
|
189
|
-
*/
|
|
190
|
-
applyChange(newText: string, description: string): void {
|
|
191
|
-
undoStack.push(newText, description);
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Undo last change
|
|
196
|
-
*/
|
|
197
|
-
undo(): DocumentChange | null {
|
|
198
|
-
const result = undoStack.undo();
|
|
199
|
-
if (result) {
|
|
200
|
-
return {
|
|
201
|
-
text: result.state as string,
|
|
202
|
-
description: result.description,
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
return null;
|
|
206
|
-
},
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Redo last undone change
|
|
210
|
-
*/
|
|
211
|
-
redo(): DocumentChange | null {
|
|
212
|
-
const result = undoStack.redo();
|
|
213
|
-
if (result) {
|
|
214
|
-
return {
|
|
215
|
-
text: result.state as string,
|
|
216
|
-
description: result.description,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
return null;
|
|
220
|
-
},
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Check if undo is available
|
|
224
|
-
*/
|
|
225
|
-
canUndo(): boolean {
|
|
226
|
-
return undoStack.canUndo();
|
|
227
|
-
},
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Check if redo is available
|
|
231
|
-
*/
|
|
232
|
-
canRedo(): boolean {
|
|
233
|
-
return undoStack.canRedo();
|
|
234
|
-
},
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Get stack info
|
|
238
|
-
*/
|
|
239
|
-
info(): StackInfo {
|
|
240
|
-
return undoStack.info();
|
|
241
|
-
},
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Get change history
|
|
245
|
-
*/
|
|
246
|
-
history(limit: number = 10): HistoryEntry[] {
|
|
247
|
-
return undoStack.history(limit);
|
|
248
|
-
},
|
|
249
|
-
};
|
|
250
|
-
}
|
package/lib/utils.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared utility functions
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Count words in text (excluding markdown syntax)
|
|
7
|
-
* @param text - Markdown text
|
|
8
|
-
* @returns Word count
|
|
9
|
-
*/
|
|
10
|
-
export function countWords(text: string): number {
|
|
11
|
-
return text
|
|
12
|
-
.replace(/^---[\s\S]*?---/m, '') // Remove YAML frontmatter
|
|
13
|
-
.replace(/!\[.*?\]\(.*?\)/g, '') // Remove images
|
|
14
|
-
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // Keep link text
|
|
15
|
-
.replace(/#+\s*/g, '') // Remove headers
|
|
16
|
-
.replace(/\*\*|__|[*_`]/g, '') // Remove formatting
|
|
17
|
-
.replace(/```[\s\S]*?```/g, '') // Remove code blocks
|
|
18
|
-
.replace(/\{[^}]+\}/g, '') // Remove CriticMarkup and attributes
|
|
19
|
-
.replace(/@\w+:\w+/g, '') // Remove cross-references
|
|
20
|
-
.replace(/@\w+/g, '') // Remove citations
|
|
21
|
-
.replace(/\|[^|]+\|/g, ' ') // Remove table cells
|
|
22
|
-
.replace(/[-=]{3,}/g, '') // Remove horizontal rules
|
|
23
|
-
.replace(/\n+/g, ' ') // Newlines to spaces
|
|
24
|
-
.replace(/\s+/g, ' ') // Collapse multiple spaces
|
|
25
|
-
.trim()
|
|
26
|
-
.split(/\s+/)
|
|
27
|
-
.filter(w => w.length > 0).length;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Normalize whitespace in text
|
|
32
|
-
* @param text - Input text
|
|
33
|
-
* @returns Normalized text
|
|
34
|
-
*/
|
|
35
|
-
export function normalizeWhitespace(text: string): string {
|
|
36
|
-
return text
|
|
37
|
-
.replace(/\r\n/g, '\n')
|
|
38
|
-
.replace(/\t/g, ' ')
|
|
39
|
-
.replace(/ +/g, ' ')
|
|
40
|
-
.trim();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Escape XML special characters
|
|
45
|
-
* @param str - Input string
|
|
46
|
-
* @returns XML-safe string
|
|
47
|
-
*/
|
|
48
|
-
export function escapeXml(str: string): string {
|
|
49
|
-
return str
|
|
50
|
-
.replace(/&/g, '&')
|
|
51
|
-
.replace(/</g, '<')
|
|
52
|
-
.replace(/>/g, '>')
|
|
53
|
-
.replace(/"/g, '"')
|
|
54
|
-
.replace(/'/g, ''');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Escape LaTeX special characters
|
|
59
|
-
* @param text - Text to escape
|
|
60
|
-
* @returns Escaped text
|
|
61
|
-
*/
|
|
62
|
-
export function escapeLatex(text: string): string {
|
|
63
|
-
return text
|
|
64
|
-
.replace(/\\/g, '\\textbackslash{}')
|
|
65
|
-
.replace(/([#$%&_{}])/g, '\\$1')
|
|
66
|
-
.replace(/\^/g, '\\textasciicircum{}')
|
|
67
|
-
.replace(/~/g, '\\textasciitilde{}')
|
|
68
|
-
.replace(/\n/g, ' ');
|
|
69
|
-
}
|
package/lib/variables.ts
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
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
|
-
}
|