this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

encoding/yaml: decode empty YAML files as `*null | _`

This allows empty YAML files to be loaded with non-empty YAML files,
which usually decode as structs, without resulting in conflicts.
The default allows the loading of a single empty YAML file to still
result in a concrete `null` value, which is desirable.

Thanks to Roger for coming up with the disjunction idea.

Fixes #3744.

Signed-off-by: Daniel Martí <mvdan@mvdan.cc>
Change-Id: I9a2c4d9ec45af6ff080ffa25ad07ac913552cdc1
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1211360
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
Reviewed-by: Roger Peppe <rogpeppe@gmail.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+32 -18
+7 -7
cmd/cue/cmd/testdata/script/empty_yaml.txtar
··· 1 1 # Empty YAML files by themselves decode as null, following the YAML spec. 2 2 # However, for the sake of the user experience when joining with other YAML files, 3 3 # we allow unifying with them as well. This is done by decoding empty YAML as `*null | _`. 4 - # TODO: implement the above and make the second test case below work. 5 4 6 5 exec cue export empty.yaml 7 6 cmp stdout export-empty.stdout 8 7 9 - ! exec cue export one.yaml empty.yaml two.yaml 10 - cmp stderr export-all.stderr 8 + exec cue export one.yaml empty.yaml two.yaml 9 + cmp stdout export-all.stdout 11 10 12 11 -- export-empty.stdout -- 13 12 null 14 - -- export-all.stderr -- 15 - conflicting values null and {two:"two text"} (mismatched types null and struct): 16 - ./empty.yaml 17 - ./two.yaml:1:1 13 + -- export-all.stdout -- 14 + { 15 + "one": "one text", 16 + "two": "two text" 17 + } 18 18 -- one.yaml -- 19 19 one: "one text" 20 20 -- empty.yaml --
+1 -1
cmd/cue/cmd/testdata/script/import_list.txtar
··· 58 58 language: version: "v0.9.0" 59 59 -- issue2721/empty.yaml -- 60 60 -- issue2721/empty.cue.golden -- 61 - [null] 61 + [*null | _]
+2 -2
encoding/yaml/yaml_test.go
··· 33 33 name: "empty", 34 34 yaml: "", 35 35 yamlOut: "null", 36 - want: "null", 36 + want: "*null | _", 37 37 }, { 38 38 name: "empty stream", 39 - want: "null", 39 + want: "*null | _", 40 40 isStream: true, 41 41 }, { 42 42 name: "string literal",
+19 -5
internal/encoding/yaml/decode.go
··· 103 103 // Any further Decode calls must return EOF to avoid an endless loop. 104 104 d.decodeErr = io.EOF 105 105 106 - // If the input is empty, we produce a single null literal with EOF. 106 + // If the input is empty, we produce `*null | _` followed by EOF. 107 107 // Note that when the input contains "---", we get an empty document 108 108 // with a null scalar value inside instead. 109 109 if !d.yamlNonEmpty { 110 - return &ast.BasicLit{ 111 - Kind: token.NULL, 112 - ValuePos: d.tokFile.Pos(0, token.NoRelPos), 113 - Value: "null", 110 + // Attach positions which at least point to the filename. 111 + pos := d.tokFile.Pos(0, token.NoRelPos) 112 + return &ast.BinaryExpr{ 113 + Op: token.OR, 114 + OpPos: pos, 115 + X: &ast.UnaryExpr{ 116 + Op: token.MUL, 117 + OpPos: pos, 118 + X: &ast.BasicLit{ 119 + Kind: token.NULL, 120 + ValuePos: pos, 121 + Value: "null", 122 + }, 123 + }, 124 + Y: &ast.Ident{ 125 + Name: "_", 126 + NamePos: pos, 127 + }, 114 128 }, nil 115 129 } 116 130 // If the input wasn't empty, we already decoded some CUE syntax nodes,
+2 -2
internal/encoding/yaml/decode_test.go
··· 42 42 }{ 43 43 { 44 44 "", 45 - "null", 45 + "*null | _", 46 46 }, 47 47 { 48 48 "{}", ··· 857 857 want string 858 858 }{{ 859 859 "", 860 - "null", 860 + "*null | _", 861 861 }, { 862 862 "a: b", 863 863 `a: "b"`,
+1 -1
pkg/encoding/yaml/testdata/gen.txtar
··· 79 79 }, { 80 80 b: 2 81 81 }] 82 - empty: [null] 82 + empty: [*null | _] 83 83 nums: [1, 2] 84 84 null1: [1, null, 2] 85 85 null2: [1, null, 2]