lint-staged 17.0.4 → 17.0.6

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/lib/cli.js CHANGED
@@ -167,6 +167,15 @@ export const parseCliOptions = (argv) => {
167
167
  values['hide-unstaged'] = false // becomes redundant
168
168
  }
169
169
 
170
+ const maxArgLength =
171
+ values['max-arg-length'] !== undefined ? parseInt(values['max-arg-length'], 10) : undefined
172
+
173
+ if (Number.isNaN(maxArgLength)) {
174
+ throw new TypeError(`Option '--mar-arg-length' takes a numeric argument`, {
175
+ cause: { '--max-arg-length': values['max-arg-length'] },
176
+ })
177
+ }
178
+
170
179
  return {
171
180
  allowEmpty: values['allow-empty'] ?? false,
172
181
  concurrent: values.concurrent === undefined ? true : JSON.parse(values.concurrent),
@@ -181,7 +190,7 @@ export const parseCliOptions = (argv) => {
181
190
  hidePartiallyStaged: values['hide-partially-staged'] ?? true,
182
191
  hideUnstaged: !!values['hide-unstaged'],
183
192
  hideAll: !!values['hide-all'],
184
- maxArgLength: parseInt(values['max-arg-length'], 10),
193
+ maxArgLength,
185
194
  quiet: !!values.quiet,
186
195
  relative: !!values.relative,
187
196
  revert: values.revert ?? true,
package/lib/execGit.js CHANGED
@@ -23,7 +23,6 @@ export const execGit = async (cmd, options) => {
23
23
  nodeOptions: {
24
24
  env: options?.env,
25
25
  cwd: options?.cwd,
26
- stdio: ['ignore'],
27
26
  },
28
27
  })
29
28
 
@@ -91,7 +91,6 @@ export const getSpawnedTask = ({
91
91
  // e.g `npm` should run tasks in the actual CWD
92
92
  cwd: /^git(\.exe)?/i.test(cmd) ? topLevelDir : cwd,
93
93
  env: color ? { FORCE_COLOR: 'true' } : { NO_COLOR: 'true' },
94
- stdio: ['ignore'],
95
94
  },
96
95
  }
97
96
 
@@ -1,4 +1,5 @@
1
1
  import crypto from 'node:crypto'
2
+ import fs from 'node:fs/promises'
2
3
  import path from 'node:path'
3
4
 
4
5
  import { createDebug } from './debug.js'
@@ -80,13 +81,23 @@ export class GitWorkflow {
80
81
  /**
81
82
  * @param {Object} opts
82
83
  */
83
- constructor({ allowEmpty, diff, diffFilter, failOnChanges, gitConfigDir, topLevelDir }) {
84
+ constructor({
85
+ allowEmpty,
86
+ diff,
87
+ diffFilter,
88
+ failOnChanges,
89
+ gitConfigDir,
90
+ matchedFileChunks,
91
+ topLevelDir,
92
+ }) {
84
93
  this.execGit = (args, options = {}) => execGit(args, { ...options, cwd: topLevelDir })
85
94
  this.allowEmpty = allowEmpty
86
95
  this.diff = diff
87
96
  this.diffFilter = diffFilter
88
97
  this.gitConfigDir = gitConfigDir
89
98
  this.failOnChanges = !!failOnChanges
99
+ /** @type {import('./getStagedFiles.js').StagedFile[][]} */
100
+ this.matchedFileChunks = matchedFileChunks
90
101
  this.topLevelDir = topLevelDir
91
102
 
92
103
  /**
@@ -299,30 +310,46 @@ export class GitWorkflow {
299
310
  ? normalizePath(process.env.GIT_INDEX_FILE)
300
311
  : process.env.GIT_INDEX_FILE
301
312
 
302
- debugLog('Updating active Git index again: %s', activeIndexFile)
303
- await this.execGit(['update-index', '--again'])
304
- debugLog('Done updating Git index again: %s', activeIndexFile)
313
+ /** Needs to be run serially because of locking Git operation */
314
+ for (const files of this.matchedFileChunks) {
315
+ const accessCheckedFiles = await Promise.allSettled(
316
+ files.map(async (f) => {
317
+ if (f.status === 'D') {
318
+ await fs.access(f.filepath)
319
+ return f.filepath // File is no longer deleted and can be added
320
+ } else {
321
+ return f.filepath
322
+ }
323
+ })
324
+ )
305
325
 
306
- if (activeIndexFile?.endsWith('.lock')) {
307
- const defaultIndexLock = normalizePath(
308
- await this.execGit(['rev-parse', '--path-format=absolute', '--git-path', 'index.lock'])
326
+ const addableFiles = accessCheckedFiles.flatMap((r) =>
327
+ r.status === 'fulfilled' ? [r.value] : []
309
328
  )
310
329
 
311
- /**
312
- * If the active index file is a non-default lockfile, we are committing with a pathspec
313
- * without having explicitly run `git add`. In this case we need to also update the
314
- * default index, otherwise there will be leftover diff after committing
315
- */
316
- if (activeIndexFile !== defaultIndexLock) {
317
- debugLog('Updating default Git index lock again: %s', defaultIndexLock)
330
+ debugLog('Updating active Git index: %s', activeIndexFile)
331
+ await this.execGit(['add', '--', ...addableFiles])
332
+ debugLog('Done updating Git index: %s', activeIndexFile)
318
333
 
319
- await this.execGit(['update-index', '--again'], {
320
- env: {
321
- GIT_INDEX_FILE: defaultIndexLock,
322
- },
323
- })
334
+ if (activeIndexFile?.endsWith('.lock')) {
335
+ const defaultIndexLock = normalizePath(
336
+ await this.execGit(['rev-parse', '--path-format=absolute', '--git-path', 'index.lock'])
337
+ )
324
338
 
325
- debugLog('Done updating default Git index lock again: %s', defaultIndexLock)
339
+ /**
340
+ * If the active index file is a non-default lockfile, we are committing with a pathspec
341
+ * without having explicitly run `git add`. In this case we need to also update the
342
+ * default index, otherwise there will be leftover diff after committing
343
+ */
344
+ if (activeIndexFile !== defaultIndexLock) {
345
+ debugLog('Updating default Git index again: %s', defaultIndexLock)
346
+ await this.execGit(['add', '--', ...addableFiles], {
347
+ env: {
348
+ GIT_INDEX_FILE: defaultIndexLock,
349
+ },
350
+ })
351
+ debugLog('Done updating default Git index lock: %s', defaultIndexLock)
352
+ }
326
353
  }
327
354
  }
328
355
 
package/lib/runAll.js CHANGED
@@ -302,12 +302,23 @@ export const runAll = async (
302
302
  return ctx
303
303
  }
304
304
 
305
+ // Chunk matched files for better Windows compatibility
306
+ /** @type {import('./getStagedFiles.js').StagedFile[][]} */
307
+ const matchedFileChunks = chunkFiles({
308
+ // matched files are relative to `cwd`, not `topLevelDir`, when `relative` is used
309
+ baseDir: cwd,
310
+ files: Array.from(matchedFiles),
311
+ maxArgLength,
312
+ relative: false,
313
+ })
314
+
305
315
  const git = new GitWorkflow({
306
316
  allowEmpty,
307
317
  diff,
308
318
  diffFilter,
309
319
  failOnChanges,
310
320
  gitConfigDir,
321
+ matchedFileChunks,
311
322
  topLevelDir,
312
323
  })
313
324
 
@@ -328,7 +339,7 @@ export const runAll = async (
328
339
  skip: () => listrTasks.every((task) => task.skip()),
329
340
  },
330
341
  {
331
- title: 'Updating Git index again...',
342
+ title: 'Staging changes from tasks...',
332
343
  task: (ctx) => git.updateIndex(ctx),
333
344
  skip: updateIndexSkipped,
334
345
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lint-staged",
3
- "version": "17.0.4",
3
+ "version": "17.0.6",
4
4
  "description": "Lint files staged by git",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -18,6 +18,10 @@
18
18
  "funding": {
19
19
  "url": "https://opencollective.com/lint-staged"
20
20
  },
21
+ "publishConfig": {
22
+ "provenance": true,
23
+ "access": "public"
24
+ },
21
25
  "engines": {
22
26
  "node": ">=22.22.1"
23
27
  },
@@ -51,31 +55,31 @@
51
55
  "listr2": "^10.2.1",
52
56
  "picomatch": "^4.0.4",
53
57
  "string-argv": "^0.3.2",
54
- "tinyexec": "^1.1.2"
58
+ "tinyexec": "1.2.2"
55
59
  },
56
60
  "optionalDependencies": {
57
- "yaml": "^2.8.4"
61
+ "yaml": "^2.9.0"
58
62
  },
59
63
  "devDependencies": {
60
64
  "@changesets/changelog-github": "0.7.0",
61
65
  "@changesets/cli": "2.31.0",
62
- "@commitlint/cli": "21.0.0",
63
- "@commitlint/config-conventional": "21.0.0",
66
+ "@commitlint/cli": "21.0.2",
67
+ "@commitlint/config-conventional": "21.0.2",
64
68
  "@eslint/js": "10.0.1",
65
- "@vitest/coverage-istanbul": "4.1.5",
66
- "@vitest/eslint-plugin": "1.6.17",
69
+ "@vitest/coverage-istanbul": "4.1.7",
70
+ "@vitest/eslint-plugin": "1.6.18",
67
71
  "consolemock": "1.1.0",
68
72
  "cross-env": "10.1.0",
69
- "eslint": "10.3.0",
73
+ "eslint": "10.4.1",
70
74
  "eslint-config-prettier": "10.1.8",
71
75
  "eslint-plugin-n": "18.0.1",
72
- "eslint-plugin-prettier": "5.5.5",
76
+ "eslint-plugin-prettier": "5.5.6",
73
77
  "eslint-plugin-simple-import-sort": "13.0.0",
74
78
  "husky": "9.1.7",
75
79
  "mock-stdin": "1.0.0",
76
80
  "prettier": "3.8.3",
77
- "semver": "7.8.0",
78
- "vitest": "4.1.5"
81
+ "semver": "7.8.1",
82
+ "vitest": "4.1.7"
79
83
  },
80
84
  "keywords": [
81
85
  "lint",