internal/langserver/schema/schema.go (219 lines of code) (raw):

package schema import ( "fmt" "strings" "github.com/Azure/azapi-lsp/internal/azure/types" "github.com/Azure/azapi-lsp/internal/parser" ) func GetDef(resourceType *types.TypeBase, hclNodes []*parser.HclNode, index int) []*types.TypeBase { if resourceType == nil { return nil } if len(hclNodes) == index { if t, ok := (*resourceType).(*types.DiscriminatedObjectType); ok { if discriminator, ok := hclNodes[index-1].Children[t.Discriminator]; ok && discriminator != nil && discriminator.Value != nil { if discriminatorValue := strings.Trim(*discriminator.Value, `"`); len(discriminatorValue) > 0 { if t.Elements[discriminatorValue] != nil && t.Elements[discriminatorValue].Type != nil { selectedDiscriminatedObjectType := &types.DiscriminatedObjectType{ Name: t.Name, Discriminator: t.Discriminator, BaseProperties: t.BaseProperties, Elements: map[string]*types.TypeReference{ discriminatorValue: t.Elements[discriminatorValue], }, } return []*types.TypeBase{selectedDiscriminatedObjectType.AsTypeBase()} } } } } return []*types.TypeBase{resourceType} } key := hclNodes[index].Key switch t := (*resourceType).(type) { case *types.ArrayType: if t.ItemType != nil { if strings.Contains(key, ".") { return GetDef(t.ItemType.Type, hclNodes, index+1) } return GetDef(t.ItemType.Type, hclNodes, index) } return nil case *types.DiscriminatedObjectType: if value, ok := t.BaseProperties[key]; ok { if value.Type != nil { return GetDef(value.Type.Type, hclNodes, index+1) } } if index != 0 { if discriminator, ok := hclNodes[index-1].Children[t.Discriminator]; ok && discriminator != nil && discriminator.Value != nil { if discriminatorValue := strings.Trim(*discriminator.Value, `"`); len(discriminatorValue) > 0 { if t.Elements[discriminatorValue] != nil && t.Elements[discriminatorValue].Type != nil { return GetDef(t.Elements[discriminatorValue].Type, hclNodes, index) } } } } res := make([]*types.TypeBase, 0) for _, discriminator := range t.Elements { if resourceType := GetDef(discriminator.Type, hclNodes, index); resourceType != nil { res = append(res, resourceType...) } } return res case *types.ObjectType: if value, ok := t.Properties[key]; ok { if value.Type != nil { return GetDef(value.Type.Type, hclNodes, index+1) } } if t.AdditionalProperties != nil { return GetDef(t.AdditionalProperties.Type, hclNodes, index+1) } case *types.ResourceType: if t.Body != nil { return GetDef(t.Body.Type, hclNodes, index+1) } case *types.ResourceFunctionType: if t.Input != nil { return GetDef(t.Input.Type, hclNodes, index+1) } case *types.AnyType: return []*types.TypeBase{resourceType} case *types.BooleanType: return []*types.TypeBase{resourceType} case *types.IntegerType: return []*types.TypeBase{resourceType} case *types.StringType: return []*types.TypeBase{resourceType} case *types.StringLiteralType: return []*types.TypeBase{resourceType} case *types.UnionType: res := make([]*types.TypeBase, 0) for _, element := range t.Elements { res = append(res, GetDef(element.Type, hclNodes, index)...) } return res } return nil } func GetAllowedProperties(resourceType *types.TypeBase) []Property { if resourceType == nil { return []Property{} } props := make([]Property, 0) switch t := (*resourceType).(type) { case *types.ArrayType: return props case *types.DiscriminatedObjectType: for key, value := range t.BaseProperties { if prop := PropertyFromObjectProperty(key, value); prop != nil { props = append(props, *prop) } } for _, discriminator := range t.Elements { props = append(props, GetAllowedProperties(discriminator.Type)...) } case *types.ObjectType: for key, value := range t.Properties { if prop := PropertyFromObjectProperty(key, value); prop != nil { props = append(props, *prop) } } if t.AdditionalProperties != nil { props = append(props, GetAllowedProperties(t.AdditionalProperties.Type)...) } case *types.ResourceType: if t.Body != nil { return GetAllowedProperties(t.Body.Type) } case *types.AnyType: case *types.BooleanType: case *types.IntegerType: case *types.StringType: case *types.StringLiteralType: case *types.UnionType: } return props } func GetAllowedValues(resourceType *types.TypeBase) []string { if resourceType == nil { return nil } values := make([]string, 0) switch t := (*resourceType).(type) { case *types.ResourceType: if t.Body != nil { return GetAllowedValues(t.Body.Type) } case *types.StringLiteralType: return []string{fmt.Sprintf(`"%s"`, t.Value)} case *types.UnionType: for _, element := range t.Elements { values = append(values, GetAllowedValues(element.Type)...) } return values case *types.DiscriminatedObjectType: case *types.ObjectType: case *types.ArrayType: case *types.AnyType: case *types.BooleanType: values = append(values, "true", "false") case *types.IntegerType: case *types.StringType: } return values } func PropertyFromObjectProperty(propertyName string, property types.ObjectProperty) *Property { if property.IsReadOnly() { return nil } description := "" if property.Description != nil { description = *property.Description } modifier := Optional if property.IsRequired() { modifier = Required } propertyType := "" if property.Type != nil { propertyType = GetTypeName(property.Type.Type) } return &Property{ Name: propertyName, Description: description, Modifier: modifier, Type: propertyType, } } func GetTypeName(typeBase *types.TypeBase) string { if typeBase == nil { return "" } switch t := (*typeBase).(type) { case *types.ArrayType: return "array" case *types.DiscriminatedObjectType: return "object" case *types.ObjectType: return "object" case *types.ResourceType: return "object" case *types.AnyType: return "any" case *types.BooleanType: return "boolean" case *types.IntegerType: return "int" case *types.StringType: return "string" case *types.StringLiteralType: return "string" case *types.UnionType: for _, element := range t.Elements { return GetTypeName(element.Type) } } return "" }