@manuscripts/transform 1.5.3 → 1.5.4-LEAN-3030

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