serverless-openapi-documenter 0.0.120-beta.1 → 0.0.121

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.
package/README.md CHANGED
@@ -12,9 +12,7 @@
12
12
  </a>
13
13
  </p>
14
14
 
15
- This will generate an [OpenAPI V3](https://spec.openapis.org/oas/v3.0.0.html) (up to v3.0.4) specification file for you from your serverless file. It can optionally generate a [Postman Collection V2](https://github.com/postmanlabs/openapi-to-postman) from the OpenAPI file for you too. This currently works for `http` and `httpApi` configurations.
16
-
17
- If you are using the beta of 0.0.115, it will now try and create [OpenAPI V3.1 (3.1.x)](https://spec.openapis.org/oas/v3.1.0.html) specification file for you, should you run the command `serverless openapi generate -o openapi.json -f json -a 3.1.1 -p postman.json`. Please see this [guide on migrating to V3.1](https://www.openapis.org/blog/2021/02/16/migrating-from-openapi-3-0-to-3-1-0). Whilst I perosnally use this plugin all the time, please do open and report bugs, and I will do my best to fix them.
15
+ This will generate an OpenAPI V3 (up to v3.0.4) file for you from your serverless file. It can optionally generate a [Postman Collection V2](https://github.com/postmanlabs/openapi-to-postman) or (as of 0.0.120) [Bruno Collection](https://docs.usebruno.com/) from the OpenAPI file. This currently works for `http` and `httpApi` configurations.
18
16
 
19
17
  Originally based off of: https://github.com/temando/serverless-openapi-documentation
20
18
 
@@ -51,6 +49,7 @@ Options:
51
49
  --indent -i File indentation in spaces. Default: 2
52
50
  --openApiVersion -a OpenAPI version to generate for. Default: 3.0.0
53
51
  --postmanCollection -p Will generate a postman collection (from the generated OpenAPI Description), in json only, if passed in. Default: postman.json
52
+ --brunoCollection -b Will generate a Bruno collection (from the generated OpenAPI Description), in json only, if passed in. Default: bruno.json
54
53
  --validationWarn -w Warn about validation errors only. Will write the OpenAPI file if generation is successful. Default: false
55
54
  ```
56
55
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serverless-openapi-documenter",
3
- "version": "0.0.120-beta.1",
3
+ "version": "0.0.121",
4
4
  "description": "Generate OpenAPI v3 documentation and Postman Collections from your Serverless Config",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -22,6 +22,9 @@
22
22
  "PostmanCollections",
23
23
  "Postman-Collections",
24
24
  "Postman Collections",
25
+ "Bruno Collection",
26
+ "Bruno",
27
+ "Use Bruno",
25
28
  "AWS",
26
29
  "AWS APIGateway",
27
30
  "Api Gateway",
@@ -46,7 +49,8 @@
46
49
  "license": "MIT",
47
50
  "dependencies": {
48
51
  "@apidevtools/json-schema-ref-parser": "^9.1.0",
49
- "@redocly/openapi-core": "^1.34.5",
52
+ "@redocly/openapi-core": "^1.2.0",
53
+ "@usebruno/converters": "^0.15.0",
50
54
  "chalk": "^4.1.2",
51
55
  "js-yaml": "^4.1.1",
52
56
  "json-schema-for-openapi": "^0.5.0",
package/src/bruno.js ADDED
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ const { openApiToBruno } = require('@usebruno/converters');
4
+
5
+ const fs = require('fs/promises')
6
+
7
+ class Bruno {
8
+ constructor(output, serverless, logger) {
9
+ this.output = output;
10
+ this.logger = logger;
11
+ this.serverless = serverless;
12
+ }
13
+
14
+ async create(openAPI) {
15
+ try {
16
+ const brunoCollection = openApiToBruno(openAPI);
17
+
18
+ await fs.writeFile(this.output, JSON.stringify(brunoCollection, null, 2));
19
+ this.logger.success(
20
+ "Bruno collection Documentation Successfully Written"
21
+ );
22
+ } catch (error) {
23
+ this.logger.error(
24
+ `ERROR: An error was thrown whilst writing the Bruno collection`
25
+ );
26
+
27
+ throw new this.serverless.classes.Error(error);
28
+ }
29
+ }
30
+ }
31
+
32
+ module.exports = Bruno;
@@ -0,0 +1,29 @@
1
+ 'use strict';
2
+
3
+ const Bruno = require('./bruno');
4
+ const Postman = require('./postman');
5
+
6
+ class CollectionFactory {
7
+ constructor(outputFile, serverless, logger) {
8
+ this.outputFile = outputFile;
9
+ this.serverless = serverless;
10
+ this.logger = logger;
11
+ }
12
+
13
+ createCollection(type) {
14
+ let creator;
15
+ switch (type){
16
+ case 'bruno':
17
+ creator = new Bruno(this.outputFile, this.serverless, this.logger);
18
+ break;
19
+
20
+ case 'postman':
21
+ creator = new Postman(this.outputFile, this.serverless, this.logger);
22
+ break;
23
+ }
24
+
25
+ return creator;
26
+ }
27
+ }
28
+
29
+ module.exports = CollectionFactory;
@@ -4,9 +4,9 @@ const fs = require("fs");
4
4
  const yaml = require("js-yaml");
5
5
  const chalk = require("chalk");
6
6
 
7
+ const Collection = require('./collection')
7
8
  const DefinitionGenerator = require("./definitionGenerator");
8
9
  const Logger = require("./logger");
9
- const PostmanGenerator = require("openapi-to-postmanv2");
10
10
 
11
11
  class OpenAPIGenerator {
12
12
  constructor(serverless, options, { log = {} } = {}) {
@@ -44,10 +44,16 @@ class OpenAPIGenerator {
44
44
  },
45
45
  postmanCollection: {
46
46
  usage:
47
- "Output a postman collection and attach to OpenApi external documents [default: postman.json if passed]",
47
+ "Output a Postman collection and attach to OpenApi external documents [default: postman.json if passed]",
48
48
  shortcut: "p",
49
49
  type: "string",
50
50
  },
51
+ brunoCollection: {
52
+ usage:
53
+ "Output a Bruno collection and attach to OpenApi external documents [default: bruno.json if passed]",
54
+ shortcut: "b",
55
+ type: "string",
56
+ },
51
57
  validationWarn: {
52
58
  usage:
53
59
  "Only warn about validation errors of the OpenAPI Description, write the file if parsing is successful [default: false]",
@@ -144,8 +150,9 @@ class OpenAPIGenerator {
144
150
  throw new this.serverless.classes.Error(err);
145
151
  });
146
152
 
147
- if (this.config.postmanCollection) {
148
- this.createPostman(validOpenAPI);
153
+ if (this.shouldCreateCollection()) {
154
+ await this.createCollection(validOpenAPI)
155
+
149
156
  }
150
157
 
151
158
  let output;
@@ -210,41 +217,21 @@ class OpenAPIGenerator {
210
217
  return generator.openAPI;
211
218
  }
212
219
 
213
- createPostman(openAPI) {
214
- const postmanGeneration = (err, result) => {
215
- if (err) {
216
- this.logger.error(
217
- `ERROR: An error was thrown when generating the postman collection`
218
- );
219
- throw new this.serverless.classes.Error(err);
220
- }
220
+ async createCollection(validOpenAPI) {
221
+ const collectionOutputFile = this.config.postmanCollection || this.config.brunoCollection
222
+ const collection = new Collection(collectionOutputFile, this.serverless, this.logger)
223
+ const collectionCreator = collection.createCollection(this.collectionType())
221
224
 
222
- this.logger.success(
223
- "postman collection v2 Documentation Successfully Generated"
224
- );
225
+ await collectionCreator.create(validOpenAPI)
226
+ }
225
227
 
226
- try {
227
- fs.writeFileSync(
228
- this.config.postmanCollection,
229
- JSON.stringify(result.output[0].data)
230
- );
231
- this.logger.success(
232
- "postman collection v2 Documentation Successfully Written"
233
- );
234
- } catch (err) {
235
- this.logger.error(
236
- `ERROR: An error was thrown whilst writing the postman collection`
237
- );
238
-
239
- throw new this.serverless.classes.Error(err);
240
- }
241
- };
228
+ shouldCreateCollection() {
229
+ return Boolean(this.config.postmanCollection || this.config.brunoCollection)
230
+ }
242
231
 
243
- PostmanGenerator.convert(
244
- { type: "json", data: structuredClone(openAPI) },
245
- {},
246
- postmanGeneration
247
- );
232
+ collectionType() {
233
+ if (this.config.postmanCollection) return 'postman'
234
+ else return 'bruno'
248
235
  }
249
236
 
250
237
  processCliInput() {
@@ -254,6 +241,7 @@ class OpenAPIGenerator {
254
241
  indent: 2,
255
242
  openApiVersion: "3.0.0",
256
243
  postmanCollection: "postman.json",
244
+ brunoCollection: "bruno.json",
257
245
  validationWarn: false,
258
246
  };
259
247
 
@@ -263,6 +251,8 @@ class OpenAPIGenerator {
263
251
  this.serverless.processedInput.options.openApiVersion || "3.0.0";
264
252
  config.postmanCollection =
265
253
  this.serverless.processedInput.options.postmanCollection || null;
254
+ config.brunoCollection =
255
+ this.serverless.processedInput.options.brunoCollection || null;
266
256
  config.validationWarn =
267
257
  this.serverless.processedInput.options.validationWarn || false;
268
258
 
@@ -285,7 +275,12 @@ class OpenAPIGenerator {
285
275
  validationWarn: ${chalk.bold.green(String(config.validationWarn))}
286
276
  ${
287
277
  config.postmanCollection
288
- ? `postman collection: ${chalk.bold.green(config.postmanCollection)}`
278
+ ? `Postman collection: ${chalk.bold.green(config.postmanCollection)}`
279
+ : `\n\n`
280
+ }
281
+ ${
282
+ config.brunoCollection
283
+ ? `Bruno collection: ${chalk.bold.green(config.brunoCollection)}`
289
284
  : `\n\n`
290
285
  }`
291
286
  );
package/src/postman.js ADDED
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+
3
+ const PostmanGenerator = require("openapi-to-postmanv2");
4
+
5
+ const fs = require('fs');
6
+
7
+ class Postman {
8
+ constructor(output, serverless, logger) {
9
+ this.output = output;
10
+ this.logger = logger;
11
+ this.serverless = serverless;
12
+ }
13
+
14
+ create(openAPI) {
15
+ const postmanGeneration = (err, result) => {
16
+ if (err) {
17
+ this.logger.error(
18
+ `ERROR: An error was thrown when generating the Postman collection`
19
+ );
20
+ throw new this.serverless.classes.Error(err);
21
+ }
22
+
23
+ this.logger.success(
24
+ "Postman collection v2 Documentation Successfully Generated"
25
+ );
26
+
27
+ try {
28
+ fs.writeFileSync(
29
+ this.output,
30
+ JSON.stringify(result.output[0].data)
31
+ );
32
+
33
+ this.logger.success(
34
+ "Postman collection v2 Documentation Successfully Written"
35
+ );
36
+ } catch (err) {
37
+ this.logger.error(
38
+ `ERROR: An error was thrown whilst writing the Postman collection`
39
+ );
40
+
41
+ throw new this.serverless.classes.Error(err);
42
+ }
43
+ };
44
+
45
+ PostmanGenerator.convert(
46
+ { type: "json", data: structuredClone(openAPI) },
47
+ {},
48
+ postmanGeneration
49
+ );
50
+ }
51
+ }
52
+
53
+ module.exports = Postman;
@@ -16,12 +16,6 @@ class SchemaHandler {
16
16
  this.documentation = serverless.service.custom.documentation;
17
17
  this.openAPI = openAPI;
18
18
 
19
- this.shouldConvert = true;
20
- if (/(3\.1\.\d)/g.test(this.openAPI.openapi)) this.shouldConvert = false;
21
-
22
- this.logger.verbose(`OpenAPI version: ${this.openAPI.openapi}`);
23
- this.logger.verbose(`Convert Schemas: ${this.shouldConvert}`);
24
-
25
19
  this.modelReferences = {};
26
20
 
27
21
  this.__standardiseModels();
@@ -163,30 +157,18 @@ class SchemaHandler {
163
157
  }
164
158
  );
165
159
 
166
- if (this.shouldConvert) {
167
- this.logger.verbose(
168
- `dereferenced model: ${JSON.stringify(dereferencedSchema)}`
169
- );
170
-
171
- this.logger.verbose(`converting model: ${name}`);
172
- const convertedSchemas = SchemaConvertor.convert(
173
- dereferencedSchema,
174
- name
175
- );
160
+ this.logger.verbose(
161
+ `dereferenced model: ${JSON.stringify(dereferencedSchema)}`
162
+ );
176
163
 
177
- this.logger.verbose(
178
- `converted schemas: ${JSON.stringify(convertedSchemas)}`
179
- );
180
- return convertedSchemas;
181
- }
164
+ this.logger.verbose(`converting model: ${name}`);
165
+ const convertedSchemas = SchemaConvertor.convert(dereferencedSchema, name);
182
166
 
183
167
  this.logger.verbose(
184
- `dereferenced model: ${JSON.stringify({
185
- schemas: { [name]: dereferencedSchema },
186
- })}`
168
+ `converted schemas: ${JSON.stringify(convertedSchemas)}`
187
169
  );
188
170
 
189
- return { schemas: { [name]: dereferencedSchema } };
171
+ return convertedSchemas;
190
172
  }
191
173
 
192
174
  async __dereferenceSchema(schema) {
package/test/.mocharc.js DELETED
@@ -1,9 +0,0 @@
1
- 'use strict'
2
-
3
- module.exports = {
4
- recursive: true,
5
- reporter: 'spec',
6
- spec: 'test/unit/*.spec.js',
7
- watch: false,
8
- 'watch-files': ['src/**/*.js', 'test/**/*.spec.js'],
9
- }
@@ -1,4 +0,0 @@
1
- {
2
- "struct": "error",
3
- "operation-2xx-response": "warn"
4
- }
@@ -1,5 +0,0 @@
1
- 'use strict'
2
-
3
- module.exports = {
4
- continueOnError: true, // Don't throw on the first error
5
- }
@@ -1,19 +0,0 @@
1
- 'use strict'
2
-
3
- module.exports = {
4
- processedInput: {
5
- options: {
6
- openApiVersion: '3.0.1'
7
- }
8
- },
9
- service: {
10
- service: 'myAPI',
11
- custom: {
12
- documentation: {
13
- title: 'My new API',
14
- description: 'This API does things',
15
- version: '0.0.1'
16
- }
17
- }
18
- }
19
- }
@@ -1,91 +0,0 @@
1
- {
2
- "$comment": "JSON Schema for CSR Framework",
3
- "$schema": "http://json-schema.org/draft-04/schema",
4
- "definitions": {
5
- "log": {
6
- "type": "object",
7
- "title": "Logger options",
8
- "properties": {
9
- "channel": {
10
- "type": "string",
11
- "default": "console"
12
- },
13
- "path": {
14
- "type": "string",
15
- "default": "../src/logs"
16
- },
17
- "template": {
18
- "type": "object",
19
- "properties": {
20
- "message": {
21
- "type": "string"
22
- },
23
- "file": {
24
- "type": "string"
25
- },
26
- "dir": {
27
- "type": "string"
28
- }
29
- }
30
- },
31
- "telegram": {
32
- "type": "object",
33
- "properties": {
34
- "bot_token": {
35
- "type": "string"
36
- },
37
- "chat_id": {
38
- "type": "string"
39
- }
40
- },
41
- "required": ["chat_id", "bot_token"]
42
- }
43
- }
44
- },
45
- "template": {
46
- "type": "object",
47
- "properties": {
48
- "path": {
49
- "type": "string"
50
- },
51
- "cache": {
52
- "type": "string"
53
- }
54
- }
55
- },
56
- "database": {
57
- "type": "object",
58
- "patternProperties": {
59
- ".*": {
60
- "type": "object",
61
- "properties": {
62
- "provider": {
63
- "type": "string"
64
- },
65
- "user": {
66
- "type": "string"
67
- },
68
- "password": {
69
- "type": "string"
70
- }
71
- },
72
- "required": ["provider"]
73
- }
74
- }
75
- }
76
- },
77
- "id": "https://json.schemastore.org/csr",
78
- "properties": {
79
- "log": {
80
- "$ref": "#/definitions/log"
81
- },
82
- "template": {
83
- "$ref": "#/definitions/template"
84
- },
85
- "database": {
86
- "$ref": "#/definitions/database"
87
- }
88
- },
89
- "title": "CSR Framework schema",
90
- "type": "object"
91
- }
@@ -1,53 +0,0 @@
1
- {
2
- "last_update_utc": "2024-09-19 21:29:28",
3
- "headers": [
4
- {
5
- "name": "Cache-Control",
6
- "value": "no-store, max-age=0"
7
- },
8
- {
9
- "name": "Clear-Site-Data",
10
- "value": "\"cache\",\"cookies\",\"storage\""
11
- },
12
- {
13
- "name": "Content-Security-Policy",
14
- "value": "default-src 'self'; form-action 'self'; object-src 'none'; frame-ancestors 'none'; upgrade-insecure-requests; block-all-mixed-content"
15
- },
16
- {
17
- "name": "Cross-Origin-Embedder-Policy",
18
- "value": "require-corp"
19
- },
20
- {
21
- "name": "Cross-Origin-Opener-Policy",
22
- "value": "same-origin"
23
- },
24
- {
25
- "name": "Cross-Origin-Resource-Policy",
26
- "value": "same-origin"
27
- },
28
- {
29
- "name": "Permissions-Policy",
30
- "value": "accelerometer=(), autoplay=(), camera=(), cross-origin-isolated=(), display-capture=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(self), usb=(), web-share=(), xr-spatial-tracking=(), clipboard-read=(), clipboard-write=(), gamepad=(), hid=(), idle-detection=(), interest-cohort=(), serial=(), unload=()"
31
- },
32
- {
33
- "name": "Referrer-Policy",
34
- "value": "no-referrer"
35
- },
36
- {
37
- "name": "Strict-Transport-Security",
38
- "value": "max-age=31536000; includeSubDomains"
39
- },
40
- {
41
- "name": "X-Content-Type-Options",
42
- "value": "nosniff"
43
- },
44
- {
45
- "name": "X-Frame-Options",
46
- "value": "deny"
47
- },
48
- {
49
- "name": "X-Permitted-Cross-Domain-Policies",
50
- "value": "none"
51
- }
52
- ]
53
- }