@manuscripts/transform 1.5.2-LEAN-3047 → 1.5.2-LEAN-3032

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 (38) hide show
  1. package/dist/cjs/jats/importer/jats-body-dom-parser.js +19 -7
  2. package/dist/cjs/jats/jats-exporter.js +10 -5
  3. package/dist/cjs/lib/utils.js +10 -1
  4. package/dist/cjs/schema/index.js +7 -3
  5. package/dist/cjs/schema/nodes/affiliations_section.js +1 -1
  6. package/dist/cjs/schema/nodes/contributors_section.js +1 -1
  7. package/dist/cjs/schema/nodes/core_section.js +27 -0
  8. package/dist/cjs/schema/nodes/graphical_abstract_section.js +0 -1
  9. package/dist/cjs/schema/nodes/keywords_section.js +1 -1
  10. package/dist/cjs/schema/nodes/manuscript.js +1 -1
  11. package/dist/cjs/transformer/decode.js +67 -19
  12. package/dist/cjs/transformer/encode.js +12 -25
  13. package/dist/cjs/transformer/node-names.js +1 -1
  14. package/dist/cjs/transformer/node-title.js +1 -1
  15. package/dist/cjs/transformer/node-types.js +6 -3
  16. package/dist/cjs/transformer/section-category.js +35 -8
  17. package/dist/es/jats/importer/jats-body-dom-parser.js +19 -7
  18. package/dist/es/jats/jats-exporter.js +10 -5
  19. package/dist/es/lib/utils.js +8 -0
  20. package/dist/es/schema/index.js +7 -3
  21. package/dist/es/schema/nodes/affiliations_section.js +1 -1
  22. package/dist/es/schema/nodes/contributors_section.js +1 -1
  23. package/dist/es/schema/nodes/core_section.js +24 -0
  24. package/dist/es/schema/nodes/graphical_abstract_section.js +0 -1
  25. package/dist/es/schema/nodes/keywords_section.js +1 -1
  26. package/dist/es/schema/nodes/manuscript.js +1 -1
  27. package/dist/es/transformer/decode.js +68 -20
  28. package/dist/es/transformer/encode.js +12 -25
  29. package/dist/es/transformer/node-names.js +1 -1
  30. package/dist/es/transformer/node-title.js +1 -1
  31. package/dist/es/transformer/node-types.js +6 -3
  32. package/dist/es/transformer/section-category.js +33 -7
  33. package/dist/types/lib/utils.d.ts +1 -0
  34. package/dist/types/schema/nodes/core_section.d.ts +25 -0
  35. package/dist/types/schema/types.d.ts +1 -1
  36. package/dist/types/transformer/decode.d.ts +3 -0
  37. package/dist/types/transformer/section-category.d.ts +1 -0
  38. package/package.json +2 -2
@@ -507,7 +507,7 @@ const nodes = [
507
507
  },
