jats-xml 0.0.1 → 0.0.3
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/README.md +74 -1
- package/dist/cjs/cli/index.js +14 -0
- package/dist/cjs/cli/parse.js +199 -0
- package/dist/cjs/download.js +48 -0
- package/dist/cjs/index.js +8 -1
- package/dist/cjs/jats.js +87 -0
- package/dist/cjs/resolvers.js +63 -0
- package/dist/cjs/session.js +16 -0
- package/dist/cjs/types/elementTags.js +1285 -0
- package/dist/cjs/types/elements.js +2 -0
- package/dist/cjs/types/index.js +20 -0
- package/dist/cjs/{types.js → types/refType.js} +0 -1
- package/dist/cjs/types/session.js +2 -0
- package/dist/cjs/utils.js +98 -0
- package/dist/cjs/version.js +4 -0
- package/dist/esm/cli/index.js +9 -0
- package/dist/esm/cli/parse.js +192 -0
- package/dist/esm/download.js +41 -0
- package/dist/esm/index.js +2 -1
- package/dist/esm/jats.js +83 -0
- package/dist/esm/resolvers.js +56 -0
- package/dist/esm/session.js +11 -0
- package/dist/esm/types/elementTags.js +1282 -0
- package/dist/esm/types/elements.js +1 -0
- package/dist/esm/types/index.js +4 -0
- package/dist/esm/{types.js → types/refType.js} +0 -1
- package/dist/esm/types/session.js +1 -0
- package/dist/esm/utils.js +88 -0
- package/dist/esm/version.js +2 -0
- package/dist/jats.js +10425 -0
- package/dist/types/cli/index.d.ts +3 -0
- package/dist/types/cli/index.d.ts.map +1 -0
- package/dist/types/cli/parse.d.ts +3 -0
- package/dist/types/cli/parse.d.ts.map +1 -0
- package/dist/types/download.d.ts +4 -0
- package/dist/types/download.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/jats.d.ts +34 -0
- package/dist/types/jats.d.ts.map +1 -0
- package/dist/types/resolvers.d.ts +11 -0
- package/dist/types/resolvers.d.ts.map +1 -0
- package/dist/types/session.d.ts +11 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/types/elementTags.d.ts +1282 -0
- package/dist/types/types/elementTags.d.ts.map +1 -0
- package/dist/types/types/elements.d.ts +84 -0
- package/dist/types/types/elements.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +5 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/dist/types/{types.d.ts → types/refType.d.ts} +1 -0
- package/dist/types/types/refType.d.ts.map +1 -0
- package/dist/types/types/session.d.ts +3 -0
- package/dist/types/types/session.d.ts.map +1 -0
- package/dist/types/utils.d.ts +7 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/types/version.d.ts +3 -0
- package/dist/types/version.d.ts.map +1 -0
- package/package.json +16 -6
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/types.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/types.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,3 +1,76 @@
|
|
|
1
1
|
# jats-xml
|
|
2
2
|
|
|
3
|
-
Types and utilities for working with JATS XML documents.
|
|
3
|
+
Types and utilities for working with JATS XML documents in Node and Typescript.
|
|
4
|
+
|
|
5
|
+
Read and write JATS XML from node or see summries from the command line.
|
|
6
|
+
|
|
7
|
+
To use from the command line, use the `-g` to create a global install, which will provide a `jats` CLI:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
npm install -g jats-xml
|
|
11
|
+
jats -v
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## What is JATS?
|
|
15
|
+
|
|
16
|
+
JATS is a NISO standard for Journal Article Tags Schema, which is a way to define the XML structure of a scientific article semantically. This includes the `front`-matter (authors, funding, title, abstract, etc.), the `body` of the article (sections, figures, equations, tables, etc.), and `back`-matter (references, footnotes, etc.). The JATS can also contain `sub-articles`.
|
|
17
|
+
|
|
18
|
+
The standard documents are hosted by the NIH <https://jats.nlm.nih.gov/>. There are three flavours, this library currently uses in most cases the most precriptive tag set (for article authoring). Another helpful resource is <https://jats4r.org/>, which provides other examples and recomendations for JATS.
|
|
19
|
+
|
|
20
|
+
Note that most publishers do **not** provide the XML as a first class output - they should, it is an important part of open-science to have the content programatically accessible and interoperable. It is only [FAIR](https://www.go-fair.org/fair-principles/) 😉.
|
|
21
|
+
|
|
22
|
+
## From the command line
|
|
23
|
+
|
|
24
|
+
Commands available:
|
|
25
|
+
|
|
26
|
+
`download`: attempt to find the JATS file and download it locally.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
jats download https://docs.python.org/3.7 article.jats
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Note, currently this just downloads the XML, **not** the associated files.
|
|
33
|
+
|
|
34
|
+
`sumamry`: summarize the contents of the JATS, given a URL, DOI, or local file
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
jats summary https://elifesciences.org/articles/81952
|
|
38
|
+
jats summary 10.1371/journal.pclm.0000068
|
|
39
|
+
jats summary /local/article.jats
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This will provide a summary, including a list of what the JATS file contains.
|
|
43
|
+
|
|
44
|
+

|
|
45
|
+
|
|
46
|
+
## Working in Typescript
|
|
47
|
+
|
|
48
|
+
All tags are accessible as types/enums. There is also documentation from each node-type
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { Tags } from 'jats-xml';
|
|
52
|
+
|
|
53
|
+
Tags.journalId;
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Reading JATS in Node
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import 'fs' from 'fs';
|
|
60
|
+
import { Inventory, toDate } from 'jats-xml';
|
|
61
|
+
import { toText } from 'myst-common';
|
|
62
|
+
import { select, selectAll } from 'unist-util-select';
|
|
63
|
+
|
|
64
|
+
const data = fs.readFileSync('article.jats').toString();
|
|
65
|
+
const jats = new JATS(data);
|
|
66
|
+
// Easy access to properties
|
|
67
|
+
jats.doi
|
|
68
|
+
jats.body // A tree of the body (or front/back)
|
|
69
|
+
toDate(jats.publicationDate) // as a Javascript Date object
|
|
70
|
+
select('[id=fig1]', jats.body) // select a figure by an ID
|
|
71
|
+
selectAll('fig', jats.body) // Or selectAll figures
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Write JATS in Node
|
|
75
|
+
|
|
76
|
+
TODO!
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const commander_1 = __importDefault(require("commander"));
|
|
8
|
+
const version_1 = __importDefault(require("../version"));
|
|
9
|
+
const parse_1 = require("./parse");
|
|
10
|
+
const program = new commander_1.default.Command();
|
|
11
|
+
(0, parse_1.addDownloadCLI)(program);
|
|
12
|
+
program.version(`v${version_1.default}`, '-v, --version', 'Print the current version of jats-xml');
|
|
13
|
+
program.option('-d, --debug', 'Log out any errors to the console.');
|
|
14
|
+
program.parse(process.argv);
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.addDownloadCLI = void 0;
|
|
16
|
+
const commander_1 = require("commander");
|
|
17
|
+
const fs_1 = __importDefault(require("fs"));
|
|
18
|
+
const path_1 = require("path");
|
|
19
|
+
const myst_cli_utils_1 = require("myst-cli-utils");
|
|
20
|
+
const doi_utils_1 = __importDefault(require("doi-utils"));
|
|
21
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
22
|
+
const session_1 = require("../session");
|
|
23
|
+
const types_1 = require("../types");
|
|
24
|
+
const jats_1 = require("../jats");
|
|
25
|
+
const myst_common_1 = require("myst-common");
|
|
26
|
+
const unist_util_select_1 = require("unist-util-select");
|
|
27
|
+
const download_1 = require("../download");
|
|
28
|
+
const resolvers_1 = require("../resolvers");
|
|
29
|
+
const utils_1 = require("../utils");
|
|
30
|
+
function hasValidExtension(output) {
|
|
31
|
+
return ['.xml', '.jats'].includes((0, path_1.extname)(output).toLowerCase());
|
|
32
|
+
}
|
|
33
|
+
function downloadJats(session, urlOrDoi, output) {
|
|
34
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
if (fs_1.default.existsSync(urlOrDoi)) {
|
|
36
|
+
throw new Error(`File "${urlOrDoi}" is local and cannot be downloaded!`);
|
|
37
|
+
}
|
|
38
|
+
if (!(doi_utils_1.default.validate(urlOrDoi) || (0, myst_cli_utils_1.isUrl)(urlOrDoi))) {
|
|
39
|
+
throw new Error(`Path must be a URL or DOI, not "${urlOrDoi}"`);
|
|
40
|
+
}
|
|
41
|
+
if (!hasValidExtension(output)) {
|
|
42
|
+
session.log.warn(`The extension ${(0, path_1.extname)(output)} is not a valid extension for JATS, try using ".xml" or ".jats"`);
|
|
43
|
+
}
|
|
44
|
+
const data = yield (0, download_1.downloadJatsFromUrl)(session, urlOrDoi, resolvers_1.DEFAULT_RESOLVERS);
|
|
45
|
+
(0, myst_cli_utils_1.writeFileToFolder)(output, data);
|
|
46
|
+
return data;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function parseJats(session, file) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
const toc = (0, myst_cli_utils_1.tic)();
|
|
52
|
+
if (fs_1.default.existsSync(file)) {
|
|
53
|
+
session.log.debug(`Found ${file} locally, parsing`);
|
|
54
|
+
const data = fs_1.default.readFileSync(file).toString();
|
|
55
|
+
session.log.debug(toc(`Parsed JATS file from disk in %s`));
|
|
56
|
+
return new jats_1.Jats(data);
|
|
57
|
+
}
|
|
58
|
+
if (doi_utils_1.default.validate(file) || (0, myst_cli_utils_1.isUrl)(file)) {
|
|
59
|
+
const data = yield (0, download_1.downloadJatsFromUrl)(session, file, resolvers_1.DEFAULT_RESOLVERS);
|
|
60
|
+
session.log.debug(toc(`Downloaded and parsed JATS file in %s`));
|
|
61
|
+
return new jats_1.Jats(data);
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`Could not find ${file} locally, and it doesn't look like a URL or DOI`);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function formatLongString(data, offset = 0, length = 88 - offset) {
|
|
67
|
+
const out = [data.slice(0, length)];
|
|
68
|
+
let left = data.slice(length);
|
|
69
|
+
while (left.length > length) {
|
|
70
|
+
out.push(left.slice(0, length).trim());
|
|
71
|
+
left = left.slice(length);
|
|
72
|
+
}
|
|
73
|
+
if (left)
|
|
74
|
+
out.push(left.trim());
|
|
75
|
+
return out.join(`\n${' '.repeat(offset)}`);
|
|
76
|
+
}
|
|
77
|
+
function formatDictionary(dict, opts) {
|
|
78
|
+
const maxLabel = Object.keys(dict).reduce((a, b) => Math.max(a, b.length), 0);
|
|
79
|
+
return Object.entries(dict)
|
|
80
|
+
.map(([k, t]) => {
|
|
81
|
+
var _a;
|
|
82
|
+
let value = t;
|
|
83
|
+
let color = chalk_1.default.yellow.bold;
|
|
84
|
+
if (t && typeof t === 'object') {
|
|
85
|
+
if (!t.value)
|
|
86
|
+
return null;
|
|
87
|
+
color = (_a = t.label) !== null && _a !== void 0 ? _a : color;
|
|
88
|
+
value = t.value;
|
|
89
|
+
}
|
|
90
|
+
const wrapped = (opts === null || opts === void 0 ? void 0 : opts.wrap) === false
|
|
91
|
+
? String(value)
|
|
92
|
+
: formatLongString(String(value), maxLabel + 2, opts === null || opts === void 0 ? void 0 : opts.wrap);
|
|
93
|
+
return `${color(k)}:${' '.repeat(maxLabel - k.length + 1)}${wrapped}`;
|
|
94
|
+
})
|
|
95
|
+
.filter((o) => !!o)
|
|
96
|
+
.join('\n');
|
|
97
|
+
}
|
|
98
|
+
function jatsSummaryCLI(session, file) {
|
|
99
|
+
var _a, _b;
|
|
100
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
101
|
+
const jats = yield parseJats(session, file);
|
|
102
|
+
const summary = {
|
|
103
|
+
DOI: jats.doi ? doi_utils_1.default.buildUrl(jats.doi) : null,
|
|
104
|
+
Title: (_a = (0, myst_common_1.toText)(jats.articleTitle)) === null || _a === void 0 ? void 0 : _a.replace(/\n/g, ' '),
|
|
105
|
+
Date: (0, utils_1.formatDate)((0, utils_1.toDate)(jats.publicationDate)),
|
|
106
|
+
Authors: jats.articleAuthors
|
|
107
|
+
.map((a) => `${(0, myst_common_1.toText)((0, unist_util_select_1.select)(types_1.Tags.givenNames, a))} ${(0, myst_common_1.toText)((0, unist_util_select_1.select)(types_1.Tags.surname, a))}`)
|
|
108
|
+
.join(', '),
|
|
109
|
+
Abstract: (_b = (0, myst_common_1.toText)(jats.abstract)) === null || _b === void 0 ? void 0 : _b.replace(/\n/g, ' '),
|
|
110
|
+
Keywords: jats.keywords.map((k) => (0, myst_common_1.toText)(k)).join(', '),
|
|
111
|
+
License: jats.license['xlink:href'],
|
|
112
|
+
Figures: { label: chalk_1.default.blue.bold, value: String((0, unist_util_select_1.selectAll)(types_1.Tags.fig, jats.body).length) },
|
|
113
|
+
Equations: {
|
|
114
|
+
label: chalk_1.default.blue.bold,
|
|
115
|
+
value: String((0, unist_util_select_1.selectAll)(types_1.Tags.dispFormula, jats.body).length),
|
|
116
|
+
},
|
|
117
|
+
Tables: {
|
|
118
|
+
label: chalk_1.default.blue.bold,
|
|
119
|
+
value: String((0, unist_util_select_1.selectAll)(types_1.Tags.table, jats.body).length),
|
|
120
|
+
},
|
|
121
|
+
Code: {
|
|
122
|
+
label: chalk_1.default.blue.bold,
|
|
123
|
+
value: String((0, unist_util_select_1.selectAll)(types_1.Tags.code, jats.body).length),
|
|
124
|
+
},
|
|
125
|
+
Sections: {
|
|
126
|
+
label: chalk_1.default.blue.bold,
|
|
127
|
+
value: String((0, unist_util_select_1.selectAll)(types_1.Tags.sec, jats.body).length),
|
|
128
|
+
},
|
|
129
|
+
Paragraphs: {
|
|
130
|
+
label: chalk_1.default.blue.bold,
|
|
131
|
+
value: String((0, unist_util_select_1.selectAll)(types_1.Tags.p, jats.body).length),
|
|
132
|
+
},
|
|
133
|
+
Citations: { label: chalk_1.default.blue.bold, value: String(jats.references.length) },
|
|
134
|
+
'Cross-References': {
|
|
135
|
+
label: chalk_1.default.blue.bold,
|
|
136
|
+
value: String((0, unist_util_select_1.selectAll)(types_1.Tags.xref, jats.body).length),
|
|
137
|
+
},
|
|
138
|
+
'Sub Articles': { label: chalk_1.default.blue.bold, value: String(jats.subArticles.length) },
|
|
139
|
+
};
|
|
140
|
+
session.log.info(formatDictionary(summary));
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
function jatsReferencesCLI(session, file) {
|
|
144
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
145
|
+
const jats = yield parseJats(session, file);
|
|
146
|
+
const sorted = jats.references
|
|
147
|
+
.map((ref) => {
|
|
148
|
+
const doi = (0, utils_1.findDoi)(ref);
|
|
149
|
+
const title = (0, myst_common_1.toText)((0, unist_util_select_1.select)(types_1.Tags.articleTitle, ref));
|
|
150
|
+
const year = (0, myst_common_1.toText)((0, unist_util_select_1.select)(types_1.Tags.year, ref));
|
|
151
|
+
const surnames = (0, unist_util_select_1.selectAll)(types_1.Tags.surname, ref);
|
|
152
|
+
const short = surnames.length > 2
|
|
153
|
+
? (0, myst_common_1.toText)(surnames[0]) + ' et al.'
|
|
154
|
+
: surnames.length === 2
|
|
155
|
+
? (0, myst_common_1.toText)(surnames[0]) + ' and ' + (0, myst_common_1.toText)(surnames[1])
|
|
156
|
+
: (0, myst_common_1.toText)(surnames[0]);
|
|
157
|
+
const s = (0, unist_util_select_1.selectAll)(`[rid=${ref.id}]`, jats.body);
|
|
158
|
+
return {
|
|
159
|
+
Citation: `${short} (${year})`,
|
|
160
|
+
Title: title,
|
|
161
|
+
DOI: doi ? doi_utils_1.default.buildUrl(doi) : null,
|
|
162
|
+
Count: s.length,
|
|
163
|
+
};
|
|
164
|
+
})
|
|
165
|
+
.sort((a, b) => b.Count - a.Count);
|
|
166
|
+
sorted.forEach((r) => {
|
|
167
|
+
session.log.info(formatDictionary(r, { wrap: false }) + '\n');
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function makeSummaryCLI(program) {
|
|
172
|
+
const command = new commander_1.Command('summary')
|
|
173
|
+
.description('Parse a JATS file and provide a summary')
|
|
174
|
+
.argument('<jats>', 'The JATS file or remote URL to be parsed')
|
|
175
|
+
.action((0, myst_cli_utils_1.clirun)(jatsSummaryCLI, { program, getSession: session_1.getSession }));
|
|
176
|
+
return command;
|
|
177
|
+
}
|
|
178
|
+
function makeReferencesCLI(program) {
|
|
179
|
+
const command = new commander_1.Command('refs')
|
|
180
|
+
.alias('references')
|
|
181
|
+
.description('Parse a JATS file and provide a summary')
|
|
182
|
+
.argument('<jats>', 'The JATS file or remote URL to be parsed')
|
|
183
|
+
.action((0, myst_cli_utils_1.clirun)(jatsReferencesCLI, { program, getSession: session_1.getSession }));
|
|
184
|
+
return command;
|
|
185
|
+
}
|
|
186
|
+
function makeDownloadCLI(program) {
|
|
187
|
+
const command = new commander_1.Command('download')
|
|
188
|
+
.description('Parse a JATS file and provide a summary')
|
|
189
|
+
.argument('<url>', 'The JATS url or a DOI')
|
|
190
|
+
.argument('<output>', 'The JATS url or a DOI')
|
|
191
|
+
.action((0, myst_cli_utils_1.clirun)(downloadJats, { program, getSession: session_1.getSession }));
|
|
192
|
+
return command;
|
|
193
|
+
}
|
|
194
|
+
function addDownloadCLI(program) {
|
|
195
|
+
program.addCommand(makeDownloadCLI(program));
|
|
196
|
+
program.addCommand(makeSummaryCLI(program));
|
|
197
|
+
program.addCommand(makeReferencesCLI(program));
|
|
198
|
+
}
|
|
199
|
+
exports.addDownloadCLI = addDownloadCLI;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.downloadJatsFromUrl = void 0;
|
|
16
|
+
const doi_utils_1 = __importDefault(require("doi-utils"));
|
|
17
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
18
|
+
const myst_cli_utils_1 = require("myst-cli-utils");
|
|
19
|
+
const resolvers_1 = require("./resolvers");
|
|
20
|
+
function dowloadFromUrl(session, jatsUrl) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
session.log.debug(`Fetching JATS from ${jatsUrl}`);
|
|
23
|
+
const jatsResp = yield (0, node_fetch_1.default)(jatsUrl);
|
|
24
|
+
if (!jatsResp.ok)
|
|
25
|
+
throw new Error(`Problem fetching JATS from ${jatsUrl}`);
|
|
26
|
+
const contentType = jatsResp.headers.get('content-type');
|
|
27
|
+
if (!(contentType === 'application/xml' || (contentType === null || contentType === void 0 ? void 0 : contentType.includes('text/plain')))) {
|
|
28
|
+
throw new Error(`Expected content-type "application/xml" instead we got ${contentType} for ${jatsUrl}`);
|
|
29
|
+
}
|
|
30
|
+
const data = yield jatsResp.text();
|
|
31
|
+
return data;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
function downloadJatsFromUrl(session, urlOrDoi, resolvers) {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
if (doi_utils_1.default.validate(urlOrDoi)) {
|
|
37
|
+
const jatsUrl = yield (0, resolvers_1.resolveJatsUrlFromDoi)(session, urlOrDoi, resolvers);
|
|
38
|
+
const data = yield dowloadFromUrl(session, jatsUrl);
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
if ((0, myst_cli_utils_1.isUrl)(urlOrDoi)) {
|
|
42
|
+
const data = yield dowloadFromUrl(session, urlOrDoi);
|
|
43
|
+
return data;
|
|
44
|
+
}
|
|
45
|
+
throw new Error(`Could not find ${urlOrDoi} locally, and it doesn't look like a URL or DOI`);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
exports.downloadJatsFromUrl = downloadJatsFromUrl;
|
package/dist/cjs/index.js
CHANGED
|
@@ -13,6 +13,13 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
|
13
13
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
17
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
18
|
+
};
|
|
16
19
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.Jats = exports.version = void 0;
|
|
21
|
+
var version_1 = require("./version");
|
|
22
|
+
Object.defineProperty(exports, "version", { enumerable: true, get: function () { return __importDefault(version_1).default; } });
|
|
23
|
+
var jats_1 = require("./jats");
|
|
24
|
+
Object.defineProperty(exports, "Jats", { enumerable: true, get: function () { return jats_1.Jats; } });
|
|
17
25
|
__exportStar(require("./types"), exports);
|
|
18
|
-
//# sourceMappingURL=index.js.map
|
package/dist/cjs/jats.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Jats = void 0;
|
|
4
|
+
const xml_js_1 = require("xml-js");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
const unist_util_select_1 = require("unist-util-select");
|
|
7
|
+
const types_1 = require("./types");
|
|
8
|
+
class Jats {
|
|
9
|
+
constructor(data) {
|
|
10
|
+
this.raw = (0, xml_js_1.xml2js)(data, { compact: false });
|
|
11
|
+
const { declaration, elements } = this.raw;
|
|
12
|
+
this.declaration = declaration === null || declaration === void 0 ? void 0 : declaration.attributes;
|
|
13
|
+
if (!((elements === null || elements === void 0 ? void 0 : elements.length) === 2 && elements[0].type === 'doctype' && elements[1].name === 'article')) {
|
|
14
|
+
throw new Error('article is not the only element of the JATS');
|
|
15
|
+
}
|
|
16
|
+
this.doctype = elements[0].doctype;
|
|
17
|
+
this.tree = (0, utils_1.convertToUnist)(elements[1]);
|
|
18
|
+
}
|
|
19
|
+
get front() {
|
|
20
|
+
return (0, unist_util_select_1.select)(types_1.Tags.front, this.tree);
|
|
21
|
+
}
|
|
22
|
+
get premissions() {
|
|
23
|
+
return (0, unist_util_select_1.select)(types_1.Tags.permissions, this.front);
|
|
24
|
+
}
|
|
25
|
+
get doi() {
|
|
26
|
+
return (0, utils_1.findDoi)(this.front);
|
|
27
|
+
}
|
|
28
|
+
get publicationDates() {
|
|
29
|
+
return (0, unist_util_select_1.selectAll)(types_1.Tags.pubDate, this.front);
|
|
30
|
+
}
|
|
31
|
+
get publicationDate() {
|
|
32
|
+
return this.publicationDates.find((d) => !!(0, unist_util_select_1.select)(types_1.Tags.day, d));
|
|
33
|
+
}
|
|
34
|
+
get license() {
|
|
35
|
+
return (0, unist_util_select_1.select)(types_1.Tags.license, this.premissions);
|
|
36
|
+
}
|
|
37
|
+
get keywordGroup() {
|
|
38
|
+
return (0, unist_util_select_1.select)(types_1.Tags.kwdGroup, this.front);
|
|
39
|
+
}
|
|
40
|
+
/** The first keywords */
|
|
41
|
+
get keywords() {
|
|
42
|
+
return (0, unist_util_select_1.selectAll)(types_1.Tags.kwd, this.keywordGroup);
|
|
43
|
+
}
|
|
44
|
+
get keywordGroups() {
|
|
45
|
+
return (0, unist_util_select_1.selectAll)(types_1.Tags.kwdGroup, this.front);
|
|
46
|
+
}
|
|
47
|
+
get titleGroup() {
|
|
48
|
+
return (0, unist_util_select_1.select)(types_1.Tags.titleGroup, this.front);
|
|
49
|
+
}
|
|
50
|
+
get articleTitle() {
|
|
51
|
+
return (0, unist_util_select_1.select)(types_1.Tags.articleTitle, this.titleGroup);
|
|
52
|
+
}
|
|
53
|
+
get articleSubtitle() {
|
|
54
|
+
return (0, unist_util_select_1.select)(types_1.Tags.subtitle, this.titleGroup);
|
|
55
|
+
}
|
|
56
|
+
get abstract() {
|
|
57
|
+
return (0, unist_util_select_1.select)(types_1.Tags.abstract, this.front);
|
|
58
|
+
}
|
|
59
|
+
get abstracts() {
|
|
60
|
+
return (0, unist_util_select_1.selectAll)(types_1.Tags.abstract, this.front);
|
|
61
|
+
}
|
|
62
|
+
get contribGroup() {
|
|
63
|
+
return (0, unist_util_select_1.select)(types_1.Tags.contribGroup, this.front);
|
|
64
|
+
}
|
|
65
|
+
get contribGroups() {
|
|
66
|
+
return (0, unist_util_select_1.selectAll)(types_1.Tags.contribGroup, this.front);
|
|
67
|
+
}
|
|
68
|
+
get articleAuthors() {
|
|
69
|
+
return (0, unist_util_select_1.selectAll)(types_1.Tags.contrib, this.contribGroup);
|
|
70
|
+
}
|
|
71
|
+
get body() {
|
|
72
|
+
return (0, unist_util_select_1.select)(types_1.Tags.body, this.tree);
|
|
73
|
+
}
|
|
74
|
+
get back() {
|
|
75
|
+
return (0, unist_util_select_1.select)(types_1.Tags.back, this.tree);
|
|
76
|
+
}
|
|
77
|
+
get subArticles() {
|
|
78
|
+
return (0, unist_util_select_1.selectAll)(types_1.Tags.subArticle, this.tree);
|
|
79
|
+
}
|
|
80
|
+
get refList() {
|
|
81
|
+
return (0, unist_util_select_1.select)(types_1.Tags.refList, this.back);
|
|
82
|
+
}
|
|
83
|
+
get references() {
|
|
84
|
+
return (0, unist_util_select_1.selectAll)(types_1.Tags.ref, this.refList);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
exports.Jats = Jats;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.resolveJatsUrlFromDoi = exports.DEFAULT_RESOLVERS = exports.joss = exports.plos = exports.elife = void 0;
|
|
16
|
+
const doi_utils_1 = __importDefault(require("doi-utils"));
|
|
17
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
18
|
+
exports.elife = {
|
|
19
|
+
test(url) {
|
|
20
|
+
return new URL(url).hostname === 'elifesciences.org';
|
|
21
|
+
},
|
|
22
|
+
jatsUrl(url) {
|
|
23
|
+
return `${url}.xml`;
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
exports.plos = {
|
|
27
|
+
test(url) {
|
|
28
|
+
return new URL(url).hostname === 'journals.plos.org';
|
|
29
|
+
},
|
|
30
|
+
jatsUrl(url) {
|
|
31
|
+
return url.replace('/article?', '/article/file?') + '&type=manuscript';
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
exports.joss = {
|
|
35
|
+
test(url) {
|
|
36
|
+
return new URL(url).hostname === 'joss.theoj.org';
|
|
37
|
+
},
|
|
38
|
+
jatsUrl(url) {
|
|
39
|
+
// Probably a better way to do this, the joss papers on on github!
|
|
40
|
+
const doi = new URL(url).pathname.replace('/papers/', '');
|
|
41
|
+
const [org, jossId] = doi.split('/');
|
|
42
|
+
const id = jossId.split('.')[1];
|
|
43
|
+
return `https://raw.githubusercontent.com/openjournals/joss-papers/master/joss.${id}/${org}.${jossId}.jats`;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
exports.DEFAULT_RESOLVERS = [exports.elife, exports.plos, exports.joss];
|
|
47
|
+
function resolveJatsUrlFromDoi(session, doi, resolvers = exports.DEFAULT_RESOLVERS) {
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
if (!doi_utils_1.default.validate(doi))
|
|
50
|
+
throw new Error(`The doi ${doi} is not valid`);
|
|
51
|
+
const doiUrl = doi_utils_1.default.buildUrl(doi);
|
|
52
|
+
session.log.debug(`Resolving DOI ${doiUrl}`);
|
|
53
|
+
const resp = yield (0, node_fetch_1.default)(doiUrl);
|
|
54
|
+
const articleUrl = resp.url;
|
|
55
|
+
session.log.debug(`Found resolved URL for DOI at ${articleUrl}`);
|
|
56
|
+
const resolver = resolvers.find((r) => r.test(articleUrl));
|
|
57
|
+
if (!resolver)
|
|
58
|
+
throw new Error(`Could not resolve JATS for ${articleUrl}, no resolver matched`);
|
|
59
|
+
const jatsUrl = resolver.jatsUrl(articleUrl);
|
|
60
|
+
return jatsUrl;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
exports.resolveJatsUrlFromDoi = resolveJatsUrlFromDoi;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSession = exports.Session = void 0;
|
|
4
|
+
const myst_cli_utils_1 = require("myst-cli-utils");
|
|
5
|
+
class Session {
|
|
6
|
+
constructor(opts) {
|
|
7
|
+
var _a;
|
|
8
|
+
this.API_URL = 'https://api.myst.tools';
|
|
9
|
+
this.log = (_a = opts === null || opts === void 0 ? void 0 : opts.logger) !== null && _a !== void 0 ? _a : (0, myst_cli_utils_1.chalkLogger)(myst_cli_utils_1.LogLevel.debug);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.Session = Session;
|
|
13
|
+
function getSession(logger) {
|
|
14
|
+
return new Session({ logger });
|
|
15
|
+
}
|
|
16
|
+
exports.getSession = getSession;
|