Skip to content

Commit 69298a0

Browse files
Merge pull request #11 from evilmonkeyinc/feat/double-quote-keys
feat: support double quotes in subscript for keys
2 parents 5185503 + a6cc88d commit 69298a0

File tree

5 files changed

+78
-18
lines changed

5 files changed

+78
-18
lines changed

test/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ This implementation would be closer to the 'Scalar consensus' as it does not alw
6161
|: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"]}]`|
6262
|:white_check_mark:|`$['ü']`|`{"ü": 42}`|`nil`|`null`|
6363
|:white_check_mark:|`$['two.some']`|`{ "one": {"key": "value"}, "two": {"some": "more", "key": "other value"}, "two.some": "42" }`|`"42"`|`"42"`|
64-
|:no_entry:|`$["key"]`|`{"key": "value"}`|`"value"`|`null`|
64+
|:white_check_mark:|`$["key"]`|`{"key": "value"}`|`"value"`|`"value"`|
6565
|:white_check_mark:|`$[]`|`{"": 42, "''": 123, "\"\"": 222}`|`nil`|`null`|
6666
|:white_check_mark:|`$['']`|`{"": 42, "''": 123, "\"\"": 222}`|`42`|`42`|
67-
|:no_entry:|`$[""]`|`{"": 42, "''": 123, "\"\"": 222}`|`42`|`null`|
67+
|:white_check_mark:|`$[""]`|`{"": 42, "''": 123, "\"\"": 222}`|`42`|`42`|
6868
|:white_check_mark:|`$[-2]`|`["one element"]`|`nil`|`null`|
6969
|:white_check_mark:|`$[2]`|`["first", "second", "third", "forth", "fifth"]`|`"third"`|`"third"`|
7070
|: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
109109
|---|---|---|---|---|
110110
|:no_entry:|`@.a`|`{"a": 1}`|`nil`|`1`|
111111
|:white_check_mark:|`$.['key']`|`{ "key": "value", "other": {"key": [{"key": 42}]} }`|`"value"`|`"value"`|
112-
|:question:|`$.["key"]`|`{ "key": "value", "other": {"key": [{"key": 42}]} }`|none|`null`|
112+
|:question:|`$.["key"]`|`{ "key": "value", "other": {"key": [{"key": 42}]} }`|none|`"value"`|
113113
|:question:|`$.[key]`|`{ "key": "value", "other": {"key": [{"key": 42}]} }`|none|`null`|
114114
|:white_check_mark:|`$.key`|`{ "key": "value" }`|`"value"`|`"value"`|
115115
|:white_check_mark:|`$.key`|`[0, 1]`|`nil`|`null`|

