Standardized toJSON, fromJSON, toString and fromString interfaces

This commit is contained in:
Braydon Fuller 2014-12-12 01:01:14 -05:00
parent d6caab69ca
commit 1858766627
11 changed files with 219 additions and 28 deletions

View File

@ -3,6 +3,7 @@
var base58check = require('./encoding/base58check');
var Networks = require('./networks');
var Hash = require('./crypto/hash');
var jsUtil = require('./util/js');
/**
* Instantiate an address from an address String or Buffer, a public key or script hash Buffer,
@ -305,6 +306,20 @@ Address.fromString = function(str, network, type) {
return new Address(info.hashBuffer, info.network, info.type);
};
/**
* Instantiate an address from JSON
*
* @param {String} json - An JSON string or Object with keys: hash, network and type
* @returns {Address} A new valid instance of an Address
*/
Address.fromJSON = function fromJSON(json) {
if (jsUtil.isValidJson(json)) {
json = JSON.parse(json);
}
var hashBuffer = new Buffer(json.hash, 'hex');
return new Address(hashBuffer, json.network, json.type);
};
/**
* Will return a validation error if exists
*
@ -372,6 +387,17 @@ Address.prototype.toBuffer = function() {
return buf;
};
/**
* @returns {Object} An object of the address
*/
Address.prototype.toJSON = function toJSON() {
return {
hash: this.hashBuffer.toString('hex'),
type: this.type,
network: this.network.toString()
};
};
/**
* Will return a the string representation of the address
*

View File

@ -121,6 +121,15 @@ Block.fromBuffer = function fromBuffer(buf) {
return Block.fromBufferReader(BufferReader(buf));
};
/**
* @param {String} - str - A hex encoded string of the block
* @returns {Block} - A hex encoded string of the block
*/
Block.fromString = function fromString(str) {
var buf = new Buffer(str, 'hex');
return Block.fromBuffer(buf);
};
/**
* @param {Binary} - Raw block binary data or buffer
* @returns {Block} - An instance of block
@ -158,6 +167,13 @@ Block.prototype.toBuffer = function toBuffer() {
return this.toBufferWriter().concat();
};
/**
* @returns {String} - A hex encoded string of the block
*/
Block.prototype.toString = function toString() {
return this.toBuffer().toString('hex');
};
/**
* @param {BufferWriter} - An existing instance of BufferWriter
* @returns {BufferWriter} - An instance of BufferWriter representation of the Block

View File

@ -103,6 +103,15 @@ BlockHeader.fromBuffer = function fromBuffer(buf) {
return new BlockHeader(info);
};
/**
* @param {String} - A hex encoded buffer of the block header
* @returns {BlockHeader} - An instance of block header
*/
BlockHeader.fromString = function fromString(str) {
var buf = new Buffer(str, 'hex');
return BlockHeader.fromBuffer(buf);
};
/**
* @param {BufferReader} - A BufferReader of the block header
* @returns {Object} - An object representing block header data
@ -150,6 +159,13 @@ BlockHeader.prototype.toBuffer = function toBuffer() {
return this.toBufferWriter().concat();
};
/**
* @returns {String} - A hex encoded string of the BlockHeader
*/
BlockHeader.prototype.toString = function toString() {
return this.toBuffer().toString('hex');
};
/**
* @param {BufferWriter} - An existing instance BufferWriter
* @returns {BufferWriter} - An instance of BufferWriter representation of the BlockHeader

View File

@ -2,6 +2,7 @@
var _ = require('lodash');
var BufferUtil = require('./util/buffer');
var jsUtil = require('./util/js');
/**
* A network is merely a map containing values that correspond to version

View File

@ -1,5 +1,7 @@
'use strict';
var jsUtil = require('./util/js');
/**
*
* Bitcore Unit
@ -27,6 +29,9 @@ function Unit(amount, code) {
return new Unit(amount, code);
}
this._amount = amount;
this._code = code;
this._value = this._from(amount, code);
var self = this;
@ -51,9 +56,20 @@ Object.keys(UNITS).forEach(function(key) {
Unit[key] = key;
});
/**
* Will return a Unit instance created from JSON string or object
*
* @param {String|Object} json - JSON with keys: amount and code
* @returns {Unit} A Unit instance
*/
Unit.fromJSON = function fromJSON(json){
if (jsUtil.isValidJson(json)) {
json = JSON.parse(json);
}
return new Unit(json.amount, json.code);
};
/**
*
* Will return a Unit instance created from an amount in BTC
*
* @param {Number} amount - The amount in BTC
@ -64,7 +80,6 @@ Unit.fromBTC = function(amount) {
};
/**
*
* Will return a Unit instance created from an amount in mBTC
*
* @param {Number} amount - The amount in mBTC
@ -75,7 +90,6 @@ Unit.fromMilis = function(amount) {
};
/**
*
* Will return a Unit instance created from an amount in bits
*
* @param {Number} amount - The amount in bits
@ -86,7 +100,6 @@ Unit.fromBits = function(amount) {
};
/**
*
* Will return a Unit instance created from an amount in satoshis
*
* @param {Number} amount - The amount in satoshis
@ -103,7 +116,6 @@ Unit.prototype._from = function(amount, code) {
};
/**
*
* Will return the value represented in the specified unit
*
* @param {string} code - The unit code
@ -117,7 +129,6 @@ Unit.prototype.to = function(code) {
};
/**
*
* Will return the value represented in BTC
*
* @returns {Number} The value converted to BTC
@ -137,7 +148,6 @@ Unit.prototype.toMilis = function(code) {
};
/**
*
* Will return the value represented in bits
*
* @returns {Number} The value converted to bits
@ -147,7 +157,6 @@ Unit.prototype.toBits = function(code) {
};
/**
*
* Will return the value represented in satoshis
*
* @returns {Number} The value converted to satoshis
@ -157,7 +166,6 @@ Unit.prototype.toSatoshis = function() {
};
/**
*
* Will return a the string representation of the value in satoshis
*
* @returns {String} the value in satoshis
@ -167,7 +175,18 @@ Unit.prototype.toString = function() {
};
/**
* Will return a the JSON object representation of the unit
*
* @returns {Object} An object with the keys: amount and code
*/
Unit.prototype.toJSON = function toJSON(){
return {
amount: this._amount,
code: this._code
};
};
/**
* Will return a string formatted for the console
*
* @returns {String} the value in satoshis

View File

@ -5,9 +5,9 @@ var URL = require('url');
var Address = require('./address');
var Unit = require('./unit');
var jsUtil = require('./util/js');
/**
*
* Bitcore URI
*
* Instantiate an URI from a bitcoin URI String or an Object. An URI instance
@ -35,11 +35,13 @@ var URI = function(data, knownParams) {
this.knownParams = knownParams || [];
this.address = this.network = this.amount = this.message = null;
if (typeof(data) == 'string') {
if (typeof(data) === 'string') {
var params = URI.parse(data);
if (params.amount) params.amount = this._parseAmount(params.amount);
if (params.amount) {
params.amount = this._parseAmount(params.amount);
}
this._fromObject(params);
} else if (typeof(data) == 'object') {
} else if (typeof(data) === 'object') {
this._fromObject(data);
} else {
throw new TypeError('Unrecognized data format.');
@ -47,7 +49,32 @@ var URI = function(data, knownParams) {
};
/**
* Instantiate a URI from a String
*
* @param {String} str - JSON string or object of the URI
* @returns {URI} A new instance of a URI
*/
URI.fromString = function fromString(str) {
if (typeof(str) !== 'string') {
throw TypeError('Expected a string');
}
return new URI(str);
};
/**
* Instantiate a URI from JSON
*
* @param {String|Object} json - JSON string or object of the URI
* @returns {URI} A new instance of a URI
*/
URI.fromJSON = function fromJSON(json) {
if (jsUtil.isValidJson(json)) {
json = JSON.parse(json);
}
return new URI(json);
};
/**
* Check if an bitcoin URI string is valid
*
* @example
@ -69,7 +96,6 @@ URI.isValid = function(arg, knownParams) {
};
/**
*
* Convert a bitcoin URI string into a simple object.
*
* @param {string} uri - A bitcoin URI string
@ -90,8 +116,9 @@ URI.parse = function(uri) {
return info.query;
};
URI.Members = ['address', 'amount', 'message', 'label', 'r'];
/**
*
* Internal function to load the URI instance with an object.
*
* @param {Object} obj - Object with the information
@ -100,9 +127,10 @@ URI.parse = function(uri) {
* @throws {Error} Unknown required argument
*/
URI.prototype._fromObject = function(obj) {
var members = ['address', 'amount', 'message', 'label', 'r'];
if (!Address.isValid(obj.address)) throw new TypeError('Invalid bitcoin address');
if (!Address.isValid(obj.address)) {
throw new TypeError('Invalid bitcoin address');
}
this.address = new Address(obj.address);
this.network = this.address.network;
@ -115,13 +143,12 @@ URI.prototype._fromObject = function(obj) {
throw Error('Unknown required argument ' + key);
}
var destination = members.indexOf(key) > -1 ? this : this.extras;
var destination = URI.Members.indexOf(key) > -1 ? this : this.extras;
destination[key] = obj[key];
}
};
/**
*
* Internal function to transform a BTC string amount into satoshis
*
* @param {String} amount - Amount BTC string
@ -129,21 +156,49 @@ URI.prototype._fromObject = function(obj) {
* @returns {Object} Amount represented in satoshis
*/
URI.prototype._parseAmount = function(amount) {
var amount = Number(amount);
if (isNaN(amount)) throw new TypeError('Invalid amount');
amount = Number(amount);
if (isNaN(amount)) {
throw new TypeError('Invalid amount');
}
return Unit.fromBTC(amount).toSatoshis();
};
URI.prototype.toJSON = function() {
var json = {};
for(var i=0;i<URI.Members.length;i++){
var m = URI.Members[i];
if (this.hasOwnProperty(m) && typeof(this[m]) !== 'undefined'){
if (typeof(this[m].toString) === 'function') {
json[m] = this[m].toString();
} else {
json[m] = this[m];
}
}
}
_.extend(json, this.extras);
return json;
};
/**
*
* Will return a the string representation of the URI
*
* @returns {String} Bitcoin URI string
*/
URI.prototype.toString = function() {
var query = _.clone(this.extras);
if (this.amount) query.amount = Unit.fromSatoshis(this.amount).toBTC();
if (this.message) query.message = this.message;
var query = {};
if (this.amount) {
query.amount = Unit.fromSatoshis(this.amount).toBTC();
}
if (this.message) {
query.message = this.message;
}
if (this.label) {
query.label = this.label;
}
if (this.r) {
query.r = this.r;
}
_.extend(query, this.extras);
return URL.format({
protocol: 'bitcoin:',
@ -153,13 +208,12 @@ URI.prototype.toString = function() {
};
/**
*
* Will return a string formatted for the console
*
* @returns {String} Bitcoin URI
*/
URI.prototype.inspect = function() {
return '<URI: ' + this.toString()+ '>';
}
};
module.exports = URI;

View File

@ -355,6 +355,21 @@ describe('Address', function() {
});
describe('#json', function() {
it('should output/input a JSON object', function() {
var address = Address.fromJSON(new Address(str).toJSON());
address.toString().should.equal(str);
});
it('should output/input a JSON string', function() {
var json = JSON.stringify(new Address(str).toJSON());
var address = Address.fromJSON(json);
address.toString().should.equal(str);
});
});
describe('#toString', function() {
it('should output a livenet pubkeyhash address', function() {

View File

@ -118,6 +118,15 @@ describe('Block', function() {
});
describe('#fromString/#toString', function() {
it('should output/input a block hex string', function() {
var b = Block.fromString(blockhex);
b.toString().should.equal(blockhex);
});
});
describe('#fromBuffer', function() {
it('should make a block from this known buffer', function() {

View File

@ -122,6 +122,15 @@ describe('BlockHeader', function() {
});
describe('#fromString/#toString', function() {
it('should output/input a block hex string', function() {
var b = BlockHeader.fromString(bhhex);
b.toString().should.equal(bhhex);
});
});
describe('#fromBuffer', function() {
it('should parse this known buffer', function() {

View File

@ -123,6 +123,12 @@ describe('Unit', function() {
unit.toString().should.be.a('string');
});
it('should input/output JSON', function() {
var json = {amount:1.3, code:'BTC'};
var unit = Unit.fromJSON(json);
unit.toJSON().should.deep.equal(json);
});
it('should have an inspect method', function() {
var unit = new Unit(1.3, 'BTC');
should.exist(unit.inspect);

View File

@ -65,6 +65,11 @@ describe('URI', function() {
uri.address.should.be.instanceof(bitcore.Address);
uri.network.should.equal(Networks.livenet);
uri = URI.fromString('bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?amount=123.22');
uri.address.toString().should.equal('1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
uri.amount.should.equal(12322000000);
expect(uri.otherParam).to.be.undefined;
uri = new URI('bitcoin:mkYY5NRvikVBY1EPtaq9fAFgquesdjqECw');
uri.address.should.be.instanceof(bitcore.Address);
uri.network.should.equal(Networks.testnet);
@ -135,6 +140,21 @@ describe('URI', function() {
uri.address.toString().should.equal('1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj');
});
it('should input/output String', function() {
var str = 'bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?message=Donation%20for%20project%20xyz&label=myLabel&other=xD';
URI.fromString(str).toString().should.equal(str);
});
it('should input/output JSON', function() {
var json = {
address: '1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj',
message: 'Donation for project xyz',
label: 'myLabel',
other: 'xD'
};
URI.fromJSON(json).toJSON().should.deep.equal(json);
});
it('should support numeric amounts', function() {
var uri = new URI('bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?amount=12.10001');
expect(uri.amount).to.be.equal(1210001000);
@ -166,7 +186,7 @@ describe('URI', function() {
message: 'Hello World',
something: 'else'
}).toString().should.equal(
'bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?something=else&amount=1.10001&message=Hello%20World'
'bitcoin:1DP69gMMvSuYhbnxsi4EJEFufUAbDrEQfj?amount=1.10001&message=Hello%20World&something=else'
);
});