guards
Version:
Data type & structure checking, runtime analog of types
736 lines (630 loc) • 37.3 kB
HTML
<html>
<head>
<title>Dont forget to use --title to specify me!</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<style>body {
margin: 0;
padding: 0;
font: 14px/1.5 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
color: #252519;
}
a {
color: #252519;
}
a:hover {
text-decoration: underline;
color: #19469D;
}
p {
margin: 12px 0;
}
h1, h2, h3 {
margin: 0;
padding: 0;
}
table#source {
width: 100%;
border-collapse: collapse;
}
table#source td:first-child {
padding: 30px 40px 30px 40px;
vertical-align: top;
}
table#source td:first-child,
table#source td:first-child pre {
width: 450px;
}
table#source td:last-child {
padding: 30px 0 30px 40px;
border-left: 1px solid #E5E5EE;
background: #F5F5FF;
}
table#source tr {
border-bottom: 1px solid #E5E5EE;
}
table#source tr.filename {
padding-top: 40px;
border-top: 1px solid #E5E5EE;
}
table#source tr.filename td:first-child {
text-transform: capitalize;
}
table#source tr.filename td:last-child {
font-size: 12px;
}
table#source tr.filename h2 {
margin: 0;
padding: 0;
cursor: pointer;
}
table#source tr.code h1,
table#source tr.code h2,
table#source tr.code h3 {
margin-top: 30px;
font-family: "Lucida Grande", "Helvetica Nueue", Arial, sans-serif;
font-size: 18px;
}
table#source tr.code h2 {
font-size: 16px;
}
table#source tr.code h3 {
font-size: 14px;
}
table#source tr.code ul {
margin: 15px 0 15px 35px;
padding: 0;
}
table#source tr.code ul li {
margin: 0;
padding: 1px 0;
}
table#source tr.code ul li p {
margin: 0;
padding: 0;
}
table#source tr.code td:first-child pre {
padding: 20px;
}
#ribbon {
position: fixed;
top: 0;
right: 0;
}
code .string { color: #219161; }
code .regexp { color: #219161; }
code .keyword { color: #954121; }
code .number { color: #19469D; }
code .comment { color: #bbb; }
code .this { color: #19469D; }</style>
<script>
$(function(){
$('tr.code').hide();
$('tr.filename').toggle(function(){
$(this).nextUntil('.filename').fadeIn();
}, function(){
$(this).nextUntil('.filename').fadeOut();
});
});
</script>
</head>
<body>
<table id="source"><tbody><tr><td><h1>Dont forget to use --title to specify me!</h1></td><td></td></tr><tr class="filename"><td><h2 id="lib/guards.js"><a href="#">guards</a></h2></td><td>lib/guards.js</td></tr><tr class="code">
<td class="docs">
<p> vim:set ts=2 sw=2 sts=2 expandtab </p>
</td>
<td class="code">
</td>
</tr>
<tr class="code">
<td class="docs">
<p>jshint newcap: true undef: true es5: true node: true devel: true
forin: true </p>
</td>
<td class="code">
</td>
</tr>
<tr class="code">
<td class="docs">
<p>global define: true </p>
</td>
<td class="code">
<pre><code>(<span class="keyword">typeof</span> <span class="variable">define</span> !== <span class="string">"function"</span> ? <span class="keyword">function</span>($){ $(<span class="variable">require</span>, <span class="variable">exports</span>, <span class="variable">module</span>); } : <span class="variable">define</span>)(<span class="keyword">function</span>(<span class="variable">require</span>, <span class="variable">exports</span>, <span class="variable">module</span>, <span class="variable">undefined</span>) {
<span class="keyword">var</span> <span class="variable">utils</span> = <span class="variable">require</span>(<span class="string">"./type"</span>);
<span class="keyword">var</span> <span class="class">Extendable</span> = <span class="variable">require</span>(<span class="string">"./extendables"</span>).<span class="class">Extendable</span>;
<span class="keyword">var</span> <span class="variable">isArray</span> = <span class="variable">utils</span>.<span class="variable">isArray</span>;
<span class="keyword">var</span> <span class="variable">isFunction</span> = <span class="variable">utils</span>.<span class="variable">isFunction</span>;
<span class="keyword">var</span> <span class="variable">isUndefined</span> = <span class="variable">utils</span>.<span class="variable">isUndefined</span>;
<span class="keyword">var</span> <span class="variable">isNull</span> = <span class="variable">utils</span>.<span class="variable">isNull</span>;
<span class="keyword">var</span> <span class="variable">isNumber</span> = <span class="variable">utils</span>.<span class="variable">isNumber</span>;
<span class="keyword">var</span> <span class="variable">isString</span> = <span class="variable">utils</span>.<span class="variable">isString</span>;
<span class="keyword">var</span> <span class="variable">isObject</span> = <span class="variable">utils</span>.<span class="variable">isObject</span>;
<span class="keyword">var</span> <span class="variable">isBoolean</span> = <span class="variable">utils</span>.<span class="variable">isBoolean</span>;
<span class="keyword">var</span> <span class="variable">owns</span> = <span class="class">Function</span>.<span class="variable">prototype</span>.<span class="variable">call</span>.<span class="variable">bind</span>(<span class="class">Object</span>.<span class="variable">prototype</span>.<span class="variable">hasOwnProperty</span>);
<span class="keyword">function</span> <span class="variable">getOwnPropertyDescriptors</span>(<span class="variable">object</span>) {
<span class="keyword">var</span> <span class="variable">descriptors</span> = {};
<span class="class">Object</span>.<span class="variable">getOwnPropertyNames</span>(<span class="variable">object</span>).<span class="variable">forEach</span>(<span class="keyword">function</span>(<span class="variable">name</span>) {
<span class="variable">descriptors</span>[<span class="variable">name</span>] = <span class="class">Object</span>.<span class="variable">getOwnPropertyDescriptor</span>(<span class="variable">object</span>, <span class="variable">name</span>);
});
<span class="keyword">return</span> <span class="variable">descriptors</span>;
}
<span class="keyword">var</span> <span class="class">NO_DEFAULT</span> = { <span class="variable">valueOf</span>: <span class="keyword">function</span>() { <span class="keyword">return</span> <span class="string">"Guard without default"</span>; } };
<span class="variable">exports</span>.<span class="variable">version</span> = <span class="string">"0.2.0"</span>;</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<h1>Guard</h1>
<p>Function takes <code>isValid</code> function and <code>message</code> as an argument and returns
guard generator function. Returned function may be used to generate value
guards that are validated with given <code>isValid</code> function. Please see
<code>exports.Number</code> or <code>exports.String</code> for more details.
## </p>
<ul><li><p><strong>param</strong>: <em>Function</em> isValid</p><p>Function that will be used by guard to validate values. It will be called
with <code>value</code> argument that needs to be validated. If function returns
<code>true</code> value is valid if <code>false</code> it's not.</p></li><li><p><strong>param</strong>: <em>String</em> [message="Unexpected value: `{{value}}`"]</p><p>Optional <code>message</code> argument may be passed that will be used as a template
for a <code>TypeError</code> message that is thrown by generated guards when called
with invalid values.</p></li></ul>
</td>
<td class="code">
</td>
</tr>
<tr class="code">
<td class="docs">
<h1>Guard</h1>
<p>Guard function that may be called with a <code>value</code> to be set to a guarded
variable. If <code>value</code> is invalid <code>TypeError</code> is thrown. Optionally second
<code>name</code> argument may be passed, which is useful when guards are used for
object properties. In such case <code>name</code> argument just name of object
property and will be used to give a better error messages.
## </p>
<ul><li><p><strong>param</strong>: <em>Object | String | Number | function</em> value</p><p>Value to be validated.</p></li><li><p><strong>param</strong>: <em>String</em> name</p><p>Name of the property that is being guarded.</p></li></ul>
</td>
<td class="code">
<pre><code><span class="keyword">var</span> <span class="class">Guard</span> = <span class="class">Extendable</span>.<span class="variable">extend</span>({
<span class="variable">constructor</span>: <span class="keyword">function</span> <span class="class">Guard</span>(<span class="variable">value</span>, <span class="variable">name</span>) {
<span class="comment">// If guard has a default value and guard is called with `undefined`</span>
<span class="comment">// `value` just falling back to the `defaultValue`.</span>
<span class="keyword">if</span> (<span class="this">this</span>.<span class="variable">defaults</span> !== <span class="class">NO_DEFAULT</span> && <span class="variable">isUndefined</span>(<span class="variable">value</span>))
<span class="variable">value</span> = <span class="this">this</span>.<span class="variable">defaults</span>;
<span class="keyword">if</span> (!<span class="this">this</span>.<span class="variable">isValid</span>(<span class="variable">value</span>))
<span class="keyword">throw</span> <span class="keyword">new</span> <span class="class">TypeError</span>(<span class="this">this</span>.<span class="variable">message</span>.<span class="variable">replace</span>(<span class="string">"{{name}}"</span>, <span class="variable">name</span>).
<span class="variable">replace</span>(<span class="string">"{{value}}"</span>, <span class="variable">value</span>).
<span class="variable">replace</span>(<span class="string">"{{type}}"</span>, <span class="keyword">typeof</span> <span class="variable">value</span>));
<span class="keyword">return</span> <span class="this">this</span>.<span class="variable">validate</span>(<span class="variable">value</span>, <span class="variable">name</span>);
},
<span class="variable">defaults</span>: <span class="class">NO_DEFAULT</span>,</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<p>Default error <code>message</code> used to by <code>TypeError</code> thrown when invalid value
is used.
</p>
</td>
<td class="code">
<pre><code><span class="variable">message</span>: <span class="string">"Unexpected value: `{{value}}`"</span>,
<span class="variable">isValid</span>: <span class="keyword">function</span> <span class="variable">isValid</span>(<span class="variable">value</span>) {
<span class="keyword">return</span> <span class="variable">true</span>;
},</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<p> </p>
</td>
<td class="code">
<pre><code><span class="variable">validate</span>: <span class="keyword">function</span> <span class="variable">validate</span>(<span class="variable">value</span>, <span class="variable">name</span>) {
<span class="keyword">return</span> <span class="variable">value</span>;
}
});
<span class="class">Guard</span>.<span class="variable">isGuard</span> = <span class="variable">true</span>;
<span class="variable">exports</span>.<span class="class">Guard</span> = <span class="class">Guard</span>;</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<h1>Function</h1>
<p>Function creates a function guard - function that may be used to perform run
time type checks on the values. Function takes an optional <code>defaultValue</code>
that will be returned by a created guard if it's invoked without (or with
<code>undefined</code>) <code>value</code> argument. The <code>defaultValue</code> will fall back to
<code>undefined</code> if not provided. Function also takes another optional argument
<code>message</code> that represents a template of a message of the <code>TypeError</code> that
will be thrown by guard if it's invoked with invalid <code>value</code>.</p>
<h2></h2>
<ul><li><p><strong>param</strong>: <em>Object | String | Number | function</em> [defaultValue]</p><p>Value that returned guard is going to fall back to if invoked without
a <code>value</code> or if it's <code>undefined</code>.</p></li><li><p><strong>param</strong>: <em>String</em> [message]</p><p>Optional error message template that will be a message of a <code>TypeError</code>
that is will be thrown if returned guard is invoked with a wrong <code>value</code>
type. If <code>message</code> contains <code>"{{value}}"</code> and <code>"{{type}}"</code> strings they
are going to be replaced with an actual <code>value</code> and it's type.</p></li></ul>
<h2>Examples</h2>
<pre><code> var guards = require("guards");
var Callee = guards.Function("Anonymous");
Callee(Object) == Object
// true
Callee(function() { return "hello world" })
Callee(function() { return "hello world" })
Callee(7);
// TypeError: Function expected instead of number `7`
guards.Function("Hi", "{{type}} is not a function.");
Callee({})
// TypeError: object is not a function</code></pre>
<p> </p>
</td>
<td class="code">
<pre><code><span class="variable">exports</span>.<span class="class">Function</span> = <span class="class">Guard</span>.<span class="variable">extend</span>({
<span class="variable">isValid</span>: <span class="variable">isFunction</span>,
<span class="variable">message</span>: <span class="string">"Function expected instead of {{type}} `{{value}}`"</span>
});</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<h1>String</h1>
<p>Function creates a string guard - function that may be used to perform run
time type checks on the values. Function takes an optional <code>defaultValue</code>
that will be returned by a created guard if it's invoked without (or with
<code>undefined</code>) <code>value</code> argument. The <code>defaultValue</code> will fallback to
<code>undefined</code> if not provided. Function also takes another optional argument
<code>message</code> that represents a template of a message of the <code>TypeError</code> that
will be thrown by guard if it's invoked with incorrect value.</p>
<h2></h2>
<ul><li><p><strong>param</strong>: <em>Object | String | Number | function</em> [defaultValue]</p><p>Value that returned guard is going to fall back to if invoked without
a <code>value</code> or if it's <code>undefined</code>.</p></li><li><p><strong>param</strong>: <em>String</em> [message]</p><p>Optional error message template that will be a message of a <code>TypeError</code>
that is will be thrown if returned guard is invoked with a wrong <code>value</code>
type. If <code>message</code> contains <code>"{{value}}"</code> and <code>"{{type}}"</code> strings they
are going to be replaced with an actual <code>value</code> and it's type.</p></li></ul>
<h2>Examples</h2>
<pre><code> var guards = require("guards");
var gUser = guards.String("Anonymous");
var user1 = gUser("Jack");
// "Jack"
var user2 = gUser();
// "Anonymous"
var user3 = gUser(7);
// TypeError: String expected instead of number `7`
var gHi = guards.String("Hi", "string expected not a {{type}}");
var msg = gHi(function() {});
// TypeError: string expected not a function</code></pre>
<p> </p>
</td>
<td class="code">
<pre><code><span class="variable">exports</span>.<span class="class">String</span> = <span class="class">Guard</span>.<span class="variable">extend</span>({
<span class="variable">isValid</span>: <span class="variable">isString</span>,
<span class="variable">message</span>: <span class="string">"String expected instead of {{type}} `{{value}}`"</span>
});</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<h1>Number</h1>
<p>Function creates a number guard - function that may be used to perform run
time type checks on the values. Function takes an optional <code>defaultValue</code>
that will be returned by a created guard if it's invoked without (or with
<code>undefined</code>) <code>value</code> argument. The <code>defaultValue</code> will fallback to
<code>undefined</code> if not provided. Function also takes another optional argument
<code>message</code> that represents a template of a message of the <code>TypeError</code> that
will be thrown by guard if it's invoked with incorrect value.</p>
<h2></h2>
<ul><li><p><strong>param</strong>: <em>Object | String | Number | function</em> [defaultValue]</p><p>Value that returned guard is going to fall back to if invoked without
a <code>value</code> or if it's <code>undefined</code>.</p></li><li><p><strong>param</strong>: <em>String</em> [message]</p><p>Optional error message template that will be a message of a <code>TypeError</code>
that is will be thrown if returned guard is invoked with a wrong <code>value</code>
type. If <code>message</code> contains <code>"{{value}}"</code> and <code>"{{type}}"</code> strings they
are going to be replaced with an actual <code>value</code> and it's type.</p></li></ul>
<h2>examples</h2>
<pre><code> var guards = require("guards")
var Length = guards.Number.extend({ defaults: 0 })
Length()
// 0
Length(17)
// 17
Length("7")
// TypeError: Number expected instead of string `7`
var Count = guards.Number.extend({
defaults: 0,
message: "number expected not a {{type}}"
});
Count({ value: 4 });
// TypeError: number expected not a object</code></pre>
<p> </p>
</td>
<td class="code">
<pre><code><span class="variable">exports</span>.<span class="class">Number</span> = <span class="class">Guard</span>.<span class="variable">extend</span>({
<span class="variable">isValid</span>: <span class="variable">isNumber</span>,
<span class="variable">message</span>: <span class="string">"Number expected instead of {{type}} `{{value}}`"</span>
});
<span class="variable">exports</span>.<span class="class">Boolean</span> = <span class="class">Guard</span>.<span class="variable">extend</span>({
<span class="variable">isValid</span>: <span class="variable">isBoolean</span>,
<span class="variable">message</span>: <span class="string">"Boolean expected instead of {{type}} `{{value}}`"</span>
});
<span class="variable">exports</span>.<span class="class">Null</span> = <span class="class">Guard</span>.<span class="variable">extend</span>({
<span class="variable">isValid</span>: <span class="variable">isNull</span>,
<span class="variable">message</span>: <span class="string">"Boolean expected instead of {{type}} `{{value}}`"</span>
});</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<h1>Schema</h1>
<p>Schema is useful for defining guards for data objects that have particular
structure. Function takes <code>descriptor</code> argument that is a map of guards
guarding same named properties of the value being validated. Scheme may
contain guards for a primitive values like <code>String</code> and <code>Number</code> and also
guards for more complex data structures defined by other <code>Schema</code>s, or to
put it other way <code>Schema</code> may contain guards that were created by <code>Schema</code>
itself which allows defining deeply nested data structures.</p>
<p>Generated guard will accept only object <code>values</code> as an argument. All the
non-guarded properties (that are not present in the <code>descriptor</code>) of the
<code>value</code> will be stripped out. All the missing properties of the <code>value</code>
will be replaced / assembled from the defaults if associated guards provide
fallback mechanism to default value.</p>
<h2></h2>
<ul><li><p><strong>param</strong>: <em>Object</em> descriptor</p><p>Object containing guards for the associated (same named properties) of
the guarded object <code>value</code>.</p></li><li><p><strong>param</strong>: <em>String</em> [message]</p><p>Optional error message template that will be a message of a <code>TypeError</code>
that is will be thrown if returned guard is invoked with a wrong <code>value</code>
type (other then "object" or "undefined"). If <code>message</code> contains
<code>"{{value}}"</code> and <code>"{{type}}"</code> strings they are going to be replaced with
an actual <code>value</code> and it's type.</p></li></ul>
<h2>Examples</h2>
<pre><code> var guards = require("guards");
var Point = guards.Schema.extend({
x: guards.Number.extend({ defaults: 0 }),
y: guards.Number.extend({ defaults: 0 })
})
new Point
// { x: 0, y: 0 }
Point({ x: 17, z: 50 })
// { x: 17, y: 0 }
Point({ x: "5" })
// TypeError: Number expected instead of string `5`
Point("{ y: 6 }")
// TypeError: Object expected instead of string `{ y: 6 }`
var Segment = guards.Schema.extend({
start: Point,
end: Point,
opacity: guards.Number.extend({ defaults: 1 })
})
new Segment
// { start: { x: 0, y: 0 }, end: { x: 0, y: 0 }, opacity: 1 }
Segment({ end: { x: 17 }, opacity: 0.5 })
// { start: { x: 0, y: 0 }, end: { x: 17, y: 0 }, opacity: 0.5 }
Segment({ start: 17 });
// TypeError: Object expected instead of number `17`</code></pre>
<p> </p>
</td>
<td class="code">
<pre><code><span class="keyword">var</span> <span class="class">Schema</span> = <span class="class">Guard</span>.<span class="variable">extend</span>({
<span class="variable">message</span>: <span class="string">"Object expected instead of {{type}} `{{value}}`"</span>,
<span class="variable">isValid</span>: <span class="keyword">function</span> <span class="variable">isValid</span>(<span class="variable">value</span>, <span class="variable">name</span>) {
<span class="keyword">return</span> <span class="variable">isUndefined</span>(<span class="variable">value</span>) || (<span class="variable">isObject</span>(<span class="variable">value</span>) && !<span class="variable">isArray</span>(<span class="variable">value</span>));
},
<span class="variable">validate</span>: <span class="keyword">function</span> <span class="variable">validate</span>(<span class="variable">value</span>, <span class="variable">name</span>) {
<span class="variable">value</span> = <span class="variable">value</span> || {};
<span class="comment">// At this point we have an object `value` containing properties that must</span>
<span class="comment">// be verified by guards of the `descriptor` to make sure that `value` has</span>
<span class="comment">// correct schema. We loop over `descriptor`s guards and invoke them with</span>
<span class="comment">// an associated `key` and `value`. Results are mapped to the `data` object</span>
<span class="comment">// that represents verified and normalized value. If any of the property</span>
<span class="comment">// guards will throw an exception it will propagate to a caller of this</span>
<span class="comment">// guard notifying it that given `value` does not has desired schema.</span>
<span class="keyword">var</span> <span class="variable">data</span> = {};
<span class="keyword">for</span> (<span class="keyword">var</span> <span class="variable">key</span> <span class="keyword">in</span> <span class="this">this</span>) {
<span class="keyword">if</span> (<span class="this">this</span>[<span class="variable">key</span>].<span class="variable">isGuard</span>)
<span class="variable">data</span>[<span class="variable">key</span>] = <span class="this">this</span>[<span class="variable">key</span>](<span class="variable">value</span>[<span class="variable">key</span>], <span class="variable">name</span>);
}
<span class="comment">// If error was not thrown the `value` has a schema described by</span>
<span class="comment">// a `descriptor`. In such case we return map of the values properties</span>
<span class="comment">// (We can't return `value` itself as it may not contain default values</span>
<span class="comment">// for certain properties or may contain extra properties that have to</span>
<span class="comment">// be dropped).</span>
<span class="keyword">return</span> <span class="variable">data</span>;
}
});
<span class="variable">exports</span>.<span class="class">Schema</span> = <span class="class">Schema</span>;</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<h1>Array</h1>
<p>Array can be used to define guards for an arrays containing elements of some
type or schema. Function takes <code>guard</code> as an argument that will guard all the
elements of the <code>value</code> array that is passed to the returned guard.</p>
<h2></h2>
<ul><li><p><strong>param</strong>: <em>Function</em> guard</p><p>Guard that is going to be used to verify elements of the array. It can
be any guard created by <code>String</code>, <code>Schema</code>, <code>Array</code> or any custom guard
as well.</p></li><li><p><strong>param</strong>: <em>String</em> [message]</p><p>Optional error message template that will be a message of a <code>TypeError</code>
that is will be thrown if returned guard is invoked with a wrong <code>value</code>
type (other then "array" or "undefined"). If <code>message</code> contains
<code>"{{value}}"</code> and <code>"{{type}}"</code> strings they are going to be replaced with
an actual <code>value</code> and it's type.</p></li></ul>
<h2>Examples</h2>
<pre><code> var guards = require("guards")
var Words = guards.Array.extend([
guards.String.extend({ defaults: "" })
])
Words([ "foo", "bar" ])
// [ 'foo', 'bar' ]
Words([ "foo", 9 ])
// TypeError: String expected instead of number `9`
var Point = guards.Schema.extend({
x: guards.Number.extend({ defaults: 0 }),
y: guards.Number.extend({ defaults: 0 })
})
var Points = guards.Array.extend([ Point ])
new Points([{}, { x: 2, y: 8 }])
// [ { x: 0, y: 0 }, { x: 2, y: 8 } ]
Points({ x: 2, y: 8 })
// TypeError: Array expected instead of object `[object Object]`
var Graph = guards.Array.extend([ Points ])
new Graph
// []
Graph([
[{ x: 17, foo: "bar" }, { x: 16 }],
[{ y: 4 }],
[]
])
// [ [ { x: 17, y: 0 }, { x: 16, y: 0 } ], [ { x: 0, y: 4 } ], [] ]</code></pre>
<p> </p>
</td>
<td class="code">
<pre><code><span class="keyword">var</span> <span class="class">Array</span> = <span class="class">Guard</span>.<span class="variable">extend</span>({
<span class="variable">message</span>: <span class="string">"Array expected instead of {{type}} `{{value}}`"</span>,
<span class="variable">isValid</span>: <span class="keyword">function</span> <span class="variable">isValid</span>(<span class="variable">value</span>) {
<span class="keyword">return</span> <span class="variable">isArray</span>(<span class="variable">value</span>) || <span class="variable">isUndefined</span>(<span class="variable">value</span>);
},
<span class="variable">validate</span>: <span class="keyword">function</span> <span class="variable">validate</span>(<span class="variable">value</span>, <span class="variable">name</span>) {
<span class="comment">// At this point we have an array `value` containing properties that must</span>
<span class="comment">// be verified by a desired `guard`. As result we return mapped array</span>
<span class="comment">// containing guarded values of the given array. Please note that we need</span>
<span class="comment">// to map original array as some values of it may be normalized (default</span>
<span class="comment">// values added for missing properties) by guards. If any of the element</span>
<span class="comment">// does not passes validation guard will throw `TypeError` and it will</span>
<span class="comment">// propagate to a caller of this guard notifying it that `value` does not</span>
<span class="comment">// validates.</span>
<span class="variable">value</span> = <span class="variable">value</span> || [];
<span class="keyword">return</span> <span class="variable">value</span>.<span class="variable">map</span>(<span class="keyword">function</span>(<span class="variable">value</span>, <span class="variable">index</span>) {
<span class="keyword">return</span> <span class="this">this</span>[<span class="number integer">0</span>](<span class="variable">value</span>, <span class="variable">index</span>);
}, <span class="this">this</span>);
}
});
<span class="variable">exports</span>.<span class="class">Array</span> = <span class="class">Array</span>;</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<h1>Tuple</h1>
<p>Tuple can be used to define guards for an arrays containing predefined
amount of elements guarded by specific guards. Tuple guards are something
in between Array and Schema guards. Function takes array of guards as an
argument that will be used to validate same indexed elements of the <code>value</code>
array that is passed to the returned guard.</p>
<h2></h2>
<ul><li><p><strong>param</strong>: <em>Function[]</em> guards</p><p>Guards that are going to be used to verify elements of the array. It can
be any guard created by <code>String</code>, <code>Schema</code>, <code>Array</code> or any custom guard
as well.</p></li><li><p><strong>param</strong>: <em>String</em> [message]</p><p>Optional error message template that will be a message of a <code>TypeError</code>
that is will be thrown if returned guard is invoked with a wrong <code>value</code>
type (other then "array" or "undefined"). If <code>message</code> contains
<code>"{{value}}"</code> and <code>"{{type}}"</code> strings they are going to be replaced with
an actual <code>value</code> and it's type.</p></li></ul>
<h2>Examples</h2>
<pre><code> var guards = require("guards");
var Point = guards.Schema({
x: guards.Number(0),
y: guards.Number(0)
});
var Segment = guards.Schema({
start: Point,
end: Point,
opacity: guards.Number(1)
});
var Triangle = guards.Tuple([ Segment, Segment, Segment ]);
var t1 = Triangle();
// [ { start: { x: 0, y: 0 }, end: { x: 0, y: 0 }, opacity: 1 },
// { start: { x: 0, y: 0 }, end: { x: 0, y: 0 }, opacity: 1 },
// { start: { x: 0, y: 0 }, end: { x: 0, y: 0 }, opacity: 1 }
// ]
var t2 = Triangle([
{ opacity: 0, foo: "bar" },
{ start: { x: 2 } }
]);
// [ { start: { x: 0, y: 0 }, end: { x: 0, y: 0 }, opacity: 0 },
// { start: { x: 2, y: 0 }, end: { x: 0, y: 0 }, opacity: 1 },
// { start: { x: 0, y: 0 }, end: { x: 0, y: 0 }, opacity: 1 }
// ]
var t2 = Triangle("foo");
// TypeError: Array expected instead of string `foo`
var t3 = Triangle([{ start: { x: '3' } } ]);
// TypeError: Number expected instead of string `3`
var Pointer = guards.Tuple([ Point, Segment ]);
var p1 = Pointer();
// [ { x: 0, y: 0 }, { start: { x: 0, y: 0 }, end: { x: 0, y: 0 }, opacity: 1 } ]
var p2 = Pointer([ { x: 17 }, { opacity: 0 } ]);
// [ { x: 17, y: 0 }, { start: { x: 0, y: 0 }, end: { x: 0, y: 0 }, opacity: 0 } ]
var p3 = Pointer([ { foo: "bar" }, { baz: "bla" }, "foo" ]);
// [ { x: 0, y: 0 }, { start: { x: 0, y: 0 }, end: { x: 0, y: 0 }, opacity: 1 } ]</code></pre>
<p> </p>
</td>
<td class="code">
<pre><code><span class="keyword">var</span> <span class="class">Tuple</span> = <span class="class">Guard</span>.<span class="variable">extend</span>({
<span class="variable">message</span>: <span class="string">"Array expected instead of {{type}} `{{value}}`"</span>,
<span class="variable">isValid</span>: <span class="keyword">function</span> <span class="variable">isValid</span>(<span class="variable">value</span>) {
<span class="keyword">return</span> <span class="variable">isArray</span>(<span class="variable">value</span>) || <span class="variable">isUndefined</span>(<span class="variable">value</span>);
},
<span class="variable">validate</span>: <span class="keyword">function</span> <span class="variable">validate</span>(<span class="variable">value</span>, <span class="variable">name</span>) {
<span class="comment">// At this point we have an array `value` containing properties that must</span>
<span class="comment">// be verified by a guards in the `descriptor`. As result we return mapped</span>
<span class="comment">// array containing guarded values of the given array. Please note that we</span>
<span class="comment">// need to map original array as some values of it may be normalized</span>
<span class="comment">// (default values added for missing properties) by guards also we map only</span>
<span class="comment">// elements that are guarded by `descriptor` any additional ones will be</span>
<span class="comment">// stripped off. If any element won't pass validation, responsible guard</span>
<span class="comment">// will throw `TypeError` and it will propagate to a caller of this guard</span>
<span class="comment">// notifying it that `value` does not validates.</span>
<span class="variable">value</span> = <span class="variable">value</span> || [];
<span class="keyword">var</span> <span class="variable">data</span> = [];
<span class="keyword">for</span> (<span class="keyword">var</span> <span class="variable">key</span> <span class="keyword">in</span> <span class="this">this</span>) {
<span class="keyword">if</span> (<span class="this">this</span>[<span class="variable">key</span>].<span class="variable">isGuard</span>)
<span class="variable">data</span>[<span class="variable">key</span>] = <span class="this">this</span>[<span class="variable">key</span>](<span class="variable">value</span>[<span class="variable">key</span>], <span class="variable">name</span>);
}
<span class="keyword">return</span> <span class="variable">data</span>;
}
});
<span class="variable">exports</span>.<span class="class">Tuple</span> = <span class="class">Tuple</span>;</code></pre>
</td>
</tr>
<tr class="code">
<td class="docs">
<h1>AnyOf</h1>
<p><code>AnyOf</code> can be used to define guards that validates <code>value</code>s that must
satisfy just one of many guards. This is handy in specific specific
scenarios were valid <code>value</code> may have different types or schemas.
Function takes any number guards as an arguments and returns composed
guard, which when called will try to validate a given <code>value</code> with a given
guards in an order they were passed, the first validate <code>value</code> is returned
as result, unless non will validate in which case <code>TypeError</code> is thrown.</p>
<h2></h2>
<ul><li><p><strong>params</strong>: <em>Function</em> guard</p><p>Guards used for validations.</p></li><li><p><strong>returns</strong>: <em>Function</em> </p></li></ul>
<h2>Examples</h2>
<pre><code> var guards = require("guards")
var ObjectPoint = guards.Schema.extend({
x: guards.Number.extend({ defaults: 0 }),
y: guards.Number.extend({ defaults: 0 })
})
var ArrayPoint = guards.Tuple.extend([
guards.Number.extend({ defaults: 0 }),
guards.Number.extend({ defaults: 0 })
])
var Point = guards.AnyOf.extend([ ObjectPoint, ArrayPoint ]);
Point([ 1 ])
// [ 1, 0 ]
Point({ y: 15 })
// { x: 0, y: 15 }
Point(1, 2)
// TypeError: Passed value: `1` has invalid type or structure</code></pre>
<p> </p>
</td>
<td class="code">
<pre><code><span class="keyword">var</span> <span class="class">AnyOf</span> = <span class="class">Guard</span>.<span class="variable">extend</span>({
<span class="comment">// Template of error `message` that will be thrown if incorrect `value` is</span>
<span class="comment">// passed to it.</span>
<span class="variable">message</span>: <span class="string">"Passed value: `{{value}}` has invalid type or structure"</span>,
<span class="comment">// Saving array of the value guards.</span>
<span class="variable">validate</span>: <span class="keyword">function</span> <span class="variable">validate</span>(<span class="variable">value</span>, <span class="variable">name</span>) {
<span class="comment">// We try to return `value` that passes at least on validation, by trying</span>
<span class="comment">// to validate it with each guard.</span>
<span class="keyword">for</span> (<span class="keyword">var</span> <span class="variable">key</span> <span class="keyword">in</span> <span class="this">this</span>) {
<span class="keyword">if</span> (<span class="this">this</span>[<span class="variable">key</span>].<span class="variable">isGuard</span>)
<span class="keyword">try</span> { <span class="keyword">return</span> <span class="this">this</span>[<span class="variable">key</span>](<span class="variable">value</span>, <span class="variable">name</span>); } <span class="keyword">catch</span>(<span class="variable">error</span>) {}
}
<span class="comment">// If got this far then non of the validations succeeded as value was not</span>
<span class="comment">// returned, so we throw a `TypeError` that will propagate to a caller of</span>
<span class="comment">// this guard notifying it that `value` does not validates.</span>
<span class="keyword">throw</span> <span class="keyword">new</span> <span class="class">TypeError</span>(<span class="this">this</span>.<span class="variable">message</span>.<span class="variable">replace</span>(<span class="string">"{{value}}"</span>, <span class="variable">value</span>));
}
});
<span class="variable">exports</span>.<span class="class">AnyOf</span> = <span class="class">AnyOf</span>;
});
</code></pre>
</td>
</tr> </body>
</html></tbody></table>