@boomerang-io/utils
Version:
A library of reusable utilities and hooks for React webapps on the Boomerang platform.
315 lines (234 loc) • 13.2 kB
JavaScript
;
function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.transform = transform;
exports.transformAll = transformAll;
exports.transformObject = transformObject;
var yup = _interopRequireWildcard(require("yup"));
var _customValidators = require("./customValidators");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _toArray(arr) { return _arrayWithHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableRest(); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var ValidationError = /*#__PURE__*/_createClass(function ValidationError(message) {
_classCallCheck(this, ValidationError);
this.message = message;
});
/**
* Searches for {substring} in {string}.
* If found, returns the {string}, sliced after substring.
*
* @param {string} string - String to be sliced.
* @param {string} substring - String to search for.
* @returns {string|null} Null if no match found.
*/
function getSubString(string, substring) {
if (!string) return null;
var testedIndex = string.indexOf(substring);
if (testedIndex > -1) {
return string.slice(testedIndex + substring.length);
}
return null;
}
/**
* Returns a function from yup, by passing in a function name from our schema.
* @param {string} functionName - The string to search for a function.
* @param {Object} previousInstance - Object from previous validator result or yup itself.
* @returns {Function} Either the found yup function or the default validator.
*/
function getYupFunction(functionName) {
var previousInstance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : yup;
// Make sure we're dealing with a string
if (functionName instanceof Array) {
functionName = functionName[0];
} // Attempt to retrieve any custom validators first
var customValidator = (0, _customValidators.getCustomValidator)(functionName);
if (customValidator) {
return customValidator;
}
var yupName = getSubString(functionName, "yup.");
if (yupName && previousInstance[yupName] instanceof Function) {
return previousInstance[yupName].bind(previousInstance);
}
if (yupName && yup[yupName] instanceof Function) {
return yup[yupName].bind(yup);
}
throw new ValidationError("Could not find validator " + functionName);
}
/**
* Here we check to see if a passed array could be a prefix notation function.
* @param {Array} item - Item to be checked.
* @param {any} item.functionName - We'll check this, and perhaps it's a prefix function name.
* @returns {boolean} True if we are actually looking at prefix notation.
*/
function isPrefixNotation(_ref) {
var _ref2 = _slicedToArray(_ref, 1),
functionName = _ref2[0];
if (functionName instanceof Array) {
if (isPrefixNotation(functionName)) return true;
}
if (typeof functionName !== "string") return false;
if (functionName.indexOf("yup.") < 0) return false;
return true;
}
/**
* Ensure that the argument passed is an array.
* @param {Any} maybeArray - To be checked.
* @returns {Array} forced to array.
*/
function ensureArray(maybeArray) {
if (maybeArray instanceof Array === false) {
return [maybeArray];
}
return maybeArray;
}
/**
* Converts an array of ['yup.number'] to yup.number().
* @param {[Any]} arrayArgument - The validation array.
* @param {Object} previousInstance - The result of a call to yup.number()
* i.e. an object schema validation set
* @returns {Function} generated yup validator
*/
function convertArray(arrayArgument) {
var previousInstance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : yup;
var _ensureArray = ensureArray(arrayArgument),
_ensureArray2 = _toArray(_ensureArray),
functionName = _ensureArray2[0],
argsToPass = _ensureArray2.slice(1); // Handle the case when we have a previous instance
// but we don't want to use it for this transformation
// [['yup.array'], ['yup.of', [['yup.object'], ['yup.shape'] ...]]]
if (functionName instanceof Array) {
return transformArray(arrayArgument);
}
var gotFunc = getYupFunction(functionName, previousInstance, arrayArgument); // Here we'll actually call the function
// This might be something like yup.number().min(5)
// We could be passing different types of arguments here
// so we'll try to transform them before calling the function
// yup.object().shape({ test: yup.string()}) should also be transformed
var convertedArguments = transformAll(argsToPass, previousInstance); // Handle the case when we've got an array of empty elements
if (convertedArguments instanceof Array) {
if (convertedArguments.filter(function (i) {
return i;
}).length < 1) {
return gotFunc();
} // Spread the array over the function
return gotFunc.apply(void 0, _toConsumableArray(convertedArguments));
} // Handle the case when we're passing another validator
return gotFunc(convertedArguments);
}
/**
* Transforms an array JSON schema to yup array schema.
*
* @param {Array} jsonArray - array in JSON to be transformed.
* @returns {Array} Array with same keys, but values as yup validators.
*/
function transformArray(jsonArray) {
var previousInstance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : yup;
var toReturn = convertArray(jsonArray[0]);
jsonArray.slice(1).forEach(function (item) {
// Found an array, move to prefix extraction
if (item instanceof Array) {
toReturn = convertArray(item, toReturn);
return;
} // Found an object, move to object extraction
if (item instanceof Object) {
toReturn = transformObject(item, previousInstance);
return;
} // Handle an edge case where we have something like
// [['yup.ref', 'linkName'], 'custom error'], and we don't want
// to consume 'custom error as a variable yet'
if (toReturn instanceof Array) {
toReturn = toReturn.concat(item);
return;
}
toReturn = [toReturn, item];
});
return toReturn;
}
/**
* Transforms an object JSON schema to yup object schema.
*
* @param {Object} jsonObject - Object in JSON to be transformed.
* @returns {Object} Object with same keys, but values as yup validators.
*/
function transformObject(jsonObject) {
var previousInstance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : yup;
var toReturn = {};
Object.entries(jsonObject).forEach(function (_ref3) {
var _ref4 = _slicedToArray(_ref3, 2),
key = _ref4[0],
value = _ref4[1];
// Found an array move to array extraction
if (value instanceof Array) {
toReturn[key] = transformArray(value, previousInstance);
return;
} // Found an object recursive extraction
if (value instanceof Object) {
toReturn[key] = transformObject(value, previousInstance);
return;
}
toReturn[key] = value;
});
return toReturn;
}
/**
* Steps into arrays and objects and resolve the items inside to yup validators.
* @param {Any} jsonObjectOrArray - Object to be transformed.
* @returns {yup.Validator}
*/
function transformAll(jsonObjectOrArray) {
var previousInstance = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : yup;
// We're dealing with an array
// This could be a prefix notation function
// If so, we'll call the converter
if (jsonObjectOrArray instanceof Array) {
if (isPrefixNotation(jsonObjectOrArray)) {
return transformArray(jsonObjectOrArray, previousInstance);
}
return jsonObjectOrArray.map(function (i) {
return transformAll(i, previousInstance);
});
} // If we're dealing with an object
// we should check each of the values for that object.
// Some of them may also be prefix notation functiosn
if (jsonObjectOrArray instanceof Object) {
return transformObject(jsonObjectOrArray, previousInstance);
} // No case here, just return anything else
return jsonObjectOrArray;
}
/**
* Can transform arrays or an object into a single validator.
* This should be your initial entrypoint.
*
* @param {Any} jsonObjectOrArray - Object to be transformed.
* @returns {yup.Validator}
*/
function transform(jsonObjectOrArray) {
try {
if (jsonObjectOrArray instanceof Object) {
return transformAll([// build a custom validator which takes an object as parameter
// If we don't do this, we'll get back an object of validators
["yup.object"], ["yup.required"], ["yup.shape", jsonObjectOrArray]]);
} // No case here, just return anything else
return transformAll(jsonObjectOrArray);
} catch (error) {
if (error instanceof ValidationError) {
throw new Error("Could not validate " + JSON.stringify(jsonObjectOrArray, null, 4) + "\n".concat(error.message));
}
throw error;
}
}