@ben-studios/envedit 0.0.0-stage → 1.0.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.
@@ -0,0 +1,139 @@
1
+ TN:
2
+ SF:lib/config.ts
3
+ FNF:12
4
+ FNH:12
5
+ DA:1,46
6
+ DA:2,50
7
+ DA:3,48
8
+ DA:4,52
9
+ DA:5,48
10
+ DA:8,62
11
+ DA:10,86
12
+ DA:12,133
13
+ DA:13,108
14
+ DA:14,114
15
+ DA:39,1
16
+ DA:41,27
17
+ DA:42,81
18
+ DA:43,10
19
+ DA:44,94
20
+ DA:45,22
21
+ DA:46,9
22
+ DA:48,154
23
+ DA:50,39
24
+ DA:52,103
25
+ DA:54,124
26
+ DA:55,118
27
+ DA:59,20
28
+ DA:60,12
29
+ DA:61,42
30
+ DA:62,52
31
+ DA:63,56
32
+ DA:64,102
33
+ DA:65,90
34
+ DA:66,26
35
+ DA:67,26
36
+ DA:68,12
37
+ DA:70,33
38
+ DA:73,22
39
+ DA:74,160
40
+ DA:76,99
41
+ DA:79,28
42
+ DA:80,70
43
+ DA:81,61
44
+ DA:82,9
45
+ DA:84,123
46
+ DA:85,136
47
+ DA:86,9
48
+ DA:88,32
49
+ DA:91,43
50
+ DA:92,123
51
+ DA:93,122
52
+ DA:94,9
53
+ DA:96,43
54
+ DA:99,38
55
+ DA:100,72
56
+ DA:102,127
57
+ DA:103,104
58
+ DA:104,72
59
+ DA:105,9
60
+ DA:107,28
61
+ DA:108,76
62
+ DA:109,30
63
+ DA:110,8
64
+ DA:112,2
65
+ DA:114,62
66
+ DA:115,33
67
+ DA:116,91
68
+ DA:117,42
69
+ DA:118,42
70
+ DA:119,36
71
+ DA:121,60
72
+ DA:122,32
73
+ DA:123,5
74
+ DA:124,9
75
+ DA:127,20
76
+ DA:128,50
77
+ DA:129,109
78
+ DA:130,86
79
+ DA:131,8
80
+ DA:133,2
81
+ LF:76
82
+ LH:76
83
+ end_of_record
84
+ TN:
85
+ SF:lib/error.ts
86
+ FNF:1
87
+ FNH:1
88
+ DA:1,42
89
+ DA:2,15
90
+ DA:3,19
91
+ DA:4,31
92
+ LF:4
93
+ LH:4
94
+ end_of_record
95
+ TN:
96
+ SF:lib/logger.ts
97
+ FNF:6
98
+ FNH:6
99
+ DA:1,47
100
+ DA:14,1
101
+ DA:16,177
102
+ DA:17,61
103
+ DA:20,43
104
+ DA:21,69
105
+ DA:22,32
106
+ DA:24,41
107
+ DA:25,68
108
+ DA:26,32
109
+ DA:28,41
110
+ DA:29,68
111
+ DA:30,32
112
+ DA:32,43
113
+ DA:33,69
114
+ DA:34,32
115
+ DA:36,43
116
+ DA:37,69
117
+ DA:38,30
118
+ DA:40,2
119
+ LF:20
120
+ LH:20
121
+ end_of_record
122
+ TN:
123
+ SF:test/util.ts
124
+ FNF:2
125
+ FNH:2
126
+ DA:1,21
127
+ DA:2,21
128
+ DA:3,23
129
+ DA:4,24
130
+ DA:7,30
131
+ DA:8,47
132
+ DA:9,22
133
+ DA:10,24
134
+ DA:11,17
135
+ DA:12,2
136
+ DA:13,4
137
+ LF:11
138
+ LH:11
139
+ end_of_record
@@ -0,0 +1,37 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <testsuites name="bun test" tests="16" assertions="34" failures="0" skipped="0" time="0.164498">
3
+ <testsuite name="test/error.test.ts" file="test/error.test.ts" tests="1" assertions="4" failures="0" skipped="0" time="0.052159" hostname="Bens-Mac.local">
4
+ <testsuite name="Error Handling" file="test/error.test.ts" line="8" tests="1" assertions="4" failures="0" skipped="0" time="0.003" hostname="Bens-Mac.local">
5
+ <testcase name="NotFoundError should have correct name and message" classname="Error Handling" time="0.003242" file="test/error.test.ts" line="9" assertions="4" />
6
+ </testsuite>
7
+ </testsuite>
8
+ <testsuite name="test/variable.test.ts" file="test/variable.test.ts" tests="9" assertions="20" failures="0" skipped="0" time="0.024627" hostname="Bens-Mac.local">
9
+ <testsuite name="Variable Management" file="test/variable.test.ts" line="8" tests="9" assertions="20" failures="0" skipped="0" time="0.002" hostname="Bens-Mac.local">
10
+ <testcase name="Import variables from .env content" classname="Variable Management" time="0.001122" file="test/variable.test.ts" line="11" assertions="2" />
11
+ <testcase name="Add a new variable" classname="Variable Management" time="0.001079" file="test/variable.test.ts" line="26" assertions="1" />
12
+ <testcase name="Edit an existing variable" classname="Variable Management" time="0.000109" file="test/variable.test.ts" line="35" assertions="1" />
13
+ <testcase name="Remove an existing variable" classname="Variable Management" time="0.000379" file="test/variable.test.ts" line="43" assertions="1" />
14
+ <testcase name="Verify Type Details" classname="Variable Management" time="0.000082" file="test/variable.test.ts" line="51" assertions="7" />
15
+ <testsuite name="Environment File" file="test/variable.test.ts" line="67" tests="4" assertions="8" failures="0" skipped="0" time="0" hostname="Bens-Mac.local">
16
+ <testcase name="Has Initialized Properly" classname="Environment File &gt; Variable Management" time="0.000251" file="test/variable.test.ts" line="76" assertions="3" />
17
+ <testcase name="Add Variable" classname="Environment File &gt; Variable Management" time="0.000169" file="test/variable.test.ts" line="82" assertions="2" />
18
+ <testcase name="Edit Variable" classname="Environment File &gt; Variable Management" time="0.000142" file="test/variable.test.ts" line="91" assertions="2" />
19
+ <testcase name="Remove Variable" classname="Environment File &gt; Variable Management" time="0.000087" file="test/variable.test.ts" line="100" assertions="1" />
20
+ </testsuite>
21
+ </testsuite>
22
+ </testsuite>
23
+ <testsuite name="test/config.test.ts" file="test/config.test.ts" tests="5" assertions="5" failures="0" skipped="0" time="0.001569" hostname="Bens-Mac.local">
24
+ <testsuite name="Environment Management" file="test/config.test.ts" line="8" tests="5" assertions="5" failures="0" skipped="0" time="0" hostname="Bens-Mac.local">
25
+ <testcase name="Add a new environment" classname="Environment Management" time="0.000073" file="test/config.test.ts" line="11" assertions="1" />
26
+ <testcase name="Edit an existing environment" classname="Environment Management" time="0.000056" file="test/config.test.ts" line="20" assertions="1" />
27
+ <testcase name="Set an environment as active" classname="Environment Management" time="0.000176" file="test/config.test.ts" line="30" assertions="1" />
28
+ <testcase name="Set no environment as active" classname="Environment Management" time="0.000066" file="test/config.test.ts" line="40" assertions="1" />
29
+ <testcase name="Remove an existing environment" classname="Environment Management" time="0.000072" file="test/config.test.ts" line="47" assertions="1" />
30
+ </testsuite>
31
+ </testsuite>
32
+ <testsuite name="test/logger.test.ts" file="test/logger.test.ts" tests="1" assertions="5" failures="0" skipped="0" time="0.049246" hostname="Bens-Mac.local">
33
+ <testsuite name="Logging Utilities" file="test/logger.test.ts" line="8" tests="1" assertions="5" failures="0" skipped="0" time="0.001" hostname="Bens-Mac.local">
34
+ <testcase name="To Not Throw Errors" classname="Logging Utilities" time="0.001158" file="test/logger.test.ts" line="15" assertions="5" />
35
+ </testsuite>
36
+ </testsuite>
37
+ </testsuites>
@@ -0,0 +1,139 @@
1
+ TN:
2
+ SF:lib/config.ts
3
+ FNF:12
4
+ FNH:12
5
+ DA:1,46
6
+ DA:2,50
7
+ DA:3,48
8
+ DA:4,52
9
+ DA:5,48
10
+ DA:8,62
11
+ DA:10,86
12
+ DA:12,133
13
+ DA:13,108
14
+ DA:14,114
15
+ DA:39,1
16
+ DA:41,27
17
+ DA:42,81
18
+ DA:43,10
19
+ DA:44,94
20
+ DA:45,22
21
+ DA:46,9
22
+ DA:48,154
23
+ DA:50,39
24
+ DA:52,103
25
+ DA:54,124
26
+ DA:55,118
27
+ DA:59,20
28
+ DA:60,12
29
+ DA:61,42
30
+ DA:62,52
31
+ DA:63,56
32
+ DA:64,102
33
+ DA:65,90
34
+ DA:66,26
35
+ DA:67,26
36
+ DA:68,12
37
+ DA:70,33
38
+ DA:73,22
39
+ DA:74,160
40
+ DA:76,99
41
+ DA:79,28
42
+ DA:80,70
43
+ DA:81,61
44
+ DA:82,9
45
+ DA:84,123
46
+ DA:85,136
47
+ DA:86,9
48
+ DA:88,32
49
+ DA:91,43
50
+ DA:92,123
51
+ DA:93,122
52
+ DA:94,9
53
+ DA:96,43
54
+ DA:99,38
55
+ DA:100,72
56
+ DA:102,127
57
+ DA:103,104
58
+ DA:104,72
59
+ DA:105,9
60
+ DA:107,28
61
+ DA:108,76
62
+ DA:109,30
63
+ DA:110,8
64
+ DA:112,2
65
+ DA:114,62
66
+ DA:115,33
67
+ DA:116,91
68
+ DA:117,42
69
+ DA:118,42
70
+ DA:119,36
71
+ DA:121,60
72
+ DA:122,32
73
+ DA:123,5
74
+ DA:124,9
75
+ DA:127,20
76
+ DA:128,50
77
+ DA:129,109
78
+ DA:130,86
79
+ DA:131,8
80
+ DA:133,2
81
+ LF:76
82
+ LH:76
83
+ end_of_record
84
+ TN:
85
+ SF:lib/error.ts
86
+ FNF:1
87
+ FNH:1
88
+ DA:1,42
89
+ DA:2,15
90
+ DA:3,19
91
+ DA:4,31
92
+ LF:4
93
+ LH:4
94
+ end_of_record
95
+ TN:
96
+ SF:lib/logger.ts
97
+ FNF:6
98
+ FNH:6
99
+ DA:1,47
100
+ DA:14,1
101
+ DA:16,177
102
+ DA:17,61
103
+ DA:20,43
104
+ DA:21,69
105
+ DA:22,32
106
+ DA:24,41
107
+ DA:25,68
108
+ DA:26,32
109
+ DA:28,41
110
+ DA:29,68
111
+ DA:30,32
112
+ DA:32,43
113
+ DA:33,69
114
+ DA:34,32
115
+ DA:36,43
116
+ DA:37,69
117
+ DA:38,30
118
+ DA:40,2
119
+ LF:20
120
+ LH:20
121
+ end_of_record
122
+ TN:
123
+ SF:test/util.ts
124
+ FNF:2
125
+ FNH:2
126
+ DA:1,21
127
+ DA:2,21
128
+ DA:3,23
129
+ DA:4,24
130
+ DA:7,30
131
+ DA:8,47
132
+ DA:9,22
133
+ DA:10,24
134
+ DA:11,17
135
+ DA:12,2
136
+ DA:13,4
137
+ LF:11
138
+ LH:11
139
+ end_of_record
package/lib/config.ts ADDED
@@ -0,0 +1,133 @@
1
+ import {
2
+ existsSync as exists,
3
+ readFileSync as read,
4
+ writeFileSync as write,
5
+ appendFileSync as append,
6
+ } from 'fs';
7
+
8
+ import { parse } from 'dotenv';
9
+
10
+ import { NotFoundError } from '#lib/error';
11
+
12
+ export enum VariableType {
13
+ Public,
14
+ Private,
15
+ }
16
+
17
+ export interface VariableConfiguration {
18
+ name: string;
19
+ type: VariableType;
20
+ }
21
+
22
+ export interface EnvironmentConfiguration {
23
+ name: string;
24
+ prefix: string;
25
+ file: string;
26
+ isActive: boolean;
27
+ }
28
+
29
+ export interface GeneralConfiguration {
30
+ version: number;
31
+ environments: EnvironmentConfiguration[];
32
+ variables: VariableConfiguration[];
33
+ }
34
+
35
+ export class Configuration {
36
+ public readonly vars: Map<string, VariableConfiguration> = new Map();
37
+ public readonly envs: Map<string, EnvironmentConfiguration> = new Map();
38
+ public readonly version: number = 1;
39
+ private readonly configFilePath: string = 'env.config.yaml';
40
+
41
+ constructor() {
42
+ if (!exists(this.configFilePath)) {
43
+ this
44
+ .importFromEnv(exists('.env') ? read('.env', "utf-8") : '')
45
+ .save();
46
+ }
47
+
48
+ const configContent = Bun.YAML.parse(read(this.configFilePath, "utf-8")) as GeneralConfiguration;
49
+
50
+ const setWrapper = <
51
+ K extends EnvironmentConfiguration | VariableConfiguration
52
+ >(map: Map<string, K>): ((item: K) => void) => (item: K) => void map.set(item.name, item);
53
+
54
+ configContent.environments.forEach(setWrapper(this.envs))
55
+ configContent.variables.forEach(setWrapper(this.vars))
56
+ }
57
+
58
+ public save() {
59
+ write(
60
+ this.configFilePath,
61
+ Bun.YAML.stringify({
62
+ "$schema": "https://benshawmean.com/api/schema/envedit",
63
+ version: this.version,
64
+ environments: Array.from(this.envs.values()),
65
+ variables: Array.from(this.vars.values()),
66
+ }, null, 2),
67
+ { mode: 0o600 },
68
+ );
69
+
70
+ return this;
71
+ }
72
+
73
+ public get active() {
74
+ const activeEnv = Array.from(this.envs.values()).find(env => env.isActive);
75
+
76
+ return activeEnv ? activeEnv.name : undefined;
77
+ }
78
+
79
+ public set active(env: string | undefined) {
80
+ if (env && !this.envs.has(env)) {
81
+ throw new NotFoundError(`Environment not found: ${env}`)
82
+ }
83
+
84
+ for (const [name, environment] of this.envs.entries()) {
85
+ this.envs.set(name, { ...environment, isActive: name === env });
86
+ }
87
+
88
+ this.save();
89
+ }
90
+
91
+ public importFromEnv(content: string): Configuration {
92
+ for (const [key, _] of Object.entries(parse(content))) {
93
+ this.vars.set(key, { name: key, type: VariableType.Private });
94
+ }
95
+
96
+ return this;
97
+ }
98
+
99
+ public static getTypeDetails(type: VariableType) {
100
+ const VariableTypeMap = new Map<number, keyof typeof VariableType>();
101
+
102
+ for (const [key, value] of Object.entries(VariableType)) {
103
+ if (typeof value !== "number") continue;
104
+ VariableTypeMap.set(value, key as keyof typeof VariableType);
105
+ }
106
+
107
+ return {
108
+ name: VariableTypeMap.get(type)!,
109
+ value: type
110
+ };
111
+ }
112
+ }
113
+
114
+ export class EnvironmentFile {
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
+ }
124
+ }
125
+ }
126
+
127
+ public save() {
128
+ write(this.path, '')
129
+ for (const [key, value] of this.vars.entries()) {
130
+ append(this.path, `${key}='${value}'\n`);
131
+ }
132
+ }
133
+ }
package/lib/error.ts ADDED
@@ -0,0 +1,6 @@
1
+ export class NotFoundError extends Error {
2
+ constructor(message?: string) {
3
+ super(message);
4
+ this.name = 'NotFoundError';
5
+ }
6
+ };
package/lib/logger.ts ADDED
@@ -0,0 +1,40 @@
1
+ import pino from 'pino';
2
+ import type { LevelWithSilentOrString, Logger as PinoLogger } from 'pino';
3
+
4
+ export class Logger {
5
+ private readonly logger: PinoLogger<never, boolean> = pino({
6
+ transport: {
7
+ target: 'pino-pretty',
8
+ options: {
9
+ colorize: true,
10
+ translateTime: 'SYS:standard',
11
+ ignore: 'pid,hostname',
12
+ },
13
+ },
14
+ });
15
+
16
+ constructor(public readonly level: LevelWithSilentOrString, private testMode: boolean = false) {
17
+ this.logger.level = level;
18
+ }
19
+
20
+ public readonly debug = (msg: string) => {
21
+ this.testMode ? '' : this.logger.debug(msg);
22
+ return this;
23
+ }
24
+ public readonly info = (msg: string) => {
25
+ this.testMode ? '' : this.logger.info(msg);
26
+ return this;
27
+ }
28
+ public readonly warn = (msg: string) => {
29
+ this.testMode ? '' : this.logger.warn(msg);
30
+ return this;
31
+ }
32
+ public readonly error = (msg: string) => {
33
+ this.testMode ? '' : this.logger.error(msg);
34
+ return this;
35
+ }
36
+ public readonly fatal = (msg: string) => {
37
+ this.testMode ? '' : this.logger.fatal(msg);
38
+ return this;
39
+ }
40
+ }
package/package.json CHANGED
@@ -1,6 +1,29 @@
1
1
  {
2
2
  "name": "@ben-studios/envedit",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "type": "module",
4
+ "version": "1.0.0",
5
+ "license": "GPL-3.0-only",
6
+ "bin": {
7
+ "envedit": "cli/index.ts"
8
+ },
9
+ "repository": {
10
+ "url": "https://gitlab.com/ben-studios/envedit.git"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "devDependencies": {
16
+ "@types/bun": "^1.3.14",
17
+ "@types/yargs": "^17.0.35"
18
+ },
19
+ "peerDependencies": {
20
+ "typescript": "^5"
21
+ },
22
+ "dependencies": {
23
+ "@inquirer/prompts": "^8.5.2",
24
+ "dotenv": "^17.4.2",
25
+ "pino": "^10.3.1",
26
+ "pino-pretty": "^13.1.3",
27
+ "yargs": "^18.1.0"
28
+ }
6
29
  }
package/tsconfig.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "compilerOptions": {
3
+ // Environment setup & latest features
4
+ "lib": ["ESNext"],
5
+ "target": "ESNext",
6
+ "module": "Preserve",
7
+ "moduleDetection": "force",
8
+ "jsx": "react-jsx",
9
+ "allowJs": true,
10
+ "types": ["bun", "./@types/custom.d.ts"],
11
+
12
+ // Bundler mode
13
+ "moduleResolution": "bundler",
14
+ "allowImportingTsExtensions": true,
15
+ "verbatimModuleSyntax": true,
16
+ "noEmit": true,
17
+
18
+ // Best practices
19
+ "strict": true,
20
+ "skipLibCheck": true,
21
+ "noFallthroughCasesInSwitch": true,
22
+ "noUncheckedIndexedAccess": true,
23
+ "noImplicitOverride": true,
24
+
25
+ // Some stricter flags (disabled by default)
26
+ "noUnusedLocals": false,
27
+ "noUnusedParameters": false,
28
+ "noPropertyAccessFromIndexSignature": false,
29
+
30
+ "paths": {
31
+ "@/*": ["./*"],
32
+ "#lib/*": ["./lib/*"]
33
+ }
34
+ }
35
+ }