From ca04a3e7ac86a127a58b8c3a7be9b5b832961c39 Mon Sep 17 00:00:00 2001 From: Klemen Tusar Date: Mon, 11 Mar 2024 17:12:48 +0000 Subject: [PATCH] feat: add support for raw strings and no interpolation (#95) --- examples/envied_example/.env | 3 +- examples/envied_example/.env_debug | 3 +- .../envied_example/lib/app_env_fields.dart | 1 + .../envied_example/lib/constant_case_env.dart | 1 + examples/envied_example/lib/debug_env.dart | 10 + examples/envied_example/lib/debug_env.g.dart | 2 + examples/envied_example/lib/env.dart | 3 + examples/envied_example/lib/env.g.dart | 2 + examples/envied_example/lib/release_env.dart | 10 + .../envied_example/lib/release_env.g.dart | 2 + packages/envied/lib/src/envied_base.dart | 34 +++ .../envied_generator/lib/src/env_val.dart | 18 ++ .../lib/src/generate_field.dart | 6 +- .../envied_generator/lib/src/generator.dart | 35 ++- .../envied_generator/lib/src/load_envs.dart | 3 +- packages/envied_generator/lib/src/parser.dart | 81 ++++-- packages/envied_generator/pubspec.yaml | 1 + packages/envied_generator/test/.env.example | 5 + .../test/.env.example_with_path_override | 1 + .../test/src/generator_tests.dart | 261 +++++++++++------- .../generator_tests_with_path_override.dart | 10 +- 21 files changed, 349 insertions(+), 143 deletions(-) create mode 100644 packages/envied_generator/lib/src/env_val.dart diff --git a/examples/envied_example/.env b/examples/envied_example/.env index 8e4193c..b5a3c65 100644 --- a/examples/envied_example/.env +++ b/examples/envied_example/.env @@ -5,4 +5,5 @@ key4=123 key5=false key6=http://foo.bar/baz key7=2023-11-06T23:09:51.123Z -key8=lorem \ No newline at end of file +key8=lorem +key9=uneascaped$ \ No newline at end of file diff --git a/examples/envied_example/.env_debug b/examples/envied_example/.env_debug index 8693219..175face 100644 --- a/examples/envied_example/.env_debug +++ b/examples/envied_example/.env_debug @@ -5,4 +5,5 @@ key4=456 key5=true key6=http://zomg.test/bbq key7=2022-09-01T12:01:12.001Z -key8=ipsum \ No newline at end of file +key8=ipsum +key9=unescaped$ \ No newline at end of file diff --git a/examples/envied_example/lib/app_env_fields.dart b/examples/envied_example/lib/app_env_fields.dart index f3c255d..c94e71a 100644 --- a/examples/envied_example/lib/app_env_fields.dart +++ b/examples/envied_example/lib/app_env_fields.dart @@ -10,4 +10,5 @@ abstract interface class AppEnvFields { abstract final Uri key6; abstract final DateTime key7; abstract final ExampleEnum key8; + abstract final String key9; } diff --git a/examples/envied_example/lib/constant_case_env.dart b/examples/envied_example/lib/constant_case_env.dart index d7f8211..2ac1505 100644 --- a/examples/envied_example/lib/constant_case_env.dart +++ b/examples/envied_example/lib/constant_case_env.dart @@ -6,6 +6,7 @@ part 'constant_case_env.g.dart'; final class ConstantCaseEnv { @EnviedField() static const String key1 = _ConstantCaseEnv.key1; + @EnviedField() static const String key2 = _ConstantCaseEnv.key2; } diff --git a/examples/envied_example/lib/debug_env.dart b/examples/envied_example/lib/debug_env.dart index ee4054d..c0772e0 100644 --- a/examples/envied_example/lib/debug_env.dart +++ b/examples/envied_example/lib/debug_env.dart @@ -13,21 +13,27 @@ final class DebugEnv implements AppEnv, AppEnvFields { @override @EnviedField(varName: 'KEY1') final String key1 = _Env.key1; + @override @EnviedField(varName: 'KEY2') final String key2 = _Env.key2; + @override @EnviedField() final String key3 = _Env.key3; + @override @EnviedField() final int key4 = _Env.key4; + @override @EnviedField() final bool key5 = _Env.key5; + @override @EnviedField() final Uri key6 = _Env.key6; + @override @EnviedField() final DateTime key7 = _Env.key7; @@ -35,4 +41,8 @@ final class DebugEnv implements AppEnv, AppEnvFields { @override @EnviedField() final ExampleEnum key8 = _Env.key8; + + @override + @EnviedField(rawString: true) + final String key9 = _Env.key9; } diff --git a/examples/envied_example/lib/debug_env.g.dart b/examples/envied_example/lib/debug_env.g.dart index e3f9a17..78dd429 100644 --- a/examples/envied_example/lib/debug_env.g.dart +++ b/examples/envied_example/lib/debug_env.g.dart @@ -24,4 +24,6 @@ final class _Env { static final DateTime key7 = DateTime.parse('2022-09-01T12:01:12.001Z'); static final ExampleEnum key8 = ExampleEnum.values.byName('ipsum'); + + static const String key9 = r'unescaped$'; } diff --git a/examples/envied_example/lib/env.dart b/examples/envied_example/lib/env.dart index 1d1ee76..20d9b29 100644 --- a/examples/envied_example/lib/env.dart +++ b/examples/envied_example/lib/env.dart @@ -25,4 +25,7 @@ final class Env { @EnviedField() static final ExampleEnum key8 = _Env.key8; + + @EnviedField(rawString: true) + static final String key9 = _Env.key9; } diff --git a/examples/envied_example/lib/env.g.dart b/examples/envied_example/lib/env.g.dart index 103197d..3f48d61 100644 --- a/examples/envied_example/lib/env.g.dart +++ b/examples/envied_example/lib/env.g.dart @@ -24,4 +24,6 @@ final class _Env { static final DateTime key7 = DateTime.parse('2023-11-06T23:09:51.123Z'); static final ExampleEnum key8 = ExampleEnum.values.byName('lorem'); + + static const String key9 = r'uneascaped$'; } diff --git a/examples/envied_example/lib/release_env.dart b/examples/envied_example/lib/release_env.dart index 12bdd23..ba53a9d 100644 --- a/examples/envied_example/lib/release_env.dart +++ b/examples/envied_example/lib/release_env.dart @@ -13,21 +13,27 @@ final class ReleaseEnv implements AppEnv, AppEnvFields { @override @EnviedField(varName: 'KEY1') final String key1 = _Env.key1; + @override @EnviedField(varName: 'KEY2') final String key2 = _Env.key2; + @override @EnviedField() final String key3 = _Env.key3; + @override @EnviedField() final int key4 = _Env.key4; + @override @EnviedField() final bool key5 = _Env.key5; + @override @EnviedField() final Uri key6 = _Env.key6; + @override @EnviedField() final DateTime key7 = _Env.key7; @@ -35,4 +41,8 @@ final class ReleaseEnv implements AppEnv, AppEnvFields { @override @EnviedField() final ExampleEnum key8 = _Env.key8; + + @override + @EnviedField(rawString: true) + final String key9 = _Env.key9; } diff --git a/examples/envied_example/lib/release_env.g.dart b/examples/envied_example/lib/release_env.g.dart index 418f738..c56e77e 100644 --- a/examples/envied_example/lib/release_env.g.dart +++ b/examples/envied_example/lib/release_env.g.dart @@ -24,4 +24,6 @@ final class _Env { static final DateTime key7 = DateTime.parse('2023-11-06T23:09:51.123Z'); static final ExampleEnum key8 = ExampleEnum.values.byName('lorem'); + + static const String key9 = r'uneascaped$'; } diff --git a/packages/envied/lib/src/envied_base.dart b/packages/envied/lib/src/envied_base.dart index 7eb0663..e509154 100644 --- a/packages/envied/lib/src/envied_base.dart +++ b/packages/envied/lib/src/envied_base.dart @@ -72,6 +72,20 @@ final class Envied { /// ``` final bool useConstantCase; + /// Whether to interpolate the values for all fields. + /// If [interpolate] is `true`, the value will be interpolated + /// with the environment variables. + final bool interpolate; + + /// Whether to use the raw string format for all string values. + /// + /// **NOTE**: The string is always formatted `''`. + /// + /// If [rawStrings] is `true`, all Strings will be raw formatted `r''` + /// and the value may not contain a single quote. + /// Escapes single quotes and newlines in the value. + final bool rawStrings; + const Envied({ String? path, bool? requireEnvFile, @@ -79,6 +93,8 @@ final class Envied { this.obfuscate = false, this.allowOptionalFields = false, this.useConstantCase = false, + this.interpolate = true, + this.rawStrings = false, }) : path = path ?? '.env', requireEnvFile = requireEnvFile ?? false; } @@ -128,11 +144,29 @@ final class EnviedField { /// ``` final bool? useConstantCase; + /// Whether to use the interpolated value for the field. + /// If [interpolate] is `true`, the value will be interpolated + /// with the environment variables. + final bool? interpolate; + + /// Whether to use the raw string format for the value. + /// + /// Can only be used with a [String] type. + /// + /// **NOTE**: The string is always formatted `''`. + /// + /// If [rawString] is `true`, creates a raw String formatted `r''` + /// and the value may not contain a single quote. + /// Escapes single quotes and newlines in the value. + final bool? rawString; + const EnviedField({ this.varName, this.obfuscate, this.defaultValue, this.optional, this.useConstantCase, + this.interpolate, + this.rawString, }); } diff --git a/packages/envied_generator/lib/src/env_val.dart b/packages/envied_generator/lib/src/env_val.dart new file mode 100644 index 0000000..04af480 --- /dev/null +++ b/packages/envied_generator/lib/src/env_val.dart @@ -0,0 +1,18 @@ +import 'package:equatable/equatable.dart'; + +/// Represents a raw environment variable as well as its interpolated value. +class EnvVal with EquatableMixin { + const EnvVal({ + required this.raw, + String? interpolated, + }) : interpolated = interpolated ?? raw; + + final String raw; + final String interpolated; + + @override + String toString() => interpolated; + + @override + List get props => [raw, interpolated]; +} diff --git a/packages/envied_generator/lib/src/generate_field.dart b/packages/envied_generator/lib/src/generate_field.dart index b94bda2..9958b1f 100644 --- a/packages/envied_generator/lib/src/generate_field.dart +++ b/packages/envied_generator/lib/src/generate_field.dart @@ -15,6 +15,7 @@ Iterable generateFields( FieldElement field, String? value, { bool allowOptional = false, + bool rawString = false, }) { final String type = field.type.getDisplayString(withNullability: false); @@ -127,7 +128,10 @@ Iterable generateFields( literalString(value), ], ); - } else if (field.type.isDartCoreString || field.type is DynamicType) { + } else if (field.type.isDartCoreString) { + modifier = FieldModifier.constant; + result = literalString(value, raw: rawString); + } else if (field.type is DynamicType) { modifier = FieldModifier.constant; result = literalString(value); } else { diff --git a/packages/envied_generator/lib/src/generator.dart b/packages/envied_generator/lib/src/generator.dart index dc3a4fb..b999961 100644 --- a/packages/envied_generator/lib/src/generator.dart +++ b/packages/envied_generator/lib/src/generator.dart @@ -1,4 +1,4 @@ -import 'dart:io'; +import 'dart:io' show Platform; import 'package:analyzer/dart/constant/value.dart'; import 'package:analyzer/dart/element/element.dart'; @@ -9,6 +9,7 @@ import 'package:code_builder/code_builder.dart'; import 'package:dart_style/dart_style.dart'; import 'package:envied/envied.dart'; import 'package:envied_generator/src/build_options.dart'; +import 'package:envied_generator/src/env_val.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'; @@ -51,9 +52,11 @@ final class EnviedGenerator extends GeneratorForAnnotation { annotation.read('allowOptionalFields').literalValue as bool? ?? false, useConstantCase: annotation.read('useConstantCase').literalValue as bool? ?? false, + interpolate: annotation.read('interpolate').literalValue as bool? ?? true, + rawStrings: annotation.read('rawStrings').literalValue as bool? ?? false, ); - final Map envs = + final Map envs = await loadEnvs(config.path, (String error) { if (config.requireEnvFile) { throw InvalidGenerationSourceError( @@ -91,7 +94,7 @@ final class EnviedGenerator extends GeneratorForAnnotation { static Iterable _generateFields({ required FieldElement field, required Envied config, - required Map envs, + required Map envs, }) { final DartObject? dartObject = _typeChecker(EnviedField).firstAnnotationOf(field); @@ -112,14 +115,15 @@ final class EnviedGenerator extends GeneratorForAnnotation { final Object? defaultValue = reader.read('defaultValue').literalValue; - late final String? varValue; + late final EnvVal? varValue; if (envs.containsKey(varName)) { varValue = envs[varName]; } else if (Platform.environment.containsKey(varName)) { - varValue = Platform.environment[varName]; + varValue = EnvVal(raw: Platform.environment[varName]!); } else { - varValue = defaultValue?.toString(); + varValue = + defaultValue != null ? EnvVal(raw: defaultValue.toString()) : null; } if (field.type is InvalidType) { @@ -132,6 +136,12 @@ final class EnviedGenerator extends GeneratorForAnnotation { final bool optional = reader.read('optional').literalValue as bool? ?? config.allowOptionalFields; + final bool interpolate = + reader.read('interpolate').literalValue as bool? ?? config.interpolate; + + final bool rawString = + reader.read('rawString').literalValue as bool? ?? config.rawStrings; + // Throw if value is null but the field is not nullable bool isNullable = field.type is DynamicType || field.type.nullabilitySuffix == NullabilitySuffix.question; @@ -143,7 +153,16 @@ final class EnviedGenerator extends GeneratorForAnnotation { } return reader.read('obfuscate').literalValue as bool? ?? config.obfuscate - ? generateFieldsEncrypted(field, varValue, allowOptional: optional) - : generateFields(field, varValue, allowOptional: optional); + ? generateFieldsEncrypted( + field, + interpolate ? varValue?.interpolated : varValue?.raw, + allowOptional: optional, + ) + : generateFields( + field, + interpolate ? varValue?.interpolated : varValue?.raw, + allowOptional: optional, + rawString: rawString, + ); } } diff --git a/packages/envied_generator/lib/src/load_envs.dart b/packages/envied_generator/lib/src/load_envs.dart index da38d0f..458bea9 100644 --- a/packages/envied_generator/lib/src/load_envs.dart +++ b/packages/envied_generator/lib/src/load_envs.dart @@ -1,5 +1,6 @@ import 'dart:io' show File; +import 'package:envied_generator/src/env_val.dart'; import 'package:envied_generator/src/parser.dart'; /// Load the environment variables from the supplied [path], @@ -7,7 +8,7 @@ import 'package:envied_generator/src/parser.dart'; /// /// If file doesn't exist, an error will be thrown through the /// [onError] function. -Future> loadEnvs( +Future> loadEnvs( String path, Function(String) onError, ) async { diff --git a/packages/envied_generator/lib/src/parser.dart b/packages/envied_generator/lib/src/parser.dart index 78a1b06..0682365 100644 --- a/packages/envied_generator/lib/src/parser.dart +++ b/packages/envied_generator/lib/src/parser.dart @@ -1,7 +1,13 @@ +import 'package:envied_generator/src/env_val.dart'; + /// Creates key-value pairs from strings formatted as environment /// variable definitions. +/// +/// More or less a copy of the `dotenv` package parser +/// https://github.com/mockturtl/dotenv/blob/4.2.0/lib/src/parser.dart final class Parser { static const String _singleQuot = "'"; + static const String _doubleQuot = '"'; static final RegExp _leadingExport = RegExp(r'''^ *export ?'''); static final RegExp _comment = RegExp(r'''#[^'"]*$'''); static final RegExp _commentWithQuotes = RegExp(r'''#.*$'''); @@ -11,10 +17,10 @@ final class Parser { /// Creates a [Map](dart:core). /// Duplicate keys are silently discarded. - static Map parse(Iterable lines) { - final Map out = {}; + static Map parse(Iterable lines) { + final Map out = {}; for (final String line in lines) { - final Map kv = parseOne(line, env: out); + final Map kv = parseOne(line, env: out); if (kv.isNotEmpty) { out.putIfAbsent(kv.keys.single, () => kv.values.single); } @@ -23,41 +29,59 @@ final class Parser { } /// Parses a single line into a key-value pair. - static Map parseOne( + static Map parseOne( String line, { - Map env = const {}, + Map env = const {}, }) { final String stripped = strip(line); + + /// If the line is empty or a comment, return an empty map. if (!_isValid(stripped)) return {}; - final int idx = stripped.indexOf('='); - final String lhs = stripped.substring(0, idx); - final String k = swallow(lhs); - if (k.isEmpty) return {}; + /// Split the line into key and value. + final [String lhs, String rhs] = stripped.split('='); + + /// Remove the 'export' keyword. + final String key = swallow(lhs); + + /// If the key is empty, return an empty map. + if (key.isEmpty) return {}; + + /// Get the quote character, if any. + final String quotChar = surroundingQuote(rhs.trim()); - final String rhs = stripped.substring(idx + 1, stripped.length).trim(); - final String quotChar = surroundingQuote(rhs); - String v = unquote(rhs); + /// Remove quotes + String val = unquote(rhs.trim()); + + /// Values with single quotes are not interpolated. if (quotChar == _singleQuot) { - v = v.replaceAll("\\'", "'"); - return {k: v}; + return { + key: EnvVal( + raw: val.replaceAll(r"\'", "'"), + ), + }; } - if (quotChar == '"') { - v = v.replaceAll('\\"', '"').replaceAll('\\n', '\n'); + + /// Values with double quotes are interpolated. + if (quotChar == _doubleQuot) { + val = val.replaceAll(r'\"', '"').replaceAll(r'\n', '\n'); } - final String interpolatedValue = - interpolate(v, env).replaceAll("\\\$", "\$"); - return {k: interpolatedValue}; + + return { + key: EnvVal( + interpolated: interpolate(val, env).replaceAll(r'\$', r'$'), + raw: val), + }; } /// Substitutes $bash_vars in [val] with values from [env]. - static String interpolate(String val, Map env) => - val.replaceAllMapped(_bashVar, (Match m) { - if ((m.group(1) ?? "") == "\\") { - return m.input.substring(m.start, m.end); + static String interpolate(String val, Map env) => + val.replaceAllMapped(_bashVar, (Match match) { + if ((match.group(1) ?? '') == r'\') { + return match.input.substring(match.start, match.end); } else { - final String k = m.group(3)!; - return _has(env, k) ? env[k]! : ''; + final String key = match.group(3)!; + return _has(env, key) ? env[key]!.interpolated : ''; } }); @@ -73,10 +97,7 @@ final class Parser { : strip(val, includeQuotes: true).trim(); /// Strips comments (trailing or whole-line). - static String strip( - String line, { - bool includeQuotes = false, - }) => + static String strip(String line, {bool includeQuotes = false}) => line.replaceAll(includeQuotes ? _commentWithQuotes : _comment, '').trim(); /// Omits 'export' keyword. @@ -86,6 +107,6 @@ final class Parser { static bool _isValid(String s) => s.isNotEmpty && s.contains('='); /// [ null ] is a valid value in a Dart map, but the env var representation is empty string, not the string 'null' - static bool _has(Map map, String key) => + static bool _has(Map map, String key) => map.containsKey(key) && map[key] != null; } diff --git a/packages/envied_generator/pubspec.yaml b/packages/envied_generator/pubspec.yaml index 561c084..99ff024 100644 --- a/packages/envied_generator/pubspec.yaml +++ b/packages/envied_generator/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: source_gen: ^1.4.0 analyzer: ">=5.1.0 <7.0.0" recase: ^4.1.0 + equatable: ^2.0.5 dev_dependencies: lints: ">=2.1.1 <4.0.0" diff --git a/packages/envied_generator/test/.env.example b/packages/envied_generator/test/.env.example index 9d0ee45..5829db7 100644 --- a/packages/envied_generator/test/.env.example +++ b/packages/envied_generator/test/.env.example @@ -1,6 +1,11 @@ test_string=test_string testString=testString TEST_STRING=TEST_STRING +testUnescapedString=foo$ +test_unescaped_string=bar$ +testUnescapedString2='foo$bar\baz%' +testUnescapedString3="foo$bar\baz%" +testUnescapedString4=foo$bar\baz% testInt=123 TEST_INT=123 testDouble=1.23 diff --git a/packages/envied_generator/test/.env.example_with_path_override b/packages/envied_generator/test/.env.example_with_path_override index fc4e5fd..f1e86d2 100644 --- a/packages/envied_generator/test/.env.example_with_path_override +++ b/packages/envied_generator/test/.env.example_with_path_override @@ -1,2 +1,3 @@ foo=bar baz=qux +bad=unescaped$ \ No newline at end of file diff --git a/packages/envied_generator/test/src/generator_tests.dart b/packages/envied_generator/test/src/generator_tests.dart index 725662a..6ee4183 100644 --- a/packages/envied_generator/test/src/generator_tests.dart +++ b/packages/envied_generator/test/src/generator_tests.dart @@ -11,7 +11,7 @@ import 'example_enum.dart'; @Envied() const foo = 'bar'; -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env0 {} @@ -95,12 +95,20 @@ abstract class Env7 { static const bool? testString = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env8 { static const String testString = 'testString'; + static const String testUnescapedString = r'foo$'; + + static const String testUnescapedString2 = r'foo$bar\baz%'; + + static const String testUnescapedString3 = r'foo$bar\baz%'; + + static const String testUnescapedString4 = r'foo$bar\baz%'; + static const int testInt = 123; static const double testDouble = 1.23; @@ -114,6 +122,14 @@ final class _Env8 { abstract class Env8 { @EnviedField() static const String? testString = null; + @EnviedField(rawString: true, interpolate: false) + static const String? testUnescapedString = null; + @EnviedField(rawString: true, interpolate: false) + static const String? testUnescapedString2 = null; + @EnviedField(rawString: true, interpolate: false) + static const String? testUnescapedString3 = null; + @EnviedField(rawString: true, interpolate: false) + static const String? testUnescapedString4 = null; @EnviedField() static const int? testInt = null; @EnviedField() @@ -124,12 +140,14 @@ abstract class Env8 { static const testDynamic = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env8b { static const String? testString = 'testString'; + static const String? testUnescapedString = r'foo$'; + static const int? testInt = 123; static const double? testDouble = 1.23; @@ -143,6 +161,8 @@ final class _Env8b { abstract class Env8b { @EnviedField() static const String? testString = null; + @EnviedField(rawString: true) + static const String? testUnescapedString = null; @EnviedField() static const int? testInt = null; @EnviedField() @@ -153,7 +173,7 @@ abstract class Env8b { static const testDynamic = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env9 { @@ -166,7 +186,7 @@ abstract class Env9 { static const String? testString = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env9b { @@ -179,7 +199,20 @@ abstract class Env9b { static const String? testString = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' +// coverage:ignore-file +// ignore_for_file: type=lint +final class _Env9c { + static const String testUnescapedString = r'bar$'; +} +''') +@Envied(path: 'test/.env.example', rawStrings: true) +abstract class Env9c { + @EnviedField(varName: 'test_unescaped_string') + static const String? testUnescapedString = null; +} + +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env10 { @@ -192,7 +225,7 @@ abstract class Env10 { static const String? systemVar = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env10b { @@ -205,7 +238,7 @@ abstract class Env10b { static const String? systemVar = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Foo { @@ -218,7 +251,7 @@ abstract class Env11 { static const String? testString = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Foo { @@ -231,9 +264,9 @@ abstract class Env11b { static const String? testString = null; } -@ShouldGenerate('static const List _enviedkeytestString', contains: true) -@ShouldGenerate('static const List _envieddatatestString', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestString', contains: true) +@ShouldGenerate(r'static const List _envieddatatestString', contains: true) +@ShouldGenerate(r''' static final String testString = String.fromCharCodes(List.generate( _envieddatatestString.length, (int i) => i, @@ -246,9 +279,9 @@ abstract class Env12 { static const String? testString = null; } -@ShouldGenerate('static const List _enviedkeytestString', contains: true) -@ShouldGenerate('static const List _envieddatatestString', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestString', contains: true) +@ShouldGenerate(r'static const List _envieddatatestString', contains: true) +@ShouldGenerate(r''' static final String? testString = String.fromCharCodes(List.generate( _envieddatatestString.length, (int i) => i, @@ -261,9 +294,9 @@ abstract class Env12b { static const String? testString = null; } -@ShouldGenerate('static const List _enviedkeytestString', contains: true) -@ShouldGenerate('static const List _envieddatatestString', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestString', contains: true) +@ShouldGenerate(r'static const List _envieddatatestString', contains: true) +@ShouldGenerate(r''' static final String testString = String.fromCharCodes(List.generate( _envieddatatestString.length, (int i) => i, @@ -276,9 +309,9 @@ abstract class Env13 { static const String? testString = null; } -@ShouldGenerate('static const List _enviedkeytestString', contains: true) -@ShouldGenerate('static const List _envieddatatestString', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestString', contains: true) +@ShouldGenerate(r'static const List _envieddatatestString', contains: true) +@ShouldGenerate(r''' static final String? testString = String.fromCharCodes(List.generate( _envieddatatestString.length, (int i) => i, @@ -298,7 +331,7 @@ abstract class Env14 { static const String? testDefaultParam = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env14b { @@ -311,7 +344,7 @@ abstract class Env14b { static const String? testDefaultParam = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env15 { @@ -344,7 +377,7 @@ abstract class Env15 { static const dynamic testDynamic = '123abc'; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env15b { @@ -373,7 +406,36 @@ abstract class Env15b { static const bool testBool = true; } -@ShouldGenerate(''' +@ShouldGenerate(r''' +// coverage:ignore-file +// ignore_for_file: type=lint +final class _Env15c { + static const String testDefaultParam = r'test_'; + + static const String testString = r'testString'; + + static const int testInt = 123; + + static const double testDouble = 1.23; + + static const bool testBool = true; +} +''') +@Envied(path: 'test/.env.example', rawStrings: true) +abstract class Env15c { + @EnviedField(defaultValue: 'test_') + static const String? testDefaultParam = null; + @EnviedField() + static const String testString = 'testString'; + @EnviedField() + static const int testInt = 123; + @EnviedField() + static const double testDouble = 1.23; + @EnviedField() + static const bool testBool = true; +} + +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env16 { @@ -386,7 +448,7 @@ abstract class Env16 { static const String? testDefaultParam = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env16b { @@ -399,9 +461,9 @@ abstract class Env16b { static const String? testDefaultParam = null; } -@ShouldGenerate('static const List _enviedkeytestString', contains: true) -@ShouldGenerate('static const List _envieddatatestString', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestString', contains: true) +@ShouldGenerate(r'static const List _envieddatatestString', contains: true) +@ShouldGenerate(r''' static final String testString = String.fromCharCodes(List.generate( _envieddatatestString.length, (int i) => i, @@ -414,9 +476,9 @@ abstract class Env17 { static const String? testString = null; } -@ShouldGenerate('static const List _enviedkeytestString', contains: true) -@ShouldGenerate('static const List _envieddatatestString', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestString', contains: true) +@ShouldGenerate(r'static const List _envieddatatestString', contains: true) +@ShouldGenerate(r''' static final String? testString = String.fromCharCodes(List.generate( _envieddatatestString.length, (int i) => i, @@ -429,9 +491,9 @@ abstract class Env17b { static const String? testString = null; } -@ShouldGenerate('static const List _enviedkeytestString', contains: true) -@ShouldGenerate('static const List _envieddatatestString', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestString', contains: true) +@ShouldGenerate(r'static const List _envieddatatestString', contains: true) +@ShouldGenerate(r''' static final String testString = String.fromCharCodes(List.generate( _envieddatatestString.length, (int i) => i, @@ -444,9 +506,9 @@ abstract class Env18 { static const String testString = "test_"; } -@ShouldGenerate('static const List _enviedkeytestString', contains: true) -@ShouldGenerate('static const List _envieddatatestString', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestString', contains: true) +@ShouldGenerate(r'static const List _envieddatatestString', contains: true) +@ShouldGenerate(r''' static final String? testString = String.fromCharCodes(List.generate( _envieddatatestString.length, (int i) => i, @@ -459,9 +521,9 @@ abstract class Env18b { static const String? testString = null; } -@ShouldGenerate('static const List _enviedkeytestString', contains: true) -@ShouldGenerate('static const List _envieddatatestString', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestString', contains: true) +@ShouldGenerate(r'static const List _envieddatatestString', contains: true) +@ShouldGenerate(r''' static final String? testString = String.fromCharCodes(List.generate( _envieddatatestString.length, (int i) => i, @@ -474,7 +536,7 @@ abstract class Env18c { static const String? testString = null; } -@ShouldGenerate('static final int _enviedkeytestInt', contains: true) +@ShouldGenerate(r'static final int _enviedkeytestInt', contains: true) @ShouldGenerate( 'static final int testInt = _enviedkeytestInt ^', contains: true, @@ -485,7 +547,7 @@ abstract class Env19 { static const int testInt = 123; } -@ShouldGenerate('static final int _enviedkeytestInt', contains: true) +@ShouldGenerate(r'static final int _enviedkeytestInt', contains: true) @ShouldGenerate( 'static final int? testInt = _enviedkeytestInt ^', contains: true, @@ -496,7 +558,7 @@ abstract class Env19b { static const int? testInt = 123; } -@ShouldGenerate('static final bool _enviedkeytestBool', contains: true) +@ShouldGenerate(r'static final bool _enviedkeytestBool', contains: true) @ShouldGenerate( 'static final bool testBool = _enviedkeytestBool ^', contains: true, @@ -507,7 +569,7 @@ abstract class Env20 { static const bool testBool = true; } -@ShouldGenerate('static final bool _enviedkeytestBool', contains: true) +@ShouldGenerate(r'static final bool _enviedkeytestBool', contains: true) @ShouldGenerate( 'static final bool? testBool = _enviedkeytestBool ^', contains: true, @@ -518,9 +580,10 @@ abstract class Env20b { static const bool? testBool = true; } -@ShouldGenerate('static const List _enviedkeytestDynamic', contains: true) -@ShouldGenerate('static const List _envieddatatestDynamic', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestDynamic', contains: true) +@ShouldGenerate(r'static const List _envieddatatestDynamic', + contains: true) +@ShouldGenerate(r''' static final testDynamic = String.fromCharCodes(List.generate( _envieddatatestDynamic.length, (int i) => i, @@ -563,7 +626,7 @@ abstract class Env25 { static const dynamic foo = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' static final foo = null; ''', contains: true) @Envied(path: 'test/.env.example', allowOptionalFields: true) @@ -572,7 +635,7 @@ abstract class Env25b { static const dynamic foo = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env26 { @@ -585,7 +648,7 @@ abstract class Env26 { static const String? foo = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env27 { @@ -598,7 +661,7 @@ abstract class Env27 { static const int? foo = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env28 { @@ -611,7 +674,7 @@ abstract class Env28 { static const bool? foo = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env29 { @@ -631,7 +694,7 @@ abstract class Env29invalid { static final Uri? invalidTestUrl = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env29b { @@ -651,9 +714,9 @@ abstract class Env29bInvalid { static final Uri? invalidTestUrl = null; } -@ShouldGenerate('static const List _enviedkeytestUrl', contains: true) -@ShouldGenerate('static const List _envieddatatestUrl', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestUrl', contains: true) +@ShouldGenerate(r'static const List _envieddatatestUrl', contains: true) +@ShouldGenerate(r''' static final Uri testUrl = Uri.parse(String.fromCharCodes(List.generate( _envieddatatestUrl.length, (int i) => i, @@ -673,9 +736,9 @@ abstract class Env29cInvalid { static final Uri? invalidTestUrl = null; } -@ShouldGenerate('static const List _enviedkeytestUrl', contains: true) -@ShouldGenerate('static const List _envieddatatestUrl', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestUrl', contains: true) +@ShouldGenerate(r'static const List _envieddatatestUrl', contains: true) +@ShouldGenerate(r''' static final Uri? testUrl = Uri.parse(String.fromCharCodes(List.generate( _envieddatatestUrl.length, (int i) => i, @@ -695,7 +758,7 @@ abstract class Env29dInvalid { static final Uri? invalidTestUrl = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env29empty { @@ -708,7 +771,7 @@ abstract class Env29empty { static final Uri? emptyTestUrl = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env30 { @@ -722,7 +785,7 @@ abstract class Env30 { static final DateTime? testDateTime = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env30b { @@ -736,10 +799,11 @@ abstract class Env30b { static final DateTime? testDateTime = null; } -@ShouldGenerate('static const List _enviedkeytestDateTime', contains: true) -@ShouldGenerate('static const List _envieddatatestDateTime', +@ShouldGenerate(r'static const List _enviedkeytestDateTime', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _envieddatatestDateTime', + contains: true) +@ShouldGenerate(r''' static final DateTime testDateTime = DateTime.parse(String.fromCharCodes(List.generate( _envieddatatestDateTime.length, @@ -753,10 +817,11 @@ abstract class Env30c { static final DateTime? testDateTime = null; } -@ShouldGenerate('static const List _enviedkeytestDateTime', contains: true) -@ShouldGenerate('static const List _envieddatatestDateTime', +@ShouldGenerate(r'static const List _enviedkeytestDateTime', + contains: true) +@ShouldGenerate(r'static const List _envieddatatestDateTime', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r''' static final DateTime? testDateTime = DateTime.parse(String.fromCharCodes(List.generate( _envieddatatestDateTime.length, @@ -806,7 +871,7 @@ abstract class Env30dInvalid { static final DateTime? invalidTestDateTime = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env31 { @@ -819,7 +884,7 @@ abstract class Env31 { static final DateTime? testDate = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env31b { @@ -832,9 +897,9 @@ abstract class Env31b { static final DateTime? testDate = null; } -@ShouldGenerate('static const List _enviedkeytestDate', contains: true) -@ShouldGenerate('static const List _envieddatatestDate', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestDate', contains: true) +@ShouldGenerate(r'static const List _envieddatatestDate', contains: true) +@ShouldGenerate(r''' static final DateTime testDate = DateTime.parse(String.fromCharCodes(List.generate( _envieddatatestDate.length, @@ -848,9 +913,9 @@ abstract class Env31c { static final DateTime? testDate = null; } -@ShouldGenerate('static const List _enviedkeytestDate', contains: true) -@ShouldGenerate('static const List _envieddatatestDate', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestDate', contains: true) +@ShouldGenerate(r'static const List _envieddatatestDate', contains: true) +@ShouldGenerate(r''' static final DateTime? testDate = DateTime.parse(String.fromCharCodes(List.generate( _envieddatatestDate.length, @@ -892,9 +957,9 @@ abstract class Env31dInvalid { static final DateTime? invalidTestDate = null; } -@ShouldGenerate('static const List _enviedkeytestDouble', contains: true) -@ShouldGenerate('static const List _envieddatatestDouble', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestDouble', contains: true) +@ShouldGenerate(r'static const List _envieddatatestDouble', contains: true) +@ShouldGenerate(r''' static final double testDouble = double.parse(String.fromCharCodes(List.generate( _envieddatatestDouble.length, @@ -908,9 +973,9 @@ abstract class Env32a { static const double testDouble = 1.23; } -@ShouldGenerate('static const List _enviedkeytestDouble', contains: true) -@ShouldGenerate('static const List _envieddatatestDouble', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestDouble', contains: true) +@ShouldGenerate(r'static const List _envieddatatestDouble', contains: true) +@ShouldGenerate(r''' static final double? testDouble = double.parse(String.fromCharCodes(List.generate( _envieddatatestDouble.length, @@ -924,9 +989,9 @@ abstract class Env32b { static const double? testDouble = 1.23; } -@ShouldGenerate('static const List _enviedkeytestNum', contains: true) -@ShouldGenerate('static const List _envieddatatestNum', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestNum', contains: true) +@ShouldGenerate(r'static const List _envieddatatestNum', contains: true) +@ShouldGenerate(r''' static final num testNum = num.parse(String.fromCharCodes(List.generate( _envieddatatestNum.length, (int i) => i, @@ -939,9 +1004,9 @@ abstract class Env33a { static const num testNum = 1.23; } -@ShouldGenerate('static const List _enviedkeytestNum', contains: true) -@ShouldGenerate('static const List _envieddatatestNum', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestNum', contains: true) +@ShouldGenerate(r'static const List _envieddatatestNum', contains: true) +@ShouldGenerate(r''' static final num? testNum = num.parse(String.fromCharCodes(List.generate( _envieddatatestNum.length, (int i) => i, @@ -954,7 +1019,7 @@ abstract class Env33b { static const num? testNum = 1.23; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env34 { @@ -991,7 +1056,7 @@ abstract class Env34 { static const String testDynamic = '123_ABC'; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env35 { @@ -1004,7 +1069,7 @@ abstract class Env35 { static final ExampleEnum? testEnum = null; } -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _Env35b { @@ -1017,9 +1082,9 @@ abstract class Env35b { static final ExampleEnum? testEnum = null; } -@ShouldGenerate('static const List _enviedkeytestEnum', contains: true) -@ShouldGenerate('static const List _envieddatatestEnum', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestEnum', contains: true) +@ShouldGenerate(r'static const List _envieddatatestEnum', contains: true) +@ShouldGenerate(r''' static final ExampleEnum testEnum = ExampleEnum.values.byName(String.fromCharCodes(List.generate( _envieddatatestEnum.length, @@ -1033,9 +1098,9 @@ abstract class Env35c { static final ExampleEnum? testEnum = null; } -@ShouldGenerate('static const List _enviedkeytestEnum', contains: true) -@ShouldGenerate('static const List _envieddatatestEnum', contains: true) -@ShouldGenerate(''' +@ShouldGenerate(r'static const List _enviedkeytestEnum', contains: true) +@ShouldGenerate(r'static const List _envieddatatestEnum', contains: true) +@ShouldGenerate(r''' static final ExampleEnum? testEnum = ExampleEnum.values.byName(String.fromCharCodes(List.generate( _envieddatatestEnum.length, diff --git a/packages/envied_generator/test/src/generator_tests_with_path_override.dart b/packages/envied_generator/test/src/generator_tests_with_path_override.dart index d25bd2d..d5effa3 100644 --- a/packages/envied_generator/test/src/generator_tests_with_path_override.dart +++ b/packages/envied_generator/test/src/generator_tests_with_path_override.dart @@ -3,7 +3,7 @@ import 'package:envied/envied.dart'; import 'package:source_gen_test/annotations.dart'; -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _EnvWithPathOverride0 {} @@ -11,7 +11,7 @@ final class _EnvWithPathOverride0 {} @Envied() abstract class EnvWithPathOverride0 {} -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _EnvWithPathOverride1 {} @@ -19,13 +19,15 @@ final class _EnvWithPathOverride1 {} @Envied(requireEnvFile: true) abstract class EnvWithPathOverride1 {} -@ShouldGenerate(''' +@ShouldGenerate(r''' // coverage:ignore-file // ignore_for_file: type=lint final class _EnvWithPathOverride2 { static const String foo = 'bar'; static const String baz = 'qux'; + + static const String bad = r'unescaped$'; } ''') @Envied() @@ -34,4 +36,6 @@ abstract class EnvWithPathOverride2 { static const String? foo = null; @EnviedField() static const String? baz = null; + @EnviedField(rawString: true) + static const String? bad = null; }