-
-
Notifications
You must be signed in to change notification settings - Fork 425
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: try to automatically fix and warn about invalid brace patterns (#…
…992) * refactor: use arrow function * fix: correctly handle incorrect patterns with braces of only single value Technically brace patterns like `*.{js}` are invalid because braces should always contain at least one comma or a sequence, for example `*.{js,ts}` or `file{1..10}.js`. The `micromatch` library used to match patterns to files will silently ignore such invalid braces and thus lead to the pattern always matching zero files. This is a unintuitive, so lint-staged should normalize such cases by simply removing the unnecessary braces before matching files. * test: add test for matching pattern with bracket sequence * refactor: less nesting in validateConfig * refactor: move pattern fixing to validateConfig * refactor: move error to messages * refactor: throw early for empty configuration * fix: improve configuration error output * refactor: move formatConfig into validateConfig * test: update snapshot serializer to remove absolute file path * fix: do not pass unused logger argument * refactor: move config validation logging to validateConfig * fix: do not match escaped curly braces (`\{` or `\}`) * test: better error message in snapshot * test: add missing assertions * fix: match braces with escaped comma inside * fix: do not match braces when they start with the dollar sign (`$`) * docs: update BRACES_REGEXP comment * refactor: move brace pattern validation to separate file * fix: correctly handle nested braces * refactor: clean up code * test: add some more tests
- Loading branch information
Showing
19 changed files
with
504 additions
and
401 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
const { incorrectBraces } = require('./messages') | ||
|
||
/** | ||
* A correctly-formed brace expansion must contain unquoted opening and closing braces, | ||
* and at least one unquoted comma or a valid sequence expression. | ||
* Any incorrectly formed brace expansion is left unchanged. | ||
* | ||
* @see https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html | ||
* | ||
* Lint-staged uses `micromatch` for brace expansion, and its behavior is to treat | ||
* invalid brace expansions as literal strings, which means they (typically) do not match | ||
* anything. | ||
* | ||
* This RegExp tries to match most cases of invalid brace expansions, so that they can be | ||
* detected, warned about, and re-formatted by removing the braces and thus hopefully | ||
* matching the files as intended by the user. The only real fix is to remove the incorrect | ||
* braces from user configuration, but this is left to the user (after seeing the warning). | ||
* | ||
* @example <caption>Globs with brace expansions</caption> | ||
* - *.{js,tx} // expanded as *.js, *.ts | ||
* - *.{{j,t}s,css} // expanded as *.js, *.ts, *.css | ||
* - file_{1..10}.css // expanded as file_1.css, file_2.css, …, file_10.css | ||
* | ||
* @example <caption>Globs with incorrect brace expansions</caption> | ||
* - *.{js} // should just be *.js | ||
* - *.{js,{ts}} // should just be *.{js,ts} | ||
* - *.\{js\} // escaped braces, so they're treated literally | ||
* - *.${js} // dollar-sign inhibits expansion, so treated literally | ||
* - *.{js\,ts} // the comma is escaped, so treated literally | ||
*/ | ||
const BRACES_REGEXP = /(?<![\\$])({)(?:(?!(?<!\\),|\.\.|\{|\}).)*?(?<!\\)(})/g | ||
|
||
/** | ||
* @param {string} pattern | ||
* @returns {string} | ||
*/ | ||
const withoutIncorrectBraces = (pattern) => { | ||
let output = `${pattern}` | ||
let match = null | ||
|
||
while ((match = BRACES_REGEXP.exec(pattern))) { | ||
const fullMatch = match[0] | ||
const withoutBraces = fullMatch.replace(/{/, '').replace(/}/, '') | ||
output = output.replace(fullMatch, withoutBraces) | ||
} | ||
|
||
return output | ||
} | ||
|
||
/** | ||
* Validate and remove incorrect brace expansions from glob pattern. | ||
* For example `*.{js}` is incorrect because it doesn't contain a `,` or `..`, | ||
* and will be reformatted as `*.js`. | ||
* | ||
* @param {string} pattern the glob pattern | ||
* @param {*} logger | ||
* @returns {string} | ||
*/ | ||
const validateBraces = (pattern, logger) => { | ||
const fixedPattern = withoutIncorrectBraces(pattern) | ||
|
||
if (fixedPattern !== pattern) { | ||
logger.warn(incorrectBraces(pattern, fixedPattern)) | ||
} | ||
|
||
return fixedPattern | ||
} | ||
|
||
module.exports = validateBraces | ||
|
||
module.exports.BRACES_REGEXP = BRACES_REGEXP |
Oops, something went wrong.