@manuscripts/transform 1.5.3 → 1.5.4-LEAN-3030
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/importer/jats-body-dom-parser.js +23 -18
- package/dist/cjs/jats/importer/jats-body-transformations.js +3 -3
- package/dist/cjs/jats/importer/parse-jats-article.js +11 -2
- package/dist/cjs/jats/jats-exporter.js +19 -12
- package/dist/cjs/lib/utils.js +10 -1
- package/dist/cjs/schema/index.js +19 -12
- package/dist/cjs/schema/nodes/affiliations.js +15 -0
- package/dist/cjs/schema/nodes/contributors.js +15 -0
- package/dist/cjs/schema/nodes/core_section.js +27 -0
- package/dist/cjs/schema/nodes/keyword.js +0 -1
- package/dist/cjs/schema/nodes/{keywords_group.js → keyword_group.js} +6 -6
- package/dist/cjs/schema/nodes/{keywords_section.js → keywords.js} +7 -7
- package/dist/cjs/schema/nodes/keywords_element.js +1 -1
- package/dist/cjs/schema/nodes/manuscript.js +1 -1
- package/dist/cjs/schema/nodes/title.js +29 -0
- package/dist/cjs/transformer/builders.js +8 -3
- package/dist/cjs/transformer/decode.js +119 -105
- package/dist/cjs/transformer/encode.js +19 -26
- package/dist/cjs/transformer/html.js +6 -5
- package/dist/cjs/transformer/node-names.js +1 -1
- package/dist/cjs/transformer/node-title.js +7 -5
- package/dist/cjs/transformer/node-types.js +8 -4
- package/dist/cjs/transformer/project-bundle.js +22 -1
- package/dist/cjs/transformer/section-category.js +35 -8
- package/dist/es/jats/importer/jats-body-dom-parser.js +23 -18
- package/dist/es/jats/importer/jats-body-transformations.js +3 -3
- package/dist/es/jats/importer/parse-jats-article.js +11 -2
- package/dist/es/jats/jats-exporter.js +20 -13
- package/dist/es/lib/utils.js +8 -0
- package/dist/es/schema/index.js +19 -12
- package/dist/es/schema/nodes/{affiliations_section.js → affiliations.js} +3 -3
- package/dist/es/schema/nodes/{contributors_section.js → contributors.js} +3 -3
- package/dist/es/schema/nodes/core_section.js +24 -0
- package/dist/es/schema/nodes/keyword.js +0 -1
- package/dist/es/schema/nodes/{keywords_group.js → keyword_group.js} +4 -4
- package/dist/es/schema/nodes/{keywords_section.js → keywords.js} +5 -5
- package/dist/es/schema/nodes/keywords_element.js +1 -1
- package/dist/es/schema/nodes/manuscript.js +1 -1
- package/dist/es/schema/nodes/title.js +26 -0
- package/dist/es/transformer/builders.js +6 -2
- package/dist/es/transformer/decode.js +120 -106
- package/dist/es/transformer/encode.js +19 -26
- package/dist/es/transformer/html.js +7 -6
- package/dist/es/transformer/node-names.js +1 -1
- package/dist/es/transformer/node-title.js +8 -6
- package/dist/es/transformer/node-types.js +8 -4
- package/dist/es/transformer/project-bundle.js +20 -0
- package/dist/es/transformer/section-category.js +33 -7
- package/dist/types/lib/utils.d.ts +1 -0
- package/dist/types/schema/index.d.ts +4 -3
- package/dist/types/schema/nodes/affiliations.d.ts +11 -0
- package/dist/types/schema/nodes/contributors.d.ts +11 -0
- package/dist/types/schema/nodes/core_section.d.ts +17 -0
- package/dist/types/schema/nodes/keyword.d.ts +0 -1
- package/dist/types/schema/nodes/{keywords_group.d.ts → keyword_group.d.ts} +3 -3
- package/dist/types/schema/nodes/{keywords_section.d.ts → keywords.d.ts} +3 -3
- package/dist/types/schema/nodes/title.d.ts +28 -0
- package/dist/types/schema/types.d.ts +1 -1
- package/dist/types/transformer/builders.d.ts +3 -2
- package/dist/types/transformer/decode.d.ts +6 -5
- package/dist/types/transformer/project-bundle.d.ts +2 -1
- package/dist/types/transformer/section-category.d.ts +1 -0
- package/package.json +2 -2
- package/dist/cjs/schema/nodes/affiliations_section.js +0 -15
- package/dist/cjs/schema/nodes/contributors_section.js +0 -15
- package/dist/types/schema/nodes/affiliations_section.d.ts +0 -11
- package/dist/types/schema/nodes/contributors_section.d.ts +0 -11
|
@@ -28,11 +28,13 @@ import { ObjectTypes, } from '@manuscripts/json-schema';
|
|
|
28
28
|
import debug from 'debug';
|
|
29
29
|
import { DOMParser } from 'prosemirror-model';
|
|
30
30
|
import { MissingElement } from '../errors';
|
|
31
|
+
import { groupBy } from '../lib/utils';
|
|
31
32
|
import { schema, } from '../schema';
|
|
33
|
+
import { buildTitles } from './builders';
|
|
32
34
|
import { insertHighlightMarkers } from './highlight-markers';
|
|
33
35
|
import { generateNodeID } from './id';
|
|
34
36
|
import { ExtraObjectTypes, hasObjectType, isCommentAnnotation, isManuscript, } from './object-types';
|
|
35
|
-
import { chooseSectionLableName, chooseSectionNodeType, chooseSecType, guessSectionCategory, } from './section-category';
|
|
37
|
+
import { chooseCoreSectionBySection, chooseSectionLableName, chooseSectionNodeType, chooseSecType, guessSectionCategory, } from './section-category';
|
|
36
38
|
import { timestamp } from './timestamp';
|
|
37
39
|
const warn = debug('manuscripts-transform');
|
|
38
40
|
const parser = DOMParser.fromSchema(schema);
|
|
@@ -53,17 +55,41 @@ export const sortSectionsByPriority = (a, b) => a.priority === b.priority ? 0 :
|
|
|
53
55
|
const getSections = (modelMap) => getModelsByType(modelMap, ObjectTypes.Section).sort(sortSectionsByPriority);
|
|
54
56
|
const getAffiliations = (modelMap) => getModelsByType(modelMap, ObjectTypes.Affiliation);
|
|
55
57
|
const getContributors = (modelMap) => getModelsByType(modelMap, ObjectTypes.Contributor);
|
|
58
|
+
const getKeywordElements = (modelMap) => getModelsByType(modelMap, ObjectTypes.KeywordsElement);
|
|
59
|
+
const getKeywordGroups = (modelMap) => getModelsByType(modelMap, ObjectTypes.KeywordGroup);
|
|
60
|
+
const getKeywords = (modelMap) => getModelsByType(modelMap, ObjectTypes.Keyword);
|
|
61
|
+
const getTitles = (modelMap) => getModelsByType(modelMap, ObjectTypes.Titles)[0];
|
|
56
62
|
export const isManuscriptNode = (model) => model !== null;
|
|
57
|
-
const isParagraphElement = hasObjectType(ObjectTypes.ParagraphElement);
|
|
58
63
|
const isFootnote = hasObjectType(ObjectTypes.Footnote);
|
|
59
|
-
const isKeyword = hasObjectType(ObjectTypes.Keyword);
|
|
60
|
-
const isKeywordsSection = (model) => model.category === 'MPSectionCategory:keywords';
|
|
61
|
-
const isAffiliationsSection = (model) => model.category === 'MPSectionCategory:affiliations';
|
|
62
|
-
const isContributorsSection = (model) => model.category === 'MPSectionCategory:contributors';
|
|
63
64
|
const hasParentSection = (id) => (section) => section.path &&
|
|
64
65
|
section.path.length > 1 &&
|
|
65
66
|
section.path[section.path.length - 2] === id;
|
|
66
67
|
export class Decoder {
|
|
68
|
+
createTitleNode() {
|
|
69
|
+
const titles = getTitles(this.modelMap) || buildTitles();
|
|
70
|
+
return this.decode(titles);
|
|
71
|
+
}
|
|
72
|
+
createAffiliationsNode() {
|
|
73
|
+
const affiliations = getAffiliations(this.modelMap)
|
|
74
|
+
.map((a) => this.decode(a))
|
|
75
|
+
.filter(Boolean);
|
|
76
|
+
return schema.nodes.affiliations.createAndFill({}, affiliations);
|
|
77
|
+
}
|
|
78
|
+
createContributorsNode() {
|
|
79
|
+
const contributors = getContributors(this.modelMap)
|
|
80
|
+
.map((c) => this.decode(c))
|
|
81
|
+
.filter(Boolean);
|
|
82
|
+
return schema.nodes.contributors.createAndFill({}, contributors);
|
|
83
|
+
}
|
|
84
|
+
createKeywordsNode() {
|
|
85
|
+
const elements = getKeywordElements(this.modelMap)
|
|
86
|
+
.map((e) => this.decode(e))
|
|
87
|
+
.filter(Boolean);
|
|
88
|
+
return schema.nodes.keywords.createAndFill({}, [
|
|
89
|
+
schema.nodes.section_title.create({}, schema.text('Keywords')),
|
|
90
|
+
...elements,
|
|
91
|
+
]);
|
|
92
|
+
}
|
|
67
93
|
createMetaSectionNode() {
|
|
68
94
|
const commentListNode = this.createCommentListNode();
|
|
69
95
|
return schema.nodes.meta_section.createAndFill({}, [
|
|
@@ -75,49 +101,51 @@ export class Decoder {
|
|
|
75
101
|
...this.comments.values(),
|
|
76
102
|
]);
|
|
77
103
|
}
|
|
78
|
-
handleMissingRootSectionNodes(rootSectionNodes) {
|
|
79
|
-
if (!rootSectionNodes.find((node) => node.type.name === 'affiliations_section')) {
|
|
80
|
-
this.createAffiliationSectionNode(rootSectionNodes);
|
|
81
|
-
}
|
|
82
|
-
if (!rootSectionNodes.find((node) => node.type.name === 'contributors_section')) {
|
|
83
|
-
this.createContributorSectionNode(rootSectionNodes);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
createAffiliationSectionNode(rootSectionNodes) {
|
|
87
|
-
const affiliationNodes = getAffiliations(this.modelMap)
|
|
88
|
-
.map((affiliation) => this.decode(affiliation))
|
|
89
|
-
.filter(Boolean);
|
|
90
|
-
if (affiliationNodes.length) {
|
|
91
|
-
const node = schema.nodes.affiliations_section.createAndFill({
|
|
92
|
-
id: generateNodeID(schema.nodes.section),
|
|
93
|
-
}, affiliationNodes);
|
|
94
|
-
rootSectionNodes.unshift(node);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
createContributorSectionNode(rootSectionNodes) {
|
|
98
|
-
const contributorNodes = getContributors(this.modelMap)
|
|
99
|
-
.map((contributor) => this.decode(contributor))
|
|
100
|
-
.filter(Boolean);
|
|
101
|
-
if (contributorNodes.length) {
|
|
102
|
-
const node = schema.nodes.contributors_section.createAndFill({
|
|
103
|
-
id: generateNodeID(schema.nodes.section),
|
|
104
|
-
}, contributorNodes);
|
|
105
|
-
rootSectionNodes.unshift(node);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
104
|
createRootSectionNodes() {
|
|
109
|
-
let rootSections = getSections(this.modelMap)
|
|
105
|
+
let rootSections = getSections(this.modelMap)
|
|
106
|
+
.filter((section) => !section.path || section.path.length <= 1)
|
|
107
|
+
.filter((section) => section.category !== 'MPSectionCategory:contributors' &&
|
|
108
|
+
section.category !== 'MPSectionCategory:affiliations' &&
|
|
109
|
+
section.category !== 'MPSectionCategory:keywords');
|
|
110
110
|
rootSections = this.addGeneratedLabels(rootSections);
|
|
111
|
-
const
|
|
111
|
+
const sectionGroups = groupBy(rootSections, (sec) => {
|
|
112
|
+
var _a;
|
|
113
|
+
return chooseCoreSectionBySection((_a = sec.category) !== null && _a !== void 0 ? _a : '');
|
|
114
|
+
});
|
|
115
|
+
this.ensureCoreSectionsExist(sectionGroups);
|
|
116
|
+
const absSectionNode = sectionGroups['MPSectionCategory:abstracts']
|
|
112
117
|
.map(this.decode)
|
|
113
118
|
.filter(isManuscriptNode);
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
const bodySectionNodes = sectionGroups['MPSectionCategory:body']
|
|
120
|
+
.map(this.decode)
|
|
121
|
+
.filter(isManuscriptNode);
|
|
122
|
+
const backmatterSectionNodes = sectionGroups['MPSectionCategory:backmatter']
|
|
123
|
+
.map(this.decode)
|
|
124
|
+
.filter(isManuscriptNode);
|
|
125
|
+
const abstractCoreSectionNodes = this.createAndFill(schema.nodes.abstracts, absSectionNode);
|
|
126
|
+
const bodyCoreSectionNodes = this.createAndFill(schema.nodes.body, bodySectionNodes);
|
|
127
|
+
const backmatterCoreSectionNodes = this.createAndFill(schema.nodes.backmatter, backmatterSectionNodes);
|
|
128
|
+
return {
|
|
129
|
+
abstracts: abstractCoreSectionNodes,
|
|
130
|
+
body: bodyCoreSectionNodes,
|
|
131
|
+
backmatter: backmatterCoreSectionNodes,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
ensureCoreSectionsExist(coreSections) {
|
|
135
|
+
if (!coreSections['MPSectionCategory:abstracts']) {
|
|
136
|
+
coreSections['MPSectionCategory:abstracts'] = [];
|
|
119
137
|
}
|
|
120
|
-
|
|
138
|
+
if (!coreSections['MPSectionCategory:body']) {
|
|
139
|
+
coreSections['MPSectionCategory:body'] = [];
|
|
140
|
+
}
|
|
141
|
+
if (!coreSections['MPSectionCategory:backmatter']) {
|
|
142
|
+
coreSections['MPSectionCategory:backmatter'] = [];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
createAndFill(nodeType, content) {
|
|
146
|
+
return nodeType.createAndFill({
|
|
147
|
+
id: generateNodeID(nodeType),
|
|
148
|
+
}, content);
|
|
121
149
|
}
|
|
122
150
|
createCommentsNode(model) {
|
|
123
151
|
const comments = [];
|
|
@@ -137,6 +165,14 @@ export class Decoder {
|
|
|
137
165
|
constructor(modelMap, allowMissingElements = false) {
|
|
138
166
|
this.comments = new Map();
|
|
139
167
|
this.creators = {
|
|
168
|
+
[ObjectTypes.Titles]: (data) => {
|
|
169
|
+
const model = data;
|
|
170
|
+
return this.parseContents(model.title, 'div', undefined, {
|
|
171
|
+
topNode: schema.nodes.title.create({
|
|
172
|
+
id: model._id,
|
|
173
|
+
}),
|
|
174
|
+
});
|
|
175
|
+
},
|
|
140
176
|
[ObjectTypes.BibliographyElement]: (data) => {
|
|
141
177
|
var _a;
|
|
142
178
|
const model = data;
|
|
@@ -315,19 +351,32 @@ export class Decoder {
|
|
|
315
351
|
},
|
|
316
352
|
[ObjectTypes.KeywordsElement]: (data) => {
|
|
317
353
|
const model = data;
|
|
318
|
-
const keywordGroups = this.
|
|
354
|
+
const keywordGroups = getKeywordGroups(this.modelMap).map(k => this.decode(k));
|
|
319
355
|
return schema.nodes.keywords_element.create({
|
|
320
356
|
id: model._id,
|
|
321
357
|
paragraphStyle: model.paragraphStyle,
|
|
322
358
|
}, keywordGroups);
|
|
323
359
|
},
|
|
360
|
+
[ObjectTypes.KeywordGroup]: (data) => {
|
|
361
|
+
const keywordGroup = data;
|
|
362
|
+
const keywords = getKeywords(this.modelMap).filter(k => k.containedGroup === keywordGroup._id).map(k => this.decode(k));
|
|
363
|
+
const comments = this.createCommentsNode(keywordGroup);
|
|
364
|
+
comments.forEach((c) => this.comments.set(c.attrs.id, c));
|
|
365
|
+
return schema.nodes.keyword_group.create({
|
|
366
|
+
id: keywordGroup._id,
|
|
367
|
+
type: keywordGroup.type,
|
|
368
|
+
comments: comments.map((c) => c.attrs.id),
|
|
369
|
+
}, keywords);
|
|
370
|
+
},
|
|
324
371
|
[ObjectTypes.Keyword]: (data) => {
|
|
325
|
-
const
|
|
372
|
+
const keyword = data;
|
|
373
|
+
const comments = this.createCommentsNode(keyword);
|
|
374
|
+
comments.forEach((c) => this.comments.set(c.attrs.id, c));
|
|
326
375
|
return schema.nodes.keyword.create({
|
|
327
|
-
id:
|
|
328
|
-
contents:
|
|
329
|
-
comments:
|
|
330
|
-
}, schema.text(
|
|
376
|
+
id: keyword._id,
|
|
377
|
+
contents: keyword.name,
|
|
378
|
+
comments: comments.map((c) => c.attrs.id),
|
|
379
|
+
}, schema.text(keyword.name));
|
|
331
380
|
},
|
|
332
381
|
[ObjectTypes.ListElement]: (data) => {
|
|
333
382
|
const model = data;
|
|
@@ -449,9 +498,6 @@ export class Decoder {
|
|
|
449
498
|
for (const id of model.elementIDs) {
|
|
450
499
|
const element = this.getModel(id);
|
|
451
500
|
if (element) {
|
|
452
|
-
if (isKeywordsSection(model) && isParagraphElement(element)) {
|
|
453
|
-
continue;
|
|
454
|
-
}
|
|
455
501
|
elements.push(element);
|
|
456
502
|
}
|
|
457
503
|
else if (this.allowMissingElements) {
|
|
@@ -492,17 +538,11 @@ export class Decoder {
|
|
|
492
538
|
const sectionNodeType = chooseSectionNodeType(sectionCategory);
|
|
493
539
|
const commentNodes = this.createCommentsNode(model);
|
|
494
540
|
commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
content = (sectionLabelNode
|
|
501
|
-
? [sectionLabelNode, sectionTitleNode]
|
|
502
|
-
: [sectionTitleNode])
|
|
503
|
-
.concat(elementNodes)
|
|
504
|
-
.concat(nestedSections);
|
|
505
|
-
}
|
|
541
|
+
const content = (sectionLabelNode
|
|
542
|
+
? [sectionLabelNode, sectionTitleNode]
|
|
543
|
+
: [sectionTitleNode])
|
|
544
|
+
.concat(elementNodes)
|
|
545
|
+
.concat(nestedSections);
|
|
506
546
|
const sectionNode = sectionNodeType.createAndFill({
|
|
507
547
|
id: model._id,
|
|
508
548
|
category: sectionCategory,
|
|
@@ -621,9 +661,22 @@ export class Decoder {
|
|
|
621
661
|
};
|
|
622
662
|
this.getModel = (id) => this.modelMap.get(id);
|
|
623
663
|
this.createArticleNode = (manuscriptID) => {
|
|
624
|
-
const
|
|
625
|
-
const
|
|
626
|
-
const
|
|
664
|
+
const title = this.createTitleNode();
|
|
665
|
+
const contributors = this.createContributorsNode();
|
|
666
|
+
const affiliations = this.createAffiliationsNode();
|
|
667
|
+
const keywords = this.createKeywordsNode();
|
|
668
|
+
const { abstracts, body, backmatter } = this.createRootSectionNodes();
|
|
669
|
+
const meta = this.createMetaSectionNode();
|
|
670
|
+
const contents = [
|
|
671
|
+
title,
|
|
672
|
+
contributors,
|
|
673
|
+
affiliations,
|
|
674
|
+
keywords,
|
|
675
|
+
abstracts,
|
|
676
|
+
body,
|
|
677
|
+
backmatter,
|
|
678
|
+
meta,
|
|
679
|
+
];
|
|
627
680
|
return schema.nodes.manuscript.create({
|
|
628
681
|
id: manuscriptID || this.getManuscriptID(),
|
|
629
682
|
}, contents);
|
|
@@ -664,23 +717,6 @@ export class Decoder {
|
|
|
664
717
|
}
|
|
665
718
|
return parser.parse(template.content.firstElementChild, options);
|
|
666
719
|
};
|
|
667
|
-
this.getKeywords = (id) => {
|
|
668
|
-
const keywordsOfKind = [];
|
|
669
|
-
const keywordsByGroup = [...this.modelMap.values()].filter((m) => m.objectType === ObjectTypes.Keyword &&
|
|
670
|
-
m.containedGroup === id);
|
|
671
|
-
for (const model of keywordsByGroup) {
|
|
672
|
-
if (isKeyword(model)) {
|
|
673
|
-
const keyword = this.parseContents(model.name || '', 'div', this.getComments(model), {
|
|
674
|
-
topNode: schema.nodes.keyword.create({
|
|
675
|
-
id: model._id,
|
|
676
|
-
contents: model.name,
|
|
677
|
-
}),
|
|
678
|
-
});
|
|
679
|
-
keywordsOfKind.push(keyword);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
return keywordsOfKind;
|
|
683
|
-
};
|
|
684
720
|
this.getManuscriptID = () => {
|
|
685
721
|
for (const item of this.modelMap.values()) {
|
|
686
722
|
if (isManuscript(item)) {
|
|
@@ -765,26 +801,4 @@ export class Decoder {
|
|
|
765
801
|
}
|
|
766
802
|
return listing;
|
|
767
803
|
}
|
|
768
|
-
getKeywordGroups() {
|
|
769
|
-
const kwdGroupNodes = [];
|
|
770
|
-
const kwdGroupsModels = [
|
|
771
|
-
...this.modelMap.values(),
|
|
772
|
-
].filter((model) => model.objectType === ObjectTypes.KeywordGroup);
|
|
773
|
-
if (kwdGroupsModels.length > 0) {
|
|
774
|
-
for (const kwdGroupModel of kwdGroupsModels) {
|
|
775
|
-
const keywords = this.getKeywords(kwdGroupModel._id);
|
|
776
|
-
const commentNodes = this.createCommentsNode(kwdGroupModel);
|
|
777
|
-
commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
|
|
778
|
-
const contents = [];
|
|
779
|
-
contents.push(...keywords);
|
|
780
|
-
const kwdGroupNode = schema.nodes.keywords_group.create({
|
|
781
|
-
id: kwdGroupModel._id,
|
|
782
|
-
type: kwdGroupModel.type,
|
|
783
|
-
comments: commentNodes.map((c) => c.attrs.id),
|
|
784
|
-
}, contents);
|
|
785
|
-
kwdGroupNodes.push(kwdGroupNode);
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
return kwdGroupNodes;
|
|
789
|
-
}
|
|
790
804
|
}
|
|
@@ -255,6 +255,12 @@ function figureElementEncoder(node) {
|
|
|
255
255
|
};
|
|
256
256
|
}
|
|
257
257
|
const encoders = {
|
|
258
|
+
title: (node) => ({
|
|
259
|
+
title: inlineContents(node),
|
|
260
|
+
subtitle: node.attrs.subtitle,
|
|
261
|
+
runningTitle: node.attrs.runningTitle,
|
|
262
|
+
_id: node.attrs._id,
|
|
263
|
+
}),
|
|
258
264
|
bibliography_element: (node) => ({
|
|
259
265
|
elementType: 'div',
|
|
260
266
|
contents: '',
|
|
@@ -414,34 +420,9 @@ const encoders = {
|
|
|
414
420
|
elementType: 'div',
|
|
415
421
|
paragraphStyle: node.attrs.paragraphStyle || undefined,
|
|
416
422
|
}),
|
|
417
|
-
|
|
423
|
+
keyword_group: (node) => ({
|
|
418
424
|
type: node.attrs.type,
|
|
419
425
|
}),
|
|
420
|
-
keywords_section: (node, parent, path, priority) => ({
|
|
421
|
-
category: buildSectionCategory(node),
|
|
422
|
-
priority: priority.value++,
|
|
423
|
-
title: inlineContentsOfNodeType(node, node.type.schema.nodes.section_title),
|
|
424
|
-
path: path.concat([node.attrs.id]),
|
|
425
|
-
elementIDs: childElements(node)
|
|
426
|
-
.map((childNode) => childNode.attrs.id)
|
|
427
|
-
.filter((id) => id),
|
|
428
|
-
}),
|
|
429
|
-
affiliations_section: (node, parent, path, priority) => ({
|
|
430
|
-
category: buildSectionCategory(node),
|
|
431
|
-
priority: priority.value++,
|
|
432
|
-
path: path.concat([node.attrs.id]),
|
|
433
|
-
elementIDs: childElements(node)
|
|
434
|
-
.map((childNode) => childNode.attrs.id)
|
|
435
|
-
.filter((id) => id),
|
|
436
|
-
}),
|
|
437
|
-
contributors_section: (node, parent, path, priority) => ({
|
|
438
|
-
category: buildSectionCategory(node),
|
|
439
|
-
priority: priority.value++,
|
|
440
|
-
path: path.concat([node.attrs.id]),
|
|
441
|
-
elementIDs: childElements(node)
|
|
442
|
-
.map((childNode) => childNode.attrs.id)
|
|
443
|
-
.filter((id) => id),
|
|
444
|
-
}),
|
|
445
426
|
missing_figure: (node) => ({
|
|
446
427
|
position: node.attrs.position || undefined,
|
|
447
428
|
}),
|
|
@@ -561,6 +542,14 @@ export const modelFromNode = (node, parent, path, priority) => {
|
|
|
561
542
|
}
|
|
562
543
|
return { model, commentAnnotationsMap };
|
|
563
544
|
};
|
|
545
|
+
function isCoreSection(child) {
|
|
546
|
+
return (child.type === schema.nodes.abstracts ||
|
|
547
|
+
child.type === schema.nodes.body ||
|
|
548
|
+
child.type === schema.nodes.backmatter ||
|
|
549
|
+
child.type === schema.nodes.affiliations ||
|
|
550
|
+
child.type === schema.nodes.contributors ||
|
|
551
|
+
child.type === schema.nodes.keywords);
|
|
552
|
+
}
|
|
564
553
|
export const encode = (node) => {
|
|
565
554
|
const models = new Map();
|
|
566
555
|
const priority = {
|
|
@@ -568,6 +557,10 @@ export const encode = (node) => {
|
|
|
568
557
|
};
|
|
569
558
|
const placeholders = ['placeholder', 'placeholder_element'];
|
|
570
559
|
const addModel = (path, parent) => (child) => {
|
|
560
|
+
if (isCoreSection(child)) {
|
|
561
|
+
child.forEach(addModel([], child));
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
571
564
|
if (!child.attrs.id) {
|
|
572
565
|
return;
|
|
573
566
|
}
|
|
@@ -23,7 +23,7 @@ import { generateAttachmentFilename } from './filename';
|
|
|
23
23
|
import { buildTargets } from './labels';
|
|
24
24
|
import { isNodeType } from './node-types';
|
|
25
25
|
import { hasObjectType } from './object-types';
|
|
26
|
-
import { findJournal, findManuscript } from './project-bundle';
|
|
26
|
+
import { findJournal, findManuscript, findTitles } from './project-bundle';
|
|
27
27
|
import { chooseSecType } from './section-category';
|
|
28
28
|
const chooseNodeName = (element) => {
|
|
29
29
|
const nodeName = element.nodeName.toLowerCase();
|
|
@@ -146,6 +146,7 @@ export class HTMLTransformer {
|
|
|
146
146
|
this.buildFront = () => {
|
|
147
147
|
const manuscript = findManuscript(this.modelMap);
|
|
148
148
|
const journal = findJournal(this.modelMap);
|
|
149
|
+
const titles = findTitles(this.modelMap);
|
|
149
150
|
if (!manuscript) {
|
|
150
151
|
throw new Error('Manuscript not found in project modelMap');
|
|
151
152
|
}
|
|
@@ -164,14 +165,14 @@ export class HTMLTransformer {
|
|
|
164
165
|
}
|
|
165
166
|
const articleMeta = this.document.createElement('div');
|
|
166
167
|
front.appendChild(articleMeta);
|
|
167
|
-
const
|
|
168
|
-
if (
|
|
169
|
-
|
|
168
|
+
const title = this.document.createElement('h1');
|
|
169
|
+
if (titles.title) {
|
|
170
|
+
title.innerHTML = titles.title;
|
|
170
171
|
}
|
|
171
172
|
if (journal === null || journal === void 0 ? void 0 : journal.title) {
|
|
172
|
-
|
|
173
|
+
title.setAttribute('data-journal', journal.title);
|
|
173
174
|
}
|
|
174
|
-
articleMeta.appendChild(
|
|
175
|
+
articleMeta.appendChild(title);
|
|
175
176
|
if (manuscript.DOI) {
|
|
176
177
|
const articleID = this.document.createElement('article-id');
|
|
177
178
|
articleID.setAttribute('pub-id-type', 'doi');
|
|
@@ -35,6 +35,6 @@ export const nodeNames = new Map([
|
|
|
35
35
|
[schema.nodes.table_element, 'Table'],
|
|
36
36
|
[schema.nodes.blockquote_element, 'Block Quote'],
|
|
37
37
|
[schema.nodes.pullquote_element, 'Pull Quote'],
|
|
38
|
-
[schema.nodes.
|
|
38
|
+
[schema.nodes.keywords, 'Section'],
|
|
39
39
|
[schema.nodes.toc_section, 'Section'],
|
|
40
40
|
]);
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
import { iterateChildren } from '../lib/utils';
|
|
17
|
-
import { isHighlightMarkerNode } from '../schema';
|
|
17
|
+
import { isHighlightMarkerNode, schema } from '../schema';
|
|
18
18
|
import { nodeNames } from './node-names';
|
|
19
19
|
const textSnippet = (node, max = 100) => {
|
|
20
20
|
let text = '';
|
|
@@ -29,7 +29,7 @@ const textSnippet = (node, max = 100) => {
|
|
|
29
29
|
text += ' ';
|
|
30
30
|
}
|
|
31
31
|
});
|
|
32
|
-
return text.
|
|
32
|
+
return text.substring(0, max);
|
|
33
33
|
};
|
|
34
34
|
const snippetOfNodeType = (node, nodeType) => {
|
|
35
35
|
for (const child of iterateChildren(node, true)) {
|
|
@@ -40,12 +40,14 @@ const snippetOfNodeType = (node, nodeType) => {
|
|
|
40
40
|
return null;
|
|
41
41
|
};
|
|
42
42
|
export const nodeTitle = (node) => {
|
|
43
|
-
const nodes =
|
|
43
|
+
const nodes = schema.nodes;
|
|
44
44
|
switch (node.type) {
|
|
45
|
+
case nodes.manuscript:
|
|
46
|
+
return snippetOfNodeType(node, nodes.title);
|
|
45
47
|
case nodes.section:
|
|
46
48
|
case nodes.bibliography_section:
|
|
47
49
|
case nodes.footnotes_section:
|
|
48
|
-
case nodes.
|
|
50
|
+
case nodes.keywords:
|
|
49
51
|
case nodes.toc_section:
|
|
50
52
|
case nodes.graphical_abstract_section:
|
|
51
53
|
return snippetOfNodeType(node, nodes.section_title);
|
|
@@ -68,9 +70,9 @@ export const nodeTitle = (node) => {
|
|
|
68
70
|
}
|
|
69
71
|
};
|
|
70
72
|
export const nodeTitlePlaceholder = (nodeType) => {
|
|
71
|
-
const nodes =
|
|
73
|
+
const nodes = schema.nodes;
|
|
72
74
|
switch (nodeType) {
|
|
73
|
-
case nodes.
|
|
75
|
+
case nodes.manuscript:
|
|
74
76
|
return 'Untitled Manuscript';
|
|
75
77
|
case nodes.section:
|
|
76
78
|
return 'Untitled Section';
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
import { ObjectTypes } from '@manuscripts/json-schema';
|
|
17
17
|
import { GROUP_ELEMENT, GROUP_EXECUTABLE, GROUP_SECTION, hasGroup, schema, } from '../schema';
|
|
18
18
|
export const nodeTypesMap = new Map([
|
|
19
|
+
[schema.nodes.abstracts, ObjectTypes.Section],
|
|
20
|
+
[schema.nodes.body, ObjectTypes.Section],
|
|
21
|
+
[schema.nodes.backmatter, ObjectTypes.Section],
|
|
19
22
|
[schema.nodes.comment, ObjectTypes.CommentAnnotation],
|
|
20
23
|
[schema.nodes.bibliography_item, ObjectTypes.BibliographyItem],
|
|
21
24
|
[schema.nodes.bibliography_element, ObjectTypes.BibliographyElement],
|
|
@@ -37,8 +40,8 @@ export const nodeTypesMap = new Map([
|
|
|
37
40
|
[schema.nodes.inline_equation, ObjectTypes.InlineMathFragment],
|
|
38
41
|
[schema.nodes.keyword, ObjectTypes.Keyword],
|
|
39
42
|
[schema.nodes.keywords_element, ObjectTypes.KeywordsElement],
|
|
40
|
-
[schema.nodes.
|
|
41
|
-
[schema.nodes.
|
|
43
|
+
[schema.nodes.keywords, ObjectTypes.Section],
|
|
44
|
+
[schema.nodes.keyword_group, ObjectTypes.KeywordGroup],
|
|
42
45
|
[schema.nodes.listing, ObjectTypes.Listing],
|
|
43
46
|
[schema.nodes.listing_element, ObjectTypes.ListingElement],
|
|
44
47
|
[schema.nodes.manuscript, ObjectTypes.Manuscript],
|
|
@@ -54,8 +57,9 @@ export const nodeTypesMap = new Map([
|
|
|
54
57
|
[schema.nodes.affiliation, ObjectTypes.Affiliation],
|
|
55
58
|
[schema.nodes.contributor, ObjectTypes.Contributor],
|
|
56
59
|
[schema.nodes.table_element_footer, ObjectTypes.TableElementFooter],
|
|
57
|
-
[schema.nodes.
|
|
58
|
-
[schema.nodes.
|
|
60
|
+
[schema.nodes.contributors, ObjectTypes.Section],
|
|
61
|
+
[schema.nodes.affiliations, ObjectTypes.Section],
|
|
62
|
+
[schema.nodes.title, ObjectTypes.Titles],
|
|
59
63
|
]);
|
|
60
64
|
export const isExecutableNodeType = (type) => hasGroup(type, GROUP_EXECUTABLE);
|
|
61
65
|
export const isElementNodeType = (type) => hasGroup(type, GROUP_ELEMENT);
|
|
@@ -63,3 +63,23 @@ export const findManuscriptById = (modelMap, manuscriptID) => {
|
|
|
63
63
|
}
|
|
64
64
|
throw new Error(`There is no manuscript found for the following _id (${manuscriptID})`);
|
|
65
65
|
};
|
|
66
|
+
const isTitle = hasObjectType(ObjectTypes.Titles);
|
|
67
|
+
export const findTitles = (modelMap) => {
|
|
68
|
+
for (const model of modelMap.values()) {
|
|
69
|
+
if (isTitle(model)) {
|
|
70
|
+
return model;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const defaultTitle = {
|
|
74
|
+
_id: 'MPTitles:8EB79C14-9F61-483A-902F-A0B8EF5973C1',
|
|
75
|
+
createdAt: 1538472121.690101,
|
|
76
|
+
updatedAt: 1538472121.690101,
|
|
77
|
+
objectType: 'MPTitles',
|
|
78
|
+
title: 'main title',
|
|
79
|
+
subtitle: 'subtitle',
|
|
80
|
+
runningTitle: 'running title',
|
|
81
|
+
manuscriptID: 'MPManuscript:E3830344-E77B-42BA-BD77-3E95489712A0',
|
|
82
|
+
containerID: 'MPProject:1',
|
|
83
|
+
};
|
|
84
|
+
return defaultTitle;
|
|
85
|
+
};
|
|
@@ -19,7 +19,7 @@ import { schema } from '../schema';
|
|
|
19
19
|
const sectionNodeTypes = [
|
|
20
20
|
schema.nodes.bibliography_section,
|
|
21
21
|
schema.nodes.footnotes_section,
|
|
22
|
-
schema.nodes.
|
|
22
|
+
schema.nodes.keywords,
|
|
23
23
|
schema.nodes.section,
|
|
24
24
|
schema.nodes.toc_section,
|
|
25
25
|
];
|
|
@@ -40,11 +40,11 @@ export const chooseSectionNodeType = (category) => {
|
|
|
40
40
|
case 'MPSectionCategory:endnotes':
|
|
41
41
|
return schema.nodes.footnotes_section;
|
|
42
42
|
case 'MPSectionCategory:keywords':
|
|
43
|
-
return schema.nodes.
|
|
43
|
+
return schema.nodes.keywords;
|
|
44
44
|
case 'MPSectionCategory:affiliations':
|
|
45
|
-
return schema.nodes.
|
|
45
|
+
return schema.nodes.affiliations;
|
|
46
46
|
case 'MPSectionCategory:contributors':
|
|
47
|
-
return schema.nodes.
|
|
47
|
+
return schema.nodes.contributors;
|
|
48
48
|
case 'MPSectionCategory:toc':
|
|
49
49
|
return schema.nodes.toc_section;
|
|
50
50
|
default:
|
|
@@ -82,15 +82,15 @@ export const buildSectionCategory = (node) => {
|
|
|
82
82
|
return 'MPSectionCategory:bibliography';
|
|
83
83
|
case schema.nodes.footnotes_section:
|
|
84
84
|
return 'MPSectionCategory:endnotes';
|
|
85
|
-
case schema.nodes.
|
|
85
|
+
case schema.nodes.keywords:
|
|
86
86
|
return 'MPSectionCategory:keywords';
|
|
87
87
|
case schema.nodes.toc_section:
|
|
88
88
|
return 'MPSectionCategory:toc';
|
|
89
89
|
case schema.nodes.graphical_abstract_section:
|
|
90
90
|
return 'MPSectionCategory:abstract-graphical';
|
|
91
|
-
case schema.nodes.
|
|
91
|
+
case schema.nodes.affiliations:
|
|
92
92
|
return 'MPSectionCategory:affiliations';
|
|
93
|
-
case schema.nodes.
|
|
93
|
+
case schema.nodes.contributors:
|
|
94
94
|
return 'MPSectionCategory:contributors';
|
|
95
95
|
default:
|
|
96
96
|
return node.attrs.category || undefined;
|
|
@@ -117,6 +117,32 @@ export const chooseSecType = (sectionCategory) => {
|
|
|
117
117
|
return suffix;
|
|
118
118
|
}
|
|
119
119
|
};
|
|
120
|
+
export const chooseCoreSectionBySection = (section) => {
|
|
121
|
+
switch (section) {
|
|
122
|
+
case 'MPSectionCategory:abstract':
|
|
123
|
+
case 'MPSectionCategory:abstract-teaser':
|
|
124
|
+
case 'MPSectionCategory:abstract-graphical':
|
|
125
|
+
return 'MPSectionCategory:abstracts';
|
|
126
|
+
case 'MPSectionCategory:acknowledgement':
|
|
127
|
+
case 'MPSectionCategory:availability':
|
|
128
|
+
case 'MPSectionCategory:conclusions':
|
|
129
|
+
case 'MPSectionCategory:bibliography':
|
|
130
|
+
case 'MPSectionCategory:discussion':
|
|
131
|
+
case 'MPSectionCategory:endnotes':
|
|
132
|
+
case 'MPSectionCategory:appendices':
|
|
133
|
+
case 'MPSectionCategory:competing-interests':
|
|
134
|
+
case 'MPSectionCategory:con':
|
|
135
|
+
case 'MPSectionCategory:deceased':
|
|
136
|
+
case 'MPSectionCategory:ethics-statement':
|
|
137
|
+
case 'MPSectionCategory:financial-disclosure':
|
|
138
|
+
case 'MPSectionCategory:supplementary-material':
|
|
139
|
+
case 'MPSectionCategory:supported-by':
|
|
140
|
+
case 'MPSectionCategory:abbreviations':
|
|
141
|
+
case 'MPSectionCategory:results':
|
|
142
|
+
return 'MPSectionCategory:backmatter';
|
|
143
|
+
}
|
|
144
|
+
return 'MPSectionCategory:body';
|
|
145
|
+
};
|
|
120
146
|
export const chooseSectionCategoryByType = (secType) => {
|
|
121
147
|
switch (secType) {
|
|
122
148
|
case 'abstract':
|
|
@@ -27,3 +27,4 @@ export declare const findParentNodeClosestToPos: ($pos: ResolvedPos, predicate:
|
|
|
27
27
|
node: ProsemirrorNode;
|
|
28
28
|
} | undefined;
|
|
29
29
|
export declare const getTrimmedTextContent: (node: Element | Document, querySelector: string) => string | null | undefined;
|
|
30
|
+
export declare const groupBy: <T, K extends string | number | symbol>(list: T[], getKey: (item: T) => K) => Record<K, T[]>;
|
|
@@ -44,7 +44,7 @@ export * from './nodes/inline_equation';
|
|
|
44
44
|
export * from './nodes/inline_footnote';
|
|
45
45
|
export * from './nodes/keyword';
|
|
46
46
|
export * from './nodes/keywords_element';
|
|
47
|
-
export * from './nodes/
|
|
47
|
+
export * from './nodes/keywords';
|
|
48
48
|
export * from './nodes/link';
|
|
49
49
|
export * from './nodes/list';
|
|
50
50
|
export * from './nodes/listing';
|
|
@@ -68,6 +68,7 @@ export * from './nodes/affiliation';
|
|
|
68
68
|
export * from './nodes/meta_section';
|
|
69
69
|
export * from './nodes/contributor';
|
|
70
70
|
export * from './nodes/table_element_footer';
|
|
71
|
-
export * from './nodes/
|
|
72
|
-
export * from './nodes/
|
|
71
|
+
export * from './nodes/title';
|
|
72
|
+
export * from './nodes/affiliations';
|
|
73
|
+
export * from './nodes/contributors';
|
|
73
74
|
export declare const schema: Schema<Nodes, Marks>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NodeSpec } from 'prosemirror-model';
|
|
2
|
+
import { ManuscriptNode } from '../types';
|
|
3
|
+
interface Attrs {
|
|
4
|
+
id: string;
|
|
5
|
+
}
|
|
6
|
+
export interface AffiliationsNode extends ManuscriptNode {
|
|
7
|
+
attrs: Attrs;
|
|
8
|
+
}
|
|
9
|
+
export declare const affiliations: NodeSpec;
|
|
10
|
+
export declare const isAffiliationsNode: (node: ManuscriptNode) => node is AffiliationsNode;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NodeSpec } from 'prosemirror-model';
|
|
2
|
+
import { ManuscriptNode } from '../types';
|
|
3
|
+
interface Attrs {
|
|
4
|
+
id: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ContributorsNode extends ManuscriptNode {
|
|
7
|
+
attrs: Attrs;
|
|
8
|
+
}
|
|
9
|
+
export declare const contributors: NodeSpec;
|
|
10
|
+
export declare const isContributorsNode: (node: ManuscriptNode) => node is ContributorsNode;
|
|
11
|
+
export {};
|