Skip to content

Commit

Permalink
Merge pull request #34 from alexquick/fix-parsing-issues
Browse files Browse the repository at this point in the history
Fix some small parsing bugs
  • Loading branch information
joho authored Aug 22, 2017
2 parents 59f2022 + a905e99 commit c9360df
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 14 deletions.
41 changes: 27 additions & 14 deletions godotenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"io"
"os"
"os/exec"
"regexp"
"strings"
)

Expand Down Expand Up @@ -203,11 +204,11 @@ func parseLine(line string) (key string, value string, err error) {
line = strings.Join(segmentsToKeep, "#")
}

// now split key from value
firstEquals := strings.Index(line, "=")
firstColon := strings.Index(line, ":")
splitString := strings.SplitN(line, "=", 2)

if len(splitString) != 2 {
// try yaml mode!
if firstColon != -1 && (firstColon < firstEquals || firstEquals == -1) {
//this is a yaml-style line
splitString = strings.SplitN(line, ":", 2)
}

Expand All @@ -224,27 +225,39 @@ func parseLine(line string) (key string, value string, err error) {
key = strings.Trim(key, " ")

// Parse the value
value = splitString[1]
value = parseValue(splitString[1])
return
}

func parseValue(value string) string {

// trim
value = strings.Trim(value, " ")

// check if we've got quoted values
if value != "" {
// check if we've got quoted values or possible escapes
if len(value) > 1 {
first := string(value[0:1])
last := string(value[len(value)-1:])
if first == last && strings.ContainsAny(first, `"'`) {
// pull the quotes off the edges
value = strings.Trim(value, `"'`)

// expand quotes
value = strings.Replace(value, `\"`, `"`, -1)
// expand newlines
value = strings.Replace(value, `\n`, "\n", -1)
value = value[1 : len(value)-1]
// handle escapes
escapeRegex := regexp.MustCompile(`\\.`)
value = escapeRegex.ReplaceAllStringFunc(value, func(match string) string {
c := strings.TrimPrefix(match, `\`)
switch c {
case "n":
return "\n"
case "r":
return "\r"
default:
return c
}
})
}
}

return
return value
}

func isIgnoredLine(line string) bool {
Expand Down
18 changes: 18 additions & 0 deletions godotenv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,18 @@ func TestParsing(t *testing.T) {
// parses escaped double quotes
parseAndCompare(t, `FOO="escaped\"bar"`, "FOO", `escaped"bar`)

// parses single quotes inside double quotes
parseAndCompare(t, `FOO="'d'"`, "FOO", `'d'`)

// parses yaml style options
parseAndCompare(t, "OPTION_A: 1", "OPTION_A", "1")

//parses yaml values with equal signs
parseAndCompare(t, "OPTION_A: Foo=bar", "OPTION_A", "Foo=bar")

// parses non-yaml options with colons
parseAndCompare(t, "OPTION_A=1:B", "OPTION_A", "1:B")

// parses export keyword
parseAndCompare(t, "export OPTION_A=2", "OPTION_A", "2")
parseAndCompare(t, `export OPTION_B='\n'`, "OPTION_B", "\n")
Expand Down Expand Up @@ -256,6 +265,15 @@ func TestParsing(t *testing.T) {
parseAndCompare(t, `FOO="ba#r"`, "FOO", "ba#r")
parseAndCompare(t, "FOO='ba#r'", "FOO", "ba#r")

//newlines and backslashes should be escaped
parseAndCompare(t, `FOO="bar\n\ b\az"`, "FOO", "bar\n baz")
parseAndCompare(t, `FOO="bar\\\n\ b\az"`, "FOO", "bar\\\n baz")
parseAndCompare(t, `FOO="bar\\r\ b\az"`, "FOO", "bar\\r baz")

parseAndCompare(t, `="value"`, "", "value")
parseAndCompare(t, `KEY="`, "KEY", "\"")
parseAndCompare(t, `KEY="value`, "KEY", "\"value")

// it 'throws an error if line format is incorrect' do
// expect{env('lol$wut')}.to raise_error(Dotenv::FormatError)
badlyFormattedLine := "lol$wut"
Expand Down

0 comments on commit c9360df

Please sign in to comment.