serverless-openapi-documenter 0.0.118 → 0.0.120-beta.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.
package/README.md CHANGED
@@ -12,7 +12,9 @@
12
12
  </a>
13
13
  </p>
14
14
 
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) from the OpenAPI file for you too. This currently works for `http` and `httpApi` configurations.
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.
16
18
 
17
19
  Originally based off of: https://github.com/temando/serverless-openapi-documentation
18
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serverless-openapi-documenter",
3
- "version": "0.0.118",
3
+ "version": "0.0.120-beta.1",
4
4
  "description": "Generate OpenAPI v3 documentation and Postman Collections from your Serverless Config",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -46,11 +46,11 @@
46
46
  "license": "MIT",
47
47
  "dependencies": {
48
48
  "@apidevtools/json-schema-ref-parser": "^9.1.0",
49
- "@redocly/openapi-core": "^1.2.0",
49
+ "@redocly/openapi-core": "^1.34.5",
50
50
  "chalk": "^4.1.2",
51
51
  "js-yaml": "^4.1.1",
52
52
  "json-schema-for-openapi": "^0.5.0",
53
- "openapi-to-postmanv2": "^5.4.1",
53
+ "openapi-to-postmanv2": "^5.6.0",
54
54
  "uuid": "^11.1.0"
55
55
  },
56
56
  "engines": {
@@ -16,6 +16,12 @@ 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
+
19
25
  this.modelReferences = {};
20
26
 
21
27
  this.__standardiseModels();
@@ -157,18 +163,30 @@ class SchemaHandler {
157
163
  }
158
164
  );
159
165
 
160
- this.logger.verbose(
161
- `dereferenced model: ${JSON.stringify(dereferencedSchema)}`
162
- );
166
+ if (this.shouldConvert) {
167
+ this.logger.verbose(
168
+ `dereferenced model: ${JSON.stringify(dereferencedSchema)}`
169
+ );
163
170
 
164
- this.logger.verbose(`converting model: ${name}`);
165
- const convertedSchemas = SchemaConvertor.convert(dereferencedSchema, name);
171
+ this.logger.verbose(`converting model: ${name}`);
172
+ const convertedSchemas = SchemaConvertor.convert(
173
+ dereferencedSchema,
174
+ name
175
+ );
176
+
177
+ this.logger.verbose(
178
+ `converted schemas: ${JSON.stringify(convertedSchemas)}`
179
+ );
180
+ return convertedSchemas;
181
+ }
166
182
 
167
183
  this.logger.verbose(
168
- `converted schemas: ${JSON.stringify(convertedSchemas)}`
184
+ `dereferenced model: ${JSON.stringify({
185
+ schemas: { [name]: dereferencedSchema },
186
+ })}`
169
187
  );
170
188
 
171
- return convertedSchemas;
189
+ return { schemas: { [name]: dereferencedSchema } };
172
190
  }
173
191
 
