Skip to content

Commit

Permalink
Add code comments to globsToMatcher
Browse files Browse the repository at this point in the history
The logic here might be a little confusing, so I am adding some
comments that I hope will help make it easier for future explorers to
understand. While I was doing this, I noticed a small way to simplify
this function even more.
  • Loading branch information
lencioni committed Jun 8, 2020
1 parent f51fd34 commit f588ada
Showing 1 changed file with 32 additions and 8 deletions.
40 changes: 32 additions & 8 deletions packages/jest-util/src/globsToMatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,44 @@ const globsMatchers = new Map<
}
>();

// Every time micromatch is called, it will parse the glob strings and turn them
// into regexp instances. Instead of calling micromatch repeatedly with the same
// globs, we can use this function which will build the micromatch matchers
// ahead of time and then have an optimized path for determining whether an
// individual path matches.
//
// This function is intended to match the behavior of `micromatch()`.

export default function globsToMatcher(
globs: Array<Config.Glob>,
): (path: Config.Path) => boolean {
if (globs.length === 0) {
// Since there were no globs given, we can simply have a fast path here and
// return with a very simple function.
return (_: Config.Path): boolean => false;
}

const micromatchOptions = {dot: true};
const matchers = globs.map(glob => {
if (!globsMatchers.has(glob)) {
const state = micromatch.scan(glob, {dot: true});
// Matchers that are negated have different behavior than matchers that
// are not negated, so we need to store this information ahead of time.
const {negated} = micromatch.scan(glob, micromatchOptions);

const matcher = {
isMatch: micromatch.matcher(glob, {dot: true}),
negated: state.negated,
isMatch: micromatch.matcher(glob, micromatchOptions),
negated,
};

globsMatchers.set(glob, matcher);
}

return globsMatchers.get(glob)!;
});

return (path: Config.Path): boolean => {
const replacedPath = replacePathSepForGlob(path);
let kept = false;
let omitted = false;
let kept = undefined;
let negatives = 0;

for (let i = 0; i < matchers.length; i++) {
Expand All @@ -50,14 +65,23 @@ export default function globsToMatcher(
const matched = isMatch(replacedPath);

if (!matched && negated) {
// The path was not matched, and the matcher is a negated matcher, so we
// want to omit the path. This means that the negative matcher is
// filtering the path out.
kept = false;
omitted = true;
} else if (matched && !negated) {
// The path was matched, and the matcher is not a negated matcher, so we
// want to keep the path.
kept = true;
omitted = false;
}
}

return negatives === matchers.length ? !omitted : kept && !omitted;
// If all of the globs were negative globs, then we want to include the path
// as long as it was not explicitly not kept. Otherwise only include
// the path if it was kept. This allows sets of globs that are all negated
// to allow some paths to be matched, while sets of globs that are mixed
// negated and non-negated to cause the negated matchers to only omit paths
// and not keep them.
return negatives === matchers.length ? kept !== false : !!kept;
};
}

0 comments on commit f588ada

Please sign in to comment.