v8r 0.5.0 â 0.8.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 +19 -0
- package/README.md +28 -7
- package/package.json +16 -12
- package/src/ajv.js +69 -0
- package/src/cache.js +61 -54
- package/src/cli.js +82 -61
- package/src/index.js +1 -3
- package/src/logging.js +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## đĻ [0.8.0](https://www.npmjs.com/package/v8r/v/0.9.0) - 2021-12-25
|
|
4
|
+
|
|
5
|
+
* Switch from CommonJS to ESModules internally
|
|
6
|
+
* Requires node `^12.20.0 || ^14.13.1 || >=15.0.0`
|
|
7
|
+
|
|
8
|
+
## đĻ [0.7.0](https://www.npmjs.com/package/v8r/v/0.7.0) - 2021-11-30
|
|
9
|
+
|
|
10
|
+
* Upgrade to ajv 8 internally
|
|
11
|
+
Adds compatibility for JSON Schema draft 2019-09 and draft 2020-12
|
|
12
|
+
* Docs/logging improvements to clarify behaviour of `--catalogs` param
|
|
13
|
+
|
|
14
|
+
## đĻ [0.6.1](https://www.npmjs.com/package/v8r/v/0.6.1) - 2021-08-06
|
|
15
|
+
|
|
16
|
+
* Refactor cache module to remove global state
|
|
17
|
+
|
|
18
|
+
## đĻ [0.6.0](https://www.npmjs.com/package/v8r/v/0.6.0) - 2021-07-28
|
|
19
|
+
|
|
20
|
+
* Add the ability to search custom schema catalogs using the `--catalogs` param
|
|
21
|
+
|
|
3
22
|
## đĻ [0.5.0](https://www.npmjs.com/package/v8r/v/0.5.0) - 2021-01-13
|
|
4
23
|
|
|
5
24
|
* Allow validation against a local schema
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# v8r
|
|
2
2
|
|
|
3
|
-

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
8
|
|
|
9
9
|
A command-line JSON and YAML validator that's on your wavelength.
|
|
10
10
|
|
|
@@ -50,10 +50,25 @@ Validating action.yml against schema from https://json.schemastore.org/github-ac
|
|
|
50
50
|
$ v8r feature.geojson
|
|
51
51
|
â Could not find a schema to validate feature.geojson
|
|
52
52
|
|
|
53
|
-
# ..you can specify
|
|
53
|
+
# ..you can specify a schema
|
|
54
54
|
$ v8r feature.geojson -s https://json.schemastore.org/geojson
|
|
55
55
|
Validating feature.geojson against schema from https://json.schemastore.org/geojson ...
|
|
56
56
|
â
feature.geojson is valid
|
|
57
|
+
|
|
58
|
+
# ..or use a custom catalog
|
|
59
|
+
# v8r will search any custom catalogs before falling back to Schema Store
|
|
60
|
+
$ cat > my-catalog.json <<EOF
|
|
61
|
+
{ "\$schema": "https://json.schemastore.org/schema-catalog.json",
|
|
62
|
+
"version": 1,
|
|
63
|
+
"schemas": [ { "name": "geojson",
|
|
64
|
+
"description": "geojson",
|
|
65
|
+
"url": "https://json.schemastore.org/geojson.json",
|
|
66
|
+
"fileMatch": ["*.geojson"] } ] }
|
|
67
|
+
EOF
|
|
68
|
+
$ v8r feature.geojson -c my-catalog.json
|
|
69
|
+
âšī¸ Found schema in my-catalog.json ...
|
|
70
|
+
Validating feature.geojson against schema from https://json.schemastore.org/geojson ...
|
|
71
|
+
â
feature.geojson is valid
|
|
57
72
|
```
|
|
58
73
|
|
|
59
74
|
## Exit codes
|
|
@@ -89,7 +104,13 @@ Validating feature.geojson against schema from https://json.schemastore.org/geoj
|
|
|
89
104
|
|
|
90
105
|
### â What JSON schema versions are supported?
|
|
91
106
|
|
|
92
|
-
đĄ `v8r` works with JSON schema
|
|
107
|
+
đĄ `v8r` works with JSON schema drafts:
|
|
108
|
+
|
|
109
|
+
* draft-04
|
|
110
|
+
* draft-06
|
|
111
|
+
* draft-07
|
|
112
|
+
* draft 2019-09
|
|
113
|
+
* draft 2020-12
|
|
93
114
|
|
|
94
115
|
### â Will 100% of the schemas on schemastore.org work with this tool?
|
|
95
116
|
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "v8r",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "A command-line JSON and YAML validator that's on your wavelength",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"test": "V8R_CACHE_NAME=v8r-test
|
|
6
|
+
"test": "V8R_CACHE_NAME=v8r-test c8 --reporter=text mocha \"src/**/*.spec.js\"",
|
|
7
7
|
"lint": "eslint \"src/**/*.js\"",
|
|
8
|
-
"coverage": "
|
|
8
|
+
"coverage": "c8 report --reporter=cobertura",
|
|
9
9
|
"prettier": "prettier --write \"**/*.js\"",
|
|
10
10
|
"prettier:check": "prettier --check \"**/*.js\"",
|
|
11
11
|
"v8r": "src/index.js"
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"v8r": "src/index.js"
|
|
15
15
|
},
|
|
16
16
|
"main": "src/index.js",
|
|
17
|
+
"exports": "./src/index.js",
|
|
17
18
|
"repository": {
|
|
18
19
|
"type": "git",
|
|
19
20
|
"url": "git+https://github.com/chris48s/v8r.git"
|
|
@@ -22,29 +23,32 @@
|
|
|
22
23
|
"author": "chris48s",
|
|
23
24
|
"license": "MIT",
|
|
24
25
|
"dependencies": {
|
|
25
|
-
"ajv": "^
|
|
26
|
+
"ajv": "^8.8.2",
|
|
27
|
+
"ajv-draft-04": "^1.0.0",
|
|
28
|
+
"ajv-formats": "^2.1.1",
|
|
26
29
|
"flat-cache": "^3.0.4",
|
|
27
30
|
"got": "^11.8.0",
|
|
28
31
|
"is-url": "^1.2.4",
|
|
29
32
|
"js-yaml": "^4.0.0",
|
|
30
33
|
"minimatch": "^3.0.4",
|
|
31
|
-
"yargs": "^
|
|
34
|
+
"yargs": "^17.0.1"
|
|
32
35
|
},
|
|
33
36
|
"devDependencies": {
|
|
37
|
+
"c8": "^7.10.0",
|
|
34
38
|
"chai": "^4.2.0",
|
|
35
39
|
"chai-as-promised": "^7.1.1",
|
|
36
|
-
"eslint": "^
|
|
37
|
-
"eslint-config-prettier": "^
|
|
38
|
-
"eslint-plugin-mocha": "^
|
|
39
|
-
"eslint-plugin-prettier": "^
|
|
40
|
-
"mocha": "^
|
|
40
|
+
"eslint": "^8.0.1",
|
|
41
|
+
"eslint-config-prettier": "^8.1.0",
|
|
42
|
+
"eslint-plugin-mocha": "^9.0.0",
|
|
43
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
44
|
+
"mocha": "^9.0.0",
|
|
41
45
|
"nock": "^13.0.4",
|
|
42
|
-
"nyc": "^15.1.0",
|
|
43
46
|
"prettier": "^2.1.2"
|
|
44
47
|
},
|
|
45
48
|
"engines": {
|
|
46
|
-
"node": ">=
|
|
49
|
+
"node": "^12.20.0 || ^14.13.1 || >=15.0.0"
|
|
47
50
|
},
|
|
51
|
+
"type": "module",
|
|
48
52
|
"keywords": [
|
|
49
53
|
"JSON",
|
|
50
54
|
"YAML",
|
package/src/ajv.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createRequire } from "module";
|
|
2
|
+
// TODO: once JSON modules is stable these requires could become imports
|
|
3
|
+
// https://nodejs.org/api/esm.html#esm_experimental_json_modules
|
|
4
|
+
const require = createRequire(import.meta.url);
|
|
5
|
+
|
|
6
|
+
import AjvDraft4 from "ajv-draft-04";
|
|
7
|
+
import Ajv from "ajv";
|
|
8
|
+
import Ajv2019 from "ajv/dist/2019.js";
|
|
9
|
+
import Ajv2020 from "ajv/dist/2020.js";
|
|
10
|
+
import addFormats from "ajv-formats";
|
|
11
|
+
|
|
12
|
+
function _ajvFactory(schema, cache) {
|
|
13
|
+
const resolver = (url) => cache.fetch(url);
|
|
14
|
+
const opts = { loadSchema: resolver, strict: "log" };
|
|
15
|
+
|
|
16
|
+
if (
|
|
17
|
+
typeof schema["$schema"] === "string" ||
|
|
18
|
+
schema["$schema"] instanceof String
|
|
19
|
+
) {
|
|
20
|
+
if (schema["$schema"].includes("json-schema.org/draft-04/schema")) {
|
|
21
|
+
opts.schemaId = "auto";
|
|
22
|
+
return new AjvDraft4(opts);
|
|
23
|
+
} else if (schema["$schema"].includes("json-schema.org/draft-06/schema")) {
|
|
24
|
+
const ajvDraft06 = new Ajv(opts);
|
|
25
|
+
ajvDraft06.addMetaSchema(
|
|
26
|
+
require("ajv/lib/refs/json-schema-draft-06.json")
|
|
27
|
+
);
|
|
28
|
+
return ajvDraft06;
|
|
29
|
+
} else if (schema["$schema"].includes("json-schema.org/draft-07/schema")) {
|
|
30
|
+
return new Ajv(opts);
|
|
31
|
+
} else if (
|
|
32
|
+
schema["$schema"].includes("json-schema.org/draft/2019-09/schema")
|
|
33
|
+
) {
|
|
34
|
+
return new Ajv2019(opts);
|
|
35
|
+
} else if (
|
|
36
|
+
schema["$schema"].includes("json-schema.org/draft/2020-12/schema")
|
|
37
|
+
) {
|
|
38
|
+
return new Ajv2020(opts);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// hedge our bets as best we can
|
|
43
|
+
const ajv = new Ajv(opts);
|
|
44
|
+
ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-06.json"));
|
|
45
|
+
return ajv;
|
|
46
|
+
|
|
47
|
+
/* TODO:
|
|
48
|
+
const ajv = new Ajv2019(opts);
|
|
49
|
+
ajv.addMetaSchema(require("ajv/dist/refs/json-schema-draft-07.json"));
|
|
50
|
+
return ajv
|
|
51
|
+
|
|
52
|
+
might also be an equally valid fallback here
|
|
53
|
+
*/
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function validate(data, schema, cache) {
|
|
57
|
+
const ajv = _ajvFactory(schema, cache);
|
|
58
|
+
addFormats(ajv);
|
|
59
|
+
const validateFn = await ajv.compileAsync(schema);
|
|
60
|
+
const valid = validateFn(data);
|
|
61
|
+
if (!valid) {
|
|
62
|
+
console.log("\nErrors:");
|
|
63
|
+
console.log(validateFn.errors);
|
|
64
|
+
console.log("");
|
|
65
|
+
}
|
|
66
|
+
return valid;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { _ajvFactory, validate };
|
package/src/cache.js
CHANGED
|
@@ -1,66 +1,73 @@
|
|
|
1
|
-
|
|
1
|
+
import got from "got";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (!("timestamp" in cachedResponse) || !("body" in cachedResponse)) {
|
|
10
|
-
console.debug(`âšī¸ Cache error: deleting malformed response`);
|
|
11
|
-
cache.removeKey(url);
|
|
12
|
-
} else if (Date.now() > cachedResponse.timestamp + ttl) {
|
|
13
|
-
console.debug(`âšī¸ Cache stale: deleting cached response from ${url}`);
|
|
14
|
-
cache.removeKey(url);
|
|
15
|
-
}
|
|
16
|
-
cache.save(true);
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function limitDepth(url) {
|
|
21
|
-
/*
|
|
22
|
-
It is possible to create cyclic dependencies with external references
|
|
23
|
-
in JSON schema. Ajv doesn't detect this when resolving external references,
|
|
24
|
-
so we keep a count of how many times we've called the same URL.
|
|
25
|
-
If we are calling the same URL over and over we've probably hit a circular
|
|
26
|
-
external reference and we need to break the loop.
|
|
27
|
-
*/
|
|
28
|
-
if (url in callCounter) {
|
|
29
|
-
callCounter[url]++;
|
|
30
|
-
} else {
|
|
31
|
-
callCounter[url] = 1;
|
|
3
|
+
class Cache {
|
|
4
|
+
constructor(flatCache, ttl) {
|
|
5
|
+
this.cache = flatCache;
|
|
6
|
+
this.ttl = ttl;
|
|
7
|
+
this.callCounter = {};
|
|
8
|
+
this.callLimit = 10;
|
|
32
9
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
10
|
+
|
|
11
|
+
expire() {
|
|
12
|
+
Object.entries(this.cache.all()).forEach(
|
|
13
|
+
function ([url, cachedResponse]) {
|
|
14
|
+
if (!("timestamp" in cachedResponse) || !("body" in cachedResponse)) {
|
|
15
|
+
console.debug(`âšī¸ Cache error: deleting malformed response`);
|
|
16
|
+
this.cache.removeKey(url);
|
|
17
|
+
} else if (Date.now() > cachedResponse.timestamp + this.ttl) {
|
|
18
|
+
console.debug(`âšī¸ Cache stale: deleting cached response from ${url}`);
|
|
19
|
+
this.cache.removeKey(url);
|
|
20
|
+
}
|
|
21
|
+
this.cache.save(true);
|
|
22
|
+
}.bind(this)
|
|
36
23
|
);
|
|
37
24
|
}
|
|
38
|
-
}
|
|
39
25
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
26
|
+
limitDepth(url) {
|
|
27
|
+
/*
|
|
28
|
+
It is possible to create cyclic dependencies with external references
|
|
29
|
+
in JSON schema. Ajv doesn't detect this when resolving external references,
|
|
30
|
+
so we keep a count of how many times we've called the same URL.
|
|
31
|
+
If we are calling the same URL over and over we've probably hit a circular
|
|
32
|
+
external reference and we need to break the loop.
|
|
33
|
+
*/
|
|
34
|
+
if (url in this.callCounter) {
|
|
35
|
+
this.callCounter[url]++;
|
|
36
|
+
} else {
|
|
37
|
+
this.callCounter[url] = 1;
|
|
38
|
+
}
|
|
39
|
+
if (this.callCounter[url] > this.callLimit) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`â Called ${url} >${this.callLimit} times. Possible circular reference.`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
47
44
|
}
|
|
48
45
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
46
|
+
async fetch(url) {
|
|
47
|
+
this.limitDepth(url);
|
|
48
|
+
this.expire();
|
|
49
|
+
const cachedResponse = this.cache.getKey(url);
|
|
50
|
+
if (cachedResponse !== undefined) {
|
|
51
|
+
console.debug(`âšī¸ Cache hit: using cached response from ${url}`);
|
|
52
|
+
return cachedResponse.body;
|
|
56
53
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
console.debug(`âšī¸ Cache miss: calling ${url}`);
|
|
57
|
+
const resp = await got(url);
|
|
58
|
+
const parsedBody = JSON.parse(resp.body);
|
|
59
|
+
if (this.ttl > 0) {
|
|
60
|
+
this.cache.setKey(url, { timestamp: Date.now(), body: parsedBody });
|
|
61
|
+
this.cache.save(true);
|
|
62
|
+
}
|
|
63
|
+
return parsedBody;
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if (error.response) {
|
|
66
|
+
throw new Error(`â Failed fetching ${url}\n${error.response.body}`);
|
|
67
|
+
}
|
|
68
|
+
throw new Error(`â Failed fetching ${url}`);
|
|
61
69
|
}
|
|
62
|
-
throw new Error(`â Failed fetching ${url}`);
|
|
63
70
|
}
|
|
64
71
|
}
|
|
65
72
|
|
|
66
|
-
|
|
73
|
+
export { Cache };
|
package/src/cli.js
CHANGED
|
@@ -1,25 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const { cachedFetch } = require("./cache.js");
|
|
14
|
-
const logging = require("./logging.js");
|
|
1
|
+
import flatCache from "flat-cache";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import isUrl from "is-url";
|
|
4
|
+
import minimatch from "minimatch";
|
|
5
|
+
import os from "os";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import yaml from "js-yaml";
|
|
8
|
+
import yargs from "yargs";
|
|
9
|
+
import { hideBin } from "yargs/helpers";
|
|
10
|
+
import { validate } from "./ajv.js";
|
|
11
|
+
import { Cache } from "./cache.js";
|
|
12
|
+
import logging from "./logging.js";
|
|
15
13
|
|
|
16
14
|
const SCHEMASTORE_CATALOG_URL =
|
|
17
15
|
"https://www.schemastore.org/api/json/catalog.json";
|
|
16
|
+
|
|
17
|
+
const SCHEMASTORE_CATALOG_SCHEMA_URL =
|
|
18
|
+
"https://json.schemastore.org/schema-catalog.json";
|
|
19
|
+
|
|
18
20
|
const CACHE_DIR = path.join(os.tmpdir(), "flat-cache");
|
|
19
21
|
|
|
20
|
-
async function
|
|
21
|
-
|
|
22
|
+
async function getFromUrlOrFile(location, cache) {
|
|
23
|
+
return isUrl(location)
|
|
24
|
+
? await cache.fetch(location)
|
|
25
|
+
: JSON.parse(fs.readFileSync(location, "utf8").toString());
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function getSchemaUrlForFilename(catalogs, filename, cache) {
|
|
29
|
+
for (const [i, catalogLocation] of catalogs.entries()) {
|
|
30
|
+
const catalog = await getFromUrlOrFile(catalogLocation, cache);
|
|
31
|
+
const catalogSchema = await getFromUrlOrFile(
|
|
32
|
+
SCHEMASTORE_CATALOG_SCHEMA_URL,
|
|
33
|
+
cache
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// Validate the catalog
|
|
37
|
+
const valid = await validate(catalog, catalogSchema, cache);
|
|
38
|
+
if (!valid || catalog.schemas === undefined) {
|
|
39
|
+
throw new Error(`â Malformed catalog at ${catalogLocation}`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const { schemas } = catalog;
|
|
43
|
+
const matches = getSchemaMatchesForFilename(schemas, filename);
|
|
44
|
+
console.debug(`âšī¸ Searching for schema in ${catalogLocation} ...`);
|
|
45
|
+
if (matches.length === 1) {
|
|
46
|
+
console.log(`âšī¸ Found schema in ${catalogLocation} ...`);
|
|
47
|
+
return matches[0].url; // Match found. We're done.
|
|
48
|
+
}
|
|
49
|
+
if (matches.length === 0 && i < catalogs.length - 1) {
|
|
50
|
+
continue; // No match found. Try the next catalog in the array.
|
|
51
|
+
}
|
|
52
|
+
if (matches.length > 1) {
|
|
53
|
+
// We found >1 matches in the same catalog. This is always a hard error.
|
|
54
|
+
console.log(
|
|
55
|
+
`Found multiple possible schemas for ${filename}. Possible matches:`
|
|
56
|
+
);
|
|
57
|
+
matches.forEach(function (match) {
|
|
58
|
+
console.log(`${match.description}: ${match.url}`);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
// Either we found >1 matches in the same catalog or we found 0 matches
|
|
62
|
+
// in the last catalog and there are no more catalogs left to try.
|
|
63
|
+
throw new Error(`â Could not find a schema to validate ${filename}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
22
66
|
|
|
67
|
+
function getSchemaMatchesForFilename(schemas, filename) {
|
|
23
68
|
const matches = [];
|
|
24
69
|
schemas.forEach(function (schema) {
|
|
25
70
|
if ("fileMatch" in schema) {
|
|
@@ -35,33 +80,7 @@ async function getSchemaUrlForFilename(filename, cache, ttl) {
|
|
|
35
80
|
}
|
|
36
81
|
}
|
|
37
82
|
});
|
|
38
|
-
|
|
39
|
-
if (matches.length === 1) {
|
|
40
|
-
return matches[0].url;
|
|
41
|
-
}
|
|
42
|
-
if (matches.length > 1) {
|
|
43
|
-
console.log(
|
|
44
|
-
`Found multiple possible schemas for ${filename}. Possible matches:`
|
|
45
|
-
);
|
|
46
|
-
matches.forEach(function (match) {
|
|
47
|
-
console.log(`${match.description}: ${match.url}`);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
throw new Error(`â Could not find a schema to validate ${filename}`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function validate(data, schema, resolver) {
|
|
54
|
-
const ajv = new Ajv({ schemaId: "auto", loadSchema: resolver });
|
|
55
|
-
ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-04.json"));
|
|
56
|
-
ajv.addMetaSchema(require("ajv/lib/refs/json-schema-draft-06.json"));
|
|
57
|
-
const validate = await ajv.compileAsync(schema);
|
|
58
|
-
const valid = validate(data);
|
|
59
|
-
if (!valid) {
|
|
60
|
-
console.log("\nErrors:");
|
|
61
|
-
console.log(validate.errors);
|
|
62
|
-
console.log("");
|
|
63
|
-
}
|
|
64
|
-
return valid;
|
|
83
|
+
return matches;
|
|
65
84
|
}
|
|
66
85
|
|
|
67
86
|
function parseFile(contents, format) {
|
|
@@ -82,7 +101,7 @@ function secondsToMilliseconds(seconds) {
|
|
|
82
101
|
return seconds * 1000;
|
|
83
102
|
}
|
|
84
103
|
|
|
85
|
-
function
|
|
104
|
+
function getFlatCache() {
|
|
86
105
|
if (process.env.V8R_CACHE_NAME) {
|
|
87
106
|
return flatCache.load(process.env.V8R_CACHE_NAME);
|
|
88
107
|
}
|
|
@@ -90,35 +109,29 @@ function getCache() {
|
|
|
90
109
|
}
|
|
91
110
|
|
|
92
111
|
function Validator() {
|
|
93
|
-
const cache = getCache();
|
|
94
|
-
|
|
95
112
|
return async function (args) {
|
|
96
113
|
const filename = args.filename;
|
|
97
114
|
const ttl = secondsToMilliseconds(args.cacheTtl || 0);
|
|
115
|
+
const cache = new Cache(getFlatCache(), ttl);
|
|
98
116
|
|
|
99
117
|
const data = parseFile(
|
|
100
118
|
fs.readFileSync(filename, "utf8").toString(),
|
|
101
119
|
path.extname(filename)
|
|
102
120
|
);
|
|
121
|
+
|
|
103
122
|
const schemaLocation =
|
|
104
|
-
args.schema ||
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
) {
|
|
112
|
-
throw new Error(`â Unsupported JSON schema version ${schema.$schema}`);
|
|
113
|
-
}
|
|
123
|
+
args.schema ||
|
|
124
|
+
(await getSchemaUrlForFilename(
|
|
125
|
+
(args.catalogs || []).concat([SCHEMASTORE_CATALOG_URL]),
|
|
126
|
+
filename,
|
|
127
|
+
cache
|
|
128
|
+
));
|
|
129
|
+
const schema = await getFromUrlOrFile(schemaLocation, cache);
|
|
114
130
|
console.log(
|
|
115
131
|
`Validating ${filename} against schema from ${schemaLocation} ...`
|
|
116
132
|
);
|
|
117
133
|
|
|
118
|
-
const
|
|
119
|
-
return cachedFetch(url, cache, ttl);
|
|
120
|
-
};
|
|
121
|
-
const valid = await validate(data, schema, resolver);
|
|
134
|
+
const valid = await validate(data, schema, cache);
|
|
122
135
|
if (valid) {
|
|
123
136
|
console.log(`â
${filename} is valid`);
|
|
124
137
|
} else {
|
|
@@ -169,6 +182,14 @@ function parseArgs(argv) {
|
|
|
169
182
|
describe:
|
|
170
183
|
"Local path or URL of schema to validate file against. If not supplied, we will attempt to find an appropriate schema on schemastore.org using the filename",
|
|
171
184
|
})
|
|
185
|
+
.option("catalogs", {
|
|
186
|
+
type: "string",
|
|
187
|
+
alias: "c",
|
|
188
|
+
array: true,
|
|
189
|
+
describe:
|
|
190
|
+
"Local path or URL of custom catalogs to use prior to schemastore.org",
|
|
191
|
+
})
|
|
192
|
+
.conflicts("schema", "catalogs")
|
|
172
193
|
.option("ignore-errors", {
|
|
173
194
|
type: "boolean",
|
|
174
195
|
default: false,
|
|
@@ -183,4 +204,4 @@ function parseArgs(argv) {
|
|
|
183
204
|
}).argv;
|
|
184
205
|
}
|
|
185
206
|
|
|
186
|
-
|
|
207
|
+
export { cli, parseArgs };
|
package/src/index.js
CHANGED
package/src/logging.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
1
|
const origWarn = console.warn;
|
|
4
2
|
const origInfo = console.info;
|
|
5
3
|
const origDebug = console.debug;
|
|
@@ -19,4 +17,5 @@ function cleanup() {
|
|
|
19
17
|
console.debug = origDebug;
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
const logging = { cleanup, init };
|
|
21
|
+
export default logging;
|