v8r 2.0.0 → 3.0.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 CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 📦 [3.0.0](https://www.npmjs.com/package/v8r/v/3.0.0) - 2024-01-25
4
+
5
+ * Drop compatibility with node 16
6
+ * Add ability to validate Toml documents
7
+
8
+ ## 📦 [2.1.0](https://www.npmjs.com/package/v8r/v/2.1.0) - 2023-10-23
9
+
10
+ * Add compatibility with JSON schemas serialized as Yaml
11
+
3
12
  ## 📦 [2.0.0](https://www.npmjs.com/package/v8r/v/2.0.0) - 2023-05-02
4
13
 
5
14
  * Drop compatibility with node 14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "v8r",
3
- "version": "2.0.0",
3
+ "version": "3.0.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\"",
@@ -32,32 +32,31 @@
32
32
  "ajv-draft-04": "^1.0.0",
33
33
  "ajv-formats": "^2.1.1",
34
34
  "chalk": "^5.0.0",
35
- "cosmiconfig": "^8.0.0",
35
+ "cosmiconfig": "^9.0.0",
36
36
  "decamelize": "^6.0.0",
37
- "flat-cache": "^3.0.4",
37
+ "flat-cache": "^4.0.0",
38
38
  "glob": "^10.1.0",
39
- "got": "^12.0.1",
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",
43
43
  "minimatch": "^9.0.0",
44
+ "smol-toml": "^1.0.1",
44
45
  "yargs": "^17.0.1"
45
46
  },
46
47
  "devDependencies": {
47
- "c8": "^7.10.0",
48
- "chai": "^4.2.0",
49
- "chai-as-promised": "^7.1.1",
48
+ "c8": "^9.1.0",
50
49
  "eslint": "^8.0.1",
51
- "eslint-config-prettier": "^8.1.0",
50
+ "eslint-config-prettier": "^9.0.0",
52
51
  "eslint-plugin-mocha": "^10.0.3",
53
- "eslint-plugin-prettier": "^4.0.0",
52
+ "eslint-plugin-prettier": "^5.0.0",
54
53
  "mocha": "^10.0.0",
55
54
  "mock-cwd": "^1.0.0",
56
55
  "nock": "^13.0.4",
57
- "prettier": "^2.1.2"
56
+ "prettier": "^3.0.0"
58
57
  },
59
58
  "engines": {
60
- "node": ">=16"
59
+ "node": ">=18"
61
60
  },
62
61
  "type": "module",
63
62
  "keywords": [
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 = JSON.parse(resp.body);
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 { parseFile } from "./parser.js";
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 = parseFile(
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/index.js CHANGED
@@ -2,7 +2,5 @@
2
2
 
3
3
  import { cli } from "./cli.js";
4
4
 
5
- (async () => {
6
- const exitCode = await cli();
7
- process.exit(exitCode);
8
- })();
5
+ const exitCode = await cli();
6
+ process.exit(exitCode);
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 JSON.parse(
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 JSON.parse(await fs.promises.readFile(location, "utf8"));
17
+ return parseSchema(await fs.promises.readFile(location, "utf8"), location);
16
18
  }
17
19
 
18
20
  export { getFromUrlOrFile };
@@ -7,7 +7,7 @@ function logErrors(filename, errors) {
7
7
  ajv.errorsText(errors, {
8
8
  separator: "\n",
9
9
  dataVar: filename + "#",
10
- })
10
+ }),
11
11
  );
12
12
  logger.log("");
13
13
  }
package/src/parser.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import JSON5 from "json5";
2
2
  import yaml from "js-yaml";
3
+ import { parse } from "smol-toml";
3
4
 
4
- function parseFile(contents, format) {
5
+ function parseDocument(contents, format) {
5
6
  switch (format) {
6
7
  case ".json":
7
8
  case ".geojson":
@@ -13,9 +14,23 @@ function parseFile(contents, format) {
13
14
  case ".yml":
14
15
  case ".yaml":
15
16
  return yaml.load(contents);
17
+ case ".toml":
18
+ return parse(contents);
16
19
  default:
17
20
  throw new Error(`Unsupported format ${format}`);
18
21
  }
19
22
  }
20
23
 
21
- export { parseFile };
24
+ function parseSchema(contents, location) {
25
+ if (location.endsWith(".yml") || location.endsWith(".yaml")) {
26
+ return yaml.load(contents);
27
+ }
28
+ /*
29
+ Always fall back and assume json even if no .json extension
30
+ Sometimes a JSON schema is served from a URL like
31
+ https://json-stat.org/format/schema/2.0/
32
+ */
33
+ return JSON.parse(contents);
34
+ }
35
+
36
+ export { parseDocument, parseSchema };
@@ -1,10 +1,6 @@
1
- import chai from "chai";
2
- import chaiAsPromised from "chai-as-promised";
3
1
  import flatCache from "flat-cache";
4
2
  import logger from "./logger.js";
5
3
 
6
- chai.use(chaiAsPromised);
7
-
8
4
  const origWriteOut = logger.writeOut;
9
5
  const origWriteErr = logger.writeErr;
10
6
  const testCacheName = process.env.V8R_CACHE_NAME;
@@ -48,7 +44,6 @@ function logContainsError(expectedString, expectedCount = 1) {
48
44
  }
49
45
 
50
46
  export {
51
- chai,
52
47
  testCacheName,
53
48
  setUp,
54
49
  tearDown,