tcomb
Advanced tools
Comparing version 0.3.6 to 0.4.0
@@ -0,1 +1,9 @@ | ||
# v0.4.0 | ||
**BREAKING** | ||
- `t.irreducible` instead of `t.irriducible`, fix #77 | ||
- Prevent illegal type definitions and make easy type analysis, fix #78 | ||
- change default name for unnamed types, fix #79 | ||
# v0.3.6 | ||
@@ -2,0 +10,0 @@ |
174
index.js
@@ -70,3 +70,3 @@ (function (root, factory) { | ||
if (overwrite !== true) { | ||
assert(!target.hasOwnProperty(k), 'cannot overwrite property %s', k); | ||
assert(!target.hasOwnProperty(k), 'Cannot overwrite property %s', k); | ||
} | ||
@@ -119,8 +119,13 @@ target[k] = source[k]; | ||
function getName(type) { | ||
assert(Type.is(type), 'Invalid argument `type` of value `%j` supplied to `getName()`, expected a type.', type); | ||
assert(Type.is(type), 'Invalid argument `type` = `%s` supplied to `getName()`', type); | ||
return type.meta.name; | ||
} | ||
function getFunctionName(f) { | ||
assert(typeof f === 'function', 'Invalid argument `f` = `%s` supplied to `getFunctionName()`', f); | ||
return f.displayName || f.name || format('<function%s>', f.length); | ||
} | ||
function getKind(type) { | ||
assert(Type.is(type), 'Invalid argument `type` of value `%j` supplied to `geKind()`, expected a type.', type); | ||
assert(Type.is(type), 'Invalid argument `type` = `%s` supplied to `geKind()`', type); | ||
return type.meta.kind; | ||
@@ -130,3 +135,3 @@ } | ||
function blockNew(x, type) { | ||
assert(!(x instanceof type), 'Operator `new` is forbidden for `%s`', getName(type)); | ||
assert(!(x instanceof type), 'Operator `new` is forbidden for type `%s`', getName(type)); | ||
} | ||
@@ -204,21 +209,21 @@ | ||
// | ||
// irriducibles | ||
// irreducibles | ||
// | ||
function irriducible(name, is) { | ||
function irreducible(name, is) { | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a string | ||
assert(typeof name === 'string', 'Invalid argument `name` supplied to `irriducible()`'); | ||
assert(typeof name === 'string', 'Invalid argument `name` = `%s` supplied to `irreducible()`', name); | ||
// DEBUG HINT: if the debugger stops here, the second argument is not a function | ||
assert(typeof is === 'function', 'Invalid argument `is` supplied to `irriducible()`'); | ||
assert(typeof is === 'function', 'Invalid argument `is` = `%s` supplied to `irreducible()`', is); | ||
function Irriducible(value) { | ||
function Irreducible(value) { | ||
// DEBUG HINT: if the debugger stops here, you have used the `new` operator but it's forbidden | ||
blockNew(this, Irriducible); | ||
blockNew(this, Irreducible); | ||
// DEBUG HINT: if the debugger stops here, the first argument is invalid | ||
// mouse over the `value` variable to see what's wrong. In `name` there is the name of the type | ||
assert(is(value), 'Invalid `%s` supplied to `%s`', value, name); | ||
assert(is(value), 'Invalid argument `value` = `%s` supplied to irreducible type `%s`', value, name); | ||
@@ -228,59 +233,59 @@ return value; | ||
Irriducible.meta = { | ||
kind: 'irriducible', | ||
Irreducible.meta = { | ||
kind: 'irreducible', | ||
name: name | ||
}; | ||
Irriducible.displayName = name; | ||
Irreducible.displayName = name; | ||
Irriducible.is = is; | ||
Irreducible.is = is; | ||
return Irriducible; | ||
return Irreducible; | ||
} | ||
var Any = irriducible('Any', function isAny() { | ||
var Any = irreducible('Any', function isAny() { | ||
return true; | ||
}); | ||
var Nil = irriducible('Nil', function isNil(x) { | ||
var Nil = irreducible('Nil', function isNil(x) { | ||
return x === null || x === void 0; | ||
}); | ||
var Str = irriducible('Str', function isStr(x) { | ||
var Str = irreducible('Str', function isStr(x) { | ||
return typeof x === 'string'; | ||
}); | ||
var Num = irriducible('Num', function isNum(x) { | ||
var Num = irreducible('Num', function isNum(x) { | ||
return typeof x === 'number' && isFinite(x) && !isNaN(x); | ||
}); | ||
var Bool = irriducible('Bool', function isBool(x) { | ||
var Bool = irreducible('Bool', function isBool(x) { | ||
return x === true || x === false; | ||
}); | ||
var Arr = irriducible('Arr', function isArr(x) { | ||
var Arr = irreducible('Arr', function isArr(x) { | ||
return x instanceof Array; | ||
}); | ||
var Obj = irriducible('Obj', function isObj(x) { | ||
var Obj = irreducible('Obj', function isObj(x) { | ||
return !Nil.is(x) && typeof x === 'object' && !Arr.is(x); | ||
}); | ||
var Func = irriducible('Func', function isFunc(x) { | ||
var Func = irreducible('Func', function isFunc(x) { | ||
return typeof x === 'function'; | ||
}); | ||
var Err = irriducible('Err', function isErr(x) { | ||
var Err = irreducible('Err', function isErr(x) { | ||
return x instanceof Error; | ||
}); | ||
var Re = irriducible('Re', function isRe(x) { | ||
var Re = irreducible('Re', function isRe(x) { | ||
return x instanceof RegExp; | ||
}); | ||
var Dat = irriducible('Dat', function isDat(x) { | ||
var Dat = irreducible('Dat', function isDat(x) { | ||
return x instanceof Date; | ||
}); | ||
var Type = irriducible('Type', function isType(x) { | ||
var Type = irreducible('Type', function isType(x) { | ||
return Func.is(x) && Obj.is(x.meta); | ||
@@ -293,10 +298,12 @@ }); | ||
// mouse over the `props` variable to see what's wrong | ||
assert(dict(Str, Type).is(props), 'Invalid argument `props` supplied to `struct()`'); | ||
assert(dict(Str, Type).is(props), 'Invalid argument `props` = `%s` supplied to `struct` combinator', props); | ||
// DEBUG HINT: if the debugger stops here, the second argument is not a string | ||
// mouse over the `name` variable to see what's wrong | ||
assert(maybe(Str).is(name), 'Invalid argument `name` supplied to `struct()`'); | ||
assert(maybe(Str).is(name), 'Invalid argument `name` = `%s` supplied to `struct` combinator', name); | ||
// DEBUG HINT: always give a name to a type, the debug will be easier | ||
name = name || 'struct'; | ||
name = name || format('{%s}', Object.keys(props).map(function (prop) { | ||
return format('%s: %s', prop, getName(props[prop])); | ||
}).join(', ')); | ||
@@ -312,3 +319,3 @@ function Struct(value, mut) { | ||
// mouse over the `value` variable to see what's wrong. In `name` there is the name of the type | ||
assert(Obj.is(value), 'Invalid `%s` supplied to `%s`, expected an `Obj`', value, name); | ||
assert(Obj.is(value), 'Invalid argument `value` = `%s` supplied to struct type `%s`', value, name); | ||
@@ -351,6 +358,10 @@ // makes `new` optional | ||
Struct.extend = function extendStruct(newProps, name) { | ||
var newStruct = struct([props].concat(newProps).reduce(mixin, {}), name); | ||
mixin(newStruct.prototype, Struct.prototype); // prototypal inheritance | ||
return newStruct; | ||
Struct.extend = function extendStruct(arr, name) { | ||
arr = [].concat(arr).map(function (x) { | ||
return Obj.is(x) ? x : x.meta.props; | ||
}); | ||
arr.unshift(props); | ||
var ret = struct(arr.reduce(mixin, {}), name); | ||
mixin(ret.prototype, Struct.prototype); // prototypal inheritance | ||
return ret; | ||
}; | ||
@@ -364,14 +375,15 @@ | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a list of types | ||
assert(list(Type).is(types), 'Invalid argument `types` supplied to `union()`'); | ||
assert(list(Type).is(types), 'Invalid argument `types` = `%s` supplied to `union` combinator', types); | ||
var len = types.length; | ||
var defaultName = types.map(getName).join(' | '); | ||
// DEBUG HINT: if the debugger stops here, there are too few types (they must be at least two) | ||
assert(len >= 2, 'Invalid argument `types` supplied to `union()`'); | ||
assert(len >= 2, 'Invalid argument `types` = `%s` supplied to `union` combinator, provide at least two types', defaultName); | ||
// DEBUG HINT: if the debugger stops here, the second argument is not a string | ||
// mouse over the `name` variable to see what's wrong | ||
assert(maybe(Str).is(name), 'Invalid argument `name` supplied to `union()`'); | ||
assert(maybe(Str).is(name), 'Invalid argument `name` = `%s` supplied to `union` combinator', name); | ||
name = name || format('union([%s])', types.map(getName).join(', ')); | ||
name = name || defaultName; | ||
@@ -384,3 +396,3 @@ function Union(value, mut) { | ||
// DEBUG HINT: if the debugger stops here, you must implement the `dispatch` static method for this type | ||
assert(Func.is(Union.dispatch), 'unimplemented %s.dispatch()', name); | ||
assert(Func.is(Union.dispatch), 'Unimplemented `dispatch()` function for union type `%s`', name); | ||
@@ -390,3 +402,3 @@ var type = Union.dispatch(value); | ||
// DEBUG HINT: if the debugger stops here, the `dispatch` static method returns no type | ||
assert(Type.is(type), '%s.dispatch() returns no type', name); | ||
assert(Type.is(type), 'The `dispatch()` function of union type `%s` returns no type constructor', name); | ||
@@ -427,6 +439,6 @@ // DEBUG HINT: if the debugger stops here, `value` can't be converted to `type` | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a type | ||
assert(Type.is(type), 'Invalid argument `type` supplied to `maybe()`'); | ||
assert(Type.is(type), 'Invalid argument `type` = `%s` supplied to `maybe` combinator', type); | ||
// makes the combinator idempotent | ||
if (getKind(type) === 'maybe') { | ||
// makes the combinator idempotent and handle Any, Nil | ||
if (getKind(type) === 'maybe' || type === Any || type === Nil) { | ||
return type; | ||
@@ -437,5 +449,5 @@ } | ||
// mouse over the `name` variable to see what's wrong | ||
assert(Nil.is(name) || Str.is(name), 'Invalid argument `name` supplied to `maybe()`'); | ||
assert(Nil.is(name) || Str.is(name), 'Invalid argument `name` = `%s` supplied to `maybe` combinator', name); | ||
name = name || format('maybe(%s)', getName(type)); | ||
name = name || ('?' + getName(type)); | ||
@@ -471,13 +483,13 @@ function Maybe(value, mut) { | ||
// mouse over the `map` variable to see what's wrong | ||
assert(Obj.is(map), 'Invalid argument `map` supplied to `enums()`'); | ||
assert(Obj.is(map), 'Invalid argument `map` = `%s` supplied to `enums` combinator', map); | ||
// DEBUG HINT: if the debugger stops here, the second argument is not a string | ||
// mouse over the `name` variable to see what's wrong | ||
assert(maybe(Str).is(name), 'Invalid argument `name` supplied to `enums()`'); | ||
assert(maybe(Str).is(name), 'Invalid argument `name` = `%s` supplied to `enums` combinator', name); | ||
name = name || 'enums'; | ||
// cache enums | ||
var keys = Object.keys(map); | ||
name = name || keys.map(function (k) { return JSON.stringify(k); }).join(' | '); | ||
function Enums(value) { | ||
@@ -490,3 +502,3 @@ | ||
// mouse over the `value`, `name` and `keys` variables to see what's wrong | ||
assert(Enums.is(value), 'Invalid `%s` supplied to `%s`, expected one of %j', value, name, keys); | ||
assert(Enums.is(value), 'Invalid argument `value` = `%s` supplied to enums type `%s`, expected one of %j', value, name, keys); | ||
@@ -523,3 +535,3 @@ return value; | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a list of types | ||
assert(list(Type).is(types), 'Invalid argument `types` supplied to `tuple()`'); | ||
assert(list(Type).is(types), 'Invalid argument `types` = `%s` supplied to `tuple` combinator', types); | ||
@@ -530,5 +542,5 @@ var len = types.length; | ||
// mouse over the `name` variable to see what's wrong | ||
assert(maybe(Str).is(name), 'Invalid argument `name` supplied to `tuple()`'); | ||
assert(maybe(Str).is(name), 'Invalid argument `name` = `%s` supplied to `tuple` combinator', name); | ||
name = name || format('tuple([%s])', types.map(getName).join(', ')); | ||
name = name || format('[%s]', types.map(getName).join(', ')); | ||
@@ -539,3 +551,3 @@ function Tuple(value, mut) { | ||
// mouse over the `value`, `name` and `len` variables to see what's wrong | ||
assert(Arr.is(value) && value.length === len, 'Invalid `%s` supplied to `%s`, expected an `Arr` of length `%s`', value, name, len); | ||
assert(Arr.is(value) && value.length === len, 'Invalid argument `value` = `%s` supplied to tuple type `%s`, expected an `Arr` of length `%s`', value, name, len); | ||
@@ -593,17 +605,14 @@ var frozen = (mut !== true); | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a type | ||
assert(Type.is(type), 'Invalid argument `type` supplied to `subtype()`'); | ||
assert(Type.is(type), 'Invalid argument `type` = `%s` supplied to `subtype` combinator', type); | ||
// DEBUG HINT: if the debugger stops here, the second argument is not a function | ||
assert(Func.is(predicate), 'Invalid argument `predicate` supplied to `subtype()`'); | ||
assert(Func.is(predicate), 'Invalid argument `predicate` = `%s` supplied to `subtype` combinator', predicate); | ||
// DEBUG HINT: if the debugger stops here, the third argument is not a string | ||
// mouse over the `name` variable to see what's wrong | ||
assert(maybe(Str).is(name), 'Invalid argument `name` supplied to `subtype()`'); | ||
assert(maybe(Str).is(name), 'Invalid argument `name` = `%s` supplied to `subtype` combinator', name); | ||
// DEBUG HINT: always give a name to a type, the debug will be easier | ||
name = name || format('subtype(%s)', getName(type)); | ||
name = name || format('{%s | %s}', getName(type), getFunctionName(predicate)); | ||
// cache expected value | ||
var expected = predicate.__doc__ || format('insert a valid value for %s', predicate.name || 'the subtype'); | ||
function Subtype(value, mut) { | ||
@@ -619,3 +628,3 @@ | ||
// but the predicate returns `false` | ||
assert(predicate(x), 'Invalid `%s` supplied to `%s`, %s', value, name, expected); | ||
assert(predicate(x), 'Invalid argument `value` = `%s` supplied to subtype type `%s`', value, name); | ||
return x; | ||
@@ -647,10 +656,10 @@ } | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a type | ||
assert(Type.is(type), 'Invalid argument `type` supplied to `list()`'); | ||
assert(Type.is(type), 'Invalid argument `type` = `%s` supplied to `list` combinator', type); | ||
// DEBUG HINT: if the debugger stops here, the third argument is not a string | ||
// mouse over the `name` variable to see what's wrong | ||
assert(maybe(Str).is(name), 'Invalid argument `name` supplied to `list()`'); | ||
assert(maybe(Str).is(name), 'Invalid argument `name` = `%s` supplied to `list` combinator', name); | ||
// DEBUG HINT: always give a name to a type, the debug will be easier | ||
name = name || format('list(%s)', getName(type)); | ||
name = name || format('Array<%s>', getName(type)); | ||
@@ -663,3 +672,3 @@ function List(value, mut) { | ||
// mouse over the `value` and `name` variables to see what's wrong | ||
assert(Arr.is(value), 'Invalid `%s` supplied to `%s`, expected an `Arr`', value, name); | ||
assert(Arr.is(value), 'Invalid argument `value` = `%s` supplied to list type `%s`', value, name); | ||
@@ -713,13 +722,13 @@ var frozen = (mut !== true); | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a type | ||
assert(Type.is(domain), 'Invalid argument `domain` supplied to `dict()`'); | ||
assert(Type.is(domain), 'Invalid argument `domain` = `%s` supplied to `dict` combinator', domain); | ||
// DEBUG HINT: if the debugger stops here, the second argument is not a type | ||
assert(Type.is(codomain), 'Invalid argument `codomain` supplied to `dict()`'); | ||
assert(Type.is(codomain), 'Invalid argument `codomain` = `%s` supplied to `dict` combinator', codomain); | ||
// DEBUG HINT: if the debugger stops here, the third argument is not a string | ||
// mouse over the `name` variable to see what's wrong | ||
assert(maybe(Str).is(name), 'Invalid argument `name` supplied to `dict()`'); | ||
assert(maybe(Str).is(name), 'Invalid argument `name` = `%s` supplied to `dict` combinator', name); | ||
// DEBUG HINT: always give a name to a type, the debug will be easier | ||
name = name || format('dict(%s, %s)', getName(domain), getName(codomain)); | ||
name = name || format('{[key:%s]: %s}', getName(domain), getName(codomain)); | ||
@@ -730,3 +739,3 @@ function Dict(value, mut) { | ||
// mouse over the `value` and `name` variables to see what's wrong | ||
assert(Obj.is(value), 'Invalid `%s` supplied to `%s`, expected an `Obj`', value, name); | ||
assert(Obj.is(value), 'Invalid argument `value` = `%s` supplied to dict type `%s`', value, name); | ||
@@ -795,9 +804,13 @@ var frozen = (mut !== true); | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a list of types | ||
assert(list(Type).is(domain), 'Invalid argument `domain` supplied to `func()`'); | ||
assert(list(Type).is(domain), 'Invalid argument `domain` = `%s` supplied to `func` combinator', domain); | ||
// DEBUG HINT: if the debugger stops here, the second argument is not a type | ||
assert(Type.is(codomain), 'Invalid argument `codomain` supplied to `func()`'); | ||
assert(Type.is(codomain), 'Invalid argument `codomain` = `%s` supplied to `func` combinator', codomain); | ||
// DEBUG HINT: if the debugger stops here, the third argument is not a string | ||
// mouse over the `name` variable to see what's wrong | ||
assert(maybe(Str).is(name), 'Invalid argument `name` = `%s` supplied to `func` combinator', name); | ||
// DEBUG HINT: always give a name to a type, the debug will be easier | ||
name = name || format('func([%s], %s)', domain.map(getName).join(', '), getName(codomain)); | ||
name = name || format('(%s) -> %s', domain.map(getName).join(', '), getName(codomain)); | ||
@@ -816,3 +829,3 @@ // cache the domain length | ||
// mouse over the `value` and `name` variables to see what's wrong | ||
assert(Func.is(value), 'Invalid `%s` supplied to `%s`', value, name); | ||
assert(Func.is(value), 'Invalid argument `value` = `%s` supplied to func type `%s`', value, name); | ||
@@ -902,6 +915,7 @@ return value; | ||
util: { | ||
mixin: mixin, | ||
format: format, | ||
getKind: getKind, | ||
getFunctionName: getFunctionName, | ||
getName: getName, | ||
getKind: getKind, | ||
mixin: mixin, | ||
slice: slice, | ||
@@ -929,3 +943,3 @@ shallowCopy: shallowCopy, | ||
irriducible: irriducible, | ||
irreducible: irreducible, | ||
struct: struct, | ||
@@ -932,0 +946,0 @@ enums: enums, |
{ | ||
"name": "tcomb", | ||
"version": "0.3.6", | ||
"version": "0.4.0", | ||
"description": "Pragmatic runtime type checking for JavaScript", | ||
"main": "index.js", | ||
"scripts": { | ||
"cover": "istanbul cover _mocha -- --ui bdd -R dot", | ||
"compile-browser-tests": "watchify ./test/test.js -o ./test/browser -v" | ||
"cover": "istanbul cover _mocha -- --ui bdd -R dot" | ||
}, | ||
@@ -29,4 +28,3 @@ "repository": { | ||
"jshint-stylish": "^0.4.0", | ||
"mocha": "^1.21.4", | ||
"react": "*" | ||
"mocha": "^1.21.4" | ||
}, | ||
@@ -33,0 +31,0 @@ "tags": [ |
761
README.md
@@ -1,26 +0,17 @@ | ||
> "Si vis pacem, para bellum" (Vegetius 5th century) | ||
tcomb is a library for Node.js and the browser which allows you to **check the types** of | ||
JavaScript values at runtime with a simple syntax. It's great for **Domain Driven Design**, | ||
for testing and for adding safety to your internal code. | ||
JavaScript values at runtime with a simple syntax. It's great for **Domain Driven Design** | ||
and for adding safety to your internal code. | ||
# The Idea | ||
# Site and documentation | ||
tcomb is based on set theory. | ||
What's a type? In tcomb a type is a function `T` such that | ||
[https://gcanti.github.io/tcomb](https://gcanti.github.io/tcomb) | ||
1. `T` has signature `T(value, [mut])` where `value` depends on the nature of `T` and the optional boolean `mut` makes the instance mutable (default `false`) | ||
2. `T` is idempotent: `T(T(value, mut), mut) === T(value, mut)` | ||
3. `T` owns a static function `T.is(x)` returning `true` if `x` is an instance of `T` | ||
# Features | ||
**Note**: 2. implies that `T` can be used as a default JSON decoder | ||
- write complex domain models in a breeze and with a small code footprint | ||
- easy debugging | ||
- instances are immutables by default | ||
- encodes/decodes domain models to/from JSON for free | ||
- **type reflection at runtime** | ||
# Articles on tcomb | ||
- [JavaScript, Types and Sets Part 1](http://gcanti.github.io/2014/09/29/javascript-types-and-sets.html) | ||
- [JavaScript, Types and Sets Part 2](https://gcanti.github.io/2014/10/07/javascript-types-and-sets-part-II.html) | ||
- [What if your domain model could validate the UI for free?](http://gcanti.github.io/2014/08/12/what-if-your-domain-model-could-validate-the-ui-for-free.html) | ||
- [JSON Deserialization Into An Object Model](http://gcanti.github.io/2014/09/12/json-deserialization-into-an-object-model.html) | ||
- [JSON API Validation In Node.js](http://gcanti.github.io/2014/09/15/json-api-validation-in-node.html) | ||
# Contributors | ||
@@ -31,736 +22,4 @@ | ||
# Contents | ||
- [Features](#features) | ||
- [Quick Examples](#quick-examples) | ||
- [Setup](#setup) | ||
- [Requirements](#requirements) | ||
- [Tests](#tests) | ||
- [Api](#api) | ||
- [options](#options) | ||
- [options.onFail](#optionsonfail) | ||
- [assert](#assert) | ||
- [structs](#structs) | ||
- [unions](#unions) | ||
- [maybe](#maybe) | ||
- [enums](#enums) | ||
- [subtypes](#subtypes) | ||
- [lists](#lists) | ||
- [dicts](#dicts) | ||
- [built-in (immutable) updates](#updates) | ||
- [functions](#functions) | ||
- [sweet.js macros (experimental)](#macros) | ||
# Features | ||
- **write complex domain models** in a breeze and with small code footprint | ||
- easy debugging | ||
- instances are immutables by default | ||
- encode/decode of domain models to/from JSON for free | ||
The library provides a built-in `assert` function, if an assert fails the **debugger kicks in** | ||
so you can inspect the stack and quickly find out what's wrong. | ||
You can handle: | ||
**JavaScript native types** | ||
- Nil: `null` and `undefined` | ||
- Str: strings | ||
- Num: numbers | ||
- Bool: booleans | ||
- Arr: arrays | ||
- Obj: plain objects | ||
- Func: functions | ||
- Err: errors | ||
- Re: regular expressions | ||
- Dat: dates | ||
- Any: * | ||
**type combinators** (build new types from those already defined) | ||
- struct (i.e. classes) | ||
- union | ||
- maybe | ||
- enums | ||
- tuple | ||
- subtype | ||
- list | ||
- dict | ||
- function type | ||
# Quick Examples | ||
Let's build a product model | ||
```js | ||
var Product = struct({ | ||
name: Str, // required string | ||
desc: maybe(Str), // optional string, can be null | ||
home: Url, // a subtype of a string | ||
shippings: list(Str), // a list of shipping methods | ||
category: Category, // enum, one of [audio, video] | ||
price: Price, // a price (dollars) OR in another currency | ||
size: tuple([Num, Num]), // width x height | ||
warranty: dict(Str, Num) // a dictionary country -> covered years | ||
}); | ||
var Url = subtype(Str, function (s) { | ||
return s.indexOf('http://') === 0; | ||
}); | ||
var Category = enums.of('audio video'); | ||
var ForeignPrice = struct({ currency: Str, amount: Num }); | ||
var Price = union([Num, ForeignPrice]); | ||
Price.dispatch = function (x) { | ||
return Num.is(x) ? Num : ForeignPrice; | ||
}; | ||
// JSON of a product | ||
var json = { | ||
name: 'iPod', | ||
desc: 'Engineered for maximum funness.', | ||
home: 'http://www.apple.com/ipod/', | ||
shippings: ['Same Day', 'Next Businness Day'], | ||
category: 'audio', | ||
price: {currency: 'EUR', amount: 100}, | ||
size: [2.4, 4.1], | ||
warranty: { | ||
US: 2, | ||
IT: 1 | ||
} | ||
}; | ||
// get an immutable instance, `new` is optional | ||
var ipod = Product(json); | ||
``` | ||
You have existing code and you want to add safety | ||
```js | ||
// your code: plain old JavaScript class | ||
function Point (x, y) { | ||
this.x = x; | ||
this.y = y; | ||
} | ||
var p = new Point(1, 'a'); // silent error | ||
``` | ||
in order to "tcombify" your code you can simply add some asserts | ||
```js | ||
function Point (x, y) { | ||
assert(Num.is(x)); | ||
assert(Num.is(y)); | ||
this.x = x; | ||
this.y = y; | ||
} | ||
var p = new Point(1, 'a'); // => fail! debugger kicks in | ||
``` | ||
# Setup | ||
Node | ||
npm install tcomb | ||
Browser | ||
bower install tcomb | ||
or download the `tcomb.min.js` file. | ||
# Requirements | ||
This library uses a few ES5 methods, you can use `es5-shim`, `es5-sham` and `json2` to support old browsers | ||
# Tests | ||
Run `mocha` or `npm test` in the project root. | ||
# Api | ||
## options | ||
### options.onFail | ||
In production envs you don't want to leak failures to the user | ||
```js | ||
// override onFail hook | ||
options.onFail = function (message) { | ||
try { | ||
// capture stack trace | ||
throw new Error(message); | ||
} catch (e) { | ||
// use you favourite JavaScript error logging service | ||
console.log(e.stack); | ||
} | ||
}; | ||
``` | ||
## assert | ||
```js | ||
assert(guard, [message], [values...]); | ||
``` | ||
If `guard !== true` the debugger kicks in. | ||
- `guard` boolean condition | ||
- `message` optional string useful for debugging, formatted with values like [util.format in Node](http://nodejs.org/api/util.html#util_util_format_format) | ||
Example | ||
```js | ||
assert(1 === 2); // throws 'assert(): failed' | ||
assert(1 === 2, 'error!'); // throws 'error!' | ||
assert(1 === 2, 'error: %s !== %s', 1, 2); // throws 'error: 1 !== 2' | ||
``` | ||
To customize failure behaviour, see `options.onFail`. | ||
## structs | ||
```js | ||
struct(props, [name]) | ||
``` | ||
Defines a struct like type. | ||
- `props` hash name -> type | ||
- `name` optional string useful for debugging | ||
Example | ||
```js | ||
"use strict"; | ||
// defines a struct with two numerical props | ||
var Point = struct({ | ||
x: Num, | ||
y: Num | ||
}); | ||
// methods are defined as usual | ||
Point.prototype.toString = function () { | ||
return '(' + this.x + ', ' + this.y + ')'; | ||
}; | ||
// costructor usage, p is immutable | ||
var p = Point({x: 1, y: 2}); | ||
p.x = 2; // => TypeError | ||
p = Point({x: 1, y: 2}, true); // now p is mutable | ||
p.x = 2; // ok | ||
``` | ||
### is(x) | ||
Returns `true` if `x` is an instance of the struct. | ||
```js | ||
Point.is(p); // => true | ||
``` | ||
### extend(props, [name]) | ||
Returns a new type with the additional specified `props` | ||
```js | ||
var Point = struct({ | ||
x: Num, | ||
y: Num | ||
}, 'Point'); | ||
var Point3D = Point.extend({z: Num}, 'Point3D'); // composition, not inheritance | ||
var p = new Point3D({x: 1, y: 2, z: 3}); | ||
// `props` can be an array of new props | ||
var Point4D = Point.extend([{z: Num}, {time: Num}], 'Point4D'); | ||
``` | ||
## unions | ||
```js | ||
union(types, [name]) | ||
``` | ||
Defines a union of types. | ||
- `types` array of types | ||
- `name` optional string useful for debugging | ||
Example | ||
```js | ||
var Circle = struct({ | ||
center: Point, | ||
radius: Num | ||
}); | ||
var Rectangle = struct({ | ||
bl: Point, // bottom left vertex | ||
tr: Point // top right vertex | ||
}); | ||
var Shape = union([ | ||
Circle, | ||
Rectangle | ||
]); | ||
// you must implement the dispatch() function in order to use `Shape` as a contructor | ||
Shape.dispatch = function (x) { | ||
return x.hasOwnProperty('center') ? Circle : Rectangle; | ||
}; | ||
var circle = Shape({center: {x: 1, y: 0}, radius: 10}); | ||
var rectangle = Shape({bl: {x: 0, y: 0}, tr: {x: 1, y: 1}}); | ||
``` | ||
### is(x) | ||
Returns `true` if `x` belongs to the union. | ||
```js | ||
Shape.is(new Circle({center: p, radius: 10})); // => true | ||
``` | ||
## maybe | ||
```js | ||
maybe(type, [name]) | ||
``` | ||
Same as `union([Nil, type])`. | ||
```js | ||
// the value of a radio input where null = no selection | ||
var Radio = maybe(Str); | ||
Radio.is('a'); // => true | ||
Radio.is(null); // => true | ||
Radio.is(1); // => false | ||
``` | ||
## enums | ||
```js | ||
enums(map, [name]) | ||
``` | ||
Defines an enum of strings. | ||
- `map` hash enum -> value | ||
- `name` optional string useful for debugging | ||
Example | ||
```js | ||
var Direction = enums({ | ||
North: 'North', | ||
East: 'East', | ||
South: 'South', | ||
West: 'West' | ||
}); | ||
``` | ||
### is(x) | ||
Returns `true` if `x` belongs to the enum. | ||
```js | ||
Direction.is('North'); // => true | ||
``` | ||
### enums.of(keys, [name]) | ||
Returns an enums of an array of keys, useful when you don't mind to define | ||
custom values for the enums. | ||
- `keys` array (or string) of keys | ||
- `name` optional string useful for debugging | ||
Example | ||
```js | ||
// result is the same as the main example | ||
var Direction = enums.of(['North', 'East', 'South', 'West']); | ||
// or.. | ||
Direction = enums.of('North East South West'); | ||
``` | ||
## tuples | ||
```js | ||
tuple(types, [name]) | ||
``` | ||
Defines a tuple whose coordinates have the specified types. | ||
- `types` array of coordinates types | ||
- `name` optional string useful for debugging | ||
Example | ||
```js | ||
var Area = tuple([Num, Num]); | ||
// constructor usage, area is immutable | ||
var area = Area([1, 2]); | ||
``` | ||
0-tuples and 1-tuples are also supported | ||
```js | ||
var Nothing = tuple([]); | ||
var JustNum = tuple([Num]); | ||
``` | ||
### is(x) | ||
Returns `true` if `x` belongs to the tuple. | ||
```js | ||
Area.is([1, 2]); // => true | ||
Area.is([1, 'a']); // => false, the second element is not a Num | ||
Area.is([1, 2, 3]); // => false, too many elements | ||
``` | ||
## subtypes | ||
```js | ||
subtype(type, predicate, [name]) | ||
``` | ||
Defines a subtype of an existing type. | ||
- `type` the supertype | ||
- `predicate` a function with signature `(x) -> boolean` | ||
- `name` optional string useful for debugging | ||
Example | ||
```js | ||
// points of the first quadrant | ||
var Q1Point = subtype(Point, function (p) { | ||
return p.x >= 0 && p.y >= 0; | ||
}); | ||
// costructor usage, p is immutable | ||
var p = Q1Point({x: 1, y: 2}); | ||
p = Q1Point({x: -1, y: -2}); // => fail! | ||
``` | ||
**Note**. You can't add methods to `Q1Point` `prototype`, add them to the supertype `prototype` if needed. | ||
### is(x) | ||
Returns `true` if `x` belongs to the subtype. | ||
```js | ||
var Int = subtype(Num, function (n) { | ||
return n === parseInt(n, 10); | ||
}); | ||
Int.is(2); // => true | ||
Int.is(1.1); // => false | ||
``` | ||
## lists | ||
```js | ||
list(type, [name]) | ||
``` | ||
Defines an array where all the elements are of type `T`. | ||
- `type` type of all the elements | ||
- `name` optional string useful for debugging | ||
Example | ||
```js | ||
var Path = list(Point); | ||
// costructor usage, path is immutable | ||
var path = Path([ | ||
{x: 0, y: 0}, | ||
{x: 1, y: 1} | ||
]); | ||
``` | ||
### is(x) | ||
Returns `true` if `x` belongs to the list. | ||
```js | ||
var p1 = Point({x: 0, y: 0}); | ||
var p2 = Point({x: 1, y: 2}); | ||
Path.is([p1, p2]); // => true | ||
``` | ||
## dicts | ||
```js | ||
dict(domain, codomain, [name]) | ||
``` | ||
Defines a dictionary domain -> codomain. | ||
- `domain` the type of the keys | ||
- `codomain` the type of the values | ||
- `name` optional string useful for debugging | ||
Example | ||
```js | ||
// defines a dictionary of numbers | ||
var Tel = dict(Str, Num); | ||
``` | ||
### is(x) | ||
Returns `true` if `x` is an instance of the dict. | ||
```js | ||
Tel.is({'jack': 4098, 'sape': 4139}); // => true | ||
``` | ||
## Updates | ||
```js | ||
Type.update(instance, spec) | ||
``` | ||
The following commands are compatible with the [Facebook Immutability Helpers](http://facebook.github.io/react/docs/update.html). | ||
- $push | ||
- $unshift | ||
- $splice | ||
- $set | ||
- $apply | ||
- $merge | ||
### Removing a value form a dict | ||
`{$remove: keys}` | ||
```js | ||
var Type = dict(Str, Num); | ||
var instance = Type({a: 1, b: 2}); | ||
var updated = Type.update(instance, {$remove: ['a']}); // => {b: 2} | ||
``` | ||
### Swapping two list elements | ||
`{$swap: {from: number, to: number}}` | ||
```js | ||
var Type = list(Num); | ||
var instance = Type([1, 2, 3, 4]); | ||
var updated = Type.update(instance, {'$swap': {from: 1, to: 2}}); // => [1, 3, 2, 4] | ||
``` | ||
### Adding other commands | ||
You can add your custom commands updating the `util.update.commands` hash. | ||
## functions | ||
Typed functions may be defined like this: | ||
```js | ||
// add takes two `Num`s and returns a `Num` | ||
var add = func([Num, Num], Num) | ||
.of(function (x, y) { return x + y; }); | ||
``` | ||
And used like this: | ||
```js | ||
add("Hello", 2); // Raises error: Invalid `Hello` supplied to `Num` | ||
add("Hello"); // Raises error: Invalid `Hello` supplied to `Num` | ||
add(1, 2); // Returns: 3 | ||
add(1)(2); // Returns: 3 | ||
``` | ||
### func(A, B, [name]) | ||
```js | ||
func(Domain, Codomain, name) | ||
``` | ||
Returns a function type whose functions have their domain and codomain specified and constrained. | ||
- `Domain`: the type of the function's argument (or `list` of types of the function's arguments) | ||
- `Codomain`: the type of the function's return value | ||
- `name`: optional string useful for debugging | ||
`func` can be used to define function types using native types: | ||
```js | ||
// An `A` takes a `Str` and returns an `Num` | ||
var A = func(Str, Num); | ||
``` | ||
The domain and codomain can also be specified using types from any combinator including `func`: | ||
```js | ||
// A `B` takes a `Func` (which takes a `Str` and returns a `Num`) and returns a `Str`. | ||
var B = func(func(Str, Num), Str); | ||
// An `ExcitedStr` is a `Str` containing an exclamation mark | ||
var ExcitedStr = subtype(Str, function (s) { return s.indexOf('!') !== -1; }, 'ExcitedStr'); | ||
// An `Exciter` takes a `Str` and returns an `ExcitedStr` | ||
var Exciter = func(Str, ExcitedStr); | ||
``` | ||
Additionally the domain can be expressed as a `list` of types: | ||
```js | ||
// A `C` takes an `A`, a `B` and a `Str` and returns a `Num` | ||
var C = func([A, B, Str], Num); | ||
``` | ||
### .of(f) | ||
```js | ||
func(A, B).of(f); | ||
``` | ||
Returns a function where the domain and codomain are typechecked against the function type. | ||
If the function is passed values which are outside of the domain or returns values which are outside of the codomain it will raise an error: | ||
```js | ||
var simpleQuestionator = Exciter.of(function (s) { return s + '?'; }); | ||
var simpleExciter = Exciter.of(function (s) { return s + '!'; }); | ||
// Raises error: | ||
// Invalid `Hello?` supplied to `ExcitedStr`, insert a valid value for the subtype | ||
simpleQuestionator('Hello'); | ||
// Raises error: Invalid `1` supplied to `Str` | ||
simpleExciter(1); | ||
// Returns: 'Hello!' | ||
simpleExciter('Hello'); | ||
``` | ||
The returned function may also be partially applied: | ||
```js | ||
// We can reasonably suggest that add has the following type signature | ||
// add : Num -> Num -> Num | ||
var add = func([Num, Num], Num) | ||
.of(function (x, y) { return x + y }); | ||
var addHello = add("Hello"); // As this raises: "Error: Invalid `Hello` supplied to `Num`" | ||
var add2 = add(2); | ||
add2(1); // And this returns: 3 | ||
``` | ||
### .is(x) | ||
```js | ||
func(A, B).is(x); | ||
``` | ||
Returns true if x belongs to the type. | ||
```js | ||
Exciter.is(simpleExciter); // Returns: true | ||
Exciter.is(simpleQuestionator); // Returns: true | ||
var id = function (x) { return x; }; | ||
func([Num, Num], Num).is(func([Num, Num], Num).of(id)); // Returns: true | ||
func([Num, Num], Num).is(func(Num, Num).of(id)); // Returns: false | ||
``` | ||
### Rules | ||
1. Typed functions' domains are checked when they are called | ||
2. Typed functions' codomains are checked when they return | ||
3. The domain and codomain of a typed function's type is checked when the typed function is passed to a function type (such as when used as an argument in another typed function). | ||
# Macros (experimental) | ||
I added a `tcomb.sjs` file containing some [sweet.js](http://sweetjs.org/) macros, here some examples: | ||
```js | ||
// structs | ||
type Point struct { | ||
x: Num, | ||
y: Num | ||
} | ||
// unions | ||
type Shape union { | ||
Circle, | ||
Rectangle | ||
} | ||
// tuples | ||
type Coords tuple { | ||
Num, | ||
Num | ||
} | ||
// enums | ||
type Direction enums { | ||
'North', | ||
'East', | ||
'South', | ||
'West' | ||
} | ||
// enums with specified values | ||
type Direction enums { | ||
'North': 0, | ||
'East': 1, | ||
'South': 2, | ||
'West': 3 | ||
} | ||
// subtypes | ||
type Positive subtype<Num> n { | ||
return n > 0; | ||
} | ||
// irriducibles types, like JavaScript primitives | ||
type Irriducible irriducible x { | ||
return typeof x === 'function'; | ||
} | ||
// maybe | ||
type Maybe maybe<Str> | ||
// lists | ||
type List list<Str> | ||
// dictionaries | ||
type Dict dict<Str> | ||
// functions | ||
fn add (x: Num, y: Num) { | ||
return x + y; | ||
} | ||
// functions with checked return value | ||
fn add (x: Num, y: Num) -> Num { | ||
return x + y; | ||
} | ||
``` | ||
# License | ||
The MIT License (MIT) |
@@ -1,6 +0,6 @@ | ||
// tcomb 0.3.6 | ||
// tcomb 0.4.0 | ||
// https://github.com/gcanti/tcomb | ||
// (c) 2014 Giulio Canti <giulio.canti@gmail.com> | ||
// tcomb may be freely distributed under the MIT license. | ||
!function(a,b){"use strict";"function"==typeof define&&define.amd?define([],b):"object"==typeof exports?module.exports=b():a.t=b()}(this,function(){"use strict";function a(a){throw v=!0,new Error(a)}function b(a){w.onFail(a)}function c(a){if(a!==!0){var c=x.call(arguments,1),d=c[0]?e.apply(null,c):"assert failed";b(d)}}function d(a,b,d){if(z.is(b))return a;for(var e in b)b.hasOwnProperty(e)&&(d!==!0&&c(!a.hasOwnProperty(e),"cannot overwrite property %s",e),a[e]=b[e]);return a}function e(){function a(a,f){if("%%"===a)return"%";if(d>=c)return a;var g=e.formatters[f];return g?g(b[d++]):a}var b=x.call(arguments),c=b.length,d=1,f=b[0],g=f.replace(/%([a-z%])/g,a);return c>d&&(g+=" "+b.slice(d).join(" ")),g}function f(a,b){return"function"==typeof b?e("Func",b.name):b}function g(a){return c(J.is(a),"Invalid argument `type` of value `%j` supplied to `getName()`, expected a type.",a),a.meta.name}function h(a){return c(J.is(a),"Invalid argument `type` of value `%j` supplied to `geKind()`, expected a type.",a),a.meta.kind}function i(a,b){c(!(a instanceof b),"Operator `new` is forbidden for `%s`",g(b))}function j(a){return D.is(a)?a.concat():E.is(a)?d({},a):a}function k(a,b){c(E.is(b));var d=j(a);for(var e in b)if(b.hasOwnProperty(e)){if(k.commands.hasOwnProperty(e))return c(1===Object.keys(b).length),k.commands[e](b[e],d);d[e]=k(d[e],b[e])}return d}function l(a,b){function d(e){return i(this,d),c(b(e),"Invalid `%s` supplied to `%s`",e,a),e}return c("string"==typeof a,"Invalid argument `name` supplied to `irriducible()`"),c("function"==typeof b,"Invalid argument `is` supplied to `irriducible()`"),d.meta={kind:"irriducible",name:a},d.displayName=a,d.is=b,d}function m(a,b){function e(d,f){if(e.is(d))return d;if(c(E.is(d),"Invalid `%s` supplied to `%s`, expected an `Obj`",d,b),!(this instanceof e))return new e(d,f);for(var g in a)if(a.hasOwnProperty(g)){var h=a[g],i=d[g];this[g]=h(i,f)}f!==!0&&Object.freeze(this)}return c(t(A,J).is(a),"Invalid argument `props` supplied to `struct()`"),c(o(A).is(b),"Invalid argument `name` supplied to `struct()`"),b=b||"struct",e.meta={kind:"struct",props:a,name:b},e.displayName=b,e.is=function(a){return a instanceof e},e.update=function(a,b,c){return new e(k(a,b,c))},e.extend=function(b,c){var f=m([a].concat(b).reduce(d,{}),c);return d(f.prototype,e.prototype),f},e}function n(a,b){function d(a,e){i(this,d),c(F.is(d.dispatch),"unimplemented %s.dispatch()",b);var f=d.dispatch(a);return c(J.is(f),"%s.dispatch() returns no type",b),f(a,e)}c(s(J).is(a),"Invalid argument `types` supplied to `union()`");var f=a.length;return c(f>=2,"Invalid argument `types` supplied to `union()`"),c(o(A).is(b),"Invalid argument `name` supplied to `union()`"),b=b||e("union([%s])",a.map(g).join(", ")),d.meta={kind:"union",types:a,name:b},d.displayName=b,d.is=function(b){return a.some(function(a){return a.is(b)})},d.dispatch=function(b){for(var c=0,d=a.length;d>c;c++)if(a[c].is(b))return a[c]},d}function o(a,b){function d(b,c){return i(this,d),z.is(b)?null:a(b,c)}return c(J.is(a),"Invalid argument `type` supplied to `maybe()`"),"maybe"===h(a)?a:(c(z.is(b)||A.is(b),"Invalid argument `name` supplied to `maybe()`"),b=b||e("maybe(%s)",g(a)),d.meta={kind:"maybe",type:a,name:b},d.displayName=b,d.is=function(b){return z.is(b)||a.is(b)},d)}function p(a,b){function d(a){return i(this,d),c(d.is(a),"Invalid `%s` supplied to `%s`, expected one of %j",a,b,e),a}c(E.is(a),"Invalid argument `map` supplied to `enums()`"),c(o(A).is(b),"Invalid argument `name` supplied to `enums()`"),b=b||"enums";var e=Object.keys(a);return d.meta={kind:"enums",map:a,name:b},d.displayName=b,d.is=function(b){return A.is(b)&&a.hasOwnProperty(b)},d}function q(a,b){function d(e,g){c(D.is(e)&&e.length===f,"Invalid `%s` supplied to `%s`, expected an `Arr` of length `%s`",e,b,f);var h=g!==!0;if(d.isTuple(e)&&Object.isFrozen(e)===h)return e;for(var i=[],j=0;f>j;j++){var k=a[j],l=e[j];i.push(k(l,g))}return h&&Object.freeze(i),i}c(s(J).is(a),"Invalid argument `types` supplied to `tuple()`");var f=a.length;return c(o(A).is(b),"Invalid argument `name` supplied to `tuple()`"),b=b||e("tuple([%s])",a.map(g).join(", ")),d.meta={kind:"tuple",types:a,length:f,name:b},d.displayName=b,d.isTuple=function(b){return a.every(function(a,c){return a.is(b[c])})},d.is=function(a){return D.is(a)&&a.length===f&&d.isTuple(a)},d.update=function(a,b,c){return d(k(a,b,c))},d}function r(a,b,d){function f(e,g){i(this,f);var j=a(e,g);return c(b(j),"Invalid `%s` supplied to `%s`, %s",e,d,h),j}c(J.is(a),"Invalid argument `type` supplied to `subtype()`"),c(F.is(b),"Invalid argument `predicate` supplied to `subtype()`"),c(o(A).is(d),"Invalid argument `name` supplied to `subtype()`"),d=d||e("subtype(%s)",g(a));var h=b.__doc__||e("insert a valid value for %s",b.name||"the subtype");return f.meta={kind:"subtype",type:a,predicate:b,name:d},f.displayName=d,f.is=function(c){return a.is(c)&&b(c)},f.update=function(a,b,c){return f(k(a,b,c))},f}function s(a,b){function d(e,f){c(D.is(e),"Invalid `%s` supplied to `%s`, expected an `Arr`",e,b);var g=f!==!0;if(d.isList(e)&&Object.isFrozen(e)===g)return e;for(var h=[],i=0,j=e.length;j>i;i++){var k=e[i];h.push(a(k,f))}return g&&Object.freeze(h),h}return c(J.is(a),"Invalid argument `type` supplied to `list()`"),c(o(A).is(b),"Invalid argument `name` supplied to `list()`"),b=b||e("list(%s)",g(a)),d.meta={kind:"list",type:a,name:b},d.displayName=b,d.isList=function(b){return b.every(a.is)},d.is=function(a){return D.is(a)&&d.isList(a)},d.update=function(a,b,c){return d(k(a,b,c))},d}function t(a,b,d){function f(e,g){c(E.is(e),"Invalid `%s` supplied to `%s`, expected an `Obj`",e,d);var h=g!==!0;if(f.isDict(e)&&Object.isFrozen(e)===h)return e;var i={};for(var j in e)if(e.hasOwnProperty(j)){j=a(j);var k=e[j];i[j]=b(k,g)}return h&&Object.freeze(i),i}return c(J.is(a),"Invalid argument `domain` supplied to `dict()`"),c(J.is(b),"Invalid argument `codomain` supplied to `dict()`"),c(o(A).is(d),"Invalid argument `name` supplied to `dict()`"),d=d||e("dict(%s, %s)",g(a),g(b)),f.meta={kind:"dict",domain:a,codomain:b,name:d},f.displayName=d,f.isDict=function(c){for(var d in c)if(c.hasOwnProperty(d)&&(!a.is(d)||!b.is(c[d])))return!1;return!0},f.is=function(a){return E.is(a)&&f.isDict(a)},f.update=function(a,b,c){return f(k(a,b,c))},f}function u(a,b,d){function f(a){return u.is(a)||(a=f.of(a)),c(f.is(a),"Invalid `%s` supplied to `%s`",a,d),a}a=D.is(a)?a:[a],c(s(J).is(a),"Invalid argument `domain` supplied to `func()`"),c(J.is(b),"Invalid argument `codomain` supplied to `func()`"),d=d||e("func([%s], %s)",a.map(g).join(", "),g(b));var h=a.length;return f.meta={kind:"func",domain:a,codomain:b,name:d},f.displayName=d,f.is=function(c){return u.is(c)&&c.func.domain.length===a.length&&c.func.domain.every(function(b,c){return b===a[c]})&&c.func.codomain===b},f.of=function(d){function e(){var c=x.call(arguments),e=Math.min(c.length,h);if(c=q(a.slice(0,e))(c),e===h){var f=d.apply(this,c);return f=b(f)}var g=Function.prototype.bind.apply(d,[this].concat(c)),i=u(a.slice(e),b);return i.of(g)}return c("function"==typeof d),f.is(d)?d:(e.func={domain:a,codomain:b,f:d},e)},f}var v=!1,w={onFail:a},x=Array.prototype.slice;e.formatters={s:function(a){return String(a)},j:function(a){try{return JSON.stringify(a,f)}catch(b){return String(a)}}},k.commands={$apply:function(a,b){return c(F.is(a)),a(b)},$push:function(a,b){return c(D.is(a)),c(D.is(b)),b.concat(a)},$remove:function(a,b){c(D.is(a)),c(E.is(b));for(var d=0,e=a.length;e>d;d++)delete b[a[d]];return b},$set:function(a){return a},$splice:function(a,b){return c(s(D).is(a)),c(D.is(b)),a.reduce(function(a,b){return a.splice.apply(a,b),a},b)},$swap:function(a,b){c(E.is(a)),c(B.is(a.from)),c(B.is(a.to)),c(D.is(b));var d=b[a.to];return b[a.to]=b[a.from],b[a.from]=d,b},$unshift:function(a,b){return c(D.is(a)),c(D.is(b)),a.concat(b)},$merge:function(a,b){return d(d({},b),a,!0)}};var y=l("Any",function(){return!0}),z=l("Nil",function(a){return null===a||void 0===a}),A=l("Str",function(a){return"string"==typeof a}),B=l("Num",function(a){return"number"==typeof a&&isFinite(a)&&!isNaN(a)}),C=l("Bool",function(a){return a===!0||a===!1}),D=l("Arr",function(a){return a instanceof Array}),E=l("Obj",function(a){return!z.is(a)&&"object"==typeof a&&!D.is(a)}),F=l("Func",function(a){return"function"==typeof a}),G=l("Err",function(a){return a instanceof Error}),H=l("Re",function(a){return a instanceof RegExp}),I=l("Dat",function(a){return a instanceof Date}),J=l("Type",function(a){return F.is(a)&&E.is(a.meta)});return p.of=function(a,b){a=A.is(a)?a.split(" "):a;var c={};return a.forEach(function(a){c[a]=a}),p(c,b)},u.is=function(a){return F.is(a)&&E.is(a.func)},{util:{mixin:d,format:e,getName:g,getKind:h,slice:x,shallowCopy:j,update:k},options:w,assert:c,fail:b,Any:y,Nil:z,Str:A,Num:B,Bool:C,Arr:D,Obj:E,Func:F,Err:G,Re:H,Dat:I,Type:J,irriducible:l,struct:m,enums:p,union:n,maybe:o,tuple:q,subtype:r,list:s,dict:t,func:u}}); | ||
!function(a,b){"use strict";"function"==typeof define&&define.amd?define([],b):"object"==typeof exports?module.exports=b():a.t=b()}(this,function(){"use strict";function a(a){throw w=!0,new Error(a)}function b(a){x.onFail(a)}function c(a){if(a!==!0){var c=y.call(arguments,1),d=c[0]?e.apply(null,c):"assert failed";b(d)}}function d(a,b,d){if(A.is(b))return a;for(var e in b)b.hasOwnProperty(e)&&(d!==!0&&c(!a.hasOwnProperty(e),"Cannot overwrite property %s",e),a[e]=b[e]);return a}function e(){function a(a,f){if("%%"===a)return"%";if(d>=c)return a;var g=e.formatters[f];return g?g(b[d++]):a}var b=y.call(arguments),c=b.length,d=1,f=b[0],g=f.replace(/%([a-z%])/g,a);return c>d&&(g+=" "+b.slice(d).join(" ")),g}function f(a,b){return"function"==typeof b?e("Func",b.name):b}function g(a){return c(K.is(a),"Invalid argument `type` = `%s` supplied to `getName()`",a),a.meta.name}function h(a){return c("function"==typeof a,"Invalid argument `f` = `%s` supplied to `getFunctionName()`",a),a.displayName||a.name||e("<function%s>",a.length)}function i(a){return c(K.is(a),"Invalid argument `type` = `%s` supplied to `geKind()`",a),a.meta.kind}function j(a,b){c(!(a instanceof b),"Operator `new` is forbidden for type `%s`",g(b))}function k(a){return E.is(a)?a.concat():F.is(a)?d({},a):a}function l(a,b){c(F.is(b));var d=k(a);for(var e in b)if(b.hasOwnProperty(e)){if(l.commands.hasOwnProperty(e))return c(1===Object.keys(b).length),l.commands[e](b[e],d);d[e]=l(d[e],b[e])}return d}function m(a,b){function d(e){return j(this,d),c(b(e),"Invalid argument `value` = `%s` supplied to irreducible type `%s`",e,a),e}return c("string"==typeof a,"Invalid argument `name` = `%s` supplied to `irreducible()`",a),c("function"==typeof b,"Invalid argument `is` = `%s` supplied to `irreducible()`",b),d.meta={kind:"irreducible",name:a},d.displayName=a,d.is=b,d}function n(a,b){function f(d,e){if(f.is(d))return d;if(c(F.is(d),"Invalid argument `value` = `%s` supplied to struct type `%s`",d,b),!(this instanceof f))return new f(d,e);for(var g in a)if(a.hasOwnProperty(g)){var h=a[g],i=d[g];this[g]=h(i,e)}e!==!0&&Object.freeze(this)}return c(u(B,K).is(a),"Invalid argument `props` = `%s` supplied to `struct` combinator",a),c(p(B).is(b),"Invalid argument `name` = `%s` supplied to `struct` combinator",b),b=b||e("{%s}",Object.keys(a).map(function(b){return e("%s: %s",b,g(a[b]))}).join(", ")),f.meta={kind:"struct",props:a,name:b},f.displayName=b,f.is=function(a){return a instanceof f},f.update=function(a,b,c){return new f(l(a,b,c))},f.extend=function(b,c){b=[].concat(b).map(function(a){return F.is(a)?a:a.meta.props}),b.unshift(a);var e=n(b.reduce(d,{}),c);return d(e.prototype,f.prototype),e},f}function o(a,b){function d(a,e){j(this,d),c(G.is(d.dispatch),"Unimplemented `dispatch()` function for union type `%s`",b);var f=d.dispatch(a);return c(K.is(f),"The `dispatch()` function of union type `%s` returns no type constructor",b),f(a,e)}c(t(K).is(a),"Invalid argument `types` = `%s` supplied to `union` combinator",a);var e=a.length,f=a.map(g).join(" | ");return c(e>=2,"Invalid argument `types` = `%s` supplied to `union` combinator, provide at least two types",f),c(p(B).is(b),"Invalid argument `name` = `%s` supplied to `union` combinator",b),b=b||f,d.meta={kind:"union",types:a,name:b},d.displayName=b,d.is=function(b){return a.some(function(a){return a.is(b)})},d.dispatch=function(b){for(var c=0,d=a.length;d>c;c++)if(a[c].is(b))return a[c]},d}function p(a,b){function d(b,c){return j(this,d),A.is(b)?null:a(b,c)}return c(K.is(a),"Invalid argument `type` = `%s` supplied to `maybe` combinator",a),"maybe"===i(a)||a===z||a===A?a:(c(A.is(b)||B.is(b),"Invalid argument `name` = `%s` supplied to `maybe` combinator",b),b=b||"?"+g(a),d.meta={kind:"maybe",type:a,name:b},d.displayName=b,d.is=function(b){return A.is(b)||a.is(b)},d)}function q(a,b){function d(a){return j(this,d),c(d.is(a),"Invalid argument `value` = `%s` supplied to enums type `%s`, expected one of %j",a,b,e),a}c(F.is(a),"Invalid argument `map` = `%s` supplied to `enums` combinator",a),c(p(B).is(b),"Invalid argument `name` = `%s` supplied to `enums` combinator",b);var e=Object.keys(a);return b=b||e.map(function(a){return JSON.stringify(a)}).join(" | "),d.meta={kind:"enums",map:a,name:b},d.displayName=b,d.is=function(b){return B.is(b)&&a.hasOwnProperty(b)},d}function r(a,b){function d(e,g){c(E.is(e)&&e.length===f,"Invalid argument `value` = `%s` supplied to tuple type `%s`, expected an `Arr` of length `%s`",e,b,f);var h=g!==!0;if(d.isTuple(e)&&Object.isFrozen(e)===h)return e;for(var i=[],j=0;f>j;j++){var k=a[j],l=e[j];i.push(k(l,g))}return h&&Object.freeze(i),i}c(t(K).is(a),"Invalid argument `types` = `%s` supplied to `tuple` combinator",a);var f=a.length;return c(p(B).is(b),"Invalid argument `name` = `%s` supplied to `tuple` combinator",b),b=b||e("[%s]",a.map(g).join(", ")),d.meta={kind:"tuple",types:a,length:f,name:b},d.displayName=b,d.isTuple=function(b){return a.every(function(a,c){return a.is(b[c])})},d.is=function(a){return E.is(a)&&a.length===f&&d.isTuple(a)},d.update=function(a,b,c){return d(l(a,b,c))},d}function s(a,b,d){function f(e,g){j(this,f);var h=a(e,g);return c(b(h),"Invalid argument `value` = `%s` supplied to subtype type `%s`",e,d),h}return c(K.is(a),"Invalid argument `type` = `%s` supplied to `subtype` combinator",a),c(G.is(b),"Invalid argument `predicate` = `%s` supplied to `subtype` combinator",b),c(p(B).is(d),"Invalid argument `name` = `%s` supplied to `subtype` combinator",d),d=d||e("{%s | %s}",g(a),h(b)),f.meta={kind:"subtype",type:a,predicate:b,name:d},f.displayName=d,f.is=function(c){return a.is(c)&&b(c)},f.update=function(a,b,c){return f(l(a,b,c))},f}function t(a,b){function d(e,f){c(E.is(e),"Invalid argument `value` = `%s` supplied to list type `%s`",e,b);var g=f!==!0;if(d.isList(e)&&Object.isFrozen(e)===g)return e;for(var h=[],i=0,j=e.length;j>i;i++){var k=e[i];h.push(a(k,f))}return g&&Object.freeze(h),h}return c(K.is(a),"Invalid argument `type` = `%s` supplied to `list` combinator",a),c(p(B).is(b),"Invalid argument `name` = `%s` supplied to `list` combinator",b),b=b||e("Array<%s>",g(a)),d.meta={kind:"list",type:a,name:b},d.displayName=b,d.isList=function(b){return b.every(a.is)},d.is=function(a){return E.is(a)&&d.isList(a)},d.update=function(a,b,c){return d(l(a,b,c))},d}function u(a,b,d){function f(e,g){c(F.is(e),"Invalid argument `value` = `%s` supplied to dict type `%s`",e,d);var h=g!==!0;if(f.isDict(e)&&Object.isFrozen(e)===h)return e;var i={};for(var j in e)if(e.hasOwnProperty(j)){j=a(j);var k=e[j];i[j]=b(k,g)}return h&&Object.freeze(i),i}return c(K.is(a),"Invalid argument `domain` = `%s` supplied to `dict` combinator",a),c(K.is(b),"Invalid argument `codomain` = `%s` supplied to `dict` combinator",b),c(p(B).is(d),"Invalid argument `name` = `%s` supplied to `dict` combinator",d),d=d||e("{[key:%s]: %s}",g(a),g(b)),f.meta={kind:"dict",domain:a,codomain:b,name:d},f.displayName=d,f.isDict=function(c){for(var d in c)if(c.hasOwnProperty(d)&&(!a.is(d)||!b.is(c[d])))return!1;return!0},f.is=function(a){return F.is(a)&&f.isDict(a)},f.update=function(a,b,c){return f(l(a,b,c))},f}function v(a,b,d){function f(a){return v.is(a)||(a=f.of(a)),c(f.is(a),"Invalid argument `value` = `%s` supplied to func type `%s`",a,d),a}a=E.is(a)?a:[a],c(t(K).is(a),"Invalid argument `domain` = `%s` supplied to `func` combinator",a),c(K.is(b),"Invalid argument `codomain` = `%s` supplied to `func` combinator",b),c(p(B).is(d),"Invalid argument `name` = `%s` supplied to `func` combinator",d),d=d||e("(%s) -> %s",a.map(g).join(", "),g(b));var h=a.length;return f.meta={kind:"func",domain:a,codomain:b,name:d},f.displayName=d,f.is=function(c){return v.is(c)&&c.func.domain.length===a.length&&c.func.domain.every(function(b,c){return b===a[c]})&&c.func.codomain===b},f.of=function(d){function e(){var c=y.call(arguments),e=Math.min(c.length,h);if(c=r(a.slice(0,e))(c),e===h){var f=d.apply(this,c);return f=b(f)}var g=Function.prototype.bind.apply(d,[this].concat(c)),i=v(a.slice(e),b);return i.of(g)}return c("function"==typeof d),f.is(d)?d:(e.func={domain:a,codomain:b,f:d},e)},f}var w=!1,x={onFail:a},y=Array.prototype.slice;e.formatters={s:function(a){return String(a)},j:function(a){try{return JSON.stringify(a,f)}catch(b){return String(a)}}},l.commands={$apply:function(a,b){return c(G.is(a)),a(b)},$push:function(a,b){return c(E.is(a)),c(E.is(b)),b.concat(a)},$remove:function(a,b){c(E.is(a)),c(F.is(b));for(var d=0,e=a.length;e>d;d++)delete b[a[d]];return b},$set:function(a){return a},$splice:function(a,b){return c(t(E).is(a)),c(E.is(b)),a.reduce(function(a,b){return a.splice.apply(a,b),a},b)},$swap:function(a,b){c(F.is(a)),c(C.is(a.from)),c(C.is(a.to)),c(E.is(b));var d=b[a.to];return b[a.to]=b[a.from],b[a.from]=d,b},$unshift:function(a,b){return c(E.is(a)),c(E.is(b)),a.concat(b)},$merge:function(a,b){return d(d({},b),a,!0)}};var z=m("Any",function(){return!0}),A=m("Nil",function(a){return null===a||void 0===a}),B=m("Str",function(a){return"string"==typeof a}),C=m("Num",function(a){return"number"==typeof a&&isFinite(a)&&!isNaN(a)}),D=m("Bool",function(a){return a===!0||a===!1}),E=m("Arr",function(a){return a instanceof Array}),F=m("Obj",function(a){return!A.is(a)&&"object"==typeof a&&!E.is(a)}),G=m("Func",function(a){return"function"==typeof a}),H=m("Err",function(a){return a instanceof Error}),I=m("Re",function(a){return a instanceof RegExp}),J=m("Dat",function(a){return a instanceof Date}),K=m("Type",function(a){return G.is(a)&&F.is(a.meta)});return q.of=function(a,b){a=B.is(a)?a.split(" "):a;var c={};return a.forEach(function(a){c[a]=a}),q(c,b)},v.is=function(a){return G.is(a)&&F.is(a.func)},{util:{format:e,getKind:i,getFunctionName:h,getName:g,mixin:d,slice:y,shallowCopy:k,update:l},options:x,assert:c,fail:b,Any:z,Nil:A,Str:B,Num:C,Bool:D,Arr:E,Obj:F,Func:G,Err:H,Re:I,Dat:J,Type:K,irreducible:m,struct:n,enums:q,union:o,maybe:p,tuple:r,subtype:s,list:t,dict:u,func:v}}); | ||
//# sourceMappingURL=tcomb.min.js.map |
Sorry, the diff of this file is not supported yet
9
759
56866
25