diff --git a/example/output/json/components.schemas/Address.json b/example/output/json/components.schemas/Address.json index b039275..5f45d2a 100644 --- a/example/output/json/components.schemas/Address.json +++ b/example/output/json/components.schemas/Address.json @@ -15,5 +15,5 @@ } }, "title": "Address", - "$id": "Address.json" + "$id": "components.schemas/Address.json" } \ No newline at end of file diff --git a/example/output/json/components.schemas/ApiResponse.json b/example/output/json/components.schemas/ApiResponse.json index 58f6f16..f39bfb0 100644 --- a/example/output/json/components.schemas/ApiResponse.json +++ b/example/output/json/components.schemas/ApiResponse.json @@ -15,5 +15,5 @@ } }, "title": "ApiResponse", - "$id": "ApiResponse.json" + "$id": "components.schemas/ApiResponse.json" } \ No newline at end of file diff --git a/example/output/json/components.schemas/Category.json b/example/output/json/components.schemas/Category.json index fd3e08d..a2ea851 100644 --- a/example/output/json/components.schemas/Category.json +++ b/example/output/json/components.schemas/Category.json @@ -12,5 +12,5 @@ } }, "title": "Category", - "$id": "Category.json" + "$id": "components.schemas/Category.json" } \ No newline at end of file diff --git a/example/output/json/components.schemas/Customer.json b/example/output/json/components.schemas/Customer.json index 6c35bed..c639998 100644 --- a/example/output/json/components.schemas/Customer.json +++ b/example/output/json/components.schemas/Customer.json @@ -18,5 +18,5 @@ } }, "title": "Customer", - "$id": "Customer.json" + "$id": "components.schemas/Customer.json" } \ No newline at end of file diff --git a/example/output/json/components.schemas/Order.json b/example/output/json/components.schemas/Order.json index 3447d31..5cfc140 100644 --- a/example/output/json/components.schemas/Order.json +++ b/example/output/json/components.schemas/Order.json @@ -37,5 +37,5 @@ } }, "title": "Order", - "$id": "Order.json" + "$id": "components.schemas/Order.json" } \ No newline at end of file diff --git a/example/output/json/components.schemas/Pet.json b/example/output/json/components.schemas/Pet.json index 4e4330b..677f04f 100644 --- a/example/output/json/components.schemas/Pet.json +++ b/example/output/json/components.schemas/Pet.json @@ -47,5 +47,5 @@ } }, "title": "Pet", - "$id": "Pet.json" + "$id": "components.schemas/Pet.json" } \ No newline at end of file diff --git a/example/output/json/components.schemas/Tag.json b/example/output/json/components.schemas/Tag.json index 89f882c..1798ee3 100644 --- a/example/output/json/components.schemas/Tag.json +++ b/example/output/json/components.schemas/Tag.json @@ -12,5 +12,5 @@ } }, "title": "Tag", - "$id": "Tag.json" + "$id": "components.schemas/Tag.json" } \ No newline at end of file diff --git a/example/output/json/components.schemas/User.json b/example/output/json/components.schemas/User.json index 94440d7..b538efc 100644 --- a/example/output/json/components.schemas/User.json +++ b/example/output/json/components.schemas/User.json @@ -34,5 +34,5 @@ } }, "title": "User", - "$id": "User.json" + "$id": "components.schemas/User.json" } \ No newline at end of file diff --git a/example/output/json/paths/Pet.json b/example/output/json/paths/Pet.json new file mode 100644 index 0000000..9bddacf --- /dev/null +++ b/example/output/json/paths/Pet.json @@ -0,0 +1,129 @@ +{ + "type": "object", + "properties": { + "put": { + "type": "object", + "required": [ + "requestBody", + "responses" + ], + "description": "Update an existing pet by Id", + "summary": "Update an existing pet", + "properties": { + "requestBody": { + "type": "object", + "properties": { + "content": { + "type": "object", + "required": [], + "properties": { + "application/json": { + "$ref": "../components.schemas/Pet.json", + "description": "Update an existent pet in the store" + }, + "application/xml": { + "$ref": "../components.schemas/Pet.json", + "description": "Update an existent pet in the store" + }, + "application/x-www-form-urlencoded": { + "$ref": "../components.schemas/Pet.json", + "description": "Update an existent pet in the store" + } + } + } + }, + "description": "Update an existent pet in the store" + }, + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/json": { + "$ref": "../components.schemas/Pet.json", + "description": "Successful operation" + }, + "application/xml": { + "$ref": "../components.schemas/Pet.json", + "description": "Successful operation" + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + }, + "405": { + "description": "Validation exception" + } + } + } + } + }, + "post": { + "type": "object", + "required": [ + "requestBody", + "responses" + ], + "description": "Add a new pet to the store", + "summary": "Add a new pet to the store", + "properties": { + "requestBody": { + "type": "object", + "properties": { + "content": { + "type": "object", + "required": [], + "properties": { + "application/json": { + "$ref": "../components.schemas/Pet.json", + "description": "Create a new pet in the store" + }, + "application/xml": { + "$ref": "../components.schemas/Pet.json", + "description": "Create a new pet in the store" + }, + "application/x-www-form-urlencoded": { + "$ref": "../components.schemas/Pet.json", + "description": "Create a new pet in the store" + } + } + } + }, + "description": "Create a new pet in the store" + }, + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/json": { + "$ref": "../components.schemas/Pet.json", + "description": "Successful operation" + }, + "application/xml": { + "$ref": "../components.schemas/Pet.json", + "description": "Successful operation" + } + } + }, + "405": { + "description": "Invalid input" + } + } + } + } + } + }, + "required": [ + "put", + "post" + ], + "title": "Pet", + "$id": "paths/Pet.json" +} \ No newline at end of file diff --git a/example/output/json/paths/PetFindByStatus.json b/example/output/json/paths/PetFindByStatus.json new file mode 100644 index 0000000..0c0b144 --- /dev/null +++ b/example/output/json/paths/PetFindByStatus.json @@ -0,0 +1,63 @@ +{ + "type": "object", + "properties": { + "get": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "description": "Multiple status values can be provided with comma separated strings", + "summary": "Finds Pets by status", + "properties": { + "parameters": { + "type": "object", + "properties": { + "status": { + "type": "string", + "default": "available", + "enum": [ + "available", + "pending", + "sold" + ], + "description": "Status values that need to be considered for filter" + } + } + }, + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/json": { + "type": "array", + "items": { + "$ref": "../components.schemas/Pet.json" + }, + "description": "successful operation" + }, + "application/xml": { + "type": "array", + "items": { + "$ref": "../components.schemas/Pet.json" + }, + "description": "successful operation" + } + } + }, + "400": { + "description": "Invalid status value" + } + } + } + } + } + }, + "required": [ + "get" + ], + "title": "PetFindByStatus", + "$id": "paths/PetFindByStatus.json" +} \ No newline at end of file diff --git a/example/output/json/paths/PetFindByTags.json b/example/output/json/paths/PetFindByTags.json new file mode 100644 index 0000000..15c9adb --- /dev/null +++ b/example/output/json/paths/PetFindByTags.json @@ -0,0 +1,60 @@ +{ + "type": "object", + "properties": { + "get": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "description": "Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + "summary": "Finds Pets by tags", + "properties": { + "parameters": { + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags to filter by" + } + } + }, + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/json": { + "type": "array", + "items": { + "$ref": "../components.schemas/Pet.json" + }, + "description": "successful operation" + }, + "application/xml": { + "type": "array", + "items": { + "$ref": "../components.schemas/Pet.json" + }, + "description": "successful operation" + } + } + }, + "400": { + "description": "Invalid tag value" + } + } + } + } + } + }, + "required": [ + "get" + ], + "title": "PetFindByTags", + "$id": "paths/PetFindByTags.json" +} \ No newline at end of file diff --git a/example/output/json/paths/PetPetId.json b/example/output/json/paths/PetPetId.json new file mode 100644 index 0000000..a9f0e53 --- /dev/null +++ b/example/output/json/paths/PetPetId.json @@ -0,0 +1,140 @@ +{ + "type": "object", + "properties": { + "get": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "description": "Returns a single pet", + "summary": "Find pet by ID", + "properties": { + "parameters": { + "type": "object", + "properties": { + "petId": { + "type": "integer", + "format": "int64", + "minimum": -9223372036854776000, + "maximum": 9223372036854776000, + "description": "ID of pet to return" + } + }, + "required": [ + "petId" + ] + }, + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/json": { + "$ref": "../components.schemas/Pet.json", + "description": "successful operation" + }, + "application/xml": { + "$ref": "../components.schemas/Pet.json", + "description": "successful operation" + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + } + } + } + } + }, + "post": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "summary": "Updates a pet in the store with form data", + "properties": { + "parameters": { + "type": "object", + "properties": { + "petId": { + "type": "integer", + "format": "int64", + "minimum": -9223372036854776000, + "maximum": 9223372036854776000, + "description": "ID of pet that needs to be updated" + }, + "name": { + "type": "string", + "description": "Name of pet that needs to be updated" + }, + "status": { + "type": "string", + "description": "Status of pet that needs to be updated" + } + }, + "required": [ + "petId" + ] + }, + "responses": { + "type": "object", + "properties": { + "405": { + "description": "Invalid input" + } + } + } + } + }, + "delete": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "description": "delete a pet", + "summary": "Deletes a pet", + "properties": { + "parameters": { + "type": "object", + "properties": { + "api_key": { + "type": "string" + }, + "petId": { + "type": "integer", + "format": "int64", + "minimum": -9223372036854776000, + "maximum": 9223372036854776000, + "description": "Pet id to delete" + } + }, + "required": [ + "petId" + ] + }, + "responses": { + "type": "object", + "properties": { + "400": { + "description": "Invalid pet value" + } + } + } + } + } + }, + "required": [ + "get", + "post", + "delete" + ], + "title": "PetPetId", + "$id": "paths/PetPetId.json" +} \ No newline at end of file diff --git a/example/output/json/paths/PetPetIdUploadImage.json b/example/output/json/paths/PetPetIdUploadImage.json new file mode 100644 index 0000000..fb4d079 --- /dev/null +++ b/example/output/json/paths/PetPetIdUploadImage.json @@ -0,0 +1,65 @@ +{ + "type": "object", + "properties": { + "post": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "summary": "uploads an image", + "properties": { + "requestBody": { + "type": "object", + "properties": { + "content": { + "type": "object", + "required": [], + "properties": { + "application/octet-stream": {} + } + } + } + }, + "parameters": { + "type": "object", + "properties": { + "petId": { + "type": "integer", + "format": "int64", + "minimum": -9223372036854776000, + "maximum": 9223372036854776000, + "description": "ID of pet to update" + }, + "additionalMetadata": { + "type": "string", + "description": "Additional Metadata" + } + }, + "required": [ + "petId" + ] + }, + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/json": { + "$ref": "../components.schemas/ApiResponse.json", + "description": "successful operation" + } + } + } + } + } + } + } + }, + "required": [ + "post" + ], + "title": "PetPetIdUploadImage", + "$id": "paths/PetPetIdUploadImage.json" +} \ No newline at end of file diff --git a/example/output/json/paths/StoreInventory.json b/example/output/json/paths/StoreInventory.json new file mode 100644 index 0000000..47decac --- /dev/null +++ b/example/output/json/paths/StoreInventory.json @@ -0,0 +1,40 @@ +{ + "type": "object", + "properties": { + "get": { + "type": "object", + "required": [ + "responses" + ], + "description": "Returns a map of status codes to quantities", + "summary": "Returns pet inventories by status", + "properties": { + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/json": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32", + "minimum": -2147483648, + "maximum": 2147483647 + }, + "description": "successful operation" + } + } + } + } + } + } + } + }, + "required": [ + "get" + ], + "title": "StoreInventory", + "$id": "paths/StoreInventory.json" +} \ No newline at end of file diff --git a/example/output/json/paths/StoreOrder.json b/example/output/json/paths/StoreOrder.json new file mode 100644 index 0000000..af58909 --- /dev/null +++ b/example/output/json/paths/StoreOrder.json @@ -0,0 +1,57 @@ +{ + "type": "object", + "properties": { + "post": { + "type": "object", + "required": [ + "responses" + ], + "description": "Place a new order in the store", + "summary": "Place an order for a pet", + "properties": { + "requestBody": { + "type": "object", + "properties": { + "content": { + "type": "object", + "required": [], + "properties": { + "application/json": { + "$ref": "../components.schemas/Order.json" + }, + "application/xml": { + "$ref": "../components.schemas/Order.json" + }, + "application/x-www-form-urlencoded": { + "$ref": "../components.schemas/Order.json" + } + } + } + } + }, + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/json": { + "$ref": "../components.schemas/Order.json", + "description": "successful operation" + } + } + }, + "405": { + "description": "Invalid input" + } + } + } + } + } + }, + "required": [ + "post" + ], + "title": "StoreOrder", + "$id": "paths/StoreOrder.json" +} \ No newline at end of file diff --git a/example/output/json/paths/StoreOrderOrderId.json b/example/output/json/paths/StoreOrderOrderId.json new file mode 100644 index 0000000..13abd0b --- /dev/null +++ b/example/output/json/paths/StoreOrderOrderId.json @@ -0,0 +1,98 @@ +{ + "type": "object", + "properties": { + "get": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "description": "For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.", + "summary": "Find purchase order by ID", + "properties": { + "parameters": { + "type": "object", + "properties": { + "orderId": { + "type": "integer", + "format": "int64", + "minimum": -9223372036854776000, + "maximum": 9223372036854776000, + "description": "ID of order that needs to be fetched" + } + }, + "required": [ + "orderId" + ] + }, + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/json": { + "$ref": "../components.schemas/Order.json", + "description": "successful operation" + }, + "application/xml": { + "$ref": "../components.schemas/Order.json", + "description": "successful operation" + } + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + } + } + }, + "delete": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "description": "For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors", + "summary": "Delete purchase order by ID", + "properties": { + "parameters": { + "type": "object", + "properties": { + "orderId": { + "type": "integer", + "format": "int64", + "minimum": -9223372036854776000, + "maximum": 9223372036854776000, + "description": "ID of the order that needs to be deleted" + } + }, + "required": [ + "orderId" + ] + }, + "responses": { + "type": "object", + "properties": { + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + } + } + } + }, + "required": [ + "get", + "delete" + ], + "title": "StoreOrderOrderId", + "$id": "paths/StoreOrderOrderId.json" +} \ No newline at end of file diff --git a/example/output/json/paths/User.json b/example/output/json/paths/User.json new file mode 100644 index 0000000..5d39426 --- /dev/null +++ b/example/output/json/paths/User.json @@ -0,0 +1,62 @@ +{ + "type": "object", + "properties": { + "post": { + "type": "object", + "required": [ + "responses" + ], + "description": "This can only be done by the logged in user.", + "summary": "Create user", + "properties": { + "requestBody": { + "type": "object", + "properties": { + "content": { + "type": "object", + "required": [], + "properties": { + "application/json": { + "$ref": "../components.schemas/User.json", + "description": "Created user object" + }, + "application/xml": { + "$ref": "../components.schemas/User.json", + "description": "Created user object" + }, + "application/x-www-form-urlencoded": { + "$ref": "../components.schemas/User.json", + "description": "Created user object" + } + } + } + }, + "description": "Created user object" + }, + "responses": { + "type": "object", + "properties": { + "default": { + "type": "object", + "properties": { + "application/json": { + "$ref": "../components.schemas/User.json", + "description": "successful operation" + }, + "application/xml": { + "$ref": "../components.schemas/User.json", + "description": "successful operation" + } + } + } + } + } + } + } + }, + "required": [ + "post" + ], + "title": "User", + "$id": "paths/User.json" +} \ No newline at end of file diff --git a/example/output/json/paths/UserCreateWithList.json b/example/output/json/paths/UserCreateWithList.json new file mode 100644 index 0000000..5015429 --- /dev/null +++ b/example/output/json/paths/UserCreateWithList.json @@ -0,0 +1,53 @@ +{ + "type": "object", + "properties": { + "post": { + "type": "object", + "required": [ + "responses" + ], + "description": "Creates list of users with given input array", + "summary": "Creates list of users with given input array", + "properties": { + "requestBody": { + "type": "object", + "properties": { + "content": { + "type": "object", + "required": [], + "properties": { + "application/json": {} + } + } + } + }, + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/json": { + "$ref": "../components.schemas/User.json", + "description": "Successful operation" + }, + "application/xml": { + "$ref": "../components.schemas/User.json", + "description": "Successful operation" + } + } + }, + "default": { + "description": "successful operation" + } + } + } + } + } + }, + "required": [ + "post" + ], + "title": "UserCreateWithList", + "$id": "paths/UserCreateWithList.json" +} \ No newline at end of file diff --git a/example/output/json/paths/UserLogin.json b/example/output/json/paths/UserLogin.json new file mode 100644 index 0000000..a73db05 --- /dev/null +++ b/example/output/json/paths/UserLogin.json @@ -0,0 +1,54 @@ +{ + "type": "object", + "properties": { + "get": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "summary": "Logs user into the system", + "properties": { + "parameters": { + "type": "object", + "properties": { + "username": { + "type": "string", + "description": "The user name for login" + }, + "password": { + "type": "string", + "description": "The password for login in clear text" + } + } + }, + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/xml": { + "type": "string", + "description": "successful operation" + }, + "application/json": { + "type": "string", + "description": "successful operation" + } + } + }, + "400": { + "description": "Invalid username/password supplied" + } + } + } + } + } + }, + "required": [ + "get" + ], + "title": "UserLogin", + "$id": "paths/UserLogin.json" +} \ No newline at end of file diff --git a/example/output/json/paths/UserLogout.json b/example/output/json/paths/UserLogout.json new file mode 100644 index 0000000..c1ac3d3 --- /dev/null +++ b/example/output/json/paths/UserLogout.json @@ -0,0 +1,32 @@ +{ + "type": "object", + "properties": { + "get": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "summary": "Logs out current logged in user session", + "properties": { + "parameters": { + "type": "object", + "properties": {} + }, + "responses": { + "type": "object", + "properties": { + "default": { + "description": "successful operation" + } + } + } + } + } + }, + "required": [ + "get" + ], + "title": "UserLogout", + "$id": "paths/UserLogout.json" +} \ No newline at end of file diff --git a/example/output/json/paths/UserUsername.json b/example/output/json/paths/UserUsername.json new file mode 100644 index 0000000..69160c5 --- /dev/null +++ b/example/output/json/paths/UserUsername.json @@ -0,0 +1,147 @@ +{ + "type": "object", + "properties": { + "get": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "summary": "Get user by user name", + "properties": { + "parameters": { + "type": "object", + "properties": { + "username": { + "type": "string", + "description": "The name that needs to be fetched. Use user1 for testing. " + } + }, + "required": [ + "username" + ] + }, + "responses": { + "type": "object", + "properties": { + "200": { + "type": "object", + "properties": { + "application/json": { + "$ref": "../components.schemas/User.json", + "description": "successful operation" + }, + "application/xml": { + "$ref": "../components.schemas/User.json", + "description": "successful operation" + } + } + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + } + } + } + } + }, + "put": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "description": "This can only be done by the logged in user.", + "summary": "Update user", + "properties": { + "requestBody": { + "type": "object", + "properties": { + "content": { + "type": "object", + "required": [], + "properties": { + "application/json": { + "$ref": "../components.schemas/User.json", + "description": "Update an existent user in the store" + }, + "application/xml": { + "$ref": "../components.schemas/User.json", + "description": "Update an existent user in the store" + }, + "application/x-www-form-urlencoded": { + "$ref": "../components.schemas/User.json", + "description": "Update an existent user in the store" + } + } + } + }, + "description": "Update an existent user in the store" + }, + "parameters": { + "type": "object", + "properties": { + "username": { + "type": "string", + "description": "name that need to be deleted" + } + }, + "required": [ + "username" + ] + }, + "responses": { + "type": "object", + "properties": { + "default": { + "description": "successful operation" + } + } + } + } + }, + "delete": { + "type": "object", + "required": [ + "parameters", + "responses" + ], + "description": "This can only be done by the logged in user.", + "summary": "Delete user", + "properties": { + "parameters": { + "type": "object", + "properties": { + "username": { + "type": "string", + "description": "The name that needs to be deleted" + } + }, + "required": [ + "username" + ] + }, + "responses": { + "type": "object", + "properties": { + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + } + } + } + } + } + }, + "required": [ + "get", + "put", + "delete" + ], + "title": "UserUsername", + "$id": "paths/UserUsername.json" +} \ No newline at end of file diff --git a/example/output/types/Address.d.ts b/example/output/types/components.schemas/Address.d.ts similarity index 100% rename from example/output/types/Address.d.ts rename to example/output/types/components.schemas/Address.d.ts diff --git a/example/output/types/ApiResponse.d.ts b/example/output/types/components.schemas/ApiResponse.d.ts similarity index 100% rename from example/output/types/ApiResponse.d.ts rename to example/output/types/components.schemas/ApiResponse.d.ts diff --git a/example/output/types/Category.d.ts b/example/output/types/components.schemas/Category.d.ts similarity index 100% rename from example/output/types/Category.d.ts rename to example/output/types/components.schemas/Category.d.ts diff --git a/example/output/types/Customer.d.ts b/example/output/types/components.schemas/Customer.d.ts similarity index 100% rename from example/output/types/Customer.d.ts rename to example/output/types/components.schemas/Customer.d.ts diff --git a/example/output/types/Order.d.ts b/example/output/types/components.schemas/Order.d.ts similarity index 100% rename from example/output/types/Order.d.ts rename to example/output/types/components.schemas/Order.d.ts diff --git a/example/output/types/Pet.d.ts b/example/output/types/components.schemas/Pet.d.ts similarity index 100% rename from example/output/types/Pet.d.ts rename to example/output/types/components.schemas/Pet.d.ts diff --git a/example/output/types/Tag.d.ts b/example/output/types/components.schemas/Tag.d.ts similarity index 100% rename from example/output/types/Tag.d.ts rename to example/output/types/components.schemas/Tag.d.ts diff --git a/example/output/types/User.d.ts b/example/output/types/components.schemas/User.d.ts similarity index 100% rename from example/output/types/User.d.ts rename to example/output/types/components.schemas/User.d.ts diff --git a/example/output/types/paths/Pet.d.ts b/example/output/types/paths/Pet.d.ts new file mode 100644 index 0000000..9c88d5a --- /dev/null +++ b/example/output/types/paths/Pet.d.ts @@ -0,0 +1,90 @@ +import { Pet } from '../components.schemas/Pet' +import { Category } from '../components.schemas/Category' +import { Tag } from '../components.schemas/Tag' + +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface Pet { + /** + * Update an existing pet by Id + */ + put: { + /** + * Update an existent pet in the store + */ + requestBody: { + content?: { + 'application/json'?: Pet1; + 'application/xml'?: Pet2; + 'application/x-www-form-urlencoded'?: Pet3; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + responses: { + '200'?: { + 'application/json'?: Pet4; + 'application/xml'?: Pet5; + [k: string]: unknown; + }; + /** + * Invalid ID supplied + */ + '400'?: { + [k: string]: unknown; + }; + /** + * Pet not found + */ + '404'?: { + [k: string]: unknown; + }; + /** + * Validation exception + */ + '405'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + /** + * Add a new pet to the store + */ + post: { + /** + * Create a new pet in the store + */ + requestBody: { + content?: { + 'application/json'?: Pet6; + 'application/xml'?: Pet7; + 'application/x-www-form-urlencoded'?: Pet8; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + responses: { + '200'?: { + 'application/json'?: Pet9; + 'application/xml'?: Pet10; + [k: string]: unknown; + }; + /** + * Invalid input + */ + '405'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/PetFindByStatus.d.ts b/example/output/types/paths/PetFindByStatus.d.ts new file mode 100644 index 0000000..b8c048e --- /dev/null +++ b/example/output/types/paths/PetFindByStatus.d.ts @@ -0,0 +1,47 @@ +import { Pet } from '../components.schemas/Pet' +import { Category } from '../components.schemas/Category' +import { Tag } from '../components.schemas/Tag' + +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface PetFindByStatus { + /** + * Multiple status values can be provided with comma separated strings + */ + get: { + parameters: { + /** + * Status values that need to be considered for filter + */ + status?: 'available' | 'pending' | 'sold'; + [k: string]: unknown; + }; + responses: { + '200'?: { + /** + * successful operation + */ + 'application/json'?: Pet[]; + /** + * successful operation + */ + 'application/xml'?: Pet[]; + [k: string]: unknown; + }; + /** + * Invalid status value + */ + '400'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/PetFindByTags.d.ts b/example/output/types/paths/PetFindByTags.d.ts new file mode 100644 index 0000000..a0a2123 --- /dev/null +++ b/example/output/types/paths/PetFindByTags.d.ts @@ -0,0 +1,47 @@ +import { Pet } from '../components.schemas/Pet' +import { Category } from '../components.schemas/Category' +import { Tag } from '../components.schemas/Tag' + +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface PetFindByTags { + /** + * Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. + */ + get: { + parameters: { + /** + * Tags to filter by + */ + tags?: string[]; + [k: string]: unknown; + }; + responses: { + '200'?: { + /** + * successful operation + */ + 'application/json'?: Pet[]; + /** + * successful operation + */ + 'application/xml'?: Pet[]; + [k: string]: unknown; + }; + /** + * Invalid tag value + */ + '400'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/PetPetId.d.ts b/example/output/types/paths/PetPetId.d.ts new file mode 100644 index 0000000..1cc107a --- /dev/null +++ b/example/output/types/paths/PetPetId.d.ts @@ -0,0 +1,97 @@ +import { Pet } from '../components.schemas/Pet' +import { Category } from '../components.schemas/Category' +import { Tag } from '../components.schemas/Tag' + +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface PetPetId { + /** + * Returns a single pet + */ + get: { + parameters: { + /** + * ID of pet to return + */ + petId: number; + [k: string]: unknown; + }; + responses: { + '200'?: { + 'application/json'?: Pet; + 'application/xml'?: Pet1; + [k: string]: unknown; + }; + /** + * Invalid ID supplied + */ + '400'?: { + [k: string]: unknown; + }; + /** + * Pet not found + */ + '404'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + post: { + parameters: { + /** + * ID of pet that needs to be updated + */ + petId: number; + /** + * Name of pet that needs to be updated + */ + name?: string; + /** + * Status of pet that needs to be updated + */ + status?: string; + [k: string]: unknown; + }; + responses: { + /** + * Invalid input + */ + '405'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + /** + * delete a pet + */ + delete: { + parameters: { + api_key?: string; + /** + * Pet id to delete + */ + petId: number; + [k: string]: unknown; + }; + responses: { + /** + * Invalid pet value + */ + '400'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/PetPetIdUploadImage.d.ts b/example/output/types/paths/PetPetIdUploadImage.d.ts new file mode 100644 index 0000000..559c0b8 --- /dev/null +++ b/example/output/types/paths/PetPetIdUploadImage.d.ts @@ -0,0 +1,40 @@ +import { ApiResponse } from '../components.schemas/ApiResponse' + +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface PetPetIdUploadImage { + post: { + requestBody?: { + content?: { + 'application/octet-stream'?: unknown; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + parameters: { + /** + * ID of pet to update + */ + petId: number; + /** + * Additional Metadata + */ + additionalMetadata?: string; + [k: string]: unknown; + }; + responses: { + '200'?: { + 'application/json'?: ApiResponse; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/StoreInventory.d.ts b/example/output/types/paths/StoreInventory.d.ts new file mode 100644 index 0000000..aa5debe --- /dev/null +++ b/example/output/types/paths/StoreInventory.d.ts @@ -0,0 +1,28 @@ +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface StoreInventory { + /** + * Returns a map of status codes to quantities + */ + get: { + responses: { + '200'?: { + /** + * successful operation + */ + 'application/json'?: { + [k: string]: number; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/StoreOrder.d.ts b/example/output/types/paths/StoreOrder.d.ts new file mode 100644 index 0000000..50a2af4 --- /dev/null +++ b/example/output/types/paths/StoreOrder.d.ts @@ -0,0 +1,40 @@ +import { Order } from '../components.schemas/Order' + +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface StoreOrder { + /** + * Place a new order in the store + */ + post: { + requestBody?: { + content?: { + 'application/json'?: Order; + 'application/xml'?: Order; + 'application/x-www-form-urlencoded'?: Order; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + responses: { + '200'?: { + 'application/json'?: Order1; + [k: string]: unknown; + }; + /** + * Invalid input + */ + '405'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/StoreOrderOrderId.d.ts b/example/output/types/paths/StoreOrderOrderId.d.ts new file mode 100644 index 0000000..3265f7d --- /dev/null +++ b/example/output/types/paths/StoreOrderOrderId.d.ts @@ -0,0 +1,73 @@ +import { Order } from '../components.schemas/Order' + +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface StoreOrderOrderId { + /** + * For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions. + */ + get: { + parameters: { + /** + * ID of order that needs to be fetched + */ + orderId: number; + [k: string]: unknown; + }; + responses: { + '200'?: { + 'application/json'?: Order; + 'application/xml'?: Order1; + [k: string]: unknown; + }; + /** + * Invalid ID supplied + */ + '400'?: { + [k: string]: unknown; + }; + /** + * Order not found + */ + '404'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + /** + * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + */ + delete: { + parameters: { + /** + * ID of the order that needs to be deleted + */ + orderId: number; + [k: string]: unknown; + }; + responses: { + /** + * Invalid ID supplied + */ + '400'?: { + [k: string]: unknown; + }; + /** + * Order not found + */ + '404'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/User.d.ts b/example/output/types/paths/User.d.ts new file mode 100644 index 0000000..2eef627 --- /dev/null +++ b/example/output/types/paths/User.d.ts @@ -0,0 +1,38 @@ +import { User } from '../components.schemas/User' + +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface User { + /** + * This can only be done by the logged in user. + */ + post: { + /** + * Created user object + */ + requestBody?: { + content?: { + 'application/json'?: User1; + 'application/xml'?: User2; + 'application/x-www-form-urlencoded'?: User3; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + responses: { + default?: { + 'application/json'?: User4; + 'application/xml'?: User5; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/UserCreateWithList.d.ts b/example/output/types/paths/UserCreateWithList.d.ts new file mode 100644 index 0000000..bfaf81a --- /dev/null +++ b/example/output/types/paths/UserCreateWithList.d.ts @@ -0,0 +1,39 @@ +import { User } from '../components.schemas/User' + +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface UserCreateWithList { + /** + * Creates list of users with given input array + */ + post: { + requestBody?: { + content?: { + 'application/json'?: unknown; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + responses: { + '200'?: { + 'application/json'?: User; + 'application/xml'?: User1; + [k: string]: unknown; + }; + /** + * successful operation + */ + default?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/UserLogin.d.ts b/example/output/types/paths/UserLogin.d.ts new file mode 100644 index 0000000..2d012ec --- /dev/null +++ b/example/output/types/paths/UserLogin.d.ts @@ -0,0 +1,44 @@ +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface UserLogin { + get: { + parameters: { + /** + * The user name for login + */ + username?: string; + /** + * The password for login in clear text + */ + password?: string; + [k: string]: unknown; + }; + responses: { + '200'?: { + /** + * successful operation + */ + 'application/xml'?: string; + /** + * successful operation + */ + 'application/json'?: string; + [k: string]: unknown; + }; + /** + * Invalid username/password supplied + */ + '400'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/UserLogout.d.ts b/example/output/types/paths/UserLogout.d.ts new file mode 100644 index 0000000..000482b --- /dev/null +++ b/example/output/types/paths/UserLogout.d.ts @@ -0,0 +1,25 @@ +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface UserLogout { + get: { + parameters: { + [k: string]: unknown; + }; + responses: { + /** + * successful operation + */ + default?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/example/output/types/paths/UserUsername.d.ts b/example/output/types/paths/UserUsername.d.ts new file mode 100644 index 0000000..dd4b208 --- /dev/null +++ b/example/output/types/paths/UserUsername.d.ts @@ -0,0 +1,104 @@ +import { User } from '../components.schemas/User' + +/* eslint-disable */ +/** + * This file was automatically generated by openapi-transformer-toolkit CLI/methods. + * DO NOT MODIFY IT BY HAND. Instead, modify the source OpenAPI file, + * and run openapi-transformer-toolkit CLI/methods to regenerate this file. + */ + +export interface UserUsername { + get: { + parameters: { + /** + * The name that needs to be fetched. Use user1 for testing. + */ + username: string; + [k: string]: unknown; + }; + responses: { + '200'?: { + 'application/json'?: User; + 'application/xml'?: User1; + [k: string]: unknown; + }; + /** + * Invalid username supplied + */ + '400'?: { + [k: string]: unknown; + }; + /** + * User not found + */ + '404'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + /** + * This can only be done by the logged in user. + */ + put: { + /** + * Update an existent user in the store + */ + requestBody?: { + content?: { + 'application/json'?: User2; + 'application/xml'?: User3; + 'application/x-www-form-urlencoded'?: User4; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + parameters: { + /** + * name that need to be deleted + */ + username: string; + [k: string]: unknown; + }; + responses: { + /** + * successful operation + */ + default?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + /** + * This can only be done by the logged in user. + */ + delete: { + parameters: { + /** + * The name that needs to be deleted + */ + username: string; + [k: string]: unknown; + }; + responses: { + /** + * Invalid username supplied + */ + '400'?: { + [k: string]: unknown; + }; + /** + * User not found + */ + '404'?: { + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; + }; + [k: string]: unknown; +} diff --git a/package-lock.json b/package-lock.json index a5ed248..8403ea5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "lodash.get": "^4.4.2", "lodash.trimstart": "^4.5.1", "lodash.upperfirst": "^4.3.1", - "pino": "^9.0.0", + "pino": "^8.14.1", "yaml": "^2.2.2" }, "bin": { @@ -8529,9 +8529,9 @@ } }, "node_modules/pino": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-9.0.0.tgz", - "integrity": "sha512-uI1ThkzTShNSwvsUM6b4ND8ANzWURk9zTELMztFkmnCQeR/4wkomJ+echHee5GMWGovoSfjwdeu80DsFIt7mbA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.21.0.tgz", + "integrity": "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==", "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", @@ -16754,9 +16754,9 @@ "dev": true }, "pino": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-9.0.0.tgz", - "integrity": "sha512-uI1ThkzTShNSwvsUM6b4ND8ANzWURk9zTELMztFkmnCQeR/4wkomJ+echHee5GMWGovoSfjwdeu80DsFIt7mbA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.21.0.tgz", + "integrity": "sha512-ip4qdzjkAyDDZklUaZkcRFb2iA118H9SgRh8yzTkSQK8HilsOJF7rSY8HoW5+I0M46AZgX/pxbprf2vvzQCE0Q==", "requires": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", diff --git a/package.json b/package.json index d04fb8b..0bef8f9 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,9 @@ "json2ts": "./dist/esm/src/cli.js json2ts -i ./example/output/json/components.schemas -o ./example/output/types -c ./example/json-schema-to-typescript-config.json", "lint": "eslint .", "preoas2json": "npm run build", - "oas2json": "./dist/esm/src/cli.js oas2json -i ./example/openapi.yml -o ./example/output/json", + "oas2json": "./dist/esm/src/cli.js oas2json -i ./example/openapi.yml -o ./example/output/json -p paths", "preoas2ts": "npm run build", - "oas2ts": "./dist/esm/src/cli.js oas2ts -i ./example/openapi.yml -o ./example/output/types -c ./example/json-schema-to-typescript-config.json", + "oas2ts": "./dist/esm/src/cli.js oas2ts -i ./example/openapi.yml -o ./example/output/types -c ./example/json-schema-to-typescript-config.json -p paths", "preoas2tson": "npm run build", "oas2tson": "./dist/esm/src/cli.js oas2tson -i ./example/openapi.yml -o ./example/output/ts", "prepare": "husky", @@ -49,7 +49,7 @@ "lodash.get": "^4.4.2", "lodash.trimstart": "^4.5.1", "lodash.upperfirst": "^4.3.1", - "pino": "^9.0.0", + "pino": "^8.14.1", "yaml": "^2.2.2" }, "devDependencies": { diff --git a/src/commands/json2ts.ts b/src/commands/json2ts.ts index 403c04a..62261f3 100644 --- a/src/commands/json2ts.ts +++ b/src/commands/json2ts.ts @@ -18,6 +18,7 @@ const generateAndWriteTsFile = async ( tsTypesPath: string, options: Json2TsOptions ) => { + const schemaFolder = schemaPath.split('/').slice(-2, -1).join('/') const ts = await compileFromFile(schemaPath, options) const interfaceName = path.basename(schemaPath, '.json') @@ -26,63 +27,105 @@ const generateAndWriteTsFile = async ( await parser.dereference(schemaPath) const imports = Object.values(parser.$refs.values()) - .filter( - refSchema => - refSchema.$id && refSchema.title && refSchema.title !== interfaceName - ) - .map( - refSchema => - `import { ${refSchema.title} } from './${refSchema.$id.replace( - '.json', - '' - )}'` - ) + .filter(refSchema => { + return ( + refSchema.$id && + refSchema.$id !== `${schemaFolder}/${interfaceName}.json` + ) + }) + .map(refSchema => { + let importFrom = '' + if (refSchema.$id.startsWith(`${schemaFolder}/`)) { + importFrom = `./${refSchema.title}` + } else { + importFrom = `../${refSchema.$id.replace('.json', '')}` + } + return `import { ${refSchema.title} } from '${importFrom}'` + }) .join('\n') const tsWithImports = `${imports ? `${imports}\n\n` : ''}${ts}` const tsFileName = path.basename(schemaPath, '.json') + '.d.ts' - fs.writeFileSync(path.join(tsTypesPath, tsFileName), tsWithImports) } export const runCommand = async ( - schemasPath: string, + // schemasPath: string, + tempFolder: string, tsTypesPath: string, + propertiesToExport?: string, customOptions?: Json2TsOptions, logger = pino() ) => { - fs.removeSync(tsTypesPath) - fs.ensureDirSync(tsTypesPath) - - let schemaPaths - - try { - schemaPaths = fs.readdirSync(schemasPath) - } catch (e) { - logger.error('❌ Could not find the JSON schemas folder') - exit(1) + const definitionKeywords = [ + ...new Set([ + ...(propertiesToExport?.split(',') || []), + 'components.schemas' + ]) + ] + + type pathInfoItem = { + filename: string + schemasPath: string + tsTypesPath: string } + const pathInfo: pathInfoItem[] = [] + + definitionKeywords.forEach(key => { + const schemasPath = path.join(tempFolder, key) + let schemaPaths + + try { + schemaPaths = fs.readdirSync(schemasPath) + } catch (e) { + logger.error('❌ Could not find the JSON schemas folder') + exit(1) + } + const outputPath = path.join(tsTypesPath, key) + schemaPaths.forEach(filename => + pathInfo.push({ + filename, + schemasPath, + tsTypesPath: outputPath + }) + ) - const defaultOptions: Json2TsDefaultOptions = { - cwd: schemasPath, - bannerComment: doNotEditText, - declareExternallyReferenced: false - } + fs.removeSync(outputPath) + fs.ensureDirSync(outputPath) + }) + + for (const { schemasPath, filename, tsTypesPath } of pathInfo) { + const defaultOptions: Json2TsDefaultOptions = { + cwd: schemasPath, + bannerComment: doNotEditText, + declareExternallyReferenced: false + } - const options = { ...defaultOptions, ...customOptions } + const options = { ...defaultOptions, ...customOptions } - for (const schemaFileName of schemaPaths) { - const schemaPath = path.join(schemasPath, schemaFileName) + const schemaPath = path.join(schemasPath, filename) await generateAndWriteTsFile(schemaPath, tsTypesPath, options) + // break } + // for (const schemaFileName of schemaPaths) { + // const schemaPath = path.join(schemasPath, schemaFileName) + // await generateAndWriteTsFile(schemaPath, tsTypesPath, options) + // } + logger.info('✅ TypeScript types generated successfully from JSON schemas') } const main = () => { const options = json2ts.optsWithGlobals() const customOptions = options.config ? readConfigFile(options.config) : {} - runCommand(options.input, options.output, customOptions, options.muteLogger) + runCommand( + options.input, + options.output, + options.properties, + customOptions, + options.muteLogger + ) } const json2ts = new Command('json2ts') @@ -106,6 +149,10 @@ json2ts '-c, --config ', 'Path to the JSON/JS config file with these possible options: https://www.npmjs.com/package/json-schema-to-typescript' ) + .option( + '-p, --properties ', + 'Comma-separated list of properties to convert from the OpenAPI file' + ) .allowUnknownOption() .allowExcessArguments(true) .action(main) diff --git a/src/commands/oas2json.ts b/src/commands/oas2json.ts index 85cab0f..8db1296 100644 --- a/src/commands/oas2json.ts +++ b/src/commands/oas2json.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { Command } from 'commander' import filenamify from 'filenamify' import fs from 'fs-extra' @@ -10,7 +11,11 @@ import YAML from 'yaml' import type { JSONSchema4 } from 'json-schema' -import { fromSchema } from '../utils/openapi-schema-to-json-schema-wrapper.js' +import { + fromSchema, + fromParameter +} from '../utils/openapi-schema-to-json-schema-wrapper.js' +import { formatFileName } from '../utils/paths.js' const COMPONENT_REF_REGEXP = /#\/components\/(callbacks|examples|headers|links|parameters|requestBodies|responses|schemas|securitySchemes)\/[^"]+/g @@ -19,12 +24,13 @@ const INVALID_URI_CHARS_REGEXP = /[^a-zA-Z0-9\-._~:/?#[\]@!$&'()*+,;=]/g export const adaptSchema = ( generatedSchema: JSONSchema4, name: string, - filename: string + filename: string, + definitionKeyword: string ) => { const sanitizedFilename = filename.replace(INVALID_URI_CHARS_REGEXP, '') delete generatedSchema.$schema generatedSchema.title = name - generatedSchema.$id = `${sanitizedFilename}.json` + generatedSchema.$id = `${definitionKeyword}/${sanitizedFilename}.json` if (generatedSchema.format?.includes('date')) { generatedSchema.tsType = 'Date' @@ -42,14 +48,21 @@ const processSchema = ( // to just use its key, so go into the parsed schema and get the // actual name so the files are more easily identifiable const name = isArray ? value.name : key - const filename = _trimStart(filenamify(name, { replacement: '-' }), '-') + const filename = formatFileName( + _trimStart(filenamify(name, { replacement: '-' }), '-') + ) - adaptSchema(value, name, filename) + adaptSchema(value, name, filename, definitionKeyword) let schemaAsString = JSON.stringify(value, null, 2) const refs = schemaAsString.match(COMPONENT_REF_REGEXP) + + const pattern = 'components.schemas' refs?.forEach(ref => { - const refName = ref.split('/').slice(-1) + let refName = ref.split('/').slice(-1).join('/') + if (definitionKeyword !== pattern) { + refName = path.join('..', pattern, refName) + } schemaAsString = schemaAsString.replace(ref, `${refName}.json`) }) @@ -61,6 +74,175 @@ const processSchema = ( }) } +type ParameterType = { + name: string + in: string + required?: boolean + schema?: any +} + +interface OpenApiPath { + [path: string]: { + [method: string]: { + description?: string + summary?: string + parameters?: ParameterType[] + requestBody?: JSONSchema4 + responses?: { + [statusCode: string]: { + description: string + content?: { + [contentType: string]: { + schema?: any + } + } + } + } + } + } +} + +function convertOpenApiPathsToSchema(paths: OpenApiPath): any { + const pathObjects: { [key: string]: any } = {} + for (const [path, methods] of Object.entries(paths)) { + const pathObject = formatFileName(path) + const schema: any = { + type: 'object', + properties: {}, + required: [] + } + + for (const [method, rawMethodSchema] of Object.entries(methods)) { + const { description, summary, parameters, requestBody, responses } = + rawMethodSchema + schema.required.push(method) + const schemaMethodProperties: JSONSchema4 = { + type: 'object', + required: [] + } + + if (description) { + schemaMethodProperties['description'] = description + } + + if (summary) { + schemaMethodProperties['summary'] = summary + } + + const methodPropertiesRequired = [] + const methodProperties: { [key: string]: any } = {} + + if (requestBody) { + if (requestBody.required) { + methodPropertiesRequired.push('requestBody') + } + + const requestBodyObject: JSONSchema4 = { + type: 'object', + properties: {} + } + if (requestBody.description) { + requestBodyObject.description = requestBody.description + } + if (requestBody.content) { + const content: JSONSchema4 = { + type: 'object', + required: [], + properties: {} + } + + Object.entries(fromParameter(requestBody)).forEach( + ([key, value]: [string, any]) => { + const keyContent: JSONSchema4 = {} + + if (value?.$ref) { + keyContent['$ref'] = value.$ref + } + if (value?.description) { + keyContent['description'] = value.description + } + + if (content.properties) { + content.properties[key] = keyContent + } + } + ) + if (requestBodyObject.properties) { + requestBodyObject.properties['content'] = content + } + } + + methodProperties['requestBody'] = requestBodyObject + delete methodProperties['requestBody']['$schema'] + } + + if (parameters) { + methodPropertiesRequired.push('parameters') + + const requiredParameters: string[] = [] + const propertiesParameters: { [key: string]: JSONSchema4 } = + parameters.reduce((a: { [key: string]: JSONSchema4 }, c) => { + a[c.name] = fromParameter(c) + delete a[c.name]['$schema'] + if (c.required) { + requiredParameters.push(c.name) + } + return a + }, {}) + + const parametersSchema: JSONSchema4 = { + type: 'object', + properties: propertiesParameters + } + + if (requiredParameters.length > 0) { + parametersSchema['required'] = requiredParameters + } + + methodProperties['parameters'] = parametersSchema + } + + if (responses) { + methodPropertiesRequired.push('responses') + const responsesWithContent: { [key: string]: any } = {} + for (const httpStatusCode in responses) { + if (responses[httpStatusCode]['content']) { + const responsesSchema = fromParameter(responses[httpStatusCode]) + for (const key in responsesSchema) { + delete responsesSchema[key]['$schema'] + } + responsesWithContent[httpStatusCode] = { + type: 'object', + properties: responsesSchema + } + } else { + responsesWithContent[httpStatusCode] = fromSchema( + responses[httpStatusCode] + ) + + delete responsesWithContent[httpStatusCode]['$schema'] + } + } + methodProperties['responses'] = { + type: 'object', + properties: responsesWithContent + } + } + + schemaMethodProperties['properties'] = methodProperties + + if (methodPropertiesRequired.length) { + schemaMethodProperties['required'] = methodPropertiesRequired + } + + schema.properties[method] = schemaMethodProperties + } + pathObjects[pathObject] = schema + } + + return pathObjects +} + export const runCommand = ( openApiPath: string, schemasPath: string, @@ -88,17 +270,30 @@ export const runCommand = ( ]) ] + // console.log({ definitionKeywords }) + try { const generatedSchema = fromSchema(parsedOpenAPIContent, { definitionKeywords }) definitionKeywords.forEach(key => { - const schema: JSONSchema4 = _get(generatedSchema, key) + // const schema: JSONSchema4 = _get(generatedSchema, key) + const schema: JSONSchema4 = + key === 'paths' + ? convertOpenApiPathsToSchema( + // generatedSchema.paths['/pet/findByStatus'] + generatedSchema.paths + ) + : _get(generatedSchema, key) + + // console.log(key, { schema }) + const isArray = Array.isArray(_get(parsedOpenAPIContent, key)) processSchema(schema, schemasPath, key, isArray) }) } catch (error) { + console.log(error) logger.warn('Failed to convert non-object attribute, skipping') return } diff --git a/src/commands/oas2ts.ts b/src/commands/oas2ts.ts index f5fc82f..2d7f6a1 100644 --- a/src/commands/oas2ts.ts +++ b/src/commands/oas2ts.ts @@ -18,17 +18,23 @@ const cleanUpTempFolder = (logger: Logger) => export const runCommand = async ( openApiPath: string, tsTypesPath: string, + propertiesToExport?: string, customOptions?: Json2TsOptions, logger: Logger = pino() ) => { try { const silentLogger = pino({ level: 'silent' }) - const schemasDir = path.join(TEMP_FOLDER, 'components.schemas') - runOas2JsonCommand(openApiPath, TEMP_FOLDER, undefined, silentLogger) + runOas2JsonCommand( + openApiPath, + TEMP_FOLDER, + propertiesToExport, + silentLogger + ) await runJson2TsCommand( - schemasDir, + TEMP_FOLDER, tsTypesPath, + propertiesToExport, customOptions, silentLogger ) @@ -47,7 +53,13 @@ export const runCommand = async ( const main = async () => { const options = oas2ts.optsWithGlobals() const customOptions = options.config ? readConfigFile(options.config) : {} - runCommand(options.input, options.output, customOptions, options.logger) + runCommand( + options.input, + options.output, + options.properties, + customOptions, + options.logger + ) } const oas2ts = new Command('oas2ts') @@ -71,6 +83,10 @@ oas2ts '-c, --config ', 'Path to the JSON/JS config file with these possible options: https://www.npmjs.com/package/json-schema-to-typescript' ) + .option( + '-p, --properties ', + 'Comma-separated list of properties to convert from the OpenAPI file' + ) .allowUnknownOption() .allowExcessArguments(true) .action(main) diff --git a/src/types/Json2TsOptions.d.ts b/src/types/Json2TsOptions.d.ts index 0ed6838..9de6c94 100644 --- a/src/types/Json2TsOptions.d.ts +++ b/src/types/Json2TsOptions.d.ts @@ -4,6 +4,7 @@ import { Logger } from 'pino' export type Json2TsArgs = { input: string output: string + properties?: string config?: string muteLogger?: Logger } diff --git a/src/utils/openapi-schema-to-json-schema-wrapper.ts b/src/utils/openapi-schema-to-json-schema-wrapper.ts index 53eafbe..74205ca 100644 --- a/src/utils/openapi-schema-to-json-schema-wrapper.ts +++ b/src/utils/openapi-schema-to-json-schema-wrapper.ts @@ -1 +1,4 @@ -export { fromSchema } from '@openapi-contrib/openapi-schema-to-json-schema' +export { + fromSchema, + fromParameter +} from '@openapi-contrib/openapi-schema-to-json-schema'