test/bracket_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ var bracketTests []testData = []testData{
6868
{
6969
query: `$["key"]`,
7070
data: `{"key": "value"}`,
71-
expected: nil,
71+
expected: "value",
7272
consensus: "value",
73-
expectedError: "invalid JSONPath query '$[\"key\"]' invalid token. '[\"key\"]' does not match any token format",
73+
expectedError: "",
7474
},
7575
{
7676
query: "$[]",
@@ -89,9 +89,9 @@ var bracketTests []testData = []testData{
8989
{
9090
query: `$[""]`,
9191
data: `{"": 42, "''": 123, "\"\"": 222}`,
92-
expected: nil,
92+
expected: float64(42),
9393
consensus: float64(42),
94-
expectedError: "invalid JSONPath query '$[\"\"]' invalid token. '[\"\"]' does not match any token format",
94+
expectedError: "",
9595
},
9696
{
9797
query: "$[-2]",

test/dot_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ var dotTests []testData = []testData{
2323
{
2424
query: `$.["key"]`,
2525
data: `{ "key": "value", "other": {"key": [{"key": 42}]} }`,
26-
expected: nil,
26+
expected: "value",
2727
consensus: consensusNone,
28-
expectedError: "invalid JSONPath query '$.[\"key\"]' invalid token. '[\"key\"]' does not match any token format",
28+
expectedError: "",
2929
},
3030
{
3131
query: `$.[key]`,

token/token.go

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,9 @@ func Parse(tokenString string, options *Options) (Token, error) {
194194
}
195195

196196
isKey := func(token string) bool {
197-
return len(token) > 1 && strings.HasPrefix(token, "'") && strings.HasSuffix(token, "'")
197+
isSingleQuoted := strings.HasPrefix(token, "'") && strings.HasSuffix(token, "'")
198+
isDoubleQuoted := strings.HasPrefix(token, "\"") && strings.HasSuffix(token, "\"")
199+
return len(token) > 1 && (isSingleQuoted || isDoubleQuoted)
198200
}
199201

200202
tokenString = strings.TrimSpace(tokenString)
@@ -247,7 +249,12 @@ func Parse(tokenString string, options *Options) (Token, error) {
247249
// which would result in the parsing being invalid
248250

249251
openBracketCount, closeBracketCount := 0, 0
250-
openQuote := false
252+
openSingleQuote := false
253+
openDoubleQuote := false
254+
255+
inQuotes := func() bool {
256+
return openSingleQuote || openDoubleQuote
257+
}
251258

252259
args := []interface{}{}
253260

@@ -256,13 +263,13 @@ func Parse(tokenString string, options *Options) (Token, error) {
256263
bufferString += string(rne)
257264
switch rne {
258265
case ' ':
259-
if !openQuote && openBracketCount == closeBracketCount {
266+
if !inQuotes() && openBracketCount == closeBracketCount {
260267
// remove whitespace
261268
bufferString = strings.TrimSpace(bufferString)
262269
}
263270
break
264271
case '(':
265-
if openQuote {
272+
if inQuotes() {
266273
continue
267274
}
268275
openBracketCount++
@@ -281,7 +288,7 @@ func Parse(tokenString string, options *Options) (Token, error) {
281288
}
282289
break
283290
case '\'':
284-
if openBracketCount != closeBracketCount {
291+
if openDoubleQuote || openBracketCount != closeBracketCount {
285292
continue
286293
}
287294

@@ -291,9 +298,9 @@ func Parse(tokenString string, options *Options) (Token, error) {
291298
break
292299
}
293300

294-
openQuote = !openQuote
301+
openSingleQuote = !openSingleQuote
295302

296-
if openQuote {
303+
if openSingleQuote {
297304
// open quote
298305
if bufferString != "'" {
299306
return nil, getInvalidTokenFormatError(tokenString)
@@ -307,8 +314,35 @@ func Parse(tokenString string, options *Options) (Token, error) {
307314
bufferString = ""
308315
}
309316
break
317+
case '"':
318+
if openSingleQuote || openBracketCount != closeBracketCount {
319+
continue
320+
}
321+
322+
// if last token is escape character, then this is not an open or close
323+
if len(bufferString) > 1 && bufferString[len(bufferString)-2] == '\\' {
324+
bufferString = bufferString[0:len(bufferString)-2] + "\""
325+
break
326+
}
327+
328+
openDoubleQuote = !openDoubleQuote
329+
330+
if openDoubleQuote {
331+
// open quote
332+
if bufferString != "\"" {
333+
return nil, getInvalidTokenFormatError(tokenString)
334+
}
335+
} else {
336+
// close quote
337+
if !isKey(bufferString) {
338+
return nil, getInvalidTokenFormatError(tokenString)
339+
}
340+
args = append(args, bufferString[:])
341+
bufferString = ""
342+
}
343+
break
310344
case ':':
311-
if openQuote || (openBracketCount != closeBracketCount) {
345+
if inQuotes() || (openBracketCount != closeBracketCount) {
312346
continue
313347
}
314348
if arg := bufferString[:len(bufferString)-1]; arg != "" {
@@ -326,7 +360,7 @@ func Parse(tokenString string, options *Options) (Token, error) {
326360
bufferString = ""
327361
break
328362
case ',':
329-
if openQuote || (openBracketCount != closeBracketCount) {
363+
if inQuotes() || (openBracketCount != closeBracketCount) {
330364
continue
331365
}
332366

token/token_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,32 @@ func Test_Parse(t *testing.T) {
466466
err: "invalid token. '[\\'key\\'s']' does not match any token format",
467467
},
468468
},
469+
{
470+
input: input{query: `["key"]`},
471+
expected: expected{
472+
token: newKeyToken("key"),
473+
},
474+
},
475+
{
476+
input: input{query: `["key's"]`},
477+
expected: expected{
478+
token: newKeyToken("key's"),
479+
},
480+
},
481+
{
482+
input: input{query: `["\"keys\""]`},
483+
expected: expected{
484+
token: newKeyToken("\"keys\""),
485+
},
486+
},
487+
{
488+
input: input{query: `["one","two",'three']`},
489+
expected: expected{
490+
token: &unionToken{
491+
arguments: []interface{}{"one", "two", "three"},
492+
},
493+
},
494+
},
469495
}
470496

471497
for idx, test := range tests {

0 commit comments

Comments
 (0)