lint-staged 10.1.3 → 10.1.7

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.
@@ -81,7 +81,7 @@ const options = {
81
81
  debug('Options parsed from command-line:', options)
82
82
 
83
83
  lintStaged(options)
84
- .then(passed => {
84
+ .then((passed) => {
85
85
  process.exitCode = passed ? 0 : 1
86
86
  })
87
87
  .catch(() => {
package/lib/chunkFiles.js CHANGED
@@ -38,7 +38,7 @@ module.exports = function chunkFiles({ files, baseDir, maxArgLength = null, rela
38
38
  return [files]
39
39
  }
40
40
 
41
- const normalizedFiles = files.map(file =>
41
+ const normalizedFiles = files.map((file) =>
42
42
  normalize(relative || !baseDir ? file : path.resolve(baseDir, file))
43
43
  )
44
44
  const fileListLength = normalizedFiles.join(' ').length
@@ -25,8 +25,8 @@ module.exports = function generateTasks({
25
25
  }) {
26
26
  debug('Generating linter tasks')
27
27
 
28
- const absoluteFiles = files.map(file => normalize(path.resolve(gitDir, file)))
29
- const relativeFiles = absoluteFiles.map(file => normalize(path.relative(cwd, file)))
28
+ const absoluteFiles = files.map((file) => normalize(path.resolve(gitDir, file)))
29
+ const relativeFiles = absoluteFiles.map((file) => normalize(path.relative(cwd, file)))
30
30
 
31
31
  return Object.entries(config).map(([pattern, commands]) => {
32
32
  const isParentDirPattern = pattern.startsWith('../')
@@ -35,7 +35,7 @@ module.exports = function generateTasks({
35
35
  relativeFiles
36
36
  // Only worry about children of the CWD unless the pattern explicitly
37
37
  // specifies that it concerns a parent directory.
38
- .filter(file => {
38
+ .filter((file) => {
39
39
  if (isParentDirPattern) return true
40
40
  return !file.startsWith('..') && !path.isAbsolute(file)
41
41
  }),
@@ -48,7 +48,7 @@ module.exports = function generateTasks({
48
48
  // match both `test.js` and `subdirectory/test.js`.
49
49
  matchBase: !pattern.includes('/')
50
50
  }
51
- ).map(file => normalize(relative ? file : path.resolve(cwd, file)))
51
+ ).map((file) => normalize(relative ? file : path.resolve(cwd, file)))
52
52
 
53
53
  const task = { pattern, commands, fileList }
54
54
  debug('Generated task: \n%O', task)
@@ -85,7 +85,7 @@ class GitWorkflow {
85
85
  */
86
86
  async getBackupStash(ctx) {
87
87
  const stashes = await this.execGit(['stash', 'list'])
88
- const index = stashes.split('\n').findIndex(line => line.includes(STASH))
88
+ const index = stashes.split('\n').findIndex((line) => line.includes(STASH))
89
89
  if (index === -1) {
90
90
  ctx.gitGetBackupStashError = true
91
91
  throw new Error('lint-staged automatic backup is missing!')
@@ -102,7 +102,7 @@ class GitWorkflow {
102
102
  const deletedFiles = lsFiles
103
103
  .split('\n')
104
104
  .filter(Boolean)
105
- .map(file => path.resolve(this.gitDir, file))
105
+ .map((file) => path.resolve(this.gitDir, file))
106
106
  debug('Found deleted files:', deletedFiles)
107
107
  return deletedFiles
108
108
  }
@@ -113,9 +113,9 @@ class GitWorkflow {
113
113
  async backupMergeStatus() {
114
114
  debug('Backing up merge state...')
115
115
  await Promise.all([
116
- readFile(this.mergeHeadFilename).then(buffer => (this.mergeHeadBuffer = buffer)),
117
- readFile(this.mergeModeFilename).then(buffer => (this.mergeModeBuffer = buffer)),
118
- readFile(this.mergeMsgFilename).then(buffer => (this.mergeMsgBuffer = buffer))
116
+ readFile(this.mergeHeadFilename).then((buffer) => (this.mergeHeadBuffer = buffer)),
117
+ readFile(this.mergeModeFilename).then((buffer) => (this.mergeModeBuffer = buffer)),
118
+ readFile(this.mergeMsgFilename).then((buffer) => (this.mergeMsgBuffer = buffer))
119
119
  ])
120
120
  debug('Done backing up merge state!')
121
121
  }
@@ -149,7 +149,7 @@ class GitWorkflow {
149
149
  const status = await this.execGit(['status', '--porcelain'])
150
150
  const partiallyStaged = status
151
151
  .split('\n')
152
- .filter(line => {
152
+ .filter((line) => {
153
153
  /**
154
154
  * See https://git-scm.com/docs/git-status#_short_format
155
155
  * The first letter of the line represents current index status,
@@ -158,7 +158,8 @@ class GitWorkflow {
158
158
  const [index, workingTree] = line
159
159
  return index !== ' ' && workingTree !== ' ' && index !== '?' && workingTree !== '?'
160
160
  })
161
- .map(line => line.substr(3)) // Remove first three letters (index, workingTree, and a whitespace)
161
+ .map((line) => line.substr(3)) // Remove first three letters (index, workingTree, and a whitespace)
162
+ .filter(Boolean) // Filter empty string
162
163
  debug('Found partially staged files:', partiallyStaged)
163
164
  return partiallyStaged.length ? partiallyStaged : null
164
165
  }
@@ -166,7 +167,7 @@ class GitWorkflow {
166
167
  /**
167
168
  * Create a diff of partially staged files and backup stash if enabled.
168
169
  */
169
- async prepare(ctx, stash) {
170
+ async prepare(ctx, shouldBackup) {
170
171
  try {
171
172
  debug('Backing up original state...')
172
173
 
@@ -184,32 +185,24 @@ class GitWorkflow {
184
185
  /**
185
186
  * If backup stash should be skipped, no need to continue
186
187
  */
187
- if (!stash) return
188
+ if (!shouldBackup) return
189
+
190
+ // When backup is enabled, the revert will clear ongoing merge status.
191
+ await this.backupMergeStatus()
188
192
 
189
193
  // Get a list of unstaged deleted files, because certain bugs might cause them to reappear:
190
- // - in git versions =< 2.13.0 the `--keep-index` flag resurrects deleted files
194
+ // - in git versions =< 2.13.0 the `git stash --keep-index` option resurrects deleted files
191
195
  // - git stash can't infer RD or MD states correctly, and will lose the deletion
192
196
  this.deletedFiles = await this.getDeletedFiles()
193
197
 
194
- // the `git stash` clears metadata about a possible git merge
195
- // Manually check and backup if necessary
196
- await this.backupMergeStatus()
197
-
198
- // Save stash of original state
199
- await this.execGit(['stash', 'save', STASH])
200
- await this.execGit(['stash', 'apply', '--quiet', '--index', await this.getBackupStash()])
201
-
202
- // Restore meta information about ongoing git merge, cleared by `git stash`
203
- await this.restoreMergeStatus()
204
-
205
- // If stashing resurrected deleted files, clean them out
206
- await Promise.all(this.deletedFiles.map(file => unlink(file)))
198
+ // Save stash of all staged files.
199
+ // The `stash create` command creates a dangling commit without removing any files,
200
+ // and `stash store` saves it as an actual stash.
201
+ const hash = await this.execGit(['stash', 'create'])
202
+ await this.execGit(['stash', 'store', '--quiet', '--message', STASH, hash])
207
203
 
208
204
  debug('Done backing up original state!')
209
205
  } catch (error) {
210
- if (error.message && error.message.includes('You do not have the initial commit yet')) {
211
- ctx.emptyGitRepo = true
212
- }
213
206
  handleError(error, ctx)
214
207
  }
215
208
  }
@@ -306,10 +299,10 @@ class GitWorkflow {
306
299
  await this.restoreMergeStatus()
307
300
 
308
301
  // If stashing resurrected deleted files, clean them out
309
- await Promise.all(this.deletedFiles.map(file => unlink(file)))
302
+ await Promise.all(this.deletedFiles.map((file) => unlink(file)))
310
303
 
311
304
  // Clean out patch
312
- if (this.partiallyStagedFiles) await unlink(PATCH_UNSTAGED)
305
+ await unlink(this.getHiddenFilepath(PATCH_UNSTAGED))
313
306
 
314
307
  debug('Done restoring original state!')
315
308
  } catch (error) {
@@ -2,11 +2,11 @@
2
2
 
3
3
  // istanbul ignore next
4
4
  // Work-around for duplicated error logs, see #142
5
- const errMsg = err => (err.privateMsg != null ? err.privateMsg : err.message)
5
+ const errMsg = (err) => (err.privateMsg != null ? err.privateMsg : err.message)
6
6
 
7
7
  module.exports = function printErrors(errorInstance, logger) {
8
8
  if (Array.isArray(errorInstance.errors)) {
9
- errorInstance.errors.forEach(lintError => {
9
+ errorInstance.errors.forEach((lintError) => {
10
10
  logger.error(errMsg(lintError))
11
11
  })
12
12
  } else {
@@ -15,7 +15,7 @@ const fsLstat = promisify(fs.lstat)
15
15
  * Resolve path to the .git directory, with special handling for
16
16
  * submodules and worktrees
17
17
  */
18
- const resolveGitConfigDir = async gitDir => {
18
+ const resolveGitConfigDir = async (gitDir) => {
19
19
  const defaultDir = normalize(path.join(gitDir, '.git'))
20
20
  const stats = await fsLstat(defaultDir)
21
21
  // If .git is a directory, use it
@@ -28,7 +28,7 @@ const resolveGitConfigDir = async gitDir => {
28
28
  /**
29
29
  * Resolve git directory and possible submodule paths
30
30
  */
31
- const resolveGitRepo = async cwd => {
31
+ const resolveGitRepo = async (cwd) => {
32
32
  try {
33
33
  debugLog('Resolving git repo from `%s`', cwd)
34
34
 
@@ -8,7 +8,7 @@ const symbols = require('log-symbols')
8
8
 
9
9
  const debug = require('debug')('lint-staged:task')
10
10
 
11
- const successMsg = linter => `${symbols.success} ${linter} passed!`
11
+ const successMsg = (linter) => `${symbols.success} ${linter} passed!`
12
12
 
13
13
  /**
14
14
  * Create and returns an error instance with a given message.
@@ -81,7 +81,7 @@ module.exports = function resolveTaskFn({ command, files, gitDir, isFn, relative
81
81
  }
82
82
  debug('execaOptions:', execaOptions)
83
83
 
84
- return async ctx => {
84
+ return async (ctx) => {
85
85
  const promise = shell
86
86
  ? execa.command(isFn ? command : `${command} ${files.join(' ')}`, execaOptions)
87
87
  : execa(cmd, isFn ? args : args.concat(files), execaOptions)
package/lib/runAll.js CHANGED
@@ -7,6 +7,7 @@ const Listr = require('listr')
7
7
  const symbols = require('log-symbols')
8
8
 
9
9
  const chunkFiles = require('./chunkFiles')
10
+ const execGit = require('./execGit')
10
11
  const generateTasks = require('./generateTasks')
11
12
  const getStagedFiles = require('./getStagedFiles')
12
13
  const GitWorkflow = require('./gitWorkflow')
@@ -28,7 +29,7 @@ const MESSAGES = {
28
29
  GIT_ERROR: 'Skipped because of previous git error.'
29
30
  }
30
31
 
31
- const shouldSkipApplyModifications = ctx => {
32
+ const shouldSkipApplyModifications = (ctx) => {
32
33
  // Should be skipped in case of git errors
33
34
  if (ctx.gitError) {
34
35
  return MESSAGES.GIT_ERROR
@@ -39,14 +40,14 @@ const shouldSkipApplyModifications = ctx => {
39
40
  }
40
41
  }
41
42
 
42
- const shouldSkipRevert = ctx => {
43
+ const shouldSkipRevert = (ctx) => {
43
44
  // Should be skipped in case of unknown git errors
44
45
  if (ctx.gitError && !ctx.gitApplyEmptyCommitError && !ctx.gitRestoreUnstagedChangesError) {
45
46
  return MESSAGES.GIT_ERROR
46
47
  }
47
48
  }
48
49
 
49
- const shouldSkipCleanup = ctx => {
50
+ const shouldSkipCleanup = (ctx) => {
50
51
  // Should be skipped in case of unknown git errors
51
52
  if (ctx.gitError && !ctx.gitApplyEmptyCommitError && !ctx.gitRestoreUnstagedChangesError) {
52
53
  return MESSAGES.GIT_ERROR
@@ -91,15 +92,22 @@ const runAll = async (
91
92
  ) => {
92
93
  debugLog('Running all linter scripts')
93
94
 
94
- if (!stash) {
95
- logger.warn(
96
- `${symbols.warning} ${chalk.yellow('Skipping backup because `--no-stash` was used.')}`
97
- )
98
- }
99
-
100
95
  const { gitDir, gitConfigDir } = await resolveGitRepo(cwd)
101
96
  if (!gitDir) throw new Error('Current directory is not a git directory!')
102
97
 
98
+ // Test whether we have any commits or not.
99
+ // Stashing must be disabled with no initial commit.
100
+ const hasInitialCommit = await execGit(['log', '-1'], { cwd: gitDir })
101
+ .then(() => true)
102
+ .catch(() => false)
103
+
104
+ // Lint-staged should create a backup stash only when there's an initial commit
105
+ const shouldBackup = hasInitialCommit && stash
106
+ if (!shouldBackup) {
107
+ const reason = hasInitialCommit ? '`--no-stash` was used' : 'there’s no initial commit yet'
108
+ logger.warn(`${symbols.warning} ${chalk.yellow(`Skipping backup because ${reason}.\n`)}`)
109
+ }
110
+
103
111
  const files = await getStagedFiles({ cwd: gitDir })
104
112
  if (!files) throw new Error('Unable to get staged files!')
105
113
  debugLog('Loaded list of staged files in git:\n%O', files)
@@ -141,11 +149,11 @@ const runAll = async (
141
149
  })
142
150
 
143
151
  // Add files from task to match set
144
- task.fileList.forEach(file => {
152
+ task.fileList.forEach((file) => {
145
153
  matchedFiles.add(file)
146
154
  })
147
155
 
148
- hasDeprecatedGitAdd = subTasks.some(subTask => subTask.command === 'git add')
156
+ hasDeprecatedGitAdd = subTasks.some((subTask) => subTask.command === 'git add')
149
157
 
150
158
  chunkListrTasks.push({
151
159
  title: `Running tasks for ${task.pattern}`,
@@ -176,7 +184,7 @@ const runAll = async (
176
184
  // Skip if the first step (backup) failed
177
185
  if (ctx.gitError) return MESSAGES.GIT_ERROR
178
186
  // Skip chunk when no every task is skipped (due to no matches)
179
- if (chunkListrTasks.every(task => task.skip())) return 'No tasks to run.'
187
+ if (chunkListrTasks.every((task) => task.skip())) return 'No tasks to run.'
180
188
  return false
181
189
  }
182
190
  })
@@ -191,7 +199,7 @@ const runAll = async (
191
199
 
192
200
  // If all of the configured tasks should be skipped
193
201
  // avoid executing any lint-staged logic
194
- if (listrTasks.every(task => task.skip())) {
202
+ if (listrTasks.every((task) => task.skip())) {
195
203
  logger.log('No staged files match any of provided globs.')
196
204
  return 'No tasks to run.'
197
205
  }
@@ -202,38 +210,38 @@ const runAll = async (
202
210
  [
203
211
  {
204
212
  title: 'Preparing...',
205
- task: ctx => git.prepare(ctx, stash)
213
+ task: (ctx) => git.prepare(ctx, shouldBackup)
206
214
  },
207
215
  {
208
216
  title: 'Hiding unstaged changes to partially staged files...',
209
- task: ctx => git.hideUnstagedChanges(ctx),
210
- enabled: ctx => ctx.hasPartiallyStagedFiles
217
+ task: (ctx) => git.hideUnstagedChanges(ctx),
218
+ enabled: (ctx) => ctx.hasPartiallyStagedFiles
211
219
  },
212
220
  ...listrTasks,
213
221
  {
214
222
  title: 'Applying modifications...',
215
- task: ctx => git.applyModifications(ctx),
223
+ task: (ctx) => git.applyModifications(ctx),
216
224
  // Always apply back unstaged modifications when skipping backup
217
- skip: ctx => stash && shouldSkipApplyModifications(ctx)
225
+ skip: (ctx) => shouldBackup && shouldSkipApplyModifications(ctx)
218
226
  },
219
227
  {
220
228
  title: 'Restoring unstaged changes to partially staged files...',
221
- task: ctx => git.restoreUnstagedChanges(ctx),
222
- enabled: ctx => ctx.hasPartiallyStagedFiles,
229
+ task: (ctx) => git.restoreUnstagedChanges(ctx),
230
+ enabled: (ctx) => ctx.hasPartiallyStagedFiles,
223
231
  skip: shouldSkipApplyModifications
224
232
  },
225
233
  {
226
234
  title: 'Reverting to original state because of errors...',
227
- task: ctx => git.restoreOriginalState(ctx),
228
- enabled: ctx =>
229
- stash &&
235
+ task: (ctx) => git.restoreOriginalState(ctx),
236
+ enabled: (ctx) =>
237
+ shouldBackup &&
230
238
  (ctx.taskError || ctx.gitApplyEmptyCommitError || ctx.gitRestoreUnstagedChangesError),
231
239
  skip: shouldSkipRevert
232
240
  },
233
241
  {
234
242
  title: 'Cleaning up...',
235
- task: ctx => git.cleanup(ctx),
236
- enabled: () => stash,
243
+ task: (ctx) => git.cleanup(ctx),
244
+ enabled: () => shouldBackup,
237
245
  skip: shouldSkipCleanup
238
246
  }
239
247
  ],
@@ -251,12 +259,7 @@ const runAll = async (
251
259
  } else if (error.context.gitError && !error.context.gitGetBackupStashError) {
252
260
  logger.error(`\n ${symbols.error} ${chalk.red(`lint-staged failed due to a git error.`)}`)
253
261
 
254
- if (error.context.emptyGitRepo) {
255
- logger.error(
256
- `\n The initial commit is needed for lint-staged to work.
257
- Please use the --no-verify flag to skip running lint-staged.`
258
- )
259
- } else if (stash) {
262
+ if (shouldBackup) {
260
263
  // No sense to show this if the backup stash itself is missing.
261
264
  logger.error(` Any lost modifications can be restored from a git stash:
262
265
 
@@ -8,17 +8,17 @@ const format = require('stringify-object')
8
8
  const debug = require('debug')('lint-staged:cfg')
9
9
 
10
10
  const TEST_DEPRECATED_KEYS = new Map([
11
- ['concurrent', key => typeof key === 'boolean'],
12
- ['chunkSize', key => typeof key === 'number'],
13
- ['globOptions', key => typeof key === 'object'],
14
- ['linters', key => typeof key === 'object'],
15
- ['ignore', key => Array.isArray(key)],
16
- ['subTaskConcurrency', key => typeof key === 'number'],
17
- ['renderer', key => typeof key === 'string'],
18
- ['relative', key => typeof key === 'boolean']
11
+ ['concurrent', (key) => typeof key === 'boolean'],
12
+ ['chunkSize', (key) => typeof key === 'number'],
13
+ ['globOptions', (key) => typeof key === 'object'],
14
+ ['linters', (key) => typeof key === 'object'],
15
+ ['ignore', (key) => Array.isArray(key)],
16
+ ['subTaskConcurrency', (key) => typeof key === 'number'],
17
+ ['renderer', (key) => typeof key === 'string'],
18
+ ['relative', (key) => typeof key === 'boolean']
19
19
  ])
20
20
 
21
- const formatError = helpMsg => `● Validation Error:
21
+ const formatError = (helpMsg) => `● Validation Error:
22
22
 
23
23
  ${helpMsg}
24
24
 
@@ -68,7 +68,7 @@ module.exports = function validateConfig(config) {
68
68
 
69
69
  if (
70
70
  (!Array.isArray(task) ||
71
- task.some(item => typeof item !== 'string' && typeof item !== 'function')) &&
71
+ task.some((item) => typeof item !== 'string' && typeof item !== 'function')) &&
72
72
  typeof task !== 'string' &&
73
73
  typeof task !== 'function'
74
74
  ) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lint-staged",
3
- "version": "10.1.3",
3
+ "version": "10.1.7",
4
4
  "description": "Lint files staged by git",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/okonet/lint-staged",
@@ -34,12 +34,12 @@
34
34
  }
35
35
  },
36
36
  "dependencies": {
37
- "chalk": "^3.0.0",
38
- "commander": "^4.0.1",
37
+ "chalk": "^4.0.0",
38
+ "commander": "^5.0.0",
39
39
  "cosmiconfig": "^6.0.0",
40
40
  "debug": "^4.1.1",
41
41
  "dedent": "^0.7.0",
42
- "execa": "^3.4.0",
42
+ "execa": "^4.0.0",
43
43
  "listr": "^0.14.3",
44
44
  "log-symbols": "^3.0.0",
45
45
  "micromatch": "^4.0.2",
@@ -49,27 +49,27 @@
49
49
  "stringify-object": "^3.3.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@babel/core": "^7.7.4",
53
- "@babel/plugin-proposal-object-rest-spread": "^7.7.4",
54
- "@babel/preset-env": "^7.7.4",
55
- "babel-eslint": "^10.0.3",
56
- "babel-jest": "^24.9.0",
52
+ "@babel/core": "^7.9.0",
53
+ "@babel/plugin-proposal-object-rest-spread": "^7.9.5",
54
+ "@babel/preset-env": "^7.9.5",
55
+ "babel-eslint": "^10.1.0",
56
+ "babel-jest": "^25.3.0",
57
57
  "consolemock": "^1.1.0",
58
- "eslint": "^6.7.2",
58
+ "eslint": "^6.8.0",
59
59
  "eslint-config-okonet": "^7.0.2",
60
- "eslint-config-prettier": "^6.7.0",
61
- "eslint-plugin-flowtype": "^4.5.2",
62
- "eslint-plugin-import": "^2.18.2",
60
+ "eslint-config-prettier": "^6.10.1",
61
+ "eslint-plugin-flowtype": "^4.7.0",
62
+ "eslint-plugin-import": "^2.20.2",
63
63
  "eslint-plugin-jsx-a11y": "^6.2.3",
64
- "eslint-plugin-node": "^10.0.0",
65
- "eslint-plugin-prettier": "^3.1.1",
66
- "eslint-plugin-react": "^7.17.0",
67
- "fs-extra": "^8.1.0",
68
- "husky": "^3.1.0",
69
- "jest": "^24.9.0",
64
+ "eslint-plugin-node": "^11.1.0",
65
+ "eslint-plugin-prettier": "^3.1.3",
66
+ "eslint-plugin-react": "^7.19.0",
67
+ "fs-extra": "^9.0.0",
68
+ "husky": "^4.2.5",
69
+ "jest": "^25.3.0",
70
70
  "jest-snapshot-serializer-ansi": "^1.0.0",
71
- "nanoid": "^2.1.7",
72
- "prettier": "^1.19.1"
71
+ "nanoid": "^3.1.3",
72
+ "prettier": "^2.0.4"
73
73
  },
74
74
  "config": {
75
75
  "commitizen": {