From 21145cc9b36e5a8e44b71ca1a49763e919a5370d Mon Sep 17 00:00:00 2001 From: Miles Johnson Date: Wed, 3 Jan 2024 19:59:04 -0800 Subject: [PATCH] fix: Fix env_prefix inheritance. --- CHANGELOG.md | 7 +++++++ crates/macros/src/common/field.rs | 14 +++++++++++++- crates/macros/src/common/macros.rs | 10 +++++++++- crates/macros/src/config/container.rs | 4 ++-- crates/macros/src/config/field.rs | 9 +++------ crates/macros/src/config/mod.rs | 3 +-- crates/schematic/tests/generator_test.rs | 1 + .../snapshots/env_test__generates_typescript.snap | 9 ++++++++- .../generator_test__template_json__defaults.snap | 3 ++- .../generator_test__template_toml__defaults.snap | 3 ++- .../generator_test__template_yaml__defaults.snap | 3 ++- 11 files changed, 50 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a7abe81..ffe1b15b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Unreleased + +#### 🐞 Fixes + +- Fixed an issue where environment variables for `SchemaField` weren't being populated from + `env_prefix`. + ## 0.13.0 #### 💥 Breaking diff --git a/crates/macros/src/common/field.rs b/crates/macros/src/common/field.rs index 3b01efa5..71963967 100644 --- a/crates/macros/src/common/field.rs +++ b/crates/macros/src/common/field.rs @@ -52,6 +52,7 @@ pub struct Field<'l> { pub name: &'l Ident, pub value: &'l Type, pub value_type: FieldValue<'l>, + pub env_prefix: Option, } impl<'l> Field<'l> { @@ -70,6 +71,7 @@ impl<'l> Field<'l> { }, args, serde_args, + env_prefix: None, }; if field.args.default.is_some() { @@ -117,6 +119,16 @@ impl<'l> Field<'l> { } } + pub fn get_env_var(&self) -> Option { + if let Some(env_name) = &self.args.env { + Some(env_name.to_owned()) + } else { + self.env_prefix + .as_ref() + .map(|env_prefix| format!("{}{}", env_prefix, self.get_name(None)).to_uppercase()) + } + } + pub fn get_serde_meta(&self) -> Option { let mut meta = vec![]; @@ -164,7 +176,7 @@ impl<'l> Field<'l> { let nullable = map_bool_quote("nullable", self.is_optional()); let description = map_option_quote("description", extract_comment(&self.attrs)); let deprecated = map_option_quote("deprecated", extract_deprecated(&self.attrs)); - let env_var = map_option_quote("env_var", self.args.env.as_ref()); + let env_var = map_option_quote("env_var", self.get_env_var()); let value = self.value; let mut type_of = if self.is_nested() { diff --git a/crates/macros/src/common/macros.rs b/crates/macros/src/common/macros.rs index 08008326..8274a7f2 100644 --- a/crates/macros/src/common/macros.rs +++ b/crates/macros/src/common/macros.rs @@ -56,7 +56,15 @@ impl<'l> Macro<'l> { let config_type = match &input.data { Data::Struct(data) => match &data.fields { Fields::Named(fields) => Container::NamedStruct { - fields: fields.named.iter().map(Field::from).collect::>(), + fields: fields + .named + .iter() + .map(|f| { + let mut field = Field::from(f); + field.env_prefix = args.env_prefix.clone(); + field + }) + .collect::>(), }, Fields::Unnamed(_) => { panic!("Unnamed structs are not supported."); diff --git a/crates/macros/src/config/container.rs b/crates/macros/src/config/container.rs index d188192a..e44ced29 100644 --- a/crates/macros/src/config/container.rs +++ b/crates/macros/src/config/container.rs @@ -40,14 +40,14 @@ impl<'l> Container<'l> { } } - pub fn generate_env_values(&self, prefix: Option<&String>) -> TokenStream { + pub fn generate_env_values(&self) -> TokenStream { match self { Self::NamedStruct { fields: settings, .. } => { let env_stmts = settings .iter() - .filter_map(|s| s.generate_env_statement(prefix)) + .filter_map(|s| s.generate_env_statement()) .collect::>(); if env_stmts.is_empty() { diff --git a/crates/macros/src/config/field.rs b/crates/macros/src/config/field.rs index 5992f893..25b20018 100644 --- a/crates/macros/src/config/field.rs +++ b/crates/macros/src/config/field.rs @@ -13,18 +13,15 @@ impl<'l> Field<'l> { } } - pub fn generate_env_statement(&self, prefix: Option<&String>) -> Option { + pub fn generate_env_statement(&self) -> Option { if self.is_nested() { return None; } let name = self.name; + let env = self.get_env_var(); - let env = if let Some(env_name) = &self.args.env { - env_name.to_owned() - } else if let Some(env_prefix) = prefix { - format!("{}{}", env_prefix, self.get_name(None)).to_uppercase() - } else { + if env.is_none() { if self.args.parse_env.is_some() { panic!("Cannot use `parse_env` without `env` or a parent `env_prefix`."); } diff --git a/crates/macros/src/config/mod.rs b/crates/macros/src/config/mod.rs index d03aacf0..97514a35 100644 --- a/crates/macros/src/config/mod.rs +++ b/crates/macros/src/config/mod.rs @@ -13,7 +13,6 @@ impl<'l> ToTokens for ConfigMacro<'l> { fn to_tokens(&self, tokens: &mut TokenStream) { let cfg = &self.0; let name = cfg.name; - let env_prefix = cfg.args.env_prefix.as_ref(); // Generate the partial implementation let partial_name = format_ident!("Partial{}", cfg.name); @@ -27,7 +26,7 @@ impl<'l> ToTokens for ConfigMacro<'l> { // Generate implementations let meta = cfg.get_meta_struct(); let default_values = cfg.type_of.generate_default_values(); - let env_values = cfg.type_of.generate_env_values(env_prefix); + let env_values = cfg.type_of.generate_env_values(); let extends_from = cfg.type_of.generate_extends_from(); let finalize = cfg.type_of.generate_finalize(); let merge = cfg.type_of.generate_merge(); diff --git a/crates/schematic/tests/generator_test.rs b/crates/schematic/tests/generator_test.rs index ab7db533..9416cba7 100644 --- a/crates/schematic/tests/generator_test.rs +++ b/crates/schematic/tests/generator_test.rs @@ -62,6 +62,7 @@ struct GenConfig { /// Some comment. #[derive(Clone, Config)] +#[config(env_prefix = "ENV_PREFIX_")] pub struct TwoDepthConfig { /// An optional string. opt: Option, diff --git a/crates/schematic/tests/snapshots/env_test__generates_typescript.snap b/crates/schematic/tests/snapshots/env_test__generates_typescript.snap index b592ac00..6de1354a 100644 --- a/crates/schematic/tests/snapshots/env_test__generates_typescript.snap +++ b/crates/schematic/tests/snapshots/env_test__generates_typescript.snap @@ -1,5 +1,5 @@ --- -source: crates/config/tests/env_test.rs +source: crates/schematic/tests/env_test.rs expression: "std::fs::read_to_string(file).unwrap()" --- // Automatically generated by schematic. DO NOT MODIFY! @@ -12,12 +12,19 @@ export interface EnvVarsNested { } export interface EnvVarsPrefixed { + /** @envvar ENV_BOOL */ bool: boolean; + /** @envvar ENV_LIST1 */ list1: string[]; + /** @envvar ENV_LIST2 */ list2: number[]; + /** @envvar ENV_NESTED */ nested: EnvVarsNested; + /** @envvar ENV_NUMBER */ number: number; + /** @envvar ENV_PATH */ path: string; + /** @envvar ENV_STRING */ string: string; } diff --git a/crates/schematic/tests/snapshots/generator_test__template_json__defaults.snap b/crates/schematic/tests/snapshots/generator_test__template_json__defaults.snap index 0be3573a..28da9a4a 100644 --- a/crates/schematic/tests/snapshots/generator_test__template_json__defaults.snap +++ b/crates/schematic/tests/snapshots/generator_test__template_json__defaults.snap @@ -1,5 +1,5 @@ --- -source: crates/config/tests/generator_test.rs +source: crates/schematic/tests/generator_test.rs expression: "fs::read_to_string(file).unwrap()" --- { @@ -39,6 +39,7 @@ expression: "fs::read_to_string(file).unwrap()" // This is another nested field. "two": { // An optional string. + // @envvar ENV_PREFIX_OPT "opt": "", }, }, diff --git a/crates/schematic/tests/snapshots/generator_test__template_toml__defaults.snap b/crates/schematic/tests/snapshots/generator_test__template_toml__defaults.snap index 77de7442..05ffdfce 100644 --- a/crates/schematic/tests/snapshots/generator_test__template_toml__defaults.snap +++ b/crates/schematic/tests/snapshots/generator_test__template_toml__defaults.snap @@ -1,5 +1,5 @@ --- -source: crates/config/tests/generator_test.rs +source: crates/schematic/tests/generator_test.rs expression: "fs::read_to_string(file).unwrap()" --- # This is a boolean with a medium length description. @@ -44,6 +44,7 @@ enums = "foo" # This is another nested field. [one.two] # An optional string. +# @envvar ENV_PREFIX_OPT opt = "" diff --git a/crates/schematic/tests/snapshots/generator_test__template_yaml__defaults.snap b/crates/schematic/tests/snapshots/generator_test__template_yaml__defaults.snap index 25ad4600..eb4dab45 100644 --- a/crates/schematic/tests/snapshots/generator_test__template_yaml__defaults.snap +++ b/crates/schematic/tests/snapshots/generator_test__template_yaml__defaults.snap @@ -1,5 +1,5 @@ --- -source: crates/config/tests/generator_test.rs +source: crates/schematic/tests/generator_test.rs expression: "fs::read_to_string(file).unwrap()" --- # This is a boolean with a medium length description. @@ -37,6 +37,7 @@ one: # This is another nested field. two: # An optional string. + # @envvar ENV_PREFIX_OPT opt: "" # This is a string.