serverless-openapi-documenter 0.0.81 → 0.0.82

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
@@ -49,6 +49,7 @@ Options:
49
49
  --indent -i File indentation in spaces. Default: 2
50
50
  --openApiVersion -a OpenAPI version to generate for. Default: 3.0.0
51
51
  --postmanCollection -p Will generate a postman collection (from the generated openAPI documentation), in json only, if passed in. Default postman.json
52
+ --validationWarn -w Warn about validation errors only. Will write the OpenAPI file if generation is successful. Default: false
52
53
  ```
53
54
 
54
55
  ### README Highlighted Reading
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serverless-openapi-documenter",
3
- "version": "0.0.81",
3
+ "version": "0.0.82",
4
4
  "description": "Generate OpenAPI v3 documentation and Postman Collections from your Serverless Config",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -1,251 +1,332 @@
1
- 'use strict'
1
+ "use strict";
2
2
 
3
- const fs = require('fs')
4
- const yaml = require('js-yaml');
5
- const chalk = require('chalk')
3
+ const fs = require("fs");
4
+ const yaml = require("js-yaml");
5
+ const chalk = require("chalk");
6
6
 
7
- const DefinitionGenerator = require('./definitionGenerator')
8
- const PostmanGenerator = require('openapi-to-postmanv2')
7
+ const DefinitionGenerator = require("./definitionGenerator");
8
+ const PostmanGenerator = require("openapi-to-postmanv2");
9
9
 
10
10
  class OpenAPIGenerator {
11
- constructor(serverless, options, {log = {}} = {}) {
12
- this.logOutput = log;
13
- this.serverless = serverless
14
- this.options = options
15
-
16
- this.logTypes = {
17
- NOTICE: 'notice',
18
- DEBUG: 'debug',
19
- ERROR: 'error',
20
- WARNING: 'warning',
21
- INFO: 'info',
22
- VERBOSE: 'verbose',
23
- SUCCESS: 'success',
24
- }
25
-
26
- this.defaultLog = this.logTypes.NOTICE;
27
-
28
- this.commands = {
29
- openapi: {
30
- commands: {
31
- generate: {
32
- lifecycleEvents: [
33
- 'serverless',
34
- ],
35
- usage: 'Generate OpenAPI v3 Documentation',
36
- options: {
37
- output: {
38
- usage: 'Output file location [default: openapi.json|yml]',
39
- shortcut: 'o',
40
- type: 'string',
41
- },
42
- format: {
43
- usage: 'OpenAPI file format (yml|json) [default: json]',
44
- shortcut: 'f',
45
- type: 'string',
46
- },
47
- indent: {
48
- usage: 'File indentation in spaces [default: 2]',
49
- shortcut: 'i',
50
- type: 'string',
51
- },
52
- openApiVersion: {
53
- usage: 'OpenAPI version number [default 3.0.0]',
54
- shortcut: 'a',
55
- type: 'string'
56
- },
57
- postmanCollection: {
58
- usage: 'Output a postman collection and attach to openApi external documents [default: postman.json if passed]',
59
- shortcut: 'p',
60
- type: 'string'
61
- }
62
- },
11
+ constructor(serverless, options, { log = {} } = {}) {
12
+ this.logOutput = log;
13
+ this.serverless = serverless;
14
+ this.options = options;
15
+
16
+ this.logTypes = {
17
+ NOTICE: "notice",
18
+ DEBUG: "debug",
19
+ ERROR: "error",
20
+ WARNING: "warning",
21
+ INFO: "info",
22
+ VERBOSE: "verbose",
23
+ SUCCESS: "success",
24
+ };
25
+
26
+ this.defaultLog = this.logTypes.NOTICE;
27
+
28
+ this.commands = {
29
+ openapi: {
30
+ commands: {
31
+ generate: {
32
+ lifecycleEvents: ["serverless"],
33
+ usage: "Generate OpenAPI v3 Documentation",
34
+ options: {
35
+ output: {
36
+ usage: "Output file location [default: openapi.json|yml]",
37
+ shortcut: "o",
38
+ type: "string",
39
+ },
40
+ format: {
41
+ usage: "OpenAPI file format (yml|json) [default: json]",
42
+ shortcut: "f",
43
+ type: "string",
44
+ },
45
+ indent: {
46
+ usage: "File indentation in spaces [default: 2]",
47
+ shortcut: "i",
48
+ type: "string",
49
+ },
50
+ openApiVersion: {
51
+ usage: "OpenAPI version number [default: 3.0.0]",
52
+ shortcut: "a",
53
+ type: "string",
54
+ },
55
+ postmanCollection: {
56
+ usage:
57
+ "Output a postman collection and attach to OpenApi external documents [default: postman.json if passed]",
58
+ shortcut: "p",
59
+ type: "string",
60
+ },
61
+ validationWarn: {
62
+ usage:
63
+ "Only warn about validation errors of the OpenAPI document, write the file if parsing is successful [default: false]",
64
+ shortcut: "w",
65
+ type: "boolean",
63
66
  },
64
67
  },
65
68
  },
66
- }
69
+ },
70
+ },
71
+ };
67
72
 
68
- this.hooks = {
69
- 'openapi:generate:serverless': this.generate.bind(this),
70
- };
73
+ this.hooks = {
74
+ "openapi:generate:serverless": this.generate.bind(this),
75
+ };
71
76
 
72
- this.customVars = this.serverless.variables.service.custom;
77
+ this.customVars = this.serverless.variables.service.custom;
73
78
 
74
- const functionEventDocumentationSchema = {
79
+ const functionEventDocumentationSchema = {
80
+ properties: {
81
+ documentation: {
82
+ type: "object",
75
83
  properties: {
76
- documentation: {
77
- type: 'object',
78
- properties: {
79
- methodResponses: {
80
- type: 'array'
81
- },
82
- },
83
- required: ['methodResponses']
84
+ methodResponses: {
85
+ type: "array",
84
86
  },
85
87
  },
88
+ required: ["methodResponses"],
89
+ },
90
+ },
91
+ };
92
+
93
+ this.serverless.configSchemaHandler.defineCustomProperties({
94
+ type: "object",
95
+ properties: {
96
+ documentation: {
97
+ type: "object",
98
+ },
99
+ },
100
+ required: ["documentation"],
101
+ });
102
+
103
+ this.serverless.configSchemaHandler.defineFunctionEventProperties(
104
+ "aws",
105
+ "http",
106
+ functionEventDocumentationSchema
107
+ );
108
+
109
+ this.serverless.configSchemaHandler.defineFunctionEventProperties(
110
+ "aws",
111
+ "httpApi",
112
+ functionEventDocumentationSchema
113
+ );
114
+
115
+ this.serverless.configSchemaHandler.defineFunctionProperties("aws", {
116
+ properties: {
117
+ summary: { type: "string" },
118
+ servers: { anyOf: [{ type: "object" }, { type: "array" }] },
119
+ },
120
+ });
121
+ }
122
+
123
+ log(str, type = this.defaultLog) {
124
+ switch (this.serverless.version[0]) {
125
+ case "2":
126
+ let colouredString = str;
127
+ if (type === "error") {
128
+ colouredString = chalk.bold.red(`✖ ${str}`);
129
+ } else if (type === "success") {
130
+ colouredString = chalk.bold.green(`✓ ${str}`);
86
131
  }
87
132
 
88
- this.serverless.configSchemaHandler.defineCustomProperties({
89
- type: 'object',
90
- properties: {
91
- documentation: {
92
- type: 'object'
93
- }
94
- },
95
- required: ['documentation']
96
- })
133
+ this.serverless.cli.log(colouredString);
134
+ break;
97
135
 
98
- this.serverless.configSchemaHandler.defineFunctionEventProperties('aws', 'http', functionEventDocumentationSchema);
136
+ case "3":
137
+ this.logOutput[type](str);
138
+ break;
99
139
 
100
- this.serverless.configSchemaHandler.defineFunctionEventProperties('aws', 'httpApi', functionEventDocumentationSchema);
101
-
102
- this.serverless.configSchemaHandler.defineFunctionProperties('aws', {
103
- properties: {
104
- summary: {type: 'string'},
105
- servers: {anyOf: [{type:'object'}, {type:'array'}]},
106
- }
107
- })
108
- }
109
-
110
- log(str, type = this.defaultLog) {
111
- switch(this.serverless.version[0]) {
112
- case '2':
113
- let colouredString = str
114
- if (type === 'error') {
115
- colouredString = chalk.bold.red(`✖ ${str}`)
116
- } else if (type === 'success') {
117
- colouredString = chalk.bold.green(`✓ ${str}`)
118
- }
119
-
120
- this.serverless.cli.log(colouredString)
121
- break
122
-
123
- case '3':
124
- this.logOutput[type](str)
125
- break
126
-
127
- default:
128
- process.stdout.write(str.join(' '))
129
- break
130
- }
140
+ default:
141
+ process.stdout.write(str.join(" "));
142
+ break;
131
143
  }
144
+ }
132
145
 
133
- async generate() {
134
- this.log(chalk.bold.underline('OpenAPI v3 Document Generation'))
135
- this.processCliInput()
146
+ async generate() {
147
+ this.log(chalk.bold.underline("OpenAPI v3 Document Generation"));
148
+ this.processCliInput();
136
149
 
137
- const validOpenAPI = await this.generationAndValidation()
138
- .catch(err => {
139
- throw new this.serverless.classes.Error(err)
140
- })
150
+ const validOpenAPI = await this.generationAndValidation().catch((err) => {
151
+ throw new this.serverless.classes.Error(err);
152
+ });
141
153
 
142
- if (this.config.postmanCollection) {
143
- this.createPostman(validOpenAPI)
144
- }
145
-
146
- let output
147
- switch (this.config.format.toLowerCase()) {
148
- case 'json':
149
- output = JSON.stringify(validOpenAPI, null, this.config.indent);
150
- break;
151
- case 'yaml':
152
- default:
153
- output = yaml.dump(validOpenAPI, { indent: this.config.indent });
154
- break;
155
- }
156
- try {
157
- fs.writeFileSync(this.config.file, output);
158
- this.log('OpenAPI v3 Documentation Successfully Written', this.logTypes.SUCCESS)
159
- } catch (err) {
160
- this.log(`ERROR: An error was thrown whilst writing the openAPI Documentation`, this.logTypes.ERROR)
161
- throw new this.serverless.classes.Error(err)
162
- }
154
+ if (this.config.postmanCollection) {
155
+ this.createPostman(validOpenAPI);
163
156
  }
164
157
 
165
- async generationAndValidation() {
166
- const generator = new DefinitionGenerator(this.serverless);
167
-
168
- await generator.parse()
169
- .catch(err => {
170
- this.log(`ERROR: An error was thrown generating the OpenAPI v3 documentation`, this.logTypes.ERROR)
171
- throw new this.serverless.classes.Error(err)
172
- })
173
-
174
- await generator.validate()
175
- .catch(err => {
176
- this.log(`ERROR: An error was thrown validating the OpenAPI v3 documentation`, this.logTypes.ERROR)
177
- this.validationErrorDetails(err)
178
- throw new this.serverless.classes.Error(err)
179
- })
180
-
181
-
182
- this.log('OpenAPI v3 Documentation Successfully Generated', this.logTypes.SUCCESS)
183
-
184
- return generator.openAPI
158
+ let output;
159
+ switch (this.config.format.toLowerCase()) {
160
+ case "json":
161
+ output = JSON.stringify(validOpenAPI, null, this.config.indent);
162
+ break;
163
+ case "yaml":
164
+ default:
165
+ output = yaml.dump(validOpenAPI, { indent: this.config.indent });
166
+ break;
185
167
  }
168
+ try {
169
+ fs.writeFileSync(this.config.file, output);
170
+ this.log(
171
+ "OpenAPI v3 Documentation Successfully Written",
172
+ this.logTypes.SUCCESS
173
+ );
174
+ } catch (err) {
175
+ this.log(
176
+ `ERROR: An error was thrown whilst writing the openAPI Documentation`,
177
+ this.logTypes.ERROR
178
+ );
179
+ throw new this.serverless.classes.Error(err);
180
+ }
181
+ }
186
182
 
187
- createPostman(openAPI) {
188
- const postmanGeneration = (err, result) => {
189
- if (err) {
190
- this.log(`ERROR: An error was thrown when generating the postman collection`, this.logTypes.ERROR)
191
- throw new this.serverless.classes.Error(err)
192
- }
183
+ async generationAndValidation() {
184
+ const generator = new DefinitionGenerator(this.serverless);
193
185
 
194
- this.log('postman collection v2 Documentation Successfully Generated', this.logTypes.SUCCESS)
195
- try {
196
- fs.writeFileSync(this.config.postmanCollection, JSON.stringify(result.output[0].data))
197
- this.log('postman collection v2 Documentation Successfully Written', this.logTypes.SUCCESS)
198
- } catch (err) {
199
- this.log(`ERROR: An error was thrown whilst writing the postman collection`, this.logTypes.ERROR)
200
- throw new this.serverless.classes.Error(err)
201
- }
186
+ this.log(`Generating OpenAPI documentation`, this.logTypes.NOTICE);
187
+ await generator.parse().catch((err) => {
188
+ this.log(
189
+ `ERROR: An error was thrown generating the OpenAPI v3 documentation`,
190
+ this.logTypes.ERROR
191
+ );
192
+ throw new this.serverless.classes.Error(err);
193
+ });
194
+
195
+ this.log(
196
+ `Validating generated OpenAPI documentation`,
197
+ this.logTypes.NOTICE
198
+ );
199
+
200
+ await generator.validate().catch((err) => {
201
+ this.log(
202
+ `ERROR: An error was thrown validating the OpenAPI v3 documentation`,
203
+ this.logTypes.ERROR
204
+ );
205
+ this.validationErrorDetails(err);
206
+ if (this.config.validationWarn === false) {
207
+ throw new this.serverless.classes.Error(err);
208
+ }
209
+ });
210
+
211
+ this.log(
212
+ "OpenAPI v3 Documentation Successfully Generated",
213
+ this.logTypes.SUCCESS
214
+ );
215
+
216
+ return generator.openAPI;
217
+ }
218
+
219
+ createPostman(openAPI) {
220
+ const postmanGeneration = (err, result) => {
221
+ if (err) {
222
+ this.log(
223
+ `ERROR: An error was thrown when generating the postman collection`,
224
+ this.logTypes.ERROR
225
+ );
226
+ throw new this.serverless.classes.Error(err);
202
227
  }
203
228
 
204
- PostmanGenerator.convert(
205
- {type: 'json', data: JSON.parse(JSON.stringify(openAPI))},
206
- {},
207
- postmanGeneration
208
- )
209
- }
210
-
211
- processCliInput () {
212
- const config = {
213
- format: 'json',
214
- file: 'openapi.json',
215
- indent: 2,
216
- openApiVersion: '3.0.0',
217
- postmanCollection: 'postman.json'
218
- };
219
-
220
- config.indent = this.serverless.processedInput.options.indent || 2;
221
- config.format = this.serverless.processedInput.options.format || 'json';
222
- config.openApiVersion = this.serverless.processedInput.options.openApiVersion || '3.0.0';
223
- config.postmanCollection = this.serverless.processedInput.options.postmanCollection || null
224
-
225
- if (['yaml', 'json'].indexOf(config.format.toLowerCase()) < 0) {
226
- throw new this.serverless.classes.Error('Invalid Output Format Specified - must be one of "yaml" or "json"')
229
+ this.log(
230
+ "postman collection v2 Documentation Successfully Generated",
231
+ this.logTypes.SUCCESS
232
+ );
233
+ try {
234
+ fs.writeFileSync(
235
+ this.config.postmanCollection,
236
+ JSON.stringify(result.output[0].data)
237
+ );
238
+ this.log(
239
+ "postman collection v2 Documentation Successfully Written",
240
+ this.logTypes.SUCCESS
241
+ );
242
+ } catch (err) {
243
+ this.log(
244
+ `ERROR: An error was thrown whilst writing the postman collection`,
245
+ this.logTypes.ERROR
246
+ );
247
+ throw new this.serverless.classes.Error(err);
227
248
  }
249
+ };
250
+
251
+ PostmanGenerator.convert(
252
+ { type: "json", data: JSON.parse(JSON.stringify(openAPI)) },
253
+ {},
254
+ postmanGeneration
255
+ );
256
+ }
257
+
258
+ processCliInput() {
259
+ const config = {
260
+ format: "json",
261
+ file: "openapi.json",
262
+ indent: 2,
263
+ openApiVersion: "3.0.0",
264
+ postmanCollection: "postman.json",
265
+ validationWarn: false,
266
+ };
267
+
268
+ config.indent = this.serverless.processedInput.options.indent || 2;
269
+ config.format = this.serverless.processedInput.options.format || "json";
270
+ config.openApiVersion =
271
+ this.serverless.processedInput.options.openApiVersion || "3.0.0";
272
+ config.postmanCollection =
273
+ this.serverless.processedInput.options.postmanCollection || null;
274
+ config.validationWarn =
275
+ this.serverless.processedInput.options.validationWarn || false;
276
+
277
+ if (["yaml", "json"].indexOf(config.format.toLowerCase()) < 0) {
278
+ throw new this.serverless.classes.Error(
279
+ 'Invalid Output Format Specified - must be one of "yaml" or "json"'
280
+ );
281
+ }
228
282
 
229
- config.file = this.serverless.processedInput.options.output ||
230
- ((config.format === 'yaml') ? 'openapi.yml' : 'openapi.json');
283
+ config.file =
284
+ this.serverless.processedInput.options.output ||
285
+ (config.format === "yaml" ? "openapi.yml" : "openapi.json");
231
286
 
232
- this.log(
233
- `${chalk.bold.green('[OPTIONS]')}
287
+ this.log(
288
+ `${chalk.bold.green("[OPTIONS]")}
234
289
  openApiVersion: "${chalk.bold.green(String(config.openApiVersion))}"
235
290
  format: "${chalk.bold.green(config.format)}"
236
291
  output file: "${chalk.bold.green(config.file)}"
237
292
  indentation: "${chalk.bold.green(String(config.indent))}"
238
- ${config.postmanCollection ? `postman collection: ${chalk.bold.green(config.postmanCollection)}`: `\n\n`}`
239
- )
240
-
241
- this.config = config
242
- }
243
-
244
- validationErrorDetails(validationError) {
245
- this.log(`${chalk.bold.yellow('[VALIDATION]')} Failed to validate OpenAPI document: \n`, this.logTypes.ERROR);
246
- this.log(`${chalk.bold.yellow('Context:')} ${JSON.stringify(validationError.options.context[validationError.options.context.length-1], null, 2)}\n`, this.logTypes.ERROR);
247
- this.log(`${chalk.bold.yellow('Error Message:')} ${JSON.stringify(validationError.message, null, 2)}\n`, this.logTypes.ERROR);
248
- }
293
+ validationWarn: ${chalk.bold.green(String(config.validationWarn))}
294
+ ${
295
+ config.postmanCollection
296
+ ? `postman collection: ${chalk.bold.green(config.postmanCollection)}`
297
+ : `\n\n`
298
+ }`
299
+ );
300
+
301
+ this.config = config;
302
+ }
303
+
304
+ validationErrorDetails(validationError) {
305
+ this.log(
306
+ `${chalk.bold.yellow(
307
+ "[VALIDATION]"
308
+ )} Failed to validate OpenAPI document: \n`,
309
+ this.logTypes.ERROR
310
+ );
311
+ this.log(
312
+ `${chalk.bold.yellow("Context:")} ${JSON.stringify(
313
+ validationError.options.context[
314
+ validationError.options.context.length - 1
315
+ ],
316
+ null,
317
+ 2
318
+ )}\n`,
319
+ this.logTypes.ERROR
320
+ );
321
+ this.log(
322
+ `${chalk.bold.yellow("Error Message:")} ${JSON.stringify(
323
+ validationError.message,
324
+ null,
325
+ 2
326
+ )}\n`,
327
+ this.logTypes.ERROR
328
+ );
329
+ }
249
330
  }
250
331
 
251
- module.exports = OpenAPIGenerator
332
+ module.exports = OpenAPIGenerator;