UNPKG

3.22 kBJavaScriptView Raw
1/** @typedef {import('./index').Logger} Logger */
2
3import path from 'path'
4
5import debug from 'debug'
6import objectInspect from 'object-inspect'
7
8import { loadConfig } from './loadConfig.js'
9import { ConfigNotFoundError } from './symbols.js'
10import { validateConfig } from './validateConfig.js'
11
12const debugLog = debug('lint-staged:getConfigGroups')
13
14/**
15 * Return matched files grouped by their configuration.
16 *
17 * @param {object} options
18 * @param {Object} [options.configObject] - Explicit config object from the js API
19 * @param {string} [options.configPath] - Explicit path to a config file
20 * @param {string} [options.cwd] - Current working directory
21 * @param {string} [options.files] - List of staged files
22 * @param {Logger} logger
23 */
24export const getConfigGroups = async (
25 { configObject, configPath, cwd, files },
26 logger = console
27) => {
28 debugLog('Grouping configuration files...')
29
30 // Return explicit config object from js API
31 if (configObject) {
32 debugLog('Using single direct configuration object...')
33
34 const config = validateConfig(configObject, 'config object', logger)
35 return { '': { config, files } }
36 }
37
38 // Use only explicit config path instead of discovering multiple
39 if (configPath) {
40 debugLog('Using single configuration path...')
41
42 const { config, filepath } = await loadConfig({ configPath }, logger)
43
44 if (!config) {
45 logger.error(`${ConfigNotFoundError.message}.`)
46 throw ConfigNotFoundError
47 }
48
49 const validatedConfig = validateConfig(config, filepath, logger)
50 return { [configPath]: { config: validatedConfig, files } }
51 }
52
53 debugLog('Grouping staged files by their directories...')
54
55 // Group files by their base directory
56 const filesByDir = files.reduce((acc, file) => {
57 const dir = path.normalize(path.dirname(file))
58
59 if (dir in acc) {
60 acc[dir].push(file)
61 } else {
62 acc[dir] = [file]
63 }
64
65 return acc
66 }, {})
67
68 debugLog('Grouped staged files into %d directories:', Object.keys(filesByDir).length)
69 debugLog(objectInspect(filesByDir, { indent: 2 }))
70
71 // Group files by their discovered config
72 // { '.lintstagedrc.json': { config: {...}, files: [...] } }
73 const configGroups = {}
74
75 debugLog('Searching config files...')
76
77 const searchConfig = async (cwd, files = []) => {
78 const { config, filepath } = await loadConfig({ cwd }, logger)
79 if (!config) {
80 debugLog('Found no config from "%s"!', cwd)
81 return
82 }
83
84 if (filepath in configGroups) {
85 debugLog('Found existing config "%s" from "%s"!', filepath, cwd)
86 // Re-use cached config and skip validation
87 configGroups[filepath].files.push(...files)
88 } else {
89 debugLog('Found new config "%s" from "%s"!', filepath, cwd)
90
91 const validatedConfig = validateConfig(config, filepath, logger)
92 configGroups[filepath] = { config: validatedConfig, files }
93 }
94 }
95
96 // Start by searching from cwd
97 await searchConfig(cwd)
98
99 // Discover configs from the base directory of each file
100 await Promise.all(Object.entries(filesByDir).map(([dir, files]) => searchConfig(dir, files)))
101
102 debugLog('Grouped staged files into %d groups!', Object.keys(configGroups).length)
103
104 return configGroups
105}