lint-staged 12.2.2 → 12.3.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 CHANGED
@@ -81,38 +81,36 @@ See [Releases](https://github.com/okonet/lint-staged/releases).
81
81
 
82
82
  ## Command line flags
83
83
 
84
- ```bash
84
+ ```
85
85
  ❯ npx lint-staged --help
86
86
  Usage: lint-staged [options]
87
87
 
88
88
  Options:
89
89
  -V, --version output the version number
90
- --allow-empty allow empty commits when tasks revert all staged changes
91
- (default: false)
90
+ --allow-empty allow empty commits when tasks revert all staged changes (default: false)
91
+ -p, --concurrent <number|boolean> the number of tasks to run concurrently, or false for serial (default: true)
92
92
  -c, --config [path] path to configuration file, or - to read from stdin
93
+ --cwd [path] run all tasks in specific directory, instead of the current
93
94
  -d, --debug print additional debug information (default: false)
94
- --no-stash disable the backup stash, and do not revert in case of
95
- errors
96
- -p, --concurrent <parallel tasks> the number of tasks to run concurrently, or false to run
97
- tasks serially (default: true)
95
+ --no-stash disable the backup stash, and do not revert in case of errors
98
96
  -q, --quiet disable lint-staged’s own console output (default: false)
99
97
  -r, --relative pass relative filepaths to tasks (default: false)
100
- -x, --shell [path] skip parsing of tasks for better shell support (default:
101
- false)
102
- -v, --verbose show task output even when tasks succeed; by default only
103
- failed output is shown (default: false)
98
+ -x, --shell [path] skip parsing of tasks for better shell support (default: false)
99
+ -v, --verbose show task output even when tasks succeed; by default only failed output is shown
100
+ (default: false)
104
101
  -h, --help display help for command
105
102
  ```
106
103
 
107
104
  - **`--allow-empty`**: By default, when linter tasks undo all staged changes, lint-staged will exit with an error and abort the commit. Use this flag to allow creating empty git commits.
105
+ - **`--concurrent [number|boolean]`**: Controls the concurrency of tasks being run by lint-staged. **NOTE**: This does NOT affect the concurrency of subtasks (they will always be run sequentially). Possible values are:
106
+ - `false`: Run all tasks serially
107
+ - `true` (default) : _Infinite_ concurrency. Runs as many tasks in parallel as possible.
108
+ - `{number}`: Run the specified number of tasks in parallel, where `1` is equivalent to `false`.
108
109
  - **`--config [path]`**: Manually specify a path to a config file or npm package name. Note: when used, lint-staged won't perform the config file search and will print an error if the specified file cannot be found. If '-' is provided as the filename then the config will be read from stdin, allowing piping in the config like `cat my-config.json | npx lint-staged --config -`.
110
+ - **`--cwd [path]`**: By default tasks run in the current working directory. Use the `--cwd some/directory` to override this. The path can be absolute or relative to the current working directory.
109
111
  - **`--debug`**: Run in debug mode. When set, it does the following:
110
112
  - uses [debug](https://github.com/visionmedia/debug) internally to log additional information about staged files, commands being executed, location of binaries, etc. Debug logs, which are automatically enabled by passing the flag, can also be enabled by setting the environment variable `$DEBUG` to `lint-staged*`.
111
113
  - uses [`verbose` renderer](https://github.com/SamVerschueren/listr-verbose-renderer) for `listr`; this causes serial, uncoloured output to the terminal, instead of the default (beautified, dynamic) output.
112
- - **`--concurrent [number | (true/false)]`**: Controls the concurrency of tasks being run by lint-staged. **NOTE**: This does NOT affect the concurrency of subtasks (they will always be run sequentially). Possible values are:
113
- - `false`: Run all tasks serially
114
- - `true` (default) : _Infinite_ concurrency. Runs as many tasks in parallel as possible.
115
- - `{number}`: Run the specified number of tasks in parallel, where `1` is equivalent to `false`.
116
114
  - **`--no-stash`**: By default a backup stash will be created before running the tasks, and all task modifications will be reverted in case of an error. This option will disable creating the stash, and instead leave all modifications in the index when aborting the commit.
117
115
  - **`--quiet`**: Supress all CLI output, except from tasks.
118
116
  - **`--relative`**: Pass filepaths relative to `process.cwd()` (where `lint-staged` runs) to tasks. Default is `false`.
@@ -26,14 +26,15 @@ const version = packageJson.version
26
26
  cmdline
27
27
  .version(version)
28
28
  .option('--allow-empty', 'allow empty commits when tasks revert all staged changes', false)
29
- .option('-c, --config [path]', 'path to configuration file, or - to read from stdin')
30
- .option('-d, --debug', 'print additional debug information', false)
31
- .option('--no-stash', 'disable the backup stash, and do not revert in case of errors', false)
32
29
  .option(
33
- '-p, --concurrent <parallel tasks>',
34
- 'the number of tasks to run concurrently, or false to run tasks serially',
30
+ '-p, --concurrent <number|boolean>',
31
+ 'the number of tasks to run concurrently, or false for serial',
35
32
  true
36
33
  )
34
+ .option('-c, --config [path]', 'path to configuration file, or - to read from stdin')
35
+ .option('--cwd [path]', 'run all tasks in specific directory, instead of the current')
36
+ .option('-d, --debug', 'print additional debug information', false)
37
+ .option('--no-stash', 'disable the backup stash, and do not revert in case of errors', false)
37
38
  .option('-q, --quiet', 'disable lint-staged’s own console output', false)
38
39
  .option('-r, --relative', 'pass relative filepaths to tasks', false)
39
40
  .option('-x, --shell [path]', 'skip parsing of tasks for better shell support', false)
@@ -75,12 +76,13 @@ const options = {
75
76
  allowEmpty: !!cmdlineOptions.allowEmpty,
76
77
  concurrent: JSON.parse(cmdlineOptions.concurrent),
77
78
  configPath: cmdlineOptions.config,
79
+ cwd: cmdlineOptions.cwd,
78
80
  debug: !!cmdlineOptions.debug,
79
81
  maxArgLength: getMaxArgLength() / 2,
80
- stash: !!cmdlineOptions.stash, // commander inverts `no-<x>` flags to `!x`
81
82
  quiet: !!cmdlineOptions.quiet,
82
83
  relative: !!cmdlineOptions.relative,
83
84
  shell: cmdlineOptions.shell /* Either a boolean or a string pointing to the shell */,
85
+ stash: !!cmdlineOptions.stash, // commander inverts `no-<x>` flags to `!x`
84
86
  verbose: !!cmdlineOptions.verbose,
85
87
  }
86
88
 
package/lib/index.js CHANGED
@@ -37,7 +37,7 @@ const lintStaged = async (
37
37
  concurrent = true,
38
38
  config: configObject,
39
39
  configPath,
40
- cwd = process.cwd(),
40
+ cwd,
41
41
  debug = false,
42
42
  maxArgLength,
43
43
  quiet = false,
@@ -48,7 +48,7 @@ const lintStaged = async (
48
48
  } = {},
49
49
  logger = console
50
50
  ) => {
51
- await validateOptions({ shell }, logger)
51
+ await validateOptions({ cwd, shell }, logger)
52
52
 
53
53
  // Unset GIT_LITERAL_PATHSPECS to not mess with path interpretation
54
54
  debugLog('Unset GIT_LITERAL_PATHSPECS (was `%s`)', process.env.GIT_LITERAL_PATHSPECS)
@@ -14,7 +14,8 @@ const debugLog = debug('lint-staged:resolveGitRepo')
14
14
  * submodules and worktrees
15
15
  */
16
16
  const resolveGitConfigDir = async (gitDir) => {
17
- const defaultDir = normalize(path.join(gitDir, '.git'))
17
+ // Get the real path in case it's a symlink
18
+ const defaultDir = normalize(await fs.realpath(path.join(gitDir, '.git')))
18
19
  const stats = await fs.lstat(defaultDir)
19
20
  // If .git is a directory, use it
20
21
  if (stats.isDirectory()) return defaultDir
package/lib/runAll.js CHANGED
@@ -66,7 +66,7 @@ export const runAll = async (
66
66
  concurrent = true,
67
67
  configObject,
68
68
  configPath,
69
- cwd = process.cwd(),
69
+ cwd,
70
70
  debug = false,
71
71
  maxArgLength,
72
72
  quiet = false,
@@ -77,7 +77,12 @@ export const runAll = async (
77
77
  },
78
78
  logger = console
79
79
  ) => {
80
- debugLog('Running all linter scripts')
80
+ debugLog('Running all linter scripts...')
81
+
82
+ // Resolve relative CWD option
83
+ const hasExplicitCwd = !!cwd
84
+ cwd = hasExplicitCwd ? path.resolve(cwd) : process.cwd()
85
+ debugLog('Using working directory `%s`', cwd)
81
86
 
82
87
  const ctx = getInitialState({ quiet })
83
88
 
@@ -116,6 +121,8 @@ export const runAll = async (
116
121
 
117
122
  const configGroups = await getConfigGroups({ configObject, configPath, cwd, files }, logger)
118
123
 
124
+ const hasMultipleConfigs = Object.keys(configGroups).length > 1
125
+
119
126
  // lint-staged 10 will automatically add modifications to index
120
127
  // Warn user when their command includes `git add`
121
128
  let hasDeprecatedGitAdd = false
@@ -134,21 +141,25 @@ export const runAll = async (
134
141
  const matchedFiles = new Set()
135
142
 
136
143
  for (const [configPath, { config, files }] of Object.entries(configGroups)) {
144
+ const relativeConfig = normalize(path.relative(cwd, configPath))
137
145
  const stagedFileChunks = chunkFiles({ baseDir: gitDir, files, maxArgLength, relative })
138
146
 
147
+ // Use actual cwd if it's specified, or there's only a single config file.
148
+ // Otherwise use the directory of the config file for each config group,
149
+ // to make sure tasks are separated from each other.
150
+ const groupCwd = hasMultipleConfigs && !hasExplicitCwd ? path.dirname(configPath) : cwd
151
+
139
152
  const chunkCount = stagedFileChunks.length
140
153
  if (chunkCount > 1) {
141
154
  debugLog('Chunked staged files from `%s` into %d part', configPath, chunkCount)
142
155
  }
143
156
 
144
157
  for (const [index, files] of stagedFileChunks.entries()) {
145
- const relativeConfig = normalize(path.relative(cwd, configPath))
146
-
147
158
  const chunkListrTasks = await Promise.all(
148
- generateTasks({ config, cwd, files, relative }).map((task) =>
159
+ generateTasks({ config, cwd: groupCwd, files, relative }).map((task) =>
149
160
  makeCmdTasks({
150
161
  commands: task.commands,
151
- cwd,
162
+ cwd: groupCwd,
152
163
  files: task.fileList,
153
164
  gitDir,
154
165
  renderer: listrOptions.renderer,
@@ -157,7 +168,14 @@ export const runAll = async (
157
168
  }).then((subTasks) => {
158
169
  // Add files from task to match set
159
170
  task.fileList.forEach((file) => {
160
- matchedFiles.add(file)
171
+ // Make sure relative files are normalized to the
172
+ // group cwd, because other there might be identical
173
+ // relative filenames in the entire set.
174
+ const normalizedFile = path.isAbsolute(file)
175
+ ? file
176
+ : normalize(path.join(groupCwd, file))
177
+
178
+ matchedFiles.add(normalizedFile)
161
179
  })
162
180
 
163
181
  hasDeprecatedGitAdd =
@@ -1,4 +1,5 @@
1
1
  import { constants, promises as fs } from 'fs'
2
+ import path from 'path'
2
3
 
3
4
  import debug from 'debug'
4
5
 
@@ -10,6 +11,7 @@ const debugLog = debug('lint-staged:validateOptions')
10
11
  /**
11
12
  * Validate lint-staged options, either from the Node.js API or the command line flags.
12
13
  * @param {*} options
14
+ * @param {boolean|string} [options.cwd] - Current working directory
13
15
  * @param {boolean|string} [options.shell] - Skip parsing of tasks for better shell support
14
16
  *
15
17
  * @throws {InvalidOptionsError}
@@ -17,6 +19,17 @@ const debugLog = debug('lint-staged:validateOptions')
17
19
  export const validateOptions = async (options = {}, logger) => {
18
20
  debugLog('Validating options...')
19
21
 
22
+ /** Ensure the passed cwd option exists; it might also be relative */
23
+ if (typeof options.cwd === 'string') {
24
+ try {
25
+ const resolved = path.resolve(options.cwd)
26
+ await fs.access(resolved, constants.F_OK)
27
+ } catch (error) {
28
+ logger.error(invalidOption('cwd', options.cwd, error.message))
29
+ throw InvalidOptionsError
30
+ }
31
+ }
32
+
20
33
  /** Ensure the passed shell option is executable */
21
34
  if (typeof options.shell === 'string') {
22
35
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lint-staged",
3
- "version": "12.2.2",
3
+ "version": "12.3.3",
4
4
  "description": "Lint files staged by git",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/okonet/lint-staged",
@@ -35,28 +35,28 @@
35
35
  "debug": "^4.3.3",
36
36
  "execa": "^5.1.1",
37
37
  "lilconfig": "2.0.4",
38
- "listr2": "^3.13.5",
38
+ "listr2": "^4.0.1",
39
39
  "micromatch": "^4.0.4",
40
40
  "normalize-path": "^3.0.0",
41
- "object-inspect": "^1.11.1",
41
+ "object-inspect": "^1.12.0",
42
42
  "string-argv": "^0.3.1",
43
43
  "supports-color": "^9.2.1",
44
44
  "yaml": "^1.10.2"
45
45
  },
46
46
  "devDependencies": {
47
- "@babel/core": "^7.16.5",
47
+ "@babel/core": "^7.16.12",
48
48
  "@babel/eslint-parser": "^7.16.5",
49
- "@babel/preset-env": "^7.16.5",
50
- "babel-jest": "^27.4.5",
49
+ "@babel/preset-env": "^7.16.11",
50
+ "babel-jest": "^27.4.6",
51
51
  "consolemock": "^1.1.0",
52
- "eslint": "^8.4.1",
52
+ "eslint": "^8.7.0",
53
53
  "eslint-config-prettier": "^8.3.0",
54
- "eslint-plugin-import": "^2.25.3",
54
+ "eslint-plugin-import": "^2.25.4",
55
55
  "eslint-plugin-node": "^11.1.0",
56
56
  "eslint-plugin-prettier": "^4.0.0",
57
57
  "fs-extra": "^10.0.0",
58
58
  "husky": "^7.0.4",
59
- "jest": "^27.4.5",
59
+ "jest": "^27.4.7",
60
60
  "jest-snapshot-serializer-ansi": "^1.0.0",
61
61
  "prettier": "^2.5.1"
62
62
  },