Skip to content

Commit

Permalink
Merge pull request #320 from mrmlnc/ISSUE-316_fix_mixed_base_directories
Browse files Browse the repository at this point in the history
ISSUE-316: fix support for mixed base directories
  • Loading branch information
mrmlnc committed Jun 26, 2021
2 parents e4a3e7f + 4c36f6d commit c9f7a81
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 8 deletions.
15 changes: 14 additions & 1 deletion src/managers/tasks.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,20 @@ describe('Managers → Task', () => {
assert.deepStrictEqual(actual, expected);
});

it('should return two tasks', () => {
it('should return two tasks when one of patterns contains reference to the parent directory', () => {
const expected = [
tests.task.builder().base('..').positive('../*.md').build(),
tests.task.builder().base('.').positive('*').positive('a/*').negative('*.md').build()
];

const actual = manager.convertPatternsToTasks(['*', 'a/*', '../*.md'], ['*.md'], /* 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 expected = [
tests.task.builder().base('a').positive('a/*').negative('b/*.md').build(),
tests.task.builder().base('b').positive('b/*').negative('b/*.md').build()
Expand Down
30 changes: 23 additions & 7 deletions src/managers/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,34 @@ export function generate(patterns: Pattern[], settings: Settings): Task[] {
return staticTasks.concat(dynamicTasks);
}

/**
* Returns tasks grouped by basic pattern directories.
*
* 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[] {
const positivePatternsGroup = groupPatternsByBaseDirectory(positive);
const tasks: Task[] = [];

// When we have a global group – there is no reason to divide the patterns into independent tasks.
// In this case, the global task covers the rest.
if ('.' in positivePatternsGroup) {
const task = convertPatternGroupToTask('.', positive, negative, dynamic);
const patternsOutsideCurrentDirectory = utils.pattern.getPatternsOutsideCurrentDirectory(positive);
const patternsInsideCurrentDirectory = utils.pattern.getPatternsInsideCurrentDirectory(positive);

return [task];
const outsideCurrentDirectoryGroup = groupPatternsByBaseDirectory(patternsOutsideCurrentDirectory);
const insideCurrentDirectoryGroup = groupPatternsByBaseDirectory(patternsInsideCurrentDirectory);

tasks.push(...convertPatternGroupsToTasks(outsideCurrentDirectoryGroup, [], 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) {
tasks.push(convertPatternGroupToTask('.', patternsInsideCurrentDirectory, negative, dynamic));
} else {
tasks.push(...convertPatternGroupsToTasks(insideCurrentDirectoryGroup, negative, dynamic));
}

return convertPatternGroupsToTasks(positivePatternsGroup, negative, dynamic);
return tasks;
}

export function getPositivePatterns(patterns: Pattern[]): Pattern[] {
Expand Down
46 changes: 46 additions & 0 deletions src/utils/pattern.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,52 @@ describe('Utils → Pattern', () => {
});
});

describe('.getPatternsInsideCurrentDirectory', () => {
it('should return patterns', () => {
const expected: Pattern[] = ['.', './*', '*', 'a/*'];

const actual = util.getPatternsInsideCurrentDirectory(['.', './*', '*', 'a/*', '..', '../*', './..', './../*']);

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

describe('.getPatternsOutsideCurrentDirectory', () => {
it('should return patterns', () => {
const expected: Pattern[] = ['..', '../*', './..', './../*'];

const actual = util.getPatternsOutsideCurrentDirectory(['.', './*', '*', 'a/*', '..', '../*', './..', './../*']);

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

describe('.isPatternRelatedToParentDirectory', () => {
it('should be `false` when the pattern refers to the current directory', () => {
const actual = util.isPatternRelatedToParentDirectory('.');

assert.ok(!actual);
});

it('should be `true` when the pattern equals to `..`', () => {
const actual = util.isPatternRelatedToParentDirectory('..');

assert.ok(actual);
});

it('should be `true` when the pattern starts with `..` segment', () => {
const actual = util.isPatternRelatedToParentDirectory('../*');

assert.ok(actual);
});

it('should be `true` when the pattern starts with `./..` segment', () => {
const actual = util.isPatternRelatedToParentDirectory('./../*');

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

describe('.getBaseDirectory', () => {
it('should returns base directory', () => {
const expected = 'root';
Expand Down
26 changes: 26 additions & 0 deletions src/utils/pattern.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,32 @@ export function getPositivePatterns(patterns: Pattern[]): Pattern[] {
return patterns.filter(isPositivePattern);
}

/**
* Returns patterns that can be applied inside the current directory.
*
* @example
* // ['./*', '*', 'a/*']
* getPatternsInsideCurrentDirectory(['./*', '*', 'a/*', '../*', './../*'])
*/
export function getPatternsInsideCurrentDirectory(patterns: Pattern[]): Pattern[] {
return patterns.filter((pattern) => !isPatternRelatedToParentDirectory(pattern));
}

/**
* Returns patterns to be expanded relative to (outside) the current directory.
*
* @example
* // ['../*', './../*']
* getPatternsInsideCurrentDirectory(['./*', '*', 'a/*', '../*', './../*'])
*/
export function getPatternsOutsideCurrentDirectory(patterns: Pattern[]): Pattern[] {
return patterns.filter(isPatternRelatedToParentDirectory);
}

export function isPatternRelatedToParentDirectory(pattern: Pattern): boolean {
return pattern.startsWith('..') || pattern.startsWith('./..');
}

export function getBaseDirectory(pattern: Pattern): string {
return globParent(pattern, { flipBackslashes: false });
}
Expand Down

0 comments on commit c9f7a81

Please sign in to comment.