Skip to content

Commit

Permalink
feat: ability to include pattern base directory to the result
Browse files Browse the repository at this point in the history
  • Loading branch information
mrmlnc committed May 13, 2023
1 parent 2dd7b5d commit a6ee709
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 16 deletions.
173 changes: 173 additions & 0 deletions __snapshots__/include-pattern-base-directory.e2e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/**","options":{"onlyFiles":false,"includePatternBaseDirectory":true}} (sync) 1'] = [
"fixtures",
"fixtures/file.md",
"fixtures/first",
"fixtures/first/file.md",
"fixtures/first/nested",
"fixtures/first/nested/directory",
"fixtures/first/nested/directory/file.json",
"fixtures/first/nested/directory/file.md",
"fixtures/first/nested/file.md",
"fixtures/second",
"fixtures/second/file.md",
"fixtures/second/nested",
"fixtures/second/nested/directory",
"fixtures/second/nested/directory/file.md",
"fixtures/second/nested/file.md",
"fixtures/third",
"fixtures/third/library",
"fixtures/third/library/a",
"fixtures/third/library/a/book.md",
"fixtures/third/library/b",
"fixtures/third/library/b/book.md"
]

exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/**","options":{"onlyFiles":false,"includePatternBaseDirectory":true}} (async) 1'] = [
"fixtures",
"fixtures/file.md",
"fixtures/first",
"fixtures/first/file.md",
"fixtures/first/nested",
"fixtures/first/nested/directory",
"fixtures/first/nested/directory/file.json",
"fixtures/first/nested/directory/file.md",
"fixtures/first/nested/file.md",
"fixtures/second",
"fixtures/second/file.md",
"fixtures/second/nested",
"fixtures/second/nested/directory",
"fixtures/second/nested/directory/file.md",
"fixtures/second/nested/file.md",
"fixtures/third",
"fixtures/third/library",
"fixtures/third/library/a",
"fixtures/third/library/a/book.md",
"fixtures/third/library/b",
"fixtures/third/library/b/book.md"
]

exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/**","options":{"onlyFiles":false,"includePatternBaseDirectory":true}} (stream) 1'] = [
"fixtures",
"fixtures/file.md",
"fixtures/first",
"fixtures/first/file.md",
"fixtures/first/nested",
"fixtures/first/nested/directory",
"fixtures/first/nested/directory/file.json",
"fixtures/first/nested/directory/file.md",
"fixtures/first/nested/file.md",
"fixtures/second",
"fixtures/second/file.md",
"fixtures/second/nested",
"fixtures/second/nested/directory",
"fixtures/second/nested/directory/file.md",
"fixtures/second/nested/file.md",
"fixtures/third",
"fixtures/third/library",
"fixtures/third/library/a",
"fixtures/third/library/a/book.md",
"fixtures/third/library/b",
"fixtures/third/library/b/book.md"
]

exports['Options IncludePatternBaseDirectory {"pattern":"./","options":{"cwd":"fixtures","onlyFiles":false,"includePatternBaseDirectory":true}} (sync) 1'] = [
"./"
]

exports['Options IncludePatternBaseDirectory {"pattern":"./","options":{"cwd":"fixtures","onlyFiles":false,"includePatternBaseDirectory":true}} (async) 1'] = [
"./"
]

exports['Options IncludePatternBaseDirectory {"pattern":"./","options":{"cwd":"fixtures","onlyFiles":false,"includePatternBaseDirectory":true}} (stream) 1'] = [
"./"
]

exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/**","options":{"ignore":["**"],"onlyFiles":false,"includePatternBaseDirectory":true}} (sync) 1'] = []

exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/**","options":{"ignore":["**"],"onlyFiles":false,"includePatternBaseDirectory":true}} (async) 1'] = []

exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/**","options":{"ignore":["**"],"onlyFiles":false,"includePatternBaseDirectory":true}} (stream) 1'] = []

exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/{first,second}/**","options":{"onlyFiles":false,"includePatternBaseDirectory":true}} (sync) 1'] = [
"fixtures",
"fixtures/first",
"fixtures/first/file.md",
"fixtures/first/nested",
"fixtures/first/nested/directory",
"fixtures/first/nested/directory/file.json",
"fixtures/first/nested/directory/file.md",
"fixtures/first/nested/file.md",
"fixtures/second",
"fixtures/second/file.md",
"fixtures/second/nested",
"fixtures/second/nested/directory",
"fixtures/second/nested/directory/file.md",
"fixtures/second/nested/file.md"
]

exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/{first,second}/**","options":{"onlyFiles":false,"includePatternBaseDirectory":true}} (async) 1'] = [
"fixtures",
"fixtures/first",
"fixtures/first/file.md",
"fixtures/first/nested",
"fixtures/first/nested/directory",
"fixtures/first/nested/directory/file.json",
"fixtures/first/nested/directory/file.md",
"fixtures/first/nested/file.md",
"fixtures/second",
"fixtures/second/file.md",
"fixtures/second/nested",
"fixtures/second/nested/directory",
"fixtures/second/nested/directory/file.md",
"fixtures/second/nested/file.md"
]

exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/{first,second}/**","options":{"onlyFiles":false,"includePatternBaseDirectory":true}} (stream) 1'] = [
"fixtures",
"fixtures/first",
"fixtures/first/file.md",
"fixtures/first/nested",
"fixtures/first/nested/directory",
"fixtures/first/nested/directory/file.json",
"fixtures/first/nested/directory/file.md",
"fixtures/first/nested/file.md",
"fixtures/second",
"fixtures/second/file.md",
"fixtures/second/nested",
"fixtures/second/nested/directory",
"fixtures/second/nested/directory/file.md",
"fixtures/second/nested/file.md"
]

exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/{first,}/**","options":{"onlyFiles":false,"includePatternBaseDirectory":true}} (sync) 1'] = [
"fixtures",
"fixtures/first",
"fixtures/first/file.md",
"fixtures/first/nested",
"fixtures/first/nested/directory",
"fixtures/first/nested/directory/file.json",
"fixtures/first/nested/directory/file.md",
"fixtures/first/nested/file.md"
]

exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/{first,}/**","options":{"onlyFiles":false,"includePatternBaseDirectory":true}} (async) 1'] = [
"fixtures",
"fixtures/first",
"fixtures/first/file.md",
"fixtures/first/nested",
"fixtures/first/nested/directory",
"fixtures/first/nested/directory/file.json",
"fixtures/first/nested/directory/file.md",
"fixtures/first/nested/file.md"
]

exports['Options IncludePatternBaseDirectory {"pattern":"fixtures/{first,}/**","options":{"onlyFiles":false,"includePatternBaseDirectory":true}} (stream) 1'] = [
"fixtures",
"fixtures/first",
"fixtures/first/file.md",
"fixtures/first/nested",
"fixtures/first/nested/directory",
"fixtures/first/nested/directory/file.json",
"fixtures/first/nested/directory/file.md",
"fixtures/first/nested/file.md"
]
47 changes: 43 additions & 4 deletions src/managers/tasks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,39 +44,76 @@ describe('Managers → Task', () => {

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

it('should return task for the base directory', () => {
const settings = new Settings({
onlyFiles: false,
includePatternBaseDirectory: true
});

const expected = [
tests.task.builder().base('a').positive('a').negative('b/*.md').static().build(),
tests.task.builder().base('a').positive('a/*').negative('b/*.md').build()
];

const actual = manager.generate(['a/*', '!b/*.md'], settings);

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

it('should do not generate the task for the base directory when it is a static patterns', () => {
const settings = new Settings({
onlyFiles: false,
includePatternBaseDirectory: true
});

const expected = [
tests.task.builder().base('.').positive('a').static().build()
];

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

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

describe('.convertPatternsToTasks', () => {
it('should return one task when positive patterns have a global pattern', () => {
const settings = new Settings();

const expected = [
tests.task.builder().base('.').positive('*').negative('*.md').build()
];

const actual = manager.convertPatternsToTasks(['*'], ['*.md'], /* dynamic */ true);
const actual = manager.convertPatternsToTasks(['*'], ['*.md'], settings, /* dynamic */ true);

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

