tasks/assemble.js
function(src, assemble, callback) {

    var layoutStack = [];
    var layoutName = 'layout';
    var defaultLayout = assemble.engine.startDelimiter + ' body ' + assemble.engine.endDelimiter; // '{{> body }}';

    var layoutext = assemble.options.layoutext || '';
    var layout = '';
    var layoutdir = assemble.options.layoutdir || assemble.options.layouts || '';

    var load = function(src) {

      var loadFile = true;

      // if the src is empty, create a default layout in memory
      if (!src || src === false || src === '' || src.length === 0 || src === 'none') {
        loadFile = false;
        layout = defaultLayout; // '{{>body}}';
      }

      var layoutPath = src + layoutext;

      if (loadFile) {
        grunt.verbose.writeln(src);
        // Check if we should use the files resolved with glob
        if (assemble.layoutFiles) {
          var matchedLayout = assemble.layoutFiles.filter(function findLayout(layout) {
            return path.basename(layout) === layoutPath;
          })[0];
          layout = matchedLayout ? path.normalize(matchedLayout) : layoutPath;
        } else {
          // If layouts or layoutdir was not a valid glob pattern, validate that the layout file exists if we assume
          // layouts or layoutdir to be a directory path
          layout = path.normalize(path.join(layoutdir, layoutPath));
        }
        grunt.verbose.writeln(layout);

        if (!fs.existsSync(layout)) {
          var err = 'Layout file (' + layout + ') not found.';
          grunt.warn(err);
          if (callback) {
            callback({message: err}, null);
          }
          return false;
        }

        // load layout
        layoutName = path.basename(layout, path.extname(layout));

        layout = grunt.file.read(layout);
        layout = layout.replace(/\{{>\s*body\s*}}/, function() { return defaultLayout; });
      }

      var parsedLayout = matter(layout, assemble.options.matter);
      var layoutData = parsedLayout.data;

      var results = {
        layoutName: layoutName,
        layout: parsedLayout.content,
        data: layoutData
      };

      layoutStack.push(results);

      if (layoutData && (layoutData.layout || layoutData.layout === false || layoutData.layout === 'none')) {
        load(layoutData.layout);
      }
    };

    load(src);

    var layoutInfo;
    var finalResults = {
      layoutName: '',
      layout: defaultLayout, // '{{>body}}',
      data: {}
    };

    // eslint-disable-next-line
    while (layoutInfo = layoutStack.pop()) {
      finalResults.layout = injectBody(finalResults.layout, layoutInfo.layout);
      finalResults.data = _.extend({}, finalResults.data, layoutInfo.data);
      finalResults.layoutName = layoutInfo.layoutName;
    }

    if (callback) {
      callback(null, finalResults);
    }
    return finalResults;
  }
function(src, assemble, callback) {

    var layoutStack = [];
    var layoutName = 'layout';
    var defaultLayout = assemble.engine.startDelimiter + ' body ' + assemble.engine.endDelimiter; // '{{> body }}';

    var layoutext = assemble.options.layoutext || '';
    var layout = '';
    var layoutdir = assemble.options.layoutdir || assemble.options.layouts || '';

    var load = function(src) {

      var loadFile = true;

      // if the src is empty, create a default layout in memory
      if (!src || src === false || src === '' || src.length === 0 || src === 'none') {
        loadFile = false;
        layout = defaultLayout; // '{{>body}}';
      }

      var layoutPath = src + layoutext;

      if (loadFile) {
        grunt.verbose.writeln(src);
        // Check if we should use the files resolved with glob
        if (assemble.layoutFiles) {
          var matchedLayout = assemble.layoutFiles.filter(function findLayout(layout) {
            return path.basename(layout) === layoutPath;
          })[0];
          layout = matchedLayout ? path.normalize(matchedLayout) : layoutPath;
        } else {
          // If layouts or layoutdir was not a valid glob pattern, validate that the layout file exists if we assume
          // layouts or layoutdir to be a directory path
          layout = path.normalize(path.join(layoutdir, layoutPath));
        }
        grunt.verbose.writeln(layout);

        if (!fs.existsSync(layout)) {
          var err = 'Layout file (' + layout + ') not found.';
          grunt.warn(err);
          if (callback) {
            callback({message: err}, null);
          }
          return false;
        }

        // load layout
        layoutName = path.basename(layout, path.extname(layout));

        layout = grunt.file.read(layout);
        layout = layout.replace(/\{{>\s*body\s*}}/, function() { return defaultLayout; });
      }

      var parsedLayout = matter(layout, assemble.options.matter);
      var layoutData = parsedLayout.data;

      var results = {
        layoutName: layoutName,
        layout: parsedLayout.content,
        data: layoutData
      };

      layoutStack.push(results);

      if (layoutData && (layoutData.layout || layoutData.layout === false || layoutData.layout === 'none')) {
        load(layoutData.layout);
      }
    };

    load(src);

    var layoutInfo;
    var finalResults = {
      layoutName: '',
      layout: defaultLayout, // '{{>body}}',
      data: {}
    };

    // eslint-disable-next-line
    while (layoutInfo = layoutStack.pop()) {
      finalResults.layout = injectBody(finalResults.layout, layoutInfo.layout);
      finalResults.data = _.extend({}, finalResults.data, layoutInfo.data);
      finalResults.layoutName = layoutInfo.layoutName;
    }

    if (callback) {
      callback(null, finalResults);
    }
    return finalResults;
  }
Load Layout
@param  {[type]}   src      [description]
@param  {[type]}   assemble [description]
@param  {Function} callback [description]
@return {[type]}            [description]