lint-staged 12.0.3 → 12.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -25
- package/lib/index.js +4 -38
- package/lib/loadConfig.js +86 -0
- package/lib/symbols.js +5 -1
- package/lib/validateConfig.js +3 -2
- package/package.json +14 -21
package/README.md
CHANGED
|
@@ -106,12 +106,15 @@ Starting with v3.1 you can now use different ways of configuring lint-staged:
|
|
|
106
106
|
- `.lintstagedrc.json`
|
|
107
107
|
- `.lintstagedrc.yaml`
|
|
108
108
|
- `.lintstagedrc.yml`
|
|
109
|
-
- `lint-staged.config.
|
|
109
|
+
- `.lintstagedrc.mjs` or `lint-staged.config.mjs` file in ESM format
|
|
110
|
+
- the default export value should be a configuration: `export default { ... }`
|
|
111
|
+
- `.lintstagedrc.cjs` or `lint-staged.config.cjs` file in CommonJS format
|
|
112
|
+
- the exports value should be a configuration: `module.exports = { ... }`
|
|
113
|
+
- `lint-staged.config.js` or `.lintstagedrc.js` in either ESM or CommonJS format, depending on
|
|
114
|
+
whether your project's _package.json_ contains the `"type": "module"` option or not.
|
|
110
115
|
- Pass a configuration file using the `--config` or `-c` flag
|
|
111
116
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
Configuration should be an object where each value is a command to run and its key is a glob pattern to use for this command. This package uses [micromatch](https://github.com/micromatch/micromatch) for glob patterns.
|
|
117
|
+
Configuration should be an object where each value is a command to run and its key is a glob pattern to use for this command. This package uses [micromatch](https://github.com/micromatch/micromatch) for glob patterns. JavaScript files can also export advanced configuration as a function. See [Using JS configuration files](#using-js-configuration-files) for more info.
|
|
115
118
|
|
|
116
119
|
#### `package.json` example:
|
|
117
120
|
|
|
@@ -197,7 +200,7 @@ For example:
|
|
|
197
200
|
|
|
198
201
|
going to execute `eslint` and if it exits with `0` code, it will execute `prettier --write` on all staged `*.js` files.
|
|
199
202
|
|
|
200
|
-
## Using JS configuration
|
|
203
|
+
## Using JS configuration files
|
|
201
204
|
|
|
202
205
|
Writing the configuration file in JavaScript is the most powerful way to configure lint-staged (`lint-staged.config.js`, [similar](https://github.com/okonet/lint-staged/README.md#configuration), or passed via `--config`). From the configuration file, you can export either a single function or an object.
|
|
203
206
|
|
|
@@ -220,9 +223,9 @@ The function can also be async:
|
|
|
220
223
|
|
|
221
224
|
```js
|
|
222
225
|
// lint-staged.config.js
|
|
223
|
-
|
|
226
|
+
import micromatch from 'micromatch'
|
|
224
227
|
|
|
225
|
-
|
|
228
|
+
export default (allStagedFiles) => {
|
|
226
229
|
const shFiles = micromatch(allStagedFiles, ['**/src/**/*.sh'])
|
|
227
230
|
if (shFiles.length) {
|
|
228
231
|
return `printf '%s\n' "Script files aren't allowed in src directory" >&2`
|
|
@@ -242,7 +245,7 @@ module.exports = (allStagedFiles) => {
|
|
|
242
245
|
|
|
243
246
|
```js
|
|
244
247
|
// .lintstagedrc.js
|
|
245
|
-
|
|
248
|
+
export default {
|
|
246
249
|
'**/*.js?(x)': (filenames) => filenames.map((filename) => `prettier --write '${filename}'`),
|
|
247
250
|
}
|
|
248
251
|
```
|
|
@@ -256,7 +259,7 @@ module.exports = {
|
|
|
256
259
|
|
|
257
260
|
```js
|
|
258
261
|
// lint-staged.config.js
|
|
259
|
-
|
|
262
|
+
export default {
|
|
260
263
|
'**/*.ts?(x)': () => 'tsc -p tsconfig.json --noEmit',
|
|
261
264
|
}
|
|
262
265
|
```
|
|
@@ -270,7 +273,7 @@ module.exports = {
|
|
|
270
273
|
|
|
271
274
|
```js
|
|
272
275
|
// .lintstagedrc.js
|
|
273
|
-
|
|
276
|
+
export default {
|
|
274
277
|
'**/*.js?(x)': (filenames) =>
|
|
275
278
|
filenames.length > 10 ? 'eslint .' : `eslint ${filenames.join(' ')}`,
|
|
276
279
|
}
|
|
@@ -287,9 +290,9 @@ It's better to use the [function-based configuration (seen above)](https://githu
|
|
|
287
290
|
|
|
288
291
|
```js
|
|
289
292
|
// lint-staged.config.js
|
|
290
|
-
|
|
293
|
+
import micromatch from 'micromatch'
|
|
291
294
|
|
|
292
|
-
|
|
295
|
+
export default {
|
|
293
296
|
'*': (allFiles) => {
|
|
294
297
|
const codeFiles = micromatch(allFiles, ['**/*.js', '**/*.ts'])
|
|
295
298
|
const docFiles = micromatch(allFiles, ['**/*.md'])
|
|
@@ -309,9 +312,9 @@ If for some reason you want to ignore files from the glob match, you can use `mi
|
|
|
309
312
|
|
|
310
313
|
```js
|
|
311
314
|
// lint-staged.config.js
|
|
312
|
-
|
|
315
|
+
import micromatch from 'micromatch'
|
|
313
316
|
|
|
314
|
-
|
|
317
|
+
export default {
|
|
315
318
|
'*.js': (files) => {
|
|
316
319
|
// from `files` filter those _NOT_ matching `*test.js`
|
|
317
320
|
const match = micromatch.not(files, '*test.js')
|
|
@@ -330,9 +333,9 @@ Please note that for most cases, globs can achieve the same effect. For the abov
|
|
|
330
333
|
<summary>Click to expand</summary>
|
|
331
334
|
|
|
332
335
|
```js
|
|
333
|
-
|
|
336
|
+
import path from 'path'
|
|
334
337
|
|
|
335
|
-
|
|
338
|
+
export default {
|
|
336
339
|
'*.ts': (absolutePaths) => {
|
|
337
340
|
const cwd = process.cwd()
|
|
338
341
|
const relativePaths = absolutePaths.map((file) => path.relative(cwd, file))
|
|
@@ -546,7 +549,7 @@ See more on [this blog post](https://medium.com/@tomchentw/imagemin-lint-staged-
|
|
|
546
549
|
Yes!
|
|
547
550
|
|
|
548
551
|
```js
|
|
549
|
-
|
|
552
|
+
import lintStaged from 'lint-staged'
|
|
550
553
|
|
|
551
554
|
try {
|
|
552
555
|
const success = await lintStaged()
|
|
@@ -685,13 +688,13 @@ Based on the discussion from [this issue](https://github.com/eslint/eslint/issue
|
|
|
685
688
|
So you can setup a `.lintstagedrc.js` config file to do this:
|
|
686
689
|
|
|
687
690
|
```js
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
const cli = new CLIEngine({})
|
|
691
|
+
import { CLIEngine } from 'eslint'
|
|
691
692
|
|
|
692
|
-
|
|
693
|
-
'*.js': (files) =>
|
|
694
|
-
|
|
693
|
+
export default {
|
|
694
|
+
'*.js': (files) => {
|
|
695
|
+
const cli = new CLIEngine({})
|
|
696
|
+
return 'eslint --max-warnings=0 ' + files.filter((file) => !cli.isPathIgnored(file)).join(' ')
|
|
697
|
+
},
|
|
695
698
|
}
|
|
696
699
|
```
|
|
697
700
|
|
|
@@ -707,7 +710,7 @@ In versions of ESLint > 7, [isPathIgnored](https://eslint.org/docs/developer-gui
|
|
|
707
710
|
Since [10.5.3](https://github.com/okonet/lint-staged/releases), any errors due to a bad ESLint config will come through to the console.
|
|
708
711
|
|
|
709
712
|
```js
|
|
710
|
-
|
|
713
|
+
import { ESLint } from 'eslint'
|
|
711
714
|
|
|
712
715
|
const removeIgnoredFiles = async (files) => {
|
|
713
716
|
const eslint = new ESLint()
|
|
@@ -720,7 +723,7 @@ const removeIgnoredFiles = async (files) => {
|
|
|
720
723
|
return filteredFiles.join(' ')
|
|
721
724
|
}
|
|
722
725
|
|
|
723
|
-
|
|
726
|
+
export default {
|
|
724
727
|
'**/*.{ts,tsx,js,jsx}': async (files) => {
|
|
725
728
|
const filesToLint = await removeIgnoredFiles(files)
|
|
726
729
|
return [`eslint --max-warnings=0 ${filesToLint}`]
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { cosmiconfig } from 'cosmiconfig'
|
|
2
1
|
import debug from 'debug'
|
|
3
2
|
import inspect from 'object-inspect'
|
|
4
3
|
|
|
4
|
+
import { loadConfig } from './loadConfig.js'
|
|
5
5
|
import { PREVENTED_EMPTY_COMMIT, GIT_ERROR, RESTORE_STASH_EXAMPLE } from './messages.js'
|
|
6
6
|
import { printTaskOutput } from './printTaskOutput.js'
|
|
7
7
|
import { runAll } from './runAll.js'
|
|
@@ -16,32 +16,6 @@ import { validateOptions } from './validateOptions.js'
|
|
|
16
16
|
|
|
17
17
|
const debugLog = debug('lint-staged')
|
|
18
18
|
|
|
19
|
-
const resolveConfig = (configPath) => {
|
|
20
|
-
try {
|
|
21
|
-
return require.resolve(configPath)
|
|
22
|
-
} catch {
|
|
23
|
-
return configPath
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const loadConfig = (configPath) => {
|
|
28
|
-
const explorer = cosmiconfig('lint-staged', {
|
|
29
|
-
searchPlaces: [
|
|
30
|
-
'package.json',
|
|
31
|
-
'.lintstagedrc',
|
|
32
|
-
'.lintstagedrc.json',
|
|
33
|
-
'.lintstagedrc.yaml',
|
|
34
|
-
'.lintstagedrc.yml',
|
|
35
|
-
'.lintstagedrc.js',
|
|
36
|
-
'.lintstagedrc.cjs',
|
|
37
|
-
'lint-staged.config.js',
|
|
38
|
-
'lint-staged.config.cjs',
|
|
39
|
-
],
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
return configPath ? explorer.load(resolveConfig(configPath)) : explorer.search()
|
|
43
|
-
}
|
|
44
|
-
|
|
45
19
|
/**
|
|
46
20
|
* @typedef {(...any) => void} LogFunction
|
|
47
21
|
* @typedef {{ error: LogFunction, log: LogFunction, warn: LogFunction }} Logger
|
|
@@ -84,22 +58,14 @@ const lintStaged = async (
|
|
|
84
58
|
) => {
|
|
85
59
|
await validateOptions({ shell }, logger)
|
|
86
60
|
|
|
87
|
-
|
|
61
|
+
const inputConfig = configObject || (await loadConfig(configPath, logger))
|
|
88
62
|
|
|
89
|
-
|
|
90
|
-
? { config: configObject, filepath: '(input)' }
|
|
91
|
-
: await loadConfig(configPath)
|
|
92
|
-
|
|
93
|
-
if (resolved == null) {
|
|
63
|
+
if (!inputConfig) {
|
|
94
64
|
logger.error(`${ConfigNotFoundError.message}.`)
|
|
95
65
|
throw ConfigNotFoundError
|
|
96
66
|
}
|
|
97
67
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
// resolved.config is the parsed configuration object
|
|
101
|
-
// resolved.filepath is the path to the config file that was found
|
|
102
|
-
const config = validateConfig(resolved.config, logger)
|
|
68
|
+
const config = validateConfig(inputConfig, logger)
|
|
103
69
|
|
|
104
70
|
if (debug) {
|
|
105
71
|
// Log using logger to be able to test through `consolemock`.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { pathToFileURL } from 'url'
|
|
2
|
+
|
|
3
|
+
import debug from 'debug'
|
|
4
|
+
import { lilconfig } from 'lilconfig'
|
|
5
|
+
import YAML from 'yaml'
|
|
6
|
+
|
|
7
|
+
const debugLog = debug('lint-staged:loadConfig')
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The list of files `lint-staged` will read configuration
|
|
11
|
+
* from, in the declared order.
|
|
12
|
+
*/
|
|
13
|
+
const searchPlaces = [
|
|
14
|
+
'package.json',
|
|
15
|
+
'.lintstagedrc',
|
|
16
|
+
'.lintstagedrc.json',
|
|
17
|
+
'.lintstagedrc.yaml',
|
|
18
|
+
'.lintstagedrc.yml',
|
|
19
|
+
'.lintstagedrc.mjs',
|
|
20
|
+
'.lintstagedrc.js',
|
|
21
|
+
'.lintstagedrc.cjs',
|
|
22
|
+
'lint-staged.config.mjs',
|
|
23
|
+
'lint-staged.config.js',
|
|
24
|
+
'lint-staged.config.cjs',
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
/** exported for tests */
|
|
28
|
+
export const dynamicImport = (path) => import(pathToFileURL(path)).then((module) => module.default)
|
|
29
|
+
|
|
30
|
+
const jsonParse = (path, content) => JSON.parse(content)
|
|
31
|
+
|
|
32
|
+
const yamlParse = (path, content) => YAML.parse(content)
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* `lilconfig` doesn't support yaml files by default,
|
|
36
|
+
* so we add custom loaders for those. Files without
|
|
37
|
+
* an extensions are assumed to be yaml — this
|
|
38
|
+
* assumption is in `cosmiconfig` as well.
|
|
39
|
+
*/
|
|
40
|
+
const loaders = {
|
|
41
|
+
'.js': dynamicImport,
|
|
42
|
+
'.json': jsonParse,
|
|
43
|
+
'.mjs': dynamicImport,
|
|
44
|
+
'.cjs': dynamicImport,
|
|
45
|
+
'.yaml': yamlParse,
|
|
46
|
+
'.yml': yamlParse,
|
|
47
|
+
noExt: yamlParse,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const resolveConfig = (configPath) => {
|
|
51
|
+
try {
|
|
52
|
+
return require.resolve(configPath)
|
|
53
|
+
} catch {
|
|
54
|
+
return configPath
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {string} [configPath]
|
|
60
|
+
* @param {Logger} [logger]
|
|
61
|
+
*/
|
|
62
|
+
export const loadConfig = async (configPath, logger) => {
|
|
63
|
+
try {
|
|
64
|
+
if (configPath) {
|
|
65
|
+
debugLog('Loading configuration from `%s`...', configPath)
|
|
66
|
+
} else {
|
|
67
|
+
debugLog('Searching for configuration...')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const explorer = lilconfig('lint-staged', { searchPlaces, loaders })
|
|
71
|
+
|
|
72
|
+
const result = await (configPath ? explorer.load(resolveConfig(configPath)) : explorer.search())
|
|
73
|
+
if (!result) return null
|
|
74
|
+
|
|
75
|
+
// config is a promise when using the `dynamicImport` loader
|
|
76
|
+
const config = await result.config
|
|
77
|
+
|
|
78
|
+
debugLog('Successfully loaded config from `%s`:\n%O', result.filepath, config)
|
|
79
|
+
|
|
80
|
+
return config
|
|
81
|
+
} catch (error) {
|
|
82
|
+
debugLog('Failed to load configuration from `%s`', configPath)
|
|
83
|
+
logger.error(error)
|
|
84
|
+
return null
|
|
85
|
+
}
|
|
86
|
+
}
|
package/lib/symbols.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export const ApplyEmptyCommitError = Symbol('ApplyEmptyCommitError')
|
|
2
2
|
|
|
3
|
-
export const ConfigNotFoundError = new Error('
|
|
3
|
+
export const ConfigNotFoundError = new Error('Configuration could not be found')
|
|
4
|
+
|
|
5
|
+
export const ConfigFormatError = new Error('Configuration should be an object or a function')
|
|
6
|
+
|
|
7
|
+
export const ConfigEmptyError = new Error('Configuration should not be empty')
|
|
4
8
|
|
|
5
9
|
export const GetBackupStashError = Symbol('GetBackupStashError')
|
|
6
10
|
|
package/lib/validateConfig.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import debug from 'debug'
|
|
2
2
|
|
|
3
3
|
import { configurationError } from './messages.js'
|
|
4
|
+
import { ConfigEmptyError, ConfigFormatError } from './symbols.js'
|
|
4
5
|
import { validateBraces } from './validateBraces.js'
|
|
5
6
|
|
|
6
7
|
const debugLog = debug('lint-staged:validateConfig')
|
|
@@ -27,7 +28,7 @@ export const validateConfig = (config, logger) => {
|
|
|
27
28
|
debugLog('Validating config')
|
|
28
29
|
|
|
29
30
|
if (!config || (typeof config !== 'object' && typeof config !== 'function')) {
|
|
30
|
-
throw
|
|
31
|
+
throw ConfigFormatError
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/**
|
|
@@ -42,7 +43,7 @@ export const validateConfig = (config, logger) => {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
if (Object.entries(config).length === 0) {
|
|
45
|
-
throw
|
|
46
|
+
throw ConfigEmptyError
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
const errors = []
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lint-staged",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.1.3",
|
|
4
4
|
"description": "Lint files staged by git",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "https://github.com/okonet/lint-staged",
|
|
@@ -24,7 +24,6 @@
|
|
|
24
24
|
"lib"
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
|
-
"cz": "git-cz",
|
|
28
27
|
"lint": "eslint .",
|
|
29
28
|
"test": "jest --coverage",
|
|
30
29
|
"test:watch": "jest --watch"
|
|
@@ -33,39 +32,33 @@
|
|
|
33
32
|
"cli-truncate": "^3.1.0",
|
|
34
33
|
"colorette": "^2.0.16",
|
|
35
34
|
"commander": "^8.3.0",
|
|
36
|
-
"
|
|
37
|
-
"debug": "^4.3.2",
|
|
38
|
-
"enquirer": "^2.3.6",
|
|
35
|
+
"debug": "^4.3.3",
|
|
39
36
|
"execa": "^5.1.1",
|
|
40
|
-
"
|
|
37
|
+
"lilconfig": "2.0.4",
|
|
38
|
+
"listr2": "^3.13.5",
|
|
41
39
|
"micromatch": "^4.0.4",
|
|
42
40
|
"normalize-path": "^3.0.0",
|
|
43
|
-
"object-inspect": "^1.11.
|
|
41
|
+
"object-inspect": "^1.11.1",
|
|
44
42
|
"string-argv": "^0.3.1",
|
|
45
|
-
"supports-color": "^9.
|
|
43
|
+
"supports-color": "^9.2.1",
|
|
44
|
+
"yaml": "^1.10.2"
|
|
46
45
|
},
|
|
47
46
|
"devDependencies": {
|
|
48
|
-
"@babel/core": "^7.16.
|
|
49
|
-
"@babel/eslint-parser": "^7.16.
|
|
50
|
-
"@babel/preset-env": "^7.16.
|
|
51
|
-
"babel-jest": "^27.
|
|
47
|
+
"@babel/core": "^7.16.5",
|
|
48
|
+
"@babel/eslint-parser": "^7.16.5",
|
|
49
|
+
"@babel/preset-env": "^7.16.5",
|
|
50
|
+
"babel-jest": "^27.4.5",
|
|
52
51
|
"consolemock": "^1.1.0",
|
|
53
|
-
"eslint": "^8.
|
|
52
|
+
"eslint": "^8.4.1",
|
|
54
53
|
"eslint-config-prettier": "^8.3.0",
|
|
55
54
|
"eslint-plugin-import": "^2.25.3",
|
|
56
55
|
"eslint-plugin-node": "^11.1.0",
|
|
57
56
|
"eslint-plugin-prettier": "^4.0.0",
|
|
58
57
|
"fs-extra": "^10.0.0",
|
|
59
58
|
"husky": "^7.0.4",
|
|
60
|
-
"jest": "^27.
|
|
61
|
-
"jest-mock-console": "^1.2.3",
|
|
59
|
+
"jest": "^27.4.5",
|
|
62
60
|
"jest-snapshot-serializer-ansi": "^1.0.0",
|
|
63
|
-
"prettier": "^2.
|
|
64
|
-
},
|
|
65
|
-
"config": {
|
|
66
|
-
"commitizen": {
|
|
67
|
-
"path": "./node_modules/cz-conventional-changelog"
|
|
68
|
-
}
|
|
61
|
+
"prettier": "^2.5.1"
|
|
69
62
|
},
|
|
70
63
|
"keywords": [
|
|
71
64
|
"lint",
|