cmd/cue/cmd: allow lossy conversion by default and add --strict option

Applies to JSON Schema now, but generallly applicable for
other conversions.

Change-Id: Ie6abe0ea0daf2d2ede1850a16cd2c1d831fb7f13
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/5649
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/common.go b/cmd/cue/cmd/common.go
index 67ed7a9..0508105 100644
--- a/cmd/cue/cmd/common.go
+++ b/cmd/cue/cmd/common.go
@@ -492,6 +492,7 @@
 		ProtoPath: flagProtoPath.StringArray(b.cmd),
 		AllErrors: flagAllErrors.Bool(b.cmd),
 		PkgName:   flagPackage.String(b.cmd),
+		Strict:    flagStrict.Bool(b.cmd),
 	}
 	return nil
 }
diff --git a/cmd/cue/cmd/flags.go b/cmd/cue/cmd/flags.go
index f685d46..26ef387 100644
--- a/cmd/cue/cmd/flags.go
+++ b/cmd/cue/cmd/flags.go
@@ -28,6 +28,7 @@
 	flagTrace     flagName = "trace"
 	flagForce     flagName = "force"
 	flagIgnore    flagName = "ignore"
+	flagStrict    flagName = "strict"
 	flagSimplify  flagName = "simplify"
 	flagPackage   flagName = "package"
 	flagInject    flagName = "inject"
@@ -62,6 +63,8 @@
 		"simplify output")
 	f.BoolP(string(flagIgnore), "i", false,
 		"proceed in the presence of errors")
+	f.Bool(string(flagStrict), false,
+		"report errors for lossy mappings")
 	f.BoolP(string(flagVerbose), "v", false,
 		"print information about progress")
 	f.BoolP(string(flagAllErrors), "E", false, "print all available errors")
diff --git a/cmd/cue/cmd/testdata/script/def_jsonschema.txt b/cmd/cue/cmd/testdata/script/def_jsonschema.txt
index 032d6e9..7a24e5e 100644
--- a/cmd/cue/cmd/testdata/script/def_jsonschema.txt
+++ b/cmd/cue/cmd/testdata/script/def_jsonschema.txt
@@ -5,6 +5,11 @@
 cue def schema.json -p schema -l 'Person::'
 cmp stdout expect-stdout
 
+cue def jsonschema: bad.json
+
+! cue def jsonschema: bad.json --strict
+cmp stderr expect-stderr
+
 -- expect-stdout --
 package schema
 
@@ -45,4 +50,13 @@
   }
 }
 
+-- bad.json --
+{
+  "type": "number",
+  "foo": "bar"
+}
+
+-- expect-stderr --
+unsupported constraint "foo":
+    ./bad.json:3:10
 -- cue.mod --
diff --git a/cmd/cue/cmd/testdata/script/help_cmd.txt b/cmd/cue/cmd/testdata/script/help_cmd.txt
index 427164d..9adc71a 100644
--- a/cmd/cue/cmd/testdata/script/help_cmd.txt
+++ b/cmd/cue/cmd/testdata/script/help_cmd.txt
@@ -145,6 +145,7 @@
   -E, --all-errors   print all available errors
   -i, --ignore       proceed in the presence of errors
   -s, --simplify     simplify output
+      --strict       report errors for lossy mappings
       --trace        trace computation
   -v, --verbose      print information about progress
 
diff --git a/cmd/cue/cmd/testdata/script/help_hello.txt b/cmd/cue/cmd/testdata/script/help_hello.txt
index 28159e9..fad8522 100644
--- a/cmd/cue/cmd/testdata/script/help_hello.txt
+++ b/cmd/cue/cmd/testdata/script/help_hello.txt
@@ -32,5 +32,6 @@
   -E, --all-errors   print all available errors
   -i, --ignore       proceed in the presence of errors
   -s, --simplify     simplify output
+      --strict       report errors for lossy mappings
       --trace        trace computation
   -v, --verbose      print information about progress
diff --git a/encoding/jsonschema/decode.go b/encoding/jsonschema/decode.go
index bf58b4b..ac2a4af 100644
--- a/encoding/jsonschema/decode.go
+++ b/encoding/jsonschema/decode.go
@@ -380,8 +380,9 @@
 			// Convert each constraint into a either a value or a functor.
 			c := constraintMap[key]
 			if c == nil {
-				if pass == 0 {
-					s.warnf(n.Pos(), "unsupported constraint %q", key)
+				if pass == 0 && s.cfg.Strict {
+					// TODO: value is not the correct possition, albeit close. Fix this.
+					s.warnf(value.Pos(), "unsupported constraint %q", key)
 				}
 				return
 			}
diff --git a/encoding/jsonschema/jsonschema.go b/encoding/jsonschema/jsonschema.go
index 09e4173..5f5791b 100644
--- a/encoding/jsonschema/jsonschema.go
+++ b/encoding/jsonschema/jsonschema.go
@@ -57,7 +57,8 @@
 type Config struct {
 	PkgName string
 
-	ID string // URL of the original source, corresponding to the $id field.
+	// ID sets the URL of the original source, corresponding to the $id field.
+	ID string
 
 	// JSON reference of location containing schema. The empty string indicates
 	// that there is a single schema at the root.
@@ -81,5 +82,9 @@
 	// - selection and definition of formats
 	// - documentation hooks.
 
+	// Strict reports an error for unsupported features, rather than ignoring
+	// them.
+	Strict bool
+
 	_ struct{} // prohibit casting from different type.
 }
diff --git a/encoding/jsonschema/testdata/unsupported.txtar b/encoding/jsonschema/testdata/unsupported.txtar
new file mode 100644
index 0000000..b2b3449
--- /dev/null
+++ b/encoding/jsonschema/testdata/unsupported.txtar
@@ -0,0 +1,49 @@
+-- unsupported.json --
+{
+  "$schema": "http://json-schema.org/draft-07/schema",
+  "definitions": {
+    "ref": {
+      "properties": {
+        "branches": {
+          "type": "object"
+        },
+        "branches-ignore": {
+          "type": "object"
+        }
+      },
+      "oneOf": [
+        {
+          "type": "object",
+          "allOf": [
+            {
+              "not": {
+                "required": [
+                  "branches",
+                  "branches-ignore"
+                ]
+              }
+            }
+          ]
+        },
+        {
+          "type": "null"
+        }
+      ]
+    }
+  }
+}
+
+
+-- out.cue --
+Schema :: _ @jsonschema(schema="http://json-schema.org/draft-07/schema")
+Schema :: _
+
+def: ref :: null | {
+	branches?: {
+		...
+	}
+	"branches-ignore"?: {
+		...
+	}
+	...
+}
diff --git a/internal/encoding/encoding.go b/internal/encoding/encoding.go
index 5b4a733..e720284 100644
--- a/internal/encoding/encoding.go
+++ b/internal/encoding/encoding.go
@@ -132,6 +132,7 @@
 	PkgName string // package name for files to generate
 
 	Force     bool // overwrite existing files.
+	Strict    bool
 	Stream    bool // will potentially write more than one document per file
 	AllErrors bool
 
@@ -246,6 +247,8 @@
 		cfg := &jsonschema.Config{
 			ID:      id,
 			PkgName: cfg.PkgName,
+
+			Strict: cfg.Strict,
 		}
 		file, err = simplify(jsonschema.Extract(i, cfg))
 		return file, id, err