Skip to content

Commit

Permalink
Merge pull request #201 from mrmlnc/issue-199_match_base_fix
Browse files Browse the repository at this point in the history
ISSUE-199: fix `baseNameMatch` option behaviour
  • Loading branch information
mrmlnc committed Jun 10, 2019
2 parents f3642dc + 68133f8 commit 87ed886
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 22 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,13 +283,15 @@ Enable a [case-sensitive](https://en.wikipedia.org/wiki/Case_sensitivity) mode f
* Case-sensitive for `test/file.*` pattern: `test/file.md`
* Case-insensitive for `test/file.*` pattern: `test/file.md`, `test/File.md`

#### matchBase
#### baseNameMatch

* Type: `boolean`
* Default: `false`

Allow glob patterns without slashes to match a file path based on its basename. For example, `a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`.

> :book: This option has no affect to negative patterns from any source (patterns, `ignore`).
#### suppressErrors

* Type: `boolean`
Expand Down Expand Up @@ -404,7 +406,7 @@ Not fully, because `fast-glob` does not implement all options of `node-glob`. Se
| `noglobstar` | [`globstar`](#globstar) |
| `noext` | [`extglob`](#extglob) |
| `nocase` | [`caseSensitiveMatch`](#caseSensitiveMatch) |
| `matchBase` | [`matchbase`](#matchbase) |
| `matchBase` | [`baseNameMatch`](#baseNameMatch) |
| `nodir` | [`onlyFiles`](#onlyfiles) |
| `ignore` | [`ignore`](#ignore) |
| `follow` | [`followSymbolicLinks`](#followSymbolicLinks) |
Expand Down
9 changes: 9 additions & 0 deletions src/providers/filters/deep.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,15 @@ describe('Providers → Filters → Deep', () => {
assert.ok(!actual);
});

it('should return `treu` when the positive pattern has no affect to depth reading, but the `baseNameMatch` is enabled', () => {
const filter = getFilter('.', ['*'], [], { baseNameMatch: true });
const entry = tests.entry.builder().path('root/directory').directory().build();

const actual = filter(entry);

assert.ok(actual);
});

it('should return `true` when the negative pattern has no effect to depth reading', () => {
const filter = getFilter('.', ['**/*'], ['**/*']);
const entry = tests.entry.builder().path('root/directory').directory().build();
Expand Down
2 changes: 1 addition & 1 deletion src/providers/filters/deep.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export default class DeepFilter {
}

private _isSkippedByMaxPatternDepth(entryDepth: number, maxPatternDepth: number): boolean {
return maxPatternDepth !== Infinity && entryDepth > maxPatternDepth;
return !this._settings.baseNameMatch && maxPatternDepth !== Infinity && entryDepth > maxPatternDepth;
}

private _isSkippedSymbolicLink(entry: Entry): boolean {
Expand Down
24 changes: 23 additions & 1 deletion src/providers/filters/entry.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ describe('Providers → Filters → Entry', () => {
assert.ok(!actual);
});

it('should return `false` when an entry do not match to the negative pattern', () => {
it('should return `true` when an entry do not match to the negative pattern', () => {
const filter = getFilter(['**/*'], ['*'], { absolute: true });

const entry = tests.entry.builder().path('root/file.txt').file().build();
Expand All @@ -120,6 +120,28 @@ describe('Providers → Filters → Entry', () => {
});
});

describe('options.baseNameMatch', () => {
it('should return `false` when an option is disabled', () => {
const filter = getFilter(['*'], []);

const entry = tests.entry.builder().path('root/file.txt').file().build();

const actual = filter(entry);

assert.ok(!actual);
});

it('should return `true` when an option is enabled', () => {
const filter = getFilter(['*'], [], { baseNameMatch: true });

const entry = tests.entry.builder().path('root/file.txt').file().build();

const actual = filter(entry);

assert.ok(actual);
});
});

describe('Pattern', () => {
it('should return `false` when an entry match to the negative pattern', () => {
const filter = getFilter(['**/*'], ['**/*']);
Expand Down
4 changes: 3 additions & 1 deletion src/providers/filters/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ export default class EntryFilter {
return false;
}

return this._isMatchToPatterns(entry.path, positiveRe) && !this._isMatchToPatterns(entry.path, negativeRe);
const filepath = this._settings.baseNameMatch ? entry.name : entry.path;

return this._isMatchToPatterns(filepath, positiveRe) && !this._isMatchToPatterns(entry.path, negativeRe);
}

private _isDuplicateEntry(entry: Entry): boolean {
Expand Down
2 changes: 1 addition & 1 deletion src/providers/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default abstract class Provider<T> {
protected _getMicromatchOptions(): MicromatchOptions {
return {
dot: this._settings.dot,
matchBase: this._settings.matchBase,
matchBase: this._settings.baseNameMatch,
nobrace: !this._settings.braceExpansion,
nocase: !this._settings.caseSensitiveMatch,
noext: !this._settings.extglob,
Expand Down
28 changes: 14 additions & 14 deletions src/settings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,27 @@ describe('Settings', () => {
it('should return instance with default values', () => {
const settings = new Settings();

assert.strictEqual(settings.concurrency, Infinity);
assert.strictEqual(settings.cwd, process.cwd());
assert.ok(settings.deep);
assert.deepStrictEqual(settings.fs, DEFAULT_FILE_SYSTEM_ADAPTER);
assert.deepStrictEqual(settings.ignore, []);
assert.ok(!settings.absolute);
assert.ok(!settings.baseNameMatch);
assert.ok(!settings.dot);
assert.ok(!settings.markDirectories);
assert.ok(!settings.objectMode);
assert.ok(!settings.stats);
assert.ok(settings.onlyFiles);
assert.ok(!settings.onlyDirectories);
assert.ok(settings.followSymbolicLinks);
assert.ok(!settings.stats);
assert.ok(!settings.suppressErrors);
assert.ok(!settings.throwErrorOnBrokenSymbolicLink);
assert.ok(settings.unique);
assert.ok(!settings.markDirectories);
assert.ok(!settings.absolute);
assert.ok(settings.braceExpansion);
assert.ok(settings.globstar);
assert.ok(settings.extglob);
assert.ok(settings.caseSensitiveMatch);
assert.ok(!settings.matchBase);
assert.ok(!settings.suppressErrors);
assert.deepStrictEqual(settings.fs, DEFAULT_FILE_SYSTEM_ADAPTER);
assert.ok(settings.deep);
assert.ok(settings.extglob);
assert.ok(settings.followSymbolicLinks);
assert.ok(settings.globstar);
assert.ok(settings.onlyFiles);
assert.ok(settings.unique);
assert.strictEqual(settings.concurrency, Infinity);
assert.strictEqual(settings.cwd, process.cwd());
});

it('should return instance with custom values', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export interface Options {
* Allow glob patterns without slashes to match a file path based on its basename.
* For example, `a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`.
*/
matchBase?: boolean;
baseNameMatch?: boolean;
/**
* Suppress any errors from reader.
* Can be useful when the directory has entries with a special level of access.
Expand All @@ -105,6 +105,7 @@ export interface Options {

export default class Settings {
public readonly absolute: boolean = this._getValue(this._options.absolute, false);
public readonly baseNameMatch: boolean = this._getValue(this._options.baseNameMatch, false);
public readonly braceExpansion: boolean = this._getValue(this._options.braceExpansion, true);
public readonly caseSensitiveMatch: boolean = this._getValue(this._options.caseSensitiveMatch, true);
public readonly concurrency: number = this._getValue(this._options.concurrency, Infinity);
Expand All @@ -117,7 +118,6 @@ export default class Settings {
public readonly globstar: boolean = this._getValue(this._options.globstar, true);
public readonly ignore: Pattern[] = this._getValue(this._options.ignore, [] as Pattern[]);
public readonly markDirectories: boolean = this._getValue(this._options.markDirectories, false);
public readonly matchBase: boolean = this._getValue(this._options.matchBase, false);
public readonly objectMode: boolean = this._getValue(this._options.objectMode, false);
public readonly onlyDirectories: boolean = this._getValue(this._options.onlyDirectories, false);
public readonly onlyFiles: boolean = this._getValue(this._options.onlyFiles, true);
Expand Down
10 changes: 10 additions & 0 deletions src/tests/smoke/base-name-match.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as smoke from './smoke';

smoke.suite('Smoke → MatchBase', [
{
pattern: '*.md',
cwd: 'fixtures',
globOptions: { matchBase: true },
fgOptions: { baseNameMatch: true }
}
]);
12 changes: 12 additions & 0 deletions src/tests/smoke/case-sensitive-match.smoke.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as smoke from './smoke';

smoke.suite('Smoke → CaseSensitiveMatch', [
{
pattern: 'fixtures/File.md'
},
{
pattern: 'fixtures/File.md',
globOptions: { nocase: true },
fgOptions: { caseSensitiveMatch: false }
}
]);
9 changes: 9 additions & 0 deletions src/tests/smoke/mark-directories.smoke.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as smoke from './smoke';

smoke.suite('Smoke → MarkDirectories', [
{
pattern: 'fixtures/**/*',
globOptions: { mark: true },
fgOptions: { markDirectories: true }
}
]);

0 comments on commit 87ed886

Please sign in to comment.