Skip to content

Commit 705c4bb

Browse files
committed
feature/#338 - add Metalsmith.match method candidate
1 parent edc2eef commit 705c4bb

8 files changed

Lines changed: 115 additions & 35 deletions

File tree

‎lib/index.js‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ var thunkify = require('thunkify')
1111
var unyield = require('unyield')
1212
var utf8 = require('is-utf8')
1313
var Ware = require('ware')
14+
var match = require('micromatch')
1415

1516
/**
1617
* Thunks.
@@ -177,6 +178,26 @@ Metalsmith.prototype.path = function(){
177178
return path.resolve.apply(path, paths)
178179
}
179180

181+
/**
182+
* Match filepaths in the source directory by [glob](https://en.wikipedia.org/wiki/Glob_(programming)) pattern.
183+
* Use the third arg `input` to match against a subset of strings/ filepaths
184+
*
185+
* @param {String|String[]} patterns - one or more glob patterns
186+
* @param {import('micromatch').Options} options - [micromatch options](https://github.com/micromatch/micromatch#options)
187+
* @param {String[]} [input=Object.keys(files)] array of strings to match against
188+
* @returns {String[]} An array of matching file paths
189+
*/
190+
191+
Metalsmith.prototype.match = function(patterns, options, input) {
192+
input = input || Object.keys(this._files)
193+
if (!this._files) return []
194+
options = Object.assign({ dot: true }, options || {}, {
195+
// required to convert forward to backslashes on Windows and match the file keys properly
196+
format: path.normalize,
197+
})
198+
return match(input, patterns, options)
199+
}
200+
180201
/**
181202
* Build with the current settings to the destination directory.
182203
*
@@ -270,7 +291,9 @@ Metalsmith.prototype.read = unyield(function*(dir){
270291
complete += concurrency
271292
}
272293

273-
return paths.reduce(memoizer, {})
294+
var result = paths.reduce(memoizer, {})
295+
this._files = result
296+
return result
274297

275298
function memoizer(memo, file, i) {
276299
file = path.relative(dir, file)

‎package-lock.json‎

Lines changed: 24 additions & 34 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
"cross-spawn": "^7.0.3",
3131
"gray-matter": "^4.0.3",
3232
"is-utf8": "~0.2.0",
33+
"micromatch": "^4.0.4",
3334
"recursive-readdir": "^2.1.0",
3435
"rimraf": "^3.0.2",
3536
"stat-mode": "^1.0.0",

‎test/fixtures/match/src/.htaccess‎

Whitespace-only changes.

‎test/fixtures/match/src/index.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
date: 2013-12-02
3+
title: A Title
4+
---
5+
body
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nested body

‎test/fixtures/match/src/team.jpg‎

1.99 MB
Loading

‎test/index.js‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,66 @@ describe('Metalsmith', function(){
251251
})
252252
})
253253

254+
describe('#match', function(){
255+
it('should match a glob pattern', function(done){
256+
var m = Metalsmith(fixture('match'))
257+
m
258+
.process(function(err) {
259+
if (err) done(err)
260+
var matches = m.match('**/*.md').join(',')
261+
assert.equal(matches, `index.md,${path.join('nested', 'index.md')}`)
262+
done()
263+
})
264+
})
265+
266+
it('should support negation & OR patterns', function(done){
267+
var m = Metalsmith(fixture('match'))
268+
m
269+
.process(function(err) {
270+
if (err) done(err)
271+
var negationMatches = m.match('!index.md').join(',')
272+
var orMatches = m.match('*.{jpg,md}').join(',')
273+
assert.equal(negationMatches, `.htaccess,team.jpg,${path.join('nested', 'index.md')}`)
274+
assert.equal(orMatches, 'index.md,team.jpg')
275+
done()
276+
})
277+
})
278+
279+
it('should include dotfiles, unless specified otherwise', function(done){
280+
var m = Metalsmith(fixture('match'))
281+
m
282+
.process(function(err) {
283+
if (err) done(err)
284+
var matchesAll = m.match('**').join(',')
285+
var matchesNoDot = m.match('**', { dot: false }).join(',')
286+
assert.equal(matchesAll, `.htaccess,index.md,team.jpg,${path.join('nested', 'index.md')}`)
287+
assert.equal(matchesNoDot, `index.md,team.jpg,${path.join('nested', 'index.md')}`)
288+
done()
289+
})
290+
})
291+
292+
293+
// this test is included because micromatch has an obscure option called "windows",
294+
// which is set to true by default on Windows. Maintains compat with how Metalsmith 2.x functions
295+
it('should not transform backslashes to forward slashes in the returned matches', function(done){
296+
var m = Metalsmith(fixture('match'))
297+
m
298+
.use(function windowsPaths(files) {
299+
Object.keys(files).forEach(key => {
300+
if (key.indexOf('/') === -1) return
301+
files[key.replace(/\//g, '\\')] = files[key]
302+
delete files[key]
303+
})
304+
})
305+
.process(function(err) {
306+
if (err) done(err)
307+
var matches = m.match('**/*.md').join(',')
308+
assert.equal(matches, 'index.md,nested\\index.md')
309+
done()
310+
})
311+
})
312+
})
313+
254314
describe('#read', function(){
255315
it('should read from a source directory', function(done){
256316
var m = Metalsmith(fixture('read'))

0 commit comments

Comments
 (0)