@benshawmean/envedit 1.3.1 → 1.3.2-2

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/.gitlab-ci.yml CHANGED
@@ -65,6 +65,8 @@ publish:
65
65
  export PACKAGE_NAME=$(jq -r '.name' package.json)
66
66
  export CURR_VER=$(jq -r '.version' package.json)
67
67
  export LIVE_VER=$(bun info $PACKAGE_NAME version)
68
+ export IS_PRE_RELEASE=$(echo $CURR_VER | grep -E '[-+]')
69
+ export PUBLISH_FLAGS=( "--silent" )
68
70
 
69
71
  - | # Check if the current version is already published
70
72
  if [ "$LIVE_VER" == "$CURR_VER" ]; then
@@ -73,9 +75,14 @@ publish:
73
75
  fi
74
76
 
75
77
  - bun pm pack --filename package.tgz
76
- - bunx npm publish -q package.tgz
78
+ - |
79
+ if [ $IS_PRE_RELEASE ]; then
80
+ echo "Pre-release version detected. Publishing with 'next' tag."
81
+ PUBLISH_FLAGS+=( "--tag=next" )
82
+ fi
83
+ - bunx npm publish ${PUBLISH_FLAGS[*]} package.tgz
77
84
  - sh ci/npm.sh
78
- - bun publish --silent package.tgz
85
+ - bun publish ${PUBLISH_FLAGS[*]} package.tgz
79
86
  - rm package.tgz .npmrc
80
87
 
81
88
  allow_failure:
@@ -1,4 +1,8 @@
1
- import fs from "node:fs";
1
+ import {
2
+ existsSync as exists,
3
+ unlinkSync as unlink,
4
+ symlinkSync as symlink,
5
+ } from "node:fs";
2
6
 
3
7
  import { confirm, input, password, select } from "@inquirer/prompts";
4
8
 
