UNPKG

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