Skip to content
Open
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ Rule | Meaning
`components/*/utils` | ✅&nbsp;&nbsp;The directory `components` is accepted.<br/> ✅&nbsp;&nbsp;Any *first level* nested directory is accepted.<br/> ✅&nbsp;&nbsp;The *second level* nested directory `utils` is accepted.<br/> ❌&nbsp;&nbsp;Any other *second level* nested directory is not accepted.
`legacy/**` | ✅&nbsp;&nbsp;The directory `legacy` is accepted.<br/> ✅&nbsp;&nbsp;Any nested directory on *any level* is accepted.
`components/*/legacy/**` | ✅&nbsp;&nbsp;The directory `components` is accepted.<br/> ✅&nbsp;&nbsp;Any *first level* nested directory is accepted.<br/> ✅&nbsp;&nbsp;The *second level* nested directory `legacy` is accepted.<br/> ❌&nbsp;&nbsp;Any other *second level* nested directory is not accepted.<br/> ✅&nbsp;&nbsp;Any nested directory on *any level* inside of *legacy* directory is accepted.
`!pages/*` | ❌&nbsp;&nbsp;Any nested directory inside `pages` is not accepted.

⚠️ A rule like `components/*/utils` automatically make the `components` and `components/*` rules work. So, no need to specify a rule for every level directory. You need to specify the deepest path.

Expand Down
17 changes: 17 additions & 0 deletions __tests__/runLinter.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,20 @@ test('should not accept files with * and ** in the same rule', () => {
'folderslint: 2 error(s) found'
)
})

test('should not accept files with ! (negation) in the beginning of the rule ', () => {
parseConfig.mockReturnValue({
root: 'src',
rules: ['!pages/*'],
})

runLinter(['cwd/src/pages/components'])

expect(process.exit).toHaveBeenLastCalledWith(1)

expect(console.log).toHaveBeenNthCalledWith(
1,
chalk.underline('cwd/src/pages/components')
)
expect(console.log).toHaveBeenNthCalledWith(2, ERROR_MESSAGE)
})
10 changes: 10 additions & 0 deletions src/parseConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ const validateParsedConfig = (config) => {
console.error('A rule can have ** only at the end')
process.exit(1)
}

if (
rule.includes('!') &&
rule.startsWith('!') &&
rule.split('!').length > 2
) {
console.error(`Invalid rule: ${rule}`)
console.error('A rule can have at most one ! at the beginning')
process.exit(1)
}
})
return config
}
Expand Down
10 changes: 6 additions & 4 deletions src/rules.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ const getExtendedRules = (root = '', rules) => {

const isPathMatchRule = (path, rule) => {
const splittedPath = path.split('/')
const splittedRule = rule.split('/')

const isNegation = rule.startsWith('!')
const splittedRule = (isNegation ? rule.substring(1) : rule).split('/')

const isValid = splittedPath.reduce((acc, pathPart, i) => {
const rulePart = splittedRule[i]
Expand All @@ -41,14 +43,14 @@ const isPathMatchRule = (path, rule) => {
}, true)

if (!isValid) {
return false
return isNegation
}

if (!rule.includes('**') && splittedPath.length > splittedRule.length) {
return false
return isNegation
}

return true
return !isNegation
}

const checkPath = (path, rules) => {
Expand Down