Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  properties.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2019 Google Inc. All rights reserved.
//
// 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 bpdoc

import (
 "fmt"
 "go/ast"
 "go/doc"
 "html/template"
 "reflect"
 "slices"
 "strconv"
 "strings"
 "unicode"
 "unicode/utf8"

 "github.com/google/blueprint/proptools"
)

//
// Utility functions for PropertyStruct and Property
//

func (ps *PropertyStruct) Clone() *PropertyStruct {
 ret := *ps
 ret.Properties = slices.Clone(ret.Properties)
 for i, prop := range ret.Properties {
  ret.Properties[i] = prop.Clone()
 }

 return &ret
}

func (p *Property) Clone() Property {
 ret := *p
 ret.Properties = slices.Clone(ret.Properties)
 for i, prop := range ret.Properties {
  ret.Properties[i] = prop.Clone()
 }

 return ret
}

func (p *Property) Equal(other Property) bool {
 return p.Name == other.Name && p.Type == other.Type && p.Tag == other.Tag &&
  p.Text == other.Text && p.Default == other.Default &&
  stringArrayEqual(p.OtherNames, other.OtherNames) &&
  htmlArrayEqual(p.OtherTexts, other.OtherTexts) &&
  p.SameSubProperties(other)
}

func (ps *PropertyStruct) SetDefaults(defaults reflect.Value) {
 setDefaults(ps.Properties, defaults)
}

func setDefaults(properties []Property, defaults reflect.Value) {
 for i := range properties {
  prop := &properties[i]
  fieldName := proptools.FieldNameForProperty(prop.Name)
  f := defaults.FieldByName(fieldName)
  if (f == reflect.Value{}) {
   panic(fmt.Errorf("property %q does not exist in %q", fieldName, defaults.Type()))
  }

  if reflect.DeepEqual(f.Interface(), reflect.Zero(f.Type()).Interface()) {
   continue
  }

  if f.Kind() == reflect.Interface {
   f = f.Elem()
  }

  if f.Kind() == reflect.Ptr {
   if f.IsNil() {
    continue
   }
   f = f.Elem()
  }

  if f.Kind() == reflect.Struct {
   setDefaults(prop.Properties, f)
  } else {
   prop.Default = fmt.Sprintf("%v", f.Interface())
  }
 }
}

func stringArrayEqual(a, b []string) bool {
 if len(a) != len(b) {
  return false
 }

 for i := range a {
  if a[i] != b[i] {
   return false
  }
 }

 return true
}

func htmlArrayEqual(a, b []template.HTML) bool {
 if len(a) != len(b) {
  return false
 }

 for i := range a {
  if a[i] != b[i] {
   return false
  }
 }

 return true
}

func (p *Property) SameSubProperties(other Property) bool {
 if len(p.Properties) != len(other.Properties) {
  return false
 }

 for i := range p.Properties {
  if !p.Properties[i].Equal(other.Properties[i]) {
   return false
  }
 }

 return true
}

func (ps *PropertyStruct) GetByName(name string) *Property {
 return getByName(name, "", &ps.Properties)
}

func (ps *PropertyStruct) Nest(nested *PropertyStruct) {
 ps.Properties = nestUnique(ps.Properties, nested.Properties)
}

// Adds a target element to src if it does not exist in src
func nestUnique(src []Property, target []Property) []Property {
 var ret []Property
 ret = append(ret, src...)
 for _, elem := range target {
  isUnique := true
  for _, retElement := range ret {
   if elem.Equal(retElement) {
    isUnique = false
    break
   }
  }
  if isUnique {
   ret = append(ret, elem)
  }
 }
 return ret
}

func getByName(name string, prefix string, props *[]Property) *Property {
 for i := range *props {
  if prefix+(*props)[i].Name == name {
   return &(*props)[i]
  } else if strings.HasPrefix(name, prefix+(*props)[i].Name+".") {
   return getByName(name, prefix+(*props)[i].Name+".", &(*props)[i].Properties)
  }
 }
 return nil
}

func (p *Property) Nest(nested *PropertyStruct) {
 p.Properties = nestUnique(p.Properties, nested.Properties)
}

func (p *Property) SetAnonymous() {
 p.Anonymous = true
}

func newPropertyStruct(t *doc.Type) (*PropertyStruct, error) {
 typeSpec := t.Decl.Specs[0].(*ast.TypeSpec)
 ps := PropertyStruct{
  Name: t.Name,
  Text: t.Doc,
 }

 structType, ok := typeSpec.Type.(*ast.StructType)
 if !ok {
  return nil, fmt.Errorf("type of %q is not a struct", t.Name)
 }

 var err error
 ps.Properties, err = structProperties(structType)
 if err != nil {
  return nil, err
 }

 return &ps, nil
}

