apib2swagger 1.16.1 → 1.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/.github/workflows/nodejs.yml +1 -1
  2. package/Dockerfile +1 -1
  3. package/README.md +1 -1
  4. package/package.json +1 -1
  5. package/src/mson_to_json_schema.js +28 -9
  6. package/src/requests.js +18 -3
  7. package/src/responses.js +13 -1
  8. package/test/input/Issue-#72.md +43 -0
  9. package/test/input/OpenAPI3_Issue-#73.md +21 -0
  10. package/test/output/01. Simplest API.json +2 -1
  11. package/test/output/01. Simplest API.ref.json +2 -1
  12. package/test/output/02. Resource and Actions.json +6 -2
  13. package/test/output/02. Resource and Actions.ref.json +6 -2
  14. package/test/output/03. Named Resource and Actions.json +6 -2
  15. package/test/output/03. Named Resource and Actions.ref.json +6 -2
  16. package/test/output/04. Grouping Resources.json +6 -2
  17. package/test/output/04. Grouping Resources.ref.json +6 -2
  18. package/test/output/05. Responses.json +6 -2
  19. package/test/output/05. Responses.ref.json +6 -2
  20. package/test/output/06. Requests.json +6 -1
  21. package/test/output/06. Requests.ref.json +6 -1
  22. package/test/output/07. Parameters.json +8 -2
  23. package/test/output/07. Parameters.ref.json +8 -2
  24. package/test/output/08. Attributes.json +2 -1
  25. package/test/output/08. Attributes.ref.json +2 -1
  26. package/test/output/09. Advanced Attributes.json +7 -2
  27. package/test/output/09. Advanced Attributes.ref.json +7 -2
  28. package/test/output/10. Data Structures.json +7 -2
  29. package/test/output/10. Data Structures.ref.json +7 -2
  30. package/test/output/11. Resource Model.json +6 -1
  31. package/test/output/11. Resource Model.ref.json +6 -1
  32. package/test/output/12. Advanced Action.json +6 -3
  33. package/test/output/12. Advanced Action.ref.json +6 -3
  34. package/test/output/13. Named Endpoints.json +6 -0
  35. package/test/output/13. Named Endpoints.ref.json +6 -0
  36. package/test/output/Attributes.json +3 -0
  37. package/test/output/Attributes.ref.json +3 -0
  38. package/test/output/Gist Fox API + Auth.json +25 -7
  39. package/test/output/Gist Fox API + Auth.ref.json +25 -7
  40. package/test/output/Issue-#15.json +6 -3
  41. package/test/output/Issue-#15.ref.json +6 -3
  42. package/test/output/Issue-#23.json +3 -0
  43. package/test/output/Issue-#23.ref.json +3 -0
  44. package/test/output/Issue-#26.json +5 -1
  45. package/test/output/Issue-#26.ref.json +5 -1
  46. package/test/output/Issue-#29.json +5 -1
  47. package/test/output/Issue-#29.ref.json +5 -1
  48. package/test/output/Issue-#33.json +2 -1
  49. package/test/output/Issue-#33.ref.json +2 -1
  50. package/test/output/Issue-#36.json +2 -1
  51. package/test/output/Issue-#36.ref.json +2 -1
  52. package/test/output/Issue-#38.bearer.json +3 -0
  53. package/test/output/Issue-#38.json +3 -0
  54. package/test/output/Issue-#38.ref.json +3 -0
  55. package/test/output/Issue-#49.json +4 -2
  56. package/test/output/Issue-#49.ref.json +4 -2
  57. package/test/output/Issue-#57.json +3 -0
  58. package/test/output/Issue-#57.ref.json +3 -0
  59. package/test/output/Issue-#72.json +170 -0
  60. package/test/output/Issue-#72.ref.json +168 -0
  61. package/test/output/OpenAPI3_Issue-#73.json +69 -0
  62. package/test/output/OpenAPI3_Issue-#73.ref.json +63 -0
  63. package/test/output/Schema.json +9 -0
  64. package/test/output/Schema.ref.json +9 -0
  65. package/test/output/apiblueprint_uber.json +10 -5
  66. package/test/output/apiblueprint_uber.ref.json +10 -5
  67. package/test/output/apiblueprint_valid_simple.json +25 -7
  68. package/test/output/apiblueprint_valid_simple.ref.json +25 -7
  69. package/test/output/schema_without_body.json +52 -49
  70. package/test/output/schema_without_body.ref.json +52 -49
  71. package/test/test.js +3 -1
