UNPKG

@qavajs/validation

Version:

Lib that transform plain english definition to validation functions

144 lines 6.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.expect = exports.validationRegexp = exports.validationExtractRegexp = exports.validations = void 0; exports.verify = verify; exports.getValidation = getValidation; exports.getPollValidation = getPollValidation; exports.poll = poll; const matchers_1 = require("./matchers"); Object.defineProperty(exports, "expect", { enumerable: true, get: function () { return matchers_1.expect; } }); exports.validations = { EQUAL: 'equal', DEEPLY_EQUAL: 'deeply equal', STRICTLY_EQUAL: 'strictly equal', HAVE_MEMBERS: 'have member', MATCH: 'match', CONTAIN: 'contain', ABOVE: 'above', BELOW: 'below', GREATER: 'greater than', LESS: 'less than', HAVE_TYPE: 'have type', INCLUDE_MEMBERS: 'include member', HAVE_PROPERTY: 'have property', MATCH_SCHEMA: 'match schema', CASE_INSENSITIVE_EQUAL: 'case insensitive equal', SATISFY: 'satisfy' }; const isClause = '(?:is |do |does |to )?'; const notClause = '(?<reverse>not |to not )?'; const toBeClause = '(?:to )?(?:be )?'; const softlyClause = '(?<soft>softly )?'; const validationClause = `(?:(?<validation>${Object.values(exports.validations).join('|')})(?:s|es| to)?)`; exports.validationExtractRegexp = new RegExp(`^${isClause}${notClause}${toBeClause}${softlyClause}${validationClause}$`); exports.validationRegexp = new RegExp(`(${isClause}${notClause}${toBeClause}${softlyClause}${validationClause})`); const aboveFn = (expectClause, expected) => expectClause.toBeGreaterThan(toNumber(expected)); const belowFn = (expectClause, expected) => expectClause.toBeLessThan(toNumber(expected)); const validationFns = { [exports.validations.EQUAL]: (expectClause, expected) => expectClause.toSimpleEqual(expected), [exports.validations.STRICTLY_EQUAL]: (expectClause, expected) => expectClause.toEqual(expected), [exports.validations.DEEPLY_EQUAL]: (expectClause, expected) => expectClause.toDeepEqual(expected), [exports.validations.HAVE_MEMBERS]: (expectClause, expected) => expectClause.toHaveMembers(expected), [exports.validations.MATCH]: (expectClause, expected) => expectClause.toMatch(toRegexp(expected)), [exports.validations.CONTAIN]: (expectClause, expected) => expectClause.toContain(expected), [exports.validations.ABOVE]: aboveFn, [exports.validations.BELOW]: belowFn, [exports.validations.GREATER]: aboveFn, [exports.validations.LESS]: belowFn, [exports.validations.HAVE_TYPE]: (expectClause, expected) => expectClause.toHaveType(expected), [exports.validations.INCLUDE_MEMBERS]: (expectClause, expected) => expectClause.toIncludeMembers(expected), [exports.validations.HAVE_PROPERTY]: (expectClause, expected) => expectClause.toHaveProperty(expected), [exports.validations.MATCH_SCHEMA]: (expectClause, expected) => expectClause.toMatchSchema(expected), [exports.validations.CASE_INSENSITIVE_EQUAL]: (expectClause, expected) => expectClause.toCaseInsensitiveEqual(expected), [exports.validations.SATISFY]: (expectClause, expected) => expectClause.toSatisfy(expected), }; /** * Basic verification function * @param {VerifyInput} object with all needed data for validation */ function verify({ received, expected, validation, reverse, soft }) { const expectClause = (0, matchers_1.expect)(received).configure({ not: reverse, soft }); const validate = validationFns[validation]; validate(expectClause, expected); } function getValidation(validationType, options) { const match = exports.validationExtractRegexp.exec(validationType); if (!match) throw new Error(`Validation '${validationType}' is not supported`); const { reverse, validation, soft } = match.groups; const softProp = options?.soft || !!soft; return function (received, expected) { verify({ received, expected, validation, reverse: Boolean(reverse), soft: softProp }); }; } function getPollValidation(validationType, options) { const match = exports.validationExtractRegexp.exec(validationType); if (!match) throw new Error(`Poll validation '${validationType}' is not supported`); const { reverse, validation, soft } = match.groups; const softProp = options?.soft || !!soft; return async function (received, expected, options) { const timeout = options?.timeout ?? 5000; const interval = options?.interval ?? 500; let lastError = new Error(`Promise was not settled before timeout`); let intervalId; const evaluatePromise = new Promise(resolve => { intervalId = setInterval(async () => { try { const actualValue = await received(); verify({ received: actualValue, expected, validation, reverse: Boolean(reverse), soft: softProp }); clearInterval(intervalId); resolve(); } catch (err) { lastError = err; } }, interval); }); const timeoutPromise = new Promise((_, reject) => setTimeout(() => { clearInterval(intervalId); reject(lastError); }, timeout)); return Promise.race([evaluatePromise, timeoutPromise]); }; } async function poll(fn, options) { const timeout = options?.timeout ?? 5000; const interval = options?.interval ?? 500; let lastError = new Error('Unexpected error'); let intervalId; const evaluatePromise = new Promise(resolve => { intervalId = setInterval(async () => { try { await fn(); clearInterval(intervalId); resolve(); } catch (err) { lastError = err; } }, interval); }); const timeoutPromise = new Promise((_, reject) => setTimeout(() => { clearInterval(intervalId); reject(lastError); }, timeout)); return Promise.race([evaluatePromise, timeoutPromise]); } function toNumber(n) { const parsedNumber = Number.parseFloat(n); if (Number.isNaN(parsedNumber)) { throw new TypeError(`${n} is not a number`); } return parsedNumber; } function toRegexp(r) { return r instanceof RegExp ? r : new RegExp(r); } //# sourceMappingURL=verify.js.map