Skip to content

Commit 4a3b889

Browse files
committed
internal/encoding/yaml: declare YAML anchor definitions closer to where they're defined
Signed-off-by: Omri Steiner <[email protected]>
1 parent 33cc9e0 commit 4a3b889

File tree

1 file changed

+25
-18
lines changed

1 file changed

+25
-18
lines changed

internal/encoding/yaml/decode.go

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func (d *decoder) Decode() (ast.Expr, error) {
162162
return nil, err
163163
}
164164
d.yamlNonEmpty = true
165-
return d.extract(&yn)
165+
return d.extract(&yn, true)
166166
}
167167

168168
// Unmarshal parses a single YAML value to a CUE expression.
@@ -187,14 +187,14 @@ func Unmarshal(filename string, data []byte) (ast.Expr, error) {
187187
return n, nil
188188
}
189189

190-
func (d *decoder) extractNoAnchor(yn *yaml.Node) (ast.Expr, error) {
190+
func (d *decoder) extractNoAnchor(yn *yaml.Node, isTopLevel bool) (ast.Expr, error) {
191191
switch yn.Kind {
192192
case yaml.DocumentNode:
193193
return d.document(yn)
194194
case yaml.SequenceNode:
195195
return d.sequence(yn)
196196
case yaml.MappingNode:
197-
return d.mapping(yn)
197+
return d.mapping(yn, isTopLevel)
198198
case yaml.ScalarNode:
199199
return d.scalar(yn)
200200
case yaml.AliasNode:
@@ -204,16 +204,16 @@ func (d *decoder) extractNoAnchor(yn *yaml.Node) (ast.Expr, error) {
204204
}
205205
}
206206

207-
func (d *decoder) extract(yn *yaml.Node) (ast.Expr, error) {
207+
func (d *decoder) extract(yn *yaml.Node, isTopLevel bool) (ast.Expr, error) {
208208
d.addHeadCommentsToPending(yn)
209209

210210
var expr ast.Expr
211211
var err error
212212

213213
if yn.Anchor == "" {
214-
expr, err = d.extractNoAnchor(yn)
214+
expr, err = d.extractNoAnchor(yn, isTopLevel)
215215
} else {
216-
expr, err = d.anchor(yn)
216+
expr, err = d.anchor(yn, isTopLevel)
217217
}
218218

219219
if err != nil {
@@ -347,7 +347,7 @@ func (d *decoder) document(yn *yaml.Node) (ast.Expr, error) {
347347
return nil, d.posErrorf(yn, "yaml document nodes are meant to have one content node but have %d", n)
348348
}
349349

350-
expr, err := d.extract(yn.Content[0])
350+
expr, err := d.extract(yn.Content[0], true)
351351
if err != nil {
352352
return nil, err
353353
}
@@ -394,7 +394,7 @@ func (d *decoder) sequence(yn *yaml.Node) (ast.Expr, error) {
394394
closeSameLine := true
395395
for _, c := range yn.Content {
396396
d.forceNewline = multiline
397-
elem, err := d.extract(c)
397+
elem, err := d.extract(c, false)
398398
if err != nil {
399399
return nil, err
400400
}
@@ -408,14 +408,14 @@ func (d *decoder) sequence(yn *yaml.Node) (ast.Expr, error) {
408408
return list, nil
409409
}
410410

411-
func (d *decoder) mapping(yn *yaml.Node) (ast.Expr, error) {
411+
func (d *decoder) mapping(yn *yaml.Node, isTopLevel bool) (ast.Expr, error) {
412412
strct := &ast.StructLit{}
413413
multiline := false
414414
if len(yn.Content) > 0 {
415415
multiline = yn.Line < yn.Content[len(yn.Content)-1].Line
416416
}
417417

418-
if err := d.insertMap(yn, strct, multiline, false); err != nil {
418+
if err := d.insertMap(yn, strct, multiline, false, isTopLevel); err != nil {
419419
return nil, err
420420
}
421421
// TODO(mvdan): moving these positions above insertMap breaks a few tests, why?
@@ -428,7 +428,7 @@ func (d *decoder) mapping(yn *yaml.Node) (ast.Expr, error) {
428428
return strct, nil
429429
}
430430

431-
func (d *decoder) insertMap(yn *yaml.Node, m *ast.StructLit, multiline, mergeValues bool) error {
431+
func (d *decoder) insertMap(yn *yaml.Node, m *ast.StructLit, multiline, mergeValues bool, isTopLevel bool) error {
432432
l := len(yn.Content)
433433
outer:
434434
for i := 0; i < l; i += 2 {
@@ -459,7 +459,7 @@ outer:
459459
f := decl.(*ast.Field)
460460
name, _, err := ast.LabelName(f.Label)
461461
if err == nil && name == key {
462-
f.Value, err = d.extract(yv)
462+
f.Value, err = d.extract(yv, false)
463463
if err != nil {
464464
return err
465465
}
@@ -468,12 +468,19 @@ outer:
468468
}
469469
}
470470

471-
value, err := d.extract(yv)
471+
value, err := d.extract(yv, false)
472472
if err != nil {
473473
return err
474474
}
475475
field.Value = value
476476

477+
if isTopLevel {
478+
for _, field := range d.anchorFields {
479+
m.Elts = append(m.Elts, &field)
480+
}
481+
d.anchorFields = nil
482+
}
483+
477484
m.Elts = append(m.Elts, field)
478485
}
479486
return nil
@@ -482,9 +489,9 @@ outer:
482489
func (d *decoder) merge(yn *yaml.Node, m *ast.StructLit, multiline bool) error {
483490
switch yn.Kind {
484491
case yaml.MappingNode:
485-
return d.insertMap(yn, m, multiline, true)
492+
return d.insertMap(yn, m, multiline, true, false)
486493
case yaml.AliasNode:
487-
return d.insertMap(yn.Alias, m, multiline, true)
494+
return d.insertMap(yn.Alias, m, multiline, true, false)
488495
case yaml.SequenceNode:
489496
// Step backwards as earlier nodes take precedence.
490497
for _, c := range slices.Backward(yn.Content) {
@@ -706,7 +713,7 @@ func (d *decoder) inlineAlias(yn *yaml.Node) (ast.Expr, error) {
706713
}
707714
d.extractingAliases[yn] = true
708715
var node ast.Expr
709-
node, err := d.extractNoAnchor(yn.Alias)
716+
node, err := d.extractNoAnchor(yn.Alias, false)
710717
delete(d.extractingAliases, yn)
711718
return node, err
712719
}
@@ -724,7 +731,7 @@ func (d *decoder) referenceAlias(yn *yaml.Node) (ast.Expr, error) {
724731
}, nil
725732
}
726733

727-
func (d *decoder) anchor(yn *yaml.Node) (ast.Expr, error) {
734+
func (d *decoder) anchor(yn *yaml.Node, isTopLevel bool) (ast.Expr, error) {
728735
var anchorIdent string
729736

730737
// Pick a non-conflicting anchor name.
@@ -744,7 +751,7 @@ func (d *decoder) anchor(yn *yaml.Node) (ast.Expr, error) {
744751
// Process the node itself, but don't put it into the AST just yet,
745752
// store it for later to be used as an anchor identifier.
746753
pos := d.pos(yn)
747-
expr, err := d.extractNoAnchor(yn)
754+
expr, err := d.extractNoAnchor(yn, isTopLevel)
748755
if err != nil {
749756
return nil, err
750757
}

0 commit comments

Comments
 (0)