@dotenvx/dotenvx 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,11 +2,27 @@
2
2
 
3
3
  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.
4
4
 
5
- ## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.8.0...main)
5
+ ## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.9.0...main)
6
+
7
+ ## 1.9.0
8
+
9
+ ### Added
10
+
11
+ * add `--exclude-key` (`-ek`) option to `dotenvx encrypt` and `dotenvx decrypt` ([#344](https://github.com/dotenvx/dotenvx/pull/344))
12
+
13
+ ### Changed
14
+
15
+ * preserve comments and spacing on first-time generation of .env.example file ([#346](https://github.com/dotenvx/dotenvx/pull/346))
16
+
17
+ ### Removed
18
+
19
+ * removed `winston` - logger simplified to use `console.log` going forward ([#347](https://github.com/dotenvx/dotenvx/pull/347))
20
+
21
+ ## 1.8.0
6
22
 
7
23
  ### Added
8
24
 
9
- * warn when decryption fails on `run` or `get` ([#339](https://github.com/dotenvx/dotenvx/pull/339))
25
+ * warn when decryption fails on `run` ([#339](https://github.com/dotenvx/dotenvx/pull/339))
10
26
  * decrypt expanded values as necessary ([#336](https://github.com/dotenvx/dotenvx/pull/336))
11
27
 
12
28
  ### Changed
package/README.md CHANGED
@@ -27,31 +27,31 @@ console.log(`Hello ${process.env.HELLO}`)
27
27
 
28
28
  or install globally - *unlocks dotenv for any language, framework, or platform!*
29
29
 
30
- <details><summary>with brew 🍺</summary><br>
30
+ <details><summary>with curl 🌐 </summary><br>
31
31
 
32
32
  ```sh
33
- brew install dotenvx/brew/dotenvx
33
+ curl -sfS https://dotenvx.sh | sh
34
34
  dotenvx help
35
35
  ```
36
36
 
37
- [![brew installs](https://img.shields.io/github/downloads/dotenvx/dotenvx/total?label=brew%20installs)](https://github.com/dotenvx/homebrew-brew/blob/main/Formula/dotenvx.rb)
38
- <sup>*homebrew installs sourced from github releases - <a href="https://github.com/dotenvx/homebrew-brew/blob/main/Formula/dotenvx.rb">formula</a></sup>
37
+ [![mac](https://img.shields.io/endpoint?url=https://dotenvx.sh/stats/curl/darwin&label=mac)](https://github.com/dotenvx/dotenvx.sh/blob/main/install.sh)
38
+ [![linux](https://img.shields.io/endpoint?url=https://dotenvx.sh/stats/curl/linux&label=linux)](https://github.com/dotenvx/dotenvx.sh/blob/main/install.sh)
39
+ [![windows](https://img.shields.io/endpoint?url=https://dotenvx.sh/stats/curl/windows&label=windows)](https://github.com/dotenvx/dotenvx.sh/blob/main/install.sh)
40
+ <sup>*curl installs sourced from npm binary packages - <a href="https://www.npmjs.com/package/@dotenvx/dotenvx-linux-x86_64">example</a></sup>
39
41
 
40
42
  &nbsp;
41
43
 
42
44
  </details>
43
45
 
44
- <details><summary>with curl 🌐 </summary><br>
46
+ <details><summary>with brew 🍺</summary><br>
45
47
 
46
48
  ```sh
47
- curl -sfS https://dotenvx.sh | sh
49
+ brew install dotenvx/brew/dotenvx
48
50
  dotenvx help
49
51
  ```
50
52
 
51
- [![mac](https://img.shields.io/endpoint?url=https://dotenvx.sh/stats/curl/darwin&label=mac)](https://github.com/dotenvx/dotenvx.sh/blob/main/install.sh)
52
- [![linux](https://img.shields.io/endpoint?url=https://dotenvx.sh/stats/curl/linux&label=linux)](https://github.com/dotenvx/dotenvx.sh/blob/main/install.sh)
53
- [![windows](https://img.shields.io/endpoint?url=https://dotenvx.sh/stats/curl/windows&label=windows)](https://github.com/dotenvx/dotenvx.sh/blob/main/install.sh)
54
- <sup>*curl installs sourced from npm binary packages - <a href="https://www.npmjs.com/package/@dotenvx/dotenvx-linux-x86_64">example</a></sup>
53
+ [![brew installs](https://img.shields.io/github/downloads/dotenvx/dotenvx/total?label=brew%20installs)](https://github.com/dotenvx/homebrew-brew/blob/main/Formula/dotenvx.rb)
54
+ <sup>*homebrew installs sourced from github releases - <a href="https://github.com/dotenvx/homebrew-brew/blob/main/Formula/dotenvx.rb">formula</a></sup>
55
55
 
56
56
  &nbsp;
57
57
 
@@ -866,7 +866,7 @@ More examples
866
866
  </details>
867
867
  * <details><summary>`run --verbose`</summary><br>
868
868
 
869
- Set log level to `verbose`. ([log levels](https://github.com/winstonjs/winston?tab=readme-ov-file#logging))
869
+ Set log level to `verbose`. ([log levels](https://docs.npmjs.com/cli/v8/using-npm/logging#setting-log-levels))
870
870
 
871
871
  ```sh
872
872
  $ echo "HELLO=production" > .env.production
@@ -882,7 +882,7 @@ More examples
882
882
  </details>
883
883
  * <details><summary>`run --debug`</summary><br>
884
884
 
885
- Set log level to `debug`. ([log levels](https://github.com/winstonjs/winston?tab=readme-ov-file#logging))
885
+ Set log level to `debug`. ([log levels](https://docs.npmjs.com/cli/v8/using-npm/logging#setting-log-levels))
886
886
 
887
887
  ```sh
888
888
  $ echo "HELLO=production" > .env.production
@@ -904,7 +904,7 @@ More examples
904
904
  </details>
905
905
  * <details><summary>`run --quiet`</summary><br>
906
906
 
907
- Use `--quiet` to suppress all output (except errors). ([log levels](https://github.com/winstonjs/winston?tab=readme-ov-file#logging))
907
+ Use `--quiet` to suppress all output (except errors). ([log levels](https://docs.npmjs.com/cli/v8/using-npm/logging#setting-log-levels))
908
908
 
909
909
  ```sh
910
910
  $ echo "HELLO=production" > .env.production
@@ -927,7 +927,7 @@ More examples
927
927
  Hello production
928
928
  ```
929
929
 
930
- Available log levels are `error, warn, info, verbose, debug, silly` ([source](https://github.com/winstonjs/winston?tab=readme-ov-file#logging))
930
+ Available log levels are `error, warn, info, verbose, debug, silly` ([source](https://docs.npmjs.com/cli/v8/using-npm/logging#setting-log-levels))
931
931
 
932
932
  </details>
933
933
  * <details><summary>`run --convention=nextjs`</summary><br>
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.8.0",
2
+ "version": "1.9.0",
3
3
  "name": "@dotenvx/dotenvx",
4
4
  "description": "a better dotenv–from the creator of `dotenv`",
5
5
  "author": "@motdotla",
@@ -46,7 +46,6 @@
46
46
  "picomatch": "^4.0.2",
47
47
  "tinyexec": "^0.2.0",
48
48
  "which": "^4.0.0",
49
- "winston": "^3.11.0",
50
49
  "xxhashjs": "^0.2.2"
51
50
  },
52
51
  "devDependencies": {
@@ -13,7 +13,7 @@ function decrypt () {
13
13
  if (options.stdout) {
14
14
  const {
15
15
  processedEnvFiles
16
- } = main.decrypt(options.envFile, options.key)
16
+ } = main.decrypt(options.envFile, options.key, options.excludeKey)
17
17
 
18
18
  for (const processedEnvFile of processedEnvFiles) {
19
19
  process.stdout.write(processedEnvFile.envSrc)
@@ -25,7 +25,7 @@ function decrypt () {
25
25
  processedEnvFiles,
26
26
  changedFilepaths,
27
27
  unchangedFilepaths
28
- } = main.decrypt(options.envFile, options.key)
28
+ } = main.decrypt(options.envFile, options.key, options.excludeKey)
29
29
 
30
30
  for (const processedEnvFile of processedEnvFiles) {
31
31
  logger.verbose(`decrypting ${processedEnvFile.envFilepath} (${processedEnvFile.filepath})`)
@@ -15,7 +15,7 @@ function encrypt () {
15
15
  if (options.stdout) {
16
16
  const {
17
17
  processedEnvFiles
18
- } = main.encrypt(options.envFile, options.key)
18
+ } = main.encrypt(options.envFile, options.key, options.excludeKey)
19
19
 
20
20
  for (const processedEnvFile of processedEnvFiles) {
21
21
  process.stdout.write(processedEnvFile.envSrc)
@@ -27,7 +27,7 @@ function encrypt () {
27
27
  processedEnvFiles,
28
28
  changedFilepaths,
29
29
  unchangedFilepaths
30
- } = main.encrypt(options.envFile, options.key)
30
+ } = main.encrypt(options.envFile, options.key, options.excludeKey)
31
31
 
32
32
  for (const processedEnvFile of processedEnvFiles) {
33
33
  logger.verbose(`encrypting ${processedEnvFile.envFilepath} (${processedEnvFile.filepath})`)
@@ -20,9 +20,6 @@ function genexample (directory) {
20
20
 
21
21
  logger.verbose(`loading env from ${envFile}`)
22
22
 
23
- // TODO: display pre-existing
24
- // TODO: display added/appended/injected
25
-
26
23
  fs.writeFileSync(exampleFilepath, envExampleFile, ENCODING)
27
24
 
28
25
  if (addedKeys.length > 0) {
@@ -100,6 +100,7 @@ program.command('encrypt')
100
100
  .description('convert .env file(s) to encrypted .env file(s)')
101
101
  .option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
102
102
  .option('-k, --key <keys...>', 'keys(s) to encrypt (default: all keys in file)')
103
+ .option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from encryption (default: none)')
103
104
  .option('--stdout', 'send to stdout')
104
105
  .action(encryptAction)
105
106
 
@@ -109,6 +110,7 @@ program.command('decrypt')
109
110
  .description('convert encrypted .env file(s) to plain .env file(s)')
110
111
  .option('-f, --env-file <paths...>', 'path(s) to your env file(s)')
111
112
  .option('-k, --key <keys...>', 'keys(s) to decrypt (default: all keys in file)')
113
+ .option('-ek, --exclude-key <excludeKeys...>', 'keys(s) to exclude from decryption (default: none)')
112
114
  .option('--stdout', 'send to stdout')
113
115
  .action(decryptAction)
114
116
 
@@ -132,40 +134,8 @@ program.command('help [command]')
132
134
  program.addCommand(require('./commands/ext'))
133
135
 
134
136
  //
135
- // DEPRECATED or MOVED
137
+ // MOVED
136
138
  //
137
- const lsAction = require('./actions/ext/ls')
138
- program.command('ls')
139
- .description('DEPRECATED: moved to [dotenvx ext ls]')
140
- .argument('[directory]', 'directory to list .env files from', '.')
141
- .option('-f, --env-file <filenames...>', 'path(s) to your env file(s)', '.env*')
142
- .action(function (...args) {
143
- logger.warn('DEPRECATION NOTICE: [ls] has moved to [dotenvx ext ls]')
144
-
145
- lsAction.apply(this, args)
146
- })
147
-
148
- const genexampleAction = require('./actions/ext/genexample')
149
- program.command('genexample')
150
- .description('DEPRECATED: moved to [dotenvx ext genexample]')
151
- .argument('[directory]', 'directory to generate from', '.')
152
- .option('-f, --env-file <paths...>', 'path(s) to your env file(s)', '.env')
153
- .action(function (...args) {
154
- logger.warn('DEPRECATION NOTICE: [genexample] has moved to [dotenvx ext genexample]')
155
-
156
- genexampleAction.apply(this, args)
157
- })
158
-
159
- const gitignoreAction = require('./actions/ext/gitignore')
160
- program.command('gitignore')
161
- .description('DEPRECATED: moved to [dotenvx ext gitignore]')
162
- .addHelpText('after', examples.gitignore)
163
- .action(function (...args) {
164
- logger.warn('DEPRECATION NOTICE: [gitignore] has moved to [dotenvx ext gitignore]')
165
-
166
- gitignoreAction.apply(this, args)
167
- })
168
-
169
139
  const prebuildAction = require('./actions/ext/prebuild')
170
140
  program.command('prebuild')
171
141
  .description('DEPRECATED: moved to [dotenvx ext prebuild]')
@@ -187,15 +157,6 @@ program.command('precommit')
187
157
  precommitAction.apply(this, args)
188
158
  })
189
159
 
190
- const scanAction = require('./actions/ext/scan')
191
- program.command('scan')
192
- .description('DEPRECATED: moved to [dotenvx ext scan]')
193
- .action(function (...args) {
194
- logger.warn('DEPRECATION NOTICE: [scan] has moved to [dotenvx ext scan]')
195
-
196
- scanAction.apply(this, args)
197
- })
198
-
199
160
  // overide helpInformation to hide DEPRECATED commands
200
161
  program.helpInformation = function () {
201
162
  const originalHelp = Command.prototype.helpInformation.call(this)
package/src/lib/main.js CHANGED
@@ -189,13 +189,13 @@ const set = function (key, value, envFile, encrypt) {
189
189
  }
190
190
 
191
191
  /** @type {import('./main').encrypt} */
192
- const encrypt = function (envFile, key) {
193
- return new Encrypt(envFile, key).run()
192
+ const encrypt = function (envFile, key, excludeKey) {
193
+ return new Encrypt(envFile, key, excludeKey).run()
194
194
  }
195
195
 
196
196
  /** @type {import('./main').encrypt} */
197
- const decrypt = function (envFile, key) {
198
- return new Decrypt(envFile, key).run()
197
+ const decrypt = function (envFile, key, excludeKey) {
198
+ return new Decrypt(envFile, key, excludeKey).run()
199
199
  }
200
200
 
201
201
  /** @type {import('./main').status} */
@@ -14,10 +14,12 @@ class Decrypt {
14
14
  /**
15
15
  * @param {string|string[]} [envFile]
16
16
  * @param {string|string[]} [key]
17
+ * @param {string|string[]} [excludeKey]
17
18
  **/
18
- constructor (envFile = '.env', key = []) {
19
+ constructor (envFile = '.env', key = [], excludeKey = []) {
19
20
  this.envFile = envFile
20
21
  this.key = key
22
+ this.excludeKey = excludeKey
21
23
  this.processedEnvFiles = []
22
24
  this.changedFilepaths = new Set()
23
25
  this.unchangedFilepaths = new Set()
@@ -26,6 +28,7 @@ class Decrypt {
26
28
  run () {
27
29
  const envFilepaths = this._envFilepaths()
28
30
  const keys = this._keys()
31
+ const excludeKeys = this._excludeKeys()
29
32
  for (const envFilepath of envFilepaths) {
30
33
  const filepath = path.resolve(envFilepath)
31
34
 
@@ -49,17 +52,25 @@ class Decrypt {
49
52
  // iterate over all non-encrypted values and encrypt them
50
53
  const parsed = dotenv.parse(src)
51
54
  for (const [key, value] of Object.entries(parsed)) {
52
- if (keys.length < 1 || keys.includes(key)) { // optionally control which key to decrypt
53
- const encrypted = isEncrypted(key, value)
54
- if (encrypted) {
55
- row.keys.push(key) // track key(s)
55
+ // key excluded - don't decrypt it
56
+ if (excludeKeys.includes(key)) {
57
+ continue
58
+ }
59
+
60
+ // key effectively excluded (by not being in the list of includes) - don't encrypt it
61
+ if (keys.length > 0 && !keys.includes(key)) {
62
+ continue
63
+ }
64
+
65
+ const encrypted = isEncrypted(key, value)
66
+ if (encrypted) {
67
+ row.keys.push(key) // track key(s)
56
68
 
57
- const decryptedValue = decryptValue(value, privateKey)
58
- // once newSrc is built write it out
59
- src = replace(src, key, decryptedValue)
69
+ const decryptedValue = decryptValue(value, privateKey)
70
+ // once newSrc is built write it out
71
+ src = replace(src, key, decryptedValue)
60
72
 
61
- row.changed = true // track change
62
- }
73
+ row.changed = true // track change
63
74
  }
64
75
  }
65
76
 
@@ -106,6 +117,14 @@ class Decrypt {
106
117
 
107
118
  return this.key
108
119
  }
120
+
121
+ _excludeKeys () {
122
+ if (!Array.isArray(this.excludeKey)) {
123
+ return [this.excludeKey]
124
+ }
125
+
126
+ return this.excludeKey
127
+ }
109
128
  }
110
129
 
111
130
  module.exports = Decrypt
@@ -15,10 +15,12 @@ class Encrypt {
15
15
  /**
16
16
  * @param {string|string[]} [envFile]
17
17
  * @param {string|string[]} [key]
18
+ * @param {string|string[]} [excludeKey]
18
19
  **/
19
- constructor (envFile = '.env', key = []) {
20
+ constructor (envFile = '.env', key = [], excludeKey = []) {
20
21
  this.envFile = envFile
21
22
  this.key = key
23
+ this.excludeKey = excludeKey
22
24
  this.processedEnvFiles = []
23
25
  this.changedFilepaths = new Set()
24
26
  this.unchangedFilepaths = new Set()
@@ -27,6 +29,7 @@ class Encrypt {
27
29
  run () {
28
30
  const envFilepaths = this._envFilepaths()
29
31
  const keys = this._keys()
32
+ const excludeKeys = this._excludeKeys()
30
33
  for (const envFilepath of envFilepaths) {
31
34
  const filepath = path.resolve(envFilepath)
32
35
 
@@ -63,19 +66,25 @@ class Encrypt {
63
66
  // iterate over all non-encrypted values and encrypt them
64
67
  const parsed = dotenv.parse(src)
65
68
  for (const [key, value] of Object.entries(parsed)) {
66
- if (keys.length < 1 || keys.includes(key)) {
67
- // optionally control which key to encrypt
68
- const encrypted =
69
- isEncrypted(key, value) || isPublicKey(key, value)
70
- if (!encrypted) {
71
- row.keys.push(key) // track key(s)
72
-
73
- const encryptedValue = encryptValue(value, publicKey)
74
- // once newSrc is built write it out
75
- src = replace(src, key, encryptedValue)
76
-
77
- row.changed = true // track change
78
- }
69
+ // key excluded - don't encrypt it
70
+ if (excludeKeys.includes(key)) {
71
+ continue
72
+ }
73
+
74
+ // key effectively excluded (by not being in the list of includes) - don't encrypt it
75
+ if (keys.length > 0 && !keys.includes(key)) {
76
+ continue
77
+ }
78
+
79
+ const encrypted = isEncrypted(key, value) || isPublicKey(key, value)
80
+ if (!encrypted) {
81
+ row.keys.push(key) // track key(s)
82
+
83
+ const encryptedValue = encryptValue(value, publicKey)
84
+ // once newSrc is built write it out
85
+ src = replace(src, key, encryptedValue)
86
+
87
+ row.changed = true // track change
79
88
  }
80
89
  }
81
90
 
@@ -122,6 +131,14 @@ class Encrypt {
122
131
 
123
132
  return this.key
124
133
  }
134
+
135
+ _excludeKeys () {
136
+ if (!Array.isArray(this.excludeKey)) {
137
+ return [this.excludeKey]
138
+ }
139
+
140
+ return this.excludeKey
141
+ }
125
142
  }
126
143
 
127
144
  module.exports = Encrypt
@@ -5,11 +5,15 @@ const dotenv = require('dotenv')
5
5
  const ENCODING = 'utf8'
6
6
 
7
7
  const findEnvFiles = require('../helpers/findEnvFiles')
8
+ const replace = require('../helpers/replace')
8
9
 
9
10
  class Genexample {
10
11
  constructor (directory = '.', envFile) {
11
12
  this.directory = directory
12
13
  this.envFile = envFile || findEnvFiles(directory)
14
+
15
+ this.exampleFilename = '.env.example'
16
+ this.exampleFilepath = path.resolve(this.directory, this.exampleFilename)
13
17
  }
14
18
 
15
19
  run () {
@@ -27,6 +31,12 @@ class Genexample {
27
31
  const keys = new Set()
28
32
  const addedKeys = new Set()
29
33
  const envFilepaths = this._envFilepaths()
34
+ /** @type {Record<string, string>} */
35
+ const injected = {}
36
+ /** @type {Record<string, string>} */
37
+ const preExisted = {}
38
+
39
+ let exampleSrc = `# ${this.exampleFilename} - generated with dotenvx\n`
30
40
 
31
41
  for (const envFilepath of envFilepaths) {
32
42
  const filepath = path.resolve(this.directory, envFilepath)
@@ -41,43 +51,51 @@ class Genexample {
41
51
  throw error
42
52
  }
43
53
 
44
- const parsed = dotenv.configDotenv({ path: filepath }).parsed
45
- for (const key of Object.keys(parsed)) {
54
+ // get the original src
55
+ let src = fs.readFileSync(filepath, { encoding: ENCODING })
56
+ const parsed = dotenv.parse(src)
57
+ for (const key in parsed) {
58
+ // used later
46
59
  keys.add(key)
60
+
61
+ // once newSrc is built write it out
62
+ src = replace(src, key, '') // empty value
47
63
  }
48
- }
49
64
 
50
- let envExampleFile = ''
51
- const exampleFilename = '.env.example'
52
- const exampleFilepath = path.resolve(this.directory, exampleFilename)
53
- if (!fs.existsSync(exampleFilepath)) {
54
- envExampleFile += `# ${exampleFilename} - generated with dotenvx\n`
55
- } else {
56
- envExampleFile = fs.readFileSync(exampleFilepath, ENCODING)
65
+ exampleSrc += `\n${src}`
57
66
  }
58
67
 
59
- const currentEnvExample = dotenv.configDotenv({ path: exampleFilepath }).parsed
60
- /** @type {Record<string, string>} */
61
- const injected = {}
62
- /** @type {Record<string, string>} */
63
- const preExisted = {}
64
-
65
- for (const key of [...keys]) {
66
- if (key in currentEnvExample) {
67
- preExisted[key] = currentEnvExample[key]
68
- } else {
69
- envExampleFile += `${key}=""\n`
70
-
68
+ if (!fs.existsSync(this.exampleFilepath)) {
69
+ // it doesn't exist so just write this first generated one
70
+ // exampleSrc - already written to from the prior loop
71
+ for (const key of [...keys]) {
72
+ // every key is added since it's the first time generating .env.example
71
73
  addedKeys.add(key)
72
74
 
73
75
  injected[key] = ''
74
76
  }
77
+ } else {
78
+ // it already exists (which means the user might have it modified a way in which they prefer, so replace exampleSrc with their existing .env.example)
79
+ exampleSrc = fs.readFileSync(this.exampleFilepath, ENCODING)
80
+
81
+ const parsed = dotenv.parse(exampleSrc)
82
+ for (const key of [...keys]) {
83
+ if (key in parsed) {
84
+ preExisted[key] = parsed[key]
85
+ } else {
86
+ exampleSrc += `${key}=""\n`
87
+
88
+ addedKeys.add(key)
89
+
90
+ injected[key] = ''
91
+ }
92
+ }
75
93
  }
76
94
 
77
95
  return {
78
- envExampleFile,
96
+ envExampleFile: exampleSrc,
79
97
  envFile: this.envFile,
80
- exampleFilepath,
98
+ exampleFilepath: this.exampleFilepath,
81
99
  addedKeys: [...addedKeys],
82
100
  injected,
83
101
  preExisted
@@ -1,10 +1,3 @@
1
- const winston = require('winston')
2
-
3
- const printf = winston.format.printf
4
- const combine = winston.format.combine
5
- const createLogger = winston.createLogger
6
- const transports = winston.transports
7
-
8
1
  const packageJson = require('../lib/helpers/packageJson')
9
2
  const { getColor, bold } = require('./colors')
10
3
 
@@ -26,7 +19,6 @@ const levels = {
26
19
  help: 2,
27
20
  help2: 2,
28
21
  blank: 2,
29
- http: 3,
30
22
  verbose: 4,
31
23
  debug: 5,
32
24
  silly: 6
@@ -38,14 +30,27 @@ const success = getColor('green')
38
30
  const successv = getColor('olive') // yellow-ish tint that 'looks' like dotenv
39
31
  const help = getColor('blue')
40
32
  const help2 = getColor('gray')
41
- const http = getColor('green')
42
33
  const verbose = getColor('plum')
43
34
  const debug = getColor('plum')
44
35
 
45
- const dotenvxFormat = printf(({ level, message, label, timestamp }) => {
36
+ let currentLevel = levels.info // default log level
37
+
38
+ function log (level, message) {
39
+ if (levels[level] === undefined) {
40
+ throw new Error(`MISSING_LOG_LEVEL: '${level}'. implement in logger.`)
41
+ }
42
+
43
+ if (levels[level] <= currentLevel) {
44
+ const formattedMessage = formatMessage(level, message)
45
+ console.log(formattedMessage)
46
+ }
47
+ }
48
+
49
+ function formatMessage (level, message) {
46
50
  const formattedMessage = typeof message === 'object' ? JSON.stringify(message) : message
47
51
 
48
52
  switch (level.toLowerCase()) {
53
+ // errors
49
54
  case 'error':
50
55
  return error(formattedMessage)
51
56
  case 'errorv':
@@ -56,6 +61,7 @@ const dotenvxFormat = printf(({ level, message, label, timestamp }) => {
56
61
  return error(`[dotenvx@${packageJson.version}][prebuild] ${formattedMessage}`)
57
62
  case 'errornocolor':
58
63
  return formattedMessage
64
+ // warns
59
65
  case 'warn':
60
66
  return warn(formattedMessage)
61
67
  case 'warnv':
@@ -64,6 +70,7 @@ const dotenvxFormat = printf(({ level, message, label, timestamp }) => {
64
70
  return warn(`[dotenvx@${packageJson.version}][precommit] ${formattedMessage}`)
65
71
  case 'warnvpb':
66
72
  return warn(`[dotenvx@${packageJson.version}][prebuild] ${formattedMessage}`)
73
+ // successes
67
74
  case 'success':
68
75
  return success(formattedMessage)
69
76
  case 'successv': // success with 'version'
@@ -72,35 +79,66 @@ const dotenvxFormat = printf(({ level, message, label, timestamp }) => {
72
79
  return success(`[dotenvx@${packageJson.version}][precommit] ${formattedMessage}`)
73
80
  case 'successvpb': // success with 'version' and precommit
74
81
  return success(`[dotenvx@${packageJson.version}][prebuild] ${formattedMessage}`)
82
+ // info
75
83
  case 'info':
76
84
  return formattedMessage
85
+ // help
77
86
  case 'help':
78
87
  return help(formattedMessage)
79
88
  case 'help2':
80
89
  return help2(formattedMessage)
81
- case 'http':
82
- return http(formattedMessage)
90
+ // verbose
83
91
  case 'verbose':
84
92
  return verbose(formattedMessage)
93
+ // debug
85
94
  case 'debug':
86
95
  return debug(formattedMessage)
96
+ // blank
87
97
  case 'blank': // custom
88
98
  return formattedMessage
89
99
  }
90
- })
100
+ }
91
101
 
92
- const logger = createLogger({
102
+ const logger = {
103
+ // track level
93
104
  level: 'info',
94
- levels,
95
- format: combine(
96
- dotenvxFormat
97
- ),
98
- transports: [
99
- new transports.Console()
100
- ]
101
- })
102
105
 
103
- const setLogLevel = options => {
106
+ // errors
107
+ error: (msg) => log('error', msg),
108
+ errorv: (msg) => log('errorv', msg),
109
+ errorvp: (msg) => log('errorvp', msg),
110
+ errorvpb: (msg) => log('errorvpb', msg),
111
+ errornocolor: (msg) => log('errornocolor', msg),
112
+ // warns
113
+ warn: (msg) => log('warn', msg),
114
+ warnv: (msg) => log('warnv', msg),
115
+ warnvp: (msg) => log('warnvp', msg),
116
+ warnvpb: (msg) => log('warnvpb', msg),
117
+ // success
118
+ success: (msg) => log('success', msg),
119
+ successv: (msg) => log('successv', msg),
120
+ successvp: (msg) => log('successvp', msg),
121
+ successvpb: (msg) => log('successvpb', msg),
122
+ // info
123
+ info: (msg) => log('info', msg),
124
+ // help
125
+ help: (msg) => log('help', msg),
126
+ help2: (msg) => log('help2', msg),
127
+ // verbose
128
+ verbose: (msg) => log('verbose', msg),
129
+ // debug
130
+ debug: (msg) => log('debug', msg),
131
+ // blank
132
+ blank: (msg) => log('blank', msg),
133
+ setLevel: (level) => {
134
+ if (levels[level] !== undefined) {
135
+ currentLevel = levels[level]
136
+ logger.level = level
137
+ }
138
+ }
139
+ }
140
+
141
+ function setLogLevel (options) {
104
142
  const logLevel = options.debug
105
143
  ? 'debug'
106
144
  : options.verbose
@@ -110,7 +148,7 @@ const setLogLevel = options => {
110
148
  : options.logLevel
111
149
 
112
150
  if (!logLevel) return
113
- logger.level = logLevel
151
+ logger.setLevel(logLevel)
114
152
  // Only log which level it's setting if it's not set to quiet mode
115
153
  if (!options.quiet || (options.quiet && logLevel !== 'error')) {
116
154
  logger.debug(`Setting log level to ${logLevel}`)
@@ -120,5 +158,6 @@ const setLogLevel = options => {
120
158
  module.exports = {
121
159
  logger,
122
160
  getColor,
123
- setLogLevel
161
+ setLogLevel,
162
+ levels
124
163
  }