Rewrites word ranges: [a-zA-Z_0-9] -> \w
Thus, the ranges may go in any order, and other symbols/ranges
are kept untouched, e.g. [a-z_\dA-Z$] -> [\w$]
function rewriteWordRanges(path, hasIFlag, hasUFlag) {
  const {node} = path;

  let numberPath = null;
  let lowerCasePath = null;
  let upperCasePath = null;
  let underscorePath = null;
  let u017fPath = null;
  let u212aPath = null;

  node.expressions.forEach((expression, i) => {

    // \d
    if (isMetaChar(expression, '\\d')) {
      numberPath = path.getChild(i);
    }

    // a-z
    else if (isLowerCaseRange(expression)) {
      lowerCasePath = path.getChild(i);
    }

    // A-Z
    else if (isUpperCaseRange(expression)) {
      upperCasePath = path.getChild(i);
    }

    // _
    else if (isUnderscore(expression)) {
      underscorePath = path.getChild(i);
    }

    else if (hasIFlag && hasUFlag && isU017fPath(expression)) {
      u017fPath = path.getChild(i);
    }

    else if (hasIFlag && hasUFlag && isU212aPath(expression)) {
      u212aPath = path.getChild(i);
    }
  });

  // If we found the whole pattern, replace it.
  if (
    numberPath &&
    (
      (lowerCasePath && upperCasePath) ||
      (hasIFlag && (lowerCasePath || upperCasePath))
    ) &&
    underscorePath &&
    (!hasUFlag || !hasIFlag || (u017fPath && u212aPath))
  ) {

    // Put \w in place of \d.
    numberPath.replace({
      type: 'Char',
      value: '\\w',
      kind: 'meta',
    });

    // Other paths are removed.
    if (lowerCasePath) {
      lowerCasePath.remove();
    }
    if (upperCasePath) {
      upperCasePath.remove();
    }
    underscorePath.remove();
    if (u017fPath) {
      u017fPath.remove();
    }
    if (u212aPath) {
      u212aPath.remove();
    }
  }
}