v8r 2.0.0 → 2.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 +4 -0
- package/package.json +6 -6
- package/src/ajv.js +2 -2
- package/src/cache.js +4 -3
- package/src/catalogs.js +5 -5
- package/src/cli.js +5 -5
- package/src/config.js +7 -7
- package/src/io.js +5 -3
- package/src/output-formatters.js +1 -1
- package/src/parser.js +14 -2
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "v8r",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "A command-line JSON and YAML validator that's on your wavelength",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "V8R_CACHE_NAME=v8r-test c8 --reporter=text mocha \"src/**/*.spec.js\"",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"decamelize": "^6.0.0",
|
|
37
37
|
"flat-cache": "^3.0.4",
|
|
38
38
|
"glob": "^10.1.0",
|
|
39
|
-
"got": "^
|
|
39
|
+
"got": "^13.0.0",
|
|
40
40
|
"is-url": "^1.2.4",
|
|
41
41
|
"js-yaml": "^4.0.0",
|
|
42
42
|
"json5": "^2.2.0",
|
|
@@ -44,17 +44,17 @@
|
|
|
44
44
|
"yargs": "^17.0.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"c8": "^
|
|
47
|
+
"c8": "^8.0.0",
|
|
48
48
|
"chai": "^4.2.0",
|
|
49
49
|
"chai-as-promised": "^7.1.1",
|
|
50
50
|
"eslint": "^8.0.1",
|
|
51
|
-
"eslint-config-prettier": "^
|
|
51
|
+
"eslint-config-prettier": "^9.0.0",
|
|
52
52
|
"eslint-plugin-mocha": "^10.0.3",
|
|
53
|
-
"eslint-plugin-prettier": "^
|
|
53
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
54
54
|
"mocha": "^10.0.0",
|
|
55
55
|
"mock-cwd": "^1.0.0",
|
|
56
56
|
"nock": "^13.0.4",
|
|
57
|
-
"prettier": "^
|
|
57
|
+
"prettier": "^3.0.0"
|
|
58
58
|
},
|
|
59
59
|
"engines": {
|
|
60
60
|
"node": ">=16"
|
package/src/ajv.js
CHANGED
|
@@ -13,7 +13,7 @@ function _ajvFactory(
|
|
|
13
13
|
schema,
|
|
14
14
|
strictMode,
|
|
15
15
|
cache,
|
|
16
|
-
resolver = (url) => cache.fetch(url)
|
|
16
|
+
resolver = (url) => cache.fetch(url),
|
|
17
17
|
) {
|
|
18
18
|
const opts = { allErrors: true, loadSchema: resolver, strict: strictMode };
|
|
19
19
|
|
|
@@ -27,7 +27,7 @@ function _ajvFactory(
|
|
|
27
27
|
} else if (schema["$schema"].includes("json-schema.org/draft-06/schema")) {
|
|
28
28
|
const ajvDraft06 = new Ajv(opts);
|
|
29
29
|
ajvDraft06.addMetaSchema(
|
|
30
|
-
require("ajv/lib/refs/json-schema-draft-06.json")
|
|
30
|
+
require("ajv/lib/refs/json-schema-draft-06.json"),
|
|
31
31
|
);
|
|
32
32
|
return ajvDraft06;
|
|
33
33
|
} else if (schema["$schema"].includes("json-schema.org/draft-07/schema")) {
|
package/src/cache.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import got from "got";
|
|
2
2
|
import logger from "./logger.js";
|
|
3
|
+
import { parseSchema } from "./parser.js";
|
|
3
4
|
|
|
4
5
|
class Cache {
|
|
5
6
|
constructor(flatCache, ttl) {
|
|
@@ -20,7 +21,7 @@ class Cache {
|
|
|
20
21
|
this.cache.removeKey(url);
|
|
21
22
|
}
|
|
22
23
|
this.cache.save(true);
|
|
23
|
-
}.bind(this)
|
|
24
|
+
}.bind(this),
|
|
24
25
|
);
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -39,7 +40,7 @@ class Cache {
|
|
|
39
40
|
}
|
|
40
41
|
if (this.callCounter[url] > this.callLimit) {
|
|
41
42
|
throw new Error(
|
|
42
|
-
`Called ${url} >${this.callLimit} times. Possible circular reference
|
|
43
|
+
`Called ${url} >${this.callLimit} times. Possible circular reference.`,
|
|
43
44
|
);
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -60,7 +61,7 @@ class Cache {
|
|
|
60
61
|
try {
|
|
61
62
|
logger.debug(`Cache miss: calling ${url}`);
|
|
62
63
|
const resp = await got(url);
|
|
63
|
-
const parsedBody =
|
|
64
|
+
const parsedBody = parseSchema(resp.body, url);
|
|
64
65
|
if (this.ttl > 0) {
|
|
65
66
|
this.cache.setKey(url, { timestamp: Date.now(), body: parsedBody });
|
|
66
67
|
this.cache.save(true);
|
package/src/catalogs.js
CHANGED
|
@@ -32,7 +32,7 @@ function getCatalogs(config) {
|
|
|
32
32
|
catalogs = catalogs.concat(
|
|
33
33
|
config.catalogs.map(function (loc) {
|
|
34
34
|
return { location: loc };
|
|
35
|
-
})
|
|
35
|
+
}),
|
|
36
36
|
);
|
|
37
37
|
}
|
|
38
38
|
catalogs.push({ location: SCHEMASTORE_CATALOG_URL });
|
|
@@ -83,7 +83,7 @@ async function getMatchForFilename(catalogs, filename, cache) {
|
|
|
83
83
|
if (!rec.catalog) {
|
|
84
84
|
const catalogSchema = await getFromUrlOrFile(
|
|
85
85
|
SCHEMASTORE_CATALOG_SCHEMA_URL,
|
|
86
|
-
cache
|
|
86
|
+
cache,
|
|
87
87
|
);
|
|
88
88
|
|
|
89
89
|
// Validate the catalog
|
|
@@ -92,7 +92,7 @@ async function getMatchForFilename(catalogs, filename, cache) {
|
|
|
92
92
|
catalog,
|
|
93
93
|
catalogSchema,
|
|
94
94
|
strictMode,
|
|
95
|
-
cache
|
|
95
|
+
cache,
|
|
96
96
|
);
|
|
97
97
|
if (!valid || catalog.schemas === undefined) {
|
|
98
98
|
throw new Error(`Malformed catalog at ${catalogLocation}`);
|
|
@@ -123,10 +123,10 @@ async function getMatchForFilename(catalogs, filename, cache) {
|
|
|
123
123
|
// We found >1 matches in the same catalog. This is always a hard error.
|
|
124
124
|
const matchesLog = getMultipleMatchesLogMessage(matches);
|
|
125
125
|
logger.info(
|
|
126
|
-
`Found multiple possible matches for ${filename}. Possible matches:\n\n${matchesLog}
|
|
126
|
+
`Found multiple possible matches for ${filename}. Possible matches:\n\n${matchesLog}`,
|
|
127
127
|
);
|
|
128
128
|
throw new Error(
|
|
129
|
-
`Found multiple possible schemas to validate ${filename}
|
|
129
|
+
`Found multiple possible schemas to validate ${filename}`,
|
|
130
130
|
);
|
|
131
131
|
}
|
|
132
132
|
|
package/src/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import { getFiles } from "./glob.js";
|
|
|
11
11
|
import { getFromUrlOrFile } from "./io.js";
|
|
12
12
|
import logger from "./logger.js";
|
|
13
13
|
import { logErrors, resultsToJson } from "./output-formatters.js";
|
|
14
|
-
import {
|
|
14
|
+
import { parseDocument } from "./parser.js";
|
|
15
15
|
|
|
16
16
|
const EXIT = {
|
|
17
17
|
VALID: 0,
|
|
@@ -52,12 +52,12 @@ async function validateFile(filename, config, cache) {
|
|
|
52
52
|
result.schemaLocation = schemaLocation;
|
|
53
53
|
const schema = await getFromUrlOrFile(schemaLocation, cache);
|
|
54
54
|
logger.info(
|
|
55
|
-
`Validating ${filename} against schema from ${schemaLocation}
|
|
55
|
+
`Validating ${filename} against schema from ${schemaLocation} ...`,
|
|
56
56
|
);
|
|
57
57
|
|
|
58
|
-
const data =
|
|
58
|
+
const data = parseDocument(
|
|
59
59
|
await fs.promises.readFile(filename, "utf8"),
|
|
60
|
-
catalogMatch.parser ? `.${catalogMatch.parser}` : path.extname(filename)
|
|
60
|
+
catalogMatch.parser ? `.${catalogMatch.parser}` : path.extname(filename),
|
|
61
61
|
);
|
|
62
62
|
|
|
63
63
|
const strictMode = config.verbose >= 2 ? "log" : false;
|
|
@@ -70,7 +70,7 @@ async function validateFile(filename, config, cache) {
|
|
|
70
70
|
schema,
|
|
71
71
|
strictMode,
|
|
72
72
|
cache,
|
|
73
|
-
resolver
|
|
73
|
+
resolver,
|
|
74
74
|
);
|
|
75
75
|
result.valid = valid;
|
|
76
76
|
result.errors = errors;
|
package/src/config.js
CHANGED
|
@@ -21,7 +21,7 @@ function validateConfig(configFile) {
|
|
|
21
21
|
if (!valid) {
|
|
22
22
|
logErrors(
|
|
23
23
|
configFile.filepath ? configFile.filepath : "",
|
|
24
|
-
validateFn.errors
|
|
24
|
+
validateFn.errors,
|
|
25
25
|
);
|
|
26
26
|
throw new Error("Malformed config file");
|
|
27
27
|
}
|
|
@@ -36,7 +36,7 @@ function preProcessConfig(configFile) {
|
|
|
36
36
|
if (!path.isAbsolute(schema.location) && !isUrl(schema.location)) {
|
|
37
37
|
schema.location = path.join(
|
|
38
38
|
path.dirname(configFile.filepath),
|
|
39
|
-
schema.location
|
|
39
|
+
schema.location,
|
|
40
40
|
);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -45,7 +45,7 @@ function preProcessConfig(configFile) {
|
|
|
45
45
|
async function getCosmiConfig(cosmiconfigOptions) {
|
|
46
46
|
cosmiconfigOptions.stopDir = process.cwd();
|
|
47
47
|
const configFile = (await cosmiconfig("v8r", cosmiconfigOptions).search(
|
|
48
|
-
process.cwd()
|
|
48
|
+
process.cwd(),
|
|
49
49
|
)) || { config: {} };
|
|
50
50
|
if (configFile.filepath) {
|
|
51
51
|
logger.info(`Loaded config file from ${getRelativeFilePath(configFile)}`);
|
|
@@ -84,7 +84,7 @@ function parseArgs(argv, config) {
|
|
|
84
84
|
command = "$0 [patterns..]";
|
|
85
85
|
patternsOpts.default = config.config.patterns;
|
|
86
86
|
patternsOpts.defaultDescription = `${JSON.stringify(
|
|
87
|
-
config.config.patterns
|
|
87
|
+
config.config.patterns,
|
|
88
88
|
)} (from config file ${getRelativeFilePath(config)})`;
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -94,12 +94,12 @@ function parseArgs(argv, config) {
|
|
|
94
94
|
"Validate local json/yaml files against schema(s)",
|
|
95
95
|
(yargs) => {
|
|
96
96
|
yargs.positional("patterns", patternsOpts);
|
|
97
|
-
}
|
|
97
|
+
},
|
|
98
98
|
)
|
|
99
99
|
.version(
|
|
100
100
|
// Workaround for https://github.com/yargs/yargs/issues/1934
|
|
101
101
|
// TODO: remove once fixed
|
|
102
|
-
require("../package.json").version
|
|
102
|
+
require("../package.json").version,
|
|
103
103
|
)
|
|
104
104
|
.option("verbose", {
|
|
105
105
|
alias: "v",
|
|
@@ -160,7 +160,7 @@ function parseArgs(argv, config) {
|
|
|
160
160
|
parser.default(
|
|
161
161
|
decamelize(key, { separator: "-" }),
|
|
162
162
|
value,
|
|
163
|
-
`${value} (from config file ${getRelativeFilePath(config)})
|
|
163
|
+
`${value} (from config file ${getRelativeFilePath(config)})`,
|
|
164
164
|
);
|
|
165
165
|
}
|
|
166
166
|
}
|
package/src/io.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import isUrl from "is-url";
|
|
4
|
+
import { parseSchema } from "./parser.js";
|
|
4
5
|
|
|
5
6
|
async function getFromUrlOrFile(location, cache, base = null) {
|
|
6
7
|
if (isUrl(location)) {
|
|
7
8
|
return await cache.fetch(location);
|
|
8
9
|
} else {
|
|
9
10
|
if (base != null) {
|
|
10
|
-
return
|
|
11
|
-
await fs.promises.readFile(path.join(base, location), "utf8")
|
|
11
|
+
return parseSchema(
|
|
12
|
+
await fs.promises.readFile(path.join(base, location), "utf8"),
|
|
13
|
+
path.join(base, location),
|
|
12
14
|
);
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
|
-
return
|
|
17
|
+
return parseSchema(await fs.promises.readFile(location, "utf8"), location);
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export { getFromUrlOrFile };
|
package/src/output-formatters.js
CHANGED
package/src/parser.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import JSON5 from "json5";
|
|
2
2
|
import yaml from "js-yaml";
|
|
3
3
|
|
|
4
|
-
function
|
|
4
|
+
function parseDocument(contents, format) {
|
|
5
5
|
switch (format) {
|
|
6
6
|
case ".json":
|
|
7
7
|
case ".geojson":
|
|
@@ -18,4 +18,16 @@ function parseFile(contents, format) {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
function parseSchema(contents, location) {
|
|
22
|
+
if (location.endsWith(".yml") || location.endsWith(".yaml")) {
|
|
23
|
+
return yaml.load(contents);
|
|
24
|
+
}
|
|
25
|
+
/*
|
|
26
|
+
Always fall back and assume json even if no .json extension
|
|
27
|
+
Sometimes a JSON schema is served from a URL like
|
|
28
|
+
https://json-stat.org/format/schema/2.0/
|
|
29
|
+
*/
|
|
30
|
+
return JSON.parse(contents);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { parseDocument, parseSchema };
|