@manuscripts/transform 1.2.4-LEAN-2357 → 1.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/jats/importer/jats-body-transformations.js +12 -53
- package/dist/cjs/jats/importer/parse-jats-article.js +1 -0
- package/dist/cjs/jats/jats-exporter.js +14 -47
- package/dist/cjs/lib/utils.js +12 -1
- package/dist/cjs/schema/nodes/section.js +1 -1
- package/dist/cjs/transformer/encode.js +3 -10
- package/dist/cjs/transformer/section-category.js +1 -23
- package/dist/es/jats/importer/jats-body-transformations.js +13 -54
- package/dist/es/jats/importer/parse-jats-article.js +1 -0
- package/dist/es/jats/jats-exporter.js +14 -47
- package/dist/es/lib/utils.js +10 -0
- package/dist/es/schema/nodes/section.js +1 -1
- package/dist/es/transformer/encode.js +4 -11
- package/dist/es/transformer/section-category.js +1 -19
- package/dist/types/jats/importer/jats-body-transformations.d.ts +1 -7
- package/dist/types/jats/jats-exporter.d.ts +0 -2
- package/dist/types/lib/utils.d.ts +1 -0
- package/dist/types/transformer/section-category.d.ts +2 -3
- package/package.json +2 -2
|
@@ -19,17 +19,6 @@ 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
|
-
};
|
|
33
22
|
exports.jatsBodyTransformations = {
|
|
34
23
|
ensureSection(body, createElement) {
|
|
35
24
|
let section = createElement('sec');
|
|
@@ -157,64 +146,34 @@ exports.jatsBodyTransformations = {
|
|
|
157
146
|
section.append(...floatsGroup.children);
|
|
158
147
|
return section;
|
|
159
148
|
},
|
|
160
|
-
|
|
149
|
+
moveSectionsToBody(doc, body, references, createElement) {
|
|
161
150
|
const abstractNodes = doc.querySelectorAll('front > article-meta > abstract');
|
|
162
|
-
|
|
151
|
+
for (const abstractNode of abstractNodes) {
|
|
163
152
|
const abstract = this.createAbstract(abstractNode, createElement);
|
|
164
153
|
removeNodeFromParent(abstractNode);
|
|
165
|
-
|
|
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) {
|
|
154
|
+
body.insertBefore(abstract, body.firstChild);
|
|
155
|
+
}
|
|
176
156
|
for (const section of doc.querySelectorAll('back > sec')) {
|
|
177
157
|
removeNodeFromParent(section);
|
|
178
|
-
|
|
158
|
+
body.appendChild(section);
|
|
179
159
|
}
|
|
180
|
-
},
|
|
181
|
-
moveAcknowledgmentsIntoContainer(doc, backmatterContainer, createElement) {
|
|
182
160
|
const ackNode = doc.querySelector('back > ack');
|
|
183
161
|
if (ackNode) {
|
|
184
162
|
const acknowledgements = this.createAcknowledgments(ackNode, createElement);
|
|
185
163
|
removeNodeFromParent(ackNode);
|
|
186
|
-
|
|
164
|
+
body.appendChild(acknowledgements);
|
|
187
165
|
}
|
|
188
|
-
},
|
|
189
|
-
moveAppendicesIntoContainer(doc, backmatterContainer, createElement) {
|
|
190
166
|
const appGroup = doc.querySelectorAll('back > app-group > app');
|
|
191
167
|
for (const app of appGroup) {
|
|
192
168
|
const appendix = this.createAppendixSection(app, createElement);
|
|
193
169
|
removeNodeFromParent(app);
|
|
194
|
-
|
|
170
|
+
body.appendChild(appendix);
|
|
195
171
|
}
|
|
196
|
-
},
|
|
197
|
-
moveBibliographyIntoContainer(doc, backmatterContainer, references, createElement) {
|
|
198
172
|
if (references) {
|
|
199
|
-
|
|
173
|
+
body.appendChild(this.createBibliography(doc, references, createElement));
|
|
200
174
|
}
|
|
201
175
|
},
|
|
202
|
-
|
|
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) {
|
|
176
|
+
mapFootnotesToSections(doc, body, createElement) {
|
|
218
177
|
const footnoteGroups = [...doc.querySelectorAll('fn[fn-type]')];
|
|
219
178
|
for (const footnote of footnoteGroups) {
|
|
220
179
|
const type = footnote.getAttribute('fn-type') || '';
|
|
@@ -231,7 +190,7 @@ exports.jatsBodyTransformations = {
|
|
|
231
190
|
section.append(...footnote.children);
|
|
232
191
|
removeNodeFromParent(footnote);
|
|
233
192
|
section.setAttribute('sec-type', (0, transformer_1.chooseSecType)(category));
|
|
234
|
-
|
|
193
|
+
body.append(section);
|
|
235
194
|
}
|
|
236
195
|
}
|
|
237
196
|
const footnotes = [...doc.querySelectorAll('fn')];
|
|
@@ -246,7 +205,7 @@ exports.jatsBodyTransformations = {
|
|
|
246
205
|
}
|
|
247
206
|
if (!footnotesSection && containingGroup.innerHTML) {
|
|
248
207
|
const section = this.createFootnotes([containingGroup], createElement);
|
|
249
|
-
|
|
208
|
+
body.append(section);
|
|
250
209
|
}
|
|
251
210
|
let regularFootnoteGroups = [
|
|
252
211
|
...doc.querySelectorAll('back > fn-group:not([fn-type])'),
|
|
@@ -259,7 +218,7 @@ exports.jatsBodyTransformations = {
|
|
|
259
218
|
if (regularFootnoteGroups.length > 0) {
|
|
260
219
|
regularFootnoteGroups.map((g) => removeNodeFromParent(g));
|
|
261
220
|
const footnotes = this.createFootnotes(regularFootnoteGroups, createElement);
|
|
262
|
-
|
|
221
|
+
body.appendChild(footnotes);
|
|
263
222
|
}
|
|
264
223
|
},
|
|
265
224
|
moveCaptionsToEnd(body) {
|
|
@@ -116,6 +116,7 @@ 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);
|
|
119
120
|
jats_body_transformations_1.jatsBodyTransformations.moveSectionsToBody(document, body, bibliographyItems, createElement);
|
|
120
121
|
jats_body_transformations_1.jatsBodyTransformations.moveCaptionsToEnd(body);
|
|
121
122
|
jats_body_transformations_1.jatsBodyTransformations.moveTableFooterToEnd(body);
|
|
@@ -136,10 +136,8 @@ class JATSExporter {
|
|
|
136
136
|
article.appendChild(body);
|
|
137
137
|
const back = this.buildBack(body);
|
|
138
138
|
article.appendChild(back);
|
|
139
|
-
this.unwrapBody(body);
|
|
140
139
|
this.moveAbstracts(front, body);
|
|
141
140
|
this.moveFloatsGroup(body, article);
|
|
142
|
-
this.removeBackContainer(body);
|
|
143
141
|
}
|
|
144
142
|
await this.rewriteIDs(idGenerator);
|
|
145
143
|
if (mediaPathGenerator) {
|
|
@@ -1394,49 +1392,21 @@ class JATSExporter {
|
|
|
1394
1392
|
table.insertBefore(tfoot, tbody);
|
|
1395
1393
|
}
|
|
1396
1394
|
};
|
|
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));
|
|
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
1395
|
this.moveAbstracts = (front, body) => {
|
|
1420
|
-
const
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
if (!sectionTitle) {
|
|
1435
|
-
return false;
|
|
1436
|
-
}
|
|
1437
|
-
return sectionTitle.textContent === 'Abstract';
|
|
1438
|
-
});
|
|
1439
|
-
}
|
|
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';
|
|
1409
|
+
});
|
|
1440
1410
|
if (abstractSections.length) {
|
|
1441
1411
|
for (const abstractSection of abstractSections) {
|
|
1442
1412
|
const abstractNode = this.document.createElement('abstract');
|
|
@@ -1457,9 +1427,6 @@ class JATSExporter {
|
|
|
1457
1427
|
}
|
|
1458
1428
|
}
|
|
1459
1429
|
}
|
|
1460
|
-
if (container) {
|
|
1461
|
-
body.removeChild(container);
|
|
1462
|
-
}
|
|
1463
1430
|
};
|
|
1464
1431
|
this.moveSectionsToBack = (back, body) => {
|
|
1465
1432
|
const availabilitySection = body.querySelector('sec[sec-type="availability"]');
|
package/dist/cjs/lib/utils.js
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
* limitations under the License.
|
|
16
16
|
*/
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
-
exports.findParentNodeClosestToPos = exports.isInGraphicalAbstractSection = exports.findNodePositions = exports.iterateChildren = void 0;
|
|
18
|
+
exports.findParentNodeClosestToPos = exports.isInBibliographySection = exports.isInGraphicalAbstractSection = exports.findNodePositions = exports.iterateChildren = void 0;
|
|
19
|
+
const bibliography_section_1 = require("../schema/nodes/bibliography_section");
|
|
19
20
|
const graphical_abstract_section_1 = require("../schema/nodes/graphical_abstract_section");
|
|
20
21
|
function* iterateChildren(node, recurse = false) {
|
|
21
22
|
for (let i = 0; i < node.childCount; i++) {
|
|
@@ -50,6 +51,16 @@ const isInGraphicalAbstractSection = ($pos) => {
|
|
|
50
51
|
return false;
|
|
51
52
|
};
|
|
52
53
|
exports.isInGraphicalAbstractSection = isInGraphicalAbstractSection;
|
|
54
|
+
const isInBibliographySection = ($pos) => {
|
|
55
|
+
for (let i = $pos.depth; i > 0; i--) {
|
|
56
|
+
const node = $pos.node(i);
|
|
57
|
+
if ((0, bibliography_section_1.isBibliographySectionNode)(node)) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
};
|
|
63
|
+
exports.isInBibliographySection = isInBibliographySection;
|
|
53
64
|
const findParentNodeClosestToPos = ($pos, predicate) => {
|
|
54
65
|
for (let i = $pos.depth; i > 0; i--) {
|
|
55
66
|
const node = $pos.node(i);
|
|
@@ -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)*
|
|
38
|
+
content: 'section_label? section_title (paragraph | element)* section*',
|
|
39
39
|
attrs: {
|
|
40
40
|
id: { default: '' },
|
|
41
41
|
category: { default: '' },
|
|
@@ -162,15 +162,6 @@ 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
|
-
};
|
|
174
165
|
const attributeOfNodeType = (node, type, attribute) => {
|
|
175
166
|
for (const child of (0, utils_1.iterateChildren)(node)) {
|
|
176
167
|
if (child.type.name === type) {
|
|
@@ -458,7 +449,9 @@ const encoders = {
|
|
|
458
449
|
label: inlineContentsOfNodeType(node, node.type.schema.nodes.section_label) ||
|
|
459
450
|
undefined,
|
|
460
451
|
path: path.concat([node.attrs.id]),
|
|
461
|
-
elementIDs:
|
|
452
|
+
elementIDs: childElements(node)
|
|
453
|
+
.map((childNode) => childNode.attrs.id)
|
|
454
|
+
.filter((id) => id),
|
|
462
455
|
titleSuppressed: node.attrs.titleSuppressed || undefined,
|
|
463
456
|
generatedLabel: node.attrs.generatedLabel || undefined,
|
|
464
457
|
pageBreakStyle: node.attrs.pageBreakStyle || undefined,
|
|
@@ -14,12 +14,8 @@
|
|
|
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
|
-
};
|
|
20
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.chooseSectionCategoryFromTitle = exports.chooseSectionCategory = exports.chooseSectionCategoryByType = exports.chooseSecType = exports.buildSectionCategory = exports.guessSectionCategory = exports.chooseSectionLableName = exports.chooseSectionNodeType = exports.isAnySectionNode =
|
|
22
|
-
const section_categories_json_1 = __importDefault(require("@manuscripts/data/dist/shared/section-categories.json"));
|
|
18
|
+
exports.chooseSectionCategoryFromTitle = exports.chooseSectionCategory = exports.chooseSectionCategoryByType = exports.chooseSecType = exports.buildSectionCategory = exports.guessSectionCategory = exports.chooseSectionLableName = exports.chooseSectionNodeType = exports.isAnySectionNode = void 0;
|
|
23
19
|
const json_schema_1 = require("@manuscripts/json-schema");
|
|
24
20
|
const schema_1 = require("../schema");
|
|
25
21
|
const sectionNodeTypes = [
|
|
@@ -29,18 +25,6 @@ const sectionNodeTypes = [
|
|
|
29
25
|
schema_1.schema.nodes.section,
|
|
30
26
|
schema_1.schema.nodes.toc_section,
|
|
31
27
|
];
|
|
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;
|
|
44
28
|
const isAnySectionNode = (node) => sectionNodeTypes.includes(node.type);
|
|
45
29
|
exports.isAnySectionNode = isAnySectionNode;
|
|
46
30
|
const chooseSectionNodeType = (category) => {
|
|
@@ -177,12 +161,6 @@ const chooseSectionCategoryByType = (secType) => {
|
|
|
177
161
|
return 'MPSectionCategory:supported-by';
|
|
178
162
|
case 'ethics-statement':
|
|
179
163
|
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';
|
|
186
164
|
default:
|
|
187
165
|
return undefined;
|
|
188
166
|
}
|
|
@@ -13,20 +13,9 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { chooseSectionCategoryByType, chooseSecType
|
|
16
|
+
import { chooseSectionCategoryByType, chooseSecType } 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
|
-
};
|
|
30
19
|
export const jatsBodyTransformations = {
|
|
31
20
|
ensureSection(body, createElement) {
|
|
32
21
|
let section = createElement('sec');
|
|
@@ -154,64 +143,34 @@ export const jatsBodyTransformations = {
|
|
|
154
143
|
section.append(...floatsGroup.children);
|
|
155
144
|
return section;
|
|
156
145
|
},
|
|
157
|
-
|
|
146
|
+
moveSectionsToBody(doc, body, references, createElement) {
|
|
158
147
|
const abstractNodes = doc.querySelectorAll('front > article-meta > abstract');
|
|
159
|
-
|
|
148
|
+
for (const abstractNode of abstractNodes) {
|
|
160
149
|
const abstract = this.createAbstract(abstractNode, createElement);
|
|
161
150
|
removeNodeFromParent(abstractNode);
|
|
162
|
-
|
|
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) {
|
|
151
|
+
body.insertBefore(abstract, body.firstChild);
|
|
152
|
+
}
|
|
173
153
|
for (const section of doc.querySelectorAll('back > sec')) {
|
|
174
154
|
removeNodeFromParent(section);
|
|
175
|
-
|
|
155
|
+
body.appendChild(section);
|
|
176
156
|
}
|
|
177
|
-
},
|
|
178
|
-
moveAcknowledgmentsIntoContainer(doc, backmatterContainer, createElement) {
|
|
179
157
|
const ackNode = doc.querySelector('back > ack');
|
|
180
158
|
if (ackNode) {
|
|
181
159
|
const acknowledgements = this.createAcknowledgments(ackNode, createElement);
|
|
182
160
|
removeNodeFromParent(ackNode);
|
|
183
|
-
|
|
161
|
+
body.appendChild(acknowledgements);
|
|
184
162
|
}
|
|
185
|
-
},
|
|
186
|
-
moveAppendicesIntoContainer(doc, backmatterContainer, createElement) {
|
|
187
163
|
const appGroup = doc.querySelectorAll('back > app-group > app');
|
|
188
164
|
for (const app of appGroup) {
|
|
189
165
|
const appendix = this.createAppendixSection(app, createElement);
|
|
190
166
|
removeNodeFromParent(app);
|
|
191
|
-
|
|
167
|
+
body.appendChild(appendix);
|
|
192
168
|
}
|
|
193
|
-
},
|
|
194
|
-
moveBibliographyIntoContainer(doc, backmatterContainer, references, createElement) {
|
|
195
169
|
if (references) {
|
|
196
|
-
|
|
170
|
+
body.appendChild(this.createBibliography(doc, references, createElement));
|
|
197
171
|
}
|
|
198
172
|
},
|
|
199
|
-
|
|
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) {
|
|
173
|
+
mapFootnotesToSections(doc, body, createElement) {
|
|
215
174
|
const footnoteGroups = [...doc.querySelectorAll('fn[fn-type]')];
|
|
216
175
|
for (const footnote of footnoteGroups) {
|
|
217
176
|
const type = footnote.getAttribute('fn-type') || '';
|
|
@@ -228,7 +187,7 @@ export const jatsBodyTransformations = {
|
|
|
228
187
|
section.append(...footnote.children);
|
|
229
188
|
removeNodeFromParent(footnote);
|
|
230
189
|
section.setAttribute('sec-type', chooseSecType(category));
|
|
231
|
-
|
|
190
|
+
body.append(section);
|
|
232
191
|
}
|
|
233
192
|
}
|
|
234
193
|
const footnotes = [...doc.querySelectorAll('fn')];
|
|
@@ -243,7 +202,7 @@ export const jatsBodyTransformations = {
|
|
|
243
202
|
}
|
|
244
203
|
if (!footnotesSection && containingGroup.innerHTML) {
|
|
245
204
|
const section = this.createFootnotes([containingGroup], createElement);
|
|
246
|
-
|
|
205
|
+
body.append(section);
|
|
247
206
|
}
|
|
248
207
|
let regularFootnoteGroups = [
|
|
249
208
|
...doc.querySelectorAll('back > fn-group:not([fn-type])'),
|
|
@@ -256,7 +215,7 @@ export const jatsBodyTransformations = {
|
|
|
256
215
|
if (regularFootnoteGroups.length > 0) {
|
|
257
216
|
regularFootnoteGroups.map((g) => removeNodeFromParent(g));
|
|
258
217
|
const footnotes = this.createFootnotes(regularFootnoteGroups, createElement);
|
|
259
|
-
|
|
218
|
+
body.appendChild(footnotes);
|
|
260
219
|
}
|
|
261
220
|
},
|
|
262
221
|
moveCaptionsToEnd(body) {
|
|
@@ -111,6 +111,7 @@ 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);
|
|
114
115
|
jatsBodyTransformations.moveSectionsToBody(document, body, bibliographyItems, createElement);
|
|
115
116
|
jatsBodyTransformations.moveCaptionsToEnd(body);
|
|
116
117
|
jatsBodyTransformations.moveTableFooterToEnd(body);
|
|
@@ -129,10 +129,8 @@ export class JATSExporter {
|
|
|
129
129
|
article.appendChild(body);
|
|
130
130
|
const back = this.buildBack(body);
|
|
131
131
|
article.appendChild(back);
|
|
132
|
-
this.unwrapBody(body);
|
|
133
132
|
this.moveAbstracts(front, body);
|
|
134
133
|
this.moveFloatsGroup(body, article);
|
|
135
|
-
this.removeBackContainer(body);
|
|
136
134
|
}
|
|
137
135
|
await this.rewriteIDs(idGenerator);
|
|
138
136
|
if (mediaPathGenerator) {
|
|
@@ -1387,49 +1385,21 @@ export class JATSExporter {
|
|
|
1387
1385
|
table.insertBefore(tfoot, tbody);
|
|
1388
1386
|
}
|
|
1389
1387
|
};
|
|
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));
|
|
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
1388
|
this.moveAbstracts = (front, body) => {
|
|
1413
|
-
const
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
if (!sectionTitle) {
|
|
1428
|
-
return false;
|
|
1429
|
-
}
|
|
1430
|
-
return sectionTitle.textContent === 'Abstract';
|
|
1431
|
-
});
|
|
1432
|
-
}
|
|
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';
|
|
1402
|
+
});
|
|
1433
1403
|
if (abstractSections.length) {
|
|
1434
1404
|
for (const abstractSection of abstractSections) {
|
|
1435
1405
|
const abstractNode = this.document.createElement('abstract');
|
|
@@ -1450,9 +1420,6 @@ export class JATSExporter {
|
|
|
1450
1420
|
}
|
|
1451
1421
|
}
|
|
1452
1422
|
}
|
|
1453
|
-
if (container) {
|
|
1454
|
-
body.removeChild(container);
|
|
1455
|
-
}
|
|
1456
1423
|
};
|
|
1457
1424
|
this.moveSectionsToBack = (back, body) => {
|
|
1458
1425
|
const availabilitySection = body.querySelector('sec[sec-type="availability"]');
|
package/dist/es/lib/utils.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
import { isBibliographySectionNode } from '../schema/nodes/bibliography_section';
|
|
16
17
|
import { isGraphicalAbstractSectionNode } from '../schema/nodes/graphical_abstract_section';
|
|
17
18
|
export function* iterateChildren(node, recurse = false) {
|
|
18
19
|
for (let i = 0; i < node.childCount; i++) {
|
|
@@ -44,6 +45,15 @@ export const isInGraphicalAbstractSection = ($pos) => {
|
|
|
44
45
|
}
|
|
45
46
|
return false;
|
|
46
47
|
};
|
|
48
|
+
export const isInBibliographySection = ($pos) => {
|
|
49
|
+
for (let i = $pos.depth; i > 0; i--) {
|
|
50
|
+
const node = $pos.node(i);
|
|
51
|
+
if (isBibliographySectionNode(node)) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
};
|
|
47
57
|
export const findParentNodeClosestToPos = ($pos, predicate) => {
|
|
48
58
|
for (let i = $pos.depth; i > 0; i--) {
|
|
49
59
|
const node = $pos.node(i);
|
|
@@ -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)*
|
|
35
|
+
content: 'section_label? section_title (paragraph | element)* section*',
|
|
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 {
|
|
19
|
+
import { 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,15 +154,6 @@ 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
|
-
};
|
|
166
157
|
const attributeOfNodeType = (node, type, attribute) => {
|
|
167
158
|
for (const child of iterateChildren(node)) {
|
|
168
159
|
if (child.type.name === type) {
|
|
@@ -450,7 +441,9 @@ const encoders = {
|
|
|
450
441
|
label: inlineContentsOfNodeType(node, node.type.schema.nodes.section_label) ||
|
|
451
442
|
undefined,
|
|
452
443
|
path: path.concat([node.attrs.id]),
|
|
453
|
-
elementIDs:
|
|
444
|
+
elementIDs: childElements(node)
|
|
445
|
+
.map((childNode) => childNode.attrs.id)
|
|
446
|
+
.filter((id) => id),
|
|
454
447
|
titleSuppressed: node.attrs.titleSuppressed || undefined,
|
|
455
448
|
generatedLabel: node.attrs.generatedLabel || undefined,
|
|
456
449
|
pageBreakStyle: node.attrs.pageBreakStyle || undefined,
|
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import
|
|
17
|
-
import { ObjectTypes, } from '@manuscripts/json-schema';
|
|
16
|
+
import { ObjectTypes } from '@manuscripts/json-schema';
|
|
18
17
|
import { schema } from '../schema';
|
|
19
18
|
const sectionNodeTypes = [
|
|
20
19
|
schema.nodes.bibliography_section,
|
|
@@ -23,17 +22,6 @@ const sectionNodeTypes = [
|
|
|
23
22
|
schema.nodes.section,
|
|
24
23
|
schema.nodes.toc_section,
|
|
25
24
|
];
|
|
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
|
-
};
|
|
37
25
|
export const isAnySectionNode = (node) => sectionNodeTypes.includes(node.type);
|
|
38
26
|
export const chooseSectionNodeType = (category) => {
|
|
39
27
|
switch (category) {
|
|
@@ -164,12 +152,6 @@ export const chooseSectionCategoryByType = (secType) => {
|
|
|
164
152
|
return 'MPSectionCategory:supported-by';
|
|
165
153
|
case 'ethics-statement':
|
|
166
154
|
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';
|
|
173
155
|
default:
|
|
174
156
|
return undefined;
|
|
175
157
|
}
|
|
@@ -22,14 +22,8 @@ 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;
|
|
31
25
|
moveSectionsToBody(doc: Document, body: Element, references: BibliographyItem[] | null, createElement: (tagName: string) => HTMLElement): void;
|
|
32
|
-
mapFootnotesToSections(doc: Document,
|
|
26
|
+
mapFootnotesToSections(doc: Document, body: Element, createElement: (tagName: string) => HTMLElement): void;
|
|
33
27
|
moveCaptionsToEnd(body: Element): void;
|
|
34
28
|
moveTableFooterToEnd(body: Element): void;
|
|
35
29
|
moveFloatsGroupToBody(doc: Document, body: Element, createElement: (tagName: string) => HTMLElement): void;
|
|
@@ -63,8 +63,6 @@ export declare class JATSExporter {
|
|
|
63
63
|
private fixBody;
|
|
64
64
|
private changeTag;
|
|
65
65
|
private fixTable;
|
|
66
|
-
private unwrapBody;
|
|
67
|
-
private removeBackContainer;
|
|
68
66
|
private moveAbstracts;
|
|
69
67
|
private moveSectionsToBack;
|
|
70
68
|
sectionToFootnote: (section: Element, fnType: string) => HTMLElement;
|
|
@@ -18,6 +18,7 @@ import { ManuscriptEditorState, ManuscriptNode } from '../schema';
|
|
|
18
18
|
export declare function iterateChildren(node: ManuscriptNode, recurse?: boolean): Iterable<ManuscriptNode>;
|
|
19
19
|
export declare const findNodePositions: (state: ManuscriptEditorState, predicate: (node: ManuscriptNode) => boolean) => number[];
|
|
20
20
|
export declare const isInGraphicalAbstractSection: ($pos: ResolvedPos) => boolean;
|
|
21
|
+
export declare const isInBibliographySection: ($pos: ResolvedPos) => boolean;
|
|
21
22
|
export declare const findParentNodeClosestToPos: ($pos: ResolvedPos, predicate: (node: ProsemirrorNode) => boolean) => {
|
|
22
23
|
pos: number;
|
|
23
24
|
start: number;
|
|
@@ -15,10 +15,9 @@
|
|
|
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[];
|
|
19
18
|
export declare const isAnySectionNode: (node: ManuscriptNode) => boolean;
|
|
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'
|
|
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'
|
|
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';
|
|
22
21
|
export declare const chooseSectionNodeType: (category?: SectionCategory) => ManuscriptNodeType;
|
|
23
22
|
export declare const chooseSectionLableName: (type?: SecType) => string;
|
|
24
23
|
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.4",
|
|
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.1",
|
|
33
33
|
"debug": "^4.3.4",
|
|
34
34
|
"jszip": "^3.10.1",
|
|
35
35
|
"mathjax-full": "^3.2.2",
|