diff --git a/playground/impl.go b/playground/impl.go index d455ed9ff..9894b35fe 100644 --- a/playground/impl.go +++ b/playground/impl.go @@ -87,15 +87,29 @@ func handleCUECompile(in input, fn function, out output, inputVal string) (strin if err := v.Err(); err != nil { return "", fmt.Errorf("failed to build: %w", err) } - concrete := true switch out { - case outputCUE: - concrete = false - case outputJSON, outputYaml: + case outputCUE, outputJSON, outputYaml: default: return "", fmt.Errorf("unknown ouput type: %v", out) } - if err := v.Validate(cue.Concrete(concrete)); err != nil { + cueOpts := []cue.Option{ + cue.Docs(true), + cue.Attributes(true), + cue.Optional(true), + cue.Definitions(true), + } + if fn == functionExport { + // TODO(mvdan): note that functionExport doesn't actually mimic "cue export", + // since it doesn't require values to be concrete. + // This can be good for some playground examples with incomplete values that people are already sharing, + // but it's confusing for that mode to be called "export" given the inconsistency with cmd/cue. + // + // In the near future, one possible option would be to show cue@export@cue as an "eval" mode in the UI + // for backwards compatibility, and add a new proper "export" mode as cue@exportv2@cue. + // We could do a transition like this when we switch over to alpha.cuelang.org too. + cueOpts = append(cueOpts, cue.Final()) + } + if err := v.Validate(cueOpts...); err != nil { return "", err } f, err := filetypes.ParseFile(string(out)+":-", filetypes.Export) @@ -113,27 +127,18 @@ func handleCUECompile(in input, fn function, out output, inputVal string) (strin return "", fmt.Errorf("failed to build encoder: %v", err) } - syn := []cue.Option{ - cue.Docs(true), - cue.Attributes(true), - cue.Optional(true), - cue.Definitions(true), - } - var opts []format.Option + var formatOpts []format.Option switch out { case outputCUE: - if fn != functionDef { - syn = append(syn, cue.Concrete(true)) - } - opts = append(opts, format.TabIndent(true)) + formatOpts = append(formatOpts, format.TabIndent(true)) case outputJSON, outputYaml: - opts = append(opts, + formatOpts = append(formatOpts, format.TabIndent(false), format.UseSpaces(2), ) } - encConf.Format = opts - synF := getSyntax(v, syn) + encConf.Format = formatOpts + synF := getSyntax(v, cueOpts) if err := e.EncodeFile(synF); err != nil { return "", fmt.Errorf("failed to encode: %w", err) } diff --git a/playground/impl_test.go b/playground/impl_test.go index ad7c9e18a..e6d2ad709 100644 --- a/playground/impl_test.go +++ b/playground/impl_test.go @@ -33,7 +33,7 @@ var testTable = []struct { // Incomplete values. {inputCUE, functionExport, outputCUE, "foo: int", "foo: int\n", ""}, - {inputCUE, functionExport, outputJSON, "foo: int", "", "foo: incomplete value int"}, + {inputCUE, functionExport, outputJSON, "foo: int", "", "failed to encode: foo: incomplete value int"}, // Selecting defaults. {inputCUE, functionExport, outputCUE, "foo: int | *3", "foo: 3\n", ""}, @@ -55,8 +55,8 @@ var testTable = []struct { [ID=_]: x: y: ID "foo": {} `, + "{\n \"foo\": {\n \"x\": {\n \"y\": \"foo\"\n }\n }\n}\n", "", - "failed to encode: foo.x.y: incomplete value string", }, // Cases which one could argue should be errors, beyond just being incomplete.