github.com/tomwright/dasel@v1.27.3/node.go (about) 1 package dasel 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "reflect" 8 "regexp" 9 10 "github.com/tomwright/dasel/storage" 11 ) 12 13 // Selector represents the selector for a node. 14 type Selector struct { 15 // Raw is the full selector. 16 Raw string `json:"raw"` 17 // Current is the selector to be used with the current node. 18 Current string `json:"current"` 19 // Remaining is the remaining parts of the Raw selector. 20 Remaining string `json:"remaining"` 21 // Type is the type of the selector. 22 Type string `json:"type"` 23 // Property is the name of the property this selector targets, if applicable. 24 Property string `json:"property,omitempty"` 25 // Index is the index to use if applicable. 26 Index int `json:"index,omitempty"` 27 // Conditions contains a set of conditions to optionally match a target. 28 Conditions []Condition `json:"conditions,omitempty"` 29 } 30 31 // Copy returns a copy of the selector. 32 func (s Selector) Copy() Selector { 33 return Selector{ 34 Raw: s.Raw, 35 Current: s.Current, 36 Remaining: s.Remaining, 37 Type: s.Type, 38 Property: s.Property, 39 Index: s.Index, 40 Conditions: s.Conditions, 41 } 42 } 43 44 // Node represents a single node in the chain of nodes for a selector. 45 type Node struct { 46 // Previous is the previous node in the chain. 47 Previous *Node `json:"-"` 48 // Next contains the next node in the chain. 49 // This is used with Query and Put requests. 50 Next *Node `json:"next,omitempty"` 51 // NextMultiple contains the next nodes in the chain. 52 // This is used with QueryMultiple and PutMultiple requests. 53 // When a major version change occurs this will completely replace Next. 54 NextMultiple []*Node `json:"nextMultiple,omitempty"` 55 // OriginalValue is the value returned from the parser. 56 // In most cases this is the same as Value, but is different for thr YAML parser 57 // as it contains information on the original document. 58 OriginalValue interface{} `json:"-"` 59 // Value is the value of the current node. 60 Value reflect.Value `json:"value"` 61 // Selector is the selector for the current node. 62 Selector Selector `json:"selector"` 63 wasInitialised bool 64 } 65 66 // String returns the value of the node as a string. 67 // No formatting is done here, you get the raw value. 68 func (n *Node) String() string { 69 return fmt.Sprint(n.InterfaceValue()) 70 } 71 72 // InterfaceValue returns the value stored within the node as an interface{}. 73 func (n *Node) InterfaceValue() interface{} { 74 // We shouldn't be able to get here but this will stop a panic if we do. 75 if !n.Value.IsValid() { 76 return nil 77 } 78 return n.Value.Interface() 79 } 80 81 const ( 82 propertySelector = `(?P<property>[a-zA-Z\-_]+)` 83 indexSelector = `\[(?P<index>[0-9a-zA-Z\*]*?)\]` 84 ) 85 86 var ( 87 propertyRegexp = regexp.MustCompile(fmt.Sprintf("^\\.?%s", propertySelector)) 88 indexRegexp = regexp.MustCompile(fmt.Sprintf("^\\.?%s", indexSelector)) 89 newDynamicRegexp = regexp.MustCompile(fmt.Sprintf("^\\.?((?:\\(.*\\))+)")) 90 ) 91 92 func isValid(value reflect.Value) bool { 93 return value.IsValid() && !safeIsNil(value) 94 } 95 96 func safeIsNil(value reflect.Value) bool { 97 switch value.Kind() { 98 case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, 99 reflect.Interface, reflect.Slice: 100 return value.IsNil() 101 } 102 return false 103 } 104 105 func nilValue() reflect.Value { 106 return reflect.ValueOf(nil) 107 } 108 109 func unwrapValue(value reflect.Value) reflect.Value { 110 if value.Kind() == reflect.Interface && !value.IsNil() { 111 return value.Elem() 112 } 113 return value 114 } 115 116 func derefValue(value reflect.Value) reflect.Value { 117 if value.Kind() == reflect.Ptr { 118 return value.Elem() 119 } 120 return value 121 } 122 123 // New returns a new root node with the given value. 124 func New(value interface{}) *Node { 125 rootNode := &Node{ 126 Previous: nil, 127 Next: nil, 128 NextMultiple: nil, 129 Selector: Selector{ 130 Raw: ".", 131 Current: ".", 132 Remaining: "", 133 Type: "ROOT", 134 Property: "", 135 }, 136 } 137 rootNode.setRealValue(value) 138 return rootNode 139 } 140 141 // NewFromFile returns a new root node by parsing file using specified read parser. 142 func NewFromFile(filename, parser string) (*Node, error) { 143 readParser, err := storage.NewReadParserFromString(parser) 144 if err != nil { 145 return nil, err 146 } 147 148 data, err := storage.LoadFromFile(filename, readParser) 149 if err != nil { 150 return nil, err 151 } 152 153 return New(data), nil 154 } 155 156 // NewFromReader returns a new root node by parsing from Reader using specified read parser. 157 func NewFromReader(reader io.Reader, parser string) (*Node, error) { 158 readParser, err := storage.NewReadParserFromString(parser) 159 if err != nil { 160 return nil, err 161 } 162 163 data, err := storage.Load(readParser, reader) 164 if err != nil { 165 return nil, err 166 } 167 168 return New(data), nil 169 } 170 171 // WriteToFile writes data to the given file with the specified options. 172 func (n *Node) WriteToFile(filename, parser string, writeOptions []storage.ReadWriteOption) error { 173 f, err := os.Create(filename) 174 175 if err != nil { 176 return err 177 } 178 179 // https://www.joeshaw.org/dont-defer-close-on-writable-files/ 180 if err = n.Write(f, parser, writeOptions); err != nil { 181 _ = f.Close() 182 return err 183 } 184 185 return f.Close() 186 } 187 188 // Write writes data to Writer using specified write parser and options. 189 func (n *Node) Write(writer io.Writer, parser string, writeOptions []storage.ReadWriteOption) error { 190 writeParser, err := storage.NewWriteParserFromString(parser) 191 if err != nil { 192 return err 193 } 194 195 value := n.InterfaceValue() 196 originalValue := n.OriginalValue 197 198 if err := storage.Write(writeParser, value, originalValue, writer, writeOptions...); err != nil { 199 return err 200 } 201 202 return nil 203 } 204 205 func (n *Node) setValue(newValue interface{}) { 206 n.Value = reflect.ValueOf(newValue) 207 if n.Selector.Type == "ROOT" { 208 n.OriginalValue = newValue 209 } 210 } 211 212 func (n *Node) setRealValue(newValue interface{}) { 213 switch typed := newValue.(type) { 214 case storage.RealValue: 215 n.Value = reflect.ValueOf(typed.RealValue()) 216 default: 217 n.Value = reflect.ValueOf(typed) 218 } 219 if n.Selector.Type == "ROOT" { 220 n.OriginalValue = newValue 221 } 222 } 223 224 func (n *Node) setReflectValue(newValue reflect.Value) { 225 n.Value = newValue 226 if n.Selector.Type == "ROOT" { 227 n.OriginalValue = unwrapValue(newValue).Interface() 228 } 229 } 230 231 func (n *Node) setRealReflectValue(newValue reflect.Value) { 232 val := unwrapValue(newValue).Interface() 233 switch typed := val.(type) { 234 case storage.RealValue: 235 n.OriginalValue = typed 236 n.Value = reflect.ValueOf(typed.RealValue()) 237 default: 238 n.Value = newValue 239 } 240 if n.Selector.Type == "ROOT" { 241 n.OriginalValue = val 242 } 243 }