/*//////////////////////////////////////////////////////////
============================================================

Typo.js Check yourself before you wreck yourself

============================================================
//////////////////////////////////////////////////////////*/

Typo is an open source JavaScript tool providing chainable type checking and argument validation.

Typo features a robust syntax for several type-related features that are sadly missing from standard JavaScript.

Out-of-the-box support for CommonJS and AMD. It's also ready to be pooped into the global namespace (if you really must).


Typo is a mere 1.8 KB gzipped and minified.



//==========================================================
//::::

The Rundown

:::::::::::::::::::::::::::::::::::::::::
//==========================================================

Typo is small, but it's also robust.

Typo has about 30 value-testing functions, all of which are available in four usage contexts. It's hard to introduce these concepts in a strict 'all things considered' documentation-robot format, which is why this rundown section exists: to give you a quicker and more human explanation that gets straight to the meaty bits while leaving out the documentation vegetables (which you can get to later if you need to).


In the green section lower on this page, you'll find a more proper documentation that explains each and every test and the rest of Typo's API.


The following is a fast-paced rundown which aims to tersely explain, in an example-driven way, why and how you might use Typo.

Also, keep in mind that Typo is freshly available in your F12 JavaScript developer console right now, so feel free to follow along and experiment to your heart's desire.


Typo.number(5) //---------------------------=> true
Typo.number("5") //-------------------------=> false

Typo.string("5") //-------------------------=> true
Typo.string(5) //---------------------------=> false

Typo.arrayLike(arguments) //----------------=> true
Typo.array(arguments) //--------------------=> false
  // Don't forget the JS quirk that `arguments` 
  // isn't actually an instance of Array.

Typo.object({}) //--------------------------=> true
Typo.object(null) //------------------------=> false
Typo.object([]) //--------------------------=> true

Typo.plainObject({}) //---------------------=> true
Typo.plainObject([]) //---------------------=> false
Typo.plainObject(new Object) //-------------=> true
Typo.plainObject(new function Lol () {}) //-=> false

Typo.set(5) //------------------------------=> true
Typo.set({}) //-----------------------------=> true
Typo.set(null) //---------------------------=> false
Typo.set(undefined) //----------------------=> false

// See all tests in the documentation section below

Typo(5).number().lte(10).end(); //=> true
  // 5 must be a number and also 
  // less-or-equal to 10 (it is)
  
Typo(5).number().lte(4).end(); //=> false
  // 5 must be a number and also 
  // less-or-equal to 4 (it isn't)

Typo([1, 2]).array().notEmpty().e(); //=> true
Typo([]).array().notEmpty().e();     //=> false

// End a chain with the 'end' method (e() for short) to 
// get the boolean result of the entire chain.

// Proper chain context documentation below

Typo.num     === Typo.number
Typo.str     === Typo.string
Typo.obj     === Typo.object
Typo.arr     === Typo.array
Typo.arrlike === Typo.arrayLike
Typo.plob    === Typo.plainObject
Typo.bearing === Typo.notEmpty

// All synonyms are shown in the full documentation

Typo.all.number([4,  5,  6]) //=> true
Typo.all.number([4, "5", 6]) //=> false

Typo.all.string("ABC", "QWE", "XYZ") //=> true
Typo.all.string("ABC",  456,  "XYZ") //=> false

// All-static context documentation below

Typo.all([4,  5,  6]).num().lte(10).e() //=> true
Typo.all([4, "5", 6]).num().lte(10).e() //=> false
Typo.all([4, 152, 6]).num().lte(10).e() //=> false

// All-chain context documentation below

function multiplyString (input, times) {

	input = Typo(input).string().o();
	  // input must be string, or a default typo error
	  // will throw.

	times = Typo(times)
		.integer()
		.gte(0)
		.o(new Error(
			"times must be a non-negative integer"));
			  // You can specify your own errors.

	for (var o=""; times > 0; times -= 1) o += input;
	return o;
}

// You can handle failing chains by passing your own errors, 
// or fallback values; otherwise, if neither is provided, 
// a default Typo error will be thrown.

// Chain context documentation below

