Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "serverless-openapi-documenter",
"version": "0.0.112",
"version": "0.0.113",
"description": "Generate OpenAPI v3 documentation and Postman Collections from your Serverless Config",
"main": "index.js",
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion src/definitionGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ class DefinitionGenerator {
continue;
}

const obj = JSON.parse(JSON.stringify(this.DEFAULT_CORS_HEADERS[key]));
const obj = structuredClone(this.DEFAULT_CORS_HEADERS[key]);

if (key === "Access-Control-Allow-Origin") {
if (
Expand Down
2 changes: 1 addition & 1 deletion src/openAPIGenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ class OpenAPIGenerator {
};

PostmanGenerator.convert(
{ type: "json", data: JSON.parse(JSON.stringify(openAPI)) },
{ type: "json", data: structuredClone(openAPI) },
{},
postmanGeneration
);
Expand Down
78 changes: 53 additions & 25 deletions src/schemaHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,26 +71,15 @@ class SchemaHandler {
const modelName = model.name;
const modelSchema = model.schema;

this.logger.verbose(`dereferencing model: ${model.name}`);
const dereferencedSchema = await this.__dereferenceSchema(
modelSchema
const convertedSchemas = await this.__dereferenceAndConvert(
modelSchema,
modelName,
model
).catch((err) => {
if (err.errors) {
for (const error of err?.errors) {
this.__HTTPError(error, model);
}
} else {
this.__HTTPError(err, model);
}
return modelSchema;
if (err instanceof Error) throw err;
else return err;
});

this.logger.verbose(`convering model: ${model.name}`);
const convertedSchemas = SchemaConvertor.convert(
dereferencedSchema,
modelName
);

if (
typeof convertedSchemas.schemas === "object" &&
!Array.isArray(convertedSchemas.schemas) &&
Expand Down Expand Up @@ -129,13 +118,12 @@ class SchemaHandler {
return this.modelReferences[name];
}

const dereferencedSchema = await this.__dereferenceSchema(schema).catch(
(err) => {
throw err;
}
);

const convertedSchemas = SchemaConvertor.convert(dereferencedSchema, name);
const convertedSchemas = await this.__dereferenceAndConvert(schema, name, {
name,
schema,
}).catch((err) => {
throw err;
});

for (const [schemaName, schemaValue] of Object.entries(
convertedSchemas.schemas
Expand All @@ -157,6 +145,32 @@ class SchemaHandler {
return `#/components/schemas/${finalName}`;
}

async __dereferenceAndConvert(schema, name, model) {
this.logger.verbose(`dereferencing model: ${name}`);
const dereferencedSchema = await this.__dereferenceSchema(schema).catch(
(err) => {
this.__checkForHTTPErrorsAndThrow(err, model);

this.__checkForMissingPathAndThrow(err);

return schema;
}
);

this.logger.verbose(
`dereferenced model: ${JSON.stringify(dereferencedSchema)}`
);

this.logger.verbose(`converting model: ${name}`);
const convertedSchemas = SchemaConvertor.convert(dereferencedSchema, name);

this.logger.verbose(
`converted schemas: ${JSON.stringify(convertedSchemas)}`
);

return convertedSchemas;
}

async __dereferenceSchema(schema) {
const bundledSchema = await $RefParser
.bundle(schema, this.refParserOptions)
Expand Down Expand Up @@ -238,9 +252,23 @@ class SchemaHandler {
}
}

__checkForMissingPathAndThrow(error) {
if (error.message === "Expected a file path, URL, or object. Got undefined")
throw error;
}

__checkForHTTPErrorsAndThrow(error, model) {
if (error.errors) {
for (const err of error?.errors) {
this.__HTTPError(err, model);
}
} else {
this.__HTTPError(error, model);
}
}

__HTTPError(error, model) {
if (error.message.includes("HTTP ERROR")) {
// throw err;
throw new Error(
`There was an error dereferencing ${
model.name
Expand Down
10 changes: 3 additions & 7 deletions test/unit/definitionGenerator.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe("DefinitionGenerator", () => {
);

beforeEach(function () {
mockServerless = JSON.parse(JSON.stringify(serverlessMock));
mockServerless = structuredClone(serverlessMock);
Object.assign(mockServerless.service.custom.documentation, modelsDocument);
});

Expand All @@ -39,9 +39,7 @@ describe("DefinitionGenerator", () => {
});

it("should default to version 3.0.0 of openAPI when openAPI version is not passed in", function () {
const serverlessWithoutOpenAPIVersion = JSON.parse(
JSON.stringify(mockServerless)
);
const serverlessWithoutOpenAPIVersion = structuredClone(mockServerless);
delete serverlessWithoutOpenAPIVersion.processedInput;
let expected = new DefinitionGenerator(
serverlessWithoutOpenAPIVersion,
Expand Down Expand Up @@ -108,9 +106,7 @@ describe("DefinitionGenerator", () => {
});

it("should respect the version of openAPI when passed in", function () {
const serverlessWithOpenAPIVersion = JSON.parse(
JSON.stringify(mockServerless)
);
const serverlessWithOpenAPIVersion = structuredClone(mockServerless);
serverlessWithOpenAPIVersion.processedInput.options.openApiVersion =
"3.0.2";
let expected = new DefinitionGenerator(
Expand Down
12 changes: 3 additions & 9 deletions test/unit/openAPIGenerator.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,7 @@ describe("OpenAPIGenerator", () => {
const getAllFuncsStub = sinon
.stub(sls.service, "getAllFunctions")
.returns(["createUser"]);
const basicInvalidFunction = JSON.parse(
JSON.stringify(basicValidFunction)
);
const basicInvalidFunction = structuredClone(basicValidFunction);

delete basicInvalidFunction.createUser.events[0].http.documentation
.methodResponses[0].responseModels;
Expand Down Expand Up @@ -145,9 +143,7 @@ describe("OpenAPIGenerator", () => {
const getAllFuncsStub = sinon
.stub(sls.service, "getAllFunctions")
.returns(["createUser"]);
const basicInvalidFunction = JSON.parse(
JSON.stringify(basicValidFunction)
);
const basicInvalidFunction = structuredClone(basicValidFunction);

const getFuncStub = sinon
.stub(sls.service, "getFunction")
Expand Down Expand Up @@ -182,9 +178,7 @@ describe("OpenAPIGenerator", () => {
.stub(sls.service, "getAllFunctions")
.returns(["createUser"]);

const basicInvalidFunction = JSON.parse(
JSON.stringify(basicValidFunction)
);
const basicInvalidFunction = structuredClone(basicValidFunction);

delete basicInvalidFunction.createUser.events[0].http.documentation
.pathParams;
Expand Down
2 changes: 1 addition & 1 deletion test/unit/owasp.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe(`owasp`, function () {
});

it(`adds any properties contained in a new release`, async function () {
const newOWASPJSONAdded = JSON.parse(JSON.stringify(newOWASPJSON));
const newOWASPJSONAdded = structuredClone(newOWASPJSON);
newOWASPJSONAdded.headers.push({ name: "x-added", value: "true" });

nock("https://owasp.org")
Expand Down
22 changes: 9 additions & 13 deletions test/unit/schemaHandler.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ describe(`SchemaHandler`, function () {
};

beforeEach(function () {
mockServerless = JSON.parse(JSON.stringify(serverlessMock));
modelsDocument = JSON.parse(JSON.stringify(modelsDocumentOG));
modelsAltDocument = JSON.parse(JSON.stringify(modelsAltDocumentOG));
modelsListDocument = JSON.parse(JSON.stringify(modelsListDocumentOG));
modelsListAltDocument = JSON.parse(JSON.stringify(modelsListAltDocumentOG));
openAPI = JSON.parse(JSON.stringify(openAPISchema));
mockServerless = structuredClone(serverlessMock);
modelsDocument = structuredClone(modelsDocumentOG);
modelsAltDocument = structuredClone(modelsAltDocumentOG);
modelsListDocument = structuredClone(modelsListDocumentOG);
modelsListAltDocument = structuredClone(modelsListAltDocumentOG);
openAPI = structuredClone(openAPISchema);
});

describe(`constuctor`, function () {
Expand Down Expand Up @@ -135,7 +135,7 @@ describe(`SchemaHandler`, function () {
});

it(`should standardise mixed models syntax in to the correct format`, function () {
const newModelsDocument = JSON.parse(JSON.stringify(modelsDocument));
const newModelsDocument = structuredClone(modelsDocument);
Object.assign(
mockServerless.service.custom.documentation,
newModelsDocument
Expand Down Expand Up @@ -168,9 +168,7 @@ describe(`SchemaHandler`, function () {
});

it(`should standardise mixed modelsList syntax in to the correct format`, function () {
const newModelsDocument = JSON.parse(
JSON.stringify(modelsListDocument)
);
const newModelsDocument = structuredClone(modelsListDocument);
Object.assign(
mockServerless.service.custom.documentation,
newModelsDocument
Expand Down Expand Up @@ -203,9 +201,7 @@ describe(`SchemaHandler`, function () {
});

it(`should standardise mixed models and modelsList syntax in to the correct format`, function () {
const newModelsDocument = JSON.parse(
JSON.stringify(modelsListDocument)
);
const newModelsDocument = structuredClone(modelsListDocument);
Object.assign(
mockServerless.service.custom.documentation,
newModelsDocument
Expand Down