Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

v8r

Package Overview
Dependencies
Maintainers
0
Versions
31
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

v8r - npm Package Compare versions

Comparing version 4.0.1 to 4.1.0

8

CHANGELOG.md
# Changelog
## 📦 [4.1.0](https://www.npmjs.com/package/v8r/v/4.1.0) - 2024-08-25
* v8r can now parse and validate files that contain multiple yaml documents
More info: https://chris48s.github.io/v8r/usage-examples/#files-containing-multiple-documents
* The `parseInputFile()` plugin hook may now tionally return an array of `Document` objects
* The `ValidationResult` object now contains a `documentIndex` property.
This identifies the document when a multi-doc file has been validated.
## 📦 [4.0.1](https://www.npmjs.com/package/v8r/v/4.0.1) - 2024-08-19

@@ -4,0 +12,0 @@

2

package.json
{
"name": "v8r",
"version": "4.0.1",
"version": "4.1.0",
"description": "A command-line JSON, YAML and TOML validator that's on your wavelength",

@@ -5,0 +5,0 @@ "scripts": {

@@ -13,2 +13,3 @@ import flatCache from "flat-cache";

import logger from "./logger.js";
import { getDocumentLocation } from "./output-formatters.js";
import { parseFile } from "./parser.js";

@@ -37,7 +38,16 @@

async function validateFile(filename, config, plugins, cache) {
logger.info(`Processing ${filename}`);
async function validateDocument(
fileLocation,
documentIndex,
document,
schemaLocation,
schema,
strictMode,
cache,
resolver,
) {
let result = {
fileLocation: filename,
schemaLocation: null,
fileLocation,
documentIndex,
schemaLocation,
valid: null,

@@ -48,2 +58,34 @@ errors: [],

try {
const { valid, errors } = await validate(
document,
schema,
strictMode,
cache,
resolver,
);
result.valid = valid;
result.errors = errors;
const documentLocation = getDocumentLocation(result);
if (valid) {
logger.success(`${documentLocation} is valid\n`);
} else {
logger.error(`${documentLocation} is invalid\n`);
}
result.code = valid ? EXIT.VALID : EXIT.INVALID;
return result;
} catch (e) {
logger.error(`${e.message}\n`);
result.code = EXIT.ERROR;
return result;
}
}
async function validateFile(filename, config, plugins, cache) {
logger.info(`Processing ${filename}`);
let schema, schemaLocation, documents, strictMode, resolver;
try {
const catalogs = getCatalogs(config);

@@ -53,5 +95,4 @@ const catalogMatch = config.schema

: await getMatchForFilename(catalogs, filename, cache);
const schemaLocation = config.schema || catalogMatch.location;
result.schemaLocation = schemaLocation;
const schema = await getFromUrlOrFile(schemaLocation, cache);
schemaLocation = config.schema || catalogMatch.location;
schema = await getFromUrlOrFile(schemaLocation, cache);
logger.info(

@@ -61,3 +102,3 @@ `Validating ${filename} against schema from ${schemaLocation} ...`,

const data = parseFile(
documents = parseFile(
plugins,

@@ -69,9 +110,29 @@ await fs.promises.readFile(filename, "utf8"),

const strictMode = config.verbose >= 2 ? "log" : false;
const resolver = isUrl(schemaLocation)
strictMode = config.verbose >= 2 ? "log" : false;
resolver = isUrl(schemaLocation)
? (location) => getFromUrlOrFile(location, cache)
: (location) =>
getFromUrlOrFile(location, cache, path.dirname(schemaLocation));
const { valid, errors } = await validate(
data,
} catch (e) {
logger.error(`${e.message}\n`);
return [
{
fileLocation: filename,
documentIndex: null,
schemaLocation: schemaLocation || null,
valid: null,
errors: [],
code: EXIT.ERROR,
},
];
}
let results = [];
for (let i = 0; i < documents.length; i++) {
const documentIndex = documents.length === 1 ? null : i;
const result = await validateDocument(
filename,
documentIndex,
documents[i],
schemaLocation,
schema,

@@ -82,17 +143,18 @@ strictMode,

);
result.valid = valid;
result.errors = errors;
if (valid) {
logger.success(`${filename} is valid\n`);
} else {
logger.error(`${filename} is invalid\n`);
results.push(result);
for (const plugin of plugins) {
const message = plugin.getSingleResultLogMessage(
result,
filename,
config.format,
);
if (message != null) {
logger.log(message);
break;
}
}
result.code = valid ? EXIT.VALID : EXIT.INVALID;
return result;
} catch (e) {
logger.error(`${e.message}\n`);
result.code = EXIT.ERROR;
return result;
}
return results;
}

@@ -132,17 +194,4 @@

for (const filename of filenames) {
const result = await validateFile(filename, config, plugins, cache);
results.push(result);
for (const plugin of plugins) {
const message = plugin.getSingleResultLogMessage(
result,
filename,
config.format,
);
if (message != null) {
logger.log(message);
break;
}
}
const fileResults = await validateFile(filename, config, plugins, cache);
results = results.concat(fileResults);
cache.resetCounters();

@@ -149,0 +198,0 @@ }

import Ajv from "ajv";
function formatErrors(filename, errors) {
function getDocumentLocation(result) {
if (result.documentIndex == null) {
return result.fileLocation;
}
return `${result.fileLocation}[${result.documentIndex}]`;
}
function formatErrors(location, errors) {
const ajv = new Ajv();

@@ -8,3 +15,3 @@ return (

separator: "\n",
dataVar: filename + "#",
dataVar: location + "#",
}) + "\n"

@@ -14,2 +21,2 @@ );

export { formatErrors };
export { formatErrors, getDocumentLocation };

@@ -7,10 +7,16 @@ import path from "path";

for (const plugin of plugins) {
const result = plugin.parseInputFile(contents, filename, parser);
if (result != null) {
if (!(result instanceof Document)) {
throw new Error(
`Plugin ${plugin.constructor.name} returned an unexpected type from parseInputFile hook. Expected Document, got ${typeof result}`,
);
const parsedFile = plugin.parseInputFile(contents, filename, parser);
if (parsedFile != null) {
const maybeDocuments = Array.isArray(parsedFile)
? parsedFile
: [parsedFile];
for (const doc of maybeDocuments) {
if (!(doc instanceof Document)) {
throw new Error(
`Plugin ${plugin.constructor.name} returned an unexpected type from parseInputFile hook. Expected Document, got ${typeof doc}`,
);
}
}
return result.document;
return maybeDocuments.map((md) => md.document);
}

@@ -17,0 +23,0 @@ }

@@ -35,3 +35,4 @@ import path from "path";

* `parseInputFile` returns undefined, v8r will move on to the next plugin in
* the stack.
* the stack. The result of successfully parsing a file can either be a single
* Document object or an array of Document objects.
*

@@ -47,3 +48,3 @@ * @param {string} contents - The unparsed file content.

* `parseInputFile` in the `parser` param.
* @returns {Document | undefined} Parsed file contents
* @returns {Document | Document[] | undefined} Parsed file contents
*/

@@ -210,2 +211,8 @@ // eslint-disable-next-line no-unused-vars

* filename or pattern.
* @property {number | null} documentIndex - Some file formats allow multiple
* documents to be embedded in one file (e.g:
* [yaml](https://www.yaml.info/learn/document.html)). In these cases,
* `documentIndex` identifies is used to identify the sub document within the
* file. `documentIndex` will be `null` when there is a one-to-one
* relationship between file and document.
* @property {string | null} schemaLocation - Location of the schema used to

@@ -212,0 +219,0 @@ * validate this file if one could be found. `null` if no schema was found.

import { BasePlugin } from "../plugins.js";
import { formatErrors } from "../output-formatters.js";
import { formatErrors, getDocumentLocation } from "../output-formatters.js";

@@ -13,3 +13,3 @@ class TextOutput extends BasePlugin {

if (result.valid === false && format === "text") {
return formatErrors(fileLocation, result.errors);
return formatErrors(getDocumentLocation(result), result.errors);
}

@@ -16,0 +16,0 @@ }

@@ -13,6 +13,6 @@ import yaml from "js-yaml";

if (parser === "yaml") {
return new Document(yaml.load(contents));
return yaml.loadAll(contents).map((doc) => new Document(doc));
} else if (parser == null) {
if (fileLocation.endsWith(".yaml") || fileLocation.endsWith(".yml")) {
return new Document(yaml.load(contents));
return yaml.loadAll(contents).map((doc) => new Document(doc));
}

@@ -19,0 +19,0 @@ }

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc