Skip to content

Commit

Permalink
fix: improve error logging when failing to parse config file (#1423)
Browse files Browse the repository at this point in the history
  • Loading branch information
iiroj committed May 25, 2024
1 parent 31a1f95 commit 91abea0
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/smart-pets-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'lint-staged': patch
---

Improve error logging when failing to read or parse a configuration file
5 changes: 3 additions & 2 deletions lib/loadConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import debug from 'debug'
import YAML from 'yaml'

import { dynamicImport } from './dynamicImport.js'
import { failedToLoadConfig } from './messages.js'
import { resolveConfig } from './resolveConfig.js'
import {
CONFIG_FILE_NAMES,
Expand Down Expand Up @@ -117,8 +118,8 @@ export const loadConfig = async ({ configPath, cwd }, logger) => {

return { config, filepath }
} catch (error) {
debugLog('Failed to load configuration!')
logger.error(error)
debugLog('Failed to load configuration from `%s` with error:\n', configPath, error)
logger.error(failedToLoadConfig(configPath))
return {}
}
}
12 changes: 12 additions & 0 deletions lib/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,15 @@ export const RESTORE_STASH_EXAMPLE = ` Any lost modifications can be restored f
`

export const CONFIG_STDIN_ERROR = chalk.redBright(`${error} Failed to read config from stdin.`)

export const failedToLoadConfig = (filepath) =>
chalk.redBright(`${error} Failed to read config from file "${filepath}".`)

export const failedToParseConfig = (
filepath,
error
) => `${chalk.redBright(`${error} Failed to parse config from file "${filepath}".`)}
${error}
See https://github.com/okonet/lint-staged#configuration.`
33 changes: 19 additions & 14 deletions lib/validateConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { inspect } from 'node:util'

import debug from 'debug'

import { configurationError } from './messages.js'
import { configurationError, failedToParseConfig } from './messages.js'
import { ConfigEmptyError, ConfigFormatError } from './symbols.js'
import { validateBraces } from './validateBraces.js'

Expand All @@ -23,14 +23,7 @@ const TEST_DEPRECATED_KEYS = new Map([
['relative', (key) => typeof key === 'boolean'],
])

/**
* Runs config validation. Throws error if the config is not valid.
* @param {Object} config
* @param {string} configPath
* @param {Logger} logger
* @returns {Object} config
*/
export const validateConfig = (config, configPath, logger) => {
export const validateConfigLogic = (config, configPath, logger) => {
debugLog('Validating config from `%s`...', configPath)

if (!config || (typeof config !== 'object' && typeof config !== 'function')) {
Expand Down Expand Up @@ -100,11 +93,7 @@ export const validateConfig = (config, configPath, logger) => {
if (errors.length) {
const message = errors.join('\n\n')

logger.error(`Could not parse lint-staged config.
${message}
See https://github.com/okonet/lint-staged#configuration.`)
logger.error(failedToParseConfig(configPath, message))

throw new Error(message)
}
Expand All @@ -114,3 +103,19 @@ See https://github.com/okonet/lint-staged#configuration.`)

return validatedConfig
}

/**
* Runs config validation. Throws error if the config is not valid.
* @param {Object} config
* @param {string} configPath
* @param {Logger} logger
* @returns {Object} config
*/
export const validateConfig = (config, configPath, logger) => {
try {
return validateConfigLogic(config, configPath, logger)
} catch (error) {
logger.error(failedToParseConfig(configPath, error))
throw error
}
}
145 changes: 144 additions & 1 deletion test/unit/__snapshots__/validateConfig.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,153 @@ exports[`validateConfig should throw when detecting deprecated advanced configur

exports[`validateConfig should throw when detecting deprecated advanced configuration 2`] = `
"
ERROR Could not parse lint-staged config.
ERROR βœ– Validation Error:
Invalid value for 'chunkSize': 10
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'concurrent': false
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'globOptions': { matchBase: false }
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'ignore': [ 'test.js' ]
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'linters': { '*.js': [ 'eslint' ] }
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'relative': true
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'renderer': 'silent'
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'subTaskConcurrency': 10
Advanced configuration has been deprecated. Failed to parse config from file ".lintstagedrc.json".
βœ– Validation Error:
Invalid value for 'chunkSize': 10
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'concurrent': false
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'globOptions': { matchBase: false }
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'ignore': [ 'test.js' ]
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'linters': { '*.js': [ 'eslint' ] }
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'relative': true
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'renderer': 'silent'
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'subTaskConcurrency': 10
Advanced configuration has been deprecated.
See https://github.com/okonet/lint-staged#configuration.
ERROR Error: βœ– Validation Error:
Invalid value for 'chunkSize': 10
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'concurrent': false
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'globOptions': { matchBase: false }
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'ignore': [ 'test.js' ]
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'linters': { '*.js': [ 'eslint' ] }
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'relative': true
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'renderer': 'silent'
Advanced configuration has been deprecated.
βœ– Validation Error:
Invalid value for 'subTaskConcurrency': 10
Advanced configuration has been deprecated. Failed to parse config from file ".lintstagedrc.json".
Error: βœ– Validation Error:
Invalid value for 'chunkSize': 10
Advanced configuration has been deprecated.
Expand Down
4 changes: 3 additions & 1 deletion test/unit/loadConfig.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@ describe('loadConfig', () => {
})

it('should not return config when YAML config file is invalid', async () => {
expect.assertions(1)
expect.assertions(2)

const { config } = await loadConfig(
{ configPath: path.join(__dirname, '__mocks__', 'invalid-config-file.yml') },
logger
)

expect(logger.printHistory()).toMatch('Failed to read config from file')

expect(config).toBeUndefined()
})

Expand Down

0 comments on commit 91abea0

Please sign in to comment.