Today I am going to go through AngularJS’s urlUtils.js file and see what we can learn from going it. Documentation, this file has a lot of it, and most of the documentation is used for generating their documents, a feature I like but also one that tends make the code hard to read unless you have a good IDE that allows you to collapse it. So the first lesson is, make sure you have a good IDE that helps keep in focus the area of the code that you are working on, whether documentation or code. (I have never been in the case where one would work on both at the same time.) For this reason, I have removed all the JSDoc comments, and now we are left with the comments and code.

The first thing I come to that could use some clarity is this area of code:

// Support: IE 9-11 only, Edge 16-17 only (fixed in 18 Preview)
// IE/Edge don't wrap IPv6 addresses' hostnames in square brackets
// when parsed out of an anchor element. var ipv6InBrackets = urlParsingNode.hostname === '[::1]';

This variable is set to true/false based on if the hostname is in brackets. This lengthy comment tells us its purpose, where we could use a function name to describe the same thing. Also, upon reviewing the code, this variable is only used once and should be moved closer to its usage. We need to keep the scope of our variables to where they are used.

function hostnameInBrackets() {
    return urlParsingNode.hostname === '[::1]';
}

After making this update, I noticed that this is only being used to update the hostname if no brackets have been found for the hostname.

var hostname = urlParsingNode.hostname;

  if (!hostnameInBrackets() && hostname.indexOf(':') > -1) {
    hostname = '[' + hostname + ']';
  }

Seeing this leads me to another refactor to call this out to a separate method for getting the hostname for the urlResolve function class. With this refactor we are simplifying this function to do fewer things. I extracted two functions, on to get the hostname and the other for the formatting if needed.

function formateHostName(hostname) {
    if (!hostnameInBrackets() && hostname.indexOf(':') > -1) {
        hostname = '[' + hostname + ']';
    }

    return hostname;
}

function getHostName() {
    var hostname = formateHostName(urlParsingNode.hostname);

    return hostname;
}

Now in the urlResolve function, we have an area of code that could use some refactoring to reduce the amount of the number of items performed. Our goal is to reduce it to doing one thing and do it well.

// Support: IE 9-11 only
  if (msie) {
    // Normalize before parse.  Refer Implementation Notes on why this is
    // done in two steps on IE.
    urlParsingNode.setAttribute('href', href);
    href = urlParsingNode.href;
  }

The comment leads us to what this should be named, normalizeForIE.

function normalizeForIE(url) {
    var href = url;

    if (msie) {
        urlParsingNode.setAttribute('href', href);
        href = urlParsingNode.href;
    }

    return href;
}

Now we have a function that has one guard and does one thing.

function urlResolve(url) {
  if (!isString(url)) return url;

  var href = normalizeForIE(url);
  urlParsingNode.setAttribute('href', href);
  var hostname = getHostName();

  return {
    href: urlParsingNode.href,
    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
    host: urlParsingNode.host,
    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
    hostname: hostname,
    port: urlParsingNode.port,
    pathname: (urlParsingNode.pathname.charAt(0) === '/')
      ? urlParsingNode.pathname
      : '/' + urlParsingNode.pathname
  };
}

At the end of this file, we have one more area that we can make better, and it is the long comment for the if statement that is the sign.

// `document.baseURI` is available everywhere except IE
  if (!baseUrlParsingNode) {

So we create a function for adding the base URI for IE, and now getBaseUrl is doing one thing.

function getBaseUrl() {
  if (window.document.baseURI) {
    return window.document.baseURI;
  }

  baseUrlParsingNode = addBaseURIForIE(baseUrlParsingNode);
  return baseUrlParsingNode.href;
}

That is it for this file. We have learned a few things with this stable framework’s urlUtils JavaScript code file:

  1. A good IDE is needed to help bring to focus the area of the source file that needs be worked on, source or documentation.
  2. Move variables closer to where they are to be used, reduce its scope to the minimum it needs to be.
  3. Comments are signs letting us know of parts of our code that need to be refactored to separate functions.
  4. A function with multiple ifs is a function trying to do too many things, extract and simplify.

The final file without the documentation is listed below.

Remember, if you have a snippet of code that you would like refactored on split code leave a comment below with the code snippet or link to where to obtain it.