common/helpers/utils.js

"use strict";

require("core-js/modules/es.symbol.js");
require("core-js/modules/es.object.get-own-property-descriptor.js");
require("core-js/modules/web.dom-collections.for-each.js");
require("core-js/modules/es.object.get-own-property-descriptors.js");
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.calIsbn10Chk = calIsbn10Chk;
exports.calIsbn13Chk = calIsbn13Chk;
exports.collapseWhiteSpaces = collapseWhiteSpaces;
exports.filterIdentifierTypesByEntityType = filterIdentifierTypesByEntityType;
exports.filterObject = filterObject;
exports.getAliasLanguageCodes = getAliasLanguageCodes;
exports.getEntity = getEntity;
exports.getEntityByBBID = getEntityByBBID;
exports.getEntityLink = getEntityLink;
exports.getEntityModelByType = getEntityModelByType;
exports.getEntityModels = getEntityModels;
exports.getNextEnabledAndResultsArray = getNextEnabledAndResultsArray;
exports.isValidBBID = isValidBBID;
exports.isbn10To13 = isbn10To13;
exports.isbn13To10 = isbn13To10;
exports.makePromiseFromObject = makePromiseFromObject;
exports.sanitize = sanitize;
exports.sortRelationshipOrdinal = sortRelationshipOrdinal;
exports.unflatten = unflatten;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
require("core-js/modules/es.regexp.exec.js");
require("core-js/modules/es.object.keys.js");
require("core-js/modules/es.object.values.js");
require("core-js/modules/es.array.iterator.js");
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/es.promise.js");
require("core-js/modules/es.string.iterator.js");
require("core-js/modules/web.dom-collections.iterator.js");
require("core-js/modules/es.regexp.constructor.js");
require("core-js/modules/es.regexp.to-string.js");
require("core-js/modules/es.string.replace.js");
require("core-js/modules/es.string.trim.js");
require("core-js/modules/es.string.split.js");
require("core-js/modules/es.array.concat.js");
require("core-js/modules/es.number.constructor.js");
require("core-js/modules/esnext.string.replace-all.js");
require("core-js/modules/es.array.join.js");
require("core-js/modules/es.array.filter.js");
require("core-js/modules/es.array.map.js");
require("core-js/modules/es.array.reduce.js");
require("core-js/modules/es.object.assign.js");
require("core-js/modules/es.date.to-json.js");
require("core-js/modules/web.url.to-json.js");
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _upperFirst2 = _interopRequireDefault(require("lodash/upperFirst"));
var _toString2 = _interopRequireDefault(require("lodash/toString"));
var _kebabCase2 = _interopRequireDefault(require("lodash/kebabCase"));
var _isString2 = _interopRequireDefault(require("lodash/isString"));
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
/**
 * Regular expression for valid BookBrainz UUIDs (bbid)
 *
 * @private
 */
var _bbidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;

/**
 * Tests if a BookBrainz UUID is valid
 *
 * @param {string} bbid - BookBrainz UUID to validate
 * @returns {boolean} - Returns true if BookBrainz UUID is valid
 */
function isValidBBID(bbid) {
  return _bbidRegex.test(bbid);
}

/**
 * Returns all entity models defined in bookbrainz-data-js
 *
 * @param {object} orm - the BookBrainz ORM, initialized during app setup
 * @returns {object} - Object mapping model name to the entity model
 */
function getEntityModels(orm) {
  var Author = orm.Author,
    Edition = orm.Edition,
    EditionGroup = orm.EditionGroup,
    Publisher = orm.Publisher,
    Series = orm.Series,
    Work = orm.Work;
  return {
    Author: Author,
    Edition: Edition,
    EditionGroup: EditionGroup,
    Publisher: Publisher,
    Series: Series,
    Work: Work
  };
}

/**
 * Retrieves the Bookshelf entity model with the given the model name
 *
 * @param {object} orm - the BookBrainz ORM, initialized during app setup
 * @param {string} type - Name or type of model
 * @throws {Error} Throws a custom error if the param 'type' does not
 * map to a model
 * @returns {object} - Bookshelf model object with the type specified in the
 * single param
 */
function getEntityModelByType(orm, type) {
  var entityModels = getEntityModels(orm);
  if (!entityModels[type]) {
    throw new Error("Unrecognized entity type: '".concat(type, "'"));
  }
  return entityModels[type];
}

/**
 * This function maps `{a: somePromise}` to a promise that
 * resolves with `{a: resolvedValue}`.
 * @param {object} obj - an object with Promises as values
 * @returns {Promise<object>} - A Promise resolving to the object with resolved values
 */

function makePromiseFromObject(obj) {
  var keys = Object.keys(obj);
  var values = Object.values(obj);
  return Promise.all(values).then(function (resolved) {
    var res = {};
    for (var i = 0; i < keys.length; i += 1) {
      res[keys[i]] = resolved[i];
    }
    return res;
  });
}

/**
 * This function sorts the relationship array
 * @param {string} sortByProperty - name of property which will be used for sorting
 * @returns {array} - sorted relationship array
 */
