@adonisjs/env 4.1.5-0 → 4.2.0-1

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/README.md CHANGED
@@ -109,6 +109,20 @@ env.get('HOST') // is a string
109
109
  env.get('NODE_ENV') // is unknown, hence a string or undefined
110
110
  ```
111
111
 
112
+ ## Env editor
113
+ The Env editor can be used to edit dot-env files and persist changes on disk. Only the `.env` and `.env.example` files are updated (if exists).
114
+
115
+ ```ts
116
+ import { EnvEditor } from '@adonisjs/env'
117
+
118
+ const editor = await EnvEditor.create(new URL('./', import.meta.url))
119
+ editor.add('PORT', 3000)
120
+ editor.add('HOST', 'localhost')
121
+
122
+ // Write changes on disk
123
+ await editor.save()
124
+ ```
125
+
112
126
  ## Known Exceptions
113
127
 
114
128
  ### E_INVALID_ENV_VARIABLES
package/build/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { Env } from './src/env.js';
2
2
  export { EnvParser } from './src/parser.js';
3
3
  export { EnvLoader } from './src/loader.js';
4
+ export { EnvEditor } from './src/editor.js';
4
5
  export * as errors from './src/exceptions.js';
5
6
  export { EnvProcessor } from './src/processor.js';
package/build/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { Env } from './src/env.js';
2
2
  export { EnvParser } from './src/parser.js';
3
3
  export { EnvLoader } from './src/loader.js';
4
+ export { EnvEditor } from './src/editor.js';
4
5
  export * as errors from './src/exceptions.js';
5
6
  export { EnvProcessor } from './src/processor.js';
@@ -0,0 +1,13 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ export declare class EnvEditor {
3
+ #private;
4
+ static create(appRoot: URL): Promise<EnvEditor>;
5
+ constructor(appRoot: URL);
6
+ load(): Promise<void>;
7
+ add(key: string, value: string | number | boolean): void;
8
+ toJSON(): {
9
+ contents: string[];
10
+ path: string;
11
+ }[];
12
+ save(): Promise<void>;
13
+ }
@@ -0,0 +1,45 @@
1
+ import splitLines from 'split-lines';
2
+ import lodash from '@poppinss/utils/lodash';
3
+ import { writeFile } from 'node:fs/promises';
4
+ import { EnvLoader } from './loader.js';
5
+ export class EnvEditor {
6
+ #appRoot;
7
+ #loader;
8
+ #files = [];
9
+ static async create(appRoot) {
10
+ const editor = new EnvEditor(appRoot);
11
+ await editor.load();
12
+ return editor;
13
+ }
14
+ constructor(appRoot) {
15
+ this.#appRoot = appRoot;
16
+ this.#loader = new EnvLoader(this.#appRoot, true);
17
+ }
18
+ async load() {
19
+ const envFiles = await this.#loader.load();
20
+ this.#files = envFiles
21
+ .filter((envFile) => envFile.fileExists &&
22
+ (envFile.path.endsWith('.env') || envFile.path.endsWith('.env.example')))
23
+ .map((envFile) => {
24
+ return {
25
+ contents: splitLines(envFile.contents.trim()),
26
+ path: envFile.path,
27
+ };
28
+ });
29
+ }
30
+ add(key, value) {
31
+ this.#files.forEach((file) => {
32
+ let entryIndex = file.contents.findIndex((line) => line.startsWith(`${key}=`));
33
+ entryIndex = entryIndex === -1 ? file.contents.length : entryIndex;
34
+ lodash.set(file.contents, entryIndex, `${key}=${String(value)}`);
35
+ });
36
+ }
37
+ toJSON() {
38
+ return this.#files;
39
+ }
40
+ async save() {
41
+ await Promise.all(this.#files.map((file) => {
42
+ return writeFile(file.path, file.contents.join('\n'));
43
+ }));
44
+ }
45
+ }
@@ -1,9 +1,10 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
2
  export declare class EnvLoader {
3
3
  #private;
4
- constructor(appRoot: string | URL);
4
+ constructor(appRoot: string | URL, loadExampleFile?: boolean);
5
5
  load(): Promise<{
6
- path: string;
7
6
  contents: string;
7
+ path: string;
8
+ fileExists: boolean;
8
9
  }[]>;
9
10
  }
@@ -4,18 +4,21 @@ import { isAbsolute, join } from 'node:path';
4
4
  import debug from './debug.js';
5
5
  export class EnvLoader {
6
6
  #appRoot;
7
- constructor(appRoot) {
7
+ #loadExampleFile;
8
+ constructor(appRoot, loadExampleFile = false) {
8
9
  this.#appRoot = typeof appRoot === 'string' ? appRoot : fileURLToPath(appRoot);
10
+ this.#loadExampleFile = loadExampleFile;
9
11
  }
10
12
  async #loadFile(filePath) {
11
13
  try {
12
- return await readFile(filePath, 'utf-8');
14
+ const contents = await readFile(filePath, 'utf-8');
15
+ return { contents, fileExists: true };
13
16
  }
14
17
  catch (error) {
15
18
  if (error.code !== 'ENOENT') {
16
19
  throw error;
17
20
  }
18
- return '';
21
+ return { contents: '', fileExists: false };
19
22
  }
20
23
  }
21
24
  async load() {
@@ -38,28 +41,35 @@ export class EnvLoader {
38
41
  const nodeEnvLocalFile = join(baseEnvPath, `.env.${NODE_ENV}.local`);
39
42
  envFiles.push({
40
43
  path: nodeEnvLocalFile,
41
- contents: await this.#loadFile(nodeEnvLocalFile),
44
+ ...(await this.#loadFile(nodeEnvLocalFile)),
42
45
  });
43
46
  }
44
47
  if (!NODE_ENV || !['test', 'testing'].includes(NODE_ENV)) {
45
48
  const envLocalFile = join(baseEnvPath, '.env.local');
46
49
  envFiles.push({
47
50
  path: envLocalFile,
48
- contents: await this.#loadFile(envLocalFile),
51
+ ...(await this.#loadFile(envLocalFile)),
49
52
  });
50
53
  }
51
54
  if (NODE_ENV) {
52
55
  const nodeEnvFile = join(baseEnvPath, `.env.${NODE_ENV}`);
53
56
  envFiles.push({
54
57
  path: nodeEnvFile,
55
- contents: await this.#loadFile(nodeEnvFile),
58
+ ...(await this.#loadFile(nodeEnvFile)),
56
59
  });
57
60
  }
58
61
  const envFile = join(baseEnvPath, '.env');
59
62
  envFiles.push({
60
63
  path: envFile,
61
- contents: await this.#loadFile(envFile),
64
+ ...(await this.#loadFile(envFile)),
62
65
  });
66
+ if (this.#loadExampleFile) {
67
+ const envExampleFile = join(baseEnvPath, '.env.example');
68
+ envFiles.push({
69
+ path: envExampleFile,
70
+ ...(await this.#loadFile(envExampleFile)),
71
+ });
72
+ }
63
73
  return envFiles;
64
74
  }
65
75
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adonisjs/env",
3
- "version": "4.1.5-0",
3
+ "version": "4.2.0-1",
4
4
  "description": "Environment variable manager for Node.js",
5
5
  "main": "build/index.js",
6
6
  "type": "module",
@@ -33,36 +33,38 @@
33
33
  "author": "virk,adonisjs",
34
34
  "license": "MIT",
35
35
  "devDependencies": {
36
- "@commitlint/cli": "^17.4.2",
37
- "@commitlint/config-conventional": "^17.4.2",
38
- "@japa/assert": "^1.3.6",
39
- "@japa/expect-type": "^1.0.2",
40
- "@japa/run-failed-tests": "^1.1.0",
41
- "@japa/runner": "^2.2.2",
42
- "@japa/spec-reporter": "^1.3.2",
36
+ "@commitlint/cli": "^17.4.4",
37
+ "@commitlint/config-conventional": "^17.4.4",
38
+ "@japa/assert": "^1.4.1",
39
+ "@japa/expect-type": "^1.0.3",
40
+ "@japa/file-system": "^1.0.1",
41
+ "@japa/run-failed-tests": "^1.1.1",
42
+ "@japa/runner": "^2.5.1",
43
+ "@japa/spec-reporter": "^1.3.3",
43
44
  "@poppinss/dev-utils": "^2.0.3",
44
- "@swc/core": "^1.3.32",
45
+ "@swc/core": "^1.3.40",
45
46
  "@types/fs-extra": "^11.0.1",
46
- "@types/node": "^18.11.18",
47
- "c8": "^7.12.0",
47
+ "@types/node": "^18.15.3",
48
+ "c8": "^7.13.0",
48
49
  "cross-env": "^7.0.3",
49
50
  "del-cli": "^5.0.0",
50
- "eslint": "^8.33.0",
51
- "eslint-config-prettier": "^8.6.0",
51
+ "eslint": "^8.36.0",
52
+ "eslint-config-prettier": "^8.7.0",
52
53
  "eslint-plugin-adonis": "^3.0.3",
53
54
  "eslint-plugin-prettier": "^4.2.1",
54
55
  "fs-extra": "^11.1.0",
55
- "github-label-sync": "^2.2.0",
56
+ "github-label-sync": "^2.3.1",
56
57
  "husky": "^8.0.3",
57
58
  "np": "^7.6.3",
58
- "prettier": "^2.8.3",
59
+ "prettier": "^2.8.4",
59
60
  "ts-node": "^10.9.1",
60
61
  "typescript": "^4.9.5"
61
62
  },
62
63
  "dependencies": {
63
- "@poppinss/utils": "^6.5.0-0",
64
- "@poppinss/validator-lite": "^1.0.2",
65
- "dotenv": "^16.0.3"
64
+ "@poppinss/utils": "^6.5.0-1",
65
+ "@poppinss/validator-lite": "^1.0.3",
66
+ "dotenv": "^16.0.3",
67
+ "split-lines": "^3.0.0"
66
68
  },
67
69
  "repository": {
68
70
  "type": "git",