lint-staged 10.0.4 → 10.0.8

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/file.js CHANGED
@@ -2,67 +2,80 @@
2
2
 
3
3
  const debug = require('debug')('lint-staged:file')
4
4
  const fs = require('fs')
5
+ const { promisify } = require('util')
5
6
 
6
- const fsPromises = fs.promises
7
+ const fsAccess = promisify(fs.access)
8
+ const fsReadFile = promisify(fs.readFile)
9
+ const fsUnlink = promisify(fs.unlink)
10
+ const fsWriteFile = promisify(fs.writeFile)
7
11
 
8
12
  /**
9
- * Check if a file exists. Returns the filepath if exists.
10
- * @param {string} filepath
13
+ * Check if a file exists. Returns the filename if exists.
14
+ * @param {String} filename
15
+ * @returns {String|Boolean}
11
16
  */
12
- const exists = async filepath => {
17
+ const exists = async filename => {
13
18
  try {
14
- await fsPromises.access(filepath)
15
- return filepath
19
+ await fsAccess(filename)
20
+ return filename
16
21
  } catch {
17
22
  return false
18
23
  }
19
24
  }
20
25
 
21
26
  /**
27
+ * Read contents of a file to buffer
22
28
  * @param {String} filename
23
- * @returns {Promise<Buffer|Null>}
29
+ * @param {Boolean} [ignoreENOENT=true] — Whether to throw if the file doesn't exist
30
+ * @returns {Promise<Buffer>}
24
31
  */
25
- const readBufferFromFile = (filename, rejectENOENT = false) =>
26
- new Promise(resolve => {
27
- debug('Reading buffer from file `%s`', filename)
28
- fs.readFile(filename, (error, buffer) => {
29
- if (!rejectENOENT && error && error.code === 'ENOENT') {
30
- debug("File `%s` doesn't exist, ignoring...", filename)
31
- return resolve(null) // no-op file doesn't exist
32
- }
33
- debug('Done reading buffer from file `%s`!', filename)
34
- resolve(buffer)
35
- })
36
- })
32
+ const readFile = async (filename, ignoreENOENT = true) => {
33
+ debug('Reading file `%s`', filename)
34
+ try {
35
+ return await fsReadFile(filename)
36
+ } catch (error) {
37
+ if (ignoreENOENT && error.code === 'ENOENT') {
38
+ debug("File `%s` doesn't exist, ignoring...", filename)
39
+ return null // no-op file doesn't exist
40
+ } else {
41
+ throw error
42
+ }
43
+ }
44
+ }
37
45
 
38
46
  /**
39
47
  * Unlink a file if it exists
40
- * @param {*} filepath
48
+ * @param {String} filename
49
+ * @param {Boolean} [ignoreENOENT=true] — Whether to throw if the file doesn't exist
41
50
  */
42
- const unlink = async filepath => {
43
- if (filepath) {
44
- await fsPromises.access(filepath)
45
- await fsPromises.unlink(filepath)
51
+ const unlink = async (filename, ignoreENOENT = true) => {
52
+ if (filename) {
53
+ debug('Unlinking file `%s`', filename)
54
+ try {
55
+ await fsUnlink(filename)
56
+ } catch (error) {
57
+ if (ignoreENOENT && error.code === 'ENOENT') {
58
+ debug("File `%s` doesn't exist, ignoring...", filename)
59
+ } else {
60
+ throw error
61
+ }
62
+ }
46
63
  }
47
64
  }
48
65
 
49
66
  /**
67
+ * Write buffer to file
50
68
  * @param {String} filename
51
69
  * @param {Buffer} buffer
52
- * @returns {Promise<Void>}
53
70
  */
54
- const writeBufferToFile = (filename, buffer) =>
55
- new Promise(resolve => {
56
- debug('Writing buffer to file `%s`', filename)
57
- fs.writeFile(filename, buffer, () => {
58
- debug('Done writing buffer to file `%s`!', filename)
59
- resolve()
60
- })
61
- })
71
+ const writeFile = async (filename, buffer) => {
72
+ debug('Writing file `%s`', filename)
73
+ await fsWriteFile(filename, buffer)
74
+ }
62
75
 
63
76
  module.exports = {
64
77
  exists,
65
- readBufferFromFile,
78
+ readFile,
66
79
  unlink,
67
- writeBufferToFile
80
+ writeFile
68
81
  }
@@ -6,7 +6,7 @@ module.exports = async function getStagedFiles(options) {
6
6
  try {
7
7
  const lines = await execGit(['diff', '--staged', '--diff-filter=ACMR', '--name-only'], options)
8
8
  return lines ? lines.split('\n') : []
9
- } catch (error) {
9
+ } catch {
10
10
  return null
11
11
  }
12
12
  }
@@ -4,7 +4,7 @@ const debug = require('debug')('lint-staged:git')
4
4
  const path = require('path')
5
5
 
6
6
  const execGit = require('./execGit')
7
- const { exists, readBufferFromFile, unlink, writeBufferToFile } = require('./file')
7
+ const { exists, readFile, unlink, writeFile } = require('./file')
8
8
 
9
9
  const MERGE_HEAD = 'MERGE_HEAD'
10
10
  const MERGE_MODE = 'MERGE_MODE'
@@ -18,23 +18,6 @@ const PATCH_UNTRACKED = 'lint-staged_untracked.patch'
18
18
  const GIT_APPLY_ARGS = ['apply', '-v', '--whitespace=nowarn', '--recount', '--unidiff-zero']
19
19
  const GIT_DIFF_ARGS = ['--binary', '--unified=0', '--no-color', '--no-ext-diff', '--patch']
20
20
 
21
- /**
22
- * Delete untracked files using `git clean`
23
- * @param {Function} execGit function for executing git commands using execa
24
- * @returns {Promise<void>}
25
- */
26
- const cleanUntrackedFiles = async execGit => {
27
- const untrackedFiles = await execGit(['ls-files', '--others', '--exclude-standard'])
28
- if (untrackedFiles) {
29
- debug('Detected unstaged, untracked files: ', untrackedFiles)
30
- debug(
31
- 'This is probably due to a bug in git =< 2.13.0 where `git stash --keep-index` resurrects deleted files.'
32
- )
33
- debug('Deleting the files using `git clean`...')
34
- await execGit(['clean', '--force', ...untrackedFiles.split('\n')])
35
- }
36
- }
37
-
38
21
  const handleError = (error, ctx) => {
39
22
  ctx.gitError = true
40
23
  throw error
@@ -44,6 +27,7 @@ class GitWorkflow {
44
27
  constructor({ allowEmpty, gitConfigDir, gitDir, stagedFileChunks }) {
45
28
  this.execGit = (args, options = {}) => execGit(args, { ...options, cwd: gitDir })
46
29
  this.gitConfigDir = gitConfigDir
30
+ this.gitDir = gitDir
47
31
  this.unstagedDiff = null
48
32
  this.allowEmpty = allowEmpty
49
33
  this.stagedFileChunks = stagedFileChunks
@@ -73,7 +57,7 @@ class GitWorkflow {
73
57
  const resolved = this.getHiddenFilepath(filename)
74
58
  const pathIfExists = await exists(resolved)
75
59
  if (!pathIfExists) return false
76
- const buffer = await readBufferFromFile(pathIfExists)
60
+ const buffer = await readFile(pathIfExists)
77
61
  const patch = buffer.toString().trim()
78
62
  return patch.length ? filename : false
79
63
  }
@@ -97,9 +81,9 @@ class GitWorkflow {
97
81
  async backupMergeStatus() {
98
82
  debug('Backing up merge state...')
99
83
  await Promise.all([
100
- readBufferFromFile(this.mergeHeadFilename).then(buffer => (this.mergeHeadBuffer = buffer)),
101
- readBufferFromFile(this.mergeModeFilename).then(buffer => (this.mergeModeBuffer = buffer)),
102
- readBufferFromFile(this.mergeMsgFilename).then(buffer => (this.mergeMsgBuffer = buffer))
84
+ readFile(this.mergeHeadFilename).then(buffer => (this.mergeHeadBuffer = buffer)),
85
+ readFile(this.mergeModeFilename).then(buffer => (this.mergeModeBuffer = buffer)),
86
+ readFile(this.mergeMsgFilename).then(buffer => (this.mergeMsgBuffer = buffer))
103
87
  ])
104
88
  debug('Done backing up merge state!')
105
89
  }
@@ -111,9 +95,9 @@ class GitWorkflow {
111
95
  debug('Restoring merge state...')
112
96
  try {
113
97
  await Promise.all([
114
- this.mergeHeadBuffer && writeBufferToFile(this.mergeHeadFilename, this.mergeHeadBuffer),
115
- this.mergeModeBuffer && writeBufferToFile(this.mergeModeFilename, this.mergeModeBuffer),
116
- this.mergeMsgBuffer && writeBufferToFile(this.mergeMsgFilename, this.mergeMsgBuffer)
98
+ this.mergeHeadBuffer && writeFile(this.mergeHeadFilename, this.mergeHeadBuffer),
99
+ this.mergeModeBuffer && writeFile(this.mergeModeFilename, this.mergeModeBuffer),
100
+ this.mergeMsgBuffer && writeFile(this.mergeMsgFilename, this.mergeMsgBuffer)
117
101
  ])
118
102
  debug('Done restoring merge state!')
119
103
  } catch (error) {
@@ -123,6 +107,18 @@ class GitWorkflow {
123
107
  }
124
108
  }
125
109
 
110
+ /**
111
+ * List and delete untracked files
112
+ */
113
+ async cleanUntrackedFiles() {
114
+ const lsFiles = await this.execGit(['ls-files', '--others', '--exclude-standard'])
115
+ const untrackedFiles = lsFiles
116
+ .split('\n')
117
+ .filter(Boolean)
118
+ .map(file => path.resolve(this.gitDir, file))
119
+ await Promise.all(untrackedFiles.map(file => unlink(file)))
120
+ }
121
+
126
122
  /**
127
123
  * Create backup stashes, one of everything and one of only staged changes
128
124
  * Staged files are left in the index for running tasks
@@ -135,6 +131,14 @@ class GitWorkflow {
135
131
  // Manually check and backup if necessary
136
132
  await this.backupMergeStatus()
137
133
 
134
+ // Get a list of unstaged deleted files, because certain bugs might cause them to reappear:
135
+ // - in git versions =< 2.13.0 the `--keep-index` flag resurrects deleted files
136
+ // - git stash can't infer RD or MD states correctly, and will lose the deletion
137
+ this.deletedFiles = (await this.execGit(['ls-files', '--deleted']))
138
+ .split('\n')
139
+ .filter(Boolean)
140
+ .map(file => path.resolve(this.gitDir, file))
141
+
138
142
  // Save stash of entire original state, including unstaged and untracked changes.
139
143
  // `--keep-index leaves only staged files on disk, for tasks.`
140
144
  await this.execGit(['stash', 'save', '--include-untracked', '--keep-index', STASH])
@@ -144,7 +148,7 @@ class GitWorkflow {
144
148
 
145
149
  // There is a bug in git =< 2.13.0 where `--keep-index` resurrects deleted files.
146
150
  // These files should be listed and deleted before proceeding.
147
- await cleanUntrackedFiles(this.execGit)
151
+ await this.cleanUntrackedFiles()
148
152
 
149
153
  // Get a diff of unstaged changes by diffing the saved stash against what's left on disk.
150
154
  await this.execGit([
@@ -238,6 +242,9 @@ class GitWorkflow {
238
242
  ctx.gitRestoreUntrackedError = true
239
243
  handleError(error, ctx)
240
244
  }
245
+
246
+ // If stashing resurrected deleted files, clean them out
247
+ await Promise.all(this.deletedFiles.map(file => unlink(file)))
241
248
  }
242
249
 
243
250
  /**
@@ -251,9 +258,13 @@ class GitWorkflow {
251
258
  await this.execGit(['stash', 'apply', '--quiet', '--index', backupStash])
252
259
  debug('Done restoring original state!')
253
260
 
261
+ // If stashing resurrected deleted files, clean them out
262
+ await Promise.all(this.deletedFiles.map(file => unlink(file)))
263
+
254
264
  // Restore meta information about ongoing git merge
255
265
  await this.restoreMergeStatus()
256
266
  } catch (error) {
267
+ ctx.gitRestoreOriginalStateError = true
257
268
  handleError(error, ctx)
258
269
  }
259
270
  }
@@ -278,4 +289,3 @@ class GitWorkflow {
278
289
  }
279
290
 
280
291
  module.exports = GitWorkflow
281
- module.exports.cleanUntrackedFiles = cleanUntrackedFiles
package/lib/index.js CHANGED
@@ -14,7 +14,7 @@ const errConfigNotFound = new Error('Config could not be found')
14
14
  function resolveConfig(configPath) {
15
15
  try {
16
16
  return require.resolve(configPath)
17
- } catch (ignore) {
17
+ } catch {
18
18
  return configPath
19
19
  }
20
20
  }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const resolveTaskFn = require('./resolveTaskFn')
4
+ const { createError } = require('./validateConfig')
4
5
 
5
6
  const debug = require('debug')('lint-staged:make-cmd-tasks')
6
7
 
@@ -15,32 +16,34 @@ const debug = require('debug')('lint-staged:make-cmd-tasks')
15
16
  */
16
17
  module.exports = async function makeCmdTasks({ commands, files, gitDir, shell }) {
17
18
  debug('Creating listr tasks for commands %o', commands)
18
- const commandsArray = Array.isArray(commands) ? commands : [commands]
19
+ const commandArray = Array.isArray(commands) ? commands : [commands]
19
20
  const cmdTasks = []
20
21
 
21
- for (const cmd of commandsArray) {
22
+ for (const cmd of commandArray) {
22
23
  // command function may return array of commands that already include `stagedFiles`
23
24
  const isFn = typeof cmd === 'function'
24
25
  const resolved = isFn ? await cmd(files) : cmd
25
26
 
26
27
  const resolvedArray = Array.isArray(resolved) ? resolved : [resolved] // Wrap non-array command as array
27
28
 
28
- // Function command should not be used as the task title as-is
29
- // because the resolved string it might be very long
30
- // Create a matching command array with [file] in place of file names
31
- let mockCmdTasks
32
- if (isFn) {
33
- const mockFileList = Array(files.length).fill('[file]')
34
- const resolved = await cmd(mockFileList)
35
- mockCmdTasks = Array.isArray(resolved) ? resolved : [resolved]
36
- }
37
-
38
- for (const [i, command] of resolvedArray.entries()) {
29
+ for (const command of resolvedArray) {
39
30
  let title = isFn ? '[Function]' : command
40
- if (isFn && mockCmdTasks[i]) {
41
- // If command is a function, use the matching mock command as title,
42
- // but since might include multiple [file] arguments, shorten to one
43
- title = mockCmdTasks[i].replace(/\[file\].*\[file\]/, '[file]')
31
+
32
+ if (isFn) {
33
+ // If the function linter didn't return string | string[] it won't work
34
+ // Do the validation here instead of `validateConfig` to skip evaluating the function multiple times
35
+ if (typeof command !== 'string') {
36
+ throw new Error(
37
+ createError(
38
+ title,
39
+ 'Function task should return a string or an array of strings',
40
+ resolved
41
+ )
42
+ )
43
+ }
44
+
45
+ const [startOfFn] = command.split(' ')
46
+ title += ` ${startOfFn} ...` // Append function name, like `[Function] eslint ...`
44
47
  }
45
48
 
46
49
  cmdTasks.push({
@@ -1,48 +1,52 @@
1
1
  'use strict'
2
2
 
3
3
  const normalize = require('normalize-path')
4
+ const debugLog = require('debug')('lint-staged:resolveGitRepo')
5
+ const fs = require('fs')
4
6
  const path = require('path')
7
+ const { promisify } = require('util')
5
8
 
6
9
  const execGit = require('./execGit')
7
- const { readBufferFromFile } = require('./file')
10
+ const { readFile } = require('./file')
11
+
12
+ const fsLstat = promisify(fs.lstat)
8
13
 
9
14
  /**
10
15
  * Resolve path to the .git directory, with special handling for
11
- * submodules
16
+ * submodules and worktrees
12
17
  */
13
- const resolveGitConfigDir = async ({ gitDir, isSubmodule }) => {
18
+ const resolveGitConfigDir = async gitDir => {
14
19
  const defaultDir = path.resolve(gitDir, '.git')
15
- if (!isSubmodule) return normalize(defaultDir)
16
-
17
- const buffer = await readBufferFromFile(defaultDir)
18
- const dotGit = buffer.toString()
19
- const gitConfigDir = path.resolve(gitDir, dotGit.replace(/^gitdir: /, '').trim())
20
- return normalize(gitConfigDir)
20
+ const stats = await fsLstat(defaultDir)
21
+ // If .git is a directory, use it
22
+ if (stats.isDirectory()) return defaultDir
23
+ // Otherwise .git is a file containing path to real location
24
+ const file = (await readFile(defaultDir)).toString()
25
+ return path.resolve(gitDir, file.replace(/^gitdir: /, '')).trim()
21
26
  }
22
27
 
23
28
  /**
24
29
  * Resolve git directory and possible submodule paths
25
30
  */
26
- module.exports = async function resolveGitRepo(options = {}) {
31
+ const resolveGitRepo = async cwd => {
27
32
  try {
33
+ debugLog('Resolving git repo from `%s`', cwd)
28
34
  // git cli uses GIT_DIR to fast track its response however it might be set to a different path
29
35
  // depending on where the caller initiated this from, hence clear GIT_DIR
36
+ debugLog('Deleting GIT_DIR from env with value `%s`', process.env.GIT_DIR)
30
37
  delete process.env.GIT_DIR
31
38
 
32
- // The git repo root directory; this points to the root of a submodule instead of the parent
33
- const gitDir = await execGit(['rev-parse', '--show-toplevel'], options)
39
+ const gitDir = normalize(await execGit(['rev-parse', '--show-toplevel'], { cwd }))
40
+ const gitConfigDir = normalize(await resolveGitConfigDir(gitDir))
34
41
 
35
- // A super-project working tree exists only in submodules; poinst to the parent root
36
- const superprojectWorkingTree = await execGit(
37
- ['rev-parse', '--show-superproject-working-tree'],
38
- options
39
- )
42
+ debugLog('Resolved git directory to be `%s`', gitDir)
43
+ debugLog('Resolved git config directory to be `%s`', gitConfigDir)
40
44
 
41
- const isSubmodule = !!superprojectWorkingTree
42
- const gitConfigDir = await resolveGitConfigDir({ gitDir, isSubmodule })
43
-
44
- return { gitDir: normalize(gitDir), gitConfigDir, isSubmodule }
45
+ return { gitDir, gitConfigDir }
45
46
  } catch (error) {
46
- return { error, gitDir: null }
47
+ debugLog('Failed to resolve git repo with error:', error)
48
+ return { error, gitDir: null, gitConfigDir: null }
47
49
  }
48
50
  }
51
+
52
+ module.exports = resolveGitRepo
package/lib/runAll.js CHANGED
@@ -23,6 +23,40 @@ const getRenderer = ({ debug, quiet }) => {
23
23
  return 'update'
24
24
  }
25
25
 
26
+ const MESSAGES = {
27
+ TASK_ERROR: 'Skipped because of errors from tasks.',
28
+ GIT_ERROR: 'Skipped because of previous git error.'
29
+ }
30
+
31
+ const shouldSkipApplyModifications = ctx => {
32
+ // Should be skipped in case of git errors
33
+ if (ctx.gitError) {
34
+ return MESSAGES.GIT_ERROR
35
+ }
36
+ // Should be skipped when tasks fail
37
+ if (ctx.taskError) {
38
+ return MESSAGES.TASK_ERROR
39
+ }
40
+ }
41
+
42
+ const shouldSkipRevert = ctx => {
43
+ // Should be skipped in case of unknown git errors
44
+ if (ctx.gitError && !ctx.gitApplyEmptyCommit && !ctx.gitApplyModificationsError) {
45
+ return MESSAGES.GIT_ERROR
46
+ }
47
+ }
48
+
49
+ const shouldSkipCleanup = ctx => {
50
+ // Should be skipped in case of unknown git errors
51
+ if (ctx.gitError && !ctx.gitApplyEmptyCommit && !ctx.gitApplyModificationsError) {
52
+ return MESSAGES.GIT_ERROR
53
+ }
54
+ // Should be skipped when reverting to original state fails
55
+ if (ctx.gitRestoreOriginalStateError) {
56
+ return MESSAGES.GIT_ERROR
57
+ }
58
+ }
59
+
26
60
  /**
27
61
  * Executes all tasks and either resolves or rejects the promise
28
62
  *
@@ -39,7 +73,7 @@ const getRenderer = ({ debug, quiet }) => {
39
73
  * @param {Logger} logger
40
74
  * @returns {Promise}
41
75
  */
42
- module.exports = async function runAll(
76
+ const runAll = async (
43
77
  {
44
78
  allowEmpty = false,
45
79
  config,
@@ -52,14 +86,11 @@ module.exports = async function runAll(
52
86
  concurrent = true
53
87
  },
54
88
  logger = console
55
- ) {
89
+ ) => {
56
90
  debugLog('Running all linter scripts')
57
91
 
58
- const { gitDir, gitConfigDir, isSubmodule } = await resolveGitRepo({ cwd })
92
+ const { gitDir, gitConfigDir } = await resolveGitRepo(cwd)
59
93
  if (!gitDir) throw new Error('Current directory is not a git directory!')
60
- debugLog('Resolved git directory to be `%s`', gitDir)
61
- debugLog('Resolved git config directory to be `%s`', gitConfigDir)
62
- if (isSubmodule) debugLog('Current git directory is a submodule')
63
94
 
64
95
  const files = await getStagedFiles({ cwd: gitDir })
65
96
  if (!files) throw new Error('Unable to get staged files!')
@@ -130,7 +161,7 @@ module.exports = async function runAll(
130
161
  task: () => new Listr(chunkListrTasks, { ...listrOptions, concurrent }),
131
162
  skip: (ctx = {}) => {
132
163
  // Skip if the first step (backup) failed
133
- if (ctx.gitError) return 'Skipped because of previous git error.'
164
+ if (ctx.gitError) return MESSAGES.GIT_ERROR
134
165
  // Skip chunk when no every task is skipped (due to no matches)
135
166
  if (chunkListrTasks.every(task => task.skip())) return 'No tasks to run.'
136
167
  return false
@@ -154,15 +185,6 @@ module.exports = async function runAll(
154
185
 
155
186
  const git = new GitWorkflow({ allowEmpty, gitConfigDir, gitDir, stagedFileChunks })
156
187
 
157
- // Running git reset or dropping the backup stash should be skipped
158
- // when there are git errors NOT related to applying unstaged modifications.
159
- // In the latter case, the original state is restored.
160
- const cleanupNotSafe = ctx =>
161
- ctx.gitError &&
162
- !ctx.gitApplyEmptyCommit &&
163
- !ctx.gitApplyModificationsError &&
164
- 'Skipped because of previous git error.'
165
-
166
188
  const runner = new Listr(
167
189
  [
168
190
  {
@@ -172,22 +194,19 @@ module.exports = async function runAll(
172
194
  ...listrTasks,
173
195
  {
174
196
  title: 'Applying modifications...',
175
- skip: ctx => {
176
- if (ctx.gitError) return 'Skipped because of previous git error.'
177
- if (ctx.taskError) return 'Skipped because of errors from tasks.'
178
- },
179
- task: ctx => git.applyModifications(ctx)
197
+ task: ctx => git.applyModifications(ctx),
198
+ skip: shouldSkipApplyModifications
180
199
  },
181
200
  {
182
201
  title: 'Reverting to original state...',
202
+ task: ctx => git.restoreOriginalState(ctx),
183
203
  enabled: ctx => ctx.taskError || ctx.gitApplyEmptyCommit || ctx.gitApplyModificationsError,
184
- skip: cleanupNotSafe,
185
- task: ctx => git.restoreOriginalState(ctx)
204
+ skip: shouldSkipRevert
186
205
  },
187
206
  {
188
207
  title: 'Cleaning up...',
189
- skip: cleanupNotSafe,
190
- task: ctx => git.dropBackup(ctx)
208
+ task: ctx => git.dropBackup(ctx),
209
+ skip: shouldSkipCleanup
191
210
  }
192
211
  ],
193
212
  listrOptions
@@ -222,3 +241,11 @@ module.exports = async function runAll(
222
241
  throw error
223
242
  }
224
243
  }
244
+
245
+ module.exports = runAll
246
+
247
+ module.exports.shouldSkip = {
248
+ shouldSkipApplyModifications,
249
+ shouldSkipRevert,
250
+ shouldSkipCleanup
251
+ }
@@ -80,21 +80,6 @@ module.exports = function validateConfig(config) {
80
80
  )
81
81
  )
82
82
  }
83
-
84
- entries.forEach(([, task]) => {
85
- if (typeof task !== 'function') return
86
- const resolved = task(['[filename]'])
87
- if (typeof resolved === 'string') return
88
- if (!Array.isArray(resolved) || resolved.some(subtask => typeof subtask !== 'string')) {
89
- errors.push(
90
- createError(
91
- task,
92
- 'Function task should return a string or an array of strings',
93
- resolved
94
- )
95
- )
96
- }
97
- })
98
83
  })
99
84
  }
100
85
 
@@ -104,3 +89,5 @@ module.exports = function validateConfig(config) {
104
89
 
105
90
  return config
106
91
  }
92
+
93
+ module.exports.createError = createError
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lint-staged",
3
- "version": "10.0.4",
3
+ "version": "10.0.8",
4
4
  "description": "Lint files staged by git",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/okonet/lint-staged",