lint-staged 15.4.3 → 15.5.1
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 +99 -4
- package/lib/getDiffCommand.js +3 -2
- package/lib/getStagedFiles.js +41 -11
- package/lib/gitWorkflow.js +6 -1
- package/lib/state.js +2 -10
- package/package.json +26 -21
- /package/lib/{types.d.ts → index.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -876,7 +876,7 @@ export default {
|
|
|
876
876
|
}
|
|
877
877
|
```
|
|
878
878
|
|
|
879
|
-
To support backwards-compatibility, monorepo features require multiple _lint-staged_ configuration files present in the git repo. If you still want to run _lint-staged_ in only one of the packages in a monorepo, you can
|
|
879
|
+
To support backwards-compatibility, monorepo features require multiple _lint-staged_ configuration files present in the git repo. If you still want to run _lint-staged_ in only one of the packages in a monorepo, you can use the `--cwd` option (for example, `lint-staged --cwd packages/frontend`).
|
|
880
880
|
|
|
881
881
|
</details>
|
|
882
882
|
|
|
@@ -909,15 +909,15 @@ all changed files between two different branches. If you want to run _lint-stage
|
|
|
909
909
|
Try out the `git diff` command until you are satisfied with the result, for example:
|
|
910
910
|
|
|
911
911
|
```
|
|
912
|
-
git diff --diff-filter=ACMR --name-only
|
|
912
|
+
git diff --diff-filter=ACMR --name-only main...my-branch
|
|
913
913
|
```
|
|
914
914
|
|
|
915
|
-
This will print a list of _added_, _changed_, _modified_, and _renamed_ files between `
|
|
915
|
+
This will print a list of _added_, _changed_, _modified_, and _renamed_ files between `main` and `my-branch`.
|
|
916
916
|
|
|
917
917
|
You can then run lint-staged against the same files with:
|
|
918
918
|
|
|
919
919
|
```
|
|
920
|
-
npx lint-staged --diff="
|
|
920
|
+
npx lint-staged --diff="main...my-branch"
|
|
921
921
|
```
|
|
922
922
|
|
|
923
923
|
</details>
|
|
@@ -1013,3 +1013,98 @@ ESLint v8.51.0 introduced [`--no-warn-ignored` CLI flag](https://eslint.org/docs
|
|
|
1013
1013
|
</details>
|
|
1014
1014
|
|
|
1015
1015
|
</details>
|
|
1016
|
+
|
|
1017
|
+
### How can I resolve TypeScript (`tsc`) ignoring `tsconfig.json` when `lint-staged` runs via Husky hooks?
|
|
1018
|
+
|
|
1019
|
+
<details>
|
|
1020
|
+
<summary>Click to expand</summary>
|
|
1021
|
+
|
|
1022
|
+
When running `lint-staged` via Husky hooks, TypeScript may ignore `tsconfig.json`, leading to errors like:
|
|
1023
|
+
|
|
1024
|
+
> **TS17004:** Cannot use JSX unless the '--jsx' flag is provided.
|
|
1025
|
+
> **TS1056:** Accessors are only available when targeting ECMAScript 5 and higher.
|
|
1026
|
+
|
|
1027
|
+
See issue [#825](https://github.com/okonet/lint-staged/issues/825) for more details.
|
|
1028
|
+
|
|
1029
|
+
#### Root Cause
|
|
1030
|
+
|
|
1031
|
+
<details>
|
|
1032
|
+
<summary>Click to expand</summary>
|
|
1033
|
+
|
|
1034
|
+
1. `lint-staged` automatically passes matched staged files as arguments to commands.
|
|
1035
|
+
2. Certain input files can cause TypeScript to ignore `tsconfig.json`. For more details, see this TypeScript issue: [Allow tsconfig.json when input files are specified](https://github.com/microsoft/TypeScript/issues/27379).
|
|
1036
|
+
|
|
1037
|
+
</details>
|
|
1038
|
+
|
|
1039
|
+
#### Workaround 1: Use a [function signature](https://github.com/lint-staged/lint-staged?tab=readme-ov-file#example-run-tsc-on-changes-to-typescript-files-but-do-not-pass-any-filename-arguments) for the `tsc` command
|
|
1040
|
+
|
|
1041
|
+
<details>
|
|
1042
|
+
<summary>Click to expand</summary>
|
|
1043
|
+
|
|
1044
|
+
As suggested by @antoinerousseau in [#825 (comment)](https://github.com/lint-staged/lint-staged/issues/825#issuecomment-620018284), using a function prevents `lint-staged` from appending file arguments:
|
|
1045
|
+
|
|
1046
|
+
**Before:**
|
|
1047
|
+
|
|
1048
|
+
```js
|
|
1049
|
+
// package.json
|
|
1050
|
+
|
|
1051
|
+
"lint-staged": {
|
|
1052
|
+
"*.{ts,tsx}":[
|
|
1053
|
+
"tsc --noEmit",
|
|
1054
|
+
"prettier --write"
|
|
1055
|
+
]
|
|
1056
|
+
}
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
**After:**
|
|
1060
|
+
|
|
1061
|
+
```js
|
|
1062
|
+
// lint-staged.config.js
|
|
1063
|
+
module.exports = {
|
|
1064
|
+
"*.{ts,tsx}": [
|
|
1065
|
+
() => "tsc --noEmit",
|
|
1066
|
+
"prettier --write"
|
|
1067
|
+
],
|
|
1068
|
+
}
|
|
1069
|
+
```
|
|
1070
|
+
|
|
1071
|
+
</details>
|
|
1072
|
+
|
|
1073
|
+
#### Workaround 2: Take the `sh` or `bash` to wrap the `tsc` command
|
|
1074
|
+
|
|
1075
|
+
<details>
|
|
1076
|
+
<summary>Click to expand</summary>
|
|
1077
|
+
|
|
1078
|
+
As suggested by @sombreroEnPuntas in [#825 (comment)](https://github.com/lint-staged/lint-staged/issues/825#issuecomment-674575655), wrapping `tsc` in a shell command prevents `lint-staged` from modifying its arguments:
|
|
1079
|
+
|
|
1080
|
+
**Before:**
|
|
1081
|
+
|
|
1082
|
+
```js
|
|
1083
|
+
// package.json
|
|
1084
|
+
|
|
1085
|
+
"lint-staged": {
|
|
1086
|
+
"*.{ts,tsx}":[
|
|
1087
|
+
"tsc --noEmit",
|
|
1088
|
+
"prettier --write"
|
|
1089
|
+
]
|
|
1090
|
+
}
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
**After:**
|
|
1094
|
+
|
|
1095
|
+
```js
|
|
1096
|
+
// package.json
|
|
1097
|
+
|
|
1098
|
+
"lint-staged": {
|
|
1099
|
+
"*.{ts,tsx}":[
|
|
1100
|
+
"bash -c 'tsc --noEmit'"
|
|
1101
|
+
"prettier --write"
|
|
1102
|
+
]
|
|
1103
|
+
}
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
**Note:** This approach may have cross-platform compatibility issues.
|
|
1107
|
+
|
|
1108
|
+
</details>
|
|
1109
|
+
|
|
1110
|
+
</details>
|
package/lib/getDiffCommand.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
/** @type {(diff?: string, diffFilter?: string) => string[]} */
|
|
2
|
+
export const getDiffCommand = (diff, diffFilter) => {
|
|
2
3
|
/**
|
|
3
4
|
* Docs for --diff-filter option:
|
|
4
5
|
* @see https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---diff-filterACDMRTUXB82308203
|
|
@@ -12,7 +13,7 @@ export function getDiffCommand(diff, diffFilter) {
|
|
|
12
13
|
* Docs for -z option:
|
|
13
14
|
* @see https://git-scm.com/docs/git-diff#Documentation/git-diff.txt--z
|
|
14
15
|
*/
|
|
15
|
-
const diffCommand = ['diff',
|
|
16
|
+
const diffCommand = ['diff', `--diff-filter=${diffFilterArg}`, ...diffArgs]
|
|
16
17
|
|
|
17
18
|
return diffCommand
|
|
18
19
|
}
|
package/lib/getStagedFiles.js
CHANGED
|
@@ -5,21 +5,51 @@ import { getDiffCommand } from './getDiffCommand.js'
|
|
|
5
5
|
import { normalizePath } from './normalizePath.js'
|
|
6
6
|
import { parseGitZOutput } from './parseGitZOutput.js'
|
|
7
7
|
|
|
8
|
-
const listSubmoduleRoots = async ({ cwd }) => {
|
|
9
|
-
const lines = await execGit(['submodule', '--quiet', 'foreach', 'echo $displaypath'], { cwd })
|
|
10
|
-
return lines.split('\n').map((file) => normalizePath(path.resolve(cwd, file)))
|
|
11
|
-
}
|
|
12
|
-
|
|
13
8
|
export const getStagedFiles = async ({ cwd = process.cwd(), diff, diffFilter } = {}) => {
|
|
14
9
|
try {
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
/**
|
|
11
|
+
* With the raw output lines look like:
|
|
12
|
+
*
|
|
13
|
+
* :000000 100644 0000000 780ccd3\u0000A\u0000.gitmodules\u0000
|
|
14
|
+
* :000000 160000 0000000 1bb568e\u0000A\u0000submodule\u0000
|
|
15
|
+
*
|
|
16
|
+
* @see https://git-scm.com/docs/git-diff#_raw_output_format
|
|
17
|
+
*/
|
|
18
|
+
const output = await execGit([...getDiffCommand(diff, diffFilter), '--raw', '-z'], { cwd })
|
|
19
|
+
|
|
20
|
+
if (!output) return []
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Split from all colons and remove the first one, after which lines will look like:
|
|
24
|
+
*
|
|
25
|
+
* 000000 100644 0000000 780ccd3 A\u0000.gitmodules\u0000
|
|
26
|
+
* 000000 160000 0000000 47e5cff A\u0000submodule\u0000
|
|
27
|
+
*
|
|
28
|
+
* where '\u0000' is the NUL character from '-z' option. After that we
|
|
29
|
+
* parse the lines by splitting from NUL, and then split the first
|
|
30
|
+
* part from space. This yields us enough info both filter out submodule
|
|
31
|
+
* roots and get the filename.
|
|
32
|
+
*/
|
|
33
|
+
return output
|
|
34
|
+
.split(':')
|
|
35
|
+
.slice(1)
|
|
36
|
+
.map(parseGitZOutput)
|
|
37
|
+
.flatMap(([info, src, dst]) => {
|
|
38
|
+
const [, dstMode, , , ,] = info.split(' ')
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Filter out submodule root directory. "160000" is the object mode for submodules.
|
|
42
|
+
* @see https://github.com/git/git/blob/485f5f863615e670fd97ae40af744e14072cfe18/object.h#L114-L120
|
|
43
|
+
*/
|
|
44
|
+
if (dstMode === '160000') {
|
|
45
|
+
return []
|
|
46
|
+
}
|
|
17
47
|
|
|
18
|
-
|
|
48
|
+
/** "dst" exists when moving files, otherwise it's undefined and only "src" exists */
|
|
49
|
+
const filename = dst ?? src
|
|
19
50
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.filter((file) => !submodules.includes(file))
|
|
51
|
+
return [normalizePath(path.resolve(cwd, filename))]
|
|
52
|
+
})
|
|
23
53
|
} catch {
|
|
24
54
|
return null
|
|
25
55
|
}
|
package/lib/gitWorkflow.js
CHANGED
|
@@ -278,7 +278,12 @@ export class GitWorkflow {
|
|
|
278
278
|
|
|
279
279
|
debugLog('Done adding task modifications to index!')
|
|
280
280
|
|
|
281
|
-
const stagedFilesAfterAdd = await this.execGit(
|
|
281
|
+
const stagedFilesAfterAdd = await this.execGit([
|
|
282
|
+
...getDiffCommand(this.diff, this.diffFilter),
|
|
283
|
+
'--name-only',
|
|
284
|
+
'-z',
|
|
285
|
+
])
|
|
286
|
+
|
|
282
287
|
if (!stagedFilesAfterAdd && !this.allowEmpty) {
|
|
283
288
|
// Tasks reverted all staged changes and the commit would be empty
|
|
284
289
|
// Throw error to stop commit unless `--allow-empty` was used
|
package/lib/state.js
CHANGED
|
@@ -2,7 +2,6 @@ import EventEmitter from 'events'
|
|
|
2
2
|
|
|
3
3
|
import { GIT_ERROR, TASK_ERROR } from './messages.js'
|
|
4
4
|
import {
|
|
5
|
-
ApplyEmptyCommitError,
|
|
6
5
|
GitError,
|
|
7
6
|
RestoreOriginalStateError,
|
|
8
7
|
RestoreUnstagedChangesError,
|
|
@@ -49,18 +48,11 @@ export const restoreUnstagedChangesSkipped = (ctx) => {
|
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
export const restoreOriginalStateEnabled = (ctx) =>
|
|
52
|
-
ctx.shouldBackup &&
|
|
53
|
-
(ctx.errors.has(TaskError) ||
|
|
54
|
-
ctx.errors.has(ApplyEmptyCommitError) ||
|
|
55
|
-
ctx.errors.has(RestoreUnstagedChangesError))
|
|
51
|
+
ctx.shouldBackup && (ctx.errors.has(TaskError) || ctx.errors.has(RestoreUnstagedChangesError))
|
|
56
52
|
|
|
57
53
|
export const restoreOriginalStateSkipped = (ctx) => {
|
|
58
54
|
// Should be skipped in case of unknown git errors
|
|
59
|
-
if (
|
|
60
|
-
ctx.errors.has(GitError) &&
|
|
61
|
-
!ctx.errors.has(ApplyEmptyCommitError) &&
|
|
62
|
-
!ctx.errors.has(RestoreUnstagedChangesError)
|
|
63
|
-
) {
|
|
55
|
+
if (ctx.errors.has(GitError) && !ctx.errors.has(RestoreUnstagedChangesError)) {
|
|
64
56
|
return GIT_ERROR
|
|
65
57
|
}
|
|
66
58
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lint-staged",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.5.1",
|
|
4
4
|
"description": "Lint files staged by git",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"repository":
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/lint-staged/lint-staged.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/lint-staged/lint-staged#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/lint-staged/lint-staged/issues"
|
|
13
|
+
},
|
|
7
14
|
"author": "Andrey Okonetchnikov <andrey@okonet.ru>",
|
|
8
15
|
"maintainers": [
|
|
9
16
|
"Lufty Wiranda <lufty.wiranda@gmail.com>",
|
|
@@ -17,16 +24,14 @@
|
|
|
17
24
|
"node": ">=18.12.0"
|
|
18
25
|
},
|
|
19
26
|
"type": "module",
|
|
20
|
-
"bin":
|
|
27
|
+
"bin": {
|
|
28
|
+
"lint-staged": "bin/lint-staged.js"
|
|
29
|
+
},
|
|
21
30
|
"exports": {
|
|
22
|
-
".":
|
|
23
|
-
"default": "./lib/index.js",
|
|
24
|
-
"types": "./lib/types.d.ts"
|
|
25
|
-
},
|
|
31
|
+
".": "./lib/index.js",
|
|
26
32
|
"./bin": "./bin/lint-staged.js",
|
|
27
33
|
"./package.json": "./package.json"
|
|
28
34
|
},
|
|
29
|
-
"types": "lib/types.d.ts",
|
|
30
35
|
"files": [
|
|
31
36
|
"bin",
|
|
32
37
|
"lib"
|
|
@@ -35,7 +40,7 @@
|
|
|
35
40
|
"lint": "eslint .",
|
|
36
41
|
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules npx jest --coverage",
|
|
37
42
|
"test:watch": "npm run test -- --watch",
|
|
38
|
-
"typecheck": "tsc --noEmit --strict test/
|
|
43
|
+
"typecheck": "tsc --noEmit --strict test/types/index.ts",
|
|
39
44
|
"version": "npx changeset version",
|
|
40
45
|
"postversion": "npm i --package-lock-only && git commit -am \"chore(changeset): release\"",
|
|
41
46
|
"tag": "npx changeset tag"
|
|
@@ -53,26 +58,26 @@
|
|
|
53
58
|
"yaml": "^2.7.0"
|
|
54
59
|
},
|
|
55
60
|
"devDependencies": {
|
|
56
|
-
"@changesets/changelog-github": "0.5.
|
|
57
|
-
"@changesets/cli": "2.
|
|
58
|
-
"@commitlint/cli": "19.
|
|
59
|
-
"@commitlint/config-conventional": "19.
|
|
60
|
-
"@eslint/js": "9.
|
|
61
|
+
"@changesets/changelog-github": "0.5.1",
|
|
62
|
+
"@changesets/cli": "2.28.1",
|
|
63
|
+
"@commitlint/cli": "19.8.0",
|
|
64
|
+
"@commitlint/config-conventional": "19.8.0",
|
|
65
|
+
"@eslint/js": "9.22.0",
|
|
61
66
|
"consolemock": "1.1.0",
|
|
62
67
|
"cross-env": "7.0.3",
|
|
63
|
-
"eslint": "9.
|
|
64
|
-
"eslint-config-prettier": "10.
|
|
68
|
+
"eslint": "9.22.0",
|
|
69
|
+
"eslint-config-prettier": "10.1.1",
|
|
65
70
|
"eslint-plugin-jest": "28.11.0",
|
|
66
|
-
"eslint-plugin-n": "17.
|
|
71
|
+
"eslint-plugin-n": "17.16.2",
|
|
67
72
|
"eslint-plugin-prettier": "5.2.3",
|
|
68
73
|
"eslint-plugin-simple-import-sort": "12.1.1",
|
|
69
74
|
"husky": "9.1.7",
|
|
70
75
|
"jest": "29.7.0",
|
|
71
|
-
"jest-snapshot-serializer-ansi": "2.1
|
|
76
|
+
"jest-snapshot-serializer-ansi": "2.2.1",
|
|
72
77
|
"mock-stdin": "1.0.0",
|
|
73
|
-
"prettier": "3.
|
|
74
|
-
"semver": "7.
|
|
75
|
-
"typescript": "5.
|
|
78
|
+
"prettier": "3.5.3",
|
|
79
|
+
"semver": "7.7.1",
|
|
80
|
+
"typescript": "5.8.2"
|
|
76
81
|
},
|
|
77
82
|
"keywords": [
|
|
78
83
|
"lint",
|
|
File without changes
|