| "use strict"; |
| Object.defineProperty(exports, "__esModule", { value: true }); |
| exports.lilconfigSync = exports.lilconfig = exports.defaultLoaders = void 0; |
| const path = require("path"); |
| const fs = require("fs"); |
| const os = require("os"); |
| const fsReadFileAsync = fs.promises.readFile; |
| function getDefaultSearchPlaces(name) { |
| return [ |
| 'package.json', |
| `.${name}rc.json`, |
| `.${name}rc.js`, |
| `${name}.config.js`, |
| `.${name}rc.cjs`, |
| `${name}.config.cjs`, |
| ]; |
| } |
| function getSearchPaths(startDir, stopDir) { |
| return startDir |
| .split(path.sep) |
| .reduceRight((acc, _, ind, arr) => { |
| const currentPath = arr.slice(0, ind + 1).join(path.sep); |
| if (!acc.passedStopDir) |
| acc.searchPlaces.push(currentPath || path.sep); |
| if (currentPath === stopDir) |
| acc.passedStopDir = true; |
| return acc; |
| }, { searchPlaces: [], passedStopDir: false }).searchPlaces; |
| } |
| exports.defaultLoaders = Object.freeze({ |
| '.js': require, |
| '.json': require, |
| '.cjs': require, |
| noExt(_, content) { |
| return JSON.parse(content); |
| }, |
| }); |
| function getExtDesc(ext) { |
| return ext === 'noExt' ? 'files without extensions' : `extension "${ext}"`; |
| } |
| function getOptions(name, options = {}) { |
| const conf = { |
| stopDir: os.homedir(), |
| searchPlaces: getDefaultSearchPlaces(name), |
| ignoreEmptySearchPlaces: true, |
| transform: (x) => x, |
| packageProp: [name], |
| ...options, |
| loaders: { ...exports.defaultLoaders, ...options.loaders }, |
| }; |
| conf.searchPlaces.forEach(place => { |
| const key = path.extname(place) || 'noExt'; |
| const loader = conf.loaders[key]; |
| if (!loader) { |
| throw new Error(`No loader specified for ${getExtDesc(key)}, so searchPlaces item "${place}" is invalid`); |
| } |
| if (typeof loader !== 'function') { |
| throw new Error(`loader for ${getExtDesc(key)} is not a function (type provided: "${typeof loader}"), so searchPlaces item "${place}" is invalid`); |
| } |
| }); |
| return conf; |
| } |
| function getPackageProp(props, obj) { |
| if (typeof props === 'string' && props in obj) |
| return obj[props]; |
| return ((Array.isArray(props) ? props : props.split('.')).reduce((acc, prop) => (acc === undefined ? acc : acc[prop]), obj) || null); |
| } |
| function getSearchItems(searchPlaces, searchPaths) { |
| return searchPaths.reduce((acc, searchPath) => { |
| searchPlaces.forEach(fileName => acc.push({ |
| fileName, |
| filepath: path.join(searchPath, fileName), |
| loaderKey: path.extname(fileName) || 'noExt', |
| })); |
| return acc; |
| }, []); |
| } |
| function validateFilePath(filepath) { |
| if (!filepath) |
| throw new Error('load must pass a non-empty string'); |
| } |
| function validateLoader(loader, ext) { |
| if (!loader) |
| throw new Error(`No loader specified for extension "${ext}"`); |
| if (typeof loader !== 'function') |
| throw new Error('loader is not a function'); |
| } |
| function lilconfig(name, options) { |
| const { ignoreEmptySearchPlaces, loaders, packageProp, searchPlaces, stopDir, transform, } = getOptions(name, options); |
| return { |
| async search(searchFrom = process.cwd()) { |
| const searchPaths = getSearchPaths(searchFrom, stopDir); |
| const result = { |
| config: null, |
| filepath: '', |
| }; |
| const searchItems = getSearchItems(searchPlaces, searchPaths); |
| for (const { fileName, filepath, loaderKey } of searchItems) { |
| try { |
| await fs.promises.access(filepath); |
| } |
| catch (_a) { |
| continue; |
| } |
| const content = String(await fsReadFileAsync(filepath)); |
| const loader = loaders[loaderKey]; |
| if (fileName === 'package.json') { |
| const pkg = loader(filepath, content); |
| const maybeConfig = getPackageProp(packageProp, pkg); |
| if (maybeConfig != null) { |
| result.config = maybeConfig; |
| result.filepath = filepath; |
| break; |
| } |
| continue; |
| } |
| const isEmpty = content.trim() === ''; |
| if (isEmpty && ignoreEmptySearchPlaces) |
| continue; |
| if (isEmpty) { |
| result.isEmpty = true; |
| result.config = undefined; |
| } |
| else { |
| validateLoader(loader, loaderKey); |
| result.config = loader(filepath, content); |
| } |
| result.filepath = filepath; |
| break; |
| } |
| if (result.filepath === '' && result.config === null) |
| return transform(null); |
| return transform(result); |
| }, |
| async load(filepath) { |
| validateFilePath(filepath); |
| const absPath = path.resolve(process.cwd(), filepath); |
| const { base, ext } = path.parse(absPath); |
| const loaderKey = ext || 'noExt'; |
| const loader = loaders[loaderKey]; |
| validateLoader(loader, loaderKey); |
| const content = String(await fsReadFileAsync(absPath)); |
| if (base === 'package.json') { |
| const pkg = await loader(absPath, content); |
| return transform({ |
| config: getPackageProp(packageProp, pkg), |
| filepath: absPath, |
| }); |
| } |
| const result = { |
| config: null, |
| filepath: absPath, |
| }; |
| const isEmpty = content.trim() === ''; |
| if (isEmpty && ignoreEmptySearchPlaces) |
| return transform({ |
| config: undefined, |
| filepath: absPath, |
| isEmpty: true, |
| }); |
| result.config = isEmpty |
| ? undefined |
| : await loader(absPath, content); |
| return transform(isEmpty ? { ...result, isEmpty, config: undefined } : result); |
| }, |
| }; |
| } |
| exports.lilconfig = lilconfig; |
| function lilconfigSync(name, options) { |
| const { ignoreEmptySearchPlaces, loaders, packageProp, searchPlaces, stopDir, transform, } = getOptions(name, options); |
| return { |
| search(searchFrom = process.cwd()) { |
| const searchPaths = getSearchPaths(searchFrom, stopDir); |
| const result = { |
| config: null, |
| filepath: '', |
| }; |
| const searchItems = getSearchItems(searchPlaces, searchPaths); |
| for (const { fileName, filepath, loaderKey } of searchItems) { |
| try { |
| fs.accessSync(filepath); |
| } |
| catch (_a) { |
| continue; |
| } |
| const loader = loaders[loaderKey]; |
| const content = String(fs.readFileSync(filepath)); |
| if (fileName === 'package.json') { |
| const pkg = loader(filepath, content); |
| const maybeConfig = getPackageProp(packageProp, pkg); |
| if (maybeConfig != null) { |
| result.config = maybeConfig; |
| result.filepath = filepath; |
| break; |
| } |
| continue; |
| } |
| const isEmpty = content.trim() === ''; |
| if (isEmpty && ignoreEmptySearchPlaces) |
| continue; |
| if (isEmpty) { |
| result.isEmpty = true; |
| result.config = undefined; |
| } |
| else { |
| validateLoader(loader, loaderKey); |
| result.config = loader(filepath, content); |
| } |
| result.filepath = filepath; |
| break; |
| } |
| if (result.filepath === '' && result.config === null) |
| return transform(null); |
| return transform(result); |
| }, |
| load(filepath) { |
| validateFilePath(filepath); |
| const absPath = path.resolve(process.cwd(), filepath); |
| const { base, ext } = path.parse(absPath); |
| const loaderKey = ext || 'noExt'; |
| const loader = loaders[loaderKey]; |
| validateLoader(loader, loaderKey); |
| const content = String(fs.readFileSync(absPath)); |
| if (base === 'package.json') { |
| const pkg = loader(absPath, content); |
| return transform({ |
| config: getPackageProp(packageProp, pkg), |
| filepath: absPath, |
| }); |
| } |
| const result = { |
| config: null, |
| filepath: absPath, |
| }; |
| const isEmpty = content.trim() === ''; |
| if (isEmpty && ignoreEmptySearchPlaces) |
| return transform({ |
| filepath: absPath, |
| config: undefined, |
| isEmpty: true, |
| }); |
| result.config = isEmpty ? undefined : loader(absPath, content); |
| return transform(isEmpty ? { ...result, isEmpty, config: undefined } : result); |
| }, |
| }; |
| } |
| exports.lilconfigSync = lilconfigSync; |