zodify-env 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.
package/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # zodify-env 🚀
2
+
3
+ [![npm version](https://img.shields.io/npm/v/zodify-env.svg)](https://www.npmjs.com/package/zodify-env)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ A blazing-fast, **zero-dependency** CLI tool that automatically generates strongly-typed [Zod](https://zod.dev/) schemas from your `.env.example` files.
7
+
8
+ Stop manually writing validation schemas for your environment variables. `zodify-env` reads your template, infers the types (strings, numbers, booleans), and writes a ready-to-use TypeScript schema file so you get instant auto-complete and runtime validation.
9
+
10
+ ---
11
+
12
+ ## 🚀 Quick Start (No Install Required)
13
+
14
+ You don't even need to install it to use it! Just run it via `npx` in the root of your project:
15
+
16
+ ```bash
17
+ npx zodify-env
18
+ ```
19
+
20
+ By default, this looks for a `.env.example` file in your current directory and generates an `env.schema.ts` file.
21
+
22
+ ---
23
+
24
+ ## ⚙️ Arguments & Options
25
+
26
+ You can customize where `zodify-env` looks for your environment variables and where it saves the generated schema using these arguments:
27
+
28
+ | Argument | Short Flag | Default Value | Description |
29
+ | :--- | :---: | :--- | :--- |
30
+ | `--input` | `-i` | `.env.example` | The path to your environment variable template or source file. |
31
+ | `--output` | `-o` | `env.schema.ts` | The destination path and filename for the generated TypeScript file. |
32
+
33
+ ### 💡 Usage Examples
34
+
35
+ **1. Basic Run (Uses Defaults)**
36
+ Reads from `.env.example` and outputs to `env.schema.ts` in the current folder.
37
+ ```bash
38
+ npx zodify-env
39
+ ```
40
+
41
+ **2. Custom Input File**
42
+ If your team uses a different naming convention, like `.env.local` or `.env.template`:
43
+ ```bash
44
+ npx zodify-env --input .env.local
45
+ ```
46
+
47
+ **3. Custom Output Location**
48
+ If you want to save the generated schema directly into your source code folder:
49
+ ```bash
50
+ npx zodify-env --output src/config/env.ts
51
+ ```
52
+
53
+ **4. Using Short Flags for Both**
54
+ You can combine the short flags (`-i` and `-o`) for a quicker command:
55
+ ```bash
56
+ npx zodify-env -i .env.template -o src/schemas/env.ts
57
+ ```
58
+
59
+ ---
60
+
61
+ ## 📦 Installation & Team Workflow
62
+
63
+ For teams, it is highly recommended to install `zodify-env` as a development dependency so everyone stays in sync.
64
+
65
+ ### 1. Install
66
+
67
+ ```bash
68
+ npm install -D zodify-env
69
+ ```
70
+
71
+ ### 2. Add a Script
72
+
73
+ Add a sync script to your `package.json`. You can pass your custom arguments right here:
74
+
75
+ ```json
76
+ "scripts": {
77
+ "env:sync": "zodify-env --input .env.example --output src/config/env.schema.ts"
78
+ }
79
+ ```
80
+
81
+ ### 3. Run it
82
+
83
+ Whenever you add a new variable to your `.env.example`, simply run:
84
+
85
+ ```bash
86
+ npm run env:sync
87
+ ```
88
+
89
+ ---
90
+
91
+ ## 📖 How it Works
92
+
93
+ Given an input file like this (`.env.example`):
94
+
95
+ ```env
96
+ # Server Configuration
97
+ PORT=3000
98
+ DEBUG=true
99
+ API_KEY=
100
+ ```
101
+
102
+ `zodify-env` will generate the following TypeScript file:
103
+
104
+ ```typescript
105
+ import { z } from 'zod';
106
+
107
+ export const envSchema = z.object({
108
+ PORT: z.coerce.number(),
109
+ DEBUG: z.coerce.boolean(),
110
+ API_KEY: z.string(),
111
+ });
112
+
113
+ export type Env = z.infer<typeof envSchema>;
114
+ ```
115
+
116
+ ### Implementing in your app
117
+
118
+ Import the generated schema into your application entry point (e.g., `server.ts` or `index.ts`) to validate your environment variables at startup:
119
+
120
+ ```typescript
121
+ import { envSchema } from './env.schema';
122
+
123
+ const parsedEnv = envSchema.safeParse(process.env);
124
+
125
+ if (!parsedEnv.success) {
126
+ console.error("❌ Invalid environment variables:", parsedEnv.error.format());
127
+ process.exit(1);
128
+ }
129
+
130
+ // config is now fully typed!
131
+ const config = parsedEnv.data;
132
+ console.log(`Server starting on port ${config.PORT}`);
133
+ ```
134
+
135
+ ---
136
+
137
+ ## 🤝 Contributing
138
+
139
+ Contributions, issues, and feature requests are welcome!
140
+
141
+ 1. Fork the project.
142
+ 2. Clone your fork: `git clone https://github.com/your-username/zodify-env.git`
143
+ 3. Install dependencies: `npm install`
144
+ 4. Make your changes in the `src` directory.
145
+ 5. Build the project to test your changes: `npm run build`
146
+ 6. Test your local build: `node dist/index.js`
147
+ 7. Create a Pull Request!
148
+
149
+ ## 📝 License
150
+
151
+ This project is [MIT](https://opensource.org/licenses/MIT) licensed.
package/dist/index.js ADDED
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import * as fs from "fs";
5
+ import * as path from "path";
6
+ import { parseArgs } from "util";
7
+ console.log("\u{1F680} Starting zodify-env...");
8
+ var { values } = parseArgs({
9
+ options: {
10
+ input: {
11
+ type: "string",
12
+ short: "i",
13
+ default: ".env.example"
14
+ },
15
+ output: {
16
+ type: "string",
17
+ short: "o",
18
+ default: "env.schema.ts"
19
+ }
20
+ }
21
+ });
22
+ var currentDir = process.cwd();
23
+ var envFilePath = path.resolve(currentDir, values.input);
24
+ var outputPath = path.resolve(currentDir, values.output);
25
+ if (!fs.existsSync(envFilePath)) {
26
+ console.error(`\u274C Error: Could not find the input file at ${envFilePath}`);
27
+ console.error(`\u{1F4A1} Tip: Make sure the file exists, or specify a different path using --input`);
28
+ process.exit(1);
29
+ }
30
+ var envFileContent = fs.readFileSync(envFilePath, "utf-8");
31
+ var lines = envFileContent.split("\n");
32
+ var zodSchemaString = `import { z } from 'zod';
33
+
34
+ export const envSchema = z.object({
35
+ `;
36
+ for (const line of lines) {
37
+ const trimmedLine = line.trim();
38
+ if (!trimmedLine || trimmedLine.startsWith("#")) continue;
39
+ const [key, ...valueParts] = trimmedLine.split("=");
40
+ const value = valueParts.join("=").trim();
41
+ const cleanKey = key.trim();
42
+ if (!cleanKey) continue;
43
+ let zodType = "z.string()";
44
+ if (value === "true" || value === "false") {
45
+ zodType = "z.coerce.boolean()";
46
+ } else if (!isNaN(Number(value)) && value !== "") {
47
+ zodType = "z.coerce.number()";
48
+ }
49
+ zodSchemaString += ` ${cleanKey}: ${zodType},
50
+ `;
51
+ }
52
+ zodSchemaString += `});
53
+
54
+ `;
55
+ zodSchemaString += `export type Env = z.infer<typeof envSchema>;
56
+ `;
57
+ fs.writeFileSync(outputPath, zodSchemaString);
58
+ console.log(`\u2705 Success! Zod schema generated at ${outputPath}`);
package/env.schema.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { z } from 'zod';
2
+
3
+ export const envSchema = z.object({
4
+ PORT: z.coerce.number(),
5
+ DEBUG: z.coerce.boolean(),
6
+ API_KEY: z.string(),
7
+ });
8
+
9
+ export type Env = z.infer<typeof envSchema>;
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "zodify-env",
3
+ "version": "1.0.0",
4
+ "description": "Automatically generate Zod schemas from your .env files",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "zodify-env": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsup src/index.ts --format esm --clean",
12
+ "dev": "tsup src/index.ts --format esm --watch",
13
+ "start": "node dist/index.js"
14
+ },
15
+ "keywords": [
16
+ "zod",
17
+ "env",
18
+ "cli",
19
+ "typescript",
20
+ "generator"
21
+ ],
22
+ "author": "Your Name",
23
+ "license": "MIT",
24
+ "devDependencies": {
25
+ "@types/node": "^20.19.33",
26
+ "tsup": "^8.5.1",
27
+ "typescript": "^5.9.3"
28
+ }
29
+ }
package/src/index.ts ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ import { parseArgs } from 'util';
6
+
7
+ console.log('🚀 Starting zodify-env...');
8
+
9
+ // 1. Parse command-line arguments natively
10
+ const { values } = parseArgs({
11
+ options: {
12
+ input: {
13
+ type: 'string',
14
+ short: 'i',
15
+ default: '.env.example',
16
+ },
17
+ output: {
18
+ type: 'string',
19
+ short: 'o',
20
+ default: 'env.schema.ts',
21
+ },
22
+ },
23
+ });
24
+
25
+ // 2. Resolve paths based on the directory where the user runs the command (process.cwd())
26
+ const currentDir = process.cwd();
27
+ const envFilePath = path.resolve(currentDir, values.input as string);
28
+ const outputPath = path.resolve(currentDir, values.output as string);
29
+
30
+ // 3. Check if the input file exists
31
+ if (!fs.existsSync(envFilePath)) {
32
+ console.error(`❌ Error: Could not find the input file at ${envFilePath}`);
33
+ console.error(`💡 Tip: Make sure the file exists, or specify a different path using --input`);
34
+ process.exit(1);
35
+ }
36
+
37
+ // 4. Read the file
38
+ const envFileContent = fs.readFileSync(envFilePath, 'utf-8');
39
+ const lines = envFileContent.split('\n');
40
+
41
+ let zodSchemaString = `import { z } from 'zod';\n\nexport const envSchema = z.object({\n`;
42
+
43
+ // 5. Parse the variables and infer types
44
+ for (const line of lines) {
45
+ const trimmedLine = line.trim();
46
+
47
+ if (!trimmedLine || trimmedLine.startsWith('#')) continue;
48
+
49
+ const [key, ...valueParts] = trimmedLine.split('=');
50
+ const value = valueParts.join('=').trim();
51
+ const cleanKey = key.trim();
52
+
53
+ if (!cleanKey) continue;
54
+
55
+ let zodType = 'z.string()';
56
+
57
+ if (value === 'true' || value === 'false') {
58
+ zodType = 'z.coerce.boolean()';
59
+ } else if (!isNaN(Number(value)) && value !== '') {
60
+ zodType = 'z.coerce.number()';
61
+ }
62
+
63
+ zodSchemaString += ` ${cleanKey}: ${zodType},\n`;
64
+ }
65
+
66
+ zodSchemaString += `});\n\n`;
67
+ zodSchemaString += `export type Env = z.infer<typeof envSchema>;\n`;
68
+
69
+ // 6. Write the schema to the target output path
70
+ fs.writeFileSync(outputPath, zodSchemaString);
71
+ console.log(`✅ Success! Zod schema generated at ${outputPath}`);