Skip to content

Commit

Permalink
New version. More strict. Drop returnIndex and startIndex params for …
Browse files Browse the repository at this point in the history
…now.
  • Loading branch information
paulmillr committed Apr 5, 2019
1 parent c906c02 commit 02257b9
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 111 deletions.
9 changes: 2 additions & 7 deletions .travis.yml
Expand Up @@ -2,10 +2,5 @@ sudo: false
language: node_js
node_js:
- node
- '8'
- '7'
- '6'
- '5'
- '4'
- '0.12'
- '0.10'
- '10'
- '8'
15 changes: 15 additions & 0 deletions index.d.ts
@@ -0,0 +1,15 @@
// type

import sep from 'path';

// * @param {Array|Function|String|RegExp} matchers
// * @param {String=} testString
// * @param {Boolean=} returnIndex

type AnymatchPattern = String|RegExp|{(string:String): Boolean};
type AnymatchMatcher = AnymatchPattern|Array<AnymatchPattern>
function anymatch(matchers: AnymatchMatcher, testString: String): Boolean;
function anymatch(matchers: AnymatchMatcher, testString: String, returnIndex: Boolean): Number;
function anymatch(matchers: AnymatchMatcher): (testString: String) => Boolean;
function anymatch(matchers: AnymatchMatcher): (testString: String, returnIndex: Boolean) => Number;
export = anymatch;
117 changes: 62 additions & 55 deletions index.js
@@ -1,67 +1,74 @@
'use strict';

var micromatch = require('micromatch');
var normalize = require('normalize-path');
var path = require('path'); // required for tests.
var arrify = function(a) { return a == null ? [] : (Array.isArray(a) ? a : [a]); };
const micromatch = require('micromatch');
const normalizePath = require('normalize-path');
const {sep} = require('path'); // required for tests.

