retire 5.0.0 → 5.1.0
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/CHANGELOG.md +17 -0
- package/lib/cli.js +1 -1
- package/lib/deepscan.js +1 -2
- package/lib/depsdev.js +1 -2
- package/lib/repo.js +4 -5
- package/lib/reporters/cyclonedx-1_6-json.d.ts +3 -0
- package/lib/reporters/cyclonedx-1_6-json.js +118 -0
- package/lib/reporters/cyclonedx-json.js +5 -1
- package/lib/reporters/utils.js +1 -2
- package/lib/reporting.d.ts +0 -3
- package/lib/reporting.js +4 -2
- package/lib/resolve.d.ts +0 -1
- package/lib/resolve.js +1 -2
- package/lib/retire.js +2 -2
- package/lib/scanner.js +3 -4
- package/lib/types.d.ts +0 -1
- package/lib/utils.js +4 -5
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [5.1.0]
|
|
4
|
+
|
|
5
|
+
## Add
|
|
6
|
+
|
|
7
|
+
- Support for CycloneDX 1.6 JSON as output format
|
|
8
|
+
- Adding file location as property in CycloneDX 1.4 JSON output
|
|
9
|
+
|
|
10
|
+
## [5.0.1]
|
|
11
|
+
|
|
12
|
+
### Fix
|
|
13
|
+
|
|
14
|
+
- Fix filename issue for windows file paths
|
|
15
|
+
|
|
16
|
+
## [5.0.0]
|
|
17
|
+
|
|
18
|
+
No changes. Just moving from beta to final.
|
|
19
|
+
|
|
3
20
|
## [5.0.0-beta.1]
|
|
4
21
|
|
|
5
22
|
### Added
|
package/lib/cli.js
CHANGED
|
@@ -60,7 +60,7 @@ const prg = commander_1.program
|
|
|
60
60
|
.option('--jsrepo <path|url>', "Local or internal version of repo. Can be multiple comma separated. Default: 'central')")
|
|
61
61
|
.option('--cachedir <path>', 'Path to use for local cache instead of /tmp/.retire-cache')
|
|
62
62
|
.option('--proxy <url>', 'Proxy url (http://some.host:8080)')
|
|
63
|
-
.option('--outputformat <format>', 'Valid formats: text, json, jsonsimple, depcheck (experimental), cyclonedx and
|
|
63
|
+
.option('--outputformat <format>', 'Valid formats: text, json, jsonsimple, depcheck (experimental), cyclonedx, cyclonedxJSON and cyclonedxJSON1_6')
|
|
64
64
|
.option('--outputpath <path>', 'File to which output should be written')
|
|
65
65
|
.option('--ignore <paths>', 'Comma delimited list of paths to ignore')
|
|
66
66
|
.option('--ignorefile <path>', 'Custom ignore file, defaults to .retireignore / .retireignore.json')
|
package/lib/deepscan.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.deepScan =
|
|
3
|
+
exports.deepScan = deepScan;
|
|
4
4
|
const astronomical_1 = require("astronomical");
|
|
5
5
|
function deepScan(content, repo) {
|
|
6
6
|
const astQueries = {};
|
|
@@ -34,4 +34,3 @@ function deepScan(content, repo) {
|
|
|
34
34
|
return acc;
|
|
35
35
|
}, []);
|
|
36
36
|
}
|
|
37
|
-
exports.deepScan = deepScan;
|
package/lib/depsdev.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.checkOSV =
|
|
6
|
+
exports.checkOSV = checkOSV;
|
|
7
7
|
const https_1 = __importDefault(require("https"));
|
|
8
8
|
const retire_1 = require("./retire");
|
|
9
9
|
function loadJson(url, options) {
|
|
@@ -80,4 +80,3 @@ async function checkOSV(packageName, version, options) {
|
|
|
80
80
|
return [];
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
exports.checkOSV = checkOSV;
|
package/lib/repo.js
CHANGED
|
@@ -23,7 +23,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.
|
|
26
|
+
exports.validateRepository = validateRepository;
|
|
27
|
+
exports.asbowerrepo = asbowerrepo;
|
|
28
|
+
exports.loadrepository = loadrepository;
|
|
29
|
+
exports.loadrepositoryFromFile = loadrepositoryFromFile;
|
|
27
30
|
const fs = __importStar(require("fs"));
|
|
28
31
|
const path = __importStar(require("path"));
|
|
29
32
|
const http = __importStar(require("http"));
|
|
@@ -151,7 +154,6 @@ function validateRepository(repo, replacer) {
|
|
|
151
154
|
.strict());
|
|
152
155
|
return validator.safeParse(repo);
|
|
153
156
|
}
|
|
154
|
-
exports.validateRepository = validateRepository;
|
|
155
157
|
function formatValidationError(error) {
|
|
156
158
|
return JSON.stringify(error.format(), (key, value) => (Array.isArray(value) && value.length === 0 ? undefined : value), 2);
|
|
157
159
|
}
|
|
@@ -255,7 +257,6 @@ function asbowerrepo(jsRepo) {
|
|
|
255
257
|
});
|
|
256
258
|
return result;
|
|
257
259
|
}
|
|
258
|
-
exports.asbowerrepo = asbowerrepo;
|
|
259
260
|
async function loadrepository(repoUrl, options) {
|
|
260
261
|
options = { ...options, process: retire.replaceVersion };
|
|
261
262
|
if (options.nocache) {
|
|
@@ -263,9 +264,7 @@ async function loadrepository(repoUrl, options) {
|
|
|
263
264
|
}
|
|
264
265
|
return await loadFromCache(repoUrl, options.cachedir, options);
|
|
265
266
|
}
|
|
266
|
-
exports.loadrepository = loadrepository;
|
|
267
267
|
async function loadrepositoryFromFile(filepath, options) {
|
|
268
268
|
options = { ...options, process: retire.replaceVersion };
|
|
269
269
|
return await loadJsonFromFile(filepath, options);
|
|
270
270
|
}
|
|
271
|
-
exports.loadrepositoryFromFile = loadrepositoryFromFile;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
const retire = __importStar(require("../retire"));
|
|
27
|
+
const fs = __importStar(require("fs"));
|
|
28
|
+
const uuid_1 = require("uuid");
|
|
29
|
+
const utils_1 = require("./utils");
|
|
30
|
+
const path = __importStar(require("path"));
|
|
31
|
+
function configureCycloneDXJSONLogger(logger, writer, config, hash) {
|
|
32
|
+
let vulnsFound = false;
|
|
33
|
+
const finalResults = {
|
|
34
|
+
version: retire.version,
|
|
35
|
+
start: new Date().toISOString(),
|
|
36
|
+
data: [],
|
|
37
|
+
messages: [],
|
|
38
|
+
errors: [],
|
|
39
|
+
};
|
|
40
|
+
logger.info = finalResults.messages.push;
|
|
41
|
+
logger.debug = config.verbose
|
|
42
|
+
? finalResults.messages.push
|
|
43
|
+
: function () {
|
|
44
|
+
return;
|
|
45
|
+
};
|
|
46
|
+
logger.warn = logger.error = finalResults.errors.push;
|
|
47
|
+
logger.logVulnerableDependency = function (finding) {
|
|
48
|
+
vulnsFound = true;
|
|
49
|
+
finalResults.data.push(finding);
|
|
50
|
+
};
|
|
51
|
+
logger.logDependency = function (finding) {
|
|
52
|
+
if (finding.results.length > 0) {
|
|
53
|
+
finalResults.data.push(finding);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
logger.close = function (callback) {
|
|
57
|
+
const write = vulnsFound ? writer.err : writer.out;
|
|
58
|
+
const seen = new Map();
|
|
59
|
+
const components = finalResults.data
|
|
60
|
+
.filter((d) => d.results)
|
|
61
|
+
.map((r) => r.results
|
|
62
|
+
.map((dep) => {
|
|
63
|
+
dep.version = (dep.version.split('.').length >= 3 ? dep.version : dep.version + '.0').replace(/-/g, '.');
|
|
64
|
+
let hashes;
|
|
65
|
+
const filepath = r.file;
|
|
66
|
+
const evidence = { occurrences: [] };
|
|
67
|
+
if (filepath) {
|
|
68
|
+
const file = fs.readFileSync(filepath);
|
|
69
|
+
const relativePath = path.relative(process.cwd(), filepath);
|
|
70
|
+
evidence.occurrences.push({ location: relativePath });
|
|
71
|
+
hashes = [
|
|
72
|
+
{ alg: 'MD5', content: hash.md5(file) },
|
|
73
|
+
{ alg: 'SHA-1', content: hash.sha1(file) },
|
|
74
|
+
{ alg: 'SHA-256', content: hash.sha256(file) },
|
|
75
|
+
{ alg: 'SHA-512', content: hash.sha512(file) },
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
const purl = (0, utils_1.generatePURL)(dep);
|
|
79
|
+
if (seen.has(purl)) {
|
|
80
|
+
seen.get(purl)?.evidence.occurrences.push(...evidence.occurrences);
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
const result = {
|
|
84
|
+
type: 'library',
|
|
85
|
+
name: dep.component,
|
|
86
|
+
version: dep.version,
|
|
87
|
+
purl: purl,
|
|
88
|
+
hashes: hashes,
|
|
89
|
+
evidence,
|
|
90
|
+
};
|
|
91
|
+
seen.set(purl, result);
|
|
92
|
+
return result;
|
|
93
|
+
})
|
|
94
|
+
.filter((x) => x != undefined))
|
|
95
|
+
.reduce((a, b) => a.concat(b), []);
|
|
96
|
+
write(JSON.stringify({
|
|
97
|
+
bomFormat: 'CycloneDX',
|
|
98
|
+
specVersion: '1.6',
|
|
99
|
+
serialNumber: `urn:uuid:${(0, uuid_1.v4)()}`,
|
|
100
|
+
version: 1,
|
|
101
|
+
metadata: {
|
|
102
|
+
timestamp: finalResults.start,
|
|
103
|
+
tools: [
|
|
104
|
+
{
|
|
105
|
+
vendor: 'RetireJS',
|
|
106
|
+
name: 'retire.js',
|
|
107
|
+
version: retire.version,
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
components: components,
|
|
112
|
+
}, undefined, 2));
|
|
113
|
+
writer.close(callback);
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
exports.default = {
|
|
117
|
+
configure: configureCycloneDXJSONLogger,
|
|
118
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/*jshint esversion: 6 */
|
|
3
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
3
|
if (k2 === undefined) k2 = k;
|
|
5
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -28,6 +27,7 @@ const retire = __importStar(require("../retire"));
|
|
|
28
27
|
const fs = __importStar(require("fs"));
|
|
29
28
|
const uuid_1 = require("uuid");
|
|
30
29
|
const utils_1 = require("./utils");
|
|
30
|
+
const path = __importStar(require("path"));
|
|
31
31
|
function configureCycloneDXJSONLogger(logger, writer, config, hash) {
|
|
32
32
|
let vulnsFound = false;
|
|
33
33
|
const finalResults = {
|
|
@@ -63,8 +63,11 @@ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
|
|
|
63
63
|
dep.version = (dep.version.split('.').length >= 3 ? dep.version : dep.version + '.0').replace(/-/g, '.');
|
|
64
64
|
let hashes;
|
|
65
65
|
const filepath = r.file;
|
|
66
|
+
const properties = [];
|
|
66
67
|
if (filepath) {
|
|
67
68
|
const file = fs.readFileSync(filepath);
|
|
69
|
+
const relativePath = path.relative(process.cwd(), filepath);
|
|
70
|
+
properties.push({ name: 'location', value: relativePath });
|
|
68
71
|
hashes = [
|
|
69
72
|
{ alg: 'MD5', content: hash.md5(file) },
|
|
70
73
|
{ alg: 'SHA-1', content: hash.sha1(file) },
|
|
@@ -82,6 +85,7 @@ function configureCycloneDXJSONLogger(logger, writer, config, hash) {
|
|
|
82
85
|
version: dep.version,
|
|
83
86
|
purl: purl,
|
|
84
87
|
hashes: hashes,
|
|
88
|
+
properties,
|
|
85
89
|
};
|
|
86
90
|
})
|
|
87
91
|
.filter((x) => x != undefined))
|
package/lib/reporters/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generatePURL =
|
|
3
|
+
exports.generatePURL = generatePURL;
|
|
4
4
|
function generatePURL(component) {
|
|
5
5
|
if (component.basePurl) {
|
|
6
6
|
return component.basePurl + '@' + component.version;
|
|
@@ -8,4 +8,3 @@ function generatePURL(component) {
|
|
|
8
8
|
const compName = component.npmname || component.component;
|
|
9
9
|
return `pkg:npm/${compName}@${component.version}`;
|
|
10
10
|
}
|
|
11
|
-
exports.generatePURL = generatePURL;
|
package/lib/reporting.d.ts
CHANGED
package/lib/reporting.js
CHANGED
|
@@ -26,7 +26,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.
|
|
29
|
+
exports.hash = void 0;
|
|
30
|
+
exports.open = open;
|
|
30
31
|
const fs = __importStar(require("fs"));
|
|
31
32
|
const crypto = __importStar(require("crypto"));
|
|
32
33
|
const console_1 = __importDefault(require("./reporters/console"));
|
|
@@ -34,6 +35,7 @@ const json_1 = __importDefault(require("./reporters/json"));
|
|
|
34
35
|
const depcheck_1 = __importDefault(require("./reporters/depcheck"));
|
|
35
36
|
const cyclonedx_1 = __importDefault(require("./reporters/cyclonedx"));
|
|
36
37
|
const cyclonedx_json_1 = __importDefault(require("./reporters/cyclonedx-json"));
|
|
38
|
+
const cyclonedx_1_6_json_1 = __importDefault(require("./reporters/cyclonedx-1_6-json"));
|
|
37
39
|
const loggers = {
|
|
38
40
|
console: console_1.default,
|
|
39
41
|
text: console_1.default,
|
|
@@ -41,6 +43,7 @@ const loggers = {
|
|
|
41
43
|
depcheck: depcheck_1.default,
|
|
42
44
|
cyclonedx: cyclonedx_1.default,
|
|
43
45
|
cyclonedxJSON: cyclonedx_json_1.default,
|
|
46
|
+
cyclonedxJSON1_6: cyclonedx_1_6_json_1.default,
|
|
44
47
|
clean: console_1.default,
|
|
45
48
|
jsonsimple: json_1.default,
|
|
46
49
|
};
|
|
@@ -127,4 +130,3 @@ function open(config) {
|
|
|
127
130
|
configureFileWriter(config);
|
|
128
131
|
return logger;
|
|
129
132
|
}
|
|
130
|
-
exports.open = open;
|
package/lib/resolve.d.ts
CHANGED
package/lib/resolve.js
CHANGED
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.scanJsFiles =
|
|
26
|
+
exports.scanJsFiles = scanJsFiles;
|
|
27
27
|
const fs = __importStar(require("fs"));
|
|
28
28
|
const walkdir = __importStar(require("walkdir"));
|
|
29
29
|
function scanJsFiles(path, options) {
|
|
@@ -51,4 +51,3 @@ function scanJsFiles(path, options) {
|
|
|
51
51
|
});
|
|
52
52
|
return finder;
|
|
53
53
|
}
|
|
54
|
-
exports.scanJsFiles = scanJsFiles;
|
package/lib/retire.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
var exports = exports || {};
|
|
7
|
-
exports.version = '5.
|
|
7
|
+
exports.version = '5.1.0';
|
|
8
8
|
|
|
9
9
|
function isDefined(o) {
|
|
10
10
|
return typeof o !== 'undefined';
|
|
@@ -168,7 +168,7 @@ exports.scanUri = function (uri, repo) {
|
|
|
168
168
|
};
|
|
169
169
|
|
|
170
170
|
exports.scanFileName = function (fileName, repo) {
|
|
171
|
-
var result = scan(fileName, 'filename', repo, splitAndMatchAll(
|
|
171
|
+
var result = scan(fileName, 'filename', repo, splitAndMatchAll(/[\/\\]/));
|
|
172
172
|
return check(result, repo);
|
|
173
173
|
};
|
|
174
174
|
|
package/lib/scanner.js
CHANGED
|
@@ -23,7 +23,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.
|
|
26
|
+
exports.scanJsFile = scanJsFile;
|
|
27
|
+
exports.scanBowerFile = scanBowerFile;
|
|
28
|
+
exports.on = on;
|
|
27
29
|
const events_1 = require("events");
|
|
28
30
|
const retire = __importStar(require("./retire"));
|
|
29
31
|
const fs = __importStar(require("fs"));
|
|
@@ -137,7 +139,6 @@ function scanJsFile(file, repo, options) {
|
|
|
137
139
|
}
|
|
138
140
|
emitResults({ file: file, results: results }, options);
|
|
139
141
|
}
|
|
140
|
-
exports.scanJsFile = scanJsFile;
|
|
141
142
|
function scanBowerFile(file, repo, options) {
|
|
142
143
|
if (options.ignore && shouldIgnorePath([file], options.ignore)) {
|
|
143
144
|
return;
|
|
@@ -153,8 +154,6 @@ function scanBowerFile(file, repo, options) {
|
|
|
153
154
|
options.log.warn(`Could not parse file: ${file}`);
|
|
154
155
|
}
|
|
155
156
|
}
|
|
156
|
-
exports.scanBowerFile = scanBowerFile;
|
|
157
157
|
function on(event, handler) {
|
|
158
158
|
events.on(event, handler);
|
|
159
159
|
}
|
|
160
|
-
exports.on = on;
|
package/lib/types.d.ts
CHANGED
package/lib/utils.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.info = info;
|
|
4
|
+
exports.warn = warn;
|
|
5
|
+
exports.pick = pick;
|
|
6
|
+
exports.flatten = flatten;
|
|
4
7
|
function info(options) {
|
|
5
8
|
return function (...message) {
|
|
6
9
|
(options.logger || console.log)(message);
|
|
7
10
|
};
|
|
8
11
|
}
|
|
9
|
-
exports.info = info;
|
|
10
12
|
function warn(options) {
|
|
11
13
|
return function (...message) {
|
|
12
14
|
(options.warnlogger || options.logger || console.warn)(message);
|
|
13
15
|
};
|
|
14
16
|
}
|
|
15
|
-
exports.warn = warn;
|
|
16
17
|
function pick(p, keys) {
|
|
17
18
|
const result = {};
|
|
18
19
|
keys.forEach((k) => {
|
|
@@ -22,8 +23,6 @@ function pick(p, keys) {
|
|
|
22
23
|
});
|
|
23
24
|
return result;
|
|
24
25
|
}
|
|
25
|
-
exports.pick = pick;
|
|
26
26
|
function flatten(e) {
|
|
27
27
|
return e.reduce((x, y) => x.concat(y), []);
|
|
28
28
|
}
|
|
29
|
-
exports.flatten = flatten;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"author": "Erlend Oftedal <erlend@oftedal.no>",
|
|
3
3
|
"name": "retire",
|
|
4
4
|
"description": "Retire is a tool for detecting use of vulnerable libraries",
|
|
5
|
-
"version": "5.
|
|
5
|
+
"version": "5.1.0",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"eslint": "^8.34.0",
|
|
31
31
|
"eslint-config-prettier": "^9.0.0",
|
|
32
32
|
"jsonschema": "^1.4.1",
|
|
33
|
-
"libxmljs": "^1.0.8",
|
|
34
33
|
"mocha": "^10.2.0",
|
|
35
34
|
"prettier": "^3.1.0",
|
|
36
|
-
"typescript": "^5.0.4"
|
|
35
|
+
"typescript": "^5.0.4",
|
|
36
|
+
"xsd-schema-validator": "^0.9.0"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"test": "./test",
|