@microsoft/jest-sarif
Version:
A collection of jest matchers for working with SARIF
139 lines • 5.64 kB
JavaScript
;
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