function sortRelationshipOrdinal(sortByProperty) {
  return function (a, b) {
    var value1 = a[sortByProperty] || '';
    var value2 = b[sortByProperty] || '';
    // eslint-disable-next-line no-undefined
    return value1.localeCompare(value2, undefined, {
      numeric: true
    });
  };
}

/**
 * This function repalces other space control character to U+0020 and trim extra spaces
 * @param {string} text - text to sanitize
 * @returns {string} - sanitized text
 */
function collapseWhiteSpaces(text) {
  // replace any whitespace space characters
  var spaceRegex = RegExp(/\s+/gi);
  var sanitizedText = text.replace(spaceRegex, " ");
  return sanitizedText.trim();
}

/**
 * This function is to sanitize text inputs
 * @param {string} text - text to sanitize
 * @returns {string} - sanitized text
 */
function sanitize(text) {
  if (!(0, _isString2.default)(text)) {
    return text;
  }
  // unicode normalization to convert text into normal text
  var sanitizeText = text.normalize('NFC');
  sanitizeText = collapseWhiteSpaces(sanitizeText);
  // eslint-disable-next-line no-control-regex
  // https://www.w3.org/TR/xml/#charsets remove invalid xml characters
  var invalidXMLRgx = RegExp(/[^\u0020-\uD7FF\uE000-\uFFFD]/gi);
  sanitizeText = sanitizeText.replace(invalidXMLRgx, '');
  // get rid of all control charcters
  var ccRegex = RegExp(/[\0-\x1F\x7F-\x9F\xAD\u200B]/g);
  sanitizeText = sanitizeText.replace(ccRegex, '');
  sanitizeText = collapseWhiteSpaces(sanitizeText);
  return sanitizeText;
}

/**
 * Takes a flatten object and convert it into unflatten one
 * eg. { "a.c": 2 } -> { "a": { "c" : 2 } }
 *
 * @param {Object} flattenObj the flattened object i.e in diasy chain form
 */

function unflatten(flattenObj) {
  var _result$;
  var result = {};
  var cur;
  var prop;
  var parts;
  if (Array.isArray(flattenObj) || Object(flattenObj) !== flattenObj) {
    return flattenObj;
  }
  for (var dotKey in flattenObj) {
    if (Object.prototype.hasOwnProperty.call(flattenObj, dotKey)) {
      cur = result;
      prop = '';
      parts = dotKey.split('.');
      for (var i = 0; i < parts.length; i++) {
        cur = cur[prop] || (cur[prop] = {});
        prop = parts[i];
      }
      cur[prop] = flattenObj[dotKey];
    }
  }
  return (_result$ = result['']) !== null && _result$ !== void 0 ? _result$ : {};
}

/**
 * Returns an API path for interacting with the given Bookshelf entity model
 *
 * @param {object} entity - Entity object
 * @returns {string} - URL path to interact with entity
 */
function getEntityLink(entity) {
  return "/".concat((0, _kebabCase2.default)(entity.type), "/").concat(entity.bbid);
}
function getNextEnabledAndResultsArray(array, size) {
  if (array.length > size) {
    while (array.length > size) {
      array.pop();
    }
    return {
      newResultsArray: array,
      nextEnabled: true
    };
  }
  return {
    newResultsArray: array,
    nextEnabled: false
  };
}

/**
 * Calculate check digit for isbn10
 * @param {string} isbn ISBN-10
 * @returns {string} check digit
 */

function calIsbn10Chk(isbn) {
  var digits = [];
  var sum = 0;
  var chkDigit;
  digits = "".concat(isbn).substring(0, 9).split('');
  for (var i = 0; i < 9; i++) {
    sum += digits[i] * (10 - i);
  }
  var chkTmp = 11 - sum % 11;
  switch (chkTmp) {
    case 10:
      chkDigit = 'X';
      break;
    case 11:
      chkDigit = 0;
      break;
    default:
      chkDigit = chkTmp;
      break;
  }
  return (0, _toString2.default)(chkDigit);
}

/**
 * Calculate check digit for isbn13
 * @param {string} isbn ISBN-13
 * @returns {string} check digit
 */
function calIsbn13Chk(isbn) {
  var totalSum = 0;
  for (var i = 0; i < 12; i++) {
    totalSum += Number(isbn.charAt(i)) * (i % 2 === 0 ? 1 : 3);
  }
  var lastDigit = (10 - totalSum % 10) % 10;
  return (0, _toString2.default)(lastDigit);
}

/**
 * Convert ISBN-10 to ISBN-13
 * @param {string} isbn10 valid ISBN-10
 * @returns {string} ISBN-13
 */

function isbn10To13(isbn10) {
  var isbn10Regex = RegExp(/^(?=[0-9X]{10}$|(?=(?:[0-9]+[- ]){3})[- 0-9X]{13}$)[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9X]$/);
  if (!isbn10Regex.test(isbn10)) {
    return null;
  }
  var tempISBN10 = "".concat(isbn10).replaceAll('-', '');
  var isbn13 = "978".concat(tempISBN10.substring(0, 9));
  var lastDigit = calIsbn13Chk(isbn13);
  return isbn13 + lastDigit;
}

