Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/gopkg.in/yaml.v3/yaml.go
2872 views
1
//
2
// Copyright (c) 2011-2019 Canonical Ltd
3
//
4
// Licensed under the Apache License, Version 2.0 (the "License");
5
// you may not use this file except in compliance with the License.
6
// You may obtain a copy of the License at
7
//
8
// http://www.apache.org/licenses/LICENSE-2.0
9
//
10
// Unless required by applicable law or agreed to in writing, software
11
// distributed under the License is distributed on an "AS IS" BASIS,
12
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
// See the License for the specific language governing permissions and
14
// limitations under the License.
15
16
// Package yaml implements YAML support for the Go language.
17
//
18
// Source code and other details for the project are available at GitHub:
19
//
20
// https://github.com/go-yaml/yaml
21
//
22
package yaml
23
24
import (
25
"errors"
26
"fmt"
27
"io"
28
"reflect"
29
"strings"
30
"sync"
31
"unicode/utf8"
32
)
33
34
// The Unmarshaler interface may be implemented by types to customize their
35
// behavior when being unmarshaled from a YAML document.
36
type Unmarshaler interface {
37
UnmarshalYAML(value *Node) error
38
}
39
40
type obsoleteUnmarshaler interface {
41
UnmarshalYAML(unmarshal func(interface{}) error) error
42
}
43
44
// The Marshaler interface may be implemented by types to customize their
45
// behavior when being marshaled into a YAML document. The returned value
46
// is marshaled in place of the original value implementing Marshaler.
47
//
48
// If an error is returned by MarshalYAML, the marshaling procedure stops
49
// and returns with the provided error.
50
type Marshaler interface {
51
MarshalYAML() (interface{}, error)
52
}
53
54
// Unmarshal decodes the first document found within the in byte slice
55
// and assigns decoded values into the out value.
56
//
57
// Maps and pointers (to a struct, string, int, etc) are accepted as out
58
// values. If an internal pointer within a struct is not initialized,
59
// the yaml package will initialize it if necessary for unmarshalling
60
// the provided data. The out parameter must not be nil.
61
//
62
// The type of the decoded values should be compatible with the respective
63
// values in out. If one or more values cannot be decoded due to a type
64
// mismatches, decoding continues partially until the end of the YAML
65
// content, and a *yaml.TypeError is returned with details for all
66
// missed values.
67
//
68
// Struct fields are only unmarshalled if they are exported (have an
69
// upper case first letter), and are unmarshalled using the field name
70
// lowercased as the default key. Custom keys may be defined via the
71
// "yaml" name in the field tag: the content preceding the first comma
72
// is used as the key, and the following comma-separated options are
73
// used to tweak the marshalling process (see Marshal).
74
// Conflicting names result in a runtime error.
75
//
76
// For example:
77
//
78
// type T struct {
79
// F int `yaml:"a,omitempty"`
80
// B int
81
// }
82
// var t T
83
// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
84
//
85
// See the documentation of Marshal for the format of tags and a list of
86
// supported tag options.
87
//
88
func Unmarshal(in []byte, out interface{}) (err error) {
89
return unmarshal(in, out, false)
90
}
91
92
// A Decoder reads and decodes YAML values from an input stream.
93
type Decoder struct {
94
parser *parser
95
knownFields bool
96
}
97
98
// NewDecoder returns a new decoder that reads from r.
99
//
100
// The decoder introduces its own buffering and may read
101
// data from r beyond the YAML values requested.
102
func NewDecoder(r io.Reader) *Decoder {
103
return &Decoder{
104
parser: newParserFromReader(r),
105
}
106
}
107
108
// KnownFields ensures that the keys in decoded mappings to
109
// exist as fields in the struct being decoded into.
110
func (dec *Decoder) KnownFields(enable bool) {
111
dec.knownFields = enable
112
}
113
114
// Decode reads the next YAML-encoded value from its input
115
// and stores it in the value pointed to by v.
116
//
117
// See the documentation for Unmarshal for details about the
118
// conversion of YAML into a Go value.
119
func (dec *Decoder) Decode(v interface{}) (err error) {
120
d := newDecoder()
121
d.knownFields = dec.knownFields
122
defer handleErr(&err)
123
node := dec.parser.parse()
124
if node == nil {
125
return io.EOF
126
}
127
out := reflect.ValueOf(v)
128
if out.Kind() == reflect.Ptr && !out.IsNil() {
129
out = out.Elem()
130
}
131
d.unmarshal(node, out)
132
if len(d.terrors) > 0 {
133
return &TypeError{d.terrors}
134
}
135
return nil
136
}
137
138
// Decode decodes the node and stores its data into the value pointed to by v.
139
//
140
// See the documentation for Unmarshal for details about the
141
// conversion of YAML into a Go value.
142
func (n *Node) Decode(v interface{}) (err error) {
143
d := newDecoder()
144
defer handleErr(&err)
145
out := reflect.ValueOf(v)
146
if out.Kind() == reflect.Ptr && !out.IsNil() {
147
out = out.Elem()
148
}
149
d.unmarshal(n, out)
150
if len(d.terrors) > 0 {
151
return &TypeError{d.terrors}
152
}
153
return nil
154
}
155
156
func unmarshal(in []byte, out interface{}, strict bool) (err error) {
157
defer handleErr(&err)
158
d := newDecoder()
159
p := newParser(in)
160
defer p.destroy()
161
node := p.parse()
162
if node != nil {
163
v := reflect.ValueOf(out)
164
if v.Kind() == reflect.Ptr && !v.IsNil() {
165
v = v.Elem()
166
}
167
d.unmarshal(node, v)
168
}
169
if len(d.terrors) > 0 {
170
return &TypeError{d.terrors}
171
}
172
return nil
173
}
174
175
// Marshal serializes the value provided into a YAML document. The structure
176
// of the generated document will reflect the structure of the value itself.
177
// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
178
//
179
// Struct fields are only marshalled if they are exported (have an upper case
180
// first letter), and are marshalled using the field name lowercased as the
181
// default key. Custom keys may be defined via the "yaml" name in the field
182
// tag: the content preceding the first comma is used as the key, and the
183
// following comma-separated options are used to tweak the marshalling process.
184
// Conflicting names result in a runtime error.
185
//
186
// The field tag format accepted is:
187
//
188
// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
189
//
190
// The following flags are currently supported:
191
//
192
// omitempty Only include the field if it's not set to the zero
193
// value for the type or to empty slices or maps.
194
// Zero valued structs will be omitted if all their public
195
// fields are zero, unless they implement an IsZero
196
// method (see the IsZeroer interface type), in which
197
// case the field will be excluded if IsZero returns true.
198
//
199
// flow Marshal using a flow style (useful for structs,
200
// sequences and maps).
201
//
202
// inline Inline the field, which must be a struct or a map,
203
// causing all of its fields or keys to be processed as if
204
// they were part of the outer struct. For maps, keys must
205
// not conflict with the yaml keys of other struct fields.
206
//
207
// In addition, if the key is "-", the field is ignored.
208
//
209
// For example:
210
//
211
// type T struct {
212
// F int `yaml:"a,omitempty"`
213
// B int
214
// }
215
// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
216
// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
217
//
218
func Marshal(in interface{}) (out []byte, err error) {
219
defer handleErr(&err)
220
e := newEncoder()
221
defer e.destroy()
222
e.marshalDoc("", reflect.ValueOf(in))
223
e.finish()
224
out = e.out
225
return
226
}
227
228
// An Encoder writes YAML values to an output stream.
229
type Encoder struct {
230
encoder *encoder
231
}
232
233
// NewEncoder returns a new encoder that writes to w.
234
// The Encoder should be closed after use to flush all data
235
// to w.
236
func NewEncoder(w io.Writer) *Encoder {
237
return &Encoder{
238
encoder: newEncoderWithWriter(w),
239
}
240
}
241
242
// Encode writes the YAML encoding of v to the stream.
243
// If multiple items are encoded to the stream, the
244
// second and subsequent document will be preceded
245
// with a "---" document separator, but the first will not.
246
//
247
// See the documentation for Marshal for details about the conversion of Go
248
// values to YAML.
249
func (e *Encoder) Encode(v interface{}) (err error) {
250
defer handleErr(&err)
251
e.encoder.marshalDoc("", reflect.ValueOf(v))
252
return nil
253
}
254
255
// Encode encodes value v and stores its representation in n.
256
//
257
// See the documentation for Marshal for details about the
258
// conversion of Go values into YAML.
259
func (n *Node) Encode(v interface{}) (err error) {
260
defer handleErr(&err)
261
e := newEncoder()
262
defer e.destroy()
263
e.marshalDoc("", reflect.ValueOf(v))
264
e.finish()
265
p := newParser(e.out)
266
p.textless = true
267
defer p.destroy()
268
doc := p.parse()
269
*n = *doc.Content[0]
270
return nil
271
}
272
273
// SetIndent changes the used indentation used when encoding.
274
func (e *Encoder) SetIndent(spaces int) {
275
if spaces < 0 {
276
panic("yaml: cannot indent to a negative number of spaces")
277
}
278
e.encoder.indent = spaces
279
}
280
281
// Close closes the encoder by writing any remaining data.
282
// It does not write a stream terminating string "...".
283
func (e *Encoder) Close() (err error) {
284
defer handleErr(&err)
285
e.encoder.finish()
286
return nil
287
}
288
289
func handleErr(err *error) {
290
if v := recover(); v != nil {
291
if e, ok := v.(yamlError); ok {
292
*err = e.err
293
} else {
294
panic(v)
295
}
296
}
297
}
298
299
type yamlError struct {
300
err error
301
}
302
303
func fail(err error) {
304
panic(yamlError{err})
305
}
306
307
func failf(format string, args ...interface{}) {
308
panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
309
}
310
311
// A TypeError is returned by Unmarshal when one or more fields in
312
// the YAML document cannot be properly decoded into the requested
313
// types. When this error is returned, the value is still
314
// unmarshaled partially.
315
type TypeError struct {
316
Errors []string
317
}
318
319
func (e *TypeError) Error() string {
320
return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n "))
321
}
322
323
type Kind uint32
324
325
const (
326
DocumentNode Kind = 1 << iota
327
SequenceNode
328
MappingNode
329
ScalarNode
330
AliasNode
331
)
332
333
type Style uint32
334
335
const (
336
TaggedStyle Style = 1 << iota
337
DoubleQuotedStyle
338
SingleQuotedStyle
339
LiteralStyle
340
FoldedStyle
341
FlowStyle
342
)
343
344
// Node represents an element in the YAML document hierarchy. While documents
345
// are typically encoded and decoded into higher level types, such as structs
346
// and maps, Node is an intermediate representation that allows detailed
347
// control over the content being decoded or encoded.
348
//
349
// It's worth noting that although Node offers access into details such as
350
// line numbers, colums, and comments, the content when re-encoded will not
351
// have its original textual representation preserved. An effort is made to
352
// render the data plesantly, and to preserve comments near the data they
353
// describe, though.
354
//
355
// Values that make use of the Node type interact with the yaml package in the
356
// same way any other type would do, by encoding and decoding yaml data
357
// directly or indirectly into them.
358
//
359
// For example:
360
//
361
// var person struct {
362
// Name string
363
// Address yaml.Node
364
// }
365
// err := yaml.Unmarshal(data, &person)
366
//
367
// Or by itself:
368
//
369
// var person Node
370
// err := yaml.Unmarshal(data, &person)
371
//
372
type Node struct {
373
// Kind defines whether the node is a document, a mapping, a sequence,
374
// a scalar value, or an alias to another node. The specific data type of
375
// scalar nodes may be obtained via the ShortTag and LongTag methods.
376
Kind Kind
377
378
// Style allows customizing the apperance of the node in the tree.
379
Style Style
380
381
// Tag holds the YAML tag defining the data type for the value.
382
// When decoding, this field will always be set to the resolved tag,
383
// even when it wasn't explicitly provided in the YAML content.
384
// When encoding, if this field is unset the value type will be
385
// implied from the node properties, and if it is set, it will only
386
// be serialized into the representation if TaggedStyle is used or
387
// the implicit tag diverges from the provided one.
388
Tag string
389
390
// Value holds the unescaped and unquoted represenation of the value.
391
Value string
392
393
// Anchor holds the anchor name for this node, which allows aliases to point to it.
394
Anchor string
395
396
// Alias holds the node that this alias points to. Only valid when Kind is AliasNode.
397
Alias *Node
398
399
// Content holds contained nodes for documents, mappings, and sequences.
400
Content []*Node
401
402
// HeadComment holds any comments in the lines preceding the node and
403
// not separated by an empty line.
404
HeadComment string
405
406
// LineComment holds any comments at the end of the line where the node is in.
407
LineComment string
408
409
// FootComment holds any comments following the node and before empty lines.
410
FootComment string
411
412
// Line and Column hold the node position in the decoded YAML text.
413
// These fields are not respected when encoding the node.
414
Line int
415
Column int
416
}
417
418
// IsZero returns whether the node has all of its fields unset.
419
func (n *Node) IsZero() bool {
420
return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil &&
421
n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0
422
}
423
424
425
// LongTag returns the long form of the tag that indicates the data type for
426
// the node. If the Tag field isn't explicitly defined, one will be computed
427
// based on the node properties.
428
func (n *Node) LongTag() string {
429
return longTag(n.ShortTag())
430
}
431
432
// ShortTag returns the short form of the YAML tag that indicates data type for
433
// the node. If the Tag field isn't explicitly defined, one will be computed
434
// based on the node properties.
435
func (n *Node) ShortTag() string {
436
if n.indicatedString() {
437
return strTag
438
}
439
if n.Tag == "" || n.Tag == "!" {
440
switch n.Kind {
441
case MappingNode:
442
return mapTag
443
case SequenceNode:
444
return seqTag
445
case AliasNode:
446
if n.Alias != nil {
447
return n.Alias.ShortTag()
448
}
449
case ScalarNode:
450
tag, _ := resolve("", n.Value)
451
return tag
452
case 0:
453
// Special case to make the zero value convenient.
454
if n.IsZero() {
455
return nullTag
456
}
457
}
458
return ""
459
}
460
return shortTag(n.Tag)
461
}
462
463
func (n *Node) indicatedString() bool {
464
return n.Kind == ScalarNode &&
465
(shortTag(n.Tag) == strTag ||
466
(n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0)
467
}
468
469
// SetString is a convenience function that sets the node to a string value
470
// and defines its style in a pleasant way depending on its content.
471
func (n *Node) SetString(s string) {
472
n.Kind = ScalarNode
473
if utf8.ValidString(s) {
474
n.Value = s
475
n.Tag = strTag
476
} else {
477
n.Value = encodeBase64(s)
478
n.Tag = binaryTag
479
}
480
if strings.Contains(n.Value, "\n") {
481
n.Style = LiteralStyle
482
}
483
}
484
485
// --------------------------------------------------------------------------
486
// Maintain a mapping of keys to structure field indexes
487
488
// The code in this section was copied from mgo/bson.
489
490
// structInfo holds details for the serialization of fields of
491
// a given struct.
492
type structInfo struct {
493
FieldsMap map[string]fieldInfo
494
FieldsList []fieldInfo
495
496
// InlineMap is the number of the field in the struct that
497
// contains an ,inline map, or -1 if there's none.
498
InlineMap int
499
500
// InlineUnmarshalers holds indexes to inlined fields that
501
// contain unmarshaler values.
502
InlineUnmarshalers [][]int
503
}
504
505
type fieldInfo struct {
506
Key string
507
Num int
508
OmitEmpty bool
509
Flow bool
510
// Id holds the unique field identifier, so we can cheaply
511
// check for field duplicates without maintaining an extra map.
512
Id int
513
514
// Inline holds the field index if the field is part of an inlined struct.
515
Inline []int
516
}
517
518
var structMap = make(map[reflect.Type]*structInfo)
519
var fieldMapMutex sync.RWMutex
520
var unmarshalerType reflect.Type
521
522
func init() {
523
var v Unmarshaler
524
unmarshalerType = reflect.ValueOf(&v).Elem().Type()
525
}
526
527
func getStructInfo(st reflect.Type) (*structInfo, error) {
528
fieldMapMutex.RLock()
529
sinfo, found := structMap[st]
530
fieldMapMutex.RUnlock()
531
if found {
532
return sinfo, nil
533
}
534
535
n := st.NumField()
536
fieldsMap := make(map[string]fieldInfo)
537
fieldsList := make([]fieldInfo, 0, n)
538
inlineMap := -1
539
inlineUnmarshalers := [][]int(nil)
540
for i := 0; i != n; i++ {
541
field := st.Field(i)
542
if field.PkgPath != "" && !field.Anonymous {
543
continue // Private field
544
}
545
546
info := fieldInfo{Num: i}
547
548
tag := field.Tag.Get("yaml")
549
if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
550
tag = string(field.Tag)
551
}
552
if tag == "-" {
553
continue
554
}
555
556
inline := false
557
fields := strings.Split(tag, ",")
558
if len(fields) > 1 {
559
for _, flag := range fields[1:] {
560
switch flag {
561
case "omitempty":
562
info.OmitEmpty = true
563
case "flow":
564
info.Flow = true
565
case "inline":
566
inline = true
567
default:
568
return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st))
569
}
570
}
571
tag = fields[0]
572
}
573
574
if inline {
575
switch field.Type.Kind() {
576
case reflect.Map:
577
if inlineMap >= 0 {
578
return nil, errors.New("multiple ,inline maps in struct " + st.String())
579
}
580
if field.Type.Key() != reflect.TypeOf("") {
581
return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String())
582
}
583
inlineMap = info.Num
584
case reflect.Struct, reflect.Ptr:
585
ftype := field.Type
586
for ftype.Kind() == reflect.Ptr {
587
ftype = ftype.Elem()
588
}
589
if ftype.Kind() != reflect.Struct {
590
return nil, errors.New("option ,inline may only be used on a struct or map field")
591
}
592
if reflect.PtrTo(ftype).Implements(unmarshalerType) {
593
inlineUnmarshalers = append(inlineUnmarshalers, []int{i})
594
} else {
595
sinfo, err := getStructInfo(ftype)
596
if err != nil {
597
return nil, err
598
}
599
for _, index := range sinfo.InlineUnmarshalers {
600
inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...))
601
}
602
for _, finfo := range sinfo.FieldsList {
603
if _, found := fieldsMap[finfo.Key]; found {
604
msg := "duplicated key '" + finfo.Key + "' in struct " + st.String()
605
return nil, errors.New(msg)
606
}
607
if finfo.Inline == nil {
608
finfo.Inline = []int{i, finfo.Num}
609
} else {
610
finfo.Inline = append([]int{i}, finfo.Inline...)
611
}
612
finfo.Id = len(fieldsList)
613
fieldsMap[finfo.Key] = finfo
614
fieldsList = append(fieldsList, finfo)
615
}
616
}
617
default:
618
return nil, errors.New("option ,inline may only be used on a struct or map field")
619
}
620
continue
621
}
622
623
if tag != "" {
624
info.Key = tag
625
} else {
626
info.Key = strings.ToLower(field.Name)
627
}
628
629
if _, found = fieldsMap[info.Key]; found {
630
msg := "duplicated key '" + info.Key + "' in struct " + st.String()
631
return nil, errors.New(msg)
632
}
633
634
info.Id = len(fieldsList)
635
fieldsList = append(fieldsList, info)
636
fieldsMap[info.Key] = info
637
}
638
639
sinfo = &structInfo{
640
FieldsMap: fieldsMap,
641
FieldsList: fieldsList,
642
InlineMap: inlineMap,
643
InlineUnmarshalers: inlineUnmarshalers,
644
}
645
646
fieldMapMutex.Lock()
647
structMap[st] = sinfo
648
fieldMapMutex.Unlock()
649
return sinfo, nil
650
}
651
652
// IsZeroer is used to check whether an object is zero to
653
// determine whether it should be omitted when marshaling
654
// with the omitempty flag. One notable implementation
655
// is time.Time.
656
type IsZeroer interface {
657
IsZero() bool
658
}
659
660
func isZero(v reflect.Value) bool {
661
kind := v.Kind()
662
if z, ok := v.Interface().(IsZeroer); ok {
663
if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
664
return true
665
}
666
return z.IsZero()
667
}
668
switch kind {
669
case reflect.String:
670
return len(v.String()) == 0
671
case reflect.Interface, reflect.Ptr:
672
return v.IsNil()
673
case reflect.Slice:
674
return v.Len() == 0
675
case reflect.Map:
676
return v.Len() == 0
677
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
678
return v.Int() == 0
679
case reflect.Float32, reflect.Float64:
680
return v.Float() == 0
681
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
682
return v.Uint() == 0
683
case reflect.Bool:
684
return !v.Bool()
685
case reflect.Struct:
686
vt := v.Type()
687
for i := v.NumField() - 1; i >= 0; i-- {
688
if vt.Field(i).PkgPath != "" {
689
continue // Private field
690
}
691
if !isZero(v.Field(i)) {
692
return false
693
}
694
}
695
return true
696
}
697
return false
698
}
699
700