UNPKG

@shopgate/pwa-common

Version:

Common library for the Shopgate Connect PWA.

134 lines (120 loc) 4.14 kB
import pathMatch from 'path-match'; import queryString from 'query-string'; /** * The Redirects class. */ let Redirects = /*#__PURE__*/function () { /** * The constructor. */ function Redirects() { this.redirects = new Map(); this.matcher = pathMatch({ sensitive: false, strict: false, end: true }); } /** * Returns a specified element from the internal "redirects" Map object. * @param {string} pathname The pathname to lookup. * @private * @returns {string|Function|Promise|null} */ var _proto = Redirects.prototype; _proto.get = function get(pathname) { return this.redirects.get(pathname) || null; } /** * Returns the redirect for a passed pathname. * @param {string} pathname The pathname to check. * @return {string|Function|Promise|null} */; _proto.getRedirect = function getRedirect(pathname) { /** * Try to make a direct match with the pathname. * If we get lucky then we don't have to iterate over the protected patterns. */ let redirect = this.get(pathname); /** * If we didn't find a direct match then we need to match * the given pathname against the protected patters. */ if (!redirect) { // Get the protected patterns as an array. const patterns = Array.from(this.redirects.keys()); const [withoutParams] = pathname.split('?'); // Loop over the patterns until a match is found. const patternMatch = patterns.find(pattern => !!this.matcher(pattern)(withoutParams)); // Match found, set the redirect. if (patternMatch) { redirect = this.redirects.get(patternMatch); } } return redirect; } /** * @typedef RedirectExtendedData * @property {string} matcher The value passed as "from" to set() * @property {string|Function|Promise} handler The value passed as "to" to set() * @property {Object} pathParams Decoded params from the pathname - defined within the matcher * @property {Object} queryParams Decoded query params from the pathname */ /** * Unlike "getRedirect" which only returns a matching handler for a passed pathname, this method * returns an object that contains some extended data. * * @param {string} pathname The pathname to check. * @returns {RedirectExtendedData} */; _proto.getRedirectExtended = function getRedirectExtended(pathname) { const { url, query } = queryString.parseUrl(pathname); // At the fist check if there is a redirect for the pathname const redirect = this.getRedirect(url); if (!redirect) { return null; } // Retrieve the matching pattern for the redirect from the redirects collection const [patternMatch] = Array.from(this.redirects.entries()).find(([, handler]) => handler === redirect) || []; const result = { handler: redirect, queryParams: JSON.parse(JSON.stringify(query)) }; if (patternMatch) { // decode params from route patterns (e.g. /item/:productCode) const matcherResult = this.matcher(patternMatch)(url); result.matcher = patternMatch; result.pathParams = matcherResult; } return result; } /** * Adds a redirect handler to the collection. * @param {string} from The link to redirect from. Route patterns are also supported. * @param {string|Function|Promise} to redirect / handle to create a dynamic link. * @param {boolean} force Whether or not to forcefully set the redirect. */; _proto.set = function set(from = null, to = null, force = false) { if (!from || !to) { return; } if (!force && this.redirects.has(from)) { return; } this.redirects.set(from, to); } /* eslint-disable extra-rules/potential-point-free */ /** * Removes a specified element from the internal "redirects" Map object. * @param {string} pathname The pathname to remove. */; _proto.unset = function unset(pathname) { this.redirects.delete(pathname); } /* eslint-enable extra-rules/potential-point-free */; return Redirects; }(); export default new Redirects();