jats-xml 1.0.8 → 1.0.10

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 CHANGED
@@ -6,15 +6,6 @@
6
6
 
7
7
  Types and utilities for working with JATS XML documents in Node and Typescript.
8
8
 
9
- Read and write JATS XML from node or see summries from the command line.
10
-
11
- To use from the command line, use the `-g` to create a global install, which will provide a `jats` CLI:
12
-
13
- ```
14
- npm install -g jats-xml
15
- jats -v
16
- ```
17
-
18
9
  ## What is JATS?
19
10
 
20
11
  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`.
@@ -23,58 +14,6 @@ The standard documents are hosted by the NIH <https://jats.nlm.nih.gov/>. There
23
14
 
24
15
  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/) 😉.
25
16
 
26
- ## From the command line
27
-
28
- Commands available:
29
-
30
- `download`: attempt to find the JATS file and download it locally.
31
-
32
- ```bash
33
- jats download https://elifesciences.org/articles/81952 article.jats
34
- ```
35
-
36
- Note, currently this just downloads the XML, **not** the associated files.
37
-
38
- `summary`: summarize the contents of the JATS, given a URL, DOI, or local file
39
-
40
- ```bash
41
- jats summary https://elifesciences.org/articles/81952
42
- jats summary 10.1371/journal.pclm.0000068
43
- jats summary /local/article.jats
44
- ```
45
-
46
- This will provide a summary, including a list of what the JATS file contains.
47
-
48
- ![Output of `jats summary`](/images/jats-output.png)
49
-
50
- `validate`: validate local file against JATS Archive DTD schema. By default, this uses JATS 1.3.
51
-
52
- ```bash
53
- jats validate article.jats --jats 1.2 --mathmml 2
54
- ```
55
-
56
- `test`: test a JATS file against a list of unit tests in YAML
57
-
58
- The test cases are useful for known exports and expecting specific pieces of information in the XML.
59
-
60
- ```bash
61
- jats test article.jats --cases tests.yml
62
- ```
63
-
64
- ```yaml
65
- cases:
66
- - title: Correct publisher ID (publisher-id)
67
- select: 'front > journal-meta > journal-id[journal-id-type="publisher-id"] > *'
68
- equals:
69
- type: text
70
- value: plos
71
- - title: Every orcid is authenticated
72
- selectAll: 'front > article-meta > contrib-group > contrib > contrib-id'
73
- equals:
74
- contrib-id-type: orcid
75
- authenticated: 'true'
76
- ```
77
-
78
17
  ## Working in Typescript
79
18
 
80
19
  All tags are accessible as types/enums. There is also documentation from each node-type
@@ -116,6 +55,6 @@ As of v1.0.0 this package is [ESM only](https://gist.github.com/sindresorhus/a39
116
55
  <p style="text-align: center; color: #aaa; padding-top: 50px">
117
56
  Made with love by
118
57
  <a href="https://curvenote.com" target="_blank" style="color: #aaa">
119
- <img src="https://curvenote.dev/images/icon.png" style="height: 1em" /> Curvenote
58
+ <img src="https://cdn.curvenote.com/brand/logo-blue-icon.png" style="height: 1em" /> Curvenote
120
59
  </a>
121
60
  </p>
package/dist/index.d.ts CHANGED
@@ -2,5 +2,6 @@ export { default as version } from './version.js';
2
2
  export { Jats } from './jats.js';
3
3
  export * from './session.js';
4
4
  export * from './types.js';
5
+ export * from './utils.js';
5
6
  export * from './validate/index.js';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -2,4 +2,5 @@ export { default as version } from './version.js';
2
2
  export { Jats } from './jats.js';
3
3
  export * from './session.js';
4
4
  export * from './types.js';
5
+ export * from './utils.js';
5
6
  export * from './validate/index.js';
package/dist/jats.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { GenericParent } from 'myst-common';
2
2
  import type { Element, DeclarationAttributes } from 'xml-js';
3
- import type { PageFrontmatter } from 'myst-frontmatter';
4
- import type { Front, Body, Back, SubArticle, RefList, Reference, TitleGroup, ArticleTitle, Subtitle, Permissions, PubDate, License, Abstract, ContribGroup, Contrib, KeywordGroup, Keyword, ArticleCategories, ArticleMeta } from 'jats-tags';
3
+ import { type PageFrontmatter } from 'myst-frontmatter';
4
+ import type { Front, Body, Back, SubArticle, RefList, Reference, TitleGroup, ArticleTitle, Subtitle, Permissions, PubDate, License, Abstract, ContribGroup, Contrib, Affiliation, KeywordGroup, Keyword, ArticleCategories, ArticleMeta } from 'jats-tags';
5
5
  import type { Logger } from 'myst-cli-utils';
6
6
  import { type SerializationOptions } from 'jats-utils';
7
7
  type Options = {
@@ -43,6 +43,7 @@ export declare class Jats {
43
43
  get contribGroup(): ContribGroup | undefined;
44
44
  get contribGroups(): ContribGroup[];
45
45
  get articleAuthors(): Contrib[];
46
+ get articleAffiliations(): Affiliation[];
46
47
  get body(): Body | undefined;
47
48
  get back(): Back | undefined;
48
49
  get subArticles(): SubArticle[];
@@ -1 +1 @@
1
- {"version":3,"file":"jats.d.ts","sourceRoot":"","sources":["../src/jats.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jats.d.ts","sourceRoot":"","sources":["../src/jats.ts"],"names":[],"mappings":"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"}
package/dist/jats.js CHANGED
@@ -1,11 +1,12 @@
1
1
  import { toText } from 'myst-common';
2
2
  import { xml2js } from 'xml-js';
3
3
  import { doi } from 'doi-utils';
4
+ import { validatePageFrontmatter } from 'myst-frontmatter';
4
5
  import { select as unistSelect, selectAll } from 'unist-util-select';
5
6
  import { Tags } from 'jats-tags';
6
- import { authorAndAffiliation, findArticleId } from './utils.js';
7
+ import { findArticleId, processAffiliation, processContributor } from './utils.js';
7
8
  import { tic } from 'myst-cli-utils';
8
- import { articleMetaOrder } from './order.js';
9
+ import { articleMetaOrder, tableWrapOrder } from './order.js';
9
10
  import { serializeJatsXml, convertToUnist, convertToXml, toDate, } from 'jats-utils';
10
11
  function select(selector, node) {
11
12
  var _a;
@@ -14,7 +15,7 @@ function select(selector, node) {
14
15
  const DEFAULT_DOCTYPE = 'article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD with MathML3 v1.3 20210610//EN" "http://jats.nlm.nih.gov/publishing/1.3/JATS-archivearticle1-3-mathml3.dtd"';
15
16
  export class Jats {
16
17
  constructor(data, opts) {
17
- var _a;
18
+ var _a, _b;
18
19
  const toc = tic();
19
20
  this.log = opts === null || opts === void 0 ? void 0 : opts.log;
20
21
  if (opts === null || opts === void 0 ? void 0 : opts.source)
@@ -27,34 +28,85 @@ export class Jats {
27
28
  }
28
29
  const { declaration, elements } = this.raw;
29
30
  this.declaration = declaration === null || declaration === void 0 ? void 0 : declaration.attributes;
31
+ if ((elements === null || elements === void 0 ? void 0 : elements.length) && elements[0].type !== 'doctype') {
32
+ (_a = this.log) === null || _a === void 0 ? void 0 : _a.warn('JATS is missing DOCTYPE declaration');
33
+ elements.unshift({ type: 'doctype' });
34
+ }
30
35
  if (!((elements === null || elements === void 0 ? void 0 : elements.length) === 2 && elements[0].type === 'doctype' && hasSingleArticle(elements[1]))) {
31
- throw new Error('Element <article> is not the only element of the JATS');
36
+ throw new Error('JATS must be structured as <!DOCTYPE><article>...</article>');
32
37
  }
33
38
  this.doctype = elements[0].doctype;
34
39
  const converted = convertToUnist(elements[1]);
35
40
  this.tree = select('article', converted);
36
- (_a = this.log) === null || _a === void 0 ? void 0 : _a.debug(toc('Parsed and converted JATS to unist tree in %s'));
41
+ (_b = this.log) === null || _b === void 0 ? void 0 : _b.debug(toc('Parsed and converted JATS to unist tree in %s'));
37
42
  }
38
43
  get frontmatter() {
39
- var _a, _b, _c, _d;
44
+ var _a, _b, _c, _d, _e, _f, _g, _h;
40
45
  const title = this.articleTitle;
41
46
  const subtitle = this.articleSubtitle;
42
47
  const short_title = this.articleAltTitle;
43
- const date = this.publicationDate;
44
- const authors = this.articleAuthors;
45
- const firstSubject = select(Tags.subject, (_a = this.articleCategories) !== null && _a !== void 0 ? _a : this.front);
48
+ let date;
49
+ if (this.publicationDate) {
50
+ const pubDate = toDate(this.publicationDate);
51
+ if (pubDate) {
52
+ const year = pubDate.getFullYear();
53
+ const month = (pubDate.getMonth() + 1).toString().padStart(2, '0');
54
+ const day = pubDate.getDate().toString().padStart(2, '0');
55
+ date = `${year}-${month}-${day}`;
56
+ }
57
+ }
58
+ const authors = (_a = this.articleAuthors) === null || _a === void 0 ? void 0 : _a.map((auth) => {
59
+ return processContributor(auth);
60
+ });
61
+ const affiliations = (_b = this.articleAffiliations) === null || _b === void 0 ? void 0 : _b.map((aff) => {
62
+ return processAffiliation(aff);
63
+ });
64
+ const keywords = (_d = (_c = this.keywords) === null || _c === void 0 ? void 0 : _c.map((k) => toText(k))) !== null && _d !== void 0 ? _d : [];
65
+ const firstSubject = select(Tags.subject, (_e = this.articleCategories) !== null && _e !== void 0 ? _e : this.front);
46
66
  const journalTitle = select(Tags.journalTitle, this.front);
47
- return {
67
+ const license = this.license;
68
+ let licenseString = null;
69
+ if (license === null || license === void 0 ? void 0 : license['xlink:href']) {
70
+ licenseString = license['xlink:href'];
71
+ }
72
+ else if (select('[type=ali:license_ref]', license)) {
73
+ licenseString = toText(select('[type=ali:license_ref]', license));
74
+ }
75
+ else if (selectAll('ext-link', license).length === 1) {
76
+ // this should only happen if there is only one ext-link
77
+ licenseString = (_f = select('ext-link', license)['xlink:href']) !== null && _f !== void 0 ? _f : null;
78
+ }
79
+ else if (license) {
80
+ licenseString = toText(license);
81
+ }
82
+ let openAccess;
83
+ const licenseType = (_g = license === null || license === void 0 ? void 0 : license['license-type']) === null || _g === void 0 ? void 0 : _g.toLowerCase();
84
+ if (licenseType && ['openaccess', 'open-access'].includes(licenseType)) {
85
+ openAccess = true;
86
+ }
87
+ else if (licenseString === null || licenseString === void 0 ? void 0 : licenseString.match(/^\s*Open Access\s*This/)) {
88
+ licenseString = licenseString.replace(/^\s*Open Access\s*/, '');
89
+ openAccess = true;
90
+ }
91
+ else if (licenseString === null || licenseString === void 0 ? void 0 : licenseString.toLowerCase().startsWith('this is an open access article')) {
92
+ openAccess = true;
93
+ }
94
+ const frontmatter = validatePageFrontmatter({
48
95
  title: title ? toText(title) : undefined,
49
96
  subtitle: subtitle ? toText(subtitle) : undefined,
50
97
  short_title: short_title ? toText(short_title) : undefined,
51
- doi: (_b = this.doi) !== null && _b !== void 0 ? _b : undefined,
52
- date: date ? (_c = toDate(date)) === null || _c === void 0 ? void 0 : _c.toISOString() : undefined,
53
- authors: authors === null || authors === void 0 ? void 0 : authors.map((a) => authorAndAffiliation(a, this.tree)),
54
- keywords: (_d = this.keywords) === null || _d === void 0 ? void 0 : _d.map((k) => toText(k)),
98
+ doi: (_h = this.doi) !== null && _h !== void 0 ? _h : undefined,
99
+ date,
100
+ authors: authors.length ? authors : undefined,
101
+ // editors,
102
+ affiliations: affiliations.length ? affiliations : undefined,
103
+ keywords: keywords.length ? keywords : undefined,
55
104
  venue: journalTitle ? { title: toText(journalTitle) } : undefined,
56
105
  subject: firstSubject ? toText(firstSubject) : undefined,
57
- };
106
+ license: licenseString !== null && licenseString !== void 0 ? licenseString : undefined,
107
+ open_access: openAccess,
108
+ }, { property: 'frontmatter', messages: {} });
109
+ return frontmatter;
58
110
  }
59
111
  get front() {
60
112
  return select(Tags.front, this.tree);
@@ -123,7 +175,18 @@ export class Jats {
123
175
  return selectAll(Tags.contribGroup, this.front);
124
176
  }
125
177
  get articleAuthors() {
126
- return selectAll(Tags.contrib, this.contribGroup);
178
+ const contribs = selectAll(Tags.contrib, {
179
+ type: 'contribGroups',
180
+ children: this.contribGroups,
181
+ });
182
+ const authors = contribs.filter((contrib) => {
183
+ const contribType = contrib['contrib-type'];
184
+ return !contribType || contribType === 'author';
185
+ });
186
+ return authors;
187
+ }
188
+ get articleAffiliations() {
189
+ return selectAll(`${Tags.aff}[id]`, this.front);
127
190
  }
128
191
  get body() {
129
192
  return select(Tags.body, this.tree);
@@ -146,6 +209,9 @@ export class Jats {
146
209
  this.articleMeta.children = (_a = this.articleMeta) === null || _a === void 0 ? void 0 : _a.children.sort((a, b) => articleMetaOrder.findIndex((x) => x === a.type) -
147
210
  articleMetaOrder.findIndex((x) => x === b.type));
148
211
  }
212
+ selectAll('table-wrap', this.tree).forEach((tw) => {
213
+ tw.children = tw.children.sort((a, b) => { var _a, _b; return ((_a = tableWrapOrder[a.type]) !== null && _a !== void 0 ? _a : -1) - ((_b = tableWrapOrder[b.type]) !== null && _b !== void 0 ? _b : -1); });
214
+ });
149
215
  }
150
216
  serialize(opts) {
151
217
  var _a;
package/dist/order.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export declare const articleMetaOrder: string[];
2
+ export declare const tableWrapOrder: Record<string, number>;
2
3
  //# sourceMappingURL=order.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"order.d.ts","sourceRoot":"","sources":["../src/order.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,UAgD5B,CAAC"}
1
+ {"version":3,"file":"order.d.ts","sourceRoot":"","sources":["../src/order.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,gBAAgB,UAgD5B,CAAC;AAaF,eAAO,MAAM,cAAc,wBA0BzB,CAAC"}
package/dist/order.js CHANGED
@@ -47,3 +47,39 @@ export const articleMetaOrder = [
47
47
  'counts',
48
48
  'custom-meta-group',
49
49
  ];
50
+ function order(tags) {
51
+ return Object.fromEntries(tags
52
+ .map((tag, i) => {
53
+ if (typeof tag === 'string')
54
+ return [[tag, i]];
55
+ return tag.map((t) => [t, i]);
56
+ })
57
+ .flat());
58
+ }
59
+ export const tableWrapOrder = order([
60
+ 'object-id',
61
+ 'label',
62
+ 'caption',
63
+ 'abstract',
64
+ 'kwd-group',
65
+ 'subj-group',
66
+ ['alt-text', 'long-desc', 'email', 'ext-link', 'uri'],
67
+ [
68
+ 'disp-quote',
69
+ 'speech',
70
+ 'statement',
71
+ 'verse-group',
72
+ 'def-list',
73
+ 'list',
74
+ 'alternatives',
75
+ 'chem-struct-wrap',
76
+ 'code',
77
+ 'disp-formula',
78
+ 'graphic',
79
+ 'media',
80
+ 'preformat',
81
+ 'table',
82
+ 'xref',
83
+ ],
84
+ ['table-wrap-foot', 'attrib', 'permissions'],
85
+ ]);
package/dist/session.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { Response } from 'node-fetch';
1
2
  import type { Logger } from 'myst-cli-utils';
2
3
  import type { ISession } from './types.js';
3
4
  export declare class Session implements ISession {
@@ -5,6 +6,7 @@ export declare class Session implements ISession {
5
6
  constructor(opts?: {
6
7
  logger?: Logger;
7
8
  });
9
+ fetch(): Promise<Response>;
8
10
  }
9
11
  export declare function getSession(logger: Logger): Session;
10
12
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAc3C,qBAAa,OAAQ,YAAW,QAAQ;IACtC,GAAG,EAAE,MAAM,CAAC;gBACA,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;CAGvC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,WAExC"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAc3C,qBAAa,OAAQ,YAAW,QAAQ;IACtC,GAAG,EAAE,MAAM,CAAC;gBACA,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAGtC,KAAK,IAAI,OAAO,CAAC,QAAQ,CAAC;CAG3B;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,WAExC"}
package/dist/session.js CHANGED
@@ -17,6 +17,9 @@ export class Session {
17
17
  var _a;
18
18
  this.log = xmllintLogWrapper((_a = opts === null || opts === void 0 ? void 0 : opts.logger) !== null && _a !== void 0 ? _a : chalkLogger(LogLevel.debug));
19
19
  }
20
+ fetch() {
21
+ throw new Error('fetch not implemented on session');
22
+ }
20
23
  }
21
24
  export function getSession(logger) {
22
25
  return new Session({ logger });
package/dist/utils.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type { GenericParent } from 'myst-common';
2
- import type { Contributor } from 'myst-frontmatter';
2
+ import type { Affiliation, Contrib } from 'jats-tags';
3
+ import type { Affiliation as AffiliationFM, Contributor as ContributorFM } from 'myst-frontmatter';
3
4
  export type PubIdTypes = 'doi' | 'pmc' | 'pmid' | 'publisher-id' | string;
4
5
  export declare function findArticleId(node: GenericParent | undefined, pubIdType?: PubIdTypes): string | undefined;
5
- export declare function authorAndAffiliation(node: GenericParent, article: GenericParent): Contributor;
6
+ export declare function processContributor(contrib: Contrib): ContributorFM;
7
+ export declare function processAffiliation(aff: Affiliation): AffiliationFM;
6
8
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAMjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,cAAc,GAAG,MAAM,CAAC;AAE1E,wBAAgB,aAAa,CAC3B,IAAI,EAAE,aAAa,GAAG,SAAS,EAC/B,SAAS,GAAE,UAAkB,GAC5B,MAAM,GAAG,SAAS,CAQpB;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,GAAG,WAAW,CAyC7F"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,aAAa,CAAC;AAK9D,OAAO,KAAK,EAAE,WAAW,EAAa,OAAO,EAAmB,MAAM,WAAW,CAAC;AAElF,OAAO,KAAK,EAAE,WAAW,IAAI,aAAa,EAAE,WAAW,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGnG,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,cAAc,GAAG,MAAM,CAAC;AAE1E,wBAAgB,aAAa,CAC3B,IAAI,EAAE,aAAa,GAAG,SAAS,EAC/B,SAAS,GAAE,UAAkB,GAC5B,MAAM,GAAG,SAAS,CAQpB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CAmBlE;AAmBD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,CAqElE"}
package/dist/utils.js CHANGED
@@ -2,6 +2,7 @@ import { toText } from 'myst-common';
2
2
  import { doi } from 'doi-utils';
3
3
  import { select, selectAll } from 'unist-util-select';
4
4
  import { Tags } from 'jats-tags';
5
+ import { remove } from 'unist-util-remove';
5
6
  export function findArticleId(node, pubIdType = 'doi') {
6
7
  if (!node)
7
8
  return undefined;
@@ -11,43 +12,107 @@ export function findArticleId(node, pubIdType = 'doi') {
11
12
  const doiTag = selectAll(`${Tags.articleId},${Tags.pubId}`, node).find((t) => doi.validate(toText(t)));
12
13
  return toText(doiTag) || undefined;
13
14
  }
14
- export function authorAndAffiliation(node, article) {
15
+ export function processContributor(contrib) {
15
16
  const author = {
16
- name: `${toText(select(Tags.givenNames, node))} ${toText(select(Tags.surname, node))}`,
17
+ name: `${toText(select(Tags.givenNames, contrib))} ${toText(select(Tags.surname, contrib))}`,
17
18
  };
18
- const orcid = select('[contrib-id-type=orcid]', node);
19
+ const orcid = select('[contrib-id-type=orcid]', contrib);
19
20
  if (orcid) {
20
21
  author.orcid = toText(orcid).replace(/(https?:\/\/)?orcid\.org\//, '');
21
22
  }
22
- //
23
- /**
24
- * For example:
25
- *
26
- * ```xml
27
- * <aff id="aff2">
28
- * <label>2</label>
29
- * <institution-wrap>
30
- * <institution-id institution-id-type="ror">https://ror.org/00t9vx427</institution-id>
31
- * <institution>Department of Biochemistry, University of Texas Southwestern Medical Center</institution>
32
- * </institution-wrap>
33
- * <addr-line>
34
- * <named-content content-type="city">Dallas</named-content>
35
- * </addr-line>
36
- * <country>United States</country>
37
- * </aff>
38
- * ```
39
- */
40
- const affiliationRefs = selectAll('xref[ref-type=aff]', node);
41
- const affiliations = affiliationRefs.map((xref) => select(`[id=${xref.rid}]`, article));
42
- const affiliationText = affiliations
43
- .map((aff) => {
44
- // TODO: handle rors!
45
- const ror = select(`[institution-id-type=ror]`, aff);
46
- return toText(select('institution', aff));
47
- })
48
- .filter((t) => !!t);
49
- if (affiliationText.length > 0) {
50
- author.affiliations = affiliationText;
23
+ const affiliationRefs = selectAll('xref[ref-type=aff]', contrib);
24
+ const affiliationIds = affiliationRefs.map((xref) => xref.rid);
25
+ if (affiliationIds.length > 0) {
26
+ author.affiliations = affiliationIds;
51
27
  }
28
+ const uri = select('uri', contrib);
29
+ if (uri === null || uri === void 0 ? void 0 : uri['xlink:href']) {
30
+ author.url = uri['xlink:href'];
31
+ }
32
+ // If there are no aff xrefs AND contrib is in a contrib group with affs AND those affs do not have IDs, add them as affiliations...
52
33
  return author;
53
34
  }
35
+ /**
36
+ * Perform standard toText, trim, remove trailing comma and semicolon
37
+ *
38
+ * Additionally, this returns undefined instead of empty string if node is undefined
39
+ */
40
+ function toTextAndTrim(content) {
41
+ const text = toText(content);
42
+ if (!text)
43
+ return undefined;
44
+ return text.replace(/^[\s;,]+/, '').replace(/[\s;,]+$/, '');
45
+ }
46
+ function markForDeletion(nodes) {
47
+ nodes.forEach((node) => {
48
+ if (node)
49
+ node.type = '__delete__';
50
+ });
51
+ }
52
+ export function processAffiliation(aff) {
53
+ var _a, _b;
54
+ const id = aff.id;
55
+ let ror;
56
+ let isni;
57
+ const rorNode = select(`institution-id[institution-id-type=ror]`, aff);
58
+ if (rorNode) {
59
+ ror = toTextAndTrim(rorNode);
60
+ }
61
+ const isniNode = select(`institution-id[institution-id-type=ISNI]`, aff);
62
+ if (isniNode) {
63
+ isni = toTextAndTrim(isniNode);
64
+ }
65
+ markForDeletion(selectAll('institution-id', aff));
66
+ remove(aff, '__delete__');
67
+ const institutions = selectAll('institution', aff);
68
+ const textAddress = selectAll('addr-line > text', aff);
69
+ const namedContent = selectAll('named-content', aff);
70
+ const departmentNode = (_a = institutions.find((inst) => inst['content-type'] === 'dept')) !== null && _a !== void 0 ? _a : namedContent.find((content) => content['content-type'] === 'organisation-division');
71
+ const addressNode = namedContent.find((content) => content['content-type'] === 'street');
72
+ const cityNode = namedContent.find((content) => content['content-type'] === 'city');
73
+ const stateNode = namedContent.find((content) => content['content-type'] === 'country-part');
74
+ const postalCodeNode = namedContent.find((content) => content['content-type'] === 'post-code');
75
+ const countryNode = (_b = select('country', aff)) !== null && _b !== void 0 ? _b : namedContent.find((content) => content['content-type'] === 'country');
76
+ markForDeletion([
77
+ ...textAddress,
78
+ ...namedContent,
79
+ departmentNode,
80
+ addressNode,
81
+ cityNode,
82
+ stateNode,
83
+ postalCodeNode,
84
+ countryNode,
85
+ ]);
86
+ remove(aff, '__delete__');
87
+ const affChildren = aff.children.filter((child) => child.type !== 'label');
88
+ let institution;
89
+ if (affChildren.filter((child) => ['text', 'institution-wrap', 'institution'].includes(child.type))
90
+ .length === affChildren.length) {
91
+ institution = toTextAndTrim(affChildren);
92
+ }
93
+ else {
94
+ institution = toTextAndTrim(institutions.find((inst) => inst['content-type'] !== 'dept'));
95
+ }
96
+ const addressLines = textAddress
97
+ .map((line) => toTextAndTrim(line))
98
+ .filter((line) => !!line);
99
+ let department = departmentNode
100
+ ? toTextAndTrim(departmentNode)
101
+ : addressLines.find((line) => line.toLowerCase().includes('department'));
102
+ let address = addressNode
103
+ ? toTextAndTrim(addressNode)
104
+ : addressLines.find((line) => !line.toLowerCase().includes('department'));
105
+ if (address && !institution) {
106
+ institution = address;
107
+ address = undefined;
108
+ }
109
+ if (department && !institution) {
110
+ institution = department;
111
+ department = undefined;
112
+ }
113
+ const city = toTextAndTrim(cityNode);
114
+ const state = toTextAndTrim(stateNode);
115
+ const postal_code = toTextAndTrim(postalCodeNode);
116
+ const country = toTextAndTrim(countryNode);
117
+ return { id, ror, isni, department, institution, address, city, state, postal_code, country };
118
+ }
package/dist/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- declare const version = "1.0.8";
1
+ declare const version = "1.0.10";
2
2
  export default version;
3
3
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,OAAO,UAAU,CAAC;AACxB,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,QAAA,MAAM,OAAO,WAAW,CAAC;AACzB,eAAe,OAAO,CAAC"}
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
- const version = '1.0.8';
1
+ const version = '1.0.10';
2
2
  export default version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jats-xml",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Types and utilities for working with JATS in Typescript",
5
5
  "author": "Rowan Cockett <rowan@curvenote.com>",
6
6
  "homepage": "https://github.com/curvenote/jats",
@@ -24,53 +24,41 @@
24
24
  "type": "git",
25
25
  "url": "git+https://github.com/curvenote/jats.git"
26
26
  },
27
- "bin": {
28
- "jats": "./dist/jats.cjs"
29
- },
30
27
  "scripts": {
31
28
  "copy:version": "echo \"const version = '\"$npm_package_version\"';\nexport default version;\" > src/version.ts",
32
29
  "clean": "rm -rf dist",
33
- "unlink": "npm uninstall -g jats-xml;",
34
- "link": "npm run unlink; npm link;",
35
- "dev": "npm run copy:version && npm run link && esbuild src/cli/index.ts --bundle --outfile=dist/jats.cjs --platform=node --watch",
36
30
  "test": "npm run copy:version && vitest run",
37
31
  "test:watch": "npm run copy:version && vitest watch",
38
32
  "lint": "eslint \"src/**/*.ts*\" -c ./.eslintrc.cjs",
39
33
  "lint:format": "prettier --check \"src/**/*.{ts,tsx,md}\"",
40
34
  "build:esm": "tsc",
41
- "build:cli": "esbuild src/cli/index.ts --bundle --outfile=dist/jats.cjs --platform=node",
42
- "build": "npm-run-all -l clean copy:version -p build:esm build:cli"
35
+ "build": "npm-run-all -l clean copy:version -p build:esm"
43
36
  },
44
37
  "bugs": {
45
38
  "url": "https://github.com/curvenote/jats/issues"
46
39
  },
47
40
  "dependencies": {
48
41
  "adm-zip": "^0.5.10",
49
- "doi-utils": "^2.0.0",
50
- "fair-principles": "^2.0.0",
51
- "jats-fetch": "^1.0.8",
52
- "jats-tags": "^1.0.8",
53
- "jats-utils": "^1.0.8",
54
- "js-yaml": "^4.1.0",
42
+ "doi-utils": "^2.0.3",
43
+ "jats-tags": "^1.0.10",
44
+ "jats-utils": "^1.0.10",
45
+ "myst-cli-utils": "^2.0.11",
46
+ "myst-common": "^1.7.5",
47
+ "myst-frontmatter": "^1.7.5",
55
48
  "node-fetch": "^3.3.1",
56
- "unist-util-is": "^5.2.1",
57
- "unist-util-remove": "^3.1.0",
58
49
  "unist-util-select": "^4.0.0",
50
+ "unist-util-remove": "4.0.0",
59
51
  "which": "^3.0.1",
60
52
  "xml-js": "^1.6.11"
61
53
  },
62
54
  "peerDependencies": {
63
- "chalk": "^5.2.0",
64
- "commander": "^10.0.1"
55
+ "chalk": "^5.2.0"
65
56
  },
66
57
  "devDependencies": {
67
58
  "@types/adm-zip": "^0.5.0",
68
59
  "@types/js-yaml": "^4.0.5",
69
60
  "@types/which": "^3.0.0",
70
61
  "chalk": "^5.2.0",
71
- "commander": "^10.0.1",
72
- "myst-cli-utils": "^2.0.0",
73
- "myst-common": "^1.0.0",
74
- "myst-frontmatter": "^1.0.0"
62
+ "js-yaml": "^4.1.0"
75
63
  }
76
64
  }
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
package/dist/cli/index.js DELETED
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import version from '../version.js';
4
- import { addDownloadCLI } from './parse.js';
5
- import { addValidateCLI } from './validate.js';
6
- import { addTestCLI } from './jats-test.js';
7
- const program = new Command();
8
- addDownloadCLI(program);
9
- addValidateCLI(program);
10
- addTestCLI(program);
11
- program.version(`v${version}`, '-v, --version', 'Print the current version of jats-xml');
12
- program.option('-d, --debug', 'Log out any errors to the console.');
13
- program.parse(process.argv);