508
508
  {
509
509
  tag: 'sec[sec-type="affiliations"]',
510
- node: 'affiliations_section',
510
+ node: 'affiliations',
511
511
  getAttrs: (node) => {
512
512
  const element = node;
513
513
  return {
@@ -519,7 +519,7 @@ const nodes = [
519
519
  {
520
520
  tag: 'aff',
521
521
  node: 'affiliation',
522
- context: 'affiliations_section/',
522
+ context: 'affiliations/',
523
523
  getAttrs: (node) => {
524
524
  const element = node;
525
525
  const aff = {
@@ -566,7 +566,7 @@ const nodes = [
566
566
  },
567
567
  {
568
568
  tag: 'sec[sec-type="contributors"]',
569
- node: 'contributors_section',
569
+ node: 'contributors',
570
570
  getAttrs: (node) => {
571
571
  const element = node;
572
572
  return {
@@ -578,7 +578,7 @@ const nodes = [
578
578
  {
579
579
  tag: 'contrib',
580
580
  node: 'contributor',
581
- context: 'contributors_section/',
581
+ context: 'contributors/',
582
582
  getAttrs: (node) => {
583
583
  const element = node;
584
584
  const contrib = {
@@ -633,7 +633,7 @@ const nodes = [
633
633
  },
634
634
  {
635
635
  tag: 'sec[sec-type="keywords"]',
636
- node: 'keywords_section',
636
+ node: 'keywords',
637
637
  getAttrs: (node) => {
638
638
  const element = node;
639
639
  return {
@@ -644,9 +644,21 @@ const nodes = [
644
644
  },
645
645
  {
646
646
  tag: 'kwd-group-list',
647
- context: 'keywords_section/',
647
+ context: 'keywords/',
648
648
  node: 'keywords_element',
649
649
  },
650
+ {
651
+ tag: 'sec[sec-type="abstracts"]',
652
+ node: 'abstracts',
653
+ },
654
+ {
655
+ tag: 'sec[sec-type="body"]',
656
+ node: 'body',
657
+ },
658
+ {
659
+ tag: 'sec[sec-type="backmatter"]',
660
+ node: 'backmatter',
661
+ },
650
662
  {
651
663
  tag: 'sec',
652
664
  node: 'section',
@@ -726,7 +738,7 @@ const nodes = [
726
738
  {
727
739
  tag: 'title',
728
740
  node: 'section_title',
729
- context: 'section/|footnotes_section/|bibliography_section/|keywords_section/',
741
+ context: 'section/|footnotes_section/|bibliography_section/|keywords/',
730
742
  },
731
743
  {
732
744
  tag: 'title',
@@ -430,9 +430,11 @@ class JATSExporter {
430
430
  }
431
431
  };
432
432
  this.buildBody = (fragment) => {
433
- const content = this.serializeFragment(fragment);
434
433
  const body = this.document.createElement('body');
435
- body.appendChild(content);
434
+ fragment.forEach((cFragment) => {
435
+ const serializedNode = this.serializeNode(cFragment);
436
+ body.append(...serializedNode.childNodes);
437
+ });
436
438
  this.fixBody(body, fragment);
437
439
  return body;
438
440
  };
@@ -598,8 +600,8 @@ class JATSExporter {
598
600
  this.createSerializer = () => {
599
601
  const getModel = (id) => id ? this.modelMap.get(id) : undefined;
600
602
  const nodes = {
601
- affiliations_section: () => '',
602
- contributors_section: () => '',
603
+ affiliations: () => '',
604
+ contributors: () => '',
603
605
  table_element_footer: () => ['table-wrap-foot', 0],
604
606
  contributor: () => '',
605
607
  affiliation: () => '',
@@ -609,6 +611,9 @@ class JATSExporter {
609
611
  bibliography_item: () => '',
610
612
  comment_list: () => '',
611
613
  keywords_group: () => '',
614
+ body: () => ['body', 0],
615
+ abstracts: () => ['abstract', 0],
616
+ backmatter: () => ['backmatter', 0],
612
617
  bibliography_section: (node) => [
613
618
  'ref-list',
614
619
  { id: normalizeID(node.attrs.id) },
@@ -787,7 +792,7 @@ class JATSExporter {
787
792
  },
788
793
  keyword: () => '',
789
794
  keywords_element: () => '',
790
- keywords_section: () => '',
795
+ keywords: () => '',
791
796
  link: (node) => {
792
797
  const text = node.textContent;
793
798
  if (!text) {
@@ -15,7 +15,7 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.getTrimmedTextContent = exports.findParentNodeClosestToPos = exports.isInAbstractsSection = exports.isInBibliographySection = exports.isInGraphicalAbstractSection = exports.findNodePositions = exports.iterateChildren = void 0;
18
+ exports.groupBy = exports.getTrimmedTextContent = exports.findParentNodeClosestToPos = exports.isInAbstractsSection = exports.isInBibliographySection = exports.isInGraphicalAbstractSection = exports.findNodePositions = exports.iterateChildren = void 0;
19
19
  const bibliography_section_1 = require("../schema/nodes/bibliography_section");
20
20
  const graphical_abstract_section_1 = require("../schema/nodes/graphical_abstract_section");
21
21
  function* iterateChildren(node, recurse = false) {
@@ -94,3 +94,12 @@ const getTrimmedTextContent = (node, querySelector) => {
94
94
  return (_b = (_a = node.querySelector(querySelector)) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim();
95
95
  };
96
96
  exports.getTrimmedTextContent = getTrimmedTextContent;
97
+ const groupBy = (list, getKey) => list.reduce((previous, currentItem) => {
98
+ const group = getKey(currentItem);
99
+ if (!previous[group]) {
100
+ previous[group] = [];
101
+ }
102
+ previous[group].push(currentItem);
103
+ return previous;
104
+ }, {});
105
+ exports.groupBy = groupBy;
@@ -46,6 +46,7 @@ const comment_1 = require("./nodes/comment");
46
46
  const comment_list_1 = require("./nodes/comment_list");
47
47
  const contributor_1 = require("./nodes/contributor");
48
48
  const contributors_section_1 = require("./nodes/contributors_section");
49
+ const core_section_1 = require("./nodes/core_section");
49
50
  const cross_reference_1 = require("./nodes/cross_reference");
50
51
  const doc_1 = require("./nodes/doc");
51
52
  const equation_1 = require("./nodes/equation");
@@ -168,6 +169,9 @@ exports.schema = new prosemirror_model_1.Schema({
168
169
  caption: caption_1.caption,
169
170
  caption_title: caption_title_1.captionTitle,
170
171
  citation: citation_1.citation,
172
+ abstracts: core_section_1.coreSection,
173
+ body: core_section_1.coreSection,
174
+ backmatter: core_section_1.coreSection,
171
175
  cross_reference: cross_reference_1.crossReference,
172
176
  doc: doc_1.doc,
173
177
  equation: equation_1.equation,
@@ -185,7 +189,7 @@ exports.schema = new prosemirror_model_1.Schema({
185
189
  inline_footnote: inline_footnote_1.inlineFootnote,
186
190
  keyword: keyword_1.keyword,
187
191
  keywords_element: keywords_element_1.keywordsElement,
188
- keywords_section: keywords_section_1.keywordsSection,
192
+ keywords: keywords_section_1.keywordsSection,
189
193
  keywords_group: keywords_group_1.keywordsGroup,
190
194
  link: link_1.link,
191
195
  list_item: list_1.listItem,
@@ -216,7 +220,7 @@ exports.schema = new prosemirror_model_1.Schema({
216
220
  meta_section: meta_section_1.metaSection,
217
221
  contributor: contributor_1.contributor,
218
222
  table_element_footer: table_element_footer_1.tableElementFooter,
219
- affiliations_section: affiliations_section_1.affiliationsSection,
220
- contributors_section: contributors_section_1.contributorsSection,
223
+ affiliations: affiliations_section_1.affiliationsSection,
224
+ contributors: contributors_section_1.contributorsSection,
221
225
  },
222
226
  });
@@ -11,5 +11,5 @@ exports.affiliationsSection = {
11
11
  selectable: false,
12
12
  toDOM: () => ['section', 0],
13
13
  };
14
- const isAffiliationsSectionNode = (node) => node.type === node.type.schema.nodes.affiliations_section;
14
+ const isAffiliationsSectionNode = (node) => node.type === node.type.schema.nodes.affiliations;
15
15
  exports.isAffiliationsSectionNode = isAffiliationsSectionNode;
@@ -11,5 +11,5 @@ exports.contributorsSection = {
11
11
  selectable: false,
12
12
  toDOM: () => ['section', 0],
13
13
  };
14
- const isContributorsSectionNode = (node) => node.type === node.type.schema.nodes.contributors_section;
14
+ const isContributorsSectionNode = (node) => node.type === node.type.schema.nodes.contributors;
15
15
  exports.isContributorsSectionNode = isContributorsSectionNode;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2019 Atypon Systems LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.coreSection = void 0;
19
+ exports.coreSection = {
20
+ content: '(section | sections)*',
21
+ atom: true,
22
+ attrs: {
23
+ id: { default: '' },
24
+ },
25
+ group: 'block sections',
26
+ toDOM: () => ['section', 0],
27
+ };
@@ -21,7 +21,6 @@ exports.graphicalAbstractSection = {
21
21
  attrs: {
22
22
  id: { default: '' },
23
23
  category: { default: '' },
24
- dataTracked: { default: null },
25
24
  },
26
25
  group: 'block sections',
27
26
  selectable: false,
@@ -43,5 +43,5 @@ exports.keywordsSection = {
43
43
  ];
44
44
  },
45
45
  };
46
- const isKeywordsSectionNode = (node) => node.type === node.type.schema.nodes.keywords_section;
46
+ const isKeywordsSectionNode = (node) => node.type === node.type.schema.nodes.keywords;
47
47
  exports.isKeywordsSectionNode = isKeywordsSectionNode;
@@ -17,7 +17,7 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.manuscript = void 0;
19
19
  exports.manuscript = {
20
- content: '(section | sections)+ meta_section',
20
+ content: 'contributors? affiliations? keywords? abstracts body backmatter meta_section',
21
21
  attrs: {
22
22
  id: { default: '' },
23
23
  },
@@ -34,6 +34,7 @@ const json_schema_1 = require("@manuscripts/json-schema");
34
34
  const debug_1 = __importDefault(require("debug"));
35
35
  const prosemirror_model_1 = require("prosemirror-model");
36
36
  const errors_1 = require("../errors");
37
+ const utils_1 = require("../lib/utils");
37
38
  const schema_1 = require("../schema");
38
39
  const highlight_markers_1 = require("./highlight-markers");
39
40
  const id_1 = require("./id");
@@ -62,6 +63,7 @@ exports.sortSectionsByPriority = sortSectionsByPriority;
62
63
  const getSections = (modelMap) => (0, exports.getModelsByType)(modelMap, json_schema_1.ObjectTypes.Section).sort(exports.sortSectionsByPriority);
63
64
  const getAffiliations = (modelMap) => (0, exports.getModelsByType)(modelMap, json_schema_1.ObjectTypes.Affiliation);
64
65
  const getContributors = (modelMap) => (0, exports.getModelsByType)(modelMap, json_schema_1.ObjectTypes.Contributor);
66
+ const getKeywordElements = (modelMap) => (0, exports.getModelsByType)(modelMap, json_schema_1.ObjectTypes.KeywordsElement);
65
67
  const isManuscriptNode = (model) => model !== null;
66
68
  exports.isManuscriptNode = isManuscriptNode;
67
69
  const isParagraphElement = (0, object_types_1.hasObjectType)(json_schema_1.ObjectTypes.ParagraphElement);
@@ -86,10 +88,13 @@ class Decoder {
86
88
  ]);
87
89
  }
88
90
  handleMissingRootSectionNodes(rootSectionNodes) {
89
- if (!rootSectionNodes.find((node) => node.type.name === 'affiliations_section')) {
91
+ if (!rootSectionNodes.find((node) => node.type.name === 'keywords')) {
92
+ this.createKeywordsSectionNode(rootSectionNodes);
93
+ }
94
+ if (!rootSectionNodes.find((node) => node.type.name === 'affiliations')) {
90
95
  this.createAffiliationSectionNode(rootSectionNodes);
91
96
  }
92
- if (!rootSectionNodes.find((node) => node.type.name === 'contributors_section')) {
97
+ if (!rootSectionNodes.find((node) => node.type.name === 'contributors')) {
93
98
  this.createContributorSectionNode(rootSectionNodes);
94
99
  }
95
100
  }
@@ -97,37 +102,79 @@ class Decoder {
97
102
  const affiliationNodes = getAffiliations(this.modelMap)
98
103
  .map((affiliation) => this.decode(affiliation))
99
104
  .filter(Boolean);
100
- if (affiliationNodes.length) {
101
- const node = schema_1.schema.nodes.affiliations_section.createAndFill({
102
- id: (0, id_1.generateNodeID)(schema_1.schema.nodes.section),
103
- }, affiliationNodes);
104
- rootSectionNodes.unshift(node);
105
- }
105
+ const node = schema_1.schema.nodes.affiliations.createAndFill({
106
+ id: (0, id_1.generateNodeID)(schema_1.schema.nodes.section),
107
+ }, affiliationNodes);
108
+ rootSectionNodes.unshift(node);
106
109
  }
107
110
  createContributorSectionNode(rootSectionNodes) {
108
111
  const contributorNodes = getContributors(this.modelMap)
109
112
  .map((contributor) => this.decode(contributor))
110
113
  .filter(Boolean);
111
- if (contributorNodes.length) {
112
- const node = schema_1.schema.nodes.contributors_section.createAndFill({
114
+ const node = schema_1.schema.nodes.contributors.createAndFill({
115
+ id: (0, id_1.generateNodeID)(schema_1.schema.nodes.section),
116
+ }, contributorNodes);
117
+ rootSectionNodes.unshift(node);
118
+ }
119
+ createKeywordsSectionNode(rootSectionNodes) {
120
+ const keywordElementNodes = getKeywordElements(this.modelMap)
121
+ .map((keywordEl) => this.decode(keywordEl))
122
+ .filter(Boolean);
123
+ if (keywordElementNodes) {
124
+ const node = schema_1.schema.nodes.keywords.createAndFill({
113
125
  id: (0, id_1.generateNodeID)(schema_1.schema.nodes.section),
114
- }, contributorNodes);
126
+ }, [
127
+ schema_1.schema.nodes.section_title.create({}, schema_1.schema.text('Keywords')),
128
+ ...keywordElementNodes,
129
+ ]);
115
130
  rootSectionNodes.unshift(node);
116
131
  }
117
132
  }
118
133
  createRootSectionNodes() {
119
- let rootSections = getSections(this.modelMap).filter((section) => !section.path || section.path.length <= 1);
134
+ let rootSections = getSections(this.modelMap)
135
+ .filter((section) => !section.path || section.path.length <= 1)
136
+ .filter((section) => section.category !== 'MPSectionCategory:contributors' &&
137
+ section.category !== 'MPSectionCategory:affiliations' &&
138
+ section.category !== 'MPSectionCategory:keywords');
120
139
  rootSections = this.addGeneratedLabels(rootSections);
121
- const rootSectionNodes = rootSections
140
+ const sectionGroups = (0, utils_1.groupBy)(rootSections, (sec) => {
141
+ var _a;
142
+ return (0, section_category_1.chooseCoreSectionBySection)((_a = sec.category) !== null && _a !== void 0 ? _a : '');
143
+ });
144
+ this.ensureCoreSectionsExist(sectionGroups);
145
+ const absSectionNode = sectionGroups['MPSectionCategory:abstracts']
122
146
  .map(this.decode)
123
147
  .filter(exports.isManuscriptNode);
124
- this.handleMissingRootSectionNodes(rootSectionNodes);
125
- if (!rootSectionNodes.length) {
126
- rootSectionNodes.push(schema_1.schema.nodes.section.createAndFill({
127
- id: (0, id_1.generateNodeID)(schema_1.schema.nodes.section),
128
- }));
148
+ const bodySectionNodes = sectionGroups['MPSectionCategory:body']
149
+ .map(this.decode)
150
+ .filter(exports.isManuscriptNode);
151
+ const backmatterSectionNodes = sectionGroups['MPSectionCategory:backmatter']
152
+ .map(this.decode)
153
+ .filter(exports.isManuscriptNode);
154
+ const abstractCoreSectionNodes = this.createAndFill(schema_1.schema.nodes.abstracts, absSectionNode);
155
+ const bodyCoreSectionNodes = this.createAndFill(schema_1.schema.nodes.body, bodySectionNodes);
156
+ const backmatterCoreSectionNodes = this.createAndFill(schema_1.schema.nodes.backmatter, backmatterSectionNodes);
157
+ return [
158
+ abstractCoreSectionNodes,
159
+ bodyCoreSectionNodes,
160
+ backmatterCoreSectionNodes,
161
+ ];
162
+ }
163
+ ensureCoreSectionsExist(coreSections) {
164
+ if (!coreSections['MPSectionCategory:abstracts']) {
165
+ coreSections['MPSectionCategory:abstracts'] = [];
129
166
  }
130
- return rootSectionNodes;
167
+ if (!coreSections['MPSectionCategory:body']) {
168
+ coreSections['MPSectionCategory:body'] = [];
169
+ }
170
+ if (!coreSections['MPSectionCategory:backmatter']) {
171
+ coreSections['MPSectionCategory:backmatter'] = [];
172
+ }
173
+ }
174
+ createAndFill(nodeType, content) {
175
+ return nodeType.createAndFill({
176
+ id: (0, id_1.generateNodeID)(nodeType),
177
+ }, content);
131
178
  }
132
179
  createCommentsNode(model) {
133
180
  const comments = [];
@@ -632,6 +679,7 @@ class Decoder {
632
679
  this.getModel = (id) => this.modelMap.get(id);
633
680
  this.createArticleNode = (manuscriptID) => {
634
681
  const rootSectionNodes = this.createRootSectionNodes();
682
+ this.handleMissingRootSectionNodes(rootSectionNodes);
635
683
  const metaSectionNode = this.createMetaSectionNode();
636
684
  const contents = [...rootSectionNodes, metaSectionNode];
637
685
  return schema_1.schema.nodes.manuscript.create({
@@ -425,31 +425,6 @@ const encoders = {
425
425
  keywords_group: (node) => ({
426
426
  type: node.attrs.type,
427
427
  }),
428
- keywords_section: (node, parent, path, priority) => ({
429
- category: (0, section_category_1.buildSectionCategory)(node),
430
- priority: priority.value++,
431
- title: inlineContentsOfNodeType(node, node.type.schema.nodes.section_title),
432
- path: path.concat([node.attrs.id]),
433
- elementIDs: childElements(node)
434
- .map((childNode) => childNode.attrs.id)
435
- .filter((id) => id),
436
- }),
437
- affiliations_section: (node, parent, path, priority) => ({
438
- category: (0, section_category_1.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
- contributors_section: (node, parent, path, priority) => ({
446
- category: (0, section_category_1.buildSectionCategory)(node),
447
- priority: priority.value++,
448
- path: path.concat([node.attrs.id]),
449
- elementIDs: childElements(node)
450
- .map((childNode) => childNode.attrs.id)
451
- .filter((id) => id),
452
- }),
453
428
  missing_figure: (node) => ({
454
429
  position: node.attrs.position || undefined,
455
430
  }),
@@ -570,6 +545,14 @@ const modelFromNode = (node, parent, path, priority) => {
570
545
  return { model, commentAnnotationsMap };
571
546
  };
572
547
  exports.modelFromNode = modelFromNode;
548
+ function isCoreSection(child) {
549
+ return (child.type === schema_1.schema.nodes.abstracts ||
550
+ child.type === schema_1.schema.nodes.body ||
551
+ child.type === schema_1.schema.nodes.backmatter ||
552
+ child.type === schema_1.schema.nodes.affiliations ||
553
+ child.type === schema_1.schema.nodes.contributors ||
554
+ child.type === schema_1.schema.nodes.keywords);
555
+ }
573
556
  const encode = (node) => {
574
557
  const models = new Map();
575
558
  const priority = {
@@ -577,6 +560,10 @@ const encode = (node) => {
577
560
  };
578
561
  const placeholders = ['placeholder', 'placeholder_element'];
579
562
  const addModel = (path, parent) => (child) => {
563
+ if (isCoreSection(child)) {
564
+ child.forEach(addModel([], child));
565
+ return;
566
+ }
580
567
  if (!child.attrs.id) {
581
568
  return;
582
569
  }
@@ -38,6 +38,6 @@ exports.nodeNames = new Map([
38
38
  [schema_1.schema.nodes.table_element, 'Table'],
39
39
  [schema_1.schema.nodes.blockquote_element, 'Block Quote'],
40
40
  [schema_1.schema.nodes.pullquote_element, 'Pull Quote'],
41
- [schema_1.schema.nodes.keywords_section, 'Section'],
41
+ [schema_1.schema.nodes.keywords, 'Section'],
42
42
  [schema_1.schema.nodes.toc_section, 'Section'],
43
43
  ]);
@@ -48,7 +48,7 @@ const nodeTitle = (node) => {
48
48
  case nodes.section:
49
49
  case nodes.bibliography_section:
50
50
  case nodes.footnotes_section:
51
- case nodes.keywords_section:
51
+ case nodes.keywords:
52
52
  case nodes.toc_section:
53
53
  case nodes.graphical_abstract_section:
54
54
  return snippetOfNodeType(node, nodes.section_title);
@@ -19,6 +19,9 @@ exports.isNodeType = exports.isSectionNodeType = exports.isElementNodeType = exp
19
19
  const json_schema_1 = require("@manuscripts/json-schema");
20
20
  const schema_1 = require("../schema");
21
21
  exports.nodeTypesMap = new Map([
22
+ [schema_1.schema.nodes.abstracts, json_schema_1.ObjectTypes.Section],
23
+ [schema_1.schema.nodes.body, json_schema_1.ObjectTypes.Section],
24
+ [schema_1.schema.nodes.backmatter, json_schema_1.ObjectTypes.Section],
22
25
  [schema_1.schema.nodes.comment, json_schema_1.ObjectTypes.CommentAnnotation],
23
26
  [schema_1.schema.nodes.bibliography_item, json_schema_1.ObjectTypes.BibliographyItem],
24
27
  [schema_1.schema.nodes.bibliography_element, json_schema_1.ObjectTypes.BibliographyElement],
@@ -40,7 +43,7 @@ exports.nodeTypesMap = new Map([
40
43
  [schema_1.schema.nodes.inline_equation, json_schema_1.ObjectTypes.InlineMathFragment],
41
44
  [schema_1.schema.nodes.keyword, json_schema_1.ObjectTypes.Keyword],
42
45
  [schema_1.schema.nodes.keywords_element, json_schema_1.ObjectTypes.KeywordsElement],
43
- [schema_1.schema.nodes.keywords_section, json_schema_1.ObjectTypes.Section],
46
+ [schema_1.schema.nodes.keywords, json_schema_1.ObjectTypes.Section],
44
47
  [schema_1.schema.nodes.keywords_group, json_schema_1.ObjectTypes.KeywordGroup],
45
48
  [schema_1.schema.nodes.listing, json_schema_1.ObjectTypes.Listing],
46
49
  [schema_1.schema.nodes.listing_element, json_schema_1.ObjectTypes.ListingElement],
@@ -57,8 +60,8 @@ exports.nodeTypesMap = new Map([
57
60
  [schema_1.schema.nodes.affiliation, json_schema_1.ObjectTypes.Affiliation],
58
61
  [schema_1.schema.nodes.contributor, json_schema_1.ObjectTypes.Contributor],
59
62
  [schema_1.schema.nodes.table_element_footer, json_schema_1.ObjectTypes.TableElementFooter],
60
- [schema_1.schema.nodes.contributors_section, json_schema_1.ObjectTypes.Section],
61
- [schema_1.schema.nodes.affiliations_section, json_schema_1.ObjectTypes.Section],
63
+ [schema_1.schema.nodes.contributors, json_schema_1.ObjectTypes.Section],
64
+ [schema_1.schema.nodes.affiliations, json_schema_1.ObjectTypes.Section],
62
65
  ]);
63
66
  const isExecutableNodeType = (type) => (0, schema_1.hasGroup)(type, schema_1.GROUP_EXECUTABLE);
64
67
  exports.isExecutableNodeType = isExecutableNodeType;
@@ -15,14 +15,14 @@
15
15
  * limitations under the License.
16
16
  */
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.chooseSectionCategoryFromTitle = exports.chooseSectionCategory = exports.chooseSectionCategoryByType = exports.chooseSecType = exports.chooseJatsFnType = exports.buildSectionCategory = exports.guessSectionCategory = exports.chooseSectionLableName = exports.chooseSectionNodeType = exports.isAnySectionNode = exports.getCoreSectionTitles = void 0;
18
+ exports.chooseSectionCategoryFromTitle = exports.chooseSectionCategory = exports.chooseSectionCategoryByType = exports.chooseCoreSectionBySection = exports.chooseSecType = exports.chooseJatsFnType = exports.buildSectionCategory = exports.guessSectionCategory = exports.chooseSectionLableName = exports.chooseSectionNodeType = exports.isAnySectionNode = exports.getCoreSectionTitles = void 0;
19
19
  const json_schema_1 = require("@manuscripts/json-schema");
20
20
  const core_section_categories_1 = require("../lib/core-section-categories");
21
21
  const schema_1 = require("../schema");
22
22
  const sectionNodeTypes = [
23
23
  schema_1.schema.nodes.bibliography_section,
24
24
  schema_1.schema.nodes.footnotes_section,
25
- schema_1.schema.nodes.keywords_section,
25
+ schema_1.schema.nodes.keywords,
26
26
  schema_1.schema.nodes.section,
27
27
  schema_1.schema.nodes.toc_section,
28
28
  ];
@@ -45,11 +45,11 @@ const chooseSectionNodeType = (category) => {
45
45
  case 'MPSectionCategory:endnotes':
46
46
  return schema_1.schema.nodes.footnotes_section;
47
47
  case 'MPSectionCategory:keywords':
48
- return schema_1.schema.nodes.keywords_section;
48
+ return schema_1.schema.nodes.keywords;
49
49
  case 'MPSectionCategory:affiliations':
50
- return schema_1.schema.nodes.affiliations_section;
50
+ return schema_1.schema.nodes.affiliations;
51
51
  case 'MPSectionCategory:contributors':
52
- return schema_1.schema.nodes.contributors_section;
52
+ return schema_1.schema.nodes.contributors;
53
53
  case 'MPSectionCategory:toc':
54
54
  return schema_1.schema.nodes.toc_section;
55
55
  default:
@@ -90,15 +90,15 @@ const buildSectionCategory = (node) => {
90
90
  return 'MPSectionCategory:bibliography';
91
91
  case schema_1.schema.nodes.footnotes_section:
92
92
  return 'MPSectionCategory:endnotes';
93
- case schema_1.schema.nodes.keywords_section:
93
+ case schema_1.schema.nodes.keywords:
94
94
  return 'MPSectionCategory:keywords';
95
95
  case schema_1.schema.nodes.toc_section:
96
96
  return 'MPSectionCategory:toc';
97
97
  case schema_1.schema.nodes.graphical_abstract_section:
98
98
  return 'MPSectionCategory:abstract-graphical';
99
- case schema_1.schema.nodes.affiliations_section:
99
+ case schema_1.schema.nodes.affiliations:
100
100
  return 'MPSectionCategory:affiliations';
101
- case schema_1.schema.nodes.contributors_section:
101
+ case schema_1.schema.nodes.contributors:
102
102
  return 'MPSectionCategory:contributors';
103
103
  default:
104
104
  return node.attrs.category || undefined;
@@ -128,6 +128,33 @@ const chooseSecType = (sectionCategory) => {
128
128
  }
129
129
  };
130
130
  exports.chooseSecType = chooseSecType;
131
+ const chooseCoreSectionBySection = (section) => {
132
+ switch (section) {
133
+ case 'MPSectionCategory:abstract':
134
+ case 'MPSectionCategory:abstract-teaser':
135
+ case 'MPSectionCategory:abstract-graphical':
136
+ return 'MPSectionCategory:abstracts';
137
+ case 'MPSectionCategory:acknowledgement':
138
+ case 'MPSectionCategory:availability':
139
+ case 'MPSectionCategory:conclusions':
140
+ case 'MPSectionCategory:bibliography':
141
+ case 'MPSectionCategory:discussion':
142
+ case 'MPSectionCategory:endnotes':
143
+ case 'MPSectionCategory:appendices':
144
+ case 'MPSectionCategory:competing-interests':
145
+ case 'MPSectionCategory:con':
146
+ case 'MPSectionCategory:deceased':
147
+ case 'MPSectionCategory:ethics-statement':
148
+ case 'MPSectionCategory:financial-disclosure':
149
+ case 'MPSectionCategory:supplementary-material':
150
+ case 'MPSectionCategory:supported-by':
151
+ case 'MPSectionCategory:abbreviations':
152
+ case 'MPSectionCategory:results':
153
+ return 'MPSectionCategory:backmatter';
154
+ }
155
+ return 'MPSectionCategory:body';
156
+ };
157
+ exports.chooseCoreSectionBySection = chooseCoreSectionBySection;
131
158
  const chooseSectionCategoryByType = (secType) => {
132
159
  switch (secType) {
133
160
  case 'abstract':
@@ -501,7 +501,7 @@ const nodes = [
501
501
  },
502
502
  {
503
503
  tag: 'sec[sec-type="affiliations"]',
504
- node: 'affiliations_section',
504
+ node: 'affiliations',
505
505
  getAttrs: (node) => {
506
506
  const element = node;
507
507
  return {
@@ -513,7 +513,7 @@ const nodes = [
513
513
  {
514
514
  tag: 'aff',
515
515
  node: 'affiliation',
516
- context: 'affiliations_section/',
516
+ context: 'affiliations/',
517
517
  getAttrs: (node) => {
518
518
  const element = node;
519
519
  const aff = {
@@ -560,7 +560,7 @@ const nodes = [
560
560
  },
561
561
  {
562
562
  tag: 'sec[sec-type="contributors"]',
563
- node: 'contributors_section',
563
+ node: 'contributors',
564
564
  getAttrs: (node) => {
565
565
  const element = node;
566
566
  return {
@@ -572,7 +572,7 @@ const nodes = [
572
572
  {
573
573
  tag: 'contrib',
574
574
  node: 'contributor',
575
- context: 'contributors_section/',
575
+ context: 'contributors/',
576
576
  getAttrs: (node) => {
577
577
  const element = node;
578
578
  const contrib = {
@@ -627,7 +627,7 @@ const nodes = [
627
627
  },
628
628
  {
629
629
  tag: 'sec[sec-type="keywords"]',
630
- node: 'keywords_section',
630
+ node: 'keywords',
631
631
  getAttrs: (node) => {
632
632
  const element = node;
633
633
  return {
@@ -638,9 +638,21 @@ const nodes = [
638
638
  },
639
639
  {
640
640
  tag: 'kwd-group-list',
641
- context: 'keywords_section/',
641
+ context: 'keywords/',
642
642
  node: 'keywords_element',
643
643
  },
644
+ {
645
+ tag: 'sec[sec-type="abstracts"]',
646
+ node: 'abstracts',
647
+ },
648
+ {
649
+ tag: 'sec[sec-type="body"]',
650
+ node: 'body',
651
+ },
652
+ {
653
+ tag: 'sec[sec-type="backmatter"]',
654
+ node: 'backmatter',
655
+ },
644
656
  {
645
657
  tag: 'sec',
646
658
  node: 'section',
@@ -720,7 +732,7 @@ const nodes = [
720
732
  {
721
733
  tag: 'title',
722
734
  node: 'section_title',
723
- context: 'section/|footnotes_section/|bibliography_section/|keywords_section/',
735
+ context: 'section/|footnotes_section/|bibliography_section/|keywords/',
724
736
  },
725
737
  {
726
738
  tag: 'title',
@@ -423,9 +423,11 @@ export class JATSExporter {
423
423
  }
424
424
  };
425
425
  this.buildBody = (fragment) => {
426
- const content = this.serializeFragment(fragment);
427
426
  const body = this.document.createElement('body');
428
- body.appendChild(content);
427
+ fragment.forEach((cFragment) => {
428
+ const serializedNode = this.serializeNode(cFragment);
429
+ body.append(...serializedNode.childNodes);
430
+ });
429
431
  this.fixBody(body, fragment);
430
432
  return body;
431
433
  };
@@ -591,8 +593,8 @@ export class JATSExporter {
591
593
  this.createSerializer = () => {
592
594
  const getModel = (id) => id ? this.modelMap.get(id) : undefined;
593
595
  const nodes = {
594
- affiliations_section: () => '',
595
- contributors_section: () => '',
596
+ affiliations: () => '',
597
+ contributors: () => '',
596
598
  table_element_footer: () => ['table-wrap-foot', 0],
597
599
  contributor: () => '',
598
600
  affiliation: () => '',
@@ -602,6 +604,9 @@ export class JATSExporter {
602
604
  bibliography_item: () => '',
603
605
  comment_list: () => '',
604
606
  keywords_group: () => '',
607
+ body: () => ['body', 0],
608
+ abstracts: () => ['abstract', 0],
609
+ backmatter: () => ['backmatter', 0],
605
610
  bibliography_section: (node) => [
606
611
  'ref-list',
607
612
  { id: normalizeID(node.attrs.id) },
@@ -780,7 +785,7 @@ export class JATSExporter {
780
785
  },
781
786
  keyword: () => '',
782
787
  keywords_element: () => '',
783
- keywords_section: () => '',
788
+ keywords: () => '',
784
789
  link: (node) => {
785
790
  const text = node.textContent;
786
791
  if (!text) {
@@ -84,3 +84,11 @@ export const getTrimmedTextContent = (node, querySelector) => {
84
84
  }
85
85
  return (_b = (_a = node.querySelector(querySelector)) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim();
86
86
  };
87
+ export const groupBy = (list, getKey) => list.reduce((previous, currentItem) => {
88
+ const group = getKey(currentItem);
89
+ if (!previous[group]) {
90
+ previous[group] = [];
91
+ }
92
+ previous[group].push(currentItem);
93
+ return previous;
94
+ }, {});
@@ -29,6 +29,7 @@ import { comment } from './nodes/comment';
29
29
  import { commentList } from './nodes/comment_list';
30
30
  import { contributor } from './nodes/contributor';
31
31
  import { contributorsSection } from './nodes/contributors_section';
32
+ import { coreSection } from './nodes/core_section';
32
33
  import { crossReference } from './nodes/cross_reference';
33
34
  import { doc } from './nodes/doc';
34
35
  import { equation } from './nodes/equation';
@@ -151,6 +152,9 @@ export const schema = new Schema({
151
152
  caption,
152
153
  caption_title: captionTitle,
153
154
  citation,
155
+ abstracts: coreSection,
156
+ body: coreSection,
157
+ backmatter: coreSection,
154
158
  cross_reference: crossReference,
155
159
  doc,
156
160
  equation,
@@ -168,7 +172,7 @@ export const schema = new Schema({
168
172
  inline_footnote: inlineFootnote,
169
173
  keyword,
170
174
  keywords_element: keywordsElement,
171
- keywords_section: keywordsSection,
175
+ keywords: keywordsSection,
172
176
  keywords_group: keywordsGroup,
173
177
  link,
174
178
  list_item: listItem,
@@ -199,7 +203,7 @@ export const schema = new Schema({
199
203
  meta_section: metaSection,
200
204
  contributor: contributor,
201
205
  table_element_footer: tableElementFooter,
202
- affiliations_section: affiliationsSection,
203
- contributors_section: contributorsSection,
206
+ affiliations: affiliationsSection,
207
+ contributors: contributorsSection,
204
208
  },
205
209
  });
@@ -8,4 +8,4 @@ export const affiliationsSection = {
8
8
  selectable: false,
9
9
  toDOM: () => ['section', 0],
10
10
  };
11
- export const isAffiliationsSectionNode = (node) => node.type === node.type.schema.nodes.affiliations_section;
11
+ export const isAffiliationsSectionNode = (node) => node.type === node.type.schema.nodes.affiliations;
@@ -8,4 +8,4 @@ export const contributorsSection = {
8
8
  selectable: false,
9
9
  toDOM: () => ['section', 0],
10
10
  };
11
- export const isContributorsSectionNode = (node) => node.type === node.type.schema.nodes.contributors_section;
11
+ export const isContributorsSectionNode = (node) => node.type === node.type.schema.nodes.contributors;
@@ -0,0 +1,24 @@
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
+ export const coreSection = {
17
+ content: '(section | sections)*',
18
+ atom: true,
19
+ attrs: {
20
+ id: { default: '' },
21
+ },
22
+ group: 'block sections',
23
+ toDOM: () => ['section', 0],
24
+ };
@@ -18,7 +18,6 @@ export const graphicalAbstractSection = {
18
18
  attrs: {
19
19
  id: { default: '' },
20
20
  category: { default: '' },
21
- dataTracked: { default: null },
22
21
  },
23
22
  group: 'block sections',
24
23
  selectable: false,
@@ -40,4 +40,4 @@ export const keywordsSection = {
40
40
  ];
41
41
  },
42
42
  };
43
- export const isKeywordsSectionNode = (node) => node.type === node.type.schema.nodes.keywords_section;
43
+ export const isKeywordsSectionNode = (node) => node.type === node.type.schema.nodes.keywords;
@@ -14,7 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  export const manuscript = {
17
- content: '(section | sections)+ meta_section',
17
+ content: 'contributors? affiliations? keywords? abstracts body backmatter meta_section',
18
18
  attrs: {
19
19
  id: { default: '' },
20
20
  },
@@ -28,11 +28,12 @@ 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';
32
33
  import { insertHighlightMarkers } from './highlight-markers';
33
34
  import { generateNodeID } from './id';
34
35
  import { ExtraObjectTypes, hasObjectType, isCommentAnnotation, isManuscript, } from './object-types';
35
- import { chooseSectionLableName, chooseSectionNodeType, chooseSecType, guessSectionCategory, } from './section-category';
36
+ import { chooseCoreSectionBySection, chooseSectionLableName, chooseSectionNodeType, chooseSecType, guessSectionCategory, } from './section-category';
36
37
  import { timestamp } from './timestamp';
37
38
  const warn = debug('manuscripts-transform');
38
39
  const parser = DOMParser.fromSchema(schema);
@@ -53,6 +54,7 @@ export const sortSectionsByPriority = (a, b) => a.priority === b.priority ? 0 :
53
54
  const getSections = (modelMap) => getModelsByType(modelMap, ObjectTypes.Section).sort(sortSectionsByPriority);
54
55
  const getAffiliations = (modelMap) => getModelsByType(modelMap, ObjectTypes.Affiliation);
55
56
  const getContributors = (modelMap) => getModelsByType(modelMap, ObjectTypes.Contributor);
57
+ const getKeywordElements = (modelMap) => getModelsByType(modelMap, ObjectTypes.KeywordsElement);
56
58
  export const isManuscriptNode = (model) => model !== null;
57
59
  const isParagraphElement = hasObjectType(ObjectTypes.ParagraphElement);
58
60
  const isFootnote = hasObjectType(ObjectTypes.Footnote);
@@ -76,10 +78,13 @@ export class Decoder {
76
78
  ]);
77
79
  }
78
80
  handleMissingRootSectionNodes(rootSectionNodes) {
79
- if (!rootSectionNodes.find((node) => node.type.name === 'affiliations_section')) {
81
+ if (!rootSectionNodes.find((node) => node.type.name === 'keywords')) {
82
+ this.createKeywordsSectionNode(rootSectionNodes);
83
+ }
84
+ if (!rootSectionNodes.find((node) => node.type.name === 'affiliations')) {
80
85
  this.createAffiliationSectionNode(rootSectionNodes);
81
86
  }
82
- if (!rootSectionNodes.find((node) => node.type.name === 'contributors_section')) {
87
+ if (!rootSectionNodes.find((node) => node.type.name === 'contributors')) {
83
88
  this.createContributorSectionNode(rootSectionNodes);
84
89
  }
85
90
  }
@@ -87,37 +92,79 @@ export class Decoder {
87
92
  const affiliationNodes = getAffiliations(this.modelMap)
88
93
  .map((affiliation) => this.decode(affiliation))
89
94
  .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
- }
95
+ const node = schema.nodes.affiliations.createAndFill({
96
+ id: generateNodeID(schema.nodes.section),
97
+ }, affiliationNodes);
98
+ rootSectionNodes.unshift(node);
96
99
  }
97
100
  createContributorSectionNode(rootSectionNodes) {
98
101
  const contributorNodes = getContributors(this.modelMap)
99
102
  .map((contributor) => this.decode(contributor))
100
103
  .filter(Boolean);
101
- if (contributorNodes.length) {
102
- const node = schema.nodes.contributors_section.createAndFill({
104
+ const node = schema.nodes.contributors.createAndFill({
105
+ id: generateNodeID(schema.nodes.section),
106
+ }, contributorNodes);
107
+ rootSectionNodes.unshift(node);
108
+ }
109
+ createKeywordsSectionNode(rootSectionNodes) {
110
+ const keywordElementNodes = getKeywordElements(this.modelMap)
111
+ .map((keywordEl) => this.decode(keywordEl))
112
+ .filter(Boolean);
113
+ if (keywordElementNodes) {
114
+ const node = schema.nodes.keywords.createAndFill({
103
115
  id: generateNodeID(schema.nodes.section),
104
- }, contributorNodes);
116
+ }, [
117
+ schema.nodes.section_title.create({}, schema.text('Keywords')),
118
+ ...keywordElementNodes,
119
+ ]);
105
120
  rootSectionNodes.unshift(node);
106
121
  }
107
122
  }
108
123
  createRootSectionNodes() {
109
- let rootSections = getSections(this.modelMap).filter((section) => !section.path || section.path.length <= 1);
124
+ let rootSections = getSections(this.modelMap)
125
+ .filter((section) => !section.path || section.path.length <= 1)
126
+ .filter((section) => section.category !== 'MPSectionCategory:contributors' &&
127
+ section.category !== 'MPSectionCategory:affiliations' &&
128
+ section.category !== 'MPSectionCategory:keywords');
110
129
  rootSections = this.addGeneratedLabels(rootSections);
111
- const rootSectionNodes = rootSections
130
+ const sectionGroups = groupBy(rootSections, (sec) => {
131
+ var _a;
132
+ return chooseCoreSectionBySection((_a = sec.category) !== null && _a !== void 0 ? _a : '');
133
+ });
134
+ this.ensureCoreSectionsExist(sectionGroups);
135
+ const absSectionNode = sectionGroups['MPSectionCategory:abstracts']
112
136
  .map(this.decode)
113
137
  .filter(isManuscriptNode);
114
- this.handleMissingRootSectionNodes(rootSectionNodes);
115
- if (!rootSectionNodes.length) {
116
- rootSectionNodes.push(schema.nodes.section.createAndFill({
117
- id: generateNodeID(schema.nodes.section),
118
- }));
138
+ const bodySectionNodes = sectionGroups['MPSectionCategory:body']
139
+ .map(this.decode)
140
+ .filter(isManuscriptNode);
141
+ const backmatterSectionNodes = sectionGroups['MPSectionCategory:backmatter']
142
+ .map(this.decode)
143
+ .filter(isManuscriptNode);
144
+ const abstractCoreSectionNodes = this.createAndFill(schema.nodes.abstracts, absSectionNode);
145
+ const bodyCoreSectionNodes = this.createAndFill(schema.nodes.body, bodySectionNodes);
146
+ const backmatterCoreSectionNodes = this.createAndFill(schema.nodes.backmatter, backmatterSectionNodes);
147
+ return [
148
+ abstractCoreSectionNodes,
149
+ bodyCoreSectionNodes,
150
+ backmatterCoreSectionNodes,
151
+ ];
152
+ }
153
+ ensureCoreSectionsExist(coreSections) {
154
+ if (!coreSections['MPSectionCategory:abstracts']) {
155
+ coreSections['MPSectionCategory:abstracts'] = [];
119
156
  }
120
- return rootSectionNodes;
157
+ if (!coreSections['MPSectionCategory:body']) {
158
+ coreSections['MPSectionCategory:body'] = [];
159
+ }
160
+ if (!coreSections['MPSectionCategory:backmatter']) {
161
+ coreSections['MPSectionCategory:backmatter'] = [];
162
+ }
163
+ }
164
+ createAndFill(nodeType, content) {
165
+ return nodeType.createAndFill({
166
+ id: generateNodeID(nodeType),
167
+ }, content);
121
168
  }
122
169
  createCommentsNode(model) {
123
170
  const comments = [];
@@ -622,6 +669,7 @@ export class Decoder {
622
669
  this.getModel = (id) => this.modelMap.get(id);
623
670
  this.createArticleNode = (manuscriptID) => {
624
671
  const rootSectionNodes = this.createRootSectionNodes();
672
+ this.handleMissingRootSectionNodes(rootSectionNodes);
625
673
  const metaSectionNode = this.createMetaSectionNode();
626
674
  const contents = [...rootSectionNodes, metaSectionNode];
627
675
  return schema.nodes.manuscript.create({
@@ -417,31 +417,6 @@ const encoders = {
417
417
  keywords_group: (node) => ({
418
418
  type: node.attrs.type,
419
419
  }),
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
420
  missing_figure: (node) => ({
446
421
  position: node.attrs.position || undefined,
447
422
  }),
@@ -561,6 +536,14 @@ export const modelFromNode = (node, parent, path, priority) => {
561
536
  }
562
537
  return { model, commentAnnotationsMap };
563
538
  };
539
+ function isCoreSection(child) {
540
+ return (child.type === schema.nodes.abstracts ||
541
+ child.type === schema.nodes.body ||
542
+ child.type === schema.nodes.backmatter ||
543
+ child.type === schema.nodes.affiliations ||
544
+ child.type === schema.nodes.contributors ||
545
+ child.type === schema.nodes.keywords);
546
+ }
564
547
  export const encode = (node) => {
565
548
  const models = new Map();
566
549
  const priority = {
@@ -568,6 +551,10 @@ export const encode = (node) => {
568
551
  };
569
552
  const placeholders = ['placeholder', 'placeholder_element'];
570
553
  const addModel = (path, parent) => (child) => {
554
+ if (isCoreSection(child)) {
555
+ child.forEach(addModel([], child));
556
+ return;
557
+ }
571
558
  if (!child.attrs.id) {
572
559
  return;
573
560
  }
@@ -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.keywords_section, 'Section'],
38
+ [schema.nodes.keywords, 'Section'],
39
39
  [schema.nodes.toc_section, 'Section'],
40
40
  ]);
@@ -45,7 +45,7 @@ export const nodeTitle = (node) => {
45
45
  case nodes.section:
46
46
  case nodes.bibliography_section:
47
47
  case nodes.footnotes_section:
48
- case nodes.keywords_section:
48
+ case nodes.keywords:
49
49
  case nodes.toc_section:
50
50
  case nodes.graphical_abstract_section:
51
51
  return snippetOfNodeType(node, nodes.section_title);
@@ -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,7 +40,7 @@ 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.keywords_section, ObjectTypes.Section],
43
+ [schema.nodes.keywords, ObjectTypes.Section],
41
44
  [schema.nodes.keywords_group, ObjectTypes.KeywordGroup],
42
45
  [schema.nodes.listing, ObjectTypes.Listing],
43
46
  [schema.nodes.listing_element, ObjectTypes.ListingElement],
@@ -54,8 +57,8 @@ 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.contributors_section, ObjectTypes.Section],
58
- [schema.nodes.affiliations_section, ObjectTypes.Section],
60
+ [schema.nodes.contributors, ObjectTypes.Section],
61
+ [schema.nodes.affiliations, ObjectTypes.Section],
59
62
  ]);
60
63
  export const isExecutableNodeType = (type) => hasGroup(type, GROUP_EXECUTABLE);
61
64
  export const isElementNodeType = (type) => hasGroup(type, GROUP_ELEMENT);
@@ -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.keywords_section,
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.keywords_section;
43
+ return schema.nodes.keywords;
44
44
  case 'MPSectionCategory:affiliations':
45
- return schema.nodes.affiliations_section;
45
+ return schema.nodes.affiliations;
46
46
  case 'MPSectionCategory:contributors':
47
- return schema.nodes.contributors_section;
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.keywords_section:
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.affiliations_section:
91
+ case schema.nodes.affiliations:
92
92
  return 'MPSectionCategory:affiliations';
93
- case schema.nodes.contributors_section:
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[]>;
@@ -0,0 +1,25 @@
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
+ import { NodeSpec } from 'prosemirror-model';
17
+ import { ManuscriptNode } from '../types';
18
+ interface Attrs {
19
+ id: string;
20
+ }
21
+ export interface CoreSection extends ManuscriptNode {
22
+ attrs: Attrs;
23
+ }
24
+ export declare const coreSection: NodeSpec;
25
+ export {};
@@ -17,7 +17,7 @@ import { Fragment, Mark as ProsemirrorMark, MarkType, Node as ProsemirrorNode, N
17
17
  import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from 'prosemirror-state';
18
18
  import { EditorView, NodeView } from 'prosemirror-view';
19
19
  export type Marks = 'bold' | 'code' | 'italic' | 'smallcaps' | 'strikethrough' | 'styled' | 'subscript' | 'superscript' | 'underline' | 'tracked_insert' | 'tracked_delete';
20
- export type Nodes = 'attribution' | 'bibliography_item' | 'bibliography_element' | 'bibliography_section' | 'blockquote_element' | 'bullet_list' | 'caption' | 'caption_title' | 'comment' | 'comment_list' | 'citation' | 'cross_reference' | 'doc' | 'equation' | 'equation_element' | 'figcaption' | 'figure' | 'graphical_abstract_section' | 'figure_element' | 'footnote' | 'footnotes_element' | 'footnotes_section' | 'hard_break' | 'highlight_marker' | 'inline_equation' | 'inline_footnote' | 'keyword' | 'keywords_element' | 'keywords_group' | 'keywords_section' | 'link' | 'list_item' | 'listing' | 'listing_element' | 'manuscript' | 'missing_figure' | 'ordered_list' | 'paragraph' | 'placeholder' | 'placeholder_element' | 'pullquote_element' | 'section' | 'section_label' | 'section_title' | 'section_title_plain' | 'table' | 'table_body' | 'table_cell' | 'table_element' | 'table_row' | 'table_colgroup' | 'table_col' | 'text' | 'toc_element' | 'toc_section' | 'affiliation' | 'meta_section' | 'contributor' | 'table_element_footer' | 'affiliations_section' | 'contributors_section';
20
+ export type Nodes = 'attribution' | 'bibliography_item' | 'bibliography_element' | 'bibliography_section' | 'blockquote_element' | 'bullet_list' | 'caption' | 'caption_title' | 'comment' | 'comment_list' | 'citation' | 'cross_reference' | 'doc' | 'equation' | 'equation_element' | 'figcaption' | 'figure' | 'graphical_abstract_section' | 'figure_element' | 'footnote' | 'footnotes_element' | 'footnotes_section' | 'hard_break' | 'highlight_marker' | 'inline_equation' | 'inline_footnote' | 'keyword' | 'keywords_element' | 'keywords_group' | 'keywords' | 'link' | 'list_item' | 'listing' | 'listing_element' | 'manuscript' | 'abstracts' | 'body' | 'backmatter' | 'missing_figure' | 'ordered_list' | 'paragraph' | 'placeholder' | 'placeholder_element' | 'pullquote_element' | 'section' | 'section_label' | 'section_title' | 'section_title_plain' | 'table' | 'table_body' | 'table_cell' | 'table_element' | 'table_row' | 'table_colgroup' | 'table_col' | 'text' | 'toc_element' | 'toc_section' | 'affiliation' | 'meta_section' | 'contributor' | 'table_element_footer' | 'affiliations' | 'contributors';
21
21
  export type ManuscriptSchema = Schema<Nodes, Marks>;
22
22
  export type ManuscriptEditorState = EditorState;
23
23
  export type ManuscriptEditorView = EditorView;
@@ -30,7 +30,10 @@ export declare class Decoder {
30
30
  private handleMissingRootSectionNodes;
31
31
  private createAffiliationSectionNode;
32
32
  private createContributorSectionNode;
33
+ private createKeywordsSectionNode;
33
34
  private createRootSectionNodes;
35
+ private ensureCoreSectionsExist;
36
+ private createAndFill;
34
37
  private createCommentsNode;
35
38
  private getComments;
36
39
  private extractListing;
@@ -25,6 +25,7 @@ export declare const guessSectionCategory: (elements: Element[]) => SectionCateg
25
25
  export declare const buildSectionCategory: (node: ManuscriptNode) => SectionCategory | undefined;
26
26
  export declare const chooseJatsFnType: (footnoteType: string) => string;
27
27
  export declare const chooseSecType: (sectionCategory: SectionCategory) => SecType;
28
+ export declare const chooseCoreSectionBySection: (section: string) => string;
28
29
  export declare const chooseSectionCategoryByType: (secType: string) => SectionCategory | undefined;
29
30
  export declare const chooseSectionCategory: (section: HTMLElement) => SectionCategory | undefined;
30
31
  export declare const chooseSectionCategoryFromTitle: (title: string | null) => SectionCategory | undefined;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@manuscripts/transform",
3
3
  "description": "ProseMirror transformer for Manuscripts applications",
4
- "version": "1.5.2-LEAN-3047",
4
+ "version": "1.5.2-LEAN-3032",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-transform",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",
@@ -82,4 +82,4 @@
82
82
  "prosemirror-state": "^1.4.2",
83
83
  "prosemirror-view": "^1.29.1"
84
84
  }
85
- }
85
+ }