diff --git a/lib/variable/__tests__/array-variable.test.js b/lib/variable/__tests__/array-variable.test.js index bf9440b..afba9ed 100644 --- a/lib/variable/__tests__/array-variable.test.js +++ b/lib/variable/__tests__/array-variable.test.js @@ -68,6 +68,14 @@ describe('ArrayVariable', () => { }) }) + describe('empty', () => { + it('is an alias for #isEmpty', () => { + variable.isEmpty = jest.fn() + variable.empty() + expect(variable.isEmpty).toHaveBeenCalled() + }) + }) + describe('endsWith', () => { it('tests an array to end with a specific value by identity', () => { expect(variable.endsWith(someOtherVariable).value).toBe(false) @@ -88,19 +96,11 @@ describe('ArrayVariable', () => { }) }) - describe('isNonEmpty', () => { + describe('isNotEmpty', () => { it('declares true when an ArrayVariable has one or more values', () => { - expect(variable.isNonEmpty().value).toBe(true) + expect(variable.isNotEmpty().value).toBe(true) variable.value.length = 0 - expect(variable.isNonEmpty().value).toBe(false) - }) - }) - - describe('isNotEmpty', () => { - it('is an alias for #nonEmpty', () => { - variable.nonEmpty = jest.fn() - variable.isNotEmpty() - expect(variable.nonEmpty).toHaveBeenCalled() + expect(variable.isNotEmpty().value).toBe(false) }) }) @@ -280,6 +280,14 @@ describe('ArrayVariable', () => { ) }) + describe('nonEmpty', () => { + it('is an alias for #isNotEmpty', () => { + variable.isNotEmpty = jest.fn() + variable.nonEmpty() + expect(variable.isNotEmpty).toHaveBeenCalled() + }) + }) + describe('notEqualTo', () => { it('evaluates whether it is not equal to another variable *by identity*', () => { variable = new ArrayVariable('variable', [2, 3]) diff --git a/lib/variable/array-variable.js b/lib/variable/array-variable.js index 4b1bd3a..ea22445 100644 --- a/lib/variable/array-variable.js +++ b/lib/variable/array-variable.js @@ -2,40 +2,35 @@ const Proposition = require('../proposition/proposition') const Variable = require('./variable') const camelCase = require('lodash.camelcase') const dataTypePredicateMap = require('./helpers/data-type-predicate-map') -const debug = require('debug')('@archetypes/rules/variable/ArrayVariable') +const getValidatedNumberValue = require('./helpers/get-validated-number-value') const ow = require('ow') /** - * @classdesc - * * - * @class ArrayVariable - * @extends {Variable} + * @private */ -const getValidatedNumberValue = (variable) => { - const val = variable.valueOf() - debug(`getValidatedNumberValue: variable.valueOf(): ${val}`) - ow(val, ow.any(ow.array, ow.number, ow.string)) - if (Array.isArray(val) || ow.isValid(val, ow.string)) { - debug(`getValidatedNumberValue => ${val.length}`) - return val.length - } - debug(`getValidatedNumberValue => ${val}`) - return val -} - const getVariableType = (variable) => { ow(variable, ow.any(ow.object, ow.string)) if (ow.isValid(variable, ow.string)) { return variable } - return camelCase(variable.type - .split('/') - .pop() - .replace('Variable', '')) + return camelCase( + variable.type + .split('/') + .pop() + .replace('Variable', '') + ) } +/** + * @classdesc + * + * + * @class ArrayVariable + * @extends {Variable} + */ + class ArrayVariable extends Variable { constructor (name, value = []) { super(name, value, ow.array) @@ -50,10 +45,7 @@ class ArrayVariable extends Variable { */ empty () { - return new Proposition( - `(IS_EMPTY ${this.name})`, - ow.isValid(this.value, ow.array.empty) - ) + return this.isEmpty() } /** @@ -87,7 +79,7 @@ class ArrayVariable extends Variable { greaterThan (variable) { const number = getValidatedNumberValue(variable) return new Proposition( - `(${this.name} HAS_LENGTH_GREATER_THAN ${number})`, + `(${this.name} GREATER_THAN ${number})`, this.value.length > number ) } @@ -95,7 +87,7 @@ class ArrayVariable extends Variable { greaterThanOrEqualTo (variable) { const number = getValidatedNumberValue(variable) return new Proposition( - `(${this.name} HAS_LENGTH_GREATER_THAN_OR_EQUAL_TO ${number})`, + `(${this.name} GREATER_THAN_OR_EQUAL_TO ${number})`, this.value.length >= number ) } @@ -129,15 +121,10 @@ class ArrayVariable extends Variable { */ isEmpty () { - return this.empty() - } - - /** - * Determine whether the ArrayVariable's value has one or more elements. - */ - - isNonEmpty () { - return this.nonEmpty() + return new Proposition( + `(IS_EMPTY ${this.name})`, + ow.isValid(this.value, ow.array.empty) + ) } /** @@ -145,7 +132,10 @@ class ArrayVariable extends Variable { */ isNotEmpty () { - return this.nonEmpty() + return new Proposition( + `(IS_NOT_EMPTY ${this.name})`, + ow.isValid(this.value, ow.array.nonEmpty) + ) } /** @@ -155,7 +145,7 @@ class ArrayVariable extends Variable { length (variable) { const number = getValidatedNumberValue(variable) return new Proposition( - `(${this.name} HAS_LENGTH_OF ${number})`, + `(${this.name} LENGTH ${number})`, ow.isValid(this.value, ow.array.length(number)) ) } @@ -163,7 +153,7 @@ class ArrayVariable extends Variable { lessThan (variable) { const number = getValidatedNumberValue(variable) return new Proposition( - `(${this.name} HAS_LENGTH_LESS_THAN ${number})`, + `(${this.name} LESS_THAN ${number})`, this.value.length < number ) } @@ -171,7 +161,7 @@ class ArrayVariable extends Variable { lessThanOrEqualTo (variable) { const number = getValidatedNumberValue(variable) return new Proposition( - `(${this.name} HAS_LENGTH_LESS_THAN_OR_EQUAL_TO ${number})`, + `(${this.name} LESS_THAN_OR_EQUAL ${number})`, this.value.length <= number ) } @@ -183,7 +173,7 @@ class ArrayVariable extends Variable { maxLength (variable) { const number = getValidatedNumberValue(variable) return new Proposition( - `(${this.name} HAS_MAX_LENGTH_OF ${number})`, + `(${this.name} MAX_LENGTH ${number})`, ow.isValid(this.value, ow.array.maxLength(number)) ) } @@ -195,7 +185,7 @@ class ArrayVariable extends Variable { minLength (variable) { const number = getValidatedNumberValue(variable) return new Proposition( - `(${this.name} HAS_MIN_LENGTH_OF ${number})`, + `(${this.name} MIN_LENGTH ${number})`, ow.isValid(this.value, ow.array.minLength(number)) ) } @@ -205,10 +195,7 @@ class ArrayVariable extends Variable { */ nonEmpty () { - return new Proposition( - `(IS_NOT_EMPTY ${this.name})`, - ow.isValid(this.value, ow.array.nonEmpty) - ) + return this.isNotEmpty() } /** @@ -216,10 +203,11 @@ class ArrayVariable extends Variable { */ ofType (variable) { + ow(variable, ow.any(ow.object.instanceOf(Variable), ow.string)) const dataType = getVariableType(variable) const predicate = dataTypePredicateMap.get(dataType) return new Proposition( - `(${this.name} IS_OF_TYPE ${dataType})`, + `(${this.name} OF_TYPE ${dataType})`, ow.isValid(this.value, ow.array.ofType(predicate)) ) } diff --git a/lib/variable/helpers/get-validated-number-value.js b/lib/variable/helpers/get-validated-number-value.js new file mode 100644 index 0000000..8000cbf --- /dev/null +++ b/lib/variable/helpers/get-validated-number-value.js @@ -0,0 +1,31 @@ +const debug = require('debug')( + '@archetypes/rules/variable/helpers/get-validated-number-value' +) +const ow = require('ow') + +/** + * Returns a Number. + * + * @private + * + * @param {@archetypes/rules/variable|number|string} variable - A valid + * - Instance of @archetypes/rules/variable + * - ECMAScript Number + * - ECMAScript String + * @throws {ArgumentError} + * @returns {number} - The length of an ArrayVariable or string. + */ + +const getValidatedNumberValue = (variable) => { + const val = variable.valueOf() + debug(`getValidatedNumberValue: variable.valueOf(): ${val}`) + ow(val, ow.any(ow.array, ow.number, ow.string)) + if (Array.isArray(val) || ow.isValid(val, ow.string)) { + debug(`getValidatedNumberValue => ${val.length}`) + return val.length + } + debug(`getValidatedNumberValue => ${val}`) + return val +} + +module.exports = getValidatedNumberValue