Comparing version 0.2.1 to 0.3.0
@@ -0,1 +1,14 @@ | ||
# v0.3.0 | ||
- added `Struct.extend(props, [name])`, fix #55 | ||
- added built-in immutable updates, fix #31 | ||
**BREAKING** | ||
- change `dict(B)` combinator to `dict(A, B)` where A is the set of keys, fix #54 | ||
- removed `util.isKind` | ||
- removed `util.isType`, use `Type.is` instead | ||
- refactoring of `func`. Now is a proper type combinator. fix #42 | ||
- removed `options.update` | ||
# v0.2.1 | ||
@@ -2,0 +15,0 @@ |
463
index.js
@@ -30,6 +30,5 @@ (function (root, factory) { | ||
} | ||
var options = { | ||
onFail: onFail, | ||
update: null | ||
onFail: onFail | ||
}; | ||
@@ -81,3 +80,3 @@ | ||
function merge() { | ||
return Array.prototype.reduce.call(arguments, function (x, y) { | ||
return Array.prototype.reduce.call(arguments, function reducer(x, y) { | ||
return mixin(x, y, true); | ||
@@ -120,41 +119,145 @@ }, {}); | ||
function isType(type) { | ||
return Func.is(type) && Obj.is(type.meta); | ||
} | ||
function getName(type) { | ||
assert(isType(type), 'Invalid argument `type` of value `%j` supplied to `getName()`, expected a type.', type); | ||
assert(Type.is(type), 'Invalid argument `type` of value `%j` supplied to `getName()`, expected a type.', type); | ||
return type.meta.name; | ||
} | ||
function deprecated(message) { | ||
if (console && console.warn) { | ||
console.warn(message); | ||
} | ||
} | ||
function getKind(type) { | ||
assert(isType(type), 'Invalid argument `type` of value `%j` supplied to `geKind()`, expected a type.', type); | ||
assert(Type.is(type), 'Invalid argument `type` of value `%j` supplied to `geKind()`, expected a type.', type); | ||
return type.meta.kind; | ||
} | ||
function isKind(type, kind) { | ||
deprecated('`isKind(type, kind)` is deprecated, use `getKind(type) === kind` instead'); | ||
return getKind(type) === kind; | ||
} | ||
function blockNew(x, type) { | ||
// DEBUG HINT: since in tcomb the only real constructors are those provided | ||
// by `struct`, the `new` operator is forbidden for all types | ||
assert(!(x instanceof type), 'Operator `new` is forbidden for `%s`', getName(type)); | ||
} | ||
function update() { | ||
assert(Func.is(options.update), 'Missing `options.update` implementation'); | ||
/*jshint validthis:true*/ | ||
var T = this; | ||
var value = options.update.apply(T, arguments); | ||
return T(value); | ||
/* | ||
function namespace(path, module) { | ||
if (!Arr.is(path)) { | ||
path = path.split('.'); | ||
} | ||
var lastIndex = path.length - 1; | ||
var init = {}; | ||
var isModule = arguments.length > 1; | ||
path.reduce(function reducer(acc, x, i) { | ||
return (acc[x] = isModule && i === lastIndex ? module : {}); | ||
}, init); | ||
return init; | ||
} | ||
function update(instance, spec, value) { | ||
if (!spec) { return instance; } | ||
// handle update(instance, path, value) | ||
if (Str.is(spec)) { | ||
return update(instance, namespace(spec, {$set: value})); | ||
} | ||
value = shallowCopy(instance); | ||
for (var k in spec) { | ||
if (spec.hasOwnProperty(k)) { | ||
var s = spec[k]; | ||
switch (k) { | ||
case '$apply' : | ||
return s(instance); | ||
case '$concat' : | ||
// TODO optimize | ||
return value.concat(s); | ||
case '$set' : | ||
return spec[k]; | ||
case '$splice' : | ||
value.splice.apply(value, s); | ||
return value; | ||
case '$swap' : | ||
var el = value[s.to]; | ||
value[s.to] = value[s.from]; | ||
value[s.from] = el; | ||
return value; | ||
case '$remove' : | ||
return update._; | ||
case '$prepend' : | ||
// TODO optimize | ||
return [].concat(s).concat(value); | ||
} | ||
value[k] = update(value[k], s); | ||
if (value[k] === update._) { | ||
delete value[k]; | ||
} | ||
} | ||
} | ||
return value; | ||
} | ||
update._ = {}; | ||
*/ | ||
function shallowCopy(x) { | ||
return Arr.is(x) ? x.concat() : Obj.is(x) ? mixin({}, x) : x; | ||
} | ||
function update(instance, spec) { | ||
assert(!Nil.is(instance)); | ||
assert(Obj.is(spec)); | ||
var value = shallowCopy(instance); | ||
for (var k in spec) { | ||
if (spec.hasOwnProperty(k)) { | ||
if (update.commands.hasOwnProperty(k)) { | ||
assert(Object.keys(spec).length === 1); | ||
return update.commands[k](spec[k], value); | ||
} else { | ||
value[k] = update(value[k], spec[k]); | ||
} | ||
} | ||
} | ||
return value; | ||
} | ||
update.commands = { | ||
'$apply': function (f, value) { | ||
assert(Func.is(f)); | ||
return f(value); | ||
}, | ||
'$push': function (elements, arr) { | ||
assert(Arr.is(elements)); | ||
assert(Arr.is(arr)); | ||
return arr.concat(elements); | ||
}, | ||
'$remove': function (keys, obj) { | ||
assert(Arr.is(keys)); | ||
assert(Obj.is(obj)); | ||
for (var i = 0, len = keys.length ; i < len ; i++ ) { | ||
delete obj[keys[i]]; | ||
} | ||
return obj; | ||
}, | ||
'$set': function (value) { | ||
return value; | ||
}, | ||
'$splice': function (splices, arr) { | ||
assert(list(Arr).is(splices)); | ||
assert(Arr.is(arr)); | ||
return splices.reduce(function (acc, splice) { | ||
acc.splice.apply(acc, splice); | ||
return acc; | ||
}, arr); | ||
}, | ||
'$swap': function (config, arr) { | ||
assert(Obj.is(config)); | ||
assert(Num.is(config.from)); | ||
assert(Num.is(config.to)); | ||
assert(Arr.is(arr)); | ||
var element = arr[config.to]; | ||
arr[config.to] = arr[config.from]; | ||
arr[config.from] = element; | ||
return arr; | ||
}, | ||
'$unshift': function (elements, arr) { | ||
assert(Arr.is(elements)); | ||
assert(Arr.is(arr)); | ||
return elements.concat(arr); | ||
} | ||
}; | ||
// | ||
@@ -194,47 +297,49 @@ // irriducibles | ||
var Any = irriducible('Any', function () { | ||
var Any = irriducible('Any', function isAny() { | ||
return true; | ||
}); | ||
var Nil = irriducible('Nil', function (x) { | ||
return x === null || x === undefined; | ||
var Nil = irriducible('Nil', function isNil(x) { | ||
return x === null || x === void 0; | ||
}); | ||
var Str = irriducible('Str', function (x) { | ||
var Str = irriducible('Str', function isStr(x) { | ||
return typeof x === 'string'; | ||
}); | ||
var Num = irriducible('Num', function (x) { | ||
var Num = irriducible('Num', function isNum(x) { | ||
return typeof x === 'number' && isFinite(x) && !isNaN(x); | ||
}); | ||
var Bool = irriducible('Bool', function (x) { | ||
var Bool = irriducible('Bool', function isBool(x) { | ||
return x === true || x === false; | ||
}); | ||
var Arr = irriducible('Arr', function (x) { | ||
var Arr = irriducible('Arr', function isArr(x) { | ||
return x instanceof Array; | ||
}); | ||
var Obj = irriducible('Obj', function (x) { | ||
var Obj = irriducible('Obj', function isObj(x) { | ||
return !Nil.is(x) && typeof x === 'object' && !Arr.is(x); | ||
}); | ||
var Func = irriducible('Func', function (x) { | ||
var Func = irriducible('Func', function isFunc(x) { | ||
return typeof x === 'function'; | ||
}); | ||
var Err = irriducible('Err', function (x) { | ||
var Err = irriducible('Err', function isErr(x) { | ||
return x instanceof Error; | ||
}); | ||
var Re = irriducible('Re', function (x) { | ||
var Re = irriducible('Re', function isRe(x) { | ||
return x instanceof RegExp; | ||
}); | ||
var Dat = irriducible('Dat', function (x) { | ||
var Dat = irriducible('Dat', function isDat(x) { | ||
return x instanceof Date; | ||
}); | ||
var Type = irriducible('Type', isType); | ||
var Type = irriducible('Type', function isType(x) { | ||
return Func.is(x) && Obj.is(x.meta); | ||
}); | ||
@@ -245,3 +350,3 @@ function struct(props, name) { | ||
// mouse over the `props` variable to see what's wrong | ||
assert(dict(Type).is(props), 'Invalid argument `props` supplied to `struct()`'); | ||
assert(dict(Str, Type).is(props), 'Invalid argument `props` supplied to `struct()`'); | ||
@@ -281,3 +386,3 @@ // DEBUG HINT: if the debugger stops here, the second argument is not a string | ||
if (!mut) { | ||
if (mut !== true) { | ||
Object.freeze(this); | ||
@@ -293,8 +398,14 @@ } | ||
Struct.is = function (x) { | ||
Struct.is = function isStruct(x) { | ||
return x instanceof Struct; | ||
}; | ||
Struct.update = update; | ||
Struct.update = function updateStruct(instance, spec, value) { | ||
return new Struct(update(instance, spec, value)); | ||
}; | ||
Struct.extend = function extendStruct(newProps, name) { | ||
return struct(mixin(mixin({}, props), newProps), name); | ||
}; | ||
return Struct; | ||
@@ -330,3 +441,3 @@ } | ||
// DEBUG HINT: if the debugger stops here, the `dispatch` static method returns no type | ||
assert(isType(type), '%s.dispatch() returns no type', name); | ||
assert(Type.is(type), '%s.dispatch() returns no type', name); | ||
@@ -344,4 +455,4 @@ // DEBUG HINT: if the debugger stops here, `value` can't be converted to `type` | ||
Union.is = function (x) { | ||
return types.some(function (type) { | ||
Union.is = function isUnion(x) { | ||
return types.some(function isType(type) { | ||
return type.is(x); | ||
@@ -352,3 +463,3 @@ }); | ||
// default dispatch implementation | ||
Union.dispatch = function (x) { | ||
Union.dispatch = function dispatch(x) { | ||
for (var i = 0, len = types.length ; i < len ; i++ ) { | ||
@@ -367,3 +478,3 @@ if (types[i].is(x)) { | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a type | ||
assert(isType(type), 'Invalid argument `type` supplied to `maybe()`'); | ||
assert(Type.is(type), 'Invalid argument `type` supplied to `maybe()`'); | ||
@@ -397,3 +508,3 @@ // makes the combinator idempotent | ||
Maybe.is = function (x) { | ||
Maybe.is = function isMaybe(x) { | ||
return Nil.is(x) || type.is(x); | ||
@@ -438,3 +549,3 @@ }; | ||
Enums.is = function (x) { | ||
Enums.is = function isEnums(x) { | ||
return Str.is(x) && map.hasOwnProperty(x); | ||
@@ -446,3 +557,3 @@ }; | ||
enums.of = function (keys, name) { | ||
enums.of = function enumsOf(keys, name) { | ||
keys = Str.is(keys) ? keys.split(' ') : keys; | ||
@@ -463,5 +574,2 @@ var value = {}; | ||
// 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 `tuple()`'); | ||
// DEBUG HINT: if the debugger stops here, the second argument is not a string | ||
@@ -475,5 +583,2 @@ // mouse over the `name` variable to see what's wrong | ||
// DEBUG HINT: if the debugger stops here, you have used the `new` operator but it's forbidden | ||
blockNew(this, Tuple); | ||
// DEBUG HINT: if the debugger stops here, the value is not one of the defined enums | ||
@@ -497,3 +602,3 @@ // mouse over the `value`, `name` and `len` variables to see what's wrong | ||
if (!mut) { | ||
if (mut !== true) { | ||
Object.freeze(arr); | ||
@@ -507,2 +612,3 @@ } | ||
types: types, | ||
length: len, | ||
name: name | ||
@@ -517,7 +623,9 @@ }; | ||
Tuple.is = function (x) { | ||
Tuple.is = function isTuple(x) { | ||
return Arr.is(x) && x.length === len && Tuple.isTuple(x); | ||
}; | ||
Tuple.update = update; | ||
Tuple.update = function updateTuple(instance, spec, value) { | ||
return Tuple(update(instance, spec, value)); | ||
}; | ||
@@ -530,3 +638,3 @@ return Tuple; | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a type | ||
assert(isType(type), 'Invalid argument `type` supplied to `subtype()`'); | ||
assert(Type.is(type), 'Invalid argument `type` supplied to `subtype()`'); | ||
@@ -567,6 +675,10 @@ // DEBUG HINT: if the debugger stops here, the second argument is not a function | ||
Subtype.is = function (x) { | ||
Subtype.is = function isSubtype(x) { | ||
return type.is(x) && predicate(x); | ||
}; | ||
Subtype.update = function updateSubtype(instance, spec, value) { | ||
return Subtype(update(instance, spec, value)); | ||
}; | ||
return Subtype; | ||
@@ -578,3 +690,3 @@ } | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a type | ||
assert(isType(type), 'Invalid argument `type` supplied to `list()`'); | ||
assert(Type.is(type), 'Invalid argument `type` supplied to `list()`'); | ||
@@ -591,3 +703,2 @@ // DEBUG HINT: if the debugger stops here, the third argument is not a string | ||
// DEBUG HINT: if the debugger stops here, you have used the `new` operator but it's forbidden | ||
blockNew(this, List); | ||
@@ -611,3 +722,3 @@ // DEBUG HINT: if the debugger stops here, the value is not one of the defined enums | ||
if (!mut) { | ||
if (mut !== true) { | ||
Object.freeze(arr); | ||
@@ -628,16 +739,20 @@ } | ||
List.is = function (x) { | ||
List.is = function isList(x) { | ||
return Arr.is(x) && List.isList(x); | ||
}; | ||
List.update = function updateList(instance, spec, value) { | ||
return List(update(instance, spec, value)); | ||
}; | ||
List.update = update; | ||
return List; | ||
} | ||
function dict(type, name) { | ||
function dict(domain, codomain, name) { | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a type | ||
assert(isType(type), 'Invalid argument `type` supplied to `dict()`'); | ||
assert(Type.is(domain), 'Invalid argument `domain` supplied to `dict()`'); | ||
// DEBUG HINT: if the debugger stops here, the second argument is not a type | ||
assert(Type.is(codomain), 'Invalid argument `codomain` supplied to `dict()`'); | ||
@@ -649,10 +764,7 @@ // DEBUG HINT: if the debugger stops here, the third argument is not a string | ||
// DEBUG HINT: always give a name to a type, the debug will be easier | ||
name = name || format('dict(%s)', getName(type)); | ||
name = name || format('dict(%s, %s)', getName(domain), getName(codomain)); | ||
function Dict(value, mut) { | ||
// DEBUG HINT: if the debugger stops here, you have used the `new` operator but it's forbidden | ||
blockNew(this, Dict); | ||
// DEBUG HINT: if the debugger stops here, the value is not one of the defined enums | ||
// DEBUG HINT: if the debugger stops here, the value is not an object | ||
// mouse over the `value` and `name` variables to see what's wrong | ||
@@ -669,10 +781,13 @@ assert(Obj.is(value), 'Invalid `%s` supplied to `%s`, expected an `Obj`', value, name); | ||
if (value.hasOwnProperty(k)) { | ||
// DEBUG HINT: if the debugger stops here, the `k` value supplied to the `domain` type is invalid | ||
// mouse over the `k` and `domain` variables to see what's wrong | ||
k = domain(k); | ||
var actual = value[k]; | ||
// DEBUG HINT: if the debugger stops here, the `actual` value supplied to the `type` type is invalid | ||
// mouse over the `actual` and `type` variables to see what's wrong | ||
obj[k] = type(actual, mut); | ||
// DEBUG HINT: if the debugger stops here, the `actual` value supplied to the `codomain` type is invalid | ||
// mouse over the `actual` and `codomain` variables to see what's wrong | ||
obj[k] = codomain(actual, mut); | ||
} | ||
} | ||
if (!mut) { | ||
if (mut !== true) { | ||
Object.freeze(obj); | ||
@@ -685,3 +800,4 @@ } | ||
kind: 'dict', | ||
type: type, | ||
domain: domain, | ||
codomain: codomain, | ||
name: name | ||
@@ -692,4 +808,4 @@ }; | ||
for (var k in x) { | ||
if (x.hasOwnProperty(k) && !type.is(x[k])) { | ||
return false; | ||
if (x.hasOwnProperty(k)) { | ||
if (!domain.is(k) || !codomain.is(x[k])) { return false; } | ||
} | ||
@@ -700,3 +816,3 @@ } | ||
Dict.is = function (x) { | ||
Dict.is = function isDict(x) { | ||
return Obj.is(x) && Dict.isDict(x); | ||
@@ -706,3 +822,5 @@ }; | ||
Dict.update = update; | ||
Dict.update = function updateDict(instance, spec, value) { | ||
return Dict(update(instance, spec, value)); | ||
}; | ||
@@ -712,96 +830,108 @@ return Dict; | ||
function func(Arguments, f, Return, name) { | ||
name = name || 'func()'; | ||
Arguments = Arr.is(Arguments) ? tuple(Arguments, 'Arguments') : Arguments; | ||
function func(domain, codomain, name) { | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a type | ||
assert(isType(Arguments), 'Invalid argument `Arguments` supplied to `func()`'); | ||
// handle handy syntax for unary functions | ||
domain = Arr.is(domain) ? domain : [domain]; | ||
// DEBUG HINT: if the debugger stops here, the second argument is not a function | ||
assert(Func.is(f), 'Invalid argument `f` supplied to `func()`'); | ||
// 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()`'); | ||
// DEBUG HINT: if the debugger stops here, the third argument is not a type (or Nil) | ||
assert(Nil.is(Return) || isType(Return), 'Invalid argument `Return` supplied to `func()`'); | ||
// DEBUG HINT: if the debugger stops here, the second argument is not a type | ||
assert(Type.is(codomain), 'Invalid argument `codomain` supplied to `func()`'); | ||
// 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 `func()`'); | ||
// 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)); | ||
// DEBUG HINT: always give a name to a type, the debug will be easier | ||
name = name || f.name || 'func'; | ||
// makes the combinator idempotent | ||
Return = Return || null; | ||
if (isType(f) && f.meta.Arguments === Arguments && f.meta.Return === Return) { | ||
return f; | ||
} | ||
function fn() { | ||
var args = slice.call(arguments); | ||
// handle optional arguments | ||
if (args.length < f.length) { | ||
args.length = f.length; | ||
// cache the domain length | ||
var domainLen = domain.length; | ||
function Func(value) { | ||
// automatically instrument the function if is not already instrumented | ||
if (!func.is(value)) { | ||
value = Func.of(value); | ||
} | ||
// DEBUG HINT: if the debugger stops here, the arguments of the function are invalid | ||
// mouse over the `args` variable to see what's wrong | ||
args = Arguments(args); | ||
/*jshint validthis: true */ | ||
var r = f.apply(this, args); | ||
if (Return) { | ||
// DEBUG HINT: if the debugger stops here, the return value of the function is invalid | ||
// mouse over the `r` variable to see what's wrong | ||
r = Return(r); | ||
} | ||
return r; | ||
// DEBUG HINT: if the debugger stops here, the first argument is invalid | ||
// mouse over the `value` and `name` variables to see what's wrong | ||
assert(Func.is(value), 'Invalid `%s` supplied to `%s`', value, name); | ||
return value; | ||
} | ||
fn.is = function (x) { | ||
return x === fn; | ||
}; | ||
fn.meta = { | ||
Func.meta = { | ||
kind: 'func', | ||
Arguments: Arguments, | ||
f: f, | ||
Return: Return, | ||
domain: domain, | ||
codomain: codomain, | ||
name: name | ||
}; | ||
return fn; | ||
} | ||
function alias(type, name) { | ||
Func.is = function isFunc(x) { | ||
return func.is(x) && | ||
x.func.domain.length === domain.length && | ||
x.func.domain.every(function (type, i) { | ||
return type === domain[i]; | ||
}) && | ||
x.func.codomain === codomain; | ||
}; | ||
// DEBUG HINT: if the debugger stops here, the first argument is not a type | ||
assert(isType(type), 'Invalid argument `type` supplied to `alias()`'); | ||
// 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 `alias()`'); | ||
Func.of = function funcOf(f) { | ||
// DEBUG HINT: always give a name to a type, the debug will be easier | ||
name = name || 'alias(' + getName(type) + ')'; | ||
// DEBUG HINT: if the debugger stops here, f is not a function | ||
assert(typeof f === 'function'); | ||
function Alias(value, mut) { | ||
return type(value, mut); | ||
} | ||
// makes Func.of idempotent | ||
if (Func.is(f)) { | ||
return f; | ||
} | ||
Alias.is = function (x) { | ||
return type.is(x); | ||
function fn() { | ||
var args = slice.call(arguments); | ||
var len = Math.min(args.length, domainLen); | ||
// DEBUG HINT: if the debugger stops here, you provided wrong arguments to the function | ||
// mouse over the `args` variable to see what's wrong | ||
args = tuple(domain.slice(0, len))(args); | ||
if (len === domainLen) { | ||
/* jshint validthis: true */ | ||
var r = f.apply(this, args); | ||
// DEBUG HINT: if the debugger stops here, the return value of the function is invalid | ||
// mouse over the `r` variable to see what's wrong | ||
r = codomain(r); | ||
return r; | ||
} else { | ||
var curried = Function.prototype.bind.apply(f, [this].concat(args)); | ||
var newdomain = func(domain.slice(len), codomain); | ||
return newdomain.of(curried); | ||
} | ||
} | ||
fn.func = { | ||
domain: domain, | ||
codomain: codomain, | ||
f: f | ||
}; | ||
return fn; | ||
}; | ||
Alias.meta = type.meta; | ||
Alias.name = name; | ||
return Func; | ||
return Alias; | ||
} | ||
// returns true if x is an instrumented function | ||
func.is = function (f) { | ||
return Func.is(f) && Obj.is(f.func); | ||
}; | ||
return { | ||
@@ -813,7 +943,7 @@ | ||
format: format, | ||
isType: isType, | ||
getName: getName, | ||
getKind: getKind, | ||
isKind: isKind, | ||
slice: slice | ||
slice: slice, | ||
shallowCopy: shallowCopy, | ||
update: update | ||
}, | ||
@@ -847,5 +977,4 @@ | ||
dict: dict, | ||
func: func, | ||
alias: alias | ||
func: func | ||
}; | ||
})); |
{ | ||
"name": "tcomb", | ||
"version": "0.2.1", | ||
"version": "0.3.0", | ||
"description": "Pragmatic runtime type checking for JavaScript", | ||
"main": "index.js", | ||
"scripts": { | ||
"cover": "istanbul cover _mocha -- --ui bdd -R dot" | ||
"cover": "istanbul cover _mocha -- --ui bdd -R dot", | ||
"compile-browser-tests": "watchify ./test/test.js -o ./test/browser -v" | ||
}, | ||
@@ -9,0 +10,0 @@ "repository": { |
565
README.md
@@ -1,9 +0,31 @@ | ||
% tcomb | ||
> "Si vis pacem, para bellum" (Vegetius 5th century) | ||
![tcomb logo](http://gcanti.github.io/resources/tcomb/logo.png) | ||
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. | ||
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. | ||
# The Idea | ||
tcomb is based on set theory. | ||
What's a type? In tcomb a type is a function `T` such that | ||
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` | ||
**Note**: 2. implies that `T` can be used as a default JSON decoder | ||
# 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 | ||
- [Giulio Canti](https://github.com/gcanti) | ||
- [Becky Conning](https://github.com/beckyconning) 'func' combinator ideas and documentation. | ||
# Contents | ||
@@ -16,7 +38,5 @@ | ||
- [Tests](#tests) | ||
- [The Idea](#the-idea) | ||
- [Api](#api) | ||
- [options](#options) | ||
- [options.onFail](#optionsonfail) | ||
- [options.update](#optionsupdate) | ||
- [assert](#assert) | ||
@@ -30,5 +50,5 @@ - [structs](#structs) | ||
- [dicts](#dicts) | ||
- [built-in (immutable) updates](#updates) | ||
- [functions](#functions) | ||
- [sweet.js macros (experimental)](#macros) | ||
- [Articles on tcomb](#articles-on-tcomb) | ||
@@ -42,3 +62,3 @@ # Features | ||
The library provides a built-in `assert` function, if an assert fails the **debugger kicks in** | ||
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. | ||
@@ -78,3 +98,3 @@ | ||
```javascript | ||
```js | ||
var Product = struct({ | ||
@@ -86,5 +106,5 @@ name: Str, // required string | ||
category: Category, // enum, one of [audio, video] | ||
price: union([Num, Price]), // a price (dollars) OR in another currency | ||
price: Price, // a price (dollars) OR in another currency | ||
size: tuple([Num, Num]), // width x height | ||
warranty: dict(Num) // a dictionary country -> covered years | ||
warranty: dict(Str, Num) // a dictionary country -> covered years | ||
}); | ||
@@ -95,7 +115,9 @@ | ||
}); | ||
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; | ||
}; | ||
var Price = struct({ currency: Str, amount: Num }); | ||
// JSON of a product | ||
@@ -122,3 +144,3 @@ var json = { | ||
```javascript | ||
```js | ||
// your code: plain old JavaScript class | ||
@@ -135,3 +157,3 @@ function Point (x, y) { | ||
```javascript | ||
```js | ||
function Point (x, y) { | ||
@@ -161,26 +183,4 @@ assert(Num.is(x)); | ||
This library uses a few ES5 methods | ||
This library uses a few ES5 methods, you can use `es5-shim`, `es5-sham` and `json2` to support old browsers | ||
- `Array.forEach()` | ||
- `Array.map()` | ||
- `Array.some()` | ||
- `Array.every()` | ||
- `Object.keys()` | ||
- `Object.freeze()` | ||
- `JSON.stringify()` | ||
you can use `es5-shim`, `es5-sham` and `json2` to support old browsers | ||
```html | ||
<!--[if lt IE 9]> | ||
<script src="json2.js"></script> | ||
<script src="es5-shim.min.js"></script> | ||
<script src="es5-sham.min.js"></script> | ||
<![endif]--> | ||
<script type="text/javascript" src="tcomb.js"></script> | ||
<script type="text/javascript"> | ||
console.log(t); | ||
</script> | ||
``` | ||
# Tests | ||
@@ -190,21 +190,11 @@ | ||
# The Idea | ||
What's a type? In tcomb a type is a function `T` such that | ||
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` | ||
**Note**: 2. implies that `T` can be used as a default JSON decoder | ||
# Api | ||
## options | ||
### options.onFail | ||
In production envs you don't want to leak failures to the user | ||
```javascript | ||
```js | ||
// override onFail hook | ||
@@ -221,18 +211,2 @@ options.onFail = function (message) { | ||
``` | ||
### options.update | ||
Adds to structs, tuples, lists and dicts a static method `update` that returns a new instance | ||
without modifying the original. | ||
Example | ||
```javascript | ||
// see http://facebook.github.io/react/docs/update.html | ||
options.update = function (x, updates) { | ||
return React.addons.update(mixin({}, x), updates); | ||
}; | ||
var p1 = Point({x: 0, y: 0}); | ||
var p2 = Point.update(p1, {x: {$set: 1}}); // => Point({x: 1, y: 0}) | ||
``` | ||
@@ -244,11 +218,11 @@ ## assert | ||
``` | ||
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 | ||
```javascript | ||
```js | ||
assert(1 === 2); // throws 'assert(): failed' | ||
@@ -258,3 +232,3 @@ assert(1 === 2, 'error!'); // throws 'error!' | ||
``` | ||
To customize failure behaviour, see `options.onFail`. | ||
@@ -267,13 +241,13 @@ | ||
``` | ||
Defines a struct like type. | ||
- `props` hash name -> type | ||
- `name` optional string useful for debugging | ||
Example | ||
```javascript | ||
```js | ||
"use strict"; | ||
// defines a struct with two numerical props | ||
@@ -284,3 +258,3 @@ var Point = struct({ | ||
}); | ||
// methods are defined as usual | ||
@@ -290,21 +264,36 @@ Point.prototype.toString = function () { | ||
}; | ||
// 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. | ||
```javascript | ||
```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}); | ||
``` | ||
## unions | ||
@@ -315,11 +304,11 @@ | ||
``` | ||
Defines a union of types. | ||
- `types` array of types | ||
- `name` optional string useful for debugging | ||
Example | ||
```javascript | ||
```js | ||
var Circle = struct({ | ||
@@ -329,3 +318,3 @@ center: Point, | ||
}); | ||
var Rectangle = struct({ | ||
@@ -335,15 +324,23 @@ bl: Point, // bottom left vertex | ||
}); | ||
var Shape = union([ | ||
Circle, | ||
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. | ||
```javascript | ||
Shape.is(Circle({center: p, radius: 10})); // => true | ||
```js | ||
Shape.is(new Circle({center: p, radius: 10})); // => true | ||
``` | ||
@@ -356,9 +353,9 @@ | ||
``` | ||
Same as `union([Nil, type])`. | ||
```javascript | ||
```js | ||
// the value of a radio input where null = no selection | ||
var Radio = maybe(Str); | ||
Radio.is('a'); // => true | ||
@@ -374,40 +371,40 @@ Radio.is(null); // => true | ||
``` | ||
Defines an enum of strings. | ||
- `map` hash enum -> value | ||
- `name` optional string useful for debugging | ||
Example | ||
```javascript | ||
```js | ||
var Direction = enums({ | ||
North: 'North', | ||
North: 'North', | ||
East: 'East', | ||
South: 'South', | ||
South: 'South', | ||
West: 'West' | ||
}); | ||
``` | ||
### is(x) | ||
Returns `true` if `x` belongs to the enum. | ||
```javascript | ||
```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 | ||
```javascript | ||
```js | ||
// result is the same as the main example | ||
var Direction = enums.of(['North', 'East', 'South', 'West']); | ||
// or.. | ||
@@ -422,22 +419,29 @@ Direction = enums.of('North East South West'); | ||
``` | ||
Defines a tuple whose coordinates have the specified types. | ||
- `types` array of coordinates types | ||
- `name` optional string useful for debugging | ||
Example | ||
```javascript | ||
```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. | ||
```javascript | ||
```js | ||
Area.is([1, 2]); // => true | ||
@@ -453,12 +457,12 @@ Area.is([1, 'a']); // => false, the second element is not a Num | ||
``` | ||
Defines a subtype of an existing type. | ||
- `type` the supertype | ||
- `predicate` a function with signature `(x) -> boolean` | ||
- `name` optional string useful for debugging | ||
Example | ||
```javascript | ||
```js | ||
// points of the first quadrant | ||
@@ -468,19 +472,19 @@ var Q1Point = subtype(Point, function (p) { | ||
}); | ||
// 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. | ||
```javascript | ||
```js | ||
var Int = subtype(Num, function (n) { | ||
return n === parseInt(n, 10); | ||
}); | ||
Int.is(2); // => true | ||
@@ -495,25 +499,25 @@ Int.is(1.1); // => false | ||
``` | ||
Defines an array where all the elements are of type `T`. | ||
- `type` type of all the elements | ||
- `name` optional string useful for debugging | ||
Example | ||
```javascript | ||
```js | ||
var Path = list(Point); | ||
// costructor usage, path is immutable | ||
var path = Path([ | ||
{x: 0, y: 0}, | ||
{x: 0, y: 0}, | ||
{x: 1, y: 1} | ||
]); | ||
``` | ||
### is(x) | ||
Returns `true` if `x` belongs to the list. | ||
```javascript | ||
```js | ||
var p1 = Point({x: 0, y: 0}); | ||
@@ -527,54 +531,191 @@ var p2 = Point({x: 1, y: 2}); | ||
```js | ||
dict(type, [name]) | ||
dict(domain, codomain, [name]) | ||
``` | ||
Defines a dictionary Str -> type. | ||
- `type` the type of the values | ||
Defines a dictionary domain -> codomain. | ||
- `domain` the type of the keys | ||
- `codomain` the type of the values | ||
- `name` optional string useful for debugging | ||
Example | ||
```javascript | ||
```js | ||
// defines a dictionary of numbers | ||
var Tel = dict(Num); | ||
var Tel = dict(Str, Num); | ||
``` | ||
### is(x) | ||
Returns `true` if `x` is an instance of the dict. | ||
```javascript | ||
```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 | ||
### 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 | ||
func(Arguments, f, [Return], [name]) | ||
// add takes two `Num`s and returns a `Num` | ||
var add = func([Num, Num], Num) | ||
.of(function (x, y) { return x + y; }); | ||
``` | ||
Defines a function where the `arguments` and the return value are checked. | ||
- `Arguments` the type of `arguments` (can be a list of types) | ||
- `f` the function to execute | ||
- `Return` optional, check the type of the return value | ||
- `name` optional string useful for debugging | ||
Example | ||
```javascript | ||
var sum = func([Num, Num], function (a, b) { | ||
return a + b; | ||
}, Num); | ||
sum(1, 2); // => 3 | ||
sum(1, 'a'); // => fail! | ||
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 | ||
``` | ||
# Macros | ||
### func(A, B, [name]) | ||
**Experimental**. I added a `tcomb.sjs` file containing some [sweet.js](http://sweetjs.org/) macros, here some examples: | ||
```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 | ||
@@ -600,13 +741,13 @@ type Point struct { | ||
type Direction enums { | ||
'North', | ||
'North', | ||
'East', | ||
'South', | ||
'South', | ||
'West' | ||
} | ||
// enums with specified values | ||
// enums with specified values | ||
type Direction enums { | ||
'North': 0, | ||
'North': 0, | ||
'East': 1, | ||
'South': 2, | ||
'South': 2, | ||
'West': 3 | ||
@@ -645,34 +786,4 @@ } | ||
# Articles on tcomb | ||
# License | ||
- [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) | ||
# Contribution | ||
If you do have a contribution for the package feel free to put up a Pull Request or open an Issue. | ||
# License (MIT) | ||
The MIT License (MIT) | ||
Copyright (c) 2014 Giulio Canti | ||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
@@ -1,6 +0,6 @@ | ||
// tcomb 0.2.0 | ||
// tcomb 0.2.1 | ||
// 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 z=!0,new Error(a)}function b(a){A.onFail(a)}function c(a){if(a!==!0){var c=B.call(arguments,1),d=c[0]?f.apply(null,c):"assert failed";b(d)}}function d(a,b,d){if(D.is(b))return a;for(var e in b)b.hasOwnProperty(e)&&(d||c(!a.hasOwnProperty(e),"cannot overwrite property %s",e),a[e]=b[e]);return a}function e(){return Array.prototype.reduce.call(arguments,function(a,b){return d(a,b,!0)},{})}function f(){function a(a,e){if("%%"===a)return"%";if(d>=c)return a;var g=f.formatters[e];return g?g(b[d++]):a}var b=B.call(arguments),c=b.length,d=1,e=b[0],g=e.replace(/%([a-z%])/g,a);return c>d&&(g+=" "+b.slice(d).join(" ")),g}function g(a,b){return"function"==typeof b?f("Func",b.name):b}function h(a){return J.is(a)&&I.is(a.meta)}function i(a){return c(h(a),"Invalid argument `type` of value `%j` supplied to `getName()`, expected a type.",a),a.meta.name}function j(a){console&&console.warn&&console.warn(a)}function k(a){return c(h(a),"Invalid argument `type` of value `%j` supplied to `geKind()`, expected a type.",a),a.meta.kind}function l(a,b){return j("`isKind(type, kind)` is deprecated, use `getKind(type) === kind` instead"),k(a)===b}function m(a,b){c(!(a instanceof b),"Operator `new` is forbidden for `%s`",i(b))}function n(){c(J.is(A.update),"Missing `options.update` implementation");var a=this,b=A.update.apply(a,arguments);return a(b)}function o(a,b){function d(e){return m(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.is=b,d}function p(a,b){function d(e,f){if(d.is(e))return e;if(c(I.is(e),"Invalid `%s` supplied to `%s`, expected an `Obj`",e,b),!(this instanceof d))return new d(e,f);for(var g in a)if(a.hasOwnProperty(g)){var h=a[g],i=e[g];this[g]=h(i,f)}f||Object.freeze(this)}return c(w(N).is(a),"Invalid argument `props` supplied to `struct()`"),c(r(E).is(b),"Invalid argument `name` supplied to `struct()`"),b=b||"struct",d.meta={kind:"struct",props:a,name:b},d.is=function(a){return a instanceof d},d.update=n,d}function q(a,b){function d(a,e){m(this,d),c(J.is(d.dispatch),"unimplemented %s.dispatch()",b);var f=d.dispatch(a);return c(h(f),"%s.dispatch() returns no type",b),f(a,e)}c(v(N).is(a),"Invalid argument `types` supplied to `union()`");var e=a.length;return c(e>=2,"Invalid argument `types` supplied to `union()`"),c(r(E).is(b),"Invalid argument `name` supplied to `union()`"),b=b||f("union([%s])",a.map(i).join(", ")),d.meta={kind:"union",types:a,name: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 r(a,b){function d(b,c){return m(this,d),D.is(b)?null:a(b,c)}return c(h(a),"Invalid argument `type` supplied to `maybe()`"),"maybe"===k(a)?a:(c(D.is(b)||E.is(b),"Invalid argument `name` supplied to `maybe()`"),b=b||f("maybe(%s)",i(a)),d.meta={kind:"maybe",type:a,name:b},d.is=function(b){return D.is(b)||a.is(b)},d)}function s(a,b){function d(a){return m(this,d),c(d.is(a),"Invalid `%s` supplied to `%s`, expected one of %j",a,b,e),a}c(I.is(a),"Invalid argument `map` supplied to `enums()`"),c(r(E).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.is=function(b){return E.is(b)&&a.hasOwnProperty(b)},d}function t(a,b){function d(f,g){if(m(this,d),c(H.is(f)&&f.length===e,"Invalid `%s` supplied to `%s`, expected an `Arr` of length `%s`",f,b,e),d.isTuple(f))return f;for(var h=[],i=0;e>i;i++){var j=a[i],k=f[i];h.push(j(k,g))}return g||Object.freeze(h),h}c(v(N).is(a),"Invalid argument `types` supplied to `tuple()`");var e=a.length;return c(e>=2,"Invalid argument `types` supplied to `tuple()`"),c(r(E).is(b),"Invalid argument `name` supplied to `tuple()`"),b=b||f("tuple([%s])",a.map(i).join(", ")),d.meta={kind:"tuple",types:a,name:b},d.isTuple=function(b){return a.every(function(a,c){return a.is(b[c])})},d.is=function(a){return H.is(a)&&a.length===e&&d.isTuple(a)},d.update=n,d}function u(a,b,d){function e(f,h){m(this,e);var i=a(f,h);return c(b(i),"Invalid `%s` supplied to `%s`, %s",f,d,g),i}c(h(a),"Invalid argument `type` supplied to `subtype()`"),c(J.is(b),"Invalid argument `predicate` supplied to `subtype()`"),c(r(E).is(d),"Invalid argument `name` supplied to `subtype()`"),d=d||f("subtype(%s)",i(a));var g=b.__doc__||f("insert a valid value for %s",b.name||"the subtype");return e.meta={kind:"subtype",type:a,predicate:b,name:d},e.is=function(c){return a.is(c)&&b(c)},e}function v(a,b){function d(e,f){if(m(this,d),c(H.is(e),"Invalid `%s` supplied to `%s`, expected an `Arr`",e,b),d.isList(e))return e;for(var g=[],h=0,i=e.length;i>h;h++){var j=e[h];g.push(a(j,f))}return f||Object.freeze(g),g}return c(h(a),"Invalid argument `type` supplied to `list()`"),c(r(E).is(b),"Invalid argument `name` supplied to `list()`"),b=b||f("list(%s)",i(a)),d.meta={kind:"list",type:a,name:b},d.isList=function(b){return b.every(a.is)},d.is=function(a){return H.is(a)&&d.isList(a)},d.update=n,d}function w(a,b){function d(e,f){if(m(this,d),c(I.is(e),"Invalid `%s` supplied to `%s`, expected an `Obj`",e,b),d.isDict(e))return e;var g={};for(var h in e)if(e.hasOwnProperty(h)){var i=e[h];g[h]=a(i,f)}return f||Object.freeze(g),g}return c(h(a),"Invalid argument `type` supplied to `dict()`"),c(r(E).is(b),"Invalid argument `name` supplied to `dict()`"),b=b||f("dict(%s)",i(a)),d.meta={kind:"dict",type:a,name:b},d.isDict=function(b){for(var c in b)if(b.hasOwnProperty(c)&&!a.is(b[c]))return!1;return!0},d.is=function(a){return I.is(a)&&d.isDict(a)},d.update=n,d}function x(a,b,d,e){function f(){var c=B.call(arguments);c.length<b.length&&(c.length=b.length),c=a(c);var e=b.apply(this,c);return d&&(e=d(e)),e}return e=e||"func()",a=H.is(a)?t(a,"Arguments"):a,c(h(a),"Invalid argument `Arguments` supplied to `func()`"),c(J.is(b),"Invalid argument `f` supplied to `func()`"),c(D.is(d)||h(d),"Invalid argument `Return` supplied to `func()`"),c(r(E).is(e),"Invalid argument `name` supplied to `func()`"),e=e||b.name||"func",d=d||null,h(b)&&b.meta.Arguments===a&&b.meta.Return===d?b:(f.is=function(a){return a===f},f.meta={kind:"func",Arguments:a,f:b,Return:d,name:e},f)}function y(a,b){function d(b,c){return a(b,c)}return c(h(a),"Invalid argument `type` supplied to `alias()`"),c(r(E).is(b),"Invalid argument `name` supplied to `alias()`"),b=b||"alias("+i(a)+")",d.is=function(b){return a.is(b)},d.meta=a.meta,d.name=b,d}var z=!1,A={onFail:a,update:null},B=Array.prototype.slice;f.formatters={s:function(a){return String(a)},j:function(a){return JSON.stringify(a,g)}};var C=o("Any",function(){return!0}),D=o("Nil",function(a){return null===a||void 0===a}),E=o("Str",function(a){return"string"==typeof a}),F=o("Num",function(a){return"number"==typeof a&&isFinite(a)&&!isNaN(a)}),G=o("Bool",function(a){return a===!0||a===!1}),H=o("Arr",function(a){return a instanceof Array}),I=o("Obj",function(a){return!D.is(a)&&"object"==typeof a&&!H.is(a)}),J=o("Func",function(a){return"function"==typeof a}),K=o("Err",function(a){return a instanceof Error}),L=o("Re",function(a){return a instanceof RegExp}),M=o("Dat",function(a){return a instanceof Date}),N=o("Type",h);return s.of=function(a,b){a=E.is(a)?a.split(" "):a;var c={};return a.forEach(function(a){c[a]=a}),s(c,b)},{util:{mixin:d,merge:e,format:f,isType:h,getName:i,getKind:k,isKind:l,slice:B},options:A,assert:c,fail:b,Any:C,Nil:D,Str:E,Num:F,Bool:G,Arr:H,Obj:I,Func:J,Err:K,Re:L,Dat:M,Type:N,irriducible:o,struct:p,enums:s,union:q,maybe:r,tuple:t,subtype:u,list:v,dict:w,func:x,alias:y}}); | ||
!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]?f.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||c(!a.hasOwnProperty(e),"cannot overwrite property %s",e),a[e]=b[e]);return a}function e(){return Array.prototype.reduce.call(arguments,function(a,b){return d(a,b,!0)},{})}function f(){function a(a,e){if("%%"===a)return"%";if(d>=c)return a;var g=f.formatters[e];return g?g(b[d++]):a}var b=y.call(arguments),c=b.length,d=1,e=b[0],g=e.replace(/%([a-z%])/g,a);return c>d&&(g+=" "+b.slice(d).join(" ")),g}function g(a,b){return"function"==typeof b?f("Func",b.name):b}function h(a){return c(K.is(a),"Invalid argument `type` of value `%j` supplied to `getName()`, expected a type.",a),a.meta.name}function i(a){return c(K.is(a),"Invalid argument `type` of value `%j` supplied to `geKind()`, expected a type.",a),a.meta.kind}function j(a,b){c(!(a instanceof b),"Operator `new` is forbidden for `%s`",h(b))}function k(a){return E.is(a)?a.concat():F.is(a)?d({},a):a}function l(a,b){c(!A.is(a)),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 `%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.is=b,d}function n(a,b){function e(d,f){if(e.is(d))return d;if(c(F.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(u(B,K).is(a),"Invalid argument `props` supplied to `struct()`"),c(p(B).is(b),"Invalid argument `name` supplied to `struct()`"),b=b||"struct",e.meta={kind:"struct",props:a,name:b},e.is=function(a){return a instanceof e},e.update=function(a,b,c){return new e(l(a,b,c))},e.extend=function(b,c){return n(d(d({},a),b),c)},e}function o(a,b){function d(a,e){j(this,d),c(G.is(d.dispatch),"unimplemented %s.dispatch()",b);var f=d.dispatch(a);return c(K.is(f),"%s.dispatch() returns no type",b),f(a,e)}c(t(K).is(a),"Invalid argument `types` supplied to `union()`");var e=a.length;return c(e>=2,"Invalid argument `types` supplied to `union()`"),c(p(B).is(b),"Invalid argument `name` supplied to `union()`"),b=b||f("union([%s])",a.map(h).join(", ")),d.meta={kind:"union",types:a,name: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` supplied to `maybe()`"),"maybe"===i(a)?a:(c(A.is(b)||B.is(b),"Invalid argument `name` supplied to `maybe()`"),b=b||f("maybe(%s)",h(a)),d.meta={kind:"maybe",type:a,name: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 `%s` supplied to `%s`, expected one of %j",a,b,e),a}c(F.is(a),"Invalid argument `map` supplied to `enums()`"),c(p(B).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.is=function(b){return B.is(b)&&a.hasOwnProperty(b)},d}function r(a,b){function d(f,g){if(c(E.is(f)&&f.length===e,"Invalid `%s` supplied to `%s`, expected an `Arr` of length `%s`",f,b,e),d.isTuple(f))return f;for(var h=[],i=0;e>i;i++){var j=a[i],k=f[i];h.push(j(k,g))}return g!==!0&&Object.freeze(h),h}c(t(K).is(a),"Invalid argument `types` supplied to `tuple()`");var e=a.length;return c(p(B).is(b),"Invalid argument `name` supplied to `tuple()`"),b=b||f("tuple([%s])",a.map(h).join(", ")),d.meta={kind:"tuple",types:a,length:e,name: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===e&&d.isTuple(a)},d.update=function(a,b,c){return d(l(a,b,c))},d}function s(a,b,d){function e(f,h){j(this,e);var i=a(f,h);return c(b(i),"Invalid `%s` supplied to `%s`, %s",f,d,g),i}c(K.is(a),"Invalid argument `type` supplied to `subtype()`"),c(G.is(b),"Invalid argument `predicate` supplied to `subtype()`"),c(p(B).is(d),"Invalid argument `name` supplied to `subtype()`"),d=d||f("subtype(%s)",h(a));var g=b.__doc__||f("insert a valid value for %s",b.name||"the subtype");return e.meta={kind:"subtype",type:a,predicate:b,name:d},e.is=function(c){return a.is(c)&&b(c)},e.update=function(a,b,c){return e(l(a,b,c))},e}function t(a,b){function d(e,f){if(c(E.is(e),"Invalid `%s` supplied to `%s`, expected an `Arr`",e,b),d.isList(e))return e;for(var g=[],h=0,i=e.length;i>h;h++){var j=e[h];g.push(a(j,f))}return f!==!0&&Object.freeze(g),g}return c(K.is(a),"Invalid argument `type` supplied to `list()`"),c(p(B).is(b),"Invalid argument `name` supplied to `list()`"),b=b||f("list(%s)",h(a)),d.meta={kind:"list",type:a,name: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 e(f,g){if(c(F.is(f),"Invalid `%s` supplied to `%s`, expected an `Obj`",f,d),e.isDict(f))return f;var h={};for(var i in f)if(f.hasOwnProperty(i)){i=a(i);var j=f[i];h[i]=b(j,g)}return g!==!0&&Object.freeze(h),h}return c(K.is(a),"Invalid argument `domain` supplied to `dict()`"),c(K.is(b),"Invalid argument `codomain` supplied to `dict()`"),c(p(B).is(d),"Invalid argument `name` supplied to `dict()`"),d=d||f("dict(%s, %s)",h(a),h(b)),e.meta={kind:"dict",domain:a,codomain:b,name:d},e.isDict=function(c){for(var d in c)if(c.hasOwnProperty(d)&&(!a.is(d)||!b.is(c[d])))return!1;return!0},e.is=function(a){return F.is(a)&&e.isDict(a)},e.update=function(a,b,c){return e(l(a,b,c))},e}function v(a,b,d){function e(a){return v.is(a)||(a=e.of(a)),c(e.is(a),"Invalid `%s` supplied to `%s`",a,d),a}a=E.is(a)?a:[a],c(t(K).is(a),"Invalid argument `domain` supplied to `func()`"),c(K.is(b),"Invalid argument `codomain` supplied to `func()`"),d=d||f("func([%s], %s)",a.map(h).join(", "),h(b));var g=a.length;return e.meta={kind:"func",domain:a,codomain:b,name:d},e.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},e.of=function(d){function f(){var c=y.call(arguments),e=Math.min(c.length,g);if(c=r(a.slice(0,e))(c),e===g){var f=d.apply(this,c);return f=b(f)}var h=Function.prototype.bind.apply(d,[this].concat(c)),i=v(a.slice(e),b);return i.of(h)}return c("function"==typeof d),e.is(d)?d:(f.func={domain:a,codomain:b,f:d},f)},e}var w=!1,x={onFail:a},y=Array.prototype.slice;f.formatters={s:function(a){return String(a)},j:function(a){return JSON.stringify(a,g)}},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)}};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:{mixin:d,merge:e,format:f,getName:h,getKind:i,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,irriducible: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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
68765
780
762
7