objectPath = (obj, selector) ->
@obj = obj
@selector = selector.split "."
@
validator = require "./validator"
type = require "./type"
message = require "./message"
error = require "./error"
class type._object extends type.Base
constructor: (schema) ->
super()
self = @
@original_schema = schema
ar = self.schema = []
push = (path, val) ->
sc = type(val)
if sc
ar.push [ path, sc ]
else if validator.isArray(val) and type.array
ar.push [ path, type.array.apply(null, val) ] if path
else if validator.isObject(val)
for key, v of val
push (if path then (path + "." + key) else key), v
push null, schema
clone: ->
new_schema = {}
for k,v of @original_schema
new_schema[k] = v.clone()
obj = new @constructor new_schema
for key, val of @
if @hasOwnProperty(key) && key != '_value' && key != 'schema'
obj[key] = val
return obj
afterValue: ->
ob = @_value
schema = @schema
len = schema.length
i = 0
while i < len
sc = schema[i]
path = new objectPath(ob, sc[0])
if path.exists()
path.set sc[1].value(path.get()).value()
else
sc[1].value null
i++
@
validate: (callback) ->
self = @
er1 = undefined
er2 = @_validate (err) -> er1 = self.validateChild(err, false, callback)
er1 or er2
validateChild: (err, ignoreUndefined, callback) ->
ob = @_value
completed = 0
schema = @schema
_errors = err or new error()
len = schema.length
iterate = ->
sc = schema[completed]
path = new objectPath(ob, sc[0])
return next() if ob == null
return next() if ignoreUndefined and not path.exists()
sc[1].context(ob).validate ((err) ->
_errors.on sc[0], err if err
next()
), ignoreUndefined
next = ->
completed++
if completed is len
done()
else
iterate()
errors = -> _errors.ok and _errors or null
done = ->
e = errors()
callback and callback(e)
e
iterate()
return errors()
@alias: Object
@check: (obj) -> validator.isObject obj
@from: (obj) -> (if validator.exists(obj) then (if validator.isObject(obj) then obj else obj) else obj)
@path: objectPath
hasOwnProperty = Object::hasOwnProperty
objectPath::exists = ->
val = @obj
selector = @selector
i = 0
len = selector.length
while i < len
key = selector[i]
return false if not val or not hasOwnProperty.call(val, key)
val = val[key]
i++
true
objectPath::get = ->
val = @obj
selector = @selector
i = 0
len = selector.length
while i < len
key = selector[i]
return `undefined` if not val or not hasOwnProperty.call(val, key)
val = val[key]
i++
val
objectPath::set = (value) ->
val = @obj
selector = @selector
return unless val
i = 0
len = selector.length
while i < len
key = selector[i]
if i is (len - 1)
val[key] = value
else
val[key] = {} unless val[key]
val = val[key]
i++
type.register 'object', type._object