You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			252 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			JavaScript
		
	
			
		
		
	
	
			252 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			JavaScript
		
	
"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}rc.cjs`,
 | 
						|
        `.config/${name}rc`,
 | 
						|
        `.config/${name}rc.json`,
 | 
						|
        `.config/${name}rc.js`,
 | 
						|
        `.config/${name}rc.cjs`,
 | 
						|
        `${name}.config.js`,
 | 
						|
        `${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(sp => acc.push({
 | 
						|
            searchPlace: sp,
 | 
						|
            filepath: path.join(searchPath, sp),
 | 
						|
            loaderKey: path.extname(sp) || '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 { searchPlace, filepath, loaderKey } of searchItems) {
 | 
						|
                try {
 | 
						|
                    await fs.promises.access(filepath);
 | 
						|
                }
 | 
						|
                catch (_a) {
 | 
						|
                    continue;
 | 
						|
                }
 | 
						|
                const content = String(await fsReadFileAsync(filepath));
 | 
						|
                const loader = loaders[loaderKey];
 | 
						|
                if (searchPlace === 'package.json') {
 | 
						|
                    const pkg = await 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 = await 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 { searchPlace, filepath, loaderKey } of searchItems) {
 | 
						|
                try {
 | 
						|
                    fs.accessSync(filepath);
 | 
						|
                }
 | 
						|
                catch (_a) {
 | 
						|
                    continue;
 | 
						|
                }
 | 
						|
                const loader = loaders[loaderKey];
 | 
						|
                const content = String(fs.readFileSync(filepath));
 | 
						|
                if (searchPlace === '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;
 |