Skip to content

Commit

Permalink
Add dotRelative option
Browse files Browse the repository at this point in the history
Fix: #495

PR-URL: #500
Credit: @isaacs
Close: #500
Reviewed-by: @isaacs
  • Loading branch information
isaacs committed Mar 1, 2023
1 parent 08e7348 commit 0833310
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 1 deletion.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,16 @@ share the previously loaded cache.
Only has effect on the {@link hasMagic} function, no effect on
glob pattern matching itself.

- `dotRelative` Prepend all relative path strings with `./` (or
`.\` on Windows).

Without this option, returned relative paths are "bare", so
instead of returning `'./foo/bar'`, they are returned as
`'foo/bar'`.

Relative patterns starting with `'../'` are not prepended with
`./`, even if this option is set.

- `mark` Add a `/` character to directory matches. Note that this
requires additional stat calls.

Expand Down
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
absolute.
- Add `magicalBraces` option to treat brace expansion as "magic"
in the `hasMagic` function.
- Add `dotRelative` option

## 9.0

Expand Down
13 changes: 13 additions & 0 deletions src/glob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,17 @@ export interface GlobOptions {
*/
dot?: boolean

/**
* Prepend all relative path strings with `./` (or `.\` on Windows).
*
* Without this option, returned relative paths are "bare", so instead of
* returning `'./foo/bar'`, they are returned as `'foo/bar'`.
*
* Relative patterns starting with `'../'` are not prepended with `./`, even
* if this option is set.
*/
dotRelative?: boolean

/**
* Follow symlinked directories when expanding `**`
* patterns. This can result in a lot of duplicate references in
Expand Down Expand Up @@ -269,6 +280,7 @@ export class Glob<Opts extends GlobOptions> implements GlobOptions {
cwd: string
root?: string
dot: boolean
dotRelative: boolean
follow: boolean
ignore?: Ignore
magicalBraces: boolean
Expand Down Expand Up @@ -314,6 +326,7 @@ export class Glob<Opts extends GlobOptions> implements GlobOptions {
this.signal = opts.signal
this.follow = !!opts.follow
this.dot = !!opts.dot
this.dotRelative = !!opts.dotRelative
this.nodir = !!opts.nodir
this.mark = !!opts.mark
if (!opts.cwd) {
Expand Down
5 changes: 4 additions & 1 deletion src/walker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface GlobWalkerOpts {
allowWindowsEscape?: boolean
cwd?: string | URL
dot?: boolean
dotRelative?: boolean
follow?: boolean
ignore?: string | string[] | Ignore
mark?: boolean
Expand Down Expand Up @@ -200,7 +201,9 @@ export abstract class GlobUtil<O extends GlobWalkerOpts = GlobWalkerOpts> {
this.matchEmit(e.fullpath() + mark)
} else {
const rel = e.relative()
this.matchEmit(!rel && mark ? '.' + mark : rel + mark)
const pre = this.opts.dotRelative && !rel.startsWith('..' + this.#sep)
? '.' + this.#sep : ''
this.matchEmit(!rel && mark ? '.' + mark : pre + rel + mark)
}
}

Expand Down
75 changes: 75 additions & 0 deletions test/dot-relative.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import t from 'tap'
import { Glob } from '../'
import { bashResults } from './bash-results'
import {resolve, sep} from 'path'

const pattern = 'a/b/**'
process.chdir(__dirname + '/fixtures')

const marks = [true, false]
for (const mark of marks) {
t.test('mark=' + mark, t => {
t.plan(3)

t.test('Emits relative matches prefixed with ./', async t => {
const g = new Glob(pattern, { dotRelative: true })
const results = await g.walk()

t.equal(
results.length,
bashResults[pattern].length,
'must match all files'
)
for (const m of results) {
t.ok(m.startsWith('.' + sep))
}
})

t.test('returns ./ prefixed matches synchronously', async t => {
const g = new Glob(pattern, { dotRelative: true })
const results = g.walkSync()

t.equal(
results.length,
bashResults[pattern].length,
'must match all files'
)
for (const m of results) {
t.ok(m.startsWith('.' + sep))
}
})

t.test('does not prefix with ./ unless dotRelative is true', async t => {
const g = new Glob(pattern, {})
const results = await g.walk()

t.equal(
results.length,
bashResults[pattern].length,
'must match all files'
)
for (const m of results) {
t.ok(mark && m === '.' + sep || !m.startsWith('.' + sep))
}
})
})
}

t.test('does not add ./ for patterns starting in ../', async t => {
t.plan(2)
const pattern = '../a/b/**'
const cwd = resolve(__dirname, 'fixtures/a')
t.test('async', async t => {
const g = new Glob(pattern, { dotRelative: true, cwd })
for await (const m of g) {
t.ok(!m.startsWith('.' + sep + '..' + sep))
}
})
t.test('sync', t => {
const g = new Glob(pattern, { dotRelative: true, cwd })
for (const m of g) {
t.ok(!m.startsWith('.' + sep + '..' + sep))
}
t.end()
})
})

0 comments on commit 0833310

Please sign in to comment.