UNPKG

1.78 kBJavaScriptView Raw
1import path from 'path'
2
3import debug from 'debug'
4
5import { ConfigObjectSymbol } from './searchConfigs.js'
6
7const debugLog = debug('lint-staged:groupFilesByConfig')
8
9export const groupFilesByConfig = async ({ configs, files }) => {
10 debugLog('Grouping %d files by %d configurations', files.length, Object.keys(configs).length)
11
12 const filesSet = new Set(files)
13 const filesByConfig = {}
14
15 /** Configs are sorted deepest first by `searchConfigs` */
16 for (const filepath of Reflect.ownKeys(configs)) {
17 const config = configs[filepath]
18
19 /** When passed an explicit config object via the Node.js API, skip logic */
20 if (filepath === ConfigObjectSymbol) {
21 filesByConfig[filepath] = { config, files }
22 break
23 }
24
25 const dir = path.normalize(path.dirname(filepath))
26
27 /** Check if file is inside directory of the configuration file */
28 const isInsideDir = (file) => {
29 const relative = path.relative(dir, file)
30 return relative && !relative.startsWith('..') && !path.isAbsolute(relative)
31 }
32
33 /** This config should match all files since it has a parent glob */
34 const includeAllFiles = Object.keys(config).some((glob) => glob.startsWith('..'))
35
36 const scopedFiles = new Set(includeAllFiles ? filesSet : undefined)
37
38 /**
39 * Without a parent glob, if file is inside the config file's directory,
40 * assign it to that configuration.
41 */
42 if (!includeAllFiles) {
43 filesSet.forEach((file) => {
44 if (isInsideDir(file)) {
45 scopedFiles.add(file)
46 }
47 })
48 }
49
50 /** Files should only match a single config */
51 scopedFiles.forEach((file) => {
52 filesSet.delete(file)
53 })
54
55 filesByConfig[filepath] = { config, files: Array.from(scopedFiles) }
56 }
57
58 return filesByConfig
59}