it('should return two tasks when one of patterns contains reference to the parent directory', () => {
const settings = new Settings();

const expected = [
tests.task.builder().base('..').positive('../*.md').negative('*.md').build(),
tests.task.builder().base('.').positive('*').positive('a/*').negative('*.md').build()
];

const actual = manager.convertPatternsToTasks(['*', 'a/*', '../*.md'], ['*.md'], /* dynamic */ true);
const actual = manager.convertPatternsToTasks(['*', 'a/*', '../*.md'], ['*.md'], settings, /* dynamic */ true);

console.dir(actual, { colors: true });

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

it('should return two tasks when all patterns refers to the different base directories', () => {
const settings = new Settings();

const expected = [
tests.task.builder().base('a').positive('a/*').negative('b/*.md').build(),
tests.task.builder().base('b').positive('b/*').negative('b/*.md').build()
];

const actual = manager.convertPatternsToTasks(['a/*', 'b/*'], ['b/*.md'], /* dynamic */ true);
const actual = manager.convertPatternsToTasks(['a/*', 'b/*'], ['b/*.md'], settings, /* dynamic */ true);

assert.deepStrictEqual(actual, expected);
});
Expand Down Expand Up @@ -133,12 +170,14 @@ describe('Managers → Task', () => {

describe('.convertPatternGroupsToTasks', () => {
it('should return two tasks', () => {
const settings = new Settings();

const expected = [
tests.task.builder().base('a').positive('a/*').negative('b/*.md').build(),
tests.task.builder().base('b').positive('b/*').negative('b/*.md').build()
];

const actual = manager.convertPatternGroupsToTasks({ a: ['a/*'], b: ['b/*'] }, ['b/*.md'], /* dynamic */ true);
const actual = manager.convertPatternGroupsToTasks({ a: ['a/*'], b: ['b/*'] }, ['b/*.md'], settings, /* dynamic */ true);

assert.deepStrictEqual(actual, expected);
});
Expand Down
34 changes: 25 additions & 9 deletions src/managers/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export function generate(patterns: Pattern[], settings: Settings): Task[] {
const staticPatterns = positivePatterns.filter((pattern) => utils.pattern.isStaticPattern(pattern, settings));
const dynamicPatterns = positivePatterns.filter((pattern) => utils.pattern.isDynamicPattern(pattern, settings));

const staticTasks = convertPatternsToTasks(staticPatterns, negativePatterns, /* dynamic */ false);
const dynamicTasks = convertPatternsToTasks(dynamicPatterns, negativePatterns, /* dynamic */ true);
const staticTasks = convertPatternsToTasks(staticPatterns, negativePatterns, settings, /* dynamic */ false);
const dynamicTasks = convertPatternsToTasks(dynamicPatterns, negativePatterns, settings, /* dynamic */ true);

return staticTasks.concat(dynamicTasks);
}
Expand All @@ -29,7 +29,7 @@ export function generate(patterns: Pattern[], settings: Settings): Task[] {
* Patterns that can be found inside (`./`) and outside (`../`) the current directory are handled separately.
* This is necessary because directory traversal starts at the base directory and goes deeper.
*/
export function convertPatternsToTasks(positive: Pattern[], negative: Pattern[], dynamic: boolean): Task[] {
export function convertPatternsToTasks(positive: Pattern[], negative: Pattern[], settings: Settings, dynamic: boolean): Task[] {
const tasks: Task[] = [];

const patternsOutsideCurrentDirectory = utils.pattern.getPatternsOutsideCurrentDirectory(positive);
Expand All @@ -38,16 +38,20 @@ export function convertPatternsToTasks(positive: Pattern[], negative: Pattern[],
const outsideCurrentDirectoryGroup = groupPatternsByBaseDirectory(patternsOutsideCurrentDirectory);
const insideCurrentDirectoryGroup = groupPatternsByBaseDirectory(patternsInsideCurrentDirectory);

tasks.push(...convertPatternGroupsToTasks(outsideCurrentDirectoryGroup, negative, dynamic));
tasks.push(...convertPatternGroupsToTasks(outsideCurrentDirectoryGroup, negative, settings, dynamic));

/*
* For the sake of reducing future accesses to the file system, we merge all tasks within the current directory
* into a global task, if at least one pattern refers to the root (`.`). In this case, the global task covers the rest.
*/
if ('.' in insideCurrentDirectoryGroup) {
if (settings.includePatternBaseDirectory && dynamic) {
tasks.push(createBaseDirectoryTask('.', negative));
}

tasks.push(convertPatternGroupToTask('.', patternsInsideCurrentDirectory, negative, dynamic));
} else {
tasks.push(...convertPatternGroupsToTasks(insideCurrentDirectoryGroup, negative, dynamic));
tasks.push(...convertPatternGroupsToTasks(insideCurrentDirectoryGroup, negative, settings, dynamic));
}

return tasks;
Expand Down Expand Up @@ -80,10 +84,22 @@ export function groupPatternsByBaseDirectory(patterns: Pattern[]): PatternsGroup
}, group);
}

export function convertPatternGroupsToTasks(positive: PatternsGroup, negative: Pattern[], dynamic: boolean): Task[] {
return Object.keys(positive).map((base) => {
return convertPatternGroupToTask(base, positive[base], negative, dynamic);
});
export function convertPatternGroupsToTasks(group: PatternsGroup, negative: Pattern[], settings: Settings, dynamic: boolean): Task[] {
const tasks: Task[] = [];

for (const [base, patterns] of Object.entries(group)) {
if (settings.includePatternBaseDirectory && dynamic) {
tasks.push(createBaseDirectoryTask(base, negative));
}

tasks.push(convertPatternGroupToTask(base, patterns, negative, dynamic));
}

return tasks;
}

function createBaseDirectoryTask(base: string, negative: Pattern[]): Task {
return convertPatternGroupToTask(base, [base], negative, /* dynamic */ false);
}

export function convertPatternGroupToTask(base: string, positive: Pattern[], negative: Pattern[], dynamic: boolean): Task {
Expand Down
18 changes: 15 additions & 3 deletions src/settings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe('Settings', () => {
assert.ok(settings.globstar);
assert.ok(settings.onlyFiles);
assert.ok(settings.unique);
assert.ok(!settings.includePatternBaseDirectory);
assert.strictEqual(settings.concurrency, os.cpus().length);
assert.strictEqual(settings.cwd, process.cwd());
});
Expand All @@ -38,16 +39,27 @@ describe('Settings', () => {
assert.ok(!settings.onlyFiles);
});

it('should set the "onlyFiles" option when the "onlyDirectories" is enabled', () => {
it('should set the "onlyFiles" option when the "onlyDirectories" option is enabled', () => {
const settings = new Settings({
onlyDirectories: true
onlyDirectories: true,
onlyFiles: true
});

assert.ok(!settings.onlyFiles);
assert.ok(settings.onlyDirectories);
});

it('should set the "objectMode" option when the "stats" is enabled', () => {
it('should disable the "includePatternBaseDirectory" option when the "onlyFiles" option is enabled', () => {
const settings = new Settings({
onlyFiles: true,
includePatternBaseDirectory: true
});

assert.ok(settings.onlyFiles);
assert.ok(!settings.includePatternBaseDirectory);
});

it('should set the "objectMode" option when the "stats" option is enabled', () => {
const settings = new Settings({
stats: true
});
Expand Down
Loading

0 comments on commit a6ee709

Please sign in to comment.