diff --git a/CHANGELOG.md b/CHANGELOG.md index 85c66a5d976f..f881d9a48448 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ ### Performance +- `[jest-core]` Cache micromatch in SearchSource globsToMatcher + ## 26.0.1 ### Fixes diff --git a/packages/jest-core/src/SearchSource.ts b/packages/jest-core/src/SearchSource.ts index 48c630f2adb4..763e868eba14 100644 --- a/packages/jest-core/src/SearchSource.ts +++ b/packages/jest-core/src/SearchSource.ts @@ -37,8 +37,57 @@ export type TestSelectionConfig = { watch?: boolean; }; -const globsToMatcher = (globs: Array) => (path: Config.Path) => - micromatch([replacePathSepForGlob(path)], globs, {dot: true}).length > 0; +const globsMatchers = new Map< + string, + { + isMatch: (str: string) => boolean; + negated: boolean; + } +>(); + +const globsToMatcher = (globs: Array) => { + const matchers = globs.map(glob => { + if (!globsMatchers.has(glob)) { + const state = micromatch.scan(glob, {dot: true}); + const matcher = { + isMatch: micromatch.matcher(glob, {dot: true}), + negated: state.negated, + }; + globsMatchers.set(glob, matcher); + } + return globsMatchers.get(glob); + }); + + return (path: Config.Path) => { + const omit = new Set(); + const keep = new Set(); + let negatives = 0; + const replacedPath = replacePathSepForGlob(path); + + for (let i = 0; i < matchers.length; i++) { + const matcher = matchers[i]; + if (!matcher) continue; + const {isMatch, negated} = matcher; + if (negated) negatives++; + + const matched = isMatch(replacedPath); + + const match = negated ? !matched : matched; + if (!match) continue; + + if (negated) { + omit.add(replacedPath); + } else { + omit.delete(replacedPath); + keep.add(replacedPath); + } + } + + const result = negatives === matchers.length ? [replacedPath] : [...keep]; + + return result.some(item => !omit.has(item)); + }; +}; const regexToMatcher = (testRegex: Config.ProjectConfig['testRegex']) => ( path: Config.Path,