encoding/openapi: support nested defintitions

This perpares for Protobuf remodeling, where the nested
definitions of protobufs are are also nested within the
corresponding CUE types.

- Use Dereference
- Get comments from definitions, not fields, if applicable
- Allow embedded closed disjunctions.
- Allow nested types.
- Don't expand array element references.

Note that this removes the simplification in the openapi.cue
test: nested closed structs were not handled correctly by
this optimization.

Change-Id: Ie6adf44b37ac72139e21539094df5a728a309bd1
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/5405
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/encoding/openapi/testdata/builtins.json b/encoding/openapi/testdata/builtins.json
index 91db4e7..8d43e35 100644
--- a/encoding/openapi/testdata/builtins.json
+++ b/encoding/openapi/testdata/builtins.json
@@ -5,7 +5,6 @@
    "components": {
       "schemas": {
          "Duration": {
-            "description": "This is not an OpenAPI type and has no format. In this case\nwe map to a type so that it can be documented properly (without\nrepeating it).",
             "type": "string"
          },
          "MyStruct": {
diff --git a/encoding/openapi/testdata/nested.cue b/encoding/openapi/testdata/nested.cue
index f1343e0..a95b2b0 100644
--- a/encoding/openapi/testdata/nested.cue
+++ b/encoding/openapi/testdata/nested.cue
@@ -4,5 +4,8 @@
 	T :: int
 
 	a?: T
-	b?: T
+
+	{b?: T}
+
+	c?: [...T]
 }
diff --git a/encoding/openapi/testdata/nested.json b/encoding/openapi/testdata/nested.json
index d390c64..c392b15 100644
--- a/encoding/openapi/testdata/nested.json
+++ b/encoding/openapi/testdata/nested.json
@@ -10,6 +10,12 @@
                "a": {
                   "$ref": "#/components/schemas/Struct.T"
                },
+               "c": {
+                  "type": "array",
+                  "items": {
+                     "$ref": "#/components/schemas/Struct.T"
+                  }
+               },
                "b": {
                   "$ref": "#/components/schemas/Struct.T"
                }
diff --git a/encoding/openapi/testdata/oneof-funcs.json b/encoding/openapi/testdata/oneof-funcs.json
index 19c7fe3..b61f51b 100644
--- a/encoding/openapi/testdata/oneof-funcs.json
+++ b/encoding/openapi/testdata/oneof-funcs.json
@@ -16,59 +16,123 @@
                   "type": "integer"
                }
             },
