node-code-error
Advanced tools
Comparing version 0.1.42 to 1.0.0
50
error.js
'use strict' | ||
var util = require('./util') | ||
var __ = require('./i18n').__ | ||
var hasProp = {}.hasOwnProperty | ||
var statusCodeMap = require('./httpStatusCode.json') | ||
module.exports = CodeError | ||
util.extend(CodeError, Error) | ||
function CodeError (msg, code, originalError) { | ||
CodeError.__super__.constructor.apply(this, arguments) | ||
this._customCode = code | ||
this.message = msg | ||
this.originalError = originalError | ||
extend(CodeError, Error) | ||
function CodeError (opts, msg) { | ||
CodeError.__super__.constructor.call(this) | ||
this.message = statusCodeMap[opts.type] || opts.type + ' error' + (msg ? ': ' + msg : '') | ||
this.status = opts.status || 500 | ||
this.code = buildCode(opts) | ||
this.type = opts.type | ||
return this | ||
} | ||
CodeError.prototype.toString = function () { | ||
return this.name + ': ' + this.message | ||
return this.message | ||
} | ||
@@ -23,6 +26,12 @@ | ||
message: this.message, | ||
type: this.name | ||
type: this.type | ||
} | ||
} | ||
CodeError.prototype.attach = function (err) { | ||
this.originalError = err | ||
this.stack = err.stack | ||
return this | ||
} | ||
CodeError.prototype.toLocaleJSON = function (opts, data) { | ||
@@ -34,3 +43,3 @@ opts = opts || {} | ||
localed.code = this.code | ||
localed.type = this.name | ||
localed.type = this.type | ||
localed.status = this.status | ||
@@ -40,6 +49,19 @@ return localed | ||
Object.defineProperty(CodeError.prototype, 'code', { | ||
get: function () { | ||
return +('' + this._baseCode + this._customCode) | ||
function buildCode (opts) { | ||
opts.actionCode = opts.actionCode || '' | ||
opts.objectCode = opts.objectCode || '' | ||
return +('' + opts.typeCode + opts.objectCode + opts.actionCode) | ||
} | ||
function extend (child, parent) { | ||
for (var key in parent) { | ||
if (hasProp.call(parent, key)) child[key] = parent[key] | ||
} | ||
}) | ||
function Ctor () { | ||
this.constructor = child | ||
} | ||
Ctor.prototype = parent.prototype | ||
child.prototype = new Ctor() | ||
child.__super__ = parent.prototype | ||
return child | ||
} |
135
index.js
'use strict' | ||
var CodeError = require('./error') | ||
var util = require('./util') | ||
var i18n = require('./i18n') | ||
var Errors = { | ||
_eMap: {}, | ||
_name2codeMaps: [], | ||
_split: ' ' | ||
var CONFIG = { | ||
splitLetter: ' ', | ||
get: function (type, key) { | ||
var map = this[type + 'Map'] | ||
return map && map[key] | ||
} | ||
} | ||
Errors.get = function (name) { | ||
if (!name || !util.isString(name) && !util.isNumber(name)) return null | ||
name = ('' + name).toLowerCase() | ||
return this._eMap[name] | ||
} | ||
Errors.extend = function (name, status, baseCode, customCode, message) { | ||
if (!name || !util.isNumberLike(baseCode)) { | ||
return null | ||
} | ||
var existed = this.get(name) | ||
if (existed) return existed | ||
util.extend(Ctor, CodeError) | ||
function Ctor (msg, code, orignalError) { | ||
if (Errors._useMsgCode && !util.isNumberLike(code)) { | ||
orignalError = code | ||
code = Errors.ensureCode(msg) | ||
module.exports = function (type, msg) { | ||
var codeObj | ||
if (isNumber(type)) { | ||
codeObj = { | ||
type: type, | ||
status: type, | ||
typeCode: type | ||
} | ||
Ctor.__super__.constructor(msg, code, orignalError) | ||
this.name = util.toErrorName(name) | ||
this._baseCode = baseCode | ||
this.status = this.statusCode = status || 500 | ||
if (customCode !== undefined) this._customCode = customCode | ||
if (message !== undefined) this.message = message | ||
} else { | ||
codeObj = CONFIG.get('type', type) | ||
if (!codeObj) throw new Error('unrecognized error type: ' + type) | ||
} | ||
this._eMap[name] = Ctor | ||
return Ctor | ||
if (msg) { | ||
var arr = msg.split(CONFIG.splitLetter) | ||
var objCode = CONFIG.get('object', arr[0]) | ||
var actCode = CONFIG.get('action', arr[1]) | ||
if (!isCode(objCode)) throw new Error('unrecognized error object') | ||
if (!isCode(actCode)) throw new Error('unrecognized error action') | ||
codeObj.objectCode = objCode | ||
codeObj.actionCode = actCode | ||
} | ||
codeObj.type = type | ||
return new CodeError(codeObj, msg) | ||
} | ||
Errors.configure = function (opts) { | ||
module.exports.configure = function (opts) { | ||
opts = opts || {} | ||
if (opts.maps) this._name2codeMaps = opts.maps | ||
if (opts.splitLetter) this._split = opts.splitLetter | ||
// 对象映射 | ||
CONFIG.objectMap = opts.objectMap || {} | ||
// 行为映射 | ||
CONFIG.actionMap = opts.actionMap || {} | ||
// 错误类型映射 | ||
CONFIG.typeMap = opts.typeMap || {} | ||
if (opts.splitLetter) CONFIG.splitLetter = opts.splitLetter | ||
if (opts.i18n || opts.additionKeys) { | ||
@@ -51,62 +53,25 @@ i18n.configure({ | ||
} | ||
this._useMsgCode = !!opts.useMsgForCode | ||
} | ||
Errors.str2code = function (str) { | ||
var arr = str.split(this._split) | ||
var maps = this._name2codeMaps | ||
var code = '' | ||
arr.forEach(function (item, ind) { | ||
var codePart = maps[ind] && maps[ind][item] | ||
if (codePart !== undefined) code += codePart | ||
}) | ||
if (!code) return 0 | ||
return +code | ||
module.exports.extend = function (name, status, typeCode, objectCode, actionCode) { | ||
var codeObj = { | ||
type: name, | ||
status: status, | ||
typeCode: typeCode | ||
} | ||
if (objectCode !== undefined) codeObj.objectCode = objectCode | ||
if (objectCode !== undefined) codeObj.actionCode = actionCode | ||
CONFIG.typeMap[name] = codeObj | ||
} | ||
Errors.ensureCode = function (code) { | ||
if (util.isNumberLike(code)) return +code | ||
if (util.isString(code) && ~code.indexOf(this._split)) { | ||
return this.str2code(code) | ||
} | ||
return null | ||
function isNumber (str) { | ||
return typeof str == 'number' | ||
} | ||
Errors.wrap = function (err, type) { | ||
if (!type) { | ||
type = err.status || err.statusCode || 500 | ||
} | ||
var Err = this.get(type) | ||
if (!Err) return null | ||
var msg = err.message || '' + err | ||
var wraped = new Err(msg, err.code, err) | ||
wraped.stack = err.stack | ||
return wraped | ||
function isString (str) { | ||
return typeof str == 'string' | ||
} | ||
module.exports = function (type, msg, code, orignalError) { | ||
var Err = Errors.get(type) | ||
if (!Err) return null | ||
if (arguments.length === 1) { | ||
if (util.isNumberLike(type)) { | ||
return new Err() | ||
} else { | ||
return Err | ||
} | ||
} else { | ||
code = Errors.ensureCode(code) | ||
return new Err(msg, code, orignalError) | ||
} | ||
function isCode (code) { | ||
return isNumber(code) && code >= 0 && code < 10000 || isString(code) && /^\d{1, 3}$/.test(code) | ||
} | ||
var apis = ['extend', 'wrap', 'configure'] | ||
apis.forEach(function (name) { | ||
module.exports[name] = function () { | ||
return Errors[name].apply(Errors, arguments) | ||
} | ||
}) | ||
var statusCodeMap = require('./httpStatusCode.json') | ||
Object.keys(statusCodeMap).sort().forEach(function (key, ind) { | ||
Errors.extend(key, +key, +key, '', statusCodeMap[key]) | ||
}) |
{ | ||
"name": "node-code-error", | ||
"version": "0.1.42", | ||
"version": "1.0.0", | ||
"description": "define node error with code", | ||
@@ -5,0 +5,0 @@ "main": "./index.js", |
322
README.md
@@ -1,12 +0,9 @@ | ||
node-code-error | ||
=== | ||
define errror with code | ||
Introduction | ||
==================== | ||
Validator Framework, write once and use anywhere. | ||
[![NPM version][npm-image]][npm-url] | ||
[![Build Status][travis-image]][travis-url] | ||
## Installation | ||
Install | ||
------------------- | ||
```bash | ||
npm install node-code-error | ||
$ npm install vfw | ||
``` | ||
@@ -16,115 +13,240 @@ | ||
```js | ||
// extend a new type of error | ||
var CodeError = require('node-code-error') | ||
CodeError.extend('api', 400, 100) | ||
var err = CodeError('api', 'db is not defined', 32) | ||
err.status // 400 | ||
err.toString() // 'ApiError: db is not defined' | ||
err.toJSON() | ||
/* | ||
{ | ||
code: 10032, | ||
message: 'ApiError: db is not defined', | ||
type: 'ApiError' | ||
var vfw = require('vfw') | ||
// check object | ||
var ruleSet = vfw.parse({ | ||
a: 'String:required', | ||
b: 'Money' | ||
}) | ||
ruleSet.check({a: 'as', b: 99}) // => true | ||
ruleSet.check({a: 12, b: 'x.x'}) // => false | ||
// check array | ||
ruleSet = vfw.parse(['String', 'Moeny']) | ||
ruleSet.check(['as',99]) // => true | ||
ruleSet.check([123, 'x.x']) // => false | ||
// check multidimensional array | ||
ruleSet = vfw.parse({ | ||
$array: { | ||
$array: 'String' | ||
} | ||
*/ | ||
}) | ||
ruleSet.check([['as'], ['ds']]) // => true | ||
// configure CodeError and describe code by keywords | ||
CodeError.configure({ | ||
maps: [{ | ||
user: 1, | ||
book: 2, | ||
cat: 3 | ||
}, { | ||
missed: 1, | ||
invalid: 2, | ||
unmatched: 3 | ||
}], | ||
splitLetter: ' ' // default is ' ', | ||
useMsgForCode: true // default is false | ||
// your can parse and check any js object | ||
ruleSet = vfw.parse({ | ||
a: { | ||
b: 'String' | ||
c: ['Method', 'Url'] | ||
} | ||
}) | ||
// then you can create err like this | ||
err = CodeError('api', 'user invalid') | ||
err.status // 400 | ||
err.toString() // 'ApiError: user invalid' | ||
err.toJSON() | ||
/* | ||
{ | ||
code: 10012, | ||
message: 'ApiError: user invalid', | ||
type: 'ApiError' | ||
ruleSet.check({a: {b: 'as', c: ['get', 'http://github.com']}}) | ||
// with logic element, $and ,$or and $xor is supported, and your can extend more | ||
ruleSet = vfw.parse({ | ||
$or: { | ||
a: 'String', | ||
b: 'Moeny' | ||
} | ||
*/ | ||
}) | ||
ruleSet.check({a: 'as'}) // => true | ||
ruleSet.check({a: 23, b: 12.2}) // => true | ||
// with expression | ||
ruleSet = vfw.parse({ | ||
a: { | ||
$eq: 1 | ||
} | ||
}) | ||
ruleSet.check({a: 1}) // => 1 | ||
// use without parse api | ||
vfw.type('String', 'as') // => true | ||
var a = 1 | ||
vfw.expression('eq', a, 1) // => true | ||
// $ is short for expression | ||
vfw.$('eq', a, 1) // => true | ||
// everything in vfw is extendable | ||
// extend your own type | ||
vfw.extend('type', { | ||
Word: function (str) { | ||
return /^\w+$/.test(str) | ||
} | ||
}) | ||
vfw.type('Word', 'azAZ_09') // => true | ||
ruleSet = vfw.parse({a: 'Word'}) | ||
ruleSet.check({a: 'azAZ_09'}) // => true | ||
// extend your own expression | ||
vfw.extend('expression', { | ||
$gt: function (str, len) { | ||
return str && str.length > len | ||
} | ||
}) | ||
var b = [1, 2] | ||
vfw.$('gt', b, 1) // => true | ||
ruleSet = vfw.parse({a: {$gt: 2}}) | ||
ruleSet.check({a: 'aas'}) // => true | ||
// extend your own struct | ||
vfw.extend('struct', 'User', { | ||
name: 'Word:required', | ||
// 类型 Word 长度 小于等于6 | ||
password: { | ||
$type: 'Word', | ||
$lte: 6 | ||
} | ||
}) | ||
vfw.struct('User', {name: 'asd_123', password: 'asd_as'}) // => true | ||
vfw.struct('User', {name: 'asd_123', password: 'asd_as123'}) // => false | ||
vfw.struct('User', {password: 'ass123'}) // => false | ||
``` | ||
## CLASS | ||
### RuleType | ||
- type, expression, struct are all intanceof RuleType, and you can extend your own RuleType by extendRule api. | ||
* #### attributes | ||
* _extended: `Object` store extended functions | ||
* _includes: `Array` store included libs | ||
* #### methods | ||
* canHandle(rule) | ||
* `required` check if the rule can be handled by this ruleType | ||
* check(arr, rule) | ||
* you can rewrite this function and check in aother way | ||
* the first arguments is Array | ||
* extend(obj) | ||
* define how to extend | ||
* include(lib) | ||
* define how to include a lib | ||
* get(key) | ||
* get handler by key | ||
* has(key) | ||
### Rule | ||
* #### attributes | ||
* _name: `String` name of rule type | ||
* _rule: rule object. for {a: 'String'}, _rule is 'String' | ||
* _path: the path of the object. for {a: 'String'}, _path is 'a' | ||
* _hdl: handler of this rule | ||
* #### methods | ||
* check(target) | ||
* check the target | ||
* clone() | ||
* clone this rule | ||
* addPath(path, depth) | ||
* add a path to this rule.depth is default 0. | ||
* setHandler(handler, rule) | ||
* set _hdl and _rule | ||
* finish() | ||
* before add to struct, you should finish this rule first | ||
### Struct | ||
- collection of rules | ||
* #### attributes | ||
* uid `String` uniq id of this struct | ||
* _rules `Array` array of rules | ||
* _ruleMap `Object` map of rules | ||
* #### methods | ||
* add(rule) add a rule to this struct | ||
* check(obj, opts) if opts.withErrors is true, check function will return [res, errs] | ||
## API | ||
### CodeError(name, msg, code, originalError) | ||
- factory function for getting an error constructor or creating an instance | ||
### vfw.type(Type, target) | ||
```js | ||
vfw.type('String', 'asd') // => true | ||
vfw.type('Number', 'asd') // => false | ||
``` | ||
### vfw.expression or vfw.$ | ||
```js | ||
var CodeError = require('node-code-error') | ||
CodeError.extend('api', 400, 100) | ||
CodeError('api') // => function ApiError | ||
CodeError('api', 'api error', 32, new Error('xxx')) // => instance of ApiError | ||
vfw.$('in', [1, 2], 1) // => true | ||
``` | ||
### CodeError.extend(name, status, baseCode, customCode) | ||
### vfw.struct(StructName, target) | ||
```js | ||
vfw.struct('User', {user: 'lee', password: '123456'}) | ||
``` | ||
- `name` *Required*, `String`, define the type of the error | ||
- `status` `Number`, define the status of the error, default is 500 | ||
- `baseCode` *Required*, `Number`, the first part of the code | ||
- `customCode` *Option*, `Number`, if passed, the last part of code will be always the customCode, this is used for errors with stationary code, like SystemError | ||
### vfw.extendRule(opts) | ||
- extend your own RuleType. type, expression, struct are all instanceof RuleType. | ||
```js | ||
vfw.extendRule({ | ||
// canHandle function must be rewrited to tell vfw what it can handle | ||
canHandle: function (obj) { | ||
return /^@/.test(obj) | ||
}, | ||
name: 'custom' | ||
}) | ||
// if name supported | ||
vfw.custom('@as', 12) | ||
// and you can write rule like this | ||
vfw.parse({ | ||
a: '@string' | ||
}) | ||
``` | ||
### vfw.extendParser(Function) | ||
```js | ||
var CodeError = require('node-code-error') | ||
CodeError.extend('api', 400, 100) | ||
CodeError('api', 'api error', 43) // code == 10043 | ||
CodeError.extend('system', 500, 101, 10) | ||
CodeError('system', 'system error', 43) // code == 10110 | ||
// extend a new RuleType, the rule '#xxx' will be handled by isXxx | ||
// for example, #string will be handled by isString | ||
vfw.extendParser(function (rule, struct, ruleIns) { | ||
// if this function cant handle the rule, return false, and this rule will handled by others | ||
if (!(typeof rule === 'string' && rule.charAt(0) === '#')) return false | ||
rule = rule.slice(1) | ||
rule = 'is' + rule.charAt(0).toUpperCase() + rule.slice(1) | ||
var handler = vfw.get(rule) | ||
if (!handler) return false | ||
ruleIns.setHandler(handler, rule) | ||
struct.add(ruleIns) | ||
return true | ||
}) | ||
var _ = require('lodash') | ||
vfw.include('type', _) | ||
// use _.isPlainObject | ||
var struct = vfw.parse({a: '#PlainObject'}) | ||
struct.check({a: {a: 1}}) // => true | ||
``` | ||
### CodeError.configure(opts) | ||
- global config.only used for transfering message to code right now. | ||
- maps `Array` map of values for keywords.for common use, you can use maps[0] as map of model, use maps[1] as map of action.then, your error message will like 'user invalid', 'password unmatch', etc. | ||
### vfw.extend(type, extends) | ||
- type `String` name of RuleType, like 'type', 'expression' | ||
- extends `Object` the functions you want to extend | ||
```js | ||
var CodeError = require('node-code-error') | ||
CodeError.configure({ | ||
maps: [{ | ||
user: 1, | ||
book: 2, | ||
cat: 3 | ||
}, { | ||
missed: 1, | ||
invalid: 2, | ||
unmatch: 3 | ||
}], | ||
splitLetter: ' ' // default is ' ', | ||
useMsgForCode: true // default is false | ||
vfw.extend('type', { | ||
Money: function(){}, | ||
Url: function(){} | ||
}) | ||
CodeError.extend('api', 400, 100) | ||
var err = CodeError('api', 'use missed') | ||
err.code // => 10011 | ||
var err = CodeError('api', 'book unmatch') | ||
err.code // => 10023 | ||
vfw.extend('expression', { | ||
$lt: function(target, len){}, | ||
$startWith: function(target, char){} | ||
}) | ||
// once extended, those rules can be used anywhere | ||
``` | ||
### CodeError.wrap(err, name) | ||
- err *Required* `Error` the error to be wrapped | ||
- name *Option* `String` which type of error to wrap, default is 'system' | ||
### vfw.include(type, obj) | ||
- type `String` name of RuleType, like 'type', 'expression' | ||
- obj `Object` | ||
- you can include a lib like lodash, validator or others and use the functions they supported | ||
```js | ||
var _ = require('lodash') | ||
vfw.include('type', _) | ||
// use _.isPlainObject | ||
var struct = vfw.parse({a: '#PlainObject'}) | ||
struct.check({a: {a: 1}}) // => true | ||
``` | ||
### vfw.parse(obj) | ||
- parse a rule object and return an instance of Struct | ||
```js | ||
CodeError.extend('system', 500, 100, 10) | ||
var err = new Error("I'm a nodejs Error") | ||
var wrapped = CodeError.wrap(err, 'system') | ||
wrapped.toString() // => "SystemError: I'm a nodejs Error" | ||
wrapped.toJSON() | ||
/* | ||
=> { | ||
code: 10010, | ||
message: "SystemError: I'm a nodejs Error", | ||
type: "SystemError" | ||
} | ||
*/ | ||
``` | ||
var rule = { | ||
a: 'String:required', | ||
b: 'Money' | ||
} | ||
var struct = vfw.parse(rule) | ||
struct.check({a: 'as', b: 1.2}) // => true | ||
``` |
@@ -9,3 +9,3 @@ 'use strict' | ||
Object.keys(webHttpStatus).forEach(function (key) { | ||
var err = CodeError(key) | ||
var err = CodeError(+key) | ||
assert(err.toJSON().code) | ||
@@ -17,51 +17,21 @@ assert(err.toString()) | ||
it('extend', function () { | ||
CodeError.extend('internal', 500, 101, 0) | ||
var err = CodeError('internal', 'this is a internal error with default code') | ||
assert(err.code === 1010) | ||
assert(err.toString() === 'InternalError: this is a internal error with default code') | ||
assert(err.toJSON().type === 'InternalError') | ||
CodeError.extend('api', 400, 104) | ||
err = CodeError('api', 'this is a internal error without default code', 62) | ||
assert(err.code === 10462) | ||
assert(err.toString() === 'ApiError: this is a internal error without default code') | ||
assert(err.toJSON().type === 'ApiError') | ||
}) | ||
it('configure', function () { | ||
// use keywords to define code | ||
CodeError.configure({ | ||
maps: [{ | ||
objectMap: { | ||
user: 1, | ||
alien: 2, | ||
token: 3 | ||
}, { | ||
}, | ||
actionMap: { | ||
invalid: 1, | ||
unmatch: 2, | ||
missed: 3 | ||
}] | ||
}) | ||
var err = CodeError('api', 'invalid user in xx api', 'user invalid') | ||
assert(err.code === 10411) | ||
assert(err.toString() === 'ApiError: invalid user in xx api') | ||
assert(err.toJSON().type === 'ApiError') | ||
// use msg for code | ||
CodeError.configure({ | ||
useMsgForCode: true | ||
}) | ||
err = CodeError('api', 'user invalid') | ||
assert(err.code === 10411) | ||
assert(err.toString() === 'ApiError: user invalid') | ||
assert(err.toJSON().type === 'ApiError') | ||
// config split letter | ||
CodeError.configure({ | ||
splitLetter: ',', | ||
useMsgForCode: false | ||
}) | ||
err = CodeError('api', 'invalid user in xx api', 'user,invalid') | ||
assert(err.code === 10411) | ||
assert(err.toString() === 'ApiError: invalid user in xx api') | ||
assert(err.toJSON().type === 'ApiError') | ||
// config additionKeys | ||
CodeError.configure({ | ||
}, | ||
typeMap: { | ||
api: { | ||
typeCode: 104, | ||
status: 400 | ||
} | ||
}, | ||
additionKeys: ['action', 'refer'], | ||
@@ -74,3 +44,8 @@ i18n: { | ||
}) | ||
err = CodeError('api', 'invalid user in xx api', 11) | ||
var err = CodeError('api', 'user invalid') | ||
assert(err.code === 10411) | ||
console.log(err.toString()) | ||
assert(err.toString() === 'api error: user invalid') | ||
assert(err.toJSON().type === 'api') | ||
err = CodeError('api', 'user invalid') | ||
var localeJson = err.toLocaleJSON({action: 'create', refer: 'github'}) | ||
@@ -82,1 +57,8 @@ assert(localeJson.message === '创建Github账户失败') | ||
}) | ||
it('extend', function () { | ||
CodeError.extend('internal', 500, 101, 10, 10) | ||
var err = CodeError('internal') | ||
assert(err.code === 1011010) | ||
assert(err.toJSON().type === 'internal') | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
18305
0
252
13
340