174
192
  async __dereferenceSchema(schema) {
@@ -38,7 +38,7 @@ describe("DefinitionGenerator", () => {
38
38
  expect(expected).to.be.an.instanceOf(DefinitionGenerator);
39
39
  });
40
40
 
41
- it("should default to version 3.0.0 of openAPI when openAPI version is not passed in", function () {
41
+ it("should default to version 3.0.0 of OpenAPI when OpenAPI version is not passed in", function () {
42
42
  const serverlessWithoutOpenAPIVersion = structuredClone(mockServerless);
43
43
  delete serverlessWithoutOpenAPIVersion.processedInput;
44
44
  let expected = new DefinitionGenerator(
@@ -105,7 +105,7 @@ describe("DefinitionGenerator", () => {
105
105
  expect(expected.version).to.be.equal("3.0.0");
106
106
  });
107
107
 
108
- it("should respect the version of openAPI when passed in", function () {
108
+ it("should respect the version of OpenAPI when passed in", function () {
109
109
  const serverlessWithOpenAPIVersion = structuredClone(mockServerless);
110
110
  serverlessWithOpenAPIVersion.processedInput.options.openApiVersion =
111
111
  "3.0.2";
@@ -157,7 +157,7 @@ describe("DefinitionGenerator", () => {
157
157
  });
158
158
 
159
159
  describe("createInfo", () => {
160
- it("should create openAPI info object correctly", function () {
160
+ it("should create OpenAPI info object correctly", function () {
161
161
  const definitionGenerator = new DefinitionGenerator(
162
162
  mockServerless,
163
163
  logger
@@ -918,14 +918,15 @@ describe("DefinitionGenerator", () => {
918
918
  definitionGenerator.openAPI.components.securitySchemes
919
919
  ).to.have.property("x_amazon_api_key");
920
920
  expect(
921
- definitionGenerator.openAPI.components.securitySchemes.x_amazon_api_key
921
+ definitionGenerator.openAPI.components.securitySchemes
922
+ .x_amazon_api_key
922
923
  ).to.have.property("x-amazon-apigateway-authtype");
923
924
  });
924
925
  });
925
926
  });
926
927
 
927
928
  describe("createTags", () => {
928
- it("should add tags to the openAPI object correctly", function () {
929
+ it("should add tags to the OpenAPI object correctly", function () {
929
930
  mockServerless.service.custom.documentation.tags = [{ name: "tag1" }];
930
931
 
931
932
  const definitionGenerator = new DefinitionGenerator(
@@ -68,7 +68,7 @@ describe("OpenAPIGenerator", () => {
68
68
  });
69
69
 
70
70
  describe("generationAndValidation", () => {
71
- it("should correctly generate a valid openAPI document", async function () {
71
+ it("should correctly generate a valid OpenAPI document", async function () {
72
72
  const succSpy = sinon.spy(logOutput.log, "success");
73
73
  const errSpy = sinon.spy(logOutput.log, "error");
74
74
 
@@ -99,7 +99,7 @@ describe("OpenAPIGenerator", () => {
99
99
  getFuncStub.reset();
100
100
  });
101
101
 
102
- xit("should throw an error when trying to generate an invalid openAPI document", async function () {
102
+ xit("should throw an error when trying to generate an invalid OpenAPI document", async function () {
103
103
  const succSpy = sinon.spy(logOutput.log, "success");
104
104
  const errSpy = sinon.spy(logOutput.log, "error");
105
105
 
@@ -135,7 +135,7 @@ describe("OpenAPIGenerator", () => {
135
135
  getFuncStub.reset();
136
136
  });
137
137
 
138
- it("should correctly validate a valid openAPI document", async function () {
138
+ it("should correctly validate a valid OpenAPI document", async function () {
139
139
  const succSpy = sinon.spy(logOutput.log, "success");
140
140
  const errSpy = sinon.spy(logOutput.log, "error");
141
141
 
@@ -168,7 +168,7 @@ describe("OpenAPIGenerator", () => {
168
168
  getFuncStub.reset();
169
169
  });
170
170
 
171
- it("should throw an error when trying to validate an invalid openAPI document", async function () {
171
+ it("should throw an error when trying to validate an invalid OpenAPI document", async function () {
172
172
  const succSpy = sinon.spy(logOutput.log, "success");
173
173
  const errSpy = sinon.spy(logOutput.log, "error");
174
174
 
@@ -212,7 +212,7 @@ describe("OpenAPIGenerator", () => {
212
212
  });
213
213
 
214
214
  describe("createPostman", () => {
215
- it("should generate a postman collection when a valid openAPI file is generated", function () {
215
+ it("should generate a postman collection when a valid OpenAPI file is generated", function () {
216
216
  const fsStub = sinon.stub(fs, "writeFileSync").returns(true);
217
217
  const succSpy = sinon.spy(logOutput.log, "success");
218
218
  const errSpy = sinon.spy(logOutput.log, "error");
@@ -4,7 +4,9 @@ const fs = require("fs").promises;
4
4
  const path = require("path");
5
5
 
6
6
  const expect = require("chai").expect;
7
+ const SchemaConvertor = require("json-schema-for-openapi");
7
8
  const nock = require("nock");
9
+ const sinon = require("sinon");
8
10
 
9
11
  const modelsDocumentOG = require("../models/models/models.json");
10
12
  const modelsAltDocumentOG = require("../models/models/models-alt.json");
@@ -36,7 +38,7 @@ describe(`SchemaHandler`, function () {
36
38
  );
37
39
 
38
40
  const openAPISchema = {
39
- version: "3.0.3",
41
+ openapi: "3.0.3",
40
42
  components: {
41
43
  schemas: {},
42
44
  },
@@ -277,7 +279,7 @@ describe(`SchemaHandler`, function () {
277
279
 
278
280
  describe(`addModelsToOpenAPI`, function () {
279
281
  describe(`embedded simple schemas`, function () {
280
- it(`should add the model to the openAPI schema`, async function () {
282
+ it(`should add the model to the OpenAPI schema`, async function () {
281
283
  Object.assign(
282
284
  mockServerless.service.custom.documentation,
283
285
  modelsDocument
@@ -306,7 +308,7 @@ describe(`SchemaHandler`, function () {
306
308
  });
307
309
  });
308
310
 
309
- it(`should add a model with references to the openAPI schema`, async function () {
311
+ it(`should add a model with references to the OpenAPI schema`, async function () {
310
312
  Object.assign(
311
313
  mockServerless.service.custom.documentation,
312
314
  modelsDocument
@@ -379,7 +381,7 @@ describe(`SchemaHandler`, function () {
379
381
  });
380
382
  });
381
383
 
382
- it(`should add a model with poorly dereferenced references to the openAPI schema`, async function () {
384
+ it(`should add a model with poorly dereferenced references to the OpenAPI schema`, async function () {
383
385
  Object.assign(
384
386
  mockServerless.service.custom.documentation,
385
387
  modelsDocument
@@ -446,7 +448,7 @@ describe(`SchemaHandler`, function () {
446
448
  });
447
449
 
448
450
  describe(`component references`, function () {
449
- it(`should add schemas with component references to the openAPI schema`, async function () {
451
+ it(`should add schemas with component references to the OpenAPI schema`, async function () {
450
452
  Object.assign(
451
453
  mockServerless.service.custom.documentation,
452
454
  modelsDocument
@@ -517,10 +519,86 @@ describe(`SchemaHandler`, function () {
517
519
  type: "string",
518
520
  });
519
521
  });
522
+
523
+ it(`should add schemas with component references to the OpenAPI schema using OpenAPI 3.1`, async function () {
524
+ Object.assign(
525
+ mockServerless.service.custom.documentation,
526
+ modelsDocument
527
+ );
528
+
529
+ mockServerless.service.custom.documentation.models.push({
530
+ name: "SuccessResponse",
531
+ contentType: "application/json",
532
+ schema: {
533
+ type: "array",
534
+ items: {
535
+ $ref: "#/components/schemas/Agency",
536
+ },
537
+ },
538
+ });
539
+
540
+ mockServerless.service.custom.documentation.models.push({
541
+ name: "Agency",
542
+ contentType: "application/json",
543
+ schema: {
544
+ type: "string",
545
+ },
546
+ });
547
+
548
+ openAPI.openapi = "3.1.0";
549
+
550
+ const schemaHandler = new SchemaHandler(
551
+ mockServerless,
552
+ openAPI,
553
+ logger
554
+ );
555
+
556
+ await schemaHandler.addModelsToOpenAPI();
557
+
558
+ expect(schemaHandler.openAPI).to.have.property("components");
559
+ expect(schemaHandler.openAPI.components).to.have.property("schemas");
560
+ expect(schemaHandler.openAPI.components.schemas).to.have.property(
561
+ "ErrorResponse"
562
+ );
563
+ expect(
564
+ schemaHandler.openAPI.components.schemas.ErrorResponse
565
+ ).to.be.an("object");
566
+ expect(
567
+ schemaHandler.openAPI.components.schemas.ErrorResponse
568
+ ).to.be.eql({
569
+ type: "object",
570
+ properties: { error: { type: "string" } },
571
+ });
572
+
573
+ expect(schemaHandler.openAPI.components.schemas).to.have.property(
574
+ "SuccessResponse"
575
+ );
576
+ expect(
577
+ schemaHandler.openAPI.components.schemas.SuccessResponse
578
+ ).to.be.an("object");
579
+ expect(
580
+ schemaHandler.openAPI.components.schemas.SuccessResponse
581
+ ).to.be.eql({
582
+ type: "array",
583
+ items: {
584
+ $ref: "#/components/schemas/Agency",
585
+ },
586
+ });
587
+
588
+ expect(schemaHandler.openAPI.components.schemas).to.have.property(
589
+ "Agency"
590
+ );
591
+ expect(schemaHandler.openAPI.components.schemas.Agency).to.be.an(
592
+ "object"
593
+ );
594
+ expect(schemaHandler.openAPI.components.schemas.Agency).to.be.eql({
595
+ type: "string",
596
+ });
597
+ });
520
598
  });
521
599
 
522
600
  describe(`other references`, function () {
523
- it(`should add a model that is a webUrl to the openAPI schema`, async function () {
601
+ it(`should add a model that is a webUrl to the OpenAPI schema`, async function () {
524
602
  Object.assign(
525
603
  mockServerless.service.custom.documentation,
526
604
  modelsDocument
@@ -589,7 +667,7 @@ describe(`SchemaHandler`, function () {
589
667
  });
590
668
  });
591
669
 
592
- it(`should add a complex model that is a webUrl to the openAPI schema`, async function () {
670
+ it(`should add a complex model that is a webUrl to the OpenAPI schema`, async function () {
593
671
  Object.assign(
594
672
  mockServerless.service.custom.documentation,
595
673
  modelsDocument
@@ -710,6 +788,28 @@ describe(`SchemaHandler`, function () {
710
788
  });
711
789
 
712
790
  describe(`createSchema`, function () {
791
+ it(`does not convert schemas when using OpenAPI 3.1.x`, async function () {
792
+ Object.assign(
793
+ mockServerless.service.custom.documentation,
794
+ modelsDocument
795
+ );
796
+
797
+ openAPI.openapi = "3.1.0";
798
+
799
+ const schemaHandler = new SchemaHandler(mockServerless, openAPI, logger);
800
+
801
+ const spy = sinon.spy(SchemaConvertor, "convert");
802
+
803
+ await schemaHandler.addModelsToOpenAPI();
804
+
805
+ const expected = await schemaHandler.createSchema("ErrorResponse");
806
+
807
+ expect(expected).to.be.equal("#/components/schemas/ErrorResponse");
808
+ expect(spy.calledOnce).to.be.false;
809
+
810
+ spy.restore();
811
+ });
812
+
713
813
  it(`returns a reference to the schema when the schema already exists in components and we don't pass through a schema`, async function () {
714
814
  Object.assign(
715
815
  mockServerless.service.custom.documentation,