From 069003fc7db3660f14ff90ddbf045ceb7bdec5fd Mon Sep 17 00:00:00 2001 From: Dmitry Afanasiev Date: Wed, 3 Dec 2025 14:57:48 +0300 Subject: [PATCH] feat: allow skip inline comment strip logic --- dotconfig.go | 13 ++++++++++--- dotconfig_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/dotconfig.go b/dotconfig.go index dcd47a2..c4f9afd 100644 --- a/dotconfig.go +++ b/dotconfig.go @@ -20,6 +20,7 @@ const ( EnforceStructTags // Make sure all fields in config struct have `env` struct tags AllowWhitespace // Allow leading/trailing whitespace in string values SkipNewlineDecoding // Don't turn "\n" into newlines + SkipCommentStrip // Don't exclude the comment from value that ends with #some_inline_comment ) type options struct { @@ -27,6 +28,7 @@ type options struct { EnforceStructTags bool AllowWhitespace bool SkipNewlineDecoding bool + SkipCommentStrip bool } func optsFromVariadic(opts []DecodeOption) options { @@ -41,6 +43,8 @@ func optsFromVariadic(opts []DecodeOption) options { v.AllowWhitespace = true case SkipNewlineDecoding: v.SkipNewlineDecoding = true + case SkipCommentStrip: + v.SkipCommentStrip = true } } return v @@ -113,9 +117,12 @@ func FromReader[T any](r io.Reader, opts ...DecodeOption) (T, error) { key := line[0:strings.Index(line, "=")] value := line[len(key)+1:] - // If there is a inline comment, so a space and then a #, exclude the comment. - if strings.Contains(value, " #") { - value = value[0:strings.Index(value, " #")] + if !decodedOpts.SkipCommentStrip { + // If there is a inline comment, so a space and then a #, exclude the comment. + ci := strings.Index(value, " #") + if ci >= 0 { + value = value[0:ci] + } } // Determine if our string is single quoted, double quoted, or just raw value. diff --git a/dotconfig_test.go b/dotconfig_test.go index eeab10c..a1206c4 100644 --- a/dotconfig_test.go +++ b/dotconfig_test.go @@ -251,3 +251,41 @@ func TestAllowWhitespace(t *testing.T) { t.Error("Expected to allow whitespace.") } } + +func TestInlineComments(t *testing.T) { + const dotenv = ` +# this is line comment + # and this also line comment +FOO=bar # this maybe part of FOO value (see SkipCommentStrip option) +` + + type configT struct { + Foo string `env:"FOO"` + } + + { + const expected = "bar" + r := strings.NewReader(dotenv) + config, err := dotconfig.FromReader[configT](r, dotconfig.EnforceStructTags) + if err != nil { + t.Fatalf("unexpected error (SkipCommentStrip disabled):%v", err) + } + + if config.Foo != expected { + t.Errorf("incorrect parsed value (SkipCommentStrip disabled), expected: %s, actual: %s", expected, config.Foo) + } + } + + { + const expected = "bar # this maybe part of FOO value (see SkipCommentStrip option)" + r := strings.NewReader(dotenv) + config, err := dotconfig.FromReader[configT](r, dotconfig.EnforceStructTags, dotconfig.SkipCommentStrip) + if err != nil { + t.Fatalf("unexpected error (SkipCommentStrip enabled) :%v", err) + } + + if config.Foo != expected { + t.Errorf("incorrect parsed value (SkipCommentStrip enabled), expected: %s, actual: %s", expected, config.Foo) + } + } +}