| package json |
| |
| import ( |
| "encoding/json" |
| |
| "github.com/zclconf/go-cty/cty" |
| "github.com/zclconf/go-cty/cty/function" |
| ) |
| |
| // Function is a description of the JSON representation of the signature of |
| // a function callable from the Terraform language. |
| type Function struct { |
| // Name is the leaf name of the function, without any namespace prefix. |
| Name string `json:"name"` |
| |
| Params []FunctionParam `json:"params"` |
| VariadicParam *FunctionParam `json:"variadic_param,omitempty"` |
| |
| // ReturnType is type constraint which is a static approximation of the |
| // possibly-dynamic return type of the function. |
| ReturnType json.RawMessage `json:"return_type"` |
| |
| Description string `json:"description,omitempty"` |
| DescriptionKind string `json:"description_kind,omitempty"` |
| } |
| |
| // FunctionParam represents a single parameter to a function, as represented |
| // by type Function. |
| type FunctionParam struct { |
| // Name is a name for the function which is used primarily for |
| // documentation purposes, because function arguments are positional |
| // and therefore don't appear directly in configuration source code. |
| Name string `json:"name"` |
| |
| // Type is a type constraint which is a static approximation of the |
| // possibly-dynamic type of the parameter. Particular functions may |
| // have additional requirements that a type constraint alone cannot |
| // represent. |
| Type json.RawMessage `json:"type"` |
| |
| // Maybe some of the other fields in function.Parameter would be |
| // interesting to describe here too, but we'll wait to see if there |
| // is a use-case first. |
| |
| Description string `json:"description,omitempty"` |
| DescriptionKind string `json:"description_kind,omitempty"` |
| } |
| |
| // DescribeFunction returns a description of the signature of the given cty |
| // function, as a pointer to this package's serializable type Function. |
| func DescribeFunction(name string, f function.Function) *Function { |
| ret := &Function{ |
| Name: name, |
| } |
| |
| params := f.Params() |
| ret.Params = make([]FunctionParam, len(params)) |
| typeCheckArgs := make([]cty.Type, len(params), len(params)+1) |
| for i, param := range params { |
| ret.Params[i] = describeFunctionParam(¶m) |
| typeCheckArgs[i] = param.Type |
| } |
| if varParam := f.VarParam(); varParam != nil { |
| descParam := describeFunctionParam(varParam) |
| ret.VariadicParam = &descParam |
| typeCheckArgs = append(typeCheckArgs, varParam.Type) |
| } |
| |
| retType, err := f.ReturnType(typeCheckArgs) |
| if err != nil { |
| // Getting an error when type-checking with exactly the type constraints |
| // the function called for is weird, so we'll just treat it as if it |
| // has a dynamic return type instead, for our purposes here. |
| // One reason this can happen is for a function which has a variadic |
| // parameter but has logic inside it which considers it invalid to |
| // specify exactly one argument for that parameter (since that's what |
| // we did in typeCheckArgs as an approximation of a valid call above.) |
| retType = cty.DynamicPseudoType |
| } |
| |
| if raw, err := retType.MarshalJSON(); err != nil { |
| // Again, we'll treat any errors as if the function is dynamically |
| // typed because it would be weird to get here. |
| ret.ReturnType = json.RawMessage(`"dynamic"`) |
| } else { |
| ret.ReturnType = json.RawMessage(raw) |
| } |
| |
| // We don't currently have any sense of descriptions for functions and |
| // their parameters, so we'll just leave those fields unpopulated for now. |
| |
| return ret |
| } |
| |
| func describeFunctionParam(p *function.Parameter) FunctionParam { |
| ret := FunctionParam{ |
| Name: p.Name, |
| } |
| |
| if raw, err := p.Type.MarshalJSON(); err != nil { |
| // We'll treat any errors as if the function is dynamically |
| // typed because it would be weird to get here. |
| ret.Type = json.RawMessage(`"dynamic"`) |
| } else { |
| ret.Type = json.RawMessage(raw) |
| } |
| |
| // We don't currently have any sense of descriptions for functions and |
| // their parameters, so we'll just leave those fields unpopulated for now. |
| |
| return ret |
| } |