84 lines
2.3 KiB
JavaScript
84 lines
2.3 KiB
JavaScript
|
'use strict'
|
||
|
const arrayify = require('array-back')
|
||
|
const t = require('typical')
|
||
|
|
||
|
/**
|
||
|
* @module test-value
|
||
|
* @example
|
||
|
* const testValue = require('test-value')
|
||
|
*/
|
||
|
module.exports = testValue
|
||
|
|
||
|
/**
|
||
|
* @alias module:test-value
|
||
|
* @param {any} - a value to test
|
||
|
* @param {any} - the test query
|
||
|
* @param [options] {object}
|
||
|
* @param [options.strict] {boolean} - Treat an object like a value not a query.
|
||
|
* @returns {boolean}
|
||
|
*/
|
||
|
function testValue (value, test, options) {
|
||
|
options = options || {}
|
||
|
if (test !== Object.prototype && t.isPlainObject(test) && t.isObject(value) && !options.strict) {
|
||
|
return Object.keys(test).every(function (prop) {
|
||
|
let queryValue = test[prop]
|
||
|
|
||
|
/* get flags */
|
||
|
let isNegated = false
|
||
|
let isContains = false
|
||
|
|
||
|
if (prop.charAt(0) === '!') {
|
||
|
isNegated = true
|
||
|
} else if (prop.charAt(0) === '+') {
|
||
|
isContains = true
|
||
|
}
|
||
|
|
||
|
/* strip flag char */
|
||
|
prop = (isNegated || isContains) ? prop.slice(1) : prop
|
||
|
let objectValue = value[prop]
|
||
|
|
||
|
if (isContains) {
|
||
|
queryValue = arrayify(queryValue)
|
||
|
objectValue = arrayify(objectValue)
|
||
|
}
|
||
|
|
||
|
const result = testValue(objectValue, queryValue, options)
|
||
|
return isNegated ? !result : result
|
||
|
})
|
||
|
} else if (test !== Array.prototype && Array.isArray(test)) {
|
||
|
const tests = test
|
||
|
if (value === Array.prototype || !Array.isArray(value)) value = [ value ]
|
||
|
return value.some(function (val) {
|
||
|
return tests.some(function (test) {
|
||
|
return testValue(val, test, options)
|
||
|
})
|
||
|
})
|
||
|
|
||
|
/*
|
||
|
regexes queries will always return `false` for `null`, `undefined`, `NaN`.
|
||
|
This is to prevent a query like `/.+/` matching the string `undefined`.
|
||
|
*/
|
||
|
} else if (test instanceof RegExp) {
|
||
|
if ([ 'boolean', 'string', 'number' ].indexOf(typeof value) === -1) {
|
||
|
return false
|
||
|
} else {
|
||
|
return test.test(value)
|
||
|
}
|
||
|
} else if (test !== Function.prototype && typeof test === 'function') {
|
||
|
return test(value)
|
||
|
} else {
|
||
|
return test === value
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a callback suitable for use by `Array` methods like `some`, `filter`, `find` etc.
|
||
|
* @param {any} - the test query
|
||
|
* @returns {function}
|
||
|
*/
|
||
|
testValue.where = function (test) {
|
||
|
return function (value) {
|
||
|
return testValue(value, test)
|
||
|
}
|
||
|
}
|