Skip to content

Commit

Permalink
perf: use lilconfig only when searching for config files outside git …
Browse files Browse the repository at this point in the history
…repo
  • Loading branch information
iiroj committed Dec 2, 2023
1 parent 934ce5c commit 777d4e9
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changeset/selfish-pillows-remember.md
@@ -0,0 +1,5 @@
---
'lint-staged': patch
---

To improve performance, only use `lilconfig` when searching for config files outside the git repo. In the regular case, _lint-staged_ finds the config files from the Git index and loads them directly.
45 changes: 36 additions & 9 deletions lib/loadConfig.js
@@ -1,9 +1,9 @@
/** @typedef {import('./index').Logger} Logger */

import fs from 'node:fs/promises'
import path from 'node:path'

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

import { dynamicImport } from './dynamicImport.js'
Expand Down Expand Up @@ -37,8 +37,10 @@ export const searchPlaces = [
]

const jsonParse = (filePath, content) => {
const isPackageFile = PACKAGE_JSON_FILE.includes(path.basename(filePath))
try {
return JSON.parse(content)
const json = JSON.parse(content)
return isPackageFile ? json[CONFIG_NAME] : json
} catch (error) {
if (path.basename(filePath) === PACKAGE_JSON_FILE) {
debugLog('Ignoring invalid package file `%s` with content:\n%s', filePath, content)
Expand All @@ -64,6 +66,8 @@ const yamlParse = (filePath, content) => {
}
}

const NO_EXT = 'noExt'

/**
* `lilconfig` doesn't support yaml files by default,
* so we add custom loaders for those. Files without
Expand All @@ -77,10 +81,31 @@ const loaders = {
'.cjs': dynamicImport,
'.yaml': yamlParse,
'.yml': yamlParse,
noExt: yamlParse,
[NO_EXT]: yamlParse,
}

const readFile = async (filepath) => {
const absolutePath = path.resolve(filepath)
const file = await fs.readFile(absolutePath)
return await file.toString()
}

const explorer = lilconfig(CONFIG_NAME, { searchPlaces, loaders })
const loadConfigByExt = async (filepath) => {
filepath = path.resolve(filepath)
const ext = path.extname(filepath) || NO_EXT
const loader = loaders[ext]

/**
* No need to read file contents when loader only takes in the filepath argument
* and reads itself; this is for `lilconfig` compatibility
*/
const content = loader.length > 1 ? await readFile(filepath) : undefined

return {
config: await loader(filepath, content),
filepath,
}
}

/**
* @param {object} options
Expand All @@ -89,20 +114,22 @@ const explorer = lilconfig(CONFIG_NAME, { searchPlaces, loaders })
*/
export const loadConfig = async ({ configPath, cwd }, logger) => {
try {
let result

if (configPath) {
debugLog('Loading configuration from `%s`...', configPath)
result = await loadConfigByExt(resolveConfig(configPath))
} else {
debugLog('Searching for configuration from `%s`...', cwd)
const { lilconfig } = await import('lilconfig')
const explorer = lilconfig(CONFIG_NAME, { searchPlaces, loaders })
result = await explorer.search(cwd)
}

const result = await (configPath
? explorer.load(resolveConfig(configPath))
: explorer.search(cwd))

if (!result) return {}

// config is a promise when using the `dynamicImport` loader
const config = await result.config
const config = (await result.config) ?? null
const filepath = result.filepath

debugLog('Successfully loaded config from `%s`:\n%O', filepath, config)
Expand Down
2 changes: 1 addition & 1 deletion test/unit/loadConfig.spec.js
Expand Up @@ -286,7 +286,7 @@ describe('loadConfig', () => {

const { config } = await loadConfig({ configPath: configFile }, logger)

expect(config).toBeUndefined()
expect(config).toBeNull()

await fs.rm(configFile)
})
Expand Down

0 comments on commit 777d4e9

Please sign in to comment.