diff --git a/README.md b/README.md
index 100b3a5..0e15fc6 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,20 @@
# EnvTypesWebpack
+
+
+
+
+
+
-[](https://www.npmjs.com/package/EnvTypesWebpack)
+[](https://www.npmjs.com/package/@xxanderwp/env-types-webpack-plugin)
+
[](https://github.com/XXanderWP/EnvTypesWebpack/actions)
[](https://github.com/XXanderWP/EnvTypesWebpack/blob/main/LICENSE)
+
Webpack plugin that automatically generates TypeScript definitions for environment variables from `.env` files.
## Features
@@ -132,6 +140,7 @@ const apiKey = process.env.API_KEY; // Type: string | undefined
| `addExportEnds` | `boolean` | `false` | Add `export {};` at end |
| `namespace` | `string` | `NodeJS` | Optional namespace for the generated types |
| `interface` | `string` | `ProcessEnv` | Optional interface name for the generated types |
+| `useValuesAsTypes` | `boolean` | `false` | Use values as types instead of string literals |
#### Shorthand
diff --git a/icon.png b/icon.png
new file mode 100644
index 0000000..70adab8
Binary files /dev/null and b/icon.png differ
diff --git a/package-lock.json b/package-lock.json
index c4223de..b067a13 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@xxanderwp/env-types-webpack-plugin",
- "version": "1.3.1",
+ "version": "1.4.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@xxanderwp/env-types-webpack-plugin",
- "version": "1.3.1",
+ "version": "1.4.0",
"license": "MIT",
"devDependencies": {
"@types/eslint__eslintrc": "^2.1.2",
diff --git a/package.json b/package.json
index 11e0fa0..c7f6ad1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@xxanderwp/env-types-webpack-plugin",
- "version": "1.3.1",
+ "version": "1.4.0",
"description": "Webpack plugin that automatically generates TypeScript definitions for environment variables from .env files",
"main": "dist/EnvTypesPlugin.js",
"types": "dist/EnvTypesPlugin.d.ts",
diff --git a/src/EnvTypesGenerator.ts b/src/EnvTypesGenerator.ts
index 7a47266..b0d0045 100644
--- a/src/EnvTypesGenerator.ts
+++ b/src/EnvTypesGenerator.ts
@@ -10,6 +10,8 @@ export interface EnvEntry {
key: string;
/** JSDoc comment describing the variable */
comment: string | null;
+ /** Value for useValuesAsTypes mode */
+ value: string;
}
/**
@@ -30,6 +32,7 @@ export class EnvTypesGenerator {
private readonly addExportEnds: boolean;
private readonly interface: string;
private readonly namespace: string;
+ private readonly useValuesAsTypes: boolean;
constructor(options: EnvTypesGeneratorOptions) {
this.envFiles = options.envFiles || ['.env', '.env.example'];
@@ -39,6 +42,7 @@ export class EnvTypesGenerator {
this.addExportEnds = options.addExportEnds ?? false;
this.interface = options.interface || 'ProcessEnv';
this.namespace = options.namespace || 'NodeJS';
+ this.useValuesAsTypes = options.useValuesAsTypes ?? false;
}
/**
@@ -103,6 +107,7 @@ export class EnvTypesGenerator {
entries.push({
key,
comment: comments.length ? comments.join('\n') : null,
+ value: valuePart.split('#')[0].trim(),
});
commentBuffer = [];
@@ -128,13 +133,23 @@ export class EnvTypesGenerator {
*/
private generateInterfaceBody(entries: EnvEntry[]): string {
return entries
- .map(({ key, comment }) => {
+ .map(({ key, comment, value }) => {
+ // Определяем тип или конкретное значение
+ let typeOrValue: string;
+ if (this.useValuesAsTypes) {
+ typeOrValue = `"${value.replace(/"/g, '\\"')}"`;
+ } else {
+ typeOrValue = 'string';
+ }
+
+ const optional = this.disablePartialType ? '' : '?';
+
if (!comment) {
- return ` ${key}${this.disablePartialType ? '' : '?'}: string;`;
+ return ` ${key}${optional}: ${typeOrValue};`;
}
const jsdoc = this.generateJSDoc(comment);
- return `${jsdoc}\n ${key}${this.disablePartialType ? '' : '?'}: string;`;
+ return `${jsdoc}\n ${key}${optional}: ${typeOrValue};`;
})
.join('\n');
}
@@ -240,6 +255,7 @@ if (require.main === module) {
const addExportEnds = process.env.ADD_END === '1';
const interfaceName = process.env.INTERFACE || 'ProcessEnv';
const namespace = process.env.NAMESPACE || 'NodeJS';
+ const useValuesAsTypes = process.env.USE_VALUES_AS_TYPES === '1';
if (!outputPath) {
console.error(
@@ -256,6 +272,7 @@ if (require.main === module) {
addExportEnds,
interface: interfaceName,
namespace,
+ useValuesAsTypes,
});
generator.generate();
}
diff --git a/src/EnvTypesPlugin.ts b/src/EnvTypesPlugin.ts
index 5cba4f7..f17b7b0 100644
--- a/src/EnvTypesPlugin.ts
+++ b/src/EnvTypesPlugin.ts
@@ -58,6 +58,7 @@ export class EnvTypesPlugin {
addExportEnds: options.addExportEnds || false,
interface: options.interface || 'ProcessEnv',
namespace: options.namespace || 'NodeJS',
+ useValuesAsTypes: options.useValuesAsTypes || false,
};
this.outputAbsolutePath = path.resolve(this.options.outputPath);
@@ -101,6 +102,7 @@ export class EnvTypesPlugin {
ADD_END: this.options.addExportEnds ? '1' : '0',
INTERFACE: this.options.interface,
NAMESPACE: this.options.namespace,
+ USE_VALUES_AS_TYPES: this.options.useValuesAsTypes ? '1' : '0',
};
execSync(`node ${this.options.generatorScript}`, {
diff --git a/src/types/EnvTypesGenerator.d.ts b/src/types/EnvTypesGenerator.d.ts
index 8977313..a10bd53 100644
--- a/src/types/EnvTypesGenerator.d.ts
+++ b/src/types/EnvTypesGenerator.d.ts
@@ -36,4 +36,9 @@ export interface EnvTypesGeneratorOptions {
* @default "ProcessEnv"
*/
interface?: string;
+ /** Use values as types instead of string literals
+ * @default false
+ * If true, the generated types will use the actual values from the .env files as types instead of string literals. For example, if you have a variable `API_URL=http://localhost:3000`, the generated type will be `API_URL: "http://localhost:3000"` instead of `API_URL: string`.
+ */
+ useValuesAsTypes?: boolean;
}
diff --git a/tests/EnvTypesGenerator.test.ts b/tests/EnvTypesGenerator.test.ts
index f87c81a..f1cf324 100644
--- a/tests/EnvTypesGenerator.test.ts
+++ b/tests/EnvTypesGenerator.test.ts
@@ -24,6 +24,7 @@ describe('EnvTypesGenerator', () => {
describe('constructor', () => {
it('should create instance with valid options', () => {
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: ['.env'],
outputPath: 'test.d.ts',
});
@@ -44,6 +45,7 @@ API_KEY=secret
fs.writeFileSync(envFile, envContent);
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: [envFile],
outputPath: outputFile,
});
@@ -75,6 +77,7 @@ DB_PORT=5432
fs.writeFileSync(envFile, envContent);
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: [envFile],
outputPath: outputFile,
});
@@ -97,6 +100,7 @@ DB_PORT=5432
fs.writeFileSync(envFile, envContent);
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: [envFile],
outputPath: outputFile,
});
@@ -117,6 +121,7 @@ DB_PORT=5432
fs.writeFileSync(envFile, envContent);
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: [envFile],
outputPath: outputFile,
});
@@ -142,6 +147,7 @@ DB_HOST=localhost
fs.writeFileSync(envFile, envContent);
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: [envFile],
outputPath: outputFile,
});
@@ -193,6 +199,7 @@ DB_HOST=localhost
fs.writeFileSync(envFile, 'DB_HOST=localhost');
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: [envFile],
outputPath: nestedOutput,
});
@@ -207,6 +214,7 @@ DB_HOST=localhost
it('should throw error if no env file found', () => {
// Arrange
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: ['.env.nonexistent'],
outputPath: outputFile,
});
@@ -224,6 +232,7 @@ DB_HOST=localhost
fs.writeFileSync(env2, 'PROD_VAR=prod');
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: [env1, env2],
outputPath: outputFile,
});
@@ -263,6 +272,30 @@ DB_HOST=localhost
expect(content).toContain('Line 3 of comment');
});
+ it('should handle useValuesAsTypes option', () => {
+ // Arrange
+ const envContent = `
+DB_HOST=localhost
+`.trim();
+
+ fs.writeFileSync(envFile, envContent);
+
+ const generator = new EnvTypesGenerator({
+ silent: true,
+ envFiles: [envFile],
+ outputPath: outputFile,
+ useValuesAsTypes: true,
+ });
+
+ // Act
+ generator.generate();
+
+ // Assert
+ const content = fs.readFileSync(outputFile, 'utf-8');
+ expect(content).toContain('DB_HOST');
+ expect(content).toContain('"localhost"');
+ });
+
it('should handle values with equals signs', () => {
// Arrange
const envContent = 'CONNECTION_STRING=host=localhost;port=5432';
@@ -270,6 +303,7 @@ DB_HOST=localhost
fs.writeFileSync(envFile, envContent);
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: [envFile],
outputPath: outputFile,
});
@@ -287,6 +321,7 @@ DB_HOST=localhost
fs.writeFileSync(envFile, 'DB_HOST=localhost');
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: [envFile],
outputPath: outputFile,
});
@@ -304,6 +339,7 @@ DB_HOST=localhost
fs.writeFileSync(envFile, 'DB_HOST=localhost');
const generator = new EnvTypesGenerator({
+ silent: true,
envFiles: [envFile],
outputPath: outputFile,
});