HEX
Server: nginx/1.24.0
System: Linux nowruzgan 6.8.0-57-generic #59-Ubuntu SMP PREEMPT_DYNAMIC Sat Mar 15 17:40:59 UTC 2025 x86_64
User: babak (1000)
PHP: 8.3.6
Disabled: NONE
Upload Files
File: /var/dev/nowruzgan/rest/node_modules/sort-route-addresses/index.js
/**
 * Module dependencies.
 */
var _ = require('@sailshq/lodash');

module.exports = function sortRouteAddresses (addresses, options) {

  // Ensure options is an object.
  options = options || {};

  // Regular expression to test whether an address corresponds to a
  // Sails regex route.
  var regExRoute = /^r\|(.*)\|(.*)$/;

  // First, find the # of components in the longest route path.
  var maxComponents = _.reduce(addresses, function(memo, address) {

    // Parse the path out of the address.
    var addressInfo = parseAddress(address);
    var path = addressInfo.path;

    // If the path is a Sails regex, skip it (unless we're instructed not to)
    if (path.match(regExRoute) && !options.sortRegexes) {
      return memo;
    }

    // Split the path into components.
    var components = path.split('/');

    // The first part should be blank (since routes should start with /),
    // but gracefully handle the case of routes not starting with /
    if (components[0] === '') {
      components.shift();
    }

    // If this path has more components than the max we've encountered so far,
    // make it the new max.
    if (components.length > memo) {memo = components.length;}

    return memo;

  }, 0);

  // Declare a var to hold the last rank produced
  // (used for sorting regex addresses)
  var lastRank = Array(maxComponents).fill(0).join('');

  // Now create a dictionary mapping ranks to addresses.
  var rankedAddresses = _.reduce(addresses, function(memo, address) {

    // Get the verb and path from the address.
    var addressInfo = parseAddress(address);
    var path = addressInfo.path;
    var verb = addressInfo.verb;

    // If the path represents a Sails regex address, and we're not told
    // explicitly to sort it, just give it the same rank as the whatever
    // address we saw last.  This means it'll be placed directly after
    // whichever address it was following in the unsorted address list.
    if (path.match(regExRoute) && !options.sortRegexes) {
      rank = lastRank;
      memo[rank] = memo[rank] || [];
      memo[rank].push(address);
      return memo;
    }

    // Declare a flag indicating whether a (non-"all") verb was specified.
    var hasVerb = (verb && verb !== 'all');

    // Split the path int components.
    var components = path.split('/');

    // The first component should be blank (since routes should start with /),
    // but gracefully handle the case of routes not starting with /
    if (components[0] === '') {
      components.shift();
    }

    // Declare a flag indicating whether the path contains a wildcard component.
    var seenWildcard = false;

    // Declare a flag indicating whether the path contains a static component.
    var seenStatic = false;

    // Declare a string to hold the route address rank as we build it.
    var rank = '';

    // Iterate from 0 to maxComponents, examining this particular address's component
    // at each index (if any) and assigning it a value.
    for (var i = 0; i < maxComponents; i++) {

      // If the current route address has a component at the current index (i.e. it has
      // at least `i+1` components)...
      if (components[i]) {
        // Add a '3' for each wildcard.
        if (components[i] === '*' || components[i] === '?*') {
          rank += '3';
          // Indicate that this address has a wildcard.
          seenWildcard = true;
        }
        // Add a `2` for each param.
        else if (components[i][0] === ':') {
          rank += '2';
        }
        // Add a `1` for each static path component.
        else {
          rank += '1';
          // Indicate that this address has a static component.
          seenStatic = true;
        }
      }
      // If the current route address does NOT have a component at the current index
      // (i.e. it has fewer than `i+1` components)...
      else {
        // Add a `4` to pad out spaces if the address has any wildcards.
        if (seenWildcard) {
          rank += '4';
        }
        // Add a `0` to pad out spaces if no wildcard has been seen.
        else {
          rank += '0';
        }
      }
    }

    // Add a final 0 or 1 to ensure that routes with no verb come after
    // ranks with a verb specified.
    if (hasVerb) {
      rank += '0';
    }
    else {
      rank += '1';
    }

    // Add a `5` to the beginning of the rank if the address has _no_ static
    // components, to ensure that _all_ routes with at least one static component
    // is bound before _any_ route without one.
    if (!seenStatic) {
      rank = '5' + rank;
    }

    // More than one address may end up with the same rank, so we'll map each
    // rank to an _array_ of addresses.
    memo[rank] = memo[rank] || [];
    memo[rank].push(address);

    // Update `lastRank`.
    lastRank = rank;

    return memo;

  }, {});

  // If we are being asked to just return the ranked addresses, do so now.
  if (options.returnRanked) {
    return rankedAddresses;
  }

  // Sort the ranks.
  var sortedRanks = _.keys(rankedAddresses).sort();

  // Get the final sorted list of addresses.
  var sortedAddresses = _.reduce(sortedRanks, function(memo, rank) {
    memo = memo.concat(rankedAddresses[rank]);
    return memo;

  }, []);

  // Return the final sorted list.
  return sortedAddresses;

};

function parseAddress(address) {
  var path = address.toLowerCase();
  var verbExpr = /^(all|get|post|put|delete|trace|options|connect|patch|head)\s+/i;
  var verbSpecified = _.last(address.match(verbExpr) || []) || '';
  verbSpecified = verbSpecified.toLowerCase();

  // If a verb was specified, eliminate the verb from the original string
  if (verbSpecified) {
    path = path.replace(verbExpr, '');
  }

  return {
    verb: verbSpecified,
    path: path
  };

}