Skip to content

Commit

Permalink
Merge branch 'master' into add-node-cli-require-support
Browse files Browse the repository at this point in the history
  • Loading branch information
motdotla authored Feb 1, 2022
2 parents 736833f + 1cc80d0 commit b5a5e85
Show file tree
Hide file tree
Showing 15 changed files with 6,789 additions and 967 deletions.
3 changes: 2 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
coverage/
examples/
test/
tests/
.editorconfig
.travis.yml
Contributing.md
dotenv-expand.png
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ node_js:
- 5
- 6
- 7
- 8
- 9
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Changelog

All notable changes to this project will be documented in this file. See [standard-version](/~https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [Unreleased](/~https://github.com/motdotla/dotenv-expand/compare/v6.0.1...master)

## [6.0.1](/~https://github.com/motdotla/dotenv-expand/compare/v6.0.0...v6.0.1) (2022-01-17)

### Changed

- Updated README

## [6.0.0](/~https://github.com/motdotla/dotenv-expand/compare/v5.1.0...v6.0.0) (2022-01-17)

### Changed

- _Breaking_ Move default export to export of `expand` function ([#14b1f2](/~https://github.com/motdotla/dotenv-expand/commit/14b1f28f608bc73450dca8c5aaf3a1e4f65e09ca))

### Added

- Add default expansion 🎉 ([#39](/~https://github.com/motdotla/dotenv-expand/pull/39))
- Add missing type descriptions

## 5.1.0 and prior

Please see commit history.




109 changes: 104 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
<p align="center">
<strong>Announcement 📣</strong><br/>From the makers that brought you Dotenv, introducing <a href="https://sync.dotenv.org">Dotenv Sync</a>.<br/>Sync your .env files between machines, environments, and team members.<br/><a href="https://sync.dotenv.org">Join the early access list.💛</a>
</p>

# dotenv-expand

<img src="https://raw.githubusercontent.com/motdotla/dotenv-expand/master/dotenv-expand.png" alt="dotenv-expand" align="right" />
Expand All @@ -14,25 +18,116 @@ dotenv-expand is your tool.
## Install

```bash
# Install locally (recommended)
npm install dotenv --save
npm install dotenv-expand --save
```

Or installing with yarn? `yarn add dotenv-expand`

## Usage

As early as possible in your application, require dotenv and dotenv-expand, and
wrap dotenv-expand around dotenv.
Usage is a cinch!

### 1. Create a .env file with variable expansions in the root directory of your project

```dosini
# .env file
#
# Add environment-specific variables on new lines in the form of NAME=VALUE
#
PASSWORD=s1mpl3
DB_HOST=localhost
DB_USER=root
DB_PASS=$PASSWORD
```

### 2. As early as possible in your application, import dotenv and expand with dotenv-expand

```js
var dotenv = require('dotenv')
var dotenvExpand = require('dotenv-expand')

var myEnv = dotenv.config()
dotenvExpand(myEnv)
dotenvExpand.expand(myEnv)

console.log(process.env)
```

### 3. That's it! 👏

`process.env` now has the expanded keys and values you defined in your `.env` file.

## Examples

See [tests/.env](/~https://github.com/motdotla/dotenv-expand/blob/master/tests/.env) for simple and complex examples of variable expansion in your `.env`
file.

## Documentation

DotenvExpand exposes one function:

* expand

### Expand

`expand` will expand your environment variables.

```js
const dotenv = {
parsed: {
BASIC: 'basic',
BASIC_EXPAND: '${BASIC}',
BASIC_EXPAND_SIMPLE: '$BASIC'
}
}

const obj = dotenvExpand.expand(dotenv)

console.log(obj)
```

#### Options

##### ignoreProcessEnv

Default: `false`

Turn off writing to `process.env`.

```js
const dotenv = {
ignoreProcessEnv: true,
parsed: {
SHOULD_NOT_EXIST: 'testing'
}
}
const obj = dotenvExpand.expand(dotenv).parsed

console.log(obj.SHOULD_NOT_EXIST) // testing
console.log(process.env.SHOULD_NOT_EXIST) // undefined
```

See [test/.env](./test/.env) for examples of variable expansion in your `.env`
file.
## FAQ

### What rules does the expansion engine follow?

The expansion engine roughly has the following rules:

* `$KEY` will expand any env with the name `KEY`
* `${KEY}` will expand any env with the name `KEY`
* `\$KEY` will escape the `$KEY` rather than expand
* `${KEY:-default}` will first attempt to expand any env with the name `KEY`. If not one, then it will return `default`

You can see a full list of examples [here](/~https://github.com/motdotla/dotenv-expand/blob/master/tests/.env).

## Contributing Guide

See [CONTRIBUTING.md](CONTRIBUTING.md)

## CHANGELOG

See [CHANGELOG.md](CHANGELOG.md)

### Preload

Expand All @@ -57,3 +152,7 @@ $ DOTENV_CONFIG_<OPTION>=value node -r dotenv-extend/config your_script.js
```bash
$ DOTENV_CONFIG_ENCODING=latin1 node -r dotenv-extend/config your_script.js dotenv_config_path=/custom/path/to/.env
```

## Who's using dotenv-expand?

[These npm modules depend on it.](https://www.npmjs.com/browse/depended/dotenv-expand)
Binary file modified dotenv-expand.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 0 additions & 15 deletions index.d.ts

This file was deleted.

29 changes: 29 additions & 0 deletions lib/main.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// TypeScript Version: 3.0
/// <reference types="node" />

export interface DotenvExpandOptions {
ignoreProcessEnv?: boolean;
error?: Error;
parsed?: {
[name: string]: string;
}
}

export interface DotenvExpandOutput {
ignoreProcessEnv?: boolean;
error?: Error;
parsed?: {
[name: string]: string;
};
}

/**
* Adds variable expansion on top of dotenv.
*
* See https://docs.dotenv.org
*
* @param options - additional options. example: `{ ignoreProcessEnv: false, error: null, parsed: { { KEY: 'value' } }`
* @returns an object with a `parsed` key if successful or `error` key if an error occurred. example: { parsed: { KEY: 'value' } }
*
*/
export function expand(options?: DotenvExpandOptions): DotenvExpandOutput
78 changes: 46 additions & 32 deletions lib/main.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,60 @@
'use strict'

var dotenvExpand = function (config) {
// if ignoring process.env, use a blank object
var environment = config.ignoreProcessEnv ? {} : process.env

var interpolate = function (envValue) {
var matches = envValue.match(/(.?\${?(?:[a-zA-Z0-9_]+)?}?)/g) || []

return matches.reduce(function (newEnv, match) {
var parts = /(.?)\${?([a-zA-Z0-9_]+)?}?/g.exec(match)
var prefix = parts[1]

var value, replacePart

if (prefix === '\\') {
replacePart = parts[0]
value = replacePart.replace('\\$', '$')
} else {
var key = parts[2]
replacePart = parts[0].substring(prefix.length)
// process.env value 'wins' over .env file's value
value = environment.hasOwnProperty(key) ? environment[key] : (config.parsed[key] || '')

// Resolve recursive interpolations
value = interpolate(value)
function _interpolate (envValue, environment, config) {
const matches = envValue.match(/(.?\${*[\w]*(?::-)?[\w]*}*)/g) || []

return matches.reduce(function (newEnv, match, index) {
const parts = /(.?)\${*([\w]*(?::-)?[\w]*)?}*/g.exec(match)
if (!parts || parts.length === 0) {
return newEnv
}

const prefix = parts[1]

let value, replacePart

if (prefix === '\\') {
replacePart = parts[0]
value = replacePart.replace('\\$', '$')
} else {
const keyParts = parts[2].split(':-')
const key = keyParts[0]
replacePart = parts[0].substring(prefix.length)
// process.env value 'wins' over .env file's value
value = Object.prototype.hasOwnProperty.call(environment, key)
? environment[key]
: (config.parsed[key] || keyParts[1] || '')

// If the value is found, remove nested expansions.
if (keyParts.length > 1 && value) {
const replaceNested = matches[index + 1]
matches[index + 1] = ''

newEnv = newEnv.replace(replaceNested, '')
}
// Resolve recursive interpolations
value = _interpolate(value, environment, config)
}

return newEnv.replace(replacePart, value)
}, envValue)
}
return newEnv.replace(replacePart, value)
}, envValue)
}

function expand (config) {
// if ignoring process.env, use a blank object
const environment = config.ignoreProcessEnv ? {} : process.env

for (var configKey in config.parsed) {
var value = environment.hasOwnProperty(configKey) ? environment[configKey] : config.parsed[configKey]
for (const configKey in config.parsed) {
const value = Object.prototype.hasOwnProperty.call(environment, configKey) ? environment[configKey] : config.parsed[configKey]

config.parsed[configKey] = interpolate(value)
config.parsed[configKey] = _interpolate(value, environment, config)
}

for (var processKey in config.parsed) {
for (const processKey in config.parsed) {
environment[processKey] = config.parsed[processKey]
}

return config
}

module.exports = dotenvExpand
module.exports.expand = expand
Loading

0 comments on commit b5a5e85

Please sign in to comment.