Socket
Socket
Sign inDemoInstall

cosmiconfig

Package Overview
Dependencies
17
Maintainers
2
Versions
56
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 8.3.6 to 9.0.0-alpha.0

dist/cacheWrapper.d.ts

87

dist/Explorer.js

@@ -10,4 +10,6 @@ "use strict";

const path_type_1 = require("path-type");
const defaults_1 = require("./defaults");
const ExplorerBase_js_1 = require("./ExplorerBase.js");
const loaders_js_1 = require("./loaders.js");
const merge_1 = require("./merge");
const util_js_1 = require("./util.js");

@@ -37,9 +39,15 @@ /**

}
const stopDir = path_1.default.resolve(this.config.stopDir);
from = path_1.default.resolve(from);
const dirs = this.#getDirs(from);
const firstDirIter = await dirs.next();
/* istanbul ignore if -- @preserve */
if (firstDirIter.done) {
// this should never happen
throw new Error(`Could not find any folders to iterate through (start from ${from})`);
}
let currentDir = firstDirIter.value;
const search = async () => {
/* istanbul ignore if -- @preserve */
if (await (0, path_type_1.isDirectory)(from)) {
for (const place of this.config.searchPlaces) {
const filepath = path_1.default.join(from, place);
if (await (0, path_type_1.isDirectory)(currentDir.path)) {
for (const filepath of this.getSearchPlacesForDir(currentDir, defaults_1.globalConfigSearchPlaces)) {
try {

@@ -62,7 +70,7 @@ const result = await this.#readConfiguration(filepath);

}
const dir = path_1.default.dirname(from);
if (from !== stopDir && from !== dir) {
from = dir;
const nextDirIter = await dirs.next();
if (!nextDirIter.done) {
currentDir = nextDirIter.value;
if (this.searchCache) {
return await (0, util_js_1.emplace)(this.searchCache, from, search);
return await (0, util_js_1.emplace)(this.searchCache, currentDir.path, search);
}

@@ -78,6 +86,25 @@ return await search();

}
async #readConfiguration(filepath) {
async #readConfiguration(filepath, importStack = []) {
const contents = await promises_1.default.readFile(filepath, { encoding: 'utf-8' });
return this.toCosmiconfigResult(filepath, await this.#loadConfiguration(filepath, contents));
return this.toCosmiconfigResult(filepath, await this.#loadConfigFileWithImports(filepath, contents, importStack));
}
async #loadConfigFileWithImports(filepath, contents, importStack) {
const loadedContent = await this.#loadConfiguration(filepath, contents);
if (!loadedContent || !(0, merge_1.hasOwn)(loadedContent, '$import')) {
return loadedContent;
}
const fileDirectory = path_1.default.dirname(filepath);
const { $import: imports, ...ownContent } = loadedContent;
const importPaths = Array.isArray(imports) ? imports : [imports];
const newImportStack = [...importStack, filepath];
this.validateImports(filepath, importPaths, newImportStack);
const importedConfigs = await Promise.all(importPaths.map(async (importPath) => {
const fullPath = path_1.default.resolve(fileDirectory, importPath);
const result = await this.#readConfiguration(fullPath, newImportStack);
return result?.config;
}));
return (0, merge_1.mergeAll)([...importedConfigs, ownContent], {
mergeArrays: this.config.mergeImportArrays,
});
}
async #loadConfiguration(filepath, contents) {

@@ -88,3 +115,3 @@ if (contents.trim() === '') {

if (path_1.default.basename(filepath) === 'package.json') {
return ((0, util_js_1.getPropertyByPath)((0, loaders_js_1.loadJson)(filepath, contents), this.config.packageProp) ?? null);
return ((0, util_js_1.getPropertyByPath)((0, loaders_js_1.loadJson)(filepath, contents), this.config.packageProp ?? this.config.moduleName) ?? null);
}

@@ -106,4 +133,42 @@ const extension = path_1.default.extname(filepath);

}
async #fileExists(path) {
try {
await promises_1.default.stat(path);
return true;
}
catch (e) {
return false;
}
}
async *#getDirs(startDir) {
switch (this.config.searchStrategy) {
case 'none': {
// only check in the passed directory (defaults to working directory)
yield { path: startDir, isGlobalConfig: false };
return;
}
case 'project': {
let currentDir = startDir;
while (true) {
yield { path: currentDir, isGlobalConfig: false };
if (await this.#fileExists(path_1.default.join(currentDir, 'package.json'))) {
break;
}
const parentDir = path_1.default.dirname(currentDir);
/* istanbul ignore if -- @preserve */
if (parentDir === currentDir) {
// we're probably at the root of the directory structure
break;
}
currentDir = parentDir;
}
return;
}
case 'global': {
yield* this.getGlobalDirs(startDir);
}
}
}
}
exports.Explorer = Explorer;
//# sourceMappingURL=Explorer.js.map

@@ -7,2 +7,4 @@ "use strict";

exports.getExtensionDescription = exports.ExplorerBase = void 0;
const env_paths_1 = __importDefault(require("env-paths"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));

@@ -66,3 +68,4 @@ const util_js_1 = require("./util.js");

this.#loadingMetaConfig) {
config = (0, util_js_1.getPropertyByPath)(config, this.config.packageProp);
const packageProp = this.config.packageProp ?? this.config.moduleName;
config = (0, util_js_1.getPropertyByPath)(config, packageProp);
}

@@ -74,2 +77,43 @@ if (config === undefined) {

}
validateImports(containingFilePath, imports, importStack) {
const fileDirectory = path_1.default.dirname(containingFilePath);
for (const importPath of imports) {
if (typeof importPath !== 'string') {
throw new Error(`${containingFilePath}: Key $import must contain a string or a list of strings`);
}
const fullPath = path_1.default.resolve(fileDirectory, importPath);
if (fullPath === containingFilePath) {
throw new Error(`Self-import detected in ${containingFilePath}`);
}
const idx = importStack.indexOf(fullPath);
if (idx !== -1) {
throw new Error(`Circular import detected:
${[...importStack, fullPath]
.map((path, i) => `${i + 1}. ${path}`)
.join('\n')} (same as ${idx + 1}.)`);
}
}
}
getSearchPlacesForDir(dir, globalConfigPlaces) {
return (dir.isGlobalConfig ? globalConfigPlaces : this.config.searchPlaces).map((place) => path_1.default.join(dir.path, place));
}
getGlobalConfigDir() {
return (0, env_paths_1.default)(this.config.moduleName, { suffix: '' }).config;
}
*getGlobalDirs(startDir) {
const stopDir = path_1.default.resolve(this.config.stopDir ?? os_1.default.homedir());
yield { path: startDir, isGlobalConfig: false };
let currentDir = startDir;
while (currentDir !== stopDir) {
const parentDir = path_1.default.dirname(currentDir);
/* istanbul ignore if -- @preserve */
if (parentDir === currentDir) {
// we're probably at the root of the directory structure
break;
}
yield { path: parentDir, isGlobalConfig: false };
currentDir = parentDir;
}
yield { path: this.getGlobalConfigDir(), isGlobalConfig: true };
}
}

@@ -76,0 +120,0 @@ exports.ExplorerBase = ExplorerBase;

@@ -10,4 +10,6 @@ "use strict";

const path_type_1 = require("path-type");
const defaults_1 = require("./defaults");
const ExplorerBase_js_1 = require("./ExplorerBase.js");
const loaders_js_1 = require("./loaders.js");
const merge_1 = require("./merge");
const util_js_1 = require("./util.js");

@@ -37,9 +39,15 @@ /**

}
const stopDir = path_1.default.resolve(this.config.stopDir);
from = path_1.default.resolve(from);
const dirs = this.#getDirs(from);
const firstDirIter = dirs.next();
/* istanbul ignore if -- @preserve */
if (firstDirIter.done) {
// this should never happen
throw new Error(`Could not find any folders to iterate through (start from ${from})`);
}
let currentDir = firstDirIter.value;
const search = () => {
/* istanbul ignore if -- @preserve */
if ((0, path_type_1.isDirectorySync)(from)) {
for (const place of this.config.searchPlaces) {
const filepath = path_1.default.join(from, place);
if ((0, path_type_1.isDirectorySync)(currentDir.path)) {
for (const filepath of this.getSearchPlacesForDir(currentDir, defaults_1.globalConfigSearchPlacesSync)) {
try {

@@ -62,7 +70,7 @@ const result = this.#readConfiguration(filepath);

}
const dir = path_1.default.dirname(from);
if (from !== stopDir && from !== dir) {
from = dir;
const nextDirIter = dirs.next();
if (!nextDirIter.done) {
currentDir = nextDirIter.value;
if (this.searchCache) {
return (0, util_js_1.emplace)(this.searchCache, from, search);
return (0, util_js_1.emplace)(this.searchCache, currentDir.path, search);
}

@@ -78,6 +86,25 @@ return search();

}
#readConfiguration(filepath) {
#readConfiguration(filepath, importStack = []) {
const contents = fs_1.default.readFileSync(filepath, 'utf8');
return this.toCosmiconfigResult(filepath, this.#loadConfiguration(filepath, contents));
return this.toCosmiconfigResult(filepath, this.#loadConfigFileWithImports(filepath, contents, importStack));
}
#loadConfigFileWithImports(filepath, contents, importStack) {
const loadedContent = this.#loadConfiguration(filepath, contents);
if (!loadedContent || !(0, merge_1.hasOwn)(loadedContent, '$import')) {
return loadedContent;
}
const fileDirectory = path_1.default.dirname(filepath);
const { $import: imports, ...ownContent } = loadedContent;
const importPaths = Array.isArray(imports) ? imports : [imports];
const newImportStack = [...importStack, filepath];
this.validateImports(filepath, importPaths, newImportStack);
const importedConfigs = importPaths.map((importPath) => {
const fullPath = path_1.default.resolve(fileDirectory, importPath);
const result = this.#readConfiguration(fullPath, newImportStack);
return result?.config;
});
return (0, merge_1.mergeAll)([...importedConfigs, ownContent], {
mergeArrays: this.config.mergeImportArrays,
});
}
#loadConfiguration(filepath, contents) {

@@ -88,3 +115,3 @@ if (contents.trim() === '') {

if (path_1.default.basename(filepath) === 'package.json') {
return ((0, util_js_1.getPropertyByPath)((0, loaders_js_1.loadJson)(filepath, contents), this.config.packageProp) ?? null);
return ((0, util_js_1.getPropertyByPath)((0, loaders_js_1.loadJson)(filepath, contents), this.config.packageProp ?? this.config.moduleName) ?? null);
}

@@ -105,2 +132,40 @@ const extension = path_1.default.extname(filepath);

}
#fileExists(path) {
try {
fs_1.default.statSync(path);
return true;
}
catch (e) {
return false;
}
}
*#getDirs(startDir) {
switch (this.config.searchStrategy) {
case 'none': {
// there is no next dir
yield { path: startDir, isGlobalConfig: false };
return;
}
case 'project': {
let currentDir = startDir;
while (true) {
yield { path: currentDir, isGlobalConfig: false };
if (this.#fileExists(path_1.default.join(currentDir, 'package.json'))) {
break;
}
const parentDir = path_1.default.dirname(currentDir);
/* istanbul ignore if -- @preserve */
if (parentDir === currentDir) {
// we're probably at the root of the directory structure
break;
}
currentDir = parentDir;
}
return;
}
case 'global': {
yield* this.getGlobalDirs(startDir);
}
}
}
/**

@@ -107,0 +172,0 @@ * @deprecated Use {@link ExplorerSync.prototype.load}.

29

dist/index.d.ts

@@ -1,25 +0,6 @@

export * from './types.js';
import { Options, OptionsSync, PublicExplorer, PublicExplorerSync } from './types.js';
export declare const metaSearchPlaces: string[];
export declare const defaultLoaders: Readonly<{
readonly '.mjs': import("./types.js").Loader;
readonly '.cjs': import("./types.js").Loader;
readonly '.js': import("./types.js").Loader;
readonly '.ts': import("./types.js").Loader;
readonly '.json': import("./types.js").LoaderSync;
readonly '.yaml': import("./types.js").LoaderSync;
readonly '.yml': import("./types.js").LoaderSync;
readonly noExt: import("./types.js").LoaderSync;
}>;
export declare const defaultLoadersSync: Readonly<{
readonly '.cjs': import("./types.js").LoaderSync;
readonly '.js': import("./types.js").LoaderSync;
readonly '.ts': import("./types.js").LoaderSync;
readonly '.json': import("./types.js").LoaderSync;
readonly '.yaml': import("./types.js").LoaderSync;
readonly '.yml': import("./types.js").LoaderSync;
readonly noExt: import("./types.js").LoaderSync;
}>;
export declare function cosmiconfig(moduleName: string, options?: Readonly<Options>): PublicExplorer;
export declare function cosmiconfigSync(moduleName: string, options?: Readonly<OptionsSync>): PublicExplorerSync;
import { getDefaultSearchPlaces, getDefaultSearchPlacesSync, globalConfigSearchPlaces, globalConfigSearchPlacesSync } from './defaults';
import { CommonOptions, Config, CosmiconfigResult, Loader, LoaderResult, Loaders, LoadersSync, LoaderSync, Options, OptionsSync, PublicExplorer, PublicExplorerBase, PublicExplorerSync, SearchStrategy, Transform, TransformSync } from './types.js';
export declare function cosmiconfig(moduleName: string, options?: Readonly<Partial<Options>>): PublicExplorer;
export declare function cosmiconfigSync(moduleName: string, options?: Readonly<Partial<OptionsSync>>): PublicExplorerSync;
export { Config, CosmiconfigResult, LoaderResult, Loader, Loaders, LoaderSync, LoadersSync, Transform, TransformSync, SearchStrategy, CommonOptions, Options, OptionsSync, PublicExplorerBase, PublicExplorer, PublicExplorerSync, getDefaultSearchPlaces, getDefaultSearchPlacesSync, globalConfigSearchPlaces, globalConfigSearchPlacesSync, };
//# sourceMappingURL=index.d.ts.map
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.cosmiconfigSync = exports.cosmiconfig = exports.defaultLoadersSync = exports.defaultLoaders = exports.metaSearchPlaces = void 0;
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
__exportStar(require("./types.js"), exports);
const os_1 = __importDefault(require("os"));
exports.globalConfigSearchPlacesSync = exports.globalConfigSearchPlaces = exports.getDefaultSearchPlacesSync = exports.getDefaultSearchPlaces = exports.cosmiconfigSync = exports.cosmiconfig = void 0;
const defaults_1 = require("./defaults");
Object.defineProperty(exports, "getDefaultSearchPlaces", { enumerable: true, get: function () { return defaults_1.getDefaultSearchPlaces; } });
Object.defineProperty(exports, "getDefaultSearchPlacesSync", { enumerable: true, get: function () { return defaults_1.getDefaultSearchPlacesSync; } });
Object.defineProperty(exports, "globalConfigSearchPlaces", { enumerable: true, get: function () { return defaults_1.globalConfigSearchPlaces; } });
Object.defineProperty(exports, "globalConfigSearchPlacesSync", { enumerable: true, get: function () { return defaults_1.globalConfigSearchPlacesSync; } });
const Explorer_js_1 = require("./Explorer.js");
const ExplorerSync_js_1 = require("./ExplorerSync.js");
const loaders_js_1 = require("./loaders.js");
const util_1 = require("./util");
// this needs to be hardcoded, as this is intended for end users, who can't supply options at this point
exports.metaSearchPlaces = [
'package.json',
'.config.json',
'.config.yaml',
'.config.yml',
'.config.js',
'.config.ts',
'.config.cjs',
'.config.mjs',
];
// do not allow mutation of default loaders. Make sure it is set inside options
exports.defaultLoaders = Object.freeze({
'.mjs': loaders_js_1.loadJs,
'.cjs': loaders_js_1.loadJs,
'.js': loaders_js_1.loadJs,
'.ts': loaders_js_1.loadTs,
'.json': loaders_js_1.loadJson,
'.yaml': loaders_js_1.loadYaml,
'.yml': loaders_js_1.loadYaml,
noExt: loaders_js_1.loadYaml,
});
exports.defaultLoadersSync = Object.freeze({
'.cjs': loaders_js_1.loadJsSync,
'.js': loaders_js_1.loadJsSync,
'.ts': loaders_js_1.loadTsSync,
'.json': loaders_js_1.loadJson,
'.yaml': loaders_js_1.loadYaml,
'.yml': loaders_js_1.loadYaml,
noExt: loaders_js_1.loadYaml,
});
const identity = function identity(x) {
return x;
};
function getInternalOptions(moduleName, options) {
function getUserDefinedOptionsFromMetaConfig() {
const metaExplorer = new ExplorerSync_js_1.ExplorerSync({
packageProp: 'cosmiconfig',
moduleName: 'cosmiconfig',
stopDir: process.cwd(),
searchPlaces: exports.metaSearchPlaces,
searchPlaces: defaults_1.metaSearchPlaces,
ignoreEmptySearchPlaces: false,
applyPackagePropertyPathToConfiguration: true,
loaders: exports.defaultLoaders,
loaders: defaults_1.defaultLoaders,
transform: identity,
cache: true,
metaConfigFilePath: null,
mergeImportArrays: true,
mergeSearchPlaces: true,
searchStrategy: 'none',
});
const metaConfig = metaExplorer.search();
if (!metaConfig) {
return options;
return null;
}

@@ -81,45 +37,42 @@ if (metaConfig.config?.loaders) {

}
const overrideOptions = metaConfig.config ?? {};
if (overrideOptions.searchPlaces) {
overrideOptions.searchPlaces = overrideOptions.searchPlaces.map((path) => path.replace('{name}', moduleName));
if (metaConfig.config?.searchStrategy) {
throw new Error('Can not specify searchStrategy in meta config file');
}
overrideOptions.metaConfigFilePath = metaConfig.filepath;
return { ...options, ...(0, util_1.removeUndefinedValuesFromObject)(overrideOptions) };
}
function normalizeOptions(moduleName, options) {
const defaults = {
packageProp: moduleName,
searchPlaces: [
'package.json',
`.${moduleName}rc`,
`.${moduleName}rc.json`,
`.${moduleName}rc.yaml`,
`.${moduleName}rc.yml`,
`.${moduleName}rc.js`,
`.${moduleName}rc.ts`,
`.${moduleName}rc.cjs`,
`.${moduleName}rc.mjs`,
`.config/${moduleName}rc`,
`.config/${moduleName}rc.json`,
`.config/${moduleName}rc.yaml`,
`.config/${moduleName}rc.yml`,
`.config/${moduleName}rc.js`,
`.config/${moduleName}rc.ts`,
`.config/${moduleName}rc.cjs`,
`.config/${moduleName}rc.mjs`,
`${moduleName}.config.js`,
`${moduleName}.config.ts`,
`${moduleName}.config.cjs`,
`${moduleName}.config.mjs`,
],
ignoreEmptySearchPlaces: true,
stopDir: os_1.default.homedir(),
cache: true,
transform: identity,
loaders: exports.defaultLoaders,
metaConfigFilePath: null,
const overrideOptions = {
mergeSearchPlaces: true,
...(metaConfig.config ?? {}),
};
return {
config: (0, util_1.removeUndefinedValuesFromObject)(overrideOptions),
filepath: metaConfig.filepath,
};
}
function getResolvedSearchPlaces(moduleName, toolDefinedSearchPlaces, userConfiguredOptions) {
const userConfiguredSearchPlaces = userConfiguredOptions.searchPlaces?.map((path) => path.replace('{name}', moduleName));
if (userConfiguredOptions.mergeSearchPlaces) {
return [...(userConfiguredSearchPlaces ?? []), ...toolDefinedSearchPlaces];
}
return (userConfiguredSearchPlaces ??
/* istanbul ignore next */ toolDefinedSearchPlaces);
}
function mergeOptionsBase(moduleName, defaults, options) {
const userDefinedConfig = getUserDefinedOptionsFromMetaConfig();
if (!userDefinedConfig) {
return {
...defaults,
...(0, util_1.removeUndefinedValuesFromObject)(options),
loaders: {
...defaults.loaders,
...options.loaders,
},
};
}
const userConfiguredOptions = userDefinedConfig.config;
const toolDefinedSearchPlaces = options.searchPlaces ?? defaults.searchPlaces;
return {
...defaults,
...(0, util_1.removeUndefinedValuesFromObject)(options),
metaConfigFilePath: userDefinedConfig.filepath,
...userConfiguredOptions,
searchPlaces: getResolvedSearchPlaces(moduleName, toolDefinedSearchPlaces, userConfiguredOptions),
loaders: {

@@ -131,44 +84,43 @@ ...defaults.loaders,

}
function normalizeOptionsSync(moduleName, options) {
function validateOptions(options) {
if (options.searchStrategy != null &&
options.searchStrategy !== 'global' &&
options.stopDir) {
throw new Error('Can not supply `stopDir` option with `searchStrategy` other than "global"');
}
}
function mergeOptions(moduleName, options) {
validateOptions(options);
const defaults = {
packageProp: moduleName,
searchPlaces: [
'package.json',
`.${moduleName}rc`,
`.${moduleName}rc.json`,
`.${moduleName}rc.yaml`,
`.${moduleName}rc.yml`,
`.${moduleName}rc.js`,
`.${moduleName}rc.ts`,
`.${moduleName}rc.cjs`,
`.config/${moduleName}rc`,
`.config/${moduleName}rc.json`,
`.config/${moduleName}rc.yaml`,
`.config/${moduleName}rc.yml`,
`.config/${moduleName}rc.js`,
`.config/${moduleName}rc.ts`,
`.config/${moduleName}rc.cjs`,
`${moduleName}.config.js`,
`${moduleName}.config.ts`,
`${moduleName}.config.cjs`,
],
moduleName,
searchPlaces: (0, defaults_1.getDefaultSearchPlaces)(moduleName),
ignoreEmptySearchPlaces: true,
stopDir: os_1.default.homedir(),
cache: true,
transform: identity,
loaders: exports.defaultLoadersSync,
loaders: defaults_1.defaultLoaders,
metaConfigFilePath: null,
mergeImportArrays: true,
mergeSearchPlaces: true,
searchStrategy: options.stopDir ? 'global' : 'none',
};
return {
...defaults,
...(0, util_1.removeUndefinedValuesFromObject)(options),
loaders: {
...defaults.loaders,
...options.loaders,
},
return mergeOptionsBase(moduleName, defaults, options);
}
function mergeOptionsSync(moduleName, options) {
validateOptions(options);
const defaults = {
moduleName,
searchPlaces: (0, defaults_1.getDefaultSearchPlacesSync)(moduleName),
ignoreEmptySearchPlaces: true,
cache: true,
transform: identity,
loaders: defaults_1.defaultLoadersSync,
metaConfigFilePath: null,
mergeImportArrays: true,
mergeSearchPlaces: true,
searchStrategy: options.stopDir ? 'global' : 'none',
};
return mergeOptionsBase(moduleName, defaults, options);
}
function cosmiconfig(moduleName, options = {}) {
const internalOptions = getInternalOptions(moduleName, options);
const normalizedOptions = normalizeOptions(moduleName, internalOptions);
const normalizedOptions = mergeOptions(moduleName, options);
const explorer = new Explorer_js_1.Explorer(normalizedOptions);

@@ -185,4 +137,3 @@ return {

function cosmiconfigSync(moduleName, options = {}) {
const internalOptions = getInternalOptions(moduleName, options);
const normalizedOptions = normalizeOptionsSync(moduleName, internalOptions);
const normalizedOptions = mergeOptionsSync(moduleName, options);
const explorerSync = new ExplorerSync_js_1.ExplorerSync(normalizedOptions);

@@ -189,0 +140,0 @@ return {

@@ -36,8 +36,15 @@ /**

*/
export type SearchStrategy = 'none' | 'project' | 'global';
/**
* @public
*/
export interface CommonOptions {
packageProp?: string | Array<string>;
searchPlaces?: Array<string>;
ignoreEmptySearchPlaces?: boolean;
searchPlaces: Array<string>;
ignoreEmptySearchPlaces: boolean;
stopDir?: string;
cache?: boolean;
cache: boolean;
mergeImportArrays: boolean;
mergeSearchPlaces: boolean;
searchStrategy: SearchStrategy;
}

@@ -48,4 +55,4 @@ /**

export interface Options extends CommonOptions {
loaders?: Loaders;
transform?: Transform;
loaders: Loaders;
transform: Transform;
}

@@ -56,4 +63,4 @@ /**

export interface OptionsSync extends CommonOptions {
loaders?: LoadersSync;
transform?: TransformSync;
loaders: LoadersSync;
transform: TransformSync;
}

@@ -60,0 +67,0 @@ /**

@@ -42,6 +42,2 @@ "use strict";

function removeUndefinedValuesFromObject(options) {
/* istanbul ignore if -- @preserve */
if (!options) {
return undefined;
}
return Object.fromEntries(Object.entries(options).filter(([, value]) => value !== undefined));

@@ -48,0 +44,0 @@ }

{
"name": "cosmiconfig",
"version": "8.3.6",
"version": "9.0.0-alpha.0",
"description": "Find and load configuration from a package.json property, rc file, TypeScript module, and more!",

@@ -71,2 +71,3 @@ "main": "dist/index.js",

"dependencies": {
"env-paths": "^2.2.1",
"import-fresh": "^3.3.0",

@@ -73,0 +74,0 @@ "js-yaml": "^4.1.0",

@@ -10,3 +10,3 @@ # cosmiconfig

By default, Cosmiconfig will start where you tell it to start and search up the directory tree for the following:
By default, Cosmiconfig will check the current directory for the following:

@@ -24,6 +24,7 @@ - a `package.json` property

- a `.myapprc.json`, `.myapprc.yaml`, `.myapprc.yml`, `.myapprc.js`, `.myapprc.ts`, `.myapprc.mjs`, or `.myapprc.cjs` file
- a `myapprc`, `myapprc.json`, `myapprc.yaml`, `myapprc.yml`, `myapprc.js`, `myapprc.ts` or `myapprc.cjs` file inside a `.config` subdirectory
- a `myapprc`, `myapprc.json`, `myapprc.yaml`, `myapprc.yml`, `myapprc.js`, `myapprc.ts`, `myapprc.mjs`, or `myapprc.cjs` file inside a `.config` subdirectory
- a `myapp.config.js`, `myapp.config.ts`, `myapp.config.mjs`, or `myapp.config.cjs` file
Cosmiconfig continues to search up the directory tree, checking each of these places in each directory, until it finds some acceptable configuration (or hits the home directory).
Optionally, you can tell it to search up the directory tree using [search strategies],
checking each of these places in each directory, until it finds some acceptable configuration (or hits the home directory).

@@ -50,2 +51,3 @@ ## Table of contents

- [cosmiconfigOptions](#cosmiconfigoptions)
- [searchStrategy](#searchstrategy)
- [searchPlaces](#searchplaces)

@@ -62,2 +64,3 @@ - [loaders](#loaders)

- [Usage for end users](#usage-for-end-users)
- [Imports](#imports)
- [Contributing & Development](#contributing--development)

@@ -100,3 +103,3 @@

// See documentation for load, below.
explorer.load(pathToConfig).then(..);
explorer.load(pathToConfig).then(/* ... */);

@@ -124,3 +127,3 @@ // You can also search and load synchronously.

const { cosmiconfig } = require('cosmiconfig');
const explorer = cosmiconfig(moduleName[, cosmiconfigOptions])
const explorer = cosmiconfig(moduleName, /* optional */ cosmiconfigOptions)
```

@@ -144,3 +147,3 @@

```js
explorer.search([searchFrom]).then(result => {..})
explorer.search([searchFrom]).then(result => { /* ... */ })
```

@@ -158,9 +161,14 @@

2. A `.goldengrahamsrc` file with JSON or YAML syntax.
3. A `.goldengrahamsrc.json`, `.goldengrahamsrc.yaml`, `.goldengrahamsrc.yml`, `.goldengrahamsrc.js`, `.goldengrahamsrc.ts`, or `.goldengrahamsrc.cjs` file. (To learn more about how JS files are loaded, see ["Loading JS modules"].)
4. A `goldengrahamsrc`, `goldengrahamsrc.json`, `goldengrahamsrc.yaml`, `goldengrahamsrc.yml`, `goldengrahamsrc.js`, `goldengrahamsrc.ts`, or `goldengrahamsrc.cjs` file in the `.config` subdirectory.
3. A `.goldengrahamsrc.json`, `.goldengrahamsrc.yaml`, `.goldengrahamsrc.yml`, `.goldengrahamsrc.js`, `.goldengrahamsrc.ts`, `.goldengrahamsrc.mjs`, or `.goldengrahamsrc.cjs` file. (To learn more about how JS files are loaded, see ["Loading JS modules"].)
4. A `goldengrahamsrc`, `goldengrahamsrc.json`, `goldengrahamsrc.yaml`, `goldengrahamsrc.yml`, `goldengrahamsrc.js`, `goldengrahamsrc.ts`, `goldengrahamsrc.mjs`, or `goldengrahamsrc.cjs` file in the `.config` subdirectory.
5. A `goldengrahams.config.js`, `goldengrahams.config.ts`, `goldengrahams.config.mjs`, or `goldengrahams.config.cjs` file. (To learn more about how JS files are loaded, see ["Loading JS modules"].)
- If none of those searches reveal a configuration object, move up one directory level and try again.
So the search continues in `./`, `../`, `../../`, `../../../`, etc., checking the same places in each directory.
- Continue searching until arriving at your home directory (or some other directory defined by the cosmiconfig option [`stopDir`]).
- For JS files,
- If none of those searches reveal a configuration object, continue depending on the current search strategy:
- If it's `none` (which is the default if you don't specify a [`stopDir`] option), stop here and return/resolve with `null`.
- If it's `global` (which is the default if you specify a [`stopDir`] option), move up one directory level and try again,
recursing until arriving at the configured [`stopDir`] option, which defaults to the user's home directory.
- After arriving at the [`stopDir`], the global configuration directory (as defined by [`env-paths`] without prefix) is also checked,
looking at the files `config`, `config.json`, `config.yaml`, `config.yml`, `config.js`, `config.ts`, `config.cjs`, and `config.mjs`
in the directory `~/.config/goldengrahams/` (on Linux; see [`env-paths`] documentation for other OSs).
- If it's `project`, check whether a `package.json` file is present in the current directory, and if not,
move up one directory level and try again, recursing until there is one.
- If at any point a parsable configuration is found, the [`search()`] Promise resolves with its [result] \(or, with [`explorerSync.search()`], the [result] is returned).

@@ -189,3 +197,3 @@ - If no configuration object is found, the [`search()`] Promise resolves with `null` (or, with [`explorerSync.search()`], `null` is returned).

```js
explorer.load(loadPath).then(result => {..})
explorer.load(loadPath).then(result => { /* ... */ })
```

@@ -223,3 +231,3 @@

const { cosmiconfigSync } = require('cosmiconfig');
const explorerSync = cosmiconfigSync(moduleName[, cosmiconfigOptions])
const explorerSync = cosmiconfigSync(moduleName, /* optional */ cosmiconfigOptions)
```

@@ -269,2 +277,29 @@

### searchStrategy
Type: `string`
Default: `global` if [`stopDir`] is specified, `none` otherwise.
The strategy that should be used to determine which directories to check for configuration files.
- `none`: Only checks in the current working directory.
- `project`: Starts in the current working directory, traversing upwards until a `package.json` file is found.
- `global`: Starts in the current working directory, traversing upwards until the configured [`stopDir`]
(or the current user's home directory if none is given). Then, if no configuration is found, also look in the
operating system's default configuration directory (according to [`env-paths`] without prefix),
where a different set of file names is checked:
```js
[
`config`,
`config.json`,
`config.yaml`,
`config.yml`,
`config.js`,
`config.ts`,
`config.cjs`,
`config.mjs`
]
```
### searchPlaces

@@ -299,2 +334,3 @@

`.config/${moduleName}rc.ts`,
`.config/${moduleName}rc.mjs`,
`.config/${moduleName}rc.cjs`,

@@ -323,22 +359,31 @@ `${moduleName}.config.js`,

// Disallow extensions on rc files:
['package.json', '.porgyrc', 'porgy.config.js'][
// Limit the options dramatically:
('package.json', '.porgyrc')
][
// Maybe you want to look for a wide variety of JS flavors:
('porgy.config.js',
['package.json', '.porgyrc', 'porgy.config.js']
```
```js
// Limit the options dramatically:
['package.json', '.porgyrc']
```
```js
// Maybe you want to look for a wide variety of JS flavors:
[
'porgy.config.js',
'porgy.config.mjs',
'porgy.config.ts',
'porgy.config.coffee')
][
// ^^ You will need to designate custom loaders to tell
// Cosmiconfig how to handle `.ts` and `.coffee` files.
'porgy.config.coffee'
]
// ^^ You will need to designate a custom loader to tell
// Cosmiconfig how to handle `.coffee` files.
```
// Look within a .config/ subdirectory of every searched directory:
('package.json',
```js
// Look within a .config/ subdirectory of every searched directory:
[
'package.json',
'.porgyrc',
'.config/.porgyrc',
'.porgyrc.json',
'.config/.porgyrc.json')
];
'.config/.porgyrc.json'
]
```

@@ -404,10 +449,5 @@

**Third-party loaders:**
- [cosmiconfig-typescript-loader](https://github.com/codex-/cosmiconfig-typescript-loader)
**Use cases for custom loader function:**
- Allow configuration syntaxes that aren't handled by Cosmiconfig's defaults, like JSON5, INI, or XML.
- Allow ES2015 modules from `.mjs` configuration files.
- Parse JS files with Babel before deriving the configuration.

@@ -417,8 +457,8 @@

```js
```ts
// Sync
(filepath: string, content: string) => Object | null
type SyncLoader = (filepath: string, content: string) => Object | null
// Async
(filepath: string, content: string) => Object | null | Promise<Object | null>
type AsyncLoader = (filepath: string, content: string) => Object | null | Promise<Object | null>
```

@@ -440,20 +480,28 @@

// Allow JSON5 syntax:
{
'.json': json5Loader
}
cosmiconfig('foo', {
loaders: {
'.json': json5Loader
}
});
// Allow a special configuration syntax of your own creation:
{
'.special': specialLoader
}
cosmiconfig('foo', {
loaders: {
'.special': specialLoader
}
});
// Allow many flavors of JS, using custom loaders:
{
'.coffee': coffeeScriptLoader
}
cosmiconfig('foo', {
loaders: {
'.coffee': coffeeScriptLoader
}
});
// Allow many flavors of JS but rely on require hooks:
{
'.coffee': defaultLoaders['.js']
}
cosmiconfig('foo', {
loaders: {
'.coffee': defaultLoaders['.js']
}
});
```

@@ -475,3 +523,3 @@

"configs": {
"myPackage": {..}
"myPackage": {"option": "value"}
}

@@ -487,3 +535,3 @@ }

"foo.bar": {
"baz": {..}
"baz": {"option": "value"}
}

@@ -596,5 +644,7 @@ }

.config/{NAME}rc.ts
.config/{NAME}rc.mjs
.config/{NAME}rc.cjs
{NAME}.config.js
{NAME}.config.ts
{NAME}.config.mjs
{NAME}.config.cjs

@@ -631,17 +681,20 @@ ```

```
.config.json
.config.yaml
.config.yml
.config.js
.config.ts
.config.cjs
.config/config.json
.config/config.yaml
.config/config.yml
.config/config.js
.config/config.ts
.config/config.cjs
```
The following property is currently actively supported in these places:
The following properties are currently actively supported in these places:
```yaml
cosmiconfig:
# overrides where configuration files are being searched to enforce a custom naming convention and format
# adds places where configuration files are being searched
searchPlaces:
- .config/{name}.yml
# to enforce a custom naming convention and format, don't merge the above with the tool-defined search places
# (`true` is the default setting)
mergeSearchPlaces: false
```

@@ -651,2 +704,4 @@

> but everything not listed above should be used at your own risk, as it has not been tested explicitly.
> The only exceptions to this are the `loaders` property, which is explicitly not supported at this time,
> and the `searchStrategy` property, which is intentionally disallowed.

@@ -664,2 +719,37 @@ You can also add more root properties outside the `cosmiconfig` property

### Imports
Wherever you put your configuration (the package.json file, a root config file or a package-specific config file),
you can use the special `$import` key to import another file as a base.
For example, you can import from an npm package (in this example, `@foocorp/config`).
`.prettierrc.base.yml` in said npm package could define some company-wide defaults:
```yaml
printWidth: 120
semi: true
tabWidth: 2
```
And then, the `.prettierrc.yml` file in the project itself would just reference that file,
optionally overriding the defaults with project-specific settings:
```yaml
$import: node_modules/@foocorp/config/.prettierrc.base.yml
# we want more space!
printWidth: 200
```
It is possible to import multiple base files by specifying an array of paths,
which will be processed in declaration order;
that means that the last entry will win if there are conflicting properties.
It is also possible to import file formats other than the importing format
as long as they are supported by the loaders specified by the developer of the tool you're configuring.
```yaml
$import: [first.yml, second.json, third.config.js]
```
## Contributing & Development

@@ -708,1 +798,5 @@

["Loading JS modules"]: #loading-js-modules
[`env-paths`]: https://github.com/sindresorhus/env-paths
[search strategies]: #searchstrategy

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc