json-api-schema
Version:
JSON Api Schema is a JSON dialect that can describe any Web Based API that uses JSON to exchange data.
178 lines (142 loc) • 5 kB
text/coffeescript
EntityIterator = require "./iterators/entity_iterator"
ObjectIterator = require "./iterators/object_iterator"
ArrayIterator = require "./iterators/array_iterator"
NullIterator = require "./iterators/null_iterator"
IteratorsIterator = require "./iterators/iterators_iterator"
null_iterator = new NullIterator()
# The base class of API model.
#
# Provides facilities for traversing, and adding external behaviour
#
class Entity
# Part of mixins implementation taken from http://arcturo.github.io/library/coffeescript/03_classes.html
#
: (obj) ->
for key, value of obj when key not in ['extended', 'included']
@[key] = value
obj.extended?.apply(@)
this
# Part of mixins implementation taken from http://arcturo.github.io/library/coffeescript/03_classes.html
#
: (obj) ->
for key, value of obj when key not in ['extended', 'included']
@::[key] = value
obj.included?.apply(@)
this
: (properties..., templates) ->
camelize = (string) ->
string.replace /(?:^|[-_])(\w)/g, (_, c) ->
(if c then c.toUpperCase() else "")
singularize = (string) ->
string.replace /s$/, ""
propertyToMethod = (prefix, property) ->
prefix + camelize(property.replace(/^_+/, ""))
propertyToSingularizedMethod = (prefix, property) ->
singularize(propertyToMethod(prefix,property))
proto = @::
templates.forEach (template) ->
switch template
when "get"
properties.forEach (prop) ->
methodName = propertyToMethod("get", prop)
proto[methodName] = ->
@[prop]
when "set"
properties.forEach (prop) ->
methodName = propertyToMethod("set", prop)
proto[methodName] = (value) ->
if value instanceof Entity
value.setParent(@)
@[prop] = value
when "get-key"
properties.forEach (prop) ->
methodName = propertyToSingularizedMethod("get", prop)
proto[methodName] = (k) ->
m = @[prop] or {}
m[k]
when "put-key"
properties.forEach (prop) ->
methodName = propertyToSingularizedMethod("put", prop)
proto[methodName] = (k, v) ->
if v instanceof Entity
v.setParent(@)
m = @[prop] ?= {}
m[k] = v
when "delete-key"
properties.forEach (prop) ->
methodName = propertyToSingularizedMethod("delete", prop)
proto[methodName] = (k) ->
m = @[prop]
v = m[k]
if v instanceof Entity
v.setParent(undefined)
delete m[k]
v
when "put-keys"
properties.forEach (prop) ->
methodName = propertyToMethod("put", prop)
proto[methodName] = (obj) ->
for k, v of obj
if v instanceof Entity
v.setParent(@)
m = @[prop]
m[k] = v
prop
: (children...) ->
isArray = (array) ->
not (not array or (not array.length or array.length is 0) or typeof array isnt "object" or not array.constructor or array.nodeType or array.item)
iteratorFor = (object) ->
if object instanceof Entity
new EntityIterator(object)
else if isArray(object)
new ArrayIterator(object)
else if typeof object is "object"
new ObjectIterator(object)
else
null_iterator
@::getChildrenIterator = ->
if children.length == 0
null_iterator
else if children.length == 1
iteratorFor(@[children[0]])
else
subIterators = []
for child in children
if @[child]
subIterators.push(iteratorFor(@[child]))
new IteratorsIterator(subIterators)
"title", "description", [ "get", "set" ]
"annotations", ["get-key", "put-key", "put-keys", "delete-key"]
"locals", ["get-key", "put-key", "put-keys", "delete-key"]
: (name) ->
@::getEntityType = ->
name
@::isInstanceOfEntity = (type) ->
type is name or super(name)
constructor: (options) ->
for k, v of options
@[k] = v
getEntityType: () ->
"Entity"
isInstanceOfEntity: (type) ->
type is "Entity"
# Create a composite traversable structure
#
getParent: ->
setParent: (parent) ->
= parent
isRoot: () ->
!!
getAncestors: ->
ancestors = []
e = @
while parent = e.getParent()
ancestors.unshift(parent)
e = parent
ancestors
getChildrenIterator: ->
null_iterator
isLeaf: () ->
not .hasNext()
module.exports = Entity