Skip to content

Commit

Permalink
docs: add usage section & various tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
ngryman committed Nov 16, 2020
1 parent fb53658 commit 49ca2e3
Showing 1 changed file with 131 additions and 27 deletions.
158 changes: 131 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<p align="center">
<a href="#features">Features</a> β€’
<a href="#getting-started">Gettings Started</a> β€’
<a href="#getting-started">Getting Started</a> β€’
<a href="#usage">Usage</a> β€’
<a href="#api">API</a> β€’
</p>
Expand All @@ -21,11 +21,11 @@

## Features

- **One dependency** to load and validate your settings.
- **Load from multiple sources** such as JSON, YAML, JavaScript, Typescript, CLI arguments, and environment variables.
- **Validate your settings** with a JSON schema. BONUS: Your settings files have auto-completion in VSCode!
- **One dependency** to load and validate your configuration.
- **Load from multiple sources** such as JSON, YAML, JavaScript, Typescript, command-line arguments, and environment variables.
- **Validate your configuration** with a JSON schema. BONUS: Your configuration files have auto-completion in VSCode!
- **Generate types** for your Typescript code and for Typescript configuration files.
- **Expand environment variables** in any settings value.
- **Expand environment variables** in any configuration value.

## Getting Started

Expand All @@ -44,74 +44,178 @@ npm install fauda
```json
{
"$schema": "http://json-schema.org/draft-07/schema",
"title": "My awesome package settings",
"title": "My awesome pasta app configuration",
"type": "object",
"properties": {
"$schema": {
"description": "Path to my package's schema.",
"description": "Path to my pasta app's schema.",
"type": "string"
},
"address": {
"description": "The address the server listens on.",
"type": {
"description": "The type of pasta.",
"type": "string",
"default": "0.0.0.0"
"enum": ["Fettuccine", "Tagliatelle"],
"required": true,
"default": "Fettuccine"
},
"port": {
"description": "The port the server listens on.",
"cookingTime": {
"description": "Cooking time in seconds.",
"type": "number",
"default": 3000
"default": 300
},
"pages": {
"description": "A list of pages to serve.",
"seasoning": {
"description": "A list of seasoning ingredients.",
"type": "array",
"items": {
"type": "string"
},
"default": ["/home"]
"default": ["Salt", "Pepper", "Olive Oil", "Pecorino"]
}
}
}
```

Fauda relies on a [JSON schema](https://json-schema.org/) to load and validate your settings, but also to generate types.
Fauda relies on a [JSON schema](https://json-schema.org/) to load and validate your configuration, but also to generate types.

For more information please take a look at TODO.

</details>

<details>
<summary><b>3️⃣ Generate</b> Typescript typings _(optional)_</summary><br>
<summary><b>3️⃣ Generate</b> Typescript typings <i>optional</i></summary><br>

```sh
$ npx fauda types
```

This will generate the `Settings` type in `src/settings.ts` by default.
This will generate the `Configuration` type in `src/configuration.ts` by default.

```ts
export interface Settings {
address?: string
port?: number
pages?: string[]
export interface Configuration {
type: 'Fettuccine' | 'Tagliatelle'
cookingTime?: number
seasoning?: string[]
}
```

</details>

<details>
<summary><b>4️⃣ Load & validate</b> your settings.</summary><br>
<summary><b>4️⃣ Load & validate</b> your configuration.</summary><br>

Assuming your package is named `pasta`:

```ts
import fauda from 'fauda'
import { Settings } from './settings'
import { Configuration } from './configuration'

async function loadSettings() {
async function loadConfiguration() {
try {
const settings = await fauda<Settings>('myPackage')
const configuration = await fauda<Configuration>('pasta')
} catch (err) {
console.error(err.message)
}
}
```

</details>

## How does Fauda work?

It first collects your configuration from various sources at the same time:

- Environment variables
- Command-line arguments
- Configuration files

Once collected, configurations are merged using the above order of precedence. It means that if the same option is collected from both an environment variable and a configuration file, the former will kept.

Finally, it normalizes your configuration. The normalization process validates your configuration using the provided JSON schema. It checks that the types of the collected options are valid and sets default values if necessary. It also expand environment variables that are references in options.

<details>
<summary><i>πŸ™‹πŸ»β€β™‚οΈ What is environment variable expansion?</i></summary><br>

You can reference an environment variable's name as your option's value. Fauda will replace it by the variable's value when loading the configuration.

Here's an example of an option referencing a environment variable:

```json
{
"cookingTime": "${SOME_VAR}"
}
```

</details>

## Usage

## Configuration files

First, it tries to find the `config.${myPackage}` property in your `package.json` file.

Then, it tries to load a configuration file starting from the current directory up to the root.

The following files are supported by default:

| File | Format |
| ---------------------------------- | ------ |
| `.${namespace}rc` | `json` |
| `${namespace}.config.js` | `js` |
| `${namespace}.config.json` | `json` |
| `${namespace}.config.ts` | `ts` |
| `${namespace}.config.yaml` | `yaml` |
| `${namespace}.config.yml` | `yaml` |
| `.config/${namespace}rc` | `json` |
| `.config/${namespace}.config.js` | `js` |
| `.config/${namespace}.config.json` | `json` |
| `.config/${namespace}.config.ts` | `ts` |
| `.config/${namespace}.config.yaml` | `yaml` |
| `.config/\${namespace}.config.yml` | `yaml` |

You can however customize these defaults with the [TODO] options.

## Command-line arguments

Fauda parses command-line arguments as you can expect from any other argument parsers!

<details>
<summary><i>πŸ™‹πŸ»β€β™‚οΈ What about arrays?</i></summary><br>

Arrays are supported in two ways.

1. Declare a JSON-compatible array as value.
2. Use the same argument multiple times.

Here's an example that gives the same result:

```sh
$ pasta --types=Fettuccine --types=Fettuccine
$ pasta --types="['Fettuccine', 'Tagliatelle']"
```

</details>

## Environment variables

Fauda parses environment variables that are prefixed with your package's name. This is done to avoid name clashes with other tools of system-wide environment variables.

For instance, if your package's name is `pasta`, then Fauda will parse variables starting with `PASTA_`.

<details>
<summary><i>πŸ™‹πŸ»β€β™‚οΈ What about arrays?</i></summary><br>

Arrays are supported! You simply need to declare a JSON-compatible array wrapped between quotes.

Here's an example:

```sh
$ PASTA_TYPES="['Fettuccine', 'Tagliatelle']"
```

</details>

## FAQ

### Why not supporting nested options?

Fauda only supports a flat options object, simply because it's easier to manipulate and to reason about. Nested options are usually neither a good idea as it makes merging default options harder, nor necessary as one can express a sense of hierarchy using "dotted names" instead (eg. `cooking.time`) or just camel case (eg. `cookingTime`).

0 comments on commit 49ca2e3

Please sign in to comment.