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.
Files changed (306) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/PLAN-tables-and-postprocess.md +850 -0
  3. package/README.md +33 -0
  4. package/bin/rev.js +12 -131
  5. package/bin/rev.ts +145 -0
  6. package/dist/bin/rev.d.ts +9 -0
  7. package/dist/bin/rev.d.ts.map +1 -0
  8. package/dist/bin/rev.js +118 -0
  9. package/dist/bin/rev.js.map +1 -0
  10. package/dist/lib/annotations.d.ts +91 -0
  11. package/dist/lib/annotations.d.ts.map +1 -0
  12. package/dist/lib/annotations.js +554 -0
  13. package/dist/lib/annotations.js.map +1 -0
  14. package/dist/lib/build.d.ts +171 -0
  15. package/dist/lib/build.d.ts.map +1 -0
  16. package/dist/lib/build.js +755 -0
  17. package/dist/lib/build.js.map +1 -0
  18. package/dist/lib/citations.d.ts +34 -0
  19. package/dist/lib/citations.d.ts.map +1 -0
  20. package/dist/lib/citations.js +140 -0
  21. package/dist/lib/citations.js.map +1 -0
  22. package/dist/lib/commands/build.d.ts +13 -0
  23. package/dist/lib/commands/build.d.ts.map +1 -0
  24. package/dist/lib/commands/build.js +678 -0
  25. package/dist/lib/commands/build.js.map +1 -0
  26. package/dist/lib/commands/citations.d.ts +11 -0
  27. package/dist/lib/commands/citations.d.ts.map +1 -0
  28. package/dist/lib/commands/citations.js +428 -0
  29. package/dist/lib/commands/citations.js.map +1 -0
  30. package/dist/lib/commands/comments.d.ts +11 -0
  31. package/dist/lib/commands/comments.d.ts.map +1 -0
  32. package/dist/lib/commands/comments.js +883 -0
  33. package/dist/lib/commands/comments.js.map +1 -0
  34. package/dist/lib/commands/context.d.ts +35 -0
  35. package/dist/lib/commands/context.d.ts.map +1 -0
  36. package/dist/lib/commands/context.js +59 -0
  37. package/dist/lib/commands/context.js.map +1 -0
  38. package/dist/lib/commands/core.d.ts +11 -0
  39. package/dist/lib/commands/core.d.ts.map +1 -0
  40. package/dist/lib/commands/core.js +246 -0
  41. package/dist/lib/commands/core.js.map +1 -0
  42. package/dist/lib/commands/doi.d.ts +11 -0
  43. package/dist/lib/commands/doi.d.ts.map +1 -0
  44. package/dist/lib/commands/doi.js +373 -0
  45. package/dist/lib/commands/doi.js.map +1 -0
  46. package/dist/lib/commands/history.d.ts +11 -0
  47. package/dist/lib/commands/history.d.ts.map +1 -0
  48. package/dist/lib/commands/history.js +245 -0
  49. package/dist/lib/commands/history.js.map +1 -0
  50. package/dist/lib/commands/index.d.ts +28 -0
  51. package/dist/lib/commands/index.d.ts.map +1 -0
  52. package/dist/lib/commands/index.js +35 -0
  53. package/dist/lib/commands/index.js.map +1 -0
  54. package/dist/lib/commands/init.d.ts +11 -0
  55. package/dist/lib/commands/init.d.ts.map +1 -0
  56. package/dist/lib/commands/init.js +209 -0
  57. package/dist/lib/commands/init.js.map +1 -0
  58. package/dist/lib/commands/response.d.ts +11 -0
  59. package/dist/lib/commands/response.d.ts.map +1 -0
  60. package/dist/lib/commands/response.js +317 -0
  61. package/dist/lib/commands/response.js.map +1 -0
  62. package/dist/lib/commands/sections.d.ts +11 -0
  63. package/dist/lib/commands/sections.d.ts.map +1 -0
  64. package/dist/lib/commands/sections.js +1071 -0
  65. package/dist/lib/commands/sections.js.map +1 -0
  66. package/dist/lib/commands/utilities.d.ts +19 -0
  67. package/dist/lib/commands/utilities.d.ts.map +1 -0
  68. package/dist/lib/commands/utilities.js +2009 -0
  69. package/dist/lib/commands/utilities.js.map +1 -0
  70. package/dist/lib/comment-realign.d.ts +50 -0
  71. package/dist/lib/comment-realign.d.ts.map +1 -0
  72. package/dist/lib/comment-realign.js +372 -0
  73. package/dist/lib/comment-realign.js.map +1 -0
  74. package/dist/lib/config.d.ts +41 -0
  75. package/dist/lib/config.d.ts.map +1 -0
  76. package/dist/lib/config.js +76 -0
  77. package/dist/lib/config.js.map +1 -0
  78. package/dist/lib/crossref.d.ts +108 -0
  79. package/dist/lib/crossref.d.ts.map +1 -0
  80. package/dist/lib/crossref.js +597 -0
  81. package/dist/lib/crossref.js.map +1 -0
  82. package/dist/lib/dependencies.d.ts +30 -0
  83. package/dist/lib/dependencies.d.ts.map +1 -0
  84. package/dist/lib/dependencies.js +95 -0
  85. package/dist/lib/dependencies.js.map +1 -0
  86. package/dist/lib/doi-cache.d.ts +29 -0
  87. package/dist/lib/doi-cache.d.ts.map +1 -0
  88. package/dist/lib/doi-cache.js +104 -0
  89. package/dist/lib/doi-cache.js.map +1 -0
  90. package/dist/lib/doi.d.ts +65 -0
  91. package/dist/lib/doi.d.ts.map +1 -0
  92. package/dist/lib/doi.js +710 -0
  93. package/dist/lib/doi.js.map +1 -0
  94. package/dist/lib/equations.d.ts +61 -0
  95. package/dist/lib/equations.d.ts.map +1 -0
  96. package/dist/lib/equations.js +445 -0
  97. package/dist/lib/equations.js.map +1 -0
  98. package/dist/lib/errors.d.ts +60 -0
  99. package/dist/lib/errors.d.ts.map +1 -0
  100. package/dist/lib/errors.js +303 -0
  101. package/dist/lib/errors.js.map +1 -0
  102. package/dist/lib/format.d.ts +104 -0
  103. package/dist/lib/format.d.ts.map +1 -0
  104. package/dist/lib/format.js +416 -0
  105. package/dist/lib/format.js.map +1 -0
  106. package/dist/lib/git.d.ts +88 -0
  107. package/dist/lib/git.d.ts.map +1 -0
  108. package/dist/lib/git.js +304 -0
  109. package/dist/lib/git.js.map +1 -0
  110. package/dist/lib/grammar.d.ts +62 -0
  111. package/dist/lib/grammar.d.ts.map +1 -0
  112. package/dist/lib/grammar.js +244 -0
  113. package/dist/lib/grammar.js.map +1 -0
  114. package/dist/lib/image-registry.d.ts +68 -0
  115. package/dist/lib/image-registry.d.ts.map +1 -0
  116. package/dist/lib/image-registry.js +112 -0
  117. package/dist/lib/image-registry.js.map +1 -0
  118. package/dist/lib/import.d.ts +184 -0
  119. package/dist/lib/import.d.ts.map +1 -0
  120. package/dist/lib/import.js +1581 -0
  121. package/dist/lib/import.js.map +1 -0
  122. package/dist/lib/journals.d.ts +55 -0
  123. package/dist/lib/journals.d.ts.map +1 -0
  124. package/dist/lib/journals.js +417 -0
  125. package/dist/lib/journals.js.map +1 -0
  126. package/dist/lib/merge.d.ts +138 -0
  127. package/dist/lib/merge.d.ts.map +1 -0
  128. package/dist/lib/merge.js +603 -0
  129. package/dist/lib/merge.js.map +1 -0
  130. package/dist/lib/orcid.d.ts +36 -0
  131. package/dist/lib/orcid.d.ts.map +1 -0
  132. package/dist/lib/orcid.js +117 -0
  133. package/dist/lib/orcid.js.map +1 -0
  134. package/dist/lib/pdf-comments.d.ts +95 -0
  135. package/dist/lib/pdf-comments.d.ts.map +1 -0
  136. package/dist/lib/pdf-comments.js +192 -0
  137. package/dist/lib/pdf-comments.js.map +1 -0
  138. package/dist/lib/pdf-import.d.ts +118 -0
  139. package/dist/lib/pdf-import.d.ts.map +1 -0
  140. package/dist/lib/pdf-import.js +397 -0
  141. package/dist/lib/pdf-import.js.map +1 -0
  142. package/dist/lib/plugins.d.ts +76 -0
  143. package/dist/lib/plugins.d.ts.map +1 -0
  144. package/dist/lib/plugins.js +235 -0
  145. package/dist/lib/plugins.js.map +1 -0
  146. package/dist/lib/postprocess.d.ts +42 -0
  147. package/dist/lib/postprocess.d.ts.map +1 -0
  148. package/dist/lib/postprocess.js +138 -0
  149. package/dist/lib/postprocess.js.map +1 -0
  150. package/dist/lib/pptx-template.d.ts +59 -0
  151. package/dist/lib/pptx-template.d.ts.map +1 -0
  152. package/dist/lib/pptx-template.js +613 -0
  153. package/dist/lib/pptx-template.js.map +1 -0
  154. package/dist/lib/pptx-themes.d.ts +80 -0
  155. package/dist/lib/pptx-themes.d.ts.map +1 -0
  156. package/dist/lib/pptx-themes.js +818 -0
  157. package/dist/lib/pptx-themes.js.map +1 -0
  158. package/dist/lib/protect-restore.d.ts +137 -0
  159. package/dist/lib/protect-restore.d.ts.map +1 -0
  160. package/dist/lib/protect-restore.js +394 -0
  161. package/dist/lib/protect-restore.js.map +1 -0
  162. package/dist/lib/rate-limiter.d.ts +27 -0
  163. package/dist/lib/rate-limiter.d.ts.map +1 -0
  164. package/dist/lib/rate-limiter.js +79 -0
  165. package/dist/lib/rate-limiter.js.map +1 -0
  166. package/dist/lib/response.d.ts +41 -0
  167. package/dist/lib/response.d.ts.map +1 -0
  168. package/dist/lib/response.js +150 -0
  169. package/dist/lib/response.js.map +1 -0
  170. package/dist/lib/review.d.ts +35 -0
  171. package/dist/lib/review.d.ts.map +1 -0
  172. package/dist/lib/review.js +263 -0
  173. package/dist/lib/review.js.map +1 -0
  174. package/dist/lib/schema.d.ts +66 -0
  175. package/dist/lib/schema.d.ts.map +1 -0
  176. package/dist/lib/schema.js +339 -0
  177. package/dist/lib/schema.js.map +1 -0
  178. package/dist/lib/scientific-words.d.ts +6 -0
  179. package/dist/lib/scientific-words.d.ts.map +1 -0
  180. package/dist/lib/scientific-words.js +66 -0
  181. package/dist/lib/scientific-words.js.map +1 -0
  182. package/dist/lib/sections.d.ts +40 -0
  183. package/dist/lib/sections.d.ts.map +1 -0
  184. package/dist/lib/sections.js +288 -0
  185. package/dist/lib/sections.js.map +1 -0
  186. package/dist/lib/slides.d.ts +86 -0
  187. package/dist/lib/slides.d.ts.map +1 -0
  188. package/dist/lib/slides.js +676 -0
  189. package/dist/lib/slides.js.map +1 -0
  190. package/dist/lib/spelling.d.ts +76 -0
  191. package/dist/lib/spelling.d.ts.map +1 -0
  192. package/dist/lib/spelling.js +272 -0
  193. package/dist/lib/spelling.js.map +1 -0
  194. package/dist/lib/templates.d.ts +30 -0
  195. package/dist/lib/templates.d.ts.map +1 -0
  196. package/dist/lib/templates.js +504 -0
  197. package/dist/lib/templates.js.map +1 -0
  198. package/dist/lib/themes.d.ts +85 -0
  199. package/dist/lib/themes.d.ts.map +1 -0
  200. package/dist/lib/themes.js +652 -0
  201. package/dist/lib/themes.js.map +1 -0
  202. package/dist/lib/trackchanges.d.ts +51 -0
  203. package/dist/lib/trackchanges.d.ts.map +1 -0
  204. package/dist/lib/trackchanges.js +202 -0
  205. package/dist/lib/trackchanges.js.map +1 -0
  206. package/dist/lib/tui.d.ts +76 -0
  207. package/dist/lib/tui.d.ts.map +1 -0
  208. package/dist/lib/tui.js +377 -0
  209. package/dist/lib/tui.js.map +1 -0
  210. package/dist/lib/types.d.ts +447 -0
  211. package/dist/lib/types.d.ts.map +1 -0
  212. package/dist/lib/types.js +6 -0
  213. package/dist/lib/types.js.map +1 -0
  214. package/dist/lib/undo.d.ts +57 -0
  215. package/dist/lib/undo.d.ts.map +1 -0
  216. package/dist/lib/undo.js +185 -0
  217. package/dist/lib/undo.js.map +1 -0
  218. package/dist/lib/utils.d.ts +16 -0
  219. package/dist/lib/utils.d.ts.map +1 -0
  220. package/dist/lib/utils.js +40 -0
  221. package/dist/lib/utils.js.map +1 -0
  222. package/dist/lib/variables.d.ts +42 -0
  223. package/dist/lib/variables.d.ts.map +1 -0
  224. package/dist/lib/variables.js +141 -0
  225. package/dist/lib/variables.js.map +1 -0
  226. package/dist/lib/word.d.ts +80 -0
  227. package/dist/lib/word.d.ts.map +1 -0
  228. package/dist/lib/word.js +360 -0
  229. package/dist/lib/word.js.map +1 -0
  230. package/dist/lib/wordcomments.d.ts +51 -0
  231. package/dist/lib/wordcomments.d.ts.map +1 -0
  232. package/dist/lib/wordcomments.js +587 -0
  233. package/dist/lib/wordcomments.js.map +1 -0
  234. package/eslint.config.js +27 -0
  235. package/lib/annotations.ts +622 -0
  236. package/lib/apply-buildup-colors.py +88 -0
  237. package/lib/build.ts +1013 -0
  238. package/lib/{citations.js → citations.ts} +38 -27
  239. package/lib/commands/{build.js → build.ts} +80 -27
  240. package/lib/commands/{citations.js → citations.ts} +36 -18
  241. package/lib/commands/{comments.js → comments.ts} +187 -54
  242. package/lib/commands/{context.js → context.ts} +18 -8
  243. package/lib/commands/{core.js → core.ts} +34 -20
  244. package/lib/commands/{doi.js → doi.ts} +32 -16
  245. package/lib/commands/{history.js → history.ts} +25 -12
  246. package/lib/commands/{index.js → index.ts} +9 -5
  247. package/lib/commands/{init.js → init.ts} +20 -8
  248. package/lib/commands/{response.js → response.ts} +47 -20
  249. package/lib/commands/{sections.js → sections.ts} +273 -68
  250. package/lib/commands/{utilities.js → utilities.ts} +338 -158
  251. package/lib/{comment-realign.js → comment-realign.ts} +117 -45
  252. package/lib/config.ts +84 -0
  253. package/lib/{crossref.js → crossref.ts} +213 -138
  254. package/lib/dependencies.ts +106 -0
  255. package/lib/doi-cache.ts +115 -0
  256. package/lib/{doi.js → doi.ts} +115 -281
  257. package/lib/{equations.js → equations.ts} +60 -64
  258. package/lib/{errors.js → errors.ts} +56 -48
  259. package/lib/{format.js → format.ts} +137 -63
  260. package/lib/{git.js → git.ts} +66 -63
  261. package/lib/{grammar.js → grammar.ts} +45 -32
  262. package/lib/image-registry.ts +180 -0
  263. package/lib/import.ts +2060 -0
  264. package/lib/journals.ts +505 -0
  265. package/lib/{merge.js → merge.ts} +185 -135
  266. package/lib/{orcid.js → orcid.ts} +17 -22
  267. package/lib/{pdf-comments.js → pdf-comments.ts} +76 -18
  268. package/lib/{pdf-import.js → pdf-import.ts} +148 -70
  269. package/lib/{plugins.js → plugins.ts} +82 -39
  270. package/lib/postprocess.ts +188 -0
  271. package/lib/pptx-color-filter.lua +37 -0
  272. package/lib/pptx-template.ts +625 -0
  273. package/lib/pptx-themes/academic.pptx +0 -0
  274. package/lib/pptx-themes/corporate.pptx +0 -0
  275. package/lib/pptx-themes/dark.pptx +0 -0
  276. package/lib/pptx-themes/default.pptx +0 -0
  277. package/lib/pptx-themes/minimal.pptx +0 -0
  278. package/lib/pptx-themes/plant.pptx +0 -0
  279. package/lib/pptx-themes.ts +896 -0
  280. package/lib/protect-restore.ts +516 -0
  281. package/lib/rate-limiter.ts +94 -0
  282. package/lib/{response.js → response.ts} +36 -21
  283. package/lib/{review.js → review.ts} +53 -43
  284. package/lib/{schema.js → schema.ts} +70 -25
  285. package/lib/{sections.js → sections.ts} +71 -76
  286. package/lib/slides.ts +793 -0
  287. package/lib/{spelling.js → spelling.ts} +43 -59
  288. package/lib/{templates.js → templates.ts} +20 -17
  289. package/lib/themes.ts +742 -0
  290. package/lib/{trackchanges.js → trackchanges.ts} +52 -23
  291. package/lib/types.ts +509 -0
  292. package/lib/{undo.js → undo.ts} +75 -52
  293. package/lib/utils.ts +41 -0
  294. package/lib/{variables.js → variables.ts} +60 -54
  295. package/lib/word.ts +428 -0
  296. package/lib/{wordcomments.js → wordcomments.ts} +94 -40
  297. package/package.json +15 -5
  298. package/skill/REFERENCE.md +67 -0
  299. package/tsconfig.json +26 -0
  300. package/lib/annotations.js +0 -414
  301. package/lib/build.js +0 -639
  302. package/lib/config.js +0 -79
  303. package/lib/import.js +0 -1145
  304. package/lib/journals.js +0 -629
  305. package/lib/word.js +0 -225
  306. /package/lib/{scientific-words.js → scientific-words.ts} +0 -0