-            "oneOf": [
+            "allOf": [
                {
-                  "not": {
-                     "anyOf": [
-                        {
-                           "required": [
-                              "b"
-                           ],
-                           "properties": {
-                              "b": {
-                                 "description": "Randomly picked description from a set of size one.",
-                                 "type": "integer"
+                  "oneOf": [
+                     {
+                        "not": {
+                           "anyOf": [
+                              {
+                                 "required": [
+                                    "b"
+                                 ],
+                                 "properties": {
+                                    "b": {
+                                       "$ref": "#/components/schemas/EMBED_T"
+                                    }
+                                 }
+                              },
+                              {
+                                 "required": [
+                                    "c"
+                                 ],
+                                 "properties": {
+                                    "c": {
+                                       "description": "Randomly picked description from a set of size one.",
+                                       "type": "integer"
+                                    }
+                                 }
                               }
-                           }
-                        },
-                        {
-                           "required": [
-                              "c"
-                           ],
-                           "properties": {
-                              "c": {
-                                 "description": "Randomly picked description from a set of size one.",
-                                 "type": "integer"
-                              }
+                           ]
+                        }
+                     },
+                     {
+                        "required": [
+                           "b"
+                        ],
+                        "properties": {
+                           "b": {
+                              "$ref": "#/components/schemas/EMBED_T"
                            }
                         }
-                     ]
-                  }
+                     },
+                     {
+                        "required": [
+                           "c"
+                        ],
+                        "properties": {
+                           "c": {
+                              "description": "Randomly picked description from a set of size one.",
+                              "type": "integer"
+                           }
+                        }
+                     }
+                  ]
                },
                {
-                  "required": [
-                     "b"
-                  ],
-                  "properties": {
-                     "b": {
-                        "description": "Randomly picked description from a set of size one.",
-                        "type": "integer"
+                  "oneOf": [
+                     {
+                        "not": {
+                           "anyOf": [
+                              {
+                                 "required": [
+                                    "d"
+                                 ],
+                                 "properties": {
+                                    "d": {
+                                       "$ref": "#/components/schemas/EMBED_T"
+                                    }
+                                 }
+                              },
+                              {
+                                 "required": [
+                                    "e"
+                                 ],
+                                 "properties": {
+                                    "e": {
+                                       "description": "Randomly picked description from a set of size one.",
+                                       "type": "integer"
+                                    }
+                                 }
+                              }
+                           ]
+                        }
+                     },
+                     {
+                        "required": [
+                           "d"
+                        ],
+                        "properties": {
+                           "d": {
+                              "$ref": "#/components/schemas/EMBED_T"
+                           }
+                        }
+                     },
+                     {
+                        "required": [
+                           "e"
+                        ],
+                        "properties": {
+                           "e": {
+                              "description": "Randomly picked description from a set of size one.",
+                              "type": "integer"
+                           }
+                        }
                      }
-                  }
-               },
-               {
-                  "required": [
-                     "c"
-                  ],
-                  "properties": {
-                     "c": {
-                        "description": "Randomly picked description from a set of size one.",
-                        "type": "integer"
-                     }
-                  }
+                  ]
                }
             ]
          },
+         "EMBED_T": {
+            "description": "Randomly picked description from a set of size one.",
+            "type": "object",
+            "properties": {
+               "b": {
+                  "description": "Randomly picked description from a set of size one.",
+                  "type": "integer"
+               }
+            }
+         },
          "FOO": {
             "description": "Randomly picked description from a set of size one.",
             "type": "object",
diff --git a/encoding/openapi/testdata/oneof-resolve.json b/encoding/openapi/testdata/oneof-resolve.json
index 038f2ac..2b894b0 100644
--- a/encoding/openapi/testdata/oneof-resolve.json
+++ b/encoding/openapi/testdata/oneof-resolve.json
@@ -13,42 +13,100 @@
                "a": {
                   "type": "integer"
                },
-               "b": {
+               "d": {
+                  "type": "object",
+                  "properties": {
+                     "b": {
+                        "type": "integer"
+                     }
+                  }
+               },
+               "e": {
                   "type": "integer"
                },
+               "b": {
+                  "type": "object",
+                  "properties": {
+                     "b": {
+                        "type": "integer"
+                     }
+                  }
+               },
                "c": {
                   "type": "integer"
                }
             },
-            "oneOf": [
+            "allOf": [
                {
-                  "not": {
-                     "anyOf": [
-                        {
-                           "required": [
-                              "b"
-                           ]
-                        },
-                        {
-                           "required": [
-                              "c"
+                  "oneOf": [
+                     {
+                        "not": {
+                           "anyOf": [
+                              {
+                                 "required": [
+                                    "b"
+                                 ]
+                              },
+                              {
+                                 "required": [
+                                    "c"
+                                 ]
+                              }
                            ]
                         }
-                     ]
-                  }
-               },
-               {
-                  "required": [
-                     "b"
+                     },
+                     {
+                        "required": [
+                           "b"
+                        ]
+                     },
+                     {
+                        "required": [
+                           "c"
+                        ]
+                     }
                   ]
                },
                {
-                  "required": [
-                     "c"
+                  "oneOf": [
+                     {
+                        "not": {
+                           "anyOf": [
+                              {
+                                 "required": [
+                                    "d"
+                                 ]
+                              },
+                              {
+                                 "required": [
+                                    "e"
+                                 ]
+                              }
+                           ]
+                        }
+                     },
+                     {
+                        "required": [
+                           "d"
+                        ]
+                     },
+                     {
+                        "required": [
+                           "e"
+                        ]
+                     }
                   ]
                }
             ]
          },
+         "Embed.T": {
+            "type": "object",
+            "properties": {
+               "b": {
+                  "type": "integer"
+               }
+            }
+         },
          "Foo": {
             "type": "object",
             "required": [
diff --git a/encoding/openapi/testdata/oneof.cue b/encoding/openapi/testdata/oneof.cue
index 6fa37d4..a78285d 100644
--- a/encoding/openapi/testdata/oneof.cue
+++ b/encoding/openapi/testdata/oneof.cue
@@ -47,9 +47,15 @@
 	a?: int
 
 	close({}) |
-	close({b: int}) |
+	close({b: T}) |
 	close({c: int})
 
+	T :: {b?: int}
+
+	close({}) |
+	close({d: T}) |
+	close({e: int})
+
 	// TODO: maybe support builtin to write this as
 	// oneof({},
 	// {b: int},
diff --git a/encoding/openapi/testdata/oneof.json b/encoding/openapi/testdata/oneof.json
index 48ce218..6f0c9f6 100644
--- a/encoding/openapi/testdata/oneof.json
+++ b/encoding/openapi/testdata/oneof.json
@@ -11,55 +11,117 @@
                   "type": "integer"
                }
             },
-            "oneOf": [
+            "allOf": [
                {
-                  "not": {
-                     "anyOf": [
-                        {
-                           "required": [
-                              "b"
-                           ],
-                           "properties": {
-                              "b": {
-                                 "type": "integer"
+                  "oneOf": [
+                     {
+                        "not": {
+                           "anyOf": [
+                              {
+                                 "required": [
+                                    "b"
+                                 ],
+                                 "properties": {
+                                    "b": {
+                                       "$ref": "#/components/schemas/Embed.T"
+                                    }
+                                 }
+                              },
+                              {
+                                 "required": [
+                                    "c"
+                                 ],
+                                 "properties": {
+                                    "c": {
+                                       "type": "integer"
+                                    }
+                                 }
                               }
-                           }
-                        },
-                        {
-                           "required": [
-                              "c"
-                           ],
-                           "properties": {
-                              "c": {
-                                 "type": "integer"
-                              }
+                           ]
+                        }
+                     },
+                     {
+                        "required": [
+                           "b"
+                        ],
+                        "properties": {
+                           "b": {
+                              "$ref": "#/components/schemas/Embed.T"
                            }
                         }
-                     ]
-                  }
+                     },
+                     {
+                        "required": [
+                           "c"
+                        ],
+                        "properties": {
+                           "c": {
+                              "type": "integer"
+                           }
+                        }
+                     }
+                  ]
                },
                {
-                  "required": [
-                     "b"
-                  ],
-                  "properties": {
-                     "b": {
-                        "type": "integer"
+                  "oneOf": [
+                     {
+                        "not": {
+                           "anyOf": [
+                              {
+                                 "required": [
+                                    "d"
+                                 ],
+                                 "properties": {
+                                    "d": {
+                                       "$ref": "#/components/schemas/Embed.T"
+                                    }
+                                 }
+                              },
+                              {
+                                 "required": [
+                                    "e"
+                                 ],
+                                 "properties": {
+                                    "e": {
+                                       "type": "integer"
+                                    }
+                                 }
+                              }
+                           ]
+                        }
+                     },
+                     {
+                        "required": [
+                           "d"
+                        ],
+                        "properties": {
+                           "d": {
+                              "$ref": "#/components/schemas/Embed.T"
+                           }
+                        }
+                     },
+                     {
+                        "required": [
+                           "e"
+                        ],
+                        "properties": {
+                           "e": {
+                              "type": "integer"
+                           }
+                        }
                      }
-                  }
-               },
-               {
-                  "required": [
-                     "c"
-                  ],
-                  "properties": {
-                     "c": {
-                        "type": "integer"
-                     }
-                  }
+                  ]
                }
             ]
          },
+         "Embed.T": {
+            "type": "object",
+            "properties": {
+               "b": {
+                  "type": "integer"
+               }
+            }
+         },
          "Foo": {
             "type": "object",
             "required": [
diff --git a/encoding/openapi/testdata/openapi-norefs.json b/encoding/openapi/testdata/openapi-norefs.json
index d39a589..2839706 100644
--- a/encoding/openapi/testdata/openapi-norefs.json
+++ b/encoding/openapi/testdata/openapi-norefs.json
@@ -177,6 +177,11 @@
             "oneOf": [
                {
                   "required": [
+                     "a"
+                  ]
+               },
+               {
+                  "required": [
                      "b"
                   ]
                },
diff --git a/encoding/openapi/testdata/openapi.json b/encoding/openapi/testdata/openapi.json
index ef7d41c..8f8502f 100644
--- a/encoding/openapi/testdata/openapi.json
+++ b/encoding/openapi/testdata/openapi.json
@@ -166,6 +166,16 @@
             "oneOf": [
                {
                   "required": [
+                     "a"
+                  ],
+                  "properties": {
+                     "a": {
+                        "type": "number"
+                     }
+                  }
+               },
+               {
+                  "required": [
                      "b"
                   ],
                   "properties": {