From c4252f6d0a3e54694984c2c6fb36d84b832db90e Mon Sep 17 00:00:00 2001 From: Benjamin Eidelman Date: Fri, 10 Jun 2016 11:06:53 -0300 Subject: [PATCH] recursion and glob matching --- README.md | 25 ++++++++++++++- example/files/subfolder/file4.txt | 1 + example/files/subfolder/file5.md | 2 ++ lib/include-folder.js | 53 +++++++++++++++++++++++++++++-- package.json | 6 ++-- test/files/subfolder/file4.txt | 1 + test/files/subfolder/file5.md | 2 ++ test/include-folder_test.js | 27 ++++++++++++++++ 8 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 example/files/subfolder/file4.txt create mode 100644 example/files/subfolder/file5.md create mode 100644 test/files/subfolder/file4.txt create mode 100644 test/files/subfolder/file5.md diff --git a/README.md b/README.md index 27eafe0..b9819d8 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,34 @@ folder var will contains: } ``` +## Recursion + +You can include files recursive using the `recurse` parameter: + + +```javascript +var includeFolder = require('include-folder'), + folder = includeFolder("./aFolder",/^a.*/, { recurse: true }); +``` + +This include files that start with 'a', in any subfolder, subfolders are created as object properties. + ## Filter included files You can filter which files to include using the filter parameter: +### Using Globs + +```javascript +var includeFolder = require('include-folder'), + folder = includeFolder("./aFolder", [ '**/*.txt', '!README*' ]); +``` + +This includes every *.txt recursively (if a pattern references subfolders, `options.recurse` is enabled automatically) but excludes files starting with "README". + +(see https://github.com/sindresorhus/multimatch for details on matching with multiple globs) + +### Using a Regular Expression ```javascript var includeFolder = require('include-folder'), @@ -60,4 +84,3 @@ Add unit tests for any new or changed functionality. Copyright (c) 2013 Andrea Parodi Licensed under the MIT license. - diff --git a/example/files/subfolder/file4.txt b/example/files/subfolder/file4.txt new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/example/files/subfolder/file4.txt @@ -0,0 +1 @@ +hello diff --git a/example/files/subfolder/file5.md b/example/files/subfolder/file5.md new file mode 100644 index 0000000..ce0b472 --- /dev/null +++ b/example/files/subfolder/file5.md @@ -0,0 +1,2 @@ +world +===== diff --git a/lib/include-folder.js b/lib/include-folder.js index b2b4546..b30f5ff 100644 --- a/lib/include-folder.js +++ b/lib/include-folder.js @@ -1,6 +1,8 @@ 'use strict'; var fs = require('fs'); +var path = require('path'); +var micromatch = require('micromatch'); function includeFolder (folderName, filter, options) { folderName = folderName.replace(/\/$/, ''); @@ -41,10 +43,52 @@ includeFolder.stripExtension = function (fileName) { }; includeFolder.buildSource = function (folderName, filter, options) { + var self = this; var files = fs.readdirSync(folderName); var allProps = {}; - filter = filter.test.bind(filter); - var fields = files.filter(filter).map(function (fileName) { + + options = options || {}; + options.basePath = options.basePath || folderName; + + if (filter && typeof filter !== 'function') { + if (filter.test) { + filter = filter.test.bind(filter); + } else { + var globs = typeof filter === 'string' ? [filter] : filter; + if (globs.filter(function (glob) { + return /(\/|\*\*)/.test(glob); + }).length > 0) { + // a glob that includes subfolders was used, enable recursion + options.recurse = true; + } + filter = function (name) { + return micromatch([name], globs).length > 0; + }; + } + } + + var fields = files.map(function (fileName) { + var fullname = path.join(folderName, fileName); + var relative = path.relative(options.basePath, fullname); + + if (fs.lstatSync(fullname).isDirectory()) { + if (!options.recurse) { + return; + } + var folderSource = self.buildSource(fullname, filter, options); + if (!/readFileSync/.test(folderSource)) { + // folder is empty + return; + } + return 'self["' + fileName + '"] = (function(){' + + folderSource + + '})();'; + } + + if (filter && !filter(relative)) { + return; + } + var name = includeFolder.normalize( includeFolder.stripExtension(fileName, options), options @@ -62,8 +106,13 @@ includeFolder.buildSource = function (folderName, filter, options) { } return 'self["' + name + '"] = fs.readFileSync("' + folderName + '/' + fileName + '","utf8");'; + }).filter(function (source) { + // remove filtered entries + return !!source; }); + /* + */ return 'var self={},' + 'fs = require("fs");\n' + fields.join('\n') + diff --git a/package.json b/package.json index 2cd1d2b..183b1dd 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "bugs": { "url": "https://github.com/parro-it/include-folder/issues" }, - "license": "MIT", + "license": "MIT", "main": "lib/include-folder", "engines": { "node": ">= 0.10.0" @@ -42,5 +42,7 @@ "require", "readFileSync" ], - "dependencies": {} + "dependencies": { + "micromatch": "^2.3.8" + } } diff --git a/test/files/subfolder/file4.txt b/test/files/subfolder/file4.txt new file mode 100644 index 0000000..ce01362 --- /dev/null +++ b/test/files/subfolder/file4.txt @@ -0,0 +1 @@ +hello diff --git a/test/files/subfolder/file5.md b/test/files/subfolder/file5.md new file mode 100644 index 0000000..ce0b472 --- /dev/null +++ b/test/files/subfolder/file5.md @@ -0,0 +1,2 @@ +world +===== diff --git a/test/include-folder_test.js b/test/include-folder_test.js index 9a28c9f..df20e00 100644 --- a/test/include-folder_test.js +++ b/test/include-folder_test.js @@ -88,4 +88,31 @@ describe('include_folder', function () { }); }); + describe('when the recurse option is true', function () { + beforeEach(function () { + this.folderModule = includeFolder('./test/files', null, { recurse: true }); + }); + + it('subfolders are included', function () { + expect('subfolder' in this.folderModule).to.be.equal(true); + expect('file4' in this.folderModule.subfolder).to.be.equal(true); + expect('file5' in this.folderModule.subfolder).to.be.equal(true); + }); + }); + + describe('when using globs', function () { + beforeEach(function () { + this.folderModule = includeFolder('./test/files', [ + '!file*', + 'subfolder/*.txt' + ]); + }); + + it('filters, and recursion is automatic', function () { + expect('file1' in this.folderModule).to.be.equal(false); + expect('subfolder' in this.folderModule).to.be.equal(true); + expect('file4' in this.folderModule.subfolder).to.be.equal(true); + expect('file5' in this.folderModule.subfolder).to.be.equal(false); + }); + }); });