From ffc26ebed0ef728f63b7651d5b704ebcee5d6c69 Mon Sep 17 00:00:00 2001 From: DarrenPaulWright Date: Sun, 10 Mar 2019 08:37:33 -0700 Subject: [PATCH 1/6] Adding type "float"; making integer coercion more strict --- CHANGELOG.md | 12 +++- src/checks/is.js | 2 + src/checks/types/isFloat.js | 33 +++++++++++ src/checks/types/isInteger.js | 10 +++- src/enforcer/enforce.js | 2 + src/enforcer/types/enforceFloat.js | 31 +++++++++++ src/enforcer/types/enforceInteger.js | 4 +- src/enforcer/types/enforceNumber.js | 3 + src/index.js | 3 + src/methods/method.js | 2 + src/methods/types/methodFloat.js | 20 +++++++ src/types/CssSize.js | 3 +- tests/checks/isFloat.Test.js | 44 +++++++++++++++ tests/checks/isInteger.Test.js | 31 ++++++----- tests/checks/isNumber.Test.js | 31 ++++++----- tests/enforcer/types/enforceFloat.Test.js | 67 +++++++++++++++++++++++ tests/methods/types/methodFloat.Test.js | 27 +++++++++ tests/testValues.js | 47 ++++++++++------ tests/types/CssSize.Test.js | 2 +- 19 files changed, 321 insertions(+), 53 deletions(-) create mode 100644 src/checks/types/isFloat.js create mode 100644 src/enforcer/types/enforceFloat.js create mode 100644 src/methods/types/methodFloat.js create mode 100644 tests/checks/isFloat.Test.js create mode 100644 tests/enforcer/types/enforceFloat.Test.js create mode 100644 tests/methods/types/methodFloat.Test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index a99367e..d005eee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) +## [0.4.0] +### Added +- Float type (check, enforcer, and method) + +### Changed +- Integer coercion is now more strict + ## [0.3.3] - 2019-2-15 ### Changed - Switching dependencies to deep-equal instead of object-agent @@ -27,7 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.2.3] - 2019-01-30 ### Changed -- Exporting the check functions as a object +- Exporting the check functions as an object - Exporting individual enforcers and methods ## [0.2.2] - 2019-01-24 @@ -111,7 +118,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Initial enforcers, methods, and documentation -[0.3.2]: https://github.com/DarrenPaulWright/type-enforcer/compare/v0.3.2...c0.3.3 +[0.4.0]: https://github.com/DarrenPaulWright/type-enforcer/compare/v0.3.3...c0.4.0 +[0.3.3]: https://github.com/DarrenPaulWright/type-enforcer/compare/v0.3.2...c0.3.3 [0.3.2]: https://github.com/DarrenPaulWright/type-enforcer/compare/v0.3.1...c0.3.2 [0.3.1]: https://github.com/DarrenPaulWright/type-enforcer/compare/v0.3.0...c0.3.1 [0.3.0]: https://github.com/DarrenPaulWright/type-enforcer/compare/v0.2.4...c0.3.0 diff --git a/src/checks/is.js b/src/checks/is.js index af21439..17c65be 100644 --- a/src/checks/is.js +++ b/src/checks/is.js @@ -4,6 +4,7 @@ import isCssSize from './types/isCssSize'; import isDate from './types/isDate'; import isDockPoint from './types/isDockPoint'; import isElement from './types/isElement'; +import isFloat from './types/isFloat'; import isFunction from './types/isFunction'; import isInstanceOf from './types/isInstanceOf'; import isInteger from './types/isInteger'; @@ -37,6 +38,7 @@ export default { date: isDate, dockPoint: isDockPoint, element: isElement, + float: isFloat, function: isFunction, instanceOf: isInstanceOf, integer: isInteger, diff --git a/src/checks/types/isFloat.js b/src/checks/types/isFloat.js new file mode 100644 index 0000000..806f534 --- /dev/null +++ b/src/checks/types/isFloat.js @@ -0,0 +1,33 @@ +import { buildCheckWithCoerce } from './checks'; +import isNumber from './isNumber'; + +const isFinite = (item) => item !== Infinity && item !== -Infinity; + +/** + * Check if a value is a finite float + * + * @example + * ``` javascript + * import { isFloat } from 'type-enforcer'; + * + * isFloat(3.14159); + * // => true + * + * isFloat('3.14159'); + * // => false + * + * isFloat('3.14159', true); + * // => true + * ``` + * + * @function isFloat + * + * @arg {*} value + * @arg {Boolean} [coerce=false] - If true then see if the value can be coerced into a float + * + * @returns {Boolean} + */ +export default buildCheckWithCoerce((item) => isNumber(item) && item !== Infinity && item !== -Infinity, (value) => { + const parsed = parseFloat(value); + return !isNaN(value) && parsed !== Infinity && parsed !== -Infinity; +}); diff --git a/src/checks/types/isInteger.js b/src/checks/types/isInteger.js index a29a81e..6d54337 100644 --- a/src/checks/types/isInteger.js +++ b/src/checks/types/isInteger.js @@ -2,7 +2,7 @@ import { buildCheckWithCoerce } from './checks'; import isNumber from './isNumber'; /** - * Check if a value is an integer + * Check if a value is a finite integer * * @example * ``` javascript @@ -16,6 +16,9 @@ import isNumber from './isNumber'; * * isInteger('42', true); * // => true + * + * isInteger('42.5', true); + * // => false * ``` * * @function isInteger @@ -25,4 +28,7 @@ import isNumber from './isNumber'; * * @returns {Boolean} */ -export default buildCheckWithCoerce((item) => Number.isInteger(item) || isNumber(item) && Number.isInteger(Number.parseFloat(item)), (value) => !isNaN(value) && !isNaN(parseInt(value))); +export default buildCheckWithCoerce((item) => Number.isInteger(item) || isNumber(item) && Number.isInteger(Number.parseFloat(item)), (value) => { + const parsed = parseFloat(value); + return !isNaN(value) && parsed === (parsed | 0); +}); diff --git a/src/enforcer/enforce.js b/src/enforcer/enforce.js index d78083d..3b71f60 100644 --- a/src/enforcer/enforce.js +++ b/src/enforcer/enforce.js @@ -5,6 +5,7 @@ import enforceDate from './types/enforceDate'; import enforceDockPoint from './types/enforceDockPoint'; import enforceElement from './types/enforceElement'; import enforceEnum from './types/enforceEnum'; +import enforceFloat from './types/enforceFloat'; import enforceFunction from './types/enforceFunction'; import enforceInstance from './types/enforceInstance'; import enforceInteger from './types/enforceInteger'; @@ -38,6 +39,7 @@ export default { dockPoint: enforceDockPoint, element: enforceElement, enum: enforceEnum, + float: enforceFloat, function: enforceFunction, instance: enforceInstance, integer: enforceInteger, diff --git a/src/enforcer/types/enforceFloat.js b/src/enforcer/types/enforceFloat.js new file mode 100644 index 0000000..4810c79 --- /dev/null +++ b/src/enforcer/types/enforceFloat.js @@ -0,0 +1,31 @@ +import isFloat from '../../checks/types/isFloat'; +import { numericEnforcer } from './enforcer'; + +/** + * Enforce that a value is a finite float. Uses [isFloat](docs/checks.md#isFloat). + * + * @example + * ``` javascript + * import { enforce } from 'type-enforcer'; + * + * enforce.float(3.14159, 13.2); + * // => 3.14159 + * + * enforce.float('3.14159', 13.2); + * // => 13.2 + * + * enforce.float('3.14159', 13.2, true); + * // => 3.14159 + * ``` + * + * @function enforce.float + * + * @arg {*} value + * @arg {int} alt - Returned if the value is not the correct type + * @arg {Boolean} [coerce=false] - If true then coerce the value when possible + * @arg {int} [minValue] + * @arg {int} [maxValue] + * + * @returns {int} + */ +export default numericEnforcer(isFloat, Number); diff --git a/src/enforcer/types/enforceInteger.js b/src/enforcer/types/enforceInteger.js index 85aa14f..105a386 100644 --- a/src/enforcer/types/enforceInteger.js +++ b/src/enforcer/types/enforceInteger.js @@ -2,7 +2,7 @@ import isInteger from '../../checks/types/isInteger'; import { numericEnforcer } from './enforcer'; /** - * Enforce that a value is an integer. Uses [isInteger](docs/checks.md#isInteger). + * Enforce that a value is a finite integer. Uses [isInteger](docs/checks.md#isInteger). * * @example * ``` javascript @@ -28,4 +28,4 @@ import { numericEnforcer } from './enforcer'; * * @returns {int} */ -export default numericEnforcer(isInteger, Number); +export default numericEnforcer(isInteger, (item) => item - 0); diff --git a/src/enforcer/types/enforceNumber.js b/src/enforcer/types/enforceNumber.js index 34d465d..2b4011e 100644 --- a/src/enforcer/types/enforceNumber.js +++ b/src/enforcer/types/enforceNumber.js @@ -16,6 +16,9 @@ import { numericEnforcer } from './enforcer'; * * enforce.number('3.14159', 13.2, true); * // => 3.14159 + * + * enforce.number(Infinity, 13.2, true); + * // => Infinity * ``` * * @function enforce.number diff --git a/src/index.js b/src/index.js index 7a95348..6a59ada 100644 --- a/src/index.js +++ b/src/index.js @@ -52,6 +52,7 @@ export { default as isCssSize } from './checks/types/isCssSize'; export { default as isDate } from './checks/types/isDate'; export { default as isDockPoint } from './checks/types/isDockPoint'; export { default as isElement } from './checks/types/isElement'; +export { default as isFloat } from './checks/types/isFloat'; export { default as isFunction } from './checks/types/isFunction'; export { default as isInstanceOf } from './checks/types/isInstanceOf'; export { default as isInteger } from './checks/types/isInteger'; @@ -72,6 +73,7 @@ export { default as enforceDate } from './enforcer/types/enforceDate'; export { default as enforceDockPoint } from './enforcer/types/enforceDockPoint'; export { default as enforceElement } from './enforcer/types/enforceElement'; export { default as enforceEnum } from './enforcer/types/enforceEnum'; +export { default as enforceFloat } from './enforcer/types/enforceFloat'; export { default as enforceFunction } from './enforcer/types/enforceFunction'; export { default as enforceInstance } from './enforcer/types/enforceInstance'; export { default as enforceInteger } from './enforcer/types/enforceInteger'; @@ -92,6 +94,7 @@ export { default as methodDate } from './methods/types/methodDate'; export { default as methodDockPoint } from './methods/types/methodDockPoint'; export { default as methodElement } from './methods/types/methodElement'; export { default as methodEnum } from './methods/types/methodEnum'; +export { default as methodFloat } from './methods/types/methodFloat'; export { default as methodFunction } from './methods/types/methodFunction'; export { default as methodInstance } from './methods/types/methodInstance'; export { default as methodInteger } from './methods/types/methodInteger'; diff --git a/src/methods/method.js b/src/methods/method.js index 4df0de1..9a809d1 100644 --- a/src/methods/method.js +++ b/src/methods/method.js @@ -6,6 +6,7 @@ import methodDate from './types/methodDate'; import methodDockPoint from './types/methodDockPoint'; import methodElement from './types/methodElement'; import methodEnum from './types/methodEnum'; +import methodFloat from './types/methodFloat'; import methodFunction from './types/methodFunction'; import methodInstance from './types/methodInstance'; import methodInteger from './types/methodInteger'; @@ -65,6 +66,7 @@ export default { dockPoint: methodDockPoint, element: methodElement, enum: methodEnum, + float: methodFloat, function: methodFunction, integer: methodInteger, instance: methodInstance, diff --git a/src/methods/types/methodFloat.js b/src/methods/types/methodFloat.js new file mode 100644 index 0000000..5351ec3 --- /dev/null +++ b/src/methods/types/methodFloat.js @@ -0,0 +1,20 @@ +import enforceFloat from '../../enforcer/types/enforceFloat'; +import { buildMethod, mapEnforcerNumeric } from './methodAny'; + +/** + * Builds a chainable method for getting/setting a float + * + * @function method.float + * @extends method.any + * + * @arg {Object} [options] - Same as {@link method.any} with the following differences: + * @arg {Function} [options.enforce=enforce.float] + * @arg {Boolean} [options.coerce=false] - If true then coerce the value when possible + * @arg {Number} [options.min] - Passed to enforce.float + * @arg {Number} [options.max] - Passed to enforce.float + * + * @returns {Function} + */ +export default buildMethod({ + enforce: mapEnforcerNumeric(enforceFloat) +}); diff --git a/src/types/CssSize.js b/src/types/CssSize.js index e389e8a..bd07bcf 100644 --- a/src/types/CssSize.js +++ b/src/types/CssSize.js @@ -1,3 +1,4 @@ +import isFloat from '../checks/types/isFloat'; import methodElement from '../methods/types/methodElement'; import isElementInDom from '../utility/isElementInDom'; import throttle from '../utility/throttle'; @@ -94,7 +95,7 @@ const getMeasurement = (save, units, unit, element) => { return save[unit]; }; -const isNonZeroNumber = (size) => !!size && size !== ZERO_PIXELS && !isNaN(size); +const isNonZeroNumber = (size) => !!size && size !== ZERO_PIXELS && isFloat(size, true); let currentWindowWidth; let currentWindowHeight; diff --git a/tests/checks/isFloat.Test.js b/tests/checks/isFloat.Test.js new file mode 100644 index 0000000..efc8ae9 --- /dev/null +++ b/tests/checks/isFloat.Test.js @@ -0,0 +1,44 @@ +import { assert } from 'chai'; +import { is, isFloat } from '../../src'; +import { multiTest } from '../TestUtil'; +import { floatData as data } from '../testValues'; + +describe('isFloat', () => { + it('should exist in the exported "is" object', () => { + assert.deepEqual(isFloat, is.float); + }); + + multiTest({ + values: data.true, + test: (value) => isFloat(value), + assertion: 'isTrue' + }); + multiTest({ + values: data.false, + test: (value) => isFloat(value), + assertion: 'isFalse' + }); + multiTest({ + values: data.coerceTrue, + test: (value) => isFloat(value), + assertion: 'isFalse' + }); + + describe('coerce', () => { + multiTest({ + values: data.true, + test: (value) => isFloat(value, true), + assertion: 'isTrue' + }); + multiTest({ + values: data.coerceTrue, + test: (value) => isFloat(value, true), + assertion: 'isTrue' + }); + multiTest({ + values: data.coerceFalse, + test: (value) => isFloat(value, true), + assertion: 'isFalse' + }); + }); +}); diff --git a/tests/checks/isInteger.Test.js b/tests/checks/isInteger.Test.js index 8a64559..b672805 100644 --- a/tests/checks/isInteger.Test.js +++ b/tests/checks/isInteger.Test.js @@ -23,19 +23,22 @@ describe('isInteger', () => { test: (value) => isInteger(value), assertion: 'isFalse' }); - multiTest({ - values: data.true, - test: (value) => isInteger(value, true), - assertion: 'isTrue' - }); - multiTest({ - values: data.coerceTrue, - test: (value) => isInteger(value, true), - assertion: 'isTrue' - }); - multiTest({ - values: data.coerceFalse, - test: (value) => isInteger(value, true), - assertion: 'isFalse' + + describe('coerce', () => { + multiTest({ + values: data.true, + test: (value) => isInteger(value, true), + assertion: 'isTrue' + }); + multiTest({ + values: data.coerceTrue, + test: (value) => isInteger(value, true), + assertion: 'isTrue' + }); + multiTest({ + values: data.coerceFalse, + test: (value) => isInteger(value, true), + assertion: 'isFalse' + }); }); }); diff --git a/tests/checks/isNumber.Test.js b/tests/checks/isNumber.Test.js index 4e80644..0437c53 100644 --- a/tests/checks/isNumber.Test.js +++ b/tests/checks/isNumber.Test.js @@ -23,19 +23,22 @@ describe('isNumber', () => { test: (value) => isNumber(value), assertion: 'isFalse' }); - multiTest({ - values: data.true, - test: (value) => isNumber(value, true), - assertion: 'isTrue' - }); - multiTest({ - values: data.coerceTrue, - test: (value) => isNumber(value, true), - assertion: 'isTrue' - }); - multiTest({ - values: data.coerceFalse, - test: (value) => isNumber(value, true), - assertion: 'isFalse' + + describe('coerce', () => { + multiTest({ + values: data.true, + test: (value) => isNumber(value, true), + assertion: 'isTrue' + }); + multiTest({ + values: data.coerceTrue, + test: (value) => isNumber(value, true), + assertion: 'isTrue' + }); + multiTest({ + values: data.coerceFalse, + test: (value) => isNumber(value, true), + assertion: 'isFalse' + }); }); }); diff --git a/tests/enforcer/types/enforceFloat.Test.js b/tests/enforcer/types/enforceFloat.Test.js new file mode 100644 index 0000000..60f7015 --- /dev/null +++ b/tests/enforcer/types/enforceFloat.Test.js @@ -0,0 +1,67 @@ +import { assert } from 'chai'; +import { enforce, enforceFloat } from '../../../src'; +import { multiTest } from '../../TestUtil'; +import { floatData as data } from '../../testValues'; +import { runNegativeTests } from '../enforceTestUtility'; + +const validInt = 11; +const validFloat = 34.23463456; + +describe('enforce', () => { + describe('.float', () => { + it('should exist in the exported "enforce" object', () => { + assert.deepEqual(enforceFloat, enforce.float); + }); + + it('should return the setter value when an float is provided', () => { + assert.deepEqual(enforce.float(validInt, validFloat), validInt); + }); + it('should return the setter value when a float is provided', () => { + assert.deepEqual(enforce.float(validFloat, validInt), validFloat); + }); + it('should return the min value when a float less than the min value is provided', () => { + assert.deepEqual(enforce.float(-12, validInt, false, 0, 5), 0); + }); + it('should return the max value when a float greater than the max value is provided', () => { + assert.deepEqual(enforce.float(12, validInt, false, 0, 5), 5); + }); + + multiTest({ + values: data.coerceTrue.map((item) => { + return { + input: item, + output: Number(item) + }; + }), + message: (input) => `should return a coerced ${input} when coerce is true`, + test: (value) => enforce.float(value, value, true), + inputKey: 'input', + outputKey: 'output', + assertion: 'deepEqual' + }); + + multiTest({ + values: data.coerceTrue.map((item) => { + return { + input: item, + output: item + }; + }), + message: (input) => `should NOT return a coerced ${input} when coerce is false`, + test: (value) => enforce.float(value, value, false), + inputKey: 'input', + outputKey: 'output', + assertion: 'deepEqual' + }); + + multiTest({ + values: data.coerceFalse, + message: (input) => `should return the alt value when ${input} is provided and coerce is true`, + test: (value) => enforce.float(value, 'testAlt', true), + output: 'testAlt', + assertion: 'deepEqual' + }); + + runNegativeTests('float', validInt); + }); +}); diff --git a/tests/methods/types/methodFloat.Test.js b/tests/methods/types/methodFloat.Test.js new file mode 100644 index 0000000..d3501c1 --- /dev/null +++ b/tests/methods/types/methodFloat.Test.js @@ -0,0 +1,27 @@ +import { assert } from 'chai'; +import { method, methodFloat } from '../../../src'; +import { floatData as data } from '../../testValues'; +import { testMethodType } from '../methodTestUtility'; + +describe('method', () => { + describe('.float', () => { + it('should exist in the exported "method" object', () => { + assert.deepEqual(methodFloat, method.float); + }); + + testMethodType(Object.assign({}, data, { + extraProps: { + min: 1.2, + max: 10.5 + }, + coerce: [{ + value: 30.874, + coerced: 10.5 + }, { + value: -3, + coerced: 1.2 + }] + })); + }); +}); + diff --git a/tests/testValues.js b/tests/testValues.js index 2eda565..4585626 100644 --- a/tests/testValues.js +++ b/tests/testValues.js @@ -41,7 +41,8 @@ export const validFunctions = [function() { }, () => { }]; export const validIntegers = [1, 5, new Number(42), Number(11)]; -export const validNumbers = [1.3, 2.5, -10.00000001, 3.14159, new Number(42.2), Number(11.3)]; +export const validFloats = [1.3, 2.5, -10.00000001, 3.14159, new Number(42.2), Number(11.3)]; +export const validInfinities = [Infinity, -Infinity]; export const validObjects = [{}, { test1: 1 }, new Object(), Object()]; @@ -115,7 +116,7 @@ const coerceInfinity = [ 'Infinity', '-Infinity' ]; -const coerceNumberTrue = [ +const coerceIntegerTrue = [ '0', '1', '1.00', @@ -132,16 +133,17 @@ const coerceNumberTrue = [ '+0', '+0.0', '0.00', - '999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999', '0x0', '0xffffffff', '0xffffffffffffffff', '0xabad1dea', - '123456789012345678901234567890123456789', '01000', '08', - '09', - '2.2250738585072011e-308']; + '09']; +const coerceFloatTrue = [ + '3.2', + '10.5' +]; const coerceNumberFalse = [ '$1.00', '1/2', @@ -201,7 +203,8 @@ export const testValues = [].concat( validElements, validFunctions, validIntegers, - validNumbers, + validFloats, + validInfinities, validObjects, validRegExps, validStrings, @@ -234,7 +237,7 @@ export const cssSizeData = { true: validCssSizes, false: difference(testValues, validCssSizes), coerceTrue: validCssValues.map((item) => item.size), - coerceFalse: difference(testValues, validCssSizes, validIntegers, validNumbers) + coerceFalse: difference(testValues, validCssSizes, validIntegers, validFloats) }; export const dateData = { value: Date, @@ -242,7 +245,7 @@ export const dateData = { true: validDates, false: difference(testValues, validDates), coerceTrue: ['10/12/1980', 'January 8, 2014'], - coerceFalse: difference(testValues, validDates, validArrays, validNumbers, validIntegers, validRegExps, validPoints) + coerceFalse: difference(testValues, validDates, validArrays, validFloats, validIntegers, validRegExps, validPoints) }; export const dockPointData = { value: DockPoint, @@ -270,18 +273,27 @@ export const functionData = { }; export const integerData = { name: 'integer', - skip: ['number'], + skip: ['number', 'float'], true: validIntegers, - false: difference(testValues, validIntegers), - coerceTrue: coerceNumberTrue, - coerceFalse: [].concat(coerceNumberFalse, coerceInfinity) + false: difference(testValues, validIntegers, validInfinities), + coerceTrue: coerceIntegerTrue, + coerceFalse: coerceNumberFalse.concat(coerceFloatTrue, coerceInfinity) +}; +export const floatData = { + name: 'float', + skip: ['number', 'integer'], + true: validFloats, + false: difference(testValues, validFloats, validIntegers, validInfinities), + coerceTrue: coerceIntegerTrue.concat(coerceFloatTrue), + coerceFalse: coerceNumberFalse.concat(coerceInfinity) }; export const numberData = { value: Number, name: 'number', - true: validNumbers, - false: difference(testValues, validNumbers, validIntegers), - coerceTrue: [].concat(coerceNumberTrue, coerceInfinity), + skip: ['integer', 'float'], + true: validFloats.concat(validIntegers, validInfinities), + false: difference(testValues, validFloats, validIntegers, validInfinities), + coerceTrue: coerceIntegerTrue.concat(coerceInfinity), coerceFalse: coerceNumberFalse }; export const objectData = { @@ -328,7 +340,7 @@ export const thicknessData = { true: validThicknesses, false: difference(testValues, validThicknesses), coerceTrue: ['1px', '1px 2px 3px 4px'], - coerceFalse: difference(testValues, validThicknesses, validCssSizes, validIntegers, validNumbers, validArrays) + coerceFalse: difference(testValues, validThicknesses, validCssSizes, validIntegers, validFloats, validArrays) }; export const vectorData = { value: Vector, @@ -348,6 +360,7 @@ export const testTypes = [ elementData, functionData, integerData, + floatData, numberData, objectData, pointData, diff --git a/tests/types/CssSize.Test.js b/tests/types/CssSize.Test.js index 1ed638f..da9c35e 100644 --- a/tests/types/CssSize.Test.js +++ b/tests/types/CssSize.Test.js @@ -272,7 +272,7 @@ describe('CssSize', () => { const isValid = (value1, value2) => { return (value1 !== value2 && !(value1.size === 0 && value2.size === '0' || value1.size === '0' && value2.size === 0) && - !(value1.size + PIXELS === value2.size || value1.size === value2.size + PIXELS)) + !(value1.size + PIXELS === value2.size || value1.size === value2.size + PIXELS)); }; multiTest({ From da9ec467891d18549ea4bc925a30640c486fa62f Mon Sep 17 00:00:00 2001 From: DarrenPaulWright Date: Mon, 11 Mar 2019 11:22:49 -0700 Subject: [PATCH 2/6] Switching back to object-agent for deepEqual and forOwn --- package-lock.json | 10 +++++----- package.json | 2 +- src/methods/types/methodAny.js | 2 +- src/methods/types/methodKeyValue.js | 2 +- src/types/Enum.js | 2 +- src/types/Queue.js | 2 +- src/utility/forOwn.js | 2 -- tests/TestUtil.js | 2 +- 8 files changed, 11 insertions(+), 13 deletions(-) delete mode 100644 src/utility/forOwn.js diff --git a/package-lock.json b/package-lock.json index a0a9803..450e9da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2434,11 +2434,6 @@ "type-detect": "^4.0.0" } }, - "deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" - }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -6065,6 +6060,11 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, + "object-agent": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/object-agent/-/object-agent-0.3.0.tgz", + "integrity": "sha512-NfUqMs6pilKG3GTdyrK2Wz23cYp8taHwNYqhx/Ti8tmmdBVr9J/KLtksg1FnUluB7OjteyDpnneVVSKW+cmTDA==" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", diff --git a/package.json b/package.json index 2f1055f..a91c3fa 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ }, "homepage": "https://github.com/DarrenPaulWright/type-enforcer#readme", "dependencies": { - "deep-equal": "^1.0.1" + "object-agent": "^0.3.0" }, "devDependencies": { "@babel/core": "^7.2.2", diff --git a/src/methods/types/methodAny.js b/src/methods/types/methodAny.js index beb10c9..04e9ed8 100644 --- a/src/methods/types/methodAny.js +++ b/src/methods/types/methodAny.js @@ -1,4 +1,4 @@ -import deepEqual from 'deep-equal'; +import { deepEqual } from 'object-agent'; import isArray from '../../checks/types/isArray'; import enforceBoolean from '../../enforcer/types/enforceBoolean'; import before from '../variants/before'; diff --git a/src/methods/types/methodKeyValue.js b/src/methods/types/methodKeyValue.js index 84bda17..85cb7f4 100644 --- a/src/methods/types/methodKeyValue.js +++ b/src/methods/types/methodKeyValue.js @@ -1,5 +1,5 @@ +import { forOwn } from 'object-agent'; import isObject from '../../checks/types/isObject'; -import forOwn from '../../utility/forOwn'; /** * Builds a chainable method that accepts either: diff --git a/src/types/Enum.js b/src/types/Enum.js index a549661..8bda78b 100644 --- a/src/types/Enum.js +++ b/src/types/Enum.js @@ -1,4 +1,4 @@ -import forOwn from '../utility/forOwn'; +import { forOwn } from 'object-agent'; const KEYS = Symbol(); const VALUES = Symbol(); diff --git a/src/types/Queue.js b/src/types/Queue.js index 0b34a9e..c14bb77 100644 --- a/src/types/Queue.js +++ b/src/types/Queue.js @@ -1,5 +1,5 @@ +import { forOwn } from 'object-agent'; import isFunction from '../checks/types/isFunction'; -import forOwn from '../utility/forOwn'; const CALLBACKS = Symbol(); const CURRENT_ID = Symbol(); diff --git a/src/utility/forOwn.js b/src/utility/forOwn.js deleted file mode 100644 index 3f1eda9..0000000 --- a/src/utility/forOwn.js +++ /dev/null @@ -1,2 +0,0 @@ -export default (object, callback) => !(!object || !Object.keys(object) - .some((key) => key in object ? callback(object[key], key) : false)); diff --git a/tests/TestUtil.js b/tests/TestUtil.js index a7f8f3e..1c7d2cc 100644 --- a/tests/TestUtil.js +++ b/tests/TestUtil.js @@ -1,6 +1,6 @@ import { assert } from 'chai'; +import { forOwn } from 'object-agent'; import { isObject } from '../src'; -import forOwn from '../src/utility/forOwn'; export const eachPair = (array1, array2, callback, isUnique = false) => { let i; From 9bf06ab7bf40c5ee3ee104255c43bee1ff5d7238 Mon Sep 17 00:00:00 2001 From: DarrenPaulWright Date: Mon, 11 Mar 2019 11:23:18 -0700 Subject: [PATCH 3/6] Simplifying isObject and isArray checks. --- src/checks/types/isArray.js | 2 +- src/checks/types/isObject.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/checks/types/isArray.js b/src/checks/types/isArray.js index 602b165..5f71ff5 100644 --- a/src/checks/types/isArray.js +++ b/src/checks/types/isArray.js @@ -25,4 +25,4 @@ import isJson from './isJson'; * * @returns {Boolean} */ -export default buildCheckWithCoerce((item) => Array.isArray(item), (value) => isJson(value) && Array.isArray(JSON.parse(value))); +export default buildCheckWithCoerce(Array.isArray, (value) => isJson(value) && Array.isArray(JSON.parse(value))); diff --git a/src/checks/types/isObject.js b/src/checks/types/isObject.js index 6e7d901..4fed214 100644 --- a/src/checks/types/isObject.js +++ b/src/checks/types/isObject.js @@ -1,9 +1,7 @@ import { buildCheckWithCoerce } from './checks'; import isJson from './isJson'; -// const isPlainObject = (item) => item && typeof item === 'object' && item instanceof Object; -// const isPlainObject = (item) => isInstanceOf(item, Object); -const isPlainObject = (item) => item && typeof item === 'object' && toString.call(item) === '[object Object]' && item.constructor === Object; +const isPlainObject = (item) => item && item.constructor === Object; /** * Check if a value is a plain object From 3a541b69f424a4ec6be798cd7ad991829c51fe8f Mon Sep 17 00:00:00 2001 From: DarrenPaulWright Date: Mon, 11 Mar 2019 11:37:10 -0700 Subject: [PATCH 4/6] Updating change log and docs for 0.4.0 --- CHANGELOG.md | 3 ++- docs/checks.md | 23 ++++++++++++++++++++--- docs/enforce.md | 22 ++++++++++++++++++++-- docs/method.md | 19 ++++++++++++++++++- 4 files changed, 60 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d005eee..bfe79ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) -## [0.4.0] +## [0.4.0] - 2019-3-11 ### Added - Float type (check, enforcer, and method) ### Changed - Integer coercion is now more strict +- Switching dependencies back to object-agent ## [0.3.3] - 2019-2-15 ### Changed diff --git a/docs/checks.md b/docs/checks.md index 564e6d2..8b5b91f 100644 --- a/docs/checks.md +++ b/docs/checks.md @@ -29,6 +29,9 @@ A type enforcement library for javascript
isElement(value)Boolean

