Skip to content

Commit

Permalink
fix: correctly handle symlinked config files
Browse files Browse the repository at this point in the history
  • Loading branch information
iiroj committed Apr 26, 2022
1 parent 8be800f commit b3f63ec
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 23 deletions.
41 changes: 21 additions & 20 deletions lib/searchConfigs.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const debugLog = debug('lint-staged:searchConfigs')

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

const filterPossibleConfigFiles = (file) => searchPlaces.includes(basename(file))
const filterPossibleConfigFiles = (files) =>
files.filter((file) => searchPlaces.includes(basename(file)))

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

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

/** Get all possible config files known to git */
const cachedFiles = parseGitZOutput(await execGit(EXEC_GIT, { cwd: gitDir })).filter(
filterPossibleConfigFiles
)

/** Get all possible config files from uncommitted files */
const otherFiles = parseGitZOutput(
await execGit([...EXEC_GIT, '--others', '--exclude-standard'], { cwd: gitDir })
).filter(filterPossibleConfigFiles)
const [cachedFiles, otherFiles] = await Promise.all([
/** Get all possible config files known to git */
execGit(EXEC_GIT, { cwd: gitDir }).then(parseGitZOutput).then(filterPossibleConfigFiles),
/** Get all possible config files from uncommitted files */
execGit([...EXEC_GIT, '--others', '--exclude-standard'], { cwd: gitDir })
.then(parseGitZOutput)
.then(filterPossibleConfigFiles),
])

/** Sort possible config files so that deepest is first */
const possibleConfigFiles = [...cachedFiles, ...otherFiles]
.map((file) => join(gitDir, file))
.map((file) => normalize(file))
.map((file) => normalize(join(gitDir, file)))
.filter(isInsideDirectory(cwd))
.sort(sortDeepestParth)

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

/** Load and validate all configs to the above object */
await Promise.all(
possibleConfigFiles
.map((configPath) => loadConfig({ configPath }, logger))
.map((promise) =>
promise.then(({ config, filepath }) => {
if (config) {
configs[filepath] = validateConfig(config, filepath, logger)
Object.keys(configs).map((configPath) =>
loadConfig({ configPath }, logger).then(({ config, filepath }) => {
if (config) {
if (configPath !== filepath) {
debugLog('Config file "%s" resolved to "%s"', configPath, filepath)
}
})
)

configs[configPath] = validateConfig(config, filepath, logger)
}
})
)
)

/** Get validated configs from the above object, without any `null` values (not found) */
Expand Down
16 changes: 16 additions & 0 deletions test/integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,22 @@ describe('lint-staged', () => {
expect(await readFile('a/very/deep/file/path/file.js')).toEqual('')
})

it('should work with symlinked config file', async () => {
await appendFile('test.js', testJsFileUgly)

await writeFile('.config/.lintstagedrc.json', JSON.stringify(fixJsConfig.config))
await fs.ensureSymlink(
path.join(cwd, '.config/.lintstagedrc.json'),
path.join(cwd, '.lintstagedrc.json')
)

await execGit(['add', '.'])

await gitCommit()

expect(await readFile('test.js')).toEqual(testJsFilePretty) // file was fixed
})

it('should support parent globs', async () => {
// Add some empty files
await writeFile('file.js', '')
Expand Down
7 changes: 4 additions & 3 deletions test/searchConfigs.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,18 @@ describe('searchConfigs', () => {
})

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

execGit.mockResolvedValueOnce(`${configPath}\u0000`)
execGit.mockResolvedValueOnce(`${configFile}\u0000`)
loadConfig.mockResolvedValueOnce({ config, filepath: configPath })

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

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

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

0 comments on commit b3f63ec

Please sign in to comment.