From 49c10f73610d1aa66513aea3b3a86202346c8968 Mon Sep 17 00:00:00 2001 From: Yaroslav Slepukhin Date: Sun, 10 Aug 2025 00:21:31 +0400 Subject: [PATCH 1/4] chore: replace micromatch with picomatch --- packages/steiger/package.json | 4 +- .../globs/create-filter-according-to-globs.ts | 35 ++++++++------- pnpm-lock.yaml | 43 ++++++++----------- 3 files changed, 37 insertions(+), 45 deletions(-) diff --git a/packages/steiger/package.json b/packages/steiger/package.json index 1800cb1..a7a3342 100644 --- a/packages/steiger/package.json +++ b/packages/steiger/package.json @@ -50,9 +50,9 @@ "globby": "^14.0.2", "immer": "^10.1.1", "lodash-es": "^4.17.21", - "micromatch": "^4.0.8", "patronum": "^2.3.0", "picocolors": "^1.1.1", + "picomatch": "^4.0.3", "prexit": "^2.3.0", "yargs": "^17.7.2", "zod": "^3.24.1", @@ -66,7 +66,7 @@ "@steiger/types": "workspace:*", "@total-typescript/ts-reset": "^0.6.1", "@types/lodash-es": "^4.17.12", - "@types/micromatch": "^4.0.9", + "@types/picomatch": "^4.0.1", "@types/yargs": "^17.0.33", "memfs": "^4.17.0", "tsup": "^8.3.5", diff --git a/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts b/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts index 74c89a8..c62e008 100644 --- a/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts +++ b/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts @@ -1,7 +1,7 @@ import { isNegatedGlob } from './utilities' -import micromatch from 'micromatch' +import picomatch from 'picomatch' -// ! Don't use platform specific path separators in the glob patterns for globby/micromatch +// ! Don't use platform specific path separators in the glob patterns for globby/picomatch // as it only works with forward slashes! interface ApplyGlobsOptions { @@ -14,28 +14,27 @@ export function createFilterAccordingToGlobs({ inclusions, exclusions }: ApplyGl const thereAreExclusions = Array.isArray(exclusions) const inclusionsEmpty = thereAreInclusions && inclusions.length === 0 - function filterAccordingToGlobs(path: string) { - const matchesInclusionPatterns = - !thereAreInclusions || inclusions.some((pattern) => micromatch.isMatch(path, pattern)) - let isIgnored = false + const isIncluded = thereAreInclusions ? picomatch(inclusions) : () => true + + const positiveExclusionPatterns = + (thereAreExclusions && exclusions.filter((pattern) => !isNegatedGlob(pattern))) || [] + const negativeExclusionPatterns = + (thereAreExclusions && exclusions.filter((pattern) => isNegatedGlob(pattern)).map((pattern) => pattern.slice(1))) || + [] + + const isPositivelyExcluded = picomatch(positiveExclusionPatterns) + const isReIncluded = picomatch(negativeExclusionPatterns) + function filterAccordingToGlobs(path: string) { if (inclusionsEmpty) { return false } + const matchesInclusionPatterns = isIncluded(path) + let isIgnored = false + if (matchesInclusionPatterns && thereAreExclusions) { - isIgnored = exclusions - .filter((pattern) => !isNegatedGlob(pattern)) - .some((pattern) => micromatch.isMatch(path, pattern)) - - // If the path is ignored, check for any negated patterns that would include it back - if (isIgnored) { - const isNegated = exclusions.some( - (ignorePattern) => isNegatedGlob(ignorePattern) && micromatch.isMatch(path, ignorePattern.slice(1)), - ) - - isIgnored = !isNegated - } + isIgnored = isPositivelyExcluded(path) && !isReIncluded(path) } return matchesInclusionPatterns && !isIgnored diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bfaf8c1..6af4f58 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -148,15 +148,15 @@ importers: lodash-es: specifier: ^4.17.21 version: 4.17.21 - micromatch: - specifier: ^4.0.8 - version: 4.0.8 patronum: specifier: ^2.3.0 version: 2.3.0(effector@23.2.3) picocolors: specifier: ^1.1.1 version: 1.1.1 + picomatch: + specifier: ^4.0.3 + version: 4.0.3 prexit: specifier: ^2.3.0 version: 2.3.0 @@ -191,9 +191,9 @@ importers: '@types/lodash-es': specifier: ^4.17.12 version: 4.17.12 - '@types/micromatch': - specifier: ^4.0.9 - version: 4.0.9 + '@types/picomatch': + specifier: ^4.0.1 + version: 4.0.1 '@types/yargs': specifier: ^17.0.33 version: 17.0.33 @@ -1219,9 +1219,6 @@ packages: '@types/argparse@1.0.38': resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} - '@types/braces@3.0.5': - resolution: {integrity: sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w==} - '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} @@ -1234,9 +1231,6 @@ packages: '@types/lodash@4.17.4': resolution: {integrity: sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==} - '@types/micromatch@4.0.9': - resolution: {integrity: sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg==} - '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} @@ -1246,6 +1240,9 @@ packages: '@types/node@22.10.1': resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==} + '@types/picomatch@4.0.1': + resolution: {integrity: sha512-dLqxmi5VJRC9XTvc/oaTtk+bDb4RRqxLZPZ3jIpYBHEnDXX8lu02w2yWI6NsPPsELuVK298Z2iR8jgoWKRdUVQ==} + '@types/pluralize@0.0.33': resolution: {integrity: sha512-JOqsl+ZoCpP4e8TDke9W79FDcSgPAR0l6pixx2JHkhnRjvShyYiAYw2LVsnA7K08Y6DeOnaU6ujmENO4os/cYg==} @@ -2374,8 +2371,8 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} pidtree@0.6.0: @@ -3777,8 +3774,6 @@ snapshots: '@types/argparse@1.0.38': optional: true - '@types/braces@3.0.5': {} - '@types/estree@1.0.6': {} '@types/json-schema@7.0.15': {} @@ -3789,10 +3784,6 @@ snapshots: '@types/lodash@4.17.4': {} - '@types/micromatch@4.0.9': - dependencies: - '@types/braces': 3.0.5 - '@types/node@12.20.55': {} '@types/node@18.19.74': @@ -3804,6 +3795,8 @@ snapshots: undici-types: 6.20.0 optional: true + '@types/picomatch@4.0.1': {} + '@types/pluralize@0.0.33': {} '@types/yargs-parser@21.0.3': {} @@ -4506,9 +4499,9 @@ snapshots: dependencies: reusify: 1.0.4 - fdir@6.4.0(picomatch@4.0.2): + fdir@6.4.0(picomatch@4.0.3): optionalDependencies: - picomatch: 4.0.2 + picomatch: 4.0.3 figures@6.1.0: dependencies: @@ -4999,7 +4992,7 @@ snapshots: picomatch@2.3.1: {} - picomatch@4.0.2: {} + picomatch@4.0.3: {} pidtree@0.6.0: {} @@ -5339,8 +5332,8 @@ snapshots: tinyglobby@0.2.9: dependencies: - fdir: 6.4.0(picomatch@4.0.2) - picomatch: 4.0.2 + fdir: 6.4.0(picomatch@4.0.3) + picomatch: 4.0.3 tinypool@1.0.2: {} From e56c41ad16c66f9cea1c5c6fa55994654f7cad82 Mon Sep 17 00:00:00 2001 From: Yaroslav Slepukhin Date: Mon, 28 Jul 2025 19:17:50 +0400 Subject: [PATCH 2/4] chore: improve glob filtering performance by replacing micromatch with picomatch --- .changeset/chatty-ravens-prove.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/chatty-ravens-prove.md diff --git a/.changeset/chatty-ravens-prove.md b/.changeset/chatty-ravens-prove.md new file mode 100644 index 0000000..be84f7a --- /dev/null +++ b/.changeset/chatty-ravens-prove.md @@ -0,0 +1,5 @@ +--- +'steiger': patch +--- + +Improve glob filtering performance by replacing micromatch with picomatch. From 8419bd2685bc7c63d2f7e47666b14c5706477a31 Mon Sep 17 00:00:00 2001 From: Yaroslav Slepukhin Date: Mon, 28 Jul 2025 20:07:30 +0400 Subject: [PATCH 3/4] chore: add picomatch options for consistent glob matching --- .../src/shared/globs/create-filter-according-to-globs.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts b/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts index c62e008..75a06b1 100644 --- a/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts +++ b/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts @@ -13,8 +13,9 @@ export function createFilterAccordingToGlobs({ inclusions, exclusions }: ApplyGl const thereAreInclusions = Array.isArray(inclusions) const thereAreExclusions = Array.isArray(exclusions) const inclusionsEmpty = thereAreInclusions && inclusions.length === 0 + const picomatchOptions = { posixSlashes: true } - const isIncluded = thereAreInclusions ? picomatch(inclusions) : () => true + const isIncluded = thereAreInclusions ? picomatch(inclusions, picomatchOptions) : () => true const positiveExclusionPatterns = (thereAreExclusions && exclusions.filter((pattern) => !isNegatedGlob(pattern))) || [] @@ -22,8 +23,8 @@ export function createFilterAccordingToGlobs({ inclusions, exclusions }: ApplyGl (thereAreExclusions && exclusions.filter((pattern) => isNegatedGlob(pattern)).map((pattern) => pattern.slice(1))) || [] - const isPositivelyExcluded = picomatch(positiveExclusionPatterns) - const isReIncluded = picomatch(negativeExclusionPatterns) + const isPositivelyExcluded = picomatch(positiveExclusionPatterns, picomatchOptions) + const isReIncluded = picomatch(negativeExclusionPatterns, picomatchOptions) function filterAccordingToGlobs(path: string) { if (inclusionsEmpty) { From 95c6164a363a6d4f4cde5a5556b90c0ced5d85e0 Mon Sep 17 00:00:00 2001 From: Yaroslav Slepukhin Date: Sat, 9 Aug 2025 23:33:31 +0400 Subject: [PATCH 4/4] style: rename variable for clarity in glob filtering logic --- .../src/shared/globs/create-filter-according-to-globs.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts b/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts index 75a06b1..1c68b9d 100644 --- a/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts +++ b/packages/steiger/src/shared/globs/create-filter-according-to-globs.ts @@ -19,12 +19,12 @@ export function createFilterAccordingToGlobs({ inclusions, exclusions }: ApplyGl const positiveExclusionPatterns = (thereAreExclusions && exclusions.filter((pattern) => !isNegatedGlob(pattern))) || [] - const negativeExclusionPatterns = + const reInclusionPatterns = (thereAreExclusions && exclusions.filter((pattern) => isNegatedGlob(pattern)).map((pattern) => pattern.slice(1))) || [] const isPositivelyExcluded = picomatch(positiveExclusionPatterns, picomatchOptions) - const isReIncluded = picomatch(negativeExclusionPatterns, picomatchOptions) + const isReIncluded = picomatch(reInclusionPatterns, picomatchOptions) function filterAccordingToGlobs(path: string) { if (inclusionsEmpty) {