var anymatch = function(criteria, value, returnIndex, startIndex, endIndex) {
criteria = arrify(criteria);
value = arrify(value);
if (arguments.length === 1) {
return anymatch.bind(null, criteria.map(function(criterion) {
return typeof criterion === 'string' && criterion[0] !== '!' ?
micromatch.matcher(criterion) : criterion;
}));
/**
* @typedef {String|RegExp|{(string:String): Boolean}} AnymatchPattern
* @typedef {AnymatchPattern|Array<AnymatchPattern>} AnymatchMatcher
*/

const BANG = '!';
const arrify = (item) => Array.isArray(item) ? item : [item];

const createPattern = (matcher) => (string) => {
if (typeof matcher === 'function') {
return matcher(string);
}
startIndex = startIndex || 0;
var string = value[0];
var altString, altValue;
var matched = false;
var matchIndex = -1;
function testCriteria(criterion, index) {
var result;
switch (Object.prototype.toString.call(criterion)) {
case '[object String]':
result = string === criterion || altString && altString === criterion;
result = result || micromatch.isMatch(string, criterion);
break;
case '[object RegExp]':
result = criterion.test(string) || altString && criterion.test(altString);
break;
case '[object Function]':
result = criterion.apply(null, value);
result = result || altValue && criterion.apply(null, altValue);
break;
default:
result = false;
}
if (result) {
matchIndex = index + startIndex;
if (typeof matcher === 'string') {
return matcher === string || micromatch.isMatch(string, matcher);
}
if (matcher instanceof RegExp) {
return matcher.test(string);
}
return false;
};

/**
* @param {AnymatchMatcher} matchers
* @param {String} testString
* @param {Boolean=} returnIndex
* @returns {Boolean|Number|Function}
*/
const anymatch = (matchers, testString, returnIndex=false) => {
if (matchers == null) {
throw new TypeError('anymatch: specify first argument');
}
if (testString == null) {
return (testString, ri=false) => {
const returnIndex = typeof ri === 'boolean' ? ri : false;
return anymatch(matchers, testString, returnIndex);
}
return result;
}
var crit = criteria;
var negGlobs = crit.reduce(function(arr, criterion, index) {
if (typeof criterion === 'string' && criterion[0] === '!') {
if (crit === criteria) {
// make a copy before modifying
crit = crit.slice();
}
crit[index] = null;
arr.push(criterion.substr(1));
if (typeof testString !== 'string') {
throw new TypeError('anymatch: second argument must be a string: got ' +
Object.prototype.toString.call(testString))
}

const unixified = normalizePath(testString);
const arrified = arrify(matchers);
const negatedGlobs = arrified
.filter(item => typeof item === 'string' && item.charAt(0) === BANG)
.map(item => item.slice(1));

// console.log('anymatch', {matchers, testString, containsNegatedGlob, negatedGlobs});

if (negatedGlobs.length > 0) {
if (micromatch.some(unixified, negatedGlobs)) {
return returnIndex ? -1 : false;
}
return arr;
}, []);
if (!negGlobs.length || !micromatch.any(string, negGlobs)) {
if (path.sep === '\\' && typeof string === 'string') {
altString = normalize(string);
altString = altString === string ? null : altString;
if (altString) altValue = [altString].concat(value.slice(1));
}

const patterns = arrified.map(createPattern);
for (let index=0; index < patterns.length; index++) {
const pattern = patterns[index];
if (pattern(unixified)) {
return returnIndex ? index : true;
}
matched = crit.slice(startIndex, endIndex).some(testCriteria);
}
return returnIndex === true ? matchIndex : matched;

return returnIndex ? -1 : false;
};

module.exports = anymatch;
11 changes: 6 additions & 5 deletions package.json
@@ -1,9 +1,10 @@
{
"name": "anymatch",
"version": "2.0.0",
"version": "3.0.0-pre",
"description": "Matches strings against configurable strings, globs, regular expressions, and/or functions",
"files": [
"index.js"
"index.js",
"index.d.ts"
],
"author": {
"name": "Elan Shanker",
Expand Down Expand Up @@ -36,12 +37,12 @@
"test": "istanbul cover _mocha && cat ./coverage/lcov.info | coveralls"
},
"dependencies": {
"micromatch": "^3.1.4",
"normalize-path": "^2.1.1"
"micromatch": "micromatch/micromatch#dev",
"normalize-path": "^3.0.0"
},
"devDependencies": {
"coveralls": "^2.7.0",
"istanbul": "^0.4.5",
"mocha": "^3.0.0"
"mocha": "^6.0.2"
}
}
91 changes: 47 additions & 44 deletions test.js
Expand Up @@ -14,9 +14,9 @@ describe('anymatch', function() {
}
];
it('should resolve string matchers', function() {
assert.equal(true, anymatch(matchers, 'path/to/file.js'));
assert.equal(true, anymatch(matchers[0], 'path/to/file.js'));
assert.equal(false, anymatch(matchers[0], 'bar.js'));
assert(anymatch(matchers, 'path/to/file.js'));
assert(anymatch(matchers[0], 'path/to/file.js'));
assert(!anymatch(matchers[0], 'bar.js'));
});
it('should resolve glob matchers', function() {
assert.equal(true, anymatch(matchers, 'path/anyjs/baz.js'));
Expand All @@ -38,8 +38,8 @@ describe('anymatch', function() {
});
it('should ignore improperly typed matchers', function() {
var emptyObj = {};
assert.equal(false, anymatch(emptyObj, emptyObj));
assert.equal(false, anymatch(Infinity, Infinity));
assert.equal(false, anymatch(emptyObj, ''));
assert.equal(false, anymatch(Infinity, ''));
});

describe('with returnIndex = true', function() {
Expand All @@ -58,7 +58,10 @@ describe('anymatch', function() {
});

describe('curried matching function', function() {
var matchFn = anymatch(matchers);
var matchFn;
before(() => {
matchFn = anymatch(matchers);
});
it('should resolve matchers', function() {
assert.equal(true, matchFn('path/to/file.js'));
assert.equal(true, matchFn('path/anyjs/baz.js'));
Expand Down Expand Up @@ -91,46 +94,46 @@ describe('anymatch', function() {
});
});

describe('using matcher subsets', function() {
it('should skip matchers before the startIndex', function() {
assert(anymatch(matchers, 'path/to/file.js', false));
assert(!anymatch(matchers, 'path/to/file.js', false, 1));
});
it('should skip matchers after and including the endIndex', function() {
assert(anymatch(matchers, 'path/to/bars.js', false));
assert(!anymatch(matchers, 'path/to/bars.js', false, 0, 3));
assert(!anymatch(matchers, 'foo.js', false, 0, 1));
});
});
// describe('using matcher subsets', function() {
// it('should skip matchers before the startIndex', function() {
// assert(anymatch(matchers, 'path/to/file.js', false));
// assert(!anymatch(matchers, 'path/to/file.js', false, 1));
// });
// it('should skip matchers after and including the endIndex', function() {
// assert(anymatch(matchers, 'path/to/bars.js', false));
// assert(!anymatch(matchers, 'path/to/bars.js', false, 0, 3));
// assert(!anymatch(matchers, 'foo.js', false, 0, 1));
// });
// });

describe('extra args', function() {
it('should allow string to be passed as first member of an array', function() {
assert(anymatch(matchers, ['path/to/bar.js']));
});
it('should pass extra args to function matchers', function() {
matchers.push(function(string, arg1, arg2) { return arg1 || arg2; });
assert(!anymatch(matchers, 'bar.js'), 1);
assert(!anymatch(matchers, ['bar.js', 0]), 2);
assert(anymatch(matchers, ['bar.js', true]), 3);
assert(anymatch(matchers, ['bar.js', 0, true]), 4);
// with returnIndex
assert.equal(anymatch(matchers, ['bar.js', 1], true), 4, 5);
// curried versions
var matchFn1 = anymatch(matchers);
var matchFn2 = anymatch(matchers[4]);
assert(!matchFn1(['bar.js', 0]), 6);
assert(!matchFn2(['bar.js', 0]), 7);
assert(matchFn1(['bar.js', true]), 8);
assert(matchFn2(['bar.js', true]), 9);
assert(matchFn1(['bar.js', 0, true]), 10);
assert(matchFn2(['bar.js', 0, true]), 11);
// curried with returnIndex
assert.equal(matchFn1(['bar.js', 1], true), 4, 12);
assert.equal(matchFn2(['bar.js', 1], true), 0, 13);
assert.equal(matchFn1(['bar.js', 0], true), -1, 14);
assert.equal(matchFn2(['bar.js', 0], true), -1, 15);
matchers.pop();
});
it('should not allow string to be passed as first member of an array', function() {
assert.throws(() => anymatch(matchers, ['path/to/bar.js']));
});
// it('should pass extra args to function matchers', function() {
// matchers.push(function(string, arg1, arg2) { return arg1 || arg2; });
// assert(!anymatch(matchers, 'bar.js'), 1);
// assert(!anymatch(matchers, ['bar.js', 0]), 2);
// assert(anymatch(matchers, ['bar.js', true]), 3);
// assert(anymatch(matchers, ['bar.js', 0, true]), 4);
// // with returnIndex
// assert.equal(anymatch(matchers, ['bar.js', 1], true), 4, 5);
// // curried versions
// var matchFn1 = anymatch(matchers);
// var matchFn2 = anymatch(matchers[4]);
// assert(!matchFn1(['bar.js', 0]), 6);
// assert(!matchFn2(['bar.js', 0]), 7);
// assert(matchFn1(['bar.js', true]), 8);
// assert(matchFn2(['bar.js', true]), 9);
// assert(matchFn1(['bar.js', 0, true]), 10);
// assert(matchFn2(['bar.js', 0, true]), 11);
// // curried with returnIndex
// assert.equal(matchFn1(['bar.js', 1], true), 4, 12);
// assert.equal(matchFn2(['bar.js', 1], true), 0, 13);
// assert.equal(matchFn1(['bar.js', 0], true), -1, 14);
// assert.equal(matchFn2(['bar.js', 0], true), -1, 15);
// matchers.pop();
// });
});

describe('glob negation', function() {
Expand Down

0 comments on commit 02257b9

Please sign in to comment.