internal/filetypes: package for interpreting command line args
The idea is that the build.File type will be added
to the build.Instance type, replacing the current
file specs. It will be populated by the load package.
The command line tool can subsequently use this
package to determine settings on how to interpret
build.File. It is a separate internal package so that
the API can be shared by load and cmd.
Issue #280
Issue #254
Issue #183
Issue #130
Issue #116
Change-Id: I47f2391945113fe664f0ec33b0048be70326edb5
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4946
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: Daniel Martà <mvdan@mvdan.cc>
diff --git a/internal/filetypes/filetypes.go b/internal/filetypes/filetypes.go
new file mode 100644
index 0000000..da9194d
--- /dev/null
+++ b/internal/filetypes/filetypes.go
@@ -0,0 +1,219 @@
+// Copyright 2020 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//go:generate go run gen.go
+
+package filetypes
+
+import (
+ "path/filepath"
+ "strings"
+
+ "cuelang.org/go/cue"
+ "cuelang.org/go/cue/build"
+ "cuelang.org/go/cue/errors"
+ "cuelang.org/go/cue/token"
+)
+
+// Mode indicate the base mode of operation and indicates a different set of
+// defaults.
+type Mode int
+
+const (
+ Input Mode = iota // The default
+ Export
+ Def
+)
+
+func (m Mode) String() string {
+ switch m {
+ default:
+ return "input"
+ case Export:
+ return "export"
+ case Def:
+ return "def"
+ }
+}
+
+// FileInfo defines the parsing plan for a file.
+type FileInfo struct {
+ *build.File
+ // Filename string `json:"filename"`
+
+ // Tags map[string]string `json:"tags"` // code=go
+
+ Definitions bool `json:"definitions"`
+ Data bool `json:"data"`
+ Optional bool `json:"optional"`
+ Constraints bool `json:"constraints"`
+ References bool `json:"references"`
+ Cycles bool `json:"cycles"`
+ Imports bool `json:"imports"`
+ Stream bool `json:"stream"`
+
+ Docs bool `json:"docs"`
+ Attributes bool `json:"attributes"`
+}
+
+// FromFile return detailed file info for a given build file.
+// Encoding must be specified.
+func FromFile(b *build.File, mode Mode) (*FileInfo, error) {
+ i := cuegenInstance.Value()
+ i = i.Unify(i.Lookup("modes", mode.String()))
+ v := i.LookupDef("FileInfo")
+ v = v.Fill(b)
+
+ if b.Encoding == "" {
+ ext := i.Lookup("extensions", filepath.Ext(b.Filename))
+ if ext.Exists() {
+ v = v.Unify(ext)
+ }
+ }
+
+ if s, _ := v.Lookup("interpretation").String(); s != "" {
+ v = v.Unify(i.Lookup("interpretations", s))
+ } else {
+ s, err := v.Lookup("encoding").String()
+ if err != nil {
+ return nil, err
+ }
+ v = v.Unify(i.Lookup("encodings", s))
+
+ }
+ if b.Form != "" {
+ v = v.Unify(i.Lookup("forms", string(b.Form)))
+ }
+
+ fi := &FileInfo{}
+ if err := v.Decode(fi); err != nil {
+ return nil, err
+ }
+ return fi, nil
+}
+
+// ParseArgs converts a sequence of command line arguments representing
+// files into a sequence of build file specifications.
+//
+// The arguments are of the form
+//
+// file* (spec: file+)*
+//
+// where file is a filename and spec is itself of the form
+//
+// tag[=value]('+'tag[=value])*
+//
+// A file type spec applies to all its following files and until a next spec
+// is found.
+//
+// Examples:
+// json: foo.data bar.data json+schema: bar.schema
+//
+func ParseArgs(args []string) (files []*build.File, err error) {
+ v := parseType("", Input)
+
+ qualifier := ""
+ hasFiles := false
+
+ for i, s := range args {
+ a := strings.Split(s, ":")
+ switch {
+ case len(a) == 1: // filename
+ f, err := toFile(v, s)
+ if err != nil {
+ return nil, err
+ }
+ files = append(files, f)
+ hasFiles = true
+
+ case len(a) > 2 || a[0] == "":
+ return nil, errors.Newf(token.NoPos,
+ "unsupported file name %q: may not have ':'", s)
+
+ case a[1] != "":
+ return nil, errors.Newf(token.NoPos, "cannot combine scope with file")
+
+ default: // scope
+ switch {
+ case i == len(args)-1:
+ qualifier = a[0]
+ fallthrough
+ case qualifier != "" && !hasFiles:
+ return nil, errors.Newf(token.NoPos, "scoped qualifier %q without file", qualifier+":")
+ }
+ v = parseType(a[0], Input)
+ qualifier = a[0]
+ hasFiles = false
+ }
+ }
+
+ return files, nil
+}
+
+// ParseFile parses a single-argument file specifier, such as when a file is
+// passed to a command line argument.
+//
+// Example:
+// cue eval -o yaml:foo.data
+//
+func ParseFile(s string, mode Mode) (*build.File, error) {
+ scope := ""
+ file := s
+
+ if p := strings.LastIndexByte(s, ':'); p >= 0 {
+ scope = s[:p]
+ file = s[p+1:]
+ if scope == "" {
+ return nil, errors.Newf(token.NoPos, "unsupported file name %q: may not have ':", s)
+ }
+ }
+
+ if file == "" {
+ return nil, errors.Newf(token.NoPos, "empty file name in %q", s)
+ }
+
+ return toFile(parseType(scope, mode), file)
+}
+
+func toFile(v cue.Value, filename string) (*build.File, error) {
+ v = v.Fill(filename, "filename")
+ if len(filename) > 1 { // omit "" and -
+ if s, _ := v.Lookup("encoding").String(); s == "" {
+ v = v.Unify(cuegenInstance.Lookup("extensions", filepath.Ext(filename)))
+ }
+ }
+ f := &build.File{}
+ if err := v.Decode(&f); err != nil {
+ return nil, err
+ }
+ return f, nil
+}
+
+func parseType(s string, mode Mode) cue.Value {
+ i := cuegenInstance.Value()
+ i = i.Unify(i.Lookup("modes", "def"))
+ v := i.LookupDef("File")
+
+ if s != "" {
+ for _, t := range strings.Split(s, "+") {
+ if p := strings.IndexByte(t, '='); p >= 0 {
+ v = v.Fill(t[p+1:], "tags", t[:p])
+ } else {
+ v = v.Unify(i.Lookup("tags", t))
+ }
+ }
+ }
+
+ return v
+}
diff --git a/internal/filetypes/filetypes_test.go b/internal/filetypes/filetypes_test.go
new file mode 100644
index 0000000..414da62
--- /dev/null
+++ b/internal/filetypes/filetypes_test.go
@@ -0,0 +1,313 @@
+// Copyright 2020 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package filetypes
+
+import (
+ "strings"
+ "testing"
+
+ "cuelang.org/go/cue/build"
+ "github.com/google/go-cmp/cmp"
+ "github.com/google/go-cmp/cmp/cmpopts"
+)
+
+func check(t *testing.T, want, x interface{}, err error) {
+ t.Helper()
+ if err != nil {
+ x = err.Error()
+ }
+ if !cmp.Equal(x, want, cmpopts.EquateEmpty()) {
+ t.Error(cmp.Diff(want, x))
+ }
+}
+
+func TestFromFile(t *testing.T) {
+ testCases := []struct {
+ name string
+ in build.File
+ mode Mode
+ out interface{}
+ }{{
+ name: "must specify encoding",
+ in: build.File{},
+ out: `encoding: non-concrete value string`,
+ }, {
+ // Default without any
+ name: "cue",
+ in: build.File{
+ Filename: "",
+ Encoding: build.CUE,
+ },
+ mode: Def,
+ out: &FileInfo{
+ File: &build.File{
+ Filename: "",
+ Encoding: "cue",
+ Form: "schema",
+ },
+ Definitions: true,
+ Data: true,
+ Optional: true,
+ Constraints: true,
+ References: true,
+ Cycles: true,
+ Imports: true,
+ Docs: true,
+ },
+ }, {
+ name: "yaml",
+ in: build.File{
+ Filename: "foo.yaml",
+ },
+ out: &FileInfo{
+ File: &build.File{
+ Filename: "foo.yaml",
+ Encoding: "yaml",
+ Form: "graph",
+ },
+ Data: true,
+ References: true,
+ Cycles: true,
+ Stream: true,
+ Docs: true,
+ },
+ }, {
+ name: "yaml+openapi",
+ in: build.File{
+ Filename: "foo.yaml",
+ Interpretation: "openapi",
+ },
+ out: &FileInfo{
+ File: &build.File{
+ Filename: "foo.yaml",
+ Encoding: "yaml",
+ Interpretation: "openapi",
+ Form: "schema",
+ },
+ Definitions: true,
+ Data: true,
+ Optional: true,
+ Constraints: true,
+ References: true,
+ Cycles: true,
+ Imports: true,
+ Docs: true,
+ },
+ }, {
+ name: "JSONDefault",
+ in: build.File{
+ Filename: "data.json",
+ },
+ out: &FileInfo{
+ File: &build.File{
+ Filename: "data.json",
+ Encoding: "json",
+ Form: "data",
+ },
+ Data: true,
+ },
+ }, {
+ name: "JSONSchemaDefault",
+ in: build.File{
+ Filename: "foo.json",
+ Form: "schema",
+ },
+ out: &FileInfo{
+ File: &build.File{
+ Filename: "foo.json",
+ Encoding: "json",
+ Interpretation: "jsonschema",
+ Form: "schema",
+ },
+ Definitions: true,
+ Data: true,
+ Optional: true,
+ Constraints: true,
+ References: true,
+ Cycles: true,
+ Imports: true,
+ Docs: true,
+ },
+ }, {
+ name: "JSONOpenAPI",
+ in: build.File{
+ Filename: "foo.json",
+ Interpretation: "openapi",
+ },
+ mode: Def,
+ out: &FileInfo{
+ File: &build.File{
+ Filename: "foo.json",
+ Encoding: "json",
+ Interpretation: "openapi",
+ Form: "schema",
+ },
+ Definitions: true,
+ Data: true,
+ Optional: true,
+ Constraints: true,
+ References: true,
+ Cycles: true,
+ Imports: true,
+ Docs: true,
+ },
+ }, {
+ name: "OpenAPIDefaults",
+ in: build.File{
+ Filename: "-",
+ Interpretation: "openapi",
+ },
+ mode: Def,
+ out: &FileInfo{
+ File: &build.File{
+ Filename: "-",
+ Encoding: "yaml", // Input default
+ Interpretation: "openapi",
+ Form: "schema",
+ },
+ Definitions: true,
+ Data: true,
+ Optional: true,
+ Constraints: true,
+ References: true,
+ Cycles: true,
+ Imports: true,
+ Docs: true,
+ },
+ }, {
+ name: "Go",
+ in: build.File{
+ Filename: "foo.go",
+ },
+ mode: Def,
+ out: &FileInfo{
+ File: &build.File{
+ Filename: "foo.go",
+ Encoding: "code",
+ Form: "schema",
+ Tags: map[string]string{"lang": "go"},
+ },
+ Definitions: true,
+ Data: true,
+ Optional: true,
+ Constraints: true,
+ References: true,
+ Cycles: true,
+ Imports: true,
+ Stream: false,
+ Docs: true,
+ },
+ }}
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ info, err := FromFile(&tc.in, tc.mode)
+ check(t, tc.out, info, err)
+ })
+ }
+}
+
+func TestParseFile(t *testing.T) {
+ testCases := []struct {
+ in string
+ mode Mode
+ out interface{}
+ }{{
+ in: "file.json",
+ out: &build.File{
+ Filename: "file.json",
+ Encoding: "json",
+ },
+ }, {
+ in: "schema:file.json",
+ out: &build.File{
+ Filename: "file.json",
+ Encoding: "json",
+ Interpretation: "jsonschema",
+ Form: "schema",
+ },
+ }, {
+ in: "cue:file.json",
+ out: &build.File{
+ Filename: "file.json",
+ Encoding: "cue",
+ },
+ }, {
+ in: "cue+schema:-",
+ out: &build.File{
+ Filename: "-",
+ Encoding: "cue",
+ Form: "schema",
+ },
+ }, {
+ in: "code+lang=js:foo.x",
+ out: &build.File{
+ Filename: "foo.x",
+ Encoding: "code",
+ Tags: map[string]string{"lang": "js"},
+ },
+ }, {
+ in: "foo:file.bar",
+ out: `cue: marshal error: tags: value "foo" not found`,
+ }, {
+ in: "file.bar",
+ out: `cue: marshal error: extensions: value ".bar" not found`,
+ }}
+ for _, tc := range testCases {
+ t.Run(tc.in, func(t *testing.T) {
+ f, err := ParseFile(tc.in, tc.mode)
+ check(t, tc.out, f, err)
+ })
+ }
+}
+
+func TestParseArgs(t *testing.T) {
+ testCases := []struct {
+ in string
+ out interface{}
+ }{{
+ in: "foo.json baz.yaml",
+ out: []*build.File{
+ {Filename: "foo.json", Encoding: "json"},
+ {Filename: "baz.yaml", Encoding: "yaml"},
+ },
+ }, {
+ in: "json: foo.data bar.data json+schema: bar.schema",
+ out: []*build.File{
+ {Filename: "foo.data", Encoding: "json"},
+ {Filename: "bar.data", Encoding: "json"},
+ {
+ Filename: "bar.schema",
+ Encoding: "json",
+ Interpretation: "jsonschema",
+ Form: "schema",
+ },
+ },
+ }, {
+ in: "json: json+schema: bar.schema",
+ out: `scoped qualifier "json:" without file`,
+ }, {
+ in: "json:",
+ out: `scoped qualifier "json:" without file`,
+ }, {
+ in: "json:foo:bar.yaml",
+ out: `unsupported file name "json:foo:bar.yaml": may not have ':'`,
+ }}
+ for _, tc := range testCases {
+ t.Run(tc.in, func(t *testing.T) {
+ files, err := ParseArgs(strings.Split(tc.in, " "))
+ check(t, tc.out, files, err)
+ })
+ }
+}
diff --git a/internal/filetypes/gen.go b/internal/filetypes/gen.go
new file mode 100644
index 0000000..f0b9f03
--- /dev/null
+++ b/internal/filetypes/gen.go
@@ -0,0 +1,52 @@
+// Copyright 2020 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build ignore
+
+package main
+
+import (
+ "io/ioutil"
+ "log"
+ "os"
+
+ "cuelang.org/go/cue"
+ "cuelang.org/go/cue/load"
+ "cuelang.org/go/encoding/gocode"
+)
+
+func main() {
+ cwd, err := os.Getwd()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ inst := cue.Build(load.Instances([]string{"types.cue"}, &load.Config{
+ Dir: cwd,
+ ModuleRoot: cwd,
+ Module: "cuelang.org/go/cue/build",
+ }))[0]
+ if inst.Err != nil {
+ log.Fatal(inst.Err)
+ }
+
+ b, err := gocode.Generate(".", inst, &gocode.Config{})
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if err := ioutil.WriteFile("types.go", b, 0644); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/internal/filetypes/test.cue b/internal/filetypes/test.cue
new file mode 100644
index 0000000..a348041
--- /dev/null
+++ b/internal/filetypes/test.cue
@@ -0,0 +1,19 @@
+file: {
+
+ filename: "foo.json"
+ encoding: "json"
+ form: string | *""
+
+ // extensions[".json"]
+
+ form: "schema"
+} & json
+
+// tags maps command line tags to file properties.
+json: {
+ encoding: "json"
+ form: _
+ if form == "schema" {
+ interpretations: *"jsonschema" | _
+ }
+}
diff --git a/internal/filetypes/types.cue b/internal/filetypes/types.cue
new file mode 100644
index 0000000..0ea0aa4
--- /dev/null
+++ b/internal/filetypes/types.cue
@@ -0,0 +1,287 @@
+// Copyright 2020 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package build
+
+// This file describes how various cross-cutting modes influence default
+// settings.
+//
+// It is used by gen.go to compile the instance into Go data, which is then
+// used by the rest of the package to determine settings.
+//
+// There
+
+// A File corresponds to a Go build.File.
+File :: {
+ filename: string
+ encoding: Encoding
+ interpretation?: Interpretation
+ form?: Form
+ tags?: {[string]: string}
+}
+
+// A FileInfo defines how a file is encoded and interpreted.
+FileInfo :: {
+ File
+
+ // Settings
+ data: *true | false
+ references: *true | false
+ cycles: *true | false
+
+ definitions: bool
+ optional: bool
+ constraints: bool
+ keepDefaults: bool
+ incomplete: bool
+ imports: bool
+ stream: bool
+ docs: bool
+ attributes: true | *false
+}
+
+// modes sets defaults for different operational modes.
+//
+// These templates are intended to be unified in at the root of this
+// configuration.
+modes: _
+
+// input defines modes for input, such as import, eval, vet or def.
+// In input mode, settings flags are interpreted as what is allowed to occur
+// in the input. The default settings, therefore, tend to be permissive.
+modes: input: {
+ FileInfo :: x, x = {
+ docs: *true | false
+ }
+ encodings: cue: {
+ *forms.schema | _
+ }
+}
+
+modes: export: {
+ FileInfo :: x, x = {
+ docs: true | *false
+ }
+ encodings: cue: {
+ *forms.data | _
+ }
+}
+
+modes: def: {
+ FileInfo :: x, x = {
+ docs: *true | false
+ }
+ encodings: cue: {
+ *forms.schema | _
+ }
+}
+
+// Extension maps file extensions to default file properties.
+extensions: {
+ "": _
+ ".cue": tags.cue
+ ".json": tags.json
+ ".jsonl": tags.jsonl
+ ".ldjson": tags.jsonl
+ ".ndjson": tags.jsonl
+ ".yaml": tags.yaml
+ ".yml": tags.yaml
+ ".txt": tags.text
+ ".go": tags.go
+ ".proto": tags.proto
+ // TODO: jsonseq,
+ // ".textproto": tags.textpb
+ // ".pb": tags.binpb
+}
+
+// A Encoding indicates a file format for representing a program.
+Encoding :: !="" // | error("no encoding specified")
+
+// An Interpretation determines how a certain program should be interpreted.
+// For instance, data may be interpreted as describing a schema, which itself
+// can be converted to a CUE schema.
+Interpretation :: string
+
+Form :: string
+
+file: FileInfo & {
+
+ filename: "foo.json"
+ form: "schema"
+}
+
+// tags maps command line tags to file properties.
+tags: {
+ schema: form: "schema"
+ final: form: "final"
+ graph: form: "graph"
+ dag: form: "dag"
+ data: form: "data"
+
+ cue: encoding: "cue"
+
+ json: encoding: "json"
+ json: *{
+ form: *"" | "data"
+ } | {
+ form: *"schema" | "final"
+
+ interpretation: *"jsonschema" | _
+ }
+
+ jsonl: encoding: "jsonl"
+ yaml: encoding: "yaml"
+ proto: encoding: "proto"
+ // "textpb": encodings.textproto
+ // "binpb": encodings.binproto
+ text: {
+ encoding: "text"
+ form: "data"
+ }
+ go: {
+ encoding: "code"
+ interpretation: ""
+ tags: lang: "go"
+ }
+ code: {
+ encoding: "code"
+ interpretation: ""
+ tags: lang: string
+ }
+
+ jsonschema: interpretation: "jsonschema"
+ openapi: interpretation: "openapi"
+}
+
+// forms defines schema for all forms. It does not include the form ID.
+forms: [Name=string]: FileInfo
+
+forms: "": _
+
+forms: schema: {
+ form: *"schema" | "final" | "graph"
+ stream: true | *false
+
+ incomplete: *true | false
+ definitions: *true | false
+ optional: *true | false
+ constraints: *true | false
+ keepDefaults: *true | false
+ imports: *true | false
+ optional: *true | false
+}
+
+forms: final: {
+ form: "final"
+ forms.schema
+
+ keepDefaults: false
+ optional: false
+}
+
+forms: graph: {
+ form: *"graph" | "dag" | "data"
+ data: true
+
+ incomplete: false
+ definitions: false
+ optional: false
+ constraints: false
+ keepDefaults: false
+ imports: false
+}
+
+forms: dag: {
+ form: !="graph"
+ forms.graph
+
+ cycles: false
+}
+
+forms: data: {
+ form: !="dag"
+ forms.dag
+
+ constraints: false
+ references: false
+ cycles: false
+ imports: false
+ optional: false
+}
+
+// encodings: "": error("no encoding specified")
+
+encodings: cue: {
+ stream: false
+}
+
+encodings: json: {
+ forms.data
+ stream: *false | true
+ docs: false
+}
+
+encodings: yaml: {
+ forms.graph
+ stream: false | *true
+}
+
+encodings: jsonl: {
+ forms.data
+ stream: true
+}
+
+encodings: text: {
+ forms.data
+ stream: false
+}
+
+encodings: toml: {
+ forms.data
+ stream: false
+}
+
+encodings: proto: {
+ forms.schema
+ encoding: "proto"
+}
+
+// encodings: textproto: {
+// forms.DataEncoding
+// encoding: "textproto"
+// }
+
+// encodings: binproto: {
+// forms.DataEncoding
+// encoding: "binproto"
+// }
+
+encodings: code: {
+ forms.schema
+ stream: false
+}
+
+interpretations: [Name=string]: FileInfo
+
+interpretations: "": _
+
+interpretations: jsonschema: {
+ forms.schema
+ encoding: *"yaml" | _
+}
+
+interpretations: openapi: {
+ forms.schema
+ encoding: *"yaml" | _
+}
diff --git a/internal/filetypes/types.go b/internal/filetypes/types.go
new file mode 100644
index 0000000..99f43a2
--- /dev/null
+++ b/internal/filetypes/types.go
@@ -0,0 +1,51 @@
+// Code generated by gocode.Generate; DO NOT EDIT.
+
+package filetypes
+
+import (
+ "fmt"
+
+ "cuelang.org/go/cue"
+ "cuelang.org/go/encoding/gocode/gocodec"
+)
+
+var cuegenvalFileInfo = cuegenMake("FileInfo", &FileInfo{})
+
+// Validate validates x.
+func (x *FileInfo) Validate() error {
+ return cuegenCodec.Validate(cuegenvalFileInfo, x)
+}
+
+var cuegenCodec, cuegenInstance = func() (*gocodec.Codec, *cue.Instance) {
+ var r *cue.Runtime
+ r = &cue.Runtime{}
+ instances, err := r.Unmarshal(cuegenInstanceData)
+ if err != nil {
+ panic(err)
+ }
+ if len(instances) != 1 {
+ panic("expected encoding of exactly one instance")
+ }
+ return gocodec.New(r, nil), instances[0]
+}()
+
+// cuegenMake is called in the init phase to initialize CUE values for
+// validation functions.
+func cuegenMake(name string, x interface{}) cue.Value {
+ f, err := cuegenInstance.LookupField(name)
+ if err != nil {
+ panic(fmt.Errorf("could not find type %q in instance", name))
+ }
+ v := f.Value
+ if x != nil {
+ w, err := cuegenCodec.ExtractType(x)
+ if err != nil {
+ panic(err)
+ }
+ v = v.Unify(w)
+ }
+ return v
+}
+
+// Data size: 1051 bytes.
+var cuegenInstanceData = []byte("\x01\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcWKo\u0736\x13\x17\xd7\xfe\x03\u007f\x12q\xbfA\x01U\x87\xc2\xd9\xc3^\v,\x10\xf8\x92\x06\u0225(z5\x02\x83\x96(Y\x8d\x96\x14$.`#\xbb\x87\xb6i\xdaK\xbfr\xb6\x18\x0e\x1f\"\xa55\x9a\x1e\xca\xd3\xea7\x9c7\xe7\xb1W\xa7?Vdu\xfa3#\xa7_\xb3\xec\xbb\xd3/\x17\x84\xbch\u5a39,\xc5k\xae9\xe0\xe4\x82\\\xfe\xa4\x94&\xab\x8c\\\xfe\xc8\xf5\x03y\x91\x91\xff\xbdi;1\x92\u04e7,\u02fe>\xfd\xbe\"\xe4\xab\xdbw\xe5^l\uadb3\x9c\x9f2r\xfa\x98e\u05e7\xdf.\b\xf9\u007f\xc0?fdE.\u007f\xe0;\x01\x82.\r\u0232,\xfb|\xf5\x17XB\u020a\x10\xaa\x9fz1n\u02bd \x9f\xaft\xcf\xcb\xf7\xbc\x11\xf9\xfd\xbe\xed*\xc6@u\xbe\xdd\xe6\x1f\x18\x05\xa9\x92\xef\xc46\xb7g\xd4C+\x1bF\x85,U\xd5\xca\xc6\x13\xbe\xb7\x00\xa3\xad\xd4b\xe8\a\xa1\xb9n\x95\xbc\xd9\xe6o#\x80\xd1Z\r\xbb\x1b\u03d8\xe7\xf9\x1b5\xec\x18\u057c\x19o\x8cVz\x8bj\xdem\xbd\xbe#;2\xa7\x02l\xc3\xf3\u036b\xa2`\xb1x Z&\x10\x1b\xeeN\xac\aMF\x91\x16\x8f\x1a5\x06\u007f\n\x00\vF\x8d\x99\xc8\\T\\\xf3\x02\x8c\xa0\xf0\v9\x90<!\x95{1\x93U\xee\x05\x12\xc7\xf2A\xecbN\x84\x90\xfc\xf3\xa8\xe4\x8c\x19@ \xe7\xdf\xe6\xd7\xeb\xc0\xb8.\x8a\xfc\x10\x14\xe7\a\xc3\x17G\x1dn\x01\xbb\u0551\x1f\xf2\xbb\xc8#<\xeb\"\u040b\xba\x95\xbc\x03\x81/\u045cn\u045e\x0e\xed}\xe2\xbb9\x1d@$7*%\xe2)JUA@f\xd6\x16\x00\xfa\xb4P\xdaq#\xb1Q\x80\x1f\x8d\xcc~Pz&\xb60(*5\x0eD\x11\xf6.1\xda\f\xbc\u007f\x88\x88\x06qIm\x92\x9c66\xa5\xaa\x9a\xe5\xf4_y\u27b1\xf5%\xa4f\xbb\x98\xbci\xee\f\x83\xea\x85\xe4}{\u6da5\x16X&P\xbeoe\xadl\t\xe3\x8b\xf5)\xd7\xc3^\u41fc\xe6\xdd(\x18\x1dD-\x06!K1n\xe7\xc4\xf2\xa9\uc430\xc0Y\x89\xba\x95-\x18\x007\xee\x95\xea\xc0J\xf8\x86$\xc0A\xacTr\xd4\x03o\xa5\x0e\xf7\xde\v\u047f\x165\xdfw\x00\"\xd6\xcaR\xed\xfaNh\xd3k,\xb6\xeb\u0560\x9d\x05\x88\x8dz\x10\u073fb\xc4*U\x8e\xc1E\u0138\xd6C{\xbf\xd7\u8035}m\x8d\x87\x10\xb1#\u06e9J`\x9eZ\xd9\xefm'H\xc2G\xad\xf4\xc4}J7\x9b\r\xe6\u04ff\r\x97r\xdf\b(]\u00cb\x1a7\x98J[\x85\x86\u01fc\x03\xa8\xec\x0f\x8c\x8aGp\xf3Y\xed\x89\xfd_\xa6\x1d^\xc09\u0755\xa8\xff{\xb7Y\xcc\xea\x19]n\xad2od\xe8\x8e\xee\x06\x06\"?\x98\xc00\xea_\x80338>\x11\x13\x9aV\xa4\b\xe2j\xc5 \x9b\xe9\f\x89\xfa\x841\xba\x9f\xa8\tC%\xf1\xe7\xccu\xb5h\u0579\xeb\u03f7A:\r\xfc\x84+4\xb2e%\x13\x06f\x10s\xf9\x16\x96\x88W~\x16\xbb'\xe2\x84\x16\xc56\xbfs\x1f\xf3\x01\xf7\u0314\x81_\xae\xff&\x9d$}pqO\xb9\x8e\xc8/\xcdd\x8c\x10F\x93\x8e\x93\u028b{OJ\x8d\xbb\u040c\x1a\xf5\xa3\x94\x1aw\xa6\xa4b}&fS\xca\x1d?\xad\x12\x97\x97\r?\x9b>\xd42\x1bw!\x19\x18w\xdc \x9a\xe9&\x91L\nWYQv\x96\xb3\xe2\xd08\xf2\xcf\x1b\x1eGz9\xc2i\xec\x929m\xf6?\xff\x8c\u0734\x8a#\x93\xd6r\xba\xbf\x85E\x12\x87~<\x11\xbdc\xd3I\xb8\x18\x83\xc5\x10,z\x95V\xb7]n\u0163\x16r\xc40\xdb\u06b2\xe7\x8e\xd1\x026uD`\xb5\x80/\x00\u0342\xb8u |9\xb4\x03\u0623\x1d\xc0]e\xaf\u01f0\\\x86\xcd.\xe7E\u00d7A-\x18\xa3\xfaQOPh\u007f\x806\u02ba`\xd0F\x01\x86m\u0299f\xbe\xa0\u1d1d\b\xdd\u0155\x89\xfb\xe3Q\xd4Jm\xec*<Y\xc9\xddvtd\xf1:\xf4\xe5\x9d+]\xc6B[]\xe3J;\u065e\x17J-Z\xcd\xfe1/\u02f2\xbf\x03\x00\x00\xff\xff\xea*w\xba\x1d\x0e\x00\x00")