From 1508ef88c18e14d5fbe168fe5980b4ae0821ca8e Mon Sep 17 00:00:00 2001 From: Roger Peppe Date: Mon, 14 Oct 2024 18:58:30 +0100 Subject: [PATCH] encoding/jsonschema: simplify matchN expressions with only one possibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When there's only one possibility for `oneOf`, `allOf` or `anyOf`, the `matchN` call is redundant. Signed-off-by: Roger Peppe Change-Id: I51061df21904b2a95590a3985618da8f754ee1f7 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1202560 TryBot-Result: CUEcueckoo Unity-Result: CUE porcuepine Reviewed-by: Daniel Martí --- encoding/jsonschema/constraints_combinator.go | 10 ++++++++++ .../external/tests/draft2019-09/additionalItems.json | 4 ++-- .../external/tests/draft4/additionalItems.json | 4 ++-- .../external/tests/draft6/additionalItems.json | 4 ++-- .../external/tests/draft7/additionalItems.json | 4 ++-- .../jsonschema/testdata/external/tests/draft7/ref.json | 4 ++-- encoding/jsonschema/testdata/txtar/typeexcluded.txtar | 4 ++-- encoding/jsonschema/testdata/txtar/unsupported.txtar | 4 ++-- 8 files changed, 24 insertions(+), 14 deletions(-) diff --git a/encoding/jsonschema/constraints_combinator.go b/encoding/jsonschema/constraints_combinator.go index 59f56ba1b1b..85e71e60425 100644 --- a/encoding/jsonschema/constraints_combinator.go +++ b/encoding/jsonschema/constraints_combinator.go @@ -51,6 +51,11 @@ func constraintAllOf(key string, n cue.Value, s *state) { // as that's a known-impossible assertion? if len(a) > 0 { s.knownTypes &= knownTypes + if len(a) == 1 { + // Only one possibility. Use that. + s.all.add(n, a[0]) + return + } s.all.add(n, ast.NewCall( ast.NewIdent("matchN"), // TODO it would be nice to be able to use a special sentinel "all" value @@ -140,6 +145,11 @@ func constraintOneOf(key string, n cue.Value, s *state) { s.allowedTypes &= types if len(a) > 0 && hasSome { s.knownTypes &= knownTypes + if len(a) == 1 { + // Only one possibility. Use that. + s.all.add(n, a[0]) + return + } s.all.add(n, ast.NewCall( ast.NewIdent("matchN"), &ast.BasicLit{ diff --git a/encoding/jsonschema/testdata/external/tests/draft2019-09/additionalItems.json b/encoding/jsonschema/testdata/external/tests/draft2019-09/additionalItems.json index 23b27d9e296..7778e046340 100644 --- a/encoding/jsonschema/testdata/external/tests/draft2019-09/additionalItems.json +++ b/encoding/jsonschema/testdata/external/tests/draft2019-09/additionalItems.json @@ -230,8 +230,8 @@ ], "valid": true, "skip": { - "v2": "invalid value [1,null] (does not satisfy matchN(1, [null | bool | number | string | [int] | {}])): 0 matched, expected 1:\n generated.cue:2:1\n generated.cue:1:1\n generated.cue:2:8\n instance.json:1:1\n", - "v3": "invalid value [1,null] (does not satisfy matchN(1, [null | bool | number | string | [int] | {}])): 0 matched, expected 1:\n generated.cue:2:1\n generated.cue:1:1\n generated.cue:2:8\n instance.json:1:1\n" + "v2": "5 errors in empty disjunction:\nconflicting values [1,null] and {...} (mismatched types list and struct):\n generated.cue:2:1\n generated.cue:2:41\n instance.json:1:1\nconflicting values bool and [1,null] (mismatched types bool and list):\n generated.cue:2:8\n instance.json:1:1\nconflicting values null and [1,null] (mismatched types null and list):\n generated.cue:2:1\n instance.json:1:1\nconflicting values number and [1,null] (mismatched types number and list):\n generated.cue:2:15\n instance.json:1:1\nconflicting values string and [1,null] (mismatched types string and list):\n generated.cue:2:24\n instance.json:1:1\n", + "v3": "conflicting values [1,null] and {...} (mismatched types list and struct):\n generated.cue:2:41\n instance.json:1:1\nconflicting values bool and [1,null] (mismatched types bool and list):\n generated.cue:2:8\n instance.json:1:1\nconflicting values null and [1,null] (mismatched types null and list):\n generated.cue:2:1\n instance.json:1:1\nconflicting values number and [1,null] (mismatched types number and list):\n generated.cue:2:15\n instance.json:1:1\nconflicting values string and [1,null] (mismatched types string and list):\n generated.cue:2:24\n instance.json:1:1\nincompatible list lengths (1 and 2):\n instance.json:1:1\n" } } ] diff --git a/encoding/jsonschema/testdata/external/tests/draft4/additionalItems.json b/encoding/jsonschema/testdata/external/tests/draft4/additionalItems.json index dedd6fbba29..361d9685173 100644 --- a/encoding/jsonschema/testdata/external/tests/draft4/additionalItems.json +++ b/encoding/jsonschema/testdata/external/tests/draft4/additionalItems.json @@ -192,8 +192,8 @@ ], "valid": true, "skip": { - "v2": "invalid value [1,null] (does not satisfy matchN(1, [null | bool | number | string | [int] | {}])): 0 matched, expected 1:\n generated.cue:2:1\n generated.cue:2:8\n instance.json:1:1\n", - "v3": "invalid value [1,null] (does not satisfy matchN(1, [null | bool | number | string | [int] | {}])): 0 matched, expected 1:\n generated.cue:2:1\n generated.cue:2:8\n instance.json:1:1\n" + "v2": "5 errors in empty disjunction:\nconflicting values [1,null] and {...} (mismatched types list and struct):\n generated.cue:2:1\n generated.cue:2:41\n instance.json:1:1\nconflicting values bool and [1,null] (mismatched types bool and list):\n generated.cue:2:8\n instance.json:1:1\nconflicting values null and [1,null] (mismatched types null and list):\n generated.cue:2:1\n instance.json:1:1\nconflicting values number and [1,null] (mismatched types number and list):\n generated.cue:2:15\n instance.json:1:1\nconflicting values string and [1,null] (mismatched types string and list):\n generated.cue:2:24\n instance.json:1:1\n", + "v3": "conflicting values [1,null] and {...} (mismatched types list and struct):\n generated.cue:2:41\n instance.json:1:1\nconflicting values bool and [1,null] (mismatched types bool and list):\n generated.cue:2:8\n instance.json:1:1\nconflicting values null and [1,null] (mismatched types null and list):\n generated.cue:2:1\n instance.json:1:1\nconflicting values number and [1,null] (mismatched types number and list):\n generated.cue:2:15\n instance.json:1:1\nconflicting values string and [1,null] (mismatched types string and list):\n generated.cue:2:24\n instance.json:1:1\nincompatible list lengths (1 and 2):\n instance.json:1:1\n" } } ] diff --git a/encoding/jsonschema/testdata/external/tests/draft6/additionalItems.json b/encoding/jsonschema/testdata/external/tests/draft6/additionalItems.json index b6442fbcd88..3943c2ba5cb 100644 --- a/encoding/jsonschema/testdata/external/tests/draft6/additionalItems.json +++ b/encoding/jsonschema/testdata/external/tests/draft6/additionalItems.json @@ -223,8 +223,8 @@ ], "valid": true, "skip": { - "v2": "invalid value [1,null] (does not satisfy matchN(1, [null | bool | number | string | [int] | {}])): 0 matched, expected 1:\n generated.cue:2:1\n generated.cue:2:8\n instance.json:1:1\n", - "v3": "invalid value [1,null] (does not satisfy matchN(1, [null | bool | number | string | [int] | {}])): 0 matched, expected 1:\n generated.cue:2:1\n generated.cue:2:8\n instance.json:1:1\n" + "v2": "5 errors in empty disjunction:\nconflicting values [1,null] and {...} (mismatched types list and struct):\n generated.cue:2:1\n generated.cue:2:41\n instance.json:1:1\nconflicting values bool and [1,null] (mismatched types bool and list):\n generated.cue:2:8\n instance.json:1:1\nconflicting values null and [1,null] (mismatched types null and list):\n generated.cue:2:1\n instance.json:1:1\nconflicting values number and [1,null] (mismatched types number and list):\n generated.cue:2:15\n instance.json:1:1\nconflicting values string and [1,null] (mismatched types string and list):\n generated.cue:2:24\n instance.json:1:1\n", + "v3": "conflicting values [1,null] and {...} (mismatched types list and struct):\n generated.cue:2:41\n instance.json:1:1\nconflicting values bool and [1,null] (mismatched types bool and list):\n generated.cue:2:8\n instance.json:1:1\nconflicting values null and [1,null] (mismatched types null and list):\n generated.cue:2:1\n instance.json:1:1\nconflicting values number and [1,null] (mismatched types number and list):\n generated.cue:2:15\n instance.json:1:1\nconflicting values string and [1,null] (mismatched types string and list):\n generated.cue:2:24\n instance.json:1:1\nincompatible list lengths (1 and 2):\n instance.json:1:1\n" } } ] diff --git a/encoding/jsonschema/testdata/external/tests/draft7/additionalItems.json b/encoding/jsonschema/testdata/external/tests/draft7/additionalItems.json index b6442fbcd88..3943c2ba5cb 100644 --- a/encoding/jsonschema/testdata/external/tests/draft7/additionalItems.json +++ b/encoding/jsonschema/testdata/external/tests/draft7/additionalItems.json @@ -223,8 +223,8 @@ ], "valid": true, "skip": { - "v2": "invalid value [1,null] (does not satisfy matchN(1, [null | bool | number | string | [int] | {}])): 0 matched, expected 1:\n generated.cue:2:1\n generated.cue:2:8\n instance.json:1:1\n", - "v3": "invalid value [1,null] (does not satisfy matchN(1, [null | bool | number | string | [int] | {}])): 0 matched, expected 1:\n generated.cue:2:1\n generated.cue:2:8\n instance.json:1:1\n" + "v2": "5 errors in empty disjunction:\nconflicting values [1,null] and {...} (mismatched types list and struct):\n generated.cue:2:1\n generated.cue:2:41\n instance.json:1:1\nconflicting values bool and [1,null] (mismatched types bool and list):\n generated.cue:2:8\n instance.json:1:1\nconflicting values null and [1,null] (mismatched types null and list):\n generated.cue:2:1\n instance.json:1:1\nconflicting values number and [1,null] (mismatched types number and list):\n generated.cue:2:15\n instance.json:1:1\nconflicting values string and [1,null] (mismatched types string and list):\n generated.cue:2:24\n instance.json:1:1\n", + "v3": "conflicting values [1,null] and {...} (mismatched types list and struct):\n generated.cue:2:41\n instance.json:1:1\nconflicting values bool and [1,null] (mismatched types bool and list):\n generated.cue:2:8\n instance.json:1:1\nconflicting values null and [1,null] (mismatched types null and list):\n generated.cue:2:1\n instance.json:1:1\nconflicting values number and [1,null] (mismatched types number and list):\n generated.cue:2:15\n instance.json:1:1\nconflicting values string and [1,null] (mismatched types string and list):\n generated.cue:2:24\n instance.json:1:1\nincompatible list lengths (1 and 2):\n instance.json:1:1\n" } } ] diff --git a/encoding/jsonschema/testdata/external/tests/draft7/ref.json b/encoding/jsonschema/testdata/external/tests/draft7/ref.json index ed19078a480..fdd0e997f84 100644 --- a/encoding/jsonschema/testdata/external/tests/draft7/ref.json +++ b/encoding/jsonschema/testdata/external/tests/draft7/ref.json @@ -1283,8 +1283,8 @@ ] }, "skip": { - "v2": "extract error: cannot compile resulting schema: expected operand, found ']':\n generated.cue:3:14\n", - "v3": "extract error: cannot compile resulting schema: expected operand, found ']':\n generated.cue:3:14\n" + "v2": "extract error: cannot compile resulting schema: package \"example.com/ref/if\" imported but not defined in :\n generated.cue:1:8\n", + "v3": "extract error: cannot compile resulting schema: package \"example.com/ref/if\" imported but not defined in :\n generated.cue:1:8\n" }, "tests": [ { diff --git a/encoding/jsonschema/testdata/txtar/typeexcluded.txtar b/encoding/jsonschema/testdata/txtar/typeexcluded.txtar index ffbcea41945..2636fa4b793 100644 --- a/encoding/jsonschema/testdata/txtar/typeexcluded.txtar +++ b/encoding/jsonschema/testdata/txtar/typeexcluded.txtar @@ -120,10 +120,10 @@ e3?: list.UniqueItems() & [_, ...] & [...strings.MinRunes(1)] e4?: [...string] e5?: int & >=0 e6?: [...=~"^[A-Za-z0-9 _.-]+$"] -e7?: matchN(>=1, [true, matchN(1, [{ +e7?: matchN(>=1, [true, { disableFix?: bool ... -}]) & { +} & { ignoreMediaFeatureNames?: list.UniqueItems() & [_, ...] & [...string] ... }]) diff --git a/encoding/jsonschema/testdata/txtar/unsupported.txtar b/encoding/jsonschema/testdata/txtar/unsupported.txtar index f1c0143b488..08ea06aa68d 100644 --- a/encoding/jsonschema/testdata/txtar/unsupported.txtar +++ b/encoding/jsonschema/testdata/txtar/unsupported.txtar @@ -35,9 +35,9 @@ @jsonschema(schema="http://json-schema.org/draft-07/schema#") _ -#ref: matchN(1, [matchN(1, [matchN(0, [string]) & { +#ref: matchN(1, [matchN(0, [string]) & { ... -}]), null]) & (null | { +}, null]) & (null | { branches?: { ... }