Skip to content

Commit

Permalink
feat(lib): matchesGlob
Browse files Browse the repository at this point in the history
Signed-off-by: Lexus Drumgold <[email protected]>
  • Loading branch information
unicornware committed Sep 21, 2024
1 parent cb9e944 commit c08ae10
Show file tree
Hide file tree
Showing 13 changed files with 202 additions and 3 deletions.
1 change: 1 addition & 0 deletions .dictionary.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
attw
barx
cefc
codecov
commitlintrc
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ import {
isDeviceRoot,
isSep,
join,
matchesGlob,
normalize,
parse,
relative,
Expand Down Expand Up @@ -130,6 +131,7 @@ This package exports the following identifiers:
- [`isDeviceRoot`](./src/lib/is-device-root.ts)
- [`isSep`](./src/lib/is-sep.ts)
- [`join`](./src/lib/join.ts)
- [`matchesGlob`](./src/lib/matches-glob.ts)
- [`normalize`](./src/lib/normalize.ts)
- [`parse`](./src/lib/parse.ts)
- [`posix`](./src/pathe.ts)
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@
"typecheck:watch": "vitest --typecheck --mode=typecheck"
},
"dependencies": {
"@flex-development/errnode": "3.1.1"
"@flex-development/errnode": "3.1.1",
"@types/micromatch": "4.0.9",
"micromatch": "4.0.8"
},
"devDependencies": {
"@arethetypeswrong/cli": "0.16.4",
Expand Down
1 change: 1 addition & 0 deletions src/__snapshots__/index.e2e.snap
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ exports[`e2e:pathe > should expose public api 1`] = `
"isDeviceRoot",
"isSep",
"join",
"matchesGlob",
"normalize",
"parse",
"relative",
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/__tests__/platform-path.spec-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ describe('unit-d:interfaces/PlatformPath', () => {
type Subject = keyof TestSubject

// Expect
expectTypeOf<Exclude<Baseline, Subject>>().toEqualTypeOf<'matchesGlob'>()
expectTypeOf<Exclude<Baseline, Subject>>().toEqualTypeOf<never>()
})
})
22 changes: 22 additions & 0 deletions src/interfaces/platform-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
Ext,
Sep
} from '@flex-development/pathe'
import type micromatch from 'micromatch'
import type FormatInputPathObject from './format-input-path-object'
import type ParsedPath from './parsed-path'

Expand Down Expand Up @@ -158,6 +159,27 @@ interface PlatformPath {
*/
join(this: void, ...paths: string[]): string

/**
* Check if `path` matches `pattern`.
*
* @see {@linkcode micromatch.Options}
* @see {@linkcode micromatch.isMatch}
*
* @param {string} path
* The path to glob-match against
* @param {string | string[]} pattern
* Glob patterns to use for matching
* @param {micromatch.Options | null | undefined} [options]
* Options for matching
* @return {boolean}
* `true` if `path` matches `pattern`, `false` otherwise
*/
matchesGlob(
path: string,
pattern: string | string[],
options?: micromatch.Options | null | undefined
): boolean

/**
* Normalize `path`, resolving `'..'` and `'.'` segments.
*
Expand Down
63 changes: 63 additions & 0 deletions src/lib/__tests__/matches-glob.functional.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* @file Functional Tests - matchesGlob
* @module pathe/lib/tests/functional/matchesGlob
* @see https://github.com/nodejs/node/blob/v22.8.0/test/parallel/test-path-glob.js
*/

import process from '#internal/process'
import micromatch from 'micromatch'
import type { MockInstance } from 'vitest'
import testSubject from '../matches-glob'
import toPosix from '../to-posix'

describe('functional:lib/matchesGlob', () => {
let spy: MockInstance<typeof micromatch['isMatch']>

beforeEach(() => {
spy = vi.spyOn(micromatch, 'isMatch')
})

it.each<Parameters<typeof testSubject>>([
['foo/bar/baz', 'foo/**'],
['foo/bar/baz', 'foo/*/!bar/*/baz'],
['foo/bar/baz', 'foo/[!bcr]ar/baz'],
['foo/bar/baz', 'foo/[bc-r]ar/baz'],
['foo/bar/baz', 'foo/[bcr]ar/baz'],
['foo/bar/baz/boo', 'foo/[bc-r]ar/baz/*', { ignore: 'f*' }],
['foo/bar/baz/boo', 'foo/[bc-r]ar/baz/*'],
['foo/bar1/baz', 'foo/bar[0-9]/baz'],
['foo/bar5/baz', 'foo/bar[0-9]/baz'],
['foo/barx/baz', 'foo/bar[a-z]/baz'],
['foo\\bar1\\baz', ['foo/bar[0-9]/baz']],
['foo\\bar1\\baz', ['foo\\bar[0-9]\\baz']],
['foo\\bar5\\baz', ['foo/bar[0-9]/baz']],
['foo\\bar5\\baz', ['foo\\bar[0-9]\\baz']],
['foo\\bar\\baz', 'foo\\*\\!bar\\*\\baz'],
['foo\\bar\\baz', 'foo\\[!bcr]ar\\baz'],
['foo\\bar\\baz', ['foo/**']],
['foo\\bar\\baz', ['foo/[bc-r]ar/baz']],
['foo\\bar\\baz', ['foo/[bcr]ar/baz']],
['foo\\bar\\baz', ['foo\\**']],
['foo\\bar\\baz', ['foo\\[bc-r]ar\\baz']],
['foo\\bar\\baz', ['foo\\[bcr]ar\\baz']],
['foo\\bar\\baz\\boo', 'foo\\[bc-r]ar\\baz\\*', { ignore: 'f*' }],
['foo\\bar\\baz\\boo', ['foo/[bc-r]ar/baz/*']],
['foo\\bar\\baz\\boo', ['foo\\[bc-r]ar\\baz\\*']],
['foo\\barx\\baz', ['foo/bar[a-z]/baz']],
['foo\\barx\\baz', ['foo\\bar[a-z]\\baz']]
])('should call `micromatch.isMatch` (%#)', (path, pattern, options) => {
// Arrange
const pat: typeof pattern = Array.isArray(pattern)
? pattern
: toPosix(pattern)

// Act
testSubject(path, pattern, options)

// Expect
expect(spy).toHaveBeenCalledOnce()
expect(spy.mock.lastCall?.[0]).to.eq(toPosix(path))
expect(spy.mock.lastCall?.[1]).to.eq(pat)
expect(spy.mock.lastCall?.[2]).to.eql({ ...options, cwd: process.cwd() })
})
})
1 change: 1 addition & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export { default as isAbsolute } from './is-absolute'
export { default as isDeviceRoot } from './is-device-root'
export { default as isSep } from './is-sep'
export { default as join } from './join'
export { default as matchesGlob } from './matches-glob'
export { default as normalize } from './normalize'
export { default as parse } from './parse'
export { default as relative } from './relative'
Expand Down
66 changes: 66 additions & 0 deletions src/lib/matches-glob.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* @file matchesGlob
* @module pathe/lib/matchesGlob
*/

import process from '#internal/process'
import validateString from '#internal/validate-string'
import micromatch from 'micromatch'
import toPosix from './to-posix'

/**
* Check if `path` matches `pattern`.
*
* @see {@linkcode micromatch.Options}
* @see {@linkcode micromatch.isMatch}
*
* @category
* core
*
* @param {string} path
* The path to glob-match against
* @param {string | string[]} pattern
* Glob patterns to use for matching
* @param {micromatch.Options | null | undefined} [options]
* Options for matching
* @return {boolean}
* `true` if `path` matches `pattern`, `false` otherwise
*/
function matchesGlob(
path: string,
pattern: string | string[],
options?: micromatch.Options | null | undefined
): boolean {
validateString(path, 'path')

if (Array.isArray<string>(pattern)) {
/**
* Current index in {@linkcode pattern}.
*
* @var {number} i
*/
let i: number = -1

while (++i < pattern.length) {
/**
* Current pattern.
*
* @const {string} pat
*/
const pat: string = pattern[i]!

validateString(pat, `pattern[${i}]`)
pattern[i] = toPosix(pat)
}
} else {
validateString(pattern, 'pattern')
pattern = toPosix(pattern)
}

return micromatch.isMatch(toPosix(path), pattern, {
...options,
cwd: options?.cwd ?? process.cwd()
})
}

export default matchesGlob
4 changes: 4 additions & 0 deletions src/pathe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
isDeviceRoot,
isSep,
join,
matchesGlob,
normalize,
parse,
relative,
Expand All @@ -49,6 +50,7 @@ const posix: PosixPlatformPath = {
format,
isAbsolute,
join,
matchesGlob,
normalize,
parse,
posix: <PosixPlatformPath>{},
Expand All @@ -72,6 +74,7 @@ const win32: WindowsPlatformPath = {
format,
isAbsolute,
join,
matchesGlob,
normalize,
parse,
posix: <PosixPlatformPath>{},
Expand Down Expand Up @@ -112,6 +115,7 @@ const pathe: Pathe = {
isDeviceRoot,
isSep,
join,
matchesGlob,
normalize,
parse,
posix,
Expand Down
1 change: 1 addition & 0 deletions tsconfig.typecheck.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"src/internal/process.d.mts",
"typings/@faker-js/faker/global.d.ts",
"typings/@types/node/process.d.ts",
"typings/typescript/lib.es5.d.ts",
"vitest-env.d.ts"
],
"include": [
Expand Down
18 changes: 18 additions & 0 deletions typings/typescript/lib.es5.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
declare global {
interface ArrayConstructor {
/**
* Check if `value` is an array.
*
* @template {any} T
* Array item type
*
* @param {unknown} value
* Value to check
* @return {value is ReadonlyArray<T> | T[]}
* `true` if `value` is an array
*/
isArray<T>(value: unknown): value is T[] | readonly T[]
}
}

export {}
20 changes: 19 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1753,6 +1753,7 @@ __metadata:
"@types/eslint": "npm:9.6.1"
"@types/eslint__js": "npm:8.42.3"
"@types/is-ci": "npm:3.0.4"
"@types/micromatch": "npm:4.0.9"
"@types/node": "npm:22.5.5"
"@types/node-notifier": "npm:8.0.5"
"@typescript-eslint/eslint-plugin": "npm:8.6.1-alpha.5"
Expand Down Expand Up @@ -1786,6 +1787,7 @@ __metadata:
is-ci: "npm:3.0.1"
jsonc-eslint-parser: "npm:2.4.0"
lint-staged: "npm:15.2.10"
micromatch: "npm:4.0.8"
node-notifier: "npm:10.0.1"
prettier: "npm:3.3.3"
pretty-bytes: "npm:6.1.1"
Expand Down Expand Up @@ -2466,6 +2468,13 @@ __metadata:
languageName: node
linkType: hard

"@types/braces@npm:*":
version: 3.0.4
resolution: "@types/braces@npm:3.0.4"
checksum: 10/7324497b6cc34c963c44d3f8516c67a83b749ab4f18defd9418b231b071af7ee8f0a0f345a52b204e867de80f684cabb21158512e1eaecbcebbabed1d1e357a3
languageName: node
linkType: hard

"@types/concat-stream@npm:^2.0.0":
version: 2.0.3
resolution: "@types/concat-stream@npm:2.0.3"
Expand Down Expand Up @@ -2617,6 +2626,15 @@ __metadata:
languageName: node
linkType: hard

"@types/micromatch@npm:4.0.9":
version: 4.0.9
resolution: "@types/micromatch@npm:4.0.9"
dependencies:
"@types/braces": "npm:*"
checksum: 10/324f4bcb4a7caa2048bdd650f442d2c24b5bf6bc95e4d63d4741bd234fdcf3cde140217bd477b2c02c7fb0034c7293037fd7b61429ace84e997dd3b4d3b2b2f7
languageName: node
linkType: hard

"@types/ms@npm:*":
version: 0.7.34
resolution: "@types/ms@npm:0.7.34"
Expand Down Expand Up @@ -7995,7 +8013,7 @@ __metadata:
languageName: node
linkType: hard

"micromatch@npm:^4.0.4, micromatch@npm:^4.0.8, micromatch@npm:~4.0.8":
"micromatch@npm:4.0.8, micromatch@npm:^4.0.4, micromatch@npm:^4.0.8, micromatch@npm:~4.0.8":
version: 4.0.8
resolution: "micromatch@npm:4.0.8"
dependencies:
Expand Down

0 comments on commit c08ae10

Please sign in to comment.