Skip to content

Commit

Permalink
feat: Added support for JSON and TOML conversions to the Go lib.
Browse files Browse the repository at this point in the history
  • Loading branch information
skyzyx committed Nov 12, 2024
1 parent 64cf4ef commit b3d1b1a
Show file tree
Hide file tree
Showing 20 changed files with 749 additions and 111 deletions.
3 changes: 2 additions & 1 deletion .ecrc
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@
"min\\.css$",
"min\\.js$",
"package-lock\\.json$",
"standard\\.mk$"
"standard\\.mk$",
"testfixtures/.*$"
],
"IgnoreDefaults": true,
"NoColor": false,
Expand Down
20 changes: 20 additions & 0 deletions .taplo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[formatting]
align_comments = false
align_entries = false
allowed_blank_lines = 1
array_auto_collapse = true
array_auto_expand = true
array_trailing_comma = true
column_width = 120
compact_arrays = false
compact_entries = false
compact_inline_tables = false
crlf = false
indent_entries = true
indent_string = " "
indent_tables = true
inline_table_expand = false
reorder_arrays = false
reorder_inline_tables = false
reorder_keys = false
trailing_newline = true
59 changes: 59 additions & 0 deletions cmd/json2toml.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2023-2024, Northwood Labs
// Copyright 2023-2024, Ryan Parman <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd // lint:no_dupe

import (
"fmt"
"os"

"github.com/spf13/cobra"

clihelpers "github.com/northwood-labs/cli-helpers"
"github.com/northwood-labs/terraform-provider-corefunc/corefunc"
)

// json2tomlCmd represents the json2toml command
var json2tomlCmd = &cobra.Command{
Use: "json2toml",
Short: "Converts JSON to TOML.",
Long: clihelpers.LongHelpText(`
Converts JSON to TOML.
`),
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
fmt.Println("Re-run with --help to see options.")
os.Exit(1)
}

fString, err := corefunc.File(args[0])
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}

output, err := corefunc.JSONtoTOML(fString)
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}

fmt.Println(output)
},
}

func init() { // lint:allow_init
rootCmd.AddCommand(json2tomlCmd)
}
39 changes: 20 additions & 19 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

"github.com/hashicorp/terraform-plugin-framework/providerserver"

clihelpers "github.com/northwood-labs/cli-helpers"
"github.com/northwood-labs/terraform-provider-corefunc/corefuncprovider"
)