@@ -9,7 +9,7 @@ jobs:
9
9
 
10
10
  strategy:
11
11
  matrix:
12
- node-version: [14.x, 16.x, 18.x]
12
+ node-version: [18.x, 20.x]
13
13
 
14
14
  steps:
15
15
  - uses: actions/checkout@v1
package/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM node:16-alpine
1
+ FROM node:18-alpine
2
2
 
3
3
  RUN npm install -g apib2swagger
4
4
 
package/README.md CHANGED
@@ -14,7 +14,7 @@ Supported versions:
14
14
  - [Include directive](https://github.com/danielgtaylor/aglio#including-files)
15
15
  - Swagger 2.0
16
16
  - OpenAPI 3.0.3
17
- - Node.js 14.x, 16.x, 18.x or higher
17
+ - Node.js 18.x, 20.x or higher
18
18
 
19
19
  ## Install
20
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apib2swagger",
3
- "version": "1.16.1",
3
+ "version": "1.17.1",
4
4
  "description": "Convert API Blueprint to Swagger.",
5
5
  "bin": "./bin/apib2swagger.js",
6
6
  "scripts": {
@@ -32,7 +32,7 @@ function convert(mson, options) {
32
32
  return { type: 'array', items: { 'anyOf': mson.content.map((m) => convert(m, options)) } };
33
33
  }
34
34
  case 'enum':
35
- return convertEnum(mson.content);
35
+ return convertEnum(mson.content, componentsPath);
36
36
  case 'object':
37
37
  break;
38
38
  case 'boolean':
@@ -98,19 +98,38 @@ function convert(mson, options) {
98
98
  return schema;
99
99
  }
100
100
 
101
- function convertEnum(contents) {
101
+ function convertEnum(contents, componentsPath) {
102
102
  if (!contents) return null
103
- var schema = { type: '', enum: [] };
103
+ const schemaList = []
104
104
  for (var i = 0; i < contents.length; i++) {
105
105
  var content = contents[i];
106
- if (!schema.type) {
107
- schema.type = content.element;
108
- } else if (schema.type != content.element) {
109
- // WARN!! mixed type enum
106
+ switch (content.element) {
107
+ case "boolean":
108
+ case "string":
109
+ case "number":
110
+ case "array":
111
+ case "enum": // TODO
112
+ case "object":
113
+ let schema = schemaList.find(v => v.type === content.element)
114
+ if (!schema) {
115
+ schema = { type: content.element, enum: [] }
116
+ schemaList.push(schema)
117
+ }
118
+ schema.enum.push(content.content)
119
+ break
120
+ default: // CustomType
121
+ schemaList.push({ '$ref': componentsPath + escapeJSONPointer(content.element) })
122
+ break
110
123
  }
111
- schema.enum.push(content.content);
112
124
  }
113
- return schema;
125
+ switch (schemaList.length) {
126
+ case 0:
127
+ return {}
128
+ case 1:
129
+ return schemaList[0]
130
+ default:
131
+ return { oneOf: schemaList}
132
+ }
114
133
  }
115
134
 
116
135
  module.exports = convertMsonToJsonSchema;
package/src/requests.js CHANGED
@@ -308,6 +308,8 @@ module.exports.processRequests = (operation, action, context) => {
308
308
 
309
309
  let bodyExamples = {}
310
310
 
311
+ if (!openApi3) operation.consumes = []
312
+
311
313
  for (var j = 0; j < action.examples.length; j++) {
312
314
  var example = action.examples[j];
313
315
  for (var l = 0; l < example.requests.length; l++) {
@@ -320,8 +322,14 @@ module.exports.processRequests = (operation, action, context) => {
320
322
  operation.parameters = mergeHeaders(headers, operation.parameters, options)
321
323
  }
322
324
 
325
+ var contentType = 'application/json'
323
326
  const contentTypeHeader = request.headers.find((h) => h.name === 'Content-Type')
324
- const contentType = contentTypeHeader ? contentTypeHeader.value : 'application/json'
327
+ if (contentTypeHeader) {
328
+ contentType = contentTypeHeader.value
329
+ if (!openApi3 && !operation.consumes.includes(contentType)) {
330
+ operation.consumes.push(contentType)
331
+ }
332
+ }
325
333
 
326
334
  if (request.body && openApi3) {
327
335
  bodyExamples = buildBodyExamples(request.body, bodyExamples, contentType)
@@ -346,12 +354,19 @@ module.exports.processRequests = (operation, action, context) => {
346
354
  }
347
355
  }
348
356
  }
349
- if (openApi3 && (schema.length || Object.keys(bodyExamples).length)){
357
+ if (openApi3 && (schema.length || Object.keys(bodyExamples).length)) {
350
358
  operation.requestBody = { content: {} }
351
359
  if (Object.keys(bodyExamples).length) {
352
360
  operation.requestBody.content = bodyExamples
353
361
  }
354
362
  }
355
-
363
+ if (!openApi3) {
364
+ for (var s of schema) {
365
+ if (!operation.consumes.includes(s.contentType)) {
366
+ operation.consumes.push(s.contentType)
367
+ }
368
+ }
369
+ }
370
+
356
371
  return openApi3 ? setOpenApiRequestSchema(operation, schema) : setSwaggerRequestSchema(operation, schema)
357
372
  }
package/src/responses.js CHANGED
@@ -3,6 +3,7 @@ const escapeJSONPointer = require('./escape_json_pointer')
3
3
  const isEqual = require('lodash.isequal')
4
4
  const http = require('http')
5
5
  const toOpenApi = require('json-schema-to-openapi-schema')
6
+ const generateSchema = require('generate-schema')
6
7
 
7
8
  const parseResponseSchema = (schema, options) => {
8
9
  if (!schema) return
@@ -71,9 +72,20 @@ const setResponseSchema = (responses, response, schema, options) => {
71
72
  responses[response.name].schema = schema
72
73
  return responses
73
74
  }
75
+ if (schema.type === 'extend') { // Workaround for invalid JSON schema
76
+ if (schema.enum.length > 0) {
77
+ schema = generateSchema.json('', schema.enum[0])
78
+ } else {
79
+ schema.type = 'object'
80
+ }
81
+ }
74
82
  // Convert JSON Schema draft04 to OpenAPI 3.0.x (type: null -> nullable: true)
75
83
  // TODO: Skip this for OpenAPI 3.1.x or later.
76
- schema = toOpenApi(schema)
84
+ try {
85
+ schema = toOpenApi(schema)
86
+ } catch (e) {
87
+ return responses // TODO: Handle error
88
+ }
77
89
 
78
90
  // In openAPI 3 the schema lives under the content type
79
91
  const contentTypeHeader = response.headers.find((h) => h.name.toLowerCase() === 'content-type')
@@ -0,0 +1,43 @@
1
+ ### Create a user [POST /api/scim/v2/Users]
2
+
3
+ + Request
4
+ + Headers
5
+
6
+ Content-Type: application/scim+json
7
+ Authorization: Bearer token
8
+
9
+ + Body
10
+
11
+ {
12
+ "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
13
+ "userName": "fredsmith",
14
+ "name": {
15
+ "givenName": "Fred",
16
+ "familyName": "Smith"
17
+ },
18
+ "emails": [
19
+ {"primary": true, "value": "fred@example.com", "type": "work"}
20
+ ],
21
+ "displayName": "Fred Smith",
22
+ "externalId": "fred-external-id",
23
+ "active": true
24
+ }
25
+
26
+ + Response 201 (application/scim+json)
27
+
28
+ + Attributes (ExistingUser)
29
+
30
+ ### Create a user 2 [POST /api2/scim/v2/Users]
31
+
32
+ + Request
33
+ + Headers
34
+
35
+ Content-Type: application/scim+json
36
+ Authorization: Bearer token
37
+
38
+ + Response 201 (application/scim+json)
39
+
40
+ + Attributes (ExistingUser)
41
+
42
+ # Data Structures
43
+ ## ExistingUser
@@ -0,0 +1,21 @@
1
+ FORMAT: 1A
2
+ HOST: http://127.0.0.1/api/v1
3
+
4
+ # Group Extensions
5
+
6
+ ## Extensions [/extensions]
7
+
8
+ ### Get extensions [GET]
9
+
10
+ + Response 200 (application/json)
11
+ + Attributes (Extension)
12
+
13
+ ## Data Structures
14
+
15
+ ### Extension (enum)
16
+
17
+ + (Foo type)
18
+
19
+ ### Foo type (object, fixed-type)
20
+
21
+ + id (string) - the id
@@ -24,7 +24,8 @@
24
24
  "parameters": [],
25
25
  "produces": [
26
26
  "text/plain"
27
- ]
27
+ ],
28
+ "consumes": []
28
29
  }
29
30
  }
30
31
  },
@@ -24,7 +24,8 @@
24
24
  "parameters": [],
25
25
  "produces": [
26
26
  "text/plain"
27
- ]
27
+ ],
28
+ "consumes": []
28
29
  }
29
30
  }
