├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── package.json └── test └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Petka Antonov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions:

11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Installation 2 | 3 | npm install core-error-predicates 4 | 5 | #Introduction 6 | 7 | Error predicate functions for operational errors thrown by node core. 8 | 9 | Predicate functions take an error object as argument and return true if the error object matches. This useful for instance when using [bluebird catch filters](https://github.com/petkaantonov/bluebird/blob/master/API.md#catchfunction-errorclassfunction-predicate-function-handler---promise) or in the future when the JavaScript `catch` clauses will be able to take filter/predicate function parameters. 10 | 11 | Example using [bluebird](https://github.com/petkaantonov/bluebird/): 12 | 13 | ```js 14 | require("core-error-predicates").globalize(); 15 | fs.readFileAsync("test.txt", "utf8").then(function(contents) { 16 | console.log("file contents:", contents); 17 | }) 18 | .catch(FileNotFoundError, function(e) { 19 | console.log("file test.txt does not exist"); 20 | }) 21 | .catch(FileAccessError, function(e) { 22 | console.log("no permissions to access test.txt"); 23 | }); 24 | ``` 25 | 26 | #API 27 | 28 | The module exports various error predicates and the `.globalize()` method. 29 | 30 | The `.globalize()` method makes all the predicate functions available in global scope for convenience. If the name is already taken for a predicate in global scope, it will not be overwritten. 31 | 32 | Predicates can be turned into instances of their error types by using the `new` operator: 33 | 34 | ```js 35 | try { 36 | throw new FileNotFoundError("A file was not found!"); 37 | } 38 | catch (e) { 39 | assert(FileNotFoundError(e) === true); 40 | } 41 | ``` 42 | 43 | ##Error predicates 44 | 45 | - [`FileNotFoundError`](#filenotfounderror) 46 | - [`FileAccessError`](#fileaccesserror) 47 | - [`EOFError`](#eoferror) 48 | - [`UnknownHostError`](#unknownhosterror) 49 | - [`SocketError`](#socketerror) 50 | - [`ProtocolError`](#protocolerror) 51 | - [`FileSystemError`](#filesystemerror) 52 | - [`ConnectError`](#connecterror) 53 | - [`BindError`](#binderror) 54 | - [`AddressNotFoundError`](#addressnotfounderror) 55 | - [`NetworkError`](#networkerror) 56 | - [`SSLError`](#sslerror) 57 | 58 | #####`FileNotFoundError` 59 | 60 | When the error's code matches one of: 61 | 62 | - `ENOENT` 63 | 64 | #####`FileAccessError` 65 | 66 | When the error's code matches one of: 67 | 68 | - `EACCES` 69 | - `EPERM` 70 | 71 | #####`EOFError` 72 | 73 | When the error's code matches one of: 74 | 75 | - `EOF` 76 | 77 | #####`UnknownHostError` 78 | 79 | When the error's code matches one of: 80 | 81 | - `EADDRINFO` 82 | 83 | #####`SocketError` 84 | 85 | When the error's code matches one of: 86 | 87 | - `EISCONN` 88 | - `ENOTCONN` 89 | - `ENOTSOCK` 90 | - `ENOTSUP` 91 | - `EPROTOTYPE` 92 | - `EAIFAMNOSUPPORT` 93 | - `EAISERVICE` 94 | 95 | #####`ProtocolError` 96 | 97 | When the error's code matches one of: 98 | 99 | - `EPROTO` 100 | - `EPROTONOSUPPORT` 101 | - `EPROTOTYPE` 102 | 103 | #####`FileSystemError` 104 | 105 | When the error's code matches one of: 106 | 107 | - `EBUSY` 108 | - `ENOENT` 109 | - `EOF` 110 | - `EACCES` 111 | - `EAGAIN` 112 | - `EBADF` 113 | - `EMFILE` 114 | - `ENOTDIR` 115 | - `EISDIR` 116 | - `EEXIST` 117 | - `ENAMETOOLONG` 118 | - `EPERM` 119 | - `ELOOP` 120 | - `ENOTEMPTY` 121 | - `ENOSPC` 122 | - `EIO` 123 | - `EROFS` 124 | - `ENODEV` 125 | - `ESPIPE` 126 | - `ECANCELED` 127 | - `ENFILE` 128 | - `EXDEV` 129 | 130 | #####`ConnectError` 131 | 132 | When the error's code matches one of: 133 | 134 | - `ECONNABORTED` 135 | - `ECONNREFUSED` 136 | - `ECONNRESET` 137 | - `ETIMEDOUT` 138 | 139 | #####`BindError` 140 | 141 | When the error's code matches one of: 142 | 143 | - `EADDRNOTAVAIL` 144 | 145 | #####`AddressNotFoundError` 146 | 147 | When the error's code matches one of: 148 | 149 | - `ENOTFOUND` 150 | 151 | #####`NetworkError` 152 | 153 | When the error's code matches one of: 154 | 155 | - `EADDRINFO` 156 | - `EADDRNOTAVAIL` 157 | - `EAFNOSUPPORT` 158 | - `EALREADY` 159 | - `ECONNABORTED` 160 | - `ECONNREFUSED` 161 | - `ECONNRESET` 162 | - `EDESTADDRREQ` 163 | - `EHOSTUNREACH` 164 | - `EISCONN` 165 | - `EMSGSIZE` 166 | - `ENETDOWN` 167 | - `ENETUNREACH` 168 | - `ENONET` 169 | - `ENOTCONN` 170 | - `ENOTSOCK` 171 | - `ENOTSUP` 172 | - `EPIPE` 173 | - `EPROTO` 174 | - `EPROTONOSUPPORT` 175 | - `EPROTOTYPE` 176 | - `ETIMEDOUT` 177 | - `EAIFAMNOSUPPORT` 178 | - `EAISERVICE` 179 | - `EAISOCKTYPE` 180 | - `ESHUTDOWN` 181 | - `ENOTFOUND` 182 | 183 | #####`SSLError` 184 | 185 | When the error's message begins with `"SSL Error:"`. 186 | 187 | #License 188 | 189 | The MIT License (MIT) 190 | 191 | Copyright (c) 2015 Petka Antonov 192 | 193 | Permission is hereby granted, free of charge, to any person obtaining a copy 194 | of this software and associated documentation files (the "Software"), to deal 195 | in the Software without restriction, including without limitation the rights 196 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 197 | copies of the Software, and to permit persons to whom the Software is 198 | furnished to do so, subject to the following conditions:

