diff --git a/cmd/codemetagenerator/edit.go b/cmd/codemetagenerator/edit.go index 49d79b3..e2121ce 100644 --- a/cmd/codemetagenerator/edit.go +++ b/cmd/codemetagenerator/edit.go @@ -45,7 +45,7 @@ codemetagenerator edit 'name' 'My New Name' This will update the 'name' property to 'My New Name'. To edit a nested property, use dot notation. For example, to edit the 'email' property of the 'maitainer' object, run: -codemetagenerator edit 'maintainer.email' +codemetagenerator edit 'maintainer.email' 'newemail@updated.org' This will update the 'email' property of the 'maintainer' object to 'My New Email'. To edit a nested array property, use a bracket index with dot notation. For example, edit the diff --git a/go.mod b/go.mod index fb9ef4c..189e361 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,8 @@ go 1.21.6 require ( github.com/nexidian/gocliselect v1.0.0 + github.com/ohler55/ojg v1.21.0 + github.com/onsi/gomega v1.31.1 github.com/samber/lo v1.39.0 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 @@ -13,6 +15,7 @@ require ( require ( github.com/buger/goterm v1.0.3 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/magiconair/properties v1.8.7 // indirect @@ -28,6 +31,7 @@ require ( github.com/subosito/gotenv v1.6.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect + golang.org/x/net v0.19.0 // indirect golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index d2f2ec9..b70c8b5 100644 --- a/go.sum +++ b/go.sum @@ -9,8 +9,14 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -25,6 +31,12 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/nexidian/gocliselect v1.0.0 h1:BTxqUqqhwc/O3jJrPuvpF359FjQag7EYgwdEF9cYY+w= github.com/nexidian/gocliselect v1.0.0/go.mod h1:xyHtRO0Au/S+4tsEooDEj5+VZtkk+RU6RRs7q4o5TmI= +github.com/ohler55/ojg v1.21.0 h1:niqSS6yl3PQZJrqh7pKs/zinl4HebGe8urXEfpvlpYY= +github.com/ohler55/ojg v1.21.0/go.mod h1:gQhDVpQLqrmnd2eqGAvJtn+NfKoYJbe/A4Sj3/Vro4o= +github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= +github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo= +github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/term v1.1.0 h1:xIAAdCMh3QIAy+5FrE8Ad8XoDhEU4ufwbaSozViP9kk= @@ -69,12 +81,16 @@ go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/utils.go b/internal/utils.go index f75a02a..87da0f7 100644 --- a/internal/utils.go +++ b/internal/utils.go @@ -2,7 +2,6 @@ package internal import ( "bufio" - "encoding/json" "errors" "fmt" "io" @@ -13,6 +12,8 @@ import ( "strings" "time" + "github.com/ohler55/ojg/oj" + "github.com/nexidian/gocliselect" "github.com/samber/lo" "github.com/spf13/cobra" @@ -62,14 +63,14 @@ func LoadInProgressCodeMetaFile() (*map[string]any, error) { return nil, err } var codemeta map[string]any - json.Unmarshal(bytes, &codemeta) + oj.Unmarshal(bytes, &codemeta) return &codemeta, nil } } func SaveInProgressCodeMetaFile(codemeta *map[string]interface{}) error { homeDir := UserHomeDir - file, err := json.MarshalIndent(codemeta, "", " ") + file, err := oj.Marshal(*codemeta, 80.2) if err != nil { return err } @@ -378,14 +379,14 @@ func GetAndCacheLicenseFile(overwrite bool) error { return err } var licensesList LicensesList - json.Unmarshal(bytes, &licensesList) + oj.Unmarshal(bytes, &licensesList) var licensesMap map[string]string = make(map[string]string) lo.ForEach(licensesList.Licenses, func(license LicenseStruct, _ int) { licensesMap[license.LicenseId] = license.Reference }) - json, err := json.MarshalIndent(licensesMap, "", " ") + json, err := oj.Marshal(licensesMap, 80.2) if err != nil { return err } @@ -452,7 +453,7 @@ func loadLicenseFile() (*map[string]string, error) { return nil, err } var licenses map[string]string - json.Unmarshal(bytes, &licenses) + oj.Unmarshal(bytes, &licenses) return &licenses, nil } diff --git a/internal/utils_test.go b/internal/utils_test.go index de42b3a..5faab14 100644 --- a/internal/utils_test.go +++ b/internal/utils_test.go @@ -3,10 +3,13 @@ package internal import ( "testing" - "encoding/json" + "github.com/ohler55/ojg/oj" + "github.com/onsi/gomega" ) func TestUpdateMapValue(t *testing.T) { + g := gomega.NewWithT(t) + // Initialize a testMap var testMap map[string]any text := `{ @@ -28,9 +31,9 @@ func TestUpdateMapValue(t *testing.T) { } } }` - jsonErr := json.Unmarshal([]byte(text), &testMap) - if jsonErr != nil { - t.Errorf("Marshal of JSON text to object returned an error: %v", jsonErr) + ojErr := oj.Unmarshal([]byte(text), &testMap) + if ojErr != nil { + t.Errorf("Marshal of oj text to object returned an error: %v", ojErr) } // update nested key @@ -72,21 +75,12 @@ func TestUpdateMapValue(t *testing.T) { t.Errorf("UpdateMapValue did not return an error when it should have") } - // Check the state of the testMap - expected := `{"key1":[{"key2":30},{"key4":4}],"key3":["four","two"],"key5":"goodbye","key6":{"key7":"seven","key8":8,"key9":{"key10":[1,2,30],"key11":{"key12":"twenty-twelve"},"key13":"world"}}}` - - // Convert the testMap to a string - b, err := json.Marshal(testMap) - if err != nil { - t.Errorf("Marshal returned an error: %v", err) - } - actual := string(b) - if actual != expected { - t.Errorf("Final map state comparison failed, got: %v, want: %v.", actual, expected) - } + compare(g, testMap, `{"key1":[{"key2":30},{"key4":4}],"key3":["four","two"],"key5":"goodbye","key6":{"key7":"seven","key8":8,"key9":{"key10":[1,2,30],"key11":{"key12":"twenty-twelve"},"key13":"world"}}}`) } func TestInsertMapValue(t *testing.T) { + g := gomega.NewWithT(t) + // Initialize a testMap var testMap map[string]any text := `{ @@ -108,9 +102,9 @@ func TestInsertMapValue(t *testing.T) { } } }` - jsonErr := json.Unmarshal([]byte(text), &testMap) - if jsonErr != nil { - t.Errorf("Marshal of JSON text to object returned an error: %v", jsonErr) + ojErr := oj.Unmarshal([]byte(text), &testMap) + if ojErr != nil { + t.Errorf("Marshal of oj text to object returned an error: %v", ojErr) } err1 := InsertMapValue(testMap, "key1[0].key3", 3) @@ -151,20 +145,12 @@ func TestInsertMapValue(t *testing.T) { t.Errorf("InsertMapValue did not return an error when it should have") } - // Check the state of the testMap - expected := `{"key1":[{"key2":2,"key3":3},{"key14":14,"key4":4}],"key3":["one","two"],"key5":"hello","key6":{"key7":"seven","key8":8,"key9":{"key10":[1,2,3],"key11":{"key12":"twelve","key23":"twenty-three"},"key13":"world"}}}` - // Convert the testMap to a string - b, err := json.Marshal(testMap) - if err != nil { - t.Errorf("Marshal returned an error: %v", err) - } - actual := string(b) - if actual != expected { - t.Errorf("Final map state comparison failed, got: %v, want: %v.", actual, expected) - } + compare(g, testMap, `{"key1":[{"key2":2,"key3":3},{"key14":14,"key4":4}],"key3":["one","two"],"key5":"hello","key6":{"key7":"seven","key8":8,"key9":{"key10":[1,2,3],"key11":{"key12":"twelve","key23":"twenty-three"},"key13":"world"}}}`) } func TestRemoveMapValue(t *testing.T) { + g := gomega.NewWithT(t) + // Initialize a testMap var testMap map[string]any text := `{ @@ -186,9 +172,9 @@ func TestRemoveMapValue(t *testing.T) { } } }` - jsonErr := json.Unmarshal([]byte(text), &testMap) - if jsonErr != nil { - t.Errorf("Marshal of JSON text to object returned an error: %v", jsonErr) + ojErr := oj.Unmarshal([]byte(text), &testMap) + if ojErr != nil { + t.Errorf("Marshal of oj text to object returned an error: %v", ojErr) } err1 := RemoveMapValue(testMap, "key1[0].key2") // removes "key2": 2 -> [{}, {"key4": 4}] @@ -224,15 +210,17 @@ func TestRemoveMapValue(t *testing.T) { t.Errorf("RemoveMapValue returned an error: %v", err8) } - // Check the state of the testMap - expected := `{"key1":[],"key3":["one","two"],"key5":"hello","key6":{"key7":"seven","key8":8,"key9":{"key11":{"key12":"twelve"}}}}` - // Convert the testMap to a string - b, err := json.Marshal(testMap) - if err != nil { - t.Errorf("Marshal returned an error: %v", err) - } - actual := string(b) - if actual != expected { - t.Errorf("Final map state comparison failed, got: %v, want: %v.", actual, expected) - } + compare(g, testMap, `{"key1":[],"key3":["one","two"],"key5":"hello","key6":{"key7":"seven","key8":8,"key9":{"key11":{"key12":"twelve"}}}}`) +} + +func compare(g *gomega.WithT, actualMap map[string]any, expectedStr string) { + var actual map[string]any = make(map[string]any) + // Need to bounce through the oj parser for the testMap to ensure same types are used for added fields + actualStr := oj.JSON(actualMap) + oj.Unmarshal([]byte(actualStr), &actual) + + var expectedMap map[string]any = make(map[string]any) + oj.Unmarshal([]byte(expectedStr), &expectedMap) + + g.Ω(actual).Should(gomega.Equal(expectedMap)) }