/**
 * Convert ISBN-13 to ISBN-10
 * @param {string} isbn13 valid ISBN-13
 * @returns {string} ISBN-10
 */

function isbn13To10(isbn13) {
  var isbn13Regex = RegExp(/^(?=[0-9]{13}$|(?=(?:[0-9]+[- ]){1,4})[- 0-9]{14,17}$)978[- ]?[0-9]{1,5}[- ]?[0-9]+[- ]?[0-9]+[- ]?[0-9]$/);
  if (!isbn13Regex.test(isbn13)) {
    return null;
  }
  var tempISBN13 = isbn13.replaceAll('-', '');
  var digits = tempISBN13.substring(3, 12).split('');
  digits.push(calIsbn10Chk(digits.join('')));
  return digits.join('');
}
function filterIdentifierTypesByEntityType(identifierTypes, entityType) {
  return identifierTypes.filter(function (type) {
    return type.entityType === entityType;
  });
}

/**
 *
 * @param {Object} orm - orm
 * @param {string} bbid - bookbrainz id
 * @param {Array} otherRelations - entity specific relations to fetch
 * @returns {Promise} - Promise resolves to entity data if exist else null
 */
function getEntityByBBID(_x, _x2) {
  return _getEntityByBBID.apply(this, arguments);
}
function _getEntityByBBID() {
  _getEntityByBBID = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(orm, bbid) {
    var otherRelations,
      Entity,
      redirectBbid,
      entity,
      entityType,
      baseRelations,
      entityData,
      _args = arguments;
    return _regenerator.default.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            otherRelations = _args.length > 2 && _args[2] !== undefined ? _args[2] : [];
            if (isValidBBID(bbid)) {
              _context.next = 3;
              break;
            }
            return _context.abrupt("return", null);
          case 3:
            Entity = orm.Entity;
            _context.next = 6;
            return orm.func.entity.recursivelyGetRedirectBBID(orm, bbid, null);
          case 6:
            redirectBbid = _context.sent;
            _context.next = 9;
            return new Entity({
              bbid: redirectBbid
            }).fetch({
              require: false
            });
          case 9:
            entity = _context.sent;
            if (entity) {
              _context.next = 12;
              break;
            }
            return _context.abrupt("return", null);
          case 12:
            entityType = entity.get('type');
            baseRelations = ['annotation', 'disambiguation', 'defaultAlias', 'relationshipSet.relationships.type', 'aliasSet.aliases', 'identifierSet.identifiers'].concat((0, _toConsumableArray2.default)(otherRelations));
            _context.next = 16;
            return orm.func.entity.getEntity(orm, entityType, bbid, baseRelations);
          case 16:
            entityData = _context.sent;
            return _context.abrupt("return", entityData);
          case 18:
          case "end":
            return _context.stop();
        }
      }
    }, _callee);
  }));
  return _getEntityByBBID.apply(this, arguments);
}
function getEntity(_x3, _x4, _x5, _x6) {
  return _getEntity.apply(this, arguments);
}
function _getEntity() {
  _getEntity = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(orm, bbid, type, fetchOptions) {
    var finalBBID, Model, entity;
    return _regenerator.default.wrap(function _callee2$(_context2) {
      while (1) {
        switch (_context2.prev = _context2.next) {
          case 0:
            if (isValidBBID(bbid)) {
              _context2.next = 2;
              break;
            }
            return _context2.abrupt("return", null);
          case 2:
            _context2.next = 4;
            return orm.func.entity.recursivelyGetRedirectBBID(orm, bbid);
          case 4:
            finalBBID = _context2.sent;
            Model = getEntityModelByType(orm, (0, _upperFirst2.default)(type));
            _context2.next = 8;
            return new Model({
              bbid: finalBBID
            }).fetch(_objectSpread({
              require: true
            }, fetchOptions));
          case 8:
            entity = _context2.sent;
            return _context2.abrupt("return", entity && entity.toJSON());
          case 10:
          case "end":
            return _context2.stop();
        }
      }
    }, _callee2);
  }));
  return _getEntity.apply(this, arguments);
}
function getAliasLanguageCodes(entity) {
  var _entity$aliasSet$alia, _entity$aliasSet;
  return (_entity$aliasSet$alia = (_entity$aliasSet = entity.aliasSet) === null || _entity$aliasSet === void 0 ? void 0 : _entity$aliasSet.aliases.map(function (alias) {
    var _alias$language;
    return (_alias$language = alias.language) === null || _alias$language === void 0 ? void 0 : _alias$language.isoCode1;
  })
  // less common languages (and [Multiple languages]) do not have a two-letter ISO code, ignore them for now
  .filter(function (language) {
    return language !== null;
  }) // eslint-disable-next-line operator-linebreak -- fallback refers to the whole optional chain
  ) !== null && _entity$aliasSet$alia !== void 0 ? _entity$aliasSet$alia : [];
}
function filterObject(obj, filter) {
  return Object.keys(obj).filter(function (key) {
    return filter(obj[key]);
  }).reduce(function (res, key) {
    return Object.assign(res, (0, _defineProperty2.default)({}, key, obj[key]));
  }, {});
}
//# sourceMappingURL=utils.js.map