Skip to content
This repository has been archived by the owner on Jun 10, 2024. It is now read-only.

fix: behavior of global ignores #126

Merged
merged 6 commits into from
Jan 10, 2024

Conversation

mdjermanovic
Copy link
Contributor

@mdjermanovic mdjermanovic commented Jan 7, 2024

Fixes the problem in eslint/eslint#17964 (comment)

In the code that calculates global ignores, there were still some transformations of patterns that, I believe, were needed in some previous versions, but are now causing unintended behavior.

For example, ignore pattern foo/*/ should not match file foo/a.js.

I removed all those transformations and added several tests that demonstrate the difference in behavior after this change, and also a few regression tests.

Comment on lines +1294 to +1330
it('should return false when file has the same name as a directory that is ignored by a pattern that ends with `/`', () => {
configs = new ConfigArray([
{
files: ['**/foo']
},
{
ignores: [
'foo/'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isFileIgnored(path.join(basePath, 'foo'))).to.be.false;
});

it('should return false when file is in the parent directory of directories that are ignored by a pattern that ends with `/`', () => {
configs = new ConfigArray([
{
files: ['**/*.js']
},
{
ignores: [
'foo/*/'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isFileIgnored(path.join(basePath, 'foo/a.js'))).to.be.false;
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two tests were failing before this change (the files were considered ignored).

Comment on lines 1332 to 1388
it('should return true when file is in a directory that is ignored by a pattern that ends with `/`', () => {
configs = new ConfigArray([
{
files: ['**/*.js']
},
{
ignores: [
'foo/'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isFileIgnored(path.join(basePath, 'foo/a.js'))).to.be.true;
});

it('should return true when file is in a directory that is ignored by a pattern that does not end with `/`', () => {
configs = new ConfigArray([
{
files: ['**/*.js']
},
{
ignores: [
'foo'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isFileIgnored(path.join(basePath, 'foo/a.js'))).to.be.true;
});

it('should return false when file is in a directory that is ignored and then unignord by pattern that end with `/`', () => {
configs = new ConfigArray([
{
files: ['**/*.js']
},
{
ignores: [
'foo/',
'!foo/'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isFileIgnored(path.join(basePath, 'foo/a.js'))).to.be.false;
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three tests were already passing before the change. I added them just to verify that the cases the transformations were targeting still work as intended when the transformations are removed.

Comment on lines 1390 to 1432
it('should return true when file is in a directory that is ignored along its files by pattern that ends with `/**` and than unignored by pattern that ends with `/`', () => {
configs = new ConfigArray([
{
files: ['**/*.js']
},
{
ignores: [
'foo/**',

// only the directory is unignored, files are not
'!foo/'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isFileIgnored(path.join(basePath, 'foo/a.js'))).to.be.true;
});

it('should return true when file is in a directory that is ignored along its files by pattern that ends with `/**` and then unignored by pattern that does not ends with `/`', () => {
configs = new ConfigArray([
{
files: ['**/*.js']
},
{
ignores: [
'foo/**',

// only the directory is unignored, files are not
'!foo'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isFileIgnored(path.join(basePath, 'foo/a.js'))).to.be.true;
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two tests were failing before this change (the files were considered not ignored).

Comment on lines +1434 to +1454
it('should return false when file is in a directory that is ignored along its files by pattern that ends with `/**` and then unignored along its files by pattern that ends with `/**`', () => {
configs = new ConfigArray([
{
files: ['**/*.js']
},
{
ignores: [
'foo/**',

// both the directory and the files are unignored
'!foo/**'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isFileIgnored(path.join(basePath, 'foo/a.js'))).to.be.false;
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one was already passing before the change.

Comment on lines +1456 to +1526
it('should return true when file is ignored by a pattern and there are unignore patterns that target files of a directory with the same name', () => {
configs = new ConfigArray([
{
files: ['**/foo']
},
{
ignores: [
'foo',
'!foo/*',
'!foo/**'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isFileIgnored(path.join(basePath, 'foo'))).to.be.true;
});

it('should return true when file is in a directory that is ignored even if an unignore pattern that ends with `/*` matches the file', () => {
configs = new ConfigArray([
{
files: ['**/*.js']
},
{
ignores: [
'foo',
'!foo/*'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isFileIgnored(path.join(basePath, 'foo/a.js'))).to.be.true;
});

// https://github.com/eslint/eslint/issues/17964#issuecomment-1879840650
it('should return true for all files ignored in a directory tree except for explicitly unignored ones', () => {
configs = new ConfigArray([
{
files: ['**/*.js']
},
{
ignores: [

// ignore all files and directories
'tests/format/**/*',

// unignore all directories
'!tests/format/**/*/',

// unignore specific files
'!tests/format/**/jsfmt.spec.js'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isFileIgnored(path.join(basePath, 'tests/format/foo.js'))).to.be.true;
expect(configs.isFileIgnored(path.join(basePath, 'tests/format/jsfmt.spec.js'))).to.be.false;
expect(configs.isFileIgnored(path.join(basePath, 'tests/format/subdir/foo.js'))).to.be.true;
expect(configs.isFileIgnored(path.join(basePath, 'tests/format/subdir/jsfmt.spec.js'))).to.be.false;
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three tests were failing before this change (the files that should have been ignored were considered not ignored).

Comment on lines +1819 to +1842
it('should return false when a directory is later negated with **', () => {
configs = new ConfigArray([
{
files: ['**/*.js']
},
{
ignores: [
'**/node_modules/**'
]
},
{
ignores: [
'!node_modules/**'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isDirectoryIgnored(path.join(basePath, 'node_modules'))).to.be.false;
expect(configs.isDirectoryIgnored(path.join(basePath, 'node_modules/'))).to.be.false;
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one was already passing before this change.

Comment on lines 1844 to 1867
it('should return true when a directory content is later negated with *', () => {
configs = new ConfigArray([
{
files: ['**/*.js']
},
{
ignores: [
'**/node_modules/**'
]
},
{
ignores: [
'!node_modules/*'
]
}
], {
basePath
});

configs.normalizeSync();

expect(configs.isDirectoryIgnored(path.join(basePath, 'node_modules'))).to.be.true;
expect(configs.isDirectoryIgnored(path.join(basePath, 'node_modules/'))).to.be.true;
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one was failing before this change (the directory was considered not ignored).

Copy link
Contributor

@nzakas nzakas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into this. I like how this simplifies the code. Left a few suggestions for cleaning up the language in the tests and had one question about the functionality.

tests/config-array.test.js Outdated Show resolved Hide resolved
tests/config-array.test.js Outdated Show resolved Hide resolved
tests/config-array.test.js Outdated Show resolved Hide resolved
tests/config-array.test.js Outdated Show resolved Hide resolved
mdjermanovic and others added 5 commits January 9, 2024 21:41
Co-authored-by: Nicholas C. Zakas <nicholas@humanwhocodes.com>
Co-authored-by: Nicholas C. Zakas <nicholas@humanwhocodes.com>
Co-authored-by: Nicholas C. Zakas <nicholas@humanwhocodes.com>
Co-authored-by: Nicholas C. Zakas <nicholas@humanwhocodes.com>
Copy link
Contributor

@nzakas nzakas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@nzakas nzakas merged commit 9b3c72c into humanwhocodes:main Jan 10, 2024
9 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants