Skip to content

Commit

Permalink
fix: always search config from cwd first
Browse files Browse the repository at this point in the history
  • Loading branch information
iiroj committed Jan 20, 2022
1 parent 36b9546 commit 4afcda5
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 19 deletions.
41 changes: 23 additions & 18 deletions lib/getConfigGroups.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ import { validateConfig } from './validateConfig.js'
* @param {Object} [options.configObject] - Explicit config object from the js API
* @param {string} [options.configPath] - Explicit path to a config file
* @param {string} [options.cwd] - Current working directory
* @param {string} [options.files] - List of staged files
* @param {Logger} logger
*/
export const getConfigGroups = async ({ configObject, configPath, files }, logger = console) => {
export const getConfigGroups = async (
{ configObject, configPath, cwd, files },
logger = console
) => {
// Return explicit config object from js API
if (configObject) {
const config = validateConfig(configObject, 'config object', logger)
Expand Down Expand Up @@ -52,23 +56,24 @@ export const getConfigGroups = async ({ configObject, configPath, files }, logge
// { '.lintstagedrc.json': { config: {...}, files: [...] } }
const configGroups = {}

await Promise.all(
Object.entries(filesByDir).map(([dir, files]) => {
// Discover config from the base directory of the file
return loadConfig({ cwd: dir }, logger).then(({ config, filepath }) => {
if (!config) return

if (filepath in configGroups) {
// Re-use cached config and skip validation
configGroups[filepath].files.push(...files)
return
}

const validatedConfig = validateConfig(config, filepath, logger)
configGroups[filepath] = { config: validatedConfig, files }
})
})
)
const searchConfig = async (cwd, files = []) => {
const { config, filepath } = await loadConfig({ cwd }, logger)
if (!config) return

if (filepath in configGroups) {
// Re-use cached config and skip validation
configGroups[filepath].files.push(...files)
} else {
const validatedConfig = validateConfig(config, filepath, logger)
configGroups[filepath] = { config: validatedConfig, files }
}
}

// Start by searching from cwd
await searchConfig(cwd)

// Discover configs from the base directory of each file
await Promise.all(Object.entries(filesByDir).map(([dir, files]) => searchConfig(dir, files)))

// Throw if no configurations were found
if (Object.keys(configGroups).length === 0) {
Expand Down
2 changes: 1 addition & 1 deletion lib/runAll.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export const runAll = async (
return ctx
}

const configGroups = await getConfigGroups({ configObject, configPath, files }, logger)
const configGroups = await getConfigGroups({ configObject, configPath, cwd, files }, logger)

// lint-staged 10 will automatically add modifications to index
// Warn user when their command includes `git add`
Expand Down
4 changes: 4 additions & 0 deletions test/getConfigGroups.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ describe('getConfigGroups', () => {
})

it('should find config files for all staged files', async () => {
// Base cwd
loadConfig.mockResolvedValueOnce({ config, filepath: '/.lintstagedrc.json' })
// '/foo.js' and '/bar.js'
loadConfig.mockResolvedValueOnce({ config, filepath: '/.lintstagedrc.json' })
// '/deeper/foo.js'
Expand All @@ -55,6 +57,8 @@ describe('getConfigGroups', () => {
})

it('should find config for one file, and not care about other', async () => {
// Base cwd
loadConfig.mockResolvedValueOnce({})
// '/foo.js'
loadConfig.mockResolvedValueOnce({})
// '/deeper/foo.js'
Expand Down
29 changes: 29 additions & 0 deletions test/integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,35 @@ describe('lint-staged', () => {
// 'a/very/deep/file/path/file.js' matched '.lintstagedrc.json'
expect(await readFile('a/very/deep/file/path/file.js')).toMatch('level-0')
})

it('should not care about staged file outside current cwd with another staged file', async () => {
await writeFile('file.js', testJsFileUgly)
await writeFile('deeper/file.js', testJsFileUgly)
await writeFile('deeper/.lintstagedrc.json', JSON.stringify(fixJsConfig.config))
await execGit(['add', '.'])

// Run lint-staged in "deeper/""
expect(await gitCommit({ cwd: path.join(cwd, 'deeper') })).resolves

// File inside deeper/ was fixed
expect(await readFile('deeper/file.js')).toEqual(testJsFilePretty)
// ...but file outside was not
expect(await readFile('file.js')).toEqual(testJsFileUgly)
})

it('should not care about staged file outside current cwd without any other staged files', async () => {
await writeFile('file.js', testJsFileUgly)
await writeFile('deeper/.lintstagedrc.json', JSON.stringify(fixJsConfig.config))
await execGit(['add', '.'])

// Run lint-staged in "deeper/""
expect(await gitCommit({ cwd: path.join(cwd, 'deeper') })).resolves

expect(console.printHistory()).toMatch('No staged files match any configured task')

// File outside deeper/ was not fixed
expect(await readFile('file.js')).toEqual(testJsFileUgly)
})
})

describe('lintStaged', () => {
Expand Down

0 comments on commit 4afcda5

Please sign in to comment.