func structProperties(structType *ast.StructType) (props []Property, err error) {
 for _, f := range structType.Fields.List {
  names := f.Names
  if names == nil {
   // Anonymous fields have no name, use the type as the name
   // TODO: hide the name and make the properties show up in the embedding struct
   if t, ok := f.Type.(*ast.Ident); ok {
    names = append(names, t)
   }
  }
  for _, n := range names {
   var name, tag, text string
   if n != nil {
    name = proptools.PropertyNameForField(n.Name)
   }
   if f.Doc != nil {
    text = f.Doc.Text()
   }
   if f.Tag != nil {
    tag, err = strconv.Unquote(f.Tag.Value)
    if err != nil {
     return nil, err
    }
   }
   typ, innerProps, err := getType(f.Type)
   if err != nil {
    return nil, err
   }

   props = append(props, Property{
    Name:       name,
    Type:       typ,
    Tag:        reflect.StructTag(tag),
    Text:       formatText(text),
    Properties: innerProps,
   })
  }
 }

 return props, nil
}

func getType(expr ast.Expr) (typ string, innerProps []Property, err error) {
 var t ast.Expr
 if star, ok := expr.(*ast.StarExpr); ok {
  t = star.X
 } else {
  t = expr
 }
 switch a := t.(type) {
 case *ast.ArrayType:
  var elt string
  elt, innerProps, err = getType(a.Elt)
  if err != nil {
   return "", nil, err
  }
  typ = "list of " + elt
 case *ast.InterfaceType:
  typ = "interface"
 case *ast.Ident:
  typ = a.Name
 case *ast.StructType:
  innerProps, err = structProperties(a)
  if err != nil {
   return "", nil, err
  }
 case *ast.IndexExpr:
  // IndexExpr is used to represent generic type arguments
  if !isConfigurableAst(a.X) {
   var writer strings.Builder
   if err := ast.Fprint(&writer, nil, expr, nil); err != nil {
    return "", nil, err
   }
   return "", nil, fmt.Errorf("unknown type %s", writer.String())
  }
  var innerType string
  innerType, innerProps, err = getType(a.Index)
  if err != nil {
   return "", nil, err
  }
  typ = "configurable " + innerType
 default:
  typ = fmt.Sprintf("%T", expr)
 }

 return typ, innerProps, nil
}

func isConfigurableAst(expr ast.Expr) bool {
 switch e := expr.(type) {
 case *ast.Ident:
  return e.Name == "Configurable"
 case *ast.SelectorExpr:
  if l, ok := e.X.(*ast.Ident); ok && l.Name == "proptools" {
   if e.Sel.Name == "Configurable" {
    return true
   }
  }
 }
 return false
}

func (ps *PropertyStruct) ExcludeByTag(key, value string) {
 filterPropsByTag(&ps.Properties, key, value, true)
}

func (ps *PropertyStruct) IncludeByTag(key, value string) {
 filterPropsByTag(&ps.Properties, key, value, false)
}

func filterPropsByTag(props *[]Property, key, value string, exclude bool) {
 // Create a slice that shares the storage of props but has 0 length.  Appending up to
 // len(props) times to this slice will overwrite the original slice contents
 filtered := (*props)[:0]
 for _, x := range *props {
  if hasTag(x.Tag, key, value) == !exclude {
   filterPropsByTag(&x.Properties, key, value, exclude)
   filtered = append(filtered, x)
  }
 }

 *props = filtered
}

func hasTag(tag reflect.StructTag, key, value string) bool {
 for _, entry := range strings.Split(tag.Get(key), ",") {
  if entry == value {
   return true
  }
 }
 return false
}

func formatText(text string) template.HTML {
 var html template.HTML
 lines := strings.Split(text, "\n")
 preformatted := false
 for _, line := range lines {
  r, _ := utf8.DecodeRuneInString(line)
  indent := unicode.IsSpace(r)
  if indent && !preformatted {
   html += "<pre>\n\n"
   preformatted = true
  } else if !indent && line != "" && preformatted {
   html += "</pre>\n"
   preformatted = false
  }
  html += template.HTML(template.HTMLEscapeString(line)) + "\n"
 }
 if preformatted {
  html += "</pre>\n"
 }
 return html
}

[Dauer der Verarbeitung: 0.23 Sekunden, vorverarbeitet 2026-06-28]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik