@manuscripts/transform 1.5.7 → 1.5.8-LEAN-3030-1

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 (133) hide show
  1. package/dist/cjs/index.js +1 -1
  2. package/dist/cjs/jats/importer/index.js +1 -3
  3. package/dist/cjs/jats/importer/jats-body-dom-parser.js +23 -227
  4. package/dist/cjs/jats/importer/jats-body-transformations.js +110 -201
  5. package/dist/cjs/jats/importer/jats-comments.js +100 -98
  6. package/dist/cjs/jats/importer/jats-front-parser.js +87 -81
  7. package/dist/cjs/jats/importer/jats-journal-meta-parser.js +51 -39
  8. package/dist/cjs/jats/importer/jats-parser-utils.js +17 -56
  9. package/dist/cjs/jats/importer/jats-reference-parser.js +24 -79
  10. package/dist/cjs/jats/importer/jats-references.js +34 -0
  11. package/dist/cjs/jats/importer/parse-jats-article.js +67 -173
  12. package/dist/cjs/jats/index.js +1 -3
  13. package/dist/cjs/jats/jats-exporter.js +33 -54
  14. package/dist/cjs/lib/section-group-type.js +30 -0
  15. package/dist/cjs/lib/utils.js +14 -12
  16. package/dist/cjs/schema/index.js +20 -17
  17. package/dist/cjs/schema/nodes/abstracts.js +27 -0
  18. package/dist/cjs/schema/nodes/affiliations.js +27 -0
  19. package/dist/cjs/schema/nodes/backmatter.js +27 -0
  20. package/dist/cjs/schema/nodes/body.js +27 -0
  21. package/dist/cjs/schema/nodes/citation.js +10 -15
  22. package/dist/cjs/schema/nodes/{comment_list.js → comments.js} +4 -4
  23. package/dist/cjs/schema/nodes/contributors.js +27 -0
  24. package/dist/cjs/schema/nodes/{meta_section.js → core_section.js} +6 -5
  25. package/dist/cjs/schema/nodes/cross_reference.js +4 -3
  26. package/dist/cjs/schema/nodes/inline_footnote.js +6 -5
  27. package/dist/cjs/schema/nodes/keyword.js +0 -1
  28. package/dist/cjs/schema/nodes/{keywords_group.js → keyword_group.js} +6 -6
  29. package/dist/cjs/schema/nodes/{keywords_section.js → keywords.js} +7 -7
  30. package/dist/cjs/schema/nodes/keywords_element.js +1 -1
  31. package/dist/cjs/schema/nodes/manuscript.js +5 -2
  32. package/dist/cjs/transformer/builders.js +9 -86
  33. package/dist/cjs/transformer/decode.js +129 -165
  34. package/dist/cjs/transformer/encode.js +54 -45
  35. package/dist/cjs/transformer/highlight-markers.js +4 -4
  36. package/dist/cjs/transformer/html.js +5 -20
  37. package/dist/cjs/transformer/labels.js +3 -17
  38. package/dist/cjs/transformer/node-names.js +1 -1
  39. package/dist/cjs/transformer/node-title.js +1 -1
  40. package/dist/cjs/transformer/node-types.js +7 -6
  41. package/dist/cjs/transformer/object-types.js +1 -2
  42. package/dist/cjs/transformer/section-category.js +31 -31
  43. package/dist/es/index.js +1 -1
  44. package/dist/es/jats/importer/index.js +1 -1
  45. package/dist/es/jats/importer/jats-body-dom-parser.js +23 -227
  46. package/dist/es/jats/importer/jats-body-transformations.js +111 -202
  47. package/dist/es/jats/importer/jats-comments.js +97 -96
  48. package/dist/es/jats/importer/jats-front-parser.js +88 -82
  49. package/dist/es/jats/importer/jats-journal-meta-parser.js +51 -39
  50. package/dist/es/jats/importer/jats-parser-utils.js +16 -54
  51. package/dist/es/jats/importer/jats-reference-parser.js +27 -82
  52. package/dist/es/jats/importer/jats-references.js +30 -0
  53. package/dist/es/jats/importer/parse-jats-article.js +70 -174
  54. package/dist/es/jats/index.js +1 -1
  55. package/dist/es/jats/jats-exporter.js +33 -54
  56. package/dist/es/lib/section-group-type.js +27 -0
  57. package/dist/es/lib/utils.js +12 -10
  58. package/dist/es/schema/index.js +21 -18
  59. package/dist/es/schema/nodes/abstracts.js +24 -0
  60. package/dist/es/schema/nodes/affiliations.js +24 -0
  61. package/dist/es/schema/nodes/backmatter.js +24 -0
  62. package/dist/es/schema/nodes/body.js +24 -0
  63. package/dist/es/schema/nodes/citation.js +10 -15
  64. package/dist/es/schema/nodes/{comment_list.js → comments.js} +3 -3
  65. package/dist/es/schema/nodes/contributors.js +24 -0
  66. package/dist/es/schema/nodes/{meta_section.js → core_section.js} +5 -4
  67. package/dist/es/schema/nodes/cross_reference.js +4 -3
  68. package/dist/es/schema/nodes/inline_footnote.js +6 -5
  69. package/dist/es/schema/nodes/keyword.js +0 -1
  70. package/dist/es/schema/nodes/{keywords_group.js → keyword_group.js} +4 -4
  71. package/dist/es/schema/nodes/{keywords_section.js → keywords.js} +5 -5
  72. package/dist/es/schema/nodes/keywords_element.js +1 -1
  73. package/dist/es/schema/nodes/manuscript.js +3 -1
  74. package/dist/es/transformer/builders.js +6 -73
  75. package/dist/es/transformer/decode.js +129 -164
  76. package/dist/es/transformer/encode.js +57 -48
  77. package/dist/es/transformer/highlight-markers.js +1 -1
  78. package/dist/es/transformer/html.js +5 -20
  79. package/dist/es/transformer/labels.js +3 -17
  80. package/dist/es/transformer/node-names.js +1 -1
  81. package/dist/es/transformer/node-title.js +1 -1
  82. package/dist/es/transformer/node-types.js +7 -6
  83. package/dist/es/transformer/object-types.js +0 -1
  84. package/dist/es/transformer/section-category.js +29 -29
  85. package/dist/types/index.d.ts +1 -1
  86. package/dist/types/jats/importer/index.d.ts +1 -1
  87. package/dist/types/jats/importer/jats-body-transformations.d.ts +16 -19
  88. package/dist/types/jats/importer/jats-comments.d.ts +13 -9
  89. package/dist/types/jats/importer/jats-front-parser.d.ts +35 -12
  90. package/dist/types/jats/importer/jats-journal-meta-parser.d.ts +4 -4
  91. package/dist/types/jats/importer/jats-parser-utils.d.ts +1 -6
  92. package/dist/types/jats/importer/jats-reference-parser.d.ts +2 -6
  93. package/dist/types/jats/importer/jats-references.d.ts +12 -0
  94. package/dist/types/jats/importer/parse-jats-article.d.ts +5 -17
  95. package/dist/types/jats/index.d.ts +1 -1
  96. package/dist/types/lib/section-group-type.d.ts +23 -0
  97. package/dist/types/lib/utils.d.ts +3 -2
  98. package/dist/types/schema/index.d.ts +4 -5
  99. package/dist/types/schema/nodes/{meta_section.d.ts → abstracts.d.ts} +1 -9
  100. package/dist/types/schema/nodes/affiliations.d.ts +17 -0
  101. package/dist/types/schema/nodes/backmatter.d.ts +17 -0
  102. package/dist/types/schema/nodes/body.d.ts +17 -0
  103. package/dist/types/schema/nodes/citation.d.ts +3 -5
  104. package/dist/types/schema/nodes/comments.d.ts +17 -0
  105. package/dist/types/schema/nodes/contributors.d.ts +17 -0
  106. package/dist/types/schema/nodes/core_section.d.ts +17 -0
  107. package/dist/types/schema/nodes/cross_reference.d.ts +1 -1
  108. package/dist/types/schema/nodes/inline_footnote.d.ts +1 -1
  109. package/dist/types/schema/nodes/keyword.d.ts +0 -1
  110. package/dist/types/schema/nodes/{contributors_element.d.ts → keyword_group.d.ts} +3 -4
  111. package/dist/types/schema/nodes/{comment_list.d.ts → keywords.d.ts} +3 -2
  112. package/dist/types/schema/nodes/manuscript.d.ts +1 -0
  113. package/dist/types/schema/types.d.ts +1 -1
  114. package/dist/types/transformer/builders.d.ts +2 -14
  115. package/dist/types/transformer/decode.d.ts +5 -9
  116. package/dist/types/transformer/encode.d.ts +1 -1
  117. package/dist/types/transformer/highlight-markers.d.ts +1 -0
  118. package/dist/types/transformer/object-types.d.ts +1 -2
  119. package/dist/types/transformer/section-category.d.ts +4 -3
  120. package/package.json +1 -1
  121. package/dist/cjs/lib/core-section-categories.js +0 -29
  122. package/dist/cjs/schema/nodes/affiliations_section.js +0 -36
  123. package/dist/cjs/schema/nodes/contributors_element.js +0 -49
  124. package/dist/cjs/schema/nodes/contributors_section.js +0 -36
  125. package/dist/es/lib/core-section-categories.js +0 -26
  126. package/dist/es/schema/nodes/affiliations_section.js +0 -32
  127. package/dist/es/schema/nodes/contributors_element.js +0 -46
  128. package/dist/es/schema/nodes/contributors_section.js +0 -32
  129. package/dist/types/lib/core-section-categories.d.ts +0 -8
  130. package/dist/types/schema/nodes/affiliations_section.d.ts +0 -11
  131. package/dist/types/schema/nodes/contributors_section.d.ts +0 -12
  132. package/dist/types/schema/nodes/keywords_group.d.ts +0 -26
  133. package/dist/types/schema/nodes/keywords_section.d.ts +0 -26
@@ -28,12 +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 { abstractsType, backmatterType, bodyType, } from '../lib/section-group-type';
31
32
  import { schema, } from '../schema';
32
33
  import { buildTitles } from './builders';
33
34
  import { insertHighlightMarkers } from './highlight-markers';
34
- import { generateNodeID } from './id';
35
35
  import { ExtraObjectTypes, hasObjectType, isCommentAnnotation, isManuscript, } from './object-types';
36
- import { chooseSectionLableName, chooseSectionNodeType, chooseSecType, guessSectionCategory, } from './section-category';
36
+ import { chooseSectionLableName, chooseSectionNodeType, chooseSecType, getSectionGroupType, guessSectionCategory, } from './section-category';
37
37
  import { timestamp } from './timestamp';
38
38
  const warn = debug('manuscripts-transform');
39
39
  const parser = DOMParser.fromSchema(schema);
@@ -54,78 +54,70 @@ export const sortSectionsByPriority = (a, b) => a.priority === b.priority ? 0 :
54
54
  const getSections = (modelMap) => getModelsByType(modelMap, ObjectTypes.Section).sort(sortSectionsByPriority);
55
55
  const getAffiliations = (modelMap) => getModelsByType(modelMap, ObjectTypes.Affiliation);
56
56
  const getContributors = (modelMap) => getModelsByType(modelMap, ObjectTypes.Contributor);
