UNPKG

19.2 kBMarkdownView Raw
1# cosmiconfig
2
3[![Build Status](https://img.shields.io/travis/davidtheclark/cosmiconfig/main.svg?label=unix%20build)](https://travis-ci.org/davidtheclark/cosmiconfig) [![Build status](https://img.shields.io/appveyor/ci/davidtheclark/cosmiconfig/main.svg?label=windows%20build)](https://ci.appveyor.com/project/davidtheclark/cosmiconfig/branch/main)
4[![codecov](https://codecov.io/gh/davidtheclark/cosmiconfig/branch/main/graph/badge.svg)](https://codecov.io/gh/davidtheclark/cosmiconfig)
5
6Cosmiconfig searches for and loads configuration for your program.
7
8It features smart defaults based on conventional expectations in the JavaScript ecosystem.
9But it's also flexible enough to search wherever you'd like to search, and load whatever you'd like to load.
10
11By default, Cosmiconfig will start where you tell it to start and search up the directory tree for the following:
12
13- a `package.json` property
14- a JSON or YAML, extensionless "rc file"
15- an "rc file" with the extensions `.json`, `.yaml`, `.yml`, `.js`, or `.cjs`
16- a `.config.js` or `.config.cjs` CommonJS module
17
18For example, if your module's name is "myapp", cosmiconfig will search up the directory tree for configuration in the following places:
19
20- a `myapp` property in `package.json`
21- a `.myapprc` file in JSON or YAML format
22- a `.myapprc.json`, `.myapprc.yaml`, `.myapprc.yml`, `.myapprc.js`, or `.myapprc.cjs` file
23- a `myapp.config.js` or `myapp.config.cjs` CommonJS module exporting an object
24
25Cosmiconfig 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).
26
27## Table of contents
28
29- [Installation](#installation)
30- [Usage](#usage)
31- [Result](#result)
32- [Asynchronous API](#asynchronous-api)
33 - [cosmiconfig()](#cosmiconfig-1)
34 - [explorer.search()](#explorersearch)
35 - [explorer.load()](#explorerload)
36 - [explorer.clearLoadCache()](#explorerclearloadcache)
37 - [explorer.clearSearchCache()](#explorerclearsearchcache)
38 - [explorer.clearCaches()](#explorerclearcaches)
39- [Synchronous API](#synchronous-api)
40 - [cosmiconfigSync()](#cosmiconfigsync)
41 - [explorerSync.search()](#explorersyncsearch)
42 - [explorerSync.load()](#explorersyncload)
43 - [explorerSync.clearLoadCache()](#explorersyncclearloadcache)
44 - [explorerSync.clearSearchCache()](#explorersyncclearsearchcache)
45 - [explorerSync.clearCaches()](#explorersyncclearcaches)
46- [cosmiconfigOptions](#cosmiconfigoptions)
47 - [searchPlaces](#searchplaces)
48 - [loaders](#loaders)
49 - [packageProp](#packageprop)
50 - [stopDir](#stopdir)
51 - [cache](#cache)
52 - [transform](#transform)
53 - [ignoreEmptySearchPlaces](#ignoreemptysearchplaces)
54- [Caching](#caching)
55- [Differences from rc](#differences-from-rc)
56- [Contributing & Development](#contributing--development)
57
58## Installation
59
60```
61npm install cosmiconfig
62```
63
64Tested in Node 10+.
65
66## Usage
67
68Create a Cosmiconfig explorer, then either `search` for or directly `load` a configuration file.
69
70```js
71const { cosmiconfig, cosmiconfigSync } = require('cosmiconfig');
72// ...
73const explorer = cosmiconfig(moduleName);
74
75// Search for a configuration by walking up directories.
76// See documentation for search, below.
77explorer.search()
78 .then((result) => {
79 // result.config is the parsed configuration object.
80 // result.filepath is the path to the config file that was found.
81 // result.isEmpty is true if there was nothing to parse in the config file.
82 })
83 .catch((error) => {
84 // Do something constructive.
85 });
86
87// Load a configuration directly when you know where it should be.
88// The result object is the same as for search.
89// See documentation for load, below.
90explorer.load(pathToConfig).then(..);
91
92// You can also search and load synchronously.
93const explorerSync = cosmiconfigSync(moduleName);
94
95const searchedFor = explorerSync.search();
96const loaded = explorerSync.load(pathToConfig);
97```
98
99## Result
100
101The result object you get from `search` or `load` has the following properties:
102
103- **config:** The parsed configuration object. `undefined` if the file is empty.
104- **filepath:** The path to the configuration file that was found.
105- **isEmpty:** `true` if the configuration file is empty. This property will not be present if the configuration file is not empty.
106
107## Asynchronous API
108
109### cosmiconfig()
110
111```js
112const { cosmiconfig } = require('cosmiconfig');
113const explorer = cosmiconfig(moduleName[, cosmiconfigOptions])
114```
115
116Creates a cosmiconfig instance ("explorer") configured according to the arguments, and initializes its caches.
117
118#### moduleName
119
120Type: `string`. **Required.**
121
122Your module name. This is used to create the default [`searchPlaces`] and [`packageProp`].
123
124If your [`searchPlaces`] value will include files, as it does by default (e.g. `${moduleName}rc`), your `moduleName` must consist of characters allowed in filenames. That means you should not copy scoped package names, such as `@my-org/my-package`, directly into `moduleName`.
125
126**[`cosmiconfigOptions`] are documented below.**
127You may not need them, and should first read about the functions you'll use.
128
129### explorer.search()
130
131```js
132explorer.search([searchFrom]).then(result => {..})
133```
134
135Searches for a configuration file. Returns a Promise that resolves with a [result] or with `null`, if no configuration file is found.
136
137You can do the same thing synchronously with [`explorerSync.search()`].
138
139Let's say your module name is `goldengrahams` so you initialized with `const explorer = cosmiconfig('goldengrahams');`.
140Here's how your default [`search()`] will work:
141
142- Starting from `process.cwd()` (or some other directory defined by the `searchFrom` argument to [`search()`]), look for configuration objects in the following places:
143 1. A `goldengrahams` property in a `package.json` file.
144 2. A `.goldengrahamsrc` file with JSON or YAML syntax.
145 3. A `.goldengrahamsrc.json`, `.goldengrahamsrc.yaml`, `.goldengrahamsrc.yml`, `.goldengrahamsrc.js`, or `.goldengrahamsrc.cjs` file.
146 4. A `goldengrahams.config.js` or `goldengrahams.config.cjs` CommonJS module exporting the object.
147- If none of those searches reveal a configuration object, move up one directory level and try again.
148 So the search continues in `./`, `../`, `../../`, `../../../`, etc., checking the same places in each directory.
149- Continue searching until arriving at your home directory (or some other directory defined by the cosmiconfig option [`stopDir`]).
150- If at any point a parsable configuration is found, the [`search()`] Promise resolves with its [result] \(or, with [`explorerSync.search()`], the [result] is returned).
151- If no configuration object is found, the [`search()`] Promise resolves with `null` (or, with [`explorerSync.search()`], `null` is returned).
152- If a configuration object is found *but is malformed* (causing a parsing error), the [`search()`] Promise rejects with that error (so you should `.catch()` it). (Or, with [`explorerSync.search()`], the error is thrown.)
153
154**If you know exactly where your configuration file should be, you can use [`load()`], instead.**
155
156**The search process is highly customizable.**
157Use the cosmiconfig options [`searchPlaces`] and [`loaders`] to precisely define where you want to look for configurations and how you want to load them.
158
159#### searchFrom
160
161Type: `string`.
162Default: `process.cwd()`.
163
164A filename.
165[`search()`] will start its search here.
166
167If the value is a directory, that's where the search starts.
168If it's a file, the search starts in that file's directory.
169
170### explorer.load()
171
172```js
173explorer.load(loadPath).then(result => {..})
174```
175
176Loads a configuration file. Returns a Promise that resolves with a [result] or rejects with an error (if the file does not exist or cannot be loaded).
177
178Use `load` if you already know where the configuration file is and you just need to load it.
179
180```js
181explorer.load('load/this/file.json'); // Tries to load load/this/file.json.
182```
183
184If you load a `package.json` file, the result will be derived from whatever property is specified as your [`packageProp`].
185
186You can do the same thing synchronously with [`explorerSync.load()`].
187
188### explorer.clearLoadCache()
189
190Clears the cache used in [`load()`].
191
192### explorer.clearSearchCache()
193
194Clears the cache used in [`search()`].
195
196### explorer.clearCaches()
197
198Performs both [`clearLoadCache()`] and [`clearSearchCache()`].
199
200## Synchronous API
201
202### cosmiconfigSync()
203
204```js
205const { cosmiconfigSync } = require('cosmiconfig');
206const explorerSync = cosmiconfigSync(moduleName[, cosmiconfigOptions])
207```
208
209Creates a *synchronous* cosmiconfig instance ("explorerSync") configured according to the arguments, and initializes its caches.
210
211See [`cosmiconfig()`].
212
213### explorerSync.search()
214
215```js
216const result = explorerSync.search([searchFrom]);
217```
218
219Synchronous version of [`explorer.search()`].
220
221Returns a [result] or `null`.
222
223### explorerSync.load()
224
225```js
226const result = explorerSync.load(loadPath);
227```
228
229Synchronous version of [`explorer.load()`].
230
231Returns a [result].
232
233### explorerSync.clearLoadCache()
234
235Clears the cache used in [`load()`].
236
237### explorerSync.clearSearchCache()
238
239Clears the cache used in [`search()`].
240
241### explorerSync.clearCaches()
242
243Performs both [`clearLoadCache()`] and [`clearSearchCache()`].
244
245## cosmiconfigOptions
246
247Type: `Object`.
248
249Possible options are documented below.
250
251### searchPlaces
252
253Type: `Array<string>`.
254Default: See below.
255
256An array of places that [`search()`] will check in each directory as it moves up the directory tree.
257Each place is relative to the directory being searched, and the places are checked in the specified order.
258
259**Default `searchPlaces`:**
260
261```js
262[
263 'package.json',
264 `.${moduleName}rc`,
265 `.${moduleName}rc.json`,
266 `.${moduleName}rc.yaml`,
267 `.${moduleName}rc.yml`,
268 `.${moduleName}rc.js`,
269 `.${moduleName}rc.cjs`,
270 `${moduleName}.config.js`,
271 `${moduleName}.config.cjs`,
272]
273```
274
275Create your own array to search more, fewer, or altogether different places.
276
277Every item in `searchPlaces` needs to have a loader in [`loaders`] that corresponds to its extension.
278(Common extensions are covered by default loaders.)
279Read more about [`loaders`] below.
280
281`package.json` is a special value: When it is included in `searchPlaces`, Cosmiconfig will always parse it as JSON and load a property within it, not the whole file.
282That property is defined with the [`packageProp`] option, and defaults to your module name.
283
284Examples, with a module named `porgy`:
285
286```js
287// Disallow extensions on rc files:
288[
289 'package.json',
290 '.porgyrc',
291 'porgy.config.js'
292]
293
294// ESLint searches for configuration in these places:
295[
296 '.eslintrc.js',
297 '.eslintrc.yaml',
298 '.eslintrc.yml',
299 '.eslintrc.json',
300 '.eslintrc',
301 'package.json'
302]
303
304// Babel looks in fewer places:
305[
306 'package.json',
307 '.babelrc'
308]
309
310// Maybe you want to look for a wide variety of JS flavors:
311[
312 'porgy.config.js',
313 'porgy.config.mjs',
314 'porgy.config.ts',
315 'porgy.config.coffee'
316]
317// ^^ You will need to designate custom loaders to tell
318// Cosmiconfig how to handle these special JS flavors.
319
320// Look within a .config/ subdirectory of every searched directory:
321[
322 'package.json',
323 '.porgyrc',
324 '.config/.porgyrc',
325 '.porgyrc.json',
326 '.config/.porgyrc.json'
327]
328```
329
330### loaders
331
332Type: `Object`.
333Default: See below.
334
335An object that maps extensions to the loader functions responsible for loading and parsing files with those extensions.
336
337Cosmiconfig exposes its default loaders on a named export `defaultLoaders`.
338
339**Default `loaders`:**
340
341```js
342const { defaultLoaders } = require('cosmiconfig');
343
344console.log(Object.entries(defaultLoaders))
345// [
346// [ '.cjs', [Function: loadJs] ],
347// [ '.js', [Function: loadJs] ],
348// [ '.json', [Function: loadJson] ],
349// [ '.yaml', [Function: loadYaml] ],
350// [ '.yml', [Function: loadYaml] ],
351// [ 'noExt', [Function: loadYaml] ]
352// ]
353```
354
355(YAML is a superset of JSON; which means YAML parsers can parse JSON; which is how extensionless files can be either YAML *or* JSON with only one parser.)
356
357**If you provide a `loaders` object, your object will be *merged* with the defaults.**
358So you can override one or two without having to override them all.
359
360**Keys in `loaders`** are extensions (starting with a period), or `noExt` to specify the loader for files *without* extensions, like `.myapprc`.
361
362**Values in `loaders`** are a loader function (described below) whose values are loader functions.
363
364**The most common use case for custom loaders value is to load extensionless `rc` files as strict JSON**, instead of JSON *or* YAML (the default).
365To accomplish that, provide the following `loaders` value:
366
367```js
368{
369 noExt: defaultLoaders['.json']
370}
371```
372
373If you want to load files that are not handled by the loader functions Cosmiconfig exposes, you can write a custom loader function or use one from NPM if it exists.
374
375**Third-party loaders:**
376
377- [@endemolshinegroup/cosmiconfig-typescript-loader](https://github.com/EndemolShineGroup/cosmiconfig-typescript-loader)
378
379**Use cases for custom loader function:**
380
381- Allow configuration syntaxes that aren't handled by Cosmiconfig's defaults, like JSON5, INI, or XML.
382- Allow ES2015 modules from `.mjs` configuration files.
383- Parse JS files with Babel before deriving the configuration.
384
385**Custom loader functions** have the following signature:
386
387```js
388// Sync
389(filepath: string, content: string) => Object | null
390
391// Async
392(filepath: string, content: string) => Object | null | Promise<Object | null>
393```
394
395Cosmiconfig reads the file when it checks whether the file exists, so it will provide you with both the file's path and its content.
396Do whatever you need to, and return either a configuration object or `null` (or, for async-only loaders, a Promise that resolves with one of those).
397`null` indicates that no real configuration was found and the search should continue.
398
399A few things to note:
400
401- If you use a custom loader, be aware of whether it's sync or async: you cannot use async customer loaders with the sync API ([`cosmiconfigSync()`]).
402- **Special JS syntax can also be handled by using a `require` hook**, because `defaultLoaders['.js']` just uses `require`.
403 Whether you use custom loaders or a `require` hook is up to you.
404
405Examples:
406
407```js
408// Allow JSON5 syntax:
409{
410 '.json': json5Loader
411}
412
413// Allow a special configuration syntax of your own creation:
414{
415 '.special': specialLoader
416}
417
418// Allow many flavors of JS, using custom loaders:
419{
420 '.mjs': esmLoader,
421 '.ts': typeScriptLoader,
422 '.coffee': coffeeScriptLoader
423}
424
425// Allow many flavors of JS but rely on require hooks:
426{
427 '.mjs': defaultLoaders['.js'],
428 '.ts': defaultLoaders['.js'],
429 '.coffee': defaultLoaders['.js']
430}
431```
432
433### packageProp
434
435Type: `string | Array<string>`.
436Default: `` `${moduleName}` ``.
437
438Name of the property in `package.json` to look for.
439
440Use a period-delimited string or an array of strings to describe a path to nested properties.
441
442For example, the value `'configs.myPackage'` or `['configs', 'myPackage']` will get you the `"myPackage"` value in a `package.json` like this:
443
444```json
445{
446 "configs": {
447 "myPackage": {..}
448 }
449}
450```
451
452If nested property names within the path include periods, you need to use an array of strings. For example, the value `['configs', 'foo.bar', 'baz']` will get you the `"baz"` value in a `package.json` like this:
453
454```json
455{
456 "configs": {
457 "foo.bar": {
458 "baz": {..}
459 }
460 }
461}
462```
463
464If a string includes period but corresponds to a top-level property name, it will not be interpreted as a period-delimited path. For example, the value `'one.two'` will get you the `"three"` value in a `package.json` like this:
465
466```json
467{
468 "one.two": "three",
469 "one": {
470 "two": "four"
471 }
472}
473```
474
475### stopDir
476
477Type: `string`.
478Default: Absolute path to your home directory.
479
480Directory where the search will stop.
481
482### cache
483
484Type: `boolean`.
485Default: `true`.
486
487If `false`, no caches will be used.
488Read more about ["Caching"](#caching) below.
489
490### transform
491
492Type: `(Result) => Promise<Result> | Result`.
493
494A function that transforms the parsed configuration. Receives the [result].
495
496If using [`search()`] or [`load()`] \(which are async), the transform function can return the transformed result or return a Promise that resolves with the transformed result.
497If using `cosmiconfigSync`, [`search()`] or [`load()`], the function must be synchronous and return the transformed result.
498
499The reason you might use this option — instead of simply applying your transform function some other way — is that *the transformed result will be cached*. If your transformation involves additional filesystem I/O or other potentially slow processing, you can use this option to avoid repeating those steps every time a given configuration is searched or loaded.
500
501### ignoreEmptySearchPlaces
502
503Type: `boolean`.
504Default: `true`.
505
506By default, if [`search()`] encounters an empty file (containing nothing but whitespace) in one of the [`searchPlaces`], it will ignore the empty file and move on.
507If you'd like to load empty configuration files, instead, set this option to `false`.
508
509Why might you want to load empty configuration files?
510If you want to throw an error, or if an empty configuration file means something to your program.
511
512## Caching
513
514As of v2, cosmiconfig uses caching to reduce the need for repetitious reading of the filesystem or expensive transforms. Every new cosmiconfig instance (created with `cosmiconfig()`) has its own caches.
515
516To avoid or work around caching, you can do the following:
517
518- Set the `cosmiconfig` option [`cache`] to `false`.
519- Use the cache-clearing methods [`clearLoadCache()`], [`clearSearchCache()`], and [`clearCaches()`].
520- Create separate instances of cosmiconfig (separate "explorers").
521
522## Differences from [rc](https://github.com/dominictarr/rc)
523
524[rc](https://github.com/dominictarr/rc) serves its focused purpose well. cosmiconfig differs in a few key ways — making it more useful for some projects, less useful for others:
525
526- Looks for configuration in some different places: in a `package.json` property, an rc file, a `.config.js` file, and rc files with extensions.
527- Built-in support for JSON, YAML, and CommonJS formats.
528- Stops at the first configuration found, instead of finding all that can be found up the directory tree and merging them automatically.
529- Options.
530- Asynchronous by default (though can be run synchronously).
531
532## Contributing & Development
533
534Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
535
536And please do participate!
537
538[result]: #result
539
540[`load()`]: #explorerload
541
542[`search()`]: #explorersearch
543
544[`clearloadcache()`]: #explorerclearloadcache
545
546[`clearsearchcache()`]: #explorerclearsearchcache
547
548[`cosmiconfig()`]: #cosmiconfig
549
550[`cosmiconfigSync()`]: #cosmiconfigsync
551
552[`clearcaches()`]: #explorerclearcaches
553
554[`packageprop`]: #packageprop
555
556[`cache`]: #cache
557
558[`stopdir`]: #stopdir
559
560[`searchplaces`]: #searchplaces
561
562[`loaders`]: #loaders
563
564[`cosmiconfigoptions`]: #cosmiconfigoptions
565
566[`explorerSync.search()`]: #explorersyncsearch
567
568[`explorerSync.load()`]: #explorersyncload
569
570[`explorer.search()`]: #explorersearch
571
572[`explorer.load()`]: #explorerload