import flatten from 'lodash/flatten';
import debugLib from 'debug';
const debug = debugLib('SlimmingWorld:PathAliasManager');
/**
* Utility that manages loading and resolving simple path aliases (mappings from one path
* to another path).
*/
class PathAliasManager {
aliasConfigs = [];
/**
* Resolves aliases for the given path. Will load in any configuration added with addConfig,
* if they had not been loaded already.
* @param path {string} The requested path
* @param injectParams {Object} The parameters that will be injected to the getAliases callback
* of the configs. These should contain the redux store dispatch and getState.
* @returns {Promise<boolean|string>} A promise that resolves with the path that should be
* redirected to, or `false` if no matching aliases have been found.
*/
async handleRequest(path, injectParams) {
const aliases = flatten(
await Promise.all(
this.aliasConfigs
.filter(({ scope }) => path.startsWith(scope))
.map(config => config.aliases || this.getAliases(config, injectParams)),
),
);
const matchingAlias = aliases.find(({ from }) => this.matchesFrom(path, from));
if (matchingAlias) {
debug(`Found alias "${matchingAlias.from} that matched path "${path}"`);
return matchingAlias.to;
}
return false;
}
/**
* Tests if the `from` property of an alias matches a given path. Currently does a strict
* equality check, but we may add additional pattern matching here.
* @param path {string} The path to check
* @param from {string} The `from` property of an alias configuration
* @returns {boolean}
*/
matchesFrom = (path, from) => path === from;
getAliases = (config, injectParams) => {
debug(`Loading aliases for config with scope "${config.scope}"`);
return Promise.resolve(config.getAliases(injectParams)).then(aliases => {
debug(`Aliases for config with scope "${config.scope}" loaded`);
config.aliases = aliases; // eslint-disable-line no-param-reassign
return aliases;
});
};
/**
* Add aliases to the configuration
* @param getAliases {function} A callback that retrieves the aliases configuration. This function
* will only be called once the user navigates to a path that falls within the scope of this
* configuration. The function will receive the parameters that the page renderer passes to the
* `injectParams` parameter of the `handleRequest` method. This function should return an object
* or a Promise that resolves with an object of the following shape:
* ```
* [
* { from: 'from path', to: 'to path' },
* { from: 'from path', to: 'to path' },
* ...
* ]
* ```
* @param scope {string} The paths that are included in this config. Once the user navigates
* to a path that starts with this string, the `getAliases` callback will be called to load
* the aliases configuration.
*/
addConfig(getAliases, scope = '/') {
this.aliasConfigs.push({ getAliases, scope, aliases: null });
}
}
export default PathAliasManager;