Source: app/util/route-requirements/parseRouteRequirements.js

/* global WP_DEFINE_DEVELOPMENT */
import RouteRequirement from './RouteRequirement';

/**
 * Looks up the route requirements by looking at the `requirements` prop on the
 * given routes array. The `requirement` prop on child routes overrides those on parent
 * routes, so this function will only use the last `requirements` prop it can find.
 *
 * Returns an array of which route requirements must be met, based on the requirements
 * in the `requirements` prop **and its child requirements**.
 *
 * If none of the routes have a `requirements` prop defined, this will return an
 * empty array.
 * @param {Array} routes An array of react-router <Route> instances.
 * @returns {Array<RouteRequirement>} An array of RouteRequirement instances.
 * @category routing
 */
function parseRoutesRequirements(routes) {
  const lastRouteWithProp = routes.filter(route => typeof route.requirements !== 'undefined').pop();
  const requirementsProp = lastRouteWithProp ? lastRouteWithProp.requirements : [];
  const requirements = new Set();

  if (WP_DEFINE_DEVELOPMENT && lastRouteWithProp) {
    let routeDescription = `with path "${lastRouteWithProp.path}"`;
    if (!lastRouteWithProp.path && lastRouteWithProp.component) {
      routeDescription = `with component "${lastRouteWithProp.component.displayName ||
        lastRouteWithProp.component.name}"`;
    }
    if (!Array.isArray(requirementsProp)) {
      throw new TypeError(
        `Expected requirements to be an Array. Check "requirement" prop of route ${routeDescription}`,
      );
    }
    requirementsProp.forEach(requirement => {
      if (!(requirement instanceof RouteRequirement)) {
        throw new TypeError(
          `Elements in requirements should be instanceof RouteRequirement. Check "requirement" prop of route ${routeDescription}`,
        );
      }
    });
  }

  const addRequirements = requirementsToAdd => {
    requirementsToAdd.forEach(requirement => {
      addRequirements(requirement.childRequirements);

      requirements.add(requirement);
    });
  };
  addRequirements(requirementsProp);

  return Array.from(requirements);
}

export default parseRoutesRequirements;