<commit_before><cfscript>

  // PUBLIC UTILITIES

  public string function normalizePattern(required string pattern) {

    local.pattern = REReplace(arguments.pattern, "(^/+|/+$)", "", "ALL");
    local.pattern = REReplace(local.pattern, "/+\.", ".", "ALL");
    return "/" & Replace(local.pattern, "//", "/", "ALL");
  }

  public string function patternToRegex(
    required string pattern, struct constraints={})
    hint="Transform route pattern into regular expression" {

    // escape any dots in pattern, and further mask pattern variables
    // NOTE: this keeps constraint patterns from being replaced twice
    local.regex = REReplace(arguments.pattern, "([.])", "\\1", "ALL");
    local.regex = REReplace(local.regex, "\[(\*?\w+)\]", ":::\1:::", "ALL");

    // replace known variable keys using constraints
    local.constraints = StructCopy(arguments.constraints);
    StructAppend(local.constraints, variables.constraints, false);
    for (local.key in local.constraints)
      local.regex = REReplaceNoCase(
          local.regex
        , ":::#local.key#:::"
        , "(#local.constraints[local.key]#)"
        , "ALL"
      );

    // replace remaining variables with default regex
    local.regex = REReplace(local.regex, ":::\w+:::", "([^./]+)", "ALL");
    return REReplace(local.regex, "^/*(.*)/*$", "^\1/?$");
  }

  public string function stripRouteVariables(required string pattern)
    hint="Pull list of variables out of route pattern" {
    return REReplace(ArrayToList(REMatch("\[\*?(\w+)\]", arguments.pattern)), "[\*\[\]]", "", "ALL");
  }

  // PRIVATE UTILITIES

  private void function $addRoute()
    hint="Add route to cfwheels, removing useless params" {

    // remove controller and action if they are route variables
    if (Find("[controller]", arguments.pattern) AND StructKeyExists(arguments, "controller"))
      StructDelete(arguments, "controller");
    if (Find("[action]", arguments.pattern) AND StructKeyExists(arguments, "action"))
      StructDelete(arguments, "action");

    // normalize pattern, convert to regex, and strip out variable names
    arguments.pattern = normalizePattern(arguments.pattern);
    arguments.regex = patternToRegex(arguments.pattern, arguments.constraints);
    arguments.variables = stripRouteVariables(arguments.pattern);

    // add route to cfwheels
    ArrayAppend(application[$appKey()].routes, arguments);
  }

  private string function $member()<commit_msg>fix regex to escape forward slash. fix normalizePattern to fix slashs in middle of string. add arguments to $addRoute<commit_after><cfscript>

  // PUBLIC UTILITIES

  public string function normalizePattern(required string pattern)
    hint="Force leading slashes, remove trailing and duplicate slashes" {
    // first clear the ending slashes
    local.pattern = REReplace(arguments.pattern, "(^\/+|\/+$)", "", "ALL");
    // reset middle slashes to singles if they are multiple
    local.pattern = REReplace(local.pattern, "\/+", "/", "ALL");
    // remove a slash next to a period
    local.pattern = REReplace(local.pattern, "\/+\.", ".", "ALL");
    // return with a prepended slash
    return "/" & Replace(local.pattern, "//", "/", "ALL");
  }

  public string function patternToRegex(
    required string pattern, struct constraints={})
    hint="Transform route pattern into regular expression" {

    // escape any dots in pattern, and further mask pattern variables
    // NOTE: this keeps constraint patterns from being replaced twice
    local.regex = REReplace(arguments.pattern, "([.])", "\\1", "ALL");
    local.regex = REReplace(local.regex, "\[(\*?\w+)\]", ":::\1:::", "ALL");

    // replace known variable keys using constraints
    local.constraints = StructCopy(arguments.constraints);
    StructAppend(local.constraints, variables.constraints, false);
    for (local.key in local.constraints)
      local.regex = REReplaceNoCase(
          local.regex
        , ":::#local.key#:::"
        , "(#local.constraints[local.key]#)"
        , "ALL"
      );

    // replace remaining variables with default regex
    local.regex = REReplace(local.regex, ":::\w+:::", "([^.\/]+)", "ALL");
    return REReplace(local.regex, "^\/*(.*)\/*$", "^\1/?$");
  }

  public string function stripRouteVariables(required string pattern)
    hint="Pull list of variables out of route pattern" {
    local.matchArray = arrayToList(REMatch("\[\*?(\w+)\]", arguments.pattern));
    return REReplace(local.matchArray, "[\*\[\]]", "", "ALL");
  }

  // PRIVATE UTILITIES

  private void function $addRoute(
    required string pattern, required struct constraints)
    hint="Add route to cfwheels, removing useless params" {

    // remove controller and action if they are route variables
    if (Find("[controller]", arguments.pattern)
        AND StructKeyExists(arguments, "controller"))
      StructDelete(arguments, "controller");
    if (Find("[action]", arguments.pattern)
        AND StructKeyExists(arguments, "action"))
      StructDelete(arguments, "action");

    // normalize pattern, convert to regex, and strip out variable names
    arguments.pattern = normalizePattern(arguments.pattern);
    arguments.regex = patternToRegex(arguments.pattern, arguments.constraints);
    arguments.variables = stripRouteVariables(arguments.pattern);

    // add route to cfwheels
    ArrayAppend(application[$appKey()].routes, arguments);
  }

  private string function $member()
{'fraction_non_alphanumeric': 0.15420044215180545, 'fraction_numerical': 0.001105379513633014, 'mean_word_length': 3.656089193825043, 'pattern_counts': {'":': 6, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2946188', 'n_tokens_mistral': 1552, 'n_tokens_neox': 1483, 'n_words': 418}