function properDefaults (alpha, beta) {

	alpha = Typo(alpha).default(0).int().gte(0).o();

	beta = Typo(beta)
		.default([])
		.arrayLike()
		.notEmpty()
		.o(new Error("beta must be a array-like "
		             + "and not empty"));

	return [alpha, beta];
}

// 'default' only works with the 'or' (o() for short) 
// chain termination method, and doesn't work with 
// 'end' (e() for short) method since that wouldn't
// make any sense.

// Chain context documentation below

Typo(72).num().gt(45).e()           //=> true
Typo(72).num().gt(45, Typo.inv).e() //=> false

function chainModeExamples (x, y) {

	x = Typo(x, '&&') // AND is the default mode
		.integer()
		.greater(0)
		.o(new Error("x must be: "
		             + "An integer AND positive"));

	y = Typo(y, '||') // OR mode
		.number()
		.string()
		.o(new Error("y must be: "
		             + "A number OR a string"));

	return [x, y];
}

// Chain mode can be specified for regular chains 
// and Typo.all chains alike.

// Chain context documentation below

Every test below can be used in any of Typo's four usage contexts. Read the rundown for examples of how you can use Typo in these contexts, or go below to the proper documentation on them.

All tests are invertable in all contexts by passing Typo.inv as an argument.

Many tests have synonyms.


Typo.def(x) Typo.defined(x)

Returns true if x is NOT undefined. Otherwise returns false.

Typo.undef(x) Typo.undefined(x)

Returns true if x is undefined. Otherwise returns false.

Typo.nul(x) Typo.null(x)

Returns true if x is null. Otherwise returns false.

Typo.set(x)

Returns true if x is NEITHER null nor undefined. Otherwise returns false.

Typo.unset(x)

Returns true if x is either null or undefined. Otherwise returns false. ////////////////////////////////////////////////////////////

Typo.truthy(x)

Returns true if x evaluates to boolean as true. Otherwise returns false.

Typo.falsey(x)

Returns true if x evaluates to boolean as false. Otherwise returns false. ////////////////////////////////////////////////////////////

Typo.bool(x) Typo.boolean(x)

Returns true if x is a Boolean (value or object). Otherwise returns false.

Typo.num(x) Typo.number(x)

Returns true if x is a Number (value or object). Otherwise returns false.

Typo.int(x) Typo.integer(x)

Returns true if x is a Number (value or object) that is whole (not fractional; is an exact multiple of 1.0). Otherwise returns false.

Typo.str(x) Typo.string(x)

Returns true if x is a String (value or object). Otherwise returns false.

Typo.obj(x) Typo.object(x)

Returns true if x is an Object of any kind. Otherwise returns false.

Typo.plob(x) Typo.plainObject(x)

Returns true if x is an object literal (such as {}), or is an instance of Object (such as (new Object)). Otherwise returns false.

Typo.func(x) Typo.function(x)

Returns true if x is a Function object. Otherwise returns false.

Typo.arr(x) Typo.array(x)

Returns true if x is an Array object. Otherwise returns false.

Typo.arrlike(x) Typo.arrayLike(x)

Returns true if x is an object with a property named length that is a Number (value or object). Otherwise returns false.

Typo.regex(x) Typo.regExp(x)

Returns true if x is a RegExp object. Otherwise returns false. ////////////////////////////////////////////////////////////

Typo.empty(x)

Returns true if x is an 'arraylike' with a length of 0, or is an object that contains 0 properties. Otherwise returns false.

Typo.bearing(x) Typo.notEmpty(x)

Returns true if x fails the above 'empty' test. Otherwise returns false.

Typo.is(x, y)

Returns true if x is exactly equal to y. Otherwise returns false.

Typo.isnt(x, y)

Returns true if x is NOT exactly equal to y. Otherwise returns false. ////////////////////////////////////////////////////////////

Typo.gt(x, y) Typo.greater(x, y)

Returns true if x is greater (>) than y. Otherwise returns false.

Typo.lt(x, y) Typo.less(x, y)

Returns true if x is less (<) than y. Otherwise returns false.

Typo.gte(x, y) Typo.greaterOrEqual(x, y)

Returns true if x is greater than or equal to (>=) y. Otherwise returns false.

Typo.lte(x, y) Typo.lessOrEqual(x, y)