Check if a value is a DOM element

+
isFloat(value, [coerce])Boolean
+

Check if a value is a finite float

+
isFunction(value)Boolean

Check if a value is a function

@@ -36,7 +39,7 @@ A type enforcement library for javascript

Check if a value is an instance of a constructor. Fixes issues with native instanceOf and primitives Boolean, Number, and String (see example).

isInteger(value, [coerce])Boolean
-

Check if a value is an integer

+

Check if a value is a finite integer

isJson(value)Boolean

Check if a value can be parsed as JSON

@@ -161,6 +164,20 @@ Check if a value is a DOM element **Example** ``` javascript import { isElement } from 'type-enforcer'; isElement(document.createElement('div')); // => true ``` + + +## isFloat(value, [coerce]) ⇒ Boolean +Check if a value is a finite float + +**Kind**: global function + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| value | \* | | | +| [coerce] | Boolean | false | If true then see if the value can be coerced into a float | + +**Example** +``` javascript import { isFloat } from 'type-enforcer'; isFloat(3.14159); // => true isFloat('3.14159'); // => false isFloat('3.14159', true); // => true ``` ## isFunction(value) ⇒ Boolean @@ -191,7 +208,7 @@ Check if a value is an instance of a constructor. Fixes issues with native insta ## isInteger(value, [coerce]) ⇒ Boolean -Check if a value is an integer +Check if a value is a finite integer **Kind**: global function @@ -201,7 +218,7 @@ Check if a value is an integer | [coerce] | Boolean | false | If true then see if the value can be coerced into an Integer | **Example** -``` javascript import { isInteger } from 'type-enforcer'; isInteger(42); // => true isInteger('42'); // => false isInteger('42', true); // => true ``` +``` javascript import { isInteger } from 'type-enforcer'; isInteger(42); // => true isInteger('42'); // => false isInteger('42', true); // => true isInteger('42.5', true); // => false ``` ## isJson(value) ⇒ Boolean diff --git a/docs/enforce.md b/docs/enforce.md index e4c2c74..124848a 100644 --- a/docs/enforce.md +++ b/docs/enforce.md @@ -23,6 +23,7 @@ Utility functions for enforcing data types. ## Usage ``` javascript import { en * [.dockPoint(value, alt, [coerce])](#enforce.dockPoint) ⇒ DockPoint * [.element(value, alt)](#enforce.element) ⇒ Element * [.enum(value, enumerable, alt)](#enforce.enum) ⇒ String + * [.float(value, alt, [coerce], [minValue], [maxValue])](#enforce.float) ⇒ int * [.function(value, alt)](#enforce.function) ⇒ function * [.instance(value, constructor, alt)](#enforce.instance) ⇒ Object * [.integer(value, alt, [coerce], [minValue], [maxValue])](#enforce.integer) ⇒ int @@ -138,6 +139,23 @@ Enforce that a value exists in the provided [Enum](docs/Enum.md) **Example** ``` javascript import { enforce, Enum } from 'type-enforcer'; const values = new Enum({ a: 'item a', b: 'item b' }); enforce.enum(values.a, values, values.b); // => 'item a' enforce.enum(values.c, values, values.b); // => 'item b' ``` + + +### enforce.float(value, alt, [coerce], [minValue], [maxValue]) ⇒ int +Enforce that a value is a finite float. Uses [isFloat](docs/checks.md#isFloat). + +**Kind**: static method of [enforce](#enforce) + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| value | \* | | | +| alt | int | | Returned if the value is not the correct type | +| [coerce] | Boolean | false | If true then coerce the value when possible | +| [minValue] | int | | | +| [maxValue] | int | | | + +**Example** +``` javascript import { enforce } from 'type-enforcer'; enforce.float(3.14159, 13.2); // => 3.14159 enforce.float('3.14159', 13.2); // => 13.2 enforce.float('3.14159', 13.2, true); // => 3.14159 ``` ### enforce.function(value, alt) ⇒ function @@ -170,7 +188,7 @@ Enforce that a value is an instance of a constructor. Uses [isInstanceOf](docs/c ### enforce.integer(value, alt, [coerce], [minValue], [maxValue]) ⇒ int -Enforce that a value is an integer. Uses [isInteger](docs/checks.md#isInteger). +Enforce that a value is a finite integer. Uses [isInteger](docs/checks.md#isInteger). **Kind**: static method of [enforce](#enforce) @@ -200,7 +218,7 @@ Enforce that a value is a number (excluding NaN). Uses [isNumber](docs/checks.md | [maxValue] | Number | Infinity | | **Example** -``` javascript import { enforce } from 'type-enforcer'; enforce.number(3.14159, 13.2); // => 3.14159 enforce.number('3.14159', 13.2); // => 13.2 enforce.number('3.14159', 13.2, true); // => 3.14159 ``` +``` javascript import { enforce } from 'type-enforcer'; enforce.number(3.14159, 13.2); // => 3.14159 enforce.number('3.14159', 13.2); // => 13.2 enforce.number('3.14159', 13.2, true); // => 3.14159 enforce.number(Infinity, 13.2, true); // => Infinity ``` ### enforce.object(value, alt, [coerce]) ⇒ Object diff --git a/docs/method.md b/docs/method.md index c6d0955..7778357 100644 --- a/docs/method.md +++ b/docs/method.md @@ -24,6 +24,7 @@ Enforce data types and remove common boilerplate code on class methods. ## Usag * [.dockPoint([options])](#method.dockPoint) ⇒ function * [.element([options])](#method.element) ⇒ function * [.enum([options])](#method.enum) ⇒ function + * [.float([options])](#method.float) ⇒ function * [.function([options])](#method.function) ⇒ function * [.instance([options])](#method.instance) ⇒ function * [.int([options])](#method.int) ⇒ function @@ -162,6 +163,22 @@ Builds a chainable method for getting/setting an enumerable value in an [Enum](d | [options.enforce] | function | enforce.enum | | | options.enum | Enum | | An enum to restrict the values to. | + + +### method.float([options]) ⇒ function +Builds a chainable method for getting/setting a float + +**Kind**: static method of [method](#method) +**Extends**: [any](#method.any) + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [options] | Object | | Same as [any](#method.any) with the following differences: | +| [options.enforce] | function | enforce.float | | +| [options.coerce] | Boolean | false | If true then coerce the value when possible | +| [options.min] | Number | | Passed to enforce.float | +| [options.max] | Number | | Passed to enforce.float | + ### method.function([options]) ⇒ function @@ -278,7 +295,7 @@ Builds a chainable method that implements a [Queue](docs/Queue.md) | Param | Type | Description | | --- | --- | --- | | [options] | Object | | -| [options.set] | function | Called after a new callback is added to the queue. Provides a reference to the queue, sets the context to the methods constructor. | +| [options.set] | function | Called after a new callback is added to the queue. Provides a reference to the queue, the new ID for the callback, the callback, and sets the context to the methods constructor. | From a1ae4a8c63335e47efd4149f766085b18def5051 Mon Sep 17 00:00:00 2001 From: darrenpaulwright Date: Mon, 11 Mar 2019 11:37:21 -0700 Subject: [PATCH 5/6] Increment minor version to 0.4.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 450e9da..1554396 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "type-enforcer", - "version": "0.3.3", + "version": "0.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a91c3fa..8f8d7c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "type-enforcer", - "version": "0.3.3", + "version": "0.4.0", "description": "Type enforcement library for javascript", "main": "src/index.js", "scripts": { From 6a7d32cebab26c702dd55ffe98499418391f2eb1 Mon Sep 17 00:00:00 2001 From: DarrenPaulWright Date: Mon, 11 Mar 2019 11:56:09 -0700 Subject: [PATCH 6/6] Updating object-agent to 0.3.1 --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1554396..db33552 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6061,9 +6061,9 @@ "dev": true }, "object-agent": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/object-agent/-/object-agent-0.3.0.tgz", - "integrity": "sha512-NfUqMs6pilKG3GTdyrK2Wz23cYp8taHwNYqhx/Ti8tmmdBVr9J/KLtksg1FnUluB7OjteyDpnneVVSKW+cmTDA==" + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/object-agent/-/object-agent-0.3.1.tgz", + "integrity": "sha512-6RXS8xPeJ5Tow0Rpe7NUVYQhB9vboV+iwnh+7BetOshwN9X2ZHdsrsODR+n4pZzFB5sQCsNNV5Nlf1nG61ngeQ==" }, "object-assign": { "version": "4.1.1", diff --git a/package.json b/package.json index 8f8d7c1..ca62e40 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ }, "homepage": "https://github.com/DarrenPaulWright/type-enforcer#readme", "dependencies": { - "object-agent": "^0.3.0" + "object-agent": "^0.3.1" }, "devDependencies": { "@babel/core": "^7.2.2",