54

I'm using the npm module node-glob.

This snippet returns recursively all files in the current working directory.

var glob = require('glob');
glob('**/*', function(err, files) {
    console.log(files);
});

sample output:

[ 'index.html', 'js', 'js/app.js', 'js/lib.js' ]

I want to exclude index.html and js/lib.js. I tried to exclude these files with negative pattern '!' but without luck. Is there a way to achieve this only by using a pattern?

ke_wa
  • 1,176
  • 2
  • 10
  • 12

6 Answers6

71

I suppose it's not actual anymore but I got stuck with the same question and found an answer.

This can be done using only glob module. We need to use options as a second parameter to glob function

glob('pattern', {options}, cb)

There is an options.ignore pattern for your needs.

var glob = require('glob');

glob("**/*",{"ignore":['index.html', 'js', 'js/app.js', 'js/lib.js']}, function (err, files) {
  console.log(files);
})
Adam Azad
  • 11,171
  • 5
  • 29
  • 70
Sergei Panfilov
  • 1,191
  • 9
  • 15
47

Check out globby, which is pretty much glob with support for multiple patterns and a Promise API:

const globby = require('globby');

globby(['**/*', '!index.html', '!js/lib.js']).then(paths => {
    console.log(paths);
});
Sindre Sorhus
  • 62,972
  • 39
  • 168
  • 232
  • 1
    this is pretty much just glob with support for multiple patterns (not node-glob which is a dead end no downloads no readme module) – danday74 Jan 26 '17 at 12:37
  • `globby` is basically vanilla on top of the awesome `glob` library.. Not that really useful. – Ivan Seidel Aug 08 '17 at 21:42
18

You can use node-globule for that:

var globule = require('globule');
var result = globule.find(['**/*', '!index.html', '!js/lib.js']);
console.log(result);
stefanbuck
  • 429
  • 1
  • 3
  • 10
3

Or without an external dependency:

/**
    Walk directory,
    list tree without regex excludes
 */

var fs = require('fs');
var path = require('path');

var walk = function (dir, regExcludes, done) {
  var results = [];

  fs.readdir(dir, function (err, list) {
    if (err) return done(err);

    var pending = list.length;
    if (!pending) return done(null, results);

    list.forEach(function (file) {
      file = path.join(dir, file);

      var excluded = false;
      var len = regExcludes.length;
      var i = 0;

      for (; i < len; i++) {
        if (file.match(regExcludes[i])) {
          excluded = true;
        }
      }

      // Add if not in regExcludes
      if(excluded === false) {
        results.push(file);

        // Check if its a folder
        fs.stat(file, function (err, stat) {
          if (stat && stat.isDirectory()) {

            // If it is, walk again
            walk(file, regExcludes, function (err, res) {
              results = results.concat(res);

              if (!--pending) { done(null, results); }

            });
          } else {
            if (!--pending) { done(null, results); }
          }
        });
      } else {
        if (!--pending) { done(null, results); }
      }
    });
  });
};

var regExcludes = [/index\.html/, /js\/lib\.js/, /node_modules/];

walk('.', regExcludes, function(err, results) {
  if (err) {
    throw err;
  }
  console.log(results);
});
Koji
  • 230
  • 2
  • 7
  • 8
    I certainly like the idea of avoiding unnecessary external dependencies, but this snippet has redefined my scale of "worse things people never should have written". To the novice, if you you are not sure how to do the thing properly, then use an external dependency. – Romain Vincent Mar 23 '21 at 19:21
3

Here is what I wrote for my project:

var glob = require('glob');
var minimatch = require("minimatch");

function globArray(patterns, options) {
  var i, list = [];
  if (!Array.isArray(patterns)) {
    patterns = [patterns];
  }

  patterns.forEach(pattern => {
    if (pattern[0] === "!") {
      i = list.length-1;
      while( i > -1) {
        if (!minimatch(list[i], pattern)) {
          list.splice(i,1);
        }
        i--;
      }

    }
    else {
      var newList = glob.sync(pattern, options);
      newList.forEach(item => {
        if (list.indexOf(item)===-1) {
          list.push(item);
        }
      });
    }
  });

  return list;
}

And call it like this (Using an array):

var paths = globArray(["**/*.css","**/*.js","!**/one.js"], {cwd: srcPath});

or this (Using a single string):

var paths = globArray("**/*.js", {cwd: srcPath});
Intervalia
  • 10,248
  • 2
  • 30
  • 60
  • I get this : `Argument of type 'any' is not assignable to parameter of type 'never` – An-droid Jan 18 '18 at 14:05
  • Are you are using TypeScript? Is the error on this line?? `patterns = [patterns];` Can you provide more info on the error message? It looks like yours was cut off in your post. – Intervalia Jan 18 '18 at 15:36
  • Yes using typeScript 2.5.2, `if (list.indexOf(item)===-1) {` the error is on `item` and here too `list.push(item);` – An-droid Jan 18 '18 at 16:10
  • Sorry I don't use TypeScript. Does anyone else have any idea why @An-droid id getting this error? – Intervalia Mar 22 '18 at 16:00
  • You can force any type to conform by converting it to unkown first: `if( list.indexOf( item as unknown as any ) === -1 )`. However, this should only really need to be done in some very specific circumstances. I'd take another look at how you're type-specifying your arguments/parameters and see if there isn't an illogical assignment. – Rik Aug 03 '22 at 16:11
1

A samples example with gulp:

gulp.task('task_scripts', function(done){

    glob("./assets/**/*.js", function (er, files) {
        gulp.src(files)
            .pipe(gulp.dest('./public/js/'))
            .on('end', done);
    });

});
Ivan Ferrer
  • 558
  • 1
  • 5
  • 12