Skip to content

Commit 0fe5e1a

Browse files
initial
1 parent c138dd0 commit 0fe5e1a

7 files changed

+147
-4
lines changed

.env

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
FOO_fromDotEnv = true
2+
FOO_fromEnv = false

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/node_modules/
2+
/dist/
3+
.DS_Store
4+
**/.history

foo.config.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
fromConfig: true,
3+
fromDotEnv: false,
4+
fromEnv: false,
5+
}

index.js

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
const { existsSync } = require('fs')
2+
const { resolve } = require('path')
3+
let instances = {}
4+
const _defaults = {
5+
singleton: true,
6+
useDotEnv: true,
7+
useEnv: true,
8+
usePackageConfig: true,
9+
useConfig: true,
10+
sanitizeEnvValue: str => str.replace(/[-_][a-z]/g, str => str.substr(1).toUpperCase())
11+
}
12+
13+
/**
14+
*
15+
* @param {string} name
16+
* @param {Object.<string, *>} defaults
17+
* @param {Object.<string, *>=} options
18+
* @param {Partial<_defaults>=} _options
19+
*/
20+
function configent(name, defaults, options = {}, _options) {
21+
_options = { ..._defaults, ..._options }
22+
const {
23+
singleton,
24+
useDotEnv,
25+
sanitizeEnvValue,
26+
useConfig,
27+
useEnv,
28+
usePackageConfig
29+
} = _options
30+
31+
const configPath = resolve(process.cwd(), `${name}.config.js`)
32+
const upperCaseRE = new RegExp(`^${name.toUpperCase()}_`)
33+
const hash = JSON.stringify({ name, defaults, options })
34+
35+
if (!instances[hash] || !singleton) {
36+
instances[hash] = {
37+
...defaults,
38+
...usePackageConfig && getPackageConfig(),
39+
...useConfig && getUserConfig(configPath),
40+
...useEnv && getEnvConfig(),
41+
...options
42+
}
43+
}
44+
return instances[hash]
45+
46+
function getEnvConfig() {
47+
useDotEnv && require('dotenv').config()
48+
const entries = Object.entries(process.env)
49+
.filter(([key]) => key.match(upperCaseRE))
50+
.map(parseField)
51+
52+
if (entries.length)
53+
return entries.reduce((prev, { key, value }) => ({ ...prev, [key]: value }), {})
54+
55+
function parseField([key, value]) {
56+
console.log({ key, value })
57+
const shouldParseValue = k => typeof defaults[k] === 'object'
58+
59+
key = sanitizeEnvValue(key.replace(upperCaseRE, ''))
60+
value = shouldParseValue(key) ? JSON.parse(value) : value
61+
return { key, value }
62+
}
63+
}
64+
65+
function getUserConfig(path) {
66+
return existsSync(path) ? require(path) : {}
67+
}
68+
69+
function getPackageConfig() {
70+
const path = resolve(process.cwd(), 'package.json')
71+
return existsSync(path) && require(path)[name]
72+
}
73+
}
74+
75+
module.exports = { configent }

package.json

+19-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
22
"name": "configent",
3-
"version": "1.0.0",
3+
"version": "1.0.0-0",
44
"description": "",
55
"main": "index.js",
6-
"scripts": {
7-
"test": "echo \"Error: no test specified\" && exit 1"
6+
"scripts": {
7+
"test": "cd test && ava"
88
},
99
"repository": {
1010
"type": "git",
@@ -15,5 +15,20 @@
1515
"env"
1616
],
1717
"author": "[email protected]",
18-
"license": "MIT"
18+
"license": "MIT",
19+
"dependencies": {
20+
"dotenv": "^8.2.0"
21+
},
22+
"devDependencies": {
23+
"ava": "^3.13.0"
24+
},
25+
"ava": {
26+
"files": [
27+
"test/specs/**",
28+
"test/**/*.spec.*"
29+
]
30+
},
31+
"foo": {
32+
"fromPackageJson": true
33+
}
1934
}

test/no-config/all-options.spec.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
3+
const test = require('ava').default
4+
const {configent} = require('../..')
5+
6+
test('no config + env', async t => {
7+
console.log('cwd2', process.cwd())
8+
process.env.FOO_fromEnv = 'true'
9+
const defaults = {
10+
fromDefaults: true,
11+
fromDotEnv: false,
12+
fromEnv: false,
13+
fromOptions: false,
14+
fromConfig: false,
15+
fromPackageJson: false,
16+
}
17+
const options = {fromOptions: true}
18+
const result = configent('foo', defaults, options)
19+
t.deepEqual(result, {
20+
fromDefaults: true,
21+
fromDotEnv: 'true',
22+
fromEnv: 'true',
23+
fromConfig: true,
24+
fromPackageJson: true,
25+
fromOptions: true,
26+
})
27+
})

test/no-config/options-only.spec.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const test = require('ava').default
2+
const { configent } = require('../..')
3+
4+
const configentOptions = {
5+
useConfig: false,
6+
useDotEnv: false,
7+
useEnv: false,
8+
usePackageConfig: false
9+
}
10+
11+
test('no config - no env', async t => {
12+
const defaults = { bar: 123, baz: 456 }
13+
const result = configent('foo', defaults, {}, configentOptions)
14+
t.deepEqual(result, defaults)
15+
})

0 commit comments

Comments
 (0)