Skip to content

Commit

Permalink
feat: replace cosmiconfig with lilconfig + yaml to reduce depen…
Browse files Browse the repository at this point in the history
…dencies
  • Loading branch information
iiroj committed Nov 13, 2021
1 parent 08f52f6 commit 56ecc3b
Show file tree
Hide file tree
Showing 13 changed files with 175 additions and 195 deletions.
5 changes: 4 additions & 1 deletion .eslintrc.json
Expand Up @@ -33,7 +33,10 @@
],
"no-console": "off",
"node/no-unsupported-features/es-builtins": "error",
"node/no-unsupported-features/es-syntax": ["error", { "ignores": ["modules"] }],
"node/no-unsupported-features/es-syntax": [
"error",
{ "ignores": ["dynamicImport", "modules"] }
],
"node/no-unsupported-features/node-builtins": "error",
"prettier/prettier": "error"
}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -105,7 +105,7 @@ Starting with v3.1 you can now use different ways of configuring lint-staged:
- `lint-staged.config.js`, `.lintstagedrc.js`, or `.lintstagedrc.cjs` file in JS format
- Pass a configuration file using the `--config` or `-c` flag
See [cosmiconfig](https://github.com/davidtheclark/cosmiconfig) for more details on what formats are supported.
See [lilconfig](https://github.com/antonk52/lilconfig) for more details on what formats are supported.
Configuration should be an object where each value is a command to run and its key is a glob pattern to use for this command. This package uses [micromatch](https://github.com/micromatch/micromatch) for glob patterns.
Expand Down
34 changes: 3 additions & 31 deletions lib/index.js
@@ -1,7 +1,7 @@
import { cosmiconfig } from 'cosmiconfig'
import debug from 'debug'
import inspect from 'object-inspect'

import loadConfig from './loadConfig.js'
import { PREVENTED_EMPTY_COMMIT, GIT_ERROR, RESTORE_STASH_EXAMPLE } from './messages.js'
import { printTaskOutput } from './printTaskOutput.js'
import { runAll } from './runAll.js'
Expand All @@ -16,32 +16,6 @@ import { validateOptions } from './validateOptions.js'

const debugLog = debug('lint-staged')

const resolveConfig = (configPath) => {
try {
return require.resolve(configPath)
} catch {
return configPath
}
}

const loadConfig = (configPath) => {
const explorer = cosmiconfig('lint-staged', {
searchPlaces: [
'package.json',
'.lintstagedrc',
'.lintstagedrc.json',
'.lintstagedrc.yaml',
'.lintstagedrc.yml',
'.lintstagedrc.js',
'.lintstagedrc.cjs',
'lint-staged.config.js',
'lint-staged.config.cjs',
],
})

return configPath ? explorer.load(resolveConfig(configPath)) : explorer.search()
}

/**
* @typedef {(...any) => void} LogFunction
* @typedef {{ error: LogFunction, log: LogFunction, warn: LogFunction }} Logger
Expand Down Expand Up @@ -84,21 +58,19 @@ const lintStaged = async (
) => {
await validateOptions({ shell }, logger)

debugLog('Loading config using `cosmiconfig`')
debugLog('Loading config using `lilconfig`')

const resolved = configObject
? { config: configObject, filepath: '(input)' }
: await loadConfig(configPath)

if (resolved == null) {
if (!resolved) {
logger.error(`${ConfigNotFoundError.message}.`)
throw ConfigNotFoundError
}

debugLog('Successfully loaded config from `%s`:\n%O', resolved.filepath, resolved.config)

// resolved.config is the parsed configuration object
// resolved.filepath is the path to the config file that was found
const config = validateConfig(resolved.config, logger)

if (debug) {
Expand Down
57 changes: 57 additions & 0 deletions lib/loadConfig.js
@@ -0,0 +1,57 @@
import { isAbsolute } from 'path'

import { lilconfig } from 'lilconfig'
import YAML from 'yaml'

/**
* The list of files `lint-staged` will read configuration
* from, in the declared order.
*/
const searchPlaces = [
'package.json',
'.lintstagedrc',
'.lintstagedrc.json',
'.lintstagedrc.yaml',
'.lintstagedrc.yml',
'.lintstagedrc.js',
'.lintstagedrc.cjs',
'lint-staged.config.js',
'lint-staged.config.cjs',
]

/**
* `lilconfig` doesn't support yaml files by default,
* so we add custom loaders for those. Files without
* an extensions are assumed to be yaml — this
* assumption is in `cosmiconfig` as well.
*/
const loaders = { '.yml': YAML.parse, '.yaml': YAML.parse, noExt: YAML.parse }

/**
* Load and parse config from config file, with optional path.
* @param {string} [configPath]
* @returns {Promise<{ config: *; filepath: string } | null>} config
*/
const loadConfig = async (configPath) => {
const isRelativeConfigPath = configPath && !isAbsolute(configPath)

/* Try to import relative filepath as an ESM Module */
if (isRelativeConfigPath) {
try {
const { default: config } = await import(configPath)
return { config, filepath: configPath }
} catch {
/**
* We can safely ignore this error, because it probably means
* `configPath` didn't point to a module and import()
* threw a `MODULE_NOT_FOUND` error. Continue to load it as a
* relative path instead.
*/
}
}

const explorer = lilconfig('lint-staged', { searchPlaces, loaders })
return configPath ? explorer.load(configPath) : explorer.search()
}

export default loadConfig
6 changes: 5 additions & 1 deletion lib/symbols.js
@@ -1,6 +1,10 @@
export const ApplyEmptyCommitError = Symbol('ApplyEmptyCommitError')

export const ConfigNotFoundError = new Error('Config could not be found')
export const ConfigNotFoundError = new Error('Configuration could not be found')

export const ConfigFormatError = new Error('Configuration should be an object or a function')

export const ConfigEmptyError = new Error('Configuration should not be empty')

export const GetBackupStashError = Symbol('GetBackupStashError')

Expand Down
5 changes: 3 additions & 2 deletions lib/validateConfig.js
@@ -1,6 +1,7 @@
import debug from 'debug'

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

const debugLog = debug('lint-staged:validateConfig')
Expand All @@ -27,7 +28,7 @@ export const validateConfig = (config, logger) => {
debugLog('Validating config')

if (!config || (typeof config !== 'object' && typeof config !== 'function')) {
throw new Error('Configuration should be an object or a function!')
throw ConfigFormatError
}

/**
Expand All @@ -42,7 +43,7 @@ export const validateConfig = (config, logger) => {
}

if (Object.entries(config).length === 0) {
throw new Error('Configuration should not be empty!')
throw ConfigEmptyError
}

const errors = []
Expand Down

0 comments on commit 56ecc3b

Please sign in to comment.