Skip to content

Commit 8404778

Browse files
committed
Use escape, unescape, hasMagic from Minimatch
Fix: #367
1 parent acace9a commit 8404778

File tree

5 files changed

+60
-23
lines changed

5 files changed

+60
-23
lines changed

README.md

+28
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,34 @@ if you had called it on `['xay', 'xby']`. When
138138
`magicalBraces:true` is in the options, brace expansion _is_
139139
treated as a pattern having magic.
140140

141+
## `escape(pattern: string, options?: GlobOptions) => string`
142+
143+
Escape all magic characters in a glob pattern, so that it will
144+
only ever match literal strings
145+
146+
If the `windowsPathsNoEscape` option is used, then characters are
147+
escaped by wrapping in `[]`, because a magic character wrapped in
148+
a character class can only be satisfied by that exact character.
149+
150+
Slashes (and backslashes in `windowsPathsNoEscape` mode) cannot
151+
be escaped or unescaped.
152+
153+
## `unescape(pattern: string, options?: GlobOptions) => string`
154+
155+
Un-escape a glob string that may contain some escaped characters.
156+
157+
If the `windowsPathsNoEscape` option is used, then square-brace
158+
escapes are removed, but not backslash escapes. For example, it
159+
will turn the string `'[*]'` into `*`, but it will not turn
160+
`'\\*'` into `'*'`, because `\` is a path separator in
161+
`windowsPathsNoEscape` mode.
162+
163+
When `windowsPathsNoEscape` is not set, then both brace escapes
164+
and backslash escapes are removed.
165+
166+
Slashes (and backslashes in `windowsPathsNoEscape` mode) cannot
167+
be escaped or unescaped.
168+
141169
## Class `Glob`
142170

143171
An object that can perform glob pattern traversals.

src/has-magic.ts

+9-11
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
import { Glob, GlobOptions } from './glob.js'
1+
import { Minimatch } from 'minimatch'
2+
import { GlobOptions } from './glob.js'
23

34
/**
4-
* Return true if the patterns provided contain any magic
5-
* glob characters, given the options provided.
5+
* Return true if the patterns provided contain any magic glob characters,
6+
* given the options provided.
67
*
78
* Brace expansion is not considered "magic" unless the `magicalBraces` option
89
* is set, as brace expansion just turns one string into an array of strings.
910
* So a pattern like `'x{a,b}y'` would return `false`, because `'xay'` and
1011
* `'xby'` both do not contain any magic glob characters, and it's treated the
11-
* same as if you had called it on `['xay', 'xby']`. When
12-
* `magicalBraces:true` is in the options, brace expansion _is_ treated as a
13-
* pattern having magic.
12+
* same as if you had called it on `['xay', 'xby']`. When `magicalBraces:true`
13+
* is in the options, brace expansion _is_ treated as a pattern having magic.
1414
*/
1515
export const hasMagic = (
1616
pattern: string | string[],
@@ -19,10 +19,8 @@ export const hasMagic = (
1919
if (!Array.isArray(pattern)) {
2020
pattern = [pattern]
2121
}
22-
const length = pattern.length
23-
const g = new Glob(pattern, options)
24-
if (g.magicalBraces && g.patterns.length !== length) {
25-
return true
22+
for (const p of pattern) {
23+
if (new Minimatch(p, options).hasMagic()) return true
2624
}
27-
return g.patterns.some(p => p.hasMagic())
25+
return false
2826
}

src/index.ts

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { escape, unescape } from 'minimatch'
12
import type {
23
GlobOptions,
34
GlobOptionsWithFileTypesFalse,
@@ -178,6 +179,7 @@ export function globIterateSync(
178179
}
179180

180181
/* c8 ignore start */
182+
export { escape, unescape } from 'minimatch'
181183
export { Glob } from './glob.js'
182184
export type {
183185
GlobOptions,
@@ -189,6 +191,7 @@ export type {
189191
} from './glob.js'
190192
export { hasMagic } from './has-magic.js'
191193
export type { MatchStream } from './walker.js'
194+
192195
/* c8 ignore stop */
193196
export default Object.assign(glob, {
194197
glob,
@@ -199,4 +202,6 @@ export default Object.assign(glob, {
199202
globIterateSync,
200203
Glob,
201204
hasMagic,
205+
escape,
206+
unescape,
202207
})

src/pattern.ts

-12
Original file line numberDiff line numberDiff line change
@@ -230,18 +230,6 @@ export class Pattern {
230230
: ''
231231
}
232232

233-
/**
234-
* True if the pattern has any non-string components
235-
*/
236-
hasMagic(): boolean {
237-
for (let i = 0; i < this.length; i++) {
238-
if (typeof this.#patternList[i] !== 'string') {
239-
return true
240-
}
241-
}
242-
return false
243-
}
244-
245233
/**
246234
* Check to see if the current globstar pattern is allowed to follow
247235
* a symbolic link.

test/escape.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import t from 'tap'
2+
import { unescape, escape, hasMagic } from '../'
3+
import { bashResults } from './bash-results'
4+
5+
for (const pattern of Object.keys(bashResults)) {
6+
t.notOk(hasMagic(escape(pattern)), `escape(${pattern})`)
7+
const pp = escape(pattern)
8+
const pw = escape(pattern, {
9+
windowsPathsNoEscape: true
10+
})
11+
t.notOk(hasMagic(pp, { platform: 'linux' }), 'no magic after posix escape')
12+
t.notOk(hasMagic(pw, { platform: 'win32', windowsPathsNoEscape: true }),
13+
'no magic after windows escape')
14+
const up = unescape(pp)
15+
const uw = unescape(pw, { windowsPathsNoEscape: true })
16+
t.equal(up, pattern, 'unescaped posix pattern returned')
17+
t.equal(uw, pattern, 'unescaped windows pattern returned')
18+
}

0 commit comments

Comments
 (0)