@manuscripts/transform 4.3.52 → 4.4.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.
Files changed (175) hide show
  1. package/dist/cjs/jats/__tests__/jats-roundtrip.test.js +3 -3
  2. package/dist/cjs/schema/types.js +18 -0
  3. package/dist/cjs/version.js +1 -1
  4. package/dist/es/jats/__tests__/jats-roundtrip.test.js +3 -3
  5. package/dist/es/schema/types.js +17 -0
  6. package/dist/es/version.js +1 -1
  7. package/dist/types/jats/__tests__/utils.d.ts +1 -1
  8. package/dist/types/schema/types.d.ts +16 -0
  9. package/dist/types/version.d.ts +1 -1
  10. package/package.json +22 -21
  11. package/src/errors.ts +28 -0
  12. package/src/getVersion.ts +21 -0
  13. package/src/index.ts +28 -0
  14. package/src/jats/__tests__/__fixtures__/debug-example.xml +136 -0
  15. package/src/jats/__tests__/__fixtures__/jats-abstract-no-body.xml +163 -0
  16. package/src/jats/__tests__/__fixtures__/jats-citations.xml +472 -0
  17. package/src/jats/__tests__/__fixtures__/jats-comments.xml +46 -0
  18. package/src/jats/__tests__/__fixtures__/jats-document.xml +134 -0
  19. package/src/jats/__tests__/__fixtures__/jats-example-doc.xml +1235 -0
  20. package/src/jats/__tests__/__fixtures__/jats-example-front-only.xml +26 -0
  21. package/src/jats/__tests__/__fixtures__/jats-example-full.xml +209 -0
  22. package/src/jats/__tests__/__fixtures__/jats-example-no-back.xml +156 -0
  23. package/src/jats/__tests__/__fixtures__/jats-example-no-body.xml +91 -0
  24. package/src/jats/__tests__/__fixtures__/jats-example.xml +221 -0
  25. package/src/jats/__tests__/__fixtures__/jats-fn-group.xml +60 -0
  26. package/src/jats/__tests__/__fixtures__/jats-import-no-refs.xml +1077 -0
  27. package/src/jats/__tests__/__fixtures__/jats-import.xml +1561 -0
  28. package/src/jats/__tests__/__fixtures__/jats-roundtrip.xml +133 -0
  29. package/src/jats/__tests__/__fixtures__/jats-tables-example.xml +2043 -0
  30. package/src/jats/__tests__/__fixtures__/math-fragment.xml +12 -0
  31. package/src/jats/__tests__/__snapshots__/citeproc.test.ts.snap +57 -0
  32. package/src/jats/__tests__/__snapshots__/create-article-node.test.ts.snap +65 -0
  33. package/src/jats/__tests__/__snapshots__/jats-exporter.test.ts.snap +7 -0
  34. package/src/jats/__tests__/__snapshots__/jats-importer.test.ts.snap +59605 -0
  35. package/src/jats/__tests__/__snapshots__/jats-roundtrip.test.ts.snap +18 -0
  36. package/src/jats/__tests__/citations.ts +25 -0
  37. package/src/jats/__tests__/citeproc.test.ts +195 -0
  38. package/src/jats/__tests__/create-article-node.test.ts +29 -0
  39. package/src/jats/__tests__/data/section-categories.ts +212 -0
  40. package/src/jats/__tests__/files.ts +24 -0
  41. package/src/jats/__tests__/jats-exporter.test.ts +223 -0
  42. package/src/jats/__tests__/jats-importer.test.ts +567 -0
  43. package/src/jats/__tests__/jats-roundtrip.test.ts +66 -0
  44. package/src/jats/__tests__/utils.ts +90 -0
  45. package/src/jats/exporter/citeproc.ts +265 -0
  46. package/src/jats/exporter/jats-exporter.ts +2090 -0
  47. package/src/jats/exporter/jats-versions.ts +50 -0
  48. package/src/jats/exporter/labels.ts +101 -0
  49. package/src/jats/importer/create-article-node.ts +52 -0
  50. package/src/jats/importer/jats-comments.ts +111 -0
  51. package/src/jats/importer/jats-dom-parser.ts +1260 -0
  52. package/src/jats/importer/jats-parser-utils.ts +234 -0
  53. package/src/jats/importer/jats-transformations.ts +591 -0
  54. package/src/jats/importer/parse-jats-article.ts +106 -0
  55. package/src/jats/index.ts +21 -0
  56. package/src/jats/types.ts +16 -0
  57. package/src/lib/__tests__/footnotes.test.ts +36 -0
  58. package/src/lib/citeproc.ts +30 -0
  59. package/src/lib/credit-roles.ts +91 -0
  60. package/src/lib/deafults.ts +17 -0
  61. package/src/lib/footnotes.ts +85 -0
  62. package/src/lib/html.ts +56 -0
  63. package/src/lib/section-categories.ts +27 -0
  64. package/src/lib/utils.ts +145 -0
  65. package/src/lib/xml.ts +28 -0
  66. package/src/schema/__tests__/docs.ts +1911 -0
  67. package/src/schema/__tests__/groups.test.ts +61 -0
  68. package/src/schema/__tests__/migration.test.ts +23 -0
  69. package/src/schema/groups.ts +36 -0
  70. package/src/schema/index.ts +286 -0
  71. package/src/schema/marks.ts +254 -0
  72. package/src/schema/migration/migrate.ts +77 -0
  73. package/src/schema/migration/migration-script.ts +26 -0
  74. package/src/schema/migration/migration-scripts/1.2.5.ts +44 -0
  75. package/src/schema/migration/migration-scripts/2.3.22.ts +52 -0
  76. package/src/schema/migration/migration-scripts/3.0.12.ts +33 -0
  77. package/src/schema/migration/migration-scripts/3.0.21.ts +50 -0
  78. package/src/schema/migration/migration-scripts/3.0.30.ts +65 -0
  79. package/src/schema/migration/migration-scripts/3.0.31.ts +40 -0
  80. package/src/schema/migration/migration-scripts/3.0.41.ts +37 -0
  81. package/src/schema/migration/migration-scripts/3.0.55.ts +42 -0
  82. package/src/schema/migration/migration-scripts/3.0.56.ts +114 -0
  83. package/src/schema/migration/migration-scripts/4.2.13.ts +37 -0
  84. package/src/schema/migration/migration-scripts/4.2.15.ts +48 -0
  85. package/src/schema/migration/migration-scripts/4.3.23.ts +55 -0
  86. package/src/schema/migration/migration-scripts/4.3.34.ts +132 -0
  87. package/src/schema/migration/migration-scripts/4.3.35.ts +41 -0
  88. package/src/schema/migration/migration-scripts/index.ts +49 -0
  89. package/src/schema/nodes/abstracts.ts +29 -0
  90. package/src/schema/nodes/affiliation.ts +88 -0
  91. package/src/schema/nodes/affiliations.ts +30 -0
  92. package/src/schema/nodes/alt_text.ts +36 -0
  93. package/src/schema/nodes/alt_title.ts +40 -0
  94. package/src/schema/nodes/alt_titles_section.ts +58 -0
  95. package/src/schema/nodes/attachment.ts +46 -0
  96. package/src/schema/nodes/attachments.ts +45 -0
  97. package/src/schema/nodes/attribution.ts +38 -0
  98. package/src/schema/nodes/author_notes.ts +44 -0
  99. package/src/schema/nodes/award.ts +52 -0
  100. package/src/schema/nodes/awards.ts +45 -0
  101. package/src/schema/nodes/backmatter.ts +31 -0
  102. package/src/schema/nodes/bibliography_element.ts +58 -0
  103. package/src/schema/nodes/bibliography_item.ts +108 -0
  104. package/src/schema/nodes/bibliography_section.ts +60 -0
  105. package/src/schema/nodes/blockquote_element.ts +79 -0
  106. package/src/schema/nodes/body.ts +29 -0
  107. package/src/schema/nodes/box_element.ts +67 -0
  108. package/src/schema/nodes/caption.ts +67 -0
  109. package/src/schema/nodes/caption_title.ts +67 -0
  110. package/src/schema/nodes/citation.ts +70 -0
  111. package/src/schema/nodes/comment.ts +50 -0
  112. package/src/schema/nodes/comments.ts +28 -0
  113. package/src/schema/nodes/contributor.ts +87 -0
  114. package/src/schema/nodes/contributors.ts +40 -0
  115. package/src/schema/nodes/core_section.ts +27 -0
  116. package/src/schema/nodes/corresp.ts +49 -0
  117. package/src/schema/nodes/cross_reference.ts +64 -0
  118. package/src/schema/nodes/doc.ts +21 -0
  119. package/src/schema/nodes/embed.ts +55 -0
  120. package/src/schema/nodes/equation.ts +65 -0
  121. package/src/schema/nodes/equation_element.ts +61 -0
  122. package/src/schema/nodes/figure.ts +65 -0
  123. package/src/schema/nodes/figure_element.ts +73 -0
  124. package/src/schema/nodes/footnote.ts +95 -0
  125. package/src/schema/nodes/footnotes_element.ts +69 -0
  126. package/src/schema/nodes/footnotes_section.ts +61 -0
  127. package/src/schema/nodes/general_table_footnote.ts +42 -0
  128. package/src/schema/nodes/graphical_abstract_section.ts +62 -0
  129. package/src/schema/nodes/hard_break.ts +36 -0
  130. package/src/schema/nodes/hero_image.ts +46 -0
  131. package/src/schema/nodes/highlight_marker.ts +68 -0
  132. package/src/schema/nodes/image_element.ts +49 -0
  133. package/src/schema/nodes/inline_equation.ts +68 -0
  134. package/src/schema/nodes/inline_footnote.ts +66 -0
  135. package/src/schema/nodes/keyword.ts +61 -0
  136. package/src/schema/nodes/keyword_group.ts +63 -0
  137. package/src/schema/nodes/keywords.ts +59 -0
  138. package/src/schema/nodes/keywords_element.ts +64 -0
  139. package/src/schema/nodes/link.ts +79 -0
  140. package/src/schema/nodes/list.ts +134 -0
  141. package/src/schema/nodes/listing.ts +91 -0
  142. package/src/schema/nodes/listing_element.ts +61 -0
  143. package/src/schema/nodes/long_desc.ts +36 -0
  144. package/src/schema/nodes/manuscript.ts +86 -0
  145. package/src/schema/nodes/missing_figure.ts +59 -0
  146. package/src/schema/nodes/paragraph.ts +77 -0
  147. package/src/schema/nodes/placeholder.ts +62 -0
  148. package/src/schema/nodes/placeholder_element.ts +60 -0
  149. package/src/schema/nodes/pullquote_element.ts +81 -0
  150. package/src/schema/nodes/quote_image.ts +64 -0
  151. package/src/schema/nodes/section.ts +69 -0
  152. package/src/schema/nodes/section_label.ts +39 -0
  153. package/src/schema/nodes/section_title.ts +58 -0
  154. package/src/schema/nodes/subtitle.ts +40 -0
  155. package/src/schema/nodes/subtitles.ts +51 -0
  156. package/src/schema/nodes/supplement.ts +77 -0
  157. package/src/schema/nodes/supplements.ts +60 -0
  158. package/src/schema/nodes/table.ts +144 -0
  159. package/src/schema/nodes/table_col.ts +76 -0
  160. package/src/schema/nodes/table_element.ts +67 -0
  161. package/src/schema/nodes/table_element_footer.ts +42 -0
  162. package/src/schema/nodes/text.ts +31 -0
  163. package/src/schema/nodes/title.ts +43 -0
  164. package/src/schema/nodes/trans_abstract.ts +58 -0
  165. package/src/schema/nodes/trans_graphical_abstract.ts +67 -0
  166. package/src/schema/types.ts +240 -0
  167. package/src/tests.ts +33 -0
  168. package/src/transformer/id.ts +23 -0
  169. package/src/transformer/index.ts +21 -0
  170. package/src/transformer/node-names.ts +73 -0
  171. package/src/transformer/node-title.ts +111 -0
  172. package/src/transformer/node-types.ts +39 -0
  173. package/src/transformer/node-validator.ts +82 -0
  174. package/src/types.ts +25 -0
  175. package/src/version.ts +1 -0