package/lib/journals.js DELETED
@@ -1,629 +0,0 @@
1
- /**
2
- * Journal validation profiles
3
- * Check manuscripts against journal-specific requirements
4
- */
5
-
6
- import * as fs from 'fs';
7
- import * as path from 'path';
8
- import { loadCustomProfiles } from './plugins.js';
9
-
10
- /**
11
- * Journal requirement profiles
12
- * Based on publicly available author guidelines
13
- */
14
- export const JOURNAL_PROFILES = {
15
- nature: {
16
- name: 'Nature',
17
- url: 'https://www.nature.com/nature/for-authors',
18
- requirements: {
19
- wordLimit: { main: 3000, abstract: 150, title: 90 },
20
- references: { max: 50, doiRequired: true },
21
- figures: { max: 6, combinedWithTables: true },
22
- sections: {
23
- required: ['Abstract', 'Introduction', 'Results', 'Discussion', 'Methods'],
24
- methodsPosition: 'end',
25
- },
26
- authors: { maxInitial: null, correspondingRequired: true },
27
- },
28
- },
29
-
30
- science: {
31
- name: 'Science',
32
- url: 'https://www.science.org/content/page/instructions-preparing-initial-manuscript',
33
- requirements: {
34
- wordLimit: { main: 2500, abstract: 125, title: 120 },
35
- references: { max: 40, doiRequired: true },
36
- figures: { max: 4, combinedWithTables: true },
37
- sections: {
38
- required: ['Abstract', 'Introduction', 'Results', 'Discussion'],
39
- supplementary: true,
40
- },
41
- authors: { maxInitial: null, correspondingRequired: true },
42
- },
43
- },
44
-
45
- 'plos-one': {
46
- name: 'PLOS ONE',
47
- url: 'https://journals.plos.org/plosone/s/submission-guidelines',
48
- requirements: {
49
- wordLimit: { main: null, abstract: 300, title: 250 },
50
- references: { max: null, doiRequired: false },
51
- figures: { max: null, combinedWithTables: false },
52
- sections: {
53
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
54
- methodsPosition: 'before-results',
55
- },
56
- authors: { maxInitial: null, correspondingRequired: true },
57
- dataAvailability: true,
58
- },
59
- },
60
-
61
- 'pnas': {
62
- name: 'PNAS',
63
- url: 'https://www.pnas.org/author-center/submitting-your-manuscript',
64
- requirements: {
65
- wordLimit: { main: 4500, abstract: 250, title: null },
66
- references: { max: 50, doiRequired: true },
67
- figures: { max: 6, combinedWithTables: true },
68
- sections: {
69
- required: ['Abstract', 'Introduction', 'Results', 'Discussion'],
70
- significanceStatement: true,
71
- },
72
- authors: { maxInitial: null, correspondingRequired: true },
73
- },
74
- },
75
-
76
- 'ecology-letters': {
77
- name: 'Ecology Letters',
78
- url: 'https://onlinelibrary.wiley.com/page/journal/14610248/homepage/forauthors.html',
79
- requirements: {
80
- wordLimit: { main: 5000, abstract: 150, title: null },
81
- references: { max: 50, doiRequired: true },
82
- figures: { max: 6, combinedWithTables: true },
83
- sections: {
84
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
85
- },
86
- authors: { maxInitial: null, correspondingRequired: true },
87
- keywords: { min: 3, max: 10 },
88
- },
89
- },
90
-
91
- 'ecological-applications': {
92
- name: 'Ecological Applications',
93
- url: 'https://esajournals.onlinelibrary.wiley.com/hub/journal/19395582/author-guidelines',
94
- requirements: {
95
- wordLimit: { main: 7000, abstract: 350, title: null },
96
- references: { max: null, doiRequired: true },
97
- figures: { max: null, combinedWithTables: false },
98
- sections: {
99
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
100
- },
101
- dataAvailability: true,
102
- },
103
- },
104
-
105
- 'molecular-ecology': {
106
- name: 'Molecular Ecology',
107
- url: 'https://onlinelibrary.wiley.com/page/journal/1365294x/homepage/forauthors.html',
108
- requirements: {
109
- wordLimit: { main: 8000, abstract: 250, title: null },
110
- references: { max: null, doiRequired: true },
111
- figures: { max: 8, combinedWithTables: false },
112
- sections: {
113
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
114
- },
115
- dataAvailability: true,
116
- keywords: { min: 4, max: 8 },
117
- },
118
- },
119
-
120
- 'elife': {
121
- name: 'eLife',
122
- url: 'https://reviewer.elifesciences.org/author-guide/full',
123
- requirements: {
124
- wordLimit: { main: null, abstract: 150, title: null },
125
- references: { max: null, doiRequired: true },
126
- figures: { max: null, combinedWithTables: false },
127
- sections: {
128
- required: ['Abstract', 'Introduction', 'Results', 'Discussion', 'Methods'],
129
- methodsPosition: 'end',
130
- },
131
- impactStatement: true,
132
- },
133
- },
134
-
135
- 'cell': {
136
- name: 'Cell',
137
- url: 'https://www.cell.com/cell/authors',
138
- requirements: {
139
- wordLimit: { main: 7000, abstract: 150, title: null },
140
- references: { max: 100, doiRequired: true },
141
- figures: { max: 7, combinedWithTables: true },
142
- sections: {
143
- required: ['Abstract', 'Introduction', 'Results', 'Discussion'],
144
- graphicalAbstract: true,
145
- highlights: true,
146
- },
147
- authors: { maxInitial: null, correspondingRequired: true },
148
- },
149
- },
150
-
151
- 'current-biology': {
152
- name: 'Current Biology',
153
- url: 'https://www.cell.com/current-biology/authors',
154
- requirements: {
155
- wordLimit: { main: 5000, abstract: 150, title: 150 },
156
- references: { max: 60, doiRequired: true },
157
- figures: { max: 4, combinedWithTables: true },
158
- sections: {
159
- required: ['Summary', 'Results', 'Discussion'],
160
- },
161
- authors: { maxInitial: null, correspondingRequired: true },
162
- },
163
- },
164
-
165
- 'conservation-biology': {
166
- name: 'Conservation Biology',
167
- url: 'https://conbio.onlinelibrary.wiley.com/hub/journal/15231739/homepage/forauthors.html',
168
- requirements: {
169
- wordLimit: { main: 7000, abstract: 300, title: null },
170
- references: { max: null, doiRequired: true },
171
- figures: { max: 6, combinedWithTables: true },
172
- sections: {
173
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
174
- },
175
- keywords: { min: 5, max: 10 },
176
- },
177
- },
178
-
179
- 'biological-conservation': {
180
- name: 'Biological Conservation',
181
- url: 'https://www.elsevier.com/journals/biological-conservation/0006-3207/guide-for-authors',
182
- requirements: {
183
- wordLimit: { main: 8000, abstract: 400, title: null },
184
- references: { max: null, doiRequired: true },
185
- figures: { max: null, combinedWithTables: false },
186
- sections: {
187
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
188
- },
189
- highlights: true,
190
- keywords: { min: 4, max: 6 },
191
- },
192
- },
193
-
194
- 'journal-of-ecology': {
195
- name: 'Journal of Ecology',
196
- url: 'https://besjournals.onlinelibrary.wiley.com/hub/journal/13652745/author-guidelines',
197
- requirements: {
198
- wordLimit: { main: 7000, abstract: 350, title: null },
199
- references: { max: null, doiRequired: true },
200
- figures: { max: null, combinedWithTables: false },
201
- sections: {
202
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
203
- },
204
- keywords: { min: 4, max: 8 },
205
- },
206
- },
207
-
208
- 'functional-ecology': {
209
- name: 'Functional Ecology',
210
- url: 'https://besjournals.onlinelibrary.wiley.com/hub/journal/13652435/author-guidelines',
211
- requirements: {
212
- wordLimit: { main: 7000, abstract: 350, title: null },
213
- references: { max: null, doiRequired: true },
214
- figures: { max: null, combinedWithTables: false },
215
- sections: {
216
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
217
- },
218
- keywords: { min: 4, max: 8 },
219
- },
220
- },
221
-
222
- 'global-change-biology': {
223
- name: 'Global Change Biology',
224
- url: 'https://onlinelibrary.wiley.com/page/journal/13652486/homepage/forauthors.html',
225
- requirements: {
226
- wordLimit: { main: 7000, abstract: 300, title: null },
227
- references: { max: null, doiRequired: true },
228
- figures: { max: 8, combinedWithTables: false },
229
- sections: {
230
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
231
- },
232
- keywords: { min: 4, max: 8 },
233
- },
234
- },
235
-
236
- 'oikos': {
237
- name: 'Oikos',
238
- url: 'https://nsojournals.onlinelibrary.wiley.com/hub/journal/16000706/author-guidelines',
239
- requirements: {
240
- wordLimit: { main: 8000, abstract: 350, title: null },
241
- references: { max: null, doiRequired: true },
242
- figures: { max: null, combinedWithTables: false },
243
- sections: {
244
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
245
- },
246
- keywords: { min: 4, max: 10 },
247
- },
248
- },
249
-
250
- 'oecologia': {
251
- name: 'Oecologia',
252
- url: 'https://www.springer.com/journal/442/submission-guidelines',
253
- requirements: {
254
- wordLimit: { main: 8000, abstract: 250, title: null },
255
- references: { max: null, doiRequired: true },
256
- figures: { max: null, combinedWithTables: false },
257
- sections: {
258
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
259
- },
260
- keywords: { min: 4, max: 6 },
261
- },
262
- },
263
-
264
- 'biological-invasions': {
265
- name: 'Biological Invasions',
266
- url: 'https://www.springer.com/journal/10530/submission-guidelines',
267
- requirements: {
268
- wordLimit: { main: null, abstract: 250, title: null },
269
- references: { max: null, doiRequired: true },
270
- figures: { max: null, combinedWithTables: false },
271
- sections: {
272
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
273
- },
274
- keywords: { min: 4, max: 6 },
275
- },
276
- },
277
-
278
- 'diversity-distributions': {
279
- name: 'Diversity and Distributions',
280
- url: 'https://onlinelibrary.wiley.com/page/journal/14724642/homepage/forauthors.html',
281
- requirements: {
282
- wordLimit: { main: 6000, abstract: 300, title: null },
283
- references: { max: null, doiRequired: true },
284
- figures: { max: 6, combinedWithTables: true },
285
- sections: {
286
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
287
- },
288
- keywords: { min: 4, max: 8 },
289
- biosketch: true,
290
- },
291
- },
292
-
293
- 'neobiota': {
294
- name: 'NeoBiota',
295
- url: 'https://neobiota.pensoft.net/about#Author_Guidelines',
296
- requirements: {
297
- wordLimit: { main: null, abstract: 350, title: null },
298
- references: { max: null, doiRequired: true },
299
- figures: { max: null, combinedWithTables: false },
300
- sections: {
301
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
302
- },
303
- keywords: { min: 6, max: 12 },
304
- },
305
- },
306
-
307
- 'peerj': {
308
- name: 'PeerJ',
309
- url: 'https://peerj.com/about/author-instructions/',
310
- requirements: {
311
- wordLimit: { main: null, abstract: 500, title: null },
312
- references: { max: null, doiRequired: false },
313
- figures: { max: null, combinedWithTables: false },
314
- sections: {
315
- required: ['Abstract', 'Introduction', 'Methods', 'Results', 'Discussion'],
316
- },
317
- },
318
- },
319
- };
320
-
321
- /**
322
- * Get all profiles (built-in + custom)
323
- * Custom profiles override built-in ones with the same ID
324
- * @returns {Object<string, Object>}
325
- */
326
- function getAllProfiles() {
327
- const customProfiles = loadCustomProfiles();
328
- return { ...JOURNAL_PROFILES, ...customProfiles };
329
- }
330
-
331
- /**
332
- * List all available journal profiles
333
- * @param {object} options
334
- * @param {boolean} options.includeCustom - Include custom profiles (default: true)
335
- * @param {boolean} options.customOnly - Only show custom profiles
336
- * @returns {Array<{id: string, name: string, url: string, custom?: boolean}>}
337
- */
338
- export function listJournals(options = {}) {
339
- const { includeCustom = true, customOnly = false } = options;
340
-
341
- const profiles = customOnly
342
- ? loadCustomProfiles()
343
- : includeCustom
344
- ? getAllProfiles()
345
- : JOURNAL_PROFILES;
346
-
347
- return Object.entries(profiles).map(([id, profile]) => ({
348
- id,
349
- name: profile.name,
350
- url: profile.url,
351
- custom: profile.custom || false,
352
- }));
353
- }
354
-
355
- /**
356
- * Get a specific journal profile
357
- * @param {string} journalId
358
- * @returns {Object|null}
359
- */
360
- export function getJournalProfile(journalId) {
361
- const normalized = journalId.toLowerCase().replace(/\s+/g, '-');
362
- const profiles = getAllProfiles();
363
- return profiles[normalized] || null;
364
- }
365
-
366
- /**
367
- * Count words in text (excluding markdown syntax)
368
- * @param {string} text
369
- * @returns {number}
370
- */
371
- function countWords(text) {
372
- // Remove markdown syntax
373
- let clean = text
374
- .replace(/^---[\s\S]*?---/m, '') // YAML frontmatter
375
- .replace(/!\[.*?\]\(.*?\)/g, '') // Images
376
- .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // Links
377
- .replace(/#+\s*/g, '') // Headers
378
- .replace(/\*\*|__/g, '') // Bold
379
- .replace(/\*|_/g, '') // Italic
380
- .replace(/`[^`]+`/g, '') // Inline code
381
- .replace(/```[\s\S]*?```/g, '') // Code blocks
382
- .replace(/\{[^}]+\}/g, '') // CriticMarkup and attributes
383
- .replace(/@\w+:\w+/g, '') // Cross-references
384
- .replace(/@\w+/g, '') // Citations
385
- .replace(/\|[^|]+\|/g, ' ') // Table cells
386
- .replace(/[-=]{3,}/g, '') // Horizontal rules
387
- .replace(/\n+/g, ' ') // Newlines
388
- .replace(/\s+/g, ' ') // Multiple spaces
389
- .trim();
390
-
391
- return clean.split(/\s+/).filter(w => w.length > 0).length;
392
- }
393
-
394
- /**
395
- * Extract abstract from markdown
396
- * @param {string} text
397
- * @returns {string|null}
398
- */
399
- function extractAbstract(text) {
400
- // Try to find abstract section
401
- const patterns = [
402
- /^#+\s*Abstract\s*\n([\s\S]*?)(?=^#+|\Z)/mi,
403
- /^Abstract[:\s]*\n([\s\S]*?)(?=^#+|\n\n)/mi,
404
- ];
405
-
406
- for (const pattern of patterns) {
407
- const match = text.match(pattern);
408
- if (match) {
409
- return match[1].trim();
410
- }
411
- }
412
-
413
- return null;
414
- }
415
-
416
- /**
417
- * Extract title from markdown
418
- * @param {string} text
419
- * @returns {string|null}
420
- */
421
- function extractTitle(text) {
422
- // Try YAML frontmatter
423
- const yamlMatch = text.match(/^---\n[\s\S]*?title:\s*["']?([^"'\n]+)["']?[\s\S]*?\n---/m);
424
- if (yamlMatch) {
425
- return yamlMatch[1].trim();
426
- }
427
-
428
- // Try first H1
429
- const h1Match = text.match(/^#\s+(.+)$/m);
430
- if (h1Match) {
431
- return h1Match[1].trim();
432
- }
433
-
434
- return null;
435
- }
436
-
437
- /**
438
- * Extract sections from markdown
439
- * @param {string} text
440
- * @returns {string[]}
441
- */
442
- function extractSections(text) {
443
- const sections = [];
444
- const headerPattern = /^#+\s+(.+)$/gm;
445
- let match;
446
-
447
- while ((match = headerPattern.exec(text)) !== null) {
448
- sections.push(match[1].trim());
449
- }
450
-
451
- return sections;
452
- }
453
-
454
- /**
455
- * Count figures in markdown
456
- * @param {string} text
457
- * @returns {number}
458
- */
459
- function countFigures(text) {
460
- // Count images with figure captions
461
- const figurePattern = /!\[.*?\]\(.*?\)(\{#fig:[^}]+\})?/g;
462
- const matches = text.match(figurePattern) || [];
463
- return matches.length;
464
- }
465
-
466
- /**
467
- * Count tables in markdown
468
- * @param {string} text
469
- * @returns {number}
470
- */
471
- function countTables(text) {
472
- // Count tables (lines starting with |)
473
- const tablePattern = /^\|[^|]+\|/gm;
474
- const matches = text.match(tablePattern) || [];
475
- // Divide by approximate rows per table
476
- return Math.ceil(matches.length / 5);
477
- }
478
-
479
- /**
480
- * Count references/citations in markdown
481
- * @param {string} text
482
- * @returns {number}
483
- */
484
- function countReferences(text) {
485
- // Count unique citation keys
486
- const citationPattern = /@(\w+)/g;
487
- const citations = new Set();
488
- let match;
489
-
490
- while ((match = citationPattern.exec(text)) !== null) {
491
- // Exclude cross-refs like @fig:label
492
- if (!match[0].includes(':')) {
493
- citations.add(match[1]);
494
- }
495
- }
496
-
497
- return citations.size;
498
- }
499
-
500
- /**
501
- * Validate manuscript against journal requirements
502
- * @param {string} text - Markdown content
503
- * @param {string} journalId - Journal profile ID
504
- * @returns {{valid: boolean, errors: string[], warnings: string[], stats: Object}}
505
- */
506
- export function validateManuscript(text, journalId) {
507
- const profile = getJournalProfile(journalId);
508
-
509
- if (!profile) {
510
- return {
511
- valid: false,
512
- errors: [`Unknown journal: ${journalId}`],
513
- warnings: [],
514
- stats: null,
515
- };
516
- }
517
-
518
- const req = profile.requirements;
519
- const errors = [];
520
- const warnings = [];
521
-
522
- // Extract content
523
- const abstract = extractAbstract(text);
524
- const title = extractTitle(text);
525
- const sections = extractSections(text);
526
- const mainWordCount = countWords(text);
527
- const figureCount = countFigures(text);
528
- const tableCount = countTables(text);
529
- const refCount = countReferences(text);
530
-
531
- const stats = {
532
- wordCount: mainWordCount,
533
- abstractWords: abstract ? countWords(abstract) : 0,
534
- titleChars: title ? title.length : 0,
535
- figures: figureCount,
536
- tables: tableCount,
537
- references: refCount,
538
- sections: sections.length,
539
- };
540
-
541
- // Word limits
542
- if (req.wordLimit) {
543
- if (req.wordLimit.main && mainWordCount > req.wordLimit.main) {
544
- errors.push(`Main text exceeds ${req.wordLimit.main} words (current: ${mainWordCount})`);
545
- }
546
- if (req.wordLimit.abstract && abstract) {
547
- const absWords = countWords(abstract);
548
- if (absWords > req.wordLimit.abstract) {
549
- errors.push(`Abstract exceeds ${req.wordLimit.abstract} words (current: ${absWords})`);
550
- }
551
- }
552
- if (req.wordLimit.title && title) {
553
- if (title.length > req.wordLimit.title) {
554
- warnings.push(`Title exceeds ${req.wordLimit.title} characters (current: ${title.length})`);
555
- }
556
- }
557
- }
558
-
559
- // References
560
- if (req.references) {
561
- if (req.references.max && refCount > req.references.max) {
562
- errors.push(`References exceed ${req.references.max} (current: ${refCount})`);
563
- }
564
- if (req.references.doiRequired) {
565
- warnings.push('DOI required for all references - run "rev doi check" to verify');
566
- }
567
- }
568
-
569
- // Figures/tables
570
- if (req.figures) {
571
- const totalVisual = req.figures.combinedWithTables
572
- ? figureCount + tableCount
573
- : figureCount;
574
- const label = req.figures.combinedWithTables ? 'figures + tables' : 'figures';
575
-
576
- if (req.figures.max && totalVisual > req.figures.max) {
577
- errors.push(`${label} exceed ${req.figures.max} (current: ${totalVisual})`);
578
- }
579
- }
580
-
581
- // Required sections
582
- if (req.sections?.required) {
583
- for (const reqSection of req.sections.required) {
584
- const found = sections.some(s =>
585
- s.toLowerCase().includes(reqSection.toLowerCase())
586
- );
587
- if (!found) {
588
- warnings.push(`Missing required section: ${reqSection}`);
589
- }
590
- }
591
- }
592
-
593
- // Data availability
594
- if (req.dataAvailability) {
595
- const hasDataStatement = sections.some(s =>
596
- s.toLowerCase().includes('data') ||
597
- text.toLowerCase().includes('data availability') ||
598
- text.toLowerCase().includes('data statement')
599
- );
600
- if (!hasDataStatement) {
601
- warnings.push('Data availability statement may be required');
602
- }
603
- }
604
-
605
- return {
606
- valid: errors.length === 0,
607
- errors,
608
- warnings,
609
- stats,
610
- journal: profile.name,
611
- url: profile.url,
612
- };
613
- }
614
-
615
- /**
616
- * Validate multiple files against journal requirements
617
- * @param {string[]} files - Markdown file paths
618
- * @param {string} journalId - Journal profile ID
619
- * @returns {Object}
620
- */
621
- export function validateProject(files, journalId) {
622
- // Combine all file contents
623
- const combined = files
624
- .filter(f => fs.existsSync(f))
625
- .map(f => fs.readFileSync(f, 'utf-8'))
626
- .join('\n\n');
627
-
628
- return validateManuscript(combined, journalId);
629
- }