json-strict
Version:
Json Specification & Validation & Document Generation
109 lines (98 loc) • 3.33 kB
text/coffeescript
require 'coffee-mate/global'
{typeclass, instance} = require '../typeclass'
{shape, match, constraints, show, samples, sample, htmlInline, htmlBlock} = require '../typespec'
{expandBlockHead} = require '../helpers'
class NamedType
constructor: ({name, spec, desc, check, samples}) ->
unless name? and spec?
throw Error "Bad NamedType Definition: name & spec Must Be Specified"
unless spec? and typeclass('TypeSpec').hasInstance(spec.constructor)
throw Error "Bad NamedType Definition: TypeSpec as spec Expected, But Got #{spec}\n\tname: #{name}"
unless not samples? or all(match(spec))(take(100) samples)
throw Error "Bad NamedType Definition: samples Should Match spec\n\tname: #{name}\n\tspec: #{spec}"
return {
constructor: NamedType
name
spec
desc
check
samples
}
instance('TypeSpec')(NamedType).where
shape: ({spec}) -> shape(spec)
match: ({spec, check}) -> (v) ->
match(spec)(v) and (if check? then check(v) else true)
constraints: ({spec, check, name}) -> (v) -> [
{
label: -> "#{name} Expected" #, But Got #{v}"
sub: -> constraints(spec)(v)
}
{
label: -> "#{name} Expected to Satisfy #{check}, But Got #{json v}"
flag: -> if check? then check(v) else true
}
]
show: ({name, spec}) ->
name or (show spec)
samples: ({spec, samples: ls}) ->
if ls? then concat repeat ls else samples spec
htmlInline: ({name, spec}) ->
if name? then "<span class='type-name'>#{name}</span>" else htmlInline spec
htmlBlock: ({name, spec}) ->
expandBlockHead((head) ->
"<span><span class='type-name'>#{name}</span><span class='spliter'>spec:</span>#{head}</span>"
)(spec) ? {
head: "<span><span class='type-name'>#{name}</span><span class='spliter'>spec:</span>#{htmlInline spec}</span>"
}
showHtml: (t) ->
{name, desc, spec, check} = t
namePart = if not name? then '' else """
<div class='name'>
<span class='meta-field'>name</span>: <span class='type-name'>#{name}</span>
</div>
"""
descriptionPart = if not desc? then '' else do ->
s = desc
return """
<div class='desc'>
<span class='meta-field'>desc</span>: #{
if /\n/.test s then "<pre class='text'>#{s}</pre>" else "<span class='text'>#{s}</span>"
}
</div>
"""
specPart = do ->
block = htmlBlock spec
return """
<div class='spec'>
<div class='#{if block? then 'fold' else 'inline'}'><span class='meta-field'>spec</span>: #{htmlInline spec}</div>
#{if block? then (
"""
<div class='unfold'>
<span class='meta-field'>spec</span>: #{block.head}
#{block.body ? ''}
#{block.tail ? ''}
</div>
"""
) else ''}
</div>
""".replace(/(\t|\n)/g, '')
samplePart = do ->
s = prettyJson(sample(t))
return """
<div class='sample'>
<span class='meta-field'>sample</span>: #{
if /\n/.test s then "<pre class='code'>#{s}</pre>" else "<span class='code'>#{s}</span>"
}
</div>
"""
checkPart = if not check? then '' else do ->
s = check.toString()
return """
<div class='check'>
<span class='meta-field'>constraint</span>: #{
if /\n/.test s then "<pre class='code'>#{s}</pre>" else "<span class='code'>#{s}</span>"
}
</div>
"""
return "<div class='typespec'>#{ namePart + descriptionPart + specPart + samplePart + checkPart }</div>"
module.exports = {NamedType}