199 | 200 | The above copyright notice and this permission notice shall be included in 201 | all copies or substantial portions of the Software. 202 | 203 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 204 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 205 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 206 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 207 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 208 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 209 | THE SOFTWARE. 210 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var errors = []; 2 | 3 | function addError(name, code) { 4 | var codes = [].slice.call(arguments, 1); 5 | var re = new RegExp("^(" + codes.join("|") + ")$"); 6 | errors.push({ 7 | name: name, 8 | class: createClass(name, code, function(e) { 9 | if (!e) return false; 10 | if ("cause" in e && typeof e.cause.code === "string") { 11 | return re.test(e.cause.code); 12 | } else if (typeof e.code === "string") { 13 | return re.test(e.code); 14 | } else { 15 | return false; 16 | } 17 | }) 18 | }); 19 | } 20 | 21 | function createClass(name, defaultCode, predicate) { 22 | var CustomError = (new Function('name', 'defaultCode', 'predicate', [ 23 | '"use strict";', 24 | 'return function ' + name + '(message, code) {', 25 | ' if (this === undefined) return message instanceof ' + name + ' ? true : predicate(message);', 26 | ' Error.captureStackTrace(this, "' + name + '");', 27 | ' Error.call(this);', 28 | ' this.name = name;', 29 | ' this.message = message;', 30 | ' this.code = code === undefined ? defaultCode : code;', 31 | '}' 32 | ].join('\n')))(name, defaultCode, predicate); 33 | 34 | CustomError.prototype = Object.create(Error.prototype, { 35 | constructor: { 36 | value: CustomError, 37 | enumerable: false, 38 | writable: true, 39 | configurable: true 40 | } 41 | }); 42 | if (typeof Object.setPrototypeOf === 'function') { 43 | Object.setPrototypeOf(CustomError, Error); 44 | } 45 | else { 46 | CustomError.__proto__ = Error; 47 | } 48 | 49 | return CustomError; 50 | } 51 | 52 | addError("FileNotFoundError", "ENOENT"); 53 | addError("FileAccessError", "EACCES", "EPERM"); 54 | addError("EOFError", "EOF"); 55 | addError("UnknownHostError", "EADDRINFO"); 56 | addError("SocketError", "EISCONN", "ENOTCONN", "ENOTSOCK", 57 | "ENOTSUP", "EPROTOTYPE", "EAIFAMNOSUPPORT", 58 | "EAISERVICE"); 59 | addError("ProtocolError", "EPROTO", "EPROTONOSUPPORT", "EPROTOTYPE"); 60 | addError("FileSystemError", "EBUSY", "ENOENT", "EOF", "EACCES", "EAGAIN", 61 | "EBADF", "EMFILE", "ENOTDIR", "EISDIR", "EEXIST", 62 | "ENAMETOOLONG", "EPERM", "ELOOP", "ENOTEMPTY", 63 | "ENOSPC", "EIO", "EROFS", "ENODEV", "ESPIPE", 64 | "ECANCELED", "ENFILE", "EXDEV"); 65 | addError("ConnectError", "ECONNABORTED", "ECONNREFUSED", "ECONNRESET", "ETIMEDOUT"); 66 | addError("BindError", "EADDRNOTAVAIL"); 67 | addError("AddressNotFoundError", "ENOTFOUND"); 68 | addError("NetworkError", "EADDRINFO", "EADDRNOTAVAIL", "EAFNOSUPPORT", 69 | "EALREADY", "ECONNABORTED", "ECONNREFUSED", 70 | "ECONNRESET", "EDESTADDRREQ", "EHOSTUNREACH", 71 | "EISCONN", "EMSGSIZE", "ENETDOWN", "ENETUNREACH", 72 | "ENONET", "ENOTCONN", "ENOTSOCK", "ENOTSUP", "EPIPE", 73 | "EPROTO", "EPROTONOSUPPORT", "EPROTOTYPE", 74 | "ETIMEDOUT", "EAIFAMNOSUPPORT", "EAISERVICE", 75 | "EAISOCKTYPE", "ESHUTDOWN", "ENOTFOUND"); 76 | 77 | errors.push({ 78 | name: "SSLError", 79 | class: createClass("SSLError", ["SSLERROR"], function(e) { 80 | var re = /^SSL Error:/; 81 | if (!e) return false; 82 | if ("cause" in e && typeof e.cause.message === "string") { 83 | return re.test(e.cause.message); 84 | } else if (typeof e.message === "string") { 85 | return re.test(e.message); 86 | } else { 87 | return false; 88 | } 89 | }) 90 | }); 91 | 92 | 93 | errors.forEach(function(error) { 94 | module.exports[error.name] = error.class; 95 | }); 96 | 97 | module.exports.globalize = function() { 98 | errors.forEach(function(error) { 99 | if (global[error.name] === undefined) { 100 | global[error.name] = error.class; 101 | } 102 | }); 103 | return this; 104 | }; 105 | 106 | 107 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "core-error-predicates", 3 | "version": "1.1.0", 4 | "description": "Error predicate functions for operational errors thrown by node core", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git://github.com/petkaantonov/core-error-predicates.git" 12 | }, 13 | "keywords": [ 14 | "error", 15 | "errors", 16 | "patternmatching", 17 | "dsl" 18 | ], 19 | "author": "Petka Antonov (https://github.com/petkaantonov/)", 20 | "license": "MIT", 21 | "devDependencies": { 22 | "mocha": "^2.1.0" 23 | }, 24 | "readmeFilename": "README.md", 25 | "files": [ 26 | "LICENSE", 27 | "index.js" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | require("../index.js").globalize(); 2 | var assert = require("assert"); 3 | 4 | function errorWithCode(code) { 5 | var ret = new Error(); 6 | ret.code = code; 7 | return ret; 8 | } 9 | 10 | function errorWithCause(code) { 11 | var ret = new Error(); 12 | ret.cause = new Error(); 13 | ret.cause.code = code; 14 | return ret; 15 | } 16 | 17 | 18 | function testType(type, codes) { 19 | codes = [].slice.call(arguments, 1); 20 | var predicate = global[type]; 21 | describe(type, function() { 22 | codes.forEach(function(code) { 23 | describe("returns true when the direct error has code", function() { 24 | specify(code, function() { 25 | assert.strictEqual(predicate(errorWithCode(code)), true); 26 | }); 27 | }); 28 | describe("returns true when the error cause has code", function() { 29 | specify(code, function() { 30 | assert.strictEqual(predicate(errorWithCause(code)), true); 31 | }); 32 | }); 33 | 34 | describe("creates new instance, without arguments", function () { 35 | specify(code, function () { 36 | var instance = new predicate(); 37 | assert.strictEqual(instance instanceof Error, true); 38 | assert.strictEqual(instance instanceof predicate, true); 39 | assert.strictEqual(instance.code, codes[0]); 40 | }); 41 | }); 42 | 43 | describe("creates a new instance, with message argument", function () { 44 | specify(code, function () { 45 | var instance = new predicate("Something went wrong"); 46 | assert.strictEqual(instance.code, codes[0]); 47 | assert.strictEqual(instance.message, "Something went wrong"); 48 | }); 49 | }); 50 | 51 | describe("creates a new instance, with message and code arguments", function () { 52 | specify(code, function () { 53 | var instance = new predicate("Something went wrong", code); 54 | assert.strictEqual(instance.code, code); 55 | assert.strictEqual(instance.message, "Something went wrong"); 56 | }); 57 | }); 58 | 59 | describe("predicate matches instance with default code", function () { 60 | specify(code, function () { 61 | var instance = new predicate(); 62 | assert.strictEqual(predicate(instance), true); 63 | }); 64 | }); 65 | 66 | describe("predicate matches instance with specific code", function () { 67 | specify(code, function () { 68 | var instance = new predicate("Error", code); 69 | assert.strictEqual(predicate(instance), true); 70 | }); 71 | }); 72 | 73 | }); 74 | 75 | it("doesn't cause errors with weird objects", function() { 76 | assert.strictEqual(predicate(false), false); 77 | assert.strictEqual(predicate(Object.create(null)), false); 78 | }); 79 | 80 | it("matches instance with specific code, even if the code is not recognized", function () { 81 | var instance = new predicate("Error", "nonsense"); 82 | assert.strictEqual(predicate(instance), true); 83 | }); 84 | 85 | it('is throwable', function () { 86 | try { 87 | throw new predicate("Error"); 88 | } 89 | catch (e) { 90 | assert.strictEqual(predicate(e), true); 91 | } 92 | }); 93 | }); 94 | } 95 | 96 | testType("FileNotFoundError", "ENOENT"); 97 | testType("FileAccessError", "EACCES", "EPERM"); 98 | testType("EOFError", "EOF"); 99 | testType("UnknownHostError", "EADDRINFO"); 100 | testType("SocketError", "EISCONN", "ENOTCONN", "ENOTSOCK", 101 | "ENOTSUP", "EPROTOTYPE", "EAIFAMNOSUPPORT", 102 | "EAISERVICE"); 103 | testType("ProtocolError", "EPROTO", "EPROTONOSUPPORT", "EPROTOTYPE"); 104 | testType("FileSystemError", "EBUSY", "ENOENT", "EOF", "EACCES", "EAGAIN", 105 | "EBADF", "EMFILE", "ENOTDIR", "EISDIR", "EEXIST", 106 | "ENAMETOOLONG", "EPERM", "ELOOP", "ENOTEMPTY", 107 | "ENOSPC", "EIO", "EROFS", "ENODEV", "ESPIPE", 108 | "ECANCELED", "ENFILE", "EXDEV"); 109 | testType("ConnectError", "ECONNABORTED", "ECONNREFUSED", "ECONNRESET", "ETIMEDOUT"); 110 | testType("BindError", "EADDRNOTAVAIL"); 111 | testType("AddressNotFoundError", "ENOTFOUND"); 112 | testType("NetworkError", "EADDRINFO", "EADDRNOTAVAIL", "EAFNOSUPPORT", 113 | "EALREADY", "ECONNABORTED", "ECONNREFUSED", 114 | "ECONNRESET", "EDESTADDRREQ", "EHOSTUNREACH", 115 | "EISCONN", "EMSGSIZE", "ENETDOWN", "ENETUNREACH", 116 | "ENONET", "ENOTCONN", "ENOTSOCK", "ENOTSUP", "EPIPE", 117 | "EPROTO", "EPROTONOSUPPORT", "EPROTOTYPE", 118 | "ETIMEDOUT", "EAIFAMNOSUPPORT", "EAISERVICE", 119 | "EAISOCKTYPE", "ESHUTDOWN", "ENOTFOUND"); 120 | 121 | describe("SSLError", function() { 122 | specify("returns true when the direct error begins with the SSL error message", function() { 123 | var error = new Error("SSL Error:"); 124 | assert.strictEqual(SSLError(error), true); 125 | }); 126 | specify("returns true when the error cause begins with the SSL error message", function() { 127 | var error = new Error(); 128 | error.cause = new Error("SSL Error:"); 129 | assert.strictEqual(SSLError(error), true); 130 | }); 131 | 132 | specify("doesn't cause errors with weird objects", function() { 133 | assert.strictEqual(SSLError(false), false); 134 | assert.strictEqual(SSLError(Object.create(null)), false); 135 | }); 136 | 137 | it("matches instance with specific code, even if the code is not recognized", function () { 138 | var instance = new SSLError("Error", "nonsense"); 139 | assert.strictEqual(SSLError(instance), true); 140 | }); 141 | 142 | it('is throwable', function () { 143 | try { 144 | throw new SSLError("Error"); 145 | } 146 | catch (e) { 147 | assert.strictEqual(SSLError(e), true); 148 | } 149 | }); 150 | }); 151 | --------------------------------------------------------------------------------