Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISSUE-163: patterns can only use forward-slash as a path separator #178

Merged
merged 1 commit into from
May 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,32 @@ fg.sync(['**/*.md'], { ignore: '**/second/**' }); // ['first/file.txt']

You have to understand that if you write the pattern to exclude directories, then the directory will not be read under any circumstances.

## How to write patterns on Windows?

Always use forward-slashes in glob expressions (patterns and `ignore` option). Use backslashes for escaping characters. With the `cwd` option use a convenient format.

**Bad**

```ts
[
'directory\\*',
path.join(process.cwd(), '**')
]
```

**Good**

```ts
[
'directory/*',
path.join(process.cwd(), '**').replace(/\\/g, '/')
]
```

> :book: Use the [`normalize-path`](https://www.npmjs.com/package/normalize-path) or the [`unixify`](https://www.npmjs.com/package/unixify) package to convert Windows-style path to a Unix-style path.

Read more about [matching with backslashes](https://github.com/micromatch/micromatch#backslashes).

## Compatible with `node-glob`?

Not fully, because `fast-glob` does not implement all options of `node-glob`. See table below.
Expand Down
5 changes: 3 additions & 2 deletions src/adapters/fs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ describe('Adapters → FileSystem', () => {
it('should return created entry', () => {
const adapter = getAdapter();

const actual = adapter.makeEntry(tests.getFileEntry(), 'base/file.json');
const filepath = path.join('base', 'file.json');
const actual = adapter.makeEntry(tests.getFileEntry(), filepath);

assert.strictEqual(actual.path, 'base/file.json');
assert.strictEqual(actual.path, filepath);
assert.strictEqual(actual.depth, 2);
});

Expand Down
2 changes: 1 addition & 1 deletion src/adapters/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default abstract class FileSystem<T> {
*/
public makeEntry(stat: fs.Stats, pattern: Pattern): Entry {
(stat as Entry).path = pattern;
(stat as Entry).depth = pattern.split('/').length;
(stat as Entry).depth = pattern.split(path.sep).length;

return stat as Entry;
}
Expand Down
16 changes: 0 additions & 16 deletions src/managers/tasks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,6 @@ import { Task } from './tasks';

describe('Managers → Task', () => {
describe('.generate', () => {
it('should return task with windows-like patterns', () => {
const settings = new Settings();

const expected: Task[] = [{
base: 'a',
dynamic: true,
patterns: ['a/*'],
positive: ['a/*'],
negative: []
}];

const actual = manager.generate(['a\\*'], settings);

assert.deepStrictEqual(actual, expected);
});

it('should return task with negative patterns from «ignore» option', () => {
const settings = new Settings({ ignore: ['*.txt'] });

Expand Down
7 changes: 2 additions & 5 deletions src/managers/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@ export interface Task {
* Generate tasks based on parent directory of each pattern.
*/
export function generate(patterns: Pattern[], settings: Settings): Task[] {
const unixPatterns = patterns.map(utils.pattern.unixifyPattern);
const unixIgnore = settings.ignore.map(utils.pattern.unixifyPattern);

const positivePatterns = getPositivePatterns(unixPatterns);
const negativePatterns = getNegativePatternsAsPositive(unixPatterns, unixIgnore);
const positivePatterns = getPositivePatterns(patterns);
const negativePatterns = getNegativePatternsAsPositive(patterns, settings.ignore);

const staticPatterns = positivePatterns.filter(utils.pattern.isStaticPattern);
const dynamicPatterns = positivePatterns.filter(utils.pattern.isDynamicPattern);
Expand Down
15 changes: 8 additions & 7 deletions src/providers/filters/deep.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as assert from 'assert';
import * as path from 'path';

import Settings, { Options } from '../../settings';
import * as tests from '../../tests';
Expand Down Expand Up @@ -42,7 +43,7 @@ describe('Providers → Filters → Deep', () => {
const filter = getFilter(['fixtures/**'], [], { deep: 1 });

const entry = tests.getDirectoryEntry({
path: 'fixtures/one/two/three'
path: path.join('fixtures', 'one', 'two', 'three')
});

const actual = filter(entry);
Expand All @@ -54,7 +55,7 @@ describe('Providers → Filters → Deep', () => {
const filter = getFilter(['fixtures/**'], [], { deep: 1 });

const entry = tests.getDirectoryEntry({
path: 'fixtures/one/two'
path: path.join('fixtures', 'one', 'two')
});

const actual = filter(entry);
Expand All @@ -66,7 +67,7 @@ describe('Providers → Filters → Deep', () => {
const filter = getFilter(['fixtures/**'], [], { deep: 2 });

const entry = tests.getDirectoryEntry({
path: 'fixtures/one/two'
path: path.join('fixtures', 'one', 'two')
});

const actual = filter(entry);
Expand All @@ -90,7 +91,7 @@ describe('Providers → Filters → Deep', () => {
const filter = getFilter(['fixtures/*/*/*'], []);

const entry = tests.getDirectoryEntry({
path: 'fixtures/one/two'
path: path.join('fixtures', 'one', 'two')
});

const actual = filter(entry);
Expand All @@ -102,7 +103,7 @@ describe('Providers → Filters → Deep', () => {
const filter = getFilter(['fixtures/*'], []);

const entry = tests.getDirectoryEntry({
path: 'fixtures/one/two/three/four'
path: path.join('fixtures', 'one', 'two', 'three', 'four')
});

const actual = filter(entry);
Expand Down Expand Up @@ -142,7 +143,7 @@ describe('Providers → Filters → Deep', () => {
const filter = getFilter(['**/*'], [], { onlyFiles: false, dot: true });

const entry = tests.getDirectoryEntry({
path: 'fixtures/.directory'
path: path.join('fixtures', '.directory')
});

const actual = filter(entry);
Expand All @@ -154,7 +155,7 @@ describe('Providers → Filters → Deep', () => {
const filter = getFilter(['**/*'], []);

const entry = tests.getDirectoryEntry({
path: 'fixtures/.directory'
path: path.join('fixtures', '.directory')
});

const actual = filter(entry);
Expand Down
11 changes: 6 additions & 5 deletions src/providers/filters/entry.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as assert from 'assert';
import * as path from 'path';

import Settings, { Options } from '../../settings';
import * as tests from '../../tests';
Expand Down Expand Up @@ -191,7 +192,7 @@ describe('Providers → Filters → Entry', () => {
const filter = getFilter(['**/*'], [], { onlyFiles: false, dot: true });

const entry = tests.getFileEntry({
path: 'fixtures/.file.txt'
path: path.join('fixtures', '.file.txt')
});

const actual = filter(entry);
Expand All @@ -203,7 +204,7 @@ describe('Providers → Filters → Entry', () => {
const filter = getFilter(['**/*'], [], { onlyFiles: false });

const entry = tests.getFileEntry({
path: 'fixtures/.file.txt'
path: path.join('fixtures', '.file.txt')
});

const actual = filter(entry);
Expand All @@ -215,7 +216,7 @@ describe('Providers → Filters → Entry', () => {
const filter = getFilter(['**/*'], [], { onlyFiles: false, dot: true });

const entry = tests.getDirectoryEntry({
path: 'fixtures/.directory'
path: path.join('fixtures', '.directory')
});

const actual = filter(entry);
Expand All @@ -227,7 +228,7 @@ describe('Providers → Filters → Entry', () => {
const filter = getFilter(['**/*'], []);

const entry = tests.getDirectoryEntry({
path: 'fixtures/.directory'
path: path.join('fixtures', '.directory')
});

const actual = filter(entry);
Expand Down Expand Up @@ -268,7 +269,7 @@ describe('Providers → Filters → Entry', () => {
});

it('should return false for file that excluded by absolute negative patterns when `absolute` option is enabled', () => {
const negative = utils.path.makeAbsolute(process.cwd(), '**');
const negative = utils.path.makeAbsolute(process.cwd(), '**').replace(/\\/g, '/');
const filter = getFilter(['**/*'], [negative], { absolute: true });

const entry = tests.getFileEntry();
Expand Down
4 changes: 3 additions & 1 deletion src/providers/filters/entry.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as path from 'path';

import Settings from '../../settings';
import { Entry, EntryFilterFunction, MicromatchOptions, Pattern, PatternRe } from '../../types/index';
import * as utils from '../../utils/index';
Expand Down Expand Up @@ -90,6 +92,6 @@ export default class EntryFilter {
* Second, trying to apply patterns to the path with final slash (need to micromatch to support «directory/**» patterns).
*/
private isMatchToPatterns(filepath: string, patternsRe: PatternRe[]): boolean {
return utils.pattern.matchAny(filepath, patternsRe) || utils.pattern.matchAny(filepath + '/', patternsRe);
return utils.pattern.matchAny(filepath, patternsRe) || utils.pattern.matchAny(filepath + path.sep, patternsRe);
}
}
6 changes: 2 additions & 4 deletions src/providers/provider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ describe('Providers → Provider', () => {
});

assert.strictEqual(actual.basePath, '');
assert.strictEqual(actual.sep, '/');
assert.strictEqual(typeof actual.filter, 'function');
assert.strictEqual(typeof actual.deep, 'function');
});
Expand All @@ -81,7 +80,6 @@ describe('Providers → Provider', () => {
});

assert.strictEqual(actual.basePath, 'fixtures');
assert.strictEqual(actual.sep, '/');
assert.strictEqual(typeof actual.filter, 'function');
assert.strictEqual(typeof actual.deep, 'function');
});
Expand Down Expand Up @@ -124,7 +122,7 @@ describe('Providers → Provider', () => {
const entry = tests.getDirectoryEntry();

const fullpath = path.join(process.cwd(), 'fixtures/directory/');
const expected = utils.path.normalize(fullpath);
const expected = utils.path.unixify(fullpath);

const actual = provider.transform(entry);

Expand Down Expand Up @@ -160,7 +158,7 @@ describe('Providers → Provider', () => {
const entry = tests.getFileEntry();

const fullpath = path.join(process.cwd(), 'fixtures/file.txt');
const expected = utils.path.normalize(fullpath);
const expected = utils.path.unixify(fullpath);

const actual = provider.transform(entry);

Expand Down
7 changes: 4 additions & 3 deletions src/providers/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ export default abstract class Provider<T> {
return {
basePath: task.base === '.' ? '' : task.base,
filter: this.entryFilter.getFilter(task.positive, task.negative),
deep: this.deepFilter.getFilter(task.positive, task.negative),
sep: '/'
deep: this.deepFilter.getFilter(task.positive, task.negative)
};
}

Expand All @@ -67,9 +66,11 @@ export default abstract class Provider<T> {
}

if (this.settings.markDirectories && entry.isDirectory()) {
entry.path += '/';
entry.path += path.sep;
}

entry.path = utils.path.unixify(entry.path);

const item: EntryItem = this.settings.stats ? entry : entry.path;

if (this.settings.transform === null) {
Expand Down
9 changes: 5 additions & 4 deletions src/tests/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as fs from 'fs';
import * as path from 'path';
import * as stream from 'stream';

import { Entry, EntryItem } from '../types/index';
Expand Down Expand Up @@ -34,8 +35,8 @@ interface FakeFsStatOptions {
}

class FakeEntry extends fs.Stats {
public path: string = this._options.path || 'fixtures/entry';
public depth: number = this.path.split('/').length - 2;
public path: string = this._options.path || path.join('fixtures', 'entry');
public depth: number = this.path.split(path.sep).length - 2;

constructor(private readonly _options: Partial<FakeFsStatOptions> = {}) {
super();
Expand All @@ -61,15 +62,15 @@ export function getEntry(options: Partial<FakeFsStatOptions> = {}): Entry {
export function getFileEntry(options: Partial<FakeFsStatOptions> = {}): Entry {
return new FakeEntry({
isFile: true,
path: 'fixtures/file.txt',
path: path.join('fixtures', 'file.txt'),
...options
});
}

export function getDirectoryEntry(options: Partial<FakeFsStatOptions> = {}): Entry {
return new FakeEntry({
isDirectory: true,
path: 'fixtures/directory',
path: path.join('fixtures', 'directory'),
...options
});
}
12 changes: 7 additions & 5 deletions src/tests/smoke/absolute.smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as path from 'path';

import * as smoke from './smoke';

const CWD = process.cwd().replace(/\\/g, '/');

smoke.suite('Smoke → Absolute', [
{
pattern: 'fixtures/*',
Expand Down Expand Up @@ -38,13 +40,13 @@ smoke.suite('Smoke → Absolute (ignore)', [

{
pattern: 'fixtures/*',
ignore: path.join(process.cwd(), 'fixtures', '*'),
ignore: path.posix.join(CWD, 'fixtures', '*'),
globOptions: { absolute: true },
fgOptions: { absolute: true }
},
{
pattern: 'fixtures/**',
ignore: path.join(process.cwd(), 'fixtures', '*'),
ignore: path.posix.join(CWD, 'fixtures', '*'),
globOptions: { absolute: true },
fgOptions: { absolute: true },
broken: true,
Expand Down Expand Up @@ -91,21 +93,21 @@ smoke.suite('Smoke → Absolute (cwd & ignore)', [

{
pattern: '*',
ignore: path.join(process.cwd(), 'fixtures', '*'),
ignore: path.posix.join(CWD, 'fixtures', '*'),
cwd: 'fixtures',
globOptions: { absolute: true },
fgOptions: { absolute: true }
},
{
pattern: '**',
ignore: path.join(process.cwd(), 'fixtures', '*'),
ignore: path.posix.join(CWD, 'fixtures', '*'),
cwd: 'fixtures',
globOptions: { absolute: true },
fgOptions: { absolute: true }
},
{
pattern: '**',
ignore: path.join(process.cwd(), 'fixtures', '**'),
ignore: path.posix.join(CWD, 'fixtures', '**'),
cwd: 'fixtures',
globOptions: { absolute: true },
fgOptions: { absolute: true }
Expand Down
Loading