UNPKG

@microsoft/jest-sarif

Version:

A collection of jest matchers for working with SARIF

139 lines 5.64 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildMatcher = void 0; const tslib_1 = require("tslib"); const os_1 = require("os"); const ajv_1 = tslib_1.__importDefault(require("ajv")); const jest_matcher_utils_1 = require("jest-matcher-utils"); const chalk_1 = tslib_1.__importDefault(require("chalk")); // Keywords where the `Expected: ...` output is hidden const ERROR_KEYWORDS_HIDE_EXPECTED = new Set([ 'type', // String 'pattern', 'format', 'minLength', 'maxLength', // Number 'minimum', 'maximum', 'exclusiveMinimum', 'exclusiveMaximum', 'multipleOf', // Object 'minProperties', 'maxProperties', 'required', // Array 'minItems', 'maxItems', ]); const ERROR_KEYWORDS_SHOW_RECEIVED = new Set(['if', 'not']); const isObject = (value) => value !== null && typeof value === 'object'; const sarifV2Schema = require('./schemas/sarif-2.1.0-rtm.5.json'); let ajv; const formatForPrint = (input, displayType = true) => { if (input === undefined || input === null) { return chalk_1.default.yellow(`<${input}>`); } if (input === '') { return chalk_1.default.yellow('<empty string>'); } if (Array.isArray(input) || isObject(input)) { return ((displayType ? chalk_1.default.yellow(Array.isArray(input) ? '<array> ' : '<object> ') : '') + JSON.stringify(input)); } return `${chalk_1.default.yellow(`<${typeof input}>`)} ${input}`; }; function buildValidator() { if (!ajv) { const draft4MetaSchema = require('ajv/lib/refs/json-schema-draft-04.json'); ajv = new ajv_1.default({ schemaId: 'auto', validateSchema: false, }); ajv.addMetaSchema(draft4MetaSchema); ajv.addSchema(sarifV2Schema); } return ajv; } /** * Builds a Jest matcher based on the supplied @type {BuildMatcherOptions}. * * @param options * @param options.matcherName The name of the matcher. * @param options.schemaName [Optional] The name of the schema to load. * @param options.definition [Optional] The name of the SARIF schema definition fragment to dynamically build a schema for. * @returns {jest.CustomMatcher} */ function buildMatcher() { const ajv = buildValidator(); // eslint-disable-next-line no-underscore-dangle const { verbose } = ajv._opts; return function (received, definition) { let matcherName; let keyRef; if (definition) { keyRef = `${sarifV2Schema.id}#/definitions/${definition}`; matcherName = `toBeValidSarifFor('${definition}')`; } else { keyRef = sarifV2Schema.id; matcherName = 'toBeValidSarifLog'; } const validate = ajv.getSchema(keyRef); if (!validate) { throw new Error(`Could not find a definition for ${definition}. Please ensure you provide a valid definition.`); } const pass = validate(received); const message = pass ? () => { let messageToPrint = `${jest_matcher_utils_1.matcherHint(`.not.${matcherName}`, undefined, 'schema')}${os_1.EOL}${os_1.EOL}Expected value not to match schema${os_1.EOL}${os_1.EOL}`; if (verbose) { messageToPrint += chalk_1.default.red(`received${os_1.EOL}${formatForPrint(received)}${os_1.EOL}`); } return messageToPrint; } : () => { let messageToPrint = `${'received'}${os_1.EOL}`; for (const error of validate.errors) { let line = error.message; if (error.keyword === 'additionalProperties') { line = `${error.message}, but found '${error.params.additionalProperty}'`; } else if (error.dataPath) { line = `${error.dataPath} ${error.message}`; } if (verbose && error.schemaPath) { if (!ERROR_KEYWORDS_HIDE_EXPECTED.has(error.keyword)) { switch (error.keyword) { case 'if': line += `${os_1.EOL} Expected: ${formatForPrint(error.parentSchema[error.params.failingKeyword], false)}`; break; default: line += `${os_1.EOL} Expected: ${formatForPrint(error.schema, false)}`; break; } } if (error.dataPath) { line += `${os_1.EOL} Received: ${formatForPrint(error.data)}`; } else if (ERROR_KEYWORDS_SHOW_RECEIVED.has(error.keyword)) { line += `${os_1.EOL} Received: ${formatForPrint(error.data, false)}`; } line += `${os_1.EOL} Path: ${validate.schema.$id || ''}${error.schemaPath}`; } messageToPrint += chalk_1.default.red(` ${line}${os_1.EOL}`); } return `${jest_matcher_utils_1.matcherHint(`.${matcherName}`, undefined, 'schema')}${os_1.EOL}${os_1.EOL}${messageToPrint}`; }; return { actual: received, message, name: matcherName, pass, }; }; } exports.buildMatcher = buildMatcher; //# sourceMappingURL=build-matcher.js.map