All files Type.js

97.22% Statements 35/36
96.55% Branches 28/29
100% Functions 18/18
96.55% Lines 28/29
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78      4x 126x           4x                               4x 26x             23x     193x   197x 14x   183x 183x 11x 42x 34x 13x 12x   22x 11x 21x   12x 11x               4x 78x 69x   67x 67x   67x   54x          
import { values, isList, isObject, createEnumFactory } from './utils';
 
// Tiny ArgLessEnum to bypass the circular dependency shithole
const ArgLessEnum = createEnumFactory({
    createConstructor: (Type, constr) => (...args) => ({ ...constr, args }),
});
 
// type Type = Type|String;
 
// Cant use Type to define Type so ArgLessEnum
const Type = ArgLessEnum([
    'Any',
    'String',
    'Number',
    'Bool',
 
    'List',
    'Map',
    'Record',
 
    'Func',
    'Enum',
    'OneOf',
]);
 
// validateList :: (Type, [a]) -> Boolean
const validateList = (innerType, list) =>
    isList(list) && (
        (innerType && list.length > 0)
            ? list.length === [...list].filter(isOfType(innerType)).length
            : true
    );
 
// validateRecord :: Object Type -> Object a -> Boolean
export const validateRecord = (shape, obj) => validateArgs(values(shape), values(obj));
 
// isOfType :: Type -> a -> Boolean
export const isOfType = type => value => {
    // Dynamic argument description
    if(typeof type === 'string' && value !== undefined)
        return true;
 
    Eif (Type.isConstructor(type)) {
        return !!Type.match(type, {
            Any: () => true,
            String: () => typeof value === 'string',
            Number: () => typeof value === 'number',
            Bool: () => typeof value === 'boolean',
            Func: () => typeof value === 'function',
 
            List: innerType => validateList(innerType, value),
            Map: innerType => innerType && isObject(value) && validateList(innerType, values(value)),
            Record: shape => isObject(value) && (shape ? validateRecord(shape, value) : true),
 
            OneOf: typeList => !![...typeList].filter(type => isOfType(type)(value)).length,
            Enum: InnerType => value && InnerType.isConstructor(value),
        });
    }
 
    return false;
};
 
// validateArgs :: ([Type], [a]) -> Bool
export const validateArgs = (typeList, valueList) => {
    if(typeList.length !== valueList.length) return false;
    if(typeList.length === 0) return true;
 
    const [type, ...types] = typeList;
    const [val, ...vals] = valueList;
 
    if(!isOfType(type)(val)) return false;
 
    return types.length > 0 ? validateArgs(types, vals) : true;
};
 
export default Type;