docrev 0.9.11 → 0.9.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +9 -9
- package/.gitattributes +1 -1
- package/CHANGELOG.md +149 -149
- package/PLAN-tables-and-postprocess.md +850 -850
- package/README.md +391 -391
- package/bin/rev.js +11 -11
- package/bin/rev.ts +145 -145
- package/completions/rev.bash +127 -127
- package/completions/rev.ps1 +210 -210
- package/completions/rev.zsh +207 -207
- package/dev_notes/stress2/build_adversarial.ts +186 -186
- package/dev_notes/stress2/drift_matcher.ts +62 -62
- package/dev_notes/stress2/probe_anchors.ts +35 -35
- package/dev_notes/stress2/project/discussion.before.md +3 -3
- package/dev_notes/stress2/project/discussion.md +3 -3
- package/dev_notes/stress2/project/methods.before.md +20 -20
- package/dev_notes/stress2/project/methods.md +20 -20
- package/dev_notes/stress2/project/rev.yaml +5 -5
- package/dev_notes/stress2/project/sections.yaml +4 -4
- package/dev_notes/stress2/sections.yaml +5 -5
- package/dev_notes/stress2/trace_placement.ts +50 -50
- package/dev_notes/stresstest_boundaries.ts +27 -27
- package/dev_notes/stresstest_drift_apply.ts +43 -43
- package/dev_notes/stresstest_drift_compare.ts +43 -43
- package/dev_notes/stresstest_drift_v2.ts +54 -54
- package/dev_notes/stresstest_inspect.ts +54 -54
- package/dev_notes/stresstest_pstyle.ts +55 -55
- package/dev_notes/stresstest_section_debug.ts +23 -23
- package/dev_notes/stresstest_split.ts +70 -70
- package/dev_notes/stresstest_trace.ts +19 -19
- package/dev_notes/stresstest_verify_no_overwrite.ts +40 -40
- package/dist/lib/build.d.ts +50 -1
- package/dist/lib/build.d.ts.map +1 -1
- package/dist/lib/build.js +80 -30
- package/dist/lib/build.js.map +1 -1
- package/dist/lib/commands/build.d.ts.map +1 -1
- package/dist/lib/commands/build.js +38 -5
- package/dist/lib/commands/build.js.map +1 -1
- package/dist/lib/commands/utilities.js +164 -164
- package/dist/lib/commands/word-tools.js +8 -8
- package/dist/lib/grammar.js +3 -3
- package/dist/lib/import.d.ts.map +1 -1
- package/dist/lib/import.js +146 -24
- package/dist/lib/import.js.map +1 -1
- package/dist/lib/pdf-comments.js +44 -44
- package/dist/lib/plugins.js +57 -57
- package/dist/lib/pptx-themes.js +115 -115
- package/dist/lib/spelling.js +2 -2
- package/dist/lib/templates.js +387 -387
- package/dist/lib/themes.js +51 -51
- package/dist/lib/types.d.ts +20 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/word-extraction.d.ts +6 -0
- package/dist/lib/word-extraction.d.ts.map +1 -1
- package/dist/lib/word-extraction.js +46 -3
- package/dist/lib/word-extraction.js.map +1 -1
- package/dist/lib/wordcomments.d.ts.map +1 -1
- package/dist/lib/wordcomments.js +23 -5
- package/dist/lib/wordcomments.js.map +1 -1
- package/eslint.config.js +27 -27
- package/lib/anchor-match.ts +276 -276
- package/lib/annotations.ts +644 -644
- package/lib/build.ts +1300 -1227
- package/lib/citations.ts +160 -160
- package/lib/commands/build.ts +833 -801
- package/lib/commands/citations.ts +515 -515
- package/lib/commands/comments.ts +1050 -1050
- package/lib/commands/context.ts +174 -174
- package/lib/commands/core.ts +309 -309
- package/lib/commands/doi.ts +435 -435
- package/lib/commands/file-ops.ts +372 -372
- package/lib/commands/history.ts +320 -320
- package/lib/commands/index.ts +87 -87
- package/lib/commands/init.ts +259 -259
- package/lib/commands/merge-resolve.ts +378 -378
- package/lib/commands/preview.ts +178 -178
- package/lib/commands/project-info.ts +244 -244
- package/lib/commands/quality.ts +517 -517
- package/lib/commands/response.ts +454 -454
- package/lib/commands/section-boundaries.ts +82 -82
- package/lib/commands/sections.ts +451 -451
- package/lib/commands/sync.ts +706 -706
- package/lib/commands/text-ops.ts +449 -449
- package/lib/commands/utilities.ts +448 -448
- package/lib/commands/verify-anchors.ts +272 -272
- package/lib/commands/word-tools.ts +340 -340
- package/lib/comment-realign.ts +517 -517
- package/lib/config.ts +84 -84
- package/lib/crossref.ts +781 -781
- package/lib/csl.ts +191 -191
- package/lib/dependencies.ts +98 -98
- package/lib/diff-engine.ts +465 -465
- package/lib/doi-cache.ts +115 -115
- package/lib/doi.ts +897 -897
- package/lib/equations.ts +506 -506
- package/lib/errors.ts +346 -346
- package/lib/format.ts +541 -541
- package/lib/git.ts +326 -326
- package/lib/grammar.ts +303 -303
- package/lib/image-registry.ts +180 -180
- package/lib/import.ts +911 -792
- package/lib/journals.ts +543 -543
- package/lib/merge.ts +633 -633
- package/lib/orcid.ts +144 -144
- package/lib/pdf-comments.ts +263 -263
- package/lib/pdf-import.ts +524 -524
- package/lib/plugins.ts +362 -362
- package/lib/postprocess.ts +188 -188
- package/lib/pptx-color-filter.lua +37 -37
- package/lib/pptx-template.ts +469 -469
- package/lib/pptx-themes.ts +483 -483
- package/lib/protect-restore.ts +520 -520
- package/lib/rate-limiter.ts +94 -94
- package/lib/response.ts +197 -197
- package/lib/restore-references.ts +240 -240
- package/lib/review.ts +327 -327
- package/lib/schema.ts +417 -417
- package/lib/scientific-words.ts +73 -73
- package/lib/sections.ts +335 -335
- package/lib/slides.ts +756 -756
- package/lib/spelling.ts +334 -334
- package/lib/templates.ts +526 -526
- package/lib/themes.ts +742 -742
- package/lib/trackchanges.ts +247 -247
- package/lib/tui.ts +450 -450
- package/lib/types.ts +550 -530
- package/lib/undo.ts +250 -250
- package/lib/utils.ts +69 -69
- package/lib/variables.ts +179 -179
- package/lib/word-extraction.ts +806 -759
- package/lib/word.ts +643 -643
- package/lib/wordcomments.ts +817 -798
- package/package.json +137 -137
- package/scripts/postbuild.js +28 -28
- package/skill/REFERENCE.md +431 -431
- package/skill/SKILL.md +258 -258
- package/tsconfig.json +26 -26
- package/types/index.d.ts +525 -525
package/lib/image-registry.ts
CHANGED
|
@@ -1,180 +1,180 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Image registry utilities for tracking figures and tables in markdown documents
|
|
3
|
-
*
|
|
4
|
-
* The registry maps figure/table labels and display numbers to source paths,
|
|
5
|
-
* enabling Word import to match rendered figures back to original sources.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import * as fs from 'fs';
|
|
9
|
-
import * as path from 'path';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Image registry entry
|
|
13
|
-
*/
|
|
14
|
-
interface ImageEntry {
|
|
15
|
-
caption: string;
|
|
16
|
-
path: string;
|
|
17
|
-
label: string | null;
|
|
18
|
-
type: 'fig' | 'tbl';
|
|
19
|
-
number?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Image registry
|
|
24
|
-
*/
|
|
25
|
-
interface ImageRegistry {
|
|
26
|
-
figures: ImageEntry[];
|
|
27
|
-
byLabel: Map<string, ImageEntry>;
|
|
28
|
-
byNumber: Map<string, ImageEntry>;
|
|
29
|
-
byCaption: Map<string, ImageEntry>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Crossref registry info
|
|
34
|
-
*/
|
|
35
|
-
interface CrossrefInfo {
|
|
36
|
-
num: number;
|
|
37
|
-
isSupp: boolean;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Crossref registry
|
|
42
|
-
*/
|
|
43
|
-
interface CrossrefRegistry {
|
|
44
|
-
figures: Map<string, CrossrefInfo>;
|
|
45
|
-
tables: Map<string, CrossrefInfo>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Saved registry data
|
|
50
|
-
*/
|
|
51
|
-
interface RegistryData {
|
|
52
|
-
version: number;
|
|
53
|
-
created: string;
|
|
54
|
-
figures: ImageEntry[];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Pattern to extract markdown images with optional pandoc-crossref anchors
|
|
59
|
-
* Captures: {#fig:label} or 
|
|
60
|
-
* Groups: [1] = caption, [2] = path, [3] = label type (fig/tbl), [4] = label
|
|
61
|
-
*/
|
|
62
|
-
export const IMAGE_PATTERN = /!\[([^\]]*)\]\(([^)]+)\)(?:\{#(fig|tbl):([^}]+)\})?/g;
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Build image registry from markdown content
|
|
66
|
-
* Maps figure labels and display numbers to source paths
|
|
67
|
-
*/
|
|
68
|
-
export function buildImageRegistry(
|
|
69
|
-
content: string,
|
|
70
|
-
crossrefRegistry: CrossrefRegistry | null = null
|
|
71
|
-
): ImageRegistry {
|
|
72
|
-
const figures: ImageEntry[] = [];
|
|
73
|
-
const byLabel = new Map<string, ImageEntry>();
|
|
74
|
-
const byNumber = new Map<string, ImageEntry>();
|
|
75
|
-
const byCaption = new Map<string, ImageEntry>();
|
|
76
|
-
|
|
77
|
-
IMAGE_PATTERN.lastIndex = 0;
|
|
78
|
-
let match: RegExpExecArray | null;
|
|
79
|
-
|
|
80
|
-
while ((match = IMAGE_PATTERN.exec(content)) !== null) {
|
|
81
|
-
const caption = match[1];
|
|
82
|
-
const imagePath = match[2];
|
|
83
|
-
const labelType = match[3] as 'fig' | 'tbl' | undefined; // 'fig' or 'tbl' or undefined
|
|
84
|
-
const label = match[4]; // label without prefix
|
|
85
|
-
|
|
86
|
-
const entry: ImageEntry = {
|
|
87
|
-
caption,
|
|
88
|
-
path: imagePath,
|
|
89
|
-
label: label || null,
|
|
90
|
-
type: labelType || 'fig',
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// Add display number if we have a crossref registry
|
|
94
|
-
if (label && crossrefRegistry) {
|
|
95
|
-
const info = crossrefRegistry.figures.get(label) || crossrefRegistry.tables.get(label);
|
|
96
|
-
if (info) {
|
|
97
|
-
entry.number = info.isSupp ? `S${info.num}` : `${info.num}`;
|
|
98
|
-
byNumber.set(`${entry.type}:${entry.number}`, entry);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
figures.push(entry);
|
|
103
|
-
|
|
104
|
-
if (label) {
|
|
105
|
-
byLabel.set(`${labelType || 'fig'}:${label}`, entry);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Index by first 50 chars of caption for fuzzy matching
|
|
109
|
-
if (caption) {
|
|
110
|
-
const captionKey = caption.slice(0, 50).toLowerCase().trim();
|
|
111
|
-
byCaption.set(captionKey, entry);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return { figures, byLabel, byNumber, byCaption };
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Write image registry to .rev directory
|
|
120
|
-
*/
|
|
121
|
-
export function writeImageRegistry(directory: string, registry: ImageRegistry): string {
|
|
122
|
-
const revDir = path.join(directory, '.rev');
|
|
123
|
-
if (!fs.existsSync(revDir)) {
|
|
124
|
-
fs.mkdirSync(revDir, { recursive: true });
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Convert Maps to objects for JSON serialization
|
|
128
|
-
const data: RegistryData = {
|
|
129
|
-
version: 1,
|
|
130
|
-
created: new Date().toISOString(),
|
|
131
|
-
figures: registry.figures,
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const registryPath = path.join(revDir, 'image-registry.json');
|
|
135
|
-
fs.writeFileSync(registryPath, JSON.stringify(data, null, 2), 'utf-8');
|
|
136
|
-
|
|
137
|
-
return registryPath;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Read image registry from .rev directory
|
|
142
|
-
*/
|
|
143
|
-
export function readImageRegistry(directory: string): (ImageRegistry & RegistryData) | null {
|
|
144
|
-
const registryPath = path.join(directory, '.rev', 'image-registry.json');
|
|
145
|
-
|
|
146
|
-
if (!fs.existsSync(registryPath)) {
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
try {
|
|
151
|
-
const data = JSON.parse(fs.readFileSync(registryPath, 'utf-8')) as RegistryData;
|
|
152
|
-
|
|
153
|
-
// Rebuild lookup maps from figures array
|
|
154
|
-
const byLabel = new Map<string, ImageEntry>();
|
|
155
|
-
const byNumber = new Map<string, ImageEntry>();
|
|
156
|
-
const byCaption = new Map<string, ImageEntry>();
|
|
157
|
-
|
|
158
|
-
for (const entry of data.figures || []) {
|
|
159
|
-
if (entry.label) {
|
|
160
|
-
byLabel.set(`${entry.type || 'fig'}:${entry.label}`, entry);
|
|
161
|
-
}
|
|
162
|
-
if (entry.number) {
|
|
163
|
-
byNumber.set(`${entry.type || 'fig'}:${entry.number}`, entry);
|
|
164
|
-
}
|
|
165
|
-
if (entry.caption) {
|
|
166
|
-
const captionKey = entry.caption.slice(0, 50).toLowerCase().trim();
|
|
167
|
-
byCaption.set(captionKey, entry);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
...data,
|
|
173
|
-
byLabel,
|
|
174
|
-
byNumber,
|
|
175
|
-
byCaption,
|
|
176
|
-
};
|
|
177
|
-
} catch (err) {
|
|
178
|
-
return null;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Image registry utilities for tracking figures and tables in markdown documents
|
|
3
|
+
*
|
|
4
|
+
* The registry maps figure/table labels and display numbers to source paths,
|
|
5
|
+
* enabling Word import to match rendered figures back to original sources.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Image registry entry
|
|
13
|
+
*/
|
|
14
|
+
interface ImageEntry {
|
|
15
|
+
caption: string;
|
|
16
|
+
path: string;
|
|
17
|
+
label: string | null;
|
|
18
|
+
type: 'fig' | 'tbl';
|
|
19
|
+
number?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Image registry
|
|
24
|
+
*/
|
|
25
|
+
interface ImageRegistry {
|
|
26
|
+
figures: ImageEntry[];
|
|
27
|
+
byLabel: Map<string, ImageEntry>;
|
|
28
|
+
byNumber: Map<string, ImageEntry>;
|
|
29
|
+
byCaption: Map<string, ImageEntry>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Crossref registry info
|
|
34
|
+
*/
|
|
35
|
+
interface CrossrefInfo {
|
|
36
|
+
num: number;
|
|
37
|
+
isSupp: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Crossref registry
|
|
42
|
+
*/
|
|
43
|
+
interface CrossrefRegistry {
|
|
44
|
+
figures: Map<string, CrossrefInfo>;
|
|
45
|
+
tables: Map<string, CrossrefInfo>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Saved registry data
|
|
50
|
+
*/
|
|
51
|
+
interface RegistryData {
|
|
52
|
+
version: number;
|
|
53
|
+
created: string;
|
|
54
|
+
figures: ImageEntry[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Pattern to extract markdown images with optional pandoc-crossref anchors
|
|
59
|
+
* Captures: {#fig:label} or 
|
|
60
|
+
* Groups: [1] = caption, [2] = path, [3] = label type (fig/tbl), [4] = label
|
|
61
|
+
*/
|
|
62
|
+
export const IMAGE_PATTERN = /!\[([^\]]*)\]\(([^)]+)\)(?:\{#(fig|tbl):([^}]+)\})?/g;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Build image registry from markdown content
|
|
66
|
+
* Maps figure labels and display numbers to source paths
|
|
67
|
+
*/
|
|
68
|
+
export function buildImageRegistry(
|
|
69
|
+
content: string,
|
|
70
|
+
crossrefRegistry: CrossrefRegistry | null = null
|
|
71
|
+
): ImageRegistry {
|
|
72
|
+
const figures: ImageEntry[] = [];
|
|
73
|
+
const byLabel = new Map<string, ImageEntry>();
|
|
74
|
+
const byNumber = new Map<string, ImageEntry>();
|
|
75
|
+
const byCaption = new Map<string, ImageEntry>();
|
|
76
|
+
|
|
77
|
+
IMAGE_PATTERN.lastIndex = 0;
|
|
78
|
+
let match: RegExpExecArray | null;
|
|
79
|
+
|
|
80
|
+
while ((match = IMAGE_PATTERN.exec(content)) !== null) {
|
|
81
|
+
const caption = match[1];
|
|
82
|
+
const imagePath = match[2];
|
|
83
|
+
const labelType = match[3] as 'fig' | 'tbl' | undefined; // 'fig' or 'tbl' or undefined
|
|
84
|
+
const label = match[4]; // label without prefix
|
|
85
|
+
|
|
86
|
+
const entry: ImageEntry = {
|
|
87
|
+
caption,
|
|
88
|
+
path: imagePath,
|
|
89
|
+
label: label || null,
|
|
90
|
+
type: labelType || 'fig',
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// Add display number if we have a crossref registry
|
|
94
|
+
if (label && crossrefRegistry) {
|
|
95
|
+
const info = crossrefRegistry.figures.get(label) || crossrefRegistry.tables.get(label);
|
|
96
|
+
if (info) {
|
|
97
|
+
entry.number = info.isSupp ? `S${info.num}` : `${info.num}`;
|
|
98
|
+
byNumber.set(`${entry.type}:${entry.number}`, entry);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
figures.push(entry);
|
|
103
|
+
|
|
104
|
+
if (label) {
|
|
105
|
+
byLabel.set(`${labelType || 'fig'}:${label}`, entry);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Index by first 50 chars of caption for fuzzy matching
|
|
109
|
+
if (caption) {
|
|
110
|
+
const captionKey = caption.slice(0, 50).toLowerCase().trim();
|
|
111
|
+
byCaption.set(captionKey, entry);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return { figures, byLabel, byNumber, byCaption };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Write image registry to .rev directory
|
|
120
|
+
*/
|
|
121
|
+
export function writeImageRegistry(directory: string, registry: ImageRegistry): string {
|
|
122
|
+
const revDir = path.join(directory, '.rev');
|
|
123
|
+
if (!fs.existsSync(revDir)) {
|
|
124
|
+
fs.mkdirSync(revDir, { recursive: true });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Convert Maps to objects for JSON serialization
|
|
128
|
+
const data: RegistryData = {
|
|
129
|
+
version: 1,
|
|
130
|
+
created: new Date().toISOString(),
|
|
131
|
+
figures: registry.figures,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const registryPath = path.join(revDir, 'image-registry.json');
|
|
135
|
+
fs.writeFileSync(registryPath, JSON.stringify(data, null, 2), 'utf-8');
|
|
136
|
+
|
|
137
|
+
return registryPath;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Read image registry from .rev directory
|
|
142
|
+
*/
|
|
143
|
+
export function readImageRegistry(directory: string): (ImageRegistry & RegistryData) | null {
|
|
144
|
+
const registryPath = path.join(directory, '.rev', 'image-registry.json');
|
|
145
|
+
|
|
146
|
+
if (!fs.existsSync(registryPath)) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
const data = JSON.parse(fs.readFileSync(registryPath, 'utf-8')) as RegistryData;
|
|
152
|
+
|
|
153
|
+
// Rebuild lookup maps from figures array
|
|
154
|
+
const byLabel = new Map<string, ImageEntry>();
|
|
155
|
+
const byNumber = new Map<string, ImageEntry>();
|
|
156
|
+
const byCaption = new Map<string, ImageEntry>();
|
|
157
|
+
|
|
158
|
+
for (const entry of data.figures || []) {
|
|
159
|
+
if (entry.label) {
|
|
160
|
+
byLabel.set(`${entry.type || 'fig'}:${entry.label}`, entry);
|
|
161
|
+
}
|
|
162
|
+
if (entry.number) {
|
|
163
|
+
byNumber.set(`${entry.type || 'fig'}:${entry.number}`, entry);
|
|
164
|
+
}
|
|
165
|
+
if (entry.caption) {
|
|
166
|
+
const captionKey = entry.caption.slice(0, 50).toLowerCase().trim();
|
|
167
|
+
byCaption.set(captionKey, entry);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return {
|
|
172
|
+
...data,
|
|
173
|
+
byLabel,
|
|
174
|
+
byNumber,
|
|
175
|
+
byCaption,
|
|
176
|
+
};
|
|
177
|
+
} catch (err) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|