@@ -11,7 +15,7 @@ export default {
11
15
  describe: 'Add a new environment',
12
16
  builder: (yargs) => yargs,
13
17
  handler: async (argv) => {
14
- const config = new Configuration().load();
18
+ const config = new Configuration();
15
19
  const logger = new Logger(argv.level);
16
20
 
17
21
  const name = await input({
@@ -20,7 +24,7 @@ export default {
20
24
  if (!input) {
21
25
  return "Environment name cannot be empty";
22
26
  }
23
- if (config.getEnvironment(input)) {
27
+ if (config.envs.has(input)) {
24
28
  return "Environment name already exists";
25
29
  }
26
30
  return true;
@@ -38,18 +42,17 @@ export default {
38
42
 
39
43
  const isActive = await confirm({
40
44
  message: "Is this environment active?",
45
+ default: !config.active,
41
46
  });
42
47
 
43
- logger
44
- .debug(`Adding new environment "${name}" with prefix "${prefix}" and file: "${file}"`);
48
+ logger.debug(`Adding new environment "${name}" with prefix "${prefix}" and file: "${file}"`);
45
49
 
46
- config
47
- .addEnvironment({ name, prefix, file, isActive })
48
- .save();
50
+ config.envs.set(name, { name, prefix, file, isActive });
51
+ config.save();
52
+
53
+ const envFile = new EnvironmentFile(file);
49
54
 
50
- const valuesToSet: Array<[string, string]> = []
51
-
52
- if (!fs.existsSync(file)) {
55
+ if (!exists(file)) {
53
56
  logger.debug(`Environment file not found: ${file}`);
54
57
 
55
58
  const shouldClone = await confirm({
@@ -61,13 +64,10 @@ export default {
61
64
 
62
65
  const clonedEnv = await select({
63
66
  message: "Select the environment to clone from:",
64
- choices: config.configuration.environments.map(env => ({
65
- name: env.name,
66
- value: env.name,
67
- })),
67
+ choices: Array.from(config.envs.keys()),
68
68
  });
69
69
 
70
- const selectedEnv = config.getEnvironment(clonedEnv);
70
+ const selectedEnv = config.envs.get(clonedEnv);
71
71
 
72
72
  if (!selectedEnv) {
73
73
  throw new NotFoundError(`Environment not found: ${clonedEnv}`);
@@ -75,11 +75,11 @@ export default {
75
75
 
76
76
  const envSpecificFile = new EnvironmentFile(selectedEnv.file);
77
77
 
78
- for (const [key, value] of Object.entries(envSpecificFile.data)) {
79
- valuesToSet.push([key, value]);
78
+ for (const [key, value] of Object.entries(envSpecificFile.vars)) {
79
+ envFile.vars.set(key, value);
80
80
  }
81
81
  } else {
82
- for (const variable of config.configuration.variables) {
82
+ for (const [_, variable] of config.vars) {
83
83
  const request = {
84
84
  message: `Enter the value for ${variable.name} in environment ${name}:`,
85
85
  mask: variable.type === VariableType.Private ? "*" : undefined,
@@ -92,19 +92,22 @@ export default {
92
92
  logger
93
93
  .debug(`Setting variable "${variable.name}" with value "${value}" in environment "${name}"`);
94
94
 
95
- valuesToSet.push([variable.name, value]);
95
+ envFile.vars.set(variable.name, value);
96
96
  }
97
97
  }
98
98
 
99
- const envFile = new EnvironmentFile(file);
100
-
99
+ envFile.save();
100
+ }
101
101
 
102
- for (const [key, value] of valuesToSet) {
103
- logger
104
- .debug(`Setting variable "${key}" with value "${value}" in environment file: ${file}`);
102
+ if (isActive) {
103
+ config.active = name;
105
104
 
106
- envFile.setVariable(key, value);
105
+ if (exists('.env')) {
106
+ unlink('.env');
107
107
  }
108
+
109
+ const properEnv = config.envs.get(name)!;
110
+ symlink(properEnv.file, '.env', 'file');
108
111
  }
109
112
  }
110
113
  } satisfies CommandModule;
@@ -1,6 +1,9 @@
1
- import fs from "node:fs";
1
+ import {
2
+ renameSync as rename,
3
+ existsSync as exists,
4
+ } from "node:fs";
2
5
 
3
- import { confirm, input, select, checkbox } from "@inquirer/prompts";
6
+ import { input, select, checkbox } from "@inquirer/prompts";
4
7
 
5
8
  import { Configuration } from "#lib/config";
6
9
  import { NotFoundError } from "#lib/error";
@@ -11,18 +14,15 @@ export default {
11
14
  describe: 'Edit an environment',
12
15
  builder: (yargs) => yargs,
13
16
  handler: async (argv) => {
14
- const config = new Configuration().load();
17
+ const config = new Configuration();
15
18
  const logger = new Logger(argv.level);
16
19
 
17
20
  const name = await select({
18
21
  message: "Select the environment to edit:",
19
- choices: config.configuration.environments.map(env => ({
20
- name: env.name,
21
- value: env.name,
22
- })),
22
+ choices: Array.from(config.envs.keys()),
23
23
  });
24
24
 
25
- const selectedEnv = config.getEnvironment(name);
25
+ const selectedEnv = config.envs.get(name);
26
26
 
27
27
  if (!selectedEnv) {
28
28
  throw new NotFoundError(`Environment not found: ${name}`);
@@ -63,20 +63,12 @@ export default {
63
63
  });
64
64
  }
65
65
 
66
- config
67
- .editEnvironment(name, updatedEnv)
68
- .save();
66
+ config.envs.set(name, updatedEnv);
67
+ config.save();
69
68
 
70
- if (itemsToEdit.includes("file") && fs.existsSync(selectedEnv.file)) {
71
- logger.debug(`Old environment file found: ${selectedEnv.file}`);
72
- const toRename = await confirm({
73
- message: `Old environment file found: ${selectedEnv.file}. Do you want to rename it to the new file path: ${updatedEnv.file}?`
74
- });
75
-
76
- if (toRename) {
77
- logger.debug(`Renaming environment file from "${selectedEnv.file}" to "${updatedEnv.file}"`);
78
- fs.renameSync(selectedEnv.file, updatedEnv.file);
79
- }
69
+ if (itemsToEdit.includes("file") && exists(selectedEnv.file)) {
70
+ logger.debug(`Renaming environment file from "${selectedEnv.file}" to "${updatedEnv.file}"`);
71
+ rename(selectedEnv.file, updatedEnv.file);
80
72
  }
81
73
  }
82
74
  } satisfies CommandModule;
@@ -6,13 +6,11 @@ export default {
6
6
  describe: 'List all environments',
7
7
  builder: (yargs) => yargs,
8
8
  handler: async (argv) => {
9
- const config = new Configuration().load();
9
+ const config = new Configuration();
10
10
  const logger = new Logger(argv.level);
11
11
 
12
12
  logger.debug(`Listing all environments`);
13
13
 
14
- console.log(
15
- JSON.stringify(config.configuration.environments, null, 2)
16
- )
14
+ console.log(JSON.stringify(Array.from(config.envs.values()), null, 2));
17
15
  }
18
16
  } satisfies CommandModule;
@@ -1,4 +1,7 @@
1
- import fs from "node:fs";
1
+ import {
2
+ existsSync as exists,
3
+ unlinkSync as unlink,
4
+ } from "node:fs";
2
5
 
3
6
  import { confirm, select } from "@inquirer/prompts";
4
7
 
@@ -11,18 +14,15 @@ export default {
11
14
  describe: 'Remove an environment',
12
15
  builder: (yargs) => yargs,
13
16
  handler: async (argv) => {
14
- const config = new Configuration().load();
17
+ const config = new Configuration();
15
18
  const logger = new Logger(argv.level);
16
19
 
17
20
  const name = await select({
18
21
  message: "Select the environment to remove:",
19
- choices: config.configuration.environments.map(env => ({
20
- name: env.name,
21
- value: env.name,
22
- })),
22
+ choices: Array.from(config.envs.keys()),
23
23
  });
24
24
 
25
- const selectedEnv = config.getEnvironment(name);
25
+ const selectedEnv = config.envs.get(name);
26
26
 
27
27
  if (!selectedEnv) {
28
28
  throw new NotFoundError(`Environment not found: ${name}`);
@@ -30,18 +30,17 @@ export default {
30
30
 
31
31
  logger.debug(`Removing environment "${name}" with file: "${selectedEnv.file}"`);
32
32
 
33
- config
34
- .removeEnvironment(name)
35
- .save();
33
+ config.envs.delete(name);
34
+ config.save();
36
35
 
37
- if (fs.existsSync(selectedEnv.file)) {
36
+ if (exists(selectedEnv.file)) {
38
37
  const toDelete = await confirm({
39
38
  message: `Environment file found: ${selectedEnv.file}. Do you want to delete it?`
40
39
  });
41
40
 
42
41
  if (toDelete) {
43
42
  logger.debug(`Deleting environment file: ${selectedEnv.file}`);
44
- fs.unlinkSync(selectedEnv.file);
43
+ unlink(selectedEnv.file);
45
44
  }
46
45
  }
47
46
  }
@@ -1,6 +1,7 @@
1
1
  import Environment from './environment';
2
2
  import Variable from './variable';
3
3
  import Use from './use';
4
+ import Init from './init';
4
5
  import Setup from './setup';
5
6
 
6
- export default [Environment, Variable, Use, Setup];
7
+ export default [Environment, Variable, Use, Init, Setup];
@@ -1,4 +1,9 @@
1
- import fs from "node:fs";
1
+ import {
2
+ existsSync as exists,
3
+ readFileSync as read,
4
+ writeFileSync as write,
5
+ appendFileSync as append,
6
+ } from "node:fs";
2
7
 
3
8
  import { confirm } from "@inquirer/prompts";
4
9
 
@@ -6,33 +11,28 @@ import { Configuration } from "#lib/config";
6
11
  import { Logger } from "#lib/logger";
7
12
 
8
13
  export default {
9
- command: 'setup',
10
- describe: 'Setup the project for use with envedit',
14
+ command: 'init',
15
+ describe: 'Initialize the project for use with envedit',
11
16
  builder: (yargs) => yargs
12
- .usage('Usage: envedit setup'),
17
+ .usage('Usage: envedit init')
18
+ .epilogue("Note that this command is meant to be used when the project is FIRST setup, not to setup based on a pre-existing configuration. for that, please run the 'setup' command"),
13
19
  handler: async (argv) => {
14
20
  const logger = new Logger(argv.level);
21
+ new Configuration();
15
22
 
16
- new Configuration().load();
17
-
18
- if (fs.existsSync('.git')) {
23
+ if (exists('.git')) {
19
24
  logger.debug(`Git repository found. Checking for git ignore file.`);
20
25
 
21
26
  const gitignorePath = '.gitignore';
22
27
 
23
- if (!fs.existsSync(gitignorePath)) {
24
- logger.debug(`Git ignore file not found: ${gitignorePath}`);
25
-
28
+ if (!exists('.gitignore')) {
26
29
  const toCreate = await confirm({
27
- message: `Git Repository without a git ignore file not found: ${gitignorePath}. Do you want to create it?`
30
+ message: `Git Repository without a git ignore file not found. Do you want to create it?`
28
31
  });
29
32
 
30
33
  if (toCreate) {
31
- console.error(`Git Repository without a git ignore file not found: ${gitignorePath}`);
32
- process.exit(1);
34
+ write('.gitignore', "");
33
35
  }
34
-
35
- fs.writeFileSync(gitignorePath, "");
36
36
  }
37
37
 
38
38
  const expectedItems = ['.env', '.env.*'];
@@ -40,7 +40,7 @@ export default {
40
40
  logger.debug(`Checking for expected items in git ignore file: ${expectedItems.join(", ")}`);
41
41
 
42
42
  for (const item of expectedItems) {
43
- if (!fs.readFileSync(gitignorePath, "utf-8").includes(item)) {
43
+ if (read(gitignorePath, "utf-8").includes(item)) {
44
44
  logger.debug(`Item not found in git ignore file: ${item}`);
45
45
 
46
46
  const toAdd = await confirm({
@@ -52,7 +52,7 @@ export default {
52
52
  process.exit(1);
53
53
  }
54
54
 
55
- fs.appendFileSync(gitignorePath, `\n${item}`);
55
+ append(gitignorePath, `\n${item}`);
56
56
  }
57
57
  }
58
58
  }
@@ -0,0 +1,46 @@
1
+ import {
2
+ lstatSync as lstat,
3
+ existsSync as exists,
4
+ copyFileSync as copy,
5
+ unlinkSync as unlink,
6
+ symlinkSync as symlink,
7
+ } from 'node:fs';
8
+
9
+ import { Configuration, EnvironmentFile } from "#lib/config";
10
+ import { NotFoundError } from "#lib/error";
11
+
12
+ export default {
13
+ command: 'setup',
14
+ describe: 'Setup the project for use with envedit',
15
+ builder: (yargs) => yargs
16
+ .usage('Usage: envedit setup')
17
+ .epilogue("Note that this command is meant to be used after the project has been setup. To make a clean start, please run the 'init' command instead."),
18
+ handler: async (_argv) => {
19
+ if (!exists('env.config.yaml')) {
20
+ throw new NotFoundError("Could not find configuration file. Did you run the init command?")
21
+ }
22
+
23
+ const config = new Configuration();
24
+
25
+ for (const environment of config.envs.values()) {
26
+ const envFile = new EnvironmentFile(environment.file);
27
+
28
+ if (environment.isActive) {
29
+ if (exists('.env') && !lstat('.env').isSymbolicLink()) {
30
+ copy('.env', environment.file);
31
+ unlink('.env');
32
+ }
33
+
34
+ symlink(environment.file, '.env', 'file');
35
+ }
36
+
37
+ for (const variable of config.vars.values()) {
38
+ if (!envFile.vars.has(variable.name)) {
39
+ envFile.vars.set(variable.name, '');
40
+ }
41
+ }
42
+
43
+ envFile.save();
44
+ }
45
+ }
46
+ } as CommandModule;
@@ -1,4 +1,9 @@
1
- import fs from "node:fs";
1
+ import {
2
+ lstatSync as lstat,
3
+ existsSync as exists,
4
+ unlinkSync as unlink,
5
+ symlinkSync as symlink,
6
+ } from 'node:fs';
2
7
 
3
8
  import { select } from "@inquirer/prompts";
4
9
 
@@ -13,19 +18,18 @@ export default {
13
18
  .usage('Usage: envedit use'),
14
19
  handler: async (argv) => {
15
20
  const logger = new Logger(argv.level);
16
-
17
- const config = new Configuration().load();
21
+ const config = new Configuration();
18
22
 
19
23
  const name = await select({
20
24
  message: "Select the environment to use",
21
- choices: config.configuration.environments.map(env => ({
22
- name: env.name + (env.isActive ? " (active)" : ""),
23
- value: env.name,
25
+ choices: Array.from(config.envs.keys()).map(env => ({
26
+ name: env + (config.envs.get(env)?.isActive ? " (active)" : ""),
27
+ value: env,
24
28
  })),
25
29
  default: config.active,
26
30
  });
27
31
 
28
- const selectedEnv = config.getEnvironment(name);
32
+ const selectedEnv = config.envs.get(name);
29
33
 
30
34
  if (!selectedEnv) {
31
35
  throw new NotFoundError(`Environment not found: ${name}`);
@@ -45,12 +49,12 @@ export default {
45
49
 
46
50
  const envFilePath = selectedEnv.file;
47
51
 
48
- if (fs.existsSync('.env')) {
52
+ if (exists('.env')) {
49
53
  logger.debug(`Removing existing symlink or file: .env`);
50
54
 
51
- fs.unlinkSync('.env');
55
+ unlink('.env');
52
56
  }
53
57
 
54
- fs.symlinkSync(envFilePath, '.env', 'file');
58
+ symlink(envFilePath, '.env', 'file');
55
59
  }
56
60
  } as CommandModule;
@@ -9,7 +9,7 @@ export default {
9
9
  describe: 'Add a new environment variable',
10
10
  builder: (yargs) => yargs,
11
11
  handler: async (argv) => {
12
- const config = new Configuration().load();
12
+ const config = new Configuration();
13
13
  const logger = new Logger(argv.level);
14
14
 
15
15
  const name = await input({
@@ -18,7 +18,7 @@ export default {
18
18
  if (!input) {
19
19
  return "Variable name cannot be empty";
20
20
  }
21
- if (config.getVariable(input)) {
21
+ if (config.vars.has(input)) {
22
22
  return "Variable name already exists";
23
23
  }
24
24
  return true;
@@ -35,15 +35,14 @@ export default {
35
35
 
36
36
  logger.debug(`Adding new variable "${name}" with type "${type}"`);
37
37
 
38
- config
39
- .addVariable({ name, type })
40
- .save();
38
+ config.vars.set(name, { name, type });
39
+ config.save();
41
40
 
42
41
  const shouldGloballySet = await confirm({
43
42
  message: "Do you want to set this variable with a global value for all environments?",
44
43
  });
45
44
 
46
- const valuesToSet = config.configuration.environments.map(env => ({
45
+ const valuesToSet = Array.from(config.envs.values()).map(env => ({
47
46
  envName: env.name,
48
47
  value: '',
49
48
  }));
@@ -77,14 +76,17 @@ export default {
77
76
  }
78
77
 
79
78
  for (const envValue of valuesToSet) {
80
- const env = config.getEnvironment(envValue.envName);
79
+ const env = config.envs.get(envValue.envName);
81
80
  logger.debug(`Retrieving environment: ${envValue.envName}`);
82
81
 
83
82
  if (!env) {
84
83
  throw new NotFoundError(`Environment not found: ${envValue.envName}`);
85
84
  }
86
85
 
87
- EnvironmentFile.quickUpdate(env.file, name, envValue.value);
86
+ const envFile = new EnvironmentFile(env.file);
87
+
88
+ envFile.vars.set(name, envValue.value);
89
+ envFile.save();
88
90
  }
89
91
  }
90
92
  } satisfies CommandModule;
@@ -9,18 +9,15 @@ export default {
9
9
  describe: 'Edit an environment variable',
10
10
  builder: (yargs) => yargs,
11
11
  handler: async (argv) => {
12
- const config = new Configuration().load();
12
+ const config = new Configuration();
13
13
  const logger = new Logger(argv.level);
14
14
 
15
15
  const name = await select({
16
16
  message: "Select the variable to edit:",
17
- choices: config.configuration.variables.map(variable => ({
18
- name: variable.name,
19
- value: variable.name,
20
- })),
17
+ choices: Array.from(config.vars.keys()),
21
18
  });
22
19
 
23
- const variableConfiguration = config.getVariable(name);
20
+ const variableConfiguration = config.vars.get(name);
24
21
 
25
22
  if (!variableConfiguration) {
26
23
  throw new NotFoundError(`Variable not found: ${name}`);
@@ -53,17 +50,22 @@ export default {
53
50
  default: variableConfiguration.name,
54
51
  });
55
52
 
56
- for (const env of config.configuration.environments) {
53
+ for (const [_, env] of config.envs) {
57
54
  const envFile = new EnvironmentFile(env.file);
58
55
 
59
56
  logger.debug(`Editing variable "${name}" in environment file: ${env.file}`);
60
57
 
61
- if (envFile.data[name] !== undefined) {
62
- envFile
63
- .removeVariable(name)
64
- .setVariable(updatedVariable.name, envFile.data[name]);
65
- }
58
+ if (envFile.vars.has(name)) {
59
+ const value = envFile.vars.get(name) || '';
60
+
61
+ envFile.vars.delete(name);
62
+ envFile.vars.set(updatedVariable.name, value);
63
+ };
64
+
65
+ envFile.save();
66
66
  }
67
+
68
+ config.vars.delete(name);
67
69
  }
68
70
 
69
71
  if (itemsToEdit.includes("type")) {
@@ -79,13 +81,12 @@ export default {
79
81
  logger.debug(`Editing variable type for "${name}" to "${updatedVariable.type}"`);
80
82
  }
81
83
 
82
- config
83
- .editVariable(name, updatedVariable)
84
- .save();
84
+ config.vars.set(updatedVariable.name, updatedVariable);
85
+ config.save();
85
86
  } else {
86
- logger.debug(`Adding editing variable value for: ${name}`);
87
+ logger.debug(`Adding edited variable value for: ${name}`);
87
88
 
88
- let valuesToSet = config.configuration.environments.map(env => ({
89
+ let valuesToSet = Array.from(config.envs.values()).map(env => ({
89
90
  envName: env.name,
90
91
  value: '',
91
92
  }));
@@ -106,47 +107,43 @@ export default {
106
107
 
107
108
  logger.debug(`Setting variable "${variableConfiguration.name}" with global value "${globalValue}" for all environments`);
108
109
 
109
- valuesToSet.forEach((envValue) => { envValue.value = globalValue });
110
+ for (const [_, env] of config.envs) {
111
+ const envFile = new EnvironmentFile(env.file);
112
+
113
+ logger.debug(`Setting variable "${variableConfiguration.name}" with value "${globalValue}" in environment file: ${env.file}`);
114
+
115
+ envFile.vars.set(variableConfiguration.name, globalValue);
116
+ envFile.save();
117
+ }
110
118
  } else {
111
119
  const envsToEdit = await checkbox({
112
120
  message: "Select the environments to edit the variable value for:",
113
- choices: config.configuration.environments.map(env => ({
114
- name: env.name,
115
- value: env.name,
116
- })),
121
+ choices: Array.from(config.envs.keys()),
117
122
  });
118
123
 
119
124
  logger.debug(`Selected environments for editing: ${envsToEdit.join(", ")}`);
120
125
 
121
- valuesToSet = valuesToSet.filter(envValue => envsToEdit.includes(envValue.envName));
126
+ for (const selectedEnv of envsToEdit) {
127
+ const env = config.envs.get(selectedEnv);
122
128
 
123
- if (valuesToSet.length === 0) {
124
- console.log("No environments selected. Exiting.");
125
- return;
126
- }
129
+ if (!env) {
130
+ throw new NotFoundError(`Environment not found: ${selectedEnv}`);
131
+ }
132
+
133
+ const envFile = new EnvironmentFile(env.file);
127
134
 
128
- for (const envValue of valuesToSet) {
129
135
  const request = {
130
- message: `Enter the value for ${variableConfiguration.name} in environment ${envValue.envName}:`,
136
+ message: `Enter the value for ${variableConfiguration.name} in environment ${selectedEnv}:`,
131
137
  mask: variableConfiguration.type === VariableType.Private ? "*" : undefined,
132
138
  };
133
139
 
134
- envValue.value = variableConfiguration.type === VariableType.Private
140
+ const newValue = variableConfiguration.type === VariableType.Private
135
141
  ? await password(request)
136
142
  : await input(request);
137
- }
138
- }
139
-
140
- for (const envValue of valuesToSet) {
141
- const env = config.getEnvironment(envValue.envName);
142
143
 
143
- if (!env) {
144
- throw new NotFoundError(`Environment not found: ${envValue.envName}`);
144
+ envFile.vars.set(variableConfiguration.name, newValue);
145
+ envFile.save();
145
146
  }
146
-
147
- logger.debug(`Setting variable "${variableConfiguration.name}" with value "${envValue.value}" in environment file: ${env.file}`);
148
-
149
- EnvironmentFile.quickUpdate(env.file, variableConfiguration.name, envValue.value);
150
147
  }
151
148
  }
152
149
  }
@@ -7,10 +7,10 @@ export default {
7
7
  describe: 'List all environment variables',
8
8
  builder: (yargs) => yargs,
9
9
  handler: async (argv) => {
10
- const config = new Configuration().load();
10
+ const config = new Configuration();
11
11
  const logger = new Logger(argv.level);
12
12
 
13
- const activeEnv = config.active ? config.getEnvironment(config.active) : undefined;
13
+ const activeEnv = config.active ? config.envs.get(config.active)! : undefined;
14
14
 
15
15
  if (!activeEnv) {
16
16
  throw new NotFoundError(`No active environment found. Please set an active environment using the "use" command.`);
@@ -18,8 +18,8 @@ export default {
18
18
 
19
19
  const envFile = new EnvironmentFile(activeEnv.file);
20
20
 
21
- for (const [key, value] of Object.entries(envFile.data)) {
22
- const variableConfiguration = config.getVariable(key);
21
+ for (const [key, value] of envFile.vars) {
22
+ const variableConfiguration = config.vars.get(key);
23
23
  if (variableConfiguration) {
24
24
  const type = Configuration.getTypeDetails(variableConfiguration.type);
25
25
 
@@ -9,33 +9,30 @@ export default {
9
9
  describe: 'Remove an environment variable',
10
10
  builder: (yargs) => yargs,
11
11
  handler: async (argv) => {
12
- const config = new Configuration().load();
12
+ const config = new Configuration();
13
13
  const logger = new Logger(argv.level);
14
14
 
15
15
  const name = await select({
16
16
  message: "Select the variable to remove:",
17
- choices: config.configuration.variables.map(variable => ({
18
- name: variable.name,
19
- value: variable.name,
20
- })),
17
+ choices: Array.from(config.vars.keys()),
21
18
  });
22
19
 
23
- if (!config.getVariable(name)) {
20
+ if (!config.vars.has(name)) {
24
21
  throw new NotFoundError(`Variable not found: ${name}`);
25
22
  }
26
23
 
27
24
  logger.debug(`Removing variable "${name}" from configuration and all environment files`);
28
25
 
29
- config
30
- .removeVariable(name)
31
- .save();
26
+ config.vars.delete(name);
27
+ config.save();
32
28
 
33
- for (const env of config.configuration.environments) {
29
+ for (const [_, env] of config.envs) {
34
30
  const envFile = new EnvironmentFile(env.file);
35
31
 
36
- if (envFile.data[name] !== undefined) {
32
+ if (envFile.vars.has(name)) {
37
33
  logger.debug(`Removing variable "${name}" from environment file: ${env.file}`);
38
- envFile.removeVariable(name);
34
+ envFile.vars.delete(name);
35
+ envFile.save();
39
36
  }
40
37
  }
41
38
  }
@@ -9,13 +9,13 @@ await yargs(hideBin(process.argv))
9
9
  alias: "l",
10
10
  type: "string",
11
11
  description: "Set the log level",
12
- choices: ['debug', 'info', 'warn', 'error', 'fatal'],
13
12
  default: process.env.LOG_LEVEL || "info",
14
13
  })
15
14
  .env('ENVEDIT')
16
15
  .scriptName("envedit")
17
16
  .usage("Usage: $0 <command>")
18
17
  .command(Commands)
18
+ .showHelpOnFail(false)
19
19
  .demandCommand()
20
20
  .strict()
21
21
  .parseAsync();
package/lib/config.ts CHANGED
@@ -1,4 +1,9 @@
1
- import fs, { existsSync as exists, readFileSync as read, writeFileSync as write } from 'fs';
1
+ import {
2
+ existsSync as exists,
3
+ readFileSync as read,
4
+ writeFileSync as write,
5
+ appendFileSync as append,
6
+ } from 'fs';
2
7
 
3
8
  import { parse } from 'dotenv';
4
9
 
@@ -33,15 +38,7 @@ export class Configuration {
33
38
  public readonly version: number = 1;
34
39
  private readonly configFilePath: string = 'env.config.yaml';
35
40
 
36
- public get configuration(): GeneralConfiguration {
37
- return {
38
- version: this.version,
39
- environments: Array.from(this.envs.values()) || [],
40
- variables: Array.from(this.vars.values()) || [],
41
- };
42
- }
43
-
44
- public load() {
41
+ constructor() {
45
42
  if (!exists(this.configFilePath)) {
46
43
  this
47
44
  .importFromEnv(exists('.env') ? read('.env', "utf-8") : '')
@@ -57,13 +54,16 @@ export class Configuration {
57
54
  configContent.environments.forEach(setWrapper(this.envs))
58
55
  configContent.variables.forEach(setWrapper(this.vars))
59
56
 
60
- return this;
61
57
  }
62
58
 
63
59
  public save() {
64
60
  write(
65
61
  this.configFilePath,
66
- Bun.YAML.stringify(this.configuration, null, 2),
62
+ Bun.YAML.stringify({
63
+ version: this.version,
64
+ environments: Array.from(this.envs.values()),
65
+ variables: Array.from(this.vars.values()),
66
+ }, null, 2),
67
67
  { mode: 0o600 },
68
68
  );
69
69
 
@@ -88,64 +88,9 @@ export class Configuration {
88
88
  this.save();
89
89
  }
90
90
 
91
- public addEnvironment(env: EnviornmentConfiguration) {
92
- this.envs.set(env.name, env);
93
-
94
- return this;
95
- }
96
-
97
- public editEnvironment(name: string, env: Partial<EnviornmentConfiguration>) {
98
- if (!this.envs.has(name)) {
99
- throw new NotFoundError(`Environment not found: ${name}`);
100
- }
101
-
102
- this.envs.set(name, { ...this.envs.get(name)!, ...env });
103
-
104
- return this;
105
- }
106
-
107
- public removeEnvironment(name: string) {
108
- this.envs.delete(name);
109
-
110
- return this;
111
- }
112
-
113
- public getEnvironment(name: string): EnviornmentConfiguration | undefined {
114
- return this.envs.get(name);
115
- }
116
-
117
- public addVariable(variable: VariableConfiguration) {
118
- this.vars.set(variable.name, variable);
119
-
120
- return this;
121
- }
122
-
123
- public editVariable(name: string, variable: Partial<VariableConfiguration>) {
124
- if (!this.vars.has(name)) {
125
- throw new NotFoundError(`Variable not found: ${name}`);
126
- }
127
-
128
- this.vars.set(name, { ...this.vars.get(name)!, ...variable });
129
-
130
- return this;
131
- }
132
-
133
- public removeVariable(name: string) {
134
- this.vars.delete(name);
135
-
136
- return this;
137
- }
138
-
139
- public getVariable(name: string): VariableConfiguration | undefined {
140
- return this.vars.get(name);
141
- }
142
-
143
91
  public importFromEnv(content: string): Configuration {
144
92
  for (const [key, _] of Object.entries(parse(content))) {
145
- this.addVariable({
146
- name: key,
147
- type: key.includes('PRIVATE') ? VariableType.Private : VariableType.Public,
148
- });
93
+ this.vars.set(key, { name: key, type: VariableType.Private });
149
94
  }
150
95
 
151
96
  return this;
@@ -167,37 +112,22 @@ export class Configuration {
167
112
  }
168
113
 
169
114
  export class EnvironmentFile {
170
- constructor(public readonly path: string) { }
171
- public get data() {
172
- if (!fs.existsSync(this.path)) {
173
- fs.writeFileSync(this.path, '', { mode: 0o600 });
115
+ public readonly vars: Map<string, string> = new Map();
116
+ constructor(public readonly path: string) {
117
+ if (exists(path)) {
118
+ const content = read(path, "utf-8");
119
+ const parsed = parse(content);
120
+
121
+ for (const [key, value] of Object.entries(parsed)) {
122
+ this.vars.set(key, value);
123
+ }
174
124
  }
175
- return parse(fs.readFileSync(this.path, "utf-8"));
176
125
  }
177
126
 
178
- public set data(content: Record<string, string>) {
179
- const lines: string[] = [];
180
- for (const [key, value] of Object.entries(content)) {
181
- lines.push(`${key}='${value}'`);
127
+ public save() {
128
+ write(this.path, '')
129
+ for (const [key, value] of this.vars.entries()) {
130
+ append(this.path, `${key}='${value}'\n`);
182
131
  }
183
- fs.writeFileSync(this.path, lines.join('\n'));
184
- }
185
-
186
- public setVariable(name: string, value: string) {
187
- this.data = { ...this.data, [name]: value };
188
- return this;
189
- }
190
-
191
- public removeVariable(name: string) {
192
- const tmpData = Object.assign({}, this.data);
193
- delete tmpData[name];
194
- this.data = tmpData;
195
- return this;
196
- }
197
-
198
- public static quickUpdate(path: string, name: string, value: string) {
199
- const envFile = new EnvironmentFile(path);
200
- envFile.setVariable(name, value);
201
- return envFile;
202
132
  }
203
133
  }
package/package.json CHANGED
@@ -1,19 +1,17 @@
1
1
  {
2
2
  "name": "@benshawmean/envedit",
3
- "module": "index.ts",
4
3
  "type": "module",
5
- "version": "1.3.1",
4
+ "version": "1.3.2-2",
6
5
  "license": "GPL-3.0-only",
7
6
  "bin": {
8
- "envedit": "index.ts"
7
+ "envedit": "cli/index.ts"
9
8
  },
10
9
  "repository": {
11
10
  "url": "https://gitlab.com/benshawmean/envedit.git"
12
11
  },
13
12
  "publishConfig": {
14
13
  "access": "public",
15
- "provenance": true,
16
- "tag": "latest"
14
+ "provenance": true
17
15
  },
18
16
  "devDependencies": {
19
17
  "@types/bun": "^1.3.14",
File without changes
File without changes
File without changes
File without changes