docs: function(view, template, createWidget, partials, childClasses) {
    var i;
  
    // If cached version hasn't been passed down, parse childViews into an array of class names
    if (!childClasses) {
      childClasses = {};
      childClasses.flat = _.keys(view.childViews);
      childClasses.padded = _.map(childClasses.flat, function(key) {
        return ' ' + key + ' ';
      });
      childClasses.length = childClasses.flat.length;
    }
  
    // String is a dead-end
    if (typeof template === 'string') {
      return template;
    }
  
    // If this template has been attached to before, disregard any widget points
    if (template.type === 'WidgetConstructor') {
      return attachView(view, template.template.templateObj, createWidget, partials, childClasses);
    }
  
    // Arrays need iterating over
    if (Context.isArray(template)) {
      var clone = new Array(template.length);
      for (i = 0; i < template.length; i++) {
        clone[i] = attachView(view, template[i], createWidget, partials, childClasses);
      }
      // short circuit
      return clone;
    }
  
    template = _.clone(template);
  
    /* eslint-disable dot-notation */
    // If the view has childViews and this isn't the root, attempt to attach Widget
    if (!template.root && view.childViews) {
      // If this is an element with a class property, see if we should attach Widget
      if (template.a && template.a['class']) {
        var className = template.a['class'];
        // If className has dynamic values, filter them out to just the static ones
        if (typeof className !== 'string') {
          className = _.filter(className, function(obj) {
            return typeof obj === 'string';
          });
          className = className.join(' ');
        }
        // Pad with spaces for better hasClass-ing
        className = ' ' + className + ' ';
        for (i = childClasses.length; i--; ) {
          if (className.indexOf(childClasses.padded[i]) > -1) {
            // If we match a childView class, replace the template with a Widget
            template = createWidget(view.childViews[childClasses.flat[i]], template, partials);
            break;
          }
        }
      }
    }
    /* eslint-enable dot-notation */
  
    // Recurse on any child elements
    if (template.f) {
      template.f = attachView(view, template.f, createWidget, partials, childClasses);
    }
  
    // If this is a partial, lookup and recurse
    if (template.t === types.PARTIAL) {
      var partialName = template.r;
      if (!partials[partialName]) {
        errors.warningNoPartialRegisteredWithTheName(partialName);
        return null;
      } else {
        var partialTemplate = partials[partialName];
        if (partialTemplate.templateObj) {
          partialTemplate = partialTemplate.templateObj;
        }
        template = attachView(
          view,
          partialTemplate,
          createWidget,
          partials[partialName].partials || partials,
          childClasses
        );
      }
    }
  
    // Occurs after child recursion to ensure any childViews are properly bound
    if (template.t === types.SECTION && widgets[template.r] && typeof widgets[template.r] === 'function' && widgets.hasOwnProperty(template.r)) {
      var Widget = widgets[template.r];
      template = createWidget(null, Widget.getTemplate(template), partials);
      template.constructor = Widget;
    }
  
    return template;
  }