lib/zoopinator.js
function bakeFolder(source, dest) {
  var args = createArgs(source, dest, {});

  wrapFunction('BakeFolder', args, function () {
    args.files = fs.readdirSync(args.source);
    
    args.filters = [filterHidden];
    wrapFunction('FilterFiles', args, function () {
      args.filters.forEach(function (filter) {
        args.files = args.files.filter(filter);
      });
    });
    delete args.filters;
      
    wrapFunction('BakeFiles', args, function () {
      var files = [],
          dirs = [];
      
      // seperate the files from the directories
      args.files.forEach(function (file) {
        var stats = fs.statSync(path.join(args.source, file));
            
        if (stats.isDirectory()) {
          dirs.push(file);
        }
        else {
          files.push(file);
        }
      });
      
      // process all the files first
      files.forEach(function (file) {
        bakeFile(path.join(args.source, file), path.join(args.dest, file));
      });
      
      // and then process the sub directories
      dirs.forEach(function (file) {
        bakeFolder(path.join(args.source, file), path.join(args.dest, file));
      });
    });
  });
  
  function filterHidden(file) {
    return !(/^\.|~$/).test(file);
  }
}
function bakeFolder(source, dest) {
  var args = createArgs(source, dest, {});

  wrapFunction('BakeFolder', args, function () {
    args.files = fs.readdirSync(args.source);
    
    args.filters = [filterHidden];
    wrapFunction('FilterFiles', args, function () {
      args.filters.forEach(function (filter) {
        args.files = args.files.filter(filter);
      });
    });
    delete args.filters;
      
    wrapFunction('BakeFiles', args, function () {
      var files = [],
          dirs = [];
      
      // seperate the files from the directories
      args.files.forEach(function (file) {
        var stats = fs.statSync(path.join(args.source, file));
            
        if (stats.isDirectory()) {
          dirs.push(file);
        }
        else {
          files.push(file);
        }
      });
      
      // process all the files first
      files.forEach(function (file) {
        bakeFile(path.join(args.source, file), path.join(args.dest, file));
      });
      
      // and then process the sub directories
      dirs.forEach(function (file) {
        bakeFolder(path.join(args.source, file), path.join(args.dest, file));
      });
    });
  });
  
  function filterHidden(file) {
    return !(/^\.|~$/).test(file);
  }
}
function bakeFolder ( source , dest ) { var args = createArgs ( source , dest , { } ) ; wrapFunction ( 'BakeFolder' , args , function ( ) { args . files = fs . readdirSync ( args . source ) ; args . filters = [ filterHidden ] ; wrapFunction ( 'FilterFiles' , args , function ( ) { args . filters . forEach ( function ( filter ) { args . files = args . files . filter ( filter ) ; } ) ; } ) ; delete args . filters ; wrapFunction ( 'BakeFiles' , args , function ( ) { var files = [ ] , dirs = [ ] ; // seperate the files from the directories args . files . forEach ( function ( file ) { var stats = fs . statSync ( path . join ( args . source , file ) ) ; if ( stats . isDirectory ( ) ) { dirs . push ( file ) ; } else { files . push ( file ) ; } } ) ; // process all the files first files . forEach ( function ( file ) { bakeFile ( path . join ( args . source , file ) , path . join ( args . dest , file ) ) ; } ) ; // and then process the sub directories dirs . forEach ( function ( file ) { bakeFolder ( path . join ( args . source , file ) , path . join ( args . dest , file ) ) ; } ) ; } ) ; } ) ; function filterHidden ( file ) { return ! ( / ^\.|~$ / ) . test ( file ) ; } }
processes all the files in a folder
processes all the files in a folder