@manuscripts/transform 4.5.8 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/jats/__tests__/jats-exporter.test.js +23 -0
- package/dist/cjs/jats/__tests__/jats-importer.test.js +26 -0
- package/dist/cjs/jats/exporter/JATSExporterBase.js +118 -0
- package/dist/cjs/jats/exporter/jats-exporter.js +224 -342
- package/dist/cjs/jats/exporter/lib.js +62 -0
- package/dist/cjs/jats/importer/jats-dom-parser.js +11 -3
- package/dist/cjs/schema/index.js +4 -1
- package/dist/cjs/schema/migration/migration-scripts/4.5.9.js +30 -0
- package/dist/cjs/schema/migration/migration-scripts/index.js +3 -1
- package/dist/cjs/schema/nodes/bibliography_element.js +0 -1
- package/dist/cjs/schema/nodes/bio.js +24 -0
- package/dist/cjs/schema/nodes/contributor.js +1 -2
- package/dist/cjs/schema/nodes/keywords_element.js +0 -1
- package/dist/cjs/types.js +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/es/jats/__tests__/jats-exporter.test.js +23 -0
- package/dist/es/jats/__tests__/jats-importer.test.js +26 -0
- package/dist/es/jats/exporter/JATSExporterBase.js +114 -0
- package/dist/es/jats/exporter/jats-exporter.js +198 -315
- package/dist/es/jats/exporter/lib.js +55 -0
- package/dist/es/jats/importer/jats-dom-parser.js +11 -3
- package/dist/es/schema/index.js +4 -1
- package/dist/es/schema/migration/migration-scripts/4.5.9.js +28 -0
- package/dist/es/schema/migration/migration-scripts/index.js +3 -1
- package/dist/es/schema/nodes/bibliography_element.js +0 -1
- package/dist/es/schema/nodes/bio.js +20 -0
- package/dist/es/schema/nodes/contributor.js +1 -2
- package/dist/es/schema/nodes/keywords_element.js +0 -1
- package/dist/es/types.js +1 -1
- package/dist/es/version.js +1 -1
- package/dist/types/jats/exporter/JATSExporterBase.d.ts +35 -0
- package/dist/types/jats/exporter/jats-exporter.d.ts +22 -18
- package/dist/types/jats/exporter/lib.d.ts +23 -0
- package/dist/types/schema/index.d.ts +2 -1
- package/dist/types/schema/migration/migration-scripts/4.5.9.d.ts +8 -0
- package/dist/types/schema/migration/migration-scripts/index.d.ts +3 -2
- package/dist/types/schema/nodes/bio.d.ts +10 -0
- package/dist/types/schema/types.d.ts +1 -1
- package/dist/types/types.d.ts +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/jats/__tests__/__fixtures__/jats-import.xml +7 -0
- package/src/jats/__tests__/__snapshots__/jats-importer.test.ts.snap +272 -151
- package/src/jats/__tests__/__snapshots__/jats-roundtrip.test.ts.snap +2 -2
- package/src/jats/__tests__/jats-exporter.test.ts +34 -0
- package/src/jats/__tests__/jats-importer.test.ts +37 -0
- package/src/jats/exporter/JATSExporterBase.ts +164 -0
- package/src/jats/exporter/jats-exporter.ts +212 -380
- package/src/jats/exporter/lib.ts +69 -0
- package/src/jats/importer/jats-dom-parser.ts +15 -5
- package/src/schema/index.ts +4 -1
- package/src/schema/migration/migration-scripts/4.5.9.ts +62 -0
- package/src/schema/migration/migration-scripts/index.ts +3 -1
- package/src/schema/nodes/bibliography_element.ts +0 -1
- package/src/schema/nodes/bio.ts +48 -0
- package/src/schema/nodes/contributor.ts +1 -2
- package/src/schema/nodes/keywords_element.ts +0 -1
- package/src/schema/types.ts +1 -0
- package/src/types.ts +1 -1
- package/src/version.ts +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* ©
|
|
2
|
+
* © 2026 Atypon Systems LLC
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import * as Citeproc from 'citeproc'
|
|
18
|
-
import { DOMOutputSpec, DOMSerializer
|
|
19
|
-
import { findChildrenByAttr
|
|
18
|
+
import { DOMOutputSpec, DOMSerializer } from 'prosemirror-model'
|
|
19
|
+
import { findChildrenByAttr } from 'prosemirror-utils'
|
|
20
20
|
|
|
21
21
|
import { buildCiteprocCitation } from '../../lib/citeproc'
|
|
22
22
|
import { CreditRoleUrls } from '../../lib/credit-roles'
|
|
@@ -40,7 +40,6 @@ import {
|
|
|
40
40
|
FootnoteNode,
|
|
41
41
|
isBibliographyItemNode,
|
|
42
42
|
isCitationNode,
|
|
43
|
-
isNodeOfType,
|
|
44
43
|
ManuscriptMark,
|
|
45
44
|
ManuscriptNode,
|
|
46
45
|
ManuscriptNodeType,
|
|
@@ -49,12 +48,15 @@ import {
|
|
|
49
48
|
ParagraphNode,
|
|
50
49
|
QuoteImageNode,
|
|
51
50
|
schema,
|
|
51
|
+
BioNode,
|
|
52
52
|
} from '../../schema'
|
|
53
53
|
import { isExecutableNodeType } from '../../transformer'
|
|
54
54
|
import { IDGenerator } from '../types'
|
|
55
55
|
import { initJats, jatsVariableWrapper } from './citeproc'
|
|
56
56
|
import { selectVersionIDs, Version } from './jats-versions'
|
|
57
57
|
import { buildTargets, Target } from './labels'
|
|
58
|
+
import { JATSExporterBase } from './JATSExporterBase'
|
|
59
|
+
import { chooseRefType, createDefaultIDGenerator, normalizeID } from './lib'
|
|
58
60
|
|
|
59
61
|
interface Attrs {
|
|
60
62
|
[key: string]: string
|
|
@@ -66,56 +68,6 @@ type MarkSpecs = {
|
|
|
66
68
|
[key in Marks]: (mark: ManuscriptMark, inline: boolean) => DOMOutputSpec
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
const normalizeID = (id: string) => id.replace(/:/g, '_')
|
|
70
|
-
|
|
71
|
-
export const createCounter = () => {
|
|
72
|
-
const counts = new Map<string, number>()
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
increment: (field: string) => {
|
|
76
|
-
const value = counts.get(field)
|
|
77
|
-
const newValue = value === undefined ? 1 : value + 1
|
|
78
|
-
counts.set(field, newValue)
|
|
79
|
-
return newValue
|
|
80
|
-
},
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const createDefaultIDGenerator = (): IDGenerator => {
|
|
85
|
-
const counter = createCounter()
|
|
86
|
-
|
|
87
|
-
return async (element: Element) => {
|
|
88
|
-
const value = String(counter.increment(element.nodeName))
|
|
89
|
-
|
|
90
|
-
return `${element.localName}-${value}`
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const chooseRefType = (type: ManuscriptNodeType): string | undefined => {
|
|
95
|
-
switch (type) {
|
|
96
|
-
case schema.nodes.figure:
|
|
97
|
-
case schema.nodes.figure_element:
|
|
98
|
-
return 'fig'
|
|
99
|
-
|
|
100
|
-
case schema.nodes.footnote:
|
|
101
|
-
return 'fn'
|
|
102
|
-
|
|
103
|
-
case schema.nodes.table:
|
|
104
|
-
case schema.nodes.table_element:
|
|
105
|
-
return 'table'
|
|
106
|
-
|
|
107
|
-
case schema.nodes.section:
|
|
108
|
-
case schema.nodes.abstract:
|
|
109
|
-
return 'sec'
|
|
110
|
-
|
|
111
|
-
case schema.nodes.equation:
|
|
112
|
-
case schema.nodes.equation_element:
|
|
113
|
-
return 'disp-formula'
|
|
114
|
-
|
|
115
|
-
case schema.nodes.supplement:
|
|
116
|
-
return 'supplementary-material'
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
71
|
export type CSLOptions = {
|
|
120
72
|
style: string
|
|
121
73
|
locale: string
|
|
@@ -125,42 +77,14 @@ export type ExportOptions = {
|
|
|
125
77
|
csl: CSLOptions
|
|
126
78
|
}
|
|
127
79
|
|
|
128
|
-
export class JATSExporter {
|
|
129
|
-
protected document: Document
|
|
130
|
-
protected serializer: DOMSerializer
|
|
80
|
+
export class JATSExporter extends JATSExporterBase {
|
|
131
81
|
protected labelTargets: Map<string, Target>
|
|
132
82
|
protected footnoteLabels: Map<string, string>
|
|
133
83
|
protected manuscriptNode: ActualManuscriptNode
|
|
134
84
|
private engine: Citeproc.Engine
|
|
135
85
|
private renderedCitations: Map<string, string>
|
|
136
|
-
private nodesMap: Map<NodeType, ManuscriptNode[]> = new Map()
|
|
137
|
-
private contributorLabels: Map<string, number> = new Map()
|
|
138
|
-
|
|
139
|
-
private populateNodesMap = () => {
|
|
140
|
-
this.manuscriptNode.descendants((node) => {
|
|
141
|
-
const type = node.type
|
|
142
|
-
const nodes = this.nodesMap.get(type) ?? []
|
|
143
|
-
nodes.push(node)
|
|
144
|
-
this.nodesMap.set(type, nodes)
|
|
145
|
-
})
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
protected getFirstChildOfType<T extends ManuscriptNode>(
|
|
149
|
-
type: NodeType,
|
|
150
|
-
node?: ManuscriptNode
|
|
151
|
-
): T | undefined {
|
|
152
|
-
return this.getChildrenOfType<T>(type, node)[0]
|
|
153
|
-
}
|
|
154
86
|
|
|
155
|
-
|
|
156
|
-
type: NodeType,
|
|
157
|
-
node?: ManuscriptNode
|
|
158
|
-
): T[] {
|
|
159
|
-
const nodes = node
|
|
160
|
-
? findChildrenByType(node, type).map(({ node }) => node)
|
|
161
|
-
: this.nodesMap.get(type)
|
|
162
|
-
return (nodes ?? []).filter((n): n is T => isNodeOfType<T>(n, type))
|
|
163
|
-
}
|
|
87
|
+
private contributorLabels: Map<string, number> = new Map()
|
|
164
88
|
|
|
165
89
|
public export = async (
|
|
166
90
|
manuscriptNode: ActualManuscriptNode,
|
|
@@ -183,7 +107,6 @@ export class JATSExporter {
|
|
|
183
107
|
)
|
|
184
108
|
|
|
185
109
|
const $article = this.document.documentElement
|
|
186
|
-
|
|
187
110
|
$article.setAttributeNS(
|
|
188
111
|
'http://www.w3.org/2000/xmlns/',
|
|
189
112
|
'xmlns:xlink',
|
|
@@ -628,43 +551,13 @@ export class JATSExporter {
|
|
|
628
551
|
return $refList
|
|
629
552
|
}
|
|
630
553
|
|
|
631
|
-
private createElement = (
|
|
632
|
-
tag: string,
|
|
633
|
-
content?: string,
|
|
634
|
-
attrs?: Record<string, string | undefined>
|
|
635
|
-
) => {
|
|
636
|
-
const $element = this.document.createElement(tag)
|
|
637
|
-
if (content) {
|
|
638
|
-
$element.textContent = content
|
|
639
|
-
}
|
|
640
|
-
if (attrs) {
|
|
641
|
-
Object.entries(attrs).forEach(([k, v]) => {
|
|
642
|
-
if (v) {
|
|
643
|
-
$element.setAttribute(k, v)
|
|
644
|
-
}
|
|
645
|
-
})
|
|
646
|
-
}
|
|
647
|
-
return $element
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
private appendElement = (
|
|
651
|
-
$parent: Element,
|
|
652
|
-
tag: string,
|
|
653
|
-
content?: string,
|
|
654
|
-
attrs?: Record<string, string | undefined>
|
|
655
|
-
) => {
|
|
656
|
-
const $element = this.createElement(tag, content, attrs)
|
|
657
|
-
$parent.appendChild($element)
|
|
658
|
-
return $element
|
|
659
|
-
}
|
|
660
|
-
|
|
661
554
|
protected createSerializer = () => {
|
|
662
555
|
const nodes: NodeSpecs = {
|
|
663
|
-
trans_abstract: (node) => createTransAbstract(node),
|
|
664
|
-
trans_graphical_abstract: (node) => createTransAbstract(node),
|
|
556
|
+
trans_abstract: (node) => this.createTransAbstract(node),
|
|
557
|
+
trans_graphical_abstract: (node) => this.createTransAbstract(node),
|
|
665
558
|
hero_image: () => '',
|
|
666
559
|
headshot_grid: () => ['p', { 'content-type': 'headshots' }, 0],
|
|
667
|
-
headshot_element: (node) => createImage(node),
|
|
560
|
+
headshot_element: (node) => this.createImage(node),
|
|
668
561
|
headshot_image: () => '',
|
|
669
562
|
alt_text: (node) => {
|
|
670
563
|
if (node.textContent) {
|
|
@@ -689,7 +582,7 @@ export class JATSExporter {
|
|
|
689
582
|
return $selfUri
|
|
690
583
|
},
|
|
691
584
|
attachments: () => '',
|
|
692
|
-
image_element: (node) => createImage(node),
|
|
585
|
+
image_element: (node) => this.createImage(node),
|
|
693
586
|
embed: (node) => {
|
|
694
587
|
const { id, href, mimetype, mimeSubtype, extLinks } = node.attrs
|
|
695
588
|
if (!href) {
|
|
@@ -705,7 +598,7 @@ export class JATSExporter {
|
|
|
705
598
|
if (mimeSubtype) {
|
|
706
599
|
$media.setAttribute('mime-subtype', node.attrs.mimeSubtype)
|
|
707
600
|
}
|
|
708
|
-
appendLabels($media, node)
|
|
601
|
+
this.appendLabels($media, node)
|
|
709
602
|
this.appendChildNodeOfType($media, node, schema.nodes.alt_text)
|
|
710
603
|
this.appendChildNodeOfType($media, node, schema.nodes.long_desc)
|
|
711
604
|
this.appendCaption($media, node)
|
|
@@ -714,9 +607,17 @@ export class JATSExporter {
|
|
|
714
607
|
if (extLink.href) {
|
|
715
608
|
const extLinkElement = this.createElement('ext-link')
|
|
716
609
|
extLinkElement.setAttribute('ext-link-type', extLink.type)
|
|
717
|
-
extLinkElement.setAttributeNS(
|
|
610
|
+
extLinkElement.setAttributeNS(
|
|
611
|
+
XLINK_NAMESPACE,
|
|
612
|
+
'href',
|
|
613
|
+
extLink.href
|
|
614
|
+
)
|
|
718
615
|
if (extLink.lang) {
|
|
719
|
-
extLinkElement.setAttributeNS(
|
|
616
|
+
extLinkElement.setAttributeNS(
|
|
617
|
+
XML_NAMESPACE,
|
|
618
|
+
'lang',
|
|
619
|
+
extLink.lang
|
|
620
|
+
)
|
|
720
621
|
}
|
|
721
622
|
if (extLink.label) {
|
|
722
623
|
extLinkElement.textContent = extLink.label
|
|
@@ -732,7 +633,7 @@ export class JATSExporter {
|
|
|
732
633
|
const awardGroup = node as AwardNode
|
|
733
634
|
const $awardGroup = this.createElement('award-group')
|
|
734
635
|
$awardGroup.setAttribute('id', normalizeID(awardGroup.attrs.id))
|
|
735
|
-
appendChildIfPresent(
|
|
636
|
+
this.appendChildIfPresent(
|
|
736
637
|
$awardGroup,
|
|
737
638
|
'funding-source',
|
|
738
639
|
awardGroup.attrs.source
|
|
@@ -740,9 +641,9 @@ export class JATSExporter {
|
|
|
740
641
|
awardGroup.attrs.code
|
|
741
642
|
?.split(';')
|
|
742
643
|
.forEach((code) =>
|
|
743
|
-
appendChildIfPresent($awardGroup, 'award-id', code)
|
|
644
|
+
this.appendChildIfPresent($awardGroup, 'award-id', code)
|
|
744
645
|
)
|
|
745
|
-
appendChildIfPresent(
|
|
646
|
+
this.appendChildIfPresent(
|
|
746
647
|
$awardGroup,
|
|
747
648
|
'principal-award-recipient',
|
|
748
649
|
awardGroup.attrs.recipient
|
|
@@ -750,7 +651,7 @@ export class JATSExporter {
|
|
|
750
651
|
|
|
751
652
|
return $awardGroup
|
|
752
653
|
},
|
|
753
|
-
box_element: (node) => createBoxElement(node),
|
|
654
|
+
box_element: (node) => this.createBoxElement(node),
|
|
754
655
|
author_notes: () => '',
|
|
755
656
|
corresp: () => '',
|
|
756
657
|
title: () => ['article-title', 0],
|
|
@@ -771,6 +672,7 @@ export class JATSExporter {
|
|
|
771
672
|
: ['table-wrap-foot', 0],
|
|
772
673
|
contributor: (node) =>
|
|
773
674
|
this.buildContributorElement(node as ContributorNode),
|
|
675
|
+
bio: () => ['bio', 0],
|
|
774
676
|
affiliation: (node) =>
|
|
775
677
|
this.buildAffiliationElement(node as AffiliationNode),
|
|
776
678
|
attribution: () => ['attrib', 0],
|
|
@@ -805,7 +707,7 @@ export class JATSExporter {
|
|
|
805
707
|
'mime-subtype',
|
|
806
708
|
node.attrs.mimeSubType ?? ''
|
|
807
709
|
)
|
|
808
|
-
appendLabels($supplementaryMaterial, node)
|
|
710
|
+
this.appendLabels($supplementaryMaterial, node)
|
|
809
711
|
this.appendCaption($supplementaryMaterial, node)
|
|
810
712
|
return $supplementaryMaterial
|
|
811
713
|
},
|
|
@@ -851,8 +753,7 @@ export class JATSExporter {
|
|
|
851
753
|
|
|
852
754
|
const rid = rids[0]
|
|
853
755
|
const labelTarget = this.labelTargets.get(rid)
|
|
854
|
-
const isSupplement =
|
|
855
|
-
labelTarget?.type === schema.nodes.supplement.name
|
|
756
|
+
const isSupplement = labelTarget?.type === schema.nodes.supplement.name
|
|
856
757
|
const text =
|
|
857
758
|
cross.attrs.label ||
|
|
858
759
|
(isSupplement
|
|
@@ -904,13 +805,13 @@ export class JATSExporter {
|
|
|
904
805
|
equation_element: (node) => {
|
|
905
806
|
const $dispFormula = this.createElement('disp-formula')
|
|
906
807
|
$dispFormula.setAttribute('id', normalizeID(node.attrs.id))
|
|
907
|
-
appendLabels($dispFormula, node)
|
|
908
|
-
processChildNodes($dispFormula, node, schema.nodes.equation)
|
|
808
|
+
this.appendLabels($dispFormula, node)
|
|
809
|
+
this.processChildNodes($dispFormula, node, schema.nodes.equation)
|
|
909
810
|
return $dispFormula
|
|
910
811
|
},
|
|
911
|
-
figure: (node) => createGraphic(node),
|
|
812
|
+
figure: (node) => this.createGraphic(node),
|
|
912
813
|
figure_element: (node) =>
|
|
913
|
-
createFigureElement(node, node.type.schema.nodes.figure),
|
|
814
|
+
this.createFigureElement(node, node.type.schema.nodes.figure),
|
|
914
815
|
footnote: (node) => {
|
|
915
816
|
const attrs: Attrs = {}
|
|
916
817
|
|
|
@@ -1003,7 +904,7 @@ export class JATSExporter {
|
|
|
1003
904
|
return $code
|
|
1004
905
|
},
|
|
1005
906
|
listing_element: (node) =>
|
|
1006
|
-
createFigureElement(node, node.type.schema.nodes.listing),
|
|
907
|
+
this.createFigureElement(node, node.type.schema.nodes.listing),
|
|
1007
908
|
manuscript: (node) => ['article', { id: normalizeID(node.attrs.id) }, 0],
|
|
1008
909
|
missing_figure: () => {
|
|
1009
910
|
const $graphic = this.createElement('graphic')
|
|
@@ -1044,11 +945,11 @@ export class JATSExporter {
|
|
|
1044
945
|
quote_image: (node) => {
|
|
1045
946
|
const img = node as QuoteImageNode
|
|
1046
947
|
if (img.attrs.src) {
|
|
1047
|
-
return createGraphic(node)
|
|
948
|
+
return this.createGraphic(node)
|
|
1048
949
|
}
|
|
1049
950
|
return ''
|
|
1050
951
|
},
|
|
1051
|
-
graphical_abstract_section: (node) => createAbstract(node),
|
|
952
|
+
graphical_abstract_section: (node) => this.createAbstract(node),
|
|
1052
953
|
section: (node) => {
|
|
1053
954
|
const attrs: { [key: string]: string } = {
|
|
1054
955
|
id: normalizeID(node.attrs.id),
|
|
@@ -1060,13 +961,13 @@ export class JATSExporter {
|
|
|
1060
961
|
|
|
1061
962
|
return ['sec', attrs, 0]
|
|
1062
963
|
},
|
|
1063
|
-
abstract: (node) => createAbstract(node),
|
|
964
|
+
abstract: (node) => this.createAbstract(node),
|
|
1064
965
|
section_label: () => ['label', 0],
|
|
1065
966
|
section_title: () => ['title', 0],
|
|
1066
967
|
section_title_plain: () => ['title', 0],
|
|
1067
968
|
table: (node) => ['table', { id: normalizeID(node.attrs.id) }, 0],
|
|
1068
969
|
table_element: (node) => {
|
|
1069
|
-
const $tableWrap = createTableElement(node)
|
|
970
|
+
const $tableWrap = this.createTableElement(node)
|
|
1070
971
|
$tableWrap.setAttribute('position', 'anchor')
|
|
1071
972
|
if (node.attrs.type) {
|
|
1072
973
|
$tableWrap.setAttribute('content-type', node.attrs.type)
|
|
@@ -1120,134 +1021,93 @@ export class JATSExporter {
|
|
|
1120
1021
|
}
|
|
1121
1022
|
|
|
1122
1023
|
this.serializer = new DOMSerializer(nodes, marks)
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
appendLabels($element: Element, node: ManuscriptNode) {
|
|
1027
|
+
if (this.labelTargets) {
|
|
1028
|
+
const target = this.labelTargets.get(node.attrs.id)
|
|
1029
|
+
|
|
1030
|
+
if (target) {
|
|
1031
|
+
const $label = this.createElement('label')
|
|
1032
|
+
$label.textContent = target.label
|
|
1033
|
+
$element.appendChild($label)
|
|
1130
1034
|
}
|
|
1131
|
-
const $element = this.createElement(tagName)
|
|
1132
|
-
$element.textContent = textContent
|
|
1133
|
-
$parent.appendChild($element)
|
|
1134
|
-
}
|
|
1135
|
-
const processChildNodes = (
|
|
1136
|
-
$element: Element,
|
|
1137
|
-
node: ManuscriptNode,
|
|
1138
|
-
contentNodeType: ManuscriptNodeType
|
|
1139
|
-
) => {
|
|
1140
|
-
node.forEach((childNode) => {
|
|
1141
|
-
if (childNode.type === contentNodeType) {
|
|
1142
|
-
if (childNode.attrs.id) {
|
|
1143
|
-
$element.appendChild(this.serializeNode(childNode))
|
|
1144
|
-
}
|
|
1145
|
-
} else if (childNode.type === node.type.schema.nodes.paragraph) {
|
|
1146
|
-
$element.appendChild(this.serializeNode(childNode))
|
|
1147
|
-
} else if (childNode.type === node.type.schema.nodes.missing_figure) {
|
|
1148
|
-
$element.appendChild(this.serializeNode(childNode))
|
|
1149
|
-
}
|
|
1150
|
-
})
|
|
1151
1035
|
}
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1036
|
+
}
|
|
1037
|
+
appendAttributions($element: Element, node: ManuscriptNode) {
|
|
1038
|
+
if (node.attrs.attribution) {
|
|
1039
|
+
const $attrib = this.createElement('attrib')
|
|
1040
|
+
$attrib.textContent = node.attrs.attribution.literal
|
|
1041
|
+
$element.appendChild($attrib)
|
|
1156
1042
|
}
|
|
1043
|
+
}
|
|
1157
1044
|
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1045
|
+
appendTable($element: Element, node: ManuscriptNode) {
|
|
1046
|
+
const tableNode = this.getFirstChildOfType(schema.nodes.table, node)
|
|
1047
|
+
const colGroupNode = this.getFirstChildOfType(
|
|
1048
|
+
schema.nodes.table_colgroup,
|
|
1049
|
+
node
|
|
1050
|
+
)
|
|
1051
|
+
if (!tableNode) {
|
|
1052
|
+
return
|
|
1053
|
+
}
|
|
1054
|
+
const $table = this.serializeNode(tableNode)
|
|
1055
|
+
const $tbody = this.createElement('tbody')
|
|
1161
1056
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1057
|
+
while ($table.firstChild) {
|
|
1058
|
+
const $child = $table.firstChild
|
|
1059
|
+
$table.removeChild($child)
|
|
1060
|
+
$tbody.appendChild($child)
|
|
1168
1061
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
}
|
|
1062
|
+
$table.appendChild($tbody)
|
|
1063
|
+
this.normalizeTable($table)
|
|
1064
|
+
if (colGroupNode) {
|
|
1065
|
+
const $colGroup = this.serializeNode(colGroupNode)
|
|
1066
|
+
$table.insertBefore($colGroup, $table.firstChild)
|
|
1175
1067
|
}
|
|
1176
1068
|
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
const colGroupNode = this.getFirstChildOfType(
|
|
1180
|
-
schema.nodes.table_colgroup,
|
|
1181
|
-
node
|
|
1182
|
-
)
|
|
1183
|
-
if (!tableNode) {
|
|
1184
|
-
return
|
|
1185
|
-
}
|
|
1186
|
-
const $table = this.serializeNode(tableNode)
|
|
1187
|
-
const $tbody = this.createElement('tbody')
|
|
1188
|
-
|
|
1189
|
-
while ($table.firstChild) {
|
|
1190
|
-
const $child = $table.firstChild
|
|
1191
|
-
$table.removeChild($child)
|
|
1192
|
-
$tbody.appendChild($child)
|
|
1193
|
-
}
|
|
1194
|
-
$table.appendChild($tbody)
|
|
1195
|
-
this.normalizeTable($table)
|
|
1196
|
-
if (colGroupNode) {
|
|
1197
|
-
const $colGroup = this.serializeNode(colGroupNode)
|
|
1198
|
-
$table.insertBefore($colGroup, $table.firstChild)
|
|
1199
|
-
}
|
|
1069
|
+
$element.appendChild($table)
|
|
1070
|
+
}
|
|
1200
1071
|
|
|
1201
|
-
|
|
1072
|
+
createBoxElement(node: ManuscriptNode) {
|
|
1073
|
+
const $boxedText = this.createElementWithID(node, 'boxed-text')
|
|
1074
|
+
if (node.attrs.type) {
|
|
1075
|
+
$boxedText.setAttribute('content-type', node.attrs.type)
|
|
1202
1076
|
}
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
}
|
|
1208
|
-
appendLabels($boxedText, node)
|
|
1209
|
-
const child = node.firstChild
|
|
1210
|
-
if (child?.type === schema.nodes.caption_title) {
|
|
1211
|
-
this.appendCaption($boxedText, node)
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
processChildNodes($boxedText, node, node.type.schema.nodes.section)
|
|
1215
|
-
return $boxedText
|
|
1077
|
+
this.appendLabels($boxedText, node)
|
|
1078
|
+
const child = node.firstChild
|
|
1079
|
+
if (child?.type === schema.nodes.caption_title) {
|
|
1080
|
+
this.appendCaption($boxedText, node)
|
|
1216
1081
|
}
|
|
1217
1082
|
|
|
1218
|
-
|
|
1219
|
-
|
|
1083
|
+
this.processChildNodes($boxedText, node, node.type.schema.nodes.section)
|
|
1084
|
+
return $boxedText
|
|
1085
|
+
}
|
|
1220
1086
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1087
|
+
abstractTypeAttrs(category: string) {
|
|
1088
|
+
return category && category !== 'abstract'
|
|
1089
|
+
? { 'abstract-type': category }
|
|
1090
|
+
: {}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
createAbstract(node: ManuscriptNode): DOMOutputSpec {
|
|
1094
|
+
return ['abstract', this.abstractTypeAttrs(node.attrs.category), 0]
|
|
1095
|
+
}
|
|
1226
1096
|
|
|
1227
|
-
|
|
1097
|
+
createTransAbstract(node: ManuscriptNode): DOMOutputSpec {
|
|
1098
|
+
return [
|
|
1228
1099
|
'trans-abstract',
|
|
1229
1100
|
{
|
|
1230
1101
|
[`${XML_NAMESPACE} lang`]: node.attrs.lang ?? '',
|
|
1231
|
-
...abstractTypeAttrs(node.attrs.category),
|
|
1102
|
+
...this.abstractTypeAttrs(node.attrs.category),
|
|
1232
1103
|
},
|
|
1233
1104
|
0,
|
|
1234
1105
|
]
|
|
1106
|
+
}
|
|
1235
1107
|
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
descend = false
|
|
1240
|
-
) => {
|
|
1241
|
-
const nodes = this.getChildrenOfType(type)
|
|
1242
|
-
return nodes.some((node) => {
|
|
1243
|
-
const result = findChildrenByAttr(
|
|
1244
|
-
node,
|
|
1245
|
-
(attrs) => attrs.id === targetID,
|
|
1246
|
-
descend
|
|
1247
|
-
)[0]
|
|
1248
|
-
return !!result
|
|
1249
|
-
})
|
|
1250
|
-
}
|
|
1108
|
+
private createGraphic(node: ManuscriptNode) {
|
|
1109
|
+
const $graphic = this.createElement('graphic')
|
|
1110
|
+
$graphic.setAttributeNS(XLINK_NAMESPACE, 'xlink:href', node.attrs.src)
|
|
1251
1111
|
|
|
1252
1112
|
const findParentHeroImage = (targetID: string) => {
|
|
1253
1113
|
const heroes = this.getChildrenOfType(schema.nodes.hero_image)
|
|
@@ -1257,122 +1117,118 @@ export class JATSExporter {
|
|
|
1257
1117
|
)
|
|
1258
1118
|
}
|
|
1259
1119
|
|
|
1260
|
-
const
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
$extLink.setAttributeNS(XLINK_NAMESPACE, 'href', node.attrs.extLink)
|
|
1269
|
-
}
|
|
1270
|
-
this.appendCaption($graphic, node)
|
|
1271
|
-
this.appendChildNodeOfType($graphic, node, schema.nodes.alt_text)
|
|
1272
|
-
this.appendChildNodeOfType($graphic, node, schema.nodes.long_desc)
|
|
1273
|
-
return $graphic
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
|
-
const createGraphic = (node: ManuscriptNode) => {
|
|
1277
|
-
const $graphic = this.createElement('graphic')
|
|
1278
|
-
$graphic.setAttributeNS(XLINK_NAMESPACE, 'xlink:href', node.attrs.src)
|
|
1279
|
-
|
|
1280
|
-
const hero = findParentHeroImage(node.attrs.id)
|
|
1281
|
-
if (hero) {
|
|
1282
|
-
$graphic.setAttribute('content-type', hero.attrs.type || 'leading')
|
|
1283
|
-
} else if (
|
|
1284
|
-
!isChildOfNodeType(node.attrs.id, schema.nodes.figure_element) &&
|
|
1285
|
-
node.attrs.type
|
|
1286
|
-
) {
|
|
1287
|
-
$graphic.setAttribute('content-type', node.attrs.type)
|
|
1288
|
-
}
|
|
1289
|
-
return $graphic
|
|
1290
|
-
}
|
|
1291
|
-
const createFigureElement = (
|
|
1292
|
-
node: ManuscriptNode,
|
|
1293
|
-
contentNodeType: ManuscriptNodeType
|
|
1294
|
-
) => {
|
|
1295
|
-
const $fig = createElement(node, 'fig')
|
|
1296
|
-
const figNode = this.getFirstChildOfType(schema.nodes.figure, node)
|
|
1297
|
-
const figType = figNode?.attrs.type
|
|
1298
|
-
if (figType) {
|
|
1299
|
-
$fig.setAttribute('fig-type', figType)
|
|
1300
|
-
}
|
|
1301
|
-
appendLabels($fig, node)
|
|
1302
|
-
this.appendCaption($fig, node)
|
|
1303
|
-
this.appendChildNodeOfType($fig, node, schema.nodes.alt_text)
|
|
1304
|
-
this.appendChildNodeOfType($fig, node, schema.nodes.long_desc)
|
|
1305
|
-
this.appendChildNodeOfType(
|
|
1306
|
-
$fig,
|
|
1307
|
-
node,
|
|
1308
|
-
node.type.schema.nodes.footnotes_element
|
|
1309
|
-
)
|
|
1310
|
-
processChildNodes($fig, node, contentNodeType)
|
|
1311
|
-
appendAttributions($fig, node)
|
|
1312
|
-
if (isExecutableNodeType(node.type)) {
|
|
1313
|
-
processExecutableNode(node, $fig)
|
|
1314
|
-
}
|
|
1315
|
-
moveAltTextAndLongDescToGraphics($fig)
|
|
1316
|
-
return $fig
|
|
1120
|
+
const hero = findParentHeroImage(node.attrs.id)
|
|
1121
|
+
if (hero) {
|
|
1122
|
+
$graphic.setAttribute('content-type', hero.attrs.type || 'leading')
|
|
1123
|
+
} else if (
|
|
1124
|
+
!this.isChildOfNodeType(node.attrs.id, schema.nodes.figure_element) &&
|
|
1125
|
+
node.attrs.type
|
|
1126
|
+
) {
|
|
1127
|
+
$graphic.setAttribute('content-type', node.attrs.type)
|
|
1317
1128
|
}
|
|
1129
|
+
return $graphic
|
|
1130
|
+
}
|
|
1318
1131
|
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1132
|
+
createImage(node: ManuscriptNode) {
|
|
1133
|
+
const graphicNode = node.content.firstChild
|
|
1134
|
+
if (!graphicNode) {
|
|
1135
|
+
return ''
|
|
1136
|
+
}
|
|
1137
|
+
const $graphic = this.createGraphic(graphicNode)
|
|
1138
|
+
if (node.attrs.extLink) {
|
|
1139
|
+
const $extLink = this.appendElement($graphic, 'ext-link')
|
|
1140
|
+
$extLink.setAttributeNS(XLINK_NAMESPACE, 'href', node.attrs.extLink)
|
|
1141
|
+
}
|
|
1142
|
+
this.appendCaption($graphic, node)
|
|
1143
|
+
this.appendChildNodeOfType($graphic, node, schema.nodes.alt_text)
|
|
1144
|
+
this.appendChildNodeOfType($graphic, node, schema.nodes.long_desc)
|
|
1145
|
+
return $graphic
|
|
1146
|
+
}
|
|
1323
1147
|
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1148
|
+
createFigureElement(
|
|
1149
|
+
node: ManuscriptNode,
|
|
1150
|
+
contentNodeType: ManuscriptNodeType
|
|
1151
|
+
) {
|
|
1152
|
+
const $fig = this.createElementWithID(node, 'fig')
|
|
1153
|
+
const figNode = this.getFirstChildOfType(schema.nodes.figure, node)
|
|
1154
|
+
const figType = figNode?.attrs.type
|
|
1155
|
+
if (figType) {
|
|
1156
|
+
$fig.setAttribute('fig-type', figType)
|
|
1157
|
+
}
|
|
1158
|
+
this.appendLabels($fig, node)
|
|
1159
|
+
this.appendCaption($fig, node)
|
|
1160
|
+
this.appendChildNodeOfType($fig, node, schema.nodes.alt_text)
|
|
1161
|
+
this.appendChildNodeOfType($fig, node, schema.nodes.long_desc)
|
|
1162
|
+
this.appendChildNodeOfType(
|
|
1163
|
+
$fig,
|
|
1164
|
+
node,
|
|
1165
|
+
node.type.schema.nodes.footnotes_element
|
|
1166
|
+
)
|
|
1167
|
+
this.processChildNodes($fig, node, contentNodeType)
|
|
1168
|
+
this.appendAttributions($fig, node)
|
|
1169
|
+
if (isExecutableNodeType(node.type)) {
|
|
1170
|
+
this.processExecutableNode(node, $fig)
|
|
1171
|
+
}
|
|
1172
|
+
this.moveAltTextAndLongDescToGraphics($fig)
|
|
1173
|
+
return $fig
|
|
1174
|
+
}
|
|
1327
1175
|
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
if ($altText) {
|
|
1333
|
-
$graphic.prepend($altText.cloneNode(true))
|
|
1334
|
-
}
|
|
1335
|
-
})
|
|
1176
|
+
moveAltTextAndLongDescToGraphics($element: Element) {
|
|
1177
|
+
const $altText = $element.querySelector('alt-text')
|
|
1178
|
+
const $longDesc = $element.querySelector('long-desc')
|
|
1179
|
+
const $graphics = $element.querySelectorAll('graphic')
|
|
1336
1180
|
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
appendLabels($tableWrap, node)
|
|
1345
|
-
this.appendCaption($tableWrap, node)
|
|
1346
|
-
this.appendChildNodeOfType($tableWrap, node, schema.nodes.alt_text)
|
|
1347
|
-
this.appendChildNodeOfType($tableWrap, node, schema.nodes.long_desc)
|
|
1348
|
-
appendTable($tableWrap, node)
|
|
1349
|
-
this.appendChildNodeOfType(
|
|
1350
|
-
$tableWrap,
|
|
1351
|
-
node,
|
|
1352
|
-
node.type.schema.nodes.table_element_footer
|
|
1353
|
-
)
|
|
1354
|
-
if (isExecutableNodeType(node.type)) {
|
|
1355
|
-
processExecutableNode(node, $tableWrap)
|
|
1181
|
+
if ($graphics.length === 0) {
|
|
1182
|
+
return
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
$graphics.forEach(($graphic) => {
|
|
1186
|
+
if ($longDesc) {
|
|
1187
|
+
$graphic.prepend($longDesc.cloneNode(true))
|
|
1356
1188
|
}
|
|
1357
|
-
|
|
1189
|
+
if ($altText) {
|
|
1190
|
+
$graphic.prepend($altText.cloneNode(true))
|
|
1191
|
+
}
|
|
1192
|
+
})
|
|
1193
|
+
|
|
1194
|
+
$altText?.remove()
|
|
1195
|
+
$longDesc?.remove()
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
createTableElement(node: ManuscriptNode) {
|
|
1199
|
+
const nodeName = 'table-wrap'
|
|
1200
|
+
const $tableWrap = this.createElementWithID(node, nodeName)
|
|
1201
|
+
this.appendLabels($tableWrap, node)
|
|
1202
|
+
this.appendCaption($tableWrap, node)
|
|
1203
|
+
this.appendChildNodeOfType($tableWrap, node, schema.nodes.alt_text)
|
|
1204
|
+
this.appendChildNodeOfType($tableWrap, node, schema.nodes.long_desc)
|
|
1205
|
+
this.appendTable($tableWrap, node)
|
|
1206
|
+
this.appendChildNodeOfType(
|
|
1207
|
+
$tableWrap,
|
|
1208
|
+
node,
|
|
1209
|
+
node.type.schema.nodes.table_element_footer
|
|
1210
|
+
)
|
|
1211
|
+
if (isExecutableNodeType(node.type)) {
|
|
1212
|
+
this.processExecutableNode(node, $tableWrap)
|
|
1358
1213
|
}
|
|
1359
|
-
|
|
1360
|
-
|
|
1214
|
+
return $tableWrap
|
|
1215
|
+
}
|
|
1216
|
+
processExecutableNode(node: ManuscriptNode, $element: Element) {
|
|
1217
|
+
const listingNode = this.getFirstChildOfType(schema.nodes.listing, node)
|
|
1361
1218
|
|
|
1362
|
-
|
|
1363
|
-
|
|
1219
|
+
if (listingNode) {
|
|
1220
|
+
const { contents, languageKey } = listingNode.attrs
|
|
1364
1221
|
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1222
|
+
if (contents && languageKey) {
|
|
1223
|
+
const $fig = this.createElement('fig')
|
|
1224
|
+
$fig.setAttribute('specific-use', 'source')
|
|
1225
|
+
$element.appendChild($fig)
|
|
1369
1226
|
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
}
|
|
1227
|
+
const $code = this.createElement('code')
|
|
1228
|
+
$code.setAttribute('executable', 'true')
|
|
1229
|
+
$code.setAttribute('language', languageKey)
|
|
1230
|
+
$code.textContent = contents
|
|
1231
|
+
$fig.appendChild($code)
|
|
1376
1232
|
}
|
|
1377
1233
|
}
|
|
1378
1234
|
}
|
|
@@ -1398,11 +1254,6 @@ export class JATSExporter {
|
|
|
1398
1254
|
}
|
|
1399
1255
|
}
|
|
1400
1256
|
|
|
1401
|
-
protected serializeNode = (node: ManuscriptNode) =>
|
|
1402
|
-
this.serializer.serializeNode(node, {
|
|
1403
|
-
document: this.document,
|
|
1404
|
-
})
|
|
1405
|
-
|
|
1406
1257
|
private buildContributorGroup = (contributors: ContributorNode[]) => {
|
|
1407
1258
|
if (!contributors.length) {
|
|
1408
1259
|
return
|
|
@@ -1552,6 +1403,11 @@ export class JATSExporter {
|
|
|
1552
1403
|
})
|
|
1553
1404
|
})
|
|
1554
1405
|
|
|
1406
|
+
const bio = this.getFirstChildOfType<BioNode>(schema.nodes.bio, contributor)
|
|
1407
|
+
if (bio?.childCount) {
|
|
1408
|
+
$contrib.appendChild(this.serializeNode(bio))
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1555
1411
|
return $contrib
|
|
1556
1412
|
}
|
|
1557
1413
|
|
|
@@ -1717,18 +1573,6 @@ export class JATSExporter {
|
|
|
1717
1573
|
this.serializeNode(group)
|
|
1718
1574
|
)
|
|
1719
1575
|
|
|
1720
|
-
private changeTag = ($node: Element, tag: string) => {
|
|
1721
|
-
const $clone = this.createElement(tag)
|
|
1722
|
-
for (const attr of $node.attributes) {
|
|
1723
|
-
$clone.setAttributeNS(null, attr.name, attr.value)
|
|
1724
|
-
}
|
|
1725
|
-
while ($node.firstChild) {
|
|
1726
|
-
$clone.appendChild($node.firstChild)
|
|
1727
|
-
}
|
|
1728
|
-
$node.replaceWith($clone)
|
|
1729
|
-
return $clone
|
|
1730
|
-
}
|
|
1731
|
-
|
|
1732
1576
|
private normalizeTable = ($table: Node) => {
|
|
1733
1577
|
let $tbody: Element | undefined
|
|
1734
1578
|
|
|
@@ -1827,18 +1671,6 @@ export class JATSExporter {
|
|
|
1827
1671
|
}
|
|
1828
1672
|
}
|
|
1829
1673
|
|
|
1830
|
-
private fillEmptyElements(
|
|
1831
|
-
$article: Element,
|
|
1832
|
-
selector: string,
|
|
1833
|
-
tagName = 'p'
|
|
1834
|
-
) {
|
|
1835
|
-
const $empty = Array.from($article.querySelectorAll(selector)).filter(
|
|
1836
|
-
($el) => !$el.innerHTML
|
|
1837
|
-
)
|
|
1838
|
-
$empty.forEach(($element) =>
|
|
1839
|
-
$element.appendChild(this.createElement(tagName))
|
|
1840
|
-
)
|
|
1841
|
-
}
|
|
1842
1674
|
private addParagraphsToSections($article: Element) {
|
|
1843
1675
|
const $sections = $article.querySelectorAll('sec, abstract')
|
|
1844
1676
|
const TITLE_TAGS = new Set(['title', 'label', 'sec-meta'])
|