lint-staged 12.3.4 → 12.3.5

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.
@@ -99,13 +99,6 @@ export const getConfigGroups = async (
99
99
  // Discover configs from the base directory of each file
100
100
  await Promise.all(Object.entries(filesByDir).map(([dir, files]) => searchConfig(dir, files)))
101
101
 
102
- // Throw if no configurations were found
103
- if (Object.keys(configGroups).length === 0) {
104
- debugLog('Found no config groups!')
105
- logger.error(`${ConfigNotFoundError.message}.`)
106
- throw ConfigNotFoundError
107
- }
108
-
109
102
  debugLog('Grouped staged files into %d groups!', Object.keys(configGroups).length)
110
103
 
111
104
  return configGroups
@@ -3,6 +3,7 @@ import path from 'path'
3
3
  import normalize from 'normalize-path'
4
4
 
5
5
  import { execGit } from './execGit.js'
6
+ import { parseGitZOutput } from './parseGitZOutput.js'
6
7
 
7
8
  export const getStagedFiles = async ({ cwd = process.cwd() } = {}) => {
8
9
  try {
@@ -14,15 +15,7 @@ export const getStagedFiles = async ({ cwd = process.cwd() } = {}) => {
14
15
 
15
16
  if (!lines) return []
16
17
 
17
- // With `-z`, git prints `fileA\u0000fileB\u0000fileC\u0000` so we need to
18
- // remove the last occurrence of `\u0000` before splitting
19
- return (
20
- lines
21
- // eslint-disable-next-line no-control-regex
22
- .replace(/\u0000$/, '')
23
- .split('\u0000')
24
- .map((file) => normalize(path.resolve(cwd, file)))
25
- )
18
+ return parseGitZOutput(lines).map((file) => normalize(path.resolve(cwd, file)))
26
19
  } catch {
27
20
  return null
28
21
  }
package/lib/loadConfig.js CHANGED
@@ -13,7 +13,7 @@ const debugLog = debug('lint-staged:loadConfig')
13
13
  * The list of files `lint-staged` will read configuration
14
14
  * from, in the declared order.
15
15
  */
16
- const searchPlaces = [
16
+ export const searchPlaces = [
17
17
  'package.json',
18
18
  '.lintstagedrc',
19
19
  '.lintstagedrc.json',
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Return array of strings split from the output of `git <something> -z`.
3
+ * With `-z`, git prints `fileA\u0000fileB\u0000fileC\u0000` so we need to
4
+ * remove the last occurrence of `\u0000` before splitting
5
+ */
6
+ export const parseGitZOutput = (input) =>
7
+ input
8
+ .replace(/\u0000$/, '') // eslint-disable-line no-control-regex
9
+ .split('\u0000')
package/lib/runAll.js CHANGED
@@ -35,7 +35,8 @@ import {
35
35
  restoreOriginalStateSkipped,
36
36
  restoreUnstagedChangesSkipped,
37
37
  } from './state.js'
38
- import { GitRepoError, GetStagedFilesError, GitError } from './symbols.js'
38
+ import { GitRepoError, GetStagedFilesError, GitError, ConfigNotFoundError } from './symbols.js'
39
+ import { searchConfigs } from './searchConfigs.js'
39
40
 
40
41
  const debugLog = debug('lint-staged:runAll')
41
42
 
@@ -121,7 +122,19 @@ export const runAll = async (
121
122
 
122
123
  const configGroups = await getConfigGroups({ configObject, configPath, cwd, files }, logger)
123
124
 
124
- const hasMultipleConfigs = Object.keys(configGroups).length > 1
125
+ const hasExplicitConfig = configObject || configPath
126
+ const foundConfigs = hasExplicitConfig ? null : await searchConfigs(gitDir, logger)
127
+ const numberOfConfigs = hasExplicitConfig ? 1 : Object.keys(foundConfigs).length
128
+
129
+ // Throw if no configurations were found
130
+ if (numberOfConfigs === 0) {
131
+ ctx.errors.add(ConfigNotFoundError)
132
+ throw createError(ctx, ConfigNotFoundError)
133
+ }
134
+
135
+ debugLog('Found %d configs:\n%O', numberOfConfigs, foundConfigs)
136
+
137
+ const hasMultipleConfigs = numberOfConfigs > 1
125
138
 
126
139
  // lint-staged 10 will automatically add modifications to index
127
140
  // Warn user when their command includes `git add`
@@ -0,0 +1,69 @@
1
+ /** @typedef {import('./index').Logger} Logger */
2
+
3
+ import { basename, join } from 'path'
4
+
5
+ import normalize from 'normalize-path'
6
+
7
+ import { execGit } from './execGit.js'
8
+ import { loadConfig, searchPlaces } from './loadConfig.js'
9
+ import { parseGitZOutput } from './parseGitZOutput.js'
10
+ import { validateConfig } from './validateConfig.js'
11
+
12
+ const EXEC_GIT = ['ls-files', '-z', '--full-name']
13
+
14
+ const filterPossibleConfigFiles = (file) => searchPlaces.includes(basename(file))
15
+
16
+ const numberOfLevels = (file) => file.split('/').length
17
+
18
+ const sortDeepestParth = (a, b) => (numberOfLevels(a) > numberOfLevels(b) ? -1 : 1)
19
+
20
+ /**
21
+ * Search all config files from the git repository
22
+ *
23
+ * @param {string} gitDir
24
+ * @param {Logger} logger
25
+ * @returns {Promise<{ [key: string]: * }>} found configs with filepath as key, and config as value
26
+ */
27
+ export const searchConfigs = async (gitDir = process.cwd(), logger) => {
28
+ /** Get all possible config files known to git */
29
+ const cachedFiles = parseGitZOutput(await execGit(EXEC_GIT, { cwd: gitDir })).filter(
30
+ filterPossibleConfigFiles
31
+ )
32
+
33
+ /** Get all possible config files from uncommitted files */
34
+ const otherFiles = parseGitZOutput(
35
+ await execGit([...EXEC_GIT, '--others', '--exclude-standard'], { cwd: gitDir })
36
+ ).filter(filterPossibleConfigFiles)
37
+
38
+ /** Sort possible config files so that deepest is first */
39
+ const possibleConfigFiles = [...cachedFiles, ...otherFiles]
40
+ .map((file) => join(gitDir, file))
41
+ .map((file) => normalize(file))
42
+ .sort(sortDeepestParth)
43
+
44
+ /** Create object with key as config file, and value as null */
45
+ const configs = possibleConfigFiles.reduce(
46
+ (acc, configPath) => Object.assign(acc, { [configPath]: null }),
47
+ {}
48
+ )
49
+
50
+ /** Load and validate all configs to the above object */
51
+ await Promise.all(
52
+ possibleConfigFiles
53
+ .map((configPath) => loadConfig({ configPath }, logger))
54
+ .map((promise) =>
55
+ promise.then(({ config, filepath }) => {
56
+ if (config) {
57
+ configs[filepath] = validateConfig(config, filepath, logger)
58
+ }
59
+ })
60
+ )
61
+ )
62
+
63
+ /** Get validated configs from the above object, without any `null` values (not found) */
64
+ const foundConfigs = Object.entries(configs)
65
+ .filter(([, value]) => !!value)
66
+ .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
67
+
68
+ return foundConfigs
69
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lint-staged",
3
- "version": "12.3.4",
3
+ "version": "12.3.5",
4
4
  "description": "Lint files staged by git",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/okonet/lint-staged",