30
31
  },
@@ -24,7 +24,8 @@
24
24
  "parameters": [],
25
25
  "produces": [
26
26
  "text/plain"
27
- ]
27
+ ],
28
+ "consumes": []
28
29
  },
29
30
  "put": {
30
31
  "responses": {
@@ -38,7 +39,10 @@
38
39
  "operationId": "",
39
40
  "description": "OK, let's add another action. This time to put new data to our resource (essentially an update action). We will need to send something in a [request](http://www.w3.org/TR/di-gloss/#def-http-request) and then send a response back confirming the posting was a success (HTTP Status Code 204 ~ Resource updated successfully, no content is returned).",
40
41
  "tags": [],
41
- "parameters": []
42
+ "parameters": [],
43
+ "consumes": [
44
+ "text/plain"
45
+ ]
42
46
  }
43
47
  }
44
48
  },
@@ -24,7 +24,8 @@
24
24
  "parameters": [],
25
25
  "produces": [
26
26
  "text/plain"
27
- ]
27
+ ],
28
+ "consumes": []
28
29
  },
29
30
  "put": {
30
31
  "responses": {
@@ -38,7 +39,10 @@
38
39
  "operationId": "",
39
40
  "description": "OK, let's add another action. This time to put new data to our resource (essentially an update action). We will need to send something in a [request](http://www.w3.org/TR/di-gloss/#def-http-request) and then send a response back confirming the posting was a success (HTTP Status Code 204 ~ Resource updated successfully, no content is returned).",
40
41
  "tags": [],
41
- "parameters": []
42
+ "parameters": [],
43
+ "consumes": [
44
+ "text/plain"
45
+ ]
42
46
  }
43
47
  }
