Skip to content

Commit

Permalink
Export functions as JSON via cli command
Browse files Browse the repository at this point in the history
  • Loading branch information
dbanck committed Jan 16, 2023
1 parent d63e319 commit b1b8df7
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 0 deletions.
75 changes: 75 additions & 0 deletions internal/command/jsonfunction/function.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package jsonfunction

import (
"encoding/json"

"github.com/zclconf/go-cty/cty/function"
)

// FormatVersion represents the version of the json format and will be
// incremented for any change to this format that requires changes to a
// consuming parser.
const FormatVersion = "1.0"

// functions is the top-level object returned when exporting function signatures
type functions struct {
FormatVersion string `json:"format_version"`
Signatures map[string]*FunctionSignature `json:"function_signatures,omitempty"`
}

// FunctionSignature represents a function signature.
type FunctionSignature struct {
// Description is an optional human-readable description
// of the function
Description string `json:"description,omitempty"`

// ReturnTypes is the ctyjson representation of the function's
// return types based on supplying all parameters using
// dynamic types. Functions can have dynamic return types.
ReturnType string `json:"return_type"`

// Parameters describes the function's fixed positional parameters.
Parameters []*parameter `json:"parameters,omitempty"`

// VariadicParameter describes the function's variadic
// parameters, if any are supported.
VariadicParameter *parameter `json:"variadic_parameter,omitempty"`
}

func newFunctions() *functions {
signatures := make(map[string]*FunctionSignature)
return &functions{
FormatVersion: FormatVersion,
Signatures: signatures,
}
}

func Marshal(f map[string]function.Function) ([]byte, error) {
signatures := newFunctions()

for k, v := range f {
signatures.Signatures[k] = marshalFunction(v)
}

ret, err := json.Marshal(signatures)
return ret, err
}

func marshalFunction(f function.Function) *FunctionSignature {
var vp *parameter
if f.VarParam() != nil {
vp = marshalParameter(f.VarParam())
}

var p []*parameter
if len(f.Params()) > 0 {
p = marshalParameters(f.Params())
}

return &FunctionSignature{
Description: f.Description(),
ReturnType: getReturnType(f),
Parameters: p,
VariadicParameter: vp,
}
}
42 changes: 42 additions & 0 deletions internal/command/jsonfunction/parameter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package jsonfunction

import (
"github.com/zclconf/go-cty/cty/function"
)

// parameter represents a parameter to a function.
type parameter struct {
// Name is an optional name for the argument.
Name string `json:"name,omitempty"`

// Description is an optional human-readable description
// of the argument
Description string `json:"description,omitempty"`

// IsNullable is true if null is acceptable value for the argument
IsNullable bool `json:"is_nullable"`

// A type that any argument for this parameter must conform to.
Type string `json:"type"`
}

func marshalParameter(p *function.Parameter) *parameter {
if p == nil {
return &parameter{}
}

return &parameter{
Name: p.Name,
Description: p.Description,
IsNullable: p.AllowNull,
Type: p.Type.FriendlyName(),
}
}

func marshalParameters(parameters []function.Parameter) []*parameter {
ret := make([]*parameter, len(parameters))
for k, p := range parameters {
ret[k] = marshalParameter(&p)
}
return ret
}
22 changes: 22 additions & 0 deletions internal/command/jsonfunction/return_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package jsonfunction

import (
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
)

func getReturnType(f function.Function) string {
args := make([]cty.Type, 0)
for _, param := range f.Params() {
args = append(args, param.Type)
}
if f.VarParam() != nil {
args = append(args, f.VarParam().Type)
}

returnType, err := f.ReturnType(args)
if err != nil {
return "" // TODO? handle error
}
return returnType.FriendlyName()
}
15 changes: 15 additions & 0 deletions internal/command/metadata_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package command

import (
"fmt"

"github.com/hashicorp/terraform/internal/command/jsonfunction"
"github.com/hashicorp/terraform/internal/lang"
)

// MetadataFunctionsCommand is a Command implementation that prints out information
Expand Down Expand Up @@ -37,6 +40,18 @@ func (c *MetadataFunctionsCommand) Run(args []string) int {
return 1
}

scope := &lang.Scope{
ConsoleMode: true,
BaseDir: ".", // TODO? might be omitted
}
funcs := scope.Functions()
jsonFunctions, err := jsonfunction.Marshal(funcs)
if err != nil {
c.Ui.Error(fmt.Sprintf("Failed to marshal function signatures to json: %s", err))
return 1
}
c.Ui.Output(string(jsonFunctions))

return 0
}

Expand Down

0 comments on commit b1b8df7

Please # to comment.