meca 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +124 -5
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +1 -1
- package/dist/cli/validate.d.ts +1 -0
- package/dist/cli/validate.d.ts.map +1 -0
- package/dist/cli/validate.js +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -1
- package/dist/{MECA_manifest.dtd → manifest-1.0.dtd} +2 -4
- package/dist/manifest.d.ts +55 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +194 -0
- package/dist/meca.cjs +3186 -2730
- package/dist/transfer-1.0.dtd +44 -0
- package/dist/transfer.d.ts +71 -0
- package/dist/transfer.d.ts.map +1 -0
- package/dist/transfer.js +276 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +30 -0
- package/dist/{validate/dtd.d.ts → validate.d.ts} +1 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +163 -0
- package/dist/version.d.ts +2 -1
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +9 -8
- package/dist/validate/dtd.js +0 -166
- package/dist/validate/index.d.ts +0 -1
- package/dist/validate/index.js +0 -1
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "meca",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Types and utilities for working with MECA",
|
|
5
5
|
"author": "Rowan Cockett <rowan@curvenote.com>",
|
|
6
|
-
"homepage": "https://github.com/curvenote/
|
|
6
|
+
"homepage": "https://github.com/curvenote/jats",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"sideEffects": false,
|
|
9
9
|
"type": "module",
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
},
|
|
23
23
|
"repository": {
|
|
24
24
|
"type": "git",
|
|
25
|
-
"url": "git+https://github.com/curvenote/
|
|
25
|
+
"url": "git+https://github.com/curvenote/jats.git"
|
|
26
26
|
},
|
|
27
27
|
"bin": "./dist/meca.cjs",
|
|
28
28
|
"scripts": {
|
|
29
|
-
"copy:dtd": "cp ./static/
|
|
29
|
+
"copy:dtd": "cp ./static/manifest-1.0.dtd dist/manifest-1.0.dtd; cp ./static/transfer-1.0.dtd dist/transfer-1.0.dtd",
|
|
30
30
|
"copy:version": "echo \"const version = '\"$npm_package_version\"';\nexport default version;\" > src/version.ts",
|
|
31
31
|
"clean": "rm -rf dist",
|
|
32
32
|
"unlink": "npm uninstall -g meca;",
|
|
@@ -36,16 +36,17 @@
|
|
|
36
36
|
"test:watch": "npm run copy:version && vitest watch",
|
|
37
37
|
"lint": "eslint \"src/**/*.ts*\" -c ./.eslintrc.cjs",
|
|
38
38
|
"lint:format": "prettier --check \"src/**/*.{ts,tsx,md}\"",
|
|
39
|
-
"build:esm": "tsc
|
|
39
|
+
"build:esm": "tsc",
|
|
40
40
|
"build:cli": "esbuild src/cli/index.ts --bundle --outfile=dist/meca.cjs --platform=node",
|
|
41
41
|
"build": "npm-run-all -l clean copy:version -p build:esm build:cli -s copy:dtd"
|
|
42
42
|
},
|
|
43
43
|
"bugs": {
|
|
44
|
-
"url": "https://github.com/curvenote/
|
|
44
|
+
"url": "https://github.com/curvenote/jats/issues"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"adm-zip": "^0.5.10",
|
|
48
|
-
"jats-xml": "^1.0.
|
|
48
|
+
"jats-xml": "^1.0.5",
|
|
49
|
+
"node-fetch": "^3.3.1",
|
|
49
50
|
"xml-js": "^1.6.11"
|
|
50
51
|
},
|
|
51
52
|
"peerDependencies": {
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
"@types/adm-zip": "^0.5.0",
|
|
57
58
|
"chalk": "^5.2.0",
|
|
58
59
|
"commander": "^10.0.1",
|
|
59
|
-
"myst-cli-utils": "^
|
|
60
|
+
"myst-cli-utils": "^2.0.0",
|
|
60
61
|
"myst-common": "^1.0.0",
|
|
61
62
|
"myst-frontmatter": "^1.0.0"
|
|
62
63
|
}
|
package/dist/validate/dtd.js
DELETED
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import AdmZip from 'adm-zip';
|
|
5
|
-
import chalk from 'chalk';
|
|
6
|
-
import { xml2js } from 'xml-js';
|
|
7
|
-
import { validateJatsAgainstDtd, xmllintValidate } from 'jats-xml';
|
|
8
|
-
const KNOWN_ITEM_TYPES = [
|
|
9
|
-
'article-metadata',
|
|
10
|
-
'article-supporting-file',
|
|
11
|
-
'manuscript',
|
|
12
|
-
'manuscript-supporting-file',
|
|
13
|
-
'article-source',
|
|
14
|
-
'article-source-environment',
|
|
15
|
-
'article-source-directory',
|
|
16
|
-
];
|
|
17
|
-
const MANIFEST = 'manifest.xml';
|
|
18
|
-
const MANIFEST_DTD = 'MECA_manifest.dtd';
|
|
19
|
-
/**
|
|
20
|
-
* Function to log debug message for passing check
|
|
21
|
-
*/
|
|
22
|
-
function debugCheck(session, msg) {
|
|
23
|
-
session.log.debug(chalk.green(`✓ ${msg}`));
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Function to log an error and clean temp folder
|
|
27
|
-
*/
|
|
28
|
-
function errorAndClean(session, msg, tempFolder) {
|
|
29
|
-
session.log.error(msg);
|
|
30
|
-
removeTempFolder(tempFolder);
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
function removeTempFolder(tempFolder) {
|
|
34
|
-
if (tempFolder && fs.existsSync(tempFolder)) {
|
|
35
|
-
if (fs.rmSync) {
|
|
36
|
-
// Node >= 14.14
|
|
37
|
-
fs.rmSync(tempFolder, { recursive: true });
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
// Node < 14.14
|
|
41
|
-
fs.rmdirSync(tempFolder, { recursive: true });
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function createTempFolder() {
|
|
46
|
-
return fs.mkdtempSync(path.join(os.tmpdir(), 'meca'));
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Extract list of simple manifest item from valid manifest XML
|
|
50
|
-
*/
|
|
51
|
-
function extractManifestItems(manifestString) {
|
|
52
|
-
var _a, _b, _c, _d, _e;
|
|
53
|
-
const manifest = xml2js(manifestString);
|
|
54
|
-
const items = (_e = (_d = (_c = (_b = (_a = manifest.elements) === null || _a === void 0 ? void 0 : _a.find((element) => element.name === 'manifest')) === null || _b === void 0 ? void 0 : _b.elements) === null || _c === void 0 ? void 0 : _c.filter((element) => element.name === 'item')) === null || _d === void 0 ? void 0 : _d.map((item) => {
|
|
55
|
-
var _a, _b, _c;
|
|
56
|
-
const instanceAttrs = (_b = (_a = item.elements) === null || _a === void 0 ? void 0 : _a.find((element) => element.name === 'instance')) === null || _b === void 0 ? void 0 : _b.attributes;
|
|
57
|
-
const href = instanceAttrs === null || instanceAttrs === void 0 ? void 0 : instanceAttrs['xlink:href'];
|
|
58
|
-
if (!href)
|
|
59
|
-
return undefined;
|
|
60
|
-
return {
|
|
61
|
-
href,
|
|
62
|
-
itemType: (_c = item.attributes) === null || _c === void 0 ? void 0 : _c['item-type'],
|
|
63
|
-
mediaType: instanceAttrs['media-type'],
|
|
64
|
-
};
|
|
65
|
-
}).filter((item) => !!item)) !== null && _e !== void 0 ? _e : [];
|
|
66
|
-
return items;
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Validate a given file as MECA bundle
|
|
70
|
-
*
|
|
71
|
-
* Returns true if file is valid.
|
|
72
|
-
*
|
|
73
|
-
* Validation checks:
|
|
74
|
-
* - File exists and is zip format
|
|
75
|
-
* - Bundle includes manifest.xlm which validates against DTD
|
|
76
|
-
* - manifest matches items present in the bundle
|
|
77
|
-
* - manifest item types match known types
|
|
78
|
-
* - JATS items validate
|
|
79
|
-
*/
|
|
80
|
-
export async function validateMeca(session, file, opts) {
|
|
81
|
-
if (!fs.existsSync(file))
|
|
82
|
-
return errorAndClean(session, `Input file does not exists: ${file}`);
|
|
83
|
-
let mecaZip;
|
|
84
|
-
try {
|
|
85
|
-
mecaZip = new AdmZip(file);
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
return errorAndClean(session, `Input file is not a zip archive: ${file}`);
|
|
89
|
-
}
|
|
90
|
-
debugCheck(session, 'is zip archive');
|
|
91
|
-
const manifestEntry = mecaZip.getEntry(MANIFEST);
|
|
92
|
-
if (!manifestEntry) {
|
|
93
|
-
return errorAndClean(session, `Input zip archive does not include required manifest file '${MANIFEST}'`);
|
|
94
|
-
}
|
|
95
|
-
debugCheck(session, `includes ${MANIFEST}`);
|
|
96
|
-
const localDtdFile = fs.existsSync(path.join(__dirname, MANIFEST_DTD))
|
|
97
|
-
? path.join(__dirname, MANIFEST_DTD)
|
|
98
|
-
: path.join(__dirname, '..', MANIFEST_DTD);
|
|
99
|
-
if (!fs.existsSync(localDtdFile)) {
|
|
100
|
-
throw new Error(`Unable to locate manifest DTD file ${MANIFEST_DTD} in meca lib distribution`);
|
|
101
|
-
}
|
|
102
|
-
const tempFolder = createTempFolder();
|
|
103
|
-
mecaZip.extractEntryTo(MANIFEST, tempFolder);
|
|
104
|
-
const manifestIsValid = await xmllintValidate(session, path.join(tempFolder, MANIFEST), localDtdFile);
|
|
105
|
-
if (!manifestIsValid) {
|
|
106
|
-
return errorAndClean(session, `${MANIFEST} DTD validation failed`, tempFolder);
|
|
107
|
-
}
|
|
108
|
-
debugCheck(session, `${MANIFEST} passes schema validation`);
|
|
109
|
-
const manifestString = manifestEntry.getData().toString();
|
|
110
|
-
const manifestItems = extractManifestItems(manifestString);
|
|
111
|
-
const zipEntries = mecaZip.getEntries();
|
|
112
|
-
const manifestExtras = manifestItems
|
|
113
|
-
.filter((item) => !zipEntries.map((entry) => entry.entryName).includes(item.href))
|
|
114
|
-
.map((item) => item.href);
|
|
115
|
-
const zipExtras = zipEntries
|
|
116
|
-
.filter((entry) => entry.entryName !== MANIFEST)
|
|
117
|
-
.filter((entry) => !entry.isDirectory)
|
|
118
|
-
.filter((entry) => !manifestItems.map((item) => item.href).includes(entry.entryName))
|
|
119
|
-
.map((entry) => entry.entryName);
|
|
120
|
-
if (zipExtras.length) {
|
|
121
|
-
session.log.warn(`MECA bundle includes items missing from manifest:\n- ${zipExtras.join('\n- ')}`);
|
|
122
|
-
}
|
|
123
|
-
if (manifestExtras.length) {
|
|
124
|
-
return errorAndClean(session, `manifest items missing from MECA bundle:\n- ${manifestExtras.join('\n- ')}`, tempFolder);
|
|
125
|
-
}
|
|
126
|
-
debugCheck(session, 'manfiest matches MECA bundle contents');
|
|
127
|
-
manifestItems.forEach((item) => {
|
|
128
|
-
if (!item.mediaType) {
|
|
129
|
-
session.log.warn(`manifest item missing media-type: ${item.href}`);
|
|
130
|
-
}
|
|
131
|
-
if (!item.itemType) {
|
|
132
|
-
session.log.warn(`manifest item missing item-type: ${item.href} `);
|
|
133
|
-
}
|
|
134
|
-
else if (!KNOWN_ITEM_TYPES.includes(item.itemType)) {
|
|
135
|
-
session.log.warn(`manifest item has unknown item-type "${item.itemType}": ${item.href} `);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
const jatsFiles = manifestItems
|
|
139
|
-
.filter((item) => item.itemType === 'article-metadata')
|
|
140
|
-
.map((item) => item.href);
|
|
141
|
-
const invalidJatsFiles = (await Promise.all(jatsFiles.map(async (jatsFile) => {
|
|
142
|
-
mecaZip.extractEntryTo(jatsFile, tempFolder);
|
|
143
|
-
const isValid = await validateJatsAgainstDtd(session, path.join(tempFolder, ...jatsFile.split('/')), opts);
|
|
144
|
-
return isValid ? undefined : jatsFile;
|
|
145
|
-
}))).filter((jatsFile) => !!jatsFile);
|
|
146
|
-
if (invalidJatsFiles.length) {
|
|
147
|
-
return errorAndClean(session, `JATS DTD validation failed:\n- ${invalidJatsFiles.join('\n- ')}`, tempFolder);
|
|
148
|
-
}
|
|
149
|
-
debugCheck(session, 'JATS validation passed');
|
|
150
|
-
removeTempFolder(tempFolder);
|
|
151
|
-
return true;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Validate a given file as MECA bundle
|
|
155
|
-
*
|
|
156
|
-
* Logs confirmation message if valid and throws an error if invalid.
|
|
157
|
-
*/
|
|
158
|
-
export async function validateMecaWrapper(session, file, opts) {
|
|
159
|
-
const success = await validateMeca(session, file, opts);
|
|
160
|
-
if (success) {
|
|
161
|
-
session.log.info(chalk.greenBright('MECA validation passed!'));
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
throw new Error('MECA validation failed.');
|
|
165
|
-
}
|
|
166
|
-
}
|
package/dist/validate/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './dtd.js';
|
package/dist/validate/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './dtd.js';
|