Comparing version 1.6.0 to 1.6.1
@@ -17,2 +17,9 @@ # Changelog | ||
# 1.6.1 | ||
- **Bug Fix** | ||
- `taggedUnion` should handle sub unions / tagged unions correctly, closes #257 (@gcanti) | ||
- **Experimental** | ||
- optimize `union` with the same algorithm used in `taggedUnion` (@gcanti) | ||
# 1.6.0 | ||
@@ -19,0 +26,0 @@ |
@@ -726,13 +726,12 @@ import { Either } from 'fp-ts/lib/Either'; | ||
export declare type Tagged<Tag extends string, A = any, O = A> = InterfaceType<TaggedProps<Tag>, A, O> | StrictType<TaggedProps<Tag>, A, O> | TaggedRefinement<Tag, A, O> | TaggedUnion<Tag, A, O> | TaggedIntersection<Tag, A, O> | TaggedExact<Tag, A, O> | RecursiveType<any, A, O>; | ||
declare type Index = Array<[unknown, Mixed]>; | ||
interface IndexRecord extends Record<string, Index> { | ||
} | ||
/** | ||
* @since 1.3.0 | ||
* @internal | ||
*/ | ||
export declare const isTagged: <Tag extends string>(tag: Tag) => (type: Mixed) => type is Tagged<Tag, any, any>; | ||
export declare const getIndexRecord: (types: Mixed[]) => IndexRecord; | ||
/** | ||
* @since 1.3.0 | ||
*/ | ||
export declare const getTagValue: <Tag extends string>(tag: Tag) => (type: Tagged<Tag, any, any>) => LiteralValue; | ||
/** | ||
* @since 1.3.0 | ||
*/ | ||
export declare class TaggedUnionType<Tag extends string, CS extends Array<Tagged<Tag>>, A = any, O = A, I = unknown> extends UnionType<CS, A, O, I> { | ||
@@ -739,0 +738,0 @@ readonly tag: Tag; |
277
lib/index.js
@@ -432,3 +432,5 @@ "use strict"; | ||
exports.keyof = function (keys, name) { | ||
if (name === void 0) { name = "(keyof " + JSON.stringify(Object.keys(keys)) + ")"; } | ||
if (name === void 0) { name = Object.keys(keys) | ||
.map(function (k) { return JSON.stringify(k); }) | ||
.join(' | '); } | ||
var is = function (u) { return exports.string.is(u) && hasOwnProperty.call(keys, u); }; | ||
@@ -637,3 +639,3 @@ return new KeyofType(name, is, function (u, c) { return (is(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity, keys); | ||
exports.partial = function (props, name) { | ||
if (name === void 0) { name = "PartialType<" + getNameFromProps(props) + ">"; } | ||
if (name === void 0) { name = "Partial<" + getNameFromProps(props) + ">"; } | ||
var keys = Object.keys(props); | ||
@@ -716,3 +718,5 @@ var types = keys.map(function (key) { return props[key]; }); | ||
exports.DictionaryType = DictionaryType; | ||
var refinedDictionary = exports.refinement(exports.Dictionary, function (d) { return Object.prototype.toString.call(d) === '[object Object]'; }); | ||
var isUnknownType = function (type) { return type._tag === 'UnknownType'; }; | ||
var isAnyType = function (type) { return type._tag === 'AnyType'; }; | ||
var isObject = function (r) { return Object.prototype.toString.call(r) === '[object Object]'; }; | ||
/** | ||
@@ -723,8 +727,12 @@ * @since 1.0.0 | ||
if (name === void 0) { name = "{ [K in " + domain.name + "]: " + codomain.name + " }"; } | ||
var isIndexSignatureRequired = codomain !== exports.any; | ||
var D = isIndexSignatureRequired ? refinedDictionary : exports.Dictionary; | ||
return new DictionaryType(name, function (u) { | ||
return D.is(u) && Object.keys(u).every(function (k) { return domain.is(k) && codomain.is(u[k]); }); | ||
if (!exports.Dictionary.is(u)) { | ||
return false; | ||
} | ||
if (!isUnknownType(codomain) && !isAnyType(codomain) && !isObject(u)) { | ||
return false; | ||
} | ||
return Object.keys(u).every(function (k) { return domain.is(k) && codomain.is(u[k]); }); | ||
}, function (u, c) { | ||
var dictionaryValidation = D.validate(u, c); | ||
var dictionaryValidation = exports.Dictionary.validate(u, c); | ||
if (dictionaryValidation.isLeft()) { | ||
@@ -735,2 +743,5 @@ return dictionaryValidation; | ||
var o = dictionaryValidation.value; | ||
if (!isUnknownType(codomain) && !isAnyType(codomain) && !isObject(o)) { | ||
return exports.failure(u, c); | ||
} | ||
var a = {}; | ||
@@ -792,2 +803,11 @@ var errors = []; | ||
exports.UnionType = UnionType; | ||
var fst = function (r) { | ||
for (var k in r) { | ||
return [k, r[k]]; | ||
} | ||
return undefined; | ||
}; | ||
var getUnionName = function (types) { | ||
return '(' + types.map(function (type) { return type.name; }).join(' | ') + ')'; | ||
}; | ||
/** | ||
@@ -797,3 +817,7 @@ * @since 1.0.0 | ||
exports.union = function (types, name) { | ||
if (name === void 0) { name = "(" + types.map(function (type) { return type.name; }).join(' | ') + ")"; } | ||
if (name === void 0) { name = getUnionName(types); } | ||
var index = fst(exports.getIndexRecord(types)); | ||
if (index) { | ||
return taggedUnionWithIndex(index[1], index[0], types, name); | ||
} | ||
var len = types.length; | ||
@@ -1004,57 +1028,141 @@ return new UnionType(name, function (u) { return types.some(function (type) { return type.is(u); }); }, function (u, c) { | ||
}; | ||
/** | ||
* @since 1.3.0 | ||
*/ | ||
exports.isTagged = function (tag) { | ||
var f = function (type) { | ||
if (type instanceof InterfaceType || type instanceof StrictType) { | ||
return hasOwnProperty.call(type.props, tag); | ||
var isLiteralCodec = function (codec) { return codec._tag === 'LiteralType'; }; | ||
var isInterfaceCodec = function (codec) { return codec._tag === 'InterfaceType'; }; | ||
var isStrictCodec = function (codec) { return codec._tag === 'StrictType'; }; | ||
var isIntersectionCodec = function (codec) { | ||
return codec._tag === 'IntersectionType'; | ||
}; | ||
var isUnionCodec = function (codec) { return codec._tag === 'UnionType'; }; | ||
var isExactCodec = function (codec) { return codec._tag === 'ExactType'; }; | ||
var isRefinementCodec = function (codec) { return codec._tag === 'RefinementType'; }; | ||
var isRecursiveCodec = function (codec) { return codec._tag === 'RecursiveType'; }; | ||
var getCodecIndexRecord = function (codec, override) { | ||
if (override === void 0) { override = codec; } | ||
var _a; | ||
var ir = {}; | ||
if (isInterfaceCodec(codec) || isStrictCodec(codec)) { | ||
for (var k in codec.props) { | ||
var prop = codec.props[k]; | ||
if (isLiteralCodec(prop)) { | ||
var value = prop.value; | ||
ir[k] = [[value, override]]; | ||
} | ||
} | ||
else if (type instanceof IntersectionType) { | ||
return type.types.some(f); | ||
} | ||
else if (isIntersectionCodec(codec)) { | ||
var types = codec.types; | ||
ir = getCodecIndexRecord(types[0], codec); | ||
for (var i = 1; i < types.length; i++) { | ||
var cir = getCodecIndexRecord(types[i], codec); | ||
for (var k in cir) { | ||
if (ir.hasOwnProperty(k)) { | ||
(_a = ir[k]).push.apply(_a, cir[k]); | ||
} | ||
else { | ||
ir[k] = cir[k]; | ||
} | ||
} | ||
} | ||
else if (type instanceof UnionType) { | ||
return type.types.every(f); | ||
} | ||
else if (type instanceof RefinementType || type instanceof ExactType) { | ||
return f(type.type); | ||
} | ||
else { | ||
return false; | ||
} | ||
}; | ||
return f; | ||
} | ||
else if (isUnionCodec(codec)) { | ||
return exports.getIndexRecord(codec.types); | ||
} | ||
else if (isExactCodec(codec) || isRefinementCodec(codec)) { | ||
return getCodecIndexRecord(codec.type, codec); | ||
} | ||
else if (isRecursiveCodec(codec)) { | ||
return getCodecIndexRecord(codec.type, codec); | ||
} | ||
return ir; | ||
}; | ||
var findTagged = function (tag, types) { | ||
var isIndexableCodec = function (codec) { | ||
return (isInterfaceCodec(codec) || | ||
isExactCodec(codec) || | ||
isIntersectionCodec(codec) || | ||
isUnionCodec(codec) || | ||
isStrictCodec(codec) || | ||
isRefinementCodec(codec) || | ||
isRecursiveCodec(codec)); | ||
}; | ||
/** | ||
* @internal | ||
*/ | ||
exports.getIndexRecord = function (types) { | ||
var len = types.length; | ||
var is = exports.isTagged(tag); | ||
var i = 0; | ||
for (; i < len - 1; i++) { | ||
var type_8 = types[i]; | ||
if (is(type_8)) { | ||
return type_8; | ||
if (len === 0 || !types.every(isIndexableCodec)) { | ||
return {}; | ||
} | ||
var ir = getCodecIndexRecord(types[0]); | ||
for (var i = 1; i < len; i++) { | ||
var cir = getCodecIndexRecord(types[i]); | ||
for (var k in ir) { | ||
if (cir.hasOwnProperty(k)) { | ||
var is = ir[k]; | ||
var cis = cir[k]; | ||
var _loop_1 = function (j) { | ||
var pair = cis[j]; | ||
var index = is.findIndex(function (_a) { | ||
var v = _a[0]; | ||
return v === pair[0]; | ||
}); | ||
if (index === -1) { | ||
is.push(pair); | ||
} | ||
else if (cis[index][1] !== is[index][1]) { | ||
delete ir[k]; | ||
return "break-loop"; | ||
} | ||
}; | ||
loop: for (var j = 0; j < cis.length; j++) { | ||
var state_1 = _loop_1(j); | ||
switch (state_1) { | ||
case "break-loop": break loop; | ||
} | ||
} | ||
} | ||
else { | ||
delete ir[k]; | ||
} | ||
} | ||
} | ||
return types[i]; | ||
return ir; | ||
}; | ||
/** | ||
* @since 1.3.0 | ||
*/ | ||
exports.getTagValue = function (tag) { | ||
var f = function (type) { | ||
switch (type._tag) { | ||
case 'InterfaceType': | ||
case 'StrictType': | ||
return type.props[tag].value; | ||
case 'IntersectionType': | ||
return f(findTagged(tag, type.types)); | ||
case 'UnionType': | ||
return f(type.types[0]); | ||
case 'RefinementType': | ||
case 'ExactType': | ||
case 'RecursiveType': | ||
return f(type.type); | ||
var taggedUnionWithIndex = function (index, tag, types, name) { | ||
var len = types.length; | ||
var find = function (tagValue) { | ||
for (var i = 0; i < index.length; i++) { | ||
var pair = index[i]; | ||
if (pair[0] === tagValue) { | ||
return [i, pair[1]]; | ||
} | ||
} | ||
}; | ||
return f; | ||
var isTagValue = function (u) { return find(u) !== undefined; }; | ||
var TagValue = new Type(index.map(function (_a) { | ||
var v = _a[0]; | ||
return JSON.stringify(v); | ||
}).join(' | '), isTagValue, function (u, c) { return (isTagValue(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity); | ||
return new TaggedUnionType(name, function (u) { | ||
if (!exports.Dictionary.is(u)) { | ||
return false; | ||
} | ||
var tagValue = u[tag]; | ||
var type = find(tagValue); | ||
return type ? type[1].is(u) : false; | ||
}, function (u, c) { | ||
var dictionaryResult = exports.Dictionary.validate(u, c); | ||
if (dictionaryResult.isLeft()) { | ||
return dictionaryResult; | ||
} | ||
else { | ||
var d = dictionaryResult.value; | ||
var tagValue = d[tag]; | ||
var tagValueValidation = TagValue.validate(d[tag], exports.appendContext(c, tag, TagValue)); | ||
if (tagValueValidation.isLeft()) { | ||
return tagValueValidation; | ||
} | ||
var _a = find(tagValue), typeIndex = _a[0], type_8 = _a[1]; | ||
return type_8.validate(d, exports.appendContext(c, String(typeIndex), type_8)); | ||
} | ||
}, useIdentity(types, len) ? exports.identity : function (a) { return find(a[tag])[1].encode(a); }, types, tag); | ||
}; | ||
@@ -1079,53 +1187,14 @@ /** | ||
exports.taggedUnion = function (tag, types, name) { | ||
if (name === void 0) { name = "(" + types.map(function (type) { return type.name; }).join(' | ') + ")"; } | ||
var len = types.length; | ||
var values = new Array(len); | ||
var hash = {}; | ||
var useHash = true; | ||
var get = exports.getTagValue(tag); | ||
for (var i = 0; i < len; i++) { | ||
var value = get(types[i]); | ||
useHash = useHash && exports.string.is(value); | ||
values[i] = value; | ||
hash[String(value)] = i; | ||
if (name === void 0) { name = getUnionName(types); } | ||
var indexRecord = exports.getIndexRecord(types); | ||
if (!indexRecord.hasOwnProperty(tag)) { | ||
var message = "Cannot create a tagged union: " + name + " is not a tagged union with respect to \"" + tag + "\""; | ||
var candidates = Object.keys(indexRecord); | ||
if (candidates.length > 0) { | ||
message += ". Possible alternative candidates: " + JSON.stringify(candidates); | ||
} | ||
throw new Error(message); | ||
} | ||
var isTagValue = useHash | ||
? function (u) { return exports.string.is(u) && hasOwnProperty.call(hash, u); } | ||
: function (u) { return values.indexOf(u) !== -1; }; | ||
var getIndex = useHash | ||
? function (tag) { return hash[tag]; } | ||
: function (tag) { | ||
var i = 0; | ||
for (; i < len - 1; i++) { | ||
if (values[i] === tag) { | ||
break; | ||
} | ||
} | ||
return i; | ||
}; | ||
var TagValue = new Type(values.map(function (l) { return JSON.stringify(l); }).join(' | '), isTagValue, function (u, c) { return (isTagValue(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity); | ||
return new TaggedUnionType(name, function (v) { | ||
if (!exports.Dictionary.is(v)) { | ||
return false; | ||
} | ||
var tagValue = v[tag]; | ||
return TagValue.is(tagValue) && types[getIndex(tagValue)].is(v); | ||
}, function (s, c) { | ||
var dictionaryValidation = exports.Dictionary.validate(s, c); | ||
if (dictionaryValidation.isLeft()) { | ||
return dictionaryValidation; | ||
} | ||
else { | ||
var d = dictionaryValidation.value; | ||
var tagValueValidation = TagValue.validate(d[tag], exports.appendContext(c, tag, TagValue)); | ||
if (tagValueValidation.isLeft()) { | ||
return tagValueValidation; | ||
} | ||
else { | ||
var i = getIndex(tagValueValidation.value); | ||
var type_9 = types[i]; | ||
return type_9.validate(d, exports.appendContext(c, String(i), type_9)); | ||
} | ||
} | ||
}, useIdentity(types, len) ? exports.identity : function (a) { return types[getIndex(a[tag])].encode(a); }, types, tag); | ||
var index = indexRecord[tag]; | ||
return taggedUnionWithIndex(index, tag, types, name); | ||
}; | ||
@@ -1132,0 +1201,0 @@ /** |
{ | ||
"name": "io-ts", | ||
"version": "1.6.0", | ||
"version": "1.6.1", | ||
"description": "TypeScript compatible runtime type system for IO validation", | ||
@@ -5,0 +5,0 @@ "files": [ |
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
97925
2162