Skip to content

Commit

Permalink
fix(managers): fix issue with patterns that refers to the parent dire…
Browse files Browse the repository at this point in the history
…ctory
  • Loading branch information
mrmlnc committed Jun 26, 2021
1 parent 295db2a commit 7e28a63
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 8 deletions.
49 changes: 48 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 All @@ -69,6 +82,40 @@ describe('Managers → Task', () => {
});
});

describe('.hasGroupsWithBaseDirectoriesRelatedToParents', () => {
it('should be `false` when all the base directories do not contain references to the parent directories', () => {
const groups: PatternsGroup = {
'.': ['*.md']
};

const actual = manager.hasGroupsWithBaseDirectoriesRelatedToParents(groups);

assert.ok(!actual);
});

it('should be `true` when at least one base directory starts with `..` segment', () => {
const groups: PatternsGroup = {
'.': ['*.md'],
'..': ['../*.md']
};

const actual = manager.hasGroupsWithBaseDirectoriesRelatedToParents(groups);

assert.ok(actual);
});

it('should be `true` when at least one base directory starts with `./..` segment', () => {
const groups: PatternsGroup = {
'.': ['*.md'],
'./..': ['../*.md']
};

const actual = manager.hasGroupsWithBaseDirectoriesRelatedToParents(groups);

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

describe('.getPositivePatterns', () => {
it('should return only positive patterns', () => {
const expected = ['*'];
Expand Down
34 changes: 27 additions & 7 deletions src/managers/tasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,38 @@ 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 hasGroupsWithBaseDirectoriesRelatedToParents(group: PatternsGroup): boolean {
return Object.keys(group).some((key) => key.startsWith('..') || key.startsWith('./..'));
}

export function getPositivePatterns(patterns: Pattern[]): Pattern[] {
Expand Down

0 comments on commit 7e28a63

Please sign in to comment.