57
- export const isManuscriptNode = (model) => model !== null;
58
- const isParagraphElement = hasObjectType(ObjectTypes.ParagraphElement);
57
+ const getKeywordElements = (modelMap) => getModelsByType(modelMap, ObjectTypes.KeywordsElement);
58
+ const getKeywordGroups = (modelMap) => getModelsByType(modelMap, ObjectTypes.KeywordGroup);
59
+ const getKeywords = (modelMap) => getModelsByType(modelMap, ObjectTypes.Keyword);
60
+ const getTitles = (modelMap) => getModelsByType(modelMap, ObjectTypes.Titles)[0];
59
61
  const isFootnote = hasObjectType(ObjectTypes.Footnote);
60
- const isKeyword = hasObjectType(ObjectTypes.Keyword);
61
- const isKeywordsSection = (model) => model.category === 'MPSectionCategory:keywords';
62
- const isAffiliationsSection = (model) => model.category === 'MPSectionCategory:affiliations';
63
- const isContributorsSection = (model) => model.category === 'MPSectionCategory:contributors';
64
62
  const hasParentSection = (id) => (section) => section.path &&
65
63
  section.path.length > 1 &&
66
64
  section.path[section.path.length - 2] === id;
67
65
  export class Decoder {
68
- createMetaSectionNode() {
69
- const commentListNode = this.createCommentListNode();
70
- return schema.nodes.meta_section.createAndFill({}, [
71
- commentListNode,
72
- ]);
73
- }
74
- createCommentListNode() {
75
- return schema.nodes.comment_list.createAndFill({}, [
76
- ...this.comments.values(),
77
- ]);
66
+ createTitleNode() {
67
+ const titles = getTitles(this.modelMap) || buildTitles();
68
+ return this.decode(titles);
78
69
  }
79
- handleMissingRootSectionNodes(rootSectionNodes) {
80
- if (!rootSectionNodes.find((node) => node.type.name === 'affiliations_section')) {
81
- this.createAffiliationSectionNode(rootSectionNodes);
82
- }
83
- if (!rootSectionNodes.find((node) => node.type.name === 'contributors_section')) {
84
- this.createContributorSectionNode(rootSectionNodes);
85
- }
70
+ createAffiliationsNode() {
71
+ const affiliations = getAffiliations(this.modelMap)
72
+ .map((a) => this.decode(a))
73
+ .filter(Boolean);
74
+ return schema.nodes.affiliations.createAndFill({}, affiliations);
86
75
  }
87
- createAffiliationSectionNode(rootSectionNodes) {
88
- const affiliationNodes = getAffiliations(this.modelMap)
89
- .map((affiliation) => this.decode(affiliation))
76
+ createContributorsNode() {
77
+ const contributors = getContributors(this.modelMap)
78
+ .map((c) => this.decode(c))
90
79
  .filter(Boolean);
91
- if (affiliationNodes.length) {
92
- const node = schema.nodes.affiliations_section.createAndFill({
93
- id: generateNodeID(schema.nodes.section),
94
- }, affiliationNodes);
95
- rootSectionNodes.unshift(node);
96
- }
80
+ return schema.nodes.contributors.createAndFill({}, contributors);
97
81
  }
98
- createContributorSectionNode(rootSectionNodes) {
99
- const contributorNodes = getContributors(this.modelMap)
100
- .map((contributor) => this.decode(contributor))
82
+ createKeywordsNode() {
83
+ const elements = getKeywordElements(this.modelMap)
84
+ .map((e) => this.decode(e))
101
85
  .filter(Boolean);
102
- if (contributorNodes.length) {
103
- const node = schema.nodes.contributors_section.createAndFill({
104
- id: generateNodeID(schema.nodes.section),
105
- }, contributorNodes);
106
- rootSectionNodes.unshift(node);
107
- }
86
+ return schema.nodes.keywords.createAndFill({}, [
87
+ schema.nodes.section_title.create({}, schema.text('Keywords')),
88
+ ...elements,
89
+ ]);
108
90
  }
109
- createTitleNode() {
110
- const titles = getModelsByType(this.modelMap, ObjectTypes.Titles)[0] ||
111
- buildTitles();
112
- return this.decode(titles);
91
+ createCommentsNode() {
92
+ return schema.nodes.comments.createAndFill({}, [
93
+ ...this.comments.values(),
94
+ ]);
113
95
  }
114
- createRootSectionNodes() {
115
- let rootSections = getSections(this.modelMap).filter((section) => !section.path || section.path.length <= 1);
116
- rootSections = this.addGeneratedLabels(rootSections);
117
- const rootSectionNodes = rootSections
118
- .map(this.decode)
119
- .filter(isManuscriptNode);
120
- this.handleMissingRootSectionNodes(rootSectionNodes);
121
- if (!rootSectionNodes.length) {
122
- rootSectionNodes.push(schema.nodes.section.createAndFill({
123
- id: generateNodeID(schema.nodes.section),
124
- }));
96
+ createContentSections() {
97
+ let sections = getSections(this.modelMap);
98
+ sections = this.addGeneratedLabels(sections);
99
+ const groups = {
100
+ abstracts: [],
101
+ body: [],
102
+ backmatter: [],
103
+ };
104
+ for (const section of sections) {
105
+ const category = section.category;
106
+ const group = category
107
+ ? getSectionGroupType(category)
108
+ : bodyType;
109
+ groups[group._id].push(this.decode(section));
125
110
  }
126
- return rootSectionNodes;
111
+ const abstracts = schema.nodes.abstracts.createAndFill({}, groups[abstractsType._id]);
112
+ const body = schema.nodes.body.createAndFill({}, groups[bodyType._id]);
113
+ const backmatter = schema.nodes.backmatter.createAndFill({}, groups[backmatterType._id]);
114
+ return {
115
+ abstracts,
116
+ body,
117
+ backmatter,
118
+ };
127
119
  }
128
- createCommentsNode(model) {
120
+ createCommentNodes(model) {
129
121
  const comments = [];
130
122
  for (const comment of this.getComments(model)) {
131
123
  comments.push(this.decode(comment));
@@ -170,8 +162,8 @@ export class Decoder {
170
162
  },
171
163
  [ObjectTypes.BibliographyItem]: (data) => {
172
164
  const model = data;
173
- const commentNodes = this.createCommentsNode(model);
174
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
165
+ const comments = this.createCommentNodes(model);
166
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
175
167
  return schema.nodes.bibliography_item.create({
176
168
  id: model._id,
177
169
  type: model.type,
@@ -185,7 +177,7 @@ export class Decoder {
185
177
  page: model.page,
186
178
  title: model.title,
187
179
  literal: model.literal,
188
- comments: commentNodes.map((c) => c.attrs.id),
180
+ comments: comments.map((c) => c.attrs.id),
189
181
  });
190
182
  },
191
183
  [ExtraObjectTypes.PlaceholderElement]: (data) => {
@@ -196,14 +188,14 @@ export class Decoder {
196
188
  },
197
189
  [ObjectTypes.Figure]: (data) => {
198
190
  const model = data;
199
- const commentNodes = this.createCommentsNode(model);
200
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
191
+ const comments = this.createCommentNodes(model);
192
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
201
193
  return schema.nodes.figure.create({
202
194
  id: model._id,
203
195
  contentType: model.contentType,
204
196
  src: model.src,
205
197
  position: model.position,
206
- comments: commentNodes.map((c) => c.attrs.id),
198
+ comments: comments.map((c) => c.attrs.id),
207
199
  });
208
200
  },
209
201
  [ObjectTypes.FigureElement]: (data) => {
@@ -232,8 +224,8 @@ export class Decoder {
232
224
  figures.push(schema.nodes.figure.createAndFill());
233
225
  }
234
226
  const figcaption = this.getFigcaption(model);
235
- const commentNodes = this.createCommentsNode(model);
236
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
227
+ const comments = this.createCommentNodes(model);
228
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
237
229
  const content = [...paragraphs, ...figures, figcaption];
238
230
  const listing = this.extractListing(model);
239
231
  if (listing) {
@@ -254,7 +246,7 @@ export class Decoder {
254
246
  suppressTitle: Boolean(model.suppressTitle === undefined ? true : model.suppressTitle),
255
247
  attribution: model.attribution,
256
248
  alternatives: model.alternatives,
257
- comments: commentNodes.map((c) => c.attrs.id),
249
+ comments: comments.map((c) => c.attrs.id),
258
250
  }, content);
259
251
  },
260
252
  [ObjectTypes.Equation]: (data) => {
@@ -297,13 +289,13 @@ export class Decoder {
297
289
  if (isFootnote(model) &&
298
290
  model.kind === collateByKind &&
299
291
  model.containingObject === foonotesElementModel._id) {
300
- const commentNodes = this.createCommentsNode(model);
301
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
292
+ const comments = this.createCommentNodes(model);
293
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
302
294
  const footnote = this.parseContents(model.contents || '<div></div>', undefined, this.getComments(model), {
303
295
  topNode: schema.nodes.footnote.create({
304
296
  id: model._id,
305
297
  kind: model.kind,
306
- comments: commentNodes.map((c) => c.attrs.id),
298
+ comments: comments.map((c) => c.attrs.id),
307
299
  }),
308
300
  });
309
301
  footnotesOfKind.push(footnote);
@@ -317,36 +309,51 @@ export class Decoder {
317
309
  },
318
310
  [ObjectTypes.Footnote]: (data) => {
319
311
  const footnoteModel = data;
320
- const commentNodes = this.createCommentsNode(footnoteModel);
321
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
312
+ const comments = this.createCommentNodes(footnoteModel);
313
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
322
314
  return this.parseContents(footnoteModel.contents || '<div></div>', undefined, this.getComments(footnoteModel), {
323
315
  topNode: schema.nodes.footnote.create({
324
316
  id: footnoteModel._id,
325
317
  kind: footnoteModel.kind,
326
- comments: commentNodes.map((c) => c.attrs.id),
318
+ comments: comments.map((c) => c.attrs.id),
327
319
  }),
328
320
  });
329
321
  },
330
322
  [ObjectTypes.KeywordsElement]: (data) => {
331
323
  const model = data;
332
- const keywordGroups = this.getKeywordGroups();
324
+ const keywordGroups = getKeywordGroups(this.modelMap).map((k) => this.decode(k));
333
325
  return schema.nodes.keywords_element.create({
334
326
  id: model._id,
335
327
  paragraphStyle: model.paragraphStyle,
336
328
  }, keywordGroups);
337
329
  },
330
+ [ObjectTypes.KeywordGroup]: (data) => {
331
+ const keywordGroup = data;
332
+ const keywords = getKeywords(this.modelMap)
333
+ .filter((k) => k.containedGroup === keywordGroup._id)
334
+ .map((k) => this.decode(k));
335
+ const comments = this.createCommentNodes(keywordGroup);
336
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
337
+ return schema.nodes.keyword_group.create({
338
+ id: keywordGroup._id,
339
+ type: keywordGroup.type,
340
+ comments: comments.map((c) => c.attrs.id),
341
+ }, keywords);
342
+ },
338
343
  [ObjectTypes.Keyword]: (data) => {
339
- const model = data;
344
+ const keyword = data;
345
+ const comments = this.createCommentNodes(keyword);
346
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
340
347
  return schema.nodes.keyword.create({
341
- id: model._id,
342
- contents: model.name,
343
- comments: this.createCommentsNode(model),
344
- }, schema.text(model.name));
348
+ id: keyword._id,
349
+ contents: keyword.name,
350
+ comments: comments.map((c) => c.attrs.id),
351
+ }, schema.text(keyword.name));
345
352
  },
346
353
  [ObjectTypes.ListElement]: (data) => {
347
354
  const model = data;
348
- const commentNodes = this.createCommentsNode(model);
349
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
355
+ const comments = this.createCommentNodes(model);
356
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
350
357
  switch (model.elementType) {
351
358
  case 'ol':
352
359
  return this.parseContents(model.contents || '<ol></ol>', undefined, this.getComments(model), {
@@ -354,7 +361,7 @@ export class Decoder {
354
361
  id: model._id,
355
362
  listStyleType: model.listStyleType,
356
363
  paragraphStyle: model.paragraphStyle,
357
- comments: commentNodes.map((c) => c.attrs.id),
364
+ comments: comments.map((c) => c.attrs.id),
358
365
  }),
359
366
  });
360
367
  case 'ul':
@@ -370,14 +377,14 @@ export class Decoder {
370
377
  },
371
378
  [ObjectTypes.Listing]: (data) => {
372
379
  const model = data;
373
- const commentNodes = this.createCommentsNode(model);
374
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
380
+ const comments = this.createCommentNodes(model);
381
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
375
382
  return schema.nodes.listing.createChecked({
376
383
  id: model._id,
377
384
  contents: model.contents,
378
385
  language: model.language,
379
386
  languageKey: model.languageKey,
380
- comments: commentNodes.map((c) => c.attrs.id),
387
+ comments: comments.map((c) => c.attrs.id),
381
388
  });
382
389
  },
383
390
  [ObjectTypes.ListingElement]: (data) => {
@@ -397,13 +404,13 @@ export class Decoder {
397
404
  throw new MissingElement(model.containedObjectID);
398
405
  }
399
406
  const figcaption = this.getFigcaption(model);
400
- const commentNodes = this.createCommentsNode(model);
401
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
407
+ const comments = this.createCommentNodes(model);
408
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
402
409
  return schema.nodes.listing_element.createChecked({
403
410
  id: model._id,
404
411
  suppressCaption: model.suppressCaption,
405
412
  suppressTitle: Boolean(model.suppressTitle === undefined ? true : model.suppressTitle),
406
- comments: commentNodes.map((c) => c.attrs.id),
413
+ comments: comments.map((c) => c.attrs.id),
407
414
  }, [listing, figcaption]);
408
415
  },
409
416
  [ObjectTypes.MissingFigure]: (data) => {
@@ -415,14 +422,14 @@ export class Decoder {
415
422
  },
416
423
  [ObjectTypes.ParagraphElement]: (data) => {
417
424
  const model = data;
418
- const commentNodes = this.createCommentsNode(model);
419
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
425
+ const comments = this.createCommentNodes(model);
426
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
420
427
  return this.parseContents(model.contents || '<p></p>', undefined, this.getComments(model), {
421
428
  topNode: schema.nodes.paragraph.create({
422
429
  id: model._id,
423
430
  paragraphStyle: model.paragraphStyle,
424
431
  placeholder: model.placeholderInnerHTML,
425
- comments: commentNodes.map((c) => c.attrs.id),
432
+ comments: comments.map((c) => c.attrs.id),
426
433
  }),
427
434
  });
428
435
  },
@@ -463,9 +470,6 @@ export class Decoder {
463
470
  for (const id of model.elementIDs) {
464
471
  const element = this.getModel(id);
465
472
  if (element) {
466
- if (isKeywordsSection(model) && isParagraphElement(element)) {
467
- continue;
468
- }
469
473
  elements.push(element);
470
474
  }
471
475
  else if (this.allowMissingElements) {
@@ -484,9 +488,7 @@ export class Decoder {
484
488
  }
485
489
  }
486
490
  }
487
- const elementNodes = elements
488
- .map(this.decode)
489
- .filter(isManuscriptNode);
491
+ const elementNodes = elements.map((e) => this.decode(e));
490
492
  const sectionTitle = 'section_title';
491
493
  const sectionTitleNode = model.title
492
494
  ? this.parseContents(model.title, 'h1', this.getComments(model), {
@@ -504,26 +506,20 @@ export class Decoder {
504
506
  .map(this.creators[ObjectTypes.Section]);
505
507
  const sectionCategory = model.category || guessSectionCategory(elements);
506
508
  const sectionNodeType = chooseSectionNodeType(sectionCategory);
507
- const commentNodes = this.createCommentsNode(model);
508
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
509
- let content;
510
- if (isAffiliationsSection(model) || isContributorsSection(model)) {
511
- content = elementNodes.concat(nestedSections);
512
- }
513
- else {
514
- content = (sectionLabelNode
515
- ? [sectionLabelNode, sectionTitleNode]
516
- : [sectionTitleNode])
517
- .concat(elementNodes)
518
- .concat(nestedSections);
519
- }
509
+ const comments = this.createCommentNodes(model);
510
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
511
+ const content = (sectionLabelNode
512
+ ? [sectionLabelNode, sectionTitleNode]
513
+ : [sectionTitleNode])
514
+ .concat(elementNodes)
515
+ .concat(nestedSections);
520
516
  const sectionNode = sectionNodeType.createAndFill({
521
517
  id: model._id,
522
518
  category: sectionCategory,
523
519
  titleSuppressed: model.titleSuppressed,
524
520
  pageBreakStyle: model.pageBreakStyle,
525
521
  generatedLabel: model.generatedLabel,
526
- comments: commentNodes.map((c) => c.attrs.id),
522
+ comments: comments.map((c) => c.attrs.id),
527
523
  }, content);
528
524
  if (!sectionNode) {
529
525
  console.error(model);
@@ -533,12 +529,12 @@ export class Decoder {
533
529
  },
534
530
  [ObjectTypes.Table]: (data) => {
535
531
  const model = data;
536
- const commentNodes = this.createCommentsNode(model);
537
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
532
+ const comments = this.createCommentNodes(model);
533
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
538
534
  return this.parseContents(model.contents, undefined, this.getComments(model), {
539
535
  topNode: schema.nodes.table.create({
540
536
  id: model._id,
541
- comments: commentNodes.map((c) => c.attrs.id),
537
+ comments: comments.map((c) => c.attrs.id),
542
538
  }),
543
539
  });
544
540
  },
@@ -547,8 +543,8 @@ export class Decoder {
547
543
  const table = this.createTable(model);
548
544
  const tableElementFooter = this.createTableElementFooter(model);
549
545
  const figcaption = this.getFigcaption(model);
550
- const commentNodes = this.createCommentsNode(model);
551
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
546
+ const comments = this.createCommentNodes(model);
547
+ comments.forEach((c) => this.comments.set(c.attrs.id, c));
552
548
  const content = tableElementFooter
553
549
  ? [table, figcaption, tableElementFooter]
554
550
  : [table, figcaption];
@@ -569,7 +565,7 @@ export class Decoder {
569
565
  suppressHeader: model.suppressHeader,
570
566
  tableStyle: model.tableStyle,
571
567
  paragraphStyle: model.paragraphStyle,
572
- comments: commentNodes.map((c) => c.attrs.id),
568
+ comments: comments.map((c) => c.attrs.id),
573
569
  }, content);
574
570
  },
575
571
  [ObjectTypes.TOCElement]: (data) => {
@@ -635,13 +631,21 @@ export class Decoder {
635
631
  };
636
632
  this.getModel = (id) => this.modelMap.get(id);
637
633
  this.createArticleNode = (manuscriptID) => {
638
- const titlesNode = this.createTitleNode();
639
- const rootSectionNodes = this.createRootSectionNodes();
640
- const metaSectionNode = this.createMetaSectionNode();
634
+ const title = this.createTitleNode();
635
+ const contributors = this.createContributorsNode();
636
+ const affiliations = this.createAffiliationsNode();
637
+ const keywords = this.createKeywordsNode();
638
+ const { abstracts, body, backmatter } = this.createContentSections();
639
+ const comments = this.createCommentsNode();
641
640
  const contents = [
642
- titlesNode,
643
- ...rootSectionNodes,
644
- metaSectionNode,
641
+ title,
642
+ contributors,
643
+ affiliations,
644
+ keywords,
645
+ abstracts,
646
+ body,
647
+ backmatter,
648
+ comments,
645
649
  ];
646
650
  return schema.nodes.manuscript.create({
647
651
  id: manuscriptID || this.getManuscriptID(),
@@ -683,23 +687,6 @@ export class Decoder {
683
687
  }
684
688
  return parser.parse(template.content.firstElementChild, options);
685
689
  };
686
- this.getKeywords = (id) => {
687
- const keywordsOfKind = [];
688
- const keywordsByGroup = [...this.modelMap.values()].filter((m) => m.objectType === ObjectTypes.Keyword &&
689
- m.containedGroup === id);
690
- for (const model of keywordsByGroup) {
691
- if (isKeyword(model)) {
692
- const keyword = this.parseContents(model.name || '', 'div', this.getComments(model), {
693
- topNode: schema.nodes.keyword.create({
694
- id: model._id,
695
- contents: model.name,
696
- }),
697
- });
698
- keywordsOfKind.push(keyword);
699
- }
700
- }
701
- return keywordsOfKind;
702
- };
703
690
  this.getManuscriptID = () => {
704
691
  for (const item of this.modelMap.values()) {
705
692
  if (isManuscript(item)) {
@@ -784,26 +771,4 @@ export class Decoder {
784
771
  }
785
772
  return listing;
786
773
  }
787
- getKeywordGroups() {
788
- const kwdGroupNodes = [];
789
- const kwdGroupsModels = [
790
- ...this.modelMap.values(),
791
- ].filter((model) => model.objectType === ObjectTypes.KeywordGroup);
792
- if (kwdGroupsModels.length > 0) {
793
- for (const kwdGroupModel of kwdGroupsModels) {
794
- const keywords = this.getKeywords(kwdGroupModel._id);
795
- const commentNodes = this.createCommentsNode(kwdGroupModel);
796
- commentNodes.forEach((c) => this.comments.set(c.attrs.id, c));
797
- const contents = [];
798
- contents.push(...keywords);
799
- const kwdGroupNode = schema.nodes.keywords_group.create({
800
- id: kwdGroupModel._id,
801
- type: kwdGroupModel.type,
802
- comments: commentNodes.map((c) => c.attrs.id),
803
- }, contents);
804
- kwdGroupNodes.push(kwdGroupNode);
805
- }
806
- }
807
- return kwdGroupNodes;
808
- }
809
774
  }
@@ -15,10 +15,11 @@
15
15
  */
16
16
  import { DOMSerializer } from 'prosemirror-model';
17
17
  import serializeToXML from 'w3c-xmlserializer';
18
- import { iterateChildren } from '../lib/utils';
19
- import { hasGroup, isHighlightMarkerNode, isSectionNode, schema, } from '../schema';
20
- import { buildAttribution } from './builders';
18
+ import { iterateChildren, modelsEqual } from '../lib/utils';
19
+ import { hasGroup, isHighlightMarkerNode, isManuscriptNode, isSectionNode, schema, } from '../schema';
20
+ import { auxiliaryObjectTypes, buildAttribution, buildElementsOrder, } from './builders';
21
21
  import { extractHighlightMarkers, isHighlightableModel, } from './highlight-markers';
22
+ import { generateID } from './id';
22
23
  import { nodeTypesMap } from './node-types';
23
24
  import { buildSectionCategory } from './section-category';
24
25
  const serializer = DOMSerializer.fromSchema(schema);
@@ -420,34 +421,9 @@ const encoders = {
420
421
  elementType: 'div',
421
422
  paragraphStyle: node.attrs.paragraphStyle || undefined,
422
423
  }),
423
- keywords_group: (node) => ({
424
+ keyword_group: (node) => ({
424
425
  type: node.attrs.type,
425
426
  }),
426
- keywords_section: (node, parent, path, priority) => ({
427
- category: buildSectionCategory(node),
428
- priority: priority.value++,
429
- title: inlineContentsOfNodeType(node, node.type.schema.nodes.section_title),
430
- path: path.concat([node.attrs.id]),
431
- elementIDs: childElements(node)
432
- .map((childNode) => childNode.attrs.id)
433
- .filter((id) => id),
434
- }),
435
- affiliations_section: (node, parent, path, priority) => ({
436
- category: buildSectionCategory(node),
437
- priority: priority.value++,
438
- path: path.concat([node.attrs.id]),
439
- elementIDs: childElements(node)
440
- .map((childNode) => childNode.attrs.id)
441
- .filter((id) => id),
442
- }),
443
- contributors_section: (node, parent, path, priority) => ({
444
- category: buildSectionCategory(node),
445
- priority: priority.value++,
446
- path: path.concat([node.attrs.id]),
447
- elementIDs: childElements(node)
448
- .map((childNode) => childNode.attrs.id)
449
- .filter((id) => id),
450
- }),
451
427
  missing_figure: (node) => ({
452
428
  position: node.attrs.position || undefined,
453
429
  }),
@@ -568,28 +544,48 @@ export const modelFromNode = (node, parent, path, priority) => {
568
544
  const comments = [...commentAnnotationsMap.values()];
569
545
  return { model, comments };
570
546
  };
571
- export const encode = (node) => {
547
+ const containerTypes = [
548
+ schema.nodes.affiliations,
549
+ schema.nodes.contributors,
550
+ schema.nodes.affiliations,
551
+ schema.nodes.keywords,
552
+ schema.nodes.abstracts,
553
+ schema.nodes.body,
554
+ schema.nodes.backmatter,
555
+ schema.nodes.comments,
556
+ ];
557
+ export const encode = (node, preserveWithRepeatedID = false) => {
572
558
  const models = new Map();
573
559
  const priority = {
574
560
  value: 1,
575
561
  };
576
562
  const placeholders = ['placeholder', 'placeholder_element'];
577
- const addModel = (path, parent) => (child) => {
563
+ const processNode = (path, parent) => (child) => {
564
+ if (containerTypes.includes(child.type)) {
565
+ child.forEach(processNode([], child));
566
+ return;
567
+ }
578
568
  if (!child.attrs.id) {
579
569
  return;
580
570
  }
581
571
  if (isHighlightMarkerNode(child)) {
582
572
  return;
583
573
  }
584
- if (child.type === schema.nodes.meta_section) {
574
+ if (placeholders.includes(child.type.name)) {
585
575
  return;
586
576
  }
587
- if (placeholders.includes(child.type.name)) {
577
+ if (parent.type === schema.nodes.paragraph) {
588
578
  return;
589
579
  }
590
580
  const { model, comments } = modelFromNode(child, parent, path, priority);
591
- if (models.has(model._id)) {
592
- throw Error(`Encountered duplicate ids in models map while encoding: ${model._id}`);
581
+ const existingModel = models.get(model._id);
582
+ if (existingModel) {
583
+ if (preserveWithRepeatedID && !modelsEqual(model, existingModel)) {
584
+ model._id = generateID(model.objectType);
585
+ }
586
+ else {
587
+ throw Error(`Encountered duplicate ids in models map while encoding: ${model._id}`);
588
+ }
593
589
  }
594
590
  comments.forEach((comment) => {
595
591
  const proseMirrorComment = models.get(comment._id);
@@ -600,22 +596,35 @@ export const encode = (node) => {
600
596
  }
601
597
  });
602
598
  models.set(model._id, model);
603
- child.forEach(addModel(path.concat(child.attrs.id), child));
599
+ child.forEach(processNode(path.concat(child.attrs.id), child));
604
600
  };
605
- node.forEach((cNode) => {
606
- if (cNode.type === schema.nodes.meta_section) {
607
- processMetaSectionNode(cNode, models, priority);
608
- }
609
- });
610
- node.forEach(addModel([], node));
601
+ node.forEach(processNode([], node));
602
+ if (isManuscriptNode(node)) {
603
+ auxiliaryObjectTypes.forEach((t) => {
604
+ const order = generateElementOrder(node, t);
605
+ if (order) {
606
+ models.set(order._id, order);
607
+ }
608
+ });
609
+ }
611
610
  return models;
612
611
  };
613
- const processMetaSectionNode = (node, models, priority) => {
614
- node.descendants((child) => {
615
- if ((!child.content || child.content.size === 0) &&
616
- nodeTypesMap.get(child.type)) {
617
- const { model } = modelFromNode(child, node, [], priority);
618
- models.set(model._id, model);
612
+ const generateElementOrder = (node, nodeType) => {
613
+ const ids = [];
614
+ node.descendants((n) => {
615
+ if (n.type === nodeType) {
616
+ ids.push(n.attrs.id);
619
617
  }
618
+ return true;
620
619
  });
620
+ if (!ids.length) {
621
+ return undefined;
622
+ }
623
+ const type = nodeTypesMap.get(nodeType);
624
+ if (!type) {
625
+ return undefined;
626
+ }
627
+ const order = buildElementsOrder(type);
628
+ order.elements = ids;
629
+ return order;
621
630
  };