provider-schema/result.go (187 lines of code) (raw):
package provider_schema
import (
"fmt"
"slices"
"strings"
"github.com/Azure/azurerm-lsp/provider-schema/azurerm/schema"
"github.com/Azure/azurerm-lsp/provider-schema/processors"
)
var finalTerraformObject processors.TerraformObjects
func GetFinalTerraformObject() processors.TerraformObjects {
if finalTerraformObject == nil {
terraformObject, err := processors.LoadProcessedOutput()
if err != nil {
panic(err)
}
finalTerraformObject = terraformObject
}
return finalTerraformObject
}
func ListAllResources() []string {
var resources []string
for name, terraformObject := range GetFinalTerraformObject() {
if terraformObject.IsDataSource() {
continue
}
resources = append(resources, name)
}
return resources
}
func ListAllDataSources() []string {
var dataSources []string
for _, terraformObject := range GetFinalTerraformObject() {
if !terraformObject.IsDataSource() {
continue
}
dataSources = append(dataSources, terraformObject.GetName())
}
return dataSources
}
func ListAllResourcesAndDataSources() []string {
var resourcesAndDataSources []string
for name := range GetFinalTerraformObject() {
resourcesAndDataSources = append(resourcesAndDataSources, name)
}
return resourcesAndDataSources
}
// NavigateToNestedBlock navigates down a nested block path and returns the final block or property
func NavigateToNestedBlock(objectName, path string) (*schema.SchemaAttribute, error) {
resource, exists := GetFinalTerraformObject()[objectName]
if !exists {
return nil, fmt.Errorf("resource/data source '%s' not found", objectName)
}
parts := strings.Split(path, ".")
if len(parts) == 0 {
return nil, fmt.Errorf("invalid path '%s'", path)
}
curFields := resource.Fields
var result *schema.SchemaAttribute
for _, part := range parts {
result, exists = curFields[part]
if !exists {
return nil, fmt.Errorf("path '%s' not found in resource/data source '%s'", path, objectName)
}
curFields = result.Fields
}
if result == nil {
return nil, fmt.Errorf("path '%s' is nil in resource/data source '%s'", path, objectName)
}
return result, nil
}
func GetObjectInfo(objectName string) (*processors.TerraformObject, error) {
resource, exists := GetFinalTerraformObject()[objectName]
if !exists {
return nil, fmt.Errorf("resource/data source '%s' not found", objectName)
}
return resource, nil
}
func GetPropertyInfo(objectName, propertyPath string) (*schema.SchemaAttribute, error) {
return NavigateToNestedBlock(objectName, propertyPath)
}
func GetPossibleValuesForProperty(objectName, propertyName string) ([]string, error) {
block, err := NavigateToNestedBlock(objectName, propertyName)
if err != nil {
return nil, err
}
if block == nil {
return nil, fmt.Errorf("block '%s' not found in resource/data source '%s'", propertyName, objectName)
}
if block.PossibleValues == nil {
return nil, fmt.Errorf("no possible values found for block '%s' in resource/data source '%s'", propertyName, objectName)
}
return block.GetAutoCompletePossibleValues(), nil
}
func ListDirectProperties(objectName string, path string) ([]*schema.SchemaAttribute, error) {
resource, exists := GetFinalTerraformObject()[objectName]
if !exists {
return nil, fmt.Errorf("resource/data source '%s' not found", objectName)
}
fields := resource.Fields
if path != "" {
block, err := NavigateToNestedBlock(objectName, path)
if err != nil {
return nil, err
}
if block == nil {
return nil, fmt.Errorf("block '%s' not found in resource/data source '%s'", path, objectName)
}
fields = block.Fields
}
var properties []*schema.SchemaAttribute
for _, property := range fields {
if property.Computed {
continue
}
properties = append(properties, property)
}
setSort(properties)
return properties, nil
}
func setSort(properties []*schema.SchemaAttribute) {
slices.SortFunc(properties, func(a, b *schema.SchemaAttribute) int {
if a.Required && !b.Required {
return -1
}
if !a.Required && b.Required {
return 1
}
return strings.Compare(a.Name, b.Name)
})
sortIndex := 0
for _, property := range properties {
property.SetSortOrder(fmt.Sprintf("%d", sortIndex))
sortIndex++
}
}
func GetSnippet(objectName string) (string, error) {
resource, exists := GetFinalTerraformObject()[objectName]
if !exists {
return "", fmt.Errorf("resource/data source '%s' not found", objectName)
}
return resource.GetSnippet(), nil
}
func GetPropertyDocContent(objectName string, property *schema.SchemaAttribute) string {
if property == nil {
return ""
}
propertyDescription := property.GetDescription()
// try to get direct properties of this property
directProperties, err := ListDirectProperties(objectName, property.AttributePath)
if err != nil || len(directProperties) == 0 {
return propertyDescription
}
// if there are direct properties, append them to the description
var directPropertiesDescriptions []string
for _, directProperty := range directProperties {
directPropertiesDescriptions = append(directPropertiesDescriptions, fmt.Sprintf(" - %s: %s", directProperty.Name, directProperty.GetDescription()))
}
return fmt.Sprintf("%s\n\n%s", propertyDescription, strings.Join(directPropertiesDescriptions, "\n"))
}
func GetResourceContent(resourceName string) (string, bool, error) {
resourceInfo, err := GetObjectInfo(resourceName)
if err != nil {
return "", false, fmt.Errorf("error retrieving resource info: %v", err)
}
return fmt.Sprintf(ResourceTemplate,
resourceName,
resourceInfo.GetResourceOrDataSourceDocLink(),
resourceInfo.GetGitHubIssueLink(),
resourceInfo.GetDocContent(),
), resourceInfo.IsDataSource(), nil
}
func GetAttributeContent(resourceName, path string) (string, *schema.SchemaAttribute, error) {
obj, err := GetObjectInfo(resourceName)
if err != nil {
return "", nil, fmt.Errorf("error retrieving object info: %v", err)
}
prop, err := GetPropertyInfo(resourceName, path)
if err != nil {
return "", nil, fmt.Errorf("error retrieving property info: %v", err)
}
return fmt.Sprintf(AttributeTemplate,
prop.Name,
prop.GetRequirementType(),
prop.AttributeType.FriendlyName(),
prop.GetAttributeDocLink(obj.GetResourceOrDataSourceDocLink()),
prop.GetGitHubIssueLink(),
strings.Join(prop.GetDetails(), "\n"),
GetPropertyDocContent(resourceName, prop),
), prop, nil
}