@manuscripts/transform 4.3.53 → 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 (172) hide show
  1. package/dist/cjs/jats/__tests__/jats-roundtrip.test.js +3 -3
  2. package/dist/cjs/version.js +1 -1
  3. package/dist/es/jats/__tests__/jats-roundtrip.test.js +3 -3
  4. package/dist/es/version.js +1 -1
  5. package/dist/types/jats/__tests__/utils.d.ts +1 -1
  6. package/dist/types/version.d.ts +1 -1
  7. package/package.json +22 -21
  8. package/src/errors.ts +28 -0
  9. package/src/getVersion.ts +21 -0
  10. package/src/index.ts +28 -0
  11. package/src/jats/__tests__/__fixtures__/debug-example.xml +136 -0
  12. package/src/jats/__tests__/__fixtures__/jats-abstract-no-body.xml +163 -0
  13. package/src/jats/__tests__/__fixtures__/jats-citations.xml +472 -0
  14. package/src/jats/__tests__/__fixtures__/jats-comments.xml +46 -0
  15. package/src/jats/__tests__/__fixtures__/jats-document.xml +134 -0
  16. package/src/jats/__tests__/__fixtures__/jats-example-doc.xml +1235 -0
  17. package/src/jats/__tests__/__fixtures__/jats-example-front-only.xml +26 -0
  18. package/src/jats/__tests__/__fixtures__/jats-example-full.xml +209 -0
  19. package/src/jats/__tests__/__fixtures__/jats-example-no-back.xml +156 -0
  20. package/src/jats/__tests__/__fixtures__/jats-example-no-body.xml +91 -0
  21. package/src/jats/__tests__/__fixtures__/jats-example.xml +221 -0
  22. package/src/jats/__tests__/__fixtures__/jats-fn-group.xml +60 -0
  23. package/src/jats/__tests__/__fixtures__/jats-import-no-refs.xml +1077 -0
  24. package/src/jats/__tests__/__fixtures__/jats-import.xml +1561 -0
  25. package/src/jats/__tests__/__fixtures__/jats-roundtrip.xml +133 -0
  26. package/src/jats/__tests__/__fixtures__/jats-tables-example.xml +2043 -0
  27. package/src/jats/__tests__/__fixtures__/math-fragment.xml +12 -0
  28. package/src/jats/__tests__/__snapshots__/citeproc.test.ts.snap +57 -0
  29. package/src/jats/__tests__/__snapshots__/create-article-node.test.ts.snap +65 -0
  30. package/src/jats/__tests__/__snapshots__/jats-exporter.test.ts.snap +7 -0
  31. package/src/jats/__tests__/__snapshots__/jats-importer.test.ts.snap +59605 -0
  32. package/src/jats/__tests__/__snapshots__/jats-roundtrip.test.ts.snap +18 -0
  33. package/src/jats/__tests__/citations.ts +25 -0
  34. package/src/jats/__tests__/citeproc.test.ts +195 -0
  35. package/src/jats/__tests__/create-article-node.test.ts +29 -0
  36. package/src/jats/__tests__/data/section-categories.ts +212 -0
  37. package/src/jats/__tests__/files.ts +24 -0
  38. package/src/jats/__tests__/jats-exporter.test.ts +223 -0
  39. package/src/jats/__tests__/jats-importer.test.ts +567 -0
  40. package/src/jats/__tests__/jats-roundtrip.test.ts +66 -0
  41. package/src/jats/__tests__/utils.ts +90 -0
  42. package/src/jats/exporter/citeproc.ts +265 -0
  43. package/src/jats/exporter/jats-exporter.ts +2090 -0
  44. package/src/jats/exporter/jats-versions.ts +50 -0
  45. package/src/jats/exporter/labels.ts +101 -0
  46. package/src/jats/importer/create-article-node.ts +52 -0
  47. package/src/jats/importer/jats-comments.ts +111 -0
  48. package/src/jats/importer/jats-dom-parser.ts +1260 -0
  49. package/src/jats/importer/jats-parser-utils.ts +234 -0
  50. package/src/jats/importer/jats-transformations.ts +591 -0
  51. package/src/jats/importer/parse-jats-article.ts +106 -0
  52. package/src/jats/index.ts +21 -0
  53. package/src/jats/types.ts +16 -0
  54. package/src/lib/__tests__/footnotes.test.ts +36 -0
  55. package/src/lib/citeproc.ts +30 -0
  56. package/src/lib/credit-roles.ts +91 -0
  57. package/src/lib/deafults.ts +17 -0
  58. package/src/lib/footnotes.ts +85 -0
  59. package/src/lib/html.ts +56 -0
  60. package/src/lib/section-categories.ts +27 -0
  61. package/src/lib/utils.ts +145 -0
  62. package/src/lib/xml.ts +28 -0
  63. package/src/schema/__tests__/docs.ts +1911 -0
  64. package/src/schema/__tests__/groups.test.ts +61 -0
  65. package/src/schema/__tests__/migration.test.ts +23 -0
  66. package/src/schema/groups.ts +36 -0
  67. package/src/schema/index.ts +286 -0
  68. package/src/schema/marks.ts +254 -0
  69. package/src/schema/migration/migrate.ts +77 -0
  70. package/src/schema/migration/migration-script.ts +26 -0
  71. package/src/schema/migration/migration-scripts/1.2.5.ts +44 -0
  72. package/src/schema/migration/migration-scripts/2.3.22.ts +52 -0
  73. package/src/schema/migration/migration-scripts/3.0.12.ts +33 -0
  74. package/src/schema/migration/migration-scripts/3.0.21.ts +50 -0
  75. package/src/schema/migration/migration-scripts/3.0.30.ts +65 -0
  76. package/src/schema/migration/migration-scripts/3.0.31.ts +40 -0
  77. package/src/schema/migration/migration-scripts/3.0.41.ts +37 -0
  78. package/src/schema/migration/migration-scripts/3.0.55.ts +42 -0
  79. package/src/schema/migration/migration-scripts/3.0.56.ts +114 -0
  80. package/src/schema/migration/migration-scripts/4.2.13.ts +37 -0
  81. package/src/schema/migration/migration-scripts/4.2.15.ts +48 -0
  82. package/src/schema/migration/migration-scripts/4.3.23.ts +55 -0
  83. package/src/schema/migration/migration-scripts/4.3.34.ts +132 -0
  84. package/src/schema/migration/migration-scripts/4.3.35.ts +41 -0
  85. package/src/schema/migration/migration-scripts/index.ts +49 -0
  86. package/src/schema/nodes/abstracts.ts +29 -0
  87. package/src/schema/nodes/affiliation.ts +88 -0
  88. package/src/schema/nodes/affiliations.ts +30 -0
  89. package/src/schema/nodes/alt_text.ts +36 -0
  90. package/src/schema/nodes/alt_title.ts +40 -0
  91. package/src/schema/nodes/alt_titles_section.ts +58 -0
  92. package/src/schema/nodes/attachment.ts +46 -0
  93. package/src/schema/nodes/attachments.ts +45 -0
  94. package/src/schema/nodes/attribution.ts +38 -0
  95. package/src/schema/nodes/author_notes.ts +44 -0
  96. package/src/schema/nodes/award.ts +52 -0
  97. package/src/schema/nodes/awards.ts +45 -0
  98. package/src/schema/nodes/backmatter.ts +31 -0
  99. package/src/schema/nodes/bibliography_element.ts +58 -0
  100. package/src/schema/nodes/bibliography_item.ts +108 -0
  101. package/src/schema/nodes/bibliography_section.ts +60 -0
  102. package/src/schema/nodes/blockquote_element.ts +79 -0
  103. package/src/schema/nodes/body.ts +29 -0
  104. package/src/schema/nodes/box_element.ts +67 -0
  105. package/src/schema/nodes/caption.ts +67 -0
  106. package/src/schema/nodes/caption_title.ts +67 -0
  107. package/src/schema/nodes/citation.ts +70 -0
  108. package/src/schema/nodes/comment.ts +50 -0
  109. package/src/schema/nodes/comments.ts +28 -0
  110. package/src/schema/nodes/contributor.ts +87 -0
  111. package/src/schema/nodes/contributors.ts +40 -0
  112. package/src/schema/nodes/core_section.ts +27 -0
  113. package/src/schema/nodes/corresp.ts +49 -0
  114. package/src/schema/nodes/cross_reference.ts +64 -0
  115. package/src/schema/nodes/doc.ts +21 -0
  116. package/src/schema/nodes/embed.ts +55 -0
  117. package/src/schema/nodes/equation.ts +65 -0
  118. package/src/schema/nodes/equation_element.ts +61 -0
  119. package/src/schema/nodes/figure.ts +65 -0
  120. package/src/schema/nodes/figure_element.ts +73 -0
  121. package/src/schema/nodes/footnote.ts +95 -0
  122. package/src/schema/nodes/footnotes_element.ts +69 -0
  123. package/src/schema/nodes/footnotes_section.ts +61 -0
  124. package/src/schema/nodes/general_table_footnote.ts +42 -0
  125. package/src/schema/nodes/graphical_abstract_section.ts +62 -0
  126. package/src/schema/nodes/hard_break.ts +36 -0
  127. package/src/schema/nodes/hero_image.ts +46 -0
  128. package/src/schema/nodes/highlight_marker.ts +68 -0
  129. package/src/schema/nodes/image_element.ts +49 -0
  130. package/src/schema/nodes/inline_equation.ts +68 -0
  131. package/src/schema/nodes/inline_footnote.ts +66 -0
  132. package/src/schema/nodes/keyword.ts +61 -0
  133. package/src/schema/nodes/keyword_group.ts +63 -0
  134. package/src/schema/nodes/keywords.ts +59 -0
  135. package/src/schema/nodes/keywords_element.ts +64 -0
  136. package/src/schema/nodes/link.ts +79 -0
  137. package/src/schema/nodes/list.ts +134 -0
  138. package/src/schema/nodes/listing.ts +91 -0
  139. package/src/schema/nodes/listing_element.ts +61 -0
  140. package/src/schema/nodes/long_desc.ts +36 -0
  141. package/src/schema/nodes/manuscript.ts +86 -0
  142. package/src/schema/nodes/missing_figure.ts +59 -0
  143. package/src/schema/nodes/paragraph.ts +77 -0
  144. package/src/schema/nodes/placeholder.ts +62 -0
  145. package/src/schema/nodes/placeholder_element.ts +60 -0
  146. package/src/schema/nodes/pullquote_element.ts +81 -0
  147. package/src/schema/nodes/quote_image.ts +64 -0
  148. package/src/schema/nodes/section.ts +69 -0
  149. package/src/schema/nodes/section_label.ts +39 -0
  150. package/src/schema/nodes/section_title.ts +58 -0
  151. package/src/schema/nodes/subtitle.ts +40 -0
  152. package/src/schema/nodes/subtitles.ts +51 -0
  153. package/src/schema/nodes/supplement.ts +77 -0
  154. package/src/schema/nodes/supplements.ts +60 -0
  155. package/src/schema/nodes/table.ts +144 -0
  156. package/src/schema/nodes/table_col.ts +76 -0
  157. package/src/schema/nodes/table_element.ts +67 -0
  158. package/src/schema/nodes/table_element_footer.ts +42 -0
  159. package/src/schema/nodes/text.ts +31 -0
  160. package/src/schema/nodes/title.ts +43 -0
  161. package/src/schema/nodes/trans_abstract.ts +58 -0
  162. package/src/schema/nodes/trans_graphical_abstract.ts +67 -0
  163. package/src/schema/types.ts +240 -0
  164. package/src/tests.ts +33 -0
  165. package/src/transformer/id.ts +23 -0
  166. package/src/transformer/index.ts +21 -0
  167. package/src/transformer/node-names.ts +73 -0
  168. package/src/transformer/node-title.ts +111 -0
  169. package/src/transformer/node-types.ts +39 -0
  170. package/src/transformer/node-validator.ts +82 -0
  171. package/src/types.ts +25 -0
  172. package/src/version.ts +1 -0