@@ -0,0 +1,567 @@
1
+ /*!
2
+ * © 2020 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { schema } from '../../schema'
18
+ import { parseJATSArticle } from '../importer/parse-jats-article'
19
+ import { sectionCategories } from './data/section-categories'
20
+ import { readAndParseFixture } from './files'
21
+ import {
22
+ changeIDs,
23
+ createNodeFromJATS,
24
+ findNodeByType,
25
+ findNodesByType,
26
+ updateNodeID,
27
+ } from './utils'
28
+
29
+ describe('JATS importer', () => {
30
+ describe('title node', () => {
31
+ it('should have title node with content if title element exists', async () => {
32
+ const jats = await readAndParseFixture('jats-import.xml')
33
+ const node = parseJATSArticle(jats, sectionCategories)
34
+ const titleNode = findNodeByType(node, schema.nodes.title)
35
+ expect(titleNode).toBeDefined()
36
+ updateNodeID(titleNode)
37
+ expect(titleNode).toMatchSnapshot()
38
+ })
39
+ it('should have title node with default content if title element does not exist', async () => {
40
+ const jats = await readAndParseFixture('jats-import.xml')
41
+ const titleEl = jats.querySelector(
42
+ 'article-meta > title-group > article-title'
43
+ )
44
+ titleEl?.remove()
45
+ const node = parseJATSArticle(jats, sectionCategories)
46
+ const titleNode = findNodeByType(node, schema.nodes.title)
47
+ updateNodeID(titleNode)
48
+ expect(titleNode).toMatchSnapshot()
49
+ })
50
+ })
51
+ describe('contributors node', () => {
52
+ it('should have contributors node with content if contributors element exists', async () => {
53
+ const jats = await readAndParseFixture('jats-import.xml')
54
+ const node = parseJATSArticle(jats, sectionCategories)
55
+ changeIDs(node)
56
+ const contributorNodes = findNodesByType(node, schema.nodes.contributor)
57
+ expect(contributorNodes).toHaveLength(2)
58
+ expect(contributorNodes).toMatchSnapshot()
59
+ })
60
+ it('should not have contributors node if contributors element does not exist', async () => {
61
+ const jats = await readAndParseFixture('jats-import.xml')
62
+ const $contribGroup = jats.querySelector('article-meta > contrib-group')!
63
+ $contribGroup.remove()
64
+ const node = parseJATSArticle(jats, sectionCategories)
65
+ const contributorsNode = findNodesByType(node, schema.nodes.contributors)
66
+ const contributorNodes = findNodesByType(node, schema.nodes.contributor)
67
+ expect(contributorNodes).toHaveLength(0)
68
+ expect(contributorsNode).toHaveLength(0)
69
+ })
70
+ })
71
+ describe('affiliations', () => {
72
+ it('should correctly parse affiliation nodes', async () => {
73
+ const jats = await readAndParseFixture('jats-import.xml')
74
+ const node = parseJATSArticle(jats, sectionCategories)
75
+ const affiliationNodes = findNodesByType(node, schema.nodes.affiliation)
76
+ affiliationNodes.forEach(updateNodeID)
77
+ expect(affiliationNodes).toMatchSnapshot()
78
+ })
79
+ it('should not have affiliations node or affiliation nodes if affiliations element does not exist', async () => {
80
+ const jats = await readAndParseFixture('jats-import.xml')
81
+ const affiliationsElements = jats.querySelectorAll(
82
+ 'article-meta > contrib-group > aff'
83
+ )
84
+ affiliationsElements.forEach((aff) => {
85
+ aff.remove()
86
+ })
87
+ const node = parseJATSArticle(jats, sectionCategories)
88
+ const affiliationsNode = findNodeByType(node, schema.nodes.affiliations)
89
+ const affiliationNodes = findNodesByType(node, schema.nodes.affiliation)
90
+ expect(affiliationNodes).toHaveLength(0)
91
+ expect(affiliationsNode).toBeUndefined()
92
+ })
93
+ })
94
+ describe('author-notes', () => {
95
+ it('should have author notes node with content if author notes element exists', async () => {
96
+ const jats = await readAndParseFixture('jats-import.xml')
97
+ const node = parseJATSArticle(jats, sectionCategories)
98
+ const authorNotesNode = findNodeByType(node, schema.nodes.author_notes)
99
+ expect(authorNotesNode).toBeDefined()
100
+ expect(
101
+ findNodesByType(authorNotesNode, schema.nodes.footnote)
102
+ ).toHaveLength(2)
103
+ expect(
104
+ findNodesByType(authorNotesNode, schema.nodes.corresp)
105
+ ).toHaveLength(1)
106
+ changeIDs(authorNotesNode)
107
+ expect(authorNotesNode).toMatchSnapshot()
108
+ })
109
+ it('should not have author notes node if author notes element does not exist', async () => {
110
+ const jats = await readAndParseFixture('jats-import.xml')
111
+ const authorNotesEl = jats.querySelector('article-meta > author-notes')
112
+ authorNotesEl?.remove()
113
+ const node = parseJATSArticle(jats, sectionCategories)
114
+ const authorNotesNode = findNodeByType(node, schema.nodes.authorNotes)
115
+ expect(authorNotesNode).toBeUndefined()
116
+ })
117
+ })
118
+ describe('awards', () => {
119
+ it('should have awards node if awards element exists', async () => {
120
+ const jats = await readAndParseFixture('jats-import.xml')
121
+ const node = parseJATSArticle(jats, sectionCategories)
122
+ const awardsNode = findNodeByType(node, schema.nodes.awards)
123
+ expect(awardsNode).toBeDefined()
124
+ expect(
125
+ findNodesByType(awardsNode, schema.nodes.award).length
126
+ ).toBeGreaterThan(0)
127
+ })
128
+ it('should correctly parse award nodes', async () => {
129
+ const jats = await readAndParseFixture('jats-import.xml')
130
+ const node = parseJATSArticle(jats, sectionCategories)
131
+ const awardsNode = findNodeByType(node, schema.nodes.awards)
132
+ changeIDs(awardsNode)
133
+ expect(awardsNode).toMatchSnapshot()
134
+ })
135
+ it('should not have awards node if awards element does not exist', async () => {
136
+ const jats = await readAndParseFixture('jats-import.xml')
137
+ const awardsEl = jats.querySelector('article-meta > funding-group')
138
+ awardsEl?.remove()
139
+ const node = parseJATSArticle(jats, sectionCategories)
140
+ const awardsNode = findNodeByType(node, schema.nodes.awards)
141
+ expect(awardsNode).toBeUndefined()
142
+ })
143
+ })
144
+ describe('keywords', () => {
145
+ it('should have keywords node with content if keywords element exists', async () => {
146
+ const jats = await readAndParseFixture('jats-import.xml')
147
+ const node = parseJATSArticle(jats, sectionCategories)
148
+ const keywords = findNodeByType(node, schema.nodes.keywords)
149
+ expect(keywords).toBeDefined()
150
+ const keywordsNodes = findNodesByType(keywords, schema.nodes.keyword)
151
+ const sectionTitle = findNodeByType(keywords, schema.nodes.section_title)
152
+ expect(sectionTitle).toBeDefined()
153
+ expect(sectionTitle.textContent).toBe('Keywords')
154
+ keywordsNodes.forEach(updateNodeID)
155
+ expect(keywordsNodes).toMatchSnapshot()
156
+ })
157
+ it('should not have keywords node if keywords element does not exist', async () => {
158
+ const jats = await readAndParseFixture('jats-import.xml')
159
+ const keywordGroup = jats.querySelector('kwd-group')
160
+ keywordGroup?.remove()
161
+ const node = parseJATSArticle(jats, sectionCategories)
162
+ const keywords = findNodeByType(node, schema.nodes.keywords)
163
+ expect(keywords).toBeUndefined()
164
+ })
165
+ })
166
+ describe('supplements', () => {
167
+ it('should have supplements node with content if supplementary-material elements exist', async () => {
168
+ const jats = await readAndParseFixture('jats-import.xml')
169
+ const node = parseJATSArticle(jats, sectionCategories)
170
+ const supplementsNode = findNodeByType(node, schema.nodes.supplement)
171
+ changeIDs(supplementsNode)
172
+ expect(supplementsNode).toMatchSnapshot()
173
+ })
174
+
175
+ it('should not have supplements node if supplementary-material elements do not exist', async () => {
176
+ const jats = await readAndParseFixture('jats-import.xml')
177
+ const supplementryMaterial = jats.querySelectorAll(
178
+ 'article-meta > supplementary-material'
179
+ )
180
+ supplementryMaterial.forEach((supplement) => {
181
+ supplement.remove()
182
+ })
183
+ const node = parseJATSArticle(jats, sectionCategories)
184
+ const supplementsNode = findNodeByType(node, schema.nodes.supplements)
185
+ expect(supplementsNode).toBeUndefined()
186
+ })
187
+ })
188
+ describe('comments', () => {
189
+ it('should parse keyword comment', async () => {
190
+ const jats = await readAndParseFixture('jats-comments.xml')
191
+ const node = parseJATSArticle(jats, sectionCategories)
192
+ const group = findNodeByType(node, schema.nodes.keyword_group)
193
+ const markers = findNodesByType(group, schema.nodes.highlight_marker)
194
+ expect(markers.length).toBe(0)
195
+
196
+ const groupID = group.attrs.id
197
+ const comments = findNodesByType(node, schema.nodes.comment)
198
+ const comment = comments.filter((c) => c.attrs.target === groupID)[0]
199
+ expect(comment.attrs.contents).toBe('Keyword comment')
200
+ })
201
+ it('should parse abstract comment', async () => {
202
+ const jats = await readAndParseFixture('jats-comments.xml')
203
+ const node = parseJATSArticle(jats, sectionCategories)
204
+ const abstracts = findNodeByType(node, schema.nodes.abstracts)
205
+ const paragraph = findNodeByType(abstracts, schema.nodes.paragraph)
206
+ const marker = findNodeByType(paragraph, schema.nodes.highlight_marker)
207
+ const commentID = marker.attrs.id
208
+
209
+ // @ts-ignore
210
+ marker.attrs.id = 'MPCommentAnnotation:test'
211
+ expect(paragraph.content).toMatchSnapshot()
212
+
213
+ const comments = findNodesByType(node, schema.nodes.comment)
214
+ const comment = comments.filter((c) => c.attrs.id === commentID)[0]
215
+ expect(comment.attrs.contents).toBe('Abstract comment')
216
+ })
217
+ it('should parse body comment', async () => {
218
+ const jats = await readAndParseFixture('jats-comments.xml')
219
+ const node = parseJATSArticle(jats, sectionCategories)
220
+ const body = findNodeByType(node, schema.nodes.body)
221
+ const paragraph = findNodeByType(body, schema.nodes.paragraph)
222
+ const marker = findNodeByType(paragraph, schema.nodes.highlight_marker)
223
+ const commentID = marker.attrs.id
224
+
225
+ // @ts-ignore
226
+ marker.attrs.id = 'MPCommentAnnotation:test'
227
+ expect(paragraph.content).toMatchSnapshot()
228
+
229
+ const comments = findNodesByType(node, schema.nodes.comment)
230
+ const comment = comments.filter((c) => c.attrs.id === commentID)[0]
231
+ expect(comment.attrs.contents).toBe('Body comment')
232
+ })
233
+ it('should parse back comment', async () => {
234
+ const jats = await readAndParseFixture('jats-comments.xml')
235
+ const node = parseJATSArticle(jats, sectionCategories)
236
+ const back = findNodeByType(node, schema.nodes.backmatter)
237
+ const paragraph = findNodeByType(back, schema.nodes.paragraph)
238
+ const marker = findNodeByType(paragraph, schema.nodes.highlight_marker)
239
+ const commentID = marker.attrs.id
240
+
241
+ // @ts-ignore
242
+ marker.attrs.id = 'MPCommentAnnotation:test'
243
+ expect(paragraph.content).toMatchSnapshot()
244
+
245
+ const comments = findNodesByType(node, schema.nodes.comment)
246
+ const comment = comments.filter((c) => c.attrs.id === commentID)[0]
247
+ expect(comment.attrs.contents).toBe('Back comment')
248
+ })
249
+ it('should parse ref-list comment', async () => {
250
+ const jats = await readAndParseFixture('jats-comments.xml')
251
+ const node = parseJATSArticle(jats, sectionCategories)
252
+ const element = findNodeByType(node, schema.nodes.bibliography_element)
253
+ const markers = findNodesByType(element, schema.nodes.highlight_marker)
254
+ expect(markers.length).toBe(0)
255
+
256
+ const item = element.child(0)
257
+ const itemID = item.attrs.id
258
+ const comments = findNodesByType(node, schema.nodes.comment)
259
+ const comment = comments.filter((c) => c.attrs.target === itemID)[0]
260
+ expect(comment.attrs.contents).toBe('Ref comment')
261
+ })
262
+ })
263
+ describe('attachments', () => {
264
+ it('should have attachment node if attachment exists', async () => {
265
+ const jats = await readAndParseFixture('jats-import.xml')
266
+ const node = parseJATSArticle(jats, sectionCategories)
267
+ const attachmentsNode = findNodeByType(node, schema.nodes.attachments)
268
+ expect(attachmentsNode).toBeDefined()
269
+ expect(
270
+ findNodesByType(attachmentsNode, schema.nodes.attachment).length
271
+ ).toBeGreaterThan(0)
272
+ })
273
+ it('should correctly parse self-uri element', async () => {
274
+ const jats = await readAndParseFixture('jats-import.xml')
275
+ const node = parseJATSArticle(jats, sectionCategories)
276
+ const attachmentNodes = findNodesByType(node, schema.nodes.attachment)
277
+ changeIDs(attachmentNodes[0])
278
+ expect(attachmentNodes[0].attrs.type).toBe('document')
279
+ expect(attachmentNodes[0]).toMatchSnapshot()
280
+ })
281
+ it('should correctly parse multiple self-uri element', async () => {
282
+ const jats = await readAndParseFixture('jats-import.xml')
283
+ const node = parseJATSArticle(jats, sectionCategories)
284
+ const attachmentNodes = findNodesByType(node, schema.nodes.attachment)
285
+ expect(attachmentNodes.length).toBe(2)
286
+ changeIDs(attachmentNodes[0])
287
+ changeIDs(attachmentNodes[1])
288
+
289
+ expect(attachmentNodes[0].attrs.type).toBe('document')
290
+ expect(attachmentNodes[1].attrs.type).toBe('document')
291
+
292
+ expect(attachmentNodes).toMatchSnapshot()
293
+ })
294
+ it('should not have attachments node if no attachment element does not exist', async () => {
295
+ const jats = await readAndParseFixture('jats-example.xml')
296
+ const node = parseJATSArticle(jats, sectionCategories)
297
+ const attachmentsNode = findNodeByType(node, schema.nodes.attachments)
298
+ expect(attachmentsNode).toBeUndefined()
299
+ })
300
+ })
301
+ describe('abstracts', () => {
302
+ it('should have abstract node if abstract element exists', async () => {
303
+ const jats = await readAndParseFixture('jats-import.xml')
304
+ const abstractsEl = jats.querySelector('front > article-meta > abstract')
305
+ if (!abstractsEl) {
306
+ throw new Error('Abstract element not found')
307
+ }
308
+ const node = parseJATSArticle(jats, sectionCategories)
309
+ const abstractsNode = findNodeByType(node, schema.nodes.abstracts)
310
+ expect(abstractsNode).toBeDefined()
311
+ })
312
+ it("should have an abstracts even if abstarcts element doesn't exist", async () => {
313
+ const jats = await readAndParseFixture('jats-import.xml')
314
+ const abstractsEl = jats.querySelector('front > article-meta > abstract')
315
+ abstractsEl?.remove()
316
+ const node = parseJATSArticle(jats, sectionCategories)
317
+ const abstractsNode = findNodeByType(node, schema.nodes.abstracts)
318
+ expect(abstractsNode).toBeDefined()
319
+ })
320
+ it('should have the correct number of sections', async () => {
321
+ const jats = await readAndParseFixture('jats-import.xml')
322
+ const abstractEl = jats.querySelector('front > article-meta > abstract')
323
+ if (!abstractEl) {
324
+ throw new Error('Abstract element not found')
325
+ }
326
+ const node = parseJATSArticle(jats, sectionCategories)
327
+ const abstractsNode = findNodeByType(node, schema.nodes.abstracts)
328
+ const sections = findNodesByType(abstractsNode, schema.nodes.section)
329
+ // first section is the abstract node
330
+ expect(sections).toHaveLength(6)
331
+ })
332
+ it('should set the title to Abstract if no title is provided', async () => {
333
+ const jats = await readAndParseFixture('jats-import.xml')
334
+ const abstractEl = jats.querySelector('front > article-meta > abstract')
335
+ if (!abstractEl) {
336
+ throw new Error('Abstract element not found')
337
+ }
338
+ const node = parseJATSArticle(jats, sectionCategories)
339
+ const abstractsNode = findNodeByType(node, schema.nodes.abstracts)
340
+ const sections = findNodesByType(abstractsNode, schema.nodes.section)
341
+ const firstSection = sections[0]
342
+ const titleNode = findNodeByType(firstSection, schema.nodes.section_title)
343
+ expect(titleNode.textContent).toBe('Abstract')
344
+ })
345
+ })
346
+
347
+ describe('body', () => {
348
+ it('should have body node if body element exists', async () => {
349
+ const jats = await readAndParseFixture('jats-import.xml')
350
+ const bodyEl = jats.querySelector('body')
351
+ if (!bodyEl) {
352
+ throw new Error('Body element not found')
353
+ }
354
+ const node = parseJATSArticle(jats, sectionCategories)
355
+ const bodyNode = findNodeByType(node, schema.nodes.body)
356
+ expect(bodyNode).toBeDefined()
357
+ })
358
+ it('should have the correct number of sections', async () => {
359
+ const jats = await readAndParseFixture('jats-import.xml')
360
+ const node = parseJATSArticle(jats, sectionCategories)
361
+ const bodyNode = findNodeByType(node, schema.nodes.body)
362
+ const sections = findNodesByType(bodyNode, schema.nodes.section, false)
363
+ expect(sections).toHaveLength(5)
364
+ })
365
+ it('should have a body node even if body element does not exist', async () => {
366
+ const jats = await readAndParseFixture('jats-import.xml')
367
+ const bodyEl = jats.querySelector('body')
368
+ bodyEl?.remove()
369
+ const node = parseJATSArticle(jats, sectionCategories)
370
+ const bodyNode = findNodeByType(node, schema.nodes.body)
371
+ expect(bodyNode).toBeDefined()
372
+ })
373
+ it('should create body element and append to article when body is missing', async () => {
374
+ const jats = await readAndParseFixture('jats-abstract-no-body.xml')
375
+ const node = parseJATSArticle(jats, sectionCategories)
376
+ const bodyNode = findNodeByType(node, schema.nodes.body)
377
+ expect(bodyNode).toBeDefined()
378
+ })
379
+ it('should have abstracts node even when no body element exists in JATS', async () => {
380
+ const jats = await readAndParseFixture('jats-abstract-no-body.xml')
381
+ const node = parseJATSArticle(jats, sectionCategories)
382
+ const abstractNode = findNodeByType(node, schema.nodes.abstracts)
383
+ expect(abstractNode).toBeDefined()
384
+ })
385
+ })
386
+ describe('backmatter', () => {
387
+ it('should have backmatter node if back element exists', async () => {
388
+ const jats = await readAndParseFixture('jats-import.xml')
389
+ const backEl = jats.querySelector('back')
390
+ if (!backEl) {
391
+ throw new Error('Back element not found')
392
+ }
393
+ const node = parseJATSArticle(jats, sectionCategories)
394
+ const backNode = findNodeByType(node, schema.nodes.backmatter)
395
+ expect(backNode).toBeDefined()
396
+ })
397
+ it('should have appendices section if app-group element exists', async () => {
398
+ const jats = await readAndParseFixture('jats-example-full.xml')
399
+ const appGroup = jats.querySelector('back > app-group')
400
+ if (!appGroup) {
401
+ throw new Error('App group element not found')
402
+ }
403
+ const node = parseJATSArticle(jats, sectionCategories)
404
+ const backNode = findNodeByType(node, schema.nodes.backmatter)
405
+ const appNode = findNodesByType(
406
+ backNode,
407
+ schema.nodes.section,
408
+ false
409
+ ).filter((node) => node.attrs.category === 'appendices')
410
+ expect(appNode).toHaveLength(1)
411
+ })
412
+ it('should correctly add back sections to the backmatter', async () => {
413
+ const jats = await readAndParseFixture('jats-example-full.xml')
414
+ const backEl = jats.querySelector('back')
415
+ if (!backEl) {
416
+ throw new Error('Back element not found')
417
+ }
418
+ const node = parseJATSArticle(jats, sectionCategories)
419
+ const backNode = findNodeByType(node, schema.nodes.backmatter)
420
+ const availabilitySection = findNodesByType(
421
+ backNode,
422
+ schema.nodes.section,
423
+ false
424
+ ).filter((node) => node.attrs.category === 'availability')
425
+ expect(availabilitySection).toHaveLength(1)
426
+ })
427
+ it('should create sections for special footnotes', async () => {
428
+ const jats = await readAndParseFixture('jats-example-full.xml')
429
+ const node = parseJATSArticle(jats, sectionCategories)
430
+ const backNode = findNodeByType(node, schema.nodes.backmatter)
431
+
432
+ const con = findNodesByType(backNode, schema.nodes.section, false).filter(
433
+ (node) => node.attrs.category === 'con'
434
+ )
435
+ const financialDisclosure = findNodesByType(
436
+ backNode,
437
+ schema.nodes.section,
438
+ false
439
+ ).filter((node) => node.attrs.category === 'financial-disclosure')
440
+ const conflict = findNodesByType(
441
+ backNode,
442
+ schema.nodes.section,
443
+ false
444
+ ).filter((node) => node.attrs.category === 'coi-statement')
445
+ expect(con).toHaveLength(1)
446
+ expect(financialDisclosure).toHaveLength(1)
447
+ expect(conflict).toHaveLength(1)
448
+ })
449
+ it('should have an endnotes section if either an endnotes section exists or there are footnotes', async () => {
450
+ const jats = await readAndParseFixture('jats-example-full.xml')
451
+ const node = parseJATSArticle(jats, sectionCategories)
452
+ const backNode = findNodeByType(node, schema.nodes.backmatter)
453
+ const endNotesSection = findNodesByType(
454
+ backNode,
455
+ schema.nodes.footnotes_section,
456
+ false
457
+ )
458
+ expect(endNotesSection).toHaveLength(1)
459
+ })
460
+ it('should have a references section if ref-list element exists', async () => {
461
+ const jats = await readAndParseFixture('jats-example-full.xml')
462
+ const refList = jats.querySelector('ref-list')
463
+ if (!refList) {
464
+ throw new Error('Ref list element not found')
465
+ }
466
+ const node = parseJATSArticle(jats, sectionCategories)
467
+ const backNode = findNodeByType(node, schema.nodes.backmatter)
468
+ const refSection = findNodesByType(
469
+ backNode,
470
+ schema.nodes.bibliography_section,
471
+ false
472
+ )
473
+ expect(refSection).toHaveLength(1)
474
+ })
475
+ it('should have an acknowledgements section if ack element exists', async () => {
476
+ const jats = await readAndParseFixture('jats-example-full.xml')
477
+ const ack = jats.querySelector('ack')
478
+ if (!ack) {
479
+ throw new Error('Ack element not found')
480
+ }
481
+ const node = parseJATSArticle(jats, sectionCategories)
482
+ const backNode = findNodeByType(node, schema.nodes.backmatter)
483
+ const ackSection = findNodesByType(
484
+ backNode,
485
+ schema.nodes.section,
486
+ false
487
+ ).filter((node) => node.attrs.category === 'acknowledgements')
488
+
489
+ expect(ackSection).toHaveLength(1)
490
+ })
491
+ it('should parse references correctly', async () => {
492
+ const jats = await readAndParseFixture('jats-example-full.xml')
493
+ const refList = jats.querySelector('back > ref-list')
494
+ if (!refList) {
495
+ throw new Error('Ref list element not found')
496
+ }
497
+ const node = parseJATSArticle(jats, sectionCategories)
498
+ const backNode = findNodeByType(node, schema.nodes.backmatter)
499
+ const refSection = findNodeByType(
500
+ backNode,
501
+ schema.nodes.bibliography_section
502
+ )
503
+ const bibliographyItems = findNodesByType(
504
+ refSection,
505
+ schema.nodes.bibliography_item
506
+ )
507
+ expect(bibliographyItems).toHaveLength(1)
508
+ expect(bibliographyItems[0].attrs.id).toBeDefined()
509
+ expect(bibliographyItems[0].attrs.author).toHaveLength(1)
510
+ updateNodeID(bibliographyItems[0])
511
+ bibliographyItems[0].attrs.author[0]._id = 'MPBibliographicName:test'
512
+ bibliographyItems[0].attrs.issued._id = 'MPBibliographicDate:test'
513
+ expect(bibliographyItems[0]).toMatchSnapshot()
514
+ })
515
+ it('should have the correct number of sections', async () => {
516
+ const jats = await readAndParseFixture('jats-example-full.xml')
517
+ const node = parseJATSArticle(jats, sectionCategories)
518
+ const backNode = findNodeByType(node, schema.nodes.backmatter)
519
+ expect(backNode.childCount).toBe(8)
520
+ })
521
+ it('should have a backmatter node even if back element does not exist', async () => {
522
+ const jats = await readAndParseFixture('jats-import.xml')
523
+ const backEl = jats.querySelector('back')
524
+ backEl?.remove()
525
+ const node = parseJATSArticle(jats, sectionCategories)
526
+ const backNode = findNodeByType(node, schema.nodes.backmatter)
527
+ expect(backNode).toBeDefined()
528
+ })
529
+ })
530
+
531
+ test('parses JATS to Manuscripts document', async () => {
532
+ const node = await createNodeFromJATS('jats-import.xml')
533
+ changeIDs(node)
534
+ expect(node).toMatchSnapshot()
535
+ })
536
+ test('parses JATS AuthorQueries example to Manuscripts document', async () => {
537
+ const node = await createNodeFromJATS('jats-document.xml')
538
+ changeIDs(node)
539
+ expect(node).toMatchSnapshot()
540
+ })
541
+ test('parses full JATS example to Manuscripts document', async () => {
542
+ const node = await createNodeFromJATS('jats-example-doc.xml')
543
+ changeIDs(node)
544
+ expect(node).toMatchSnapshot()
545
+ })
546
+ test("parses JATS article without references and doesn't create empty references section", async () => {
547
+ const node = await createNodeFromJATS('jats-import-no-refs.xml')
548
+ changeIDs(node)
549
+ expect(node).toMatchSnapshot()
550
+ })
551
+ test('parses JATS article to Manuscripts document', async () => {
552
+ const node = await createNodeFromJATS('jats-example.xml')
553
+ changeIDs(node)
554
+ expect(node).toMatchSnapshot()
555
+ })
556
+ test('parses JATS article with tables and table footnotes', async () => {
557
+ const node = await createNodeFromJATS('jats-tables-example.xml')
558
+ changeIDs(node)
559
+ expect(node).toMatchSnapshot()
560
+ })
561
+
562
+ test('parses JATS example full', async () => {
563
+ const node = await createNodeFromJATS('jats-example-full.xml')
564
+ changeIDs(node)
565
+ expect(node).toMatchSnapshot()
566
+ })
567
+ })
@@ -0,0 +1,66 @@
1
+ /*!
2
+ * © 2020 Atypon Systems LLC
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ import { parseXml } from 'libxmljs2'
18
+
19
+ import { JATSExporter } from '../exporter/jats-exporter'
20
+ import { parseJATSArticle } from '../importer/parse-jats-article'
21
+ import { DEFAULT_CSL_OPTIONS } from './citations'
22
+ import { sectionCategories } from './data/section-categories'
23
+ import { readFixture } from './files'
24
+
25
+ const parseXMLWithDTD = (data: string) =>
26
+ parseXml(data, {
27
+ dtdload: true,
28
+ dtdvalid: true,
29
+ nonet: true,
30
+ })
31
+
32
+ const roundtrip = async (filename: string) => {
33
+ const input = await readFixture(filename)
34
+ const doc = new DOMParser().parseFromString(input, 'application/xml')
35
+
36
+ const node = parseJATSArticle(doc, sectionCategories)
37
+
38
+ const exporter = new JATSExporter()
39
+ return await exporter.serializeToJATS(node, {
40
+ csl: DEFAULT_CSL_OPTIONS,
41
+ })
42
+ }
43
+
44
+ describe('JATS roundtrip', () => {
45
+ test('jats-import.xml roundtrip', async () => {
46
+ const jats = await roundtrip('jats-import.xml')
47
+ expect(jats).toMatchSnapshot()
48
+
49
+ const doc = parseXMLWithDTD(jats)
50
+ expect(doc.errors).toHaveLength(0)
51
+ }, 45000)
52
+ test('jats-roundtrip.xml roundtrip', async () => {
53
+ const jats = await roundtrip('jats-roundtrip.xml')
54
+ expect(jats).toMatchSnapshot()
55
+
56
+ const doc = parseXMLWithDTD(jats)
57
+ expect(doc.errors).toHaveLength(0)
58
+ }, 45000)
59
+ test('jats-citations.xml roundtrip', async () => {
60
+ const jats = await roundtrip('jats-citations.xml')
61
+ expect(jats).toMatchSnapshot()
62
+
63
+ const doc = parseXMLWithDTD(jats)
64
+ expect(doc.errors).toHaveLength(0)
65
+ }, 45000)
66
+ })