44
48
  },
@@ -24,7 +24,8 @@
24
24
  "parameters": [],
25
25
  "produces": [
26
26
  "text/plain"
27
- ]
27
+ ],
28
+ "consumes": []
28
29
  },
29
30
  "put": {
30
31
  "responses": {
@@ -38,7 +39,10 @@
38
39
  "operationId": "Update a Message",
39
40
  "description": "`Update a message` - nice and simple naming is the best way to go.",
40
41
  "tags": [],
41
- "parameters": []
42
+ "parameters": [],
43
+ "consumes": [
44
+ "text/plain"
45
+ ]
42
46
  }
43
47
  }
44
48
  },
@@ -24,7 +24,8 @@
24
24
  "parameters": [],
25
25
  "produces": [
26
26
  "text/plain"
27
- ]
27
+ ],
28
+ "consumes": []
28
29
  },
29
30
  "put": {
30
31
  "responses": {
@@ -38,7 +39,10 @@
38
39
  "operationId": "Update a Message",
39
40
  "description": "`Update a message` - nice and simple naming is the best way to go.",
40
41
  "tags": [],
41
- "parameters": []
42
+ "parameters": [],
43
+ "consumes": [
44
+ "text/plain"
45
+ ]
42
46
  }
43
47
  }
44
48
  },