Expand All @@ -34,30 +35,30 @@ var (
rootCmd = &cobra.Command{
Use: "terraform-provider-corefunc",
Short: "Utilities that should have been Terraform core functions.",
Long: `--------------------------------------------------------------------------------
terraform-provider-corefunc
Long: clihelpers.LongHelpText(`
terraform-provider-corefunc
Utilities that should have been Terraform core functions.
Utilities that should have been Terraform core functions.
While some of these *can* be implemented in HCL, some of them begin to push up
against the limits of Terraform and the HCL2 configuration language. We also
perform testing using the Terratest <https://terratest.gruntwork.io> framework
on a regular basis. Exposing these functions as both a Go library as well as a
Terraform provider enables us to use the same functionality in both our
Terraform applies as well as while using a testing framework.
While some of these *can* be implemented in HCL, some of them begin to push up
against the limits of Terraform and the HCL2 configuration language. We also
perform testing using the Terratest <https://terratest.gruntwork.io> framework
on a regular basis. Exposing these functions as both a Go library as well as a
Terraform provider enables us to use the same functionality in both our
Terraform applies as well as while using a testing framework.
Since Terraform doesn't have the concept of user-defined functions, the next
step to open up the possibilities is to write a custom Terraform Provider which
has the functions built-in, using Terraform's existing support for inputs and
outputs.
Since Terraform doesn't have the concept of user-defined functions, the next
step to open up the possibilities is to write a custom Terraform Provider which
has the functions built-in, using Terraform's existing support for inputs and
outputs.
**This does not add new syntax or constructs to Terraform.** Instead it uses the
existing concepts around Providers, Resources, Data Sources, Variables, and
Outputs to expose new custom-built functionality.
**This does not add new syntax or constructs to Terraform.** Instead it uses the
existing concepts around Providers, Resources, Data Sources, Variables, and
Outputs to expose new custom-built functionality.
The goal of this provider is not to call any APIs, but to provide pre-built
functions in the form of Data Sources.
--------------------------------------------------------------------------------`,
The goal of this provider is not to call any APIs, but to provide pre-built
functions in the form of Data Sources.
`),
Run: func(cmd *cobra.Command, args []string) {
err := providerserver.Serve(context.Background(), corefuncprovider.New, providerserver.ServeOpts{
Address: "registry.terraform.io/northwood-labs/corefunc",
Expand Down
59 changes: 59 additions & 0 deletions cmd/toml2json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2023-2024, Northwood Labs
// Copyright 2023-2024, Ryan Parman <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd // lint:no_dupe

import (
"fmt"
"os"

"github.com/spf13/cobra"

clihelpers "github.com/northwood-labs/cli-helpers"
"github.com/northwood-labs/terraform-provider-corefunc/corefunc"
)

// toml2jsonCmd represents the toml2json command
var toml2jsonCmd = &cobra.Command{
Use: "toml2json",
Short: "Converts TOML to JSON.",
Long: clihelpers.LongHelpText(`
Converts TOML to JSON.
`),
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 1 {
fmt.Println("Re-run with --help to see options.")
os.Exit(1)
}

fString, err := corefunc.File(args[0])
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}

output, err := corefunc.TOMLtoJSON(fString)
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}

fmt.Println(output)
},
}

func init() { // lint:allow_init
rootCmd.AddCommand(toml2jsonCmd)
}
48 changes: 48 additions & 0 deletions corefunc/file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2023-2024, Northwood Labs
// Copyright 2023-2024, Ryan Parman <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package corefunc

import (
"fmt"
"io"
"os"
)

/*
File reads the contents of a file and returns it as a string. It is meant to
simulate the behavior of the `file()` function in Terraform/OpenTofu.
----
- path (string): A file name path to read.
*/
func File(path string) (string, error) {
r, err := os.OpenFile(path, os.O_RDONLY, 0o644) // lint:allow_possible_insecure lint:allow_raw_number
if err != nil {
return "", fmt.Errorf("failed to open file: %w", err)
}

b, err := io.ReadAll(r)
if err != nil {
return "", fmt.Errorf("failed to read the file: %w", err)
}

if err := r.Close(); err != nil {
return "", fmt.Errorf("failed to close file: %w", err)
}

return string(b), nil
}
104 changes: 104 additions & 0 deletions corefunc/toml.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright 2023-2024, Northwood Labs
// Copyright 2023-2024, Ryan Parman <[email protected]>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package corefunc

import (
"bytes"
"encoding/json"
"errors"
"fmt"
"strings"

"github.com/pelletier/go-toml/v2"
)

/*
TOMLtoJSON converts a TOML string to a JSON string. The result can be passed to
`json.Unmarshal()` to convert it to a `map[string]any`.
Ported from `pelletier/go-toml`.
<https://pkg.go.dev/github.com/pelletier/go-toml/v2>
----
- tomlStr (string): A string of TOML content.
*/
func TOMLtoJSON(tomlStr string) (string, error) {
var (
v any
w bytes.Buffer
)

tomlDecoder := toml.NewDecoder(strings.NewReader(tomlStr))

err := tomlDecoder.Decode(&v)
if err != nil {
var derr *toml.DecodeError
if errors.As(err, &derr) {
row, col := derr.Position()

return "", fmt.Errorf("error occurred at row %d column %d: %s", row, col, derr.String())
}

return "", fmt.Errorf("failed to decode TOML: %w", err)
}

jsonEncoder := json.NewEncoder(&w)

err = jsonEncoder.Encode(v)
if err != nil {
return "", fmt.Errorf("failed to encode to JSON: %w", err)
}

return w.String(), nil
}

/*
JSONtoTOML converts a JSON string to a TOML string. The result can be passed to
`toml.Unmarshal()` to convert it to a `map[string]any`.
Ported from `pelletier/go-toml`.
<https://pkg.go.dev/github.com/pelletier/go-toml/v2>
----
- jsonStr (string): A string of JSON content.
*/
func JSONtoTOML(jsonStr string) (string, error) {
var (
v any
w bytes.Buffer
)

jsonDecoder := json.NewDecoder(strings.NewReader(jsonStr))
tomlEncoder := toml.NewEncoder(&w)

jsonDecoder.UseNumber()
tomlEncoder.SetMarshalJsonNumbers(true)

err := jsonDecoder.Decode(&v)
if err != nil {
return "", fmt.Errorf("failed to decode to JSON: %w", err)
}

if err = tomlEncoder.Encode(v); err != nil {
return "", fmt.Errorf("failed to encode to TOML: %w", err)
}

return w.String() + "\n", nil
}
Loading

0 comments on commit b3d1b1a

Please sign in to comment.