variant-type
Version:
A Variant is a data structure that can be used to represent any other data type.
75 lines (72 loc) • 2.38 kB
JavaScript
var checkArgTypes = require('check-arg-types');
var hasProp = Object.prototype.hasOwnProperty;
var DEFAULT_HANDLER = "_";
function getTestFunc(f) {
var str = f.toString();
if (str.includes("native code")) {
return function (v) {
return checkArgTypes.toType(v) === checkArgTypes.toType(f());
};
} else {
return f;
}
}
function VariantFactory(types) {
var Variant = {};
var typeNames = Object.keys(types).concat([DEFAULT_HANDLER]);
if (typeNames.includes("case")) {
throw new Error("`case` is a reserved key!");
}
var checkArgs = function checkArgs(args, caseKey) {
if (caseKey === DEFAULT_HANDLER) {
return;
}
var len = types[caseKey].length;
if (args.length !== len) {
throw new Error("Arguments did not match for " + caseKey + ": Expected " + len + ", Received " + args.length);
}
var validators = types[caseKey];
for (var x = 0; x < len; x++) {
var validator = validators[x];
var value = args[x];
if (!getTestFunc(validator)(value)) {
throw new TypeError("\"" + value + "\" is not a valid " + validator.name + "!");
}
}
};
typeNames.forEach(function (type) {
Variant[type] = function TypeClosure() {
var args = [].slice.call(arguments);
checkArgs(args, type);
args.type = type;
return args;
};
});
function caseFunc(cases) {
var Cases = {};
var caseKeys = Object.keys(cases);
caseKeys.forEach(function (caseKey) {
if (!typeNames.includes(caseKey)) {
throw new Error("Invalid case key given for Variant: `" + caseKey + "` not in [" + typeNames.join(", ") + "]");
}
Cases[caseKey] = function TypeCase() {
var args = Array.prototype.slice.call(arguments);
checkArgs(args, caseKey);
return cases[caseKey].apply(null, args);
};
});
return function handleCaseValue(getType) {
var args = typeof getType === "function" ? getType() : getType;
var handler = hasProp.call(Cases, args.type) ? Cases[args.type] : Cases[DEFAULT_HANDLER];
if (!handler) {
throw new Error("No handler found for case: " + args.type);
}
return handler.apply(null, args);
};
}
Variant["case"] = caseFunc;
Variant.on = caseFunc;
return Object.freeze(Variant);
}
module.exports = VariantFactory;
//# sourceMappingURL=variant-type.js.map