@@ -26,7 +26,8 @@
26
26
  "parameters": [],
27
27
  "produces": [
28
28
  "text/plain"
29
- ]
29
+ ],
30
+ "consumes": []
30
31
  },
31
32
  "put": {
32
33
  "responses": {
@@ -42,7 +43,10 @@
42
43
  "tags": [
43
44
  "Messages"
44
45
  ],
45
- "parameters": []
46
+ "parameters": [],
47
+ "consumes": [
48
+ "text/plain"
49
+ ]
46
50
  }
47
51
  }
48
52
  },
@@ -26,7 +26,8 @@
26
26
  "parameters": [],
27
27
  "produces": [
28
28
  "text/plain"
29
- ]
29
+ ],
30
+ "consumes": []
30
31
  },
31
32
  "put": {
32
33
  "responses": {
@@ -42,7 +43,10 @@
42
43
  "tags": [
43
44
  "Messages"
44
45
  ],
45
- "parameters": []
46
+ "parameters": [],
47
+ "consumes": [
48
+ "text/plain"
49
+ ]
46
50
  }
47
51
  }
48
52
  },
@@ -43,7 +43,8 @@
43
43
  "parameters": [],
44
44
  "produces": [
45
45
  "application/json"
46
- ]
46
+ ],
47
+ "consumes": []
47
48
  },
48
49
  "put": {
49
50
  "responses": {
@@ -59,7 +60,10 @@
59
60
  "tags": [
60
61
  "Messages"
61
62
  ],
62
- "parameters": []
63
+ "parameters": [],
64
+ "consumes": [
65
+ "text/plain"
66
+ ]
63
67
  }
64
68
  }
65
69
  },
@@ -43,7 +43,8 @@
43
43
  "parameters": [],
44
44
  "produces": [
45
45
  "application/json"
46
- ]
46
+ ],
47
+ "consumes": []
47
48
  },
48
49
  "put": {
49
50
  "responses": {
@@ -59,7 +60,10 @@
59
60
  "tags": [
60
61
  "Messages"
61
62
  ],
62
- "parameters": []
63
+ "parameters": [],
64
+ "consumes": [
65
+ "text/plain"
66
+ ]
63
67
  }
64
68
  }
65
69
  },
@@ -52,7 +52,8 @@
52
52
  ],
53
53
  "produces": [
54
54
  "application/json"
55
- ]
55
+ ],
56
+ "consumes": []
56
57
  },
57
58
  "put": {
58
59
  "responses": {
@@ -84,6 +85,10 @@
84
85
  }
85
86
  }
86
87
  }
88
+ ],
89
+ "consumes": [
90
+ "text/plain",
91
+ "application/json"
87
92
  ]
88
93
  }
89
94
  }
@@ -52,7 +52,8 @@
52
52
  ],
53
53
  "produces": [
54
54
  "application/json"
55
- ]
55
+ ],
56
+ "consumes": []
56
57
  },
57
58
  "put": {
58
59
  "responses": {
@@ -84,6 +85,10 @@
84
85
  }
85
86
  }
86
87
  }
88
+ ],
89
+ "consumes": [
90
+ "text/plain",
91
+ "application/json"
87
92
  ]
88
93
  }
89
94
  }
@@ -65,7 +65,8 @@
65
65
  ],
66
66
  "produces": [
67
67
  "application/json"
68
- ]
68
+ ],
69
+ "consumes": []
69
70
  },
