# Coming from rc

> An rc alternative with a drop-in path: import rc from seniority/rc, graded 1 / 1 by rc's own test — one exit-code bit, not a case count — then rc's file stack and merge with none of its four dependencies, and a resolver that says where every value came from.

Source: https://seniority.interlace.tools/docs/coming-from/rc

**seniority** is an **rc alternative** that also covers what `cosmiconfig`, `dotenv` and
`find-up` do beside it: one resolution for flags, environment, config files, a
`package.json` field and defaults, in a fixed order, with no dependencies.

## Migrate from rc in one import

```diff
- import rc from 'rc';
+ import rc from 'seniority/rc';
```

The call is rc's — `rc(name, defaults, argv, parse)` — and so is what it does: the file stack
in rc's own order (`/etc/<name>/config`, `/etc/<name>rc`, the four places under the home
directory, the nearest `.<name>rc` walking up from the working directory, then a file named
by `config` in the environment or on the command line), `<name>_*` environment keys with `__`
read as nesting, JSON with comments, `deep-extend`'s merge (arrays replaced, not
concatenated), a string `defaults` read as JSON, and the `configs` / `config` report of which
files were read. Like rc, it reads the process's environment when you pass none.

**Two differences, both on purpose.**

- **INI is refused by name, not parsed.** seniority bundles no format parser, so a file that
  is not JSON is refused with the fix in the error. Pass `ini.parse` in rc's own fourth
  position and you have rc's behaviour, with the parser as your dependency rather than
  everyone's.
- **The command line is an argument.** When `argv` is falsy, rc 1.2.8 fills it with
  `minimist(process.argv.slice(2))`; `seniority/rc` treats an omitted `argv` as empty and
  never reads the command line. Pass the flags you already parsed as the third argument.

```js
import rc from 'seniority/rc';

const config = rc('mytool', defaults, flags);
```

A fifth argument, `{ env, cwd, home, win }`, supplies the rest of the world when you would
rather not have it read from the process — which is how it is tested.

## Is seniority compatible with rc?

Graded, and the grade is coarse. rc's `test/test.js`, vendored from 1.2.8 and unmodified
apart from the import specifier, runs against `seniority/rc` beside a control that runs it
against real rc:

| | passing | grade |
| :-- | --: | :-- |
| `seniority/rc` | 1 / 1 | by exit code |
| rc itself (control) | 1 / 1 | by exit code |

From [Compatibility](https://burgee.interlace.tools/docs/compatibility), which `npm run compat:page` generates from the
oracle's last run; that page is the authority. **Read `1 / 1` as one bit, not one case:** rc's
suite is scripts of bare `assert` calls with no reporter, so the only honest grade is that
the script ran against this target and exited 0. That script covers an environment option,
a nopt-shaped `argv` outranking it, and a commented JSON `.<name>rc` in the working directory
with its `config` and `configs` report. rc 1.2.8 was never tagged upstream, so the suite is
taken from the repository's head at commit `a97f6ad`. rc's two other test files are not
graded: `ini.js` tests an internal and the `ini` package, and `nested-env-vars.js` is public
and not graded yet.

The same page grades `seniority` (cosmiconfig's own suite), `seniority/lilconfig` and
`seniority/dotenv`.

## What you gain over rc

rc 1.2.8 depends on `deep-extend`, `ini`, `minimist` and `strip-json-comments`.
`seniority/rc` depends on nothing. And where rc merges, seniority also resolves the value
and keeps the receipt:

- **Provenance on every value.** `resolve()` returns each option's winning source and every
  candidate it beat, where rc's `configs` only lists the files it read.
  `explanationJson()` is that record as `--json` data and `explanationEvent()` as an agent
  event, generated by the code that picked the value.
- **An order nobody can rearrange.** `flag > env > config file > package.json field >
  default`, exported as `ORDER`. A plugin can add a source between them and can never beat
  the flag the user typed.
- **A bounded walk.** The upward search for `.<name>rc` stops at sixty-four levels, so no
  directory tree can turn it into a hang.

## When to switch from rc

- Your rc files are JSON, or you are content to pass `ini.parse` in.
- You already parse your own flags, and would rather rc did not parse `process.argv` a
  second time behind them.
- "Why is this set to that?" is a question your users or agents ask.

The API, the discovery rules and the other drop-in paths are on
[seniority](/docs).
