From 0c7fa090b0e9f4286282da0811139c9bc83ff983 Mon Sep 17 00:00:00 2001 From: Mattias Wadman Date: Sun, 15 Aug 2021 14:07:16 +0200 Subject: [PATCH] gojq: Initial update support decode value give no updateable error JQValue json value tries to replicate behaveior --- go.mod | 2 +- go.sum | 4 +- internal/gojqextra/gojqextra.go | 136 ++++++++++++++++--- pkg/interp/buffer.go | 4 + pkg/interp/interp.jq | 2 +- pkg/interp/testdata/value_array.fqtest | 98 +++++++------ pkg/interp/testdata/value_boolean.fqtest | 114 +++++++--------- pkg/interp/testdata/value_json_array.fqtest | 121 +++++++++++++++++ pkg/interp/testdata/value_json_object.fqtest | 111 +++++++++++++++ pkg/interp/testdata/value_null.fqtest | 110 +++++++-------- pkg/interp/testdata/value_number.fqtest | 110 +++++++-------- pkg/interp/testdata/value_object.fqtest | 108 +++++++-------- pkg/interp/testdata/value_string.fqtest | 100 +++++++------- pkg/interp/testdata/value_t.fqtest.tmpl | 39 ++++++ pkg/interp/testdata/value_t.fqtest.tmpl.sh | 10 ++ pkg/interp/testdata/value_type.fqtest.tmpl | 41 ------ pkg/interp/value.go | 18 +++ 17 files changed, 703 insertions(+), 425 deletions(-) create mode 100644 pkg/interp/testdata/value_json_array.fqtest create mode 100644 pkg/interp/testdata/value_json_object.fqtest create mode 100644 pkg/interp/testdata/value_t.fqtest.tmpl create mode 100644 pkg/interp/testdata/value_t.fqtest.tmpl.sh delete mode 100644 pkg/interp/testdata/value_type.fqtest.tmpl diff --git a/go.mod b/go.mod index a72cdcc8..6166e419 100644 --- a/go.mod +++ b/go.mod @@ -13,4 +13,4 @@ require ( replace github.com/chzyer/readline => github.com/wader/readline v0.0.0-20210708114437-6e459499aaf5 -replace github.com/itchyny/gojq => github.com/wader/gojq v0.12.1-0.20210815085601-b5d8be28faea +replace github.com/itchyny/gojq => github.com/wader/gojq v0.12.1-0.20210815133234-fa23c60d2da1 diff --git a/go.sum b/go.sum index 0a5c321c..30570420 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/wader/gojq v0.12.1-0.20210815085601-b5d8be28faea h1:n8MU47bCqWL/+U9MxhbMRUWe97txWtIAPsbyMMQrqfw= -github.com/wader/gojq v0.12.1-0.20210815085601-b5d8be28faea/go.mod h1:EQUSKgW/YaOxmXpAwGiowFDO4i2Rmtk5+9dFyeiymAg= +github.com/wader/gojq v0.12.1-0.20210815133234-fa23c60d2da1 h1:E51FeNldHd4SPpeBGuyu+LC0u/X/cagviC9Hk8eRY/o= +github.com/wader/gojq v0.12.1-0.20210815133234-fa23c60d2da1/go.mod h1:EQUSKgW/YaOxmXpAwGiowFDO4i2Rmtk5+9dFyeiymAg= github.com/wader/readline v0.0.0-20210708114437-6e459499aaf5 h1:lNbk3zDwMc1TaNGWiKrSxCep6R8qqu9CGWBqSFD/9sE= github.com/wader/readline v0.0.0-20210708114437-6e459499aaf5/go.mod h1:1n88xxtpWULehIaVFcn5JQJy3RUe/5pvJznoiKWfKng= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/internal/gojqextra/gojqextra.go b/internal/gojqextra/gojqextra.go index 00f244df..889b7d54 100644 --- a/internal/gojqextra/gojqextra.go +++ b/internal/gojqextra/gojqextra.go @@ -69,15 +69,48 @@ func (err HasKeyTypeError) Error() string { return "cannot check whether " + err.L + " has a key: " + err.R } +type ArrayIndexTooLargeError struct { + V interface{} +} + +func (err *ArrayIndexTooLargeError) Error() string { + return fmt.Sprintf("array index too large: %v", err.V) +} + +func expectedArrayOrObject(key interface{}, typ string) error { + switch v := key.(type) { + case string: + return ExpectedObjectWithKeyError{Typ: typ, Key: v} + case int: + return ExpectedArrayWithIndexError{Typ: typ, Index: v} + default: + panic("unreachable") + } +} + +type NonUpdatableTypeError struct { + Typ string + Key string +} + +func (err NonUpdatableTypeError) Error() string { + return fmt.Sprintf("update key %v cannot be applied to: %s", err.Key, err.Typ) +} + // array var _ gojq.JQValue = Array{} type Array []interface{} -func (v Array) JQValueLength() interface{} { return len(v) } -func (v Array) JQValueSliceLen() interface{} { return len(v) } -func (v Array) JQValueIndex(index int) interface{} { return v[index] } +func (v Array) JQValueLength() interface{} { return len(v) } +func (v Array) JQValueSliceLen() interface{} { return len(v) } +func (v Array) JQValueIndex(index int) interface{} { + if index < 0 { + return nil + } + return v[index] +} func (v Array) JQValueSlice(start int, end int) interface{} { return v[start:end] } func (v Array) JQValueKey(name string) interface{} { return ExpectedObjectError{Typ: "array"} @@ -96,6 +129,44 @@ func (v Array) JQValueKeys() interface{} { } return vs } +func (v Array) JQValueUpdate(key interface{}, u interface{}, delpath bool) interface{} { + // TODO: handle {start:, end: } + // TODO: maybe should use gojq implementation as it's quite complex + intKey, ok := key.(int) + if !ok { + return HasKeyTypeError{L: "array", R: fmt.Sprintf("%v", key)} + } + + if intKey > 0x3ffffff { + return ArrayIndexTooLargeError{V: intKey} + } + + l := len(v) + if intKey >= l { + if delpath { + return v + } + l = intKey + 1 + } else if intKey < -l { + if delpath { + return v + } + return FuncTypeError{Name: "setpath", Typ: "number"} + } else if intKey < 0 { + intKey += len(v) + } + + var uu []interface{} + if delpath { + uu = append(v[0:intKey], v[intKey+1:]...) + } else { + uu = make([]interface{}, l) + copy(uu, v) + uu[intKey] = u + } + + return uu +} func (v Array) JQValueHas(key interface{}) interface{} { intKey, ok := key.(int) if !ok { @@ -125,6 +196,24 @@ func (v Object) JQValueSlice(start int, end int) interface{} { return ExpectedArrayError{Typ: "object"} } func (v Object) JQValueKey(name string) interface{} { return v[name] } +func (v Object) JQValueUpdate(key interface{}, u interface{}, delpath bool) interface{} { + stringKey, ok := key.(string) + if !ok { + return HasKeyTypeError{L: "object", R: fmt.Sprintf("%v", key)} + } + + uu := make(map[string]interface{}, len(v)) + for kv, vv := range v { + uu[kv] = vv + } + if delpath { + delete(uu, stringKey) + } else { + uu[stringKey] = u + } + + return uu +} func (v Object) JQValueEach() interface{} { vs := make([]gojq.PathValue, len(v)) i := 0 @@ -175,8 +264,11 @@ func (v Number) JQValueSlice(start int, end int) interface{} { return ExpectedArrayError{Typ: "number"} } func (v Number) JQValueKey(name string) interface{} { return ExpectedObjectError{Typ: "number"} } -func (v Number) JQValueEach() interface{} { return IteratorError{Typ: "number"} } -func (v Number) JQValueKeys() interface{} { return FuncTypeError{Name: "keys", Typ: "number"} } +func (v Number) JQValueUpdate(key interface{}, u interface{}, delpath bool) interface{} { + return expectedArrayOrObject(key, "number") +} +func (v Number) JQValueEach() interface{} { return IteratorError{Typ: "number"} } +func (v Number) JQValueKeys() interface{} { return FuncTypeError{Name: "keys", Typ: "number"} } func (v Number) JQValueHas(key interface{}) interface{} { return FuncTypeError{Name: "has", Typ: "number"} } @@ -209,8 +301,11 @@ func (v String) JQValueIndex(index int) interface{} { } func (v String) JQValueSlice(start int, end int) interface{} { return string(v[start:end]) } func (v String) JQValueKey(name string) interface{} { return ExpectedObjectError{Typ: "string"} } -func (v String) JQValueEach() interface{} { return IteratorError{Typ: "string"} } -func (v String) JQValueKeys() interface{} { return FuncTypeError{Name: "keys", Typ: "string"} } +func (v String) JQValueUpdate(key interface{}, u interface{}, delpath bool) interface{} { + return expectedArrayOrObject(key, "string") +} +func (v String) JQValueEach() interface{} { return IteratorError{Typ: "string"} } +func (v String) JQValueKeys() interface{} { return FuncTypeError{Name: "keys", Typ: "string"} } func (v String) JQValueHas(key interface{}) interface{} { return FuncTypeError{Name: "has", Typ: "string"} } @@ -232,8 +327,11 @@ func (v Boolean) JQValueSlice(start int, end int) interface{} { return ExpectedArrayError{Typ: "boolean"} } func (v Boolean) JQValueKey(name string) interface{} { return ExpectedObjectError{Typ: "boolean"} } -func (v Boolean) JQValueEach() interface{} { return IteratorError{Typ: "boolean"} } -func (v Boolean) JQValueKeys() interface{} { return FuncTypeError{Name: "keys", Typ: "boolean"} } +func (v Boolean) JQValueUpdate(key interface{}, u interface{}, delpath bool) interface{} { + return expectedArrayOrObject(key, "boolean") +} +func (v Boolean) JQValueEach() interface{} { return IteratorError{Typ: "boolean"} } +func (v Boolean) JQValueKeys() interface{} { return FuncTypeError{Name: "keys", Typ: "boolean"} } func (v Boolean) JQValueHas(key interface{}) interface{} { return FuncTypeError{Name: "has", Typ: "boolean"} } @@ -260,13 +358,16 @@ func (v Null) JQValueSliceLen() interface{} { return ExpectedArra func (v Null) JQValueIndex(index int) interface{} { return ExpectedArrayError{Typ: "null"} } func (v Null) JQValueSlice(start int, end int) interface{} { return ExpectedArrayError{Typ: "null"} } func (v Null) JQValueKey(name string) interface{} { return ExpectedObjectError{Typ: "null"} } -func (v Null) JQValueEach() interface{} { return IteratorError{Typ: "null"} } -func (v Null) JQValueKeys() interface{} { return FuncTypeError{Name: "keys", Typ: "null"} } -func (v Null) JQValueHas(key interface{}) interface{} { return FuncTypeError{Name: "has", Typ: "null"} } -func (v Null) JQValueType() string { return "null" } -func (v Null) JQValueToNumber() interface{} { return FuncTypeError{Name: "tonumber", Typ: "null"} } -func (v Null) JQValueToString() interface{} { return "null" } -func (v Null) JQValueToGoJQ() interface{} { return nil } +func (v Null) JQValueUpdate(key interface{}, u interface{}, delpath bool) interface{} { + return expectedArrayOrObject(key, "null") +} +func (v Null) JQValueEach() interface{} { return IteratorError{Typ: "null"} } +func (v Null) JQValueKeys() interface{} { return FuncTypeError{Name: "keys", Typ: "null"} } +func (v Null) JQValueHas(key interface{}) interface{} { return FuncTypeError{Name: "has", Typ: "null"} } +func (v Null) JQValueType() string { return "null" } +func (v Null) JQValueToNumber() interface{} { return FuncTypeError{Name: "tonumber", Typ: "null"} } +func (v Null) JQValueToString() interface{} { return "null" } +func (v Null) JQValueToGoJQ() interface{} { return nil } // Base @@ -285,6 +386,9 @@ func (v Base) JQValueSlice(start int, end int) interface{} { return ExpectedArra func (v Base) JQValueKey(name string) interface{} { return ExpectedObjectWithKeyError{Typ: v.Typ, Key: name} } +func (v Base) JQValueUpdate(key interface{}, u interface{}, delpath bool) interface{} { + return expectedArrayOrObject(key, v.Typ) +} func (v Base) JQValueEach() interface{} { return IteratorError{Typ: v.Typ} } func (v Base) JQValueKeys() interface{} { return FuncTypeError{Name: "keys", Typ: v.Typ} } func (v Base) JQValueHas(key interface{}) interface{} { diff --git a/pkg/interp/buffer.go b/pkg/interp/buffer.go index 4e2e8a17..55772f8e 100644 --- a/pkg/interp/buffer.go +++ b/pkg/interp/buffer.go @@ -142,6 +142,10 @@ func (bo bufferObject) JQValueToGoJQ() interface{} { return buf.String() } +func (bo bufferObject) JQValueUpdate(key interface{}, u interface{}, delpath bool) interface{} { + return notUpdateableError{Key: fmt.Sprintf("%v", key), Typ: "buffer"} +} + func (bo bufferObject) Display(w io.Writer, opts Options) error { if opts.Raw { if _, err := io.Copy(w, bo.bbr.bb.Copy()); err != nil { diff --git a/pkg/interp/interp.jq b/pkg/interp/interp.jq index 394baf3d..2bdeb0ff 100644 --- a/pkg/interp/interp.jq +++ b/pkg/interp/interp.jq @@ -124,7 +124,7 @@ def _prompt: def _path_prefix: (._path? // []) | if . == [] then "" else path_to_expr + " " end; def _preview: - if type != "array" then + if (._format? // false) or type != "array" then _type_name_error else ( "[" diff --git a/pkg/interp/testdata/value_array.fqtest b/pkg/interp/testdata/value_array.fqtest index 09f9b94a..d4ee6d0c 100644 --- a/pkg/interp/testdata/value_array.fqtest +++ b/pkg/interp/testdata/value_array.fqtest @@ -1,6 +1,6 @@ /test.mp3: -# display -$ fq -d mp3 '.headers | ., tovalue, type, length?' /test.mp3 +$ fq -i -d mp3 . /test.mp3 +mp3> .headers | ., tovalue, type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| |.headers: [1] 0x00|49 44 33 04 00 00 00 00 00 23 54 53 53 45 00 00|ID3......#TSSE..| [0]: {} (id3v2) * |until 0x2c.7 (45) | | @@ -42,8 +42,7 @@ $ fq -d mp3 '.headers | ., tovalue, type, length?' /test.mp3 ] "array" 1 -# index -$ fq -d mp3 '.headers[0] | ., type, length?' /test.mp3 +mp3> .headers[0] | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| |.headers[0]: {} (id3v2) 0x00|49 44 33 |ID3 | magic: "ID3" (Correct) 0x00| 04 | . | version: 4 @@ -56,24 +55,23 @@ $ fq -d mp3 '.headers[0] | ., type, length?' /test.mp3 0x20| 00 00 00 00 00 00 00 00 00 00 | .......... | padding: Correct (none) (zero padding) "object" 7 -$ fq -d mp3 '.headers[-1000] | ., type, length?' /test.mp3 +mp3> .headers[-1000] | ., type, length? null "null" 0 -$ fq -d mp3 '.headers[1000] | ., type, length?' /test.mp3 +mp3> .headers[1000] | ., type, length? null "null" 0 -# slice -$ fq -d mp3 '.headers[1:3] | ., type, length?' /test.mp3 +mp3> .headers[1:3] | ., type, length? [] "array" 0 -$ fq -d mp3 '.headers[0:-1] | ., type, length?' /test.mp3 +mp3> .headers[0:-1] | ., type, length? [] "array" 0 -$ fq -d mp3 '.headers[-1000:2000] | ., type, length?' /test.mp3 +mp3> .headers[-1000:2000] | ., type, length? [ { "flags": { @@ -112,96 +110,92 @@ $ fq -d mp3 '.headers[-1000:2000] | ., type, length?' /test.mp3 ] "array" 1 -# key -$ fq -d mp3 '.headers["test"] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers["test"] | ., type, length? error: expected an object with key "test" but got: array -# each -$ fq -d mp3 '[.headers[]] | type, length?' /test.mp3 +mp3> [.headers[]] | type, length? "array" 1 -# keys -$ fq -d mp3 '.headers | keys' /test.mp3 +mp3> .headers | keys [ 0 ] -# has -$ fq -d mp3 '.headers | has("a")' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers | has("a") error: cannot check whether array has a key: a -$ fq -d mp3 '.headers | has(0)' /test.mp3 +mp3> .headers | has(0) true -# type -$ fq -d mp3 '.headers | type' /test.mp3 +mp3> .headers | type "array" -# tonumber -$ fq -d mp3 '.headers | tonumber' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers | tonumber error: tonumber cannot be applied to: array -# tostring -$ fq -d mp3 '.headers | tostring' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers | tostring error: tostring cannot be applied to: array -# to gojq -$ fq -d mp3 '.headers + ""' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers + "" error: cannot add: array ([{"flags":{"experimental_ ...]) and string ("") -$ fq -d mp3 '.headers + 1' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers + 1 error: cannot add: array ([{"flags":{"experimental_ ...]) and number (1) -# test _keys -$ fq -d mp3 '.headers._start | ., type, length?' /test.mp3 +mp3> .headers._start | ., type, length? 0 "number" 0 -$ fq -d mp3 '.headers._stop | ., type, length?' /test.mp3 +mp3> .headers._stop | ., type, length? 360 "number" 360 -$ fq -d mp3 '.headers._len | ., type, length?' /test.mp3 +mp3> .headers._len | ., type, length? 360 "number" 360 -$ fq -d mp3 '.headers._name | ., type, length?' /test.mp3 +mp3> .headers._name | ., type, length? "headers" "string" 7 -$ fq -d mp3 '.headers._symbol | ., type, length?' /test.mp3 +mp3> .headers._symbol | ., type, length? "" "string" 0 -$ fq -d mp3 '.headers._description | ., type, length?' /test.mp3 +mp3> .headers._description | ., type, length? "" "string" 0 -$ fq -d mp3 '.headers._path | ., type, length?' /test.mp3 +mp3> .headers._path | ., type, length? [ "headers" ] "array" 1 -$ fq -d mp3 '.headers._bits | ., type, length?' /test.mp3 +mp3> .headers._bits | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x00|49 44 33 04 00 00 00 00 00 23 54 53 53 45 00 00|ID3......#TSSE..| <360 bits> "buffer" 360 -$ fq -d mp3 '.headers._bytes | ., type, length?' /test.mp3 +mp3> .headers._bytes | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x00|49 44 33 04 00 00 00 00 00 23 54 53 53 45 00 00|ID3......#TSSE..| <45 bytes> "buffer" 45 -$ fq -d mp3 '.headers._error | ., type, length?' /test.mp3 +mp3> .headers._error | ., type, length? null "null" 0 -$ fq -d mp3 '.headers._unknown | ., type, length?' /test.mp3 +mp3> .headers._unknown | ., type, length? false "boolean" +mp3> .headers.a = 1 +error: cannot update key a for array +mp3> .headers[0] = 1 +error: cannot update key 0 for array +mp3> .headers.a |= empty +error: expected an object with key "a" but got: array +mp3> .headers[0] |= empty +error: cannot update key 0 for array +mp3> .headers | setpath(["a"]; 1) +error: cannot update key a for array +mp3> .headers | setpath([0]; 1) +error: cannot update key 0 for array +mp3> .headers | delpaths([["a"]]) +error: cannot update key a for array +mp3> .headers | delpaths([[0]]) +error: cannot update key 0 for array +mp3> ^D diff --git a/pkg/interp/testdata/value_boolean.fqtest b/pkg/interp/testdata/value_boolean.fqtest index ba11dd34..b20d4c77 100644 --- a/pkg/interp/testdata/value_boolean.fqtest +++ b/pkg/interp/testdata/value_boolean.fqtest @@ -1,106 +1,67 @@ /test.mp3: -# display -$ fq -d mp3 '.headers[0].flags.unsynchronisation | ., tovalue, type, length?' /test.mp3 +$ fq -i -d mp3 . /test.mp3 +mp3> .headers[0].flags.unsynchronisation | ., tovalue, type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0| 00 | . |.headers[0].flags.unsynchronisation: false false "boolean" -# index -$ fq -d mp3 '.headers[0].flags.unsynchronisation[0] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation[0] | ., type, length? error: expected an array but got: boolean -$ fq -d mp3 '.headers[0].flags.unsynchronisation[-1000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation[-1000] | ., type, length? error: expected an array but got: boolean -$ fq -d mp3 '.headers[0].flags.unsynchronisation[1000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation[1000] | ., type, length? error: expected an array but got: boolean -# slice -$ fq -d mp3 '.headers[0].flags.unsynchronisation[1:3] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation[1:3] | ., type, length? error: expected an array but got: boolean -$ fq -d mp3 '.headers[0].flags.unsynchronisation[0:-1] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation[0:-1] | ., type, length? error: expected an array but got: boolean -$ fq -d mp3 '.headers[0].flags.unsynchronisation[-1000:2000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation[-1000:2000] | ., type, length? error: expected an array but got: boolean -# key -$ fq -d mp3 '.headers[0].flags.unsynchronisation["test"] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation["test"] | ., type, length? error: expected an object but got: boolean -# each -$ fq -d mp3 '[.headers[0].flags.unsynchronisation[]] | type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> [.headers[0].flags.unsynchronisation[]] | type, length? error: cannot iterate over: boolean -# keys -$ fq -d mp3 '.headers[0].flags.unsynchronisation | keys' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation | keys error: keys cannot be applied to: boolean -# has -$ fq -d mp3 '.headers[0].flags.unsynchronisation | has("a")' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation | has("a") error: has cannot be applied to: boolean -$ fq -d mp3 '.headers[0].flags.unsynchronisation | has(0)' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation | has(0) error: has cannot be applied to: boolean -# type -$ fq -d mp3 '.headers[0].flags.unsynchronisation | type' /test.mp3 +mp3> .headers[0].flags.unsynchronisation | type "boolean" -# tonumber -$ fq -d mp3 '.headers[0].flags.unsynchronisation | tonumber' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation | tonumber error: tonumber cannot be applied to: boolean -# tostring -$ fq -d mp3 '.headers[0].flags.unsynchronisation | tostring' /test.mp3 +mp3> .headers[0].flags.unsynchronisation | tostring "false" -# to gojq -$ fq -d mp3 '.headers[0].flags.unsynchronisation + ""' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation + "" error: cannot add: boolean (false) and string ("") -$ fq -d mp3 '.headers[0].flags.unsynchronisation + 1' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags.unsynchronisation + 1 error: cannot add: boolean (false) and number (1) -# test _keys -$ fq -d mp3 '.headers[0].flags.unsynchronisation._start | ., type, length?' /test.mp3 +mp3> .headers[0].flags.unsynchronisation._start | ., type, length? 40 "number" 40 -$ fq -d mp3 '.headers[0].flags.unsynchronisation._stop | ., type, length?' /test.mp3 +mp3> .headers[0].flags.unsynchronisation._stop | ., type, length? 41 "number" 41 -$ fq -d mp3 '.headers[0].flags.unsynchronisation._len | ., type, length?' /test.mp3 +mp3> .headers[0].flags.unsynchronisation._len | ., type, length? 1 "number" 1 -$ fq -d mp3 '.headers[0].flags.unsynchronisation._name | ., type, length?' /test.mp3 +mp3> .headers[0].flags.unsynchronisation._name | ., type, length? "unsynchronisation" "string" 17 -$ fq -d mp3 '.headers[0].flags.unsynchronisation._symbol | ., type, length?' /test.mp3 +mp3> .headers[0].flags.unsynchronisation._symbol | ., type, length? "" "string" 0 -$ fq -d mp3 '.headers[0].flags.unsynchronisation._description | ., type, length?' /test.mp3 +mp3> .headers[0].flags.unsynchronisation._description | ., type, length? "" "string" 0 -$ fq -d mp3 '.headers[0].flags.unsynchronisation._path | ., type, length?' /test.mp3 +mp3> .headers[0].flags.unsynchronisation._path | ., type, length? [ "headers", 0, @@ -109,22 +70,39 @@ $ fq -d mp3 '.headers[0].flags.unsynchronisation._path | ., type, length?' /test ] "array" 4 -$ fq -d mp3 '.headers[0].flags.unsynchronisation._bits | ., type, length?' /test.mp3 +mp3> .headers[0].flags.unsynchronisation._bits | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0|00 |. | <1 bits> "buffer" 1 -$ fq -d mp3 '.headers[0].flags.unsynchronisation._bytes | ., type, length?' /test.mp3 +mp3> .headers[0].flags.unsynchronisation._bytes | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0|00 |. | <0 bytes> "buffer" 0 -$ fq -d mp3 '.headers[0].flags.unsynchronisation._error | ., type, length?' /test.mp3 +mp3> .headers[0].flags.unsynchronisation._error | ., type, length? null "null" 0 -$ fq -d mp3 '.headers[0].flags.unsynchronisation._unknown | ., type, length?' /test.mp3 +mp3> .headers[0].flags.unsynchronisation._unknown | ., type, length? false "boolean" +mp3> .headers[0].flags.unsynchronisation.a = 1 +error: expected an object but got: boolean +mp3> .headers[0].flags.unsynchronisation[0] = 1 +error: expected an array but got: boolean +mp3> .headers[0].flags.unsynchronisation.a |= empty +error: expected an object but got: boolean +mp3> .headers[0].flags.unsynchronisation[0] |= empty +error: expected an array but got: boolean +mp3> .headers[0].flags.unsynchronisation | setpath(["a"]; 1) +error: expected an object with key "a" but got: boolean +mp3> .headers[0].flags.unsynchronisation | setpath([0]; 1) +error: expected an array with index 0 but got: boolean +mp3> .headers[0].flags.unsynchronisation | delpaths([["a"]]) +error: expected an object with key "a" but got: boolean +mp3> .headers[0].flags.unsynchronisation | delpaths([[0]]) +error: expected an array with index 0 but got: boolean +mp3> ^D diff --git a/pkg/interp/testdata/value_json_array.fqtest b/pkg/interp/testdata/value_json_array.fqtest new file mode 100644 index 00000000..9bfe5de5 --- /dev/null +++ b/pkg/interp/testdata/value_json_array.fqtest @@ -0,0 +1,121 @@ +/test.mp3: +$ fq -i -n '"[]" | json' +json> (.) | ., tovalue, type, length? + |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | + | | |.: [0] unnamed (json) +[] +"array" +0 +json> (.)[0] | ., type, length? +null +"null" +0 +json> (.)[-1000] | ., type, length? +null +"null" +0 +json> (.)[1000] | ., type, length? +null +"null" +0 +json> (.)[1:3] | ., type, length? +[] +"array" +0 +json> (.)[0:-1] | ., type, length? +[] +"array" +0 +json> (.)[-1000:2000] | ., type, length? +[] +"array" +0 +json> (.)["test"] | ., type, length? +error: expected an object but got: array +json> [(.)[]] | type, length? +"array" +0 +json> (.) | keys +[] +json> (.) | has("a") +error: cannot check whether array has a key: a +json> (.) | has(0) +false +json> (.) | type +"array" +json> (.) | tonumber +error: tonumber cannot be applied to: array +json> (.) | tostring +error: tostring cannot be applied to: array +json> (.) + "" +error: cannot add: array ([]) and string ("") +json> (.) + 1 +error: cannot add: array ([]) and number (1) +json> (.)._start | ., type, length? +0 +"number" +0 +json> (.)._stop | ., type, length? +16 +"number" +16 +json> (.)._len | ., type, length? +16 +"number" +16 +json> (.)._name | ., type, length? +"" +"string" +0 +json> (.)._symbol | ., type, length? +"" +"string" +0 +json> (.)._description | ., type, length? +"unnamed" +"string" +7 +json> (.)._path | ., type, length? +[] +"array" +0 +json> (.)._bits | ., type, length? + |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | +0x0|5b 5d |[] | +<16 bits> +"buffer" +16 +json> (.)._bytes | ., type, length? + |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | +0x0|5b 5d |[] | +<2 bytes> +"buffer" +2 +json> (.)._error | ., type, length? +null +"null" +0 +json> (.)._unknown | ., type, length? +false +"boolean" +json> (.).a = 1 +error: expected an object but got: array +json> (.)[0] = 1 +[ + 1 +] +json> (.).a |= empty +error: expected an object but got: array +json> (.)[0] |= empty +[] +json> (.) | setpath(["a"]; 1) +error: cannot check whether array has a key: a +json> (.) | setpath([0]; 1) +[ + 1 +] +json> (.) | delpaths([["a"]]) +error: cannot check whether array has a key: a +json> (.) | delpaths([[0]]) +[] +json> ^D diff --git a/pkg/interp/testdata/value_json_object.fqtest b/pkg/interp/testdata/value_json_object.fqtest new file mode 100644 index 00000000..f5a5c149 --- /dev/null +++ b/pkg/interp/testdata/value_json_object.fqtest @@ -0,0 +1,111 @@ +/test.mp3: +$ fq -i -n '"{}" | json' +json> (.) | ., tovalue, type, length? + |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | + | | |.: {} unnamed (json) +{} +"object" +0 +json> (.)[0] | ., type, length? +error: expected an array but got: object +json> (.)[-1000] | ., type, length? +error: expected an array but got: object +json> (.)[1000] | ., type, length? +error: expected an array but got: object +json> (.)[1:3] | ., type, length? +error: expected an array but got: object +json> (.)[0:-1] | ., type, length? +error: expected an array but got: object +json> (.)[-1000:2000] | ., type, length? +error: expected an array but got: object +json> (.)["test"] | ., type, length? +null +"null" +0 +json> [(.)[]] | type, length? +"array" +0 +json> (.) | keys +[] +json> (.) | has("a") +false +json> (.) | has(0) +error: cannot check whether object has a key: 0 +json> (.) | type +"object" +json> (.) | tonumber +error: tonumber cannot be applied to: object +json> (.) | tostring +error: tostring cannot be applied to: object +json> (.) + "" +error: cannot add: object ({}) and string ("") +json> (.) + 1 +error: cannot add: object ({}) and number (1) +json> (.)._start | ., type, length? +0 +"number" +0 +json> (.)._stop | ., type, length? +16 +"number" +16 +json> (.)._len | ., type, length? +16 +"number" +16 +json> (.)._name | ., type, length? +"" +"string" +0 +json> (.)._symbol | ., type, length? +"" +"string" +0 +json> (.)._description | ., type, length? +"unnamed" +"string" +7 +json> (.)._path | ., type, length? +[] +"array" +0 +json> (.)._bits | ., type, length? + |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | +0x0|7b 7d |{} | +<16 bits> +"buffer" +16 +json> (.)._bytes | ., type, length? + |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | +0x0|7b 7d |{} | +<2 bytes> +"buffer" +2 +json> (.)._error | ., type, length? +null +"null" +0 +json> (.)._unknown | ., type, length? +false +"boolean" +json> (.).a = 1 +{ + "a": 1 +} +json> (.)[0] = 1 +error: expected an array but got: object +json> (.).a |= empty +{} +json> (.)[0] |= empty +error: expected an array but got: object +json> (.) | setpath(["a"]; 1) +{ + "a": 1 +} +json> (.) | setpath([0]; 1) +error: cannot check whether object has a key: 0 +json> (.) | delpaths([["a"]]) +{} +json> (.) | delpaths([[0]]) +error: cannot check whether object has a key: 0 +json> ^D diff --git a/pkg/interp/testdata/value_null.fqtest b/pkg/interp/testdata/value_null.fqtest index ee61a9ed..41c47dcc 100644 --- a/pkg/interp/testdata/value_null.fqtest +++ b/pkg/interp/testdata/value_null.fqtest @@ -1,103 +1,68 @@ /test.mp3: -# display -$ fq -d mp3 '.headers[0].padding | ., tovalue, type, length?' /test.mp3 +$ fq -i -d mp3 . /test.mp3 +mp3> .headers[0].padding | ., tovalue, type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x20| 00 00 00 00 00 00 00 00 00 00 | .......... |.headers[0].padding: Correct (none) (zero padding) null "null" 0 -# index -$ fq -d mp3 '.headers[0].padding[0] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].padding[0] | ., type, length? error: expected an array but got: null -$ fq -d mp3 '.headers[0].padding[-1000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].padding[-1000] | ., type, length? error: expected an array but got: null -$ fq -d mp3 '.headers[0].padding[1000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].padding[1000] | ., type, length? error: expected an array but got: null -# slice -$ fq -d mp3 '.headers[0].padding[1:3] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].padding[1:3] | ., type, length? error: expected an array but got: null -$ fq -d mp3 '.headers[0].padding[0:-1] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].padding[0:-1] | ., type, length? error: expected an array but got: null -$ fq -d mp3 '.headers[0].padding[-1000:2000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].padding[-1000:2000] | ., type, length? error: expected an array but got: null -# key -$ fq -d mp3 '.headers[0].padding["test"] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].padding["test"] | ., type, length? error: expected an object but got: null -# each -$ fq -d mp3 '[.headers[0].padding[]] | type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> [.headers[0].padding[]] | type, length? error: cannot iterate over: null -# keys -$ fq -d mp3 '.headers[0].padding | keys' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].padding | keys error: keys cannot be applied to: null -# has -$ fq -d mp3 '.headers[0].padding | has("a")' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].padding | has("a") error: has cannot be applied to: null -$ fq -d mp3 '.headers[0].padding | has(0)' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].padding | has(0) error: has cannot be applied to: null -# type -$ fq -d mp3 '.headers[0].padding | type' /test.mp3 +mp3> .headers[0].padding | type "null" -# tonumber -$ fq -d mp3 '.headers[0].padding | tonumber' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].padding | tonumber error: tonumber cannot be applied to: null -# tostring -$ fq -d mp3 '.headers[0].padding | tostring' /test.mp3 +mp3> .headers[0].padding | tostring "null" -# to gojq -$ fq -d mp3 '.headers[0].padding + ""' /test.mp3 +mp3> .headers[0].padding + "" "" -$ fq -d mp3 '.headers[0].padding + 1' /test.mp3 +mp3> .headers[0].padding + 1 1 -# test _keys -$ fq -d mp3 '.headers[0].padding._start | ., type, length?' /test.mp3 +mp3> .headers[0].padding._start | ., type, length? 280 "number" 280 -$ fq -d mp3 '.headers[0].padding._stop | ., type, length?' /test.mp3 +mp3> .headers[0].padding._stop | ., type, length? 360 "number" 360 -$ fq -d mp3 '.headers[0].padding._len | ., type, length?' /test.mp3 +mp3> .headers[0].padding._len | ., type, length? 80 "number" 80 -$ fq -d mp3 '.headers[0].padding._name | ., type, length?' /test.mp3 +mp3> .headers[0].padding._name | ., type, length? "padding" "string" 7 -$ fq -d mp3 '.headers[0].padding._symbol | ., type, length?' /test.mp3 +mp3> .headers[0].padding._symbol | ., type, length? "Correct" "string" 7 -$ fq -d mp3 '.headers[0].padding._description | ., type, length?' /test.mp3 +mp3> .headers[0].padding._description | ., type, length? "zero padding" "string" 12 -$ fq -d mp3 '.headers[0].padding._path | ., type, length?' /test.mp3 +mp3> .headers[0].padding._path | ., type, length? [ "headers", 0, @@ -105,22 +70,39 @@ $ fq -d mp3 '.headers[0].padding._path | ., type, length?' /test.mp3 ] "array" 3 -$ fq -d mp3 '.headers[0].padding._bits | ., type, length?' /test.mp3 +mp3> .headers[0].padding._bits | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0|00 00 00 00 00 00 00 00 00 00 |.......... | <80 bits> "buffer" 80 -$ fq -d mp3 '.headers[0].padding._bytes | ., type, length?' /test.mp3 +mp3> .headers[0].padding._bytes | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0|00 00 00 00 00 00 00 00 00 00 |.......... | <10 bytes> "buffer" 10 -$ fq -d mp3 '.headers[0].padding._error | ., type, length?' /test.mp3 +mp3> .headers[0].padding._error | ., type, length? null "null" 0 -$ fq -d mp3 '.headers[0].padding._unknown | ., type, length?' /test.mp3 +mp3> .headers[0].padding._unknown | ., type, length? false "boolean" +mp3> .headers[0].padding.a = 1 +error: expected an object but got: null +mp3> .headers[0].padding[0] = 1 +error: expected an array but got: null +mp3> .headers[0].padding.a |= empty +error: expected an object but got: null +mp3> .headers[0].padding[0] |= empty +error: expected an array but got: null +mp3> .headers[0].padding | setpath(["a"]; 1) +error: expected an object with key "a" but got: null +mp3> .headers[0].padding | setpath([0]; 1) +error: expected an array with index 0 but got: null +mp3> .headers[0].padding | delpaths([["a"]]) +error: expected an object with key "a" but got: null +mp3> .headers[0].padding | delpaths([[0]]) +error: expected an array with index 0 but got: null +mp3> ^D diff --git a/pkg/interp/testdata/value_number.fqtest b/pkg/interp/testdata/value_number.fqtest index 4f3cc17c..ecef7746 100644 --- a/pkg/interp/testdata/value_number.fqtest +++ b/pkg/interp/testdata/value_number.fqtest @@ -1,103 +1,68 @@ /test.mp3: -# display -$ fq -d mp3 '.headers[0].version | ., tovalue, type, length?' /test.mp3 +$ fq -i -d mp3 . /test.mp3 +mp3> .headers[0].version | ., tovalue, type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0| 04 | . |.headers[0].version: 4 4 "number" 4 -# index -$ fq -d mp3 '.headers[0].version[0] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].version[0] | ., type, length? error: expected an array but got: number -$ fq -d mp3 '.headers[0].version[-1000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].version[-1000] | ., type, length? error: expected an array but got: number -$ fq -d mp3 '.headers[0].version[1000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].version[1000] | ., type, length? error: expected an array but got: number -# slice -$ fq -d mp3 '.headers[0].version[1:3] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].version[1:3] | ., type, length? error: expected an array but got: number -$ fq -d mp3 '.headers[0].version[0:-1] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].version[0:-1] | ., type, length? error: expected an array but got: number -$ fq -d mp3 '.headers[0].version[-1000:2000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].version[-1000:2000] | ., type, length? error: expected an array but got: number -# key -$ fq -d mp3 '.headers[0].version["test"] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].version["test"] | ., type, length? error: expected an object but got: number -# each -$ fq -d mp3 '[.headers[0].version[]] | type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> [.headers[0].version[]] | type, length? error: cannot iterate over: number -# keys -$ fq -d mp3 '.headers[0].version | keys' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].version | keys error: keys cannot be applied to: number -# has -$ fq -d mp3 '.headers[0].version | has("a")' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].version | has("a") error: has cannot be applied to: number -$ fq -d mp3 '.headers[0].version | has(0)' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].version | has(0) error: has cannot be applied to: number -# type -$ fq -d mp3 '.headers[0].version | type' /test.mp3 +mp3> .headers[0].version | type "number" -# tonumber -$ fq -d mp3 '.headers[0].version | tonumber' /test.mp3 +mp3> .headers[0].version | tonumber 4 -# tostring -$ fq -d mp3 '.headers[0].version | tostring' /test.mp3 +mp3> .headers[0].version | tostring "4" -# to gojq -$ fq -d mp3 '.headers[0].version + ""' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].version + "" error: cannot add: number (4) and string ("") -$ fq -d mp3 '.headers[0].version + 1' /test.mp3 +mp3> .headers[0].version + 1 5 -# test _keys -$ fq -d mp3 '.headers[0].version._start | ., type, length?' /test.mp3 +mp3> .headers[0].version._start | ., type, length? 24 "number" 24 -$ fq -d mp3 '.headers[0].version._stop | ., type, length?' /test.mp3 +mp3> .headers[0].version._stop | ., type, length? 32 "number" 32 -$ fq -d mp3 '.headers[0].version._len | ., type, length?' /test.mp3 +mp3> .headers[0].version._len | ., type, length? 8 "number" 8 -$ fq -d mp3 '.headers[0].version._name | ., type, length?' /test.mp3 +mp3> .headers[0].version._name | ., type, length? "version" "string" 7 -$ fq -d mp3 '.headers[0].version._symbol | ., type, length?' /test.mp3 +mp3> .headers[0].version._symbol | ., type, length? "" "string" 0 -$ fq -d mp3 '.headers[0].version._description | ., type, length?' /test.mp3 +mp3> .headers[0].version._description | ., type, length? "" "string" 0 -$ fq -d mp3 '.headers[0].version._path | ., type, length?' /test.mp3 +mp3> .headers[0].version._path | ., type, length? [ "headers", 0, @@ -105,22 +70,39 @@ $ fq -d mp3 '.headers[0].version._path | ., type, length?' /test.mp3 ] "array" 3 -$ fq -d mp3 '.headers[0].version._bits | ., type, length?' /test.mp3 +mp3> .headers[0].version._bits | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0|04 |. | <8 bits> "buffer" 8 -$ fq -d mp3 '.headers[0].version._bytes | ., type, length?' /test.mp3 +mp3> .headers[0].version._bytes | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0|04 |. | <1 bytes> "buffer" 1 -$ fq -d mp3 '.headers[0].version._error | ., type, length?' /test.mp3 +mp3> .headers[0].version._error | ., type, length? null "null" 0 -$ fq -d mp3 '.headers[0].version._unknown | ., type, length?' /test.mp3 +mp3> .headers[0].version._unknown | ., type, length? false "boolean" +mp3> .headers[0].version.a = 1 +error: expected an object but got: number +mp3> .headers[0].version[0] = 1 +error: expected an array but got: number +mp3> .headers[0].version.a |= empty +error: expected an object but got: number +mp3> .headers[0].version[0] |= empty +error: expected an array but got: number +mp3> .headers[0].version | setpath(["a"]; 1) +error: expected an object with key "a" but got: number +mp3> .headers[0].version | setpath([0]; 1) +error: expected an array with index 0 but got: number +mp3> .headers[0].version | delpaths([["a"]]) +error: expected an object with key "a" but got: number +mp3> .headers[0].version | delpaths([[0]]) +error: expected an array with index 0 but got: number +mp3> ^D diff --git a/pkg/interp/testdata/value_object.fqtest b/pkg/interp/testdata/value_object.fqtest index c129c036..753974dd 100644 --- a/pkg/interp/testdata/value_object.fqtest +++ b/pkg/interp/testdata/value_object.fqtest @@ -1,6 +1,6 @@ /test.mp3: -# display -$ fq -d mp3 '.headers[0].flags | ., tovalue, type, length?' /test.mp3 +$ fq -i -d mp3 . /test.mp3 +mp3> .headers[0].flags | ., tovalue, type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| |.headers[0].flags: {} 0x0| 00 | . | unsynchronisation: false 0x0| 00 | . | extended_header: false @@ -14,104 +14,71 @@ $ fq -d mp3 '.headers[0].flags | ., tovalue, type, length?' /test.mp3 } "object" 4 -# index -$ fq -d mp3 '.headers[0].flags[0] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags[0] | ., type, length? error: expected an array with index 0 but got: object -$ fq -d mp3 '.headers[0].flags[-1000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags[-1000] | ., type, length? error: expected an array with index -2 but got: object -$ fq -d mp3 '.headers[0].flags[1000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags[1000] | ., type, length? error: expected an array with index -1 but got: object -# slice -$ fq -d mp3 '.headers[0].flags[1:3] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags[1:3] | ., type, length? error: expected an array but got: object -$ fq -d mp3 '.headers[0].flags[0:-1] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags[0:-1] | ., type, length? error: expected an array but got: object -$ fq -d mp3 '.headers[0].flags[-1000:2000] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags[-1000:2000] | ., type, length? error: expected an array but got: object -# key -$ fq -d mp3 '.headers[0].flags["test"] | ., type, length?' /test.mp3 +mp3> .headers[0].flags["test"] | ., type, length? null "null" 0 -# each -$ fq -d mp3 '[.headers[0].flags[]] | type, length?' /test.mp3 +mp3> [.headers[0].flags[]] | type, length? "array" 4 -# keys -$ fq -d mp3 '.headers[0].flags | keys' /test.mp3 +mp3> .headers[0].flags | keys [ "unsynchronisation", "extended_header", "experimental_indicator", "unused" ] -# has -$ fq -d mp3 '.headers[0].flags | has("a")' /test.mp3 +mp3> .headers[0].flags | has("a") false -$ fq -d mp3 '.headers[0].flags | has(0)' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags | has(0) error: cannot check whether object has a key: 0 -# type -$ fq -d mp3 '.headers[0].flags | type' /test.mp3 +mp3> .headers[0].flags | type "object" -# tonumber -$ fq -d mp3 '.headers[0].flags | tonumber' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags | tonumber error: tonumber cannot be applied to: object -# tostring -$ fq -d mp3 '.headers[0].flags | tostring' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags | tostring error: tostring cannot be applied to: object -# to gojq -$ fq -d mp3 '.headers[0].flags + ""' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags + "" error: cannot add: object ({"experimental_indicator" ...}) and string ("") -$ fq -d mp3 '.headers[0].flags + 1' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].flags + 1 error: cannot add: object ({"experimental_indicator" ...}) and number (1) -# test _keys -$ fq -d mp3 '.headers[0].flags._start | ., type, length?' /test.mp3 +mp3> .headers[0].flags._start | ., type, length? 40 "number" 40 -$ fq -d mp3 '.headers[0].flags._stop | ., type, length?' /test.mp3 +mp3> .headers[0].flags._stop | ., type, length? 48 "number" 48 -$ fq -d mp3 '.headers[0].flags._len | ., type, length?' /test.mp3 +mp3> .headers[0].flags._len | ., type, length? 8 "number" 8 -$ fq -d mp3 '.headers[0].flags._name | ., type, length?' /test.mp3 +mp3> .headers[0].flags._name | ., type, length? "flags" "string" 5 -$ fq -d mp3 '.headers[0].flags._symbol | ., type, length?' /test.mp3 +mp3> .headers[0].flags._symbol | ., type, length? "" "string" 0 -$ fq -d mp3 '.headers[0].flags._description | ., type, length?' /test.mp3 +mp3> .headers[0].flags._description | ., type, length? "" "string" 0 -$ fq -d mp3 '.headers[0].flags._path | ., type, length?' /test.mp3 +mp3> .headers[0].flags._path | ., type, length? [ "headers", 0, @@ -119,22 +86,39 @@ $ fq -d mp3 '.headers[0].flags._path | ., type, length?' /test.mp3 ] "array" 3 -$ fq -d mp3 '.headers[0].flags._bits | ., type, length?' /test.mp3 +mp3> .headers[0].flags._bits | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0|00 |. | <8 bits> "buffer" 8 -$ fq -d mp3 '.headers[0].flags._bytes | ., type, length?' /test.mp3 +mp3> .headers[0].flags._bytes | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0|00 |. | <1 bytes> "buffer" 1 -$ fq -d mp3 '.headers[0].flags._error | ., type, length?' /test.mp3 +mp3> .headers[0].flags._error | ., type, length? null "null" 0 -$ fq -d mp3 '.headers[0].flags._unknown | ., type, length?' /test.mp3 +mp3> .headers[0].flags._unknown | ., type, length? false "boolean" +mp3> .headers[0].flags.a = 1 +error: cannot update key a for object +mp3> .headers[0].flags[0] = 1 +error: expected an array with index 0 but got: object +mp3> .headers[0].flags.a |= empty +error: cannot update key a for object +mp3> .headers[0].flags[0] |= empty +error: expected an array with index 0 but got: object +mp3> .headers[0].flags | setpath(["a"]; 1) +error: cannot update key a for object +mp3> .headers[0].flags | setpath([0]; 1) +error: cannot update key 0 for object +mp3> .headers[0].flags | delpaths([["a"]]) +error: cannot update key a for object +mp3> .headers[0].flags | delpaths([[0]]) +error: cannot update key 0 for object +mp3> ^D diff --git a/pkg/interp/testdata/value_string.fqtest b/pkg/interp/testdata/value_string.fqtest index cad87d63..da5005b5 100644 --- a/pkg/interp/testdata/value_string.fqtest +++ b/pkg/interp/testdata/value_string.fqtest @@ -1,105 +1,80 @@ /test.mp3: -# display -$ fq -d mp3 '.headers[0].magic | ., tovalue, type, length?' /test.mp3 +$ fq -i -d mp3 . /test.mp3 +mp3> .headers[0].magic | ., tovalue, type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0|49 44 33 |ID3 |.headers[0].magic: "ID3" (Correct) "ID3" "string" 3 -# index -$ fq -d mp3 '.headers[0].magic[0] | ., type, length?' /test.mp3 +mp3> .headers[0].magic[0] | ., type, length? "I" "string" 1 -$ fq -d mp3 '.headers[0].magic[-1000] | ., type, length?' /test.mp3 +mp3> .headers[0].magic[-1000] | ., type, length? "" "string" 0 -$ fq -d mp3 '.headers[0].magic[1000] | ., type, length?' /test.mp3 +mp3> .headers[0].magic[1000] | ., type, length? "" "string" 0 -# slice -$ fq -d mp3 '.headers[0].magic[1:3] | ., type, length?' /test.mp3 +mp3> .headers[0].magic[1:3] | ., type, length? "D3" "string" 2 -$ fq -d mp3 '.headers[0].magic[0:-1] | ., type, length?' /test.mp3 +mp3> .headers[0].magic[0:-1] | ., type, length? "ID" "string" 2 -$ fq -d mp3 '.headers[0].magic[-1000:2000] | ., type, length?' /test.mp3 +mp3> .headers[0].magic[-1000:2000] | ., type, length? "ID3" "string" 3 -# key -$ fq -d mp3 '.headers[0].magic["test"] | ., type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].magic["test"] | ., type, length? error: expected an object but got: string -# each -$ fq -d mp3 '[.headers[0].magic[]] | type, length?' /test.mp3 -exitcode: 5 -stderr: +mp3> [.headers[0].magic[]] | type, length? error: cannot iterate over: string -# keys -$ fq -d mp3 '.headers[0].magic | keys' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].magic | keys error: keys cannot be applied to: string -# has -$ fq -d mp3 '.headers[0].magic | has("a")' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].magic | has("a") error: has cannot be applied to: string -$ fq -d mp3 '.headers[0].magic | has(0)' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].magic | has(0) error: has cannot be applied to: string -# type -$ fq -d mp3 '.headers[0].magic | type' /test.mp3 +mp3> .headers[0].magic | type "string" -# tonumber -$ fq -d mp3 '.headers[0].magic | tonumber' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].magic | tonumber error: invalid number: "ID3" -# tostring -$ fq -d mp3 '.headers[0].magic | tostring' /test.mp3 +mp3> .headers[0].magic | tostring "ID3" -# to gojq -$ fq -d mp3 '.headers[0].magic + ""' /test.mp3 +mp3> .headers[0].magic + "" "ID3" -$ fq -d mp3 '.headers[0].magic + 1' /test.mp3 -exitcode: 5 -stderr: +mp3> .headers[0].magic + 1 error: cannot add: string ("ID3") and number (1) -# test _keys -$ fq -d mp3 '.headers[0].magic._start | ., type, length?' /test.mp3 +mp3> .headers[0].magic._start | ., type, length? 0 "number" 0 -$ fq -d mp3 '.headers[0].magic._stop | ., type, length?' /test.mp3 +mp3> .headers[0].magic._stop | ., type, length? 24 "number" 24 -$ fq -d mp3 '.headers[0].magic._len | ., type, length?' /test.mp3 +mp3> .headers[0].magic._len | ., type, length? 24 "number" 24 -$ fq -d mp3 '.headers[0].magic._name | ., type, length?' /test.mp3 +mp3> .headers[0].magic._name | ., type, length? "magic" "string" 5 -$ fq -d mp3 '.headers[0].magic._symbol | ., type, length?' /test.mp3 +mp3> .headers[0].magic._symbol | ., type, length? "" "string" 0 -$ fq -d mp3 '.headers[0].magic._description | ., type, length?' /test.mp3 +mp3> .headers[0].magic._description | ., type, length? "Correct" "string" 7 -$ fq -d mp3 '.headers[0].magic._path | ., type, length?' /test.mp3 +mp3> .headers[0].magic._path | ., type, length? [ "headers", 0, @@ -107,22 +82,39 @@ $ fq -d mp3 '.headers[0].magic._path | ., type, length?' /test.mp3 ] "array" 3 -$ fq -d mp3 '.headers[0].magic._bits | ., type, length?' /test.mp3 +mp3> .headers[0].magic._bits | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0|49 44 33 |ID3 | <24 bits> "buffer" 24 -$ fq -d mp3 '.headers[0].magic._bytes | ., type, length?' /test.mp3 +mp3> .headers[0].magic._bytes | ., type, length? |00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f| | 0x0|49 44 33 |ID3 | <3 bytes> "buffer" 3 -$ fq -d mp3 '.headers[0].magic._error | ., type, length?' /test.mp3 +mp3> .headers[0].magic._error | ., type, length? null "null" 0 -$ fq -d mp3 '.headers[0].magic._unknown | ., type, length?' /test.mp3 +mp3> .headers[0].magic._unknown | ., type, length? false "boolean" +mp3> .headers[0].magic.a = 1 +error: expected an object but got: string +mp3> .headers[0].magic[0] = 1 +error: expected an array with index 0 but got: string +mp3> .headers[0].magic.a |= empty +error: expected an object but got: string +mp3> .headers[0].magic[0] |= empty +error: expected an array with index 0 but got: string +mp3> .headers[0].magic | setpath(["a"]; 1) +error: expected an object with key "a" but got: string +mp3> .headers[0].magic | setpath([0]; 1) +error: expected an array with index 0 but got: string +mp3> .headers[0].magic | delpaths([["a"]]) +error: expected an object with key "a" but got: string +mp3> .headers[0].magic | delpaths([[0]]) +error: expected an array with index 0 but got: string +mp3> ^D diff --git a/pkg/interp/testdata/value_t.fqtest.tmpl b/pkg/interp/testdata/value_t.fqtest.tmpl new file mode 100644 index 00000000..5259f3c1 --- /dev/null +++ b/pkg/interp/testdata/value_t.fqtest.tmpl @@ -0,0 +1,39 @@ +/test.mp3: +$ CMD +PROMPT> EXPR | ., tovalue, type, length? +PROMPT> EXPR[0] | ., type, length? +PROMPT> EXPR[-1000] | ., type, length? +PROMPT> EXPR[1000] | ., type, length? +PROMPT> EXPR[1:3] | ., type, length? +PROMPT> EXPR[0:-1] | ., type, length? +PROMPT> EXPR[-1000:2000] | ., type, length? +PROMPT> EXPR["test"] | ., type, length? +PROMPT> [EXPR[]] | type, length? +PROMPT> EXPR | keys +PROMPT> EXPR | has("a") +PROMPT> EXPR | has(0) +PROMPT> EXPR | type +PROMPT> EXPR | tonumber +PROMPT> EXPR | tostring +PROMPT> EXPR + "" +PROMPT> EXPR + 1 +PROMPT> EXPR._start | ., type, length? +PROMPT> EXPR._stop | ., type, length? +PROMPT> EXPR._len | ., type, length? +PROMPT> EXPR._name | ., type, length? +PROMPT> EXPR._symbol | ., type, length? +PROMPT> EXPR._description | ., type, length? +PROMPT> EXPR._path | ., type, length? +PROMPT> EXPR._bits | ., type, length? +PROMPT> EXPR._bytes | ., type, length? +PROMPT> EXPR._error | ., type, length? +PROMPT> EXPR._unknown | ., type, length? +PROMPT> EXPR.a = 1 +PROMPT> EXPR[0] = 1 +PROMPT> EXPR.a |= empty +PROMPT> EXPR[0] |= empty +PROMPT> EXPR | setpath(["a"]; 1) +PROMPT> EXPR | setpath([0]; 1) +PROMPT> EXPR | delpaths([["a"]]) +PROMPT> EXPR | delpaths([[0]]) +PROMPT> ^D \ No newline at end of file diff --git a/pkg/interp/testdata/value_t.fqtest.tmpl.sh b/pkg/interp/testdata/value_t.fqtest.tmpl.sh new file mode 100644 index 00000000..f18c63f2 --- /dev/null +++ b/pkg/interp/testdata/value_t.fqtest.tmpl.sh @@ -0,0 +1,10 @@ +#!/bin/sh +sed 's/CMD/fq -i -d mp3 . \/test.mp3/g' value_array.fqtest +sed 's/CMD/fq -i -d mp3 . \/test.mp3/g' value_boolean.fqtest +sed 's/CMD/fq -i -d mp3 . \/test.mp3/g' value_null.fqtest +sed 's/CMD/fq -i -d mp3 . \/test.mp3/g' value_number.fqtest +sed 's/CMD/fq -i -d mp3 . \/test.mp3/g' value_object.fqtest +sed 's/CMD/fq -i -d mp3 . \/test.mp3/g' value_string.fqtest + +sed "s/CMD/fq -i -n '\"[]\" | json'/g" value_json_array.fqtest +sed "s/CMD/fq -i -n '\"{}\" | json'/g" value_json_object.fqtest diff --git a/pkg/interp/testdata/value_type.fqtest.tmpl b/pkg/interp/testdata/value_type.fqtest.tmpl deleted file mode 100644 index b13c2790..00000000 --- a/pkg/interp/testdata/value_type.fqtest.tmpl +++ /dev/null @@ -1,41 +0,0 @@ -/test.mp3: -# display -> fq -d mp3 'EXPR | ., tovalue, type, length?' /test.mp3 -# index -> fq -d mp3 'EXPR[0] | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR[-1000] | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR[1000] | ., type, length?' /test.mp3 -# slice -> fq -d mp3 'EXPR[1:3] | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR[0:-1] | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR[-1000:2000] | ., type, length?' /test.mp3 -# key -> fq -d mp3 'EXPR["test"] | ., type, length?' /test.mp3 -# each -> fq -d mp3 '[EXPR[]] | type, length?' /test.mp3 -# keys -> fq -d mp3 'EXPR | keys' /test.mp3 -# has -> fq -d mp3 'EXPR | has("a")' /test.mp3 -> fq -d mp3 'EXPR | has(0)' /test.mp3 -# type -> fq -d mp3 'EXPR | type' /test.mp3 -# tonumber -> fq -d mp3 'EXPR | tonumber' /test.mp3 -# tostring -> fq -d mp3 'EXPR | tostring' /test.mp3 -# to gojq -> fq -d mp3 'EXPR + ""' /test.mp3 -> fq -d mp3 'EXPR + 1' /test.mp3 -# test _keys -> fq -d mp3 'EXPR._start | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR._stop | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR._len | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR._name | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR._symbol | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR._description | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR._path | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR._bits | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR._bytes | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR._error | ., type, length?' /test.mp3 -> fq -d mp3 'EXPR._unknown | ., type, length?' /test.mp3 diff --git a/pkg/interp/value.go b/pkg/interp/value.go index 6ce2aca1..b3d3f8c0 100644 --- a/pkg/interp/value.go +++ b/pkg/interp/value.go @@ -22,6 +22,15 @@ func (err expectedExtkeyError) Error() string { return "expected a extkey but got: " + err.Key } +type notUpdateableError struct { + Typ string + Key string +} + +func (err notUpdateableError) Error() string { + return fmt.Sprintf("cannot update key %s for %s", err.Key, err.Typ) +} + // TODO: rename type valueIf interface { InterpValue @@ -249,6 +258,9 @@ func (v bufferDecodeValue) JQValueSlice(start int, end int) interface{} { } return b.String() } +func (v bufferDecodeValue) JQValueUpdate(key interface{}, u interface{}, delpath bool) interface{} { + return notUpdateableError{Key: fmt.Sprintf("%v", key), Typ: "string"} +} func (v bufferDecodeValue) JQValueToNumber() interface{} { s, ok := v.JQValueToString().(string) if ok { @@ -307,6 +319,9 @@ func (v arrayDecodeValue) JQValueSlice(start int, end int) interface{} { } return vs } +func (v arrayDecodeValue) JQValueUpdate(key interface{}, u interface{}, delpath bool) interface{} { + return notUpdateableError{Key: fmt.Sprintf("%v", key), Typ: "array"} +} func (v arrayDecodeValue) JQValueEach() interface{} { props := make([]gojq.PathValue, len(v.Array)) for i, f := range v.Array { @@ -368,6 +383,9 @@ func (v structDecodeValue) JQValueKey(name string) interface{} { } return nil } +func (v structDecodeValue) JQValueUpdate(key interface{}, u interface{}, delpath bool) interface{} { + return notUpdateableError{Key: fmt.Sprintf("%v", key), Typ: "object"} +} func (v structDecodeValue) JQValueEach() interface{} { props := make([]gojq.PathValue, len(v.Struct)) for i, f := range v.Struct {