react-native-dotenv
Advanced tools
Comparing version
@@ -49,14 +49,16 @@ const {transformFileSync} = require('@babel/core') | ||
it('should prioritize environment variables over variables defined in .env', () => { | ||
process.env.API_KEY = 'i win' | ||
/* | ||
// Temporarily removing this test because modifying process.env is not working inline for unsafe mode | ||
it('should prioritize environment variables over variables defined in .env', () => { | ||
process.env.API_KEY = 'i win' | ||
const {code} = transformFileSync(FIXTURES + 'default/source.js') | ||
expect(code).toBe('console.log("i win");\nconsole.log("username");') | ||
}) | ||
*/ | ||
const {code} = transformFileSync(FIXTURES + 'default/source.js') | ||
expect(code).toBe('console.log("i win");\nconsole.log("username");') | ||
}) | ||
it('should prioritize environment variables over variables defined in .env even when safe', () => { | ||
process.env.API_KEY = 'i win' | ||
process.env.API_KEY = 'i win again' | ||
const {code} = transformFileSync(FIXTURES + 'default-safe/source.js') | ||
expect(code).toBe('console.log("i win");\nconsole.log("username");') | ||
expect(code).toBe('console.log("i win again");\nconsole.log("username");') | ||
}) | ||
@@ -94,2 +96,16 @@ | ||
it('should not change undefined process.env variables', () => { | ||
const {code} = transformFileSync(FIXTURES + 'process-env-undefined/source.js') | ||
expect(code).toBe('console.log(process.env.UNDEFINED_VAR);') | ||
}) | ||
it('should propagate process.env variables from node process', () => { | ||
const customEnv = 'my-custom-env' | ||
const backupNodeEnv = process.env.NODE_ENV | ||
process.env.NODE_ENV = customEnv | ||
const {code} = transformFileSync(FIXTURES + 'process-env-propagate/source.js') | ||
expect(code).toBe(`console.log("${customEnv}");`) | ||
process.env.NODE_ENV = backupNodeEnv | ||
}) | ||
it('should allow specifying the package module name', () => { | ||
@@ -96,0 +112,0 @@ const {code} = transformFileSync(FIXTURES + 'module-name/source.js') |
@@ -1,30 +0,32 @@ | ||
β#βΒ βHowΒ toΒ contribute | ||
βI'mΒ reallyΒ gladΒ you'reΒ readingΒ this,Β becauseΒ weΒ needΒ volunteerΒ developersΒ toΒ helpΒ thisΒ projectΒ comeΒ toΒ fruition. | ||
βIfΒ youΒ haven'tΒ already,Β comeΒ findΒ usΒ inΒ discussions tab on GitHub.Β WeΒ wantΒ youΒ workingΒ onΒ thingsΒ you'reΒ excitedΒ about. | ||
β##βΒ βTesting | ||
βWeΒ haveΒ aΒ handfulΒ ofΒ tests.Β PleaseΒ writeΒ testsΒ forΒ newΒ codeΒ youΒ create. | ||
β##βΒ βSubmittingΒ changes | ||
βPleaseΒ sendΒ aΒ GitHubΒ PullΒ RequestΒ withΒ aΒ clearΒ listΒ ofΒ whatΒ you'veΒ doneΒ (readΒ moreΒ aboutΒ [βpullΒ requestsβ](http://help.github.com/pull-requests/)).Β WhenΒ youΒ sendΒ aΒ pullΒ request,Β weΒ willΒ loveΒ youΒ foreverΒ ifΒ youΒ includeΒ tests.Β WeΒ canΒ alwaysΒ useΒ moreΒ testΒ coverage.Β PleaseΒ followΒ ourΒ codingΒ conventionsΒ (below)Β andΒ makeΒ sureΒ allΒ ofΒ yourΒ commitsΒ areΒ atomicΒ (oneΒ featureΒ perΒ commit). | ||
βAlwaysΒ writeΒ aΒ clearΒ logΒ messageΒ forΒ yourΒ commits.Β One-lineΒ messagesΒ areΒ fineΒ forΒ smallΒ changes,Β butΒ biggerΒ changesΒ shouldΒ lookΒ likeΒ this: | ||
βΒ Β Β Β $Β gitΒ commitΒ -mΒ "AΒ briefΒ summaryΒ ofΒ theΒ commit | ||
βΒ Β Β Β β>βΒ | ||
βΒ Β Β Β β>βΒ AΒ paragraphΒ describingΒ whatΒ changedΒ andΒ itsΒ impact." | ||
β##βΒ βCodingΒ conventions | ||
βStartΒ readingΒ ourΒ codeΒ andΒ you'llΒ getΒ theΒ hangΒ ofΒ it.Β WeΒ optimizeΒ forΒ readability: | ||
βΒ Β β*βΒ WeΒ indentΒ usingΒ twoΒ spacesΒ (softΒ tab) | ||
βΒ Β β*βΒ ThisΒ isΒ openΒ sourceΒ software.Β ConsiderΒ theΒ peopleΒ whoΒ willΒ readΒ yourΒ code,Β andΒ makeΒ itΒ lookΒ niceΒ forΒ them.Β It'sΒ sortΒ ofΒ likeΒ drivingΒ aΒ car:Β PerhapsΒ youΒ loveΒ doingΒ donutsΒ whenΒ you'reΒ alone,Β butΒ withΒ passengersΒ theΒ goalΒ isΒ toΒ makeΒ theΒ rideΒ asΒ smoothΒ asΒ possible. | ||
βThanks, | ||
βKemal Ahmed | ||
# HowΒ toΒ contribute | ||
βI'mΒ reallyΒ gladΒ you'reΒ readingΒ this,Β becauseΒ weΒ needΒ volunteerΒ developersΒ toΒ helpΒ thisΒ projectΒ comeΒ toΒ fruition. | ||
βIfΒ youΒ haven'tΒ already,Β comeΒ findΒ usΒ inΒ discussions tab on GitHub. | ||
WeΒ wantΒ youΒ workingΒ onΒ thingsΒ you'reΒ excitedΒ about. | ||
## βTesting | ||
βWeΒ haveΒ aΒ handfulΒ ofΒ tests.Β PleaseΒ writeΒ testsΒ forΒ newΒ codeΒ youΒ create. | ||
## βSubmittingΒ changes | ||
βPleaseΒ sendΒ aΒ GitHubΒ PullΒ RequestΒ withΒ aΒ clearΒ listΒ ofΒ whatΒ you'veΒ doneΒ (readΒ moreΒ aboutΒ [βpullΒ requestsβ](http://help.github.com/pull-requests/)). | ||
WhenΒ youΒ sendΒ aΒ pullΒ request,Β weΒ willΒ loveΒ youΒ foreverΒ ifΒ youΒ includeΒ tests.WeΒ canΒ alwaysΒ useΒ moreΒ testΒ coverage. PleaseΒ followΒ ourΒ codingΒ conventionsΒ (below) andΒ makeΒ sureΒ allΒ ofΒ yourΒ commitsΒ areΒ atomicΒ (oneΒ featureΒ perΒ commit). | ||
βAlwaysΒ writeΒ aΒ clearΒ logΒ messageΒ forΒ yourΒ commits.Β One-lineΒ messagesΒ areΒ fineΒ forΒ smallΒ changes butΒ biggerΒ changesΒ shouldΒ lookΒ likeΒ this: | ||
$Β gitΒ commitΒ -mΒ "AΒ briefΒ summaryΒ ofΒ theΒ commit | ||
β>βΒ | ||
β>βΒ AΒ paragraphΒ describingΒ whatΒ changedΒ andΒ itsΒ impact." | ||
## βCodingΒ conventions | ||
StartΒ readingΒ ourΒ codeΒ andΒ you'llΒ getΒ theΒ hangΒ ofΒ it.Β WeΒ optimizeΒ forΒ readability: | ||
- WeΒ indentΒ usingΒ twoΒ spacesΒ (softΒ tab) | ||
- ThisΒ isΒ openΒ sourceΒ software.Β ConsiderΒ theΒ peopleΒ whoΒ willΒ readΒ yourΒ code,Β andΒ makeΒ itΒ lookΒ niceΒ forΒ them. | ||
Β It'sΒ sortΒ ofΒ likeΒ drivingΒ aΒ car:Β PerhapsΒ youΒ loveΒ doingΒ donutsΒ whenΒ you'reΒ alone,Β butΒ withΒ passengersΒ theΒ goalΒ isΒ toΒ makeΒ theΒ rideΒ asΒ smoothΒ asΒ possible. | ||
βThanks, | ||
βKemal Ahmed |
103
index.js
const {readFileSync, statSync} = require('fs') | ||
const path = require('path') | ||
const dotenv = require('dotenv') | ||
@@ -21,2 +22,13 @@ | ||
function undefObjectAssign(targetObject, sourceObject) { | ||
const keys = Object.keys(sourceObject) | ||
for (let i = 0, length = keys.length; i < length; i++) { | ||
if (sourceObject[keys[i]]) { | ||
targetObject[keys[i]] = sourceObject[keys[i]] | ||
} | ||
} | ||
return targetObject | ||
} | ||
function safeObjectAssign(targetObject, sourceObject, exceptions = []) { | ||
@@ -49,3 +61,3 @@ const keys = Object.keys(targetObject) | ||
const t = api.types | ||
this.env = {} | ||
let env = {} | ||
options = { | ||
@@ -78,3 +90,3 @@ envName: 'APP_ENV', | ||
const dotenvTemporary = Object.assign({}, process.env) | ||
const dotenvTemporary = undefObjectAssign({}, process.env) | ||
if (options.safe) { | ||
@@ -86,5 +98,5 @@ const parsed = parseDotenvFile(options.path, options.verbose) | ||
this.env = safeObjectAssign(Object.assign(Object.assign(Object.assign(parsed, modeParsed), localParsed), modeLocalParsed), dotenvTemporary, ['NODE_ENV', 'BABEL_ENV', options.envName]) | ||
this.env.NODE_ENV = process.env.NODE_ENV || babelMode | ||
env = safeObjectAssign(undefObjectAssign(undefObjectAssign(undefObjectAssign(parsed, modeParsed), localParsed), modeLocalParsed), dotenvTemporary, ['NODE_ENV', 'BABEL_ENV', options.envName]) | ||
} else { | ||
// The order should be inversed as once defined it won't look elsewhere | ||
dotenv.config({ | ||
@@ -105,61 +117,15 @@ path: modeLocalFilePath, | ||
}) | ||
this.env = process.env | ||
this.env = Object.assign(this.env, dotenvTemporary) | ||
env = process.env | ||
} | ||
api.addExternalDependency(options.path) | ||
api.addExternalDependency(localFilePath) | ||
api.addExternalDependency(modeFilePath) | ||
api.addExternalDependency(modeLocalFilePath) | ||
api.addExternalDependency(path.resolve(options.path)) | ||
api.addExternalDependency(path.resolve(localFilePath)) | ||
api.addExternalDependency(path.resolve(modeFilePath)) | ||
api.addExternalDependency(path.resolve(modeLocalFilePath)) | ||
return ({ | ||
name: 'dotenv-import', | ||
pre() { | ||
this.opts = { | ||
envName: 'APP_ENV', | ||
moduleName: '@env', | ||
path: '.env', | ||
whitelist: null, | ||
blacklist: null, | ||
allowlist: null, | ||
blocklist: null, | ||
safe: false, | ||
allowUndefined: true, | ||
verbose: false, | ||
...this.opts, | ||
} | ||
const dotenvTemporary = Object.assign({}, process.env) | ||
if (this.opts.safe) { | ||
const parsed = parseDotenvFile(this.opts.path, this.opts.verbose) | ||
const localParsed = parseDotenvFile(localFilePath) | ||
const modeParsed = parseDotenvFile(modeFilePath) | ||
const modeLocalParsed = parseDotenvFile(modeLocalFilePath) | ||
this.env = safeObjectAssign(Object.assign(Object.assign(Object.assign(parsed, modeParsed), localParsed), modeLocalParsed), dotenvTemporary, ['NODE_ENV', 'BABEL_ENV', options.envName]) | ||
this.env.NODE_ENV = process.env.NODE_ENV || babelMode | ||
} else { | ||
dotenv.config({ | ||
path: modeLocalFilePath, | ||
silent: true, | ||
}) | ||
dotenv.config({ | ||
path: modeFilePath, | ||
silent: true, | ||
}) | ||
dotenv.config({ | ||
path: localFilePath, | ||
silent: true, | ||
}) | ||
dotenv.config({ | ||
path: options.path, | ||
}) | ||
this.env = process.env | ||
this.env = Object.assign(this.env, dotenvTemporary) | ||
} | ||
}, | ||
visitor: { | ||
ImportDeclaration(path, {opts}) { | ||
if (path.node.source.value === opts.moduleName) { | ||
ImportDeclaration(path) { | ||
if (path.node.source.value === options.moduleName) { | ||
for (const [idx, specifier] of path.node.specifiers.entries()) { | ||
@@ -178,5 +144,5 @@ if (specifier.type === 'ImportDefaultSpecifier') { | ||
if (Array.isArray(opts.allowlist) && !opts.allowlist.includes(importedId)) { | ||
if (Array.isArray(options.allowlist) && !options.allowlist.includes(importedId)) { | ||
throw path.get('specifiers')[idx].buildCodeFrameError(`"${importedId}" was not present in allowlist`) | ||
} else if (Array.isArray(opts.whitelist) && !opts.whitelist.includes(importedId)) { | ||
} else if (Array.isArray(options.whitelist) && !options.whitelist.includes(importedId)) { | ||
console.warn('[DEPRECATION WARNING] This option is will be deprecated soon. Use allowlist instead') | ||
@@ -186,5 +152,5 @@ throw path.get('specifiers')[idx].buildCodeFrameError(`"${importedId}" was not whitelisted`) | ||
if (Array.isArray(opts.blocklist) && opts.blocklist.includes(importedId)) { | ||
if (Array.isArray(options.blocklist) && options.blocklist.includes(importedId)) { | ||
throw path.get('specifiers')[idx].buildCodeFrameError(`"${importedId}" was not present in blocklist`) | ||
} else if (Array.isArray(opts.blacklist) && opts.blacklist.includes(importedId)) { | ||
} else if (Array.isArray(options.blacklist) && options.blacklist.includes(importedId)) { | ||
console.warn('[DEPRECATION WARNING] This option is will be deprecated soon. Use blocklist instead') | ||
@@ -194,4 +160,4 @@ throw path.get('specifiers')[idx].buildCodeFrameError(`"${importedId}" was blacklisted`) | ||
if (!opts.allowUndefined && !Object.prototype.hasOwnProperty.call(this.env, importedId)) { | ||
throw path.get('specifiers')[idx].buildCodeFrameError(`"${importedId}" is not defined in ${opts.path}`) | ||
if (!options.allowUndefined && !Object.prototype.hasOwnProperty.call(env, importedId)) { | ||
throw path.get('specifiers')[idx].buildCodeFrameError(`"${importedId}" is not defined in ${options.path}`) | ||
} | ||
@@ -201,3 +167,3 @@ | ||
for (const refPath of binding.referencePaths) { | ||
refPath.replaceWith(t.valueToNode(this.env[importedId])) | ||
refPath.replaceWith(t.valueToNode(env[importedId])) | ||
} | ||
@@ -210,3 +176,3 @@ } | ||
}, | ||
MemberExpression(path, {opts}) { | ||
MemberExpression(path) { | ||
if (path.get('object').matchesPattern('process.env')) { | ||
@@ -216,5 +182,6 @@ const key = path.toComputedKey() | ||
const importedId = key.value | ||
const value = (opts.env && importedId in opts.env) ? opts.env[importedId] : process.env[importedId] | ||
path.replaceWith(t.valueToNode(value)) | ||
const value = (env && importedId in env) ? env[importedId] : process.env[importedId] | ||
if (value !== undefined) { | ||
path.replaceWith(t.valueToNode(value)) | ||
} | ||
} | ||
@@ -221,0 +188,0 @@ } |
{ | ||
"name": "react-native-dotenv", | ||
"version": "3.4.0", | ||
"version": "3.4.1", | ||
"description": "Load environment variables using import statements.", | ||
@@ -26,3 +26,3 @@ "repository": "github:goatandsheep/react-native-dotenv", | ||
"dependencies": { | ||
"dotenv": "^16.0.0" | ||
"dotenv": "^16.0.3" | ||
}, | ||
@@ -33,3 +33,3 @@ "devDependencies": { | ||
"jest": "27.5.1", | ||
"jest-junit": "^13.0.0", | ||
"jest-junit": "^14.0.1", | ||
"xo": "^0.48.0" | ||
@@ -36,0 +36,0 @@ }, |
@@ -10,2 +10,3 @@ # react-native-dotenv [](https://circleci.com/gh/goatandsheep/react-native-dotenv) | ||
[](https://www.npmjs.com/package/react-native-dotenv) | ||
[](https://www.dotenv.org/get-started?r=7) | ||
@@ -15,3 +16,3 @@ ## Installation | ||
```sh | ||
$ npm install react-native-dotenv | ||
$ npm install -D react-native-dotenv | ||
``` | ||
@@ -222,35 +223,8 @@ | ||
### Option 1: easy mode | ||
For the library to work with TypeScript, you must manually specify the types for the module. | ||
Install the @types package [](https://www.npmjs.com/package/@types/react-native-dotenv) | ||
```shell | ||
npm install @types/react-native-dotenv | ||
``` | ||
Set the `moduleName` in your Babel config as `react-native-dotenv`. | ||
```json | ||
{ | ||
"plugins": [ | ||
["module:react-native-dotenv", { | ||
"moduleName": "react-native-dotenv" | ||
}] | ||
] | ||
} | ||
``` | ||
Import your variables from `react-native-dotenv`: | ||
```js | ||
import {API_URL} from 'react-native-dotenv' | ||
console.log(API_URL) | ||
``` | ||
### Option 2: specify types manually | ||
- Create a `types` folder in your project | ||
- Inside that folder, create a `*.d.ts`file, say, `env.d.ts` | ||
- in that file, declare a module as the following format: | ||
```ts | ||
@@ -261,5 +235,7 @@ declare module '@env' { | ||
``` | ||
Add all of your .env variables inside this module. | ||
- Finally, add this folder into the `typeRoots` field in your `tsconfig.json` file: | ||
```json | ||
@@ -296,2 +272,6 @@ { | ||
`yarn start --clear` | ||
or | ||
`expo r -c` | ||
@@ -305,2 +285,6 @@ | ||
`rm -rf .expo/web/cache` | ||
or | ||
[react-native-clean-project](https://www.npmjs.com/package/react-native-clean-project) | ||
@@ -307,0 +291,0 @@ |
Sorry, the diff of this file is not supported yet
102
6.25%21
-8.7%49797
-0.36%371
-3.64%320
-4.76%Updated