Returns true if x is less than or equal to (<=) y. Otherwise returns false.

Typo.has(x, y)

Returns true if x has y as a property (y in x). Otherwise returns false.

Typo.contains(x, y)

Returns true if x (arrayLike) contains y as a value (internally uses Array.prototype.indexOf). Otherwise returns false.

Typo.test(x, y)

Returns the result of calling y (a Function) when given x as an argument. This test allows you to input your own custom test function y that is used to test x. If y isn't a function, an Error will be thrown.

Typo(x) Typo(x, mode)

Creates a Typo chain instance, onto which you can chain as many Typo tests as you'd like. You use chain termination methods (below) to yield a chain's result. Use of new is optional with this constructor. Arguments: x - The value that chained tests will scrutinize. mode [default='&&'] - In '&&' mode, x must pass all chained tests for the whole chain to pass. In '||' mode however, x must pass only one chained test for the whole chain to pass. Returns: A new 'Typo' chain instance.

Typo.prototype.end() Typo.prototype.e()

Terminates the chain, and returns the boolean result of the chain. Returns: true if the chain passes. false otherwise. Examples: Typo(5).number().gt(2).end() //=> true Typo(5).number().gt(6).end() //=> false Typo("5").number().gt(2).end() //=> false // Chain context rundown section

Typo.prototype.or(a) Typo.prototype.o(a)

Terminates the chain. If the chain passes, the orignally provided value (x) will be returned. If the chain does not pass, either an error will be thrown, or a provided fallback value will be used (depending on what was given as a). Arguments: a - undefined (or ommitted): If the chain fails, a default error will be thrown. an Error: If the chain fails, a will be thrown as an error. any other value: If the chain fails, a will be returned. Returns: If the original x value is undefined, and the default method was used to set a default value, then that default value will be returned. Otherwise (x is defined), if the chain passes, x will be returned. Otherwise (if chain fails), it depends on what the provided a value was. See 'Arguments'. Examples: Typo(5).number().gt(2).or() //=> 5 Typo(5).number().gt(6).or() //=> Uncaught Error: Typo: Chain failed Typo(5).number().gt(6).or(0) //=> 0 Typo(5).number().gt(6).or(new Error("blah")) //=> Uncaught Error: blah // Argument validation examples in rundown section

Typo.prototype.default(d)

Sets the default fallback value for this chain. If the orignally provided x is undefined, the or chain termination method will return d. Only available for regular Typo chains. Not available for Typo.all chains. Examples: Typo(undefined).default(0).number().or() //=> 0 Typo(5).default(0).number().or() //=> 5 // Defaults rundown section

Typo.all.<any typo test> Typo.All.<any typo test>

All of Typo's tests are also available under Typo.all, where instead of taking a single value to scrutinize, each test will loop over a provided array-like group of values. It's for testing groups of values instead of testing just a single value. For example, checking that all elements in an array are numbers. Arguments: See individual test documentation above. Returns: Boolean result of test. See individual test documentation above. Examples: Typo.all.number([4, 5, 6]); // true Typo.all.number([4,"5",6]); // false Typo.all.gte([4, 5, 6], 4); // true Typo.all.gte([4, 5, 6], 5); // false // Static context just for contrast. Typo.number(5); // true // All-static context rundown section

Typo.all(x) Typo.all(x, mode) Typo.All(x) Typo.All(x, mode)

This constructor creates a Typo.All chain instance, onto which you can chain as many Typo tests as you'd like. Each test will loop over each value in x, which must be an array-like group of values. Use of new is optional with this constructor. Arguments: x - The value that chained tests will scrutinize. mode [default='&&'] - In '&&' mode, x must pass all chained tests for the whole chain to pass. In '||' mode however, x must pass only one chained test for the whole chain to pass. Examples: Typo.all([4, 5, 6]).number().gte(4); // true Typo.all([4,"5",6]).number().gte(4); // false Typo.all([4, 5, 6]).number().gte(5); // false // All-chain context rundown section

Both of the chain context termination methods, end and 
or (as seen under chain documentation) are available for 
Typo.all chains! They behave the same way, so please 
read their documentation above.

On the other hand, the default chain method 
is NOT available for Typo.all chains.