diff --git a/docs/README.md b/docs/README.md index cdfc2cb0f..98ab998d1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,6 +9,7 @@ Utility methods for this package are split into groups - [is](is.md) Type checking utilities - [jsonrpc](jsonrpc.md) Convenience functions for values from @polkadot/api-jsonrpc - [keccak](keccak.md) Create Keccak256 values as hex, string & buffer output +- [number](number.md) Utility methods to convert to and from `number` values - [u8a](u8a.md) Utility methods to convert to and from `Uint8Array` objects # Available methods diff --git a/docs/is.md b/docs/is.md index 3d3de2ccf..8bc26d7b7 100644 --- a/docs/is.md +++ b/docs/is.md @@ -8,6 +8,7 @@ Type checking utilities - [isFunction](#isfunction) Tests for a `function`. - [isHex](#ishex) Tests for a hex string. - [isInstanceOf](#isinstanceof) Tests for a instance of a class. +- [isNull](#isnull) Tests for a `null` values. - [isNumber](#isnumber) Tests for a JavaScript number. - [isString](#isstring) Tests for a string. - [isUint8Array](#isuint8array) Tests for a `Uint8Array` object instance. @@ -116,6 +117,23 @@ import { isInstanceOf } from '@polkadot/util'; console.log('isinstanceOf', isInstanceOf(new Array(0), Array)); // => true ``` +## isNull + +Tests for a `null` values. + +```js +isNull (value: any): boolean +``` + + +Checks to see if the input value is `null`. + +```js +import { isNull } from '@polkadot/util'; + +console.log('isNull', isNull(null)); // => true +``` + ## isNumber Tests for a JavaScript number. diff --git a/docs/number.md b/docs/number.md new file mode 100644 index 000000000..3d4df6f87 --- /dev/null +++ b/docs/number.md @@ -0,0 +1,76 @@ +# number + +Utility methods to convert to and from `number` values + +- [numberFromBuffer](#numberfrombuffer) Creates a Number value from a Buffer object. +- [numberFromHex](#numberfromhex) Creates a Number value from a Buffer object. +- [numberToBuffer](#numbertobuffer) Creates a Buffer object from a number. +- [numberToHex](#numbertohex) Creates a hex value from a number. + +## numberFromBuffer + +Creates a Number value from a Buffer object. + +```js +numberFromBuffer (value?: Buffer): number +``` + + +`null` inputs returns an NaN result, `Buffer` values return the actual value as a `Number`. + +```js +import { numberFromBuffer } from '@polkadot/util'; + +numberFromBuffer(Buffer.from([12, 34, 56])); // => 0x123456 +``` + +## numberFromHex + +Creates a Number value from a Buffer object. + +```js +numberFromHex (value?: Hex): number +``` + + +`null` inputs returns an Nan result, `hex` values return the actual value as a `Number`. + +```js +import { numberFromHex } from '@polkadot/util'; + +numberFromBuffer('0x1234'); // => 0x1234 +``` + +## numberToBuffer + +Creates a Buffer object from a number. + +```js +numberToBuffer (value?: number): Buffer +``` + + +`null`/`undefined`/`NaN` inputs returns an empty `Buffer` result. `number` input values return the actual bytes value converted to a `Buffer`. + +```js +import { numberToBuffer } from '@polkadot/util'; + +const buffer = numberToBuffer('0x1234'); // => Buffer.from([0x12, 0x34]) +``` + +## numberToHex + +Creates a hex value from a number. + +```js +numberToHex (value?: number): string +``` + + +`null`/`undefined`/`NaN` inputs returns an empty `0x` result. `number` input values return the actual bytes value converted to a `hex`. + +```js +import { numberToHex } from '@polkadot/util'; + +const hex = numberToHex(0x1234); // => '0x1234' +``` \ No newline at end of file diff --git a/package.json b/package.json index 88c858baf..7820b3cdf 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "test": "jest --coverage src" }, "devDependencies": { - "@polkadot/api-jsonrpc": "^0.5.4", + "@polkadot/api-jsonrpc": "^0.5.5", "@polkadot/dev": "^0.9.9" }, "dependencies": { diff --git a/src/hex/addPrefix.js b/src/hex/addPrefix.js index 00a3a5c6e..5644f2993 100644 --- a/src/hex/addPrefix.js +++ b/src/hex/addPrefix.js @@ -19,5 +19,9 @@ module.exports = function hexAddPrefix (value: ?string): string { return value; } - return `0x${value || ''}`; + const prefix = value && value.length % 2 === 1 + ? '0' + : ''; + + return `0x${prefix}${value || ''}`; }; diff --git a/src/hex/index.spec.js b/src/hex/index.spec.js index d4ee1946e..4e3a0c057 100644 --- a/src/hex/index.spec.js +++ b/src/hex/index.spec.js @@ -8,14 +8,20 @@ describe('hex', () => { describe('hexAddPrefix', () => { it('does not add when prefix is available', () => { expect( - hexAddPrefix('0x123') - ).toEqual('0x123'); + hexAddPrefix('0x0123') + ).toEqual('0x0123'); }); it('adds the prefix when it is not available', () => { + expect( + hexAddPrefix('0123') + ).toEqual('0x0123'); + }); + + it('adds extra 0 when length % 2 === 1', () => { expect( hexAddPrefix('123') - ).toEqual('0x123'); + ).toEqual('0x0123'); }); it('returns null as 0x', () => { diff --git a/src/is/index.js b/src/is/index.js index d26502865..4f26bc402 100644 --- a/src/is/index.js +++ b/src/is/index.js @@ -7,6 +7,7 @@ const isError = require('./error'); const isFunction = require('./function'); const isHex = require('./hex'); const isInstanceOf = require('./instanceOf'); +const isNull = require('./null'); const isNumber = require('./number'); const isString = require('./string'); const isUndefined = require('./undefined'); @@ -21,6 +22,7 @@ module.exports = { isFunction, isHex, isInstanceOf, + isNull, isNumber, isString, isUndefined diff --git a/src/is/null.js b/src/is/null.js new file mode 100644 index 000000000..b66d66ca3 --- /dev/null +++ b/src/is/null.js @@ -0,0 +1,17 @@ +// ISC, Copyright 2017 Jaco Greeff +// @flow + +/** + @name isNull + @signature isNull (value: any): boolean + @summary Tests for a `null` values. + @description + Checks to see if the input value is `null`. + @example + import { isNull } from '@polkadot/util'; + + console.log('isNull', isNull(null)); // => true +*/ +module.exports = function isNull (value: any): boolean { + return value === null; +}; diff --git a/src/number/fromBuffer.js b/src/number/fromBuffer.js new file mode 100644 index 000000000..249107910 --- /dev/null +++ b/src/number/fromBuffer.js @@ -0,0 +1,28 @@ +// ISC, Copyright 2017 Jaco Greeff +// @flow + +/** + @name numberFromBuffer + @signature numberFromBuffer (value?: Buffer): number + @summary Creates a Number value from a Buffer object. + @description + `null` inputs returns an NaN result, `Buffer` values return the actual value as a `Number`. + @example + import { numberFromBuffer } from '@polkadot/util'; + + numberFromBuffer(Buffer.from([12, 34, 56])); // => 0x123456 +*/ +module.exports = function numberFromBuffer (buffer?: Buffer): number { + if (!buffer || !buffer.length) { + return NaN; + } + + const length = buffer.length; + let value = 0; + + for (let index = 0; index < length; ++index) { + value = (value * 256) + buffer[index]; + } + + return value; +}; diff --git a/src/number/fromHex.js b/src/number/fromHex.js new file mode 100644 index 000000000..aae73d7a7 --- /dev/null +++ b/src/number/fromHex.js @@ -0,0 +1,26 @@ +// ISC, Copyright 2017 Jaco Greeff +// @flow + +const bufferFromHex = require('../buffer/fromHex'); +const numberFromBuffer = require('./fromBuffer'); + +/** + @name numberFromHex + @signature numberFromHex (value?: Hex): number + @summary Creates a Number value from a Buffer object. + @description + `null` inputs returns an Nan result, `hex` values return the actual value as a `Number`. + @example + import { numberFromHex } from '@polkadot/util'; + + numberFromBuffer('0x1234'); // => 0x1234 +*/ +module.exports = function numberFromHex (value?: string): number { + if (!value) { + return NaN; + } + + return numberFromBuffer( + bufferFromHex(value) + ); +}; diff --git a/src/number/index.js b/src/number/index.js new file mode 100644 index 000000000..e32c2bc1c --- /dev/null +++ b/src/number/index.js @@ -0,0 +1,17 @@ +// ISC, Copyright 2017 Jaco Greeff +// @flow + +const numberFromBuffer = require('./fromBuffer'); +const numberFromHex = require('./fromHex'); +const numberToBuffer = require('./toBuffer'); +const numberToHex = require('./toHex'); + +/** + @summary Utility methods to convert to and from `number` values +*/ +module.exports = { + numberFromBuffer, + numberFromHex, + numberToBuffer, + numberToHex +}; diff --git a/src/number/index.spec.js b/src/number/index.spec.js new file mode 100644 index 000000000..86b1020ec --- /dev/null +++ b/src/number/index.spec.js @@ -0,0 +1,100 @@ +// ISC, Copyright 2017 Jaco Greeff + +const numberFromBuffer = require('./fromBuffer'); +const numberFromHex = require('./fromHex'); +const numberToBuffer = require('./toBuffer'); +const numberToHex = require('./toHex'); + +describe('number', () => { + describe('numberFromBuffer', () => { + it('converts nothing to NaN', () => { + expect( + numberFromBuffer() + ).toEqual(NaN); + }); + + it('converts empty buffer to NaN', () => { + expect( + numberFromBuffer(Buffer.from([])) + ).toEqual(NaN); + }); + + it('converts a buffer to a value', () => { + expect( + numberFromBuffer(Buffer.from([0x12, 0x34])) + ).toEqual(0x1234); + }); + }); + + describe('numberToBuffer', () => { + it('converts undefined to empty', () => { + expect( + numberToBuffer() + ).toEqual(Buffer.from([])); + }); + + it('converts null to empty', () => { + expect( + numberToBuffer(null) + ).toEqual(Buffer.from([])); + }); + + it('converts NaN to empty', () => { + expect( + numberToBuffer(NaN) + ).toEqual(Buffer.from([])); + }); + + it('converts values to the buffer', () => { + expect( + numberToBuffer(0x3456) + ).toEqual(Buffer.from([0x34, 0x56])); + }); + }); + + describe('numberFromHex', () => { + it('converts an empty to NaN', () => { + expect( + numberFromHex() + ).toEqual(NaN); + }); + + it('converts to a number from hex', () => { + expect( + numberFromHex('0x1234') + ).toEqual(0x1234); + }); + }); + + describe('numberToHex', () => { + it('converts undefined to 0x', () => { + expect( + numberToHex() + ).toEqual('0x'); + }); + + it('converts null to 0x', () => { + expect( + numberToHex(null) + ).toEqual('0x'); + }); + + it('converts Nan to 0x', () => { + expect( + numberToHex(NaN) + ).toEqual('0x'); + }); + + it('converts 0 to 0x00', () => { + expect( + numberToHex(0) + ).toEqual('0x00'); + }); + + it('converts number to hex', () => { + expect( + numberToHex(0x1245) + ).toEqual('0x1245'); + }); + }); +}); diff --git a/src/number/toBuffer.js b/src/number/toBuffer.js new file mode 100644 index 000000000..836cfde1c --- /dev/null +++ b/src/number/toBuffer.js @@ -0,0 +1,28 @@ +// ISC, Copyright 2017 Jaco Greeff +// @flow + +const bufferFromHex = require('../buffer/fromHex'); +const isNull = require('../is/null'); +const isUndefined = require('../is/undefined'); +const numberToHex = require('./toHex'); + +/** + @name numberToBuffer + @signature numberToBuffer (value?: number): Buffer + @summary Creates a Buffer object from a number. + @description + `null`/`undefined`/`NaN` inputs returns an empty `Buffer` result. `number` input values return the actual bytes value converted to a `Buffer`. + @example + import { numberToBuffer } from '@polkadot/util'; + + const buffer = numberToBuffer('0x1234'); // => Buffer.from([0x12, 0x34]) +*/ +module.exports = function numberToBuffer (value?: number): Buffer { + if (isUndefined(value) || isNull(value) || isNaN(value)) { + return Buffer.from([]); + } + + return bufferFromHex( + numberToHex(value) + ); +}; diff --git a/src/number/toHex.js b/src/number/toHex.js new file mode 100644 index 000000000..f8eb99326 --- /dev/null +++ b/src/number/toHex.js @@ -0,0 +1,27 @@ +// ISC, Copyright 2017 Jaco Greeff +// @flow + +const hexAddPrefix = require('../hex/addPrefix'); +const isNull = require('../is/null'); +const isUndefined = require('../is/undefined'); + +/** + @name numberToHex + @signature numberToHex (value?: number): string + @summary Creates a hex value from a number. + @description + `null`/`undefined`/`NaN` inputs returns an empty `0x` result. `number` input values return the actual bytes value converted to a `hex`. + @example + import { numberToHex } from '@polkadot/util'; + + const hex = numberToHex(0x1234); // => '0x1234' +*/ +module.exports = function numberToHex (value?: number): string { + if (isUndefined(value) || isNull(value) || isNaN(value)) { + return '0x'; + } + + return hexAddPrefix( + (value || 0).toString(16) + ); +};