apib2swagger 1.14.0 → 1.14.3

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.
@@ -111,6 +111,12 @@ function processBlueprint(blueprint, opts) {
111
111
  };
112
112
  apib2swagger.convert(blueprint, options, function(error, result) {
113
113
  if (error) {
114
+ if (error.stack && error.result) {
115
+ // override toString() of drafter's error to expand error.result.error.location
116
+ console.log(error.stack);
117
+ console.log(JSON.stringify(error.result, 0, 2));
118
+ return;
119
+ }
114
120
  console.log(error);
115
121
  return;
116
122
  }
package/index.js CHANGED
@@ -7,6 +7,7 @@ const { searchDataStructure, generateSchemaFromExample } = require('./src/util')
7
7
  const { processRequests } = require('./src/requests')
8
8
  const { processResponses } = require('./src/responses')
9
9
  const { processParameters } = require('./src/parameters')
10
+ const toOpenApi = require('json-schema-to-openapi-schema')
10
11
 
11
12
  var apib2swagger = module.exports.convertParsed = function (apib, options) {
12
13
  const { openApi3, infoTitle } = options
@@ -75,7 +76,7 @@ var apib2swagger = module.exports.convertParsed = function (apib, options) {
75
76
  const { id } = content.content[0].meta
76
77
  const schema = jsonSchemaFromMSON(content, options);
77
78
  if (openApi3) {
78
- output.components.schemas[id] = schema
79
+ output.components.schemas[id] = toOpenApi(schema)
79
80
  } else {
80
81
  output.definitions[id] = schema
81
82
  }
@@ -111,7 +112,7 @@ var swaggerDefinitions = function (resource, options) {
111
112
  scheme = searchDataStructure(resource.content, options); // Attributes 1
112
113
  if (openApi3) {
113
114
  if (scheme) {
114
- result[resource.name] = scheme
115
+ result[resource.name] = toOpenApi(scheme)
115
116
  }
116
117
  } else {
117
118
  result[resource.name] = scheme ? scheme : {};
@@ -126,7 +127,7 @@ var swaggerDefinitions = function (resource, options) {
126
127
  }
127
128
  if (openApi3) {
128
129
  if (scheme) {
129
- result[model.name + 'Model'] = scheme
130
+ result[model.name + 'Model'] = toOpenApi(scheme)
130
131
  }
131
132
  } else {
132
133
  result[model.name + 'Model'] = scheme ? scheme : {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apib2swagger",
3
- "version": "1.14.0",
3
+ "version": "1.14.3",
4
4
  "description": "Convert API Blueprint to Swagger.",
5
5
  "bin": "./bin/apib2swagger.js",
6
6
  "scripts": {
@@ -21,6 +21,7 @@
21
21
  "drafter.js": "^2.6.2",
22
22
  "generate-schema": "^2.5.0",
23
23
  "js-yaml": "^4.1.0",
24
+ "json-schema-to-openapi-schema": "^0.4.0",
24
25
  "lodash.isequal": "^4.5.0",
25
26
  "nopt": "^3.0.6",
26
27
  "uritemplate": "^0.3.4"
@@ -51,11 +51,11 @@ function convert(mson, options) {
51
51
  schema.required = [];
52
52
  schema.properties = {};
53
53
  for (var j = 0; mson.content && j < mson.content.length; j++) {
54
- var member = mson.content[j];
54
+ const member = mson.content[j];
55
55
  if (member.element !== "member") continue;
56
- schema.properties[member.content.key.content] = convert(member.content.value, options);
56
+ var propertySchema = convert(member.content.value, options);
57
57
  if (member.meta && member.meta.description) {
58
- schema.properties[member.content.key.content].description = member.meta.description;
58
+ propertySchema.description = member.meta.description;
59
59
  }
60
60
  var fixedType = false;
61
61
  if (member.attributes && member.attributes.typeAttributes) {
@@ -68,14 +68,19 @@ function convert(mson, options) {
68
68
  schema.required.push(member.content.key.content);
69
69
  break;
70
70
  case 'nullable':
71
- schema.properties[member.content.key.content].type = [schema.properties[member.content.key.content].type, 'null']
71
+ if (propertySchema.$ref) {
72
+ propertySchema = {oneOf: [propertySchema, {type: 'null'}]};
73
+ } else {
74
+ propertySchema.type = [propertySchema.type, 'null']
75
+ }
72
76
  break;
73
77
  }
74
78
  });
75
79
  }
76
- if (schema.properties[member.content.key.content].type === 'array' && !fixedType) {
77
- schema.properties[member.content.key.content].items = {}; // reset item schema
80
+ if (propertySchema.type === 'array' && !fixedType) {
81
+ propertySchema.items = {}; // reset item schema
78
82
  }
83
+ schema.properties[member.content.key.content] = propertySchema;
79
84
  }
80
85
 
81
86
  // According to schema definition, required is a stringArray, which must be non-empty
package/src/requests.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const { hasFileRef, getRefFromInclude, searchDataStructure, generateSchemaFromExample } = require('./util')
2
2
  const isEqual = require('lodash.isequal')
3
3
  const escapeJSONPointer = require('./escape_json_pointer')
4
+ const toOpenApi = require('json-schema-to-openapi-schema')
4
5
 
5
6
  const swaggerHeaders = function (options, headers) {
6
7
  var params = [];
@@ -250,8 +251,14 @@ const setOpenApiRequestSchema = (operation, schema) => {
250
251
  if (!operation.requestBody.content[schema[0].contentType]){
251
252
  operation.requestBody.content[schema[0].contentType] = schema[0].scheme
252
253
  } else {
253
- operation.requestBody.content[schema[0].contentType].schema = schema[0].scheme
254
+ operation.requestBody.content[schema[0].contentType].schema = schema[0].scheme
254
255
  }
256
+ Object.keys(operation.requestBody.content).forEach(contentType => {
257
+ const s = operation.requestBody.content[contentType].schema;
258
+ if (s) {
259
+ operation.requestBody.content[contentType].schema = toOpenApi(s)
260
+ }
261
+ })
255
262
  return operation
256
263
  }
257
264
 
@@ -283,6 +290,12 @@ const setOpenApiRequestSchema = (operation, schema) => {
283
290
  ]
284
291
  }
285
292
  })
293
+ Object.keys(operation.requestBody.content).forEach(contentType => {
294
+ const s = operation.requestBody.content[contentType].schema;
295
+ if (s) {
296
+ operation.requestBody.content[contentType].schema = toOpenApi(s)
297
+ }
298
+ })
286
299
  return operation
287
300
  }
288
301
 
package/src/responses.js CHANGED
@@ -2,6 +2,7 @@ const { fixArraySchema, hasFileRef, getRefFromInclude, searchDataStructure } = r
2
2
  const escapeJSONPointer = require('./escape_json_pointer')
3
3
  const isEqual = require('lodash.isequal')
4
4
  const http = require('http')
5
+ const toOpenApi = require('json-schema-to-openapi-schema')
5
6
 
6
7
  const parseResponseSchema = (schema, options) => {
7
8
  if (!schema) return
@@ -64,6 +65,10 @@ const setResponseSchema = (responses, response, schema, options) => {
64
65
  responses[response.name].schema = schema
65
66
  return responses
66
67
  }
68
+ // Convert JSON Schema draft04 to OpenAPI 3.0.x (type: null -> nullable: true)
69
+ // TODO: Skip this for OpenAPI 3.1.x or later.
70
+ schema = toOpenApi(schema)
71
+
67
72
  // In openAPI 3 the schema lives under the content type
68
73
  const contentTypeHeader = response.headers.find((h) => h.name.toLowerCase() === 'content-type')
69
74
  if (!contentTypeHeader.value) {
package/src/util.js CHANGED
@@ -87,10 +87,8 @@ module.exports.generateSchemaFromExample = function (headers, example, options)
87
87
  delete scheme.$schema;
88
88
  // if we have example values in the body then insert them into the json schema
89
89
  if (!options.openApi3) {
90
- if (scheme['type'] === 'object') {
90
+ if (scheme['type'] === 'object' || scheme['type'] === 'array') {
91
91
  scheme.example = body;
92
- } else if (scheme['type'] === 'array') {
93
- scheme.items.example = body;
94
92
  }
95
93
  }
96
94
  return scheme;
@@ -0,0 +1,14 @@
1
+ # DELETE /domains
2
+
3
+ + Request (application/json)
4
+
5
+ Domain deletes are limited to 10,000 domains per request.
6
+
7
+ + Body
8
+
9
+ [
10
+ "example1.com",
11
+ "example2.com"
12
+ ]
13
+
14
+ + Response 204 (application/json)
@@ -0,0 +1,31 @@
1
+ # Group Users
2
+
3
+ ## A user [/user]
4
+
5
+ ### Get one user [GET]
6
+ + Response 200 (application/json)
7
+ + Attributes (User)
8
+ + Response 500 (application/json)
9
+
10
+ ## Some users [/users]
11
+
12
+ ### Post a user [POST]
13
+ + Request (application/json)
14
+ + Attributes(User)
15
+ + Response 201 (application/json)
16
+ + Attributes (User)
17
+ + Response 500 (application/json)
18
+
19
+ ### Get a collection of users [GET]
20
+ + Response 200 (application/json)
21
+ + Attributes (array[User])
22
+ + Response 500 (application/json)
23
+
24
+ # Data Structures
25
+
26
+ ## User (object)
27
+ + id (string, required)
28
+ + name (string, nullable, required)
29
+
30
+ ## Users (object)
31
+ + `users`(array[User], nullable, required)
@@ -0,0 +1,6 @@
1
+ # Data Structures
2
+ ## ImagesType (object)
3
+ + `name` (string)
4
+
5
+ ## BodyType (object)
6
+ + images (required, nullable, ImagesType)
@@ -0,0 +1,44 @@
1
+ {
2
+ "swagger": "2.0",
3
+ "info": {
4
+ "title": "",
5
+ "version": "",
6
+ "description": ""
7
+ },
8
+ "paths": {
9
+ "/domains": {
10
+ "delete": {
11
+ "responses": {
12
+ "204": {
13
+ "description": "No Content",
14
+ "headers": {},
15
+ "examples": {}
16
+ }
17
+ },
18
+ "summary": "",
19
+ "operationId": "",
20
+ "description": "",
21
+ "tags": [],
22
+ "parameters": [
23
+ {
24
+ "name": "body",
25
+ "in": "body",
26
+ "schema": {
27
+ "type": "array",
28
+ "items": {
29
+ "type": "string"
30
+ },
31
+ "example": [
32
+ "example1.com",
33
+ "example2.com"
34
+ ]
35
+ }
36
+ }
37
+ ]
38
+ }
39
+ }
40
+ },
41
+ "definitions": {},
42
+ "securityDefinitions": {},
43
+ "tags": []
44
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "swagger": "2.0",
3
+ "info": {
4
+ "title": "",
5
+ "version": "",
6
+ "description": ""
7
+ },
8
+ "paths": {
9
+ "/domains": {
10
+ "delete": {
11
+ "responses": {
12
+ "204": {
13
+ "description": "No Content",
14
+ "headers": {},
15
+ "examples": {}
16
+ }
17
+ },
18
+ "summary": "",
19
+ "operationId": "",
20
+ "description": "",
21
+ "tags": [],
22
+ "parameters": [
23
+ {
24
+ "name": "body",
25
+ "in": "body",
26
+ "schema": {
27
+ "type": "array",
28
+ "items": {
29
+ "type": "string"
30
+ },
31
+ "example": [
32
+ "example1.com",
33
+ "example2.com"
34
+ ]
35
+ }
36
+ }
37
+ ]
38
+ }
39
+ }
40
+ },
41
+ "definitions": {},
42
+ "securityDefinitions": {},
43
+ "tags": []
44
+ }
@@ -0,0 +1,202 @@
1
+ {
2
+ "openapi": "3.0.3",
3
+ "info": {
4
+ "title": "",
5
+ "version": "1.0.0",
6
+ "description": ""
7
+ },
8
+ "paths": {
9
+ "/user": {
10
+ "get": {
11
+ "responses": {
12
+ "200": {
13
+ "description": "OK",
14
+ "headers": {},
15
+ "content": {
16
+ "application/json": {
17
+ "schema": {
18
+ "type": "object",
19
+ "properties": {
20
+ "id": {
21
+ "type": "string"
22
+ },
23
+ "name": {
24
+ "type": "string",
25
+ "nullable": true
26
+ }
27
+ },
28
+ "required": [
29
+ "id",
30
+ "name"
31
+ ]
32
+ },
33
+ "example": {
34
+ "id": "",
35
+ "name": null
36
+ }
37
+ }
38
+ }
39
+ },
40
+ "500": {
41
+ "description": "Internal Server Error",
42
+ "headers": {},
43
+ "content": {}
44
+ }
45
+ },
46
+ "summary": "Get one user",
47
+ "operationId": "Get one user",
48
+ "description": "",
49
+ "tags": [
50
+ "Users"
51
+ ],
52
+ "parameters": []
53
+ }
54
+ },
55
+ "/users": {
56
+ "post": {
57
+ "responses": {
58
+ "201": {
59
+ "description": "Created",
60
+ "headers": {},
61
+ "content": {
62
+ "application/json": {
63
+ "schema": {
64
+ "type": "object",
65
+ "properties": {
66
+ "id": {
67
+ "type": "string"
68
+ },
69
+ "name": {
70
+ "type": "string",
71
+ "nullable": true
72
+ }
73
+ },
74
+ "required": [
75
+ "id",
76
+ "name"
77
+ ]
78
+ },
79
+ "example": {
80
+ "id": "",
81
+ "name": null
82
+ }
83
+ }
84
+ }
85
+ },
86
+ "500": {
87
+ "description": "Internal Server Error",
88
+ "headers": {},
89
+ "content": {}
90
+ }
91
+ },
92
+ "summary": "Post a user",
93
+ "operationId": "Post a user",
94
+ "description": "",
95
+ "tags": [
96
+ "Users"
97
+ ],
98
+ "parameters": [],
99
+ "requestBody": {
100
+ "content": {
101
+ "application/json": {
102
+ "example": {
103
+ "id": "",
104
+ "name": null
105
+ },
106
+ "schema": {
107
+ "type": "object",
108
+ "properties": {
109
+ "id": {
110
+ "type": "string"
111
+ },
112
+ "name": {
113
+ "type": "string",
114
+ "nullable": true
115
+ }
116
+ },
117
+ "required": [
118
+ "id",
119
+ "name"
120
+ ]
121
+ }
122
+ }
123
+ }
124
+ }
125
+ },
126
+ "get": {
127
+ "responses": {
128
+ "200": {
129
+ "description": "OK",
130
+ "headers": {},
131
+ "content": {
132
+ "application/json": {
133
+ "schema": {
134
+ "type": "array",
135
+ "items": {}
136
+ },
137
+ "example": [
138
+ {
139
+ "id": "",
140
+ "name": null
141
+ }
142
+ ]
143
+ }
144
+ }
145
+ },
146
+ "500": {
147
+ "description": "Internal Server Error",
148
+ "headers": {},
149
+ "content": {}
150
+ }
151
+ },
152
+ "summary": "Get a collection of users",
153
+ "operationId": "Get a collection of users",
154
+ "description": "",
155
+ "tags": [
156
+ "Users"
157
+ ],
158
+ "parameters": []
159
+ }
160
+ }
161
+ },
162
+ "components": {
163
+ "schemas": {
164
+ "User": {
165
+ "type": "object",
166
+ "required": [
167
+ "id",
168
+ "name"
169
+ ],
170
+ "properties": {
171
+ "id": {
172
+ "type": "string"
173
+ },
174
+ "name": {
175
+ "type": "string",
176
+ "nullable": true
177
+ }
178
+ }
179
+ },
180
+ "Users": {
181
+ "type": "object",
182
+ "required": [
183
+ "users"
184
+ ],
185
+ "properties": {
186
+ "users": {
187
+ "type": "array",
188
+ "items": {
189
+ "$ref": "#/components/schemas/User"
190
+ },
191
+ "nullable": true
192
+ }
193
+ }
194
+ }
195
+ }
196
+ },
197
+ "tags": [
198
+ {
199
+ "name": "Users"
200
+ }
201
+ ]
202
+ }
@@ -0,0 +1,163 @@
1
+ {
2
+ "openapi": "3.0.3",
3
+ "info": {
4
+ "title": "",
5
+ "version": "1.0.0",
6
+ "description": ""
7
+ },
8
+ "paths": {
9
+ "/user": {
10
+ "get": {
11
+ "responses": {
12
+ "200": {
13
+ "description": "OK",
14
+ "headers": {},
15
+ "content": {
16
+ "application/json": {
17
+ "schema": {
18
+ "$ref": "#/components/schemas/User"
19
+ },
20
+ "example": {
21
+ "id": "",
22
+ "name": null
23
+ }
24
+ }
25
+ }
26
+ },
27
+ "500": {
28
+ "description": "Internal Server Error",
29
+ "headers": {},
30
+ "content": {}
31
+ }
32
+ },
33
+ "summary": "Get one user",
34
+ "operationId": "Get one user",
35
+ "description": "",
36
+ "tags": [
37
+ "Users"
38
+ ],
39
+ "parameters": []
40
+ }
41
+ },
42
+ "/users": {
43
+ "post": {
44
+ "responses": {
45
+ "201": {
46
+ "description": "Created",
47
+ "headers": {},
48
+ "content": {
49
+ "application/json": {
50
+ "schema": {
51
+ "$ref": "#/components/schemas/User"
52
+ },
53
+ "example": {
54
+ "id": "",
55
+ "name": null
56
+ }
57
+ }
58
+ }
59
+ },
60
+ "500": {
61
+ "description": "Internal Server Error",
62
+ "headers": {},
63
+ "content": {}
64
+ }
65
+ },
66
+ "summary": "Post a user",
67
+ "operationId": "Post a user",
68
+ "description": "",
69
+ "tags": [
70
+ "Users"
71
+ ],
72
+ "parameters": [],
73
+ "requestBody": {
74
+ "content": {
75
+ "application/json": {
76
+ "example": {
77
+ "id": "",
78
+ "name": null
79
+ },
80
+ "schema": {
81
+ "$ref": "#/components/schemas/User"
82
+ }
83
+ }
84
+ }
85
+ }
86
+ },
87
+ "get": {
88
+ "responses": {
89
+ "200": {
90
+ "description": "OK",
91
+ "headers": {},
92
+ "content": {
93
+ "application/json": {
94
+ "schema": {
95
+ "type": "array",
96
+ "items": {}
97
+ },
98
+ "example": [
99
+ {
100
+ "id": "",
101
+ "name": null
102
+ }
103
+ ]
104
+ }
105
+ }
106
+ },
107
+ "500": {
108
+ "description": "Internal Server Error",
109
+ "headers": {},
110
+ "content": {}
111
+ }
112
+ },
113
+ "summary": "Get a collection of users",
114
+ "operationId": "Get a collection of users",
115
+ "description": "",
116
+ "tags": [
117
+ "Users"
118
+ ],
119
+ "parameters": []
120
+ }
121
+ }
122
+ },
123
+ "components": {
124
+ "schemas": {
125
+ "User": {
126
+ "type": "object",
127
+ "required": [
128
+ "id",
129
+ "name"
130
+ ],
131
+ "properties": {
132
+ "id": {
133
+ "type": "string"
134
+ },
135
+ "name": {
136
+ "type": "string",
137
+ "nullable": true
138
+ }
139
+ }
140
+ },
141
+ "Users": {
142
+ "type": "object",
143
+ "required": [
144
+ "users"
145
+ ],
146
+ "properties": {
147
+ "users": {
148
+ "type": "array",
149
+ "items": {
150
+ "$ref": "#/components/schemas/User"
151
+ },
152
+ "nullable": true
153
+ }
154
+ }
155
+ }
156
+ }
157
+ },
158
+ "tags": [
159
+ {
160
+ "name": "Users"
161
+ }
162
+ ]
163
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "openapi": "3.0.3",
3
+ "info": {
4
+ "title": "",
5
+ "version": "1.0.0",
6
+ "description": ""
7
+ },
8
+ "paths": {},
9
+ "components": {
10
+ "schemas": {
11
+ "ImagesType": {
12
+ "type": "object",
13
+ "properties": {
14
+ "name": {
15
+ "type": "string"
16
+ }
17
+ }
18
+ },
19
+ "BodyType": {
20
+ "type": "object",
21
+ "required": [
22
+ "images"
23
+ ],
24
+ "properties": {
25
+ "images": {
26
+ "oneOf": [
27
+ {
28
+ "$ref": "#/components/schemas/ImagesType"
29
+ },
30
+ {
31
+ "nullable": true
32
+ }
33
+ ]
34
+ }
35
+ }
36
+ }
37
+ }
38
+ },
39
+ "tags": []
40
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "openapi": "3.0.3",
3
+ "info": {
4
+ "title": "",
5
+ "version": "1.0.0",
6
+ "description": ""
7
+ },
8
+ "paths": {},
9
+ "components": {
10
+ "schemas": {
11
+ "ImagesType": {
12
+ "type": "object",
13
+ "properties": {
14
+ "name": {
15
+ "type": "string"
16
+ }
17
+ }
18
+ },
19
+ "BodyType": {
20
+ "type": "object",
21
+ "required": [
22
+ "images"
23
+ ],
24
+ "properties": {
25
+ "images": {
26
+ "oneOf": [
27
+ {
28
+ "$ref": "#/components/schemas/ImagesType"
29
+ },
30
+ {
31
+ "nullable": true
32
+ }
33
+ ]
34
+ }
35
+ }
36
+ }
37
+ }
38
+ },
39
+ "tags": []
40
+ }
package/test/test.js CHANGED
@@ -46,6 +46,7 @@ var remote = 'https://raw.githubusercontent.com/apiaryio/api-blueprint/format-1A
46
46
  'Issue-#36.md',
47
47
  'Issue-#38.md',
48
48
  'Issue-#49.md',
49
+ 'Issue-#57.md',
49
50
  'apiblueprint_uber.md',
50
51
  'apiblueprint_valid_simple.md',
51
52
  'schema_without_body.md',
@@ -53,7 +54,9 @@ var remote = 'https://raw.githubusercontent.com/apiaryio/api-blueprint/format-1A
53
54
  'OpenAPI3_requests.md',
54
55
  'OpenAPI3_headers.md',
55
56
  'OpenAPI3_includes.md',
56
- 'OpenAPI3_attributes.md'
57
+ 'OpenAPI3_attributes.md',
58
+ 'OpenAPI3_Issue-#58.md',
59
+ 'OpenAPI3_Issue-#66.md'
57
60
  ];
58
61
 
59
62
  var fetch = function (file) {