Skip to content

Commit

Permalink
feat: custom message as function support
Browse files Browse the repository at this point in the history
  • Loading branch information
Kikobeats committed May 20, 2019
1 parent 6a55327 commit 9dc5480
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 63 deletions.
99 changes: 59 additions & 40 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,19 @@ function createTypeError (message, key, value) {
}

function throwTypeError (key, value, type, message) {
if (!message || isBoolean(message)) message = `Expected \`${type}\` for \`${key}\`, got \`${value}\``
if (!message || isBoolean(message)) {
message = `Expected \`${type}\` for \`${key}\`, got \`${value}\``
}
throw createTypeError(message, key, value)
}

function throwValidationError (key, value, description) {
let message
if (description) message = format(description, value)
else message = `Fail '${value}' validation for '${key}'.`
if (description) {
message = isFunction(description)
? description(value)
: format(description, value)
} else message = `Fail '${value}' validation for '${key}'.`
throw createTypeError(message, key, value)
}

Expand All @@ -52,47 +57,61 @@ function Osom (schemaBlueprint, globalRules) {
globalRules = globalRules || {}
const schemaTypes = {}

const schema = reduce(schemaBlueprint, function (schema, blueprint, name) {
schema = addRule(globalRules, schema, blueprint, name)
const type = schema[name].type
schemaTypes[name] = type.name.toLowerCase()
schema[name].type = chaste(type)
return schema
}, {})
const schema = reduce(
schemaBlueprint,
function (schema, blueprint, name) {
schema = addRule(globalRules, schema, blueprint, name)
const type = schema[name].type
schemaTypes[name] = type.name.toLowerCase()
schema[name].type = chaste(type)
return schema
},
{}
)

function osom (obj) {
obj = obj || {}

return reduce(schema, function applyRule (objSchema, rule, name) {
const value = obj[name]
const hasValue = !isNil(value)
const validate = rule.validate
const isRequired = rule.required || !isNil(validate)
const expectedValue = schemaTypes[name]

const isMissing = !hasValue && !validate && isRequired
if (isMissing) throwTypeError(name, value, expectedValue, isRequired)

const isCasting = rule.casting
const isCastingDisabled = hasValue && !isCasting
const isInvalidType = isCastingDisabled && is(value) !== expectedValue
if (isInvalidType) throwTypeError(name, value, expectedValue, isRequired)

let TypedValue
const defaultValue = isFunction(rule.default) ? rule.default : () => rule.default
if (hasValue) TypedValue = isCasting ? rule.type(value) : value
else if (defaultValue) TypedValue = defaultValue()

TypedValue = reduce(rule.transform, (acc, fn) => fn(acc), TypedValue)

if (isRequired && validate) {
const validator = getValidator(rule)
if (!validator(TypedValue)) throwValidationError(name, value, validate.message)
}

if (!isNil((TypedValue))) objSchema[name] = TypedValue
return objSchema
}, {})
return reduce(
schema,
function applyRule (objSchema, rule, name) {
const value = obj[name]
const hasValue = !isNil(value)
const validate = rule.validate
const isRequired = rule.required || !isNil(validate)
const expectedValue = schemaTypes[name]

const isMissing = !hasValue && !validate && isRequired
if (isMissing) throwTypeError(name, value, expectedValue, isRequired)

const isCasting = rule.casting
const isCastingDisabled = hasValue && !isCasting
const isInvalidType = isCastingDisabled && is(value) !== expectedValue
if (isInvalidType) {
throwTypeError(name, value, expectedValue, isRequired)
}

let TypedValue
const defaultValue = isFunction(rule.default)
? rule.default
: () => rule.default
if (hasValue) TypedValue = isCasting ? rule.type(value) : value
else if (defaultValue) TypedValue = defaultValue()

TypedValue = reduce(rule.transform, (acc, fn) => fn(acc), TypedValue)

if (isRequired && validate) {
const validator = getValidator(rule)
if (!validator(TypedValue)) {
throwValidationError(name, value, validate.message)
}
}

if (!isNil(TypedValue)) objSchema[name] = TypedValue
return objSchema
},
{}
)
}

return osom
Expand Down
84 changes: 61 additions & 23 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,28 @@ const osom = require('..')
describe('schema defintion', function () {
describe('simple rule', function () {
it('empty value', function () {
[{ age: Number }, { age: { type: Number } }].forEach(function (rule) {
;[{ age: Number }, { age: { type: Number } }].forEach(function (rule) {
osom(rule)().should.be.eql({})
})
})

describe('providing value', function () {
it('Number', function () {
[
{ age: Number },
{ age: { type: Number } }
].forEach(function (rule) {
;[{ age: Number }, { age: { type: Number } }].forEach(function (rule) {
osom(rule)({ age: '23' }).should.be.eql({ age: 23 })
})
})

it('Array', function () {
[
{ age: Array },
{ age: { type: Array } }
].forEach(function (rule) {
;[{ age: Array }, { age: { type: Array } }].forEach(function (rule) {
osom(rule)({ age: ['23'] }).should.be.eql({ age: ['23'] })
})
})
})
})

it('empty values', function () {
[Number, String, Function, Boolean].forEach(function (type) {
;[Number, String, Function, Boolean].forEach(function (type) {
var schema = {
age: {
type: type
Expand All @@ -53,7 +47,8 @@ describe('schema defintion', function () {
it('based in a value', function () {
var schema = {
age: {
type: Number, default: 23
type: Number,
default: 23
}
}

Expand All @@ -64,7 +59,10 @@ describe('schema defintion', function () {
it('based in a fn', function () {
var schema = {
age: {
type: Number, default: function () { return 23 }
type: Number,
default: function () {
return 23
}
}
}

Expand Down Expand Up @@ -99,7 +97,9 @@ describe('schema defintion', function () {
}

var validator = osom(schema)
;(function () { validator() }).should.throw('Expected `string` for `age`, got `undefined`')
;(function () {
validator()
}.should.throw('Expected `string` for `age`, got `undefined`'))
})

it('custom error message', function () {
Expand All @@ -112,7 +112,9 @@ describe('schema defintion', function () {

var validator = osom(schema)
var errMessage = 'your message here'
;(function () { validator() }).should.throw(errMessage)
;(function () {
validator()
}.should.throw(errMessage))
})
})

Expand All @@ -134,12 +136,14 @@ describe('schema defintion', function () {

var validator = osom(schema, { casting: false })
;[{ age: 23 }].forEach(function (obj) {
;(function () { validator(obj) }).should.throw('Expected `string` for `age`, got `23`')
;(function () {
validator(obj)
}.should.throw('Expected `string` for `age`, got `23`'))
})
})

it('works with nill values of the same type', function () {
[Number, String, Function, Boolean].forEach(function (type) {
;[Number, String, Function, Boolean].forEach(function (type) {
var schema = {
age: {
type: type
Expand Down Expand Up @@ -190,9 +194,15 @@ describe('schema defintion', function () {
}

var validator = osom(schema)
;(function () { validator() }).should.throw("Fail 'undefined' validation for 'age'.")
;(function () { validator({}) }).should.throw("Fail 'undefined' validation for 'age'.")
;(function () { validator({ age: 25 }) }).should.throw("Fail '25' validation for 'age'.")
;(function () {
validator()
}.should.throw("Fail 'undefined' validation for 'age'."))
;(function () {
validator({})
}.should.throw("Fail 'undefined' validation for 'age'."))
;(function () {
validator({ age: 25 })
}.should.throw("Fail '25' validation for 'age'."))
})

it('based in a object key', function () {
Expand All @@ -208,9 +218,15 @@ describe('schema defintion', function () {
}

var validator = osom(schema)
;(function () { validator() }).should.throw("Fail 'undefined' validation for 'age'.")
;(function () { validator({}) }).should.throw("Fail 'undefined' validation for 'age'.")
;(function () { validator({ age: 25 }) }).should.throw("Fail '25' validation for 'age'.")
;(function () {
validator()
}.should.throw("Fail 'undefined' validation for 'age'."))
;(function () {
validator({})
}.should.throw("Fail 'undefined' validation for 'age'."))
;(function () {
validator({ age: 25 })
}.should.throw("Fail '25' validation for 'age'."))
})

it('custom error message', function () {
Expand All @@ -228,7 +244,29 @@ describe('schema defintion', function () {

var validator = osom(schema)
var errMessage = 'expected a millenial value instead of 25!'
;(function () { validator({ age: 25 }) }).should.throw(errMessage)
;(function () {
validator({ age: 25 })
}.should.throw(errMessage))
})

it('custom error message as function', function () {
var schema = {
age: {
type: String,
validate: {
validator: function (v) {
return v === '23'
},
message: v => `expected a millenial value instead of ${v}!`
}
}
}

var validator = osom(schema)
var errMessage = 'expected a millenial value instead of 25!'
;(function () {
validator({ age: 25 })
}.should.throw(errMessage))
})
})
})
Expand Down

0 comments on commit 9dc5480

Please sign in to comment.