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