@manuscripts/transform 1.2.4 → 1.2.5

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.
@@ -19,6 +19,17 @@ exports.jatsBodyTransformations = void 0;
19
19
  const transformer_1 = require("../../transformer");
20
20
  const removeNodeFromParent = (node) => node.parentNode && node.parentNode.removeChild(node);
21
21
  const capitalizeFirstLetter = (str) => str.charAt(0).toUpperCase() + str.slice(1);
22
+ const createSectionContainer = (type, createElement) => {
23
+ const sectionContainer = createElement('sec');
24
+ const sectionCategory = (0, transformer_1.chooseSectionCategoryByType)(type);
25
+ sectionContainer.setAttribute('sec-type', sectionCategory ? (0, transformer_1.chooseSecType)(sectionCategory) : '');
26
+ const title = createElement('title');
27
+ title.textContent = sectionCategory
28
+ ? (0, transformer_1.getSectionTitles)(sectionCategory)[0]
29
+ : ' ';
30
+ sectionContainer.appendChild(title);
31
+ return sectionContainer;
32
+ };
22
33
  exports.jatsBodyTransformations = {
23
34
  ensureSection(body, createElement) {
24
35
  let section = createElement('sec');
@@ -146,34 +157,64 @@ exports.jatsBodyTransformations = {
146
157
  section.append(...floatsGroup.children);
147
158
  return section;
148
159
  },
149
- moveSectionsToBody(doc, body, references, createElement) {
160
+ moveAbstractsIntoContainer(doc, abstractsContainer, createElement) {
150
161
  const abstractNodes = doc.querySelectorAll('front > article-meta > abstract');
151
- for (const abstractNode of abstractNodes) {
162
+ abstractNodes.forEach((abstractNode) => {
152
163
  const abstract = this.createAbstract(abstractNode, createElement);
153
164
  removeNodeFromParent(abstractNode);
154
- body.insertBefore(abstract, body.firstChild);
155
- }
165
+ abstractsContainer.appendChild(abstract);
166
+ });
167
+ },
168
+ wrapBodySections(doc, bodyContainer) {
169
+ const bodySections = doc.querySelectorAll('body > sec:not([sec-type="backmatter"]), body > sec:not([sec-type])');
170
+ bodySections.forEach((section) => {
171
+ removeNodeFromParent(section);
172
+ bodyContainer.appendChild(section);
173
+ });
174
+ },
175
+ moveBackSectionsIntoContainer(doc, backmatterContainer) {
156
176
  for (const section of doc.querySelectorAll('back > sec')) {
157
177
  removeNodeFromParent(section);
158
- body.appendChild(section);
178
+ backmatterContainer.appendChild(section);
159
179
  }
180
+ },
181
+ moveAcknowledgmentsIntoContainer(doc, backmatterContainer, createElement) {
160
182
  const ackNode = doc.querySelector('back > ack');
161
183
  if (ackNode) {
162
184
  const acknowledgements = this.createAcknowledgments(ackNode, createElement);
163
185
  removeNodeFromParent(ackNode);
164
- body.appendChild(acknowledgements);
186
+ backmatterContainer.appendChild(acknowledgements);
165
187
  }
188
+ },
189
+ moveAppendicesIntoContainer(doc, backmatterContainer, createElement) {
166
190
  const appGroup = doc.querySelectorAll('back > app-group > app');
167
191
  for (const app of appGroup) {
168
192
  const appendix = this.createAppendixSection(app, createElement);
169
193
  removeNodeFromParent(app);
170
- body.appendChild(appendix);
194
+ backmatterContainer.appendChild(appendix);
171
195
  }
196
+ },
197
+ moveBibliographyIntoContainer(doc, backmatterContainer, references, createElement) {
172
198
  if (references) {
173
- body.appendChild(this.createBibliography(doc, references, createElement));
199
+ backmatterContainer.appendChild(this.createBibliography(doc, references, createElement));
174
200
  }
175
201
  },
176
- mapFootnotesToSections(doc, body, createElement) {
202
+ moveSectionsToBody(doc, body, references, createElement) {
203
+ const bodyContainer = createSectionContainer('body', createElement);
204
+ const abstractsContainer = createSectionContainer('abstracts', createElement);
205
+ const backmatterContainer = createSectionContainer('backmatter', createElement);
206
+ this.mapFootnotesToSections(doc, backmatterContainer, createElement);
207
+ this.wrapBodySections(doc, bodyContainer);
208
+ this.moveAbstractsIntoContainer(doc, abstractsContainer, createElement);
209
+ this.moveBackSectionsIntoContainer(doc, backmatterContainer);
210
+ this.moveAcknowledgmentsIntoContainer(doc, backmatterContainer, createElement);
211
+ this.moveAppendicesIntoContainer(doc, backmatterContainer, createElement);
212
+ this.moveBibliographyIntoContainer(doc, backmatterContainer, references, createElement);
213
+ body.insertBefore(abstractsContainer, body.firstChild);
214
+ body.insertBefore(bodyContainer, abstractsContainer.nextSibling);
215
+ body.append(backmatterContainer);
216
+ },
217
+ mapFootnotesToSections(doc, backmatterContainer, createElement) {
177
218
  const footnoteGroups = [...doc.querySelectorAll('fn[fn-type]')];
178
219
  for (const footnote of footnoteGroups) {
179
220
  const type = footnote.getAttribute('fn-type') || '';
@@ -190,7 +231,7 @@ exports.jatsBodyTransformations = {
190
231
  section.append(...footnote.children);
191
232
  removeNodeFromParent(footnote);
192
233
  section.setAttribute('sec-type', (0, transformer_1.chooseSecType)(category));
193
- body.append(section);
234
+ backmatterContainer.append(section);
194
235
  }
195
236
  }
196
237
  const footnotes = [...doc.querySelectorAll('fn')];
@@ -205,7 +246,7 @@ exports.jatsBodyTransformations = {
205
246
  }
206
247
  if (!footnotesSection && containingGroup.innerHTML) {
207
248
  const section = this.createFootnotes([containingGroup], createElement);
208
- body.append(section);
249
+ backmatterContainer.append(section);
209
250
  }
210
251
  let regularFootnoteGroups = [
211
252
  ...doc.querySelectorAll('back > fn-group:not([fn-type])'),
@@ -218,7 +259,7 @@ exports.jatsBodyTransformations = {
218
259
  if (regularFootnoteGroups.length > 0) {
219
260
  regularFootnoteGroups.map((g) => removeNodeFromParent(g));
220
261
  const footnotes = this.createFootnotes(regularFootnoteGroups, createElement);
221
- body.appendChild(footnotes);
262
+ backmatterContainer.appendChild(footnotes);
222
263
  }
223
264
  },
224
265
  moveCaptionsToEnd(body) {
@@ -116,7 +116,6 @@ const parseJATSBody = (document, body, bibliographyItems, refModels, referenceId
116
116
  const orderedFootnotesIDs = (0, footnotes_order_1.createOrderedFootnotesIDs)(document);
117
117
  jats_body_transformations_1.jatsBodyTransformations.moveFloatsGroupToBody(document, body, createElement);
118
118
  jats_body_transformations_1.jatsBodyTransformations.ensureSection(body, createElement);
119
- jats_body_transformations_1.jatsBodyTransformations.mapFootnotesToSections(document, body, createElement);
120
119
  jats_body_transformations_1.jatsBodyTransformations.moveSectionsToBody(document, body, bibliographyItems, createElement);
121
120
  jats_body_transformations_1.jatsBodyTransformations.moveCaptionsToEnd(body);
122
121
  jats_body_transformations_1.jatsBodyTransformations.moveTableFooterToEnd(body);
@@ -136,8 +136,10 @@ class JATSExporter {
136
136
  article.appendChild(body);
137
137
  const back = this.buildBack(body);
138
138
  article.appendChild(back);
139
+ this.unwrapBody(body);
139
140
  this.moveAbstracts(front, body);
140
141
  this.moveFloatsGroup(body, article);
142
+ this.removeBackContainer(body);
141
143
  }
142
144
  await this.rewriteIDs(idGenerator);
143
145
  if (mediaPathGenerator) {
@@ -1392,21 +1394,49 @@ class JATSExporter {
1392
1394
  table.insertBefore(tfoot, tbody);
1393
1395
  }
1394
1396
  };
1395
- this.moveAbstracts = (front, body) => {
1396
- const sections = body.querySelectorAll(':scope > sec');
1397
- const abstractSections = Array.from(sections).filter((section) => {
1398
- const sectionType = section.getAttribute('sec-type');
1399
- if (sectionType === 'abstract' ||
1400
- sectionType === 'abstract-teaser' ||
1401
- sectionType === 'abstract-graphical') {
1402
- return true;
1403
- }
1404
- const sectionTitle = section.querySelector(':scope > title');
1405
- if (!sectionTitle) {
1406
- return false;
1407
- }
1408
- return sectionTitle.textContent === 'Abstract';
1397
+ this.unwrapBody = (body) => {
1398
+ const container = body.querySelector(':scope > sec[sec-type="body"]');
1399
+ if (!container) {
1400
+ return;
1401
+ }
1402
+ const sections = container.querySelectorAll(':scope > sec');
1403
+ sections.forEach((section) => {
1404
+ body.appendChild(section.cloneNode(true));
1409
1405
  });
1406
+ body.removeChild(container);
1407
+ };
1408
+ this.removeBackContainer = (body) => {
1409
+ const container = body.querySelector(':scope > sec[sec-type="backmatter"]');
1410
+ if (!container) {
1411
+ return;
1412
+ }
1413
+ const isContainerEmpty = container.children.length === 0;
1414
+ if (!isContainerEmpty) {
1415
+ warn('Backmatter section is not empty.');
1416
+ }
1417
+ body.removeChild(container);
1418
+ };
1419
+ this.moveAbstracts = (front, body) => {
1420
+ const container = body.querySelector(':scope > sec[sec-type="abstracts"]');
1421
+ let abstractSections;
1422
+ if (container) {
1423
+ abstractSections = Array.from(container.querySelectorAll(':scope > sec'));
1424
+ }
1425
+ else {
1426
+ abstractSections = Array.from(body.querySelectorAll(':scope > sec')).filter((section) => {
1427
+ const sectionType = section.getAttribute('sec-type');
1428
+ if (sectionType === 'abstract' ||
1429
+ sectionType === 'abstract-teaser' ||
1430
+ sectionType === 'abstract-graphical') {
1431
+ return true;
1432
+ }
1433
+ const sectionTitle = section.querySelector(':scope > title');
1434
+ if (!sectionTitle) {
1435
+ return false;
1436
+ }
1437
+ return sectionTitle.textContent === 'Abstract';
1438
+ });
1439
+ }
1410
1440
  if (abstractSections.length) {
1411
1441
  for (const abstractSection of abstractSections) {
1412
1442
  const abstractNode = this.document.createElement('abstract');
@@ -1427,6 +1457,9 @@ class JATSExporter {
1427
1457
  }
1428
1458
  }
1429
1459
  }
1460
+ if (container) {
1461
+ body.removeChild(container);
1462
+ }
1430
1463
  };
1431
1464
  this.moveSectionsToBack = (back, body) => {
1432
1465
  const availabilitySection = body.querySelector('sec[sec-type="availability"]');
@@ -35,7 +35,7 @@ const choosePageBreakStyle = (element) => {
35
35
  return exports.PAGE_BREAK_NONE;
36
36
  };
37
37
  exports.section = {
38
- content: 'section_label? section_title (paragraph | element)* section*',
38
+ content: 'section_label? section_title (paragraph | element)* sections*',
39
39
  attrs: {
40
40
  id: { default: '' },
41
41
  category: { default: '' },
@@ -162,6 +162,15 @@ const childElements = (node) => {
162
162
  });
163
163
  return nodes;
164
164
  };
165
+ const sectionChildElementIds = (node) => {
166
+ const nodes = [];
167
+ node.forEach((childNode) => {
168
+ if (!(0, schema_1.hasGroup)(childNode.type, 'sections')) {
169
+ nodes.push(childNode);
170
+ }
171
+ });
172
+ return nodes.map((childNode) => childNode.attrs.id).filter((id) => id);
173
+ };
165
174
  const attributeOfNodeType = (node, type, attribute) => {
166
175
  for (const child of (0, utils_1.iterateChildren)(node)) {
167
176
  if (child.type.name === type) {
@@ -449,9 +458,7 @@ const encoders = {
449
458
  label: inlineContentsOfNodeType(node, node.type.schema.nodes.section_label) ||
450
459
  undefined,
451
460
  path: path.concat([node.attrs.id]),
452
- elementIDs: childElements(node)
453
- .map((childNode) => childNode.attrs.id)
454
- .filter((id) => id),
461
+ elementIDs: sectionChildElementIds(node),
455
462
  titleSuppressed: node.attrs.titleSuppressed || undefined,
456
463
  generatedLabel: node.attrs.generatedLabel || undefined,
457
464
  pageBreakStyle: node.attrs.pageBreakStyle || undefined,
@@ -14,8 +14,12 @@
14
14
  * See the License for the specific language governing permissions and
15
15
  * limitations under the License.
16
16
  */
17
+ var __importDefault = (this && this.__importDefault) || function (mod) {
18
+ return (mod && mod.__esModule) ? mod : { "default": mod };
19
+ };
17
20
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.chooseSectionCategoryFromTitle = exports.chooseSectionCategory = exports.chooseSectionCategoryByType = exports.chooseSecType = exports.buildSectionCategory = exports.guessSectionCategory = exports.chooseSectionLableName = exports.chooseSectionNodeType = exports.isAnySectionNode = void 0;
21
+ exports.chooseSectionCategoryFromTitle = exports.chooseSectionCategory = exports.chooseSectionCategoryByType = exports.chooseSecType = exports.buildSectionCategory = exports.guessSectionCategory = exports.chooseSectionLableName = exports.chooseSectionNodeType = exports.isAnySectionNode = exports.getSectionTitles = void 0;
22
+ const section_categories_json_1 = __importDefault(require("@manuscripts/data/dist/shared/section-categories.json"));
19
23
  const json_schema_1 = require("@manuscripts/json-schema");
20
24
  const schema_1 = require("../schema");
21
25
  const sectionNodeTypes = [
@@ -25,6 +29,18 @@ const sectionNodeTypes = [
25
29
  schema_1.schema.nodes.section,
26
30
  schema_1.schema.nodes.toc_section,
27
31
  ];
32
+ const sectionCategoriesMap = new Map(section_categories_json_1.default.map((section) => [
33
+ section._id,
34
+ section,
35
+ ]));
36
+ const getSectionTitles = (sectionCategory) => {
37
+ const category = sectionCategoriesMap.get(sectionCategory);
38
+ if (category) {
39
+ return category.titles.length ? category.titles : [' '];
40
+ }
41
+ throw new Error(`${sectionCategory} not found in section categories`);
42
+ };
43
+ exports.getSectionTitles = getSectionTitles;
28
44
  const isAnySectionNode = (node) => sectionNodeTypes.includes(node.type);
29
45
  exports.isAnySectionNode = isAnySectionNode;
30
46
  const chooseSectionNodeType = (category) => {
@@ -161,6 +177,12 @@ const chooseSectionCategoryByType = (secType) => {
161
177
  return 'MPSectionCategory:supported-by';
162
178
  case 'ethics-statement':
163
179
  return 'MPSectionCategory:ethics-statement';
180
+ case 'body':
181
+ return 'MPSectionCategory:body';
182
+ case 'backmatter':
183
+ return 'MPSectionCategory:backmatter';
184
+ case 'abstracts':
185
+ return 'MPSectionCategory:abstracts';
164
186
  default:
165
187
  return undefined;
166
188
  }
@@ -13,9 +13,20 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { chooseSectionCategoryByType, chooseSecType } from '../../transformer';
16
+ import { chooseSectionCategoryByType, chooseSecType, getSectionTitles, } from '../../transformer';
17
17
  const removeNodeFromParent = (node) => node.parentNode && node.parentNode.removeChild(node);
18
18
  const capitalizeFirstLetter = (str) => str.charAt(0).toUpperCase() + str.slice(1);
19
+ const createSectionContainer = (type, createElement) => {
20
+ const sectionContainer = createElement('sec');
21
+ const sectionCategory = chooseSectionCategoryByType(type);
22
+ sectionContainer.setAttribute('sec-type', sectionCategory ? chooseSecType(sectionCategory) : '');
23
+ const title = createElement('title');
24
+ title.textContent = sectionCategory
25
+ ? getSectionTitles(sectionCategory)[0]
26
+ : ' ';
27
+ sectionContainer.appendChild(title);
28
+ return sectionContainer;
29
+ };
19
30
  export const jatsBodyTransformations = {
20
31
  ensureSection(body, createElement) {
21
32
  let section = createElement('sec');
@@ -143,34 +154,64 @@ export const jatsBodyTransformations = {
143
154
  section.append(...floatsGroup.children);
144
155
  return section;
145
156
  },
146
- moveSectionsToBody(doc, body, references, createElement) {
157
+ moveAbstractsIntoContainer(doc, abstractsContainer, createElement) {
147
158
  const abstractNodes = doc.querySelectorAll('front > article-meta > abstract');
148
- for (const abstractNode of abstractNodes) {
159
+ abstractNodes.forEach((abstractNode) => {
149
160
  const abstract = this.createAbstract(abstractNode, createElement);
150
161
  removeNodeFromParent(abstractNode);
151
- body.insertBefore(abstract, body.firstChild);
152
- }
162
+ abstractsContainer.appendChild(abstract);
163
+ });
164
+ },
165
+ wrapBodySections(doc, bodyContainer) {
166
+ const bodySections = doc.querySelectorAll('body > sec:not([sec-type="backmatter"]), body > sec:not([sec-type])');
167
+ bodySections.forEach((section) => {
168
+ removeNodeFromParent(section);
169
+ bodyContainer.appendChild(section);
170
+ });
171
+ },
172
+ moveBackSectionsIntoContainer(doc, backmatterContainer) {
153
173
  for (const section of doc.querySelectorAll('back > sec')) {
154
174
  removeNodeFromParent(section);
155
- body.appendChild(section);
175
+ backmatterContainer.appendChild(section);
156
176
  }
177
+ },
178
+ moveAcknowledgmentsIntoContainer(doc, backmatterContainer, createElement) {
157
179
  const ackNode = doc.querySelector('back > ack');
158
180
  if (ackNode) {
159
181
  const acknowledgements = this.createAcknowledgments(ackNode, createElement);
160
182
  removeNodeFromParent(ackNode);
161
- body.appendChild(acknowledgements);
183
+ backmatterContainer.appendChild(acknowledgements);
162
184
  }
185
+ },
186
+ moveAppendicesIntoContainer(doc, backmatterContainer, createElement) {
163
187
  const appGroup = doc.querySelectorAll('back > app-group > app');
164
188
  for (const app of appGroup) {
165
189
  const appendix = this.createAppendixSection(app, createElement);
166
190
  removeNodeFromParent(app);
167
- body.appendChild(appendix);
191
+ backmatterContainer.appendChild(appendix);
168
192
  }
193
+ },
194
+ moveBibliographyIntoContainer(doc, backmatterContainer, references, createElement) {
169
195
  if (references) {
170
- body.appendChild(this.createBibliography(doc, references, createElement));
196
+ backmatterContainer.appendChild(this.createBibliography(doc, references, createElement));
171
197
  }
172
198
  },
173
- mapFootnotesToSections(doc, body, createElement) {
199
+ moveSectionsToBody(doc, body, references, createElement) {
200
+ const bodyContainer = createSectionContainer('body', createElement);
201
+ const abstractsContainer = createSectionContainer('abstracts', createElement);
202
+ const backmatterContainer = createSectionContainer('backmatter', createElement);
203
+ this.mapFootnotesToSections(doc, backmatterContainer, createElement);
204
+ this.wrapBodySections(doc, bodyContainer);
205
+ this.moveAbstractsIntoContainer(doc, abstractsContainer, createElement);
206
+ this.moveBackSectionsIntoContainer(doc, backmatterContainer);
207
+ this.moveAcknowledgmentsIntoContainer(doc, backmatterContainer, createElement);
208
+ this.moveAppendicesIntoContainer(doc, backmatterContainer, createElement);
209
+ this.moveBibliographyIntoContainer(doc, backmatterContainer, references, createElement);
210
+ body.insertBefore(abstractsContainer, body.firstChild);
211
+ body.insertBefore(bodyContainer, abstractsContainer.nextSibling);
212
+ body.append(backmatterContainer);
213
+ },
214
+ mapFootnotesToSections(doc, backmatterContainer, createElement) {
174
215
  const footnoteGroups = [...doc.querySelectorAll('fn[fn-type]')];
175
216
  for (const footnote of footnoteGroups) {
176
217
  const type = footnote.getAttribute('fn-type') || '';
@@ -187,7 +228,7 @@ export const jatsBodyTransformations = {
187
228
  section.append(...footnote.children);
188
229
  removeNodeFromParent(footnote);
189
230
  section.setAttribute('sec-type', chooseSecType(category));
190
- body.append(section);
231
+ backmatterContainer.append(section);
191
232
  }
192
233
  }
193
234
  const footnotes = [...doc.querySelectorAll('fn')];
@@ -202,7 +243,7 @@ export const jatsBodyTransformations = {
202
243
  }
203
244
  if (!footnotesSection && containingGroup.innerHTML) {
204
245
  const section = this.createFootnotes([containingGroup], createElement);
205
- body.append(section);
246
+ backmatterContainer.append(section);
206
247
  }
207
248
  let regularFootnoteGroups = [
208
249
  ...doc.querySelectorAll('back > fn-group:not([fn-type])'),
@@ -215,7 +256,7 @@ export const jatsBodyTransformations = {
215
256
  if (regularFootnoteGroups.length > 0) {
216
257
  regularFootnoteGroups.map((g) => removeNodeFromParent(g));
217
258
  const footnotes = this.createFootnotes(regularFootnoteGroups, createElement);
218
- body.appendChild(footnotes);
259
+ backmatterContainer.appendChild(footnotes);
219
260
  }
220
261
  },
221
262
  moveCaptionsToEnd(body) {
@@ -111,7 +111,6 @@ export const parseJATSBody = (document, body, bibliographyItems, refModels, refe
111
111
  const orderedFootnotesIDs = createOrderedFootnotesIDs(document);
112
112
  jatsBodyTransformations.moveFloatsGroupToBody(document, body, createElement);
113
113
  jatsBodyTransformations.ensureSection(body, createElement);
114
- jatsBodyTransformations.mapFootnotesToSections(document, body, createElement);
115
114
  jatsBodyTransformations.moveSectionsToBody(document, body, bibliographyItems, createElement);
116
115
  jatsBodyTransformations.moveCaptionsToEnd(body);
117
116
  jatsBodyTransformations.moveTableFooterToEnd(body);
@@ -129,8 +129,10 @@ export class JATSExporter {
129
129
  article.appendChild(body);
130
130
  const back = this.buildBack(body);
131
131
  article.appendChild(back);
132
+ this.unwrapBody(body);
132
133
  this.moveAbstracts(front, body);
133
134
  this.moveFloatsGroup(body, article);
135
+ this.removeBackContainer(body);
134
136
  }
135
137
  await this.rewriteIDs(idGenerator);
136
138
  if (mediaPathGenerator) {
@@ -1385,21 +1387,49 @@ export class JATSExporter {
1385
1387
  table.insertBefore(tfoot, tbody);
1386
1388
  }
1387
1389
  };
1388
- this.moveAbstracts = (front, body) => {
1389
- const sections = body.querySelectorAll(':scope > sec');
1390
- const abstractSections = Array.from(sections).filter((section) => {
1391
- const sectionType = section.getAttribute('sec-type');
1392
- if (sectionType === 'abstract' ||
1393
- sectionType === 'abstract-teaser' ||
1394
- sectionType === 'abstract-graphical') {
1395
- return true;
1396
- }
1397
- const sectionTitle = section.querySelector(':scope > title');
1398
- if (!sectionTitle) {
1399
- return false;
1400
- }
1401
- return sectionTitle.textContent === 'Abstract';
1390
+ this.unwrapBody = (body) => {
1391
+ const container = body.querySelector(':scope > sec[sec-type="body"]');
1392
+ if (!container) {
1393
+ return;
1394
+ }
1395
+ const sections = container.querySelectorAll(':scope > sec');
1396
+ sections.forEach((section) => {
1397
+ body.appendChild(section.cloneNode(true));
1402
1398
  });
1399
+ body.removeChild(container);
1400
+ };
1401
+ this.removeBackContainer = (body) => {
1402
+ const container = body.querySelector(':scope > sec[sec-type="backmatter"]');
1403
+ if (!container) {
1404
+ return;
1405
+ }
1406
+ const isContainerEmpty = container.children.length === 0;
1407
+ if (!isContainerEmpty) {
1408
+ warn('Backmatter section is not empty.');
1409
+ }
1410
+ body.removeChild(container);
1411
+ };
1412
+ this.moveAbstracts = (front, body) => {
1413
+ const container = body.querySelector(':scope > sec[sec-type="abstracts"]');
1414
+ let abstractSections;
1415
+ if (container) {
1416
+ abstractSections = Array.from(container.querySelectorAll(':scope > sec'));
1417
+ }
1418
+ else {
1419
+ abstractSections = Array.from(body.querySelectorAll(':scope > sec')).filter((section) => {
1420
+ const sectionType = section.getAttribute('sec-type');
1421
+ if (sectionType === 'abstract' ||
1422
+ sectionType === 'abstract-teaser' ||
1423
+ sectionType === 'abstract-graphical') {
1424
+ return true;
1425
+ }
1426
+ const sectionTitle = section.querySelector(':scope > title');
1427
+ if (!sectionTitle) {
1428
+ return false;
1429
+ }
1430
+ return sectionTitle.textContent === 'Abstract';
1431
+ });
1432
+ }
1403
1433
  if (abstractSections.length) {
1404
1434
  for (const abstractSection of abstractSections) {
1405
1435
  const abstractNode = this.document.createElement('abstract');
@@ -1420,6 +1450,9 @@ export class JATSExporter {
1420
1450
  }
1421
1451
  }
1422
1452
  }
1453
+ if (container) {
1454
+ body.removeChild(container);
1455
+ }
1423
1456
  };
1424
1457
  this.moveSectionsToBack = (back, body) => {
1425
1458
  const availabilitySection = body.querySelector('sec[sec-type="availability"]');
@@ -32,7 +32,7 @@ const choosePageBreakStyle = (element) => {
32
32
  return PAGE_BREAK_NONE;
33
33
  };
34
34
  export const section = {
35
- content: 'section_label? section_title (paragraph | element)* section*',
35
+ content: 'section_label? section_title (paragraph | element)* sections*',
36
36
  attrs: {
37
37
  id: { default: '' },
38
38
  category: { default: '' },
@@ -16,7 +16,7 @@
16
16
  import { DOMSerializer } from 'prosemirror-model';
17
17
  import serializeToXML from 'w3c-xmlserializer';
18
18
  import { iterateChildren } from '../lib/utils';
19
- import { isHighlightMarkerNode, isSectionNode, schema, } from '../schema';
19
+ import { hasGroup, isHighlightMarkerNode, isSectionNode, schema, } from '../schema';
20
20
  import { buildAttribution } from './builders';
21
21
  import { extractHighlightMarkers, isHighlightableModel, } from './highlight-markers';
22
22
  import { nodeTypesMap } from './node-types';
@@ -154,6 +154,15 @@ const childElements = (node) => {
154
154
  });
155
155
  return nodes;
156
156
  };
157
+ const sectionChildElementIds = (node) => {
158
+ const nodes = [];
159
+ node.forEach((childNode) => {
160
+ if (!hasGroup(childNode.type, 'sections')) {
161
+ nodes.push(childNode);
162
+ }
163
+ });
164
+ return nodes.map((childNode) => childNode.attrs.id).filter((id) => id);
165
+ };
157
166
  const attributeOfNodeType = (node, type, attribute) => {
158
167
  for (const child of iterateChildren(node)) {
159
168
  if (child.type.name === type) {
@@ -441,9 +450,7 @@ const encoders = {
441
450
  label: inlineContentsOfNodeType(node, node.type.schema.nodes.section_label) ||
442
451
  undefined,
443
452
  path: path.concat([node.attrs.id]),
444
- elementIDs: childElements(node)
445
- .map((childNode) => childNode.attrs.id)
446
- .filter((id) => id),
453
+ elementIDs: sectionChildElementIds(node),
447
454
  titleSuppressed: node.attrs.titleSuppressed || undefined,
448
455
  generatedLabel: node.attrs.generatedLabel || undefined,
449
456
  pageBreakStyle: node.attrs.pageBreakStyle || undefined,
@@ -13,7 +13,8 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { ObjectTypes } from '@manuscripts/json-schema';
16
+ import sectionCategories from '@manuscripts/data/dist/shared/section-categories.json';
17
+ import { ObjectTypes, } from '@manuscripts/json-schema';
17
18
  import { schema } from '../schema';
18
19
  const sectionNodeTypes = [
19
20
  schema.nodes.bibliography_section,
@@ -22,6 +23,17 @@ const sectionNodeTypes = [
22
23
  schema.nodes.section,
23
24
  schema.nodes.toc_section,
24
25
  ];
26
+ const sectionCategoriesMap = new Map(sectionCategories.map((section) => [
27
+ section._id,
28
+ section,
29
+ ]));
30
+ export const getSectionTitles = (sectionCategory) => {
31
+ const category = sectionCategoriesMap.get(sectionCategory);
32
+ if (category) {
33
+ return category.titles.length ? category.titles : [' '];
34
+ }
35
+ throw new Error(`${sectionCategory} not found in section categories`);
36
+ };
25
37
  export const isAnySectionNode = (node) => sectionNodeTypes.includes(node.type);
26
38
  export const chooseSectionNodeType = (category) => {
27
39
  switch (category) {
@@ -152,6 +164,12 @@ export const chooseSectionCategoryByType = (secType) => {
152
164
  return 'MPSectionCategory:supported-by';
153
165
  case 'ethics-statement':
154
166
  return 'MPSectionCategory:ethics-statement';
167
+ case 'body':
168
+ return 'MPSectionCategory:body';
169
+ case 'backmatter':
170
+ return 'MPSectionCategory:backmatter';
171
+ case 'abstracts':
172
+ return 'MPSectionCategory:abstracts';
155
173
  default:
156
174
  return undefined;
157
175
  }
@@ -22,8 +22,14 @@ export declare const jatsBodyTransformations: {
22
22
  createFootnotes(footnoteGroups: Element[], createElement: (tagName: string) => HTMLElement): HTMLElement;
23
23
  createAppendixSection(app: Element, createElement: (tagName: string) => HTMLElement): HTMLElement;
24
24
  createFloatsGroupSection(floatsGroup: Element, createElement: (tagName: string) => HTMLElement): HTMLElement;
25
+ moveAbstractsIntoContainer(doc: Document, abstractsContainer: Element, createElement: (tagName: string) => HTMLElement): void;
26
+ wrapBodySections(doc: Document, bodyContainer: Element): void;
27
+ moveBackSectionsIntoContainer(doc: Document, backmatterContainer: Element): void;
28
+ moveAcknowledgmentsIntoContainer(doc: Document, backmatterContainer: Element, createElement: (tagName: string) => HTMLElement): void;
29
+ moveAppendicesIntoContainer(doc: Document, backmatterContainer: Element, createElement: (tagName: string) => HTMLElement): void;
30
+ moveBibliographyIntoContainer(doc: Document, backmatterContainer: Element, references: BibliographyItem[] | null, createElement: (tagName: string) => HTMLElement): void;
25
31
  moveSectionsToBody(doc: Document, body: Element, references: BibliographyItem[] | null, createElement: (tagName: string) => HTMLElement): void;
26
- mapFootnotesToSections(doc: Document, body: Element, createElement: (tagName: string) => HTMLElement): void;
32
+ mapFootnotesToSections(doc: Document, backmatterContainer: Element, createElement: (tagName: string) => HTMLElement): void;
27
33
  moveCaptionsToEnd(body: Element): void;
28
34
  moveTableFooterToEnd(body: Element): void;
29
35
  moveFloatsGroupToBody(doc: Document, body: Element, createElement: (tagName: string) => HTMLElement): void;
@@ -63,6 +63,8 @@ export declare class JATSExporter {
63
63
  private fixBody;
64
64
  private changeTag;
65
65
  private fixTable;
66
+ private unwrapBody;
67
+ private removeBackContainer;
66
68
  private moveAbstracts;
67
69
  private moveSectionsToBack;
68
70
  sectionToFootnote: (section: Element, fnType: string) => HTMLElement;
@@ -15,9 +15,10 @@
15
15
  */
16
16
  import { Element } from '@manuscripts/json-schema';
17
17
  import { ManuscriptNode, ManuscriptNodeType } from '../schema';
18
+ export declare const getSectionTitles: (sectionCategory: SectionCategory) => string[];
18
19
  export declare const isAnySectionNode: (node: ManuscriptNode) => boolean;
19
- export type SectionCategory = 'MPSectionCategory:abstract' | 'MPSectionCategory:abstract-teaser' | 'MPSectionCategory:abstract-graphical' | 'MPSectionCategory:acknowledgement' | 'MPSectionCategory:availability' | 'MPSectionCategory:bibliography' | 'MPSectionCategory:conclusions' | 'MPSectionCategory:discussion' | 'MPSectionCategory:endnotes' | 'MPSectionCategory:introduction' | 'MPSectionCategory:keywords' | 'MPSectionCategory:materials-method' | 'MPSectionCategory:results' | 'MPSectionCategory:toc' | 'MPSectionCategory:floating-element' | 'MPSectionCategory:appendices' | 'MPSectionCategory:competing-interests' | 'MPSectionCategory:financial-disclosure' | 'MPSectionCategory:con' | 'MPSectionCategory:deceased' | 'MPSectionCategory:equal' | 'MPSectionCategory:present-address' | 'MPSectionCategory:presented-at' | 'MPSectionCategory:previously-at' | 'MPSectionCategory:supplementary-material' | 'MPSectionCategory:supported-by' | 'MPSectionCategory:ethics-statement';
20
- export type SecType = 'abstract' | 'abstract-teaser' | 'abstract-graphical' | 'acknowledgments' | 'availability' | 'bibliography' | 'conclusions' | 'data-availability' | 'discussion' | 'endnotes' | 'intro' | 'keywords' | 'materials' | 'methods' | 'results' | 'toc' | 'floating-element' | 'appendices' | 'competing-interests' | 'financial-disclosure' | 'con' | 'deceased' | 'equal' | 'present-address' | 'presented-at' | 'previously-at' | 'supplementary-material' | 'supported-by' | 'ethics-statement';
20
+ export type SectionCategory = 'MPSectionCategory:abstract' | 'MPSectionCategory:abstract-teaser' | 'MPSectionCategory:abstract-graphical' | 'MPSectionCategory:acknowledgement' | 'MPSectionCategory:availability' | 'MPSectionCategory:bibliography' | 'MPSectionCategory:conclusions' | 'MPSectionCategory:discussion' | 'MPSectionCategory:endnotes' | 'MPSectionCategory:introduction' | 'MPSectionCategory:keywords' | 'MPSectionCategory:materials-method' | 'MPSectionCategory:results' | 'MPSectionCategory:toc' | 'MPSectionCategory:floating-element' | 'MPSectionCategory:appendices' | 'MPSectionCategory:competing-interests' | 'MPSectionCategory:financial-disclosure' | 'MPSectionCategory:con' | 'MPSectionCategory:deceased' | 'MPSectionCategory:equal' | 'MPSectionCategory:present-address' | 'MPSectionCategory:presented-at' | 'MPSectionCategory:previously-at' | 'MPSectionCategory:supplementary-material' | 'MPSectionCategory:supported-by' | 'MPSectionCategory:ethics-statement' | 'MPSectionCategory:body' | 'MPSectionCategory:abstracts' | 'MPSectionCategory:backmatter';
21
+ export type SecType = 'abstract' | 'abstract-teaser' | 'abstract-graphical' | 'acknowledgments' | 'availability' | 'bibliography' | 'conclusions' | 'data-availability' | 'discussion' | 'endnotes' | 'intro' | 'keywords' | 'materials' | 'methods' | 'results' | 'toc' | 'floating-element' | 'appendices' | 'competing-interests' | 'financial-disclosure' | 'con' | 'deceased' | 'equal' | 'present-address' | 'presented-at' | 'previously-at' | 'supplementary-material' | 'supported-by' | 'ethics-statement' | 'abstracts' | 'body' | 'backmatter';
21
22
  export declare const chooseSectionNodeType: (category?: SectionCategory) => ManuscriptNodeType;
22
23
  export declare const chooseSectionLableName: (type?: SecType) => string;
23
24
  export declare const guessSectionCategory: (elements: Element[]) => 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.2.4",
4
+ "version": "1.2.5",
5
5
  "repository": "github:Atypon-OpenSource/manuscripts-transform",
6
6
  "license": "Apache-2.0",
7
7
  "main": "dist/cjs",
@@ -29,7 +29,7 @@
29
29
  "version": "yarn build"
30
30
  },
31
31
  "dependencies": {
32
- "@manuscripts/json-schema": "^2.0.1",
32
+ "@manuscripts/json-schema": "^2.0.2",
33
33
  "debug": "^4.3.4",
34
34
  "jszip": "^3.10.1",
35
35
  "mathjax-full": "^3.2.2",