@@ -0,0 +1,16 @@
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
+ export type IDGenerator = (element: Element) => Promise<string | null>
@@ -0,0 +1,36 @@
1
+ /*!
2
+ * © 2024 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
+ import {
17
+ generateAlphaFootnoteLabel,
18
+ generateNumericFootnoteLabel,
19
+ } from '../footnotes'
20
+
21
+ describe('Footnotes alpha label generation', () => {
22
+ it('should start from "a"', () => {
23
+ const label = generateAlphaFootnoteLabel(0)
24
+ expect(label).toBe('a')
25
+ })
26
+ it('should generate 2 characters for large indexes', () => {
27
+ const label = generateAlphaFootnoteLabel(26)
28
+ expect(label).toBe('aa')
29
+ })
30
+ })
31
+ describe('Footnotes numeric label generation', () => {
32
+ it('should start from "1"', () => {
33
+ const label = generateNumericFootnoteLabel(0)
34
+ expect(label).toBe('1')
35
+ })
36
+ })
@@ -0,0 +1,30 @@
1
+ /*!
2
+ * © 2025 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
+ import * as Citeproc from 'citeproc'
17
+
18
+ import { CitationAttrs } from '../schema'
19
+
20
+ export const buildCiteprocCitation = (
21
+ citation: CitationAttrs
22
+ ): Citeproc.Citation => ({
23
+ citationID: citation.id,
24
+ citationItems: citation.rids.map((rid) => ({
25
+ id: rid,
26
+ })),
27
+ properties: {
28
+ noteIndex: 0,
29
+ },
30
+ })
@@ -0,0 +1,91 @@
1
+ /*!
2
+ * © 2025 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
+ export enum CreditVocabTerm {
18
+ Conceptualization = 'Conceptualization',
19
+ DataCuration = 'Data curation',
20
+ FormalAnalysis = 'Formal analysis',
21
+ FundingAcquisition = 'Funding acquisition',
22
+ Investigation = 'Investigation',
23
+ Methodology = 'Methodology',
24
+ ProjectAdministration = 'Project administration',
25
+ Resources = 'Resources',
26
+ Software = 'Software',
27
+ Supervision = 'Supervision',
28
+ Validation = 'Validation',
29
+ Visualization = 'Visualization',
30
+ WritingOriginalDraft = 'Writing – original draft',
31
+ WritingReviewEditing = 'Writing – review & editing',
32
+ }
33
+
34
+ export const CreditRoleUrls = new Map([
35
+ [
36
+ CreditVocabTerm.Conceptualization,
37
+ 'https://credit.niso.org/contributor-roles/conceptualization/',
38
+ ],
39
+ [
40
+ CreditVocabTerm.DataCuration,
41
+ 'https://credit.niso.org/contributor-roles/data-curation/',
42
+ ],
43
+ [
44
+ CreditVocabTerm.FormalAnalysis,
45
+ 'https://credit.niso.org/contributor-roles/formal-analysis/',
46
+ ],
47
+ [
48
+ CreditVocabTerm.FundingAcquisition,
49
+ 'https://credit.niso.org/contributor-roles/funding-acquisition/',
50
+ ],
51
+ [
52
+ CreditVocabTerm.Investigation,
53
+ 'https://credit.niso.org/contributor-roles/investigation/',
54
+ ],
55
+ [
56
+ CreditVocabTerm.Methodology,
57
+ 'https://credit.niso.org/contributor-roles/methodology/',
58
+ ],
59
+ [
60
+ CreditVocabTerm.ProjectAdministration,
61
+ 'https://credit.niso.org/contributor-roles/project-administration/',
62
+ ],
63
+ [
64
+ CreditVocabTerm.Resources,
65
+ 'https://credit.niso.org/contributor-roles/resources/',
66
+ ],
67
+ [
68
+ CreditVocabTerm.Software,
69
+ 'https://credit.niso.org/contributor-roles/software/',
70
+ ],
71
+ [
72
+ CreditVocabTerm.Supervision,
73
+ 'https://credit.niso.org/contributor-roles/supervision/',
74
+ ],
75
+ [
76
+ CreditVocabTerm.Validation,
77
+ 'https://credit.niso.org/contributor-roles/validation/',
78
+ ],
79
+ [
80
+ CreditVocabTerm.Visualization,
81
+ 'https://credit.niso.org/contributor-roles/visualization/',
82
+ ],
83
+ [
84
+ CreditVocabTerm.WritingOriginalDraft,
85
+ 'https://credit.niso.org/contributor-roles/writing-original-draft/',
86
+ ],
87
+ [
88
+ CreditVocabTerm.WritingReviewEditing,
89
+ 'https://credit.niso.org/contributor-roles/writing-review-editing/',
90
+ ],
91
+ ])
@@ -0,0 +1,17 @@
1
+ /*!
2
+ * © 2024 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
+ export const defaultTitle = 'Untitled Manuscript'
@@ -0,0 +1,85 @@
1
+ /*!
2
+ * © 2024 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
+ import {
17
+ isFootnotesElementNode,
18
+ isTableElementFooter,
19
+ ManuscriptNode,
20
+ } from '../schema'
21
+
22
+ export const generateFootnoteLabels = (doc: ManuscriptNode) => {
23
+ const labels = new Map()
24
+ doc.descendants((node, pos, parent) => {
25
+ if (isFootnotesElementNode(node) && parent) {
26
+ const generator = footnoteLabelGenerator(parent)
27
+ for (let i = 0; i < node.childCount; i++) {
28
+ const footnote = node.child(i)
29
+ const label = generator(i)
30
+ labels.set(footnote.attrs.id, label)
31
+ }
32
+ return false
33
+ }
34
+ })
35
+ return labels
36
+ }
37
+
38
+ export const footnoteLabelGenerator = (parent: ManuscriptNode) => {
39
+ if (isTableElementFooter(parent)) {
40
+ return generateNumericFootnoteLabel
41
+ } else {
42
+ return generateAlphaFootnoteLabel
43
+ }
44
+ }
45
+
46
+ export const generateNumericFootnoteLabel = (index: number) => String(index + 1)
47
+
48
+ export const generateAlphaFootnoteLabel = (index: number) => {
49
+ const unicodeInterval = [97, 123]
50
+ const places = unicodeInterval[1] - unicodeInterval[0]
51
+
52
+ function getClassCount(n: number, order: number) {
53
+ return n * Math.pow(places, order - 1)
54
+ }
55
+
56
+ let indices: number[] | null = null
57
+
58
+ for (;;) {
59
+ let current = index
60
+ let position = 1
61
+ while (current >= places) {
62
+ current = current / places
63
+ position++
64
+ }
65
+ const newIndex = Math.floor(current)
66
+ indices = indices ? indices : new Array(position).fill(0)
67
+ indices.splice(indices.length - position, 1, newIndex)
68
+
69
+ index -= getClassCount(newIndex, position)
70
+
71
+ if (position === 1) {
72
+ break
73
+ }
74
+ }
75
+ return (indices || [])
76
+ .map((v, i, array) => {
77
+ // offseting to start with zero for the second and later classes
78
+ // @TODO: find better solution instead of this indexing offset
79
+ if (array.length > 1 && i !== array.length - 1) {
80
+ return String.fromCodePoint(v + unicodeInterval[0] - 1)
81
+ }
82
+ return String.fromCodePoint(v + unicodeInterval[0])
83
+ })
84
+ .join('')
85
+ }
@@ -0,0 +1,56 @@
1
+ /*!
2
+ * © 2019 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
+ function decodeHTMLEntities(text: string) {
18
+ // those entities that pertain to XML are supported and don't need to be replaced (e.g.: &amp, &quote etc)
19
+ const entities = [
20
+ ['#x27', "'"],
21
+ ['#x2F', '/'],
22
+ ['#39', "'"],
23
+ ['#47', '/'],
24
+ ['nbsp', ' '],
25
+ ]
26
+
27
+ for (let i = 0; i < entities.length; i++) {
28
+ text = text.replace(
29
+ new RegExp('&' + entities[i][0] + ';', 'g'),
30
+ entities[i][1]
31
+ )
32
+ }
33
+
34
+ return text
35
+ }
36
+
37
+ export const nodeFromHTML = (html: string) => {
38
+ html = html.trim()
39
+
40
+ if (!html.length) {
41
+ return null
42
+ }
43
+
44
+ const template = document.createElement('template')
45
+
46
+ template.innerHTML = html
47
+ template.innerHTML = decodeHTMLEntities(template.innerHTML)
48
+ return template.content.firstChild
49
+ }
50
+
51
+ export const textFromHTML = (html: string) => {
52
+ const template = document.createElement('template')
53
+
54
+ template.innerHTML = html
55
+ return template.content.textContent
56
+ }
@@ -0,0 +1,27 @@
1
+ /*!
2
+ * © 2024 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 { SectionCategory, SectionGroup } from '../schema'
18
+
19
+ export const getGroupCategories = (
20
+ sections: Map<string, SectionCategory> | SectionCategory[],
21
+ group: SectionGroup
22
+ ): SectionCategory[] => {
23
+ const sectionsArray = Array.isArray(sections)
24
+ ? sections
25
+ : Array.from(sections.values())
26
+ return sectionsArray.filter((section) => section.group === group)
27
+ }
@@ -0,0 +1,145 @@
1
+ /*!
2
+ * © 2019 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 { Node as ProsemirrorNode, ResolvedPos } from 'prosemirror-model'
18
+
19
+ import { htmlFromJatsNode } from '../jats/importer/jats-parser-utils'
20
+ import {
21
+ CreditRole,
22
+ isBibliographySectionNode,
23
+ isGraphicalAbstractSectionNode,
24
+ ManuscriptEditorState,
25
+ ManuscriptNode,
26
+ } from '../schema'
27
+ import { CreditRoleUrls, CreditVocabTerm } from './credit-roles'
28
+
29
+ export function* iterateChildren(
30
+ node: ManuscriptNode,
31
+ recurse = false
32
+ ): Iterable<ManuscriptNode> {
33
+ for (let i = 0; i < node.childCount; i++) {
34
+ const child = node.child(i)
35
+ yield child
36
+
37
+ if (recurse) {
38
+ for (const grandchild of iterateChildren(child, true)) {
39
+ yield grandchild
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+ export const findNodePositions = (
46
+ state: ManuscriptEditorState,
47
+ predicate: (node: ManuscriptNode) => boolean
48
+ ) => {
49
+ const found: number[] = []
50
+ state.doc.descendants((node, nodePos) => {
51
+ if (predicate(node as ManuscriptNode)) {
52
+ found.push(nodePos)
53
+ }
54
+ return true
55
+ })
56
+ return found
57
+ }
58
+
59
+ export const isInGraphicalAbstractSection = ($pos: ResolvedPos): boolean => {
60
+ for (let i = $pos.depth; i > 0; i--) {
61
+ const node = $pos.node(i)
62
+ if (isGraphicalAbstractSectionNode(node)) {
63
+ return true
64
+ }
65
+ }
66
+ return false
67
+ }
68
+
69
+ export const isInBibliographySection = ($pos: ResolvedPos): boolean => {
70
+ for (let i = $pos.depth; i > 0; i--) {
71
+ const node = $pos.node(i)
72
+ if (isBibliographySectionNode(node)) {
73
+ return true
74
+ }
75
+ }
76
+ return false
77
+ }
78
+
79
+ export const findParentNodeClosestToPos = (
80
+ $pos: ResolvedPos,
81
+ predicate: (node: ProsemirrorNode) => boolean
82
+ ) => {
83
+ for (let i = $pos.depth; i > 0; i--) {
84
+ const node = $pos.node(i)
85
+ if (predicate(node)) {
86
+ return {
87
+ pos: i > 0 ? $pos.before(i) : 0,
88
+ start: $pos.start(i),
89
+ depth: i,
90
+ node,
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ export const getTrimmedTextContent = (
97
+ node: Element | Document | null,
98
+ selector?: string
99
+ ) => {
100
+ if (!node) {
101
+ return undefined
102
+ }
103
+ return selector
104
+ ? node.querySelector(selector)?.textContent?.trim()
105
+ : node.textContent?.trim()
106
+ }
107
+
108
+ export const getHTMLContent = (node: Element, querySelector: string) => {
109
+ return htmlFromJatsNode(node.querySelector(querySelector))
110
+ }
111
+
112
+ export const dateToTimestamp = (dateElement: Element) => {
113
+ const selectors = ['year', 'month', 'day']
114
+ const values: Array<number> = []
115
+ for (const selector of selectors) {
116
+ const value = getTrimmedTextContent(dateElement, selector)
117
+ if (!value || isNaN(+value)) {
118
+ return
119
+ }
120
+ values.push(+value)
121
+ }
122
+
123
+ // timestamp stored in seconds in manuscript schema
124
+ return Date.UTC(values[0], values[1] - 1, values[2]) / 1000 // ms => s
125
+ }
126
+
127
+ export function getCreditRole(elem: Element) {
128
+ const sources = elem.querySelectorAll(
129
+ 'role[vocab="CRediT"][vocab-identifier="http://credit.niso.org/"][vocab-term][vocab-term-identifier]'
130
+ )
131
+ const results: CreditRole[] = []
132
+ sources.forEach((source) => {
133
+ if (
134
+ source &&
135
+ CreditRoleUrls.has(source.getAttribute('vocab-term') as CreditVocabTerm)
136
+ ) {
137
+ const result: CreditRole = {
138
+ vocabTerm: source.getAttribute('vocab-term') as CreditVocabTerm,
139
+ }
140
+ results.push(result)
141
+ }
142
+ })
143
+
144
+ return results
145
+ }
package/src/lib/xml.ts ADDED
@@ -0,0 +1,28 @@
1
+ /*!
2
+ * © 2025 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
+ export const XLINK_NAMESPACE = 'http://www.w3.org/1999/xlink'
18
+ export const XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace'
19
+
20
+ export function sanitizeXmlString(str: string): string {
21
+ return (
22
+ str
23
+ // Escape bare ampersands (not part of valid entities)
24
+ .replace(/&(?!(?:amp|lt|gt|quot|apos|#[0-9]+|#x[0-9a-fA-F]+);)/g, '&amp;')
25
+ // Escape < that doesn't start a valid tag
26
+ .replace(/<(?![a-zA-Z_\/!?])/g, '&lt;')
27
+ )
28
+ }