-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
371 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
module.exports = { | ||
extends: 'gemini-testing', | ||
root: true | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.* | ||
test/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
language: node_js | ||
node_js: 4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,40 @@ | ||
# path-utils | ||
[![Build | ||
Status](https://travis-ci.org/gemini-testing/glob-extra.png)](https://travis-ci.org/gemini-testing/glob-extra) | ||
|
||
# glob-extra | ||
|
||
Wrapper for utility [glob](https://github.com/isaacs/node-glob) with promises support which provides expanding of masks, dirs and files to absolute file paths. | ||
|
||
## Installation | ||
|
||
```bash | ||
$ npm install glob-extra | ||
``` | ||
|
||
## Usage | ||
|
||
```js | ||
const globExtra = require('glob-extra'); | ||
const paths = ['some/path', 'other/path/*.js', 'other/deep/path/**/*.js'] | ||
|
||
// options are optional | ||
globExtra.expandPaths(paths, options) | ||
.then((files) => { | ||
// ['/absolute/some/path/file1.js', | ||
// '/absolute/other/path/file2.js', | ||
// '/absolute/other/deep/path/dir/file3.js'] | ||
}) | ||
.done(); | ||
``` | ||
|
||
### Options | ||
|
||
* **formats** *{String[]}* – files formats to expand; it will expand all files by default. For example: | ||
|
||
```js | ||
globExtra.expandPaths(paths, {formats: ['.txt', '.js']}) | ||
.then((files) => { | ||
// will expand only js ant txt files | ||
}) | ||
.done(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
'use strict'; | ||
|
||
const q = require('q'); | ||
const qfs = require('q-io/fs'); | ||
const _ = require('lodash'); | ||
const glob = require('glob'); | ||
const utils = require('./utils'); | ||
|
||
const getFilesByMask = (mask) => { | ||
return q.nfcall(glob, mask) | ||
.then((paths) => { | ||
return _.isEmpty(paths) | ||
? q.reject(new Error(`Cannot find files by mask ${mask}`)) | ||
: paths; | ||
}); | ||
}; | ||
|
||
const listFiles = (path) => { | ||
return qfs.listTree(path) | ||
.then((paths) => utils.asyncFilter(paths, utils.isFile)); | ||
}; | ||
|
||
const expandPath = (path, options) => { | ||
return utils.isFile(path) | ||
.then((isFile) => isFile ? [path] : listFiles(path)) | ||
.then((paths) => paths.filter((path) => utils.matchesFormats(path, options.formats))) | ||
.then((paths) => paths.map((path) => qfs.absolute(path))); | ||
}; | ||
|
||
const processPaths = (paths, cb) => { | ||
return _(paths) | ||
.map(cb) | ||
.thru(q.all).value() | ||
.then(_.flatten) | ||
.then(_.uniq); | ||
}; | ||
|
||
exports.expandPaths = (paths, options) => { | ||
options = options || {}; | ||
|
||
return processPaths(paths, getFilesByMask) | ||
.then((matchedPaths) => processPaths(matchedPaths, (path) => expandPath(path, options))); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
'use strict'; | ||
|
||
const _ = require('lodash'); | ||
const q = require('q'); | ||
const qfs = require('q-io/fs'); | ||
|
||
exports.asyncFilter = (items, cb) => { | ||
return _(items) | ||
.map((item) => cb(item).then((res) => res && item)) | ||
.thru(q.all) | ||
.value() | ||
.then(_.compact); | ||
}; | ||
|
||
exports.matchesFormats = (path, formats) => { | ||
return _.isEmpty(formats) || _.includes(formats, qfs.extension(path)); | ||
}; | ||
|
||
exports.isFile = (path) => qfs.stat(path).then((stat) => stat.isFile()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
"name": "glob-extra", | ||
"version": "1.0.0", | ||
"description": "Utility which provides expanding of masks, dirs and files to absolute file paths.", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"lint": "eslint .", | ||
"test-unit": "mocha test", | ||
"test": "npm run lint && npm run test-unit" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/gemini-testing/path-utils.git" | ||
}, | ||
"keywords": [ | ||
"expand", | ||
"paths", | ||
"masks" | ||
], | ||
"dependencies": { | ||
"glob": "^7.0.5", | ||
"lodash": "^4.15.0", | ||
"q": "^1.1.2", | ||
"q-io": "^1.13.2" | ||
}, | ||
"devDependencies": { | ||
"chai": "^3.4.1", | ||
"chai-as-promised": "^5.3.0", | ||
"eslint": "^3.1.1", | ||
"eslint-config-gemini-testing": "^2.2.0", | ||
"mocha": "^2.4.5", | ||
"proxyquire": "^1.7.3", | ||
"sinon": "^1.17.2" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = { | ||
extends: 'gemini-testing/tests' | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
'use strict'; | ||
|
||
const proxyquire = require('proxyquire'); | ||
const qfs = require('q-io/fs'); | ||
const q = require('q'); | ||
|
||
describe('path-utils', () => { | ||
const sandbox = sinon.sandbox.create(); | ||
|
||
let glob; | ||
let pathUtils; | ||
|
||
beforeEach(() => { | ||
sandbox.stub(qfs, 'listTree'); | ||
sandbox.stub(qfs, 'absolute'); | ||
sandbox.stub(qfs, 'stat').returns(q({isFile: () => true})); | ||
|
||
glob = sandbox.stub(); | ||
|
||
pathUtils = proxyquire('../lib/index', {glob}); | ||
}); | ||
|
||
afterEach(() => sandbox.restore()); | ||
|
||
describe('masks', () => { | ||
it('should get absolute file path from passed mask', () => { | ||
glob.withArgs('some/deep/**/*.js').yields(null, ['some/deep/path/file.js']); | ||
|
||
qfs.absolute.withArgs('some/deep/path/file.js').returns('/absolute/some/deep/path/file.js'); | ||
|
||
return pathUtils.expandPaths(['some/deep/**/*.js']) | ||
.then((absolutePaths) => { | ||
assert.deepEqual(absolutePaths, ['/absolute/some/deep/path/file.js']); | ||
}); | ||
}); | ||
|
||
it('should throw an error if a mask does not match files', () => { | ||
glob.withArgs('bad/mask/*.js').yields(null, []); | ||
|
||
return assert.isRejected(pathUtils.expandPaths(['bad/mask/*.js']), /Cannot find files by mask bad\/mask\/\*\.js/); | ||
}); | ||
|
||
it('should get absolute file path from passed mask according to formats option', () => { | ||
glob.withArgs('some/path/*.*').yields(null, ['some/path/file.js', 'some/path/file.txt']); | ||
|
||
qfs.absolute | ||
.withArgs('some/path/file.js').returns('/absolute/some/path/file.js'); | ||
|
||
return pathUtils.expandPaths(['some/path/*.*'], {formats: ['.js']}) | ||
.then((absolutePaths) => { | ||
assert.deepEqual(absolutePaths, ['/absolute/some/path/file.js']); | ||
}); | ||
}); | ||
|
||
it('should get uniq absolute file path from passed masks', () => { | ||
glob.withArgs('some/path/*.js').yields(null, ['some/path/file.js']); | ||
|
||
qfs.absolute.withArgs('some/path/file.js').returns('/absolute/some/path/file.js'); | ||
|
||
return pathUtils.expandPaths(['some/path/*.js', 'some/path/*.js']) | ||
.then((absolutePaths) => { | ||
assert.deepEqual(absolutePaths, ['/absolute/some/path/file.js']); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('directories', () => { | ||
beforeEach(() => { | ||
qfs.stat.withArgs('some/path/').returns(q({isFile: () => false})); | ||
}); | ||
|
||
it('should get absolute paths for all files from passed dir', () => { | ||
glob.withArgs('some/path/').yields(null, ['some/path/']); | ||
|
||
qfs.listTree.withArgs('some/path/').returns(q(['some/path/first.js', 'some/path/second.txt'])); | ||
|
||
qfs.absolute | ||
.withArgs('some/path/first.js').returns('/absolute/some/path/first.js') | ||
.withArgs('some/path/second.txt').returns('/absolute/some/path/second.txt'); | ||
|
||
return pathUtils.expandPaths(['some/path/']) | ||
.then((absolutePaths) => { | ||
assert.deepEqual(absolutePaths, ['/absolute/some/path/first.js', '/absolute/some/path/second.txt']); | ||
}); | ||
}); | ||
|
||
it('should get absolute file paths according to formats option', () => { | ||
glob.withArgs('some/path/').yields(null, ['some/path/']); | ||
|
||
qfs.listTree.withArgs('some/path/').returns(q(['some/path/first.js', 'some/path/second.txt'])); | ||
|
||
qfs.absolute.withArgs('some/path/first.js').returns('/absolute/some/path/first.js'); | ||
|
||
return pathUtils.expandPaths(['some/path/'], {formats: ['.js']}) | ||
.then((absolutePaths) => assert.deepEqual(absolutePaths, ['/absolute/some/path/first.js'])); | ||
}); | ||
|
||
it('should get uniq absolute file path from passed dirs', () => { | ||
glob.withArgs('some/path/').yields(null, ['some/path/']); | ||
|
||
qfs.listTree.withArgs('some/path/').returns(q(['some/path/file.js'])); | ||
|
||
qfs.absolute.withArgs('some/path/file.js').returns('/absolute/some/path/file.js'); | ||
|
||
return pathUtils.expandPaths(['some/path/', 'some/path/']) | ||
.then((absolutePaths) => { | ||
assert.deepEqual(absolutePaths, ['/absolute/some/path/file.js']); | ||
}); | ||
}); | ||
|
||
it('should get only file paths from dir tree', () => { | ||
glob.withArgs('some/path/').yields(null, ['some/path/']); | ||
|
||
qfs.stat.withArgs('some/path/dir').returns(q({isFile: () => false})); | ||
|
||
qfs.listTree.withArgs('some/path/').returns(q(['some/path/file.js', 'some/path/dir'])); | ||
|
||
qfs.absolute.withArgs('some/path/file.js').returns('/absolute/some/path/file.js'); | ||
|
||
return pathUtils.expandPaths(['some/path/']) | ||
.then((absolutePaths) => { | ||
assert.deepEqual(absolutePaths, ['/absolute/some/path/file.js']); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('files', () => { | ||
it('should get absolute file path from passed file path', () => { | ||
glob.withArgs('some/path/file.js').yields(null, ['some/path/file.js']); | ||
|
||
qfs.absolute.withArgs('some/path/file.js').returns('/absolute/some/path/file.js'); | ||
|
||
return pathUtils.expandPaths(['some/path/file.js']) | ||
.then((absolutePaths) => { | ||
assert.deepEqual(absolutePaths, ['/absolute/some/path/file.js']); | ||
}); | ||
}); | ||
|
||
it('should filter files according to formats option', () => { | ||
glob | ||
.withArgs('some/path/file.js').yields(null, ['some/path/file.js']) | ||
.withArgs('some/path/file.txt').yields(null, ['some/path/file.txt']); | ||
|
||
qfs.absolute | ||
.withArgs('some/path/file.js').returns('/absolute/some/path/file.js'); | ||
|
||
return pathUtils.expandPaths(['some/path/file.js', 'some/path/file.txt'], {formats: ['.js']}) | ||
.then((absolutePaths) => { | ||
assert.deepEqual(absolutePaths, ['/absolute/some/path/file.js']); | ||
}); | ||
}); | ||
|
||
it('should get uniq absolute file path', () => { | ||
glob.withArgs('some/path/file.js').yields(null, ['some/path/file.js']); | ||
|
||
qfs.absolute.withArgs('some/path/file.js').returns('/absolute/some/path/file.js'); | ||
|
||
return pathUtils.expandPaths(['some/path/file.js', 'some/path/file.js']) | ||
.then((absolutePaths) => { | ||
assert.deepEqual(absolutePaths, ['/absolute/some/path/file.js']); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
--require ./test/setup |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
'use strict'; | ||
|
||
const chai = require('chai'); | ||
|
||
global.sinon = require('sinon'); | ||
global.assert = chai.assert; | ||
|
||
chai.use(require('chai-as-promised')); | ||
sinon.assert.expose(chai.assert, {prefix: ''}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
'use strict'; | ||
|
||
const q = require('q'); | ||
const qfs = require('q-io/fs'); | ||
const sinon = require('sinon'); | ||
const utils = require('../lib/utils'); | ||
|
||
describe('utils', () => { | ||
describe('asyncFilter', () => { | ||
it('should filter array using async function', () => { | ||
const isPositive = (number) => q.delay(1).then(() => q(number > 0)); | ||
|
||
return assert.becomes(utils.asyncFilter([-1, 0, 1], isPositive), [1]); | ||
}); | ||
}); | ||
|
||
describe('matchesFormats', () => { | ||
it('should return `true` if the formats option contain passed file format', () => { | ||
assert.isTrue(utils.matchesFormats('some/path/file.js', ['.js'])); | ||
}); | ||
|
||
it('should return `false` if the formats option does not contain passed file format', () => { | ||
assert.isFalse(utils.matchesFormats('some/path/file.js', ['.txt'])); | ||
}); | ||
}); | ||
|
||
describe('isFile', () => { | ||
const sandbox = sinon.sandbox.create(); | ||
|
||
beforeEach(() => { | ||
sandbox.stub(qfs, 'stat'); | ||
}); | ||
|
||
afterEach(() => sandbox.restore()); | ||
|
||
it('should return `true` if the passed path is file', () => { | ||
qfs.stat.returns(q({isFile: () => true})); | ||
|
||
return assert.becomes(utils.isFile('some/path/file.js'), true); | ||
}); | ||
|
||
it('should return `false` if the passed path is dir', () => { | ||
qfs.stat.returns(q({isFile: () => false})); | ||
|
||
return assert.becomes(utils.isFile('some/path/dir'), false); | ||
}); | ||
}); | ||
}); |