70
71
  "put": {
71
72
  "responses": {
@@ -105,6 +106,10 @@
105
106
  }
106
107
  }
107
108
  }
109
+ ],
110
+ "consumes": [
111
+ "text/plain",
112
+ "application/json"
108
113
  ]
109
114
  }
110
115
  },
@@ -182,7 +187,8 @@
182
187
  ],
183
188
  "produces": [
184
189
  "application/json"
185
- ]
190
+ ],
191
+ "consumes": []
186
192
  }
187
193
  }
188
194
  },
@@ -65,7 +65,8 @@
65
65
  ],
66
66
  "produces": [
67
67
  "application/json"
68
- ]
68
+ ],
69
+ "consumes": []
69
70
  },
70
71
  "put": {
71
72
  "responses": {
@@ -105,6 +106,10 @@
105
106
  }
106
107
  }
107
108
  }
109
+ ],
110
+ "consumes": [
111
+ "text/plain",
112
+ "application/json"
108
113
  ]
109
114
  }
110
115
  },
@@ -182,7 +187,8 @@
182
187
  ],
183
188
  "produces": [
184
189
  "application/json"
185
- ]
190
+ ],
191
+ "consumes": []
186
192
  }
187
193
  }
188
194
  },
@@ -41,7 +41,8 @@
41
41
  "tags": [
42
42
  "Coupons"
43
43
  ],
44
- "parameters": []
44
+ "parameters": [],
45
+ "consumes": []
45
46
  }
46
47
  }
47
48
  },
@@ -44,7 +44,8 @@
44
44
  "tags": [
45
45
  "Coupons"
46
46
  ],
47
- "parameters": []
47
+ "parameters": [],
48
+ "consumes": []
48
49
  }
49
50
  }
50
51
  },
@@ -59,7 +59,8 @@
59
59
  ],
60
60
  "produces": [
61
61
  "application/json"
62
- ]
62
+ ],
63
+ "consumes": []
63
64
  }
64
65
  },
65
66
  "/coupons": {
@@ -102,7 +103,8 @@
102
103
  ],
103
104
  "produces": [
104
105
  "application/json"
105
- ]
106
+ ],
107
+ "consumes": []
106
108
  },
107
109
  "post": {
108
110
  "responses": {
@@ -165,6 +167,9 @@
165
167
  ],
166
168
  "produces": [
167
169
  "application/json"
170
+ ],
171
+ "consumes": [
172
+ "application/json"
168
173
  ]
169
174
  }
170
175
  }
@@ -42,7 +42,8 @@
42
42
  ],
43
43
  "produces": [
44
44
  "application/json"
45
- ]
45
+ ],
46
+ "consumes": []
46
47
  }
47
48
  },
48
49
  "/coupons": {
@@ -84,7 +85,8 @@
84
85
  ],
85
86
  "produces": [
86
87
  "application/json"
87
- ]
88
+ ],
89
+ "consumes": []
88
90
  },
89
91
  "post": {
90
92
  "responses": {
@@ -130,6 +132,9 @@
130
132
  ],
131
133
  "produces": [
132
134
  "application/json"
135
+ ],
136
+ "consumes": [
137
+ "application/json"
133
138
  ]
134
139
  }
135
140
  }
@@ -59,7 +59,8 @@
59
59
  ],
60
60
  "produces": [
61
61
  "application/json"
62
- ]
62
+ ],
63
+ "consumes": []
63
64
  }
64
65
  },
65
66
  "/coupons": {
@@ -102,7 +103,8 @@
102
103
  ],
103
104
  "produces": [
104
105
  "application/json"
105
- ]
106
+ ],
107
+ "consumes": []
106
108
  },
107
109
  "post": {
108
110
  "responses": {
@@ -156,6 +158,9 @@
156
158
  ],
157
159
  "produces": [
158
160
  "application/json"
161
+ ],
162
+ "consumes": [
163
+ "application/json"
159
164
  ]
160
165
  }
161
166
  }