Skip to content

Commit

Permalink
feat: support double quotes in subscript for keys
Browse files Browse the repository at this point in the history
can now support single quotes and double quotes
  • Loading branch information
evilmonkeyinc committed Jan 22, 2022
1 parent 5185503 commit a6cc88d
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 18 deletions.
6 changes: 3 additions & 3 deletions test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`|
Expand Down Expand Up @@ -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`|
Expand Down
8 changes: 4 additions & 4 deletions test/bracket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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: "$[]",
Expand All @@ -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]",
Expand Down
4 changes: 2 additions & 2 deletions test/dot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]`,
Expand Down
52 changes: 43 additions & 9 deletions token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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{}{}

Expand All @@ -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++
Expand All @@ -281,7 +288,7 @@ func Parse(tokenString string, options *Options) (Token, error) {
}
break
case '\'':
if openBracketCount != closeBracketCount {
if openDoubleQuote || openBracketCount != closeBracketCount {
continue
}

Expand All @@ -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)
Expand All @@ -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 != "" {
Expand All @@ -326,7 +360,7 @@ func Parse(tokenString string, options *Options) (Token, error) {
bufferString = ""
break
case ',':
if openQuote || (openBracketCount != closeBracketCount) {
if inQuotes() || (openBracketCount != closeBracketCount) {
continue
}

Expand Down
26 changes: 26 additions & 0 deletions token/token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit a6cc88d

Please sign in to comment.