diff --git a/test/README.md b/test/README.md index 79d27db..161038b 100644 --- a/test/README.md +++ b/test/README.md @@ -61,10 +61,10 @@ This implementation would be closer to the 'Scalar consensus' as it does not alw |:white_check_mark:|`$..[0]`|`[ "first", { "key": [ "first nested", { "more": [ { "nested": ["deepest", "second"] }, ["more", "values"] ] } ] } ]`|`["deepest","first nested","first","more",{"nested":["deepest","second"]}]`|`["deepest","first nested","first","more",{"nested":["deepest","second"]}]`| |:white_check_mark:|`$['ü']`|`{"ü": 42}`|`nil`|`null`| |:white_check_mark:|`$['two.some']`|`{ "one": {"key": "value"}, "two": {"some": "more", "key": "other value"}, "two.some": "42" }`|`"42"`|`"42"`| -|:no_entry:|`$["key"]`|`{"key": "value"}`|`"value"`|`null`| +|:white_check_mark:|`$["key"]`|`{"key": "value"}`|`"value"`|`"value"`| |:white_check_mark:|`$[]`|`{"": 42, "''": 123, "\"\"": 222}`|`nil`|`null`| |:white_check_mark:|`$['']`|`{"": 42, "''": 123, "\"\"": 222}`|`42`|`42`| -|:no_entry:|`$[""]`|`{"": 42, "''": 123, "\"\"": 222}`|`42`|`null`| +|:white_check_mark:|`$[""]`|`{"": 42, "''": 123, "\"\"": 222}`|`42`|`42`| |:white_check_mark:|`$[-2]`|`["one element"]`|`nil`|`null`| |:white_check_mark:|`$[2]`|`["first", "second", "third", "forth", "fifth"]`|`"third"`|`"third"`| |:white_check_mark:|`$[0]`|`{ "0": "value" }`|`nil`|`null`| @@ -109,7 +109,7 @@ This implementation would be closer to the 'Scalar consensus' as it does not alw |---|---|---|---|---| |:no_entry:|`@.a`|`{"a": 1}`|`nil`|`1`| |:white_check_mark:|`$.['key']`|`{ "key": "value", "other": {"key": [{"key": 42}]} }`|`"value"`|`"value"`| -|:question:|`$.["key"]`|`{ "key": "value", "other": {"key": [{"key": 42}]} }`|none|`null`| +|:question:|`$.["key"]`|`{ "key": "value", "other": {"key": [{"key": 42}]} }`|none|`"value"`| |:question:|`$.[key]`|`{ "key": "value", "other": {"key": [{"key": 42}]} }`|none|`null`| |:white_check_mark:|`$.key`|`{ "key": "value" }`|`"value"`|`"value"`| |:white_check_mark:|`$.key`|`[0, 1]`|`nil`|`null`| diff --git a/test/bracket_test.go b/test/bracket_test.go index 44f9f4b..a4ed118 100644 --- a/test/bracket_test.go +++ b/test/bracket_test.go @@ -68,9 +68,9 @@ var bracketTests []testData = []testData{ { query: `$["key"]`, data: `{"key": "value"}`, - expected: nil, + expected: "value", consensus: "value", - expectedError: "invalid JSONPath query '$[\"key\"]' invalid token. '[\"key\"]' does not match any token format", + expectedError: "", }, { query: "$[]", @@ -89,9 +89,9 @@ var bracketTests []testData = []testData{ { query: `$[""]`, data: `{"": 42, "''": 123, "\"\"": 222}`, - expected: nil, + expected: float64(42), consensus: float64(42), - expectedError: "invalid JSONPath query '$[\"\"]' invalid token. '[\"\"]' does not match any token format", + expectedError: "", }, { query: "$[-2]", diff --git a/test/dot_test.go b/test/dot_test.go index 4703c95..1776b43 100644 --- a/test/dot_test.go +++ b/test/dot_test.go @@ -23,9 +23,9 @@ var dotTests []testData = []testData{ { query: `$.["key"]`, data: `{ "key": "value", "other": {"key": [{"key": 42}]} }`, - expected: nil, + expected: "value", consensus: consensusNone, - expectedError: "invalid JSONPath query '$.[\"key\"]' invalid token. '[\"key\"]' does not match any token format", + expectedError: "", }, { query: `$.[key]`, diff --git a/token/token.go b/token/token.go index 4e0f4a3..9fdcc66 100644 --- a/token/token.go +++ b/token/token.go @@ -194,7 +194,9 @@ func Parse(tokenString string, options *Options) (Token, error) { } isKey := func(token string) bool { - return len(token) > 1 && strings.HasPrefix(token, "'") && strings.HasSuffix(token, "'") + isSingleQuoted := strings.HasPrefix(token, "'") && strings.HasSuffix(token, "'") + isDoubleQuoted := strings.HasPrefix(token, "\"") && strings.HasSuffix(token, "\"") + return len(token) > 1 && (isSingleQuoted || isDoubleQuoted) } tokenString = strings.TrimSpace(tokenString) @@ -247,7 +249,12 @@ func Parse(tokenString string, options *Options) (Token, error) { // which would result in the parsing being invalid openBracketCount, closeBracketCount := 0, 0 - openQuote := false + openSingleQuote := false + openDoubleQuote := false + + inQuotes := func() bool { + return openSingleQuote || openDoubleQuote + } args := []interface{}{} @@ -256,13 +263,13 @@ func Parse(tokenString string, options *Options) (Token, error) { bufferString += string(rne) switch rne { case ' ': - if !openQuote && openBracketCount == closeBracketCount { + if !inQuotes() && openBracketCount == closeBracketCount { // remove whitespace bufferString = strings.TrimSpace(bufferString) } break case '(': - if openQuote { + if inQuotes() { continue } openBracketCount++ @@ -281,7 +288,7 @@ func Parse(tokenString string, options *Options) (Token, error) { } break case '\'': - if openBracketCount != closeBracketCount { + if openDoubleQuote || openBracketCount != closeBracketCount { continue } @@ -291,9 +298,9 @@ func Parse(tokenString string, options *Options) (Token, error) { break } - openQuote = !openQuote + openSingleQuote = !openSingleQuote - if openQuote { + if openSingleQuote { // open quote if bufferString != "'" { return nil, getInvalidTokenFormatError(tokenString) @@ -307,8 +314,35 @@ func Parse(tokenString string, options *Options) (Token, error) { bufferString = "" } break + case '"': + if openSingleQuote || openBracketCount != closeBracketCount { + continue + } + + // if last token is escape character, then this is not an open or close + if len(bufferString) > 1 && bufferString[len(bufferString)-2] == '\\' { + bufferString = bufferString[0:len(bufferString)-2] + "\"" + break + } + + openDoubleQuote = !openDoubleQuote + + if openDoubleQuote { + // open quote + if bufferString != "\"" { + return nil, getInvalidTokenFormatError(tokenString) + } + } else { + // close quote + if !isKey(bufferString) { + return nil, getInvalidTokenFormatError(tokenString) + } + args = append(args, bufferString[:]) + bufferString = "" + } + break case ':': - if openQuote || (openBracketCount != closeBracketCount) { + if inQuotes() || (openBracketCount != closeBracketCount) { continue } if arg := bufferString[:len(bufferString)-1]; arg != "" { @@ -326,7 +360,7 @@ func Parse(tokenString string, options *Options) (Token, error) { bufferString = "" break case ',': - if openQuote || (openBracketCount != closeBracketCount) { + if inQuotes() || (openBracketCount != closeBracketCount) { continue } diff --git a/token/token_test.go b/token/token_test.go index f714de2..d397453 100644 --- a/token/token_test.go +++ b/token/token_test.go @@ -466,6 +466,32 @@ func Test_Parse(t *testing.T) { err: "invalid token. '[\\'key\\'s']' does not match any token format", }, }, + { + input: input{query: `["key"]`}, + expected: expected{ + token: newKeyToken("key"), + }, + }, + { + input: input{query: `["key's"]`}, + expected: expected{ + token: newKeyToken("key's"), + }, + }, + { + input: input{query: `["\"keys\""]`}, + expected: expected{ + token: newKeyToken("\"keys\""), + }, + }, + { + input: input{query: `["one","two",'three']`}, + expected: expected{ + token: &unionToken{ + arguments: []interface{}{"one", "two", "three"}, + }, + }, + }, } for idx, test := range tests {