UNPKG

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