Skip to content

Commit b3f63ec

Browse files
committed
fix: correctly handle symlinked config files
1 parent 8be800f commit b3f63ec

File tree

3 files changed

+41
-23
lines changed

3 files changed

+41
-23
lines changed

lib/searchConfigs.js

+21-20
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ const debugLog = debug('lint-staged:searchConfigs')
1414

1515
const EXEC_GIT = ['ls-files', '-z', '--full-name']
1616

17-
const filterPossibleConfigFiles = (file) => searchPlaces.includes(basename(file))
17+
const filterPossibleConfigFiles = (files) =>
18+
files.filter((file) => searchPlaces.includes(basename(file)))
1819

1920
const numberOfLevels = (file) => file.split('/').length
2021

@@ -58,20 +59,18 @@ export const searchConfigs = async (
5859
return { [configPath]: validateConfig(config, filepath, logger) }
5960
}
6061

61-
/** Get all possible config files known to git */
62-
const cachedFiles = parseGitZOutput(await execGit(EXEC_GIT, { cwd: gitDir })).filter(
63-
filterPossibleConfigFiles
64-
)
65-
66-
/** Get all possible config files from uncommitted files */
67-
const otherFiles = parseGitZOutput(
68-
await execGit([...EXEC_GIT, '--others', '--exclude-standard'], { cwd: gitDir })
69-
).filter(filterPossibleConfigFiles)
62+
const [cachedFiles, otherFiles] = await Promise.all([
63+
/** Get all possible config files known to git */
64+
execGit(EXEC_GIT, { cwd: gitDir }).then(parseGitZOutput).then(filterPossibleConfigFiles),
65+
/** Get all possible config files from uncommitted files */
66+
execGit([...EXEC_GIT, '--others', '--exclude-standard'], { cwd: gitDir })
67+
.then(parseGitZOutput)
68+
.then(filterPossibleConfigFiles),
69+
])
7070

7171
/** Sort possible config files so that deepest is first */
7272
const possibleConfigFiles = [...cachedFiles, ...otherFiles]
73-
.map((file) => join(gitDir, file))
74-
.map((file) => normalize(file))
73+
.map((file) => normalize(join(gitDir, file)))
7574
.filter(isInsideDirectory(cwd))
7675
.sort(sortDeepestParth)
7776

@@ -85,15 +84,17 @@ export const searchConfigs = async (
8584

8685
/** Load and validate all configs to the above object */
8786
await Promise.all(
88-
possibleConfigFiles
89-
.map((configPath) => loadConfig({ configPath }, logger))
90-
.map((promise) =>
91-
promise.then(({ config, filepath }) => {
92-
if (config) {
93-
configs[filepath] = validateConfig(config, filepath, logger)
87+
Object.keys(configs).map((configPath) =>
88+
loadConfig({ configPath }, logger).then(({ config, filepath }) => {
89+
if (config) {
90+
if (configPath !== filepath) {
91+
debugLog('Config file "%s" resolved to "%s"', configPath, filepath)
9492
}
95-
})
96-
)
93+
94+
configs[configPath] = validateConfig(config, filepath, logger)
95+
}
96+
})
97+
)
9798
)
9899

99100
/** Get validated configs from the above object, without any `null` values (not found) */

test/integration.test.js

+16
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,22 @@ describe('lint-staged', () => {
12321232
expect(await readFile('a/very/deep/file/path/file.js')).toEqual('')
12331233
})
12341234

1235+
it('should work with symlinked config file', async () => {
1236+
await appendFile('test.js', testJsFileUgly)
1237+
1238+
await writeFile('.config/.lintstagedrc.json', JSON.stringify(fixJsConfig.config))
1239+
await fs.ensureSymlink(
1240+
path.join(cwd, '.config/.lintstagedrc.json'),
1241+
path.join(cwd, '.lintstagedrc.json')
1242+
)
1243+
1244+
await execGit(['add', '.'])
1245+
1246+
await gitCommit()
1247+
1248+
expect(await readFile('test.js')).toEqual(testJsFilePretty) // file was fixed
1249+
})
1250+
12351251
it('should support parent globs', async () => {
12361252
// Add some empty files
12371253
await writeFile('file.js', '')

test/searchConfigs.spec.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -78,17 +78,18 @@ describe('searchConfigs', () => {
7878
})
7979

8080
it('should return config found from git', async () => {
81-
const configPath = '.lintstagedrc.json'
81+
const configFile = '.lintstagedrc.json'
82+
const configPath = normalize(path.join(process.cwd(), configFile))
8283
const config = { '*.js': 'eslint' }
8384

84-
execGit.mockResolvedValueOnce(`${configPath}\u0000`)
85+
execGit.mockResolvedValueOnce(`${configFile}\u0000`)
8586
loadConfig.mockResolvedValueOnce({ config, filepath: configPath })
8687

8788
await expect(searchConfigs({})).resolves.toEqual({ [configPath]: config })
8889
})
8990

9091
it('should return auto-discovered config from cwd when not found from git', async () => {
91-
const configPath = '.lintstagedrc.json'
92+
const configPath = normalize(path.join(process.cwd(), '.lintstagedrc.json'))
9293
const config = { '*.js': 'eslint' }
9394

9495
loadConfig.mockResolvedValueOnce({ config, filepath: configPath })

0 commit comments

Comments
 (0)