From 149b7fafed79f9ea7f6dc7e8e2e6ac4030e4c574 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Mon, 12 Jan 2015 21:01:17 -0300 Subject: [PATCH] new error system with no code generation --- .gitignore | 2 - gulpfile.js | 12 +-- lib/errors/build.js | 49 --------- lib/errors/index.js | 60 +++++++++++ lib/errors/spec.js | 248 +++++++++++++++++++++----------------------- 5 files changed, 184 insertions(+), 187 deletions(-) delete mode 100644 lib/errors/build.js create mode 100644 lib/errors/index.js diff --git a/.gitignore b/.gitignore index 2be4b24..375322f 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 diff --git a/gulpfile.js b/gulpfile.js index ed80a78..012a2b8 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -21,7 +21,6 @@ *
  • `browser:compressed` - build `browser/bitcore.min.js` *
  • `browser:maketests` - build `browser/tests.js`, needed for testing without karma * ` - *
  • `errors` - autogenerate the `./lib/errors/index.js` file with error definitions *
  • `lint` - run `jshint` *
  • `coverage` - run `istanbul` with mocha to generate a report of test coverage *
  • `jsdoc` - run `jsdoc` to generate the API reference @@ -73,9 +72,9 @@ var testKarma = shell.task([ * Testing */ -gulp.task('test:node', ['errors'], testMocha); +gulp.task('test:node', testMocha); -gulp.task('test:node:nofail', ['errors'], function() { +gulp.task('test:node:nofail', function() { return testMocha().on('error', ignoreError); }); @@ -93,7 +92,7 @@ gulp.task('browser:makefolder', shell.task([ 'if [ ! -d "browser" ]; then mkdir browser; fi' ])); -gulp.task('browser:uncompressed', ['browser:makefolder', 'errors'], shell.task([ +gulp.task('browser:uncompressed', ['browser:makefolder'], shell.task([ './node_modules/.bin/browserify index.js --insert-global-vars=true --standalone=bitcore -o browser/bitcore.js' ])); @@ -116,11 +115,6 @@ 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 */ diff --git a/lib/errors/build.js b/lib/errors/build.js deleted file mode 100644 index 723e1e4..0000000 --- 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 0000000..921b2ff --- /dev/null +++ b/lib/errors/index.js @@ -0,0 +1,60 @@ +'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); + } +}; + +/* 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) { + traverseRoot(bitcore.Error, spec); +}; diff --git a/lib/errors/spec.js b/lib/errors/spec.js index 70fbeac..c68150f 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' + }] +}];