encoding/openapi: convert CUE to openapi schemas

Change-Id: Iea3369d702f7cb91e49e61153518c04d6845f03c
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2120
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/encoding/openapi/testdata/openapi-norefs.json b/encoding/openapi/testdata/openapi-norefs.json
new file mode 100644
index 0000000..075be6b
--- /dev/null
+++ b/encoding/openapi/testdata/openapi-norefs.json
@@ -0,0 +1,311 @@
+{
+   "openapi": "3.0.0",
+   "components": {
+      "schema": {
+         "MyMessage": {
+            "description": "MyMessage is my message.",
+            "allOf": [
+               {
+                  "type": "object",
+                  "required": [
+                     "foo",
+                     "bar"
+                  ],
+                  "properties": {
+                     "bar": {
+                        "type": "array",
+                        "items": {
+                           "type": "string"
+                        },
+                        "default": []
+                     },
+                     "foo": {
+                        "type": "number",
+                        "exclusiveMinimum": 10,
+                        "exclusiveMaximum": 1000
+                     },
+                     "port": {
+                        "type": "object",
+                        "required": [
+                           "port",
+                           "obj"
+                        ],
+                        "properties": {
+                           "obj": {
+                              "type": "array",
+                              "items": {
+                                 "type": "integer"
+                              },
+                              "default": []
+                           },
+                           "port": {
+                              "type": "integer"
+                           }
+                        }
+                     }
+                  }
+               },
+               {
+                  "type": "object",
+                  "anyOf": [
+                     {
+                        "type": "object",
+                        "required": [
+                           "a"
+                        ],
+                        "properties": {
+                           "a": {
+                              "description": "Field a.",
+                              "type": "integer",
+                              "enum": [
+                                 1
+                              ]
+                           }
+                        }
+                     },
+                     {
+                        "type": "object",
+                        "required": [
+                           "b"
+                        ],
+                        "properties": {
+                           "b": {
+                              "type": "string"
+                           }
+                        }
+                     }
+                  ]
+               }
+            ]
+         },
+         "Port": {
+            "type": "object",
+            "required": [
+               "port",
+               "obj"
+            ],
+            "properties": {
+               "obj": {
+                  "type": "array",
+                  "items": {
+                     "type": "integer"
+                  },
+                  "default": []
+               },
+               "port": {
+                  "type": "integer"
+               }
+            }
+         },
+         "Int32": {
+            "type": "integer",
+            "minimum": -2147483648,
+            "maximum": 2147483647
+         },
+         "YourMessage": {
+            "anyOf": [
+               {
+                  "type": "object",
+                  "required": [
+                     "b"
+                  ],
+                  "properties": {
+                     "a": {
+                        "type": "string"
+                     },
+                     "b": {
+                        "type": "string"
+                     }
+                  }
+               },
+               {
+                  "type": "object",
+                  "required": [
+                     "b"
+                  ],
+                  "properties": {
+                     "a": {
+                        "type": "string"
+                     },
+                     "b": {
+                        "type": "number"
+                     }
+                  }
+               }
+            ]
+         },
+         "YourMessage2": {
+            "allOf": [
+               {
+                  "anyOf": [
+                     {
+                        "type": "object",
+                        "required": [
+                           "a"
+                        ],
+                        "properties": {
+                           "a": {
+                              "type": "number"
+                           }
+                        }
+                     },
+                     {
+                        "type": "object",
+                        "required": [
+                           "b"
+                        ],
+                        "properties": {
+                           "b": {
+                              "type": "number"
+                           }
+                        }
+                     }
+                  ]
+               },
+               {
+                  "anyOf": [
+                     {
+                        "type": "object",
+                        "required": [
+                           "c"
+                        ],
+                        "properties": {
+                           "c": {
+                              "type": "number"
+                           }
+                        }
+                     },
+                     {
+                        "type": "object",
+                        "required": [
+                           "d"
+                        ],
+                        "properties": {
+                           "d": {
+                              "type": "number"
+                           }
+                        }
+                     }
+                  ]
+               },
+               {
+                  "anyOf": [
+                     {
+                        "type": "object",
+                        "required": [
+                           "e"
+                        ],
+                        "properties": {
+                           "e": {
+                              "type": "number"
+                           }
+                        }
+                     },
+                     {
+                        "type": "object",
+                        "required": [
+                           "f"
+                        ],
+                        "properties": {
+                           "f": {
+                              "type": "number"
+                           }
+                        }
+                     }
+                  ]
+               }
+            ]
+         },
+         "Msg2": {
+            "anyOf": [
+               {
+                  "type": "object",
+                  "required": [
+                     "b"
+                  ],
+                  "properties": {
+                     "b": {
+                        "type": "number"
+                     }
+                  }
+               },
+               {
+                  "type": "object",
+                  "required": [
+                     "a"
+                  ],
+                  "properties": {
+                     "a": {
+                        "type": "string"
+                     }
+                  }
+               }
+            ]
+         },
+         "Enum": {
+            "enum": [
+               "foo",
+               "bar",
+               "baz"
+            ]
+         },
+         "List": {
+            "type": "array",
+            "items": {
+               "type": "number"
+            },
+            "default": [
+               1,
+               2,
+               3
+            ]
+         },
+         "DefaultStruct": {
+            "allOf": [
+               {
+                  "anyOf": [
+                     {
+                        "type": "object",
+                        "required": [
+                           "port",
+                           "obj"
+                        ],
+                        "properties": {
+                           "obj": {
+                              "type": "array",
+                              "items": {
+                                 "type": "integer"
+                              },
+                              "default": []
+                           },
+                           "port": {
+                              "type": "integer"
+                           }
+                        }
+                     },
+                     {
+                        "type": "object",
+                        "required": [
+                           "port"
+                        ],
+                        "properties": {
+                           "port": {
+                              "type": "integer",
+                              "enum": [
+                                 1
+                              ]
+                           }
+                        }
+                     }
+                  ]
+               },
+               {
+                  "default": {
+                     "port": 1
+                  }
+               }
+            ]
+         }
+      }
+   }
+}
\ No newline at end of file
diff --git a/encoding/openapi/testdata/openapi.cue b/encoding/openapi/testdata/openapi.cue
new file mode 100644
index 0000000..c4308e8
--- /dev/null
+++ b/encoding/openapi/testdata/openapi.cue
@@ -0,0 +1,39 @@
+package openapi
+
+// MyMessage is my message.
+MyMessage: {
+	port?: Port & {} @protobuf(1)
+
+	foo: Int32 & >10 & <1000 & int32 @protobuf(2)
+
+	bar: [...string] @protobuf(3)
+}
+
+MyMessage: {
+	// Field a.
+	a: 1
+} | {
+	b: string //2: crash
+}
+
+YourMessage: ({a: number} | {b: string} | {b: number}) & {a?: string}
+
+YourMessage2: ({a: number} | {b: number}) &
+	({c: number} | {d: number}) &
+	({e: number} | {f: number})
+
+Msg2: {b: number} | {a: string}
+
+Int32: int32
+
+Enum: "foo" | "bar" | "baz"
+
+List: [...number] | *[1, 2, 3]
+
+DefaultStruct: Port | *{port: 1}
+
+Port: {
+	port: int
+
+	obj: [...int]
+}
diff --git a/encoding/openapi/testdata/openapi.json b/encoding/openapi/testdata/openapi.json
new file mode 100644
index 0000000..c6cc8cb
--- /dev/null
+++ b/encoding/openapi/testdata/openapi.json
@@ -0,0 +1,287 @@
+{
+   "openapi": "3.0.0",
+   "components": {
+      "schema": {
+         "MyMessage": {
+            "description": "MyMessage is my message.",
+            "allOf": [
+               {
+                  "type": "object",
+                  "required": [
+                     "foo",
+                     "bar"
+                  ],
+                  "properties": {
+                     "bar": {
+                        "type": "array",
+                        "items": {
+                           "type": "string"
+                        },
+                        "default": []
+                     },
+                     "foo": {
+                        "allOf": [
+                           {
+                              "$ref": "#/components/schema/Int32"
+                           },
+                           {
+                              "type": "number",
+                              "exclusiveMinimum": 10,
+                              "exclusiveMaximum": 1000
+                           }
+                        ]
+                     },
+                     "port": {
+                        "$ref": "#/components/schema/Port",
+                        "type": "object"
+                     }
+                  }
+               },
+               {
+                  "type": "object",
+                  "anyOf": [
+                     {
+                        "type": "object",
+                        "required": [
+                           "a"
+                        ],
+                        "properties": {
+                           "a": {
+                              "description": "Field a.",
+                              "type": "integer",
+                              "enum": [
+                                 1
+                              ]
+                           }
+                        }
+                     },
+                     {
+                        "type": "object",
+                        "required": [
+                           "b"
+                        ],
+                        "properties": {
+                           "b": {
+                              "type": "string"
+                           }
+                        }
+                     }
+                  ]
+               }
+            ]
+         },
+         "Port": {
+            "type": "object",
+            "required": [
+               "port",
+               "obj"
+            ],
+            "properties": {
+               "obj": {
+                  "type": "array",
+                  "items": {
+                     "type": "integer"
+                  },
+                  "default": []
+               },
+               "port": {
+                  "type": "integer"
+               }
+            }
+         },
+         "Int32": {
+            "type": "integer",
+            "minimum": -2147483648,
+            "maximum": 2147483647
+         },
+         "YourMessage": {
+            "anyOf": [
+               {
+                  "type": "object",
+                  "required": [
+                     "b"
+                  ],
+                  "properties": {
+                     "a": {
+                        "type": "string"
+                     },
+                     "b": {
+                        "type": "string"
+                     }
+                  }
+               },
+               {
+                  "type": "object",
+                  "required": [
+                     "b"
+                  ],
+                  "properties": {
+                     "a": {
+                        "type": "string"
+                     },
+                     "b": {
+                        "type": "number"
+                     }
+                  }
+               }
+            ]
+         },
+         "YourMessage2": {
+            "allOf": [
+               {
+                  "anyOf": [
+                     {
+                        "type": "object",
+                        "required": [
+                           "a"
+                        ],
+                        "properties": {
+                           "a": {
+                              "type": "number"
+                           }
+                        }
+                     },
+                     {
+                        "type": "object",
+                        "required": [
+                           "b"
+                        ],
+                        "properties": {
+                           "b": {
+                              "type": "number"
+                           }
+                        }
+                     }
+                  ]
+               },
+               {
+                  "anyOf": [
+                     {
+                        "type": "object",
+                        "required": [
+                           "c"
+                        ],
+                        "properties": {
+                           "c": {
+                              "type": "number"
+                           }
+                        }
+                     },
+                     {
+                        "type": "object",
+                        "required": [
+                           "d"
+                        ],
+                        "properties": {
+                           "d": {
+                              "type": "number"
+                           }
+                        }
+                     }
+                  ]
+               },
+               {
+                  "anyOf": [
+                     {
+                        "type": "object",
+                        "required": [
+                           "e"
+                        ],
+                        "properties": {
+                           "e": {
+                              "type": "number"
+                           }
+                        }
+                     },
+                     {
+                        "type": "object",
+                        "required": [
+                           "f"
+                        ],
+                        "properties": {
+                           "f": {
+                              "type": "number"
+                           }
+                        }
+                     }
+                  ]
+               }
+            ]
+         },
+         "Msg2": {
+            "anyOf": [
+               {
+                  "type": "object",
+                  "required": [
+                     "b"
+                  ],
+                  "properties": {
+                     "b": {
+                        "type": "number"
+                     }
+                  }
+               },
+               {
+                  "type": "object",
+                  "required": [
+                     "a"
+                  ],
+                  "properties": {
+                     "a": {
+                        "type": "string"
+                     }
+                  }
+               }
+            ]
+         },
+         "Enum": {
+            "enum": [
+               "foo",
+               "bar",
+               "baz"
+            ]
+         },
+         "List": {
+            "type": "array",
+            "items": {
+               "type": "number"
+            },
+            "default": [
+               1,
+               2,
+               3
+            ]
+         },
+         "DefaultStruct": {
+            "allOf": [
+               {
+                  "anyOf": [
+                     {
+                        "$ref": "#/components/schema/Port"
+                     },
+                     {
+                        "type": "object",
+                        "required": [
+                           "port"
+                        ],
+                        "properties": {
+                           "port": {
+                              "type": "integer",
+                              "enum": [
+                                 1
+                              ]
+                           }
+                        }
+                     }
+                  ]
+               },
+               {
+                  "default": {
+                     "port": 1
+                  }
+               }
+            ]
+         }
+      }
+   }
+}
\ No newline at end of file