diff --git a/.gitignore b/.gitignore index 2be4b2402..9cf6a6ae3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,6 @@ node_modules browser/tests.js docs/api -lib/errors/index.js - CONTRIBUTING.html LICENSE.html README.html @@ -16,4 +14,8 @@ apiref bower_components report .DS_Store -browser + + +bitcore.js +bitcore.min.js +tests.js diff --git a/bower.json b/bower.json index ac4c44419..8ec416bcf 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "bitcore", - "main": "browser/bitcore.min.js", + "main": "./bitcore.min.js", "version": "0.8.6", "homepage": "http://bitcore.io", "authors": [ diff --git a/gulpfile.js b/gulpfile.js index ed80a78d9..53191d2f5 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,336 +1,5 @@ -/** - * @file gulpfile.js - * - * Defines tasks that can be run on gulp. - * - * Summary: - */ -'use strict'; - -var gulp = require('gulp'); - -var bump = require('gulp-bump'); -var coveralls = require('gulp-coveralls'); -var git = require('gulp-git'); -var gutil = require('gulp-util'); -var jsdoc2md = require('jsdoc-to-markdown'); -var jshint = require('gulp-jshint'); -var mfs = require('more-fs'); -var mocha = require('gulp-mocha'); -var rename = require('gulp-rename'); -var runSequence = require('run-sequence'); -var shell = require('gulp-shell'); -var through = require('through2'); -var uglify = require('gulp-uglify'); -var files = ['lib/**/*.js']; -var tests = ['test/**/*.js']; -var alljs = files.concat(tests); +var gulp_bitcore = require('gulp-bitcore'); - -function ignoreError() { - /* jshint ignore:start */ // using `this` in this context is weird - this.emit('end'); - /* jshint ignore:end */ -} - -var testMocha = function() { - return gulp.src(tests).pipe(new mocha({ - reporter: 'spec' - })); -}; - -var testKarma = shell.task([ - './node_modules/karma/bin/karma start' -]); - -/** - * Testing - */ - -gulp.task('test:node', ['errors'], testMocha); - -gulp.task('test:node:nofail', ['errors'], function() { - return testMocha().on('error', ignoreError); -}); - -gulp.task('test:browser', ['browser:uncompressed', 'browser:maketests'], testKarma); - -gulp.task('test', function(callback) { - runSequence(['test:node'], ['test:browser'], callback); -}); - -/** - * File generation - */ - -gulp.task('browser:makefolder', shell.task([ - 'if [ ! -d "browser" ]; then mkdir browser; fi' -])); - -gulp.task('browser:uncompressed', ['browser:makefolder', 'errors'], shell.task([ - './node_modules/.bin/browserify index.js --insert-global-vars=true --standalone=bitcore -o browser/bitcore.js' -])); - -gulp.task('browser:compressed', ['browser:uncompressed'], function() { - return gulp.src('browser/bitcore.js') - .pipe(uglify({ - mangle: true, - compress: true - })) - .pipe(rename('bitcore.min.js')) - .pipe(gulp.dest('browser')) - .on('error', gutil.log); -}); - -gulp.task('browser:maketests', ['browser:makefolder'], shell.task([ - 'find test/ -type f -name "*.js" | xargs ./node_modules/.bin/browserify -t brfs -o browser/tests.js' -])); - -gulp.task('browser', function(callback) { - runSequence(['browser:compressed'], ['browser:maketests'], callback); -}); - -gulp.task('errors', shell.task([ - 'node ./lib/errors/build.js' -])); - - -/** - * Code quality and documentation - */ - -gulp.task('lint', function() { - return gulp.src(alljs) - .pipe(jshint()) - .pipe(jshint.reporter('default')); -}); - -gulp.task('plato', shell.task(['plato -d report -r -l .jshintrc -t bitcore lib'])); - -gulp.task('jsdoc', function() { - - function jsdoc() { - return through.obj(function(file, enc, cb) { - - if (file.isNull()) { - cb(null, file); - return; - } - if (file.isStream()) { - cb(new gutil.PluginError('gulp-jsdoc2md', 'Streaming not supported')); - return; - } - var destination = 'docs/api/' + file.path.replace(file.base, '').replace(/\.js$/, '.md'); - jsdoc2md.render(file.path, {}) - .on('error', function(err) { - gutil.log(gutil.colors.red('jsdoc2md failed', err.message)); - }) - .pipe(mfs.writeStream(destination)); - cb(null, file); - }); - } - - return gulp.src(files).pipe(jsdoc()); - -}); - -gulp.task('coverage', shell.task(['node_modules/.bin/./istanbul cover node_modules/.bin/_mocha -- --recursive'])); - -gulp.task('coveralls', ['coverage'], function() { - gulp.src('coverage/lcov.info').pipe(coveralls()); -}); - -/** - * Watch tasks - */ - -gulp.task('watch:test', function() { - // TODO: Only run tests that are linked to file changes by doing - // something smart like reading through the require statements - return gulp.watch(alljs, ['test']); -}); - -gulp.task('watch:test:node', function() { - // TODO: Only run tests that are linked to file changes by doing - // something smart like reading through the require statements - return gulp.watch(alljs, ['test:node']); -}); - -gulp.task('watch:test:browser', function() { - // TODO: Only run tests that are linked to file changes by doing - // something smart like reading through the require statements - return gulp.watch(alljs, ['test:browser']); -}); - -gulp.task('watch:jsdoc', function() { - // TODO: Only run tests that are linked to file changes by doing - // something smart like reading through the require statements - return gulp.watch(alljs, ['jsdoc']); -}); - -gulp.task('watch:coverage', function() { - // TODO: Only run tests that are linked to file changes by doing - // something smart like reading through the require statements - return gulp.watch(alljs, ['coverage']); -}); - -gulp.task('watch:lint', function() { - // TODO: Only lint files that are linked to file changes by doing - // something smart like reading through the require statements - return gulp.watch(alljs, ['lint']); -}); - -gulp.task('watch:browser', function() { - return gulp.watch(alljs, ['browser']); -}); - -/** - * Release automation - */ - -gulp.task('release:install', function() { - return shell.task([ - 'npm install', - ]); -}); - -gulp.task('release:bump', function() { - return gulp.src(['./bower.json', './package.json']) - .pipe(bump({ - type: 'patch' - })) - .pipe(gulp.dest('./')); -}); - -gulp.task('release:checkout-releases', function(cb) { - git.checkout('releases', { - args: '' - }, cb); -}); - -gulp.task('release:merge-master', function(cb) { - git.merge('master', { - args: '' - }, cb); -}); - -gulp.task('release:checkout-master', function(cb) { - git.checkout('master', { - args: '' - }, cb); -}); - -gulp.task('release:add-built-files', function() { - return gulp.src(['./browser/bitcore.js', './browser/bitcore.min.js', './package.json', './bower.json']) - .pipe(git.add({ - args: '-f' - })); -}); - -gulp.task('release:build-commit', ['release:add-built-files'], function() { - var pjson = require('./package.json'); - return gulp.src(['./browser/bitcore.js', './browser/bitcore.min.js', './package.json', './bower.json']) - .pipe(git.commit('Build: ' + pjson.version, { - args: '' - })); -}); - -gulp.task('release:version-commit', function() { - var pjson = require('./package.json'); - var files = ['./package.json', './bower.json']; - return gulp.src(files) - .pipe(git.commit('Bump package version to ' + pjson.version, { - args: '' - })); -}); - -gulp.task('release:push-releases', function(cb) { - git.push('bitpay', 'releases', { - args: '' - }, cb); -}); - -gulp.task('release:push', function(cb) { - git.push('bitpay', 'master', { - args: '' - }, cb); -}); - -gulp.task('release:push-tag', function(cb) { - var pjson = require('./package.json'); - var name = 'v' + pjson.version; - git.tag(name, 'Release ' + name, function() { - git.push('bitpay', name, cb); - }); -}); - -gulp.task('release:publish', shell.task([ - 'npm publish' -])); - -// requires https://hub.github.com/ -gulp.task('release', function(cb) { - runSequence( - // Checkout the `releases` branch - ['release:checkout-releases'], - // Merge the master branch - ['release:merge-master'], - // Run npm install - ['release:install'], - // Build browser bundle - ['browser:compressed'], - // Run tests with gulp test - ['test'], - // Update package.json and bower.json - ['release:bump'], - // Commit - ['release:build-commit'], - // Run git push bitpay $VERSION - ['release:push-tag'], - // Push to releases branch - ['release:push-releases'], - // Run npm publish - ['release:publish'], - // Checkout the `master` branch - ['release:checkout-master'], - // Bump package.json and bower.json, again - ['release:bump'], - // Version commit with no binary files to master - ['release:version-commit'], - // Push to master - ['release:push'], - cb); -}); - - -/* Default task */ -gulp.task('default', function(callback) { - return runSequence(['lint', 'jsdoc'], ['browser:uncompressed', 'test'], ['coverage', 'browser:compressed'], - callback); -}); +gulp_bitcore(); diff --git a/karma.conf.js b/karma.conf.js index acc9eacdc..dc5d5970e 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -23,7 +23,7 @@ module.exports = function(config) { }, singleRun: true, files: [ - 'browser/tests.js' + 'tests.js' ], plugins: [ 'karma-mocha', diff --git a/lib/errors/build.js b/lib/errors/build.js deleted file mode 100644 index 723e1e419..000000000 --- a/lib/errors/build.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; - -var _ = require('lodash'); -var fs = require('fs'); - -var defineElement = function(fullName, baseClass, message) { - return fullName + ' = function() {\n' + - ' this.message = ' + message + ';\n' + - ' this.stack = this.message + \'\\n\' + (new Error()).stack;\n' + - '};\n' + - fullName + '.prototype = Object.create(' + baseClass + '.prototype);\n' + - fullName + '.prototype.name = "' + fullName + '";\n\n'; -}; - -var traverseNode = function(baseClass, errorDefinition) { - var className = baseClass + '.' + errorDefinition.name; - var generated = defineElement(className, baseClass, errorDefinition.message); - if (errorDefinition.errors) { - generated += childDefinitions(className, errorDefinition.errors); - } - return generated; -}; - -/* jshint latedef: false */ -var childDefinitions = function(parent, childDefinitions) { - var generated = ''; - _.each(childDefinitions, function(childDefinition) { - generated += traverseNode(parent, childDefinition); - }); - return generated; -}; -/* jshint latedef: true */ - -var traverseRoot = function(errorsDefinition) { - var fullName = 'bitcore.Error'; - var path = 'Error'; - var generated = '\'use strict\';\n\n'; - generated += '/* jshint maxlen: 300 */\n'; - generated += '/* jshint quotmark: false */\n'; - generated += '/* AUTOGENERATED FILE. DON\'T EDIT, MODIFY "lib/errors/spec.js" INSTEAD */\n\n'; - generated += 'var bitcore = {};\n\n'; - generated += defineElement(fullName, path, '\'Internal error\''); - generated += childDefinitions(fullName, errorsDefinition); - generated += 'module.exports = bitcore.Error;\n'; - return generated; -}; - -var data = require('./spec'); -fs.writeFileSync(__dirname + '/index.js', traverseRoot(data)); diff --git a/lib/errors/index.js b/lib/errors/index.js new file mode 100644 index 000000000..de6f7311e --- /dev/null +++ b/lib/errors/index.js @@ -0,0 +1,61 @@ +'use strict'; + +var _ = require('lodash'); + +function format(message, args) { + return message + .replace('{0}', args[0]) + .replace('{1}', args[1]) + .replace('{2}', args[2]); +} +var traverseNode = function(parent, errorDefinition) { + var NodeError = function() { + if (_.isString(errorDefinition.message)) { + this.message = format(errorDefinition.message, arguments); + } else if (_.isFunction(errorDefinition.message)) { + this.message = errorDefinition.message.apply(null, arguments); + } else { + throw new Error('Invalid error definition for ' + errorDefinition.name); + } + this.stack = this.message + '\n' + (new Error()).stack; + }; + NodeError.prototype = Object.create(parent.prototype); + NodeError.prototype.name = parent.prototype.name + errorDefinition.name; + parent[errorDefinition.name] = NodeError; + if (errorDefinition.errors) { + childDefinitions(NodeError, errorDefinition.errors); + } + return NodeError; +}; + +/* jshint latedef: false */ +var childDefinitions = function(parent, childDefinitions) { + _.each(childDefinitions, function(childDefinition) { + traverseNode(parent, childDefinition); + }); +}; +/* jshint latedef: true */ + +var traverseRoot = function(parent, errorsDefinition) { + childDefinitions(parent, errorsDefinition); + return parent; +}; + + +var bitcore = {}; +bitcore.Error = function() { + this.message = 'Internal error'; + this.stack = this.message + '\n' + (new Error()).stack; +}; +bitcore.Error.prototype = Object.create(Error.prototype); +bitcore.Error.prototype.name = 'bitcore.Error'; + + +var data = require('./spec'); +traverseRoot(bitcore.Error, data); + +module.exports = bitcore.Error; + +module.exports.extend = function(spec) { + return traverseNode(bitcore.Error, spec); +}; diff --git a/lib/errors/spec.js b/lib/errors/spec.js index 70fbeacfb..c68150fea 100644 --- a/lib/errors/spec.js +++ b/lib/errors/spec.js @@ -1,131 +1,125 @@ 'use strict'; -function format(arg) { - return '\'' + arg - .replace('{0}', '\' + arguments[0] + \'') - .replace('{1}', '\' + arguments[1] + \'') - .replace('{2}', '\' + arguments[2] + \'') + '\''; -} - module.exports = [{ - name: 'InvalidB58Char', - message: format('Invalid Base58 character: {0} in {1}') - }, { - name: 'InvalidB58Checksum', - message: format('Invalid Base58 checksum for {0}') - }, { - name: 'InvalidNetwork', - message: format('Invalid version for network: got {0}') - }, { - name: 'InvalidState', - message: format('Invalid state: {0}') - }, { - name: 'NotImplemented', - message: format('Function {0} was not implemented yet') - }, { - name: 'InvalidNetworkArgument', - message: format('Invalid network: must be "livenet" or "testnet", got {0}') - }, { - name: 'InvalidArgument', - message: format('Invalid Argument' + '\' + (arguments[0] ? \': {0}\' : \'\') + \'') - }, { - name: 'AbstractMethodInvoked', - message: format('Abstract Method Invokation: {0}') - }, { - name: 'InvalidArgumentType', - message: format('Invalid Argument for {2}, expected {1} but got ') + '+ typeof arguments[0]', - }, { - name: 'Unit', - message: format('Internal Error on Unit {0}'), - errors: [{ - 'name': 'UnknownCode', - 'message': format('Unrecognized unit code: {0}') - },{ - 'name': 'InvalidRate', - 'message': format('Invalid exchange rate: {0}') - }] - }, { - name: 'Transaction', - message: format('Internal Error on Transaction {0}'), - errors: [ - { - name: 'Input', - message: format('Internal Error on Input {0}'), - errors: [{ - name: 'MissingScript', - message: format('Need a script to create an input') - }] - }, { - name: 'NeedMoreInfo', - message: format('{0}') - }, { - name: 'UnableToVerifySignature', - message: format('Unable to verify signature: {0}') - }, { - name: 'DustOutputs', - message: format('Dust amount detected in one output') - }, { - name: 'FeeError', - message: format('Fees are not correctly set {0}'), - }, { - name: 'ChangeAddressMissing', - message: format('Change address is missing') - } - ] - }, { - name: 'Script', - message: format('Internal Error on Script {0}'), - errors: [{ - name: 'UnrecognizedAddress', - message: format('Expected argument {0} to be an address') - }] - }, { - name: 'HDPrivateKey', - message: format('Internal Error on HDPrivateKey {0}'), - errors: [{ - name: 'InvalidDerivationArgument', - message: format('Invalid derivation argument {0}, expected string, or number and boolean') - }, { - name: 'InvalidEntropyArgument', - message: format('Invalid entropy: must be an hexa string or binary buffer, got {0}'), - errors: [{ - name: 'TooMuchEntropy', - message: format('Invalid entropy: more than 512 bits is non standard, got "{0}"') - }, { - name: 'NotEnoughEntropy', - message: format('Invalid entropy: at least 128 bits needed, got "{0}"') - }] - }, { - name: 'InvalidLength', - message: format('Invalid length for xprivkey string in {0}') - }, { - name: 'InvalidPath', - message: format('Invalid derivation path: {0}') - }, { - name: 'UnrecognizedArgument', - message: format('Invalid argument: creating a HDPrivateKey requires a string, buffer, json or object, got "{0}"') - }] - }, { - name: 'HDPublicKey', - message: format('Internal Error on HDPublicKey {0}'), - errors: [{ - name: 'ArgumentIsPrivateExtended', - message: format('Argument is an extended private key: {0}') - }, { - name: 'InvalidDerivationArgument', - message: format('Invalid derivation argument: got {0}') - }, { - name: 'InvalidLength', - message: format('Invalid length for xpubkey: got "{0}"') - }, { - name: 'InvalidPath', - message: format('Invalid derivation path, it should look like: "m/1/100", got "{0}"') - }, { - name: 'MustSupplyArgument', - message: format('Must supply an argument to create a HDPublicKey') - }, { - name: 'UnrecognizedArgument', - message: format('Invalid argument for creation, must be string, json, buffer, or object') - }] + name: 'InvalidB58Char', + message: 'Invalid Base58 character: {0} in {1}' +}, { + name: 'InvalidB58Checksum', + message: 'Invalid Base58 checksum for {0}' +}, { + name: 'InvalidNetwork', + message: 'Invalid version for network: got {0}' +}, { + name: 'InvalidState', + message: 'Invalid state: {0}' +}, { + name: 'NotImplemented', + message: 'Function {0} was not implemented yet' +}, { + name: 'InvalidNetworkArgument', + message: 'Invalid network: must be "livenet" or "testnet", got {0}' +}, { + name: 'InvalidArgument', + message: function() { + return 'Invalid Argument' + (arguments[0] ? (': ' + arguments[0]) : ''); } -]; +}, { + name: 'AbstractMethodInvoked', + message: 'Abstract Method Invokation: {0}' +}, { + name: 'InvalidArgumentType', + message: function() { + return 'Invalid Argument for ' + arguments[2] + ', expected ' + arguments[1] + ' but got ' + typeof arguments[0]; + } +}, { + name: 'Unit', + message: 'Internal Error on Unit {0}', + errors: [{ + 'name': 'UnknownCode', + 'message': 'Unrecognized unit code: {0}' + }, { + 'name': 'InvalidRate', + 'message': 'Invalid exchange rate: {0}' + }] +}, { + name: 'Transaction', + message: 'Internal Error on Transaction {0}', + errors: [{ + name: 'Input', + message: 'Internal Error on Input {0}', + errors: [{ + name: 'MissingScript', + message: 'Need a script to create an input' + }] + }, { + name: 'NeedMoreInfo', + message: '{0}' + }, { + name: 'UnableToVerifySignature', + message: 'Unable to verify signature: {0}' + }, { + name: 'DustOutputs', + message: 'Dust amount detected in one output' + }, { + name: 'FeeError', + message: 'Fees are not correctly set {0}', + }, { + name: 'ChangeAddressMissing', + message: 'Change address is missing' + }] +}, { + name: 'Script', + message: 'Internal Error on Script {0}', + errors: [{ + name: 'UnrecognizedAddress', + message: 'Expected argument {0} to be an address' + }] +}, { + name: 'HDPrivateKey', + message: 'Internal Error on HDPrivateKey {0}', + errors: [{ + name: 'InvalidDerivationArgument', + message: 'Invalid derivation argument {0}, expected string, or number and boolean' + }, { + name: 'InvalidEntropyArgument', + message: 'Invalid entropy: must be an hexa string or binary buffer, got {0}', + errors: [{ + name: 'TooMuchEntropy', + message: 'Invalid entropy: more than 512 bits is non standard, got "{0}"' + }, { + name: 'NotEnoughEntropy', + message: 'Invalid entropy: at least 128 bits needed, got "{0}"' + }] + }, { + name: 'InvalidLength', + message: 'Invalid length for xprivkey string in {0}' + }, { + name: 'InvalidPath', + message: 'Invalid derivation path: {0}' + }, { + name: 'UnrecognizedArgument', + message: 'Invalid argument: creating a HDPrivateKey requires a string, buffer, json or object, got "{0}"' + }] +}, { + name: 'HDPublicKey', + message: 'Internal Error on HDPublicKey {0}', + errors: [{ + name: 'ArgumentIsPrivateExtended', + message: 'Argument is an extended private key: {0}' + }, { + name: 'InvalidDerivationArgument', + message: 'Invalid derivation argument: got {0}' + }, { + name: 'InvalidLength', + message: 'Invalid length for xpubkey: got "{0}"' + }, { + name: 'InvalidPath', + message: 'Invalid derivation path, it should look like: "m/1/100", got "{0}"' + }, { + name: 'MustSupplyArgument', + message: 'Must supply an argument to create a HDPublicKey' + }, { + name: 'UnrecognizedArgument', + message: 'Invalid argument for creation, must be string, json, buffer, or object' + }] +}]; diff --git a/package.json b/package.json index a20d8a92a..654ed2bcd 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,7 @@ "lint": "gulp lint", "test": "gulp test", "coverage": "gulp coverage", - "build": "gulp", - "postinstall": "node ./lib/errors/build.js" + "build": "gulp" }, "contributors": [ { @@ -90,16 +89,7 @@ "chai": "~1.10.0", "closure-compiler-jar": "git://github.com/eordano/closure-compiler-jar.git", "gulp": "^3.8.10", - "gulp-bump": "^0.1.11", - "gulp-closure-compiler": "^0.2.9", - "gulp-coveralls": "^0.1.3", - "gulp-git": "^0.5.5", - "gulp-jshint": "^1.9.0", - "gulp-mocha": "^2.0.0", - "gulp-rename": "^1.2.0", - "gulp-shell": "^0.2.10", - "gulp-uglify": "^1.0.2", - "gulp-util": "=3.0.1", + "gulp-bitcore": "^0.3.0", "istanbul": "^0.3.5", "jsdoc": "^3.3.0-alpha11", "jsdoc-to-markdown": "=0.5.9",