Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Adding ability to convert field name from camelCase to CONSTANT_CASE if varName is not specified for @EnvField #42

Merged
merged 17 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions examples/envied_example/.env
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
KEY1=foo
KEY2=bar
key3=baz
key4=123
key5=false
key6=http://foo.bar/baz
key7=2023-11-06T23:09:51.123Z
KEY3=baz
KEY4=123
KEY5=false
KEY6=http://foo.bar/baz
KEY7=2023-11-06T23:09:51.123Z
TEST_KEY=TEST_VALUE
11 changes: 6 additions & 5 deletions examples/envied_example/.env_debug
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
KEY1=debug_foo
KEY2=debug_bar
key3=debug_baz
key4=456
key5=true
key6=http://zomg.test/bbq
key7=2022-09-01T12:01:12.001Z
KEY3=debug_baz
KEY4=456
KEY5=true
KEY6=http://zomg.test/bbq
KEY7=2022-09-01T12:01:12.001Z
TEST_KEY=DEBUG_VALUE
2 changes: 1 addition & 1 deletion examples/envied_example/lib/debug_env.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'app_env_fields.dart';

part 'debug_env.g.dart';

@Envied(name: 'Env', path: '.env_debug')
@Envied(name: 'Env', path: '.env_debug', useConstantCase: true)
final class DebugEnv implements AppEnv, AppEnvFields {
DebugEnv();

Expand Down
6 changes: 3 additions & 3 deletions examples/envied_example/lib/env.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:envied/envied.dart';

part 'env.g.dart';

@Envied(path: '.env')
@Envied(path: '.env', useConstantCase: true)
final class Env {
@EnviedField(varName: 'KEY1')
static const String key1 = _Env.key1;
Expand All @@ -15,10 +15,10 @@ final class Env {
static const int key4 = _Env.key4;
@EnviedField()
static const bool key5 = _Env.key5;

@EnviedField()
static final Uri key6 = _Env.key6;

@EnviedField()
static final DateTime key7 = _Env.key7;
@EnviedField()
static const String testKey = _Env.testKey;
}
2 changes: 2 additions & 0 deletions examples/envied_example/lib/env.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/envied_example/lib/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ void run() {
print(Env.key3);
print(Env.key4);
print(Env.key5);
print(Env.testKey);
}
2 changes: 1 addition & 1 deletion examples/envied_example/lib/nullable_env.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:envied/envied.dart';

part 'nullable_env.g.dart';

@Envied(path: '.env', allowOptionalFields: false)
@Envied(path: '.env', allowOptionalFields: false, useConstantCase: true)
final class NullableEnv {
@EnviedField(optional: true)
static const String? key6 = _NullableEnv.key6;
Expand Down
12 changes: 7 additions & 5 deletions examples/envied_example/lib/release_env.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ final class ReleaseEnv implements AppEnv, AppEnvFields {
@EnviedField(varName: 'KEY2')
final String key2 = _Env.key2;
@override
@EnviedField()
@EnviedField(varName: 'KEY3')
final String key3 = _Env.key3;
@override
@EnviedField()
@EnviedField(varName: 'KEY4')
final int key4 = _Env.key4;
@override
@EnviedField()
@EnviedField(varName: 'KEY5')
final bool key5 = _Env.key5;
@override
@EnviedField()
@EnviedField(varName: 'KEY6')
final Uri key6 = _Env.key6;
@override
@EnviedField()
@EnviedField(varName: 'KEY7')
final DateTime key7 = _Env.key7;
@EnviedField(varName: 'TEST_KEY')
static const String testKey = _Env.testKey;
}
2 changes: 2 additions & 0 deletions examples/envied_example/lib/release_env.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions examples/envied_example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.3"
recase:
dependency: transitive
description:
name: recase
sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213
url: "https://pub.dev"
source: hosted
version: "4.1.0"
shelf:
dependency: transitive
description:
Expand Down
45 changes: 45 additions & 0 deletions packages/envied/lib/src/envied_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,39 @@ final class Envied {
/// not set.
final bool allowOptionalFields;

/// Whether to convert field names from camelCase to CONSTANT_CASE when
/// the @EnvField annotation is not explicitly assigned a varName.
///
/// By default, this is set to `false`, which means field names will
/// retain their original camelCase format unless varName is specified. f
///
/// When set to `true`, field names will be automatically transformed into
/// CONSTANT_CASE when no specific varName is provided in or no specifics
/// useConstantCase value set to the @EnvField annotation. This follows
/// the Effective Dart naming conventions where variables and field names
/// start with lowercase letters and use uppercase for the first letter of
/// each subsequent word.
///
/// Example:
/// ```dart
/// @Envied(useUpperSnakeCase: true)
/// class MyEnvironment {
/// @EnvField()
/// String apiKey; // Transformed to 'API_KEY'
///
/// @EnvField(varName: 'MY_TOKEN')
/// String token; // Specified varName retains original format
/// }
/// ```
final bool useConstantCase;

const Envied({
String? path,
bool? requireEnvFile,
this.name,
this.obfuscate = false,
this.allowOptionalFields = false,
this.useConstantCase = false,
}) : path = path ?? '.env',
requireEnvFile = requireEnvFile ?? false;
}
Expand Down Expand Up @@ -81,10 +108,28 @@ final class EnviedField {
/// not set.
final bool? optional;

/// Whether to convert the field name to CONSTANT_CASE.
///
/// By default, this is set to `false`, which means that the field name will
/// retain its original format unless [varName] is specified.
///
/// When set to `true`, the field name will be automatically transformed
/// into CONSTANT_CASE. This follows the Dart convention for constant
/// names where all letters are capitalized, and words are separated by
/// underscores.
///
/// Example:
/// ```dart
/// @EnvField(useConstantCase: true)
/// String apiKey; // Transformed to 'API_KEY'
/// ```
final bool? useConstantCase;

const EnviedField({
this.varName,
this.obfuscate,
this.defaultValue,
this.optional,
this.useConstantCase,
});
}
20 changes: 19 additions & 1 deletion packages/envied/test/envy_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@ void main() {
expect(envied.path, '.env');
expect(envied.requireEnvFile, false);
expect(envied.obfuscate, false);
expect(envied.useConstantCase, isFalse);
});

test('Specified path', () {
final envied = Envied(path: '.env.test');
expect(envied.path, '.env.test');
});

test('Specified useConstantCase', () {
final envied = Envied(useConstantCase: true);
expect(envied.useConstantCase, isTrue);
});

test('Specified requireEnvFile', () {
final envied = Envied(requireEnvFile: true);
expect(envied.requireEnvFile, true);
Expand All @@ -36,6 +42,8 @@ void main() {
final enviedField = EnviedField();
expect(enviedField.varName, null);
expect(enviedField.obfuscate, null);
expect(enviedField.optional, null);
expect(enviedField.useConstantCase, null);
});

test('Specified path', () {
Expand All @@ -45,7 +53,17 @@ void main() {

test('Specified obfuscate', () {
final enviedField = EnviedField(obfuscate: true);
expect(enviedField.obfuscate, true);
expect(enviedField.obfuscate, isTrue);
});

test('Specified optional', () {
final enviedField = EnviedField(optional: true);
expect(enviedField.optional, isTrue);
});

test('Specified useConstantCase', () {
final enviedField = EnviedField(useConstantCase: true);
expect(enviedField.useConstantCase, isTrue);
});
});

Expand Down
36 changes: 23 additions & 13 deletions packages/envied_generator/lib/src/generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:envied/envied.dart';
import 'package:envied_generator/src/generate_field.dart';
import 'package:envied_generator/src/generate_field_encrypted.dart';
import 'package:envied_generator/src/load_envs.dart';
import 'package:recase/recase.dart';
import 'package:source_gen/source_gen.dart';

/// Generate code for classes annotated with the `@Envied()`.
Expand Down Expand Up @@ -42,19 +43,19 @@ final class EnviedGenerator extends GeneratorForAnnotation<Envied> {
obfuscate: annotation.read('obfuscate').literalValue as bool,
allowOptionalFields:
annotation.read('allowOptionalFields').literalValue as bool? ?? false,
useConstantCase:
annotation.read('useConstantCase').literalValue as bool? ?? false,
);

final Map<String, String> envs = await loadEnvs(
config.path,
(String error) {
if (config.requireEnvFile) {
throw InvalidGenerationSourceError(
error,
element: enviedEl,
);
}
},
);
final Map<String, String> envs =
await loadEnvs(config.path, (String error) {
if (config.requireEnvFile) {
throw InvalidGenerationSourceError(
error,
element: enviedEl,
);
}
});

final DartEmitter emitter = DartEmitter(useNullSafetySyntax: true);

Expand Down Expand Up @@ -91,8 +92,17 @@ final class EnviedGenerator extends GeneratorForAnnotation<Envied> {

final ConstantReader reader = ConstantReader(dartObject);

final String varName =
reader.read('varName').literalValue as String? ?? field.name;
late String varName;

final bool useConstantCase =
reader.read('useConstantCase').literalValue as bool? ??
config.useConstantCase;

if (reader.read('varName').literalValue == null) {
varName = useConstantCase ? field.name.constantCase : field.name;
} else {
varName = reader.read('varName').literalValue as String;
}

final Object? defaultValue = reader.read('defaultValue').literalValue;

Expand Down
1 change: 1 addition & 0 deletions packages/envied_generator/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies:
dart_style: ^2.3.2
source_gen: ^1.4.0
analyzer: ">=5.1.0 <7.0.0"
recase: ^4.1.0

dev_dependencies:
lints: ">=2.1.1 <4.0.0"
Expand Down
5 changes: 5 additions & 0 deletions packages/envied_generator/test/.env.example
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
test_string=test_string
testString=testString
TEST_STRING=TEST_STRING
testInt=123
TEST_INT=123
testDouble=1.23
testNum=1.23
TEST_DOUBLE=1.23
TEST_BOOL=true
testBool=true
testDynamic=123abc
TEST_DYNAMIC=123_ABC
testUrl=https://foo.bar/baz
emptyTestUrl=
testDateTime=2023-11-06T22:32:55.287Z
Expand Down
37 changes: 37 additions & 0 deletions packages/envied_generator/test/src/generator_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -863,3 +863,40 @@ abstract class Env33b {
@EnviedField(obfuscate: true)
static const num? testNum = 1.23;
}

@ShouldGenerate('''
// coverage:ignore-file
// ignore_for_file: type=lint
final class _Env34 {
static const String? testDefaultParam = 'test_';

static const String testString = 'TEST_STRING';

static const int testInt = 123;

static const double testDouble = 1.23;

static const bool testBool = true;

static const String testDynamic = '123_ABC';
}
''')
@Envied(
path: 'test/.env.example',
useConstantCase: true,
allowOptionalFields: true,
)
abstract class Env34 {
@EnviedField(defaultValue: 'test_')
static const String? testDefaultParam = null;
@EnviedField()
static const String testString = 'TEST_STRING';
@EnviedField()
static const int testInt = 123;
@EnviedField()
static const double testDouble = 1.23;
@EnviedField()
static const bool testBool = true;
@EnviedField()
static const String testDynamic = '123_ABC';
}